KWin
Loading...
Searching...
No Matches
virtual_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*/
11#include "opengl/eglswapchain.h"
13#include "opengl/glutils.h"
16#include "virtual_backend.h"
17#include "virtual_logging.h"
18#include "virtual_output.h"
19
20#include <drm_fourcc.h>
21
22namespace KWin
23{
24
26 : m_backend(backend)
27 , m_output(output)
28{
29}
30
31std::shared_ptr<GLTexture> VirtualEglLayer::texture() const
32{
33 return m_current->texture();
34}
35
36std::optional<OutputLayerBeginFrameInfo> VirtualEglLayer::beginFrame()
37{
38 m_backend->makeCurrent();
39
40 const QSize nativeSize = m_output->modeSize();
41 if (!m_swapchain || m_swapchain->size() != nativeSize) {
42 m_swapchain = EglSwapchain::create(m_backend->graphicsBufferAllocator(), m_backend->contextObject(), nativeSize, DRM_FORMAT_XRGB8888, {DRM_FORMAT_MOD_INVALID});
43 if (!m_swapchain) {
44 return std::nullopt;
45 }
46 }
47
48 m_current = m_swapchain->acquire();
49 if (!m_current) {
50 return std::nullopt;
51 }
52
53 if (!m_query) {
54 m_query = std::make_unique<GLRenderTimeQuery>();
55 }
56 m_query->begin();
57
59 .renderTarget = RenderTarget(m_current->framebuffer()),
60 .repaint = infiniteRegion(),
61 };
62}
63
64bool VirtualEglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
65{
66 m_query->end();
67 glFlush(); // flush pending rendering commands.
68 Q_EMIT m_output->outputChange(damagedRegion);
69 return true;
70}
71
72std::chrono::nanoseconds VirtualEglLayer::queryRenderTime() const
73{
74 if (m_query) {
75 m_backend->makeCurrent();
76 return m_query->result();
77 } else {
78 return std::chrono::nanoseconds::zero();
79 }
80}
81
84 , m_backend(b)
85 , m_allocator(std::make_unique<GbmGraphicsBufferAllocator>(b->gbmDevice()))
86{
87}
88
90{
91 m_outputs.clear();
92 cleanup();
93}
94
96{
97 return m_backend;
98}
99
101{
102 return m_allocator.get();
103}
104
105bool VirtualEglBackend::initializeEgl()
106{
108
109 if (!m_backend->sceneEglDisplayObject()) {
110 for (const QByteArray &extension : {QByteArrayLiteral("EGL_EXT_platform_base"), QByteArrayLiteral("EGL_KHR_platform_gbm")}) {
111 if (!hasClientExtension(extension)) {
112 qCWarning(KWIN_VIRTUAL) << extension << "client extension is not supported by the platform";
113 return false;
114 }
115 }
116
117 m_backend->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, m_backend->gbmDevice(), nullptr)));
118 }
119
120 auto display = m_backend->sceneEglDisplayObject();
121 if (!display) {
122 return false;
123 }
124 setEglDisplay(display);
125 return true;
126}
127
129{
130 if (!initializeEgl()) {
131 setFailed("Could not initialize egl");
132 return;
133 }
134 if (!initRenderingContext()) {
135 setFailed("Could not initialize rendering context");
136 return;
137 }
138
139 initKWinGL();
140 if (checkGLError("Init")) {
141 setFailed("Error during init of EglGbmBackend");
142 return;
143 }
144
146 initWayland();
147
148 const auto outputs = m_backend->outputs();
149 for (Output *output : outputs) {
150 addOutput(output);
151 }
152
153 connect(m_backend, &VirtualBackend::outputAdded, this, &VirtualEglBackend::addOutput);
154 connect(m_backend, &VirtualBackend::outputRemoved, this, &VirtualEglBackend::removeOutput);
155}
156
157bool VirtualEglBackend::initRenderingContext()
158{
159 return createContext(EGL_NO_CONFIG_KHR) && makeCurrent();
160}
161
162void VirtualEglBackend::addOutput(Output *output)
163{
164 makeCurrent();
165 m_outputs[output] = std::make_unique<VirtualEglLayer>(output, this);
166}
167
168void VirtualEglBackend::removeOutput(Output *output)
169{
170 makeCurrent();
171 m_outputs.erase(output);
172}
173
174std::unique_ptr<SurfaceTexture> VirtualEglBackend::createSurfaceTextureWayland(SurfacePixmap *pixmap)
175{
176 return std::make_unique<BasicEGLSurfaceTextureWayland>(this, pixmap);
177}
178
180{
181 return m_outputs[output].get();
182}
183
184void VirtualEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
185{
186 static_cast<VirtualOutput *>(output)->present(frame);
187}
188
189std::pair<std::shared_ptr<KWin::GLTexture>, ColorDescription> VirtualEglBackend::textureForOutput(Output *output) const
190{
191 auto it = m_outputs.find(output);
192 if (it == m_outputs.end()) {
193 return {nullptr, ColorDescription::sRGB};
194 }
195 return std::make_pair(it->second->texture(), ColorDescription::sRGB);
196}
197
198} // namespace
199
200#include "moc_virtual_egl_backend.cpp"
bool hasClientExtension(const QByteArray &ext) const
void setEglDisplay(EglDisplay *display)
bool createContext(EGLConfig config)
static const ColorDescription sRGB
Definition colorspace.h:132
static std::unique_ptr< EglDisplay > create(::EGLDisplay display, bool owning=true)
static std::shared_ptr< EglSwapchain > create(GraphicsBufferAllocator *allocator, EglContext *context, const QSize &size, uint32_t format, const QList< uint64_t > &modifiers)
void setSupportsBufferAge(bool value)
void setFailed(const QString &reason)
Sets the backend initialization to failed.
void outputAdded(Output *output)
void outputRemoved(Output *output)
void outputChange(const QRegion &damagedRegion)
QSize modeSize() const
Definition output.cpp:480
EglDisplay * sceneEglDisplayObject() const override
gbm_device * gbmDevice() const
void setEglDisplay(std::unique_ptr< EglDisplay > &&display)
Outputs outputs() const override
OpenGL Backend using Egl on a GBM surface.
void present(Output *output, const std::shared_ptr< OutputFrame > &frame) override
VirtualEglBackend(VirtualBackend *b)
VirtualBackend * backend() const
std::unique_ptr< SurfaceTexture > createSurfaceTextureWayland(SurfacePixmap *pixmap) override
GraphicsBufferAllocator * graphicsBufferAllocator() const override
OutputLayer * primaryLayer(Output *output) override
std::pair< std::shared_ptr< KWin::GLTexture >, ColorDescription > textureForOutput(Output *output) const override
std::optional< OutputLayerBeginFrameInfo > beginFrame() override
std::shared_ptr< GLTexture > texture() const
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override
std::chrono::nanoseconds queryRenderTime() const override
VirtualEglLayer(Output *output, VirtualEglBackend *backend)
KWIN_EXPORT QRect infiniteRegion()
Definition globals.h:234
bool checkGLError(const char *txt)
Definition glutils.cpp:170