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;