From 432fb52788314deae70d86db845ed2ab7c59a214 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Fri, 8 Apr 2022 04:35:08 +0200 Subject: [PATCH] backends/drm: refactor format choosing and prefer alpha formats Prefering alpha is needed for some interactions with video underlays; more directly choosing formats with an alpha channel will be needed for overlay planes, too. --- src/backends/drm/egl_gbm_backend.cpp | 55 +++++----------------------- src/backends/drm/egl_gbm_backend.h | 11 +++--- src/backends/drm/egl_gbm_layer.cpp | 39 ++++++++++++++------ src/backends/drm/shadowbuffer.cpp | 6 +-- 4 files changed, 45 insertions(+), 66 deletions(-) diff --git a/src/backends/drm/egl_gbm_backend.cpp b/src/backends/drm/egl_gbm_backend.cpp index b80bd33d55..3a7c4ef62f 100644 --- a/src/backends/drm/egl_gbm_backend.cpp +++ b/src/backends/drm/egl_gbm_backend.cpp @@ -161,42 +161,19 @@ bool EglGbmBackend::initBufferConfigs() GbmFormat format; format.drmFormat = gbmFormat; + EGLint red, green, blue; // Query number of bits for color channel - eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &format.redSize); - eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &format.greenSize); - eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &format.blueSize); + eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &red); + eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &green); + eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &blue); eglGetConfigAttrib(eglDisplay(), configs[i], EGL_ALPHA_SIZE, &format.alphaSize); - - if (m_formats.contains(format)) { + format.bpp = red + green + blue; + if (m_formats.contains(gbmFormat)) { continue; } - m_formats << format; + m_formats[gbmFormat] = format; m_configs[format.drmFormat] = configs[i]; } - - QVector colorDepthOrder = {30, 24}; - bool ok = false; - const int preferred = qEnvironmentVariableIntValue("KWIN_DRM_PREFER_COLOR_DEPTH", &ok); - if (ok) { - colorDepthOrder.prepend(preferred); - } - - std::sort(m_formats.begin(), m_formats.end(), [&colorDepthOrder](const auto &lhs, const auto &rhs) { - const int ls = lhs.redSize + lhs.greenSize + lhs.blueSize; - const int rs = rhs.redSize + rhs.greenSize + rhs.blueSize; - if (ls == rs) { - return lhs.alphaSize < rhs.alphaSize; - } else { - for (const int &d : qAsConst(colorDepthOrder)) { - if (ls == d) { - return true; - } else if (rs == d) { - return false; - } - } - return ls > rs; - } - }); if (!m_formats.isEmpty()) { return true; } @@ -242,23 +219,11 @@ QSharedPointer EglGbmBackend::textureForOutput(AbstractOutput *output return static_cast(drmOutput->outputLayer())->texture(); } -GbmFormat EglGbmBackend::gbmFormatForDrmFormat(uint32_t format) const +std::optional EglGbmBackend::gbmFormatForDrmFormat(uint32_t format) const { // TODO use a hardcoded lookup table where needed instead? - const auto it = std::find_if(m_formats.begin(), m_formats.end(), [format](const auto &gbmFormat) { - return gbmFormat.drmFormat == format; - }); - if (it == m_formats.end()) { - return GbmFormat{ - .drmFormat = DRM_FORMAT_XRGB8888, - .redSize = 8, - .greenSize = 8, - .blueSize = 8, - .alphaSize = 0, - }; - } else { - return *it; - } + const auto it = m_formats.constFind(format); + return it == m_formats.constEnd() ? std::optional() : *it; } bool EglGbmBackend::prefer10bpc() const diff --git a/src/backends/drm/egl_gbm_backend.h b/src/backends/drm/egl_gbm_backend.h index 83a2a326c3..e6de7aa755 100644 --- a/src/backends/drm/egl_gbm_backend.h +++ b/src/backends/drm/egl_gbm_backend.h @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -44,9 +45,7 @@ class DrmPipeline; struct GbmFormat { uint32_t drmFormat = 0; - EGLint redSize = -1; - EGLint greenSize = -1; - EGLint blueSize = -1; + uint32_t bpp; EGLint alphaSize = -1; }; bool operator==(const GbmFormat &lhs, const GbmFormat &rhs); @@ -76,7 +75,7 @@ public: QSharedPointer testBuffer(DrmAbstractOutput *output); EGLConfig config(uint32_t format) const; - GbmFormat gbmFormatForDrmFormat(uint32_t format) const; + std::optional gbmFormatForDrmFormat(uint32_t format) const; DrmGpu *gpu() const; Q_SIGNALS: @@ -88,8 +87,8 @@ private: bool initRenderingContext(); DrmBackend *m_backend; - QVector m_formats; - QMap m_configs; + QHash m_formats; + QHash m_configs; friend class EglGbmTexture; }; diff --git a/src/backends/drm/egl_gbm_layer.cpp b/src/backends/drm/egl_gbm_layer.cpp index ab1d4ffc9c..5ff5565443 100644 --- a/src/backends/drm/egl_gbm_layer.cpp +++ b/src/backends/drm/egl_gbm_layer.cpp @@ -100,7 +100,7 @@ OutputLayerBeginFrameInfo EglGbmLayer::beginFrame() m_shadowBuffer = m_oldShadowBuffer; } else { if (m_pipeline->pending.bufferTransformation != m_pipeline->pending.sourceTransformation) { - const auto format = m_eglBackend->gbmFormatForDrmFormat(m_gbmSurface->format()); + const auto format = m_eglBackend->gbmFormatForDrmFormat(m_gbmSurface->format()).value(); m_shadowBuffer = QSharedPointer::create(m_pipeline->sourceSize(), format); if (!m_shadowBuffer->isComplete()) { return {}; @@ -238,18 +238,35 @@ bool EglGbmLayer::createGbmSurface(uint32_t format, const QVector &mod bool EglGbmLayer::createGbmSurface() { - const auto tranches = m_eglBackend->dmabuf()->tranches(); - for (const auto &tranche : tranches) { - for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) { - const uint32_t &format = it.key(); - if (m_importMode == MultiGpuImportMode::DumbBufferXrgb8888 && format != DRM_FORMAT_XRGB8888) { - continue; - } - if (m_pipeline->isFormatSupported(format) && createGbmSurface(format, m_pipeline->supportedModifiers(format))) { - return true; - } + const auto formats = m_pipeline->supportedFormats(); + QVector sortedFormats; + for (auto it = formats.begin(); it != formats.end(); it++) { + const auto format = m_eglBackend->gbmFormatForDrmFormat(it.key()); + if (format.has_value()) { + sortedFormats << format.value(); } } + std::sort(sortedFormats.begin(), sortedFormats.end(), [this](const auto &lhs, const auto &rhs) { + if (lhs.drmFormat == rhs.drmFormat) { + // prefer having an alpha channel + return lhs.alphaSize > rhs.alphaSize; + } else if (m_eglBackend->prefer10bpc() && ((lhs.bpp == 30) != (rhs.bpp == 30))) { + // prefer 10bpc / 30bpp formats + return lhs.bpp == 30 ? true : false; + } else { + // fallback + return lhs.drmFormat < rhs.drmFormat; + } + }); + for (const auto &format : qAsConst(sortedFormats)) { + if (m_importMode == MultiGpuImportMode::DumbBufferXrgb8888 && format.drmFormat != DRM_FORMAT_XRGB8888) { + continue; + } + if (formats.contains(format.drmFormat) && createGbmSurface(format.drmFormat, formats[format.drmFormat])) { + return true; + } + } + qCCritical(KWIN_DRM, "Failed to create a gbm surface!"); return false; } diff --git a/src/backends/drm/shadowbuffer.cpp b/src/backends/drm/shadowbuffer.cpp index dea48a3be4..72983813b7 100644 --- a/src/backends/drm/shadowbuffer.cpp +++ b/src/backends/drm/shadowbuffer.cpp @@ -108,12 +108,10 @@ uint32_t ShadowBuffer::drmFormat() const GLint ShadowBuffer::internalFormat(const GbmFormat &format) const { - if (format.redSize <= 8 && format.greenSize <= 8 && format.blueSize <= 8) { + if (format.bpp <= 24) { return GL_RGBA8; - } else if (format.redSize <= 10 && format.greenSize <= 10 && format.blueSize <= 10) { + } else if (format.bpp <= 30) { return GL_RGB10_A2; - } else if (format.redSize <= 12 && format.greenSize <= 12 && format.blueSize <= 12) { - return GL_RGBA12; } else { return GL_RGBA16; }