KWin
Loading...
Searching...
No Matches
x11_windowed_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"
16#include "x11_windowed_output.h"
17
18#include <drm_fourcc.h>
19
20namespace KWin
21{
22
24 : m_output(output)
25 , m_backend(backend)
26{
27}
28
32
33std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::beginFrame()
34{
35 if (!m_backend->contextObject()->makeCurrent()) {
36 return std::nullopt;
37 }
38
39 const QSize bufferSize = m_output->modeSize();
40 if (!m_swapchain || m_swapchain->size() != bufferSize) {
41 const uint32_t format = DRM_FORMAT_XRGB8888;
42 const QHash<uint32_t, QList<uint64_t>> formatTable = m_backend->backend()->driFormats();
43 if (!formatTable.contains(format)) {
44 return std::nullopt;
45 }
46 m_swapchain = EglSwapchain::create(m_backend->graphicsBufferAllocator(), m_backend->contextObject(), bufferSize, format, formatTable[format]);
47 if (!m_swapchain) {
48 return std::nullopt;
49 }
50 }
51
52 m_buffer = m_swapchain->acquire();
53 if (!m_buffer) {
54 return std::nullopt;
55 }
56
57 QRegion repaint = m_output->exposedArea() + m_output->rect();
58 m_output->clearExposedArea();
59
60 if (!m_query) {
61 m_query = std::make_unique<GLRenderTimeQuery>();
62 }
63 m_query->begin();
65 .renderTarget = RenderTarget(m_buffer->framebuffer()),
66 .repaint = repaint,
67 };
68}
69
70bool X11WindowedEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
71{
72 m_query->end();
73 return true;
74}
75
77{
78 xcb_pixmap_t pixmap = m_output->importBuffer(m_buffer->buffer());
79 Q_ASSERT(pixmap != XCB_PIXMAP_NONE);
80
81 xcb_xfixes_region_t valid = 0;
82 xcb_xfixes_region_t update = 0;
83 uint32_t serial = 0;
84 uint32_t options = 0;
85 uint64_t targetMsc = 0;
86
87 xcb_present_pixmap(m_output->backend()->connection(),
88 m_output->window(),
89 pixmap,
90 serial,
91 valid,
92 update,
93 0,
94 0,
95 XCB_NONE,
96 XCB_NONE,
97 XCB_NONE,
98 options,
99 targetMsc,
100 0,
101 0,
102 0,
103 nullptr);
104
105 Q_EMIT m_output->outputChange(infiniteRegion());
106
107 m_swapchain->release(m_buffer);
108}
109
110std::shared_ptr<GLTexture> X11WindowedEglPrimaryLayer::texture() const
111{
112 return m_buffer->texture();
113}
114
115std::chrono::nanoseconds X11WindowedEglPrimaryLayer::queryRenderTime() const
116{
117 m_backend->makeCurrent();
118 return m_query->result();
119}
120
122 : m_output(output)
123 , m_backend(backend)
124{
125}
126
128{
129 m_backend->contextObject()->makeCurrent();
130 m_framebuffer.reset();
131 m_texture.reset();
132}
133
134std::optional<OutputLayerBeginFrameInfo> X11WindowedEglCursorLayer::beginFrame()
135{
136 if (!m_backend->contextObject()->makeCurrent()) {
137 return std::nullopt;
138 }
139
140 const auto tmp = size().expandedTo(QSize(64, 64));
141 const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
142 if (!m_texture || m_texture->size() != bufferSize) {
143 m_texture = GLTexture::allocate(GL_RGBA8, bufferSize);
144 if (!m_texture) {
145 return std::nullopt;
146 }
147 m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
148 }
149 if (!m_query) {
150 m_query = std::make_unique<GLRenderTimeQuery>();
151 }
152 m_query->begin();
154 .renderTarget = RenderTarget(m_framebuffer.get()),
155 .repaint = infiniteRegion(),
156 };
157}
158
159bool X11WindowedEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
160{
161 QImage buffer(m_framebuffer->size(), QImage::Format_RGBA8888_Premultiplied);
162
163 GLFramebuffer::pushFramebuffer(m_framebuffer.get());
164 glReadPixels(0, 0, buffer.width(), buffer.height(), GL_RGBA, GL_UNSIGNED_BYTE, buffer.bits());
166
167 m_output->cursor()->update(buffer.mirrored(false, true), hotspot());
168 m_query->end();
169
170 return true;
171}
172
173std::chrono::nanoseconds X11WindowedEglCursorLayer::queryRenderTime() const
174{
175 m_backend->makeCurrent();
176 return m_query->result();
177}
178
180 : m_allocator(std::make_unique<GbmGraphicsBufferAllocator>(backend->gbmDevice()))
181 , m_backend(backend)
182{
183}
184
189
191{
192 return m_backend;
193}
194
196{
197 return m_allocator.get();
198}
199
200bool X11WindowedEglBackend::initializeEgl()
201{
203
204 if (!m_backend->sceneEglDisplayObject()) {
205 for (const QByteArray &extension : {QByteArrayLiteral("EGL_EXT_platform_base"), QByteArrayLiteral("EGL_KHR_platform_gbm")}) {
206 if (!hasClientExtension(extension)) {
207 qCWarning(KWIN_X11WINDOWED) << extension << "client extension is not supported by the platform";
208 return false;
209 }
210 }
211
212 m_backend->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, m_backend->gbmDevice(), nullptr)));
213 }
214
215 auto display = m_backend->sceneEglDisplayObject();
216 if (!display) {
217 return false;
218 }
219 setEglDisplay(display);
220 return true;
221}
222
223bool X11WindowedEglBackend::initRenderingContext()
224{
225 if (!createContext(EGL_NO_CONFIG_KHR)) {
226 return false;
227 }
228
229 return makeCurrent();
230}
231
233{
234 qputenv("EGL_PLATFORM", "x11");
235
236 if (!initializeEgl()) {
237 setFailed(QStringLiteral("Could not initialize egl"));
238 return;
239 }
240 if (!initRenderingContext()) {
241 setFailed(QStringLiteral("Could not initialize rendering context"));
242 return;
243 }
244
245 initKWinGL();
246 initWayland();
247
248 const auto &outputs = m_backend->outputs();
249 for (const auto &output : outputs) {
250 X11WindowedOutput *x11Output = static_cast<X11WindowedOutput *>(output);
251 m_outputs[output] = Layers{
252 .primaryLayer = std::make_unique<X11WindowedEglPrimaryLayer>(this, x11Output),
253 .cursorLayer = std::make_unique<X11WindowedEglCursorLayer>(this, x11Output),
254 };
255 }
256}
257
259{
260 m_outputs.clear();
261}
262
263void X11WindowedEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
264{
265 m_outputs[output].primaryLayer->present();
266 static_cast<X11WindowedOutput *>(output)->framePending(frame);
267}
268
270{
271 return m_outputs[output].primaryLayer.get();
272}
273
275{
276 return m_outputs[output].cursorLayer.get();
277}
278
280{
281 return std::make_unique<BasicEGLSurfaceTextureWayland>(this, pixmap);
282}
283
284std::pair<std::shared_ptr<GLTexture>, ColorDescription> X11WindowedEglBackend::textureForOutput(Output *output) const
285{
286 auto it = m_outputs.find(output);
287 if (it == m_outputs.end()) {
288 return {nullptr, ColorDescription::sRGB};
289 }
290 return std::make_pair(it->second.primaryLayer->texture(), ColorDescription::sRGB);
291}
292
293} // namespace
294
295#include "moc_x11_windowed_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
bool makeCurrent(EGLSurface surface=EGL_NO_SURFACE) const
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)
static GLFramebuffer * popFramebuffer()
static void pushFramebuffer(GLFramebuffer *fbo)
static std::unique_ptr< GLTexture > allocate(GLenum internalFormat, const QSize &size, int levels=1)
void setFailed(const QString &reason)
Sets the backend initialization to failed.
QRect rect() const
Definition output.h:484
void outputChange(const QRegion &damagedRegion)
QSize modeSize() const
Definition output.cpp:480
QSizeF size() const
QPointF hotspot() const
void setEglDisplay(std::unique_ptr< EglDisplay > &&display)
xcb_connection_t * connection() const
EglDisplay * sceneEglDisplayObject() const override
QHash< uint32_t, QList< uint64_t > > driFormats() const
Outputs outputs() const override
void update(const QImage &image, const QPointF &hotspot)
OpenGL Backend using Egl windowing system over an X overlay window.
OutputLayer * primaryLayer(Output *output) override
std::pair< std::shared_ptr< GLTexture >, ColorDescription > textureForOutput(Output *output) const override
std::unique_ptr< SurfaceTexture > createSurfaceTextureWayland(SurfacePixmap *pixmap) override
OutputLayer * cursorLayer(Output *output) override
X11WindowedBackend * backend() const
GraphicsBufferAllocator * graphicsBufferAllocator() const override
X11WindowedEglBackend(X11WindowedBackend *backend)
void present(Output *output, const std::shared_ptr< OutputFrame > &frame) override
X11WindowedEglCursorLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output)
std::chrono::nanoseconds queryRenderTime() const override
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override
std::optional< OutputLayerBeginFrameInfo > beginFrame() override
std::optional< OutputLayerBeginFrameInfo > beginFrame() override
std::chrono::nanoseconds queryRenderTime() const override
X11WindowedEglPrimaryLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output)
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override
std::shared_ptr< GLTexture > texture() const
xcb_pixmap_t importBuffer(GraphicsBuffer *buffer)
X11WindowedCursor * cursor() const
X11WindowedBackend * backend() const
KWIN_EXPORT QRect infiniteRegion()
Definition globals.h:234
GLenum format
Definition gltexture.cpp:49
struct KWin::@10 formatTable[]
Options * options
Definition main.cpp:73