Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qopenglwidget.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qopenglwidget.h"
5#include <QtGui/QOpenGLContext>
6#include <QtGui/QOffscreenSurface>
7#include <QtGui/QOpenGLFunctions>
8#include <QtGui/QWindow>
9#include <QtGui/QGuiApplication>
10#include <QtGui/QScreen>
11#include <QtGui/qpa/qplatformwindow.h>
12#include <QtGui/qpa/qplatformintegration.h>
13#include <QtOpenGL/QOpenGLFramebufferObject>
14#include <QtOpenGL/QOpenGLPaintDevice>
15
16#include <QtGui/private/qguiapplication_p.h>
17#include <QtGui/private/qopenglextensions_p.h>
18#include <QtGui/private/qfont_p.h>
19#include <QtGui/private/qopenglcontext_p.h>
20#include <QtOpenGL/private/qopenglframebufferobject_p.h>
21#include <QtOpenGL/private/qopenglpaintdevice_p.h>
22
23#include <QtWidgets/private/qwidget_p.h>
24#include <QtWidgets/private/qwidgetrepaintmanager_p.h>
25
26#include <rhi/qrhi.h>
27
29
517{
518public:
522
523 void beginPaint() override;
524 void endPaint() override;
525
527};
528
536
538{
539 Q_DECLARE_PUBLIC(QOpenGLWidget)
540public:
542
543 void reset();
545 void recreateFbos();
547
548 QWidgetPrivate::TextureData texture() const override;
549 QPlatformTextureList::Flags textureListFlags() override;
550
552
553 void initialize();
554 void render();
555
556 static constexpr GLenum gl_color_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0
557 static constexpr GLenum gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT
558 static constexpr GLenum gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT
559 static constexpr GLenum gl_depth_stencil_attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT
560
563
564 void destroyFbos();
565
568 QImage grabFramebuffer() override;
570 void endBackingStorePainting() override { inBackingStorePaint = false; }
571 void beginCompose() override;
572 void endCompose() override;
573 void initializeViewportFramebuffer() override;
574 bool isStereoEnabled() override;
575 bool toggleStereoTargetBuffer() override;
576 void resizeViewportFramebuffer() override;
577 void resolveSamples() override;
578
580
591 bool initialized = false;
592 bool fakeHidden = false;
594 bool hasBeenComposed = false;
595 bool flushPending = false;
596 bool inPaintGL = false;
598};
599
601{
602 // NB! autoFillBackground is and must be false by default. Otherwise we would clear on
603 // every QPainter begin() which is not desirable. This is only for legacy use cases,
604 // like using QOpenGLWidget as the viewport of a graphics view, that expect clearing
605 // with the palette's background color.
606 if (w->autoFillBackground()) {
608 if (w->format().hasAlpha()) {
609 f->glClearColor(0, 0, 0, 0);
610 } else {
611 QColor c = w->palette().brush(w->backgroundRole()).color();
612 float alpha = c.alphaF();
613 f->glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
614 }
615 f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
616 }
617}
618
620{
622 if (!wd->initialized)
623 return;
624
625 if (!wd->inPaintGL)
626 QOpenGLContextPrivate::get(wd->context)->defaultFboRedirect = 0;
627}
628
630{
633 if (!wd->initialized)
634 return;
635
637 d->w->makeCurrent();
638 else
639 wd->fbos[wd->currentTargetBuffer]->bind();
640
641
642 if (!wd->inPaintGL)
643 QOpenGLContextPrivate::get(wd->context)->defaultFboRedirect = wd->fbos[wd->currentTargetBuffer]->handle();
644
645 // When used as a viewport, drawing is done via opening a QPainter on the widget
646 // without going through paintEvent(). We will have to make sure a glFlush() is done
647 // before the texture is accessed also in this case.
648 wd->flushPending = true;
649}
650
655
656#ifndef GL_SRGB
657#define GL_SRGB 0x8C40
658#endif
659#ifndef GL_SRGB8
660#define GL_SRGB8 0x8C41
661#endif
662#ifndef GL_SRGB_ALPHA
663#define GL_SRGB_ALPHA 0x8C42
664#endif
665#ifndef GL_SRGB8_ALPHA8
666#define GL_SRGB8_ALPHA8 0x8C43
667#endif
668
669QPlatformTextureList::Flags QOpenGLWidgetPrivate::textureListFlags()
670{
671 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
672 switch (textureFormat) {
673 case GL_SRGB:
674 case GL_SRGB8:
675 case GL_SRGB_ALPHA:
676 case GL_SRGB8_ALPHA8:
678 break;
679 default:
680 break;
681 }
682 return flags;
683}
684
686{
687 Q_Q(QOpenGLWidget);
688
689 // Destroy the OpenGL resources first. These need the context to be current.
690 if (initialized)
691 q->makeCurrent();
692
693 delete paintDevice;
694 paintDevice = nullptr;
695
696 destroyFbos();
697
698 if (initialized)
699 q->doneCurrent();
700
701 // Delete the context first, then the surface. Slots connected to
702 // the context's aboutToBeDestroyed() may still call makeCurrent()
703 // to perform some cleanup.
704 delete context;
705 context = nullptr;
706 delete surface;
707 surface = nullptr;
709}
710
712{
713 // QRhi resource created from the QRhi. These must be released whenever the
714 // widget gets associated with a different QRhi, even when all OpenGL
715 // contexts share resources.
716
717 delete wrapperTextures[0];
718 wrapperTextures[0] = nullptr;
719
720 if (isStereoEnabled()) {
721 delete wrapperTextures[1];
722 wrapperTextures[1] = nullptr;
723 }
724}
725
727{
728 Q_Q(QOpenGLWidget);
729
730 emit q->aboutToResize();
731
733
734 destroyFbos();
735
737 QOpenGLExtensions *extfuncs = static_cast<QOpenGLExtensions *>(context->functions());
738 if (!extfuncs->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
739 samples = 0;
740
743 format.setSamples(samples);
744 if (textureFormat)
745 format.setInternalTextureFormat(textureFormat);
746
747 const QSize deviceSize = q->size() * q->devicePixelRatio();
749 if (samples > 0)
751
752 const bool stereo = isStereoEnabled();
753
754 if (stereo) {
756 if (samples > 0)
758 }
759
760 textureFormat = fbos[QOpenGLWidget::LeftBuffer]->format().internalTextureFormat();
761
763 fbos[currentTargetBuffer]->bind();
764 context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
766
767 if (stereo) {
769 fbos[currentTargetBuffer]->bind();
770 context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
773 }
774
775 flushPending = true; // Make sure the FBO is initialized before use
776
777 paintDevice->setSize(deviceSize);
778 paintDevice->setDevicePixelRatio(q->devicePixelRatio());
779
780 emit q->resized();
781}
782
784{
785 Q_Q(QOpenGLWidget);
786
788
789 // If there is no rhi, because we are completely offscreen, then there's no wrapperTexture either
790 if (rhi && rhi->backend() == QRhi::OpenGLES2) {
791 const QSize deviceSize = q->size() * q->devicePixelRatio();
792 if (!wrapperTextures[currentTargetBuffer] || wrapperTextures[currentTargetBuffer]->pixelSize() != deviceSize) {
793 const uint textureId = resolvedFbos[currentTargetBuffer] ?
795 : (fbos[currentTargetBuffer] ? fbos[currentTargetBuffer]->texture() : 0);
798 else
800 if (!wrapperTextures[currentTargetBuffer]->createFrom({textureId, 0 }))
801 qWarning("QOpenGLWidget: Failed to create wrapper texture");
802 }
803 }
804}
805
807{
808 Q_Q(QOpenGLWidget);
809 if (flushPending) {
810 flushPending = false;
811 q->makeCurrent();
812 static_cast<QOpenGLExtensions *>(context->functions())->flushShared();
813 }
814 hasBeenComposed = true;
815 emit q->aboutToCompose();
816}
817
819{
820 Q_Q(QOpenGLWidget);
821 emit q->frameSwapped();
822}
823
825{
826 Q_Q(QOpenGLWidget);
827 if (initialized)
828 return;
829
830 // If no global shared context get our toplevel's context with which we
831 // will share in order to make the texture usable by the underlying window's backingstore.
832 QWidget *tlw = q->window();
833
834 // Do not include the sample count. Requesting a multisampled context is not necessary
835 // since we render into an FBO, never to an actual surface. What's more, attempting to
836 // create a pbuffer with a multisampled config crashes certain implementations. Just
837 // avoid the entire hassle, the result is the same.
840
842
843 // Could be that something else already initialized the window with some
844 // other graphics API for the QRhi, that's not good.
845 if (rhi && rhi->backend() != QRhi::OpenGLES2) {
846 qWarning("The top-level window is not using OpenGL for composition, '%s' is not compatible with QOpenGLWidget",
847 rhi->backendName());
848 return;
849 }
850
851 // If rhi or contextFromRhi is null, showing content on-screen will not work.
852 // However, offscreen rendering and grabFramebuffer() will stay fully functional.
853
854 QOpenGLContext *contextFromRhi = rhi ? static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles())->context : nullptr;
855
858
859 QOpenGLContext *shareContext = contextFromRhi ? contextFromRhi : qt_gl_global_share_context();
860 if (shareContext) {
861 context->setShareContext(shareContext);
862 context->setScreen(shareContext->screen());
863 }
864 if (Q_UNLIKELY(!context->create())) {
865 qWarning("QOpenGLWidget: Failed to create context");
866 return;
867 }
868
872 surface->create();
873
875 qWarning("QOpenGLWidget: Failed to make context current");
876 return;
877 }
878
879 // Propagate settings that make sense only for the tlw. Note that this only
880 // makes sense for properties that get picked up even after the native
881 // window is created.
882 if (tlw->windowHandle()) {
883 QSurfaceFormat tlwFormat = tlw->windowHandle()->format();
884 if (requestedFormat.swapInterval() != tlwFormat.swapInterval()) {
885 // Most platforms will pick up the changed swap interval on the next
886 // makeCurrent or swapBuffers.
888 tlw->windowHandle()->setFormat(tlwFormat);
889 }
890 if (requestedFormat.swapBehavior() != tlwFormat.swapBehavior()) {
891 tlwFormat.setSwapBehavior(requestedFormat.swapBehavior());
892 tlw->windowHandle()->setFormat(tlwFormat);
893 }
894 }
895
897 paintDevice->setSize(q->size() * q->devicePixelRatio());
898 paintDevice->setDevicePixelRatio(q->devicePixelRatio());
899
900 initialized = true;
901
902 q->initializeGL();
903}
904
910
912{
913 Q_Q(QOpenGLWidget);
914 if (resolvedFbos[targetBuffer]) {
915 q->makeCurrent(targetBuffer);
916 QRect rect(QPoint(0, 0), fbos[targetBuffer]->size());
918 flushPending = true;
919 }
920}
921
923{
924 Q_Q(QOpenGLWidget);
925
926 if (fakeHidden || !initialized)
927 return;
928
930
932 if (!ctx) {
933 qWarning("QOpenGLWidget: No current context, cannot render");
934 return;
935 }
936
938 qWarning("QOpenGLWidget: No fbo, cannot render");
939 return;
940 }
941
942 const bool stereo = isStereoEnabled();
943 if (stereo) {
944 static bool warningGiven = false;
945 if (!fbos[QOpenGLWidget::RightBuffer] && !warningGiven) {
946 qWarning("QOpenGLWidget: Stereo is enabled, but no right buffer. Using only left buffer");
947 warningGiven = true;
948 }
949 }
950
953
954 if (stereo && fbos[QOpenGLWidget::RightBuffer]) {
958 }
959
960 hasBeenComposed = false;
961 }
962
963 QOpenGLFunctions *f = ctx->functions();
964 f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio());
965 inPaintGL = true;
966
967#ifdef Q_OS_WASM
968 f->glDepthMask(GL_TRUE);
969#endif
970
971 QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbos[currentTargetBuffer]->handle();
972
973 f->glUseProgram(0);
974 f->glBindBuffer(GL_ARRAY_BUFFER, 0);
975 f->glEnable(GL_BLEND);
976
977 q->paintGL();
980
981 if (stereo && fbos[QOpenGLWidget::RightBuffer]) {
983 QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbos[currentTargetBuffer]->handle();
984 q->paintGL();
987 }
988 QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = 0;
989
990 inPaintGL = false;
991 flushPending = true;
992}
993
995{
997 if (f->hasOpenGLExtension(QOpenGLExtensions::DiscardFramebuffer)) {
998 const GLenum attachments[] = {
1002#ifdef Q_OS_WASM
1003 // webgl does not allow separate depth and stencil attachments
1004 // QTBUG-69913
1006#endif
1007 };
1008 f->discardFramebuffer(GL_FRAMEBUFFER, GLsizei(std::size(attachments)), attachments);
1009 } else {
1010 f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1011 }
1012}
1013
1015{
1016 QOpenGLExtensions *f = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
1017 if (f->hasOpenGLExtension(QOpenGLExtensions::DiscardFramebuffer)) {
1018 const GLenum attachments[] = {
1021#ifdef Q_OS_WASM
1022 // webgl does not allow separate depth and stencil attachments
1023 // QTBUG-69913
1025#endif
1026 };
1027 f->discardFramebuffer(GL_FRAMEBUFFER, GLsizei(std::size(attachments)), attachments);
1028 }
1029}
1030
1045
1050
1052{
1053 Q_Q(QOpenGLWidget);
1054
1055 initialize();
1056 if (!initialized)
1057 return QImage();
1058
1059 // The second fbo is only created when stereoscopic rendering is enabled
1060 // Just use the default one if not.
1061 if (targetBuffer == QOpenGLWidget::RightBuffer && !isStereoEnabled())
1062 targetBuffer = QOpenGLWidget::LeftBuffer;
1063
1064 if (!fbos[targetBuffer]) // could be completely offscreen, without ever getting a resize event
1065 recreateFbos();
1066
1067 if (!inPaintGL)
1068 render();
1069
1070 setCurrentTargetBuffer(targetBuffer);
1071 if (resolvedFbos[targetBuffer]) {
1072 resolveSamplesForBuffer(targetBuffer);
1073 resolvedFbos[targetBuffer]->bind();
1074 }
1075
1076 const bool hasAlpha = q->format().hasAlpha();
1077 QImage res = qt_gl_read_framebuffer(q->size() * q->devicePixelRatio(), hasAlpha, hasAlpha);
1078 res.setDevicePixelRatio(q->devicePixelRatio());
1079
1080 // While we give no guarantees of what is going to be left bound, prefer the
1081 // multisample fbo instead of the resolved one. Clients may continue to
1082 // render straight after calling this function.
1083 if (resolvedFbos[targetBuffer]) {
1084 setCurrentTargetBuffer(targetBuffer);
1085 }
1086
1087 return res;
1088}
1089
1091{
1092 Q_Q(QOpenGLWidget);
1093 // Legacy behavior for compatibility with QGLWidget when used as a graphics view
1094 // viewport: enable clearing on each painter begin.
1095 q->setAutoFillBackground(true);
1096}
1097
1099{
1100 Q_Q(QOpenGLWidget);
1101 // Note that because this internally might use the requested format,
1102 // then this can return a false positive on hardware where
1103 // steroscopic rendering is not supported.
1104 return q->format().stereo();
1105}
1106
1113
1115{
1116 Q_Q(QOpenGLWidget);
1117 if (!initialized)
1118 return;
1119
1120 if (!fbos[currentTargetBuffer] || q->size() * q->devicePixelRatio() != fbos[currentTargetBuffer]->size()) {
1121 recreateFbos();
1122 q->update();
1123 }
1124}
1125
1129QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f)
1130 : QWidget(*(new QOpenGLWidgetPrivate), parent, f)
1131{
1132 Q_D(QOpenGLWidget);
1135 qWarning("QOpenGLWidget is not supported on this platform.");
1136 else
1137 d->setRenderToTexture();
1138}
1139
1158{
1159 // NB! resetting graphics resources must be done from this destructor,
1160 // *not* from the private class' destructor. This is due to how destruction
1161 // works and due to the QWidget dtor (for toplevels) destroying the repaint
1162 // manager and rhi before the (QObject) private gets destroyed. Hence must
1163 // do it here early on.
1164
1165 Q_D(QOpenGLWidget);
1166 d->reset();
1167}
1168
1174{
1175 Q_D(QOpenGLWidget);
1176 d->updateBehavior = updateBehavior;
1177}
1178
1184{
1185 Q_D(const QOpenGLWidget);
1186 return d->updateBehavior;
1187}
1188
1207{
1208 Q_D(QOpenGLWidget);
1209 if (Q_UNLIKELY(d->initialized)) {
1210 qWarning("QOpenGLWidget: Already initialized, setting the format has no effect");
1211 return;
1212 }
1213
1214 d->requestedFormat = format;
1215}
1216
1234{
1235 Q_D(const QOpenGLWidget);
1236 return d->initialized ? d->context->format() : d->requestedFormat;
1237}
1238
1256{
1257 Q_D(QOpenGLWidget);
1258 if (Q_UNLIKELY(d->initialized)) {
1259 qWarning("QOpenGLWidget: Already initialized, setting the internal texture format has no effect");
1260 return;
1261 }
1262
1263 d->textureFormat = texFormat;
1264}
1265
1275{
1276 Q_D(const QOpenGLWidget);
1277 return d->textureFormat;
1278}
1279
1286{
1287 Q_D(const QOpenGLWidget);
1288 return d->initialized && d->context->isValid();
1289}
1290
1302{
1303 Q_D(QOpenGLWidget);
1304 if (!d->initialized)
1305 return;
1306
1307 d->context->makeCurrent(d->surface);
1308
1309 if (d->fbos[d->currentTargetBuffer]) // there may not be one if we are in reset()
1310 d->fbos[d->currentTargetBuffer]->bind();
1311}
1312
1329{
1330 Q_D(QOpenGLWidget);
1331 if (!d->initialized)
1332 return;
1333
1334 // The FBO for the right buffer is only initialized when stereo is set
1335 if (targetBuffer == TargetBuffer::RightBuffer && !format().stereo())
1336 return;
1337
1338 d->setCurrentTargetBuffer(targetBuffer); // calls makeCurrent
1339}
1340
1349{
1350 Q_D(QOpenGLWidget);
1351 if (!d->initialized)
1352 return;
1353
1354 d->context->doneCurrent();
1355}
1356
1366{
1367 Q_D(const QOpenGLWidget);
1368 return d->context;
1369}
1370
1384{
1385 Q_D(const QOpenGLWidget);
1386 return d->fbos[TargetBuffer::LeftBuffer] ? d->fbos[TargetBuffer::LeftBuffer]->handle() : 0;
1387}
1388
1406{
1407 Q_D(const QOpenGLWidget);
1408 return d->fbos[targetBuffer] ? d->fbos[targetBuffer]->handle() : 0;
1409}
1410
1427
1440{
1441 Q_UNUSED(w);
1442 Q_UNUSED(h);
1443}
1444
1479{
1480 Q_D(QOpenGLWidget);
1481 if (d->initialized)
1482 d->context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1483}
1484
1495{
1496 Q_D(QOpenGLWidget);
1497
1498 if (e->size().isEmpty()) {
1499 d->fakeHidden = true;
1500 return;
1501 }
1502 d->fakeHidden = false;
1503
1504 d->initialize();
1505 if (!d->initialized)
1506 return;
1507
1508 d->recreateFbos();
1509 // Make sure our own context is current before invoking user overrides. If
1510 // the fbo was recreated then there's a chance something else is current now.
1511 makeCurrent();
1512 resizeGL(width(), height());
1513 d->sendPaintEvent(QRect(QPoint(0, 0), size()));
1514}
1515
1528{
1529 Q_UNUSED(e);
1530 Q_D(QOpenGLWidget);
1531
1532 d->initialize();
1533 if (d->initialized) {
1534 d->ensureRhiDependentResources();
1535 if (updatesEnabled())
1536 d->render();
1537 }
1538}
1539
1547{
1548 Q_D(QOpenGLWidget);
1549 return d->grabFramebuffer();
1550}
1551
1564{
1565 Q_D(QOpenGLWidget);
1566 return d->grabFramebuffer(targetBuffer);
1567}
1568
1580{
1581 Q_D(const QOpenGLWidget);
1582 return d->currentTargetBuffer;
1583}
1584
1589{
1590 Q_D(const QOpenGLWidget);
1591 if (d->inBackingStorePaint)
1592 return QWidget::metric(metric);
1593
1596
1597 const float dpmx = qt_defaultDpiX() * 100. / 2.54;
1598 const float dpmy = qt_defaultDpiY() * 100. / 2.54;
1599
1600 switch (metric) {
1601 case PdmWidth:
1602 return width();
1603 case PdmHeight:
1604 return height();
1605 case PdmDepth:
1606 return 32;
1607 case PdmWidthMM:
1608 if (screen)
1609 return width() * screen->physicalSize().width() / screen->geometry().width();
1610 else
1611 return width() * 1000 / dpmx;
1612 case PdmHeightMM:
1613 if (screen)
1614 return height() * screen->physicalSize().height() / screen->geometry().height();
1615 else
1616 return height() * 1000 / dpmy;
1617 case PdmNumColors:
1618 return 0;
1619 case PdmDpiX:
1620 if (screen)
1622 else
1623 return qRound(dpmx * 0.0254);
1624 case PdmDpiY:
1625 if (screen)
1627 else
1628 return qRound(dpmy * 0.0254);
1629 case PdmPhysicalDpiX:
1630 if (screen)
1632 else
1633 return qRound(dpmx * 0.0254);
1634 case PdmPhysicalDpiY:
1635 if (screen)
1637 else
1638 return qRound(dpmy * 0.0254);
1640 return QWidget::metric(metric);
1642 return QWidget::metric(metric);
1643 default:
1644 qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);
1645 return 0;
1646 }
1647}
1648
1653{
1654 Q_D(const QOpenGLWidget);
1655 if (d->inBackingStorePaint)
1656 return QWidget::redirected(p);
1657
1658 return d->paintDevice;
1659}
1660
1665{
1666 Q_D(const QOpenGLWidget);
1667 // QWidget needs to "punch a hole" into the backingstore. This needs the
1668 // normal paint engine and device, not the GL one. So in this mode, behave
1669 // like a normal widget.
1670 if (d->inBackingStorePaint)
1671 return QWidget::paintEngine();
1672
1673 if (!d->initialized)
1674 return nullptr;
1675
1676 return d->paintDevice->paintEngine();
1677}
1678
1679
1681{
1682 Q_Q(QOpenGLWidget);
1683
1684 if (targetBuffer == QOpenGLWidget::RightBuffer && !isStereoEnabled())
1685 return false;
1686
1687 currentTargetBuffer = targetBuffer;
1688 q->makeCurrent();
1689
1690 return true;
1691}
1692
1697{
1698 Q_D(QOpenGLWidget);
1699 switch (e->type()) {
1701 d->resetRhiDependentResources();
1702 break;
1705 break;
1706 if (d->initialized)
1707 d->reset();
1708 if (isHidden())
1709 break;
1710 Q_FALLTHROUGH();
1711 case QEvent::Show: // reparenting may not lead to a resize so reinitialize on Show too
1712 if (d->initialized && !d->wrapperTextures[d->currentTargetBuffer] && window()->windowHandle()) {
1713 // Special case: did grabFramebuffer() for a hidden widget that then became visible.
1714 // Recreate all resources since the context now needs to share with the TLW's.
1716 d->reset();
1717 }
1718 if (d->rhi()) {
1719 if (!d->initialized && !size().isEmpty()) {
1720 d->initialize();
1721 if (d->initialized) {
1722 d->recreateFbos();
1723 // QTBUG-89812: generate a paint event, like resize would do,
1724 // otherwise a QOpenGLWidget in a QDockWidget may not show the
1725 // content upon (un)docking.
1726 d->sendPaintEvent(QRect(QPoint(0, 0), size()));
1727 }
1728 }
1729 }
1730 break;
1732 if (d->initialized && d->paintDevice->devicePixelRatio() != devicePixelRatio())
1733 d->recreateFbos();
1734 break;
1735 default:
1736 break;
1737 }
1738 return QWidget::event(e);
1739}
1740
1742
1743#include "moc_qopenglwidget.cpp"
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
float alphaF() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1497
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
\inmodule QtCore
Definition qcoreevent.h:45
@ DevicePixelRatioChange
Definition qcoreevent.h:287
@ WindowAboutToChangeInternal
Definition qcoreevent.h:285
@ WindowChangeInternal
Definition qcoreevent.h:275
Type type() const
Returns the event type.
Definition qcoreevent.h:304
static QPlatformIntegration * platformIntegration()
QScreen * primaryScreen
the primary (or default) screen of the application.
\inmodule QtGui
Definition qimage.h:37
\inmodule QtGui
void setScreen(QScreen *screen)
Sets the screen to which the offscreen surface is connected.
void create()
Allocates the platform resources associated with the offscreen surface.
void setFormat(const QSurfaceFormat &format)
Sets the offscreen surface format.
static QOpenGLContextPrivate * get(QOpenGLContext *context)
\inmodule QtGui
bool create()
Attempts to create the OpenGL context with the current configuration.
void setScreen(QScreen *screen)
Sets the screen the OpenGL context should be valid for.
bool makeCurrent(QSurface *surface)
Makes the context current in the current thread, against the given surface.
QSurfaceFormat format() const
Returns the format of the underlying platform context, if create() has been called.
void setShareContext(QOpenGLContext *shareContext)
Makes this context share textures, shaders, and other OpenGL resources with shareContext.
void setFormat(const QSurfaceFormat &format)
Sets the format the OpenGL context should be compatible with.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
QScreen * screen() const
Returns the screen the context was created for.
QOpenGLFunctions * functions() const
Get the QOpenGLFunctions instance for this context.
The QOpenGLFramebufferObjectFormat class specifies the format of an OpenGL framebuffer object.
void setAttachment(QOpenGLFramebufferObject::Attachment attachment)
Sets the attachment configuration of a framebuffer object to attachment.
The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer object.
static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, QOpenGLFramebufferObject *source, const QRect &sourceRect, GLbitfield buffers, GLenum filter, int readColorAttachmentIndex, int drawColorAttachmentIndex, FramebufferRestorePolicy restorePolicy)
GLuint handle() const
Returns the OpenGL framebuffer object handle for this framebuffer object (returned by the {glGenFrame...
GLuint texture() const
Returns the texture id for the texture attached as the default rendering target in this framebuffer o...
bool bind()
Switches rendering from the default, windowing system provided framebuffer to this framebuffer object...
The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API.
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
Convenience function that calls glViewport(x, y, width, height).
void glClear(GLbitfield mask)
Convenience function that calls glClear(mask).
The QOpenGLPaintDevice class enables painting to an OpenGL context using QPainter.
QScopedPointer< QOpenGLPaintDevicePrivate > d_ptr
void setDevicePixelRatio(qreal devicePixelRatio)
Sets the device pixel ratio for the paint device to devicePixelRatio.
void setSize(const QSize &size)
Sets the pixel size of the paint device to size.
QOpenGLWidgetPaintDevicePrivate(QOpenGLWidget *widget)
QOpenGLWidgetPaintDevice(QOpenGLWidget *widget)
void ensureActiveTarget() override
This virtual method is provided as a callback to allow re-binding a target frame buffer object or con...
void endBackingStorePainting() override
static constexpr GLenum gl_depth_attachment
void beginCompose() override
QRhiTexture * wrapperTextures[2]
QOffscreenSurface * surface
QPlatformTextureList::Flags textureListFlags() override
QOpenGLWidget::TargetBuffer currentTargetBuffer
bool setCurrentTargetBuffer(QOpenGLWidget::TargetBuffer targetBuffer)
QOpenGLWidgetPrivate()=default
QOpenGLFramebufferObject * fbos[2]
QOpenGLContext * context
void initializeViewportFramebuffer() override
static constexpr GLenum gl_depth_stencil_attachment
QWidgetPrivate::TextureData texture() const override
QOpenGLFramebufferObject * resolvedFbos[2]
void beginBackingStorePainting() override
static constexpr GLenum gl_color_attachment0
void endCompose() override
QPlatformBackingStoreRhiConfig rhiConfig() const override
static constexpr GLenum gl_stencil_attachment
QImage grabFramebuffer() override
QOpenGLWidget::UpdateBehavior updateBehavior
void resolveSamplesForBuffer(QOpenGLWidget::TargetBuffer targetBuffer)
QSurfaceFormat requestedFormat
void resolveSamples() override
bool isStereoEnabled() override
void resizeViewportFramebuffer() override
bool toggleStereoTargetBuffer() override
QOpenGLPaintDevice * paintDevice
\inmodule QtOpenGLWidgets
QSurfaceFormat format() const
Returns the context and surface format used by this widget and its toplevel window.
void setUpdateBehavior(UpdateBehavior updateBehavior)
Sets this widget's update behavior to updateBehavior.
UpdateBehavior updateBehavior() const
GLenum textureFormat() const
virtual void paintGL()
This virtual function is called whenever the widget needs to be painted.
QOpenGLContext * context() const
virtual void resizeGL(int w, int h)
This virtual function is called whenever the widget has been resized.
GLuint defaultFramebufferObject() const
QPaintDevice * redirected(QPoint *p) const override
\reimp
bool isValid() const
void setFormat(const QSurfaceFormat &format)
Sets the requested surface format.
void doneCurrent()
Releases the context.
bool event(QEvent *e) override
\reimp
void paintEvent(QPaintEvent *e) override
Handles paint events.
virtual void initializeGL()
This virtual function is called once before the first call to paintGL() or resizeGL().
void resizeEvent(QResizeEvent *e) override
Handles resize events that are passed in the e event parameter.
TargetBuffer currentTargetBuffer() const
Returns the currently active target buffer.
QPaintEngine * paintEngine() const override
\reimp
int metric(QPaintDevice::PaintDeviceMetric metric) const override
\reimp
QImage grabFramebuffer()
Renders and returns a 32-bit RGB image of the framebuffer.
~QOpenGLWidget()
Destroys the QOpenGLWidget instance, freeing its resources.
QOpenGLWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
Constructs a widget which is a child of parent, with widget flags set to f.
void makeCurrent()
Prepares for rendering OpenGL content for this widget by making the corresponding context current and...
void setTextureFormat(GLenum texFormat)
Sets a custom internal texture format of texFormat.
qreal devicePixelRatio() const
@ PdmDevicePixelRatioScaled
\inmodule QtGui
The QPaintEvent class contains event parameters for paint events.
Definition qevent.h:486
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
The QResizeEvent class contains event parameters for resize events.
Definition qevent.h:548
const QSize & size() const
Returns the new size of the widget.
Definition qevent.h:553
\variable QRhiGles2InitParams::format
\inmodule QtGui
Definition qrhi.h:895
@ RenderTarget
Definition qrhi.h:898
void setPixelSize(const QSize &sz)
Sets the texture size, specified in pixels, to sz.
Definition qrhi.h:976
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
Implementation backend() const
Definition qrhi.cpp:8651
@ OpenGLES2
Definition qrhi.h:1809
const char * backendName() const
Definition qrhi.cpp:8683
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10562
const QRhiNativeHandles * nativeHandles()
Definition qrhi.cpp:10137
T * data() const noexcept
Returns the value of the pointer referenced by this object.
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
qreal logicalDotsPerInchY
the number of logical dots or pixels per inch in the vertical direction
Definition qscreen.h:57
qreal logicalDotsPerInchX
the number of logical dots or pixels per inch in the horizontal direction
Definition qscreen.h:56
QSizeF physicalSize
the screen's physical size (in millimeters)
Definition qscreen.h:50
QRect geometry
the screen's geometry in pixels
Definition qscreen.h:45
qreal physicalDotsPerInchY
the number of physical dots or pixels per inch in the vertical direction
Definition qscreen.h:54
qreal physicalDotsPerInchX
the number of physical dots or pixels per inch in the horizontal direction
Definition qscreen.h:52
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:332
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:335
\inmodule QtCore
Definition qsize.h:25
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
int samples() const
Returns the number of samples per pixel when multisampling is enabled, or -1 when multisampling is di...
static QSurfaceFormat defaultFormat()
Returns the global default surface format.
int swapInterval() const
Returns the swap interval.
void setSamples(int numSamples)
Set the preferred number of samples per pixel when multisampling is enabled to numSamples.
void setSwapInterval(int interval)
Sets the preferred swap interval.
SwapBehavior swapBehavior() const
Returns the configured swap behaviour.
static QWidgetPrivate * get(QWidget *w)
Definition qwidget_p.h:212
QRhi * rhi() const
Definition qwidget.cpp:1030
virtual QPlatformTextureList::Flags textureListFlags()
Definition qwidget_p.h:599
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
int metric(PaintDeviceMetric) const override
Internal implementation of the virtual QPaintDevice::metric() function.
QWidget * window() const
Returns the window for this widget, i.e.
Definition qwidget.cpp:4313
bool isHidden() const
Returns true if the widget is hidden, otherwise returns false.
Definition qwidget.h:877
QSize size
the size of the widget excluding any window frame
Definition qwidget.h:113
int width
the width of the widget excluding any window frame
Definition qwidget.h:114
bool updatesEnabled
whether updates are enabled
Definition qwidget.h:143
int height
the height of the widget excluding any window frame
Definition qwidget.h:115
QPaintEngine * paintEngine() const override
Returns the widget's paint engine.
QWindow * windowHandle() const
If this is a native widget, return the associated QWindow.
Definition qwidget.cpp:2483
QPaintDevice * redirected(QPoint *offset) const override
bool event(QEvent *event) override
This is the main event handler; it handles event event.
Definition qwidget.cpp:8866
QScreen * screen() const
Returns the screen the widget is on.
Definition qwidget.cpp:2496
QSurfaceFormat format() const override
Returns the actual format of this window.
Definition qwindow.cpp:946
EGLContext ctx
QOpenGLWidget * widget
[1]
rect
[4]
Combined button and popup list for selecting options.
@ AA_ShareOpenGLContexts
Definition qnamespace.h:447
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:110
Q_GUI_EXPORT int qt_defaultDpiY()
Definition qfont.cpp:125
#define qWarning
Definition qlogging.h:166
QOpenGLContext * qt_gl_global_share_context()
GLsizei samples
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLfloat GLfloat f
typedef GLsizei(GL_APIENTRYP PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target)
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLbitfield flags
GLsizei const GLenum * attachments
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLuint res
const GLubyte * c
const GLintptr const GLsizei const GLuint const GLuint * fbos
#define GL_ARRAY_BUFFER
Definition qopenglext.h:487
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define GL_FRAMEBUFFER
GLfloat GLfloat p
[1]
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip)
#define GL_SRGB_ALPHA
#define GL_SRGB8_ALPHA8
#define GL_SRGB
#define GL_SRGB8
static bool hasAlpha(const QImage &image)
#define GLuint
#define emit
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:34