diff options
author | Kristoffer Skau <kristoffer.skau@qt.io> | 2022-10-27 15:38:53 +0200 |
---|---|---|
committer | Kristoffer Skau <kristoffer.skau@qt.io> | 2022-11-28 19:12:27 +0100 |
commit | ee2dbcada81f5220a05414d7bf9d5eeebdda8972 (patch) | |
tree | 2bca1fc0c3569a98f26a0717d9e555a9b88f2364 /src/gui/painting | |
parent | 8155bd54261688f333b2d68e2d76f0fc076a0fb4 (diff) |
Add support for stereoscopic content in QOpenGLWidget
Need to add the plumbing necessary to support two textures in
QOpenGLWidget and use these in the backing store. The changes
required on the RHI level is already done in an earlier patch.
Then paintGL() needs to be called twice, once for each buffer.
Also add overloads for the other functions of QOopenGLWidget
where it makes sense to query for left or right buffer.
Then finally create an example.
[ChangeLog][Widgets][QOpenGLWidget] Added support for
stereoscopic rendering.
Fixes: QTBUG-64587
Change-Id: I5a5c53506dcf8a56442097290dceb7eb730d50ce
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/qbackingstoredefaultcompositor.cpp | 128 | ||||
-rw-r--r-- | src/gui/painting/qbackingstoredefaultcompositor_p.h | 11 | ||||
-rw-r--r-- | src/gui/painting/qplatformbackingstore.cpp | 23 | ||||
-rw-r--r-- | src/gui/painting/qplatformbackingstore.h | 4 |
4 files changed, 125 insertions, 41 deletions
diff --git a/src/gui/painting/qbackingstoredefaultcompositor.cpp b/src/gui/painting/qbackingstoredefaultcompositor.cpp index 076ae3e984..1dd116ac81 100644 --- a/src/gui/painting/qbackingstoredefaultcompositor.cpp +++ b/src/gui/painting/qbackingstoredefaultcompositor.cpp @@ -335,7 +335,7 @@ static QRhiGraphicsPipeline *createGraphicsPipeline(QRhi *rhi, static const int UBUF_SIZE = 120; -QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::createPerQuadData(QRhiTexture *texture) +QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::createPerQuadData(QRhiTexture *texture, QRhiTexture *textureExtra) { PerQuadData d; @@ -350,13 +350,24 @@ QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::crea }); if (!d.srb->create()) qWarning("QBackingStoreDefaultCompositor: Failed to create srb"); - d.lastUsedTexture = texture; + if (textureExtra) { + d.srbExtra = m_rhi->newShaderResourceBindings(); + d.srbExtra->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUF_SIZE), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_sampler) + }); + if (!d.srbExtra->create()) + qWarning("QBackingStoreDefaultCompositor: Failed to create srb"); + } + + d.lastUsedTextureExtra = textureExtra; + return d; } -void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTexture *texture) +void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra) { // This whole check-if-texture-ptr-is-different is needed because there is // nothing saying a QPlatformTextureList cannot return a different @@ -371,8 +382,17 @@ void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTextu }); d->srb->updateResources(QRhiShaderResourceBindings::BindingsAreSorted); - d->lastUsedTexture = texture; + + if (textureExtra) { + d->srbExtra->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d->ubuf, 0, UBUF_SIZE), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_sampler) + }); + + d->srbExtra->updateResources(QRhiShaderResourceBindings::BindingsAreSorted); + d->lastUsedTextureExtra = textureExtra; + } } void QBackingStoreDefaultCompositor::updateUniforms(PerQuadData *d, QRhiResourceUpdateBatch *resourceUpdates, @@ -534,11 +554,14 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo continue; } QRhiTexture *t = textures->texture(i); + QRhiTexture *tExtra = textures->textureExtra(i); if (t) { - if (!m_textureQuadData[i].isValid()) - m_textureQuadData[i] = createPerQuadData(t); - else - updatePerQuadData(&m_textureQuadData[i], t); + if (!m_textureQuadData[i].isValid()) { + m_textureQuadData[i] = createPerQuadData(t, tExtra); + } + else { + updatePerQuadData(&m_textureQuadData[i], t, tExtra); + } updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source, NoOption); } else { m_textureQuadData[i].reset(); @@ -549,47 +572,74 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo QRhiCommandBuffer *cb = swapchain->currentFrameCommandBuffer(); const QSize outputSizeInPixels = swapchain->currentPixelSize(); QColor clearColor = translucentBackground ? Qt::transparent : Qt::black; - cb->beginPass(swapchain->currentFrameRenderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates); - cb->setGraphicsPipeline(m_psNoBlend); - cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); - QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf, 0); - cb->setVertexInput(0, 1, &vbufBinding); + cb->resourceUpdate(resourceUpdates); - // Textures for renderToTexture widgets. - for (int i = 0; i < textureWidgetCount; ++i) { - if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { - if (m_textureQuadData[i].isValid()) { - cb->setShaderResources(m_textureQuadData[i].srb); - cb->draw(6); + auto render = [&](std::optional<QRhiSwapChain::StereoTargetBuffer> buffer = std::nullopt) { + QRhiRenderTarget* target = nullptr; + if (buffer.has_value()) + target = swapchain->currentFrameRenderTarget(buffer.value()); + else + target = swapchain->currentFrameRenderTarget(); + + cb->beginPass(target, clearColor, { 1.0f, 0 }); + + cb->setGraphicsPipeline(m_psNoBlend); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + + // Textures for renderToTexture widgets. + for (int i = 0; i < textureWidgetCount; ++i) { + if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { + if (m_textureQuadData[i].isValid()) { + + QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb; + if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra) + srb = m_textureQuadData[i].srbExtra; + + cb->setShaderResources(srb); + cb->draw(6); + } } } - } - cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend : m_psBlend); + cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend : m_psBlend); - // Backingstore texture with the normal widgets. - if (m_texture) { - cb->setShaderResources(m_widgetQuadData.srb); - cb->draw(6); - } + // Backingstore texture with the normal widgets. + if (m_texture) { + cb->setShaderResources(m_widgetQuadData.srb); + cb->draw(6); + } - // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. - for (int i = 0; i < textureWidgetCount; ++i) { - const QPlatformTextureList::Flags flags = textures->flags(i); - if (flags.testFlag(QPlatformTextureList::StacksOnTop)) { - if (m_textureQuadData[i].isValid()) { - if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending)) - cb->setGraphicsPipeline(m_psPremulBlend); - else - cb->setGraphicsPipeline(m_psBlend); - cb->setShaderResources(m_textureQuadData[i].srb); - cb->draw(6); + // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. + for (int i = 0; i < textureWidgetCount; ++i) { + const QPlatformTextureList::Flags flags = textures->flags(i); + if (flags.testFlag(QPlatformTextureList::StacksOnTop)) { + if (m_textureQuadData[i].isValid()) { + if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending)) + cb->setGraphicsPipeline(m_psPremulBlend); + else + cb->setGraphicsPipeline(m_psBlend); + + QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb; + if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra) + srb = m_textureQuadData[i].srbExtra; + + cb->setShaderResources(srb); + cb->draw(6); + } } } - } - cb->endPass(); + cb->endPass(); + }; + + if (swapchain->window()->format().stereo()) { + render(QRhiSwapChain::LeftBuffer); + render(QRhiSwapChain::RightBuffer); + } else + render(); rhi->endFrame(swapchain); diff --git a/src/gui/painting/qbackingstoredefaultcompositor_p.h b/src/gui/painting/qbackingstoredefaultcompositor_p.h index 75080f6994..d69c17f98f 100644 --- a/src/gui/painting/qbackingstoredefaultcompositor_p.h +++ b/src/gui/painting/qbackingstoredefaultcompositor_p.h @@ -70,21 +70,28 @@ private: QRhiBuffer *ubuf = nullptr; // All srbs are layout-compatible. QRhiShaderResourceBindings *srb = nullptr; + QRhiShaderResourceBindings *srbExtra = nullptr; // may be null (used for stereo) QRhiTexture *lastUsedTexture = nullptr; + QRhiTexture *lastUsedTextureExtra = nullptr; // may be null (used for stereo) bool isValid() const { return ubuf && srb; } void reset() { delete ubuf; ubuf = nullptr; delete srb; srb = nullptr; + if (srbExtra) { + delete srbExtra; + srbExtra = nullptr; + } lastUsedTexture = nullptr; + lastUsedTextureExtra = nullptr; } }; PerQuadData m_widgetQuadData; QVarLengthArray<PerQuadData, 8> m_textureQuadData; - PerQuadData createPerQuadData(QRhiTexture *texture); - void updatePerQuadData(PerQuadData *d, QRhiTexture *texture); + PerQuadData createPerQuadData(QRhiTexture *texture, QRhiTexture *textureExtra = nullptr); + void updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra = nullptr); void updateUniforms(PerQuadData *d, QRhiResourceUpdateBatch *resourceUpdates, const QMatrix4x4 &target, const QMatrix3x3 &source, UpdateUniformOption option); }; diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 8a23003065..82e7778b86 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -37,6 +37,7 @@ struct QBackingstoreTextureInfo { void *source; // may be null QRhiTexture *texture; + QRhiTexture *textureExtra; QRect rect; QRect clipRect; QPlatformTextureList::Flags flags; @@ -77,6 +78,12 @@ QRhiTexture *QPlatformTextureList::texture(int index) const return d->textures.at(index).texture; } +QRhiTexture *QPlatformTextureList::textureExtra(int index) const +{ + Q_D(const QPlatformTextureList); + return d->textures.at(index).textureExtra; +} + void *QPlatformTextureList::source(int index) { Q_D(const QPlatformTextureList); @@ -123,6 +130,22 @@ void QPlatformTextureList::appendTexture(void *source, QRhiTexture *texture, con QBackingstoreTextureInfo bi; bi.source = source; bi.texture = texture; + bi.textureExtra = nullptr; + bi.rect = geometry; + bi.clipRect = clipRect; + bi.flags = flags; + d->textures.append(bi); +} + +void QPlatformTextureList::appendTexture(void *source, QRhiTexture *textureLeft, QRhiTexture *textureRight, const QRect &geometry, + const QRect &clipRect, Flags flags) +{ + Q_D(QPlatformTextureList); + + QBackingstoreTextureInfo bi; + bi.source = source; + bi.texture = textureLeft; + bi.textureExtra = textureRight; bi.rect = geometry; bi.clipRect = clipRect; bi.flags = flags; diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index c6b66e57ef..40453574aa 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -103,6 +103,7 @@ public: int count() const; bool isEmpty() const { return count() == 0; } QRhiTexture *texture(int index) const; + QRhiTexture *textureExtra(int index) const; QRect geometry(int index) const; QRect clipRect(int index) const; void *source(int index); @@ -112,6 +113,9 @@ public: void appendTexture(void *source, QRhiTexture *texture, const QRect &geometry, const QRect &clipRect = QRect(), Flags flags = { }); + + void appendTexture(void *source, QRhiTexture *textureLeft, QRhiTexture *textureRight, const QRect &geometry, + const QRect &clipRect = QRect(), Flags flags = { }); void clear(); Q_SIGNALS: |