File indexing completed on 2024-11-10 04:56:30
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 "core/graphicsbufferview.h" 0011 #include "drm_buffer.h" 0012 #include "drm_gpu.h" 0013 #include "drm_logging.h" 0014 #include "drm_pipeline.h" 0015 #include "drm_virtual_output.h" 0016 #include "platformsupport/scenes/qpainter/qpainterswapchain.h" 0017 0018 #include <cerrno> 0019 #include <drm_fourcc.h> 0020 0021 namespace KWin 0022 { 0023 0024 DrmQPainterLayer::DrmQPainterLayer(DrmPipeline *pipeline) 0025 : DrmPipelineLayer(pipeline) 0026 { 0027 } 0028 0029 std::optional<OutputLayerBeginFrameInfo> DrmQPainterLayer::beginFrame() 0030 { 0031 if (!doesSwapchainFit()) { 0032 m_swapchain = std::make_shared<QPainterSwapchain>(m_pipeline->gpu()->graphicsBufferAllocator(), m_pipeline->mode()->size(), DRM_FORMAT_XRGB8888); 0033 m_damageJournal = DamageJournal(); 0034 } 0035 0036 m_currentBuffer = m_swapchain->acquire(); 0037 if (!m_currentBuffer) { 0038 return std::nullopt; 0039 } 0040 0041 m_renderStart = std::chrono::steady_clock::now(); 0042 const QRegion repaint = m_damageJournal.accumulate(m_currentBuffer->age(), infiniteRegion()); 0043 return OutputLayerBeginFrameInfo{ 0044 .renderTarget = RenderTarget(m_currentBuffer->view()->image()), 0045 .repaint = repaint, 0046 }; 0047 } 0048 0049 bool DrmQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) 0050 { 0051 m_renderTime = std::chrono::steady_clock::now() - m_renderStart; 0052 m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{}); 0053 m_damageJournal.add(damagedRegion); 0054 m_swapchain->release(m_currentBuffer); 0055 if (!m_currentFramebuffer) { 0056 qCWarning(KWIN_DRM, "Failed to create dumb framebuffer: %s", strerror(errno)); 0057 } 0058 return m_currentFramebuffer != nullptr; 0059 } 0060 0061 bool DrmQPainterLayer::checkTestBuffer() 0062 { 0063 if (!doesSwapchainFit()) { 0064 m_swapchain = std::make_shared<QPainterSwapchain>(m_pipeline->gpu()->graphicsBufferAllocator(), m_pipeline->mode()->size(), DRM_FORMAT_XRGB8888); 0065 m_currentBuffer = m_swapchain->acquire(); 0066 if (m_currentBuffer) { 0067 m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{}); 0068 m_swapchain->release(m_currentBuffer); 0069 if (!m_currentFramebuffer) { 0070 qCWarning(KWIN_DRM, "Failed to create dumb framebuffer: %s", strerror(errno)); 0071 } 0072 } else { 0073 m_currentFramebuffer.reset(); 0074 } 0075 } 0076 return m_currentFramebuffer != nullptr; 0077 } 0078 0079 bool DrmQPainterLayer::doesSwapchainFit() const 0080 { 0081 return m_swapchain && m_swapchain->size() == m_pipeline->mode()->size(); 0082 } 0083 0084 std::shared_ptr<DrmFramebuffer> DrmQPainterLayer::currentBuffer() const 0085 { 0086 return m_currentFramebuffer; 0087 } 0088 0089 QRegion DrmQPainterLayer::currentDamage() const 0090 { 0091 return m_damageJournal.lastDamage(); 0092 } 0093 0094 void DrmQPainterLayer::releaseBuffers() 0095 { 0096 m_swapchain.reset(); 0097 } 0098 0099 std::chrono::nanoseconds DrmQPainterLayer::queryRenderTime() const 0100 { 0101 return m_renderTime; 0102 } 0103 0104 DrmCursorQPainterLayer::DrmCursorQPainterLayer(DrmPipeline *pipeline) 0105 : DrmPipelineLayer(pipeline) 0106 { 0107 } 0108 0109 std::optional<OutputLayerBeginFrameInfo> DrmCursorQPainterLayer::beginFrame() 0110 { 0111 if (!m_swapchain) { 0112 m_swapchain = std::make_shared<QPainterSwapchain>(m_pipeline->gpu()->graphicsBufferAllocator(), m_pipeline->gpu()->cursorSize(), DRM_FORMAT_ARGB8888); 0113 } 0114 m_currentBuffer = m_swapchain->acquire(); 0115 if (!m_currentBuffer) { 0116 return std::nullopt; 0117 } 0118 m_renderStart = std::chrono::steady_clock::now(); 0119 return OutputLayerBeginFrameInfo{ 0120 .renderTarget = RenderTarget(m_currentBuffer->view()->image()), 0121 .repaint = infiniteRegion(), 0122 }; 0123 } 0124 0125 bool DrmCursorQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) 0126 { 0127 m_renderTime = std::chrono::steady_clock::now() - m_renderStart; 0128 m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{}); 0129 m_swapchain->release(m_currentBuffer); 0130 if (!m_currentFramebuffer) { 0131 qCWarning(KWIN_DRM, "Failed to create dumb framebuffer for the cursor: %s", strerror(errno)); 0132 } 0133 return m_currentFramebuffer != nullptr; 0134 } 0135 0136 bool DrmCursorQPainterLayer::checkTestBuffer() 0137 { 0138 return false; 0139 } 0140 0141 std::shared_ptr<DrmFramebuffer> DrmCursorQPainterLayer::currentBuffer() const 0142 { 0143 return m_currentFramebuffer; 0144 } 0145 0146 QRegion DrmCursorQPainterLayer::currentDamage() const 0147 { 0148 return {}; 0149 } 0150 0151 void DrmCursorQPainterLayer::releaseBuffers() 0152 { 0153 m_swapchain.reset(); 0154 } 0155 0156 std::chrono::nanoseconds DrmCursorQPainterLayer::queryRenderTime() const 0157 { 0158 return m_renderTime; 0159 } 0160 0161 DrmVirtualQPainterLayer::DrmVirtualQPainterLayer(DrmVirtualOutput *output) 0162 : m_output(output) 0163 { 0164 } 0165 0166 std::optional<OutputLayerBeginFrameInfo> DrmVirtualQPainterLayer::beginFrame() 0167 { 0168 if (m_image.isNull() || m_image.size() != m_output->modeSize()) { 0169 m_image = QImage(m_output->modeSize(), QImage::Format_RGB32); 0170 } 0171 m_renderStart = std::chrono::steady_clock::now(); 0172 return OutputLayerBeginFrameInfo{ 0173 .renderTarget = RenderTarget(&m_image), 0174 .repaint = QRegion(), 0175 }; 0176 } 0177 0178 bool DrmVirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) 0179 { 0180 m_renderTime = std::chrono::steady_clock::now() - m_renderStart; 0181 m_currentDamage = damagedRegion; 0182 return true; 0183 } 0184 0185 QRegion DrmVirtualQPainterLayer::currentDamage() const 0186 { 0187 return m_currentDamage; 0188 } 0189 0190 void DrmVirtualQPainterLayer::releaseBuffers() 0191 { 0192 } 0193 0194 std::chrono::nanoseconds DrmVirtualQPainterLayer::queryRenderTime() const 0195 { 0196 return m_renderTime; 0197 } 0198 }