From c26101a9fe6e7e2f94d04e700519eafa215e59cc Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 16 Jan 2024 22:47:18 +0100 Subject: [PATCH] backends/drm: use a swapchain instead of an OpenGL texture for the shadow buffer(s) This seems to have better performance on Intel GPUs, and allows us to implement damage tracking for the shadow "buffer" in the future CCBUG: 477223 --- src/backends/drm/drm_egl_layer_surface.cpp | 51 ++++++++++++++++------ src/backends/drm/drm_egl_layer_surface.h | 4 +- src/utils/drm_format_helper.cpp | 9 ++++ src/utils/drm_format_helper.h | 1 + 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/backends/drm/drm_egl_layer_surface.cpp b/src/backends/drm/drm_egl_layer_surface.cpp index 31cf4701e5..ab0b51f468 100644 --- a/src/backends/drm/drm_egl_layer_surface.cpp +++ b/src/backends/drm/drm_egl_layer_surface.cpp @@ -121,23 +121,46 @@ std::optional EglGbmLayerSurface::startRendering(cons const QRegion repaint = bufferAgeEnabled ? m_surface->damageJournal.accumulate(slot->age(), infiniteRegion()) : infiniteRegion(); if (enableColormanagement) { - if (!m_surface->shadowBuffer || m_surface->shadowTexture->size() != m_surface->gbmSwapchain->size()) { - m_surface->shadowTexture = GLTexture::allocate(GL_RGBA16F, m_surface->gbmSwapchain->size()); - if (!m_surface->shadowTexture) { - return std::nullopt; + if (!m_surface->shadowSwapchain || m_surface->shadowSwapchain->size() != m_surface->gbmSwapchain->size()) { + const auto formats = m_eglBackend->eglDisplayObject()->nonExternalOnlySupportedDrmFormats(); + const auto createSwapchain = [&formats, this](bool requireAlpha) { + for (auto it = formats.begin(); it != formats.end(); it++) { + const auto info = FormatInfo::get(it.key()); + if (!info || info->bitsPerColor != 16 || !info->floatingPoint) { + continue; + } + if (requireAlpha && info->alphaBits == 0) { + continue; + } + m_surface->shadowSwapchain = EglSwapchain::create(m_eglBackend->drmDevice()->allocator(), m_eglBackend->openglContext(), m_surface->gbmSwapchain->size(), it.key(), it.value()); + if (m_surface->shadowSwapchain) { + break; + } + } + }; + createSwapchain(true); + if (!m_surface->shadowSwapchain && m_formatOption != FormatOption::RequireAlpha) { + createSwapchain(false); } - m_surface->shadowBuffer = std::make_unique(m_surface->shadowTexture.get()); } - m_surface->shadowTexture->setContentTransform(m_surface->currentSlot->framebuffer()->colorAttachment()->contentTransform()); + if (!m_surface->shadowSwapchain) { + qCCritical(KWIN_DRM) << "Failed to create shadow swapchain!"; + return std::nullopt; + } + m_surface->currentShadowSlot = m_surface->shadowSwapchain->acquire(); + if (!m_surface->currentShadowSlot) { + return std::nullopt; + } + m_surface->currentShadowSlot->texture()->setContentTransform(m_surface->currentSlot->framebuffer()->colorAttachment()->contentTransform()); m_surface->renderStart = std::chrono::steady_clock::now(); m_surface->timeQuery->begin(); return OutputLayerBeginFrameInfo{ - .renderTarget = RenderTarget(m_surface->shadowBuffer.get(), m_surface->intermediaryColorDescription), - .repaint = repaint, + .renderTarget = RenderTarget(m_surface->currentShadowSlot->framebuffer(), m_surface->intermediaryColorDescription), + .repaint = infiniteRegion(), }; } else { - m_surface->shadowTexture.reset(); - m_surface->shadowBuffer.reset(); + m_surface->shadowSwapchain.reset(); + m_surface->currentShadowSlot.reset(); m_surface->renderStart = std::chrono::steady_clock::now(); m_surface->timeQuery->begin(); return OutputLayerBeginFrameInfo{ @@ -173,7 +196,9 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) mat.ortho(QRectF(QPointF(), fbo->size())); binder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mat); glDisable(GL_BLEND); - m_surface->shadowTexture->render(m_surface->gbmSwapchain->size()); + m_surface->currentShadowSlot->texture()->render(m_surface->gbmSwapchain->size()); + EGLNativeFence fence(m_surface->context->displayObject()); + m_surface->shadowSwapchain->release(m_surface->currentShadowSlot, fence.fileDescriptor().duplicate()); GLFramebuffer::popFramebuffer(); } m_surface->damageJournal.add(damagedRegion); @@ -227,7 +252,7 @@ std::shared_ptr EglGbmLayerSurface::currentBuffer() const const ColorDescription &EglGbmLayerSurface::colorDescription() const { if (m_surface) { - return m_surface->shadowTexture ? m_surface->intermediaryColorDescription : m_surface->targetColorDescription; + return m_surface->currentShadowSlot ? m_surface->intermediaryColorDescription : m_surface->targetColorDescription; } else { return ColorDescription::sRGB; } @@ -241,7 +266,7 @@ bool EglGbmLayerSurface::doesSurfaceFit(const QSize &size, const QMap EglGbmLayerSurface::texture() const { if (m_surface) { - return m_surface->shadowTexture ? m_surface->shadowTexture : m_surface->currentSlot->texture(); + return m_surface->currentShadowSlot ? m_surface->currentShadowSlot->texture() : m_surface->currentSlot->texture(); } else { return nullptr; } diff --git a/src/backends/drm/drm_egl_layer_surface.h b/src/backends/drm/drm_egl_layer_surface.h index db94315b5a..c2ed18a6f4 100644 --- a/src/backends/drm/drm_egl_layer_surface.h +++ b/src/backends/drm/drm_egl_layer_surface.h @@ -99,8 +99,8 @@ private: // for color management bool colormanagementEnabled = false; - std::shared_ptr shadowTexture; - std::unique_ptr shadowBuffer; + std::shared_ptr shadowSwapchain; + std::shared_ptr currentShadowSlot; ColorDescription targetColorDescription = ColorDescription::sRGB; ColorDescription intermediaryColorDescription = ColorDescription::sRGB; QVector3D channelFactors = {1, 1, 1}; diff --git a/src/utils/drm_format_helper.cpp b/src/utils/drm_format_helper.cpp index e78f7a107d..6998da23bf 100644 --- a/src/utils/drm_format_helper.cpp +++ b/src/utils/drm_format_helper.cpp @@ -24,6 +24,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 0, .bitsPerPixel = 32, .openglFormat = GL_RGBA8, + .floatingPoint = false, }; case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ABGR8888: @@ -35,6 +36,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 8, .bitsPerPixel = 32, .openglFormat = GL_RGBA8, + .floatingPoint = false, }; case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_XBGR2101010: @@ -46,6 +48,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 0, .bitsPerPixel = 32, .openglFormat = GL_RGB10_A2, + .floatingPoint = false, }; case DRM_FORMAT_ARGB2101010: case DRM_FORMAT_ABGR2101010: @@ -57,6 +60,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 2, .bitsPerPixel = 32, .openglFormat = GL_RGB10_A2, + .floatingPoint = false, }; case DRM_FORMAT_XRGB16161616F: case DRM_FORMAT_XBGR16161616F: @@ -66,6 +70,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 0, .bitsPerPixel = 64, .openglFormat = GL_RGBA16F, + .floatingPoint = true, }; case DRM_FORMAT_ARGB16161616F: case DRM_FORMAT_ABGR16161616F: @@ -75,6 +80,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 16, .bitsPerPixel = 64, .openglFormat = GL_RGBA16F, + .floatingPoint = true, }; case DRM_FORMAT_ARGB4444: case DRM_FORMAT_ABGR4444: @@ -86,6 +92,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 4, .bitsPerPixel = 16, .openglFormat = GL_RGBA4, + .floatingPoint = false, }; case DRM_FORMAT_ARGB1555: case DRM_FORMAT_ABGR1555: @@ -97,6 +104,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 1, .bitsPerPixel = 16, .openglFormat = GL_RGB5_A1, + .floatingPoint = false, }; case DRM_FORMAT_NV12: return FormatInfo{ @@ -105,6 +113,7 @@ std::optional FormatInfo::get(uint32_t drmFormat) .alphaBits = 0, .bitsPerPixel = 24, .openglFormat = GL_R8, + .floatingPoint = false, }; default: return std::nullopt; diff --git a/src/utils/drm_format_helper.h b/src/utils/drm_format_helper.h index d68893609e..d6fa2ff2e7 100644 --- a/src/utils/drm_format_helper.h +++ b/src/utils/drm_format_helper.h @@ -45,6 +45,7 @@ struct KWIN_EXPORT FormatInfo uint32_t alphaBits; uint32_t bitsPerPixel; GLint openglFormat; + bool floatingPoint; std::optional yuvConversion() const {