KWin
Loading...
Searching...
No Matches
drm_egl_backend.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "drm_egl_backend.h"
11// kwin
12#include "drm_abstract_output.h"
13#include "drm_backend.h"
15#include "drm_egl_layer.h"
16#include "drm_gpu.h"
17#include "drm_logging.h"
18#include "drm_output.h"
19#include "drm_pipeline.h"
21// system
22#include <drm_fourcc.h>
23#include <gbm.h>
24#include <unistd.h>
25
26namespace KWin
27{
28
30 : AbstractEglBackend(drmBackend->primaryGpu()->deviceId())
31 , m_backend(drmBackend)
32{
33 drmBackend->setRenderBackend(this);
34 connect(m_backend, &DrmBackend::gpuRemoved, this, [this](DrmGpu *gpu) {
35 m_contexts.erase(gpu->eglDisplay());
36 });
37}
38
40{
41 m_backend->releaseBuffers();
42 const auto outputs = m_backend->outputs();
43 for (const auto output : outputs) {
44 if (auto drmOutput = dynamic_cast<DrmOutput *>(output)) {
45 drmOutput->pipeline()->setLayers(nullptr, nullptr);
46 }
47 }
48 m_contexts.clear();
49 cleanup();
50 m_backend->setRenderBackend(nullptr);
51}
52
53bool EglGbmBackend::initializeEgl()
54{
56 auto display = m_backend->primaryGpu()->eglDisplay();
57
58 // Use eglGetPlatformDisplayEXT() to get the display pointer
59 // if the implementation supports it.
60 if (!display) {
61 display = createEglDisplay(m_backend->primaryGpu());
62 if (!display) {
63 return false;
64 }
65 }
66 setEglDisplay(display);
67 return true;
68}
69
70EglDisplay *EglGbmBackend::createEglDisplay(DrmGpu *gpu) const
71{
72 if (!gpu->gbmDevice()) {
73 return nullptr;
74 }
75
76 for (const QByteArray &extension : {QByteArrayLiteral("EGL_EXT_platform_base"), QByteArrayLiteral("EGL_KHR_platform_gbm")}) {
77 if (!hasClientExtension(extension)) {
78 qCWarning(KWIN_DRM) << extension << "client extension is not supported by the platform";
79 return nullptr;
80 }
81 }
82
83 gpu->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, gpu->gbmDevice(), nullptr)));
84 return gpu->eglDisplay();
85}
86
88{
89 if (!initializeEgl()) {
90 setFailed("Could not initialize egl");
91 return;
92 }
93
94 if (!initRenderingContext()) {
95 setFailed("Could not initialize rendering context");
96 return;
97 }
98 initKWinGL();
100}
101
102bool EglGbmBackend::initRenderingContext()
103{
104 return createContext(EGL_NO_CONFIG_KHR) && makeCurrent();
105}
106
108{
109 if (gpu == m_backend->primaryGpu()) {
110 return eglDisplayObject();
111 }
112 auto display = gpu->eglDisplay();
113 if (!display) {
114 display = createEglDisplay(gpu);
115 }
116 return display;
117}
118
119std::shared_ptr<EglContext> EglGbmBackend::contextForGpu(DrmGpu *gpu)
120{
121 if (gpu == m_backend->primaryGpu()) {
122 return m_context;
123 }
124 auto display = gpu->eglDisplay();
125 if (!display) {
126 display = createEglDisplay(gpu);
127 if (!display) {
128 return nullptr;
129 }
130 }
131 auto &context = m_contexts[display];
132 if (const auto c = context.lock()) {
133 return c;
134 }
135 const auto ret = std::shared_ptr<EglContext>(EglContext::create(display, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT));
136 context = ret;
137 return ret;
138}
139
140std::unique_ptr<SurfaceTexture> EglGbmBackend::createSurfaceTextureWayland(SurfacePixmap *pixmap)
141{
142 return std::make_unique<BasicEGLSurfaceTextureWayland>(this, pixmap);
143}
144
149
150void EglGbmBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
151{
152 static_cast<DrmAbstractOutput *>(output)->present(frame);
153}
154
156{
157 return static_cast<DrmAbstractOutput *>(output)->primaryLayer();
158}
159
161{
162 return static_cast<DrmAbstractOutput *>(output)->cursorLayer();
163}
164
165std::pair<std::shared_ptr<KWin::GLTexture>, ColorDescription> EglGbmBackend::textureForOutput(Output *output) const
166{
167 const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
168 if (const auto virtualLayer = dynamic_cast<VirtualEglGbmLayer *>(drmOutput->primaryLayer())) {
169 return std::make_pair(virtualLayer->texture(), ColorDescription::sRGB);
170 }
171 const auto layer = static_cast<EglGbmLayer *>(drmOutput->primaryLayer());
172 return std::make_pair(layer->texture(), layer->colorDescription());
173}
174
176{
177 static bool ok = false;
178 static const int preferred = qEnvironmentVariableIntValue("KWIN_DRM_PREFER_COLOR_DEPTH", &ok);
179 return !ok || preferred == 30;
180}
181
182std::shared_ptr<DrmPipelineLayer> EglGbmBackend::createPrimaryLayer(DrmPipeline *pipeline)
183{
184 return std::make_shared<EglGbmLayer>(this, pipeline);
185}
186
187std::shared_ptr<DrmPipelineLayer> EglGbmBackend::createCursorLayer(DrmPipeline *pipeline)
188{
189 return std::make_shared<EglGbmCursorLayer>(this, pipeline);
190}
191
192std::shared_ptr<DrmOutputLayer> EglGbmBackend::createLayer(DrmVirtualOutput *output)
193{
194 return std::make_shared<VirtualEglGbmLayer>(this, output);
195}
196
198{
199 return m_backend->primaryGpu();
200}
201
202} // namespace KWin
203
204#include "moc_drm_egl_backend.cpp"
bool hasClientExtension(const QByteArray &ext) const
EglDisplay * eglDisplayObject() const
void setEglDisplay(EglDisplay *display)
bool createContext(EGLConfig config)
std::shared_ptr< EglContext > m_context
static const ColorDescription sRGB
Definition colorspace.h:132
Outputs outputs() const override
void setRenderBackend(DrmRenderBackend *backend)
void gpuRemoved(DrmGpu *gpu)
DrmGpu * primaryGpu() const
void setEglDisplay(std::unique_ptr< EglDisplay > &&display)
Definition drm_gpu.cpp:678
EglDisplay * eglDisplay() const
Definition drm_gpu.cpp:673
GraphicsBufferAllocator * graphicsBufferAllocator() const
Definition drm_gpu.cpp:834
gbm_device * gbmDevice() const
Definition drm_gpu.cpp:668
static std::unique_ptr< EglContext > create(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext)
static std::unique_ptr< EglDisplay > create(::EGLDisplay display, bool owning=true)
EglGbmBackend(DrmBackend *drmBackend)
std::shared_ptr< DrmOutputLayer > createLayer(DrmVirtualOutput *output) override
EglDisplay * displayForGpu(DrmGpu *gpu)
std::pair< std::shared_ptr< KWin::GLTexture >, ColorDescription > textureForOutput(Output *requestedOutput) const override
OutputLayer * primaryLayer(Output *output) override
std::unique_ptr< SurfaceTexture > createSurfaceTextureWayland(SurfacePixmap *pixmap) override
bool prefer10bpc() const override
std::shared_ptr< DrmPipelineLayer > createPrimaryLayer(DrmPipeline *pipeline) override
std::shared_ptr< EglContext > contextForGpu(DrmGpu *gpu)
OutputLayer * cursorLayer(Output *output) override
GraphicsBufferAllocator * graphicsBufferAllocator() const override
std::shared_ptr< DrmPipelineLayer > createCursorLayer(DrmPipeline *pipeline) override
void present(Output *output, const std::shared_ptr< OutputFrame > &frame) override
void setFailed(const QString &reason)
Sets the backend initialization to failed.