OpenCoverage

qopenglwidget.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/widgets/kernel/qopenglwidget.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
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 QtWidgets module 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 "qopenglwidget.h"-
41#include <QtGui/QOpenGLContext>-
42#include <QtGui/QOpenGLFramebufferObject>-
43#include <QtGui/QOffscreenSurface>-
44#include <QtGui/QOpenGLFunctions>-
45#include <QtGui/QWindow>-
46#include <QtGui/QGuiApplication>-
47#include <QtGui/QScreen>-
48#include <QtGui/QOpenGLPaintDevice>-
49#include <QtGui/qpa/qplatformwindow.h>-
50#include <QtGui/qpa/qplatformintegration.h>-
51#include <QtGui/private/qguiapplication_p.h>-
52#include <QtGui/private/qopenglextensions_p.h>-
53#include <QtGui/private/qfont_p.h>-
54#include <QtGui/private/qopenglpaintdevice_p.h>-
55#include <QtGui/private/qopenglcontext_p.h>-
56#include <QtWidgets/private/qwidget_p.h>-
57-
58QT_BEGIN_NAMESPACE-
59-
60/*!-
61 \class QOpenGLWidget-
62 \inmodule QtWidgets-
63 \since 5.4-
64-
65 \brief The QOpenGLWidget class is a widget for rendering OpenGL graphics.-
66-
67 QOpenGLWidget provides functionality for displaying OpenGL graphics-
68 integrated into a Qt application. It is very simple to use: Make-
69 your class inherit from it and use the subclass like any other-
70 QWidget, except that you have the choice between using QPainter and-
71 standard OpenGL rendering commands.-
72-
73 QOpenGLWidget provides three convenient virtual functions that you-
74 can reimplement in your subclass to perform the typical OpenGL-
75 tasks:-
76-
77 \list-
78 \li paintGL() - Renders the OpenGL scene. Gets called whenever the widget-
79 needs to be updated.-
80 \li resizeGL() - Sets up the OpenGL viewport, projection, etc. Gets-
81 called whenever the widget has been resized (and also when it-
82 is shown for the first time because all newly created widgets get a-
83 resize event automatically).-
84 \li initializeGL() - Sets up the OpenGL resources and state. Gets called-
85 once before the first time resizeGL() or paintGL() is called.-
86 \endlist-
87-
88 If you need to trigger a repaint from places other than paintGL() (a-
89 typical example is when using \l{QTimer}{timers} to animate scenes),-
90 you should call the widget's update() function to schedule an update.-
91-
92 Your widget's OpenGL rendering context is made current when-
93 paintGL(), resizeGL(), or initializeGL() is called. If you need to-
94 call the standard OpenGL API functions from other places (e.g. in-
95 your widget's constructor or in your own paint functions), you-
96 must call makeCurrent() first.-
97-
98 All rendering happens into an OpenGL framebuffer-
99 object. makeCurrent() ensure that it is bound in the context. Keep-
100 this in mind when creating and binding additional framebuffer-
101 objects in the rendering code in paintGL(). Never re-bind the-
102 framebuffer with ID 0. Instead, call defaultFramebufferObject() to-
103 get the ID that should be bound.-
104-
105 QOpenGLWidget allows using different OpenGL versions and profiles-
106 when the platform supports it. Just set the requested format via-
107 setFormat(). Keep in mind however that having multiple QOpenGLWidget-
108 instances in the same window requires that they all use the same-
109 format, or at least formats that do not make the contexts-
110 non-sharable. To overcome this issue, prefer using-
111 QSurfaceFormat::setDefaultFormat() instead of setFormat().-
112-
113 \note Calling QSurfaceFormat::setDefaultFormat() before constructing-
114 the QApplication instance is mandatory on some platforms (for example,-
115 \macos) when an OpenGL core profile context is requested. This is to-
116 ensure that resource sharing between contexts stays functional as all-
117 internal contexts are created using the correct version and profile.-
118-
119 \section1 Painting Techniques-
120-
121 As described above, subclass QOpenGLWidget to render pure 3D content in the-
122 following way:-
123-
124 \list-
125-
126 \li Reimplement the initializeGL() and resizeGL() functions to-
127 set up the OpenGL state and provide a perspective transformation.-
128-
129 \li Reimplement paintGL() to paint the 3D scene, calling only-
130 OpenGL functions.-
131-
132 \endlist-
133-
134 It is also possible to draw 2D graphics onto a QOpenGLWidget subclass using QPainter:-
135-
136 \list-
137-
138 \li In paintGL(), instead of issuing OpenGL commands, construct a QPainter-
139 object for use on the widget.-
140-
141 \li Draw primitives using QPainter's member functions.-
142-
143 \li Direct OpenGL commands can still be issued. However, you must make sure-
144 these are enclosed by a call to the painter's beginNativePainting() and-
145 endNativePainting().-
146-
147 \endlist-
148-
149 When performing drawing using QPainter only, it is also possible to perform-
150 the painting like it is done for ordinary widgets: by reimplementing paintEvent().-
151-
152 \list-
153-
154 \li Reimplement the paintEvent() function.-
155-
156 \li Construct a QPainter object targeting the widget. Either pass the widget to the-
157 constructor or the QPainter::begin() function.-
158-
159 \li Draw primitives using QPainter's member functions.-
160-
161 \li Painting finishes then the QPainter instance is destroyed. Alternatively,-
162 call QPainter::end() explicitly.-
163-
164 \endlist-
165-
166 \section1 OpenGL Function Calls, Headers and QOpenGLFunctions-
167-
168 When making OpenGL function calls, it is strongly recommended to avoid calling-
169 the functions directly. Instead, prefer using QOpenGLFunctions (when making-
170 portable applications) or the versioned variants (for example,-
171 QOpenGLFunctions_3_2_Core and similar, when targeting modern, desktop-only-
172 OpenGL). This way the application will work correctly in all Qt build-
173 configurations, including the ones that perform dynamic OpenGL implementation-
174 loading which means applications are not directly linking to an GL-
175 implementation and thus direct function calls are not feasible.-
176-
177 In paintGL() the current context is always accessible by caling-
178 QOpenGLContext::currentContext(). From this context an already initialized,-
179 ready-to-be-used QOpenGLFunctions instance is retrievable by calling-
180 QOpenGLContext::functions(). An alternative to prefixing every GL call is to-
181 inherit from QOpenGLFunctions and call-
182 QOpenGLFunctions::initializeOpenGLFunctions() in initializeGL().-
183-
184 As for the OpenGL headers, note that in most cases there will be no need to-
185 directly include any headers like GL.h. The OpenGL-related Qt headers will-
186 include qopengl.h which will in turn include an appropriate header for the-
187 system. This might be an OpenGL ES 3.x or 2.0 header, the highest version that-
188 is available, or a system-provided gl.h. In addition, a copy of the extension-
189 headers (called glext.h on some systems) is provided as part of Qt both for-
190 OpenGL and OpenGL ES. These will get included automatically on platforms where-
191 feasible. This means that constants and function pointer typedefs from ARB,-
192 EXT, OES extensions are automatically available.-
193-
194 \section1 Code Examples-
195-
196 To get started, the simplest QOpenGLWidget subclass could like like the following:-
197-
198 \snippet code/doc_gui_widgets_qopenglwidget.cpp 0-
199-
200 Alternatively, the prefixing of each and every OpenGL call can be avoided by deriving-
201 from QOpenGLFunctions instead:-
202-
203 \snippet code/doc_gui_widgets_qopenglwidget.cpp 1-
204-
205 To get a context compatible with a given OpenGL version or profile, or to-
206 request depth and stencil buffers, call setFormat():-
207-
208 \snippet code/doc_gui_widgets_qopenglwidget.cpp 2-
209-
210 With OpenGL 3.0+ contexts, when portability is not important, the versioned-
211 QOpenGLFunctions variants give easy access to all the modern OpenGL functions-
212 available in a given version:-
213-
214 \snippet code/doc_gui_widgets_qopenglwidget.cpp 3-
215-
216 As described above, it is simpler and more robust to set the requested format-
217 globally so that it applies to all windows and contexts during the lifetime of-
218 the application. Below is an example of this:-
219-
220 \snippet code/doc_gui_widgets_qopenglwidget.cpp 6-
221-
222 \section1 Relation to QGLWidget-
223-
224 The legacy QtOpenGL module (classes prefixed with QGL) provides a widget-
225 called QGLWidget. QOpenGLWidget is intended to be a modern replacement for-
226 it. Therefore, especially in new applications, the general recommendation is-
227 to use QOpenGLWidget.-
228-
229 While the API is very similar, there is an important difference between the-
230 two: QOpenGLWidget always renders offscreen, using framebuffer-
231 objects. QGLWidget on the other hand uses a native window and surface. The-
232 latter causes issues when using it in complex user interfaces since, depending-
233 on the platform, such native child widgets may have various limitations,-
234 regarding stacking orders for example. QOpenGLWidget avoids this by not-
235 creating a separate native window.-
236-
237 Due to being backed by a framebuffer object, the behavior of QOpenGLWidget is-
238 very similar to QOpenGLWindow with the update behavior set to \c-
239 PartialUpdateBlit or \c PartialUpdateBlend. This means that the contents are-
240 preserved between paintGL() calls so that incremental rendering is-
241 possible. With QGLWidget (and naturally QOpenGLWindow with the default update-
242 behavior) this is usually not the case because swapping the buffers leaves the-
243 back buffer with undefined contents.-
244-
245 \note Most applications do not need incremental rendering because they will-
246 render everything in the view on every paint call. In this case it is-
247 important to call glClear() as early as possible in paintGL(). This helps-
248 mobile GPUs that use a tile-based architecture to recognize that the tile-
249 buffer does not need to be reloaded with the framebuffer's previous-
250 contents. Omitting the clear call can lead to significant performance drops on-
251 such systems.-
252-
253 \note Avoid calling winId() on a QOpenGLWidget. This function triggers the creation of-
254 a native window, resulting in reduced performance and possibly rendering glitches.-
255-
256 \section1 Differences to QGLWidget-
257-
258 Besides the main conceptual difference of being backed by a framebuffer object, there-
259 are a number of smaller, internal differences between QOpenGLWidget and the older-
260 QGLWidget:-
261-
262 \list-
263-
264 \li OpenGL state when invoking paintGL(). QOpenGLWidget sets up the viewport via-
265 glViewport(). It does not perform any clearing.-
266-
267 \li Clearing when starting to paint via QPainter. Unlike regular widgets, QGLWidget-
268 defaulted to a value of \c true for-
269 \l{QWidget::autoFillBackground()}{autoFillBackground}. It then performed clearing to the-
270 palette's background color every time QPainter::begin() was used. QOpenGLWidget does not-
271 follow this: \l{QWidget::autoFillBackground()}{autoFillBackground} defaults to false,-
272 like for any other widget. The only exception is when being used as a viewport for other-
273 widgets like QGraphicsView. In such a case autoFillBackground will be automatically set-
274 to true to ensure compatibility with QGLWidget-based viewports.-
275-
276 \endlist-
277-
278 \section1 Multisampling-
279-
280 To enable multisampling, set the number of requested samples on the-
281 QSurfaceFormat that is passed to setFormat(). On systems that do not support-
282 it the request may get ignored.-
283-
284 Multisampling support requires support for multisampled renderbuffers and-
285 framebuffer blits. On OpenGL ES 2.0 implementations it is likely that these-
286 will not be present. This means that multisampling will not be available. With-
287 modern OpenGL versions and OpenGL ES 3.0 and up this is usually not a problem-
288 anymore.-
289-
290 \section1 Threading-
291-
292 Performing offscreen rendering on worker threads, for example to generate-
293 textures that are then used in the GUI/main thread in paintGL(), are supported-
294 by exposing the widget's QOpenGLContext so that additional contexts sharing-
295 with it can be created on each thread.-
296-
297 Drawing directly to the QOpenGLWidget's framebuffer outside the GUI/main-
298 thread is possible by reimplementing paintEvent() to do nothing. The context's-
299 thread affinity has to be changed via QObject::moveToThread(). After that,-
300 makeCurrent() and doneCurrent() are usable on the worker thread. Be careful to-
301 move the context back to the GUI/main thread afterwards.-
302-
303 Unlike QGLWidget, triggering a buffer swap just for the QOpenGLWidget is not-
304 possible since there is no real, onscreen native surface for it. Instead, it-
305 is up to the widget stack to manage composition and buffer swaps on the gui-
306 thread. When a thread is done updating the framebuffer, call update() \b{on-
307 the GUI/main thread} to schedule composition.-
308-
309 Extra care has to be taken to avoid using the framebuffer when the GUI/main-
310 thread is performing compositing. The signals aboutToCompose() and-
311 frameSwapped() will be emitted when the composition is starting and-
312 ending. They are emitted on the GUI/main thread. This means that by using a-
313 direct connection aboutToCompose() can block the GUI/main thread until the-
314 worker thread has finished its rendering. After that, the worker thread must-
315 perform no further rendering until the frameSwapped() signal is emitted. If-
316 this is not acceptable, the worker thread has to implement a double buffering-
317 mechanism. This involves drawing using an alternative render target, that is-
318 fully controlled by the thread, e.g. an additional framebuffer object, and-
319 blitting to the QOpenGLWidget's framebuffer at a suitable time.-
320-
321 \section1 Context Sharing-
322-
323 When multiple QOpenGLWidgets are added as children to the same top-level-
324 widget, their contexts will share with each other. This does not apply for-
325 QOpenGLWidget instances that belong to different windows.-
326-
327 This means that all QOpenGLWidgets in the same window can access each other's-
328 sharable resources, like textures, and there is no need for an extra "global-
329 share" context, as was the case with QGLWidget.-
330-
331 To set up sharing between QOpenGLWidget instances belonging to different-
332 windows, set the Qt::AA_ShareOpenGLContexts application attribute before-
333 instantiating QApplication. This will trigger sharing between all-
334 QOpenGLWidget instances without any further steps.-
335-
336 Creating extra QOpenGLContext instances that share resources like textures-
337 with the QOpenGLWidget's context is also possible. Simply pass the pointer-
338 returned from context() to QOpenGLContext::setShareContext() before calling-
339 QOpenGLContext::create(). The resulting context can also be used on a-
340 different thread, allowing threaded generation of textures and asynchronous-
341 texture uploads.-
342-
343 Note that QOpenGLWidget expects a standard conformant implementation of-
344 resource sharing when it comes to the underlying graphics drivers. For-
345 example, some drivers, in particular for mobile and embedded hardware, have-
346 issues with setting up sharing between an existing context and others that are-
347 created later. Some other drivers may behave in unexpected ways when trying to-
348 utilize shared resources between different threads.-
349-
350 \section1 Resource Initialization and Cleanup-
351-
352 The QOpenGLWidget's associated OpenGL context is guaranteed to be current-
353 whenever initializeGL() and paintGL() are invoked. Do not attempt to create-
354 OpenGL resources before initializeGL() is called. For example, attempting to-
355 compile shaders, initialize vertex buffer objects or upload texture data will-
356 fail when done in a subclass's constructor. These operations must be deferred-
357 to initializeGL(). Some of Qt's OpenGL helper classes, like QOpenGLBuffer or-
358 QOpenGLVertexArrayObject, have a matching deferred behavior: they can be-
359 instantiated without a context, but all initialization is deferred until a-
360 create(), or similar, call. This means that they can be used as normal-
361 (non-pointer) member variables in a QOpenGLWidget subclass, but the create()-
362 or similar function can only be called from initializeGL(). Be aware however-
363 that not all classes are designed like this. When in doubt, make the member-
364 variable a pointer and create and destroy the instance dynamically in-
365 initializeGL() and the destructor, respectively.-
366-
367 Releasing the resources also needs the context to be current. Therefore-
368 destructors that perform such cleanup are expected to call makeCurrent()-
369 before moving on to destroy any OpenGL resources or wrappers. Avoid deferred-
370 deletion via \l{QObject::deleteLater()}{deleteLater()} or the parenting-
371 mechanism of QObject. There is no guarantee the correct context will be-
372 current at the time the instance in question is really destroyed.-
373-
374 A typical subclass will therefore often look like the following when it comes-
375 to resource initialization and destruction:-
376-
377 \snippet code/doc_gui_widgets_qopenglwidget.cpp 4-
378-
379 This is naturally not the only possible solution. One alternative is to use-
380 the \l{QOpenGLContext::aboutToBeDestroyed()}{aboutToBeDestroyed()} signal of-
381 QOpenGLContext. By connecting a slot, using direct connection, to this signal,-
382 it is possible to perform cleanup whenever the the underlying native context-
383 handle, or the entire QOpenGLContext instance, is going to be released. The-
384 following snippet is in principal equivalent to the previous one:-
385-
386 \snippet code/doc_gui_widgets_qopenglwidget.cpp 5-
387-
388 \note For widgets that change their associated top-level window multiple times-
389 during their lifetime, a combined approach is essential. Whenever the widget-
390 or a parent of it gets reparented so that the top-level window becomes-
391 different, the widget's associated context is destroyed and a new one is-
392 created. This is then followed by a call to initializeGL() where all OpenGL-
393 resources must get reinitialized. Due to this the only option to perform-
394 proper cleanup is to connect to the context's aboutToBeDestroyed()-
395 signal. Note that the context in question may not be the current one when the-
396 signal gets emitted. Therefore it is good practice to call makeCurrent() in-
397 the connected slot. Additionally, the same cleanup steps must be performed-
398 from the derived class' destructor, since the slot connected to the signal-
399 will not get invoked when the widget is being destroyed.-
400-
401 \note When Qt::AA_ShareOpenGLContexts is set, the widget's context never-
402 changes, not even when reparenting because the widget's associated texture is-
403 guaranteed to be accessible also from the new top-level's context.-
404-
405 Proper cleanup is especially important due to context sharing. Even though-
406 each QOpenGLWidget's associated context is destroyed together with the-
407 QOpenGLWidget, the sharable resources in that context, like textures, will-
408 stay valid until the top-level window, in which the QOpenGLWidget lived, is-
409 destroyed. Additionally, settings like Qt::AA_ShareOpenGLContexts and some Qt-
410 modules may trigger an even wider scope for sharing contexts, potentially-
411 leading to keeping the resources in question alive for the entire lifetime of-
412 the application. Therefore the safest and most robust is always to perform-
413 explicit cleanup for all resources and resource wrappers used in the-
414 QOpenGLWidget.-
415-
416 \section1 Limitations-
417-
418 Putting other widgets underneath and making the QOpenGLWidget transparent will-
419 not lead to the expected results: The widgets underneath will not be-
420 visible. This is because in practice the QOpenGLWidget is drawn before all-
421 other regular, non-OpenGL widgets, and so see-through type of solutions are-
422 not feasible. Other type of layouts, like having widgets on top of the-
423 QOpenGLWidget, will function as expected.-
424-
425 When absolutely necessary, this limitation can be overcome by setting the-
426 Qt::WA_AlwaysStackOnTop attribute on the QOpenGLWidget. Be aware however that-
427 this breaks stacking order, for example it will not be possible to have other-
428 widgets on top of the QOpenGLWidget, so it should only be used in situations-
429 where a semi-transparent QOpenGLWidget with other widgets visible underneath-
430 is required.-
431-
432 Note that this does not apply when there are no other widgets underneath and-
433 the intention is to have a semi-transparent window. In that case the-
434 traditional approach of setting Qt::WA_TranslucentBackground-
435 on the top-level window is sufficient. Note that if the transparent areas are-
436 only desired in the QOpenGLWidget, then Qt::WA_NoSystemBackground will need-
437 to be turned back to \c false after enabling Qt::WA_TranslucentBackground.-
438 Additionally, requesting an alpha channel for the QOpenGLWidget's context via-
439 setFormat() may be necessary too, depending on the system.-
440-
441 QOpenGLWidget supports multiple update behaviors, just like QOpenGLWindow. In-
442 preserved mode the rendered content from the previous paintGL() call is-
443 available in the next one, allowing incremental rendering. In non-preserved-
444 mode the content is lost and paintGL() implementations are expected to redraw-
445 everything in the view.-
446-
447 Before Qt 5.5 the default behavior of QOpenGLWidget was to preserve the-
448 rendered contents between paintGL() calls. Since Qt 5.5 the default behavior-
449 is non-preserved because this provides better performance and the majority of-
450 applications have no need for the previous content. This also resembles the-
451 semantics of an OpenGL-based QWindow and matches the default behavior of-
452 QOpenGLWindow in that the color and ancillary buffers are invalidated for-
453 each frame. To restore the preserved behavior, call setUpdateBehavior() with-
454 \c PartialUpdate.-
455-
456 \section1 Alternatives-
457-
458 Adding a QOpenGLWidget into a window turns on OpenGL-based-
459 compositing for the entire window. In some special cases this may-
460 not be ideal, and the old QGLWidget-style behavior with a separate,-
461 native child window is desired. Desktop applications that understand-
462 the limitations of this approach (for example when it comes to-
463 overlaps, transparency, scroll views and MDI areas), can use-
464 QOpenGLWindow with QWidget::createWindowContainer(). This is a-
465 modern alternative to QGLWidget and is faster than QOpenGLWidget due-
466 to the lack of the additional composition step. It is strongly-
467 recommended to limit the usage of this approach to cases where there-
468 is no other choice. Note that this option is not suitable for most-
469 embedded and mobile platforms, and it is known to have issues on-
470 certain desktop platforms (e.g. \macos) too. The stable,-
471 cross-platform solution is always QOpenGLWidget.-
472-
473 \e{OpenGL is a trademark of Silicon Graphics, Inc. in the United States and other-
474 countries.}-
475-
476 \sa QOpenGLFunctions, QOpenGLWindow, Qt::AA_ShareOpenGLContexts, UpdateBehavior-
477*/-
478-
479/*!-
480 \fn void QOpenGLWidget::aboutToCompose()-
481-
482 This signal is emitted when the widget's top-level window is about to begin-
483 composing the textures of its QOpenGLWidget children and the other widgets.-
484*/-
485-
486/*!-
487 \fn void QOpenGLWidget::frameSwapped()-
488-
489 This signal is emitted after the widget's top-level window has finished-
490 composition and returned from its potentially blocking-
491 QOpenGLContext::swapBuffers() call.-
492*/-
493-
494/*!-
495 \fn void QOpenGLWidget::aboutToResize()-
496-
497 This signal is emitted when the widget's size is changed and therefore the-
498 framebuffer object is going to be recreated.-
499*/-
500-
501/*!-
502 \fn void QOpenGLWidget::resized()-
503-
504 This signal is emitted right after the framebuffer object has been recreated-
505 due to resizing the widget.-
506*/-
507-
508/*!-
509 \enum QOpenGLWidget::UpdateBehavior-
510 \since 5.5-
511-
512 This enum describes the update semantics of QOpenGLWidget.-
513-
514 \value NoPartialUpdate QOpenGLWidget will discard the-
515 contents of the color buffer and the ancillary buffers after the-
516 QOpenGLWidget is rendered to screen. This is the same behavior that can be-
517 expected by calling QOpenGLContext::swapBuffers with a default opengl-
518 enabled QWindow as the argument. NoPartialUpdate can have some performance-
519 benefits on certain hardware architectures common in the mobile and-
520 embedded space when a framebuffer object is used as the rendering target.-
521 The framebuffer object is invalidated between frames with-
522 glDiscardFramebufferEXT if supported or a glClear. Please see the-
523 documentation of EXT_discard_framebuffer for more information:-
524 https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt-
525-
526 \value PartialUpdate The framebuffer objects color buffer and ancillary-
527 buffers are not invalidated between frames.-
528-
529 \sa updateBehavior(), setUpdateBehavior()-
530*/-
531-
532class QOpenGLWidgetPaintDevicePrivate : public QOpenGLPaintDevicePrivate-
533{-
534public:-
535 QOpenGLWidgetPaintDevicePrivate(QOpenGLWidget *widget)-
536 : QOpenGLPaintDevicePrivate(QSize()),-
537 w(widget) { }
never executed: end of block
0
538-
539 void beginPaint() Q_DECL_OVERRIDE;-
540-
541 QOpenGLWidget *w;-
542};-
543-
544class QOpenGLWidgetPaintDevice : public QOpenGLPaintDevice-
545{-
546public:-
547 QOpenGLWidgetPaintDevice(QOpenGLWidget *widget)-
548 : QOpenGLPaintDevice(*new QOpenGLWidgetPaintDevicePrivate(widget)) { }
never executed: end of block
0
549 void ensureActiveTarget() Q_DECL_OVERRIDE;-
550};-
551-
552class QOpenGLWidgetPrivate : public QWidgetPrivate-
553{-
554 Q_DECLARE_PUBLIC(QOpenGLWidget)-
555public:-
556 QOpenGLWidgetPrivate()-
557 : context(0),-
558 fbo(0),-
559 resolvedFbo(0),-
560 surface(0),-
561 initialized(false),-
562 fakeHidden(false),-
563 inBackingStorePaint(false),-
564 hasBeenComposed(false),-
565 flushPending(false),-
566 paintDevice(0),-
567 updateBehavior(QOpenGLWidget::NoPartialUpdate),-
568 requestedSamples(0),-
569 inPaintGL(false)-
570 {-
571 requestedFormat = QSurfaceFormat::defaultFormat();-
572 }
never executed: end of block
0
573-
574 ~QOpenGLWidgetPrivate()-
575 {-
576 reset();-
577 }
never executed: end of block
0
578-
579 void reset();-
580 void recreateFbo();-
581-
582 GLuint textureId() const Q_DECL_OVERRIDE;-
583-
584 void initialize();-
585 void invokeUserPaint();-
586 void render();-
587-
588 void invalidateFbo();-
589-
590 QImage grabFramebuffer() Q_DECL_OVERRIDE;-
591 void beginBackingStorePainting() Q_DECL_OVERRIDE { inBackingStorePaint = true; }
never executed: end of block
0
592 void endBackingStorePainting() Q_DECL_OVERRIDE { inBackingStorePaint = false; }
never executed: end of block
0
593 void beginCompose() Q_DECL_OVERRIDE;-
594 void endCompose() Q_DECL_OVERRIDE;-
595 void initializeViewportFramebuffer() Q_DECL_OVERRIDE;-
596 void resizeViewportFramebuffer() Q_DECL_OVERRIDE;-
597 void resolveSamples() Q_DECL_OVERRIDE;-
598-
599 QOpenGLContext *context;-
600 QOpenGLFramebufferObject *fbo;-
601 QOpenGLFramebufferObject *resolvedFbo;-
602 QOffscreenSurface *surface;-
603 bool initialized;-
604 bool fakeHidden;-
605 bool inBackingStorePaint;-
606 bool hasBeenComposed;-
607 bool flushPending;-
608 QOpenGLPaintDevice *paintDevice;-
609 QSurfaceFormat requestedFormat;-
610 QOpenGLWidget::UpdateBehavior updateBehavior;-
611 int requestedSamples;-
612 bool inPaintGL;-
613};-
614-
615void QOpenGLWidgetPaintDevicePrivate::beginPaint()-
616{-
617 // NB! autoFillBackground is and must be false by default. Otherwise we would clear on-
618 // every QPainter begin() which is not desirable. This is only for legacy use cases,-
619 // like using QOpenGLWidget as the viewport of a graphics view, that expect clearing-
620 // with the palette's background color.-
621 if (w->autoFillBackground()) {
w->autoFillBackground()Description
TRUEnever evaluated
FALSEnever evaluated
0
622 QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();-
623 if (w->format().hasAlpha()) {
w->format().hasAlpha()Description
TRUEnever evaluated
FALSEnever evaluated
0
624 f->glClearColor(0, 0, 0, 0);-
625 } else {
never executed: end of block
0
626 QColor c = w->palette().brush(w->backgroundRole()).color();-
627 float alpha = c.alphaF();-
628 f->glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);-
629 }
never executed: end of block
0
630 f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);-
631 }
never executed: end of block
0
632}
never executed: end of block
0
633-
634void QOpenGLWidgetPaintDevice::ensureActiveTarget()-
635{-
636 QOpenGLWidgetPaintDevicePrivate *d = static_cast<QOpenGLWidgetPaintDevicePrivate *>(d_ptr.data());-
637 QOpenGLWidgetPrivate *wd = static_cast<QOpenGLWidgetPrivate *>(QWidgetPrivate::get(d->w));-
638 if (!wd->initialized)
!wd->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
639 return;
never executed: return;
0
640-
641 if (QOpenGLContext::currentContext() != wd->context)
QOpenGLContext...!= wd->contextDescription
TRUEnever evaluated
FALSEnever evaluated
0
642 d->w->makeCurrent();
never executed: d->w->makeCurrent();
0
643 else-
644 wd->fbo->bind();
never executed: wd->fbo->bind();
0
645-
646 // When used as a viewport, drawing is done via opening a QPainter on the widget-
647 // without going through paintEvent(). We will have to make sure a glFlush() is done-
648 // before the texture is accessed also in this case.-
649 wd->flushPending = true;-
650}
never executed: end of block
0
651-
652GLuint QOpenGLWidgetPrivate::textureId() const-
653{-
654 return resolvedFbo ? resolvedFbo->texture() : (fbo ? fbo->texture() : 0);
never executed: return resolvedFbo ? resolvedFbo->texture() : (fbo ? fbo->texture() : 0);
0
655}-
656-
657void QOpenGLWidgetPrivate::reset()-
658{-
659 Q_Q(QOpenGLWidget);-
660-
661 // Destroy the OpenGL resources first. These need the context to be current.-
662 if (initialized)
initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
663 q->makeCurrent();
never executed: q->makeCurrent();
0
664-
665 delete paintDevice;-
666 paintDevice = 0;-
667 delete fbo;-
668 fbo = 0;-
669 delete resolvedFbo;-
670 resolvedFbo = 0;-
671-
672 if (initialized)
initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
673 q->doneCurrent();
never executed: q->doneCurrent();
0
674-
675 // Delete the context first, then the surface. Slots connected to-
676 // the context's aboutToBeDestroyed() may still call makeCurrent()-
677 // to perform some cleanup.-
678 delete context;-
679 context = 0;-
680 delete surface;-
681 surface = 0;-
682 initialized = fakeHidden = inBackingStorePaint = false;-
683}
never executed: end of block
0
684-
685void QOpenGLWidgetPrivate::recreateFbo()-
686{-
687 Q_Q(QOpenGLWidget);-
688-
689 emit q->aboutToResize();-
690-
691 context->makeCurrent(surface);-
692-
693 delete fbo;-
694 fbo = 0;-
695 delete resolvedFbo;-
696 resolvedFbo = 0;-
697-
698 int samples = requestedSamples;-
699 QOpenGLExtensions *extfuncs = static_cast<QOpenGLExtensions *>(context->functions());-
700 if (!extfuncs->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
!extfuncs->has...erMultisample)Description
TRUEnever evaluated
FALSEnever evaluated
0
701 samples = 0;
never executed: samples = 0;
0
702-
703 QOpenGLFramebufferObjectFormat format;-
704 format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);-
705 format.setSamples(samples);-
706-
707 const QSize deviceSize = q->size() * q->devicePixelRatioF();-
708 fbo = new QOpenGLFramebufferObject(deviceSize, format);-
709 if (samples > 0)
samples > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
710 resolvedFbo = new QOpenGLFramebufferObject(deviceSize);
never executed: resolvedFbo = new QOpenGLFramebufferObject(deviceSize);
0
711-
712 fbo->bind();-
713 context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);-
714-
715 paintDevice->setSize(deviceSize);-
716 paintDevice->setDevicePixelRatio(q->devicePixelRatioF());-
717-
718 emit q->resized();-
719}
never executed: end of block
0
720-
721void QOpenGLWidgetPrivate::beginCompose()-
722{-
723 Q_Q(QOpenGLWidget);-
724 if (flushPending) {
flushPendingDescription
TRUEnever evaluated
FALSEnever evaluated
0
725 flushPending = false;-
726 q->makeCurrent();-
727 static_cast<QOpenGLExtensions *>(context->functions())->flushShared();-
728 }
never executed: end of block
0
729 hasBeenComposed = true;-
730 emit q->aboutToCompose();-
731}
never executed: end of block
0
732-
733void QOpenGLWidgetPrivate::endCompose()-
734{-
735 Q_Q(QOpenGLWidget);-
736 emit q->frameSwapped();-
737}
never executed: end of block
0
738-
739void QOpenGLWidgetPrivate::initialize()-
740{-
741 Q_Q(QOpenGLWidget);-
742 if (initialized)
initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
743 return;
never executed: return;
0
744-
745 // Get our toplevel's context with which we will share in order to make the-
746 // texture usable by the underlying window's backingstore.-
747 QWidget *tlw = q->window();-
748 QOpenGLContext *shareContext = get(tlw)->shareContext();-
749 if (Q_UNLIKELY(!shareContext)) {
__builtin_expe...ntext), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
750 qWarning("QOpenGLWidget: Cannot be used without a context shared with the toplevel.");-
751 return;
never executed: return;
0
752 }-
753-
754 // Do not include the sample count. Requesting a multisampled context is not necessary-
755 // since we render into an FBO, never to an actual surface. What's more, attempting to-
756 // create a pbuffer with a multisampled config crashes certain implementations. Just-
757 // avoid the entire hassle, the result is the same.-
758 requestedSamples = requestedFormat.samples();-
759 requestedFormat.setSamples(0);-
760-
761 QScopedPointer<QOpenGLContext> ctx(new QOpenGLContext);-
762 ctx->setShareContext(shareContext);-
763 ctx->setFormat(requestedFormat);-
764 ctx->setScreen(shareContext->screen());-
765 if (Q_UNLIKELY(!ctx->create())) {
__builtin_expe...ate()), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
766 qWarning("QOpenGLWidget: Failed to create context");-
767 return;
never executed: return;
0
768 }-
769-
770 // Propagate settings that make sense only for the tlw.-
771 QSurfaceFormat tlwFormat = tlw->windowHandle()->format();-
772 if (requestedFormat.swapInterval() != tlwFormat.swapInterval()) {
requestedForma...swapInterval()Description
TRUEnever evaluated
FALSEnever evaluated
0
773 // Most platforms will pick up the changed swap interval on the next-
774 // makeCurrent or swapBuffers.-
775 tlwFormat.setSwapInterval(requestedFormat.swapInterval());-
776 tlw->windowHandle()->setFormat(tlwFormat);-
777 }
never executed: end of block
0
778 if (requestedFormat.swapBehavior() != tlwFormat.swapBehavior()) {
requestedForma...swapBehavior()Description
TRUEnever evaluated
FALSEnever evaluated
0
779 tlwFormat.setSwapBehavior(requestedFormat.swapBehavior());-
780 tlw->windowHandle()->setFormat(tlwFormat);-
781 }
never executed: end of block
0
782-
783 // The top-level window's surface is not good enough since it causes way too-
784 // much trouble with regards to the QSurfaceFormat for example. So just like-
785 // in QQuickWidget, use a dedicated QOffscreenSurface.-
786 surface = new QOffscreenSurface;-
787 surface->setFormat(ctx->format());-
788 surface->setScreen(ctx->screen());-
789 surface->create();-
790-
791 if (Q_UNLIKELY(!ctx->makeCurrent(surface))) {
__builtin_expe...face)), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
792 qWarning("QOpenGLWidget: Failed to make context current");-
793 return;
never executed: return;
0
794 }-
795-
796 paintDevice = new QOpenGLWidgetPaintDevice(q);-
797 paintDevice->setSize(q->size() * q->devicePixelRatioF());-
798 paintDevice->setDevicePixelRatio(q->devicePixelRatioF());-
799-
800 context = ctx.take();-
801 initialized = true;-
802-
803 q->initializeGL();-
804}
never executed: end of block
0
805-
806void QOpenGLWidgetPrivate::resolveSamples()-
807{-
808 Q_Q(QOpenGLWidget);-
809 if (resolvedFbo) {
resolvedFboDescription
TRUEnever evaluated
FALSEnever evaluated
0
810 q->makeCurrent();-
811 QRect rect(QPoint(0, 0), fbo->size());-
812 QOpenGLFramebufferObject::blitFramebuffer(resolvedFbo, rect, fbo, rect);-
813 flushPending = true;-
814 }
never executed: end of block
0
815}
never executed: end of block
0
816-
817void QOpenGLWidgetPrivate::invokeUserPaint()-
818{-
819 Q_Q(QOpenGLWidget);-
820-
821 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
822 Q_ASSERT(ctx && fbo);-
823-
824 QOpenGLFunctions *f = ctx->functions();-
825 QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbo->handle();-
826-
827 f->glViewport(0, 0, q->width() * q->devicePixelRatioF(), q->height() * q->devicePixelRatioF());-
828 inPaintGL = true;-
829 q->paintGL();-
830 inPaintGL = false;-
831 flushPending = true;-
832-
833 QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = 0;-
834}
never executed: end of block
0
835-
836void QOpenGLWidgetPrivate::render()-
837{-
838 Q_Q(QOpenGLWidget);-
839-
840 if (fakeHidden || !initialized)
fakeHiddenDescription
TRUEnever evaluated
FALSEnever evaluated
!initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
841 return;
never executed: return;
0
842-
843 q->makeCurrent();-
844-
845 if (updateBehavior == QOpenGLWidget::NoPartialUpdate && hasBeenComposed) {
updateBehavior...oPartialUpdateDescription
TRUEnever evaluated
FALSEnever evaluated
hasBeenComposedDescription
TRUEnever evaluated
FALSEnever evaluated
0
846 invalidateFbo();-
847 hasBeenComposed = false;-
848 }
never executed: end of block
0
849-
850 invokeUserPaint();-
851}
never executed: end of block
0
852-
853void QOpenGLWidgetPrivate::invalidateFbo()-
854{-
855 QOpenGLExtensions *f = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());-
856 if (f->hasOpenGLExtension(QOpenGLExtensions::DiscardFramebuffer)) {
f->hasOpenGLEx...rdFramebuffer)Description
TRUEnever evaluated
FALSEnever evaluated
0
857 const int gl_color_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0-
858 const int gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT-
859 const int gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT-
860 const GLenum attachments[] = {-
861 gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment-
862 };-
863 f->glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof attachments / sizeof *attachments, attachments);-
864 } else {
never executed: end of block
0
865 f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);-
866 }
never executed: end of block
0
867}-
868-
869extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);-
870-
871QImage QOpenGLWidgetPrivate::grabFramebuffer()-
872{-
873 Q_Q(QOpenGLWidget);-
874 if (!initialized)
!initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
875 return QImage();
never executed: return QImage();
0
876-
877 if (!inPaintGL)
!inPaintGLDescription
TRUEnever evaluated
FALSEnever evaluated
0
878 render();
never executed: render();
0
879-
880 if (resolvedFbo) {
resolvedFboDescription
TRUEnever evaluated
FALSEnever evaluated
0
881 resolveSamples();-
882 resolvedFbo->bind();-
883 } else {
never executed: end of block
0
884 q->makeCurrent();-
885 }
never executed: end of block
0
886-
887 QImage res = qt_gl_read_framebuffer(q->size() * q->devicePixelRatioF(), false, false);-
888 res.setDevicePixelRatio(q->devicePixelRatioF());-
889-
890 // While we give no guarantees of what is going to be left bound, prefer the-
891 // multisample fbo instead of the resolved one. Clients may continue to-
892 // render straight after calling this function.-
893 if (resolvedFbo)
resolvedFboDescription
TRUEnever evaluated
FALSEnever evaluated
0
894 q->makeCurrent();
never executed: q->makeCurrent();
0
895-
896 return res;
never executed: return res;
0
897}-
898-
899void QOpenGLWidgetPrivate::initializeViewportFramebuffer()-
900{-
901 Q_Q(QOpenGLWidget);-
902 // Legacy behavior for compatibility with QGLWidget when used as a graphics view-
903 // viewport: enable clearing on each painter begin.-
904 q->setAutoFillBackground(true);-
905}
never executed: end of block
0
906-
907void QOpenGLWidgetPrivate::resizeViewportFramebuffer()-
908{-
909 Q_Q(QOpenGLWidget);-
910 if (!initialized)
!initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
911 return;
never executed: return;
0
912-
913 if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size()) {
!fboDescription
TRUEnever evaluated
FALSEnever evaluated
q->size() * q-...!= fbo->size()Description
TRUEnever evaluated
FALSEnever evaluated
0
914 recreateFbo();-
915 q->update();-
916 }
never executed: end of block
0
917}
never executed: end of block
0
918-
919/*!-
920 Constructs a widget which is a child of \a parent, with widget flags set to \a f.-
921 */-
922QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f)-
923 : QWidget(*(new QOpenGLWidgetPrivate), parent, f)-
924{-
925 Q_D(QOpenGLWidget);-
926 if (Q_UNLIKELY(!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)))
__builtin_expe...face)), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
927 qWarning("QOpenGLWidget is not supported on this platform.");
never executed: QMessageLogger(__FILE__, 927, __PRETTY_FUNCTION__).warning("QOpenGLWidget is not supported on this platform.");
0
928 else-
929 d->setRenderToTexture();
never executed: d->setRenderToTexture();
0
930}-
931-
932/*!-
933 Destroys the QOpenGLWidget instance, freeing its resources.-
934-
935 The QOpenGLWidget's context is made current in the destructor, allowing for-
936 safe destruction of any child object that may need to release OpenGL-
937 resources belonging to the context provided by this widget.-
938-
939 \warning if you have objects wrapping OpenGL resources (such as-
940 QOpenGLBuffer, QOpenGLShaderProgram, etc.) as members of a OpenGLWidget-
941 subclass, you may need to add a call to makeCurrent() in that subclass'-
942 destructor as well. Due to the rules of C++ object destruction, those objects-
943 will be destroyed \e{before} calling this function (but after that the-
944 destructor of the subclass has run), therefore making the OpenGL context-
945 current in this function happens too late for their safe disposal.-
946-
947 \sa makeCurrent-
948*/-
949QOpenGLWidget::~QOpenGLWidget()-
950{-
951 makeCurrent();-
952}
never executed: end of block
0
953-
954/*!-
955 Sets this widget's update behavior to \a updateBehavior.-
956 \since 5.5-
957*/-
958void QOpenGLWidget::setUpdateBehavior(UpdateBehavior updateBehavior)-
959{-
960 Q_D(QOpenGLWidget);-
961 d->updateBehavior = updateBehavior;-
962}
never executed: end of block
0
963-
964/*!-
965 \return the update behavior of the widget.-
966 \since 5.5-
967*/-
968QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const-
969{-
970 Q_D(const QOpenGLWidget);-
971 return d->updateBehavior;
never executed: return d->updateBehavior;
0
972}-
973-
974/*!-
975 Sets the requested surface \a format.-
976-
977 When the format is not explicitly set via this function, the format returned by-
978 QSurfaceFormat::defaultFormat() will be used. This means that when having multiple-
979 OpenGL widgets, individual calls to this function can be replaced by one single call to-
980 QSurfaceFormat::setDefaultFormat() before creating the first widget.-
981-
982 \note Requesting an alpha buffer via this function will not lead to the-
983 desired results when the intention is to make other widgets beneath visible.-
984 Instead, use Qt::WA_AlwaysStackOnTop to enable semi-transparent QOpenGLWidget-
985 instances with other widgets visible underneath. Keep in mind however that-
986 this breaks the stacking order, so it will no longer be possible to have-
987 other widgets on top of the QOpenGLWidget.-
988-
989 \sa format(), Qt::WA_AlwaysStackOnTop, QSurfaceFormat::setDefaultFormat()-
990 */-
991void QOpenGLWidget::setFormat(const QSurfaceFormat &format)-
992{-
993 Q_UNUSED(format);-
994 Q_D(QOpenGLWidget);-
995 if (Q_UNLIKELY(d->initialized)) {
__builtin_expe...lized), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
996 qWarning("QOpenGLWidget: Already initialized, setting the format has no effect");-
997 return;
never executed: return;
0
998 }-
999-
1000 d->requestedFormat = format;-
1001}
never executed: end of block
0
1002-
1003/*!-
1004 Returns the context and surface format used by this widget and its toplevel-
1005 window.-
1006-
1007 After the widget and its toplevel have both been created, resized and shown,-
1008 this function will return the actual format of the context. This may differ-
1009 from the requested format if the request could not be fulfilled by the-
1010 platform. It is also possible to get larger color buffer sizes than-
1011 requested.-
1012-
1013 When the widget's window and the related OpenGL resources are not yet-
1014 initialized, the return value is the format that has been set via-
1015 setFormat().-
1016-
1017 \sa setFormat(), context()-
1018 */-
1019QSurfaceFormat QOpenGLWidget::format() const-
1020{-
1021 Q_D(const QOpenGLWidget);-
1022 return d->initialized ? d->context->format() : d->requestedFormat;
never executed: return d->initialized ? d->context->format() : d->requestedFormat;
0
1023}-
1024-
1025/*!-
1026 \return \e true if the widget and OpenGL resources, like the context, have-
1027 been successfully initialized. Note that the return value is always false-
1028 until the widget is shown.-
1029*/-
1030bool QOpenGLWidget::isValid() const-
1031{-
1032 Q_D(const QOpenGLWidget);-
1033 return d->initialized && d->context->isValid();
never executed: return d->initialized && d->context->isValid();
0
1034}-
1035-
1036/*!-
1037 Prepares for rendering OpenGL content for this widget by making the-
1038 corresponding context current and binding the framebuffer object in that-
1039 context.-
1040-
1041 It is not necessary to call this function in most cases, because it-
1042 is called automatically before invoking paintGL().-
1043-
1044 \sa context(), paintGL(), doneCurrent()-
1045 */-
1046void QOpenGLWidget::makeCurrent()-
1047{-
1048 Q_D(QOpenGLWidget);-
1049 if (!d->initialized)
!d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1050 return;
never executed: return;
0
1051-
1052 d->context->makeCurrent(d->surface);-
1053-
1054 if (d->fbo) // there may not be one if we are in reset()
d->fboDescription
TRUEnever evaluated
FALSEnever evaluated
0
1055 d->fbo->bind();
never executed: d->fbo->bind();
0
1056}
never executed: end of block
0
1057-
1058/*!-
1059 Releases the context.-
1060-
1061 It is not necessary to call this function in most cases, since the-
1062 widget will make sure the context is bound and released properly-
1063 when invoking paintGL().-
1064 */-
1065void QOpenGLWidget::doneCurrent()-
1066{-
1067 Q_D(QOpenGLWidget);-
1068 if (!d->initialized)
!d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1069 return;
never executed: return;
0
1070-
1071 d->context->doneCurrent();-
1072}
never executed: end of block
0
1073-
1074/*!-
1075 \return The QOpenGLContext used by this widget or \c 0 if not yet initialized.-
1076-
1077 \note The context and the framebuffer object used by the widget changes when-
1078 reparenting the widget via setParent().-
1079-
1080 \sa QOpenGLContext::setShareContext(), defaultFramebufferObject()-
1081 */-
1082QOpenGLContext *QOpenGLWidget::context() const-
1083{-
1084 Q_D(const QOpenGLWidget);-
1085 return d->context;
never executed: return d->context;
0
1086}-
1087-
1088/*!-
1089 \return The framebuffer object handle or \c 0 if not yet initialized.-
1090-
1091 \note The framebuffer object belongs to the context returned by context()-
1092 and may not be accessible from other contexts.-
1093-
1094 \note The context and the framebuffer object used by the widget changes when-
1095 reparenting the widget via setParent(). In addition, the framebuffer object-
1096 changes on each resize.-
1097-
1098 \sa context()-
1099 */-
1100GLuint QOpenGLWidget::defaultFramebufferObject() const-
1101{-
1102 Q_D(const QOpenGLWidget);-
1103 return d->fbo ? d->fbo->handle() : 0;
never executed: return d->fbo ? d->fbo->handle() : 0;
0
1104}-
1105-
1106/*!-
1107 This virtual function is called once before the first call to-
1108 paintGL() or resizeGL(). Reimplement it in a subclass.-
1109-
1110 This function should set up any required OpenGL resources and state.-
1111-
1112 There is no need to call makeCurrent() because this has already been-
1113 done when this function is called. Note however that the framebuffer-
1114 is not yet available at this stage, so avoid issuing draw calls from-
1115 here. Defer such calls to paintGL() instead.-
1116-
1117 \sa paintGL(), resizeGL()-
1118*/-
1119void QOpenGLWidget::initializeGL()-
1120{-
1121}-
1122-
1123/*!-
1124 This virtual function is called whenever the widget has been-
1125 resized. Reimplement it in a subclass. The new size is passed in-
1126 \a w and \a h.-
1127-
1128 There is no need to call makeCurrent() because this has already been-
1129 done when this function is called. Additionally, the framebuffer is-
1130 also bound.-
1131-
1132 \sa initializeGL(), paintGL()-
1133*/-
1134void QOpenGLWidget::resizeGL(int w, int h)-
1135{-
1136 Q_UNUSED(w);-
1137 Q_UNUSED(h);-
1138}
never executed: end of block
0
1139-
1140/*!-
1141 This virtual function is called whenever the widget needs to be-
1142 painted. Reimplement it in a subclass.-
1143-
1144 There is no need to call makeCurrent() because this has already-
1145 been done when this function is called.-
1146-
1147 Before invoking this function, the context and the framebuffer are-
1148 bound, and the viewport is set up by a call to glViewport(). No-
1149 other state is set and no clearing or drawing is performed by the-
1150 framework.-
1151-
1152 \sa initializeGL(), resizeGL()-
1153*/-
1154void QOpenGLWidget::paintGL()-
1155{-
1156}-
1157-
1158/*!-
1159 Handles resize events that are passed in the \a e event parameter.-
1160 Calls the virtual function resizeGL().-
1161-
1162 \note Avoid overriding this function in derived classes. If that is not-
1163 feasible, make sure that QOpenGLWidget's implementation is invoked-
1164 too. Otherwise the underlying framebuffer object and related resources will-
1165 not get resized properly and will lead to incorrect rendering.-
1166*/-
1167void QOpenGLWidget::resizeEvent(QResizeEvent *e)-
1168{-
1169 Q_D(QOpenGLWidget);-
1170-
1171 if (e->size().isEmpty()) {
e->size().isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1172 d->fakeHidden = true;-
1173 return;
never executed: return;
0
1174 }-
1175 d->fakeHidden = false;-
1176-
1177 d->initialize();-
1178 if (!d->initialized)
!d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1179 return;
never executed: return;
0
1180-
1181 d->recreateFbo();-
1182 resizeGL(width(), height());-
1183 d->sendPaintEvent(QRect(QPoint(0, 0), size()));-
1184}
never executed: end of block
0
1185-
1186/*!-
1187 Handles paint events.-
1188-
1189 Calling QWidget::update() will lead to sending a paint event \a e,-
1190 and thus invoking this function. (NB this is asynchronous and will-
1191 happen at some point after returning from update()). This function-
1192 will then, after some preparation, call the virtual paintGL() to-
1193 update the contents of the QOpenGLWidget's framebuffer. The widget's-
1194 top-level window will then composite the framebuffer's texture with-
1195 the rest of the window.-
1196*/-
1197void QOpenGLWidget::paintEvent(QPaintEvent *e)-
1198{-
1199 Q_UNUSED(e);-
1200 Q_D(QOpenGLWidget);-
1201 if (!d->initialized)
!d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1202 return;
never executed: return;
0
1203-
1204 if (updatesEnabled())
updatesEnabled()Description
TRUEnever evaluated
FALSEnever evaluated
0
1205 d->render();
never executed: d->render();
0
1206}
never executed: end of block
0
1207-
1208/*!-
1209 Renders and returns a 32-bit RGB image of the framebuffer.-
1210-
1211 \note This is a potentially expensive operation because it relies on glReadPixels()-
1212 to read back the pixels. This may be slow and can stall the GPU pipeline.-
1213*/-
1214QImage QOpenGLWidget::grabFramebuffer()-
1215{-
1216 Q_D(QOpenGLWidget);-
1217 return d->grabFramebuffer();
never executed: return d->grabFramebuffer();
0
1218}-
1219-
1220/*!-
1221 \internal-
1222*/-
1223int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const-
1224{-
1225 Q_D(const QOpenGLWidget);-
1226 if (d->inBackingStorePaint)
d->inBackingStorePaintDescription
TRUEnever evaluated
FALSEnever evaluated
0
1227 return QWidget::metric(metric);
never executed: return QWidget::metric(metric);
0
1228-
1229 QWidget *tlw = window();-
1230 QWindow *window = tlw ? tlw->windowHandle() : 0;
tlwDescription
TRUEnever evaluated
FALSEnever evaluated
0
1231 QScreen *screen = tlw && tlw->windowHandle() ? tlw->windowHandle()->screen() : 0;
tlwDescription
TRUEnever evaluated
FALSEnever evaluated
tlw->windowHandle()Description
TRUEnever evaluated
FALSEnever evaluated
0
1232 if (!screen && QGuiApplication::primaryScreen())
!screenDescription
TRUEnever evaluated
FALSEnever evaluated
QGuiApplicatio...rimaryScreen()Description
TRUEnever evaluated
FALSEnever evaluated
0
1233 screen = QGuiApplication::primaryScreen();
never executed: screen = QGuiApplication::primaryScreen();
0
1234-
1235 const float dpmx = qt_defaultDpiX() * 100. / 2.54;-
1236 const float dpmy = qt_defaultDpiY() * 100. / 2.54;-
1237-
1238 switch (metric) {-
1239 case PdmWidth:
never executed: case PdmWidth:
0
1240 return width();
never executed: return width();
0
1241 case PdmHeight:
never executed: case PdmHeight:
0
1242 return height();
never executed: return height();
0
1243 case PdmDepth:
never executed: case PdmDepth:
0
1244 return 32;
never executed: return 32;
0
1245 case PdmWidthMM:
never executed: case PdmWidthMM:
0
1246 if (screen)
screenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1247 return width() * screen->physicalSize().width() / screen->geometry().width();
never executed: return width() * screen->physicalSize().width() / screen->geometry().width();
0
1248 else-
1249 return width() * 1000 / dpmx;
never executed: return width() * 1000 / dpmx;
0
1250 case PdmHeightMM:
never executed: case PdmHeightMM:
0
1251 if (screen)
screenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1252 return height() * screen->physicalSize().height() / screen->geometry().height();
never executed: return height() * screen->physicalSize().height() / screen->geometry().height();
0
1253 else-
1254 return height() * 1000 / dpmy;
never executed: return height() * 1000 / dpmy;
0
1255 case PdmNumColors:
never executed: case PdmNumColors:
0
1256 return 0;
never executed: return 0;
0
1257 case PdmDpiX:
never executed: case PdmDpiX:
0
1258 if (screen)
screenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1259 return qRound(screen->logicalDotsPerInchX());
never executed: return qRound(screen->logicalDotsPerInchX());
0
1260 else-
1261 return qRound(dpmx * 0.0254);
never executed: return qRound(dpmx * 0.0254);
0
1262 case PdmDpiY:
never executed: case PdmDpiY:
0
1263 if (screen)
screenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1264 return qRound(screen->logicalDotsPerInchY());
never executed: return qRound(screen->logicalDotsPerInchY());
0
1265 else-
1266 return qRound(dpmy * 0.0254);
never executed: return qRound(dpmy * 0.0254);
0
1267 case PdmPhysicalDpiX:
never executed: case PdmPhysicalDpiX:
0
1268 if (screen)
screenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1269 return qRound(screen->physicalDotsPerInchX());
never executed: return qRound(screen->physicalDotsPerInchX());
0
1270 else-
1271 return qRound(dpmx * 0.0254);
never executed: return qRound(dpmx * 0.0254);
0
1272 case PdmPhysicalDpiY:
never executed: case PdmPhysicalDpiY:
0
1273 if (screen)
screenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1274 return qRound(screen->physicalDotsPerInchY());
never executed: return qRound(screen->physicalDotsPerInchY());
0
1275 else-
1276 return qRound(dpmy * 0.0254);
never executed: return qRound(dpmy * 0.0254);
0
1277 case PdmDevicePixelRatio:
never executed: case PdmDevicePixelRatio:
0
1278 if (window)
windowDescription
TRUEnever evaluated
FALSEnever evaluated
0
1279 return int(window->devicePixelRatio());
never executed: return int(window->devicePixelRatio());
0
1280 else-
1281 return 1.0;
never executed: return 1.0;
0
1282 case PdmDevicePixelRatioScaled:
never executed: case PdmDevicePixelRatioScaled:
0
1283 if (window)
windowDescription
TRUEnever evaluated
FALSEnever evaluated
0
1284 return int(window->devicePixelRatio() * devicePixelRatioFScale());
never executed: return int(window->devicePixelRatio() * devicePixelRatioFScale());
0
1285 else-
1286 return 1.0;
never executed: return 1.0;
0
1287 default:
never executed: default:
0
1288 qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);-
1289 return 0;
never executed: return 0;
0
1290 }-
1291}-
1292-
1293/*!-
1294 \internal-
1295*/-
1296QPaintDevice *QOpenGLWidget::redirected(QPoint *p) const-
1297{-
1298 Q_D(const QOpenGLWidget);-
1299 if (d->inBackingStorePaint)
d->inBackingStorePaintDescription
TRUEnever evaluated
FALSEnever evaluated
0
1300 return QWidget::redirected(p);
never executed: return QWidget::redirected(p);
0
1301-
1302 return d->paintDevice;
never executed: return d->paintDevice;
0
1303}-
1304-
1305/*!-
1306 \internal-
1307*/-
1308QPaintEngine *QOpenGLWidget::paintEngine() const-
1309{-
1310 Q_D(const QOpenGLWidget);-
1311 // QWidget needs to "punch a hole" into the backingstore. This needs the-
1312 // normal paint engine and device, not the GL one. So in this mode, behave-
1313 // like a normal widget.-
1314 if (d->inBackingStorePaint)
d->inBackingStorePaintDescription
TRUEnever evaluated
FALSEnever evaluated
0
1315 return QWidget::paintEngine();
never executed: return QWidget::paintEngine();
0
1316-
1317 if (!d->initialized)
!d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1318 return 0;
never executed: return 0;
0
1319-
1320 return d->paintDevice->paintEngine();
never executed: return d->paintDevice->paintEngine();
0
1321}-
1322-
1323/*!-
1324 \internal-
1325*/-
1326bool QOpenGLWidget::event(QEvent *e)-
1327{-
1328 Q_D(QOpenGLWidget);-
1329 switch (e->type()) {-
1330 case QEvent::WindowChangeInternal:
never executed: case QEvent::WindowChangeInternal:
0
1331 if (qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts))
(static_cast<Q...penGLContexts)Description
TRUEnever evaluated
FALSEnever evaluated
0
1332 break;
never executed: break;
0
1333 if (d->initialized)
d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1334 d->reset();
never executed: d->reset();
0
1335 // FALLTHROUGH-
1336 case QEvent::Show: // reparenting may not lead to a resize so reinitalize on Show too
code before this statement never executed: case QEvent::Show:
never executed: case QEvent::Show:
0
1337 if (!d->initialized && !size().isEmpty() && window() && window()->windowHandle()) {
!d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
!size().isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
window()Description
TRUEnever evaluated
FALSEnever evaluated
window()->windowHandle()Description
TRUEnever evaluated
FALSEnever evaluated
0
1338 d->initialize();-
1339 if (d->initialized)
d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1340 d->recreateFbo();
never executed: d->recreateFbo();
0
1341 }
never executed: end of block
0
1342 break;
never executed: break;
0
1343 case QEvent::ScreenChangeInternal:
never executed: case QEvent::ScreenChangeInternal:
0
1344 if (d->initialized && d->paintDevice->devicePixelRatioF() != devicePixelRatioF())
d->initializedDescription
TRUEnever evaluated
FALSEnever evaluated
d->paintDevice...ePixelRatioF()Description
TRUEnever evaluated
FALSEnever evaluated
0
1345 d->recreateFbo();
never executed: d->recreateFbo();
0
1346 break;
never executed: break;
0
1347 default:
never executed: default:
0
1348 break;
never executed: break;
0
1349 }-
1350 return QWidget::event(e);
never executed: return QWidget::event(e);
0
1351}-
1352-
1353QT_END_NAMESPACE-
1354-
1355#include "moc_qopenglwidget.cpp"-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9