Changeset View
Changeset View
Standalone View
Standalone View
plugins/platforms/wayland/egl_wayland_backend.cpp
1 | | ||||
---|---|---|---|---|---|
2 | /******************************************************************** | 1 | /******************************************************************** | ||
3 | KWin - the KDE window manager | 2 | KWin - the KDE window manager | ||
4 | This file is part of the KDE project. | 3 | This file is part of the KDE project. | ||
5 | 4 | | |||
6 | Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org> | 5 | Copyright 2019 Roman Gilg <subdiff@gmail.com> | ||
6 | Copyright 2013 Martin Gräßlin <mgraesslin@kde.org> | ||||
7 | 7 | | |||
8 | This program is free software; you can redistribute it and/or modify | 8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | 9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | 10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | 11 | (at your option) any later version. | ||
12 | 12 | | |||
13 | This program is distributed in the hope that it will be useful, | 13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | 16 | GNU General Public License for more details. | ||
17 | 17 | | |||
18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | *********************************************************************/ | 20 | *********************************************************************/ | ||
21 | #define WL_EGL_PLATFORM 1 | 21 | #define WL_EGL_PLATFORM 1 | ||
22 | | ||||
22 | #include "egl_wayland_backend.h" | 23 | #include "egl_wayland_backend.h" | ||
23 | // kwin | 24 | | ||
25 | #include "wayland_backend.h" | ||||
26 | #include "wayland_output.h" | ||||
27 | | ||||
24 | #include "composite.h" | 28 | #include "composite.h" | ||
25 | #include "logging.h" | 29 | #include "logging.h" | ||
26 | #include "options.h" | 30 | #include "options.h" | ||
27 | #include "wayland_backend.h" | 31 | | ||
28 | #include "wayland_server.h" | 32 | #include "wayland_server.h" | ||
29 | #include <KWayland/Client/surface.h> | 33 | #include "screens.h" | ||
34 | | ||||
30 | // kwin libs | 35 | // kwin libs | ||
31 | #include <kwinglplatform.h> | 36 | #include <kwinglplatform.h> | ||
37 | | ||||
32 | // KDE | 38 | // KDE | ||
39 | #include <KWayland/Client/surface.h> | ||||
33 | #include <KWayland/Server/buffer_interface.h> | 40 | #include <KWayland/Server/buffer_interface.h> | ||
34 | #include <KWayland/Server/display.h> | 41 | #include <KWayland/Server/display.h> | ||
42 | | ||||
35 | // Qt | 43 | // Qt | ||
36 | #include <QOpenGLContext> | 44 | #include <QOpenGLContext> | ||
37 | 45 | | |||
38 | namespace KWin | 46 | namespace KWin | ||
39 | { | 47 | { | ||
48 | namespace Wayland | ||||
49 | { | ||||
40 | 50 | | |||
41 | EglWaylandBackend::EglWaylandBackend(Wayland::WaylandBackend *b) | 51 | EglWaylandOutput::EglWaylandOutput(WaylandOutput *output, QObject *parent) | ||
52 | : QObject(parent) | ||||
53 | , m_waylandOutput(output) | ||||
54 | { | ||||
55 | } | ||||
56 | | ||||
57 | bool EglWaylandOutput::init(EglWaylandBackend *backend) | ||||
58 | { | ||||
59 | auto surface = m_waylandOutput->surface(); | ||||
60 | const QSize &size = m_waylandOutput->geometry().size(); | ||||
61 | auto overlay = wl_egl_window_create(*surface, size.width(), size.height()); | ||||
62 | if (!overlay) { | ||||
63 | qCCritical(KWIN_WAYLAND_BACKEND) << "Creating Wayland Egl window failed"; | ||||
64 | return false; | ||||
65 | } | ||||
66 | m_overlay = overlay; | ||||
67 | | ||||
68 | EGLSurface eglSurface = EGL_NO_SURFACE; | ||||
69 | if (backend->havePlatformBase()) { | ||||
70 | eglSurface = eglCreatePlatformWindowSurfaceEXT(backend->eglDisplay(), backend->config(), (void *) overlay, nullptr); | ||||
71 | } else { | ||||
72 | eglSurface = eglCreateWindowSurface(backend->eglDisplay(), backend->config(), overlay, nullptr); | ||||
73 | } | ||||
74 | if (eglSurface == EGL_NO_SURFACE) { | ||||
75 | qCCritical(KWIN_WAYLAND_BACKEND) << "Create Window Surface failed"; | ||||
76 | return false; | ||||
77 | } | ||||
78 | m_eglSurface = eglSurface; | ||||
79 | | ||||
80 | connect(m_waylandOutput, &WaylandOutput::sizeChanged, this, &EglWaylandOutput::updateSize); | ||||
81 | | ||||
82 | return true; | ||||
83 | } | ||||
84 | | ||||
85 | void EglWaylandOutput::updateSize(const QSize &size) | ||||
86 | { | ||||
87 | wl_egl_window_resize(m_overlay, size.width(), size.height(), 0, 0); | ||||
88 | } | ||||
89 | | ||||
90 | EglWaylandBackend::EglWaylandBackend(WaylandBackend *b) | ||||
42 | : AbstractEglBackend() | 91 | : AbstractEglBackend() | ||
43 | , m_bufferAge(0) | 92 | , m_backend(b) | ||
44 | , m_wayland(b) | | |||
45 | , m_overlay(NULL) | | |||
46 | { | 93 | { | ||
47 | if (!m_wayland) { | 94 | if (!m_backend) { | ||
48 | setFailed("Wayland Backend has not been created"); | 95 | setFailed("Wayland Backend has not been created"); | ||
49 | return; | 96 | return; | ||
50 | } | 97 | } | ||
51 | qCDebug(KWIN_WAYLAND_BACKEND) << "Connected to Wayland display?" << (m_wayland->display() ? "yes" : "no" ); | 98 | qCDebug(KWIN_WAYLAND_BACKEND) << "Connected to Wayland display?" << (m_backend->display() ? "yes" : "no" ); | ||
52 | if (!m_wayland->display()) { | 99 | if (!m_backend->display()) { | ||
53 | setFailed("Could not connect to Wayland compositor"); | 100 | setFailed("Could not connect to Wayland compositor"); | ||
54 | return; | 101 | return; | ||
55 | } | 102 | } | ||
56 | connect(m_wayland, SIGNAL(shellSurfaceSizeChanged(QSize)), SLOT(overlaySizeChanged(QSize))); | 103 | | ||
57 | // Egl is always direct rendering | 104 | // Egl is always direct rendering | ||
58 | setIsDirectRendering(true); | 105 | setIsDirectRendering(true); | ||
106 | | ||||
107 | connect(m_backend, &WaylandBackend::outputAdded, this, &EglWaylandBackend::createEglWaylandOutput); | ||||
108 | connect(m_backend, &WaylandBackend::outputRemoved, this, | ||||
109 | [this] (WaylandOutput *output) { | ||||
110 | auto it = std::find_if(m_outputs.begin(), m_outputs.end(), | ||||
111 | [output] (const EglWaylandOutput *o) { | ||||
112 | return o->m_waylandOutput == output; | ||||
113 | } | ||||
114 | ); | ||||
115 | if (it == m_outputs.end()) { | ||||
116 | return; | ||||
117 | } | ||||
118 | cleanupOutput(*it); | ||||
119 | m_outputs.erase(it); | ||||
120 | } | ||||
121 | ); | ||||
59 | } | 122 | } | ||
60 | 123 | | |||
61 | EglWaylandBackend::~EglWaylandBackend() | 124 | EglWaylandBackend::~EglWaylandBackend() | ||
62 | { | 125 | { | ||
63 | cleanup(); | 126 | cleanup(); | ||
64 | if (m_overlay) { | | |||
65 | wl_egl_window_destroy(m_overlay); | | |||
66 | } | 127 | } | ||
128 | | ||||
129 | void EglWaylandBackend::cleanupSurfaces() | ||||
130 | { | ||||
131 | for (auto o : m_outputs) { | ||||
132 | cleanupOutput(o); | ||||
133 | } | ||||
134 | m_outputs.clear(); | ||||
135 | } | ||||
136 | | ||||
137 | bool EglWaylandBackend::createEglWaylandOutput(WaylandOutput *waylandOutput) | ||||
138 | { | ||||
139 | auto *output = new EglWaylandOutput(waylandOutput, this); | ||||
140 | if (output->init(this)) { | ||||
141 | return false; | ||||
142 | } | ||||
143 | m_outputs << output; | ||||
144 | return true; | ||||
145 | } | ||||
146 | | ||||
147 | void EglWaylandBackend::cleanupOutput(EglWaylandOutput *output) | ||||
148 | { | ||||
149 | wl_egl_window_destroy(output->m_overlay); | ||||
67 | } | 150 | } | ||
68 | 151 | | |||
69 | bool EglWaylandBackend::initializeEgl() | 152 | bool EglWaylandBackend::initializeEgl() | ||
70 | { | 153 | { | ||
71 | initClientExtensions(); | 154 | initClientExtensions(); | ||
72 | EGLDisplay display = m_wayland->sceneEglDisplay(); | 155 | EGLDisplay display = m_backend->sceneEglDisplay(); | ||
73 | 156 | | |||
74 | // Use eglGetPlatformDisplayEXT() to get the display pointer | 157 | // Use eglGetPlatformDisplayEXT() to get the display pointer | ||
75 | // if the implementation supports it. | 158 | // if the implementation supports it. | ||
76 | if (display == EGL_NO_DISPLAY) { | 159 | if (display == EGL_NO_DISPLAY) { | ||
77 | m_havePlatformBase = hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base")); | 160 | m_havePlatformBase = hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base")); | ||
78 | if (m_havePlatformBase) { | 161 | if (m_havePlatformBase) { | ||
79 | // Make sure that the wayland platform is supported | 162 | // Make sure that the wayland platform is supported | ||
80 | if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_wayland"))) | 163 | if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_wayland"))) | ||
zzag: Does such extension exist? | |||||
Pretty sure that not. Seems to be a search and replace error, when changing the m_wayland variable name to m_backen. THANKS! romangg: Pretty sure that not. Seems to be a search and replace error, when changing the m_wayland… | |||||
81 | return false; | 164 | return false; | ||
82 | 165 | | |||
83 | display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, m_wayland->display(), nullptr); | 166 | display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, m_backend->display(), nullptr); | ||
84 | } else { | 167 | } else { | ||
85 | display = eglGetDisplay(m_wayland->display()); | 168 | display = eglGetDisplay(m_backend->display()); | ||
86 | } | 169 | } | ||
87 | } | 170 | } | ||
88 | 171 | | |||
89 | if (display == EGL_NO_DISPLAY) | 172 | if (display == EGL_NO_DISPLAY) | ||
90 | return false; | 173 | return false; | ||
91 | setEglDisplay(display); | 174 | setEglDisplay(display); | ||
92 | return initEglAPI(); | 175 | return initEglAPI(); | ||
93 | } | 176 | } | ||
Show All 17 Lines | |||||
111 | bool EglWaylandBackend::initRenderingContext() | 194 | bool EglWaylandBackend::initRenderingContext() | ||
112 | { | 195 | { | ||
113 | initBufferConfigs(); | 196 | initBufferConfigs(); | ||
114 | 197 | | |||
115 | if (!createContext()) { | 198 | if (!createContext()) { | ||
116 | return false; | 199 | return false; | ||
117 | } | 200 | } | ||
118 | 201 | | |||
119 | if (!m_wayland->surface()) { | 202 | auto waylandOutputs = m_backend->waylandOutputs(); | ||
203 | | ||||
204 | // we only allow to start with at least one output | ||||
205 | if (waylandOutputs.isEmpty()) { | ||||
120 | return false; | 206 | return false; | ||
121 | } | 207 | } | ||
122 | 208 | | |||
123 | const QSize &size = m_wayland->shellSurfaceSize(); | 209 | for (auto *out : waylandOutputs) { | ||
124 | auto s = m_wayland->surface(); | 210 | if (!createEglWaylandOutput(out)) { | ||
125 | connect(s, &KWayland::Client::Surface::frameRendered, Compositor::self(), &Compositor::bufferSwapComplete); | | |||
126 | m_overlay = wl_egl_window_create(*s, size.width(), size.height()); | | |||
127 | if (!m_overlay) { | | |||
128 | qCCritical(KWIN_WAYLAND_BACKEND) << "Creating Wayland Egl window failed"; | | |||
129 | return false; | 211 | return false; | ||
130 | } | 212 | } | ||
213 | } | ||||
131 | 214 | | |||
132 | EGLSurface surface = EGL_NO_SURFACE; | 215 | if (m_outputs.isEmpty()) { | ||
133 | if (m_havePlatformBase) | 216 | qCCritical(KWIN_WAYLAND_BACKEND) << "Create Window Surfaces failed"; | ||
134 | surface = eglCreatePlatformWindowSurfaceEXT(eglDisplay(), config(), (void *) m_overlay, nullptr); | | |||
135 | else | | |||
136 | surface = eglCreateWindowSurface(eglDisplay(), config(), m_overlay, nullptr); | | |||
137 | | ||||
138 | if (surface == EGL_NO_SURFACE) { | | |||
139 | qCCritical(KWIN_WAYLAND_BACKEND) << "Create Window Surface failed"; | | |||
140 | return false; | 217 | return false; | ||
141 | } | 218 | } | ||
142 | setSurface(surface); | | |||
143 | 219 | | |||
144 | return makeContextCurrent(); | 220 | auto *firstOutput = m_outputs.first(); | ||
221 | // set our first surface as the one for the abstract backend, just to make it happy | ||||
222 | setSurface(firstOutput->m_eglSurface); | ||||
223 | return makeContextCurrent(firstOutput); | ||||
145 | } | 224 | } | ||
146 | 225 | | |||
147 | bool EglWaylandBackend::makeContextCurrent() | 226 | bool EglWaylandBackend::makeContextCurrent(EglWaylandOutput *output) | ||
148 | { | 227 | { | ||
149 | if (eglMakeCurrent(eglDisplay(), surface(), surface(), context()) == EGL_FALSE) { | 228 | const EGLSurface eglSurface = output->m_eglSurface; | ||
229 | if (eglSurface == EGL_NO_SURFACE) { | ||||
230 | return false; | ||||
231 | } | ||||
232 | if (eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, context()) == EGL_FALSE) { | ||||
150 | qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed"; | 233 | qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed"; | ||
151 | return false; | 234 | return false; | ||
152 | } | 235 | } | ||
153 | 236 | | |||
154 | EGLint error = eglGetError(); | 237 | EGLint error = eglGetError(); | ||
155 | if (error != EGL_SUCCESS) { | 238 | if (error != EGL_SUCCESS) { | ||
156 | qCWarning(KWIN_WAYLAND_BACKEND) << "Error occurred while creating context " << error; | 239 | qCWarning(KWIN_WAYLAND_BACKEND) << "Error occurred while creating context " << error; | ||
157 | return false; | 240 | return false; | ||
158 | } | 241 | } | ||
242 | | ||||
243 | const QRect &v = output->m_waylandOutput->geometry(); | ||||
I don't think that's true anymore. I did lots of fixes to it. davidedmundson: I don't think that's true anymore. I did lots of fixes to it.
We can remove that comment | |||||
244 | | ||||
davidedmundson: Use of temporary values is weird. | |||||
245 | qreal scale = output->m_waylandOutput->scale(); | ||||
246 | | ||||
247 | const QSize overall = screens()->size(); | ||||
248 | glViewport(-v.x() * scale, (v.height() - overall.height() + v.y()) * scale, | ||||
249 | overall.width() * scale, overall.height() * scale); | ||||
159 | return true; | 250 | return true; | ||
160 | } | 251 | } | ||
161 | 252 | | |||
162 | bool EglWaylandBackend::initBufferConfigs() | 253 | bool EglWaylandBackend::initBufferConfigs() | ||
163 | { | 254 | { | ||
164 | const EGLint config_attribs[] = { | 255 | const EGLint config_attribs[] = { | ||
165 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | 256 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | ||
166 | EGL_RED_SIZE, 1, | 257 | EGL_RED_SIZE, 1, | ||
Show All 17 Lines | |||||
184 | } | 275 | } | ||
185 | setConfig(configs[0]); | 276 | setConfig(configs[0]); | ||
186 | 277 | | |||
187 | return true; | 278 | return true; | ||
188 | } | 279 | } | ||
189 | 280 | | |||
190 | void EglWaylandBackend::present() | 281 | void EglWaylandBackend::present() | ||
191 | { | 282 | { | ||
192 | m_wayland->surface()->setupFrameCallback(); | 283 | for (auto *output: qAsConst(m_outputs)) { | ||
284 | makeContextCurrent(output); | ||||
285 | presentOnSurface(output); | ||||
286 | } | ||||
287 | } | ||||
288 | | ||||
289 | void EglWaylandBackend::presentOnSurface(EglWaylandOutput *output) | ||||
290 | { | ||||
291 | output->m_waylandOutput->surface()->setupFrameCallback(); | ||||
romangg: `*` instead of `&`. | |||||
193 | Compositor::self()->aboutToSwapBuffers(); | 292 | Compositor::self()->aboutToSwapBuffers(); | ||
194 | 293 | | |||
195 | if (supportsBufferAge()) { | 294 | if (supportsBufferAge()) { | ||
196 | eglSwapBuffers(eglDisplay(), surface()); | 295 | eglSwapBuffers(eglDisplay(), output->m_eglSurface); | ||
197 | eglQuerySurface(eglDisplay(), surface(), EGL_BUFFER_AGE_EXT, &m_bufferAge); | 296 | eglQuerySurface(eglDisplay(), output->m_eglSurface, EGL_BUFFER_AGE_EXT, &output->m_bufferAge); | ||
198 | setLastDamage(QRegion()); | | |||
199 | return; | | |||
200 | } else { | 297 | } else { | ||
201 | eglSwapBuffers(eglDisplay(), surface()); | 298 | eglSwapBuffers(eglDisplay(), output->m_eglSurface); | ||
202 | setLastDamage(QRegion()); | | |||
203 | } | 299 | } | ||
300 | | ||||
204 | } | 301 | } | ||
205 | 302 | | |||
206 | void EglWaylandBackend::screenGeometryChanged(const QSize &size) | 303 | void EglWaylandBackend::screenGeometryChanged(const QSize &size) | ||
207 | { | 304 | { | ||
208 | Q_UNUSED(size) | 305 | Q_UNUSED(size) | ||
209 | // no backend specific code needed | 306 | // no backend specific code needed | ||
210 | // TODO: base implementation in OpenGLBackend | 307 | // TODO: base implementation in OpenGLBackend | ||
211 | 308 | | |||
212 | // The back buffer contents are now undefined | 309 | // The back buffer contents are now undefined | ||
213 | m_bufferAge = 0; | 310 | for (auto *output : qAsConst(m_outputs)) { | ||
311 | output->m_bufferAge = 0; | ||||
312 | } | ||||
davidedmundson: qAsConst
(in both places) | |||||
The vector elements are pointers. qAsConst does not have any advantage in this case. But I forgot the asterisk on the auto keyword. Maybe that's why you thought there should be qAsConst? romangg: The vector elements are pointers. qAsConst does not have any advantage in this case. But I… | |||||
We need qAsConst to prevent QVector from detaching. (m_outputs can be shared, right?) zzag: We need qAsConst to prevent QVector from detaching. (m_outputs can be shared, right?) | |||||
Container elements are only pointer values though. So the deep copy is negligible. That's what I meant. If you prefer I will add qAsConst though. romangg: Container elements are only pointer values though. So the deep copy is negligible. That's what… | |||||
214 | } | 313 | } | ||
215 | 314 | | |||
216 | SceneOpenGLTexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGLTexture *texture) | 315 | SceneOpenGLTexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGLTexture *texture) | ||
217 | { | 316 | { | ||
218 | return new EglWaylandTexture(texture, this); | 317 | return new EglWaylandTexture(texture, this); | ||
219 | } | 318 | } | ||
220 | 319 | | |||
221 | QRegion EglWaylandBackend::prepareRenderingFrame() | 320 | QRegion EglWaylandBackend::prepareRenderingFrame() | ||
222 | { | 321 | { | ||
223 | if (!lastDamage().isEmpty()) | | |||
224 | present(); | | |||
225 | QRegion repaint; | | |||
226 | if (supportsBufferAge()) | | |||
227 | repaint = accumulatedDamageHistory(m_bufferAge); | | |||
228 | eglWaitNative(EGL_CORE_NATIVE_ENGINE); | 322 | eglWaitNative(EGL_CORE_NATIVE_ENGINE); | ||
229 | startRenderTimer(); | 323 | startRenderTimer(); | ||
230 | return repaint; | 324 | return QRegion(); | ||
325 | } | ||||
326 | | ||||
327 | QRegion EglWaylandBackend::prepareRenderingForScreen(int screenId) | ||||
328 | { | ||||
329 | auto *output = m_outputs.at(screenId); | ||||
330 | makeContextCurrent(output); | ||||
331 | if (supportsBufferAge()) { | ||||
332 | QRegion region; | ||||
333 | | ||||
334 | // Note: An age of zero means the buffer contents are undefined | ||||
335 | if (output->m_bufferAge > 0 && output->m_bufferAge <= output->m_damageHistory.count()) { | ||||
336 | for (int i = 0; i < output->m_bufferAge - 1; i++) | ||||
337 | region |= output->m_damageHistory[i]; | ||||
338 | } else { | ||||
339 | region = output->m_waylandOutput->geometry(); | ||||
340 | } | ||||
341 | | ||||
342 | return region; | ||||
343 | } | ||||
344 | return QRegion(); | ||||
231 | } | 345 | } | ||
232 | 346 | | |||
233 | void EglWaylandBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) | 347 | void EglWaylandBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) | ||
234 | { | 348 | { | ||
235 | if (damagedRegion.isEmpty()) { | 349 | Q_UNUSED(renderedRegion) | ||
236 | setLastDamage(QRegion()); | 350 | Q_UNUSED(damagedRegion) | ||
351 | } | ||||
352 | | ||||
353 | void EglWaylandBackend::endRenderingFrameForScreen(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) | ||||
354 | { | ||||
355 | EglWaylandOutput *output = m_outputs[screenId]; | ||||
356 | if (damagedRegion.intersected(output->m_waylandOutput->geometry()).isEmpty() && screenId == 0) { | ||||
237 | 357 | | |||
238 | // If the damaged region of a window is fully occluded, the only | 358 | // If the damaged region of a window is fully occluded, the only | ||
239 | // rendering done, if any, will have been to repair a reused back | 359 | // rendering done, if any, will have been to repair a reused back | ||
240 | // buffer, making it identical to the front buffer. | 360 | // buffer, making it identical to the front buffer. | ||
241 | // | 361 | // | ||
242 | // In this case we won't post the back buffer. Instead we'll just | 362 | // In this case we won't post the back buffer. Instead we'll just | ||
243 | // set the buffer age to 1, so the repaired regions won't be | 363 | // set the buffer age to 1, so the repaired regions won't be | ||
244 | // rendered again in the next frame. | 364 | // rendered again in the next frame. | ||
245 | if (!renderedRegion.isEmpty()) | 365 | if (!renderedRegion.intersected(output->m_waylandOutput->geometry()).isEmpty()) { | ||
246 | glFlush(); | 366 | glFlush(); | ||
247 | | ||||
248 | m_bufferAge = 1; | | |||
249 | return; | | |||
250 | } | 367 | } | ||
251 | 368 | | |||
252 | setLastDamage(renderedRegion); | 369 | for (auto *o : qAsConst(m_outputs)) { | ||
253 | 370 | o->m_bufferAge = 1; | |||
254 | if (!blocksForRetrace()) { | 371 | } | ||
255 | // This also sets lastDamage to empty which prevents the frame from | 372 | return; | ||
256 | // being posted again when prepareRenderingFrame() is called. | | |||
257 | present(); | | |||
258 | } else { | | |||
259 | // Make sure that the GPU begins processing the command stream | | |||
260 | // now and not the next time prepareRenderingFrame() is called. | | |||
261 | glFlush(); | | |||
262 | } | 373 | } | ||
374 | presentOnSurface(output); | ||||
263 | 375 | | |||
264 | // Save the damaged region to history | 376 | // Save the damaged region to history | ||
265 | if (supportsBufferAge()) | 377 | // Note: damage history is only collected for the first screen. See EglGbmBackend | ||
266 | addToDamageHistory(damagedRegion); | 378 | // for mor information regarding this limitation. | ||
379 | if (supportsBufferAge() && screenId == 0) { | ||||
380 | if (output->m_damageHistory.count() > 10) { | ||||
381 | output->m_damageHistory.removeLast(); | ||||
267 | } | 382 | } | ||
268 | 383 | | |||
269 | void EglWaylandBackend::overlaySizeChanged(const QSize &size) | 384 | output->m_damageHistory.prepend(damagedRegion.intersected(output->m_waylandOutput->geometry())); | ||
270 | { | 385 | } | ||
271 | wl_egl_window_resize(m_overlay, size.width(), size.height(), 0, 0); | | |||
272 | } | 386 | } | ||
273 | 387 | | |||
274 | bool EglWaylandBackend::usesOverlayWindow() const | 388 | bool EglWaylandBackend::usesOverlayWindow() const | ||
275 | { | 389 | { | ||
276 | return false; | 390 | return false; | ||
277 | } | 391 | } | ||
278 | 392 | | |||
393 | bool EglWaylandBackend::perScreenRendering() const | ||||
394 | { | ||||
395 | return true; | ||||
396 | } | ||||
397 | | ||||
279 | /************************************************ | 398 | /************************************************ | ||
280 | * EglTexture | 399 | * EglTexture | ||
281 | ************************************************/ | 400 | ************************************************/ | ||
282 | 401 | | |||
283 | EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGLTexture *texture, KWin::EglWaylandBackend *backend) | 402 | EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGLTexture *texture, KWin::Wayland::EglWaylandBackend *backend) | ||
284 | : AbstractEglTexture(texture, backend) | 403 | : AbstractEglTexture(texture, backend) | ||
285 | { | 404 | { | ||
286 | } | 405 | } | ||
287 | 406 | | |||
288 | EglWaylandTexture::~EglWaylandTexture() = default; | 407 | EglWaylandTexture::~EglWaylandTexture() = default; | ||
289 | 408 | | |||
290 | } // namespace | 409 | } | ||
410 | } |
Does such extension exist?