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_egl_backend.h" 0010 #include "core/gbmgraphicsbufferallocator.h" 0011 #include "opengl/eglswapchain.h" 0012 #include "opengl/glrendertimequery.h" 0013 #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" 0014 #include "x11_windowed_backend.h" 0015 #include "x11_windowed_logging.h" 0016 #include "x11_windowed_output.h" 0017 0018 #include <drm_fourcc.h> 0019 0020 namespace KWin 0021 { 0022 0023 X11WindowedEglPrimaryLayer::X11WindowedEglPrimaryLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output) 0024 : m_output(output) 0025 , m_backend(backend) 0026 { 0027 } 0028 0029 X11WindowedEglPrimaryLayer::~X11WindowedEglPrimaryLayer() 0030 { 0031 } 0032 0033 std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::beginFrame() 0034 { 0035 if (!m_backend->contextObject()->makeCurrent()) { 0036 return std::nullopt; 0037 } 0038 0039 const QSize bufferSize = m_output->modeSize(); 0040 if (!m_swapchain || m_swapchain->size() != bufferSize) { 0041 const uint32_t format = DRM_FORMAT_XRGB8888; 0042 const QHash<uint32_t, QList<uint64_t>> formatTable = m_backend->backend()->driFormats(); 0043 if (!formatTable.contains(format)) { 0044 return std::nullopt; 0045 } 0046 m_swapchain = EglSwapchain::create(m_backend->graphicsBufferAllocator(), m_backend->contextObject(), bufferSize, format, formatTable[format]); 0047 if (!m_swapchain) { 0048 return std::nullopt; 0049 } 0050 } 0051 0052 m_buffer = m_swapchain->acquire(); 0053 if (!m_buffer) { 0054 return std::nullopt; 0055 } 0056 0057 QRegion repaint = m_output->exposedArea() + m_output->rect(); 0058 m_output->clearExposedArea(); 0059 0060 if (!m_query) { 0061 m_query = std::make_unique<GLRenderTimeQuery>(); 0062 } 0063 m_query->begin(); 0064 return OutputLayerBeginFrameInfo{ 0065 .renderTarget = RenderTarget(m_buffer->framebuffer()), 0066 .repaint = repaint, 0067 }; 0068 } 0069 0070 bool X11WindowedEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) 0071 { 0072 m_query->end(); 0073 return true; 0074 } 0075 0076 void X11WindowedEglPrimaryLayer::present() 0077 { 0078 xcb_pixmap_t pixmap = m_output->importBuffer(m_buffer->buffer()); 0079 Q_ASSERT(pixmap != XCB_PIXMAP_NONE); 0080 0081 xcb_xfixes_region_t valid = 0; 0082 xcb_xfixes_region_t update = 0; 0083 uint32_t serial = 0; 0084 uint32_t options = 0; 0085 uint64_t targetMsc = 0; 0086 0087 xcb_present_pixmap(m_output->backend()->connection(), 0088 m_output->window(), 0089 pixmap, 0090 serial, 0091 valid, 0092 update, 0093 0, 0094 0, 0095 XCB_NONE, 0096 XCB_NONE, 0097 XCB_NONE, 0098 options, 0099 targetMsc, 0100 0, 0101 0, 0102 0, 0103 nullptr); 0104 0105 Q_EMIT m_output->outputChange(infiniteRegion()); 0106 0107 m_swapchain->release(m_buffer); 0108 } 0109 0110 std::shared_ptr<GLTexture> X11WindowedEglPrimaryLayer::texture() const 0111 { 0112 return m_buffer->texture(); 0113 } 0114 0115 std::chrono::nanoseconds X11WindowedEglPrimaryLayer::queryRenderTime() const 0116 { 0117 m_backend->makeCurrent(); 0118 return m_query->result(); 0119 } 0120 0121 X11WindowedEglCursorLayer::X11WindowedEglCursorLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output) 0122 : m_output(output) 0123 , m_backend(backend) 0124 { 0125 } 0126 0127 X11WindowedEglCursorLayer::~X11WindowedEglCursorLayer() 0128 { 0129 m_backend->contextObject()->makeCurrent(); 0130 m_framebuffer.reset(); 0131 m_texture.reset(); 0132 } 0133 0134 std::optional<OutputLayerBeginFrameInfo> X11WindowedEglCursorLayer::beginFrame() 0135 { 0136 if (!m_backend->contextObject()->makeCurrent()) { 0137 return std::nullopt; 0138 } 0139 0140 const auto tmp = size().expandedTo(QSize(64, 64)); 0141 const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height())); 0142 if (!m_texture || m_texture->size() != bufferSize) { 0143 m_texture = GLTexture::allocate(GL_RGBA8, bufferSize); 0144 if (!m_texture) { 0145 return std::nullopt; 0146 } 0147 m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get()); 0148 } 0149 if (!m_query) { 0150 m_query = std::make_unique<GLRenderTimeQuery>(); 0151 } 0152 m_query->begin(); 0153 return OutputLayerBeginFrameInfo{ 0154 .renderTarget = RenderTarget(m_framebuffer.get()), 0155 .repaint = infiniteRegion(), 0156 }; 0157 } 0158 0159 bool X11WindowedEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) 0160 { 0161 QImage buffer(m_framebuffer->size(), QImage::Format_RGBA8888_Premultiplied); 0162 0163 GLFramebuffer::pushFramebuffer(m_framebuffer.get()); 0164 glReadPixels(0, 0, buffer.width(), buffer.height(), GL_RGBA, GL_UNSIGNED_BYTE, buffer.bits()); 0165 GLFramebuffer::popFramebuffer(); 0166 0167 m_output->cursor()->update(buffer.mirrored(false, true), hotspot()); 0168 m_query->end(); 0169 0170 return true; 0171 } 0172 0173 std::chrono::nanoseconds X11WindowedEglCursorLayer::queryRenderTime() const 0174 { 0175 m_backend->makeCurrent(); 0176 return m_query->result(); 0177 } 0178 0179 X11WindowedEglBackend::X11WindowedEglBackend(X11WindowedBackend *backend) 0180 : m_allocator(std::make_unique<GbmGraphicsBufferAllocator>(backend->gbmDevice())) 0181 , m_backend(backend) 0182 { 0183 } 0184 0185 X11WindowedEglBackend::~X11WindowedEglBackend() 0186 { 0187 cleanup(); 0188 } 0189 0190 X11WindowedBackend *X11WindowedEglBackend::backend() const 0191 { 0192 return m_backend; 0193 } 0194 0195 GraphicsBufferAllocator *X11WindowedEglBackend::graphicsBufferAllocator() const 0196 { 0197 return m_allocator.get(); 0198 } 0199 0200 bool X11WindowedEglBackend::initializeEgl() 0201 { 0202 initClientExtensions(); 0203 0204 if (!m_backend->sceneEglDisplayObject()) { 0205 for (const QByteArray &extension : {QByteArrayLiteral("EGL_EXT_platform_base"), QByteArrayLiteral("EGL_KHR_platform_gbm")}) { 0206 if (!hasClientExtension(extension)) { 0207 qCWarning(KWIN_X11WINDOWED) << extension << "client extension is not supported by the platform"; 0208 return false; 0209 } 0210 } 0211 0212 m_backend->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, m_backend->gbmDevice(), nullptr))); 0213 } 0214 0215 auto display = m_backend->sceneEglDisplayObject(); 0216 if (!display) { 0217 return false; 0218 } 0219 setEglDisplay(display); 0220 return true; 0221 } 0222 0223 bool X11WindowedEglBackend::initRenderingContext() 0224 { 0225 if (!createContext(EGL_NO_CONFIG_KHR)) { 0226 return false; 0227 } 0228 0229 return makeCurrent(); 0230 } 0231 0232 void X11WindowedEglBackend::init() 0233 { 0234 qputenv("EGL_PLATFORM", "x11"); 0235 0236 if (!initializeEgl()) { 0237 setFailed(QStringLiteral("Could not initialize egl")); 0238 return; 0239 } 0240 if (!initRenderingContext()) { 0241 setFailed(QStringLiteral("Could not initialize rendering context")); 0242 return; 0243 } 0244 0245 initKWinGL(); 0246 initWayland(); 0247 0248 const auto &outputs = m_backend->outputs(); 0249 for (const auto &output : outputs) { 0250 X11WindowedOutput *x11Output = static_cast<X11WindowedOutput *>(output); 0251 m_outputs[output] = Layers{ 0252 .primaryLayer = std::make_unique<X11WindowedEglPrimaryLayer>(this, x11Output), 0253 .cursorLayer = std::make_unique<X11WindowedEglCursorLayer>(this, x11Output), 0254 }; 0255 } 0256 } 0257 0258 void X11WindowedEglBackend::cleanupSurfaces() 0259 { 0260 m_outputs.clear(); 0261 } 0262 0263 void X11WindowedEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame) 0264 { 0265 m_outputs[output].primaryLayer->present(); 0266 static_cast<X11WindowedOutput *>(output)->framePending(frame); 0267 } 0268 0269 OutputLayer *X11WindowedEglBackend::primaryLayer(Output *output) 0270 { 0271 return m_outputs[output].primaryLayer.get(); 0272 } 0273 0274 OutputLayer *X11WindowedEglBackend::cursorLayer(Output *output) 0275 { 0276 return m_outputs[output].cursorLayer.get(); 0277 } 0278 0279 std::unique_ptr<SurfaceTexture> X11WindowedEglBackend::createSurfaceTextureWayland(SurfacePixmap *pixmap) 0280 { 0281 return std::make_unique<BasicEGLSurfaceTextureWayland>(this, pixmap); 0282 } 0283 0284 std::pair<std::shared_ptr<GLTexture>, ColorDescription> X11WindowedEglBackend::textureForOutput(Output *output) const 0285 { 0286 auto it = m_outputs.find(output); 0287 if (it == m_outputs.end()) { 0288 return {nullptr, ColorDescription::sRGB}; 0289 } 0290 return std::make_pair(it->second.primaryLayer->texture(), ColorDescription::sRGB); 0291 } 0292 0293 } // namespace 0294 0295 #include "moc_x11_windowed_egl_backend.cpp"