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"