File indexing completed on 2024-06-16 05:05:12

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 }