summaryrefslogtreecommitdiffstats
path: root/src/openglwidgets/qopenglwidget.cpp
diff options
context:
space:
mode:
authorKristoffer Skau <kristoffer.skau@qt.io>2022-11-24 14:31:09 +0100
committerKristoffer Skau <kristoffer.skau@qt.io>2022-12-01 13:42:07 +0100
commitc450f6d21c5153e05bd10afdd54767623cfbe7e8 (patch)
treee7ce6d73cda2f0f83673cad8b528bb67463e9cdd /src/openglwidgets/qopenglwidget.cpp
parent9bc74d14f379ad58d7a80d5514a3db5be5012de0 (diff)
Support stereoscopic rendering with QGraphicsView
This patch adds a manual test and the required work in graphicsview and qwidget private apis to support stereoscopic rendeing. Basically it works by doing the drawing in QGraphicsView::paintEvent twice, once for each buffer. This way the scene items are rendered to both buffers. There's also an update to resolvement in QOpenGLWidgetPrivate so that multisampling works correctly. [ChangeLog][Widgets][QGraphicsView] Added support for stereoscopic rendering. Task-number: QTBUG-64587 Change-Id: I20650682daa805b64fe7f0d2ba086917d3f12229 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/openglwidgets/qopenglwidget.cpp')
-rw-r--r--src/openglwidgets/qopenglwidget.cpp96
1 files changed, 78 insertions, 18 deletions
diff --git a/src/openglwidgets/qopenglwidget.cpp b/src/openglwidgets/qopenglwidget.cpp
index 7a0ac05cee..4d8c181c22 100644
--- a/src/openglwidgets/qopenglwidget.cpp
+++ b/src/openglwidgets/qopenglwidget.cpp
@@ -552,7 +552,7 @@ public:
void destroyFbos();
- void setCurrentTargetBuffer(QOpenGLWidget::TargetBuffer targetBuffer);
+ bool setCurrentTargetBuffer(QOpenGLWidget::TargetBuffer targetBuffer);
QImage grabFramebuffer(QOpenGLWidget::TargetBuffer targetBuffer);
QImage grabFramebuffer() override;
void beginBackingStorePainting() override { inBackingStorePaint = true; }
@@ -560,9 +560,13 @@ public:
void beginCompose() override;
void endCompose() override;
void initializeViewportFramebuffer() override;
+ bool isStereoEnabled() override;
+ bool toggleStereoTargetBuffer() override;
void resizeViewportFramebuffer() override;
void resolveSamples() override;
+ void resolveSamplesForBuffer(QOpenGLWidget::TargetBuffer targetBuffer);
+
QOpenGLContext *context = nullptr;
QRhiTexture *wrapperTextures[2] = {};
QOpenGLFramebufferObject *fbos[2] = {};
@@ -697,8 +701,6 @@ void QOpenGLWidgetPrivate::reset()
void QOpenGLWidgetPrivate::resetRhiDependentResources()
{
- Q_Q(QOpenGLWidget);
-
// QRhi resource created from the QRhi. These must be released whenever the
// widget gets associated with a different QRhi, even when all OpenGL
// contexts share resources.
@@ -706,7 +708,7 @@ void QOpenGLWidgetPrivate::resetRhiDependentResources()
delete wrapperTextures[0];
wrapperTextures[0] = nullptr;
- if (q->format().stereo()) {
+ if (isStereoEnabled()) {
delete wrapperTextures[1];
wrapperTextures[1] = nullptr;
}
@@ -738,9 +740,9 @@ void QOpenGLWidgetPrivate::recreateFbos()
if (samples > 0)
resolvedFbos[QOpenGLWidget::LeftBuffer] = new QOpenGLFramebufferObject(deviceSize);
- const bool stereoEnabled = q->format().stereo();
+ const bool stereo = isStereoEnabled();
- if (stereoEnabled) {
+ if (stereo) {
fbos[QOpenGLWidget::RightBuffer] = new QOpenGLFramebufferObject(deviceSize, format);
if (samples > 0)
resolvedFbos[QOpenGLWidget::RightBuffer] = new QOpenGLFramebufferObject(deviceSize);
@@ -753,11 +755,12 @@ void QOpenGLWidgetPrivate::recreateFbos()
context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ensureRhiDependentResources();
- if (stereoEnabled) {
+ if (stereo) {
currentTargetBuffer = QOpenGLWidget::RightBuffer;
fbos[currentTargetBuffer]->bind();
context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ensureRhiDependentResources();
+ currentTargetBuffer = QOpenGLWidget::LeftBuffer;
}
flushPending = true; // Make sure the FBO is initialized before use
@@ -895,11 +898,17 @@ void QOpenGLWidgetPrivate::initialize()
void QOpenGLWidgetPrivate::resolveSamples()
{
+ resolveSamplesForBuffer(QOpenGLWidget::LeftBuffer);
+ resolveSamplesForBuffer(QOpenGLWidget::RightBuffer);
+}
+
+void QOpenGLWidgetPrivate::resolveSamplesForBuffer(QOpenGLWidget::TargetBuffer targetBuffer)
+{
Q_Q(QOpenGLWidget);
- if (resolvedFbos[currentTargetBuffer]) {
- q->makeCurrent();
- QRect rect(QPoint(0, 0), fbos[currentTargetBuffer]->size());
- QOpenGLFramebufferObject::blitFramebuffer(resolvedFbos[currentTargetBuffer], rect, fbos[currentTargetBuffer], rect);
+ if (resolvedFbos[targetBuffer]) {
+ q->makeCurrent(targetBuffer);
+ QRect rect(QPoint(0, 0), fbos[targetBuffer]->size());
+ QOpenGLFramebufferObject::blitFramebuffer(resolvedFbos[targetBuffer], rect, fbos[targetBuffer], rect);
flushPending = true;
}
}
@@ -924,8 +933,8 @@ void QOpenGLWidgetPrivate::render()
return;
}
- const bool stereoEnabled = q->format().stereo();
- if (stereoEnabled) {
+ const bool stereo = isStereoEnabled();
+ if (stereo) {
static bool warningGiven = false;
if (!fbos[QOpenGLWidget::RightBuffer] && !warningGiven) {
qWarning("QOpenGLWidget: Stereo is enabled, but no right buffer. Using only left buffer");
@@ -936,7 +945,7 @@ void QOpenGLWidgetPrivate::render()
if (updateBehavior == QOpenGLWidget::NoPartialUpdate && hasBeenComposed) {
invalidateFbo();
- if (stereoEnabled && fbos[QOpenGLWidget::RightBuffer]) {
+ if (stereo && fbos[QOpenGLWidget::RightBuffer]) {
setCurrentTargetBuffer(QOpenGLWidget::RightBuffer);
invalidateFbo();
setCurrentTargetBuffer(QOpenGLWidget::LeftBuffer);
@@ -952,7 +961,7 @@ void QOpenGLWidgetPrivate::render()
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbos[currentTargetBuffer]->handle();
q->paintGL();
- if (stereoEnabled && fbos[QOpenGLWidget::RightBuffer]) {
+ if (stereo && fbos[QOpenGLWidget::RightBuffer]) {
setCurrentTargetBuffer(QOpenGLWidget::RightBuffer);
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbos[currentTargetBuffer]->handle();
q->paintGL();
@@ -1017,7 +1026,7 @@ QImage QOpenGLWidgetPrivate::grabFramebuffer(QOpenGLWidget::TargetBuffer targetB
// The second fbo is only created when stereoscopic rendering is enabled
// Just use the default one if not.
- if (targetBuffer == QOpenGLWidget::RightBuffer && !q->format().stereo())
+ if (targetBuffer == QOpenGLWidget::RightBuffer && !isStereoEnabled())
targetBuffer = QOpenGLWidget::LeftBuffer;
if (!fbos[targetBuffer]) // could be completely offscreen, without ever getting a resize event
@@ -1028,7 +1037,7 @@ QImage QOpenGLWidgetPrivate::grabFramebuffer(QOpenGLWidget::TargetBuffer targetB
setCurrentTargetBuffer(targetBuffer);
if (resolvedFbos[targetBuffer]) {
- resolveSamples();
+ resolveSamplesForBuffer(targetBuffer);
resolvedFbos[targetBuffer]->bind();
}
@@ -1054,6 +1063,22 @@ void QOpenGLWidgetPrivate::initializeViewportFramebuffer()
q->setAutoFillBackground(true);
}
+bool QOpenGLWidgetPrivate::isStereoEnabled()
+{
+ Q_Q(QOpenGLWidget);
+ // Note that because this internally might use the requested format,
+ // then this can return a false positive on hardware where
+ // steroscopic rendering is not supported.
+ return q->format().stereo();
+}
+
+bool QOpenGLWidgetPrivate::toggleStereoTargetBuffer()
+{
+ return setCurrentTargetBuffer(currentTargetBuffer == QOpenGLWidget::LeftBuffer ?
+ QOpenGLWidget::RightBuffer :
+ QOpenGLWidget::LeftBuffer);
+}
+
void QOpenGLWidgetPrivate::resizeViewportFramebuffer()
{
Q_Q(QOpenGLWidget);
@@ -1254,6 +1279,34 @@ void QOpenGLWidget::makeCurrent()
}
/*!
+ Prepares for rendering OpenGL content for this widget by making the
+ context for the passed in buffer current and binding the framebuffer object in that
+ context.
+
+ \note This only makes sense to call when stereoscopic rendering is enabled.
+ Nothing will happen if the right buffer is requested when it's disabled.
+
+ It is not necessary to call this function in most cases, because it
+ is called automatically before invoking paintGL().
+
+ \since 6.5
+
+ \sa context(), paintGL(), doneCurrent()
+ */
+void QOpenGLWidget::makeCurrent(TargetBuffer targetBuffer)
+{
+ Q_D(QOpenGLWidget);
+ if (!d->initialized)
+ return;
+
+ // The FBO for the right buffer is only initialized when stereo is set
+ if (targetBuffer == TargetBuffer::RightBuffer && !format().stereo())
+ return;
+
+ d->setCurrentTargetBuffer(targetBuffer); // calls makeCurrent
+}
+
+/*!
Releases the context.
It is not necessary to call this function in most cases, since the
@@ -1585,11 +1638,18 @@ QPaintEngine *QOpenGLWidget::paintEngine() const
return d->paintDevice->paintEngine();
}
-void QOpenGLWidgetPrivate::setCurrentTargetBuffer(QOpenGLWidget::TargetBuffer targetBuffer)
+
+bool QOpenGLWidgetPrivate::setCurrentTargetBuffer(QOpenGLWidget::TargetBuffer targetBuffer)
{
Q_Q(QOpenGLWidget);
+
+ if (targetBuffer == QOpenGLWidget::RightBuffer && !isStereoEnabled())
+ return false;
+
currentTargetBuffer = targetBuffer;
q->makeCurrent();
+
+ return true;
}
/*!