From 082301920e924e44d777adbd676118094f05dccb Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Sat, 3 Jun 2023 12:08:15 +0300 Subject: [PATCH] backends/drm: Port to GraphicsBuffer This change ports the drm backend to the GraphicsBuffer and GraphicsBufferAllocator. The main motivation is to unify graphics buffer abstractions across various backends and to prepare it for output layers, which could be nicer if we could have direct control over the buffers. --- autotests/drm/CMakeLists.txt | 2 - autotests/drm/drmTest.cpp | 1 - src/backends/drm/CMakeLists.txt | 2 - src/backends/drm/drm_buffer.cpp | 108 ++-------- src/backends/drm/drm_buffer.h | 47 +---- src/backends/drm/drm_buffer_gbm.cpp | 222 --------------------- src/backends/drm/drm_buffer_gbm.h | 57 ------ src/backends/drm/drm_crtc.h | 1 - src/backends/drm/drm_dumb_buffer.cpp | 84 -------- src/backends/drm/drm_dumb_buffer.h | 34 ---- src/backends/drm/drm_dumb_swapchain.cpp | 115 ++++++----- src/backends/drm/drm_dumb_swapchain.h | 48 +++-- src/backends/drm/drm_egl_backend.cpp | 1 - src/backends/drm/drm_egl_backend.h | 3 - src/backends/drm/drm_egl_cursor_layer.cpp | 2 +- src/backends/drm/drm_egl_cursor_layer.h | 1 - src/backends/drm/drm_egl_layer.cpp | 11 +- src/backends/drm/drm_egl_layer.h | 1 - src/backends/drm/drm_egl_layer_surface.cpp | 189 +++++++----------- src/backends/drm/drm_egl_layer_surface.h | 27 +-- src/backends/drm/drm_gbm_swapchain.cpp | 211 ++++++++++---------- src/backends/drm/drm_gbm_swapchain.h | 69 ++++--- src/backends/drm/drm_gpu.cpp | 79 ++++++++ src/backends/drm/drm_gpu.h | 2 + src/backends/drm/drm_output.cpp | 4 - src/backends/drm/drm_pipeline.cpp | 10 +- src/backends/drm/drm_pipeline_legacy.cpp | 17 +- src/backends/drm/drm_qpainter_layer.cpp | 44 ++-- src/backends/drm/drm_qpainter_layer.h | 7 +- src/backends/drm/drm_virtual_egl_layer.cpp | 69 ++++--- src/backends/drm/drm_virtual_egl_layer.h | 21 +- src/core/graphicsbufferview.cpp | 5 + src/core/graphicsbufferview.h | 1 + 33 files changed, 533 insertions(+), 962 deletions(-) delete mode 100644 src/backends/drm/drm_buffer_gbm.cpp delete mode 100644 src/backends/drm/drm_buffer_gbm.h delete mode 100644 src/backends/drm/drm_dumb_buffer.cpp delete mode 100644 src/backends/drm/drm_dumb_buffer.h diff --git a/autotests/drm/CMakeLists.txt b/autotests/drm/CMakeLists.txt index 88975adb12..c3597e7b33 100644 --- a/autotests/drm/CMakeLists.txt +++ b/autotests/drm/CMakeLists.txt @@ -5,11 +5,9 @@ set(mockDRM_SRCS ../../src/backends/drm/drm_backend.cpp ../../src/backends/drm/drm_blob.cpp ../../src/backends/drm/drm_buffer.cpp - ../../src/backends/drm/drm_buffer_gbm.cpp ../../src/backends/drm/drm_connector.cpp ../../src/backends/drm/drm_crtc.cpp ../../src/backends/drm/drm_dmabuf_feedback.cpp - ../../src/backends/drm/drm_dumb_buffer.cpp ../../src/backends/drm/drm_dumb_swapchain.cpp ../../src/backends/drm/drm_egl_backend.cpp ../../src/backends/drm/drm_egl_cursor_layer.cpp diff --git a/autotests/drm/drmTest.cpp b/autotests/drm/drmTest.cpp index 373e041b74..17d662a620 100644 --- a/autotests/drm/drmTest.cpp +++ b/autotests/drm/drmTest.cpp @@ -16,7 +16,6 @@ #include "drm_backend.h" #include "drm_connector.h" #include "drm_crtc.h" -#include "drm_dumb_buffer.h" #include "drm_egl_backend.h" #include "drm_gpu.h" #include "drm_output.h" diff --git a/src/backends/drm/CMakeLists.txt b/src/backends/drm/CMakeLists.txt index 0700c390bf..feaaacbb01 100644 --- a/src/backends/drm/CMakeLists.txt +++ b/src/backends/drm/CMakeLists.txt @@ -4,11 +4,9 @@ target_sources(kwin PRIVATE drm_backend.cpp drm_blob.cpp drm_buffer.cpp - drm_buffer_gbm.cpp drm_connector.cpp drm_crtc.cpp drm_dmabuf_feedback.cpp - drm_dumb_buffer.cpp drm_dumb_swapchain.cpp drm_egl_backend.cpp drm_egl_cursor_layer.cpp diff --git a/src/backends/drm/drm_buffer.cpp b/src/backends/drm/drm_buffer.cpp index e5e0141e50..5ce703801a 100644 --- a/src/backends/drm/drm_buffer.cpp +++ b/src/backends/drm/drm_buffer.cpp @@ -9,6 +9,7 @@ */ #include "drm_buffer.h" +#include "core/graphicsbuffer.h" #include "drm_gpu.h" #include "drm_logging.h" @@ -25,80 +26,20 @@ namespace KWin { -DrmGpuBuffer::DrmGpuBuffer(DrmGpu *gpu, QSize size, uint32_t format, uint64_t modifier, const std::array &handles, const std::array &strides, const std::array &offsets, uint32_t planeCount) - : m_gpu(gpu) - , m_size(size) - , m_format(format) - , m_modifier(modifier) - , m_handles(handles) - , m_strides(strides) - , m_offsets(offsets) - , m_planeCount(planeCount) -{ -} - -DrmGpu *DrmGpuBuffer::gpu() const -{ - return m_gpu; -} - -uint32_t DrmGpuBuffer::format() const -{ - return m_format; -} - -uint64_t DrmGpuBuffer::modifier() const -{ - return m_modifier; -} - -QSize DrmGpuBuffer::size() const -{ - return m_size; -} - -const std::array &DrmGpuBuffer::fds() -{ - if (!m_fds[0].isValid()) { - createFds(); - } - return m_fds; -} - -std::array DrmGpuBuffer::handles() const -{ - return m_handles; -} - -std::array DrmGpuBuffer::strides() const -{ - return m_strides; -} - -std::array DrmGpuBuffer::offsets() const -{ - return m_offsets; -} - -uint32_t DrmGpuBuffer::planeCount() const -{ - return m_planeCount; -} - -void DrmGpuBuffer::createFds() -{ -} - -DrmFramebuffer::DrmFramebuffer(const std::shared_ptr &buffer, uint32_t fbId) +DrmFramebuffer::DrmFramebuffer(DrmGpu *gpu, uint32_t fbId, GraphicsBuffer *buffer) : m_framebufferId(fbId) - , m_gpu(buffer->gpu()) + , m_gpu(gpu) , m_buffer(buffer) { + m_buffer->ref(); } DrmFramebuffer::~DrmFramebuffer() { drmModeRmFB(m_gpu->fd(), m_framebufferId); + if (m_buffer) { + m_buffer->unref(); + } } uint32_t DrmFramebuffer::framebufferId() const @@ -106,41 +47,16 @@ uint32_t DrmFramebuffer::framebufferId() const return m_framebufferId; } -DrmGpuBuffer *DrmFramebuffer::buffer() const +GraphicsBuffer *DrmFramebuffer::buffer() const { - return m_buffer.get(); + return m_buffer; } void DrmFramebuffer::releaseBuffer() { - m_buffer.reset(); -} - -std::shared_ptr DrmFramebuffer::createFramebuffer(const std::shared_ptr &buffer) -{ - const auto size = buffer->size(); - const auto handles = buffer->handles(); - const auto strides = buffer->strides(); - const auto offsets = buffer->offsets(); - - uint32_t framebufferId = 0; - int ret; - if (buffer->gpu()->addFB2ModifiersSupported() && buffer->modifier() != DRM_FORMAT_MOD_INVALID) { - uint64_t modifier[4]; - for (uint32_t i = 0; i < 4; i++) { - modifier[i] = i < buffer->planeCount() ? buffer->modifier() : 0; - } - ret = drmModeAddFB2WithModifiers(buffer->gpu()->fd(), size.width(), size.height(), buffer->format(), handles.data(), strides.data(), offsets.data(), modifier, &framebufferId, DRM_MODE_FB_MODIFIERS); - } else { - ret = drmModeAddFB2(buffer->gpu()->fd(), size.width(), size.height(), buffer->format(), handles.data(), strides.data(), offsets.data(), &framebufferId, 0); - if (ret == EOPNOTSUPP && handles.size() == 1) { - ret = drmModeAddFB(buffer->gpu()->fd(), size.width(), size.height(), 24, 32, strides[0], handles[0], &framebufferId); - } - } - if (ret == 0) { - return std::make_shared(buffer, framebufferId); - } else { - return nullptr; + if (m_buffer) { + m_buffer->unref(); + m_buffer = nullptr; } } } diff --git a/src/backends/drm/drm_buffer.h b/src/backends/drm/drm_buffer.h index 78c6b3a853..94ae0a0f14 100644 --- a/src/backends/drm/drm_buffer.h +++ b/src/backends/drm/drm_buffer.h @@ -9,70 +9,33 @@ */ #pragma once -#include "utils/filedescriptor.h" - -#include -#include -#include -#include -#include +#include namespace KWin { class DrmGpu; class DrmFramebuffer; - -class DrmGpuBuffer -{ -public: - DrmGpuBuffer(DrmGpu *gpu, QSize size, uint32_t format, uint64_t modifier, const std::array &handles, const std::array &strides, const std::array &offsets, uint32_t planeCount); - virtual ~DrmGpuBuffer() = default; - - DrmGpu *gpu() const; - uint32_t format() const; - uint64_t modifier() const; - QSize size() const; - const std::array &fds(); - std::array handles() const; - std::array strides() const; - std::array offsets() const; - uint32_t planeCount() const; - -protected: - virtual void createFds(); - - DrmGpu *const m_gpu; - const QSize m_size; - const uint32_t m_format; - const uint64_t m_modifier; - const std::array m_handles; - const std::array m_strides; - const std::array m_offsets; - const uint32_t m_planeCount; - std::array m_fds; -}; +class GraphicsBuffer; class DrmFramebuffer { public: - DrmFramebuffer(const std::shared_ptr &buffer, uint32_t fbId); + DrmFramebuffer(DrmGpu *gpu, uint32_t fbId, GraphicsBuffer *buffer); ~DrmFramebuffer(); uint32_t framebufferId() const; /** * may be nullptr */ - DrmGpuBuffer *buffer() const; + GraphicsBuffer *buffer() const; void releaseBuffer(); - static std::shared_ptr createFramebuffer(const std::shared_ptr &buffer); - protected: const uint32_t m_framebufferId; DrmGpu *const m_gpu; - std::shared_ptr m_buffer; + GraphicsBuffer *m_buffer = nullptr; }; } diff --git a/src/backends/drm/drm_buffer_gbm.cpp b/src/backends/drm/drm_buffer_gbm.cpp deleted file mode 100644 index df25ddcf68..0000000000 --- a/src/backends/drm/drm_buffer_gbm.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2017 Roman Gilg - SPDX-FileCopyrightText: 2015 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "drm_buffer_gbm.h" - -#include "config-kwin.h" - -#include "core/graphicsbuffer.h" -#include "drm_gbm_swapchain.h" -#include "drm_backend.h" -#include "drm_gpu.h" -#include "drm_logging.h" -#include "kwineglutils_p.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace KWin -{ - -static std::array getHandles(gbm_bo *bo) -{ - std::array ret; - int i = 0; - for (; i < gbm_bo_get_plane_count(bo); i++) { - ret[i] = gbm_bo_get_handle(bo).u32; - } - for (; i < 4; i++) { - ret[i] = 0; - } - return ret; -} - -static std::array getStrides(gbm_bo *bo) -{ - std::array ret; - int i = 0; - for (; i < gbm_bo_get_plane_count(bo); i++) { - ret[i] = gbm_bo_get_stride_for_plane(bo, i); - } - for (; i < 4; i++) { - ret[i] = 0; - } - return ret; -} - -static std::array getOffsets(gbm_bo *bo) -{ - std::array ret; - int i = 0; - for (; i < gbm_bo_get_plane_count(bo); i++) { - ret[i] = gbm_bo_get_offset(bo, i); - } - for (; i < 4; i++) { - ret[i] = 0; - } - return ret; -} - -GbmBuffer::GbmBuffer(gbm_bo *bo, const std::shared_ptr &swapchain) - : DrmGpuBuffer(swapchain->gpu(), swapchain->size(), swapchain->format(), swapchain->modifier(), getHandles(bo), getStrides(bo), getOffsets(bo), gbm_bo_get_plane_count(bo)) - , m_bo(bo) - , m_swapchain(swapchain) - , m_flags(swapchain->flags()) -{ -} - -GbmBuffer::GbmBuffer(DrmGpu *gpu, gbm_bo *bo, uint32_t flags) - : DrmGpuBuffer(gpu, QSize(gbm_bo_get_width(bo), gbm_bo_get_height(bo)), gbm_bo_get_format(bo), gbm_bo_get_modifier(bo), getHandles(bo), getStrides(bo), getOffsets(bo), gbm_bo_get_plane_count(bo)) - , m_bo(bo) - , m_flags(flags) -{ -} - -GbmBuffer::GbmBuffer(DrmGpu *gpu, gbm_bo *bo, GraphicsBuffer *clientBuffer, uint32_t flags) - : DrmGpuBuffer(gpu, QSize(gbm_bo_get_width(bo), gbm_bo_get_height(bo)), gbm_bo_get_format(bo), gbm_bo_get_modifier(bo), getHandles(bo), getStrides(bo), getOffsets(bo), gbm_bo_get_plane_count(bo)) - , m_bo(bo) - , m_clientBuffer(clientBuffer) - , m_flags(flags) -{ - m_clientBuffer->ref(); -} - -GbmBuffer::~GbmBuffer() -{ - if (m_clientBuffer) { - m_clientBuffer->unref(); - } - if (m_mapping) { - gbm_bo_unmap(m_bo, m_mapping); - } - if (const auto swapchain = m_swapchain.lock()) { - swapchain->releaseBuffer(this); - } else { - gbm_bo_destroy(m_bo); - } -} - -gbm_bo *GbmBuffer::bo() const -{ - return m_bo; -} - -void *GbmBuffer::mappedData() const -{ - return m_data; -} - -GraphicsBuffer *GbmBuffer::clientBuffer() const -{ - return m_clientBuffer; -} - -uint32_t GbmBuffer::flags() const -{ - return m_flags; -} - -bool GbmBuffer::map(uint32_t flags) -{ - if (m_data) { - return true; - } - uint32_t stride = m_strides[0]; - m_data = gbm_bo_map(m_bo, 0, 0, m_size.width(), m_size.height(), flags, &stride, &m_mapping); - return m_data; -} - -void GbmBuffer::createFds() -{ -#if HAVE_GBM_BO_GET_FD_FOR_PLANE - for (uint32_t i = 0; i < m_planeCount; i++) { - m_fds[i] = FileDescriptor(gbm_bo_get_fd_for_plane(m_bo, i)); - if (!m_fds[i].isValid()) { - m_fds = {}; - return; - } - } - return; -#else - if (m_planeCount > 1) { - return; - } - m_fds[0] = FileDescriptor(gbm_bo_get_fd(m_bo)); -#endif -} - -std::shared_ptr GbmBuffer::importBuffer(DrmGpu *gpu, GraphicsBuffer *clientBuffer) -{ - const auto *attrs = clientBuffer->dmabufAttributes(); - gbm_bo *bo; - if (attrs->modifier != DRM_FORMAT_MOD_INVALID || attrs->offset[0] > 0 || attrs->planeCount > 1) { - gbm_import_fd_modifier_data data = {}; - data.format = attrs->format; - data.width = static_cast(attrs->width); - data.height = static_cast(attrs->height); - data.num_fds = attrs->planeCount; - data.modifier = attrs->modifier; - for (int i = 0; i < attrs->planeCount; i++) { - data.fds[i] = attrs->fd[i].get(); - data.offsets[i] = attrs->offset[i]; - data.strides[i] = attrs->pitch[i]; - } - bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT); - } else { - gbm_import_fd_data data = {}; - data.fd = attrs->fd[0].get(); - data.width = static_cast(attrs->width); - data.height = static_cast(attrs->height); - data.stride = attrs->pitch[0]; - data.format = attrs->format; - bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT); - } - if (bo) { - return std::make_shared(gpu, bo, clientBuffer, GBM_BO_USE_SCANOUT); - } else { - return nullptr; - } -} - -std::shared_ptr GbmBuffer::importBuffer(DrmGpu *gpu, GbmBuffer *buffer, uint32_t flags) -{ - const auto &fds = buffer->fds(); - if (!fds[0].isValid()) { - return nullptr; - } - const auto strides = buffer->strides(); - const auto offsets = buffer->offsets(); - gbm_import_fd_modifier_data data = { - .width = (uint32_t)buffer->size().width(), - .height = (uint32_t)buffer->size().height(), - .format = buffer->format(), - .num_fds = (uint32_t)buffer->planeCount(), - .fds = {}, - .strides = {}, - .offsets = {}, - .modifier = buffer->modifier(), - }; - for (uint32_t i = 0; i < data.num_fds; i++) { - data.fds[i] = fds[i].get(); - data.strides[i] = strides[i]; - data.offsets[i] = offsets[i]; - } - gbm_bo *bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, flags); - if (bo) { - return std::make_shared(gpu, bo, flags); - } else { - return nullptr; - } -} -} diff --git a/src/backends/drm/drm_buffer_gbm.h b/src/backends/drm/drm_buffer_gbm.h deleted file mode 100644 index 40fcc8aa49..0000000000 --- a/src/backends/drm/drm_buffer_gbm.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2017 Roman Gilg - SPDX-FileCopyrightText: 2015 Martin Gräßlin - SPDX-FileCopyrightText: 2022 Xaver Hugl - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#pragma once - -#include "drm_buffer.h" - -#include -#include - -struct gbm_bo; - -namespace KWin -{ - -class GbmSurface; -class GraphicsBuffer; -class GLTexture; -class GbmSwapchain; - -class GbmBuffer : public DrmGpuBuffer -{ -public: - GbmBuffer(DrmGpu *gpu, gbm_bo *bo, uint32_t flags); - GbmBuffer(gbm_bo *bo, const std::shared_ptr &swapchain); - GbmBuffer(DrmGpu *gpu, gbm_bo *bo, GraphicsBuffer *clientBuffer, uint32_t flags); - ~GbmBuffer() override; - - gbm_bo *bo() const; - void *mappedData() const; - GraphicsBuffer *clientBuffer() const; - uint32_t flags() const; - - bool map(uint32_t flags); - - static std::shared_ptr importBuffer(DrmGpu *gpu, GraphicsBuffer *clientBuffer); - static std::shared_ptr importBuffer(DrmGpu *gpu, GbmBuffer *buffer, uint32_t flags = GBM_BO_USE_SCANOUT); - -private: - void createFds() override; - - gbm_bo *const m_bo; - const std::weak_ptr m_swapchain; - GraphicsBuffer *const m_clientBuffer = nullptr; - const uint32_t m_flags; - void *m_data = nullptr; - void *m_mapping = nullptr; -}; - -} diff --git a/src/backends/drm/drm_crtc.h b/src/backends/drm/drm_crtc.h index e72a80504b..073456098f 100644 --- a/src/backends/drm/drm_crtc.h +++ b/src/backends/drm/drm_crtc.h @@ -18,7 +18,6 @@ namespace KWin class DrmBackend; class DrmFramebuffer; -class DrmDumbBuffer; class GammaRamp; class DrmGpu; class DrmPlane; diff --git a/src/backends/drm/drm_dumb_buffer.cpp b/src/backends/drm/drm_dumb_buffer.cpp deleted file mode 100644 index b69184be53..0000000000 --- a/src/backends/drm/drm_dumb_buffer.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2022 Xaver Hugl - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "drm_dumb_buffer.h" - -#include "drm_gpu.h" -#include "drm_logging.h" - -#include -#include -#include -#include - -namespace KWin -{ - -DrmDumbBuffer::DrmDumbBuffer(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t handle, uint32_t stride, size_t bufferSize) - : DrmGpuBuffer(gpu, size, format, DRM_FORMAT_MOD_LINEAR, {handle, 0, 0, 0}, {stride, 0, 0, 0}, {0, 0, 0, 0}, 1) - , m_bufferSize(bufferSize) -{ -} - -DrmDumbBuffer::~DrmDumbBuffer() -{ - m_image.reset(); - if (m_memory) { - munmap(m_memory, m_bufferSize); - } - drm_mode_destroy_dumb destroyArgs; - destroyArgs.handle = m_handles[0]; - drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); -} - -bool DrmDumbBuffer::map(QImage::Format format) -{ - drm_mode_map_dumb mapArgs; - memset(&mapArgs, 0, sizeof mapArgs); - mapArgs.handle = m_handles[0]; - if (drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_MAP_DUMB, &mapArgs) != 0) { - return false; - } -#ifdef KWIN_UNIT_TEST - m_memory = reinterpret_cast(mapArgs.offset); -#else - void *address = mmap(nullptr, m_bufferSize, PROT_WRITE, MAP_SHARED, m_gpu->fd(), mapArgs.offset); - if (address == MAP_FAILED) { - return false; - } - m_memory = address; -#endif - m_image = std::make_unique((uchar *)m_memory, m_size.width(), m_size.height(), m_strides[0], format); - return !m_image->isNull(); -} - -QImage *DrmDumbBuffer::image() const -{ - return m_image.get(); -} - -void *DrmDumbBuffer::data() const -{ - return m_memory; -} - -std::shared_ptr DrmDumbBuffer::createDumbBuffer(DrmGpu *gpu, const QSize &size, uint32_t format) -{ - drm_mode_create_dumb createArgs; - memset(&createArgs, 0, sizeof createArgs); - createArgs.bpp = 32; - createArgs.width = size.width(); - createArgs.height = size.height(); - if (drmIoctl(gpu->fd(), DRM_IOCTL_MODE_CREATE_DUMB, &createArgs) != 0) { - qCWarning(KWIN_DRM) << "DRM_IOCTL_MODE_CREATE_DUMB failed" << strerror(errno); - return nullptr; - } - return std::make_shared(gpu, size, format, createArgs.handle, createArgs.pitch, createArgs.size); -} - -} diff --git a/src/backends/drm/drm_dumb_buffer.h b/src/backends/drm/drm_dumb_buffer.h deleted file mode 100644 index 1f8f38f1f7..0000000000 --- a/src/backends/drm/drm_dumb_buffer.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2022 Xaver Hugl - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#pragma once - -#include "drm_buffer.h" - -namespace KWin -{ - -class DrmDumbBuffer : public DrmGpuBuffer -{ -public: - DrmDumbBuffer(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t handle, uint32_t stride, size_t bufferSize); - ~DrmDumbBuffer() override; - - bool map(QImage::Format format = QImage::Format_RGB32); - QImage *image() const; - void *data() const; - - static std::shared_ptr createDumbBuffer(DrmGpu *gpu, const QSize &size, uint32_t format); - -private: - const size_t m_bufferSize; - void *m_memory = nullptr; - std::unique_ptr m_image; -}; - -} diff --git a/src/backends/drm/drm_dumb_swapchain.cpp b/src/backends/drm/drm_dumb_swapchain.cpp index 13ba2f777c..3605fd2556 100644 --- a/src/backends/drm/drm_dumb_swapchain.cpp +++ b/src/backends/drm/drm_dumb_swapchain.cpp @@ -7,76 +7,52 @@ SPDX-License-Identifier: GPL-2.0-or-later */ -#include "drm_dumb_swapchain.h" -#include "drm_buffer.h" -#include "drm_dumb_buffer.h" -#include "drm_gpu.h" -#include "drm_logging.h" +#include "backends/drm/drm_dumb_swapchain.h" +#include "core/gbmgraphicsbufferallocator.h" +#include "core/graphicsbufferview.h" +#include "backends/drm/drm_gpu.h" + +#include namespace KWin { -DumbSwapchain::DumbSwapchain(DrmGpu *gpu, const QSize &size, uint32_t drmFormat) - : m_size(size) - , m_format(drmFormat) +DumbSwapchainSlot::DumbSwapchainSlot(GraphicsBuffer *buffer) + : m_buffer(buffer) + , m_view(std::make_unique(buffer, GraphicsBuffer::Read | GraphicsBuffer::Write)) { - for (int i = 0; i < 2; i++) { - auto buffer = DrmDumbBuffer::createDumbBuffer(gpu, size, drmFormat); - if (!buffer->map(QImage::Format::Format_ARGB32)) { - break; - } - buffer->image()->fill(Qt::black); - m_slots.append(Slot{ - .buffer = buffer, - .age = 0, - }); - } - m_damageJournal.setCapacity(2); - if (m_slots.count() < 2) { - qCWarning(KWIN_DRM) << "Failed to create dumb buffers for swapchain!"; - m_slots.clear(); - } } -std::shared_ptr DumbSwapchain::acquireBuffer(QRegion *needsRepaint) +DumbSwapchainSlot::~DumbSwapchainSlot() { - if (m_slots.isEmpty()) { - return {}; - } - index = (index + 1) % m_slots.count(); - if (needsRepaint) { - *needsRepaint = m_damageJournal.accumulate(m_slots[index].age, infiniteRegion()); - } - return m_slots[index].buffer; + m_view.reset(); + m_buffer->drop(); } -std::shared_ptr DumbSwapchain::currentBuffer() const +GraphicsBuffer *DumbSwapchainSlot::buffer() const { - return m_slots[index].buffer; + return m_buffer; } -void DumbSwapchain::releaseBuffer(const std::shared_ptr &buffer, const QRegion &damage) +GraphicsBufferView *DumbSwapchainSlot::view() const { - Q_ASSERT(m_slots[index].buffer == buffer); - - for (qsizetype i = 0; i < m_slots.count(); ++i) { - if (m_slots[i].buffer == buffer) { - m_slots[i].age = 1; - } else if (m_slots[i].age > 0) { - m_slots[i].age++; - } - } - m_damageJournal.add(damage); + return m_view.get(); } -uint32_t DumbSwapchain::drmFormat() const +int DumbSwapchainSlot::age() const { - return m_format; + return m_age; } -qsizetype DumbSwapchain::slotCount() const +DumbSwapchain::DumbSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format) + : m_allocator(std::make_unique(gpu->gbmDevice())) + , m_size(size) + , m_format(format) +{ +} + +DumbSwapchain::~DumbSwapchain() { - return m_slots.count(); } QSize DumbSwapchain::size() const @@ -84,9 +60,44 @@ QSize DumbSwapchain::size() const return m_size; } -bool DumbSwapchain::isEmpty() const +uint32_t DumbSwapchain::format() const { - return m_slots.isEmpty(); + return m_format; +} + +std::shared_ptr DumbSwapchain::acquire() +{ + for (const auto &slot : std::as_const(m_slots)) { + if (!slot->buffer()->isReferenced()) { + return slot; + } + } + + GraphicsBuffer *buffer = m_allocator->allocate(GraphicsBufferOptions{ + .size = m_size, + .format = m_format, + .software = true, + }); + if (!buffer) { + qCWarning(KWIN_DRM) << "Failed to allocate a dumb buffer"; + return nullptr; + } + + auto slot = std::make_shared(buffer); + m_slots.append(slot); + + return slot; +} + +void DumbSwapchain::release(std::shared_ptr slot) +{ + for (qsizetype i = 0; i < m_slots.count(); ++i) { + if (m_slots[i] == slot) { + m_slots[i]->m_age = 1; + } else if (m_slots[i]->m_age > 0) { + m_slots[i]->m_age++; + } + } } } diff --git a/src/backends/drm/drm_dumb_swapchain.h b/src/backends/drm/drm_dumb_swapchain.h index 1fe73e06c3..a171f6c239 100644 --- a/src/backends/drm/drm_dumb_swapchain.h +++ b/src/backends/drm/drm_dumb_swapchain.h @@ -9,8 +9,6 @@ #pragma once -#include "utils/damagejournal.h" - #include #include #include @@ -19,35 +17,45 @@ namespace KWin { -class DrmDumbBuffer; class DrmGpu; +class GraphicsBuffer; +class GraphicsBufferAllocator; +class GraphicsBufferView; + +class DumbSwapchainSlot +{ +public: + DumbSwapchainSlot(GraphicsBuffer *buffer); + ~DumbSwapchainSlot(); + + GraphicsBuffer *buffer() const; + GraphicsBufferView *view() const; + int age() const; + +private: + GraphicsBuffer *m_buffer; + std::unique_ptr m_view; + int m_age = 0; + friend class DumbSwapchain; +}; class DumbSwapchain { public: - DumbSwapchain(DrmGpu *gpu, const QSize &size, uint32_t drmFormat); + DumbSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format); + ~DumbSwapchain(); - std::shared_ptr acquireBuffer(QRegion *needsRepaint = nullptr); - std::shared_ptr currentBuffer() const; - void releaseBuffer(const std::shared_ptr &buffer, const QRegion &damage = {}); - - qsizetype slotCount() const; QSize size() const; - bool isEmpty() const; - uint32_t drmFormat() const; + uint32_t format() const; + + std::shared_ptr acquire(); + void release(std::shared_ptr slot); private: - struct Slot - { - std::shared_ptr buffer; - int age = 0; - }; - + std::unique_ptr m_allocator; + QVector> m_slots; QSize m_size; - int index = 0; uint32_t m_format; - QVector m_slots; - DamageJournal m_damageJournal; }; } diff --git a/src/backends/drm/drm_egl_backend.cpp b/src/backends/drm/drm_egl_backend.cpp index f3d64e6f7a..6f3ab6ec65 100644 --- a/src/backends/drm/drm_egl_backend.cpp +++ b/src/backends/drm/drm_egl_backend.cpp @@ -13,7 +13,6 @@ #include "core/renderloop_p.h" #include "drm_abstract_output.h" #include "drm_backend.h" -#include "drm_buffer_gbm.h" #include "drm_dumb_swapchain.h" #include "drm_egl_cursor_layer.h" #include "drm_egl_layer.h" diff --git a/src/backends/drm/drm_egl_backend.h b/src/backends/drm/drm_egl_backend.h index aa491d7ff8..cdb4b1b508 100644 --- a/src/backends/drm/drm_egl_backend.h +++ b/src/backends/drm/drm_egl_backend.h @@ -29,10 +29,7 @@ namespace KWin struct DmaBufAttributes; class Output; class DrmAbstractOutput; -class DrmBuffer; -class DrmGbmBuffer; class DrmOutput; -class GbmBuffer; class DumbSwapchain; class DrmBackend; class DrmGpu; diff --git a/src/backends/drm/drm_egl_cursor_layer.cpp b/src/backends/drm/drm_egl_cursor_layer.cpp index 03085e955f..3071e00999 100644 --- a/src/backends/drm/drm_egl_cursor_layer.cpp +++ b/src/backends/drm/drm_egl_cursor_layer.cpp @@ -76,6 +76,6 @@ void EglGbmCursorLayer::releaseBuffers() quint32 EglGbmCursorLayer::format() const { - return m_surface.currentBuffer()->buffer()->format(); + return m_surface.currentBuffer()->buffer()->dmabufAttributes()->format; } } diff --git a/src/backends/drm/drm_egl_cursor_layer.h b/src/backends/drm/drm_egl_cursor_layer.h index d2e8f3b4b9..c970e7ce85 100644 --- a/src/backends/drm/drm_egl_cursor_layer.h +++ b/src/backends/drm/drm_egl_cursor_layer.h @@ -22,7 +22,6 @@ namespace KWin { class EglGbmBackend; -class DrmGbmBuffer; class EglGbmCursorLayer : public DrmOverlayLayer { diff --git a/src/backends/drm/drm_egl_layer.cpp b/src/backends/drm/drm_egl_layer.cpp index 0b8f9e862e..4275d789f2 100644 --- a/src/backends/drm/drm_egl_layer.cpp +++ b/src/backends/drm/drm_egl_layer.cpp @@ -9,7 +9,7 @@ #include "drm_egl_layer.h" #include "drm_abstract_output.h" #include "drm_backend.h" -#include "drm_buffer_gbm.h" +#include "drm_buffer.h" #include "drm_egl_backend.h" #include "drm_gpu.h" #include "drm_logging.h" @@ -84,7 +84,7 @@ bool EglGbmLayer::checkTestBuffer() std::shared_ptr EglGbmLayer::texture() const { if (m_scanoutBuffer) { - const auto ret = m_surface.eglBackend()->importBufferObjectAsTexture(static_cast(m_scanoutBuffer->buffer())->bo()); + const auto ret = m_surface.eglBackend()->importDmaBufAsTexture(*m_scanoutBuffer->buffer()->dmabufAttributes()); ret->setContentTransform(drmToTextureRotation(m_pipeline)); return ret; } else { @@ -139,12 +139,7 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem) if (!formats[dmabufAttributes->format].contains(dmabufAttributes->modifier)) { return false; } - const auto gbmBuffer = GbmBuffer::importBuffer(m_pipeline->gpu(), buffer); - if (!gbmBuffer) { - m_dmabufFeedback.scanoutFailed(surface, formats); - return false; - } - m_scanoutBuffer = DrmFramebuffer::createFramebuffer(gbmBuffer); + m_scanoutBuffer = m_pipeline->gpu()->importBuffer(buffer); if (m_scanoutBuffer && m_pipeline->testScanout()) { m_dmabufFeedback.scanoutSuccessful(surface); m_currentDamage = surfaceItem->damage(); diff --git a/src/backends/drm/drm_egl_layer.h b/src/backends/drm/drm_egl_layer.h index a8663ae389..c6ee6a9545 100644 --- a/src/backends/drm/drm_egl_layer.h +++ b/src/backends/drm/drm_egl_layer.h @@ -22,7 +22,6 @@ namespace KWin { class EglGbmBackend; -class GbmBuffer; class EglGbmLayer : public DrmPipelineLayer { diff --git a/src/backends/drm/drm_egl_layer_surface.cpp b/src/backends/drm/drm_egl_layer_surface.cpp index 4a9f09ba0b..6d9fde7e38 100644 --- a/src/backends/drm/drm_egl_layer_surface.cpp +++ b/src/backends/drm/drm_egl_layer_surface.cpp @@ -9,19 +9,13 @@ #include "drm_egl_layer_surface.h" #include "config-kwin.h" -#include "drm_buffer_gbm.h" -#include "drm_dumb_buffer.h" +#include "core/graphicsbufferview.h" #include "drm_dumb_swapchain.h" #include "drm_egl_backend.h" #include "drm_gbm_swapchain.h" #include "drm_gpu.h" #include "drm_logging.h" -#include "drm_output.h" #include "gbm_dmabuf.h" -#include "kwineglutils_p.h" -#include "libkwineffects/kwinglplatform.h" -#include "scene/surfaceitem_wayland.h" -#include "wayland/surface_interface.h" #include #include @@ -32,6 +26,7 @@ namespace KWin { static const QVector linearModifier = {DRM_FORMAT_MOD_LINEAR}; +static const QVector implicitModifier = {DRM_FORMAT_MOD_INVALID}; static gbm_format_name_desc formatName(uint32_t format) { @@ -64,34 +59,21 @@ std::optional EglGbmLayerSurface::startRendering(cons if (!checkSurface(bufferSize, formats)) { return std::nullopt; } + if (!m_eglBackend->contextObject()->makeCurrent()) { return std::nullopt; } - auto [buffer, repaint] = m_surface.gbmSwapchain->acquire(); - if (!buffer) { + auto slot = m_surface.gbmSwapchain->acquire(); + if (!slot) { return std::nullopt; } - auto &[texture, fbo] = m_surface.textureCache[buffer->bo()]; - if (!texture) { - texture = m_eglBackend->importBufferObjectAsTexture(buffer->bo()); - if (!texture) { - return std::nullopt; - } - } - texture->setContentTransform(transformation); - if (!fbo) { - fbo = std::make_shared(texture.get()); - if (!fbo->valid()) { - fbo.reset(); - return std::nullopt; - } - } - m_surface.currentBuffer = buffer; + + slot->framebuffer()->colorAttachment()->setContentTransform(transformation); + m_surface.currentSlot = slot; if (m_surface.targetColorDescription != colorDescription || m_surface.channelFactors != channelFactors || m_surface.colormanagementEnabled != enableColormanagement) { - m_surface.gbmSwapchain->resetDamage(); - repaint = infiniteRegion(); + m_surface.damageJournal.clear(); m_surface.colormanagementEnabled = enableColormanagement; m_surface.targetColorDescription = colorDescription; m_surface.channelFactors = channelFactors; @@ -103,6 +85,8 @@ std::optional EglGbmLayerSurface::startRendering(cons m_surface.intermediaryColorDescription = colorDescription; } } + + QRegion repaint = m_surface.damageJournal.accumulate(slot->age(), infiniteRegion()); if (enableColormanagement) { if (!m_surface.shadowBuffer) { m_surface.shadowTexture = GLTexture::allocate(GL_RGBA16F, m_surface.gbmSwapchain->size()); @@ -119,7 +103,7 @@ std::optional EglGbmLayerSurface::startRendering(cons m_surface.shadowTexture.reset(); m_surface.shadowBuffer.reset(); return OutputLayerBeginFrameInfo{ - .renderTarget = RenderTarget(fbo.get()), + .renderTarget = RenderTarget(m_surface.currentSlot->framebuffer()), .repaint = repaint, }; } @@ -128,8 +112,9 @@ std::optional EglGbmLayerSurface::startRendering(cons bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) { if (m_surface.colormanagementEnabled) { - const auto &[texture, fbo] = m_surface.textureCache[m_surface.currentBuffer->bo()]; - GLFramebuffer::pushFramebuffer(fbo.get()); + GLFramebuffer *fbo = m_surface.currentSlot->framebuffer(); + GLTexture *texture = fbo->colorAttachment(); + GLFramebuffer::pushFramebuffer(fbo); ShaderBinder binder(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace); QMatrix4x4 mat = texture->contentTransformMatrix(); mat.ortho(QRectF(QPointF(), fbo->size())); @@ -144,9 +129,10 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion) m_surface.shadowTexture->render(m_surface.gbmSwapchain->size(), 1); GLFramebuffer::popFramebuffer(); } - m_surface.gbmSwapchain->damage(damagedRegion); + m_surface.damageJournal.add(damagedRegion); + m_surface.gbmSwapchain->release(m_surface.currentSlot); glFlush(); - const auto buffer = importBuffer(m_surface, m_surface.currentBuffer); + const auto buffer = importBuffer(m_surface, m_surface.currentSlot->buffer()); if (buffer) { m_surface.currentFramebuffer = buffer; return true; @@ -177,7 +163,7 @@ bool EglGbmLayerSurface::doesSurfaceFit(const QSize &size, const QMap EglGbmLayerSurface::texture() const { - return m_surface.shadowTexture ? m_surface.shadowTexture : m_surface.textureCache[m_surface.currentBuffer->bo()].first; + return m_surface.shadowTexture ? m_surface.shadowTexture : m_surface.currentSlot->texture(); } std::shared_ptr EglGbmLayerSurface::renderTestBuffer(const QSize &bufferSize, const QMap> &formats) @@ -299,17 +285,14 @@ std::optional EglGbmLayerSurface::createSurface(con Surface ret; ret.importMode = importMode; ret.forceLinear = importMode == MultiGpuImportMode::DumbBuffer || importMode == MultiGpuImportMode::LinearDmabuf || m_bufferTarget != BufferTarget::Normal; - ret.gbmSwapchain = createGbmSwapchain(m_eglBackend->gpu(), size, format, renderModifiers, ret.forceLinear); + ret.gbmSwapchain = createGbmSwapchain(m_eglBackend->gpu(), m_eglBackend->contextObject(), size, format, renderModifiers, ret.forceLinear); if (!ret.gbmSwapchain) { return std::nullopt; } if (importMode == MultiGpuImportMode::DumbBuffer || m_bufferTarget == BufferTarget::Dumb) { ret.importDumbSwapchain = std::make_shared(m_gpu, size, format); - if (ret.importDumbSwapchain->isEmpty()) { - return std::nullopt; - } } else if (importMode == MultiGpuImportMode::Egl) { - ret.importGbmSwapchain = createGbmSwapchain(m_gpu, size, format, modifiers, false); + ret.importGbmSwapchain = createGbmSwapchain(m_gpu, m_eglBackend->contextForGpu(m_gpu), size, format, modifiers, false); if (!ret.importGbmSwapchain) { return std::nullopt; } @@ -320,43 +303,36 @@ std::optional EglGbmLayerSurface::createSurface(con return ret; } -std::shared_ptr EglGbmLayerSurface::createGbmSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format, const QVector &modifiers, bool forceLinear) const +std::shared_ptr EglGbmLayerSurface::createGbmSwapchain(DrmGpu *gpu, EglContext *context, const QSize &size, uint32_t format, const QVector &modifiers, bool forceLinear) const { static bool modifiersEnvSet = false; static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0; - bool allowModifiers = gpu->addFB2ModifiersSupported() && (!modifiersEnvSet || (modifiersEnvSet && modifiersEnv)) && !modifiers.isEmpty(); + bool allowModifiers = gpu->addFB2ModifiersSupported() && (!modifiersEnvSet || (modifiersEnvSet && modifiersEnv)) && modifiers != implicitModifier; #if !HAVE_GBM_BO_GET_FD_FOR_PLANE allowModifiers &= m_gpu == gpu; #endif + if (forceLinear || (m_gpu != gpu && !allowModifiers)) { + return DrmEglSwapchain::create(gpu, context, size, format, linearModifier); + } + if (allowModifiers) { - const auto ret = GbmSwapchain::createSwapchain(gpu, size, format, forceLinear ? linearModifier : modifiers); - if (const auto surface = std::get_if>(&ret)) { - return *surface; - } else if (std::get(ret) != GbmSwapchain::Error::ModifiersUnsupported) { - return nullptr; + if (auto swapchain = DrmEglSwapchain::create(gpu, context, size, format, modifiers)) { + return swapchain; } } - uint32_t gbmFlags = GBM_BO_USE_RENDERING; - if (m_gpu == gpu) { - gbmFlags |= GBM_BO_USE_SCANOUT; - } - if (forceLinear || m_gpu != gpu) { - gbmFlags |= GBM_BO_USE_LINEAR; - } - const auto ret = GbmSwapchain::createSwapchain(gpu, size, format, gbmFlags); - const auto swapchain = std::get_if>(&ret); - return swapchain ? *swapchain : nullptr; + + return DrmEglSwapchain::create(gpu, context, size, format, implicitModifier); } std::shared_ptr EglGbmLayerSurface::doRenderTestBuffer(Surface &surface) const { - const auto [buffer, repair] = surface.gbmSwapchain->acquire(); - if (!buffer) { + auto slot = surface.gbmSwapchain->acquire(); + if (!slot) { return nullptr; } - if (const auto ret = importBuffer(surface, buffer)) { - surface.currentBuffer = buffer; + if (const auto ret = importBuffer(surface, slot->buffer())) { + surface.currentSlot = slot; surface.currentFramebuffer = ret; return ret; } else { @@ -364,38 +340,22 @@ std::shared_ptr EglGbmLayerSurface::doRenderTestBuffer(Surface & } } -std::shared_ptr EglGbmLayerSurface::importBuffer(Surface &surface, const std::shared_ptr &sourceBuffer) const +std::shared_ptr EglGbmLayerSurface::importBuffer(Surface &surface, GraphicsBuffer *buffer) const { if (m_bufferTarget == BufferTarget::Dumb || surface.importMode == MultiGpuImportMode::DumbBuffer) { - return importWithCpu(surface, sourceBuffer.get()); + return importWithCpu(surface, buffer); } else if (surface.importMode == MultiGpuImportMode::Egl) { - return importWithEgl(surface, sourceBuffer.get()); - } else if (m_gpu != m_eglBackend->gpu()) { - return importDmabuf(sourceBuffer.get()); + return importWithEgl(surface, buffer); } else { - const auto ret = DrmFramebuffer::createFramebuffer(sourceBuffer); + const auto ret = m_gpu->importBuffer(buffer); if (!ret) { - qCWarning(KWIN_DRM, "Failed to create %s framebuffer: %s", formatName(sourceBuffer->format()).name, strerror(errno)); + qCWarning(KWIN_DRM, "Failed to create framebuffer: %s", strerror(errno)); } return ret; } } -std::shared_ptr EglGbmLayerSurface::importDmabuf(GbmBuffer *sourceBuffer) const -{ - const auto imported = GbmBuffer::importBuffer(m_gpu, sourceBuffer, sourceBuffer->flags() | GBM_BO_USE_SCANOUT); - if (!imported) { - qCWarning(KWIN_DRM, "failed to import %s gbm_bo for multi-gpu usage: %s", formatName(sourceBuffer->format()).name, strerror(errno)); - return nullptr; - } - const auto ret = DrmFramebuffer::createFramebuffer(imported); - if (!ret) { - qCWarning(KWIN_DRM, "Failed to create %s framebuffer for multi-gpu: %s", formatName(imported->format()).name, strerror(errno)); - } - return ret; -} - -std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface &surface, GbmBuffer *sourceBuffer) const +std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface &surface, GraphicsBuffer *sourceBuffer) const { Q_ASSERT(surface.importGbmSwapchain); @@ -404,35 +364,21 @@ std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface &surfa return nullptr; } context->makeCurrent(); - auto &sourceTexture = surface.importedTextureCache[sourceBuffer->bo()]; + auto &sourceTexture = surface.importedTextureCache[sourceBuffer]; if (!sourceTexture) { - if (std::optional attributes = dmaBufAttributesForBo(sourceBuffer->bo())) { - sourceTexture = context->importDmaBufAsTexture(attributes.value()); - } + sourceTexture = context->importDmaBufAsTexture(*sourceBuffer->dmabufAttributes()); } if (!sourceTexture) { qCWarning(KWIN_DRM, "failed to import the source texture!"); return nullptr; } - const auto [localBuffer, repaint] = surface.importGbmSwapchain->acquire(); - auto &[texture, fbo] = surface.importTextureCache[localBuffer->bo()]; - if (!texture) { - if (std::optional attributes = dmaBufAttributesForBo(localBuffer->bo())) { - texture = context->importDmaBufAsTexture(attributes.value()); - } - if (!texture) { - qCWarning(KWIN_DRM, "failed to import the local texture!"); - return nullptr; - } - } - if (!fbo) { - fbo = std::make_shared(texture.get()); - if (!fbo->valid()) { - qCWarning(KWIN_DRM, "failed to create the fbo!"); - fbo.reset(); - return nullptr; - } + auto slot = surface.importGbmSwapchain->acquire(); + if (!slot) { + qCWarning(KWIN_DRM, "failed to import the local texture!"); + return nullptr; } + + GLFramebuffer *fbo = slot->framebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle()); glViewport(0, 0, fbo->size().width(), fbo->size().height()); glClearColor(0, 1, 0, 0); @@ -452,32 +398,45 @@ std::shared_ptr EglGbmLayerSurface::importWithEgl(Surface &surfa context->shaderManager()->popShader(); glFlush(); + surface.importGbmSwapchain->release(slot); + // restore the old context context->doneCurrent(); m_eglBackend->makeCurrent(); - return DrmFramebuffer::createFramebuffer(localBuffer); + return m_gpu->importBuffer(slot->buffer()); } -std::shared_ptr EglGbmLayerSurface::importWithCpu(Surface &surface, GbmBuffer *sourceBuffer) const +std::shared_ptr EglGbmLayerSurface::importWithCpu(Surface &surface, GraphicsBuffer *sourceBuffer) const { - Q_ASSERT(surface.importDumbSwapchain && !surface.importDumbSwapchain->isEmpty()); - if (!sourceBuffer->map(GBM_BO_TRANSFER_READ)) { - qCWarning(KWIN_DRM, "mapping a %s gbm_bo failed: %s", formatName(sourceBuffer->format()).name, strerror(errno)); + Q_ASSERT(surface.importDumbSwapchain); + const GraphicsBufferView sourceView(sourceBuffer); + if (sourceView.isNull()) { + qCWarning(KWIN_DRM) << "EglGbmLayerSurface::importWithCpu: failed to map the source buffer"; return nullptr; } - const auto importBuffer = surface.importDumbSwapchain->acquireBuffer(); - if (sourceBuffer->planeCount() != 1 || sourceBuffer->strides()[0] != importBuffer->strides()[0]) { - qCCritical(KWIN_DRM, "stride of gbm_bo (%d) and dumb buffer (%d) with format %s don't match!", - sourceBuffer->strides()[0], importBuffer->strides()[0], formatName(sourceBuffer->format()).name); + const auto slot = surface.importDumbSwapchain->acquire(); + if (!slot) { + qCWarning(KWIN_DRM) << "EglGbmLayerSurface::importWithCpu: failed to get a target dumb buffer"; return nullptr; } - if (!memcpy(importBuffer->data(), sourceBuffer->mappedData(), importBuffer->size().height() * importBuffer->strides()[0])) { + auto releaseSlot = qScopeGuard([&surface, &slot]() { + surface.importDumbSwapchain->release(slot); + }); + + if (sourceView.image()->bytesPerLine() != slot->view()->image()->bytesPerLine()) { + qCCritical(KWIN_DRM, "EglGbmLayerSurface::importWithCpu: stride of source (%" PRIdQSIZETYPE ") and target buffer (%" PRIdQSIZETYPE ") don't match", + sourceView.image()->bytesPerLine(), + slot->view()->image()->bytesPerLine()); return nullptr; } - const auto ret = DrmFramebuffer::createFramebuffer(importBuffer); + + std::memcpy(slot->view()->image()->bits(), sourceView.image()->bits(), sourceView.image()->sizeInBytes()); + + const auto ret = m_gpu->importBuffer(slot->buffer()); if (!ret) { - qCWarning(KWIN_DRM, "Failed to create %s framebuffer for CPU import: %s", formatName(sourceBuffer->format()).name, strerror(errno)); + qCWarning(KWIN_DRM, "Failed to create a framebuffer: %s", strerror(errno)); } + return ret; } } diff --git a/src/backends/drm/drm_egl_layer_surface.h b/src/backends/drm/drm_egl_layer_surface.h index 97ddd267b8..2b46bff126 100644 --- a/src/backends/drm/drm_egl_layer_surface.h +++ b/src/backends/drm/drm_egl_layer_surface.h @@ -17,6 +17,7 @@ #include "core/outputlayer.h" #include "drm_plane.h" #include "libkwineffects/kwingltexture.h" +#include "utils/damagejournal.h" struct gbm_bo; @@ -24,13 +25,15 @@ namespace KWin { class DrmFramebuffer; -class GbmSwapchain; +class DrmEglSwapchain; +class DrmEglSwapchainSlot; class DumbSwapchain; class ShadowBuffer; +class EglContext; class EglGbmBackend; +class GraphicsBuffer; class SurfaceItem; class GLTexture; -class GbmBuffer; class EglGbmLayerSurface : public QObject { @@ -75,28 +78,26 @@ private: ColorDescription targetColorDescription = ColorDescription::sRGB; ColorDescription intermediaryColorDescription = ColorDescription::sRGB; QVector3D channelFactors = {1, 1, 1}; - std::shared_ptr gbmSwapchain; + std::shared_ptr gbmSwapchain; + std::shared_ptr currentSlot; + DamageJournal damageJournal; std::shared_ptr importDumbSwapchain; - std::shared_ptr importGbmSwapchain; - QHash> importedTextureCache; - QHash, std::shared_ptr>> importTextureCache; + std::shared_ptr importGbmSwapchain; + QHash> importedTextureCache; MultiGpuImportMode importMode; - std::shared_ptr currentBuffer; std::shared_ptr currentFramebuffer; - QHash, std::shared_ptr>> textureCache; bool forceLinear = false; }; bool checkSurface(const QSize &size, const QMap> &formats); bool doesSurfaceFit(const Surface &surface, const QSize &size, const QMap> &formats) const; std::optional createSurface(const QSize &size, const QMap> &formats) const; std::optional createSurface(const QSize &size, uint32_t format, const QVector &modifiers, MultiGpuImportMode importMode) const; - std::shared_ptr createGbmSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format, const QVector &modifiers, bool forceLinear) const; + std::shared_ptr createGbmSwapchain(DrmGpu *gpu, EglContext *context, const QSize &size, uint32_t format, const QVector &modifiers, bool forceLinear) const; std::shared_ptr doRenderTestBuffer(Surface &surface) const; - std::shared_ptr importBuffer(Surface &surface, const std::shared_ptr &sourceBuffer) const; - std::shared_ptr importDmabuf(GbmBuffer *sourceBuffer) const; - std::shared_ptr importWithEgl(Surface &surface, GbmBuffer *sourceBuffer) const; - std::shared_ptr importWithCpu(Surface &surface, GbmBuffer *sourceBuffer) const; + std::shared_ptr importBuffer(Surface &surface, GraphicsBuffer *sourceBuffer) const; + std::shared_ptr importWithEgl(Surface &surface, GraphicsBuffer *sourceBuffer) const; + std::shared_ptr importWithCpu(Surface &surface, GraphicsBuffer *sourceBuffer) const; Surface m_surface; Surface m_oldSurface; diff --git a/src/backends/drm/drm_gbm_swapchain.cpp b/src/backends/drm/drm_gbm_swapchain.cpp index 4f62e1a3b9..58f3baa280 100644 --- a/src/backends/drm/drm_gbm_swapchain.cpp +++ b/src/backends/drm/drm_gbm_swapchain.cpp @@ -7,134 +7,141 @@ SPDX-License-Identifier: GPL-2.0-or-later */ -#include "drm_gbm_swapchain.h" +#include "backends/drm/drm_gbm_swapchain.h" +#include "backends/drm/drm_gpu.h" +#include "core/gbmgraphicsbufferallocator.h" +#include "libkwineffects/kwinglutils.h" +#include "platformsupport/scenes/opengl/eglcontext.h" #include #include #include -#include "drm_backend.h" -#include "drm_egl_backend.h" -#include "drm_gpu.h" -#include "drm_logging.h" -#include "kwineglutils_p.h" -#include "libkwineffects/kwinglplatform.h" - namespace KWin { -GbmSwapchain::GbmSwapchain(DrmGpu *gpu, gbm_bo *initialBuffer, uint32_t flags) - : m_gpu(gpu) - , m_size(gbm_bo_get_width(initialBuffer), gbm_bo_get_height(initialBuffer)) - , m_format(gbm_bo_get_format(initialBuffer)) - , m_modifier(gbm_bo_get_modifier(initialBuffer)) - , m_flags(flags) - , m_buffers({std::make_pair(initialBuffer, 0)}) +DrmEglSwapchainSlot::DrmEglSwapchainSlot(EglContext *context, GraphicsBuffer *buffer) + : m_buffer(buffer) +{ + m_texture = context->importDmaBufAsTexture(*buffer->dmabufAttributes()); + m_framebuffer = std::make_unique(m_texture.get()); +} + +DrmEglSwapchainSlot::~DrmEglSwapchainSlot() +{ + m_framebuffer.reset(); + m_texture.reset(); + m_buffer->drop(); +} + +GraphicsBuffer *DrmEglSwapchainSlot::buffer() const +{ + return m_buffer; +} + +std::shared_ptr DrmEglSwapchainSlot::texture() const +{ + return m_texture; +} + +GLFramebuffer *DrmEglSwapchainSlot::framebuffer() const +{ + return m_framebuffer.get(); +} + +int DrmEglSwapchainSlot::age() const +{ + return m_age; +} + +DrmEglSwapchain::DrmEglSwapchain(std::unique_ptr allocator, EglContext *context, const QSize &size, uint32_t format, uint64_t modifier, const QVector> &slots) + : m_allocator(std::move(allocator)) + , m_context(context) + , m_size(size) + , m_format(format) + , m_modifier(modifier) + , m_slots(slots) { } -GbmSwapchain::~GbmSwapchain() +DrmEglSwapchain::~DrmEglSwapchain() { - while (!m_buffers.empty()) { - gbm_bo_destroy(m_buffers.back().first); - m_buffers.pop_back(); - } } -std::pair, QRegion> GbmSwapchain::acquire() -{ - for (auto &[bo, bufferAge] : m_buffers) { - bufferAge++; - } - if (m_buffers.empty()) { - gbm_bo *newBo; - if (m_modifier == DRM_FORMAT_MOD_INVALID) { - newBo = gbm_bo_create(m_gpu->gbmDevice(), m_size.width(), m_size.height(), m_format, m_flags); - } else { - newBo = gbm_bo_create_with_modifiers(m_gpu->gbmDevice(), m_size.width(), m_size.height(), m_format, &m_modifier, 1); - } - if (!newBo) { - qCWarning(KWIN_DRM) << "Creating gbm buffer failed!" << strerror(errno); - return std::make_pair(nullptr, infiniteRegion()); - } else { - return std::make_pair(std::make_shared(newBo, shared_from_this()), infiniteRegion()); - } - } else { - const auto [bo, bufferAge] = m_buffers.front(); - m_buffers.pop_front(); - return std::make_pair(std::make_shared(bo, shared_from_this()), - m_damageJournal.accumulate(bufferAge, infiniteRegion())); - } -} - -void GbmSwapchain::damage(const QRegion &damage) -{ - m_damageJournal.add(damage); -} - -void GbmSwapchain::resetDamage() -{ - m_damageJournal.clear(); -} - -void GbmSwapchain::releaseBuffer(GbmBuffer *buffer) -{ - if (m_buffers.size() < 3) { - m_buffers.push_back(std::make_pair(buffer->bo(), 1)); - } else { - gbm_bo_destroy(buffer->bo()); - } -} - -std::variant, GbmSwapchain::Error> GbmSwapchain::createSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags) -{ - gbm_bo *bo = gbm_bo_create(gpu->gbmDevice(), size.width(), size.height(), format, flags); - if (bo) { - return std::make_shared(gpu, bo, flags); - } else { - qCWarning(KWIN_DRM) << "Creating initial gbm buffer failed!" << strerror(errno); - return Error::Unknown; - } -} - -std::variant, GbmSwapchain::Error> GbmSwapchain::createSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers) -{ - gbm_bo *bo = gbm_bo_create_with_modifiers(gpu->gbmDevice(), size.width(), size.height(), format, modifiers.constData(), modifiers.size()); - if (bo) { - // scanout is implicitly assumed with gbm_bo_create_with_modifiers - return std::make_shared(gpu, bo, GBM_BO_USE_SCANOUT); - } else { - if (errno == ENOSYS) { - return Error::ModifiersUnsupported; - } else { - qCWarning(KWIN_DRM) << "Creating initial gbm buffer failed!" << strerror(errno); - return Error::Unknown; - } - } -} - -DrmGpu *GbmSwapchain::gpu() const -{ - return m_gpu; -} - -QSize GbmSwapchain::size() const +QSize DrmEglSwapchain::size() const { return m_size; } -uint32_t GbmSwapchain::format() const +uint32_t DrmEglSwapchain::format() const { return m_format; } -uint64_t GbmSwapchain::modifier() const +uint64_t DrmEglSwapchain::modifier() const { return m_modifier; } -uint32_t GbmSwapchain::flags() const +std::shared_ptr DrmEglSwapchain::acquire() { - return m_flags; + for (const auto &slot : std::as_const(m_slots)) { + if (!slot->buffer()->isReferenced()) { + return slot; + } + } + + GraphicsBuffer *buffer = m_allocator->allocate(GraphicsBufferOptions{ + .size = m_size, + .format = m_format, + .modifiers = {m_modifier}, + }); + if (!buffer) { + qCWarning(KWIN_DRM) << "Failed to allocate a gbm graphics buffer"; + return nullptr; + } + + auto slot = std::make_shared(m_context, buffer); + m_slots.append(slot); + return slot; } + +void DrmEglSwapchain::release(std::shared_ptr slot) +{ + for (qsizetype i = 0; i < m_slots.count(); ++i) { + if (m_slots[i] == slot) { + m_slots[i]->m_age = 1; + } else if (m_slots[i]->m_age > 0) { + m_slots[i]->m_age++; + } + } } + +std::shared_ptr DrmEglSwapchain::create(DrmGpu *gpu, EglContext *context, const QSize &size, uint32_t format, const QVector &modifiers) +{ + if (!context->makeCurrent()) { + return nullptr; + } + + auto allocator = std::make_unique(gpu->gbmDevice()); + + // The seed graphics buffer is used to fixate modifiers. + GraphicsBuffer *seed = allocator->allocate(GraphicsBufferOptions{ + .size = size, + .format = format, + .modifiers = modifiers, + }); + if (!seed) { + return nullptr; + } + + const QVector> slots{std::make_shared(context, seed)}; + return std::make_shared(std::move(allocator), + context, + size, + format, + seed->dmabufAttributes()->modifier, + slots); +} + +} // namespace KWin diff --git a/src/backends/drm/drm_gbm_swapchain.h b/src/backends/drm/drm_gbm_swapchain.h index 59ff8bf91a..8ac3f5eddd 100644 --- a/src/backends/drm/drm_gbm_swapchain.h +++ b/src/backends/drm/drm_gbm_swapchain.h @@ -8,54 +8,65 @@ */ #pragma once +#include #include + #include -#include #include #include -#include - -#include "drm_buffer_gbm.h" -#include "utils/damagejournal.h" namespace KWin { +class DrmGpu; +class GraphicsBufferAllocator; +class GraphicsBuffer; class GLFramebuffer; +class GLTexture; +class EglContext; class EglGbmBackend; -class GbmSwapchain : public std::enable_shared_from_this +class DrmEglSwapchainSlot { public: - explicit GbmSwapchain(DrmGpu *gpu, gbm_bo *initialBuffer, uint32_t flags); - ~GbmSwapchain(); + DrmEglSwapchainSlot(EglContext *context, GraphicsBuffer *buffer); + ~DrmEglSwapchainSlot(); - std::pair, QRegion> acquire(); - void damage(const QRegion &damage); - void resetDamage(); - void releaseBuffer(GbmBuffer *buffer); + GraphicsBuffer *buffer() const; + std::shared_ptr texture() const; + GLFramebuffer *framebuffer() const; + int age() const; + +private: + GraphicsBuffer *m_buffer; + std::unique_ptr m_framebuffer; + std::shared_ptr m_texture; + int m_age = 0; + friend class DrmEglSwapchain; +}; + +class DrmEglSwapchain +{ +public: + DrmEglSwapchain(std::unique_ptr allocator, EglContext *context, const QSize &size, uint32_t format, uint64_t modifier, const QVector> &slots); + ~DrmEglSwapchain(); - DrmGpu *gpu() const; QSize size() const; uint32_t format() const; uint64_t modifier() const; - uint32_t flags() const; - enum class Error { - ModifiersUnsupported, - Unknown - }; - static std::variant, Error> createSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags); - static std::variant, Error> createSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers); + std::shared_ptr acquire(); + void release(std::shared_ptr slot); + + static std::shared_ptr create(DrmGpu *gpu, EglContext *context, const QSize &size, uint32_t format, const QVector &modifiers); private: - DrmGpu *const m_gpu; - const QSize m_size; - const uint32_t m_format; - const uint64_t m_modifier; - const uint32_t m_flags; - - std::deque> m_buffers; - DamageJournal m_damageJournal; + std::unique_ptr m_allocator; + EglContext *m_context; + QSize m_size; + uint32_t m_format; + uint64_t m_modifier; + QVector> m_slots; }; -} + +} // namespace KWin diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index 8b4f013e9d..d362d1361c 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -14,6 +14,7 @@ #include "core/session.h" #include "drm_atomic_commit.h" #include "drm_backend.h" +#include "drm_buffer.h" #include "drm_connector.h" #include "drm_crtc.h" #include "drm_egl_backend.h" @@ -824,6 +825,84 @@ void DrmGpu::recreateSurfaces() } } +std::shared_ptr DrmGpu::importBuffer(GraphicsBuffer *buffer) +{ + const DmaBufAttributes *attributes = buffer->dmabufAttributes(); + if (Q_UNLIKELY(!attributes)) { + return nullptr; + } + + uint32_t handles[] = {0, 0, 0, 0}; + auto cleanup = qScopeGuard([this, &handles]() { + for (int i = 0; i < 4; ++i) { + if (handles[i] == 0) { + continue; + } + bool closed = false; + for (int j = 0; j < i; ++j) { + if (handles[i] == handles[j]) { + closed = true; + break; + } + } + if (closed) { + continue; + } + drmCloseBufferHandle(m_fd, handles[i]); + } + }); + for (int i = 0; i < attributes->planeCount; ++i) { + if (drmPrimeFDToHandle(m_fd, attributes->fd[i].get(), &handles[i]) != 0) { + qCWarning(KWIN_DRM) << "drmPrimeFDToHandle() failed"; + return nullptr; + } + } + + uint32_t framebufferId = 0; + int ret; + if (addFB2ModifiersSupported() && attributes->modifier != DRM_FORMAT_MOD_INVALID) { + uint64_t modifier[4] = {0, 0, 0, 0}; + for (int i = 0; i < attributes->planeCount; ++i) { + modifier[i] = attributes->modifier; + } + ret = drmModeAddFB2WithModifiers(m_fd, + attributes->width, + attributes->height, + attributes->format, + handles, + attributes->pitch, + attributes->offset, + modifier, + &framebufferId, + DRM_MODE_FB_MODIFIERS); + } else { + ret = drmModeAddFB2(m_fd, + attributes->width, + attributes->height, + attributes->format, + handles, + attributes->pitch, + attributes->offset, + &framebufferId, + 0); + if (ret == EOPNOTSUPP && attributes->planeCount == 1) { + ret = drmModeAddFB(m_fd, + attributes->width, + attributes->height, + 24, 32, + attributes->pitch[0], + handles[0], + &framebufferId); + } + } + + if (ret != 0) { + return nullptr; + } + + return std::make_shared(this, framebufferId, buffer); +} + DrmLease::DrmLease(DrmGpu *gpu, FileDescriptor &&fd, uint32_t lesseeId, const QVector &outputs) : m_gpu(gpu) , m_fd(std::move(fd)) diff --git a/src/backends/drm/drm_gpu.h b/src/backends/drm/drm_gpu.h index 574c4af5b3..009764e719 100644 --- a/src/backends/drm/drm_gpu.h +++ b/src/backends/drm/drm_gpu.h @@ -36,6 +36,7 @@ class DrmAbstractOutput; class DrmRenderBackend; class DrmVirtualOutput; class EglDisplay; +class GraphicsBuffer; class DrmLease : public QObject { @@ -103,6 +104,7 @@ public: bool needsModeset() const; bool maybeModeset(); + std::shared_ptr importBuffer(GraphicsBuffer *buffer); void releaseBuffers(); void recreateSurfaces(); diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 02f06eb6d8..33036edbb3 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -8,7 +8,6 @@ */ #include "drm_output.h" #include "drm_backend.h" -#include "drm_buffer.h" #include "drm_connector.h" #include "drm_crtc.h" #include "drm_gpu.h" @@ -17,9 +16,6 @@ #include "core/outputconfiguration.h" #include "core/renderloop.h" #include "core/renderloop_p.h" -#include "drm_dumb_buffer.h" -#include "drm_dumb_swapchain.h" -#include "drm_egl_backend.h" #include "drm_layer.h" #include "drm_logging.h" #include "libkwineffects/kwinglutils.h" diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index ec8d9fea05..17e85e3def 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -15,7 +15,6 @@ #include "drm_atomic_commit.h" #include "drm_backend.h" #include "drm_buffer.h" -#include "drm_buffer_gbm.h" #include "drm_connector.h" #include "drm_crtc.h" #include "drm_egl_backend.h" @@ -450,12 +449,13 @@ QMap> DrmPipeline::cursorFormats() const bool DrmPipeline::pruneModifier() { - if (!m_pending.layer->currentBuffer() - || m_pending.layer->currentBuffer()->buffer()->modifier() == DRM_FORMAT_MOD_NONE - || m_pending.layer->currentBuffer()->buffer()->modifier() == DRM_FORMAT_MOD_INVALID) { + const DmaBufAttributes *dmabufAttributes = m_pending.layer->currentBuffer() ? m_pending.layer->currentBuffer()->buffer()->dmabufAttributes() : nullptr; + if (!dmabufAttributes + || dmabufAttributes->modifier == DRM_FORMAT_MOD_NONE + || dmabufAttributes->modifier == DRM_FORMAT_MOD_INVALID) { return false; } - auto &modifiers = m_pending.formats[m_pending.layer->currentBuffer()->buffer()->format()]; + auto &modifiers = m_pending.formats[dmabufAttributes->format]; if (modifiers.empty()) { return false; } else { diff --git a/src/backends/drm/drm_pipeline_legacy.cpp b/src/backends/drm/drm_pipeline_legacy.cpp index 9925e63239..8ed66a87c2 100644 --- a/src/backends/drm/drm_pipeline_legacy.cpp +++ b/src/backends/drm/drm_pipeline_legacy.cpp @@ -8,6 +8,7 @@ */ #include "drm_buffer.h" +#include "core/graphicsbuffer.h" #include "drm_connector.h" #include "drm_crtc.h" #include "drm_gpu.h" @@ -146,7 +147,14 @@ DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy() bool DrmPipeline::setCursorLegacy() { const auto bo = cursorLayer()->currentBuffer(); - const uint32_t handle = bo && bo->buffer() && cursorLayer()->isVisible() ? bo->buffer()->handles()[0] : 0; + uint32_t handle = 0; + if (bo && bo->buffer() && cursorLayer()->isVisible()) { + const DmaBufAttributes *attributes = bo->buffer()->dmabufAttributes(); + if (drmPrimeFDToHandle(gpu()->fd(), attributes->fd[0].get(), &handle) != 0) { + qCWarning(KWIN_DRM) << "drmPrimeFDToHandle() failed"; + return false; + } + } struct drm_mode_cursor2 arg = { .flags = DRM_MODE_CURSOR_BO | DRM_MODE_CURSOR_MOVE, @@ -159,7 +167,12 @@ bool DrmPipeline::setCursorLegacy() .hot_x = m_pending.cursorHotspot.x(), .hot_y = m_pending.cursorHotspot.y(), }; - return drmIoctl(gpu()->fd(), DRM_IOCTL_MODE_CURSOR2, &arg) == 0; + const int ret = drmIoctl(gpu()->fd(), DRM_IOCTL_MODE_CURSOR2, &arg); + + if (handle != 0) { + drmCloseBufferHandle(gpu()->fd(), handle); + } + return ret == 0; } bool DrmPipeline::moveCursorLegacy() diff --git a/src/backends/drm/drm_qpainter_layer.cpp b/src/backends/drm/drm_qpainter_layer.cpp index 821a866912..804b3d8a83 100644 --- a/src/backends/drm/drm_qpainter_layer.cpp +++ b/src/backends/drm/drm_qpainter_layer.cpp @@ -7,16 +7,12 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #include "drm_qpainter_layer.h" -#include "drm_abstract_output.h" -#include "drm_backend.h" +#include "core/graphicsbufferview.h" #include "drm_buffer.h" -#include "drm_dumb_buffer.h" #include "drm_dumb_swapchain.h" #include "drm_gpu.h" #include "drm_logging.h" -#include "drm_output.h" #include "drm_pipeline.h" -#include "drm_qpainter_backend.h" #include "drm_virtual_output.h" #include @@ -34,22 +30,26 @@ std::optional DrmQPainterLayer::beginFrame() { if (!doesSwapchainFit()) { m_swapchain = std::make_shared(m_pipeline->gpu(), m_pipeline->mode()->size(), DRM_FORMAT_XRGB8888); + m_damageJournal = DamageJournal(); } - QRegion needsRepaint; - if (!m_swapchain->acquireBuffer(&needsRepaint)) { + + m_currentBuffer = m_swapchain->acquire(); + if (!m_currentBuffer) { return std::nullopt; } + + const QRegion repaint = m_damageJournal.accumulate(m_currentBuffer->age(), infiniteRegion()); return OutputLayerBeginFrameInfo{ - .renderTarget = RenderTarget(m_swapchain->currentBuffer()->image()), - .repaint = needsRepaint, + .renderTarget = RenderTarget(m_currentBuffer->view()->image()), + .repaint = repaint, }; } bool DrmQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { - m_currentDamage = damagedRegion; - m_swapchain->releaseBuffer(m_swapchain->currentBuffer(), damagedRegion); - m_currentFramebuffer = DrmFramebuffer::createFramebuffer(m_swapchain->currentBuffer()); + m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer()); + m_damageJournal.add(damagedRegion); + m_swapchain->release(m_currentBuffer); if (!m_currentFramebuffer) { qCWarning(KWIN_DRM, "Failed to create dumb framebuffer: %s", strerror(errno)); } @@ -60,8 +60,10 @@ bool DrmQPainterLayer::checkTestBuffer() { if (!doesSwapchainFit()) { m_swapchain = std::make_shared(m_pipeline->gpu(), m_pipeline->mode()->size(), DRM_FORMAT_XRGB8888); - if (!m_swapchain->isEmpty()) { - m_currentFramebuffer = DrmFramebuffer::createFramebuffer(m_swapchain->currentBuffer()); + m_currentBuffer = m_swapchain->acquire(); + if (m_currentBuffer) { + m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer()); + m_swapchain->release(m_currentBuffer); if (!m_currentFramebuffer) { qCWarning(KWIN_DRM, "Failed to create dumb framebuffer: %s", strerror(errno)); } @@ -84,7 +86,7 @@ std::shared_ptr DrmQPainterLayer::currentBuffer() const QRegion DrmQPainterLayer::currentDamage() const { - return m_currentDamage; + return m_damageJournal.lastDamage(); } void DrmQPainterLayer::releaseBuffers() @@ -107,20 +109,20 @@ std::optional DrmCursorQPainterLayer::beginFrame() if (!m_swapchain) { m_swapchain = std::make_shared(m_pipeline->gpu(), m_pipeline->gpu()->cursorSize(), DRM_FORMAT_ARGB8888); } - QRegion needsRepaint; - if (!m_swapchain->acquireBuffer(&needsRepaint)) { + m_currentBuffer = m_swapchain->acquire(); + if (!m_currentBuffer) { return std::nullopt; } return OutputLayerBeginFrameInfo{ - .renderTarget = RenderTarget(m_swapchain->currentBuffer()->image()), - .repaint = needsRepaint, + .renderTarget = RenderTarget(m_currentBuffer->view()->image()), + .repaint = infiniteRegion(), }; } bool DrmCursorQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) { - m_swapchain->releaseBuffer(m_swapchain->currentBuffer(), damagedRegion); - m_currentFramebuffer = DrmFramebuffer::createFramebuffer(m_swapchain->currentBuffer()); + m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer()); + m_swapchain->release(m_currentBuffer); if (!m_currentFramebuffer) { qCWarning(KWIN_DRM, "Failed to create dumb framebuffer for the cursor: %s", strerror(errno)); } diff --git a/src/backends/drm/drm_qpainter_layer.h b/src/backends/drm/drm_qpainter_layer.h index dd5cc30cf4..2643ea7d04 100644 --- a/src/backends/drm/drm_qpainter_layer.h +++ b/src/backends/drm/drm_qpainter_layer.h @@ -8,6 +8,7 @@ */ #pragma once #include "drm_layer.h" +#include "utils/damagejournal.h" #include @@ -15,10 +16,10 @@ namespace KWin { class DumbSwapchain; +class DumbSwapchainSlot; class DrmPipeline; class DrmVirtualOutput; class DrmQPainterBackend; -class DrmDumbBuffer; class DrmFramebuffer; class DrmQPainterLayer : public DrmPipelineLayer @@ -38,8 +39,9 @@ private: bool doesSwapchainFit() const; std::shared_ptr m_swapchain; + std::shared_ptr m_currentBuffer; std::shared_ptr m_currentFramebuffer; - QRegion m_currentDamage; + DamageJournal m_damageJournal; }; class DrmCursorQPainterLayer : public DrmOverlayLayer @@ -57,6 +59,7 @@ public: private: std::shared_ptr m_swapchain; + std::shared_ptr m_currentBuffer; std::shared_ptr m_currentFramebuffer; }; diff --git a/src/backends/drm/drm_virtual_egl_layer.cpp b/src/backends/drm/drm_virtual_egl_layer.cpp index abdedf61b3..8537faeccc 100644 --- a/src/backends/drm/drm_virtual_egl_layer.cpp +++ b/src/backends/drm/drm_virtual_egl_layer.cpp @@ -42,13 +42,17 @@ std::optional VirtualEglGbmLayer::beginFrame() // gbm surface if (doesGbmSwapchainFit(m_gbmSwapchain.get())) { m_oldGbmSwapchain.reset(); + m_oldDamageJournal.clear(); } else { if (doesGbmSwapchainFit(m_oldGbmSwapchain.get())) { m_gbmSwapchain = m_oldGbmSwapchain; + m_damageJournal = m_oldDamageJournal; } else { if (const auto swapchain = createGbmSwapchain()) { m_oldGbmSwapchain = m_gbmSwapchain; + m_oldDamageJournal = m_damageJournal; m_gbmSwapchain = swapchain; + m_damageJournal = DamageJournal(); } else { return std::nullopt; } @@ -58,22 +62,22 @@ std::optional VirtualEglGbmLayer::beginFrame() if (eglMakeCurrent(m_eglBackend->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, m_eglBackend->context()) != EGL_TRUE) { return std::nullopt; } - const auto [buffer, repair] = m_gbmSwapchain->acquire(); - auto texture = m_eglBackend->importBufferObjectAsTexture(buffer->bo()); - if (!texture) { + + auto slot = m_gbmSwapchain->acquire(); + if (!slot) { return std::nullopt; } - texture->setContentTransform(TextureTransform::MirrorY); - auto fbo = std::make_shared(texture.get()); - if (!fbo) { - return std::nullopt; - } - m_currentBuffer = buffer; - m_texture = texture; - m_fbo = fbo; + + m_currentSlot = slot; m_scanoutSurface.clear(); + if (m_scanoutBuffer) { + m_scanoutBuffer->unref(); + m_scanoutBuffer = nullptr; + } + + const QRegion repair = m_damageJournal.accumulate(slot->age(), infiniteRegion()); return OutputLayerBeginFrameInfo{ - .renderTarget = RenderTarget(fbo.get()), + .renderTarget = RenderTarget(slot->framebuffer()), .repaint = repair, }; } @@ -82,7 +86,8 @@ bool VirtualEglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion & { glFlush(); m_currentDamage = damagedRegion; - m_gbmSwapchain->damage(damagedRegion); + m_damageJournal.add(damagedRegion); + m_gbmSwapchain->release(m_currentSlot); return true; } @@ -91,7 +96,7 @@ QRegion VirtualEglGbmLayer::currentDamage() const return m_currentDamage; } -std::shared_ptr VirtualEglGbmLayer::createGbmSwapchain() const +std::shared_ptr VirtualEglGbmLayer::createGbmSwapchain() const { static bool modifiersEnvSet = false; static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0; @@ -105,16 +110,14 @@ std::shared_ptr VirtualEglGbmLayer::createGbmSwapchain() const const auto modifiers = it.value(); if (allowModifiers && !modifiers.isEmpty()) { - const auto ret = GbmSwapchain::createSwapchain(m_eglBackend->gpu(), size, format, modifiers); - if (const auto surface = std::get_if>(&ret)) { - return *surface; - } else if (std::get(ret) != GbmSwapchain::Error::ModifiersUnsupported) { - continue; + if (auto swapchain = DrmEglSwapchain::create(m_eglBackend->gpu(), m_eglBackend->contextObject(), size, format, modifiers)) { + return swapchain; } } - const auto ret = GbmSwapchain::createSwapchain(m_eglBackend->gpu(), size, format, GBM_BO_USE_RENDERING); - if (const auto surface = std::get_if>(&ret)) { - return *surface; + + static const QVector implicitModifier{DRM_FORMAT_MOD_INVALID}; + if (auto swapchain = DrmEglSwapchain::create(m_eglBackend->gpu(), m_eglBackend->contextObject(), size, format, implicitModifier)) { + return swapchain; } } } @@ -122,7 +125,7 @@ std::shared_ptr VirtualEglGbmLayer::createGbmSwapchain() const return nullptr; } -bool VirtualEglGbmLayer::doesGbmSwapchainFit(GbmSwapchain *swapchain) const +bool VirtualEglGbmLayer::doesGbmSwapchainFit(DrmEglSwapchain *swapchain) const { return swapchain && swapchain->size() == m_output->modeSize(); } @@ -130,9 +133,9 @@ bool VirtualEglGbmLayer::doesGbmSwapchainFit(GbmSwapchain *swapchain) const std::shared_ptr VirtualEglGbmLayer::texture() const { if (m_scanoutSurface) { - return m_eglBackend->importBufferObjectAsTexture(m_currentBuffer->bo()); + return m_eglBackend->importDmaBufAsTexture(*m_scanoutBuffer->dmabufAttributes()); } else { - return m_texture; + return m_currentSlot->texture(); } } @@ -152,28 +155,30 @@ bool VirtualEglGbmLayer::scanout(SurfaceItem *surfaceItem) if (!buffer || !buffer->dmabufAttributes() || buffer->size() != m_output->modeSize()) { return false; } - const auto scanoutBuffer = GbmBuffer::importBuffer(m_output->gpu(), buffer); - if (!scanoutBuffer) { - return false; + buffer->ref(); + if (m_scanoutBuffer) { + m_scanoutBuffer->unref(); } + m_scanoutBuffer = buffer; // damage tracking for screen casting m_currentDamage = m_scanoutSurface == item->surface() ? surfaceItem->damage() : infiniteRegion(); surfaceItem->resetDamage(); // ensure the pixmap is updated when direct scanout ends surfaceItem->destroyPixmap(); m_scanoutSurface = item->surface(); - m_currentBuffer = scanoutBuffer; return true; } void VirtualEglGbmLayer::releaseBuffers() { eglMakeCurrent(m_eglBackend->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, m_eglBackend->context()); - m_fbo.reset(); - m_texture.reset(); m_gbmSwapchain.reset(); m_oldGbmSwapchain.reset(); - m_currentBuffer.reset(); + m_currentSlot.reset(); + if (m_scanoutBuffer) { + m_scanoutBuffer->unref(); + m_scanoutBuffer = nullptr; + } } quint32 VirtualEglGbmLayer::format() const diff --git a/src/backends/drm/drm_virtual_egl_layer.h b/src/backends/drm/drm_virtual_egl_layer.h index 42a80e897d..bf8e676230 100644 --- a/src/backends/drm/drm_virtual_egl_layer.h +++ b/src/backends/drm/drm_virtual_egl_layer.h @@ -8,6 +8,7 @@ */ #pragma once #include "drm_layer.h" +#include "utils/damagejournal.h" #include #include @@ -23,10 +24,11 @@ class SurfaceInterface; namespace KWin { -class GbmSwapchain; +class DrmEglSwapchain; +class DrmEglSwapchainSlot; +class GraphicsBuffer; class GLTexture; class EglGbmBackend; -class GbmBuffer; class DrmVirtualOutput; class VirtualEglGbmLayer : public DrmOutputLayer @@ -44,16 +46,17 @@ public: quint32 format() const override; private: - std::shared_ptr createGbmSwapchain() const; - bool doesGbmSwapchainFit(GbmSwapchain *swapchain) const; + std::shared_ptr createGbmSwapchain() const; + bool doesGbmSwapchainFit(DrmEglSwapchain *swapchain) const; QPointer m_scanoutSurface; - std::shared_ptr m_currentBuffer; - std::shared_ptr m_fbo; - std::shared_ptr m_texture; + QPointer m_scanoutBuffer; + DamageJournal m_damageJournal; + DamageJournal m_oldDamageJournal; QRegion m_currentDamage; - std::shared_ptr m_gbmSwapchain; - std::shared_ptr m_oldGbmSwapchain; + std::shared_ptr m_gbmSwapchain; + std::shared_ptr m_oldGbmSwapchain; + std::shared_ptr m_currentSlot; DrmVirtualOutput *const m_output; EglGbmBackend *const m_eglBackend; diff --git a/src/core/graphicsbufferview.cpp b/src/core/graphicsbufferview.cpp index 55c8d51019..f3df27427b 100644 --- a/src/core/graphicsbufferview.cpp +++ b/src/core/graphicsbufferview.cpp @@ -78,6 +78,11 @@ GraphicsBufferView::~GraphicsBufferView() } } +bool GraphicsBufferView::isNull() const +{ + return m_image.isNull(); +} + QImage *GraphicsBufferView::image() { return &m_image; diff --git a/src/core/graphicsbufferview.h b/src/core/graphicsbufferview.h index 49afa8a191..c47bdebdd0 100644 --- a/src/core/graphicsbufferview.h +++ b/src/core/graphicsbufferview.h @@ -19,6 +19,7 @@ public: explicit GraphicsBufferView(GraphicsBuffer *buffer, GraphicsBuffer::MapFlags accessFlags = GraphicsBuffer::Read); ~GraphicsBufferView(); + bool isNull() const; QImage *image(); const QImage *image() const;