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 QtGui 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 "qopenglwindow.h"
41#include "qpaintdevicewindow_p.h"
42#include <QtGui/QOpenGLFramebufferObject>
43#include <QtGui/QOpenGLPaintDevice>
44#include <QtGui/QOpenGLFunctions>
45#include <QtGui/QOpenGLTextureBlitter>
46#include <QtGui/private/qopenglextensions_p.h>
47#include <QtGui/private/qopenglcontext_p.h>
48#include <QtGui/QMatrix4x4>
49#include <QtGui/QOffscreenSurface>
50
51QT_BEGIN_NAMESPACE
52
53/*!
54 \class QOpenGLWindow
55 \inmodule QtGui
56 \since 5.4
57 \brief The QOpenGLWindow class is a convenience subclass of QWindow to perform OpenGL painting.
58
59 QOpenGLWindow is an enhanced QWindow that allows easily creating windows that
60 perform OpenGL rendering using an API that is compatible with QOpenGLWidget
61 and is similar to the legacy QGLWidget. Unlike QOpenGLWidget, QOpenGLWindow
62 has no dependency on the widgets module and offers better performance.
63
64 A typical application will subclass QOpenGLWindow and reimplement the following
65 virtual functions:
66
67 \list
68
69 \li initializeGL() to perform OpenGL resource initialization
70
71 \li resizeGL() to set up the transformation matrices and other window size dependent resources
72
73 \li paintGL() to issue OpenGL commands or draw using QPainter
74
75 \endlist
76
77 To schedule a repaint, call the update() function. Note that this will not
78 immediately result in a call to paintGL(). Calling update() multiple times in
79 a row will not change the behavior in any way.
80
81 This is a slot so it can be connected to a \l QTimer::timeout() signal to
82 perform animation. Note however that in the modern OpenGL world it is a much
83 better choice to rely on synchronization to the vertical refresh rate of the
84 display. See \l{QSurfaceFormat::setSwapInterval()}{setSwapInterval()} on a
85 description of the swap interval. With a swap interval of \c 1, which is the
86 case on most systems by default, the
87 \l{QOpenGLContext::swapBuffers()}{swapBuffers()} call, that is executed
88 internally by QOpenGLWindow after each repaint, will block and wait for
89 vsync. This means that whenever the swap is done, an update can be scheduled
90 again by calling update(), without relying on timers.
91
92 To request a specific configuration for the context, use setFormat()
93 like for any other QWindow. This allows, among others, requesting a
94 given OpenGL version and profile, or enabling depth and stencil
95 buffers.
96
97 Unlike QWindow, QOpenGLWindow allows opening a painter on itself and perform
98 QPainter-based drawing.
99
100 QOpenGLWindow supports multiple update behaviors. The default,
101 \c NoPartialUpdate is equivalent to a regular, OpenGL-based QWindow or the
102 legacy QGLWidget. In contrast, \c PartialUpdateBlit and \c PartialUpdateBlend are
103 more in line with QOpenGLWidget's way of working, where there is always an
104 extra, dedicated framebuffer object present. These modes allow, by
105 sacrificing some performance, redrawing only a smaller area on each paint and
106 having the rest of the content preserved from of the previous frame. This is
107 useful for applications than render incrementally using QPainter, because
108 this way they do not have to redraw the entire window content on each
109 paintGL() call.
110
111 Similarly to QOpenGLWidget, QOpenGLWindow supports the Qt::AA_ShareOpenGLContexts
112 attribute. When enabled, the OpenGL contexts of all QOpenGLWindow instances will share
113 with each other. This allows accessing each other's shareable OpenGL resources.
114
115 For more information on graphics in Qt, see \l {Graphics}.
116 */
117
118/*!
119 \enum QOpenGLWindow::UpdateBehavior
120
121 This enum describes the update strategy of the QOpenGLWindow.
122
123 \value NoPartialUpdate Indicates that the entire window surface will
124 redrawn on each update and so no additional framebuffers are needed.
125 This is the setting used in most cases and is equivalent to how drawing
126 directly via QWindow would function.
127
128 \value PartialUpdateBlit Indicates that the drawing performed in paintGL()
129 does not cover the entire window. In this case an extra framebuffer object
130 is created under the hood, and rendering performed in paintGL() will target
131 this framebuffer. This framebuffer is then blitted onto the window surface's
132 default framebuffer after each paint. This allows having QPainter-based drawing
133 code in paintGL() which only repaints a smaller area at a time, because, unlike
134 NoPartialUpdate, the previous content is preserved.
135
136 \value PartialUpdateBlend Similar to PartialUpdateBlit, but instead of using
137 framebuffer blits, the contents of the extra framebuffer is rendered by
138 drawing a textured quad with blending enabled. This, unlike PartialUpdateBlit,
139 allows alpha blended content and works even when the glBlitFramebuffer is
140 not available. Performance-wise this setting is likely to be somewhat slower
141 than PartialUpdateBlit.
142 */
143
144/*!
145 \fn void QOpenGLWindow::frameSwapped()
146
147 This signal is emitted after the potentially blocking
148 \l{QOpenGLContext::swapBuffers()}{buffer swap} has been done. Applications
149 that wish to continuously repaint synchronized to the vertical refresh,
150 should issue an update() upon this signal. This allows for a much smoother
151 experience compared to the traditional usage of timers.
152*/
153
154// GLES2 builds won't have these constants with the suffixless names
155#ifndef GL_READ_FRAMEBUFFER
156#define GL_READ_FRAMEBUFFER 0x8CA8
157#endif
158#ifndef GL_DRAW_FRAMEBUFFER
159#define GL_DRAW_FRAMEBUFFER 0x8CA9
160#endif
161
162class QOpenGLWindowPaintDevice : public QOpenGLPaintDevice
163{
164public:
165 QOpenGLWindowPaintDevice(QOpenGLWindow *window) : m_window(window) { }
166 void ensureActiveTarget() override;
167
168 QOpenGLWindow *m_window;
169};
170
171class QOpenGLWindowPrivate : public QPaintDeviceWindowPrivate
172{
173 Q_DECLARE_PUBLIC(QOpenGLWindow)
174public:
175 QOpenGLWindowPrivate(QOpenGLContext *shareContext, QOpenGLWindow::UpdateBehavior updateBehavior)
176 : updateBehavior(updateBehavior)
177 , hasFboBlit(false)
178 , shareContext(shareContext)
179 {
180 if (!shareContext)
181 this->shareContext = qt_gl_global_share_context();
182 }
183
184 ~QOpenGLWindowPrivate();
185
186 static QOpenGLWindowPrivate *get(QOpenGLWindow *w) { return w->d_func(); }
187
188 void bindFBO();
189 void initialize();
190
191 void beginPaint(const QRegion &region) override;
192 void endPaint() override;
193 void flush(const QRegion &region) override;
194
195 QOpenGLWindow::UpdateBehavior updateBehavior;
196 bool hasFboBlit;
197 QScopedPointer<QOpenGLContext> context;
198 QOpenGLContext *shareContext;
199 QScopedPointer<QOpenGLFramebufferObject> fbo;
200 QScopedPointer<QOpenGLWindowPaintDevice> paintDevice;
201 QOpenGLTextureBlitter blitter;
202 QColor backgroundColor;
203 QScopedPointer<QOffscreenSurface> offscreenSurface;
204};
205
206QOpenGLWindowPrivate::~QOpenGLWindowPrivate()
207{
208 Q_Q(QOpenGLWindow);
209 if (q->isValid()) {
210 q->makeCurrent(); // this works even when the platformwindow is destroyed
211 paintDevice.reset(other: nullptr);
212 fbo.reset(other: nullptr);
213 blitter.destroy();
214 q->doneCurrent();
215 }
216}
217
218void QOpenGLWindowPrivate::initialize()
219{
220 Q_Q(QOpenGLWindow);
221
222 if (context)
223 return;
224
225 if (!q->handle())
226 qWarning(msg: "Attempted to initialize QOpenGLWindow without a platform window");
227
228 context.reset(other: new QOpenGLContext);
229 context->setShareContext(shareContext);
230 context->setFormat(q->requestedFormat());
231 if (!context->create())
232 qWarning(msg: "QOpenGLWindow::beginPaint: Failed to create context");
233 if (!context->makeCurrent(surface: q))
234 qWarning(msg: "QOpenGLWindow::beginPaint: Failed to make context current");
235
236 paintDevice.reset(other: new QOpenGLWindowPaintDevice(q));
237 if (updateBehavior == QOpenGLWindow::PartialUpdateBlit)
238 hasFboBlit = QOpenGLFramebufferObject::hasOpenGLFramebufferBlit();
239
240 q->initializeGL();
241}
242
243void QOpenGLWindowPrivate::beginPaint(const QRegion &region)
244{
245 Q_UNUSED(region);
246 Q_Q(QOpenGLWindow);
247
248 initialize();
249 context->makeCurrent(surface: q);
250
251 const int deviceWidth = q->width() * q->devicePixelRatio();
252 const int deviceHeight = q->height() * q->devicePixelRatio();
253 const QSize deviceSize(deviceWidth, deviceHeight);
254 if (updateBehavior > QOpenGLWindow::NoPartialUpdate) {
255 if (!fbo || fbo->size() != deviceSize) {
256 QOpenGLFramebufferObjectFormat fboFormat;
257 fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
258 const int samples = q->requestedFormat().samples();
259 if (samples > 0) {
260 if (updateBehavior != QOpenGLWindow::PartialUpdateBlend)
261 fboFormat.setSamples(samples);
262 else
263 qWarning(msg: "QOpenGLWindow: PartialUpdateBlend does not support multisampling");
264 }
265 fbo.reset(other: new QOpenGLFramebufferObject(deviceSize, fboFormat));
266 markWindowAsDirty();
267 }
268 } else {
269 markWindowAsDirty();
270 }
271
272 paintDevice->setSize(QSize(deviceWidth, deviceHeight));
273 paintDevice->setDevicePixelRatio(q->devicePixelRatio());
274 context->functions()->glViewport(x: 0, y: 0, width: deviceWidth, height: deviceHeight);
275
276 context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer: context->defaultFramebufferObject());
277
278 q->paintUnderGL();
279
280 if (updateBehavior > QOpenGLWindow::NoPartialUpdate)
281 fbo->bind();
282}
283
284void QOpenGLWindowPrivate::endPaint()
285{
286 Q_Q(QOpenGLWindow);
287
288 if (updateBehavior > QOpenGLWindow::NoPartialUpdate)
289 fbo->release();
290
291 context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer: context->defaultFramebufferObject());
292
293 if (updateBehavior == QOpenGLWindow::PartialUpdateBlit && hasFboBlit) {
294 const int deviceWidth = q->width() * q->devicePixelRatio();
295 const int deviceHeight = q->height() * q->devicePixelRatio();
296 QOpenGLExtensions extensions(context.data());
297 extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer: fbo->handle());
298 extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: context->defaultFramebufferObject());
299 extensions.glBlitFramebuffer(srcX0: 0, srcY0: 0, srcX1: deviceWidth, srcY1: deviceHeight,
300 dstX0: 0, dstY0: 0, dstX1: deviceWidth, dstY1: deviceHeight,
301 GL_COLOR_BUFFER_BIT, GL_NEAREST);
302 } else if (updateBehavior > QOpenGLWindow::NoPartialUpdate) {
303 if (updateBehavior == QOpenGLWindow::PartialUpdateBlend) {
304 context->functions()->glEnable(GL_BLEND);
305 context->functions()->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
306 }
307 if (!blitter.isCreated())
308 blitter.create();
309
310 QRect windowRect(QPoint(0, 0), fbo->size());
311 QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(target: windowRect, viewport: windowRect);
312 blitter.bind();
313 blitter.blit(texture: fbo->texture(), targetTransform: target, sourceOrigin: QOpenGLTextureBlitter::OriginBottomLeft);
314 blitter.release();
315
316 if (updateBehavior == QOpenGLWindow::PartialUpdateBlend)
317 context->functions()->glDisable(GL_BLEND);
318 }
319
320 q->paintOverGL();
321}
322
323void QOpenGLWindowPrivate::bindFBO()
324{
325 if (updateBehavior > QOpenGLWindow::NoPartialUpdate)
326 fbo->bind();
327 else
328 QOpenGLFramebufferObject::bindDefault();
329}
330
331void QOpenGLWindowPrivate::flush(const QRegion &region)
332{
333 Q_UNUSED(region);
334 Q_Q(QOpenGLWindow);
335 context->swapBuffers(surface: q);
336 emit q->frameSwapped();
337}
338
339void QOpenGLWindowPaintDevice::ensureActiveTarget()
340{
341 QOpenGLWindowPrivate::get(w: m_window)->bindFBO();
342}
343
344/*!
345 Constructs a new QOpenGLWindow with the given \a parent and \a updateBehavior.
346
347 \sa QOpenGLWindow::UpdateBehavior
348 */
349QOpenGLWindow::QOpenGLWindow(QOpenGLWindow::UpdateBehavior updateBehavior, QWindow *parent)
350 : QPaintDeviceWindow(*(new QOpenGLWindowPrivate(nullptr, updateBehavior)), parent)
351{
352 setSurfaceType(QSurface::OpenGLSurface);
353}
354
355/*!
356 Constructs a new QOpenGLWindow with the given \a parent and \a updateBehavior. The QOpenGLWindow's context will share with \a shareContext.
357
358 \sa QOpenGLWindow::UpdateBehavior shareContext
359*/
360QOpenGLWindow::QOpenGLWindow(QOpenGLContext *shareContext, UpdateBehavior updateBehavior, QWindow *parent)
361 : QPaintDeviceWindow(*(new QOpenGLWindowPrivate(shareContext, updateBehavior)), parent)
362{
363 setSurfaceType(QSurface::OpenGLSurface);
364}
365
366/*!
367 Destroys the QOpenGLWindow instance, freeing its resources.
368
369 The OpenGLWindow's context is made current in the destructor, allowing for
370 safe destruction of any child object that may need to release OpenGL
371 resources belonging to the context provided by this window.
372
373 \warning if you have objects wrapping OpenGL resources (such as
374 QOpenGLBuffer, QOpenGLShaderProgram, etc.) as members of a QOpenGLWindow
375 subclass, you may need to add a call to makeCurrent() in that subclass'
376 destructor as well. Due to the rules of C++ object destruction, those objects
377 will be destroyed \e{before} calling this function (but after that the
378 destructor of the subclass has run), therefore making the OpenGL context
379 current in this function happens too late for their safe disposal.
380
381 \sa makeCurrent
382
383 \since 5.5
384*/
385QOpenGLWindow::~QOpenGLWindow()
386{
387 makeCurrent();
388}
389
390/*!
391 \return the update behavior for this QOpenGLWindow.
392*/
393QOpenGLWindow::UpdateBehavior QOpenGLWindow::updateBehavior() const
394{
395 Q_D(const QOpenGLWindow);
396 return d->updateBehavior;
397}
398
399/*!
400 \return \c true if the window's OpenGL resources, like the context, have
401 been successfully initialized. Note that the return value is always \c false
402 until the window becomes exposed (shown).
403*/
404bool QOpenGLWindow::isValid() const
405{
406 Q_D(const QOpenGLWindow);
407 return d->context && d->context->isValid();
408}
409
410/*!
411 Prepares for rendering OpenGL content for this window by making the
412 corresponding context current and binding the framebuffer object, if there is
413 one, in that context context.
414
415 It is not necessary to call this function in most cases, because it is called
416 automatically before invoking paintGL(). It is provided nonetheless to support
417 advanced, multi-threaded scenarios where a thread different than the GUI or main
418 thread may want to update the surface or framebuffer contents. See QOpenGLContext
419 for more information on threading related issues.
420
421 This function is suitable for calling also when the underlying platform window
422 is already destroyed. This means that it is safe to call this function from
423 a QOpenGLWindow subclass' destructor. If there is no native window anymore,
424 an offscreen surface is used instead. This ensures that OpenGL resource
425 cleanup operations in the destructor will always work, as long as
426 this function is called first.
427
428 \sa QOpenGLContext, context(), paintGL(), doneCurrent()
429 */
430void QOpenGLWindow::makeCurrent()
431{
432 Q_D(QOpenGLWindow);
433
434 if (!isValid())
435 return;
436
437 // The platform window may be destroyed at this stage and therefore
438 // makeCurrent() may not safely be called with 'this'.
439 if (handle()) {
440 d->context->makeCurrent(surface: this);
441 } else {
442 if (!d->offscreenSurface) {
443 d->offscreenSurface.reset(other: new QOffscreenSurface(screen()));
444 d->offscreenSurface->setFormat(d->context->format());
445 d->offscreenSurface->create();
446 }
447 d->context->makeCurrent(surface: d->offscreenSurface.data());
448 }
449
450 d->bindFBO();
451}
452
453/*!
454 Releases the context.
455
456 It is not necessary to call this function in most cases, since the widget
457 will make sure the context is bound and released properly when invoking
458 paintGL().
459
460 \sa makeCurrent()
461 */
462void QOpenGLWindow::doneCurrent()
463{
464 Q_D(QOpenGLWindow);
465
466 if (!isValid())
467 return;
468
469 d->context->doneCurrent();
470}
471
472/*!
473 \return The QOpenGLContext used by this window or \c 0 if not yet initialized.
474 */
475QOpenGLContext *QOpenGLWindow::context() const
476{
477 Q_D(const QOpenGLWindow);
478 return d->context.data();
479}
480
481/*!
482 \return The QOpenGLContext requested to be shared with this window's QOpenGLContext.
483*/
484QOpenGLContext *QOpenGLWindow::shareContext() const
485{
486 Q_D(const QOpenGLWindow);
487 return d->shareContext;
488}
489
490/*!
491 The framebuffer object handle used by this window.
492
493 When the update behavior is set to \c NoPartialUpdate, there is no separate
494 framebuffer object. In this case the returned value is the ID of the
495 default framebuffer.
496
497 Otherwise the value of the ID of the framebuffer object or \c 0 if not
498 yet initialized.
499 */
500GLuint QOpenGLWindow::defaultFramebufferObject() const
501{
502 Q_D(const QOpenGLWindow);
503 if (d->updateBehavior > NoPartialUpdate && d->fbo)
504 return d->fbo->handle();
505 else if (QOpenGLContext *ctx = QOpenGLContext::currentContext())
506 return ctx->defaultFramebufferObject();
507 else
508 return 0;
509}
510
511extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
512
513/*!
514 Returns a copy of the framebuffer.
515
516 \note This is a potentially expensive operation because it relies on
517 glReadPixels() to read back the pixels. This may be slow and can stall the
518 GPU pipeline.
519
520 \note When used together with update behavior \c NoPartialUpdate, the returned
521 image may not contain the desired content when called after the front and back
522 buffers have been swapped (unless preserved swap is enabled in the underlying
523 windowing system interface). In this mode the function reads from the back
524 buffer and the contents of that may not match the content on the screen (the
525 front buffer). In this case the only place where this function can safely be
526 used is paintGL() or paintOverGL().
527 */
528QImage QOpenGLWindow::grabFramebuffer()
529{
530 if (!isValid())
531 return QImage();
532
533 makeCurrent();
534
535 const bool hasAlpha = format().hasAlpha();
536 QImage img = qt_gl_read_framebuffer(size: size() * devicePixelRatio(), alpha_format: hasAlpha, include_alpha: hasAlpha);
537 img.setDevicePixelRatio(devicePixelRatio());
538 return img;
539}
540
541/*!
542 This virtual function is called once before the first call to paintGL() or
543 resizeGL(). Reimplement it in a subclass.
544
545 This function should set up any required OpenGL resources and state.
546
547 There is no need to call makeCurrent() because this has already been done
548 when this function is called. Note however that the framebuffer, in case
549 partial update mode is used, is not yet available at this stage, so avoid
550 issuing draw calls from here. Defer such calls to paintGL() instead.
551
552 \sa paintGL(), resizeGL()
553 */
554void QOpenGLWindow::initializeGL()
555{
556}
557
558/*!
559 This virtual function is called whenever the widget has been resized.
560 Reimplement it in a subclass. The new size is passed in \a w and \a h.
561
562 \note This is merely a convenience function in order to provide an API that is
563 compatible with QOpenGLWidget. Unlike with QOpenGLWidget, derived classes are
564 free to choose to override resizeEvent() instead of this function.
565
566 \note Avoid issuing OpenGL commands from this function as there may not be a
567 context current when it is invoked. If it cannot be avoided, call makeCurrent().
568
569 \note Scheduling updates from here is not necessary. The windowing systems
570 will send expose events that trigger an update automatically.
571
572 \sa initializeGL(), paintGL()
573 */
574void QOpenGLWindow::resizeGL(int w, int h)
575{
576 Q_UNUSED(w);
577 Q_UNUSED(h);
578}
579
580/*!
581 This virtual function is called whenever the window contents needs to be
582 painted. Reimplement it in a subclass.
583
584 There is no need to call makeCurrent() because this has already
585 been done when this function is called.
586
587 Before invoking this function, the context and the framebuffer, if there is
588 one, are bound, and the viewport is set up by a call to glViewport(). No
589 other state is set and no clearing or drawing is performed by the framework.
590
591 \note When using a partial update behavior, like \c PartialUpdateBlend, the
592 output of the previous paintGL() call is preserved and, after the additional
593 drawing perfomed in the current invocation of the function, the content is
594 blitted or blended over the content drawn directly to the window in
595 paintUnderGL().
596
597 \sa initializeGL(), resizeGL(), paintUnderGL(), paintOverGL(), UpdateBehavior
598 */
599void QOpenGLWindow::paintGL()
600{
601}
602
603/*!
604 The virtual function is called before each invocation of paintGL().
605
606 When the update mode is set to \c NoPartialUpdate, there is no difference
607 between this function and paintGL(), performing rendering in either of them
608 leads to the same result.
609
610 The difference becomes significant when using \c PartialUpdateBlend, where an
611 extra framebuffer object is used. There, paintGL() targets this additional
612 framebuffer object, which preserves its contents, while paintUnderGL() and
613 paintOverGL() target the default framebuffer, i.e. directly the window
614 surface, the contents of which is lost after each displayed frame.
615
616 \note Avoid relying on this function when the update behavior is
617 \c PartialUpdateBlit. This mode involves blitting the extra framebuffer used by
618 paintGL() onto the default framebuffer after each invocation of paintGL(),
619 thus overwriting all drawing generated in this function.
620
621 \sa paintGL(), paintOverGL(), UpdateBehavior
622 */
623void QOpenGLWindow::paintUnderGL()
624{
625}
626
627/*!
628 This virtual function is called after each invocation of paintGL().
629
630 When the update mode is set to NoPartialUpdate, there is no difference
631 between this function and paintGL(), performing rendering in either of them
632 leads to the same result.
633
634 Like paintUnderGL(), rendering in this function targets the default
635 framebuffer of the window, regardless of the update behavior. It gets called
636 after paintGL() has returned and the blit (PartialUpdateBlit) or quad drawing
637 (PartialUpdateBlend) has been done.
638
639 \sa paintGL(), paintUnderGL(), UpdateBehavior
640 */
641void QOpenGLWindow::paintOverGL()
642{
643}
644
645/*!
646 Paint \a event handler. Calls paintGL().
647
648 \sa paintGL()
649 */
650void QOpenGLWindow::paintEvent(QPaintEvent *event)
651{
652 Q_UNUSED(event);
653 paintGL();
654}
655
656/*!
657 Resize \a event handler. Calls resizeGL().
658
659 \sa resizeGL()
660 */
661void QOpenGLWindow::resizeEvent(QResizeEvent *event)
662{
663 Q_UNUSED(event);
664 Q_D(QOpenGLWindow);
665 d->initialize();
666 resizeGL(w: width(), h: height());
667}
668
669/*!
670 \internal
671 */
672int QOpenGLWindow::metric(PaintDeviceMetric metric) const
673{
674 Q_D(const QOpenGLWindow);
675
676 switch (metric) {
677 case PdmDepth:
678 if (d->paintDevice)
679 return d->paintDevice->depth();
680 break;
681 default:
682 break;
683 }
684 return QPaintDeviceWindow::metric(metric);
685}
686
687/*!
688 \internal
689 */
690QPaintDevice *QOpenGLWindow::redirected(QPoint *) const
691{
692 Q_D(const QOpenGLWindow);
693 if (QOpenGLContext::currentContext() == d->context.data())
694 return d->paintDevice.data();
695 return nullptr;
696}
697
698QT_END_NAMESPACE
699

source code of qtbase/src/gui/kernel/qopenglwindow.cpp