Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qwaylandglcontext.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
"qwaylandglcontext_p.h"
6
7
#
include
<
QtWaylandClient
/
private
/
qwaylanddisplay_p
.
h
>
8
#
include
<
QtWaylandClient
/
private
/
qwaylandwindow_p
.
h
>
9
#
include
<
QtWaylandClient
/
private
/
qwaylandsubsurface_p
.
h
>
10
#
include
<
QtWaylandClient
/
private
/
qwaylandabstractdecoration_p
.
h
>
11
#
include
<
QtWaylandClient
/
private
/
qwaylandintegration_p
.
h
>
12
#
include
"qwaylandeglwindow_p.h"
13
14
#
include
<
QDebug
>
15
#
include
<
QtGui
/
private
/
qeglconvenience_p
.
h
>
16
#
include
<
QtGui
/
private
/
qopenglcontext_p
.
h
>
17
#
include
<
QtOpenGL
/
private
/
qopengltexturecache_p
.
h
>
18
#
include
<
QtGui
/
private
/
qguiapplication_p
.
h
>
19
#
include
<
QtGui
/
private
/
qeglpbuffer_p
.
h
>
20
21
22
#
include
<
qpa
/
qplatformopenglcontext
.
h
>
23
#
include
<
QtGui
/
QSurfaceFormat
>
24
#
include
<
QtOpenGL
/
QOpenGLShaderProgram
>
25
#
include
<
QtGui
/
QOpenGLFunctions
>
26
#
include
<
QOpenGLBuffer
>
27
28
#
include
<
QtCore
/
qmutex
.
h
>
29
30
#
include
<
dlfcn
.
h
>
31
32
// Constants from EGL_KHR_create_context
33
#
ifndef
EGL_CONTEXT_MINOR_VERSION_KHR
34
#
define
EGL_CONTEXT_MINOR_VERSION_KHR
0x30FB
35
#
endif
36
#
ifndef
EGL_CONTEXT_FLAGS_KHR
37
#
define
EGL_CONTEXT_FLAGS_KHR
0x30FC
38
#
endif
39
#
ifndef
EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR
40
#
define
EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR
0x30FD
41
#
endif
42
#
ifndef
EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
43
#
define
EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
0x00000001
44
#
endif
45
#
ifndef
EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
46
#
define
EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
0x00000002
47
#
endif
48
#
ifndef
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
49
#
define
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
0x00000001
50
#
endif
51
#
ifndef
EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR
52
#
define
EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR
0x00000002
53
#
endif
54
#
ifndef
EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR
55
#
define
EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR
0x31BD
56
#
endif
57
#
ifndef
EGL_LOSE_CONTEXT_ON_RESET_KHR
58
#
define
EGL_LOSE_CONTEXT_ON_RESET_KHR
0x31BF
59
#
endif
60
#
ifndef
EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR
61
#
define
EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR
0x00000004
62
#
endif
63
64
// Constants from EGL_EXT_create_context_robustness
65
#
ifndef
EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT
66
#
define
EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT
0x30BF
67
#
endif
68
#
ifndef
EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT
69
#
define
EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT
0x3138
70
#
endif
71
#
ifndef
EGL_LOSE_CONTEXT_ON_RESET_EXT
72
#
define
EGL_LOSE_CONTEXT_ON_RESET_EXT
0x31BF
73
#
endif
74
75
// Constants for OpenGL which are not available in the ES headers.
76
#
ifndef
GL_CONTEXT_FLAGS
77
#
define
GL_CONTEXT_FLAGS
0x821E
78
#
endif
79
#
ifndef
GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
80
#
define
GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
0x0001
81
#
endif
82
#
ifndef
GL_CONTEXT_FLAG_DEBUG_BIT
83
#
define
GL_CONTEXT_FLAG_DEBUG_BIT
0x00000002
84
#
endif
85
#
ifndef
GL_CONTEXT_PROFILE_MASK
86
#
define
GL_CONTEXT_PROFILE_MASK
0x9126
87
#
endif
88
#
ifndef
GL_CONTEXT_CORE_PROFILE_BIT
89
#
define
GL_CONTEXT_CORE_PROFILE_BIT
0x00000001
90
#
endif
91
#
ifndef
GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
92
#
define
GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
0x00000002
93
#
endif
94
95
// Constants from EGL_NV_robustness_video_memory_purge
96
#
ifndef
EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
97
#
define
EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
0x334C
98
#
endif
99
100
QT_BEGIN_NAMESPACE
101
102
namespace
QtWaylandClient
{
103
104
QWaylandGLContext
::
QWaylandGLContext
()
105
:
QEGLPlatformContext
(),
106
m_api
(
EGL_OPENGL_ES_API
)
107
{
108
}
109
110
QWaylandGLContext
::
QWaylandGLContext
(
EGLDisplay
eglDisplay
,
QWaylandDisplay
*
display
,
111
const
QSurfaceFormat
&
fmt
,
QPlatformOpenGLContext
*
share
)
112
:
QEGLPlatformContext
(
fmt
,
share
,
eglDisplay
)
113
,
m_display
(
display
)
114
{
115
m_reconnectionWatcher
=
QObject
::
connect
(
m_display
, &
QWaylandDisplay
::
connected
,
116
m_display
, [
this
] {
invalidateContext
(); });
117
118
switch
(
format
().
renderableType
()) {
119
case
QSurfaceFormat
::
OpenVG
:
120
m_api
=
EGL_OPENVG_API
;
121
break
;
122
#
ifdef
EGL_VERSION_1_4
123
case
QSurfaceFormat
::
OpenGL
:
124
m_api
=
EGL_OPENGL_API
;
125
break
;
126
#
endif
// EGL_VERSION_1_4
127
default
:
128
m_api
=
EGL_OPENGL_ES_API
;
129
break
;
130
}
131
132
EGLint
a
=
EGL_MIN_SWAP_INTERVAL
;
133
EGLint
b
=
EGL_MAX_SWAP_INTERVAL
;
134
if
(!
eglGetConfigAttrib
(
eglDisplay
,
eglConfig
(),
a
, &
a
)
135
|| !
eglGetConfigAttrib
(
eglDisplay
,
eglConfig
(),
b
, &
b
) ||
a
> 0) {
136
m_supportNonBlockingSwap
=
false
;
137
}
138
{
139
bool
ok
;
140
int
supportNonBlockingSwap
=
qEnvironmentVariableIntValue
(
"QT_WAYLAND_FORCE_NONBLOCKING_SWAP_SUPPORT"
, &
ok
);
141
if
(
ok
)
142
m_supportNonBlockingSwap
=
supportNonBlockingSwap
!= 0;
143
}
144
if
(!
m_supportNonBlockingSwap
) {
145
qCWarning
(
lcQpaWayland
) <<
"Non-blocking swap buffers not supported."
146
<<
"Subsurface rendering can be affected."
147
<<
"It may also cause the event loop to freeze in some situations"
;
148
}
149
}
150
151
EGLSurface
QWaylandGLContext
::
createTemporaryOffscreenSurface
()
152
{
153
m_wlSurface
=
m_display
->
createSurface
(
nullptr
);
154
m_eglWindow
=
wl_egl_window_create
(
m_wlSurface
, 1, 1);
155
#
if
QT_CONFIG
(
egl_extension_platform_wayland
)
156
EGLSurface
eglSurface
=
157
eglCreatePlatformWindowSurface
(
eglDisplay
(),
eglConfig
(),
m_eglWindow
,
nullptr
);
158
#
else
159
EGLSurface
eglSurface
=
eglCreateWindowSurface
(
eglDisplay
(),
eglConfig
(),
m_eglWindow
,
nullptr
);
160
#
endif
161
return
eglSurface
;
162
}
163
164
void
QWaylandGLContext
::
destroyTemporaryOffscreenSurface
(
EGLSurface
eglSurface
)
165
{
166
eglDestroySurface
(
eglDisplay
(),
eglSurface
);
167
wl_egl_window_destroy
(
m_eglWindow
);
168
m_eglWindow
=
nullptr
;
169
wl_surface_destroy
(
m_wlSurface
);
170
m_wlSurface
=
nullptr
;
171
}
172
173
void
QWaylandGLContext
::
runGLChecks
()
174
{
175
bool
ok
;
176
const
int
doneCurrentWorkAround
=
qEnvironmentVariableIntValue
(
"QT_WAYLAND_ENABLE_DONECURRENT_WORKAROUND"
, &
ok
);
177
if
(
ok
) {
178
m_doneCurrentWorkAround
=
doneCurrentWorkAround
!= 0;
179
if
(
m_doneCurrentWorkAround
)
180
qCDebug
(
lcQpaWayland
) <<
"Enabling doneCurrent() workaround on request."
;
181
else
182
qCDebug
(
lcQpaWayland
) <<
"Disabling doneCurrent() workaround on request."
;
183
184
}
else
{
185
// Note that even though there is an EGL context current here,
186
// QOpenGLContext and QOpenGLFunctions are not yet usable at this stage.
187
const
char
*
renderer
=
reinterpret_cast
<
const
char
*>(
glGetString
(
GL_RENDERER
));
188
if
(
renderer
&&
strstr
(
renderer
,
"Mali"
)) {
189
qCDebug
(
lcQpaWayland
) <<
"Enabling doneCurrent() workaround for Mali GPU."
190
<<
"Set QT_WAYLAND_ENABLE_DONECURRENT_WORKAROUND=0 to disable."
;
191
m_doneCurrentWorkAround
=
true
;
192
}
193
}
194
195
QEGLPlatformContext
::
runGLChecks
();
196
}
197
198
QWaylandGLContext
::~
QWaylandGLContext
()
199
{
200
QObject
::
disconnect
(
m_reconnectionWatcher
);
201
}
202
203
void
QWaylandGLContext
::
beginFrame
()
204
{
205
if
(!
m_currentWindow
)
206
return
;
207
208
if
(
m_supportNonBlockingSwap
)
209
m_currentWindow
->
beginFrame
();
210
}
211
212
void
QWaylandGLContext
::
endFrame
()
213
{
214
if
(!
m_currentWindow
)
215
return
;
216
217
QWaylandEglWindow
*
currentWindow
=
m_currentWindow
;
218
219
if
(
m_doneCurrentWorkAround
) {
220
doneCurrent
();
221
QOpenGLContextPrivate
::
setCurrentContext
(
nullptr
);
222
}
223
224
if
(
m_supportNonBlockingSwap
)
225
currentWindow
->
endFrame
();
226
}
227
228
bool
QWaylandGLContext
::
makeCurrent
(
QPlatformSurface
*
surface
)
229
{
230
if
(!
isValid
()) {
231
return
false
;
232
}
233
234
if
(
surface
->
surface
()->
surfaceClass
() ==
QSurface
::
Offscreen
) {
235
m_currentWindow
=
nullptr
;
236
return
QEGLPlatformContext
::
makeCurrent
(
surface
);
237
}
238
239
// in QWaylandGLContext() we called eglBindAPI with the correct value. However,
240
// eglBindAPI's documentation says:
241
// "eglBindAPI defines the current rendering API for EGL in the thread it is called from"
242
// Since makeCurrent() can be called from a different thread than the one we created the
243
// context in make sure to call eglBindAPI in the correct thread.
244
if
(
eglQueryAPI
() !=
m_api
) {
245
eglBindAPI
(
m_api
);
246
}
247
248
m_currentWindow
=
static_cast
<
QWaylandEglWindow
*>(
surface
);
249
250
QMutexLocker
lock
(
m_currentWindow
->
eglSurfaceLock
());
251
252
EGLSurface
eglSurface
=
m_currentWindow
->
eglSurface
();
253
QSize
size
=
m_currentWindow
->
bufferSize
();
254
255
if
(
eglSurface
==
EGL_NO_SURFACE
) {
256
m_currentWindow
->
createSurface
(
size
);
257
eglSurface
=
m_currentWindow
->
eglSurface
();
258
}
259
260
if
(!
eglMakeCurrent
(
eglDisplay
(),
eglSurface
,
eglSurface
,
eglContext
())) {
261
qWarning
(
"QWaylandGLContext::makeCurrent: eglError: %#x, this: %p \n"
,
eglGetError
(),
this
);
262
return
false
;
263
}
264
if
(!
checkGraphicsReset
())
265
return
false
;
266
267
// Nvidia requires that the surface is current and on the render thread at the time of doing the actual resizing
268
m_currentWindow
->
updateSurfaceSize
(
size
);
269
return
true
;
270
}
271
272
void
QWaylandGLContext
::
doneCurrent
()
273
{
274
m_currentWindow
=
nullptr
;
275
eglMakeCurrent
(
eglDisplay
(),
EGL_NO_SURFACE
,
EGL_NO_SURFACE
,
EGL_NO_CONTEXT
);
276
}
277
278
void
QWaylandGLContext
::
swapBuffers
(
QPlatformSurface
*
surface
)
279
{
280
if
(
surface
->
surface
()->
surfaceClass
() ==
QSurface
::
Offscreen
) {
281
return
QEGLPlatformContext
::
swapBuffers
(
surface
);
282
}
283
284
QWaylandEglWindow
*
window
=
static_cast
<
QWaylandEglWindow
*>(
surface
);
285
286
EGLSurface
eglSurface
=
window
->
eglSurface
();
287
288
int
swapInterval
=
m_supportNonBlockingSwap
? 0 :
format
().
swapInterval
();
289
eglSwapInterval
(
eglDisplay
(),
swapInterval
);
290
if
(
swapInterval
== 0 &&
format
().
swapInterval
() > 0) {
291
// Emulating a blocking swap
292
glFlush
();
// Flush before waiting so we can swap more quickly when the frame event arrives
293
window
->
waitForFrameSync
(100);
294
}
295
window
->
handleUpdate
();
296
if
(!
eglSwapBuffers
(
eglDisplay
(),
eglSurface
))
297
qCWarning
(
lcQpaWayland
,
"eglSwapBuffers failed with %#x, surface: %p"
,
eglGetError
(),
eglSurface
);
298
}
299
300
EGLSurface
QWaylandGLContext
::
eglSurfaceForPlatformSurface
(
QPlatformSurface
*
surface
)
301
{
302
if
(
surface
->
surface
()->
surfaceClass
() ==
QSurface
::
Window
)
303
return
static_cast
<
QWaylandEglWindow
*>(
surface
)->
eglSurface
();
304
else
305
return
static_cast
<
QEGLPbuffer
*>(
surface
)->
pbuffer
();
306
}
307
308
}
309
310
QT_END_NAMESPACE
QtWaylandClient
Definition
qwaylandclientextension.h:16
qtbase
src
plugins
platforms
wayland
plugins
hardwareintegration
wayland-egl
qwaylandglcontext.cpp
Generated on
for Qt by
1.18.0