Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwindowsglcontext.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
4#include "qwindowsglcontext.h"
5#include "qwindowscontext.h"
6#include "qwindowswindow.h"
8
9#include <QtCore/qdebug.h>
10#include <QtCore/qsysinfo.h>
11#include <QtGui/qcolorspace.h>
12#include <QtGui/qguiapplication.h>
13#include <qpa/qplatformnativeinterface.h>
14#include <private/qsystemlibrary_p.h>
15#include <algorithm>
16
17#include <wingdi.h>
18#include <GL/gl.h>
19
20// #define DEBUG_GL
21
22// ARB extension API
23#ifndef WGL_ARB_multisample
24#define WGL_SAMPLE_BUFFERS_ARB 0x2041
25#define WGL_SAMPLES_ARB 0x2042
26#endif
27
28#ifndef WGL_ARB_pixel_format
29#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
30#define WGL_DRAW_TO_WINDOW_ARB 0x2001
31#define WGL_DRAW_TO_BITMAP_ARB 0x2002
32#define WGL_ACCELERATION_ARB 0x2003
33#define WGL_NEED_PALETTE_ARB 0x2004
34#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
35#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
36#define WGL_SWAP_METHOD_ARB 0x2007
37#define WGL_NUMBER_OVERLAYS_ARB 0x2008
38#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
39#define WGL_TRANSPARENT_ARB 0x200A
40#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
41#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
42#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
43#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
44#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
45#define WGL_SHARE_DEPTH_ARB 0x200C
46#define WGL_SHARE_STENCIL_ARB 0x200D
47#define WGL_SHARE_ACCUM_ARB 0x200E
48#define WGL_SUPPORT_GDI_ARB 0x200F
49#define WGL_SUPPORT_OPENGL_ARB 0x2010
50#define WGL_DOUBLE_BUFFER_ARB 0x2011
51#define WGL_STEREO_ARB 0x2012
52#define WGL_PIXEL_TYPE_ARB 0x2013
53#define WGL_COLOR_BITS_ARB 0x2014
54#define WGL_RED_BITS_ARB 0x2015
55#define WGL_RED_SHIFT_ARB 0x2016
56#define WGL_GREEN_BITS_ARB 0x2017
57#define WGL_GREEN_SHIFT_ARB 0x2018
58#define WGL_BLUE_BITS_ARB 0x2019
59#define WGL_BLUE_SHIFT_ARB 0x201A
60#define WGL_ALPHA_BITS_ARB 0x201B
61#define WGL_ALPHA_SHIFT_ARB 0x201C
62#define WGL_ACCUM_BITS_ARB 0x201D
63#define WGL_ACCUM_RED_BITS_ARB 0x201E
64#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
65#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
66#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
67#define WGL_DEPTH_BITS_ARB 0x2022
68#define WGL_STENCIL_BITS_ARB 0x2023
69#define WGL_AUX_BUFFERS_ARB 0x2024
70#define WGL_NO_ACCELERATION_ARB 0x2025
71#define WGL_GENERIC_ACCELERATION_ARB 0x2026
72#define WGL_FULL_ACCELERATION_ARB 0x2027
73#define WGL_SWAP_EXCHANGE_ARB 0x2028
74#define WGL_SWAP_COPY_ARB 0x2029
75#define WGL_SWAP_UNDEFINED_ARB 0x202A
76#define WGL_TYPE_RGBA_ARB 0x202B
77#define WGL_TYPE_COLORINDEX_ARB 0x202C
78#endif
79
80#ifndef WGL_ARB_create_context
81#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
82#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
83#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
84#define WGL_CONTEXT_FLAGS_ARB 0x2094
85#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
86#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
87#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
88#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001
89#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x0002
90// Error codes returned by GetLastError().
91#define ERROR_INVALID_VERSION_ARB 0x2095
92#define ERROR_INVALID_PROFILE_ARB 0x2096
93#endif
94
95#ifndef GL_VERSION_3_2
96#define GL_CONTEXT_PROFILE_MASK 0x9126
97#define GL_MAJOR_VERSION 0x821B
98#define GL_MINOR_VERSION 0x821C
99#define GL_NUM_EXTENSIONS 0x821D
100#define GL_CONTEXT_FLAGS 0x821E
101#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
102#endif
103
104#ifndef GL_CONTEXT_FLAG_DEBUG_BIT
105#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
106#endif
107
108// Common GL and WGL constants
109#define RESET_NOTIFICATION_STRATEGY_ARB 0x8256
110#define LOSE_CONTEXT_ON_RESET_ARB 0x8252
111
112#ifndef WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT
113#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9
114#endif
115
117
119
120QFunctionPointer QWindowsOpengl32DLL::resolve(const char *name)
121{
122 return m_lib
123 ? reinterpret_cast<QFunctionPointer>(::GetProcAddress(m_lib, name))
124 : nullptr;
125}
126
127bool QWindowsOpengl32DLL::init(bool softwareRendering)
128{
129 const QByteArray opengl32 = QByteArrayLiteral("opengl32");
130 const QByteArray swopengl = QByteArrayLiteral("opengl32sw");
131 bool useSystemLib = false;
132
133 QByteArray openglDll = qgetenv("QT_OPENGL_DLL");
134 if (openglDll.isEmpty()) {
135 openglDll = softwareRendering ? swopengl : opengl32;
136 useSystemLib = !softwareRendering;
137 }
138
139 openglDll = openglDll.toLower();
140 m_nonOpengl32 = openglDll != opengl32;
141
142 qCDebug(lcQpaGl) << "Qt: Using WGL and OpenGL from" << openglDll;
143
144 if (useSystemLib)
145 m_lib = QSystemLibrary::load((wchar_t*)(QString::fromLatin1(openglDll).utf16()));
146 else
147 m_lib = LoadLibraryA(openglDll.constData());
148 if (!m_lib) {
149 qErrnoWarning(::GetLastError(), "Failed to load %s", openglDll.constData());
150 return false;
151 }
152
153 if (moduleIsNotOpengl32()) {
154 // Load opengl32.dll always. GDI functions like ChoosePixelFormat do
155 // GetModuleHandle for opengl32.dll and behave differently (and call back into
156 // opengl32) when the module is present. This is fine for dummy contexts and windows.
157 QSystemLibrary::load(L"opengl32");
158 }
159
160 wglCreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(resolve("wglCreateContext"));
161 wglDeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(resolve("wglDeleteContext"));
162 wglGetCurrentContext = reinterpret_cast<HGLRC (WINAPI *)()>(resolve("wglGetCurrentContext"));
163 wglGetCurrentDC = reinterpret_cast<HDC (WINAPI *)()>(resolve("wglGetCurrentDC"));
164 wglGetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(resolve("wglGetProcAddress"));
165 wglMakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(resolve("wglMakeCurrent"));
166 wglShareLists = reinterpret_cast<BOOL (WINAPI *)(HGLRC, HGLRC)>(resolve("wglShareLists"));
167 wglSwapBuffers = reinterpret_cast<BOOL (WINAPI *)(HDC)>(resolve("wglSwapBuffers"));
168 wglSetPixelFormat = reinterpret_cast<BOOL (WINAPI *)(HDC, int, const PIXELFORMATDESCRIPTOR *)>(resolve("wglSetPixelFormat"));
169 wglDescribePixelFormat = reinterpret_cast<int (WINAPI *)(HDC, int, UINT, PIXELFORMATDESCRIPTOR *)>(resolve("wglDescribePixelFormat"));
170
171 glGetError = reinterpret_cast<GLenum (APIENTRY *)()>(resolve("glGetError"));
172 glGetIntegerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint *)>(resolve("glGetIntegerv"));
173 glGetString = reinterpret_cast<const GLubyte * (APIENTRY *)(GLenum )>(resolve("glGetString"));
174
175 return wglCreateContext && glGetError && glGetString;
176}
177
179{
180 return moduleIsNotOpengl32() ? wglSwapBuffers(dc) : SwapBuffers(dc);
181}
182
183BOOL QWindowsOpengl32DLL::setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd)
184{
185 return moduleIsNotOpengl32() ? wglSetPixelFormat(dc, pf, pfd) : SetPixelFormat(dc, pf, pfd);
186}
187
188int QWindowsOpengl32DLL::describePixelFormat(HDC dc, int pf, UINT size, PIXELFORMATDESCRIPTOR *pfd)
189{
190 return moduleIsNotOpengl32() ? wglDescribePixelFormat(dc, pf, size, pfd) : DescribePixelFormat(dc, pf, size, pfd);
191}
192
197
202
203template <class MaskType, class FlagType> inline bool testFlag(MaskType mask, FlagType flag)
204{
205 return (mask & MaskType(flag)) != 0;
206}
207
208static inline bool hasGLOverlay(const PIXELFORMATDESCRIPTOR &pd)
209{ return (pd.bReserved & 0x0f) != 0; }
210
211static inline bool isDirectRendering(const PIXELFORMATDESCRIPTOR &pfd)
212{ return (pfd.dwFlags & PFD_GENERIC_ACCELERATED) || !(pfd.dwFlags & PFD_GENERIC_FORMAT); }
213
214static inline void initPixelFormatDescriptor(PIXELFORMATDESCRIPTOR *d)
215{
216 memset(d, 0, sizeof(PIXELFORMATDESCRIPTOR));
217 d->nSize = sizeof(PIXELFORMATDESCRIPTOR);
218 d->nVersion = 1;
219}
220
221#ifndef QT_NO_DEBUG_STREAM
222QDebug operator<<(QDebug d, const PIXELFORMATDESCRIPTOR &pd)
223{
224 QDebugStateSaver saver(d);
225 d.nospace();
226 d << "PIXELFORMATDESCRIPTOR "
227 << "dwFlags=" << Qt::hex << Qt::showbase << pd.dwFlags << Qt::dec << Qt::noshowbase;
228 if (pd.dwFlags & PFD_DRAW_TO_WINDOW) d << " PFD_DRAW_TO_WINDOW";
229 if (pd.dwFlags & PFD_DRAW_TO_BITMAP) d << " PFD_DRAW_TO_BITMAP";
230 if (pd.dwFlags & PFD_SUPPORT_GDI) d << " PFD_SUPPORT_GDI";
231 if (pd.dwFlags & PFD_SUPPORT_OPENGL) d << " PFD_SUPPORT_OPENGL";
232 if (pd.dwFlags & PFD_GENERIC_ACCELERATED) d << " PFD_GENERIC_ACCELERATED";
233 if (pd.dwFlags & PFD_SUPPORT_DIRECTDRAW) d << " PFD_SUPPORT_DIRECTDRAW";
234 if (pd.dwFlags & PFD_DIRECT3D_ACCELERATED) d << " PFD_DIRECT3D_ACCELERATED";
235 if (pd.dwFlags & PFD_SUPPORT_COMPOSITION) d << " PFD_SUPPORT_COMPOSITION";
236 if (pd.dwFlags & PFD_GENERIC_FORMAT) d << " PFD_GENERIC_FORMAT";
237 if (pd.dwFlags & PFD_NEED_PALETTE) d << " PFD_NEED_PALETTE";
238 if (pd.dwFlags & PFD_NEED_SYSTEM_PALETTE) d << " PFD_NEED_SYSTEM_PALETTE";
239 if (pd.dwFlags & PFD_DOUBLEBUFFER) d << " PFD_DOUBLEBUFFER";
240 if (pd.dwFlags & PFD_STEREO) d << " PFD_STEREO";
241 if (pd.dwFlags & PFD_SWAP_LAYER_BUFFERS) d << " PFD_SWAP_LAYER_BUFFERS";
242 if (hasGLOverlay(pd)) d << " overlay";
243 d << " iPixelType=" << pd.iPixelType << " cColorBits=" << pd.cColorBits
244 << " cRedBits=" << pd.cRedBits << " cRedShift=" << pd.cRedShift
245 << " cGreenBits=" << pd.cGreenBits << " cGreenShift=" << pd.cGreenShift
246 << " cBlueBits=" << pd.cBlueBits << " cBlueShift=" << pd.cBlueShift;
247 d << " cDepthBits=" << pd.cDepthBits;
248 if (pd.cStencilBits)
249 d << " cStencilBits=" << pd.cStencilBits;
250 if (pd.cAuxBuffers)
251 d << " cAuxBuffers=" << pd.cAuxBuffers;
252 d << " iLayerType=" << pd.iLayerType;
253 if (pd.dwVisibleMask)
254 d << " dwVisibleMask=" << pd.dwVisibleMask;
255 if (pd.cAlphaBits)
256 d << " cAlphaBits=" << pd.cAlphaBits << " cAlphaShift=" << pd.cAlphaShift;
257 if (pd.cAccumBits)
258 d << " cAccumBits=" << pd.cAccumBits << " cAccumRedBits=" << pd.cAccumRedBits
259 << " cAccumGreenBits=" << pd.cAccumGreenBits << " cAccumBlueBits=" << pd.cAccumBlueBits
260 << " cAccumAlphaBits=" << pd.cAccumAlphaBits;
261 return d;
262}
263
265{
266 QDebugStateSaver saver(d);
267 d.nospace();
268 d << "OpenGL: " << s.vendor << ',' << s.renderer << " default "
269 << s.defaultFormat;
270 if (s.extensions & QOpenGLStaticContext::SampleBuffers)
271 d << ",SampleBuffers";
272 if (s.hasExtensions())
273 d << ", Extension-API present";
274 d << "\nExtensions: " << (s.extensionNames.count(' ') + 1);
276 d << s.extensionNames;
277 return d;
278}
279
281{
282 QDebugStateSaver saver(d);
283 d.nospace();
284 d << "ContextFormat: v" << (f.version >> 8) << '.' << (f.version & 0xFF)
285 << " profile: " << f.profile << " options: " << f.options;
286 return d;
287}
288#endif // !QT_NO_DEBUG_STREAM
289
290// Check whether an obtained PIXELFORMATDESCRIPTOR matches the request.
291static inline bool
293 const PIXELFORMATDESCRIPTOR &pfd,
294 bool ignoreGLSupport = false) // ARB format may not contain it.
295{
296 const bool pixmapRequested = testFlag(additional.formatFlags, QWindowsGLRenderToPixmap);
297 const bool pixmapOk = !pixmapRequested || testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP);
298 const bool colorOk = !pixmapRequested || pfd.cColorBits == additional.pixmapDepth;
299 const bool glOk = ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL);
300 const bool overlayOk = hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay);
301 return pixmapOk && glOk && overlayOk && colorOk;
302}
303
304static void describeFormats(HDC hdc)
305{
306 const int pfiMax = QOpenGLStaticContext::opengl32.describePixelFormat(hdc, 0, 0, nullptr);
307 for (int i = 1; i <= pfiMax; i++) {
308 PIXELFORMATDESCRIPTOR pfd;
310 QOpenGLStaticContext::opengl32.describePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
311 qCDebug(lcQpaGl) << '#' << i << '/' << pfiMax << ':' << pfd;
312 }
313}
314
315// Classic GDI API
316namespace GDI {
317static QSurfaceFormat
318 qSurfaceFormatFromPixelFormat(const PIXELFORMATDESCRIPTOR &pfd,
319 QWindowsOpenGLAdditionalFormat *additionalIn = nullptr)
320{
323 if (pfd.dwFlags & PFD_DOUBLEBUFFER)
324 format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
325 format.setDepthBufferSize(pfd.cDepthBits);
326
327 if (pfd.iPixelType == PFD_TYPE_RGBA)
328 format.setAlphaBufferSize(pfd.cAlphaBits);
329 format.setRedBufferSize(pfd.cRedBits);
330 format.setGreenBufferSize(pfd.cGreenBits);
331 format.setBlueBufferSize(pfd.cBlueBits);
332 format.setStencilBufferSize(pfd.cStencilBits);
333 format.setStereo(pfd.dwFlags & PFD_STEREO);
334 if (additionalIn) {
336 if (isDirectRendering(pfd))
338 if (hasGLOverlay(pfd))
339 additional.formatFlags |= QWindowsGLOverlay;
340 if (pfd.cAccumRedBits)
341 additional.formatFlags |= QWindowsGLAccumBuffer;
342 if (testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP)) {
343 additional.formatFlags |= QWindowsGLRenderToPixmap;
344 additional.pixmapDepth = pfd.cColorBits;
345 }
346 *additionalIn = additional;
347 }
348 return format;
349}
350
351static PIXELFORMATDESCRIPTOR
353 const QWindowsOpenGLAdditionalFormat &additional)
354{
355 PIXELFORMATDESCRIPTOR pfd;
357 pfd.iPixelType = PFD_TYPE_RGBA;
358 pfd.iLayerType = PFD_MAIN_PLANE;
359 pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_SUPPORT_COMPOSITION;
360 const bool isPixmap = (additional.formatFlags & QWindowsGLRenderToPixmap) != 0;
361 pfd.dwFlags |= isPixmap ? PFD_DRAW_TO_BITMAP : PFD_DRAW_TO_WINDOW;
362 if (!(additional.formatFlags & QWindowsGLDirectRendering))
363 pfd.dwFlags |= PFD_GENERIC_FORMAT;
364
365 if (format.stereo())
366 pfd.dwFlags |= PFD_STEREO;
367 if (format.swapBehavior() != QSurfaceFormat::SingleBuffer && !isPixmap)
368 pfd.dwFlags |= PFD_DOUBLEBUFFER;
369 pfd.cDepthBits =
370 format.depthBufferSize() >= 0 ? format.depthBufferSize() : 32;
371 const int redBufferSize = format.redBufferSize();
372 if (redBufferSize != -1)
373 pfd.cRedBits = BYTE(redBufferSize);
374 const int greenBufferSize = format.greenBufferSize();
375 if (greenBufferSize != -1)
376 pfd.cGreenBits = BYTE(greenBufferSize);
377 const int blueBufferSize = format.blueBufferSize();
378 if (blueBufferSize != -1)
379 pfd.cBlueBits = BYTE(blueBufferSize);
380 pfd.cAlphaBits = format.alphaBufferSize() > 0 ? format.alphaBufferSize() : 8;
381 pfd.cStencilBits = format.stencilBufferSize() > 0 ? format.stencilBufferSize() : 8;
382 if (additional.formatFlags & QWindowsGLAccumBuffer)
383 pfd.cAccumRedBits = pfd.cAccumGreenBits = pfd.cAccumBlueBits = pfd.cAccumAlphaBits = 16;
384 return pfd;
385}
386
387// Choose a suitable pixelformat using GDI WinAPI in case ARB
388// functions cannot be found. First tries to find a suitable
389// format using GDI function ChoosePixelFormat(). Since that
390// does not handle overlay and direct-rendering requests, manually loop
391// over the available formats to find the best one.
392// Note: As of Windows 7, it seems direct-rendering is handled, so,
393// the code might be obsolete?
394//
395// NB! When using an implementation with a name different than opengl32.dll
396// this code path should not be used since it will result in a mess due to GDI
397// relying on and possibly calling back into functions in opengl32.dll (and not
398// the one we are using). This is not a problem usually since for Mesa, which
399// we are most likely to ship with a name other than opengl32.dll, the ARB code
400// path should work. Hence the early bail out below.
401//
402static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format,
403 const QWindowsOpenGLAdditionalFormat &additional,
404 PIXELFORMATDESCRIPTOR *obtainedPfd)
405{
406 if (QOpenGLStaticContext::opengl32.moduleIsNotOpengl32()) {
407 qWarning("Attempted to use GDI functions with a non-opengl32.dll library");
408 return 0;
409 }
410
411 // 1) Try ChoosePixelFormat().
412 PIXELFORMATDESCRIPTOR requestedPfd = qPixelFormatFromSurfaceFormat(format, QWindowsGLDirectRendering);
413 initPixelFormatDescriptor(obtainedPfd);
414 int pixelFormat = ChoosePixelFormat(hdc, &requestedPfd);
415 if (pixelFormat >= 0) {
416 DescribePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd);
417 if (isAcceptableFormat(additional, *obtainedPfd))
418 return pixelFormat;
419 }
420 // 2) No matching format found, manual search loop.
421 const int pfiMax = DescribePixelFormat(hdc, 0, 0, nullptr);
422 int bestScore = -1;
423 int bestPfi = -1;
424 const bool stereoRequested = format.stereo();
425 const bool accumBufferRequested = testFlag(additional.formatFlags, QWindowsGLAccumBuffer);
426 const bool doubleBufferRequested = format.swapBehavior() == QSurfaceFormat::DoubleBuffer;
427 const bool directRenderingRequested = testFlag(additional.formatFlags, QWindowsGLDirectRendering);
428 for (int pfi = 1; pfi <= pfiMax; pfi++) {
429 PIXELFORMATDESCRIPTOR checkPfd;
430 initPixelFormatDescriptor(&checkPfd);
431 DescribePixelFormat(hdc, pfi, sizeof(PIXELFORMATDESCRIPTOR), &checkPfd);
432 if (isAcceptableFormat(additional, checkPfd)) {
433 int score = checkPfd.cColorBits + checkPfd.cAlphaBits + checkPfd.cStencilBits;
434 if (accumBufferRequested)
435 score += checkPfd.cAccumBits;
436 if (doubleBufferRequested == testFlag(checkPfd.dwFlags, PFD_DOUBLEBUFFER))
437 score += 1000;
438 if (stereoRequested == testFlag(checkPfd.dwFlags, PFD_STEREO))
439 score += 2000;
440 if (directRenderingRequested == isDirectRendering(checkPfd))
441 score += 4000;
442 if (checkPfd.iPixelType == PFD_TYPE_RGBA)
443 score += 8000;
444 if (score > bestScore) {
445 bestScore = score;
446 bestPfi = pfi;
447 *obtainedPfd = checkPfd;
448 }
449 qCDebug(lcQpaGl) << __FUNCTION__ << " checking " << pfi << '/' << pfiMax
450 << " score=" << score << " (best " << bestPfi << '/' << bestScore << ") " << checkPfd;
451 }
452 } // for
453 if (bestPfi > 0)
454 pixelFormat = bestPfi;
455 return pixelFormat;
456}
457
458static inline HGLRC createContext(HDC hdc, HGLRC shared)
459{
460 HGLRC result = QOpenGLStaticContext::opengl32.wglCreateContext(hdc);
461 if (!result) {
462 qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__);
463 return nullptr;
464 }
465 if (shared && !QOpenGLStaticContext::opengl32.wglShareLists(shared, result))
466 qErrnoWarning("%s: wglShareLists() failed.", __FUNCTION__);
467 return result;
468}
469} // namespace GDI
470
471// ARB OpenGL extension API
472namespace ARB {
473// Choose a suitable pixelformat using ARB extension functions.
474static int choosePixelFormat(HDC hdc,
475 const QOpenGLStaticContext &staticContext,
476 const QSurfaceFormat &format,
477 const QWindowsOpenGLAdditionalFormat &additional,
478 PIXELFORMATDESCRIPTOR *obtainedPfd)
479{
480 enum { attribSize = 42 };
481 if ((additional.formatFlags & QWindowsGLRenderToPixmap) || !staticContext.hasExtensions())
482 return 0;
483
484 int iAttributes[attribSize];
485 std::fill(iAttributes, iAttributes + attribSize, int(0));
486 int i = 0;
487 iAttributes[i++] = WGL_ACCELERATION_ARB;
488 iAttributes[i++] = testFlag(additional.formatFlags, QWindowsGLDirectRendering) ?
490 iAttributes[i++] = WGL_SUPPORT_OPENGL_ARB;
491 iAttributes[i++] = TRUE;
492 iAttributes[i++] = WGL_DRAW_TO_WINDOW_ARB;
493 iAttributes[i++] = TRUE;
494 iAttributes[i++] = WGL_COLOR_BITS_ARB;
495
496 iAttributes[i++] = (format.redBufferSize() > 0)
497 && (format.greenBufferSize() > 0)
498 && (format.blueBufferSize() > 0) ?
499 format.redBufferSize() + format.greenBufferSize() + format.blueBufferSize() :
500 24;
501 switch (format.swapBehavior()) {
503 iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB;
504 iAttributes[i++] = FALSE;
505 break;
509 iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB;
510 iAttributes[i++] = TRUE;
511 break;
512 }
513 if (format.stereo()) {
514 iAttributes[i++] = WGL_STEREO_ARB;
515 iAttributes[i++] = TRUE;
516 }
517 if (format.depthBufferSize() >= 0) {
518 iAttributes[i++] = WGL_DEPTH_BITS_ARB;
519 iAttributes[i++] = format.depthBufferSize();
520 }
521 iAttributes[i++] = WGL_PIXEL_TYPE_ARB;
522 iAttributes[i++] = WGL_TYPE_RGBA_ARB;
523 if (format.redBufferSize() >= 0) {
524 iAttributes[i++] = WGL_RED_BITS_ARB;
525 iAttributes[i++] = format.redBufferSize();
526 }
527 if (format.greenBufferSize() >= 0) {
528 iAttributes[i++] = WGL_GREEN_BITS_ARB;
529 iAttributes[i++] = format.greenBufferSize();
530 }
531 if (format.blueBufferSize() >= 0) {
532 iAttributes[i++] = WGL_BLUE_BITS_ARB;
533 iAttributes[i++] = format.blueBufferSize();
534 }
535 iAttributes[i++] = WGL_ALPHA_BITS_ARB;
536 iAttributes[i++] = format.alphaBufferSize() >= 0 ? format.alphaBufferSize() : 8;
537 if (additional.formatFlags & QWindowsGLAccumBuffer) {
538 iAttributes[i++] = WGL_ACCUM_BITS_ARB;
539 iAttributes[i++] = 16;
540 }
541 iAttributes[i++] = WGL_STENCIL_BITS_ARB;
542 iAttributes[i++] = 8;
543 if (additional.formatFlags & QWindowsGLOverlay) {
544 iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB;
545 iAttributes[i++] = 1;
546 }
547 // must be the one before the last one
548 const int samples = format.samples();
549 const bool sampleBuffersRequested = samples > 1
550 && testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers);
551 int sampleBuffersKeyPosition = 0;
552 int samplesValuePosition = 0;
553 if (sampleBuffersRequested) {
554 sampleBuffersKeyPosition = i;
555 iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB;
556 iAttributes[i++] = TRUE;
557 iAttributes[i++] = WGL_SAMPLES_ARB;
558 samplesValuePosition = i;
559 iAttributes[i++] = format.samples();
560 } else {
561 iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB;
562 iAttributes[i++] = FALSE;
563 }
564 // must be the last
565 bool srgbRequested = format.colorSpace() == QColorSpace::SRgb;
566 int srgbCapableKeyPosition = 0;
567 if (srgbRequested) {
568 srgbCapableKeyPosition = i;
569 iAttributes[i++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT;
570 iAttributes[i++] = TRUE;
571 }
572 // If sample or sRGB request cannot be satisfied, reduce request.
573 int pixelFormat = 0;
574 uint numFormats = 0;
575 while (true) {
576 const bool valid =
577 staticContext.wglChoosePixelFormatARB(hdc, iAttributes, nullptr, 1,
578 &pixelFormat, &numFormats)
579 && numFormats >= 1;
580 if (valid || (!sampleBuffersRequested && !srgbRequested))
581 break;
582 // NB reductions must be done in reverse order (disable the last first, then move on to the one before that, etc.)
583 if (srgbRequested) {
584 iAttributes[srgbCapableKeyPosition] = 0;
585 srgbRequested = false;
586 } else if (sampleBuffersRequested) {
587 if (iAttributes[samplesValuePosition] > 1) {
588 iAttributes[samplesValuePosition] /= 2;
589 } else if (iAttributes[samplesValuePosition] == 1) {
590 // Fallback in case it is unable to initialize with any
591 // samples to avoid falling back to the GDI path
592 iAttributes[sampleBuffersKeyPosition] = 0;
593 iAttributes[samplesValuePosition] = 0;
594 } else {
595 break;
596 }
597 }
598 }
599 // Verify if format is acceptable. Note that the returned
600 // formats have been observed to not contain PFD_SUPPORT_OPENGL, ignore.
601 initPixelFormatDescriptor(obtainedPfd);
602 QOpenGLStaticContext::opengl32.describePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd);
603 if (!isAcceptableFormat(additional, *obtainedPfd, true)) {
604 qCDebug(lcQpaGl) << __FUNCTION__ << " obtained px #" << pixelFormat
605 << " not acceptable=" << *obtainedPfd;
606 pixelFormat = 0;
607 }
608
609#ifndef QT_NO_DEBUG_OUTPUT
610 if (lcQpaGl().isDebugEnabled()) {
612 QDebug nsp(&message);
613 nsp << __FUNCTION__;
614 if (sampleBuffersRequested)
615 nsp << " samples=" << iAttributes[samplesValuePosition];
616 nsp << " Attributes: " << Qt::hex << Qt::showbase;
617 for (int ii = 0; ii < i; ++ii)
618 nsp << iAttributes[ii] << ',';
619 nsp << Qt::noshowbase << Qt::dec << "\n obtained px #" << pixelFormat
620 << " of " << numFormats << "\n " << *obtainedPfd;
621 qCDebug(lcQpaGl) << message;
622 } // Debug
623#endif
624
625 return pixelFormat;
626}
627
628static QSurfaceFormat
630 HDC hdc, int pixelFormat,
631 QWindowsOpenGLAdditionalFormat *additionalIn = nullptr)
632{
633 enum { attribSize = 42 };
634
637 if (!staticContext.hasExtensions())
638 return result;
639 int iAttributes[attribSize];
640 int iValues[attribSize];
641 std::fill(iAttributes, iAttributes + attribSize, int(0));
642 std::fill(iValues, iValues + attribSize, int(0));
643
644 int i = 0;
645 const bool hasSampleBuffers = testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers);
646 const bool hasSrgbSupport = testFlag(staticContext.extensions, QOpenGLStaticContext::sRGBCapableFramebuffer);
647
648 iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; // 0
649 iAttributes[i++] = WGL_DEPTH_BITS_ARB; // 1
650 iAttributes[i++] = WGL_PIXEL_TYPE_ARB; // 2
651 iAttributes[i++] = WGL_RED_BITS_ARB; // 3
652 iAttributes[i++] = WGL_GREEN_BITS_ARB; // 4
653 iAttributes[i++] = WGL_BLUE_BITS_ARB; // 5
654 iAttributes[i++] = WGL_ALPHA_BITS_ARB; // 6
655 iAttributes[i++] = WGL_ACCUM_BITS_ARB; // 7
656 iAttributes[i++] = WGL_STENCIL_BITS_ARB; // 8
657 iAttributes[i++] = WGL_STEREO_ARB; // 9
658 iAttributes[i++] = WGL_ACCELERATION_ARB; // 10
659 iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB; // 11
660 if (hasSampleBuffers) {
661 iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; // 12
662 iAttributes[i++] = WGL_SAMPLES_ARB; // 13
663 }
664 if (hasSrgbSupport)
665 iAttributes[i++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT; // 12 or 14
666
667 if (!staticContext.wglGetPixelFormatAttribIVARB(hdc, pixelFormat, 0, i,
668 iAttributes, iValues)) {
669 qErrnoWarning("%s: wglGetPixelFormatAttribIVARB() failed for basic parameters.", __FUNCTION__);
670 return result;
671 }
673 result.setDepthBufferSize(iValues[1]);
674 result.setRedBufferSize(iValues[3]);
675 result.setGreenBufferSize(iValues[4]);
676 result.setBlueBufferSize(iValues[5]);
677 result.setAlphaBufferSize(iValues[6]);
678 result.setStencilBufferSize(iValues[8]);
679 if (iValues[9])
681
682 if (hasSampleBuffers) {
683 result.setSamples(iValues[13]);
684 if (hasSrgbSupport && iValues[14])
685 result.setColorSpace(QColorSpace::SRgb);
686 } else {
687 if (hasSrgbSupport && iValues[12])
688 result.setColorSpace(QColorSpace::SRgb);
689 }
690 if (additionalIn) {
691 if (iValues[7])
692 additionalIn->formatFlags |= QWindowsGLAccumBuffer;
693 if (iValues[10] == WGL_FULL_ACCELERATION_ARB)
694 additionalIn->formatFlags |= QWindowsGLDirectRendering;
695 if (iValues[11])
696 additionalIn->formatFlags |= QWindowsGLOverlay;
697 }
698 return result;
699}
700
701static HGLRC createContext(const QOpenGLStaticContext &staticContext,
702 HDC hdc,
703 const QSurfaceFormat &format,
705 HGLRC shared = nullptr)
706{
707 enum { attribSize = 11 };
708
709 if (!staticContext.hasExtensions())
710 return nullptr;
711 int attributes[attribSize];
712 int attribIndex = 0;
713 std::fill(attributes, attributes + attribSize, int(0));
714
715 // We limit the requested version by the version of the static context as
716 // wglCreateContextAttribsARB fails and returns NULL if the requested context
717 // version is not supported. This means that we will get the closest supported
718 // context format that that which was requested and is supported by the driver
719 const int requestedVersion = qMin((format.majorVersion() << 8) + format.minorVersion(),
720 staticContext.defaultFormat.version);
721 const int majorVersion = requestedVersion >> 8;
722 const int minorVersion = requestedVersion & 0xFF;
723
724 if (requestedVersion > 0x0101) {
725 attributes[attribIndex++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
726 attributes[attribIndex++] = majorVersion;
727 attributes[attribIndex++] = WGL_CONTEXT_MINOR_VERSION_ARB;
728 attributes[attribIndex++] = minorVersion;
729 }
730
731 int flags = 0;
732 if (format.testOption(QSurfaceFormat::DebugContext))
734 if (requestedVersion >= 0x0300) {
737 }
738 attributes[attribIndex++] = WGL_CONTEXT_FLAGS_ARB;
739 attributes[attribIndex++] = flags;
740
741 if (requestedVersion >= 0x0302) {
742 switch (format.profile()) {
744 break;
746 attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB;
747 attributes[attribIndex++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
748 break;
750 attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB;
751 attributes[attribIndex++] = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
752 break;
753 }
754 }
755
757 attributes[attribIndex++] = RESET_NOTIFICATION_STRATEGY_ARB;
758 attributes[attribIndex++] = LOSE_CONTEXT_ON_RESET_ARB;
759 }
760
761 qCDebug(lcQpaGl) << __FUNCTION__ << "Creating context version"
762 << majorVersion << '.' << minorVersion << attribIndex / 2 << "attributes";
763
764 const HGLRC result =
765 staticContext.wglCreateContextAttribsARB(hdc, shared, attributes);
766 if (!result) {
768 QDebug(&message).nospace() << __FUNCTION__ << ": wglCreateContextAttribsARB() failed (GL error code: 0x"
769 << Qt::hex << staticContext.opengl32.glGetError() << Qt::dec << ") for format: " << format << ", shared context: " << shared;
771 }
772 return result;
773}
774
775} // namespace ARB
776
777// Helpers for temporary contexts
778static inline HWND createDummyGLWindow()
779{
781 createDummyWindow(QStringLiteral("OpenGLDummyWindow"),
782 L"OpenGLDummyWindow", nullptr, WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
783}
784
785// Create a dummy GL context (see QOpenGLTemporaryContext).
786static inline HGLRC createDummyGLContext(HDC dc)
787{
788 if (!dc)
789 return nullptr;
790 PIXELFORMATDESCRIPTOR pixelFormDescriptor;
791 initPixelFormatDescriptor(&pixelFormDescriptor);
792 pixelFormDescriptor.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT;
793 pixelFormDescriptor.iPixelType = PFD_TYPE_RGBA;
794 // Use the GDI variant, for the dummy this is fine, even when using something other than opengl32.dll.
795 const int pixelFormat = ChoosePixelFormat(dc, &pixelFormDescriptor);
796 if (!pixelFormat) {
797 qErrnoWarning("%s: ChoosePixelFormat failed.", __FUNCTION__);
798 return nullptr;
799 }
800 if (!QOpenGLStaticContext::opengl32.setPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) {
801 qErrnoWarning("%s: SetPixelFormat failed.", __FUNCTION__);
802 return nullptr;
803 }
804 HGLRC rc = QOpenGLStaticContext::opengl32.wglCreateContext(dc);
805 if (!rc) {
806 qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__);
807 return nullptr;
808 }
809 return rc;
810}
811
813{
815 result.hdc = QOpenGLStaticContext::opengl32.wglGetCurrentDC();
816 result.renderingContext = QOpenGLStaticContext::opengl32.wglGetCurrentContext();
817 return result;
818}
819
821{
824 result.hdc = GetDC(result.hwnd);
825 result.renderingContext = createDummyGLContext(result.hdc);
826 return result;
827}
828
840{
843 int major, minor;
845 result.version = (major << 8) + minor;
846 else
847 result.version = 0x0200;
849 if (result.version < 0x0300) {
851 return result;
852 }
853 // v3 onwards
854 GLint value = 0;
860 if (result.version < 0x0302)
861 return result;
862 // v3.2 onwards: Profiles
863 value = 0;
869 return result;
870}
871
873{
874 format->setMajorVersion(version >> 8);
875 format->setMinorVersion(version & 0xFF);
876 format->setProfile(profile);
881}
882
894{
895 Q_DISABLE_COPY_MOVE(QOpenGLTemporaryContext)
896public:
899
900private:
901 const QOpenGLContextData m_previous;
902 const QOpenGLContextData m_current;
903};
904
911
913{
914 QOpenGLStaticContext::opengl32.wglMakeCurrent(m_previous.hdc, m_previous.renderingContext);
915 ReleaseDC(m_current.hwnd, m_current.hdc);
916 DestroyWindow(m_current.hwnd);
917 QOpenGLStaticContext::opengl32.wglDeleteContext(m_current.renderingContext);
918}
919
942#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample"
943#define ROBUSTNESS_EXTENSION "GL_ARB_robustness"
944
945QOpenGLStaticContext::QOpenGLStaticContext() :
946 vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)),
948 extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)),
949 extensions(0),
950 defaultFormat(QWindowsOpenGLContextFormat::current()),
951 wglGetPixelFormatAttribIVARB(reinterpret_cast<WglGetPixelFormatAttribIVARB>(
952 reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")))),
953 wglChoosePixelFormatARB(reinterpret_cast<WglChoosePixelFormatARB>(
954 reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")))),
955 wglCreateContextAttribsARB(reinterpret_cast<WglCreateContextAttribsARB>(
956 reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")))),
957 wglSwapInternalExt(reinterpret_cast<WglSwapInternalExt>(
958 reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")))),
959 wglGetSwapInternalExt(reinterpret_cast<WglGetSwapInternalExt>(
960 reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")))),
961 wglGetExtensionsStringARB(reinterpret_cast<WglGetExtensionsStringARB>(
962 reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB"))))
963{
964 if (defaultFormat.version < 0x0300) {
965 if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
966 || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
967 extensions |= SampleBuffers;
968 if (extensionNames.startsWith(ROBUSTNESS_EXTENSION " ")
969 || extensionNames.indexOf(" " ROBUSTNESS_EXTENSION " ") != -1)
970 extensions |= Robustness;
971 } else {
972 typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint);
973 auto glGetStringi = reinterpret_cast<glGetStringi_t>(
974 reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi")));
975 if (glGetStringi) {
976 GLint n = 0;
978 for (GLint i = 0; i < n; ++i) {
979 const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
980 if (p) {
981 if (!strcmp(p, SAMPLE_BUFFER_EXTENSION))
982 extensions |= SampleBuffers;
983 else if (!strcmp(p, ROBUSTNESS_EXTENSION))
984 extensions |= Robustness;
985 }
986 }
987 }
988 }
989}
990
992{
993 if (const GLubyte *s = opengl32.glGetString(which))
994 return QByteArray(reinterpret_cast<const char*>(s));
995 return QByteArray();
996}
997
999{
1000 if (!opengl32.init(softwareRendering)) {
1001 qWarning("Failed to load and resolve WGL/OpenGL functions");
1002 return nullptr;
1003 }
1004
1005 // We need a current context for wglGetProcAdress()/getGLString() to work.
1006 QScopedPointer<QOpenGLTemporaryContext> temporaryContext;
1007 if (!QOpenGLStaticContext::opengl32.wglGetCurrentContext())
1008 temporaryContext.reset(new QOpenGLTemporaryContext);
1009 auto *result = new QOpenGLStaticContext;
1010 qCDebug(lcQpaGl) << __FUNCTION__ << *result;
1011 return result;
1012}
1013
1030 m_staticContext(staticContext)
1031{
1032 if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false.
1033 return;
1034
1036 if (format.renderableType() == QSurfaceFormat::DefaultRenderableType)
1038 if (format.renderableType() != QSurfaceFormat::OpenGL)
1039 return;
1040
1041 // workaround for matrox driver:
1042 // make a cheap call to opengl to force loading of DLL
1043 static bool opengl32dll = false;
1044 if (!opengl32dll) {
1045 GLint params;
1046 staticContext->opengl32.glGetIntegerv(GL_DEPTH_BITS, &params);
1047 opengl32dll = true;
1048 }
1049
1050 // SetPixelFormat (as of Windows 7) requires a real window.
1051 // Create a dummy one as we are not associated with a window yet.
1052 // Try to find a suitable pixel format using preferably ARB extensions
1053 // (default to GDI) and store that.
1054 HWND dummyWindow = nullptr;
1055 HDC hdc = nullptr;
1056 bool tryExtensions = false;
1057 int obtainedSwapInterval = -1;
1058 do {
1059 dummyWindow = createDummyGLWindow();
1060 if (!dummyWindow)
1061 break;
1062 hdc = GetDC(dummyWindow);
1063 if (!hdc)
1064 break;
1065
1067 describeFormats(hdc);
1068 // Preferably use direct rendering and ARB extensions (unless pixmap
1069 // or explicitly turned off on command line).
1071 requestedAdditional(QWindowsGLDirectRendering);
1072 tryExtensions = m_staticContext->hasExtensions()
1073 && !testFlag(requestedAdditional.formatFlags, QWindowsGLRenderToPixmap)
1075 QWindowsOpenGLAdditionalFormat obtainedAdditional;
1076 if (tryExtensions) {
1077 if (m_staticContext->wglGetExtensionsStringARB) {
1078 const char *exts = m_staticContext->wglGetExtensionsStringARB(hdc);
1079 if (exts) {
1080 qCDebug(lcQpaGl) << __FUNCTION__ << "WGL extensions:" << exts;
1081 if (strstr(exts, "WGL_EXT_framebuffer_sRGB"))
1083 }
1084 }
1085 m_pixelFormat =
1086 ARB::choosePixelFormat(hdc, *m_staticContext, format,
1087 requestedAdditional, &m_obtainedPixelFormatDescriptor);
1088 if (m_pixelFormat > 0) {
1089 m_obtainedFormat =
1090 ARB::qSurfaceFormatFromHDC(*m_staticContext, hdc, m_pixelFormat,
1091 &obtainedAdditional);
1092 m_extensionsUsed = true;
1093 }
1094 } // tryExtensions
1095 if (!m_pixelFormat) { // Failed, try GDI
1096 m_pixelFormat = GDI::choosePixelFormat(hdc, format, requestedAdditional,
1097 &m_obtainedPixelFormatDescriptor);
1098 if (m_pixelFormat)
1099 m_obtainedFormat =
1100 GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor,
1101 &obtainedAdditional);
1102 } // try GDI
1103 if (!m_pixelFormat) {
1104 qWarning("%s: Unable find a suitable pixel format.", __FUNCTION__);
1105 break;
1106 }
1107 if (!QOpenGLStaticContext::opengl32.setPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) {
1108 qErrnoWarning("SetPixelFormat failed.");
1109 break;
1110 }
1111 // Create context with sharing, again preferably using ARB.
1112 HGLRC sharingRenderingContext = nullptr;
1113 if (const QPlatformOpenGLContext *sc = context->shareHandle())
1114 sharingRenderingContext = static_cast<const QWindowsGLContext *>(sc)->renderingContext();
1115
1116 if (m_extensionsUsed)
1117 m_renderingContext =
1118 ARB::createContext(*m_staticContext, hdc,
1119 format,
1120 requestedAdditional,
1121 sharingRenderingContext);
1122 if (!m_renderingContext)
1123 m_renderingContext = GDI::createContext(hdc, sharingRenderingContext);
1124
1125 if (!m_renderingContext) {
1126 qWarning("Unable to create a GL Context.");
1127 break;
1128 }
1129
1130 // Query obtained parameters and apply swap interval.
1131 if (!updateObtainedParams(hdc, &obtainedSwapInterval))
1132 break;
1133
1134 } while (false);
1135
1136 if (hdc)
1137 ReleaseDC(dummyWindow, hdc);
1138 if (dummyWindow)
1139 DestroyWindow(dummyWindow);
1140
1141 qCDebug(lcQpaGl) << __FUNCTION__ << this << (tryExtensions ? "ARB" : "GDI")
1142 << " requested: " << context->format()
1143 << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI") << m_obtainedFormat
1144 << "\n " << m_obtainedPixelFormatDescriptor << " swap interval: " << obtainedSwapInterval
1145 << "\n default: " << m_staticContext->defaultFormat
1146 << "\n HGLRC=" << m_renderingContext;
1147}
1148
1149QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, HGLRC wglcontext, HWND wnd)
1150 : m_staticContext(staticContext)
1151{
1152 if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false.
1153 return;
1154
1155 HDC dc = GetDC(wnd);
1156 // A window with an associated pixel format is mandatory.
1157 // When no SetPixelFormat() call has been made, the following will fail.
1158 m_pixelFormat = GetPixelFormat(dc);
1159 bool ok = m_pixelFormat != 0;
1160 if (!ok)
1161 qWarning("QWindowsGLContext: Failed to get pixel format");
1162 ok = DescribePixelFormat(dc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_obtainedPixelFormatDescriptor);
1163 if (!ok) {
1164 qWarning("QWindowsGLContext: Failed to describe pixel format");
1165 } else {
1166 QWindowsOpenGLAdditionalFormat obtainedAdditional;
1167 m_obtainedFormat = GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor, &obtainedAdditional);
1168 m_renderingContext = wglcontext;
1169 ok = updateObtainedParams(dc);
1170 }
1171
1172 ReleaseDC(wnd, dc);
1173
1174 if (ok)
1175 m_ownsContext = false;
1176 else
1177 m_renderingContext = nullptr;
1178}
1179
1181{
1182 if (m_renderingContext && m_ownsContext)
1183 QOpenGLStaticContext::opengl32.wglDeleteContext(m_renderingContext);
1184 releaseDCs();
1185}
1186
1187bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
1188{
1189 HGLRC prevContext = QOpenGLStaticContext::opengl32.wglGetCurrentContext();
1190 HDC prevSurface = QOpenGLStaticContext::opengl32.wglGetCurrentDC();
1191
1192 if (!QOpenGLStaticContext::opengl32.wglMakeCurrent(hdc, m_renderingContext)) {
1193 qWarning("Failed to make context current.");
1194 return false;
1195 }
1196
1197 QWindowsOpenGLContextFormat::current().apply(&m_obtainedFormat);
1198
1199 if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval)
1200 *obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt();
1201
1202 if (testFlag(m_staticContext->extensions, QOpenGLStaticContext::Robustness)) {
1203 GLint value = 0;
1207 m_getGraphicsResetStatus = reinterpret_cast<GlGetGraphicsResetStatusArbType>(
1208 reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB")));
1209 }
1210
1211 QOpenGLStaticContext::opengl32.wglMakeCurrent(prevSurface, prevContext);
1212 return true;
1213}
1214
1215void QWindowsGLContext::releaseDCs()
1216{
1217 for (const auto &e : m_windowContexts)
1218 ReleaseDC(e.hwnd, e.hdc);
1219 m_windowContexts.clear();
1220}
1221
1223{
1224 return static_cast<QWindowsWindow *>(s);
1225}
1226
1227static inline HWND handleOf(QPlatformSurface *s)
1228{
1229 return glWindowOf(s)->handle();
1230}
1231
1232// Find a window in a context list.
1233static inline const QOpenGLContextData *
1234 findByHWND(const std::vector<QOpenGLContextData> &data, HWND hwnd)
1235{
1236 for (const auto &e : data) {
1237 if (e.hwnd == hwnd)
1238 return &e;
1239 }
1240 return nullptr;
1241}
1242
1244{
1246 qCDebug(lcQpaGl) << __FUNCTION__ << surface;
1247
1248 if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface)))
1249 QOpenGLStaticContext::opengl32.swapBuffers(contextData->hdc);
1250 else
1251 qWarning("%s: Cannot find window %p", __FUNCTION__, handleOf(surface));
1252}
1253
1255{
1256#ifdef DEBUG_GL
1258 qCDebug(lcQpaGl) << __FUNCTION__ << this << m_windowContexts.size() << "contexts";
1259#endif // DEBUG_GL
1260
1261 Q_ASSERT(surface->surface()->supportsOpenGL());
1262
1263 // Do we already have a DC entry for that window?
1264 auto *window = static_cast<QWindowsWindow *>(surface);
1265 const HWND hwnd = window->handle();
1266 if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, hwnd)) {
1267 // Repeated calls to wglMakeCurrent when vsync is enabled in the driver will
1268 // often result in 100% cpuload. This check is cheap and avoids the problem.
1269 // This is reproducible on NVidia cards and Intel onboard chips.
1270 if (QOpenGLStaticContext::opengl32.wglGetCurrentContext() == contextData->renderingContext
1271 && QOpenGLStaticContext::opengl32.wglGetCurrentDC() == contextData->hdc) {
1272 return true;
1273 }
1274 const bool success = QOpenGLStaticContext::opengl32.wglMakeCurrent(contextData->hdc, contextData->renderingContext);
1275 if (!success)
1276 qErrnoWarning("%s: wglMakeCurrent() failed for existing context data", __FUNCTION__);
1277 return success;
1278 }
1279 // Create a new entry.
1280 const QOpenGLContextData newContext(m_renderingContext, hwnd, GetDC(hwnd));
1281 if (!newContext.hdc)
1282 return false;
1283 // Initialize pixel format first time. This will apply to
1284 // the HWND as well and must be done only once.
1286 if (!QOpenGLStaticContext::opengl32.setPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) {
1287 qErrnoWarning("%s: SetPixelFormat() failed", __FUNCTION__);
1288 ReleaseDC(newContext.hwnd, newContext.hdc);
1289 return false;
1290 }
1292 if (m_obtainedFormat.swapBehavior() == QSurfaceFormat::DoubleBuffer)
1294 }
1295 m_windowContexts.push_back(newContext);
1296
1297 m_lost = false;
1298 bool success = QOpenGLStaticContext::opengl32.wglMakeCurrent(newContext.hdc, newContext.renderingContext);
1299 if (!success) {
1300 if (m_getGraphicsResetStatus && m_getGraphicsResetStatus()) {
1301 m_lost = true;
1302 qCDebug(lcQpaGl) << "makeCurrent(): context loss detected" << this;
1303 // Drop the surface. Will recreate on the next makeCurrent.
1304 window->invalidateSurface();
1305 } else {
1306 qErrnoWarning("%s: wglMakeCurrent() failed", __FUNCTION__);
1307 }
1308 }
1309
1310 // Set the swap interval
1311 if (m_staticContext->wglSwapInternalExt) {
1312 const int interval = surface->format().swapInterval();
1313 if (m_swapInterval != interval)
1314 m_swapInterval = interval;
1315 if (interval >= 0)
1316 m_staticContext->wglSwapInternalExt(interval);
1317 }
1318
1319 return success;
1320}
1321
1323{
1324#ifdef DEBUG_GL
1326 qCDebug(lcQpaGl) << __FUNCTION__ << this << m_windowContexts.size() << "contexts";
1327#endif // DEBUG_GL
1328 QOpenGLStaticContext::opengl32.wglMakeCurrent(nullptr, nullptr);
1329 releaseDCs();
1330}
1331
1332QFunctionPointer QWindowsGLContext::getProcAddress(const char *procName)
1333{
1334 // Even though we use QFunctionPointer, it does not mean the function can be called.
1335 // It will need to be cast to the proper function type with the correct calling
1336 // convention. QFunctionPointer is nothing more than a glorified void* here.
1337 auto procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName));
1338
1339 // We support AllGLFunctionsQueryable, which means this function must be able to
1340 // return a function pointer even for functions that are in GL.h and exported
1341 // normally from opengl32.dll. wglGetProcAddress() is not guaranteed to work for such
1342 // functions, however in QT_OPENGL_DYNAMIC builds QOpenGLFunctions will just blindly
1343 // call into here for _any_ OpenGL function.
1344 if (procAddress == nullptr || reinterpret_cast<quintptr>(procAddress) < 4u
1345 || procAddress == reinterpret_cast<QFunctionPointer>(-1)) {
1346 procAddress = QOpenGLStaticContext::opengl32.resolve(procName);
1347 }
1348
1350 qCDebug(lcQpaGl) << __FUNCTION__ << procName << QOpenGLStaticContext::opengl32.wglGetCurrentContext() << "returns" << procAddress;
1351
1352 return reinterpret_cast<QFunctionPointer>(procAddress);
1353}
1354
\inmodule QtCore
Definition qbytearray.h:57
QByteArray toLower() const &
Definition qbytearray.h:254
\inmodule QtCore
\inmodule QtCore
\inmodule QtGui
QSurfaceFormat format() const
Returns the format of the underlying platform context, if create() has been called.
QPlatformOpenGLContext * shareHandle() const
Returns the underlying platform context with which this context is sharing.
Static Open GL context containing version information, extension function pointers,...
const QWindowsOpenGLContextFormat defaultFormat
static QByteArray getGlString(unsigned int which)
WglGetExtensionsStringARB wglGetExtensionsStringARB
WglGetSwapInternalExt wglGetSwapInternalExt
QWindowsOpenGLContext * createContext(QOpenGLContext *context) override
WglSwapInternalExt wglSwapInternalExt
static QWindowsOpengl32DLL opengl32
A temporary context that can be instantiated on the stack.
The QPlatformOpenGLContext class provides an abstraction for native GL contexts.
QOpenGLContext * context() const
static bool parseOpenGLVersion(const QByteArray &versionString, int &major, int &minor)
The QPlatformSurface class provides an abstraction for a surface.
QSurface * surface() const
virtual QSurfaceFormat format() const =0
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
void setRenderableType(RenderableType type)
Sets the desired renderable type.
SwapBehavior swapBehavior() const
Returns the configured swap behaviour.
void setOption(FormatOption option, bool on=true)
bool supportsOpenGL() const
Returns true if the surface is OpenGL compatible and can be used in conjunction with QOpenGLContext; ...
Definition qsurface.cpp:70
static QWindowsContext * instance()
Open GL context.
void doneCurrent() override
QFunctionPointer getProcAddress(const char *procName) override
Reimplement in subclass to allow dynamic querying of OpenGL symbols.
bool makeCurrent(QPlatformSurface *surface) override
QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context)
void swapBuffers(QPlatformSurface *surface) override
Reimplement in subclass to native swap buffers calls.
HGLRC renderingContext() const
static QWindowsIntegration * instance()
static QWindowsStaticOpenGLContext * create()
Raster or OpenGL Window.
void qErrnoWarning(const char *msg,...)
static HGLRC createContext(const QOpenGLStaticContext &staticContext, HDC hdc, const QSurfaceFormat &format, const QWindowsOpenGLAdditionalFormat &, HGLRC shared=nullptr)
static int choosePixelFormat(HDC hdc, const QOpenGLStaticContext &staticContext, const QSurfaceFormat &format, const QWindowsOpenGLAdditionalFormat &additional, PIXELFORMATDESCRIPTOR *obtainedPfd)
static QSurfaceFormat qSurfaceFormatFromHDC(const QOpenGLStaticContext &staticContext, HDC hdc, int pixelFormat, QWindowsOpenGLAdditionalFormat *additionalIn=nullptr)
static PIXELFORMATDESCRIPTOR qPixelFormatFromSurfaceFormat(const QSurfaceFormat &format, const QWindowsOpenGLAdditionalFormat &additional)
static QSurfaceFormat qSurfaceFormatFromPixelFormat(const PIXELFORMATDESCRIPTOR &pfd, QWindowsOpenGLAdditionalFormat *additionalIn=nullptr)
static HGLRC createContext(HDC hdc, HGLRC shared)
static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, const QWindowsOpenGLAdditionalFormat &additional, PIXELFORMATDESCRIPTOR *obtainedPfd)
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & showbase(QTextStream &stream)
Calls QTextStream::setNumberFlags(QTextStream::numberFlags() | QTextStream::ShowBase) on stream and r...
QTextStream & noshowbase(QTextStream &stream)
Calls QTextStream::setNumberFlags(QTextStream::numberFlags() & ~QTextStream::ShowBase) on stream and ...
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
static void * context
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
static QByteArray getGlString(GLenum param)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define GL_CONTEXT_PROFILE_MASK
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
#define GL_CONTEXT_CORE_PROFILE_BIT
#define GL_CONTEXT_FLAGS
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
#define GL_CONTEXT_FLAG_DEBUG_BIT
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin)
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
typedef GLint(GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program
GLsizei samples
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLbitfield flags
GLuint GLsizei const GLchar * message
GLuint name
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLint GLsizei GLsizei GLenum format
void ** params
GLdouble s
[6]
Definition qopenglext.h:235
#define APIENTRY
Definition qopenglext.h:51
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GLuint
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
size_t quintptr
Definition qtypes.h:167
unsigned int uint
Definition qtypes.h:34
#define WGL_CONTEXT_MINOR_VERSION_ARB
#define WGL_STENCIL_BITS_ARB
#define WGL_ACCELERATION_ARB
static const QOpenGLContextData * findByHWND(const std::vector< QOpenGLContextData > &data, HWND hwnd)
static bool isDirectRendering(const PIXELFORMATDESCRIPTOR &pfd)
#define WGL_BLUE_BITS_ARB
#define RESET_NOTIFICATION_STRATEGY_ARB
#define WGL_STEREO_ARB
QDebug operator<<(QDebug d, const PIXELFORMATDESCRIPTOR &pd)
static QOpenGLContextData currentOpenGLContextData()
#define WGL_GREEN_BITS_ARB
static bool hasGLOverlay(const PIXELFORMATDESCRIPTOR &pd)
#define WGL_ALPHA_BITS_ARB
#define WGL_CONTEXT_MAJOR_VERSION_ARB
#define WGL_CONTEXT_PROFILE_MASK_ARB
#define WGL_NO_ACCELERATION_ARB
#define WGL_PIXEL_TYPE_ARB
#define WGL_DEPTH_BITS_ARB
#define ROBUSTNESS_EXTENSION
static bool isAcceptableFormat(const QWindowsOpenGLAdditionalFormat &additional, const PIXELFORMATDESCRIPTOR &pfd, bool ignoreGLSupport=false)
#define WGL_NUMBER_OVERLAYS_ARB
#define WGL_CONTEXT_DEBUG_BIT_ARB
#define WGL_DOUBLE_BUFFER_ARB
static HGLRC createDummyGLContext(HDC dc)
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB
static void initPixelFormatDescriptor(PIXELFORMATDESCRIPTOR *d)
static QOpenGLContextData createDummyWindowOpenGLContextData()
#define WGL_SAMPLES_ARB
#define WGL_DRAW_TO_WINDOW_ARB
static HWND handleOf(QPlatformSurface *s)
#define WGL_TYPE_RGBA_ARB
#define LOSE_CONTEXT_ON_RESET_ARB
#define WGL_CONTEXT_FLAGS_ARB
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
static void describeFormats(HDC hdc)
#define SAMPLE_BUFFER_EXTENSION
bool testFlag(MaskType mask, FlagType flag)
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
#define WGL_FULL_ACCELERATION_ARB
#define WGL_SAMPLE_BUFFERS_ARB
#define WGL_RED_BITS_ARB
static QWindowsWindow * glWindowOf(QPlatformSurface *s)
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT
#define WGL_ACCUM_BITS_ARB
#define GL_NUM_EXTENSIONS
static HWND createDummyGLWindow()
#define WGL_COLOR_BITS_ARB
#define WGL_SUPPORT_OPENGL_ARB
@ QWindowsGLDirectRendering
@ QWindowsGLAccumBuffer
@ QWindowsGLOverlay
@ QWindowsGLRenderToPixmap
aWidget window() -> setWindowTitle("New Window Title")
[2]
QSvgRenderer * renderer
[0]
Additional format information that is not in QSurfaceFormat.
QSurfaceFormat::FormatOptions options
majorVersion<<8 + minorVersion
QSurfaceFormat::OpenGLContextProfile profile
static QWindowsOpenGLContextFormat current()
void apply(QSurfaceFormat *format) const
bool init(bool softwareRendering)
int describePixelFormat(HDC dc, int pf, UINT size, PIXELFORMATDESCRIPTOR *pfd)
BOOL(WINAPI *wglDeleteContext)(HGLRC context)
GLenum(APIENTRY *glGetError)()
PROC(WINAPI *wglGetProcAddress)(LPCSTR name)
HGLRC(WINAPI *wglCreateContext)(HDC dc)
QFunctionPointer resolve(const char *name)
const GLubyte *APIENTRY * glGetString(GLenum name)
HDC(WINAPI *wglGetCurrentDC)()
bool moduleIsNotOpengl32() const
BOOL setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd)