summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi
diff options
context:
space:
mode:
authorKristoffer Skau <kristoffer.skau@qt.io>2022-10-25 22:30:15 +0200
committerKristoffer Skau <kristoffer.skau@qt.io>2022-11-07 09:08:44 +0100
commitc9ad5ad3b73ff60e9a40173b1ae49e67800a4b72 (patch)
treed5e2c7e2ad0c9e597b8c2d2922f37e33aa8dde1f /src/gui/rhi
parent516871d3e5d7815c0fb4a93c71f8cb35f7b3325c (diff)
Add support for stereoscopic content in QRhi::OpenGLES2
Setting the flag QSurfaceFormat::StereoBuffers does not actually do anything, because we do not utilize the extra buffers provided. We need to expose setting the correct buffers using glDrawBuffers between draw calls. Change-Id: I6a5110405e621030ac3a2886fa83df0cfe928723 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/gui/rhi')
-rw-r--r--src/gui/rhi/qrhi.cpp29
-rw-r--r--src/gui/rhi/qrhi_p.h6
-rw-r--r--src/gui/rhi/qrhigles2.cpp67
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h11
4 files changed, 101 insertions, 12 deletions
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index 701cecb3d1..20f4b4beae 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -4860,6 +4860,35 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
*/
/*!
+ \enum QRhiSwapChain::StereoTargetBuffer
+ Selects the backbuffer to use with a stereoscopic swapchain.
+
+ \value LeftBuffer
+ \value RightBuffer
+ */
+
+/*!
+ \return a render target that can be used with beginPass() in order to
+ render to the swapchain's left or right backbuffer. This overload should be
+ used only with stereoscopic rendering, that is, when the associated QWindow
+ is backed by two color buffers, one for each eye, instead of just one.
+
+ When stereoscopic rendering is not supported, the return value will be
+ null. For the time being the only backend and 3D API where traditional
+ stereoscopic rendering is supported is OpenGL (excluding OpenGL ES), in
+ combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported
+ by the graphics and display driver stack at run time. All other backends
+ are going to return null from this overload.
+
+ \note the value must not be cached and reused between frames
+ */
+QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
+{
+ Q_UNUSED(targetBuffer);
+ return nullptr;
+}
+
+/*!
\fn bool QRhiSwapChain::createOrResize()
Creates the swapchain if not already done and resizes the swapchain buffers
diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h
index 1d32d08e84..5ee0d6e1fd 100644
--- a/src/gui/rhi/qrhi_p.h
+++ b/src/gui/rhi/qrhi_p.h
@@ -1379,6 +1379,11 @@ public:
HDR10
};
+ enum StereoTargetBuffer {
+ LeftBuffer,
+ RightBuffer
+ };
+
QRhiResource::Type resourceType() const override;
QWindow *window() const { return m_window; }
@@ -1403,6 +1408,7 @@ public:
virtual QRhiCommandBuffer *currentFrameCommandBuffer() = 0;
virtual QRhiRenderTarget *currentFrameRenderTarget() = 0;
+ virtual QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer);
virtual QSize surfacePixelSize() = 0;
virtual bool isFormatSupported(Format f) = 0;
virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() = 0;
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index 1a7be9eb49..180bb7e360 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -435,6 +435,14 @@ QT_BEGIN_NAMESPACE
#define GL_GEOMETRY_SHADER 0x8DD9
#endif
+#ifndef GL_BACK_LEFT
+#define GL_BACK_LEFT 0x0402
+#endif
+
+#ifndef GL_BACK_RIGHT
+#define GL_BACK_RIGHT 0x0403
+#endif
+
/*!
Constructs a new QRhiGles2InitParams.
@@ -2997,24 +3005,31 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
cmd.args.bindShaderResources.dynamicOffsetCount);
break;
case QGles2CommandBuffer::Command::BindFramebuffer:
+ {
+ QVarLengthArray<GLenum, 8> bufs;
if (cmd.args.bindFramebuffer.fbo) {
f->glBindFramebuffer(GL_FRAMEBUFFER, cmd.args.bindFramebuffer.fbo);
+ const int colorAttCount = cmd.args.bindFramebuffer.colorAttCount;
+ bufs.append(colorAttCount > 0 ? GL_COLOR_ATTACHMENT0 : GL_NONE);
if (caps.maxDrawBuffers > 1) {
- const int colorAttCount = cmd.args.bindFramebuffer.colorAttCount;
- QVarLengthArray<GLenum, 8> bufs;
- for (int i = 0; i < colorAttCount; ++i)
+ for (int i = 1; i < colorAttCount; ++i)
bufs.append(GL_COLOR_ATTACHMENT0 + uint(i));
- f->glDrawBuffers(colorAttCount, bufs.constData());
}
} else {
f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
+ if (cmd.args.bindFramebuffer.stereo && cmd.args.bindFramebuffer.stereoTarget == QRhiSwapChain::RightBuffer)
+ bufs.append(GL_BACK_RIGHT);
+ else
+ bufs.append(caps.gles ? GL_BACK : GL_BACK_LEFT);
}
+ f->glDrawBuffers(bufs.count(), bufs.constData());
if (caps.srgbCapableDefaultFramebuffer) {
if (cmd.args.bindFramebuffer.srgb)
f->glEnable(GL_FRAMEBUFFER_SRGB);
else
f->glDisable(GL_FRAMEBUFFER_SRGB);
}
+ }
break;
case QGles2CommandBuffer::Command::Clear:
f->glDisable(GL_SCISSOR_TEST);
@@ -3980,6 +3995,9 @@ QGles2RenderTargetData *QRhiGles2::enqueueBindFramebuffer(QRhiRenderTarget *rt,
*wantsDsClear = doClearBuffers;
fbCmd.args.bindFramebuffer.fbo = 0;
fbCmd.args.bindFramebuffer.colorAttCount = 1;
+ fbCmd.args.bindFramebuffer.stereo = rtD->stereoTarget.has_value();
+ if (fbCmd.args.bindFramebuffer.stereo)
+ fbCmd.args.bindFramebuffer.stereoTarget = rtD->stereoTarget.value();
break;
case QRhiResource::TextureRenderTarget:
{
@@ -3991,6 +4009,7 @@ QGles2RenderTargetData *QRhiGles2::enqueueBindFramebuffer(QRhiRenderTarget *rt,
*wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
fbCmd.args.bindFramebuffer.fbo = rtTex->framebuffer;
fbCmd.args.bindFramebuffer.colorAttCount = rtD->colorAttCount;
+ fbCmd.args.bindFramebuffer.stereo = false;
for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
it != itEnd; ++it)
@@ -5753,6 +5772,8 @@ void QGles2CommandBuffer::destroy()
QGles2SwapChain::QGles2SwapChain(QRhiImplementation *rhi)
: QRhiSwapChain(rhi),
rt(rhi, this),
+ rtLeft(rhi, this),
+ rtRight(rhi, this),
cb(rhi)
{
}
@@ -5779,6 +5800,16 @@ QRhiRenderTarget *QGles2SwapChain::currentFrameRenderTarget()
return &rt;
}
+QRhiRenderTarget *QGles2SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
+{
+ if (targetBuffer == LeftBuffer)
+ return rtLeft.d.isValid() ? &rtLeft : &rt;
+ else if (targetBuffer == RightBuffer)
+ return rtRight.d.isValid() ? &rtRight : &rt;
+ else
+ Q_UNREACHABLE_RETURN(nullptr);
+}
+
QSize QGles2SwapChain::surfacePixelSize()
{
Q_ASSERT(m_window);
@@ -5795,6 +5826,18 @@ QRhiRenderPassDescriptor *QGles2SwapChain::newCompatibleRenderPassDescriptor()
return new QGles2RenderPassDescriptor(m_rhi);
}
+void QGles2SwapChain::initSwapChainRenderTarget(QGles2SwapChainRenderTarget *rt)
+{
+ rt->setRenderPassDescriptor(m_renderPassDesc); // for the public getter in QRhiRenderTarget
+ rt->d.rp = QRHI_RES(QGles2RenderPassDescriptor, m_renderPassDesc);
+ rt->d.pixelSize = pixelSize;
+ rt->d.dpr = float(m_window->devicePixelRatio());
+ rt->d.sampleCount = qBound(1, m_sampleCount, 64);
+ rt->d.colorAttCount = 1;
+ rt->d.dsAttCount = m_depthStencil ? 1 : 0;
+ rt->d.srgbUpdateAndBlend = m_flags.testFlag(QRhiSwapChain::sRGB);
+}
+
bool QGles2SwapChain::createOrResize()
{
// can be called multiple times due to window resizes
@@ -5813,14 +5856,14 @@ bool QGles2SwapChain::createOrResize()
m_depthStencil->create();
}
- rt.setRenderPassDescriptor(m_renderPassDesc); // for the public getter in QRhiRenderTarget
- rt.d.rp = QRHI_RES(QGles2RenderPassDescriptor, m_renderPassDesc);
- rt.d.pixelSize = pixelSize;
- rt.d.dpr = float(m_window->devicePixelRatio());
- rt.d.sampleCount = qBound(1, m_sampleCount, 64);
- rt.d.colorAttCount = 1;
- rt.d.dsAttCount = m_depthStencil ? 1 : 0;
- rt.d.srgbUpdateAndBlend = m_flags.testFlag(QRhiSwapChain::sRGB);
+ initSwapChainRenderTarget(&rt);
+
+ if (m_window->format().stereo()) {
+ initSwapChainRenderTarget(&rtLeft);
+ rtLeft.d.stereoTarget = QRhiSwapChain::LeftBuffer;
+ initSwapChainRenderTarget(&rtRight);
+ rtRight.d.stereoTarget = QRhiSwapChain::RightBuffer;
+ }
frameCount = 0;
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
index 69164e5ebf..41854f931d 100644
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ b/src/gui/rhi/qrhigles2_p_p.h
@@ -23,6 +23,7 @@
#include <QWindow>
#include <QPointer>
#include <QtCore/private/qduplicatetracker_p.h>
+#include <optional>
QT_BEGIN_NAMESPACE
@@ -173,6 +174,8 @@ struct QGles2RenderTargetData
{
QGles2RenderTargetData(QRhiImplementation *) { }
+ bool isValid() const { return rp != nullptr; }
+
QGles2RenderPassDescriptor *rp = nullptr;
QSize pixelSize;
float dpr = 1;
@@ -181,6 +184,7 @@ struct QGles2RenderTargetData
int dsAttCount = 0;
bool srgbUpdateAndBlend = false;
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
+ std::optional<QRhiSwapChain::StereoTargetBuffer> stereoTarget;
};
struct QGles2SwapChainRenderTarget : public QRhiSwapChainRenderTarget
@@ -399,6 +403,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
GLuint fbo;
bool srgb;
int colorAttCount;
+ bool stereo;
+ QRhiSwapChain::StereoTargetBuffer stereoTarget;
} bindFramebuffer;
struct {
GLenum target;
@@ -690,6 +696,7 @@ struct QGles2SwapChain : public QRhiSwapChain
QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override;
+ QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override;
@@ -697,9 +704,13 @@ struct QGles2SwapChain : public QRhiSwapChain
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool createOrResize() override;
+ void initSwapChainRenderTarget(QGles2SwapChainRenderTarget *rt);
+
QSurface *surface = nullptr;
QSize pixelSize;
QGles2SwapChainRenderTarget rt;
+ QGles2SwapChainRenderTarget rtLeft;
+ QGles2SwapChainRenderTarget rtRight;
QGles2CommandBuffer cb;
int frameCount = 0;
};