summaryrefslogtreecommitdiffstats
path: root/src/openglwidgets/qopenglwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/openglwidgets/qopenglwidget.cpp')
-rw-r--r--src/openglwidgets/qopenglwidget.cpp103
1 files changed, 68 insertions, 35 deletions
diff --git a/src/openglwidgets/qopenglwidget.cpp b/src/openglwidgets/qopenglwidget.cpp
index 5fae60ee17..cf70e16990 100644
--- a/src/openglwidgets/qopenglwidget.cpp
+++ b/src/openglwidgets/qopenglwidget.cpp
@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
\endlist
If you need to trigger a repaint from places other than paintGL() (a
- typical example is when using \l{QTimer}{timers} to animate scenes),
+ typical example is when using \l{QChronoTimer}{timers} to animate scenes),
you should call the widget's update() function to schedule an update.
Your widget's OpenGL rendering context is made current when
@@ -504,9 +504,8 @@ QT_BEGIN_NAMESPACE
benefits on certain hardware architectures common in the mobile and
embedded space when a framebuffer object is used as the rendering target.
The framebuffer object is invalidated between frames with
- glDiscardFramebufferEXT if supported or a glClear. Please see the
- documentation of EXT_discard_framebuffer for more information:
- https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt
+ glInvalidateFramebuffer (if supported), or, as fallbacks,
+ glDiscardFramebufferEXT (if supported) or a call to glClear.
\value PartialUpdate The framebuffer objects color buffer and ancillary
buffers are not invalidated between frames.
@@ -554,7 +553,13 @@ public:
void initialize();
void render();
- void invalidateFbo();
+ static constexpr GLenum gl_color_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0
+ static constexpr GLenum gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT
+ static constexpr GLenum gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT
+ static constexpr GLenum gl_depth_stencil_attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT
+
+ void invalidateFboBeforePainting();
+ void invalidateFboAfterPainting();
void destroyFbos();
@@ -779,9 +784,7 @@ void QOpenGLWidgetPrivate::ensureRhiDependentResources()
{
Q_Q(QOpenGLWidget);
- QRhi *rhi = nullptr;
- if (QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(q->window())->maybeRepaintManager())
- rhi = repaintManager->rhi();
+ QRhi *rhi = QWidgetPrivate::rhi();
// If there is no rhi, because we are completely offscreen, then there's no wrapperTexture either
if (rhi && rhi->backend() == QRhi::OpenGLES2) {
@@ -827,7 +830,6 @@ void QOpenGLWidgetPrivate::initialize()
// If no global shared context get our toplevel's context with which we
// will share in order to make the texture usable by the underlying window's backingstore.
QWidget *tlw = q->window();
- QWidgetPrivate *tlwd = get(tlw);
// Do not include the sample count. Requesting a multisampled context is not necessary
// since we render into an FBO, never to an actual surface. What's more, attempting to
@@ -836,9 +838,7 @@ void QOpenGLWidgetPrivate::initialize()
requestedSamples = requestedFormat.samples();
requestedFormat.setSamples(0);
- QRhi *rhi = nullptr;
- if (QWidgetRepaintManager *repaintManager = tlwd->maybeRepaintManager())
- rhi = repaintManager->rhi();
+ QRhi *rhi = QWidgetPrivate::rhi();
// Could be that something else already initialized the window with some
// other graphics API for the QRhi, that's not good.
@@ -855,9 +855,11 @@ void QOpenGLWidgetPrivate::initialize()
context = new QOpenGLContext;
context->setFormat(requestedFormat);
- if (contextFromRhi) {
- context->setShareContext(contextFromRhi);
- context->setScreen(contextFromRhi->screen());
+
+ QOpenGLContext *shareContext = contextFromRhi ? contextFromRhi : qt_gl_global_share_context();
+ if (shareContext) {
+ context->setShareContext(shareContext);
+ context->setScreen(shareContext->screen());
}
if (Q_UNLIKELY(!context->create())) {
qWarning("QOpenGLWidget: Failed to create context");
@@ -947,11 +949,11 @@ void QOpenGLWidgetPrivate::render()
}
if (updateBehavior == QOpenGLWidget::NoPartialUpdate && hasBeenComposed) {
- invalidateFbo();
+ invalidateFboBeforePainting();
if (stereo && fbos[QOpenGLWidget::RightBuffer]) {
setCurrentTargetBuffer(QOpenGLWidget::RightBuffer);
- invalidateFbo();
+ invalidateFboBeforePainting();
setCurrentTargetBuffer(QOpenGLWidget::LeftBuffer);
}
@@ -967,12 +969,21 @@ void QOpenGLWidgetPrivate::render()
#endif
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbos[currentTargetBuffer]->handle();
+
+ f->glUseProgram(0);
+ f->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ f->glEnable(GL_BLEND);
+
q->paintGL();
+ if (updateBehavior == QOpenGLWidget::NoPartialUpdate)
+ invalidateFboAfterPainting();
if (stereo && fbos[QOpenGLWidget::RightBuffer]) {
setCurrentTargetBuffer(QOpenGLWidget::RightBuffer);
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbos[currentTargetBuffer]->handle();
q->paintGL();
+ if (updateBehavior == QOpenGLWidget::NoPartialUpdate)
+ invalidateFboAfterPainting();
}
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = 0;
@@ -980,32 +991,43 @@ void QOpenGLWidgetPrivate::render()
flushPending = true;
}
-void QOpenGLWidgetPrivate::invalidateFbo()
+void QOpenGLWidgetPrivate::invalidateFboBeforePainting()
{
QOpenGLExtensions *f = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
if (f->hasOpenGLExtension(QOpenGLExtensions::DiscardFramebuffer)) {
- const int gl_color_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0
- const int gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT
- const int gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT
-#ifdef Q_OS_WASM
- // webgl does not allow separate depth and stencil attachments
- // QTBUG-69913
- const int gl_depth_stencil_attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT
-
const GLenum attachments[] = {
- gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment, gl_depth_stencil_attachment
- };
-#else
- const GLenum attachments[] = {
- gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment
- };
+ gl_color_attachment0,
+ gl_depth_attachment,
+ gl_stencil_attachment,
+#ifdef Q_OS_WASM
+ // webgl does not allow separate depth and stencil attachments
+ // QTBUG-69913
+ gl_depth_stencil_attachment
#endif
- f->glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof attachments / sizeof *attachments, attachments);
+ };
+ f->discardFramebuffer(GL_FRAMEBUFFER, GLsizei(std::size(attachments)), attachments);
} else {
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
}
+void QOpenGLWidgetPrivate::invalidateFboAfterPainting()
+{
+ QOpenGLExtensions *f = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
+ if (f->hasOpenGLExtension(QOpenGLExtensions::DiscardFramebuffer)) {
+ const GLenum attachments[] = {
+ gl_depth_attachment,
+ gl_stencil_attachment,
+#ifdef Q_OS_WASM
+ // webgl does not allow separate depth and stencil attachments
+ // QTBUG-69913
+ gl_depth_stencil_attachment
+#endif
+ };
+ f->discardFramebuffer(GL_FRAMEBUFFER, GLsizei(std::size(attachments)), attachments);
+ }
+}
+
void QOpenGLWidgetPrivate::destroyFbos()
{
delete fbos[QOpenGLWidget::LeftBuffer];
@@ -1432,6 +1454,10 @@ void QOpenGLWidget::resizeGL(int w, int h)
other state is set and no clearing or drawing is performed by the
framework.
+ The default implementation performs a glClear(). Subclasses are not expected
+ to invoke the base class implementation and should perform clearing on their
+ own.
+
\note To ensure portability, do not expect that state set in initializeGL()
persists. Rather, set all necessary state, for example, by calling
glEnable(), in paintGL(). This is because some platforms, such as WebAssembly
@@ -1451,6 +1477,9 @@ void QOpenGLWidget::resizeGL(int w, int h)
*/
void QOpenGLWidget::paintGL()
{
+ Q_D(QOpenGLWidget);
+ if (d->initialized)
+ d->context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
/*!
@@ -1611,6 +1640,10 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
return QWidget::metric(metric);
case PdmDevicePixelRatioScaled:
return QWidget::metric(metric);
+ case PdmDevicePixelRatioF_EncodedA:
+ Q_FALLTHROUGH();
+ case PdmDevicePixelRatioF_EncodedB:
+ return QWidget::metric(metric);
default:
qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);
return 0;
@@ -1686,8 +1719,8 @@ bool QOpenGLWidget::event(QEvent *e)
if (!QCoreApplication::testAttribute(Qt::AA_ShareOpenGLContexts))
d->reset();
}
- if (QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(window())->maybeRepaintManager()) {
- if (!d->initialized && !size().isEmpty() && repaintManager->rhi()) {
+ if (d->rhi()) {
+ if (!d->initialized && !size().isEmpty()) {
d->initialize();
if (d->initialized) {
d->recreateFbos();