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"