diff --git a/src/plugins/platforms/drm/abstract_egl_drm_backend.h b/src/plugins/platforms/drm/abstract_egl_drm_backend.h index 80aec19d68..d1215c660b 100644 --- a/src/plugins/platforms/drm/abstract_egl_drm_backend.h +++ b/src/plugins/platforms/drm/abstract_egl_drm_backend.h @@ -62,6 +62,8 @@ public: virtual QSharedPointer renderTestFrame(DrmAbstractOutput *output) = 0; + virtual uint32_t drmFormat() const = 0; + static AbstractEglDrmBackend *renderingBackend() { return static_cast(primaryBackend()); } diff --git a/src/plugins/platforms/drm/drm_buffer.cpp b/src/plugins/platforms/drm/drm_buffer.cpp index f241bea20d..2d56730097 100644 --- a/src/plugins/platforms/drm/drm_buffer.cpp +++ b/src/plugins/platforms/drm/drm_buffer.cpp @@ -18,18 +18,21 @@ // drm #include #include +#include namespace KWin { -DrmBuffer:: DrmBuffer(DrmGpu *gpu) +DrmBuffer:: DrmBuffer(DrmGpu *gpu, uint32_t format, uint64_t modifier) : m_gpu(gpu) + , m_format(format) + , m_modifier(modifier) { } // DrmDumbBuffer DrmDumbBuffer::DrmDumbBuffer(DrmGpu *gpu, const QSize &size) - : DrmBuffer(gpu) + : DrmBuffer(gpu, DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR) { m_size = size; drm_mode_create_dumb createArgs; diff --git a/src/plugins/platforms/drm/drm_buffer.h b/src/plugins/platforms/drm/drm_buffer.h index 1176a2c248..74de73b6f0 100644 --- a/src/plugins/platforms/drm/drm_buffer.h +++ b/src/plugins/platforms/drm/drm_buffer.h @@ -20,7 +20,7 @@ class DrmGpu; class DrmBuffer { public: - DrmBuffer(DrmGpu *gpu); + DrmBuffer(DrmGpu *gpu, uint32_t format, uint64_t modifier); virtual ~DrmBuffer() = default; virtual bool needsModeChange(DrmBuffer *b) const {Q_UNUSED(b) return false;} @@ -36,11 +36,19 @@ public: DrmGpu *gpu() const { return m_gpu; } + uint32_t format() const { + return m_format; + } + uint64_t modifier() const { + return m_modifier; + } protected: quint32 m_bufferId = 0; QSize m_size; DrmGpu *m_gpu; + uint32_t m_format; + uint64_t m_modifier; }; class DrmDumbBuffer : public DrmBuffer diff --git a/src/plugins/platforms/drm/drm_buffer_gbm.cpp b/src/plugins/platforms/drm/drm_buffer_gbm.cpp index 84fc554853..d0ca248e71 100644 --- a/src/plugins/platforms/drm/drm_buffer_gbm.cpp +++ b/src/plugins/platforms/drm/drm_buffer_gbm.cpp @@ -85,13 +85,13 @@ bool GbmBuffer::map(uint32_t flags) DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, GbmSurface *surface, gbm_bo *bo) - : DrmBuffer(gpu), GbmBuffer(surface, bo) + : DrmBuffer(gpu, gbm_bo_get_format(bo), gbm_bo_get_modifier(bo)), GbmBuffer(surface, bo) { initialize(); } DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, gbm_bo *buffer, KWaylandServer::ClientBuffer *clientBuffer) - : DrmBuffer(gpu), GbmBuffer(buffer, clientBuffer) + : DrmBuffer(gpu, gbm_bo_get_format(buffer), gbm_bo_get_modifier(buffer)), GbmBuffer(buffer, clientBuffer) { initialize(); } @@ -108,7 +108,6 @@ DrmGbmBuffer::~DrmGbmBuffer() void DrmGbmBuffer::initialize() { m_size = QSize(gbm_bo_get_width(m_bo), gbm_bo_get_height(m_bo)); - uint32_t format = gbm_bo_get_format(m_bo); uint32_t handles[4] = { }; uint32_t strides[4] = { }; uint32_t offsets[4] = { }; @@ -119,7 +118,7 @@ void DrmGbmBuffer::initialize() handles[i] = gbm_bo_get_handle_for_plane(m_bo, i).u32; strides[i] = gbm_bo_get_stride_for_plane(m_bo, i); offsets[i] = gbm_bo_get_offset(m_bo, i); - modifiers[i] = gbm_bo_get_modifier(m_bo); + modifiers[i] = m_modifier; } } else { handles[0] = gbm_bo_get_handle(m_bo).u32; @@ -128,17 +127,17 @@ void DrmGbmBuffer::initialize() } if (modifiers[0] != DRM_FORMAT_MOD_INVALID && m_gpu->addFB2ModifiersSupported()) { - if (drmModeAddFB2WithModifiers(m_gpu->fd(), m_size.width(), m_size.height(), format, handles, strides, offsets, modifiers, &m_bufferId, DRM_MODE_FB_MODIFIERS)) { + if (drmModeAddFB2WithModifiers(m_gpu->fd(), m_size.width(), m_size.height(), m_format, handles, strides, offsets, modifiers, &m_bufferId, DRM_MODE_FB_MODIFIERS)) { gbm_format_name_desc name; - gbm_format_get_name(format, &name); + gbm_format_get_name(m_format, &name); qCCritical(KWIN_DRM) << "drmModeAddFB2WithModifiers on GPU" << m_gpu->devNode() << "failed for a buffer with format" << name.name << "and modifier" << modifiers[0] << strerror(errno); } } else { - if (drmModeAddFB2(m_gpu->fd(), m_size.width(), m_size.height(), format, handles, strides, offsets, &m_bufferId, 0)) { + if (drmModeAddFB2(m_gpu->fd(), m_size.width(), m_size.height(), m_format, handles, strides, offsets, &m_bufferId, 0)) { // fallback if (drmModeAddFB(m_gpu->fd(), m_size.width(), m_size.height(), 24, 32, strides[0], handles[0], &m_bufferId) != 0) { gbm_format_name_desc name; - gbm_format_get_name(format, &name); + gbm_format_get_name(m_format, &name); qCCritical(KWIN_DRM) << "drmModeAddFB2 and drmModeAddFB both failed on GPU" << m_gpu->devNode() << "for a buffer with format" << name.name << "and modifier" << modifiers[0] << strerror(errno); } } diff --git a/src/plugins/platforms/drm/drm_pipeline.cpp b/src/plugins/platforms/drm/drm_pipeline.cpp index 9fdd95d080..eaa2a9c109 100644 --- a/src/plugins/platforms/drm/drm_pipeline.cpp +++ b/src/plugins/platforms/drm/drm_pipeline.cpp @@ -275,10 +275,29 @@ bool DrmPipeline::checkTestBuffer() if (!isActive()) { return true; } - QSharedPointer buffer; -#if HAVE_GBM auto backend = m_gpu->eglBackend(); - if (backend && m_output) { + QSharedPointer buffer; + // try to re-use buffers if possible. + const auto &checkBuffer = [this, backend, &buffer](const QSharedPointer &buf){ + if (buf->format() == backend->drmFormat() + && (!m_gpu->atomicModeSetting() || supportedModifiers(buf->format()).contains(buf->modifier())) + && buf->size() == sourceSize()) { + buffer = buf; + } + }; + if (m_primaryPlane && m_primaryPlane->next()) { + checkBuffer(m_primaryPlane->next()); + } else if (m_primaryPlane && m_primaryPlane->current()) { + checkBuffer(m_primaryPlane->current()); + } else if (m_crtc->next()) { + checkBuffer(m_crtc->next()); + } else if (m_crtc->current()) { + checkBuffer(m_crtc->current()); + } + // if we don't have a fitting buffer already, get or create one + if (buffer) { +#if HAVE_GBM + } else if (backend && m_output) { buffer = backend->renderTestFrame(m_output); } else if (backend && m_gpu->gbmDevice()) { gbm_bo *bo = gbm_bo_create(m_gpu->gbmDevice(), sourceSize().width(), sourceSize().height(), GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); @@ -286,12 +305,10 @@ bool DrmPipeline::checkTestBuffer() return false; } buffer = QSharedPointer::create(m_gpu, bo, nullptr); +#endif } else { buffer = QSharedPointer::create(m_gpu, sourceSize()); } -#else - buffer = QSharedPointer::create(m_gpu, sourceSize()); -#endif if (buffer && buffer->bufferId()) { m_oldTestBuffer = m_primaryBuffer; m_primaryBuffer = buffer; diff --git a/src/plugins/platforms/drm/egl_gbm_backend.cpp b/src/plugins/platforms/drm/egl_gbm_backend.cpp index 0edcb99ed0..67d2142081 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/src/plugins/platforms/drm/egl_gbm_backend.cpp @@ -734,4 +734,9 @@ bool EglGbmBackend::hasOutput(AbstractOutput *output) const return m_outputs.contains(output); } +uint32_t EglGbmBackend::drmFormat() const +{ + return m_gbmFormat; +} + } diff --git a/src/plugins/platforms/drm/egl_gbm_backend.h b/src/plugins/platforms/drm/egl_gbm_backend.h index c5142b2af6..b07fba6ede 100644 --- a/src/plugins/platforms/drm/egl_gbm_backend.h +++ b/src/plugins/platforms/drm/egl_gbm_backend.h @@ -65,6 +65,7 @@ public: bool directScanoutAllowed(AbstractOutput *output) const override; QSharedPointer renderTestFrame(DrmAbstractOutput *output) override; + uint32_t drmFormat() const override; protected: void cleanupSurfaces() override; diff --git a/src/plugins/platforms/drm/egl_stream_backend.cpp b/src/plugins/platforms/drm/egl_stream_backend.cpp index 6761def821..e5bcc086b9 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.cpp +++ b/src/plugins/platforms/drm/egl_stream_backend.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace KWin { @@ -576,6 +577,11 @@ bool EglStreamBackend::hasOutput(AbstractOutput *output) const return m_outputs.contains(output); } +uint32_t EglStreamBackend::drmFormat() const +{ + return DRM_FORMAT_XRGB8888; +} + /************************************************ * EglTexture ************************************************/ diff --git a/src/plugins/platforms/drm/egl_stream_backend.h b/src/plugins/platforms/drm/egl_stream_backend.h index c1f0c4447e..bc80f97a21 100644 --- a/src/plugins/platforms/drm/egl_stream_backend.h +++ b/src/plugins/platforms/drm/egl_stream_backend.h @@ -44,6 +44,7 @@ public: void removeOutput(DrmAbstractOutput *output) override; QSharedPointer renderTestFrame(DrmAbstractOutput *output) override; + uint32_t drmFormat() const override; protected: void cleanupSurfaces() override;