1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qwaylandglcontext.h"
41
42#include <QtWaylandClient/private/qwaylanddisplay_p.h>
43#include <QtWaylandClient/private/qwaylandwindow_p.h>
44#include <QtWaylandClient/private/qwaylandsubsurface_p.h>
45#include <QtWaylandClient/private/qwaylandabstractdecoration_p.h>
46#include <QtWaylandClient/private/qwaylandintegration_p.h>
47#include "qwaylandeglwindow.h"
48
49#include <QDebug>
50#include <QtEglSupport/private/qeglconvenience_p.h>
51#include <QtGui/private/qopenglcontext_p.h>
52#include <QtGui/private/qopengltexturecache_p.h>
53#include <QtGui/private/qguiapplication_p.h>
54
55#include <qpa/qplatformopenglcontext.h>
56#include <QtGui/QSurfaceFormat>
57#include <QtGui/QOpenGLShaderProgram>
58#include <QtGui/QOpenGLFunctions>
59#include <QOpenGLBuffer>
60
61#include <QtCore/qmutex.h>
62
63#include <dlfcn.h>
64
65// Constants from EGL_KHR_create_context
66#ifndef EGL_CONTEXT_MINOR_VERSION_KHR
67#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
68#endif
69#ifndef EGL_CONTEXT_FLAGS_KHR
70#define EGL_CONTEXT_FLAGS_KHR 0x30FC
71#endif
72#ifndef EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR
73#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
74#endif
75#ifndef EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
76#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
77#endif
78#ifndef EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
79#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
80#endif
81#ifndef EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
82#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
83#endif
84#ifndef EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR
85#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
86#endif
87
88// Constants for OpenGL which are not available in the ES headers.
89#ifndef GL_CONTEXT_FLAGS
90#define GL_CONTEXT_FLAGS 0x821E
91#endif
92#ifndef GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
93#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
94#endif
95#ifndef GL_CONTEXT_FLAG_DEBUG_BIT
96#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
97#endif
98#ifndef GL_CONTEXT_PROFILE_MASK
99#define GL_CONTEXT_PROFILE_MASK 0x9126
100#endif
101#ifndef GL_CONTEXT_CORE_PROFILE_BIT
102#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
103#endif
104#ifndef GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
105#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
106#endif
107
108QT_BEGIN_NAMESPACE
109
110namespace QtWaylandClient {
111
112class DecorationsBlitter : public QOpenGLFunctions
113{
114public:
115 DecorationsBlitter(QWaylandGLContext *context)
116 : m_context(context)
117 {
118 initializeOpenGLFunctions();
119 m_blitProgram = new QOpenGLShaderProgram();
120 m_blitProgram->addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: "attribute vec4 position;\n\
121 attribute vec4 texCoords;\n\
122 varying vec2 outTexCoords;\n\
123 void main()\n\
124 {\n\
125 gl_Position = position;\n\
126 outTexCoords = texCoords.xy;\n\
127 }");
128 m_blitProgram->addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: "varying highp vec2 outTexCoords;\n\
129 uniform sampler2D texture;\n\
130 void main()\n\
131 {\n\
132 gl_FragColor = texture2D(texture, outTexCoords);\n\
133 }");
134
135 m_blitProgram->bindAttributeLocation(name: "position", location: 0);
136 m_blitProgram->bindAttributeLocation(name: "texCoords", location: 1);
137
138 if (!m_blitProgram->link()) {
139 qDebug() << "Shader Program link failed.";
140 qDebug() << m_blitProgram->log();
141 }
142
143 m_blitProgram->bind();
144 m_blitProgram->enableAttributeArray(location: 0);
145 m_blitProgram->enableAttributeArray(location: 1);
146
147 glDisable(GL_DEPTH_TEST);
148 glDisable(GL_BLEND);
149 glDisable(GL_CULL_FACE);
150 glDisable(GL_SCISSOR_TEST);
151 glDepthMask(GL_FALSE);
152 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
153
154 m_buffer.create();
155 m_buffer.bind();
156
157 static const GLfloat squareVertices[] = {
158 -1.f, -1.f,
159 1.0f, -1.f,
160 -1.f, 1.0f,
161 1.0f, 1.0f
162 };
163 static const GLfloat inverseSquareVertices[] = {
164 -1.f, 1.f,
165 1.f, 1.f,
166 -1.f, -1.f,
167 1.f, -1.f
168 };
169 static const GLfloat textureVertices[] = {
170 0.0f, 0.0f,
171 1.0f, 0.0f,
172 0.0f, 1.0f,
173 1.0f, 1.0f,
174 };
175
176 m_squareVerticesOffset = 0;
177 m_inverseSquareVerticesOffset = sizeof(squareVertices);
178 m_textureVerticesOffset = sizeof(squareVertices) + sizeof(textureVertices);
179
180 m_buffer.allocate(count: sizeof(squareVertices) + sizeof(inverseSquareVertices) + sizeof(textureVertices));
181 m_buffer.write(offset: m_squareVerticesOffset, data: squareVertices, count: sizeof(squareVertices));
182 m_buffer.write(offset: m_inverseSquareVerticesOffset, data: inverseSquareVertices, count: sizeof(inverseSquareVertices));
183 m_buffer.write(offset: m_textureVerticesOffset, data: textureVertices, count: sizeof(textureVertices));
184
185 m_blitProgram->setAttributeBuffer(location: 1, GL_FLOAT, offset: m_textureVerticesOffset, tupleSize: 2);
186
187 m_textureWrap = m_context->context()->functions()->hasOpenGLFeature(feature: QOpenGLFunctions::NPOTTextureRepeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE;
188 }
189 ~DecorationsBlitter()
190 {
191 delete m_blitProgram;
192 }
193 void blit(QWaylandEglWindow *window)
194 {
195 QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(context: m_context->context());
196
197 QSize surfaceSize = window->surfaceSize();
198 int scale = window->scale() ;
199 glViewport(x: 0, y: 0, width: surfaceSize.width() * scale, height: surfaceSize.height() * scale);
200
201 //Draw Decoration
202 m_blitProgram->setAttributeBuffer(location: 0, GL_FLOAT, offset: m_inverseSquareVerticesOffset, tupleSize: 2);
203 QImage decorationImage = window->decoration()->contentImage();
204 cache->bindTexture(context: m_context->context(), image: decorationImage);
205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, param: m_textureWrap);
208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, param: m_textureWrap);
209 glDrawArrays(GL_TRIANGLE_STRIP, first: 0, count: 4);
210
211 //Draw Content
212 m_blitProgram->setAttributeBuffer(location: 0, GL_FLOAT, offset: m_squareVerticesOffset, tupleSize: 2);
213 glBindTexture(GL_TEXTURE_2D, texture: window->contentTexture());
214 QRect r = window->contentsRect();
215 glViewport(x: r.x() * scale, y: r.y() * scale, width: r.width() * scale, height: r.height() * scale);
216 glDrawArrays(GL_TRIANGLE_STRIP, first: 0, count: 4);
217 }
218
219 QOpenGLShaderProgram *m_blitProgram = nullptr;
220 QWaylandGLContext *m_context = nullptr;
221 QOpenGLBuffer m_buffer;
222 int m_squareVerticesOffset;
223 int m_inverseSquareVerticesOffset;
224 int m_textureVerticesOffset;
225 int m_textureWrap;
226};
227
228
229
230QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *display, const QSurfaceFormat &format, QPlatformOpenGLContext *share)
231 : QPlatformOpenGLContext()
232 , m_eglDisplay(eglDisplay)
233 , m_display(display)
234{
235 QSurfaceFormat fmt = format;
236 if (static_cast<QWaylandIntegration *>(QGuiApplicationPrivate::platformIntegration())->display()->supportsWindowDecoration())
237 fmt.setAlphaBufferSize(8);
238 m_config = q_configFromGLFormat(display: m_eglDisplay, format: fmt);
239 m_format = q_glFormatFromConfig(display: m_eglDisplay, config: m_config, referenceFormat: fmt);
240 m_shareEGLContext = share ? static_cast<QWaylandGLContext *>(share)->eglContext() : EGL_NO_CONTEXT;
241
242 QVector<EGLint> eglContextAttrs;
243 eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION);
244 eglContextAttrs.append(t: format.majorVersion());
245 const bool hasKHRCreateContext = q_hasEglExtension(display: m_eglDisplay, extensionName: "EGL_KHR_create_context");
246 if (hasKHRCreateContext) {
247 eglContextAttrs.append(EGL_CONTEXT_MINOR_VERSION_KHR);
248 eglContextAttrs.append(t: format.minorVersion());
249 int flags = 0;
250 // The debug bit is supported both for OpenGL and OpenGL ES.
251 if (format.testOption(option: QSurfaceFormat::DebugContext))
252 flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
253 // The fwdcompat bit is only for OpenGL 3.0+.
254 if (m_format.renderableType() == QSurfaceFormat::OpenGL
255 && format.majorVersion() >= 3
256 && !format.testOption(option: QSurfaceFormat::DeprecatedFunctions))
257 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
258 if (flags) {
259 eglContextAttrs.append(EGL_CONTEXT_FLAGS_KHR);
260 eglContextAttrs.append(t: flags);
261 }
262 // Profiles are OpenGL only and mandatory in 3.2+. The value is silently ignored for < 3.2.
263 if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
264 switch (format.profile()) {
265 case QSurfaceFormat::NoProfile:
266 break;
267 case QSurfaceFormat::CoreProfile:
268 eglContextAttrs.append(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
269 eglContextAttrs.append(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
270 break;
271 case QSurfaceFormat::CompatibilityProfile:
272 eglContextAttrs.append(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
273 eglContextAttrs.append(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
274 break;
275 }
276 }
277 }
278 eglContextAttrs.append(EGL_NONE);
279
280 switch (m_format.renderableType()) {
281 case QSurfaceFormat::OpenVG:
282 m_api = EGL_OPENVG_API;
283 break;
284#ifdef EGL_VERSION_1_4
285# if !defined(QT_OPENGL_ES_2)
286 case QSurfaceFormat::DefaultRenderableType:
287# endif
288 case QSurfaceFormat::OpenGL:
289 m_api = EGL_OPENGL_API;
290 break;
291#endif
292 case QSurfaceFormat::OpenGLES:
293 default:
294 m_api = EGL_OPENGL_ES_API;
295 break;
296 }
297 eglBindAPI(api: m_api);
298
299 m_context = eglCreateContext(dpy: m_eglDisplay, config: m_config, share_context: m_shareEGLContext, attrib_list: eglContextAttrs.constData());
300
301 if (m_context == EGL_NO_CONTEXT) {
302 m_context = eglCreateContext(dpy: m_eglDisplay, config: m_config, EGL_NO_CONTEXT, attrib_list: eglContextAttrs.constData());
303 m_shareEGLContext = EGL_NO_CONTEXT;
304 }
305
306 EGLint error = eglGetError();
307 if (error != EGL_SUCCESS) {
308 qWarning(msg: "QWaylandGLContext: failed to create EGLContext, error=%x", error);
309 return;
310 }
311
312 // Create an EGL context for the decorations blitter. By using a dedicated context we don't need to make sure to not
313 // change the context state and we also use OpenGL ES 2 API independently to what the app is using to draw.
314 QVector<EGLint> eglDecorationsContextAttrs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
315 m_decorationsContext = eglCreateContext(dpy: m_eglDisplay, config: m_config, share_context: m_context, attrib_list: eglDecorationsContextAttrs.constData());
316 if (m_decorationsContext == EGL_NO_CONTEXT)
317 qWarning(msg: "QWaylandGLContext: Failed to create the decorations EGLContext. Decorations will not be drawn.");
318
319 EGLint a = EGL_MIN_SWAP_INTERVAL;
320 EGLint b = EGL_MAX_SWAP_INTERVAL;
321 if (!eglGetConfigAttrib(dpy: m_eglDisplay, config: m_config, attribute: a, value: &a) ||
322 !eglGetConfigAttrib(dpy: m_eglDisplay, config: m_config, attribute: b, value: &b) ||
323 a > 0) {
324 m_supportNonBlockingSwap = false;
325 }
326 {
327 bool ok;
328 int supportNonBlockingSwap = qEnvironmentVariableIntValue(varName: "QT_WAYLAND_FORCE_NONBLOCKING_SWAP_SUPPORT", ok: &ok);
329 if (ok)
330 m_supportNonBlockingSwap = supportNonBlockingSwap != 0;
331 }
332 if (!m_supportNonBlockingSwap) {
333 qWarning(catFunc: lcQpaWayland) << "Non-blocking swap buffers not supported."
334 << "Subsurface rendering can be affected."
335 << "It may also cause the event loop to freeze in some situations";
336 }
337
338 m_supportSurfaceLessContext = q_hasEglExtension(display: m_eglDisplay, extensionName: "EGL_KHR_surfaceless_context");
339
340 updateGLFormat();
341}
342
343void QWaylandGLContext::updateGLFormat()
344{
345 // Have to save & restore to prevent QOpenGLContext::currentContext() from becoming
346 // inconsistent after QOpenGLContext::create().
347 EGLDisplay prevDisplay = eglGetCurrentDisplay();
348 if (prevDisplay == EGL_NO_DISPLAY) // when no context is current
349 prevDisplay = m_eglDisplay;
350 EGLContext prevContext = eglGetCurrentContext();
351 EGLSurface prevSurfaceDraw = eglGetCurrentSurface(EGL_DRAW);
352 EGLSurface prevSurfaceRead = eglGetCurrentSurface(EGL_READ);
353
354 wl_surface *wlSurface = m_display->createSurface(handle: nullptr);
355 wl_egl_window *eglWindow = wl_egl_window_create(wlSurface, 1, 1);
356#if QT_CONFIG(egl_extension_platform_wayland)
357 EGLSurface eglSurface = eglCreatePlatformWindowSurface(dpy: m_eglDisplay, config: m_config, native_window: eglWindow, attrib_list: nullptr);
358#else
359 EGLSurface eglSurface = eglCreateWindowSurface(m_eglDisplay, m_config, eglWindow, nullptr);
360#endif
361
362 if (eglMakeCurrent(dpy: m_eglDisplay, draw: eglSurface, read: eglSurface, ctx: m_context)) {
363 if (m_format.renderableType() == QSurfaceFormat::OpenGL
364 || m_format.renderableType() == QSurfaceFormat::OpenGLES) {
365 const GLubyte *s = glGetString(GL_VERSION);
366 if (s) {
367 QByteArray version = QByteArray(reinterpret_cast<const char *>(s));
368 int major, minor;
369 if (QPlatformOpenGLContext::parseOpenGLVersion(versionString: version, major, minor)) {
370 m_format.setMajorVersion(major);
371 m_format.setMinorVersion(minor);
372 }
373 }
374 m_format.setProfile(QSurfaceFormat::NoProfile);
375 m_format.setOptions(QSurfaceFormat::FormatOptions());
376 if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
377 // Check profile and options.
378 if (m_format.majorVersion() < 3) {
379 m_format.setOption(option: QSurfaceFormat::DeprecatedFunctions);
380 } else {
381 GLint value = 0;
382 glGetIntegerv(GL_CONTEXT_FLAGS, params: &value);
383 if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
384 m_format.setOption(option: QSurfaceFormat::DeprecatedFunctions);
385 if (value & GL_CONTEXT_FLAG_DEBUG_BIT)
386 m_format.setOption(option: QSurfaceFormat::DebugContext);
387 if (m_format.version() >= qMakePair(x: 3, y: 2)) {
388 value = 0;
389 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, params: &value);
390 if (value & GL_CONTEXT_CORE_PROFILE_BIT)
391 m_format.setProfile(QSurfaceFormat::CoreProfile);
392 else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
393 m_format.setProfile(QSurfaceFormat::CompatibilityProfile);
394 }
395 }
396 }
397 }
398 eglMakeCurrent(dpy: prevDisplay, draw: prevSurfaceDraw, read: prevSurfaceRead, ctx: prevContext);
399 }
400 eglDestroySurface(dpy: m_eglDisplay, surface: eglSurface);
401 wl_egl_window_destroy(egl_window: eglWindow);
402 wl_surface_destroy(wlSurface);
403}
404
405QWaylandGLContext::~QWaylandGLContext()
406{
407 delete m_blitter;
408 if (m_decorationsContext != EGL_NO_CONTEXT)
409 eglDestroyContext(dpy: m_eglDisplay, ctx: m_decorationsContext);
410 eglDestroyContext(dpy: m_eglDisplay, ctx: m_context);
411}
412
413bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
414{
415 // in QWaylandGLContext() we called eglBindAPI with the correct value. However,
416 // eglBindAPI's documentation says:
417 // "eglBindAPI defines the current rendering API for EGL in the thread it is called from"
418 // Since makeCurrent() can be called from a different thread than the one we created the
419 // context in make sure to call eglBindAPI in the correct thread.
420 if (eglQueryAPI() != m_api) {
421 eglBindAPI(api: m_api);
422 }
423
424 QWaylandEglWindow *window = static_cast<QWaylandEglWindow *>(surface);
425 EGLSurface eglSurface = window->eglSurface();
426
427 if (!window->needToUpdateContentFBO() && (eglSurface != EGL_NO_SURFACE)) {
428 if (!eglMakeCurrent(dpy: m_eglDisplay, draw: eglSurface, read: eglSurface, ctx: m_context)) {
429 qWarning(msg: "QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this);
430 return false;
431 }
432 return true;
433 }
434
435 if (window->isExposed())
436 window->setCanResize(false);
437 if (m_decorationsContext != EGL_NO_CONTEXT && !window->decoration())
438 window->createDecoration();
439
440 if (eglSurface == EGL_NO_SURFACE) {
441 window->updateSurface(create: true);
442 eglSurface = window->eglSurface();
443 }
444
445 if (eglSurface == EGL_NO_SURFACE && m_supportSurfaceLessContext) {
446 return false;
447 }
448
449 if (!eglMakeCurrent(dpy: m_eglDisplay, draw: eglSurface, read: eglSurface, ctx: m_context)) {
450 qWarning(msg: "QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this);
451 window->setCanResize(true);
452 return false;
453 }
454
455 //### setCurrentContext will be called in QOpenGLContext::makeCurrent after this function
456 // returns, but that's too late, as we need a current context in order to bind the content FBO.
457 QOpenGLContextPrivate::setCurrentContext(context());
458 window->bindContentFBO();
459
460 return true;
461}
462
463void QWaylandGLContext::doneCurrent()
464{
465 eglMakeCurrent(dpy: m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
466}
467
468void QWaylandGLContext::swapBuffers(QPlatformSurface *surface)
469{
470 QWaylandEglWindow *window = static_cast<QWaylandEglWindow *>(surface);
471
472 EGLSurface eglSurface = window->eglSurface();
473
474 if (window->decoration()) {
475 if (m_api != EGL_OPENGL_ES_API)
476 eglBindAPI(EGL_OPENGL_ES_API);
477
478 // save the current EGL content and surface to set it again after the blitter is done
479 EGLDisplay currentDisplay = eglGetCurrentDisplay();
480 EGLContext currentContext = eglGetCurrentContext();
481 EGLSurface currentSurfaceDraw = eglGetCurrentSurface(EGL_DRAW);
482 EGLSurface currentSurfaceRead = eglGetCurrentSurface(EGL_READ);
483 eglMakeCurrent(dpy: m_eglDisplay, draw: eglSurface, read: eglSurface, ctx: m_decorationsContext);
484
485 if (!m_blitter)
486 m_blitter = new DecorationsBlitter(this);
487 m_blitter->blit(window);
488
489 if (m_api != EGL_OPENGL_ES_API)
490 eglBindAPI(api: m_api);
491 eglMakeCurrent(dpy: currentDisplay, draw: currentSurfaceDraw, read: currentSurfaceRead, ctx: currentContext);
492 }
493
494 int swapInterval = m_supportNonBlockingSwap ? 0 : m_format.swapInterval();
495 eglSwapInterval(dpy: m_eglDisplay, interval: swapInterval);
496 if (swapInterval == 0 && m_format.swapInterval() > 0) {
497 // Emulating a blocking swap
498 glFlush(); // Flush before waiting so we can swap more quickly when the frame event arrives
499 window->waitForFrameSync(100);
500 }
501 window->handleUpdate();
502 eglSwapBuffers(dpy: m_eglDisplay, surface: eglSurface);
503
504 window->setCanResize(true);
505}
506
507GLuint QWaylandGLContext::defaultFramebufferObject(QPlatformSurface *surface) const
508{
509 return static_cast<QWaylandEglWindow *>(surface)->contentFBO();
510}
511
512bool QWaylandGLContext::isSharing() const
513{
514 return m_shareEGLContext != EGL_NO_CONTEXT;
515}
516
517bool QWaylandGLContext::isValid() const
518{
519 return m_context != EGL_NO_CONTEXT;
520}
521
522QFunctionPointer QWaylandGLContext::getProcAddress(const char *procName)
523{
524 QFunctionPointer proc = (QFunctionPointer) eglGetProcAddress(procname: procName);
525 if (!proc)
526 proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, name: procName);
527 return proc;
528}
529
530EGLConfig QWaylandGLContext::eglConfig() const
531{
532 return m_config;
533}
534
535}
536
537QT_END_NAMESPACE
538

source code of qtwayland/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp