rhi: Allow testing renderpass compatibility without the objects
Follow what has been done for QRhiShaderResourceBindings. Have a way to retrieve an opaque blob (that just happens to be a list of integers) so that a simple == comparison can be used to determine compatibility even when the objects from which the blob was retrieved are no longer alive. The contract is the following: bool a = rp1->isCompatible(rp2); bool b = rp1->serializedFormat() == rp2->serializedFormat(); assert(a == b); Pick-to: 6.2 Change-Id: I45e7d05eeb6dfa2b2de474da0a0644912aaf174a Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
parent
c5a3cabce0
commit
43a42fa196
@ -2740,7 +2740,17 @@ QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const
|
||||
\l{QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor()}{created}
|
||||
from the same QRhiTextureRenderTarget are always compatible.
|
||||
|
||||
\sa newCompatibleRenderPassDescriptor()
|
||||
Similarly to QRhiShaderResourceBindings, compatibility can also be tested
|
||||
without having two existing objects available. Extracting the opaque blob by
|
||||
calling serializedFormat() allows testing for compatibility by comparing the
|
||||
returned vector to another QRhiRenderPassDescriptor's
|
||||
serializedFormat(). This has benefits in certain situations, because it
|
||||
allows testing the compatibility of a QRhiRenderPassDescriptor with a
|
||||
QRhiGraphicsPipeline even when the QRhiRenderPassDescriptor the pipeline was
|
||||
originally built was is no longer available (but the data returned from its
|
||||
serializedFormat() still is).
|
||||
|
||||
\sa newCompatibleRenderPassDescriptor(), serializedFormat()
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -2764,6 +2774,18 @@ QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const
|
||||
\sa isCompatible()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QVector<quint32> QRhiRenderPassDescriptor::serializedFormat() const
|
||||
|
||||
\return a vector of integers containing an opaque blob describing the data
|
||||
relevant for \l{isCompatible()}{compatibility}. Given two
|
||||
QRhiRenderPassDescriptor objects \c rp1 and \c rp2, if the data returned
|
||||
from this function is identical, then \c{rp1->isCompatible(rp2)}, and vice
|
||||
versa hold true as well.
|
||||
|
||||
\sa isCompatible()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\return a pointer to a backend-specific QRhiNativeHandles subclass, such as
|
||||
QRhiVulkanRenderPassNativeHandles. The returned value is \nullptr when exposing
|
||||
|
@ -993,6 +993,8 @@ public:
|
||||
|
||||
virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const = 0;
|
||||
|
||||
virtual QVector<quint32> serializedFormat() const = 0;
|
||||
|
||||
protected:
|
||||
QRhiRenderPassDescriptor(QRhiImplementation *rhi);
|
||||
};
|
||||
|
@ -3371,6 +3371,11 @@ QRhiRenderPassDescriptor *QD3D11RenderPassDescriptor::newCompatibleRenderPassDes
|
||||
return new QD3D11RenderPassDescriptor(m_rhi);
|
||||
}
|
||||
|
||||
QVector<quint32> QD3D11RenderPassDescriptor::serializedFormat() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QD3D11ReferenceRenderTarget::QD3D11ReferenceRenderTarget(QRhiImplementation *rhi)
|
||||
: QRhiRenderTarget(rhi),
|
||||
d(rhi)
|
||||
|
@ -151,6 +151,7 @@ struct QD3D11RenderPassDescriptor : public QRhiRenderPassDescriptor
|
||||
void destroy() override;
|
||||
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
|
||||
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
|
||||
QVector<quint32> serializedFormat() const override;
|
||||
};
|
||||
|
||||
struct QD3D11RenderTargetData
|
||||
|
@ -4769,6 +4769,11 @@ QRhiRenderPassDescriptor *QGles2RenderPassDescriptor::newCompatibleRenderPassDes
|
||||
return new QGles2RenderPassDescriptor(m_rhi);
|
||||
}
|
||||
|
||||
QVector<quint32> QGles2RenderPassDescriptor::serializedFormat() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QGles2ReferenceRenderTarget::QGles2ReferenceRenderTarget(QRhiImplementation *rhi)
|
||||
: QRhiRenderTarget(rhi),
|
||||
d(rhi)
|
||||
|
@ -199,6 +199,7 @@ struct QGles2RenderPassDescriptor : public QRhiRenderPassDescriptor
|
||||
void destroy() override;
|
||||
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
|
||||
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
|
||||
QVector<quint32> serializedFormat() const override;
|
||||
};
|
||||
|
||||
struct QGles2RenderTargetData
|
||||
|
@ -2924,6 +2924,7 @@ bool QMetalSampler::create()
|
||||
QMetalRenderPassDescriptor::QMetalRenderPassDescriptor(QRhiImplementation *rhi)
|
||||
: QRhiRenderPassDescriptor(rhi)
|
||||
{
|
||||
serializedFormatData.reserve(16);
|
||||
}
|
||||
|
||||
QMetalRenderPassDescriptor::~QMetalRenderPassDescriptor()
|
||||
@ -2962,6 +2963,18 @@ bool QMetalRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *ot
|
||||
return true;
|
||||
}
|
||||
|
||||
void QMetalRenderPassDescriptor::updateSerializedFormat()
|
||||
{
|
||||
serializedFormatData.clear();
|
||||
auto p = std::back_inserter(serializedFormatData);
|
||||
|
||||
*p++ = colorAttachmentCount;
|
||||
*p++ = hasDepthStencil;
|
||||
for (int i = 0; i < colorAttachmentCount; ++i)
|
||||
*p++ = colorFormat[i];
|
||||
*p++ = hasDepthStencil ? dsFormat : 0;
|
||||
}
|
||||
|
||||
QRhiRenderPassDescriptor *QMetalRenderPassDescriptor::newCompatibleRenderPassDescriptor() const
|
||||
{
|
||||
QMetalRenderPassDescriptor *rp = new QMetalRenderPassDescriptor(m_rhi);
|
||||
@ -2969,9 +2982,15 @@ QRhiRenderPassDescriptor *QMetalRenderPassDescriptor::newCompatibleRenderPassDes
|
||||
rp->hasDepthStencil = hasDepthStencil;
|
||||
memcpy(rp->colorFormat, colorFormat, sizeof(colorFormat));
|
||||
rp->dsFormat = dsFormat;
|
||||
rp->updateSerializedFormat();
|
||||
return rp;
|
||||
}
|
||||
|
||||
QVector<quint32> QMetalRenderPassDescriptor::serializedFormat() const
|
||||
{
|
||||
return serializedFormatData;
|
||||
}
|
||||
|
||||
QMetalReferenceRenderTarget::QMetalReferenceRenderTarget(QRhiImplementation *rhi)
|
||||
: QRhiRenderTarget(rhi),
|
||||
d(new QMetalRenderTargetData)
|
||||
@ -3042,6 +3061,7 @@ QRhiRenderPassDescriptor *QMetalTextureRenderTarget::newCompatibleRenderPassDesc
|
||||
else if (m_desc.depthStencilBuffer())
|
||||
rpD->dsFormat = int(QRHI_RES(QMetalRenderBuffer, m_desc.depthStencilBuffer())->d->format);
|
||||
|
||||
rpD->updateSerializedFormat();
|
||||
return rpD;
|
||||
}
|
||||
|
||||
@ -3953,6 +3973,7 @@ QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
|
||||
rpD->dsFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||
#endif
|
||||
|
||||
rpD->updateSerializedFormat();
|
||||
return rpD;
|
||||
}
|
||||
|
||||
|
@ -146,6 +146,9 @@ struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor
|
||||
void destroy() override;
|
||||
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
|
||||
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
|
||||
QVector<quint32> serializedFormat() const override;
|
||||
|
||||
void updateSerializedFormat();
|
||||
|
||||
// there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass()
|
||||
|
||||
@ -155,6 +158,7 @@ struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor
|
||||
bool hasDepthStencil = false;
|
||||
int colorFormat[MAX_COLOR_ATTACHMENTS];
|
||||
int dsFormat;
|
||||
QVector<quint32> serializedFormatData;
|
||||
};
|
||||
|
||||
struct QMetalRenderTargetData;
|
||||
|
@ -793,6 +793,11 @@ QRhiRenderPassDescriptor *QNullRenderPassDescriptor::newCompatibleRenderPassDesc
|
||||
return new QNullRenderPassDescriptor(m_rhi);
|
||||
}
|
||||
|
||||
QVector<quint32> QNullRenderPassDescriptor::serializedFormat() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QNullReferenceRenderTarget::QNullReferenceRenderTarget(QRhiImplementation *rhi)
|
||||
: QRhiRenderTarget(rhi),
|
||||
d(rhi)
|
||||
|
@ -109,6 +109,7 @@ struct QNullRenderPassDescriptor : public QRhiRenderPassDescriptor
|
||||
void destroy() override;
|
||||
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
|
||||
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
|
||||
QVector<quint32> serializedFormat() const override;
|
||||
};
|
||||
|
||||
struct QNullRenderTargetData
|
||||
|
@ -6131,6 +6131,7 @@ bool QVkSampler::create()
|
||||
QVkRenderPassDescriptor::QVkRenderPassDescriptor(QRhiImplementation *rhi)
|
||||
: QRhiRenderPassDescriptor(rhi)
|
||||
{
|
||||
serializedFormatData.reserve(32);
|
||||
}
|
||||
|
||||
QVkRenderPassDescriptor::~QVkRenderPassDescriptor()
|
||||
@ -6223,6 +6224,46 @@ bool QVkRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other
|
||||
return true;
|
||||
}
|
||||
|
||||
void QVkRenderPassDescriptor::updateSerializedFormat()
|
||||
{
|
||||
serializedFormatData.clear();
|
||||
auto p = std::back_inserter(serializedFormatData);
|
||||
|
||||
*p++ = attDescs.count();
|
||||
*p++ = colorRefs.count();
|
||||
*p++ = resolveRefs.count();
|
||||
*p++ = hasDepthStencil;
|
||||
|
||||
auto serializeAttachmentData = [&p](const VkAttachmentDescription &a, bool used) {
|
||||
*p++ = used ? a.format : 0;
|
||||
*p++ = used ? a.samples : 0;
|
||||
*p++ = used ? a.loadOp : 0;
|
||||
*p++ = used ? a.storeOp : 0;
|
||||
*p++ = used ? a.stencilLoadOp : 0;
|
||||
*p++ = used ? a.stencilStoreOp : 0;
|
||||
*p++ = used ? a.initialLayout : 0;
|
||||
*p++ = used ? a.finalLayout : 0;
|
||||
};
|
||||
|
||||
for (int i = 0, ie = colorRefs.count(); i != ie; ++i) {
|
||||
const uint32_t attIdx = colorRefs[i].attachment;
|
||||
*p++ = attIdx;
|
||||
serializeAttachmentData(attDescs[attIdx], attIdx != VK_ATTACHMENT_UNUSED);
|
||||
}
|
||||
|
||||
if (hasDepthStencil) {
|
||||
const uint32_t attIdx = dsRef.attachment;
|
||||
*p++ = attIdx;
|
||||
serializeAttachmentData(attDescs[attIdx], attIdx != VK_ATTACHMENT_UNUSED);
|
||||
}
|
||||
|
||||
for (int i = 0, ie = resolveRefs.count(); i != ie; ++i) {
|
||||
const uint32_t attIdx = resolveRefs[i].attachment;
|
||||
*p++ = attIdx;
|
||||
serializeAttachmentData(attDescs[attIdx], attIdx != VK_ATTACHMENT_UNUSED);
|
||||
}
|
||||
}
|
||||
|
||||
QRhiRenderPassDescriptor *QVkRenderPassDescriptor::newCompatibleRenderPassDescriptor() const
|
||||
{
|
||||
QVkRenderPassDescriptor *rpD = new QVkRenderPassDescriptor(m_rhi);
|
||||
@ -6247,10 +6288,16 @@ QRhiRenderPassDescriptor *QVkRenderPassDescriptor::newCompatibleRenderPassDescri
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rpD->updateSerializedFormat();
|
||||
rhiD->registerResource(rpD);
|
||||
return rpD;
|
||||
}
|
||||
|
||||
QVector<quint32> QVkRenderPassDescriptor::serializedFormat() const
|
||||
{
|
||||
return serializedFormatData;
|
||||
}
|
||||
|
||||
const QRhiNativeHandles *QVkRenderPassDescriptor::nativeHandles()
|
||||
{
|
||||
nativeHandlesStruct.renderPass = rp;
|
||||
@ -6348,6 +6395,7 @@ QRhiRenderPassDescriptor *QVkTextureRenderTarget::newCompatibleRenderPassDescrip
|
||||
}
|
||||
|
||||
rp->ownsRp = true;
|
||||
rp->updateSerializedFormat();
|
||||
rhiD->registerResource(rp);
|
||||
return rp;
|
||||
}
|
||||
@ -7122,6 +7170,7 @@ QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor()
|
||||
}
|
||||
|
||||
rp->ownsRp = true;
|
||||
rp->updateSerializedFormat();
|
||||
rhiD->registerResource(rp);
|
||||
return rp;
|
||||
}
|
||||
|
@ -186,8 +186,11 @@ struct QVkRenderPassDescriptor : public QRhiRenderPassDescriptor
|
||||
void destroy() override;
|
||||
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
|
||||
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
|
||||
QVector<quint32> serializedFormat() const override;
|
||||
const QRhiNativeHandles *nativeHandles() override;
|
||||
|
||||
void updateSerializedFormat();
|
||||
|
||||
VkRenderPass rp = VK_NULL_HANDLE;
|
||||
bool ownsRp = false;
|
||||
QVarLengthArray<VkAttachmentDescription, 8> attDescs;
|
||||
@ -196,6 +199,7 @@ struct QVkRenderPassDescriptor : public QRhiRenderPassDescriptor
|
||||
QVarLengthArray<VkSubpassDependency, 2> subpassDeps;
|
||||
bool hasDepthStencil = false;
|
||||
VkAttachmentReference dsRef;
|
||||
QVector<quint32> serializedFormatData;
|
||||
QRhiVulkanRenderPassNativeHandles nativeHandlesStruct;
|
||||
int lastActiveFrameSlot = -1;
|
||||
};
|
||||
|
@ -3505,6 +3505,7 @@ void tst_QRhi::renderPassDescriptorCompatibility()
|
||||
|
||||
QVERIFY(rpDesc->isCompatible(rpDesc2.data()));
|
||||
QVERIFY(rpDesc2->isCompatible(rpDesc.data()));
|
||||
QCOMPARE(rpDesc->serializedFormat(), rpDesc2->serializedFormat());
|
||||
}
|
||||
|
||||
// two texture rendertargets with tex and tex2 as color0, and a depth-stencil attachment as well (compatible)
|
||||
@ -3522,6 +3523,7 @@ void tst_QRhi::renderPassDescriptorCompatibility()
|
||||
|
||||
QVERIFY(rpDesc->isCompatible(rpDesc2.data()));
|
||||
QVERIFY(rpDesc2->isCompatible(rpDesc.data()));
|
||||
QCOMPARE(rpDesc->serializedFormat(), rpDesc2->serializedFormat());
|
||||
}
|
||||
|
||||
// now one of them does not have the ds attachment (not compatible)
|
||||
@ -3536,9 +3538,13 @@ void tst_QRhi::renderPassDescriptorCompatibility()
|
||||
rt2->setRenderPassDescriptor(rpDesc2.data());
|
||||
QVERIFY(rt2->create());
|
||||
|
||||
// these backends have a real concept of rp compatibility, with those we
|
||||
// know that incompatibility must be reported; verify this
|
||||
if (impl == QRhi::Vulkan || impl == QRhi::Metal) {
|
||||
QVERIFY(!rpDesc->isCompatible(rpDesc2.data()));
|
||||
QVERIFY(!rpDesc2->isCompatible(rpDesc.data()));
|
||||
QVERIFY(!rpDesc->serializedFormat().isEmpty());
|
||||
QVERIFY(rpDesc->serializedFormat() != rpDesc2->serializedFormat());
|
||||
}
|
||||
}
|
||||
|
||||
@ -3566,6 +3572,7 @@ void tst_QRhi::renderPassDescriptorCompatibility()
|
||||
|
||||
QVERIFY(rpDesc->isCompatible(rpDesc2.data()));
|
||||
QVERIFY(rpDesc2->isCompatible(rpDesc.data()));
|
||||
QCOMPARE(rpDesc->serializedFormat(), rpDesc2->serializedFormat());
|
||||
}
|
||||
|
||||
// missing resolve for one of them (not compatible)
|
||||
@ -3591,6 +3598,8 @@ void tst_QRhi::renderPassDescriptorCompatibility()
|
||||
if (impl == QRhi::Vulkan) { // no Metal here
|
||||
QVERIFY(!rpDesc->isCompatible(rpDesc2.data()));
|
||||
QVERIFY(!rpDesc2->isCompatible(rpDesc.data()));
|
||||
QVERIFY(!rpDesc->serializedFormat().isEmpty());
|
||||
QVERIFY(rpDesc->serializedFormat() != rpDesc2->serializedFormat());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -3616,6 +3625,8 @@ void tst_QRhi::renderPassDescriptorCompatibility()
|
||||
if (impl == QRhi::Vulkan || impl == QRhi::Metal) {
|
||||
QVERIFY(!rpDesc->isCompatible(rpDesc2.data()));
|
||||
QVERIFY(!rpDesc2->isCompatible(rpDesc.data()));
|
||||
QVERIFY(!rpDesc->serializedFormat().isEmpty());
|
||||
QVERIFY(rpDesc->serializedFormat() != rpDesc2->serializedFormat());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user