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"