File indexing completed on 2025-04-20 10:57:36

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "drm_qpainter_layer.h"
0010 #include "drm_abstract_output.h"
0011 #include "drm_backend.h"
0012 #include "drm_buffer.h"
0013 #include "drm_dumb_buffer.h"
0014 #include "drm_dumb_swapchain.h"
0015 #include "drm_gpu.h"
0016 #include "drm_logging.h"
0017 #include "drm_output.h"
0018 #include "drm_pipeline.h"
0019 #include "drm_qpainter_backend.h"
0020 #include "drm_virtual_output.h"
0021 
0022 #include <cerrno>
0023 #include <drm_fourcc.h>
0024 
0025 namespace KWin
0026 {
0027 
0028 DrmQPainterLayer::DrmQPainterLayer(DrmPipeline *pipeline)
0029     : DrmPipelineLayer(pipeline)
0030 {
0031 }
0032 
0033 std::optional<OutputLayerBeginFrameInfo> DrmQPainterLayer::beginFrame()
0034 {
0035     if (!doesSwapchainFit()) {
0036         m_swapchain = std::make_shared<DumbSwapchain>(m_pipeline->gpu(), m_pipeline->bufferSize(), DRM_FORMAT_XRGB8888);
0037     }
0038     QRegion needsRepaint;
0039     if (!m_swapchain->acquireBuffer(&needsRepaint)) {
0040         return std::nullopt;
0041     }
0042     return OutputLayerBeginFrameInfo{
0043         .renderTarget = RenderTarget(m_swapchain->currentBuffer()->image()),
0044         .repaint = needsRepaint,
0045     };
0046 }
0047 
0048 bool DrmQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
0049 {
0050     m_currentDamage = damagedRegion;
0051     m_swapchain->releaseBuffer(m_swapchain->currentBuffer(), damagedRegion);
0052     m_currentFramebuffer = DrmFramebuffer::createFramebuffer(m_swapchain->currentBuffer());
0053     if (!m_currentFramebuffer) {
0054         qCWarning(KWIN_DRM, "Failed to create dumb framebuffer: %s", strerror(errno));
0055     }
0056     return m_currentFramebuffer != nullptr;
0057 }
0058 
0059 bool DrmQPainterLayer::checkTestBuffer()
0060 {
0061     if (!doesSwapchainFit()) {
0062         m_swapchain = std::make_shared<DumbSwapchain>(m_pipeline->gpu(), m_pipeline->bufferSize(), DRM_FORMAT_XRGB8888);
0063         if (!m_swapchain->isEmpty()) {
0064             m_currentFramebuffer = DrmFramebuffer::createFramebuffer(m_swapchain->currentBuffer());
0065             if (!m_currentFramebuffer) {
0066                 qCWarning(KWIN_DRM, "Failed to create dumb framebuffer: %s", strerror(errno));
0067             }
0068         } else {
0069             m_currentFramebuffer.reset();
0070         }
0071     }
0072     return m_currentFramebuffer != nullptr;
0073 }
0074 
0075 bool DrmQPainterLayer::doesSwapchainFit() const
0076 {
0077     return m_swapchain && m_swapchain->size() == m_pipeline->bufferSize();
0078 }
0079 
0080 std::shared_ptr<DrmFramebuffer> DrmQPainterLayer::currentBuffer() const
0081 {
0082     return m_currentFramebuffer;
0083 }
0084 
0085 QRegion DrmQPainterLayer::currentDamage() const
0086 {
0087     return m_currentDamage;
0088 }
0089 
0090 void DrmQPainterLayer::releaseBuffers()
0091 {
0092     m_swapchain.reset();
0093 }
0094 
0095 DrmCursorQPainterLayer::DrmCursorQPainterLayer(DrmPipeline *pipeline)
0096     : DrmOverlayLayer(pipeline)
0097 {
0098 }
0099 
0100 std::optional<OutputLayerBeginFrameInfo> DrmCursorQPainterLayer::beginFrame()
0101 {
0102     if (!m_swapchain) {
0103         m_swapchain = std::make_shared<DumbSwapchain>(m_pipeline->gpu(), m_pipeline->gpu()->cursorSize(), DRM_FORMAT_ARGB8888);
0104     }
0105     QRegion needsRepaint;
0106     if (!m_swapchain->acquireBuffer(&needsRepaint)) {
0107         return std::nullopt;
0108     }
0109     return OutputLayerBeginFrameInfo{
0110         .renderTarget = RenderTarget(m_swapchain->currentBuffer()->image()),
0111         .repaint = needsRepaint,
0112     };
0113 }
0114 
0115 bool DrmCursorQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
0116 {
0117     m_swapchain->releaseBuffer(m_swapchain->currentBuffer(), damagedRegion);
0118     m_currentFramebuffer = DrmFramebuffer::createFramebuffer(m_swapchain->currentBuffer());
0119     if (!m_currentFramebuffer) {
0120         qCWarning(KWIN_DRM, "Failed to create dumb framebuffer for the cursor: %s", strerror(errno));
0121     }
0122     return m_currentFramebuffer != nullptr;
0123 }
0124 
0125 bool DrmCursorQPainterLayer::checkTestBuffer()
0126 {
0127     return false;
0128 }
0129 
0130 std::shared_ptr<DrmFramebuffer> DrmCursorQPainterLayer::currentBuffer() const
0131 {
0132     return m_currentFramebuffer;
0133 }
0134 
0135 QRegion DrmCursorQPainterLayer::currentDamage() const
0136 {
0137     return {};
0138 }
0139 
0140 void DrmCursorQPainterLayer::releaseBuffers()
0141 {
0142     m_swapchain.reset();
0143 }
0144 
0145 DrmVirtualQPainterLayer::DrmVirtualQPainterLayer(DrmVirtualOutput *output)
0146     : m_output(output)
0147 {
0148 }
0149 
0150 std::optional<OutputLayerBeginFrameInfo> DrmVirtualQPainterLayer::beginFrame()
0151 {
0152     if (m_image.isNull() || m_image.size() != m_output->pixelSize()) {
0153         m_image = QImage(m_output->pixelSize(), QImage::Format_RGB32);
0154     }
0155     return OutputLayerBeginFrameInfo{
0156         .renderTarget = RenderTarget(&m_image),
0157         .repaint = QRegion(),
0158     };
0159 }
0160 
0161 bool DrmVirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
0162 {
0163     m_currentDamage = damagedRegion;
0164     return true;
0165 }
0166 
0167 QRegion DrmVirtualQPainterLayer::currentDamage() const
0168 {
0169     return m_currentDamage;
0170 }
0171 
0172 void DrmVirtualQPainterLayer::releaseBuffers()
0173 {
0174 }
0175 }