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 QtOpenGL 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 <QtGui/QOpenGLFunctions>
42#include <QtGui/private/qpaintdevicewindow_p.h>
43#include <QtGui/private/qopenglextensions_p.h>
44#include <QtGui/private/qopenglcontext_p.h>
45#include <QtGui/QMatrix4x4>
46#include <QtGui/QOffscreenSurface>
47
48#include <QtOpenGL/private/qopenglframebufferobject_p.h>
49#include <QtOpenGL/QOpenGLFramebufferObject>
50#include <QtOpenGL/QOpenGLTextureBlitter>
51#include <QtOpenGL/QOpenGLPaintDevice>
52
53QT_BEGIN_NAMESPACE
54
55/*!
56 \class QOpenGLWindow
57 \inmodule QtOpenGL
58 \since 5.4
59 \brief The QOpenGLWindow class is a convenience subclass of QWindow to perform OpenGL painting.
60
61 QOpenGLWindow is an enhanced QWindow that allows easily creating windows that
62 perform OpenGL rendering using an API that is compatible with QOpenGLWidget
63 Unlike QOpenGLWidget, QOpenGLWindow has no dependency on the widgets module
64 and offers better performance.
65
66 A typical application will subclass QOpenGLWindow and reimplement the following
67 virtual functions:
68
69 \list
70
71 \li initializeGL() to perform OpenGL resource initialization
72
73 \li resizeGL() to set up the transformation matrices and other window size dependent resources
74
75 \li paintGL() to issue OpenGL commands or draw using QPainter
76
77 \endlist
78
79 To schedule a repaint, call the update() function. Note that this will not
80 immediately result in a call to paintGL(). Calling update() multiple times in
81 a row will not change the behavior in any way.
82
83 This is a slot so it can be connected to a \l QTimer::timeout() signal to
84 perform animation. Note however that in the modern OpenGL world it is a much
85 better choice to rely on synchronization to the vertical refresh rate of the
86 display. See \l{QSurfaceFormat::setSwapInterval()}{setSwapInterval()} on a
87 description of the swap interval. With a swap interval of \c 1, which is the
88 case on most systems by default, the
89 \l{QOpenGLContext::swapBuffers()}{swapBuffers()} call, that is executed
90 internally by QOpenGLWindow after each repaint, will block and wait for
91 vsync. This means that whenever the swap is done, an update can be scheduled
92 again by calling update(), without relying on timers.
93
94 To request a specific configuration for the context, use setFormat()
95 like for any other QWindow. This allows, among others, requesting a
96 given OpenGL version and profile, or enabling depth and stencil
97 buffers.
98
99 Unlike QWindow, QOpenGLWindow allows opening a painter on itself and perform
100 QPainter-based drawing.
101
102 QOpenGLWindow supports multiple update behaviors. The default,
103 \c NoPartialUpdate is equivalent to a regular, OpenGL-based QWindow. In
104 contrast, \c PartialUpdateBlit and \c PartialUpdateBlend are
105 more in line with QOpenGLWidget's way of working, where there is always an
106 extra, dedicated framebuffer object present. These modes allow, by
107 sacrificing some performance, redrawing only a smaller area on each paint and
108 having the rest of the content preserved from of the previous frame. This is
109 useful for applications than render incrementally using QPainter, because
110 this way they do not have to redraw the entire window content on each
111 paintGL() call.
112
113 Similarly to QOpenGLWidget, QOpenGLWindow supports the Qt::AA_ShareOpenGLContexts
114 attribute. When enabled, the OpenGL contexts of all QOpenGLWindow instances will share
115 with each other. This allows accessing each other's shareable OpenGL resources.
116
117 For more information on graphics in Qt, see \l {Graphics}.
118 */
119
120/*!
121 \enum QOpenGLWindow::UpdateBehavior
122
123 This enum describes the update strategy of the QOpenGLWindow.
124
125 \value NoPartialUpdate Indicates that the entire window surface will
126 redrawn on each update and so no additional framebuffers are needed.
127 This is the setting used in most cases and is equivalent to how drawing
128 directly via QWindow would function.
129
130 \value PartialUpdateBlit Indicates that the drawing performed in paintGL()
131 does not cover the entire window. In this case an extra framebuffer object
132 is created under the hood, and rendering performed in paintGL() will target
133 this framebuffer. This framebuffer is then blitted onto the window surface's
134 default framebuffer after each paint. This allows having QPainter-based drawing
135 code in paintGL() which only repaints a smaller area at a time, because, unlike
136 NoPartialUpdate, the previous content is preserved.
137
138 \value PartialUpdateBlend Similar to PartialUpdateBlit, but instead of using
139 framebuffer blits, the contents of the extra framebuffer is rendered by
140 drawing a textured quad with blending enabled. This, unlike PartialUpdateBlit,
141 allows alpha blended content and works even when the glBlitFramebuffer is
142 not available. Performance-wise this setting is likely to be somewhat slower
143 than PartialUpdateBlit.
144 */
145
146/*!
147 \fn void QOpenGLWindow::frameSwapped()
148
149 This signal is emitted after the potentially blocking
150 \l{QOpenGLContext::swapBuffers()}{buffer swap} has been done. Applications
151 that wish to continuously repaint synchronized to the vertical refresh,
152 should issue an update() upon this signal. This allows for a much smoother
153 experience compared to the traditional usage of timers.
154*/
155
156// GLES2 builds won't have these constants with the suffixless names
157#ifndef GL_READ_FRAMEBUFFER
158#define GL_READ_FRAMEBUFFER 0x8CA8
159#endif
160#ifndef GL_DRAW_FRAMEBUFFER
161#define GL_DRAW_FRAMEBUFFER 0x8CA9
162#endif
163
164class QOpenGLWindowPaintDevice : public QOpenGLPaintDevice
165{
166public:
167 QOpenGLWindowPaintDevice(QOpenGLWindow *window) : m_window(window) { }
168 void ensureActiveTarget() override;
169
170 QOpenGLWindow *m_window;
171};
172
173class QOpenGLWindowPrivate : public QPaintDeviceWindowPrivate
174{
175 Q_DECLARE_PUBLIC(QOpenGLWindow)
176public:
177 QOpenGLWindowPrivate(QOpenGLContext *shareContext, QOpenGLWindow::UpdateBehavior updateBehavior)
178 : updateBehavior(updateBehavior)
179 , hasFboBlit(false)
180 , shareContext(shareContext)
181 {
182 if (!shareContext)
183 this->shareContext = qt_gl_global_share_context();
184 }
185
186 ~QOpenGLWindowPrivate();
187
188 static QOpenGLWindowPrivate *get(QOpenGLWindow *w) { return w->d_func(); }
189
190 void bindFBO();
191 void initialize();
192
193 void beginPaint(const QRegion &region) override;
194 void endPaint() override;
195 void flush(const QRegion &region) override;
196
197 QOpenGLWindow::UpdateBehavior updateBehavior;
198 bool hasFboBlit;
199 QScopedPointer<QOpenGLContext> context;
200 QOpenGLContext *shareContext;
201 QScopedPointer<QOpenGLFramebufferObject> fbo;
202 QScopedPointer<QOpenGLWindowPaintDevice> paintDevice;
203 QOpenGLTextureBlitter blitter;
204 QColor backgroundColor;
205 QScopedPointer<QOffscreenSurface> offscreenSurface;
206};
207
208QOpenGLWindowPrivate::~QOpenGLWindowPrivate()
209{
210 Q_Q(QOpenGLWindow);
211 if (q->isValid()) {
212 q->makeCurrent(); // this works even when the platformwindow is destroyed
213 paintDevice.reset(nullptr);
214 fbo.reset(nullptr);
215 blitter.destroy();
216 q->doneCurrent();
217 }
218}
219
220void QOpenGLWindowPrivate::initialize()
221{
222 Q_Q(QOpenGLWindow);
223
224 if (context)
225 return;
226
227 if (!q->handle())
228 qWarning("Attempted to initialize QOpenGLWindow without a platform window");
229
230 context.reset(new QOpenGLContext);
231 context->setShareContext(shareContext);
232 context->setFormat(q->requestedFormat());
233 if (!context->create())
234 qWarning("QOpenGLWindow::beginPaint: Failed to create context");
235 if (!context->makeCurrent(q))
236 qWarning("QOpenGLWindow::beginPaint: Failed to make context current");
237
238 paintDevice.reset(new QOpenGLWindowPaintDevice(q));
239 if (updateBehavior == QOpenGLWindow::PartialUpdateBlit)
240 hasFboBlit = QOpenGLFramebufferObject::hasOpenGLFramebufferBlit();
241
242 q->initializeGL();
243}
244
245void QOpenGLWindowPrivate::beginPaint(const QRegion &region)
246{
247 Q_UNUSED(region);
248 Q_Q(QOpenGLWindow);
249
250 initialize();
251 context->makeCurrent(q);
252
253 const int deviceWidth = q->width() * q->devicePixelRatio();
254 const int deviceHeight = q->height() * q->devicePixelRatio();
255 const QSize deviceSize(deviceWidth, deviceHeight);
256 if (updateBehavior > QOpenGLWindow::NoPartialUpdate) {
257 if (!fbo || fbo->size() != deviceSize) {
258 QOpenGLFramebufferObjectFormat fboFormat;
259 fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
260 const int samples = q->requestedFormat().samples();
261 if (samples > 0) {
262 if (updateBehavior != QOpenGLWindow::PartialUpdateBlend)
263 fboFormat.setSamples(samples);
264 else
265 qWarning("QOpenGLWindow: PartialUpdateBlend does not support multisampling");
266 }
267 fbo.reset(new QOpenGLFramebufferObject(deviceSize, fboFormat));
268 markWindowAsDirty();
269 }
270 } else {
271 markWindowAsDirty();
272 }
273
274 paintDevice->setSize(QSize(deviceWidth, deviceHeight));
275 paintDevice->setDevicePixelRatio(q->devicePixelRatio());
276 context->functions()->glViewport(0, 0, deviceWidth, deviceHeight);
277
278 context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, context->defaultFramebufferObject());
279
280 q->paintUnderGL();
281
282 if (updateBehavior > QOpenGLWindow::NoPartialUpdate)
283 fbo->bind();
284}
285
286void QOpenGLWindowPrivate::endPaint()
287{
288 Q_Q(QOpenGLWindow);
289
290 if (updateBehavior > QOpenGLWindow::NoPartialUpdate)
291 fbo->release();
292
293 context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, context->defaultFramebufferObject());
294
295 if (updateBehavior == QOpenGLWindow::PartialUpdateBlit && hasFboBlit) {
296 const int deviceWidth = q->width() * q->devicePixelRatio();
297 const int deviceHeight = q->height() * q->devicePixelRatio();
298 QOpenGLExtensions extensions(context.data());
299 extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle());
300 extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, context->defaultFramebufferObject());
301 extensions.glBlitFramebuffer(0, 0, deviceWidth, deviceHeight,
302 0, 0, deviceWidth, deviceHeight,
303 GL_COLOR_BUFFER_BIT, GL_NEAREST);
304 } else if (updateBehavior > QOpenGLWindow::NoPartialUpdate) {
305 if (updateBehavior == QOpenGLWindow::PartialUpdateBlend) {
306 context->functions()->glEnable(GL_BLEND);
307 context->functions()->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
308 }
309 if (!blitter.isCreated())
310 blitter.create();
311
312 QRect windowRect(QPoint(0, 0), fbo->size());
313 QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect);
314 blitter.bind();
315 blitter.blit(fbo->texture(), target, QOpenGLTextureBlitter::OriginBottomLeft);
316 blitter.release();
317
318 if (updateBehavior == QOpenGLWindow::PartialUpdateBlend)
319 context->functions()->glDisable(GL_BLEND);
320 }
321
322 q->paintOverGL();
323}
324
325void QOpenGLWindowPrivate::bindFBO()
326{
327 if (updateBehavior > QOpenGLWindow::NoPartialUpdate)
328 fbo->bind();
329 else
330 QOpenGLFramebufferObject::bindDefault();
331}
332
333void QOpenGLWindowPrivate::flush(const QRegion &region)
334{
335 Q_UNUSED(region);
336 Q_Q(QOpenGLWindow);
337 context->swapBuffers(q);
338 emit q->frameSwapped();
339}
340
341void QOpenGLWindowPaintDevice::ensureActiveTarget()
342{
343 QOpenGLWindowPrivate::get(m_window)->bindFBO();
344}
345
346/*!
347 Constructs a new QOpenGLWindow with the given \a parent and \a updateBehavior.
348
349 \sa QOpenGLWindow::UpdateBehavior
350 */
351QOpenGLWindow::QOpenGLWindow(QOpenGLWindow::UpdateBehavior updateBehavior, QWindow *parent)
352 : QPaintDeviceWindow(*(new QOpenGLWindowPrivate(nullptr, updateBehavior)), parent)
353{
354 setSurfaceType(QSurface::OpenGLSurface);
355}
356
357/*!
358 Constructs a new QOpenGLWindow with the given \a parent and \a updateBehavior. The QOpenGLWindow's context will share with \a shareContext.
359
360 \sa QOpenGLWindow::UpdateBehavior shareContext
361*/
362QOpenGLWindow::QOpenGLWindow(QOpenGLContext *shareContext, UpdateBehavior updateBehavior, QWindow *parent)
363 : QPaintDeviceWindow(*(new QOpenGLWindowPrivate(shareContext, updateBehavior)), parent)
364{
365 setSurfaceType(QSurface::OpenGLSurface);
366}
367
368/*!
369 Destroys the QOpenGLWindow instance, freeing its resources.
370
371 The OpenGLWindow's context is made current in the destructor, allowing for
372 safe destruction of any child object that may need to release OpenGL
373 resources belonging to the context provided by this window.
374
375 \warning if you have objects wrapping OpenGL resources (such as
376 QOpenGLBuffer, QOpenGLShaderProgram, etc.) as members of a QOpenGLWindow
377 subclass, you may need to add a call to makeCurrent() in that subclass'
378 destructor as well. Due to the rules of C++ object destruction, those objects
379 will be destroyed \e{before} calling this function (but after that the
380 destructor of the subclass has run), therefore making the OpenGL context
381 current in this function happens too late for their safe disposal.
382
383 \sa makeCurrent
384
385 \since 5.5
386*/
387QOpenGLWindow::~QOpenGLWindow()
388{
389 makeCurrent();
390}
391
392/*!
393 \return the update behavior for this QOpenGLWindow.
394*/
395QOpenGLWindow::UpdateBehavior QOpenGLWindow::updateBehavior() const
396{
397 Q_D(const QOpenGLWindow);
398 return d->updateBehavior;
399}
400
401/*!
402 \return \c true if the window's OpenGL resources, like the context, have
403 been successfully initialized. Note that the return value is always \c false
404 until the window becomes exposed (shown).
405*/
406bool QOpenGLWindow::isValid() const
407{
408 Q_D(const QOpenGLWindow);
409 return d->context && d->context->isValid();
410}
411
412/*!
413 Prepares for rendering OpenGL content for this window by making the
414 corresponding context current and binding the framebuffer object, if there is
415 one, in that context context.
416
417 It is not necessary to call this function in most cases, because it is called
418 automatically before invoking paintGL(). It is provided nonetheless to support
419 advanced, multi-threaded scenarios where a thread different than the GUI or main
420 thread may want to update the surface or framebuffer contents. See QOpenGLContext
421 for more information on threading related issues.
422
423 This function is suitable for calling also when the underlying platform window
424 is already destroyed. This means that it is safe to call this function from
425 a QOpenGLWindow subclass' destructor. If there is no native window anymore,
426 an offscreen surface is used instead. This ensures that OpenGL resource
427 cleanup operations in the destructor will always work, as long as
428 this function is called first.
429
430 \sa QOpenGLContext, context(), paintGL(), doneCurrent()
431 */
432void QOpenGLWindow::makeCurrent()
433{
434 Q_D(QOpenGLWindow);
435
436 if (!isValid())
437 return;
438
439 // The platform window may be destroyed at this stage and therefore
440 // makeCurrent() may not safely be called with 'this'.
441 if (handle()) {
442 d->context->makeCurrent(this);
443 } else {
444 if (!d->offscreenSurface) {
445 d->offscreenSurface.reset(new QOffscreenSurface(screen()));
446 d->offscreenSurface->setFormat(d->context->format());
447 d->offscreenSurface->create();
448 }
449 d->context->makeCurrent(d->offscreenSurface.data());
450 }
451
452 d->bindFBO();
453}
454
455/*!
456 Releases the context.
457
458 It is not necessary to call this function in most cases, since the widget
459 will make sure the context is bound and released properly when invoking
460 paintGL().
461
462 \sa makeCurrent()
463 */
464void QOpenGLWindow::doneCurrent()
465{
466 Q_D(QOpenGLWindow);
467
468 if (!isValid())
469 return;
470
471 d->context->doneCurrent();
472}
473
474/*!
475 \return The QOpenGLContext used by this window or \c 0 if not yet initialized.
476 */
477QOpenGLContext *QOpenGLWindow::context() const
478{
479 Q_D(const QOpenGLWindow);
480 return d->context.data();
481}
482
483/*!
484 \return The QOpenGLContext requested to be shared with this window's QOpenGLContext.
485*/
486QOpenGLContext *QOpenGLWindow::shareContext() const
487{
488 Q_D(const QOpenGLWindow);
489 return d->shareContext;
490}
491
492/*!
493 The framebuffer object handle used by this window.
494
495 When the update behavior is set to \c NoPartialUpdate, there is no separate
496 framebuffer object. In this case the returned value is the ID of the
497 default framebuffer.
498
499 Otherwise the value of the ID of the framebuffer object or \c 0 if not
500 yet initialized.
501 */
502GLuint QOpenGLWindow::defaultFramebufferObject() const
503{
504 Q_D(const QOpenGLWindow);
505 if (d->updateBehavior > NoPartialUpdate && d->fbo)
506 return d->fbo->handle();
507 else if (QOpenGLContext *ctx = QOpenGLContext::currentContext())
508 return ctx->defaultFramebufferObject();
509 else
510 return 0;
511}
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() * devicePixelRatio(), hasAlpha, 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(width(), 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