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

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 "drm_egl_backend.h"
0010 #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h"
0011 // kwin
0012 #include "drm_abstract_output.h"
0013 #include "drm_backend.h"
0014 #include "drm_egl_cursor_layer.h"
0015 #include "drm_egl_layer.h"
0016 #include "drm_gpu.h"
0017 #include "drm_logging.h"
0018 #include "drm_output.h"
0019 #include "drm_pipeline.h"
0020 #include "drm_virtual_egl_layer.h"
0021 // system
0022 #include <drm_fourcc.h>
0023 #include <gbm.h>
0024 #include <unistd.h>
0025 
0026 namespace KWin
0027 {
0028 
0029 EglGbmBackend::EglGbmBackend(DrmBackend *drmBackend)
0030     : AbstractEglBackend(drmBackend->primaryGpu()->deviceId())
0031     , m_backend(drmBackend)
0032 {
0033     drmBackend->setRenderBackend(this);
0034     connect(m_backend, &DrmBackend::gpuRemoved, this, [this](DrmGpu *gpu) {
0035         m_contexts.erase(gpu->eglDisplay());
0036     });
0037 }
0038 
0039 EglGbmBackend::~EglGbmBackend()
0040 {
0041     m_backend->releaseBuffers();
0042     const auto outputs = m_backend->outputs();
0043     for (const auto output : outputs) {
0044         if (auto drmOutput = dynamic_cast<DrmOutput *>(output)) {
0045             drmOutput->pipeline()->setLayers(nullptr, nullptr);
0046         }
0047     }
0048     m_contexts.clear();
0049     cleanup();
0050     m_backend->setRenderBackend(nullptr);
0051 }
0052 
0053 bool EglGbmBackend::initializeEgl()
0054 {
0055     initClientExtensions();
0056     auto display = m_backend->primaryGpu()->eglDisplay();
0057 
0058     // Use eglGetPlatformDisplayEXT() to get the display pointer
0059     // if the implementation supports it.
0060     if (!display) {
0061         display = createEglDisplay(m_backend->primaryGpu());
0062         if (!display) {
0063             return false;
0064         }
0065     }
0066     setEglDisplay(display);
0067     return true;
0068 }
0069 
0070 EglDisplay *EglGbmBackend::createEglDisplay(DrmGpu *gpu) const
0071 {
0072     if (!gpu->gbmDevice()) {
0073         return nullptr;
0074     }
0075 
0076     for (const QByteArray &extension : {QByteArrayLiteral("EGL_EXT_platform_base"), QByteArrayLiteral("EGL_KHR_platform_gbm")}) {
0077         if (!hasClientExtension(extension)) {
0078             qCWarning(KWIN_DRM) << extension << "client extension is not supported by the platform";
0079             return nullptr;
0080         }
0081     }
0082 
0083     gpu->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, gpu->gbmDevice(), nullptr)));
0084     return gpu->eglDisplay();
0085 }
0086 
0087 void EglGbmBackend::init()
0088 {
0089     if (!initializeEgl()) {
0090         setFailed("Could not initialize egl");
0091         return;
0092     }
0093 
0094     if (!initRenderingContext()) {
0095         setFailed("Could not initialize rendering context");
0096         return;
0097     }
0098     initKWinGL();
0099     initWayland();
0100 }
0101 
0102 bool EglGbmBackend::initRenderingContext()
0103 {
0104     return createContext(EGL_NO_CONFIG_KHR) && makeCurrent();
0105 }
0106 
0107 EglDisplay *EglGbmBackend::displayForGpu(DrmGpu *gpu)
0108 {
0109     if (gpu == m_backend->primaryGpu()) {
0110         return eglDisplayObject();
0111     }
0112     auto display = gpu->eglDisplay();
0113     if (!display) {
0114         display = createEglDisplay(gpu);
0115     }
0116     return display;
0117 }
0118 
0119 std::shared_ptr<EglContext> EglGbmBackend::contextForGpu(DrmGpu *gpu)
0120 {
0121     if (gpu == m_backend->primaryGpu()) {
0122         return m_context;
0123     }
0124     auto display = gpu->eglDisplay();
0125     if (!display) {
0126         display = createEglDisplay(gpu);
0127         if (!display) {
0128             return nullptr;
0129         }
0130     }
0131     auto &context = m_contexts[display];
0132     if (const auto c = context.lock()) {
0133         return c;
0134     }
0135     const auto ret = std::shared_ptr<EglContext>(EglContext::create(display, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT));
0136     context = ret;
0137     return ret;
0138 }
0139 
0140 std::unique_ptr<SurfaceTexture> EglGbmBackend::createSurfaceTextureWayland(SurfacePixmap *pixmap)
0141 {
0142     return std::make_unique<BasicEGLSurfaceTextureWayland>(this, pixmap);
0143 }
0144 
0145 GraphicsBufferAllocator *EglGbmBackend::graphicsBufferAllocator() const
0146 {
0147     return gpu()->graphicsBufferAllocator();
0148 }
0149 
0150 void EglGbmBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
0151 {
0152     static_cast<DrmAbstractOutput *>(output)->present(frame);
0153 }
0154 
0155 OutputLayer *EglGbmBackend::primaryLayer(Output *output)
0156 {
0157     return static_cast<DrmAbstractOutput *>(output)->primaryLayer();
0158 }
0159 
0160 OutputLayer *EglGbmBackend::cursorLayer(Output *output)
0161 {
0162     return static_cast<DrmAbstractOutput *>(output)->cursorLayer();
0163 }
0164 
0165 std::pair<std::shared_ptr<KWin::GLTexture>, ColorDescription> EglGbmBackend::textureForOutput(Output *output) const
0166 {
0167     const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
0168     if (const auto virtualLayer = dynamic_cast<VirtualEglGbmLayer *>(drmOutput->primaryLayer())) {
0169         return std::make_pair(virtualLayer->texture(), ColorDescription::sRGB);
0170     }
0171     const auto layer = static_cast<EglGbmLayer *>(drmOutput->primaryLayer());
0172     return std::make_pair(layer->texture(), layer->colorDescription());
0173 }
0174 
0175 bool EglGbmBackend::prefer10bpc() const
0176 {
0177     static bool ok = false;
0178     static const int preferred = qEnvironmentVariableIntValue("KWIN_DRM_PREFER_COLOR_DEPTH", &ok);
0179     return !ok || preferred == 30;
0180 }
0181 
0182 std::shared_ptr<DrmPipelineLayer> EglGbmBackend::createPrimaryLayer(DrmPipeline *pipeline)
0183 {
0184     return std::make_shared<EglGbmLayer>(this, pipeline);
0185 }
0186 
0187 std::shared_ptr<DrmPipelineLayer> EglGbmBackend::createCursorLayer(DrmPipeline *pipeline)
0188 {
0189     return std::make_shared<EglGbmCursorLayer>(this, pipeline);
0190 }
0191 
0192 std::shared_ptr<DrmOutputLayer> EglGbmBackend::createLayer(DrmVirtualOutput *output)
0193 {
0194     return std::make_shared<VirtualEglGbmLayer>(this, output);
0195 }
0196 
0197 DrmGpu *EglGbmBackend::gpu() const
0198 {
0199     return m_backend->primaryGpu();
0200 }
0201 
0202 } // namespace KWin
0203 
0204 #include "moc_drm_egl_backend.cpp"