File indexing completed on 2024-11-10 04:56:34

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com>
0006     SPDX-FileCopyrightText: 2013, 2015 Martin Gräßlin <mgraesslin@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "wayland_qpainter_backend.h"
0011 #include "core/graphicsbufferview.h"
0012 #include "core/shmgraphicsbufferallocator.h"
0013 #include "platformsupport/scenes/qpainter/qpainterswapchain.h"
0014 #include "wayland_backend.h"
0015 #include "wayland_output.h"
0016 
0017 #include <KWayland/Client/surface.h>
0018 
0019 #include <cmath>
0020 #include <drm_fourcc.h>
0021 #include <wayland-client-protocol.h>
0022 
0023 namespace KWin
0024 {
0025 namespace Wayland
0026 {
0027 
0028 WaylandQPainterPrimaryLayer::WaylandQPainterPrimaryLayer(WaylandOutput *output, WaylandQPainterBackend *backend)
0029     : m_waylandOutput(output)
0030     , m_backend(backend)
0031 {
0032 }
0033 
0034 WaylandQPainterPrimaryLayer::~WaylandQPainterPrimaryLayer()
0035 {
0036 }
0037 
0038 void WaylandQPainterPrimaryLayer::present()
0039 {
0040     wl_buffer *buffer = m_waylandOutput->backend()->importBuffer(m_back->buffer());
0041     Q_ASSERT(buffer);
0042 
0043     auto s = m_waylandOutput->surface();
0044     s->attachBuffer(buffer);
0045     s->damage(m_damageJournal.lastDamage());
0046     s->setScale(std::ceil(m_waylandOutput->scale()));
0047     s->commit();
0048 
0049     m_swapchain->release(m_back);
0050 }
0051 
0052 QRegion WaylandQPainterPrimaryLayer::accumulateDamage(int bufferAge) const
0053 {
0054     return m_damageJournal.accumulate(bufferAge, infiniteRegion());
0055 }
0056 
0057 std::optional<OutputLayerBeginFrameInfo> WaylandQPainterPrimaryLayer::beginFrame()
0058 {
0059     const QSize nativeSize(m_waylandOutput->modeSize());
0060     if (!m_swapchain || m_swapchain->size() != nativeSize) {
0061         m_swapchain = std::make_unique<QPainterSwapchain>(m_backend->graphicsBufferAllocator(), nativeSize, DRM_FORMAT_XRGB8888);
0062     }
0063 
0064     m_back = m_swapchain->acquire();
0065     if (!m_back) {
0066         return std::nullopt;
0067     }
0068 
0069     m_renderStart = std::chrono::steady_clock::now();
0070     return OutputLayerBeginFrameInfo{
0071         .renderTarget = RenderTarget(m_back->view()->image()),
0072         .repaint = accumulateDamage(m_back->age()),
0073     };
0074 }
0075 
0076 bool WaylandQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
0077 {
0078     m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
0079     m_damageJournal.add(damagedRegion);
0080     return true;
0081 }
0082 
0083 std::chrono::nanoseconds WaylandQPainterPrimaryLayer::queryRenderTime() const
0084 {
0085     return m_renderTime;
0086 }
0087 
0088 WaylandQPainterCursorLayer::WaylandQPainterCursorLayer(WaylandOutput *output, WaylandQPainterBackend *backend)
0089     : m_output(output)
0090     , m_backend(backend)
0091 {
0092 }
0093 
0094 WaylandQPainterCursorLayer::~WaylandQPainterCursorLayer()
0095 {
0096 }
0097 
0098 std::optional<OutputLayerBeginFrameInfo> WaylandQPainterCursorLayer::beginFrame()
0099 {
0100     const auto tmp = size().expandedTo(QSize(64, 64));
0101     const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
0102     if (!m_swapchain || m_swapchain->size() != bufferSize) {
0103         m_swapchain = std::make_unique<QPainterSwapchain>(m_backend->graphicsBufferAllocator(), bufferSize, DRM_FORMAT_ARGB8888);
0104     }
0105 
0106     m_back = m_swapchain->acquire();
0107     if (!m_back) {
0108         return std::nullopt;
0109     }
0110 
0111     m_renderStart = std::chrono::steady_clock::now();
0112     return OutputLayerBeginFrameInfo{
0113         .renderTarget = RenderTarget(m_back->view()->image()),
0114         .repaint = infiniteRegion(),
0115     };
0116 }
0117 
0118 bool WaylandQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
0119 {
0120     m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
0121     wl_buffer *buffer = m_output->backend()->importBuffer(m_back->buffer());
0122     Q_ASSERT(buffer);
0123 
0124     m_output->cursor()->update(buffer, scale(), hotspot().toPoint());
0125     m_swapchain->release(m_back);
0126     return true;
0127 }
0128 
0129 std::chrono::nanoseconds WaylandQPainterCursorLayer::queryRenderTime() const
0130 {
0131     return m_renderTime;
0132 }
0133 
0134 WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b)
0135     : QPainterBackend()
0136     , m_backend(b)
0137     , m_allocator(std::make_unique<ShmGraphicsBufferAllocator>())
0138 {
0139 
0140     const auto waylandOutputs = m_backend->waylandOutputs();
0141     for (auto *output : waylandOutputs) {
0142         createOutput(output);
0143     }
0144     connect(m_backend, &WaylandBackend::outputAdded, this, &WaylandQPainterBackend::createOutput);
0145     connect(m_backend, &WaylandBackend::outputRemoved, this, [this](Output *waylandOutput) {
0146         m_outputs.erase(waylandOutput);
0147     });
0148 }
0149 
0150 WaylandQPainterBackend::~WaylandQPainterBackend()
0151 {
0152 }
0153 
0154 void WaylandQPainterBackend::createOutput(Output *waylandOutput)
0155 {
0156     m_outputs[waylandOutput] = Layers{
0157         .primaryLayer = std::make_unique<WaylandQPainterPrimaryLayer>(static_cast<WaylandOutput *>(waylandOutput), this),
0158         .cursorLayer = std::make_unique<WaylandQPainterCursorLayer>(static_cast<WaylandOutput *>(waylandOutput), this),
0159     };
0160 }
0161 
0162 GraphicsBufferAllocator *WaylandQPainterBackend::graphicsBufferAllocator() const
0163 {
0164     return m_allocator.get();
0165 }
0166 
0167 void WaylandQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
0168 {
0169     m_outputs[output].primaryLayer->present();
0170     static_cast<WaylandOutput *>(output)->framePending(frame);
0171 }
0172 
0173 OutputLayer *WaylandQPainterBackend::primaryLayer(Output *output)
0174 {
0175     return m_outputs[output].primaryLayer.get();
0176 }
0177 
0178 OutputLayer *WaylandQPainterBackend::cursorLayer(Output *output)
0179 {
0180     return m_outputs[output].cursorLayer.get();
0181 }
0182 
0183 }
0184 }
0185 
0186 #include "moc_wayland_qpainter_backend.cpp"