File indexing completed on 2024-11-10 04:56:32
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 "virtual_egl_backend.h" 0010 #include "core/gbmgraphicsbufferallocator.h" 0011 #include "opengl/eglswapchain.h" 0012 #include "opengl/glrendertimequery.h" 0013 #include "opengl/glutils.h" 0014 #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" 0015 #include "utils/softwarevsyncmonitor.h" 0016 #include "virtual_backend.h" 0017 #include "virtual_logging.h" 0018 #include "virtual_output.h" 0019 0020 #include <drm_fourcc.h> 0021 0022 namespace KWin 0023 { 0024 0025 VirtualEglLayer::VirtualEglLayer(Output *output, VirtualEglBackend *backend) 0026 : m_backend(backend) 0027 , m_output(output) 0028 { 0029 } 0030 0031 std::shared_ptr<GLTexture> VirtualEglLayer::texture() const 0032 { 0033 return m_current->texture(); 0034 } 0035 0036 std::optional<OutputLayerBeginFrameInfo> VirtualEglLayer::beginFrame() 0037 { 0038 m_backend->makeCurrent(); 0039 0040 const QSize nativeSize = m_output->modeSize(); 0041 if (!m_swapchain || m_swapchain->size() != nativeSize) { 0042 m_swapchain = EglSwapchain::create(m_backend->graphicsBufferAllocator(), m_backend->contextObject(), nativeSize, DRM_FORMAT_XRGB8888, {DRM_FORMAT_MOD_INVALID}); 0043 if (!m_swapchain) { 0044 return std::nullopt; 0045 } 0046 } 0047 0048 m_current = m_swapchain->acquire(); 0049 if (!m_current) { 0050 return std::nullopt; 0051 } 0052 0053 if (!m_query) { 0054 m_query = std::make_unique<GLRenderTimeQuery>(); 0055 } 0056 m_query->begin(); 0057 0058 return OutputLayerBeginFrameInfo{ 0059 .renderTarget = RenderTarget(m_current->framebuffer()), 0060 .repaint = infiniteRegion(), 0061 }; 0062 } 0063 0064 bool VirtualEglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) 0065 { 0066 m_query->end(); 0067 glFlush(); // flush pending rendering commands. 0068 Q_EMIT m_output->outputChange(damagedRegion); 0069 return true; 0070 } 0071 0072 std::chrono::nanoseconds VirtualEglLayer::queryRenderTime() const 0073 { 0074 if (m_query) { 0075 m_backend->makeCurrent(); 0076 return m_query->result(); 0077 } else { 0078 return std::chrono::nanoseconds::zero(); 0079 } 0080 } 0081 0082 VirtualEglBackend::VirtualEglBackend(VirtualBackend *b) 0083 : AbstractEglBackend() 0084 , m_backend(b) 0085 , m_allocator(std::make_unique<GbmGraphicsBufferAllocator>(b->gbmDevice())) 0086 { 0087 } 0088 0089 VirtualEglBackend::~VirtualEglBackend() 0090 { 0091 m_outputs.clear(); 0092 cleanup(); 0093 } 0094 0095 VirtualBackend *VirtualEglBackend::backend() const 0096 { 0097 return m_backend; 0098 } 0099 0100 GraphicsBufferAllocator *VirtualEglBackend::graphicsBufferAllocator() const 0101 { 0102 return m_allocator.get(); 0103 } 0104 0105 bool VirtualEglBackend::initializeEgl() 0106 { 0107 initClientExtensions(); 0108 0109 if (!m_backend->sceneEglDisplayObject()) { 0110 for (const QByteArray &extension : {QByteArrayLiteral("EGL_EXT_platform_base"), QByteArrayLiteral("EGL_KHR_platform_gbm")}) { 0111 if (!hasClientExtension(extension)) { 0112 qCWarning(KWIN_VIRTUAL) << extension << "client extension is not supported by the platform"; 0113 return false; 0114 } 0115 } 0116 0117 m_backend->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, m_backend->gbmDevice(), nullptr))); 0118 } 0119 0120 auto display = m_backend->sceneEglDisplayObject(); 0121 if (!display) { 0122 return false; 0123 } 0124 setEglDisplay(display); 0125 return true; 0126 } 0127 0128 void VirtualEglBackend::init() 0129 { 0130 if (!initializeEgl()) { 0131 setFailed("Could not initialize egl"); 0132 return; 0133 } 0134 if (!initRenderingContext()) { 0135 setFailed("Could not initialize rendering context"); 0136 return; 0137 } 0138 0139 initKWinGL(); 0140 if (checkGLError("Init")) { 0141 setFailed("Error during init of EglGbmBackend"); 0142 return; 0143 } 0144 0145 setSupportsBufferAge(false); 0146 initWayland(); 0147 0148 const auto outputs = m_backend->outputs(); 0149 for (Output *output : outputs) { 0150 addOutput(output); 0151 } 0152 0153 connect(m_backend, &VirtualBackend::outputAdded, this, &VirtualEglBackend::addOutput); 0154 connect(m_backend, &VirtualBackend::outputRemoved, this, &VirtualEglBackend::removeOutput); 0155 } 0156 0157 bool VirtualEglBackend::initRenderingContext() 0158 { 0159 return createContext(EGL_NO_CONFIG_KHR) && makeCurrent(); 0160 } 0161 0162 void VirtualEglBackend::addOutput(Output *output) 0163 { 0164 makeCurrent(); 0165 m_outputs[output] = std::make_unique<VirtualEglLayer>(output, this); 0166 } 0167 0168 void VirtualEglBackend::removeOutput(Output *output) 0169 { 0170 makeCurrent(); 0171 m_outputs.erase(output); 0172 } 0173 0174 std::unique_ptr<SurfaceTexture> VirtualEglBackend::createSurfaceTextureWayland(SurfacePixmap *pixmap) 0175 { 0176 return std::make_unique<BasicEGLSurfaceTextureWayland>(this, pixmap); 0177 } 0178 0179 OutputLayer *VirtualEglBackend::primaryLayer(Output *output) 0180 { 0181 return m_outputs[output].get(); 0182 } 0183 0184 void VirtualEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame) 0185 { 0186 static_cast<VirtualOutput *>(output)->present(frame); 0187 } 0188 0189 std::pair<std::shared_ptr<KWin::GLTexture>, ColorDescription> VirtualEglBackend::textureForOutput(Output *output) const 0190 { 0191 auto it = m_outputs.find(output); 0192 if (it == m_outputs.end()) { 0193 return {nullptr, ColorDescription::sRGB}; 0194 } 0195 return std::make_pair(it->second->texture(), ColorDescription::sRGB); 0196 } 0197 0198 } // namespace 0199 0200 #include "moc_virtual_egl_backend.cpp"