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

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