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"