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 }