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.cpp129
1 files changed, 81 insertions, 48 deletions
diff --git a/src/openglwidgets/qopenglwidget.cpp b/src/openglwidgets/qopenglwidget.cpp
index d5f4e769d9..4a0bf7f492 100644
--- a/src/openglwidgets/qopenglwidget.cpp
+++ b/src/openglwidgets/qopenglwidget.cpp
@@ -23,8 +23,7 @@
#include <QtWidgets/private/qwidget_p.h>
#include <QtWidgets/private/qwidgetrepaintmanager_p.h>
-#include <QtGui/private/qrhi_p.h>
-#include <QtGui/private/qrhigles2_p.h>
+#include <rhi/qrhi.h>
QT_BEGIN_NAMESPACE
@@ -57,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
@@ -505,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.
@@ -555,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();
@@ -691,8 +695,6 @@ void QOpenGLWidgetPrivate::reset()
destroyFbos();
- resetRhiDependentResources();
-
if (initialized)
q->doneCurrent();
@@ -782,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) {
@@ -830,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
@@ -839,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.
@@ -858,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");
@@ -950,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);
}
@@ -965,13 +964,26 @@ void QOpenGLWidgetPrivate::render()
f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio());
inPaintGL = true;
+#ifdef Q_OS_WASM
+ f->glDepthMask(GL_TRUE);
+#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;
@@ -979,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];
@@ -1016,6 +1039,8 @@ void QOpenGLWidgetPrivate::destroyFbos()
fbos[QOpenGLWidget::RightBuffer] = nullptr;
delete resolvedFbos[QOpenGLWidget::RightBuffer];
resolvedFbos[QOpenGLWidget::RightBuffer] = nullptr;
+
+ resetRhiDependentResources();
}
QImage QOpenGLWidgetPrivate::grabFramebuffer()
@@ -1387,7 +1412,7 @@ GLuint QOpenGLWidget::defaultFramebufferObject(TargetBuffer targetBuffer) const
This virtual function is called once before the first call to
paintGL() or resizeGL(). Reimplement it in a subclass.
- This function should set up any required OpenGL resources and state.
+ This function should set up any required OpenGL resources.
There is no need to call makeCurrent() because this has already been
done when this function is called. Note however that the framebuffer
@@ -1429,6 +1454,17 @@ 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
+ with WebGL, may have limitations on OpenGL contexts in some situations, which
+ can lead to using the context used with the QOpenGLWidget for other purposes
+ as well.
+
When \l QSurfaceFormat::StereoBuffers is enabled, this function
will be called twice - once for each buffer. Query what buffer is
currently bound by calling currentTargetBuffer().
@@ -1441,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);
}
/*!
@@ -1598,15 +1637,9 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
else
return qRound(dpmy * 0.0254);
case PdmDevicePixelRatio:
- if (window)
- return int(window->devicePixelRatio());
- else
- return 1.0;
+ return QWidget::metric(metric);
case PdmDevicePixelRatioScaled:
- if (window)
- return int(window->devicePixelRatio() * devicePixelRatioFScale());
- else
- return int(devicePixelRatioFScale());
+ return QWidget::metric(metric);
default:
qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);
return 0;
@@ -1682,8 +1715,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();