summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/rhi')
-rw-r--r--src/gui/rhi/qrhi.cpp36
-rw-r--r--src/gui/rhi/qrhi_p_p.h77
-rw-r--r--src/gui/rhi/qrhid3d11.cpp5
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h3
-rw-r--r--src/gui/rhi/qrhigles2.cpp10
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h2
-rw-r--r--src/gui/rhi/qrhimetal.mm6
-rw-r--r--src/gui/rhi/qrhinull.cpp14
-rw-r--r--src/gui/rhi/qrhinull_p_p.h3
-rw-r--r--src/gui/rhi/qrhivulkan.cpp6
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h2
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 &currentResIdList);
+};
+
+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 &currentResIdList)
+{
+ // 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;
};