diff options
Diffstat (limited to 'src/gui/rhi')
-rw-r--r-- | src/gui/rhi/qrhi.cpp | 36 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p_p.h | 77 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11.cpp | 5 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11_p_p.h | 3 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 10 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2_p_p.h | 2 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 6 | ||||
-rw-r--r-- | src/gui/rhi/qrhinull.cpp | 14 | ||||
-rw-r--r-- | src/gui/rhi/qrhinull_p_p.h | 3 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 6 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan_p_p.h | 2 |
11 files changed, 162 insertions, 2 deletions
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 952183f55e..70525689e9 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -330,9 +330,22 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") ubuf->setSize(512); ubuf->create(); // same as ubuf->destroy(); ubuf->create(); - // that's it, srb needs no changes whatsoever + // That's it, srb needs no changes whatsoever, any references in it to + // ubuf stay valid. When it comes to internal details, such as that + // ubuf may now be backed by a completely different native buffer + // resource, that is is recognized and handled automatically by the + // next setShaderResources(). \endcode + QRhiTextureRenderTarget offers the same contract: calling + QRhiCommandBuffer::beginPass() is safe even when one of the render target's + associated textures or renderbuffers has been rebuilt (by calling \c + create() on it) since the creation of the render target object. This allows + the application to resize a texture by setting a new pixel size on the + QRhiTexture and calling create(), thus creating a whole new native texture + resource underneath, without having to update the QRhiTextureRenderTarget + as that will be done implicitly in beginPass(). + \section3 Pooled objects In addition to resources, there are pooled objects as well, such as, @@ -5669,6 +5682,25 @@ void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates) called inside a pass. Also, with the exception of setGraphicsPipeline(), they expect to have a pipeline set already on the command buffer. Unspecified issues may arise otherwise, depending on the backend. + + If \a rt is a QRhiTextureRenderTarget, beginPass() performs a check to see + if the texture and renderbuffer objects referenced from the render target + are up-to-date. This is similar to what setShaderResources() does for + QRhiShaderResourceBindings. If any of the attachments had been rebuilt + since QRhiTextureRenderTarget::create(), an implicit call to create() is + made on \a rt. Therefore, if \a rt has a QRhiTexture color attachment \c + texture, and one needs to make the texture a different size, the following + is then valid: + \badcode + rt = rhi->newTextureRenderTarget({ { texture } }); + rt->create(); + ... + texture->setPixelSize(new_size); + texture->create(); + cb->beginPass(rt, ...); // this is ok, no explicit rt->create() is required before + \endcode + + \sa endPass() */ void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt, const QColor &colorClearValue, @@ -5684,6 +5716,8 @@ void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt, \a resourceUpdates, when not null, specifies a resource update batch that is to be committed and then released. + + \sa beginPass() */ void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates) { diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 7a3f94846d..9e8a3a846f 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -706,6 +706,83 @@ private: int p = 0; }; +struct QRhiRenderTargetAttachmentTracker +{ + struct ResId { quint64 id; uint generation; }; + using ResIdList = QVarLengthArray<ResId, 8 * 2 + 1>; // color, resolve, ds + + template<typename TexType, typename RenderBufferType> + static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst); + + template<typename TexType, typename RenderBufferType> + static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList ¤tResIdList); +}; + +inline bool operator==(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b) +{ + return a.id == b.id && a.generation == b.generation; +} + +inline bool operator!=(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b) +{ + return !(a == b); +} + +template<typename TexType, typename RenderBufferType> +void QRhiRenderTargetAttachmentTracker::updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst) +{ + const quintptr colorAttCount = desc.cendColorAttachments() - desc.cbeginColorAttachments(); + const bool hasDepthStencil = desc.depthStencilBuffer() || desc.depthTexture(); + dst->resize(colorAttCount * 2 + (hasDepthStencil ? 1 : 0)); + int n = 0; + for (auto it = desc.cbeginColorAttachments(), itEnd = desc.cendColorAttachments(); it != itEnd; ++it, ++n) { + const QRhiColorAttachment &colorAtt(*it); + if (colorAtt.texture()) { + TexType *texD = QRHI_RES(TexType, colorAtt.texture()); + (*dst)[n] = { texD->globalResourceId(), texD->generation }; + } else if (colorAtt.renderBuffer()) { + RenderBufferType *rbD = QRHI_RES(RenderBufferType, colorAtt.renderBuffer()); + (*dst)[n] = { rbD->globalResourceId(), rbD->generation }; + } else { + (*dst)[n] = { 0, 0 }; + } + ++n; + if (colorAtt.resolveTexture()) { + TexType *texD = QRHI_RES(TexType, colorAtt.resolveTexture()); + (*dst)[n] = { texD->globalResourceId(), texD->generation }; + } else { + (*dst)[n] = { 0, 0 }; + } + } + if (hasDepthStencil) { + if (desc.depthTexture()) { + TexType *depthTexD = QRHI_RES(TexType, desc.depthTexture()); + (*dst)[n] = { depthTexD->globalResourceId(), depthTexD->generation }; + } else if (desc.depthStencilBuffer()) { + RenderBufferType *depthRbD = QRHI_RES(RenderBufferType, desc.depthStencilBuffer()); + (*dst)[n] = { depthRbD->globalResourceId(), depthRbD->generation }; + } else { + (*dst)[n] = { 0, 0 }; + } + } +} + +template<typename TexType, typename RenderBufferType> +bool QRhiRenderTargetAttachmentTracker::isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList ¤tResIdList) +{ + // Just as setShaderResources() recognizes if an srb's referenced + // resources have been rebuilt (got a create() since the srb's + // create()), we should do the same for the textures and renderbuffers + // referenced from the rendertarget. It is not uncommon that a texture + // or ds buffer gets resized due to following a window size in some + // form, which involves a create() on them. It is then nice if the + // render target auto-rebuilds in beginPass(). + + ResIdList resIdList; + updateResIdList<TexType, RenderBufferType>(desc, &resIdList); + return resIdList == currentResIdList; +} + QT_END_NAMESPACE #endif diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index f6076bc800..a8fd9a686f 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -1762,6 +1762,8 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb, QD3D11TextureRenderTarget *rtTex = QRHI_RES(QD3D11TextureRenderTarget, rt); wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents); wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents); + if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(rtTex->description(), rtD->currentResIdList)) + rtTex->create(); } cbD->commands.get().cmd = QD3D11CommandBuffer::Command::ResetShaderResources; @@ -2898,6 +2900,7 @@ bool QD3D11RenderBuffer::create() QRHI_PROF; QRHI_PROF_F(newRenderBuffer(this, false, false, int(sampleDesc.Count))); + generation += 1; rhiD->registerResource(this); return true; } @@ -3609,6 +3612,8 @@ bool QD3D11TextureRenderTarget::create() d.dsv = dsv; d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc); + QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D11Texture, QD3D11RenderBuffer>(m_desc, &d.currentResIdList); + rhiD->registerResource(this); return true; } diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 3a333fe8a7..70c7ad969b 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -96,6 +96,7 @@ struct QD3D11RenderBuffer : public QRhiRenderBuffer ID3D11RenderTargetView *rtv = nullptr; DXGI_FORMAT dxgiFormat; DXGI_SAMPLE_DESC sampleDesc; + uint generation = 0; friend class QRhiD3D11; }; @@ -172,6 +173,8 @@ struct QD3D11RenderTargetData static const int MAX_COLOR_ATTACHMENTS = 8; ID3D11RenderTargetView *rtv[MAX_COLOR_ATTACHMENTS]; ID3D11DepthStencilView *dsv = nullptr; + + QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList; }; struct QD3D11ReferenceRenderTarget : public QRhiRenderTarget diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index f0b97ce36a..67d08d3042 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -3793,6 +3793,12 @@ void QRhiGles2::beginPass(QRhiCommandBuffer *cb, // glMemoryBarrier() calls based on that tracker when submitted. enqueueBarriersForPass(cbD); + if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) { + QGles2TextureRenderTarget *rtTex = QRHI_RES(QGles2TextureRenderTarget, rt); + if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QGles2Texture, QGles2RenderBuffer>(rtTex->description(), rtTex->d.currentResIdList)) + rtTex->create(); + } + bool wantsColorClear, wantsDsClear; QGles2RenderTargetData *rtD = enqueueBindFramebuffer(rt, cbD, &wantsColorClear, &wantsDsClear); @@ -4626,6 +4632,7 @@ bool QGles2RenderBuffer::create() } owns = true; + generation += 1; rhiD->registerResource(this); return true; } @@ -4653,6 +4660,7 @@ bool QGles2RenderBuffer::createFrom(NativeRenderBuffer src) QRHI_PROF_F(newRenderBuffer(this, false, false, samples)); owns = false; + generation += 1; rhiD->registerResource(this); return true; } @@ -5114,6 +5122,8 @@ bool QGles2TextureRenderTarget::create() return false; } + QRhiRenderTargetAttachmentTracker::updateResIdList<QGles2Texture, QGles2RenderBuffer>(m_desc, &d.currentResIdList); + rhiD->registerResource(this); return true; } diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 6ee6af8fc5..c0f3883002 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -108,6 +108,7 @@ struct QGles2RenderBuffer : public QRhiRenderBuffer GLuint stencilRenderbuffer = 0; // when packed depth-stencil not supported int samples; bool owns = true; + uint generation = 0; friend class QRhiGles2; }; @@ -213,6 +214,7 @@ struct QGles2RenderTargetData int colorAttCount = 0; int dsAttCount = 0; bool srgbUpdateAndBlend = false; + QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList; }; struct QGles2ReferenceRenderTarget : public QRhiRenderTarget diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 5219b5c71d..626eac433b 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -296,6 +296,8 @@ struct QMetalRenderTargetData bool hasStencil = false; bool depthNeedsStore = false; } fb; + + QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList; }; struct QMetalGraphicsPipelineData @@ -2030,6 +2032,8 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb, { QMetalTextureRenderTarget *rtTex = QRHI_RES(QMetalTextureRenderTarget, rt); rtD = rtTex->d; + if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QMetalTexture, QMetalRenderBuffer>(rtTex->description(), rtD->currentResIdList)) + rtTex->create(); cbD->d->currentPassRpDesc = d->createDefaultRenderPass(rtD->dsAttCount, colorClearValue, depthStencilClearValue, rtD->colorAttCount); if (rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents)) { for (uint i = 0; i < uint(rtD->colorAttCount); ++i) @@ -3181,6 +3185,8 @@ bool QMetalTextureRenderTarget::create() d->dsAttCount = 0; } + QRhiRenderTargetAttachmentTracker::updateResIdList<QMetalTexture, QMetalRenderBuffer>(m_desc, &d->currentResIdList); + return true; } diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index b23af75bd9..6e85e02cc2 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -553,12 +553,18 @@ void QRhiNull::beginPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) { - Q_UNUSED(rt); Q_UNUSED(colorClearValue); Q_UNUSED(depthStencilClearValue); Q_UNUSED(flags); + if (resourceUpdates) resourceUpdate(cb, resourceUpdates); + + if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) { + QNullTextureRenderTarget *rtTex = QRHI_RES(QNullTextureRenderTarget, rt); + if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QNullTexture, QNullRenderBuffer>(rtTex->description(), rtTex->d.currentResIdList)) + rtTex->create(); + } } void QRhiNull::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) @@ -660,6 +666,7 @@ bool QNullRenderBuffer::create() destroy(); valid = true; + generation += 1; QRHI_PROF; QRHI_PROF_F(newRenderBuffer(this, false, false, 1)); @@ -726,6 +733,8 @@ bool QNullTexture::create() } } + generation += 1; + QRHI_PROF; QRHI_PROF_F(newTexture(this, true, mipLevelCount, layerCount, 1)); rhiD->registerResource(this); @@ -748,6 +757,8 @@ bool QNullTexture::createFrom(QRhiTexture::NativeTexture src) QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize; const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1; + generation += 1; + QRHI_PROF; QRHI_PROF_F(newTexture(this, false, mipLevelCount, isCube ? 6 : (isArray ? m_arraySize : 1), 1)); rhiD->registerResource(this); @@ -871,6 +882,7 @@ bool QNullTextureRenderTarget::create() } else if (m_desc.depthTexture()) { d.pixelSize = m_desc.depthTexture()->pixelSize(); } + QRhiRenderTargetAttachmentTracker::updateResIdList<QNullTexture, QNullRenderBuffer>(m_desc, &d.currentResIdList); return true; } diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h index 4d3c508044..217ec8ef39 100644 --- a/src/gui/rhi/qrhinull_p_p.h +++ b/src/gui/rhi/qrhinull_p_p.h @@ -78,6 +78,7 @@ struct QNullRenderBuffer : public QRhiRenderBuffer QRhiTexture::Format backingFormat() const override; bool valid = false; + uint generation = 0; }; struct QNullTexture : public QRhiTexture @@ -91,6 +92,7 @@ struct QNullTexture : public QRhiTexture bool valid = false; QVarLengthArray<std::array<QImage, QRhi::MAX_MIP_LEVELS>, 6> image; + uint generation = 0; }; struct QNullSampler : public QRhiSampler @@ -119,6 +121,7 @@ struct QNullRenderTargetData QNullRenderPassDescriptor *rp = nullptr; QSize pixelSize; float dpr = 1; + QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList; }; struct QNullReferenceRenderTarget : public QRhiRenderTarget diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 03f3fb4ad8..e23900069c 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2175,6 +2175,9 @@ static inline QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const void QRhiVulkan::activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD) { + if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QVkTexture, QVkRenderBuffer>(rtD->description(), rtD->d.currentResIdList)) + rtD->create(); + rtD->lastActiveFrameSlot = currentFrameSlot; rtD->d.rp->lastActiveFrameSlot = currentFrameSlot; QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]); @@ -5759,6 +5762,7 @@ bool QVkRenderBuffer::create() } lastActiveFrameSlot = -1; + generation += 1; rhiD->registerResource(this); return true; } @@ -6572,6 +6576,8 @@ bool QVkTextureRenderTarget::create() return false; } + QRhiRenderTargetAttachmentTracker::updateResIdList<QVkTexture, QVkRenderBuffer>(m_desc, &d.currentResIdList); + lastActiveFrameSlot = -1; rhiD->registerResource(this); return true; diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 42ae9aef3b..da69a0d70d 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -123,6 +123,7 @@ struct QVkRenderBuffer : public QRhiRenderBuffer QVkTexture *backingTexture = nullptr; VkFormat vkformat; int lastActiveFrameSlot = -1; + uint generation = 0; friend class QRhiVulkan; }; @@ -214,6 +215,7 @@ struct QVkRenderTargetData int colorAttCount = 0; int dsAttCount = 0; int resolveAttCount = 0; + QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList; static const int MAX_COLOR_ATTACHMENTS = 8; }; |