From 103d8d8abe354be0a7b37d54c72c765a6c3a9cc4 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 12 Apr 2023 16:59:42 +0300 Subject: [PATCH] {core,backends/wayland}: Refactor gbm buffer allocator --- src/CMakeLists.txt | 2 + src/backends/wayland/wayland_egl_backend.cpp | 67 ++++------ src/backends/wayland/wayland_egl_backend.h | 8 +- src/core/gbmgraphicsbufferallocator.cpp | 123 +++++++++++++++++++ src/core/gbmgraphicsbufferallocator.h | 52 ++++++++ src/core/graphicsbufferallocator.cpp | 20 +++ src/core/graphicsbufferallocator.h | 28 +++++ 7 files changed, 252 insertions(+), 48 deletions(-) create mode 100644 src/core/gbmgraphicsbufferallocator.cpp create mode 100644 src/core/gbmgraphicsbufferallocator.h create mode 100644 src/core/graphicsbufferallocator.cpp create mode 100644 src/core/graphicsbufferallocator.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c871983ae5..470e27cd03 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,7 +42,9 @@ target_sources(kwin PRIVATE core/colorlut.cpp core/colorpipelinestage.cpp core/colortransformation.cpp + core/gbmgraphicsbufferallocator.cpp core/graphicsbuffer.cpp + core/graphicsbufferallocator.cpp core/inputbackend.cpp core/inputdevice.cpp core/output.cpp diff --git a/src/backends/wayland/wayland_egl_backend.cpp b/src/backends/wayland/wayland_egl_backend.cpp index f22fa4dad5..c4d50686b6 100644 --- a/src/backends/wayland/wayland_egl_backend.cpp +++ b/src/backends/wayland/wayland_egl_backend.cpp @@ -9,7 +9,7 @@ */ #include "wayland_egl_backend.h" -#include "../drm/gbm_dmabuf.h" +#include "core/gbmgraphicsbufferallocator.h" #include "platformsupport/scenes/opengl/basiceglsurfacetexture_internal.h" #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" @@ -44,34 +44,10 @@ namespace KWin namespace Wayland { -WaylandEglLayerBuffer::WaylandEglLayerBuffer(const QSize &size, uint32_t format, const QVector &modifiers, WaylandEglBackend *backend) - : m_backend(backend) +WaylandEglLayerBuffer::WaylandEglLayerBuffer(GbmGraphicsBuffer *buffer, WaylandEglBackend *backend) + : m_graphicsBuffer(buffer) { - gbm_device *gbmDevice = backend->backend()->gbmDevice(); - - if (!modifiers.isEmpty()) { - m_bo = gbm_bo_create_with_modifiers(gbmDevice, - size.width(), - size.height(), - format, - modifiers.constData(), - modifiers.size()); - } - - if (!m_bo) { - m_bo = gbm_bo_create(gbmDevice, - size.width(), - size.height(), - format, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - } - - if (!m_bo) { - qCCritical(KWIN_WAYLAND_BACKEND) << "Failed to allocate a buffer for an output layer"; - return; - } - - DmaBufAttributes attributes = dmaBufAttributesForBo(m_bo); + const DmaBufAttributes &attributes = buffer->dmabufAttributes(); zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(backend->backend()->display()->linuxDmabuf()->handle()); for (int i = 0; i < attributes.planeCount; ++i) { @@ -84,10 +60,10 @@ WaylandEglLayerBuffer::WaylandEglLayerBuffer(const QSize &size, uint32_t format, attributes.modifier & 0xffffffff); } - m_buffer = zwp_linux_buffer_params_v1_create_immed(params, size.width(), size.height(), format, 0); + m_buffer = zwp_linux_buffer_params_v1_create_immed(params, attributes.width, attributes.height, attributes.format, 0); zwp_linux_buffer_params_v1_destroy(params); - m_texture = backend->importDmaBufAsTexture(std::move(attributes)); + m_texture = backend->importDmaBufAsTexture(attributes); m_framebuffer = std::make_unique(m_texture.get()); } @@ -96,12 +72,13 @@ WaylandEglLayerBuffer::~WaylandEglLayerBuffer() m_texture.reset(); m_framebuffer.reset(); - if (m_buffer) { - wl_buffer_destroy(m_buffer); - } - if (m_bo) { - gbm_bo_destroy(m_bo); - } + wl_buffer_destroy(m_buffer); + m_graphicsBuffer->drop(); +} + +GbmGraphicsBuffer *WaylandEglLayerBuffer::graphicsBuffer() const +{ + return m_graphicsBuffer; } wl_buffer *WaylandEglLayerBuffer::buffer() const @@ -124,17 +101,19 @@ int WaylandEglLayerBuffer::age() const return m_age; } -gbm_bo *WaylandEglLayerBuffer::bo() const -{ - return m_bo; -} - WaylandEglLayerSwapchain::WaylandEglLayerSwapchain(const QSize &size, uint32_t format, const QVector &modifiers, WaylandEglBackend *backend) : m_backend(backend) , m_size(size) { + GbmGraphicsBufferAllocator allocator(backend->backend()->gbmDevice()); + for (int i = 0; i < 2; ++i) { - m_buffers.append(std::make_shared(size, format, modifiers, backend)); + GbmGraphicsBuffer *buffer = allocator.allocate(size, format, modifiers); + if (!buffer) { + qCWarning(KWIN_WAYLAND_BACKEND) << "Failed to allocate layer swapchain buffer"; + continue; + } + m_buffers.append(std::make_shared(buffer, backend)); } } @@ -290,12 +269,12 @@ bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegio quint32 WaylandEglCursorLayer::format() const { - return gbm_bo_get_format(m_buffer->bo()); + return m_buffer->graphicsBuffer()->dmabufAttributes().format; } quint32 WaylandEglPrimaryLayer::format() const { - return gbm_bo_get_format(m_buffer->bo()); + return m_buffer->graphicsBuffer()->dmabufAttributes().format; } WaylandEglBackend::WaylandEglBackend(WaylandBackend *b) diff --git a/src/backends/wayland/wayland_egl_backend.h b/src/backends/wayland/wayland_egl_backend.h index 50625a9424..d63ec81222 100644 --- a/src/backends/wayland/wayland_egl_backend.h +++ b/src/backends/wayland/wayland_egl_backend.h @@ -25,6 +25,7 @@ struct gbm_bo; namespace KWin { class GLFramebuffer; +class GbmGraphicsBuffer; namespace Wayland { @@ -35,19 +36,18 @@ class WaylandEglBackend; class WaylandEglLayerBuffer { public: - WaylandEglLayerBuffer(const QSize &size, uint32_t format, const QVector &modifiers, WaylandEglBackend *backend); + WaylandEglLayerBuffer(GbmGraphicsBuffer *buffer, WaylandEglBackend *backend); ~WaylandEglLayerBuffer(); + GbmGraphicsBuffer *graphicsBuffer() const; wl_buffer *buffer() const; GLFramebuffer *framebuffer() const; std::shared_ptr texture() const; int age() const; - gbm_bo *bo() const; private: - WaylandEglBackend *m_backend; + GbmGraphicsBuffer *m_graphicsBuffer; wl_buffer *m_buffer = nullptr; - gbm_bo *m_bo = nullptr; std::unique_ptr m_framebuffer; std::shared_ptr m_texture; int m_age = 0; diff --git a/src/core/gbmgraphicsbufferallocator.cpp b/src/core/gbmgraphicsbufferallocator.cpp new file mode 100644 index 0000000000..eb467f230b --- /dev/null +++ b/src/core/gbmgraphicsbufferallocator.cpp @@ -0,0 +1,123 @@ +/* + SPDX-FileCopyrightText: 2023 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "core/gbmgraphicsbufferallocator.h" +#include "backends/drm/gbm_dmabuf.h" // FIXME: move dmaBufAttributesForBo() elsewhere + +#include +#include + +namespace KWin +{ + +GbmGraphicsBufferAllocator::GbmGraphicsBufferAllocator(gbm_device *device) + : m_gbmDevice(device) +{ +} + +GbmGraphicsBufferAllocator::~GbmGraphicsBufferAllocator() +{ +} + +GbmGraphicsBuffer *GbmGraphicsBufferAllocator::allocate(const QSize &size, uint32_t format, const QVector &modifiers) +{ + gbm_bo *bo = nullptr; + + if (!modifiers.isEmpty() && !(modifiers.size() == 1 && modifiers.first() == DRM_FORMAT_MOD_INVALID)) { + bo = gbm_bo_create_with_modifiers(m_gbmDevice, + size.width(), + size.height(), + format, + modifiers.constData(), + modifiers.size()); + } + + if (!bo) { + bo = gbm_bo_create(m_gbmDevice, + size.width(), + size.height(), + format, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + } + + if (!bo) { + return nullptr; + } + + return new GbmGraphicsBuffer(bo, size, format); +} + +static bool alphaChannelFromDrmFormat(uint32_t drmFormat) +{ + switch (drmFormat) { + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_BGRA4444: + + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_BGRA5551: + + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_BGRA1010102: + + case DRM_FORMAT_XRGB8888_A8: + case DRM_FORMAT_XBGR8888_A8: + case DRM_FORMAT_RGBX8888_A8: + case DRM_FORMAT_BGRX8888_A8: + case DRM_FORMAT_RGB888_A8: + case DRM_FORMAT_BGR888_A8: + case DRM_FORMAT_RGB565_A8: + case DRM_FORMAT_BGR565_A8: + return true; + default: + return false; + } +} + +GbmGraphicsBuffer::GbmGraphicsBuffer(gbm_bo *handle, const QSize &size, uint32_t format) + : m_bo(handle) + , m_dmabufAttributes(dmaBufAttributesForBo(handle)) + , m_size(size) + , m_hasAlphaChannel(alphaChannelFromDrmFormat(format)) +{ +} + +GbmGraphicsBuffer::~GbmGraphicsBuffer() +{ + gbm_bo_destroy(m_bo); +} + +QSize GbmGraphicsBuffer::size() const +{ + return m_size; +} + +bool GbmGraphicsBuffer::hasAlphaChannel() const +{ + return m_hasAlphaChannel; +} + +GraphicsBuffer::Origin GbmGraphicsBuffer::origin() const +{ + return Origin::TopLeft; +} + +const DmaBufAttributes &GbmGraphicsBuffer::dmabufAttributes() const +{ + return m_dmabufAttributes; +} + +} // namespace KWin diff --git a/src/core/gbmgraphicsbufferallocator.h b/src/core/gbmgraphicsbufferallocator.h new file mode 100644 index 0000000000..22bec9da0a --- /dev/null +++ b/src/core/gbmgraphicsbufferallocator.h @@ -0,0 +1,52 @@ +/* + SPDX-FileCopyrightText: 2023 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include "core/dmabufattributes.h" +#include "core/graphicsbuffer.h" +#include "core/graphicsbufferallocator.h" + +struct gbm_bo; +struct gbm_device; + +namespace KWin +{ + +class KWIN_EXPORT GbmGraphicsBuffer : public GraphicsBuffer +{ + Q_OBJECT + +public: + GbmGraphicsBuffer(gbm_bo *handle, const QSize &size, uint32_t format); + ~GbmGraphicsBuffer() override; + + QSize size() const override; + bool hasAlphaChannel() const override; + Origin origin() const override; + + const DmaBufAttributes &dmabufAttributes() const; + +private: + gbm_bo *m_bo; + DmaBufAttributes m_dmabufAttributes; + QSize m_size; + bool m_hasAlphaChannel; +}; + +class KWIN_EXPORT GbmGraphicsBufferAllocator : public GraphicsBufferAllocator +{ +public: + explicit GbmGraphicsBufferAllocator(gbm_device *device); + ~GbmGraphicsBufferAllocator() override; + + GbmGraphicsBuffer *allocate(const QSize &size, uint32_t format, const QVector &modifiers = {}) override; + +private: + gbm_device *m_gbmDevice; +}; + +} // namespace KWin diff --git a/src/core/graphicsbufferallocator.cpp b/src/core/graphicsbufferallocator.cpp new file mode 100644 index 0000000000..b0e36f079a --- /dev/null +++ b/src/core/graphicsbufferallocator.cpp @@ -0,0 +1,20 @@ +/* + SPDX-FileCopyrightText: 2023 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "core/graphicsbufferallocator.h" + +namespace KWin +{ + +GraphicsBufferAllocator::GraphicsBufferAllocator() +{ +} + +GraphicsBufferAllocator::~GraphicsBufferAllocator() +{ +} + +} // namespace KWin diff --git a/src/core/graphicsbufferallocator.h b/src/core/graphicsbufferallocator.h new file mode 100644 index 0000000000..292e5e2b6d --- /dev/null +++ b/src/core/graphicsbufferallocator.h @@ -0,0 +1,28 @@ +/* + SPDX-FileCopyrightText: 2023 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include "kwin_export.h" + +#include +#include + +namespace KWin +{ + +class GraphicsBuffer; + +class KWIN_EXPORT GraphicsBufferAllocator +{ +public: + GraphicsBufferAllocator(); + virtual ~GraphicsBufferAllocator(); + + virtual GraphicsBuffer *allocate(const QSize &size, uint32_t format, const QVector &modifiers = {}) = 0; +}; + +} // namespace KWin