diff --git a/src/backends/drm/drm_abstract_output.h b/src/backends/drm/drm_abstract_output.h index f8d86aeb66..595a29556d 100644 --- a/src/backends/drm/drm_abstract_output.h +++ b/src/backends/drm/drm_abstract_output.h @@ -33,6 +33,10 @@ public: virtual QSize sourceSize() const = 0; virtual bool isFormatSupported(uint32_t drmFormat) const = 0; virtual QVector supportedModifiers(uint32_t drmFormat) const = 0; + /** + * returns the maximum bits per color channel that make sense to be used for this output + */ + virtual int maxBpc() const = 0; DrmGpu *gpu() const; RenderLoop *renderLoop() const override; diff --git a/src/backends/drm/drm_object_connector.cpp b/src/backends/drm/drm_object_connector.cpp index 1e7de2bc11..eb8888ddc3 100644 --- a/src/backends/drm/drm_object_connector.cpp +++ b/src/backends/drm/drm_object_connector.cpp @@ -100,6 +100,7 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId) QByteArrayLiteral("Full"), QByteArrayLiteral("Limited 16:235") }), + PropertyDefinition(QByteArrayLiteral("max bpc"), Requirement::Optional), }, DRM_MODE_OBJECT_CONNECTOR) , m_pipeline(new DrmPipeline(this)) , m_conn(drmModeGetConnector(gpu->fd(), connectorId)) @@ -295,6 +296,9 @@ bool DrmConnector::needsModeset() const if (getProp(PropertyIndex::CrtcId)->needsCommit()) { return true; } + if (const auto &prop = getProp(PropertyIndex::MaxBpc); prop && prop->needsCommit()) { + return true; + } const auto &rgb = getProp(PropertyIndex::Broadcast_RGB); return rgb && rgb->needsCommit(); } @@ -380,6 +384,11 @@ bool DrmConnector::updateProperties() m_physicalSize = overwriteSize; } + if (auto bpc = getProp(PropertyIndex::MaxBpc)) { + // make sure the driver allows us to use high bpc + bpc->setPending(bpc->maxValue()); + } + // init modes updateModes(); diff --git a/src/backends/drm/drm_object_connector.h b/src/backends/drm/drm_object_connector.h index 75805f6a36..3fd48edb33 100644 --- a/src/backends/drm/drm_object_connector.h +++ b/src/backends/drm/drm_object_connector.h @@ -65,6 +65,7 @@ public: Underscan_vborder = 7, Underscan_hborder = 8, Broadcast_RGB = 9, + MaxBpc = 10, Count }; diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 3f996ba104..b65271d802 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -485,4 +485,10 @@ void DrmOutput::presentFailed() RenderLoopPrivate::get(m_renderLoop)->notifyFrameFailed(); } +int DrmOutput::maxBpc() const +{ + auto prop = m_connector->getProp(DrmConnector::PropertyIndex::MaxBpc); + return prop ? prop->maxValue() : 8; +} + } diff --git a/src/backends/drm/drm_output.h b/src/backends/drm/drm_output.h index 66a47a8c5c..949eaa905a 100644 --- a/src/backends/drm/drm_output.h +++ b/src/backends/drm/drm_output.h @@ -57,6 +57,7 @@ public: bool isFormatSupported(uint32_t drmFormat) const override; QVector supportedModifiers(uint32_t drmFormat) const override; bool needsSoftwareTransformation() const override; + int maxBpc() const override; bool queueChanges(const WaylandOutputConfig &config); void applyQueuedChanges(const WaylandOutputConfig &config); diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index 2d57d1e8f2..fb23f81d48 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -299,7 +299,7 @@ bool DrmPipeline::checkTestBuffer() // try to re-use buffers if possible. const auto &checkBuffer = [this, backend, &buffer](const QSharedPointer &buf){ const auto &mods = supportedModifiers(buf->format()); - if (backend && buf->format() == backend->drmFormat() + if (backend && buf->format() == backend->drmFormat(m_output) && (mods.isEmpty() || mods.contains(buf->modifier())) && buf->size() == sourceSize()) { buffer = buf; diff --git a/src/backends/drm/drm_virtual_output.cpp b/src/backends/drm/drm_virtual_output.cpp index 0deccfd264..0c31571e15 100644 --- a/src/backends/drm/drm_virtual_output.cpp +++ b/src/backends/drm/drm_virtual_output.cpp @@ -109,4 +109,9 @@ bool DrmVirtualOutput::needsSoftwareTransformation() const return false; } +int DrmVirtualOutput::maxBpc() const +{ + return 8; +} + } diff --git a/src/backends/drm/drm_virtual_output.h b/src/backends/drm/drm_virtual_output.h index 8fb665adba..18faaff70a 100644 --- a/src/backends/drm/drm_virtual_output.h +++ b/src/backends/drm/drm_virtual_output.h @@ -33,6 +33,7 @@ public: bool isFormatSupported(uint32_t drmFormat) const override; QVector supportedModifiers(uint32_t drmFormat) const override; + int maxBpc() const override; int gammaRampSize() const override; bool setGammaRamp(const GammaRamp &gamma) override; diff --git a/src/backends/drm/egl_gbm_backend.cpp b/src/backends/drm/egl_gbm_backend.cpp index 948609226d..b4a182bc6c 100644 --- a/src/backends/drm/egl_gbm_backend.cpp +++ b/src/backends/drm/egl_gbm_backend.cpp @@ -149,8 +149,15 @@ bool EglGbmBackend::initRenderingContext() bool EglGbmBackend::resetOutput(Output &output) { + std::optional gbmFormat = chooseFormat(output); + if (!gbmFormat.has_value()) { + qCCritical(KWIN_DRM) << "Could not find a suitable format for output" << output.output; + return false; + } + output.current.format = gbmFormat.value(); + uint32_t format = gbmFormat.value().drmFormat; const QSize size = output.output->sourceSize(); - QVector modifiers = output.output->supportedModifiers(m_gbmFormat); + QVector modifiers = output.output->supportedModifiers(format); QSharedPointer gbmSurface; bool modifiersEnvSet = false; @@ -168,14 +175,14 @@ bool EglGbmBackend::resetOutput(Output &output) } else { flags |= GBM_BO_USE_LINEAR; } - gbmSurface = QSharedPointer::create(m_gpu, size, m_gbmFormat, flags); + gbmSurface = QSharedPointer::create(m_gpu, size, format, flags, m_configs[format]); } else { - gbmSurface = QSharedPointer::create(m_gpu, size, m_gbmFormat, modifiers); + gbmSurface = QSharedPointer::create(m_gpu, size, format, modifiers, m_configs[format]); if (!gbmSurface->isValid()) { // the egl / gbm implementation may reject the modifier list from another gpu // as a fallback use linear, to at least make CPU copy more efficient modifiers = {DRM_FORMAT_MOD_LINEAR}; - gbmSurface = QSharedPointer::create(m_gpu, size, m_gbmFormat, modifiers); + gbmSurface = QSharedPointer::create(m_gpu, size, format, modifiers, m_configs[format]); } } if (!gbmSurface->isValid()) { @@ -191,7 +198,7 @@ bool EglGbmBackend::resetOutput(Output &output) output.current.shadowBuffer = nullptr; } else { makeContextCurrent(output.current); - output.current.shadowBuffer = QSharedPointer::create(output.output->pixelSize()); + output.current.shadowBuffer = QSharedPointer::create(output.output->pixelSize(), output.current.format); if (!output.current.shadowBuffer->isComplete()) { return false; } @@ -391,10 +398,7 @@ bool EglGbmBackend::initBufferConfigs() return false; } - qCDebug(KWIN_DRM) << "EGL buffer configs count:" << count; - - uint32_t fallbackFormat = 0; - EGLConfig fallbackConfig = nullptr; + setConfig(EGL_NO_CONFIG_KHR); // Loop through all configs, choosing the first one that has suitable format. for (EGLint i = 0; i < count; i++) { @@ -405,32 +409,49 @@ bool EglGbmBackend::initBufferConfigs() continue; } + GbmFormat format; + format.drmFormat = gbmFormat; // Query number of bits for color channel - EGLint blueSize, redSize, greenSize, alphaSize; - eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &redSize); - eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &greenSize); - eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &blueSize); - eglGetConfigAttrib(eglDisplay(), configs[i], EGL_ALPHA_SIZE, &alphaSize); + 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_ALPHA_SIZE, &format.alphaSize); - // prefer XRGB8888 as it's most likely to be supported by secondary GPUs as well - if (gbmFormat == GBM_FORMAT_XRGB8888) { - m_gbmFormat = gbmFormat; - setConfig(configs[i]); - return true; - } else if (!fallbackConfig && blueSize >= 8 && redSize >= 8 && greenSize >= 8) { - fallbackFormat = gbmFormat; - fallbackConfig = configs[i]; + if (m_formats.contains(format)) { + continue; } + m_formats << format; + m_configs[format.drmFormat] = configs[i]; } - if (fallbackConfig) { - m_gbmFormat = fallbackFormat; - setConfig(fallbackConfig); + 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; } - qCCritical(KWIN_DRM) << "Choosing EGL config did not return a suitable config. There were" - << count << "configs:"; + qCCritical(KWIN_DRM, "Choosing EGL config did not return a supported config. There were %u configs", count); for (EGLint i = 0; i < count; i++) { EGLint gbmFormat, blueSize, redSize, greenSize, alphaSize; eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &gbmFormat); @@ -637,9 +658,9 @@ bool EglGbmBackend::scanout(AbstractOutput *drmOutput, SurfaceItem *surfaceItem) tranche.flags = KWaylandServer::LinuxDmaBufV1Feedback::TrancheFlag::Scanout; // atm no format changes are sent as those might require a modeset // and thus require more elaborate feedback - const auto &mods = drmOutput->pipeline()->supportedModifiers(m_gbmFormat); + const auto &mods = drmOutput->pipeline()->supportedModifiers(output.current.format.drmFormat); for (const auto &mod : mods) { - tranche.formatTable[m_gbmFormat] << mod; + tranche.formatTable[output.current.format.drmFormat] << mod; } if (tranche.formatTable.isEmpty()) { output.scanoutCandidate->dmabufFeedbackV1()->setTranches({}); @@ -760,9 +781,10 @@ bool EglGbmBackend::hasOutput(AbstractOutput *output) const return m_outputs.contains(output); } -uint32_t EglGbmBackend::drmFormat() const +uint32_t EglGbmBackend::drmFormat(DrmAbstractOutput *output) const { - return m_gbmFormat; + const auto &o = m_outputs[output]; + return o.output ? o.current.format.drmFormat : DRM_FORMAT_XRGB8888; } DrmGpu *EglGbmBackend::gpu() const @@ -770,9 +792,38 @@ DrmGpu *EglGbmBackend::gpu() const return m_gpu; } +std::optional EglGbmBackend::chooseFormat(Output &output) const +{ + // formats are already sorted by order of preference + std::optional fallback; + for (const auto &format : qAsConst(m_formats)) { + if (output.output->isFormatSupported(format.drmFormat)) { + int bpc = std::max(format.redSize, std::max(format.greenSize, format.blueSize)); + if (bpc <= output.output->maxBpc() && !fallback.has_value()) { + fallback = format; + } else { + return format; + } + } + } + return fallback; +} + EglGbmBackend *EglGbmBackend::renderingBackend() { return static_cast(primaryBackend()); } +bool EglGbmBackend::prefer10bpc() const +{ + static bool ok = false; + static const int preferred = qEnvironmentVariableIntValue("KWIN_DRM_PREFER_COLOR_DEPTH", &ok); + return !ok || preferred == 30; +} + +bool operator==(const GbmFormat &lhs, const GbmFormat &rhs) +{ + return lhs.drmFormat == rhs.drmFormat; +} + } diff --git a/src/backends/drm/egl_gbm_backend.h b/src/backends/drm/egl_gbm_backend.h index 5329eeee7d..fff23fcdce 100644 --- a/src/backends/drm/egl_gbm_backend.h +++ b/src/backends/drm/egl_gbm_backend.h @@ -15,6 +15,7 @@ #include #include +#include struct gbm_surface; struct gbm_bo; @@ -38,6 +39,15 @@ class ShadowBuffer; class DrmBackend; class DrmGpu; +struct GbmFormat { + uint32_t drmFormat; + EGLint redSize; + EGLint greenSize; + EGLint blueSize; + EGLint alphaSize; +}; +bool operator==(const GbmFormat &lhs, const GbmFormat &rhs); + /** * @brief OpenGL Backend using Egl on a GBM surface. */ @@ -55,6 +65,7 @@ public: void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override; void init() override; bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override; + bool prefer10bpc() const override; QSharedPointer textureForOutput(AbstractOutput *requestedOutput) const override; @@ -66,7 +77,7 @@ public: bool directScanoutAllowed(AbstractOutput *output) const override; QSharedPointer renderTestFrame(DrmAbstractOutput *output); - uint32_t drmFormat() const; + uint32_t drmFormat(DrmAbstractOutput *output) const; DrmGpu *gpu() const; protected: @@ -89,6 +100,7 @@ private: QSharedPointer gbmSurface; int bufferAge = 0; DamageJournal damageJournal; + GbmFormat format; // for secondary GPU import ImportMode importMode = ImportMode::Dmabuf; @@ -113,13 +125,15 @@ private: QSharedPointer importFramebuffer(Output &output, const QRegion &dirty) const; QSharedPointer endFrameWithBuffer(AbstractOutput *output, const QRegion &dirty); void updateBufferAge(Output &output, const QRegion &dirty); + std::optional chooseFormat(Output &output) const; void cleanupRenderData(Output::RenderData &output); QMap m_outputs; - uint32_t m_gbmFormat; DrmBackend *m_backend; DrmGpu *m_gpu; + QVector m_formats; + QMap m_configs; static EglGbmBackend *renderingBackend(); diff --git a/src/backends/drm/gbm_surface.cpp b/src/backends/drm/gbm_surface.cpp index 94278ea493..595c7da4bd 100644 --- a/src/backends/drm/gbm_surface.cpp +++ b/src/backends/drm/gbm_surface.cpp @@ -19,31 +19,33 @@ namespace KWin { -GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags) +GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config) : m_surface(gbm_surface_create(gpu->gbmDevice(), size.width(), size.height(), format, flags)) , m_gpu(gpu) , m_size(size) + , m_format(format) { if (!m_surface) { qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno); return; } - m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), m_gpu->eglBackend()->config(), m_surface, nullptr); + m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), config, m_surface, nullptr); if (m_eglSurface == EGL_NO_SURFACE) { qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); } } -GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers) +GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers, EGLConfig config) : m_surface(gbm_surface_create_with_modifiers(gpu->gbmDevice(), size.width(), size.height(), format, modifiers.isEmpty() ? nullptr : modifiers.constData(), modifiers.count())) , m_gpu(gpu) , m_size(size) + , m_format(format) { if (!m_surface) { qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno); return; } - m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), m_gpu->eglBackend()->config(), m_surface, nullptr); + m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_gpu->eglDisplay(), config, m_surface, nullptr); if (m_eglSurface == EGL_NO_SURFACE) { qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); } @@ -131,4 +133,9 @@ bool GbmSurface::isValid() const return m_surface != nullptr && m_eglSurface != EGL_NO_SURFACE; } +uint32_t GbmSurface::format() const +{ + return m_format; +} + } diff --git a/src/backends/drm/gbm_surface.h b/src/backends/drm/gbm_surface.h index f7bca28394..60c1420b41 100644 --- a/src/backends/drm/gbm_surface.h +++ b/src/backends/drm/gbm_surface.h @@ -24,8 +24,8 @@ namespace KWin class GbmSurface { public: - explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags); - explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers); + explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config); + explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers, EGLConfig config); ~GbmSurface(); QSharedPointer swapBuffersForDrm(); @@ -39,12 +39,14 @@ public: EGLSurface eglSurface() const; QSize size() const; bool isValid() const; + uint32_t format() const; private: gbm_surface *m_surface; DrmGpu *m_gpu; EGLSurface m_eglSurface = EGL_NO_SURFACE; QSize m_size; + const uint32_t m_format; QSharedPointer m_currentBuffer; QSharedPointer m_currentDrmBuffer; diff --git a/src/backends/drm/shadowbuffer.cpp b/src/backends/drm/shadowbuffer.cpp index 14074a27c6..88cac6d72e 100644 --- a/src/backends/drm/shadowbuffer.cpp +++ b/src/backends/drm/shadowbuffer.cpp @@ -34,7 +34,7 @@ static const float texCoords[] = { 1.0f, 1.0f }; -ShadowBuffer::ShadowBuffer(const QSize &size) +ShadowBuffer::ShadowBuffer(const QSize &size, const GbmFormat &format) : m_size(size) { glGenFramebuffers(1, &m_framebuffer); @@ -43,7 +43,7 @@ ShadowBuffer::ShadowBuffer(const QSize &size) glGenTextures(1, &m_texture); glBindTexture(GL_TEXTURE_2D, m_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat(format), size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0); @@ -134,4 +134,17 @@ QSize ShadowBuffer::textureSize() const return m_size; } +GLint ShadowBuffer::internalFormat(const GbmFormat &format) +{ + if (format.redSize <= 8 && format.greenSize <= 8 && format.blueSize <= 8) { + return GL_RGBA8; + } else if (format.redSize <= 10 && format.greenSize <= 10 && format.blueSize <= 10) { + return GL_RGB10_A2; + } else if (format.redSize <= 12 && format.greenSize <= 12 && format.blueSize <= 12) { + return GL_RGBA12; + } else { + return GL_RGBA16; + } +} + } diff --git a/src/backends/drm/shadowbuffer.h b/src/backends/drm/shadowbuffer.h index dfb3bf535b..b05e8fbe21 100644 --- a/src/backends/drm/shadowbuffer.h +++ b/src/backends/drm/shadowbuffer.h @@ -11,6 +11,8 @@ #include #include +#include "egl_gbm_backend.h" + namespace KWin { @@ -19,7 +21,7 @@ class DrmAbstractOutput; class ShadowBuffer { public: - ShadowBuffer(const QSize &size); + ShadowBuffer(const QSize &size, const GbmFormat &format); ~ShadowBuffer(); bool isComplete() const; @@ -32,6 +34,7 @@ public: QSize textureSize() const; private: + GLint internalFormat(const GbmFormat &format); GLuint m_texture; GLuint m_framebuffer; QScopedPointer m_vbo; diff --git a/src/linux_dmabuf.cpp b/src/linux_dmabuf.cpp index 9cb3a56e25..367b002da6 100644 --- a/src/linux_dmabuf.cpp +++ b/src/linux_dmabuf.cpp @@ -53,9 +53,9 @@ KWaylandServer::LinuxDmaBufV1ClientBuffer *LinuxDmaBufV1RendererInterface::impor return nullptr; } -void LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(dev_t device, const QHash> &set) +void LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(const QVector &tranches) { - waylandServer()->linuxDmabuf()->setSupportedFormatsWithModifiers(device, set); + waylandServer()->linuxDmabuf()->setSupportedFormatsWithModifiers(tranches); } } diff --git a/src/linux_dmabuf.h b/src/linux_dmabuf.h index b46561644b..bbd617ff82 100644 --- a/src/linux_dmabuf.h +++ b/src/linux_dmabuf.h @@ -37,7 +37,7 @@ public: quint32 flags) override; protected: - void setSupportedFormatsAndModifiers(dev_t device, const QHash> &set); + void setSupportedFormatsAndModifiers(const QVector &tranches); }; } diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp index ad651079d4..5e4d3cbfdf 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -392,4 +392,10 @@ dev_t AbstractEglBackend::deviceId() const { return m_deviceId; } + +bool AbstractEglBackend::prefer10bpc() const +{ + return false; +} + } diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.h b/src/platformsupport/scenes/opengl/abstract_egl_backend.h index 920ae319f5..08cd11211c 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.h +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -71,6 +71,7 @@ public: } dev_t deviceId() const; + virtual bool prefer10bpc() const; protected: AbstractEglBackend(dev_t deviceId = 0); diff --git a/src/platformsupport/scenes/opengl/egl_dmabuf.cpp b/src/platformsupport/scenes/opengl/egl_dmabuf.cpp index 4e0c68ace0..50e4534dce 100644 --- a/src/platformsupport/scenes/opengl/egl_dmabuf.cpp +++ b/src/platformsupport/scenes/opengl/egl_dmabuf.cpp @@ -395,6 +395,34 @@ void filterFormatsWithMultiplePlanes(QVector &formats) } } +static int bpcForFormat(uint32_t format) +{ + switch(format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + return 8; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRX1010102: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_BGRA1010102: + return 10; + default: + return -1; + } +}; + void EglDmabuf::setSupportedFormatsAndModifiers() { const EGLDisplay eglDisplay = m_backend->eglDisplay(); @@ -412,30 +440,50 @@ void EglDmabuf::setSupportedFormatsAndModifiers() filterFormatsWithMultiplePlanes(formats); - QHash > set; - - for (auto format : qAsConst(formats)) { - if (eglQueryDmaBufModifiersEXT != nullptr) { - count = 0; - success = eglQueryDmaBufModifiersEXT(eglDisplay, format, 0, nullptr, nullptr, &count); - - if (success && count > 0) { - QVector modifiers(count); - if (eglQueryDmaBufModifiersEXT(eglDisplay, - format, count, modifiers.data(), - nullptr, &count)) { - QSet modifiersSet; - for (auto mod : qAsConst(modifiers)) { - modifiersSet.insert(mod); + auto queryFormats = [&formats, &eglDisplay](int bpc) { + QHash> set; + for (auto format : qAsConst(formats)) { + if (bpc != bpcForFormat(format)) { + continue; + } + if (eglQueryDmaBufModifiersEXT != nullptr) { + EGLint count = 0; + const EGLBoolean success = eglQueryDmaBufModifiersEXT(eglDisplay, format, 0, nullptr, nullptr, &count); + if (success && count > 0) { + QVector modifiers(count); + if (eglQueryDmaBufModifiersEXT(eglDisplay, format, count, modifiers.data(), nullptr, &count)) { + QSet modifiersSet; + for (const uint64_t &mod : qAsConst(modifiers)) { + modifiersSet.insert(mod); + } + set.insert(format, modifiersSet); + continue; } - set.insert(format, modifiersSet); - continue; } } + set.insert(format, QSet()); } - set.insert(format, QSet()); + return set; + }; + QVector tranches; + if (m_backend->prefer10bpc()) { + tranches.append({ + .device = m_backend->deviceId(), + .flags = {}, + .formatTable = queryFormats(10), + }); } - LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(m_backend->deviceId(), set); + tranches.append({ + .device = m_backend->deviceId(), + .flags = {}, + .formatTable = queryFormats(8), + }); + tranches.append({ + .device = m_backend->deviceId(), + .flags = {}, + .formatTable = queryFormats(-1), + }); + LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(tranches); } }