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

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "x11_windowed_qpainter_backend.h"
0010 #include "core/graphicsbufferview.h"
0011 #include "core/shmgraphicsbufferallocator.h"
0012 #include "platformsupport/scenes/qpainter/qpainterswapchain.h"
0013 #include "x11_windowed_backend.h"
0014 #include "x11_windowed_output.h"
0015 
0016 #include <cerrno>
0017 #include <cmath>
0018 #include <drm_fourcc.h>
0019 #include <string.h>
0020 #include <xcb/present.h>
0021 
0022 namespace KWin
0023 {
0024 
0025 X11WindowedQPainterPrimaryLayer::X11WindowedQPainterPrimaryLayer(X11WindowedOutput *output, X11WindowedQPainterBackend *backend)
0026     : m_output(output)
0027     , m_backend(backend)
0028 {
0029 }
0030 
0031 X11WindowedQPainterPrimaryLayer::~X11WindowedQPainterPrimaryLayer()
0032 {
0033 }
0034 
0035 std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterPrimaryLayer::beginFrame()
0036 {
0037     const QSize bufferSize = m_output->modeSize();
0038     if (!m_swapchain || m_swapchain->size() != bufferSize) {
0039         m_swapchain = std::make_unique<QPainterSwapchain>(m_backend->graphicsBufferAllocator(), bufferSize, m_output->backend()->driFormatForDepth(m_output->depth()));
0040     }
0041 
0042     m_current = m_swapchain->acquire();
0043     if (!m_current) {
0044         return std::nullopt;
0045     }
0046 
0047     QRegion repaint = m_output->exposedArea() + m_output->rect();
0048     m_output->clearExposedArea();
0049 
0050     m_renderStart = std::chrono::steady_clock::now();
0051     return OutputLayerBeginFrameInfo{
0052         .renderTarget = RenderTarget(m_current->view()->image()),
0053         .repaint = repaint,
0054     };
0055 }
0056 
0057 bool X11WindowedQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
0058 {
0059     m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
0060     return true;
0061 }
0062 
0063 void X11WindowedQPainterPrimaryLayer::present()
0064 {
0065     xcb_pixmap_t pixmap = m_output->importBuffer(m_current->buffer());
0066     Q_ASSERT(pixmap != XCB_PIXMAP_NONE);
0067 
0068     xcb_xfixes_region_t valid = 0;
0069     xcb_xfixes_region_t update = 0;
0070     uint32_t serial = 0;
0071     uint32_t options = 0;
0072     uint64_t targetMsc = 0;
0073 
0074     xcb_present_pixmap(m_output->backend()->connection(),
0075                        m_output->window(),
0076                        pixmap,
0077                        serial,
0078                        valid,
0079                        update,
0080                        0,
0081                        0,
0082                        XCB_NONE,
0083                        XCB_NONE,
0084                        XCB_NONE,
0085                        options,
0086                        targetMsc,
0087                        0,
0088                        0,
0089                        0,
0090                        nullptr);
0091 }
0092 
0093 std::chrono::nanoseconds X11WindowedQPainterPrimaryLayer::queryRenderTime() const
0094 {
0095     return m_renderTime;
0096 }
0097 
0098 X11WindowedQPainterCursorLayer::X11WindowedQPainterCursorLayer(X11WindowedOutput *output)
0099     : m_output(output)
0100 {
0101 }
0102 
0103 std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterCursorLayer::beginFrame()
0104 {
0105     const auto tmp = size().expandedTo(QSize(64, 64));
0106     const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
0107     if (m_buffer.size() != bufferSize) {
0108         m_buffer = QImage(bufferSize, QImage::Format_ARGB32_Premultiplied);
0109     }
0110 
0111     m_renderStart = std::chrono::steady_clock::now();
0112     return OutputLayerBeginFrameInfo{
0113         .renderTarget = RenderTarget(&m_buffer),
0114         .repaint = infiniteRegion(),
0115     };
0116 }
0117 
0118 std::chrono::nanoseconds X11WindowedQPainterCursorLayer::queryRenderTime() const
0119 {
0120     return m_renderTime;
0121 }
0122 
0123 bool X11WindowedQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
0124 {
0125     m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
0126     m_output->cursor()->update(m_buffer, hotspot());
0127     return true;
0128 }
0129 
0130 X11WindowedQPainterBackend::X11WindowedQPainterBackend(X11WindowedBackend *backend)
0131     : QPainterBackend()
0132     , m_backend(backend)
0133     , m_allocator(std::make_unique<ShmGraphicsBufferAllocator>())
0134 {
0135     const auto outputs = m_backend->outputs();
0136     for (Output *output : outputs) {
0137         addOutput(output);
0138     }
0139 
0140     connect(backend, &X11WindowedBackend::outputAdded, this, &X11WindowedQPainterBackend::addOutput);
0141     connect(backend, &X11WindowedBackend::outputRemoved, this, &X11WindowedQPainterBackend::removeOutput);
0142 }
0143 
0144 X11WindowedQPainterBackend::~X11WindowedQPainterBackend()
0145 {
0146     m_outputs.clear();
0147 }
0148 
0149 void X11WindowedQPainterBackend::addOutput(Output *output)
0150 {
0151     X11WindowedOutput *x11Output = static_cast<X11WindowedOutput *>(output);
0152     m_outputs[output] = Layers{
0153         .primaryLayer = std::make_unique<X11WindowedQPainterPrimaryLayer>(x11Output, this),
0154         .cursorLayer = std::make_unique<X11WindowedQPainterCursorLayer>(x11Output),
0155     };
0156 }
0157 
0158 void X11WindowedQPainterBackend::removeOutput(Output *output)
0159 {
0160     m_outputs.erase(output);
0161 }
0162 
0163 GraphicsBufferAllocator *X11WindowedQPainterBackend::graphicsBufferAllocator() const
0164 {
0165     return m_allocator.get();
0166 }
0167 
0168 void X11WindowedQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
0169 {
0170     m_outputs[output].primaryLayer->present();
0171     static_cast<X11WindowedOutput *>(output)->framePending(frame);
0172 }
0173 
0174 OutputLayer *X11WindowedQPainterBackend::primaryLayer(Output *output)
0175 {
0176     return m_outputs[output].primaryLayer.get();
0177 }
0178 
0179 OutputLayer *X11WindowedQPainterBackend::cursorLayer(Output *output)
0180 {
0181     return m_outputs[output].cursorLayer.get();
0182 }
0183 
0184 }
0185 
0186 #include "moc_x11_windowed_qpainter_backend.cpp"