Warning: That file was not part of the compilation database. It may have many parsing errors.

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

Warning: That file was not part of the compilation database. It may have many parsing errors.