From 64760504e79c3069d99b5e852688a2589ec22028 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 26 Nov 2019 12:43:56 +0100 Subject: rhi: Allow testing QRhiRenderPassDescriptors for compatibility For Metal and Vulkan this needs actual work because that's where the concept of renderpass descriptors is relevant. GL and D3D can just return true always. The big benefit of this is that Qt Quick can now compare renderpass descriptors via isCompatible() for its pipeline cache (similarly to how it is already using isLayoutCompatible() for srbs), and so renderpass descriptors for layers (Item.layer, ShaderEffect) will typically be compatible and so can pick up pipelines created by other layers from the cache. Also add autotests for shader resource binding and renderpass descriptor compatibility. Task-number: QTBUG-80318 Change-Id: I0008bc51c4ee13b0113d2c8caf799e1257f18a18 Reviewed-by: Paul Olav Tvete --- src/gui/rhi/qrhi.cpp | 18 ++++ src/gui/rhi/qrhi_p.h | 1 + src/gui/rhi/qrhid3d11.cpp | 6 ++ src/gui/rhi/qrhid3d11_p_p.h | 1 + src/gui/rhi/qrhigles2.cpp | 6 ++ src/gui/rhi/qrhigles2_p_p.h | 1 + src/gui/rhi/qrhimetal.mm | 26 ++++++ src/gui/rhi/qrhimetal_p_p.h | 1 + src/gui/rhi/qrhinull.cpp | 6 ++ src/gui/rhi/qrhinull_p_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 193 ++++++++++++++++++++++++++++--------------- src/gui/rhi/qrhivulkan_p_p.h | 10 ++- 12 files changed, 202 insertions(+), 68 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index ac5836fc68..ece5190ff7 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2318,6 +2318,24 @@ QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const return RenderPassDescriptor; } +/*! + \fn bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const; + + \return true if the \a other QRhiRenderPassDescriptor is compatible with + this one, meaning \c this and \a other can be used interchangebly in + QRhiGraphicsPipeline::setRenderPassDescriptor(). + + The concept of the compatibility of renderpass descriptors is similar to + the \l{QRhiShaderResourceBindings::isLayoutCompatible}{layout + compatibility} of QRhiShaderResourceBindings instances. They allow better + reuse of QRhiGraphicsPipeline instances: for example, a + QRhiGraphicsPipeline instance cache is expected to use these functions to + look for a matching pipeline, instead of just comparing pointers, thus + allowing a different QRhiRenderPassDescriptor and + QRhiShaderResourceBindings to be used in combination with the pipeline, as + long as they are compatible. + */ + /*! \return a pointer to a backend-specific QRhiNativeHandles subclass, such as QRhiVulkanRenderPassNativeHandles. The returned value is null when exposing diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 8cc4c7a06c..9df2c58962 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -911,6 +911,7 @@ class Q_GUI_EXPORT QRhiRenderPassDescriptor : public QRhiResource public: QRhiResource::Type resourceType() const override; + virtual bool isCompatible(const QRhiRenderPassDescriptor *other) const = 0; virtual const QRhiNativeHandles *nativeHandles(); protected: diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 7e05aefe8d..52109edce0 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -2940,6 +2940,12 @@ void QD3D11RenderPassDescriptor::release() // nothing to do here } +bool QD3D11RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + Q_UNUSED(other); + return true; +} + QD3D11ReferenceRenderTarget::QD3D11ReferenceRenderTarget(QRhiImplementation *rhi) : QRhiRenderTarget(rhi), d(rhi) diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 26de34ae0a..13c56b1d6d 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -136,6 +136,7 @@ struct QD3D11RenderPassDescriptor : public QRhiRenderPassDescriptor QD3D11RenderPassDescriptor(QRhiImplementation *rhi); ~QD3D11RenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; }; struct QD3D11RenderTargetData diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index ab61050e3e..b0e9a149f1 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -3455,6 +3455,12 @@ void QGles2RenderPassDescriptor::release() // nothing to do here } +bool QGles2RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + Q_UNUSED(other); + return true; +} + QGles2ReferenceRenderTarget::QGles2ReferenceRenderTarget(QRhiImplementation *rhi) : QRhiRenderTarget(rhi), d(rhi) diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index cc945876e6..b0f5e340fb 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -185,6 +185,7 @@ struct QGles2RenderPassDescriptor : public QRhiRenderPassDescriptor QGles2RenderPassDescriptor(QRhiImplementation *rhi); ~QGles2RenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; }; struct QGles2RenderTargetData diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 06e81465a2..e5af1cfab1 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -2658,6 +2658,32 @@ void QMetalRenderPassDescriptor::release() // nothing to do here } +bool QMetalRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + if (!other) + return false; + + const QMetalRenderPassDescriptor *o = QRHI_RES(const QMetalRenderPassDescriptor, other); + + if (colorAttachmentCount != o->colorAttachmentCount) + return false; + + if (hasDepthStencil != o->hasDepthStencil) + return false; + + for (int i = 0; i < colorAttachmentCount; ++i) { + if (colorFormat[i] != o->colorFormat[i]) + return false; + } + + if (hasDepthStencil) { + if (dsFormat != o->dsFormat) + return false; + } + + return true; +} + QMetalReferenceRenderTarget::QMetalReferenceRenderTarget(QRhiImplementation *rhi) : QRhiRenderTarget(rhi), d(new QMetalRenderTargetData) diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 2be86db5c8..7876539fcd 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -138,6 +138,7 @@ struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor QMetalRenderPassDescriptor(QRhiImplementation *rhi); ~QMetalRenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; // there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass() diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index fe606f971f..0baea1b9d6 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -690,6 +690,12 @@ void QNullRenderPassDescriptor::release() { } +bool QNullRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + Q_UNUSED(other); + return true; +} + QNullReferenceRenderTarget::QNullReferenceRenderTarget(QRhiImplementation *rhi) : QRhiRenderTarget(rhi), d(rhi) diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h index ce517bfa63..c96f279f7d 100644 --- a/src/gui/rhi/qrhinull_p_p.h +++ b/src/gui/rhi/qrhinull_p_p.h @@ -101,6 +101,7 @@ struct QNullRenderPassDescriptor : public QRhiRenderPassDescriptor QNullRenderPassDescriptor(QRhiImplementation *rhi); ~QNullRenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; }; struct QNullRenderTargetData diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index f60c2d538e..25a85a5a17 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -1032,54 +1032,62 @@ VkFormat QRhiVulkan::optimalDepthStencilFormat() return optimalDsFormat; } -bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat) +bool QRhiVulkan::createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat) { - VkAttachmentDescription attDesc[3]; - memset(attDesc, 0, sizeof(attDesc)); - // attachment list layout is color (1), ds (0-1), resolve (0-1) - attDesc[0].format = colorFormat; - attDesc[0].samples = samples; - attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc[0].storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; - attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc[0].finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - // clear on load + no store + lazy alloc + transient image should play - // nicely with tiled GPUs (no physical backing necessary for ds buffer) - attDesc[1].format = optimalDepthStencilFormat(); - attDesc[1].samples = samples; - attDesc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + VkAttachmentDescription attDesc; + memset(&attDesc, 0, sizeof(attDesc)); + attDesc.format = colorFormat; + attDesc.samples = samples; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + rpD->attDescs.append(attDesc); - if (samples > VK_SAMPLE_COUNT_1_BIT) { - attDesc[2].format = colorFormat; - attDesc[2].samples = VK_SAMPLE_COUNT_1_BIT; - attDesc[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attDesc[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc[2].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }); + + if (hasDepthStencil) { + // clear on load + no store + lazy alloc + transient image should play + // nicely with tiled GPUs (no physical backing necessary for ds buffer) + memset(&attDesc, 0, sizeof(attDesc)); + attDesc.format = optimalDepthStencilFormat(); + attDesc.samples = samples; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + rpD->attDescs.append(attDesc); + + rpD->dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; } - VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentReference dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; - VkAttachmentReference resolveRef = { 2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + if (samples > VK_SAMPLE_COUNT_1_BIT) { + memset(&attDesc, 0, sizeof(attDesc)); + attDesc.format = colorFormat; + attDesc.samples = VK_SAMPLE_COUNT_1_BIT; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + rpD->attDescs.append(attDesc); + + rpD->resolveRefs.append({ 2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }); + } VkSubpassDescription subpassDesc; memset(&subpassDesc, 0, sizeof(subpassDesc)); subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpassDesc.colorAttachmentCount = 1; - subpassDesc.pColorAttachments = &colorRef; - subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &dsRef : nullptr; + subpassDesc.pColorAttachments = rpD->colorRefs.constData(); + subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &rpD->dsRef : nullptr; // Replace the first implicit dep (TOP_OF_PIPE / ALL_COMMANDS) with our own. VkSubpassDependency subpassDep; @@ -1095,7 +1103,7 @@ bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil, memset(&rpInfo, 0, sizeof(rpInfo)); rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; rpInfo.attachmentCount = 1; - rpInfo.pAttachments = attDesc; + rpInfo.pAttachments = rpD->attDescs.constData(); rpInfo.subpassCount = 1; rpInfo.pSubpasses = &subpassDesc; rpInfo.dependencyCount = 1; @@ -1106,19 +1114,21 @@ bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil, if (samples > VK_SAMPLE_COUNT_1_BIT) { rpInfo.attachmentCount += 1; - subpassDesc.pResolveAttachments = &resolveRef; + subpassDesc.pResolveAttachments = rpD->resolveRefs.constData(); } - VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, rp); + VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, &rpD->rp); if (err != VK_SUCCESS) { qWarning("Failed to create renderpass: %d", err); return false; } + rpD->hasDepthStencil = hasDepthStencil; + return true; } -bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, +bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *firstColorAttachment, const QRhiColorAttachment *lastColorAttachment, bool preserveColor, @@ -1126,10 +1136,6 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture) { - QVarLengthArray attDescs; - QVarLengthArray colorRefs; - QVarLengthArray resolveRefs; - // attachment list layout is color (0-8), ds (0-1), resolve (0-8) for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) { @@ -1150,14 +1156,14 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, // this has to interact correctly with activateTextureRenderTarget(), hence leaving in COLOR_ATT attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attDescs.append(attDesc); + rpD->attDescs.append(attDesc); - const VkAttachmentReference ref = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - colorRefs.append(ref); + const VkAttachmentReference ref = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + rpD->colorRefs.append(ref); } - const bool hasDepthStencil = depthStencilBuffer || depthTexture; - if (hasDepthStencil) { + rpD->hasDepthStencil = depthStencilBuffer || depthTexture; + if (rpD->hasDepthStencil) { const VkFormat dsFormat = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->vkformat : QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat; const VkSampleCountFlagBits samples = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->samples @@ -1174,9 +1180,9 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, attDesc.stencilStoreOp = storeOp; attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attDescs.append(attDesc); + rpD->attDescs.append(attDesc); } - VkAttachmentReference dsRef = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; + rpD->dsRef = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) { if (it->resolveTexture()) { @@ -1194,37 +1200,37 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attDescs.append(attDesc); + rpD->attDescs.append(attDesc); - const VkAttachmentReference ref = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - resolveRefs.append(ref); + const VkAttachmentReference ref = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + rpD->resolveRefs.append(ref); } else { const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - resolveRefs.append(ref); + rpD->resolveRefs.append(ref); } } VkSubpassDescription subpassDesc; memset(&subpassDesc, 0, sizeof(subpassDesc)); subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDesc.colorAttachmentCount = uint32_t(colorRefs.count()); - Q_ASSERT(colorRefs.count() == resolveRefs.count()); - subpassDesc.pColorAttachments = !colorRefs.isEmpty() ? colorRefs.constData() : nullptr; - subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &dsRef : nullptr; - subpassDesc.pResolveAttachments = !resolveRefs.isEmpty() ? resolveRefs.constData() : nullptr; + subpassDesc.colorAttachmentCount = uint32_t(rpD->colorRefs.count()); + Q_ASSERT(rpD->colorRefs.count() == rpD->resolveRefs.count()); + subpassDesc.pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() : nullptr; + subpassDesc.pDepthStencilAttachment = rpD->hasDepthStencil ? &rpD->dsRef : nullptr; + subpassDesc.pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() : nullptr; VkRenderPassCreateInfo rpInfo; memset(&rpInfo, 0, sizeof(rpInfo)); rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rpInfo.attachmentCount = uint32_t(attDescs.count()); - rpInfo.pAttachments = attDescs.constData(); + rpInfo.attachmentCount = uint32_t(rpD->attDescs.count()); + rpInfo.pAttachments = rpD->attDescs.constData(); rpInfo.subpassCount = 1; rpInfo.pSubpasses = &subpassDesc; // don't yet know the correct initial/final access and stage stuff for the // implicit deps at this point, so leave it to the resource tracking to // generate barriers - VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, rp); + VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, &rpD->rp); if (err != VK_SUCCESS) { qWarning("Failed to create renderpass: %d", err); return false; @@ -5501,6 +5507,61 @@ void QVkRenderPassDescriptor::release() rhiD->unregisterResource(this); } +static inline bool attachmentDescriptionEquals(const VkAttachmentDescription &a, const VkAttachmentDescription &b) +{ + return a.format == b.format + && a.samples == b.samples + && a.loadOp == b.loadOp + && a.storeOp == b.storeOp + && a.stencilLoadOp == b.stencilLoadOp + && a.stencilStoreOp == b.stencilStoreOp + && a.initialLayout == b.initialLayout + && a.finalLayout == b.finalLayout; +} + +bool QVkRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + if (!other) + return false; + + const QVkRenderPassDescriptor *o = QRHI_RES(const QVkRenderPassDescriptor, other); + + if (attDescs.count() != o->attDescs.count()) + return false; + if (colorRefs.count() != o->colorRefs.count()) + return false; + if (resolveRefs.count() != o->resolveRefs.count()) + return false; + if (hasDepthStencil != o->hasDepthStencil) + return false; + + for (int i = 0, ie = colorRefs.count(); i != ie; ++i) { + const uint32_t attIdx = colorRefs[i].attachment; + if (attIdx != o->colorRefs[i].attachment) + return false; + if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx])) + return false; + } + + if (hasDepthStencil) { + const uint32_t attIdx = dsRef.attachment; + if (attIdx != o->dsRef.attachment) + return false; + if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx])) + return false; + } + + for (int i = 0, ie = resolveRefs.count(); i != ie; ++i) { + const uint32_t attIdx = resolveRefs[i].attachment; + if (attIdx != o->resolveRefs[i].attachment) + return false; + if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx])) + return false; + } + + return true; +} + const QRhiNativeHandles *QVkRenderPassDescriptor::nativeHandles() { nativeHandlesStruct.renderPass = rp; @@ -5584,7 +5645,7 @@ QRhiRenderPassDescriptor *QVkTextureRenderTarget::newCompatibleRenderPassDescrip QRHI_RES_RHI(QRhiVulkan); QVkRenderPassDescriptor *rp = new QVkRenderPassDescriptor(m_rhi); - if (!rhiD->createOffscreenRenderPass(&rp->rp, + if (!rhiD->createOffscreenRenderPass(rp, m_desc.cbeginColorAttachments(), m_desc.cendColorAttachments(), m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents), @@ -6285,7 +6346,7 @@ QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor() QRHI_RES_RHI(QRhiVulkan); QVkRenderPassDescriptor *rp = new QVkRenderPassDescriptor(m_rhi); - if (!rhiD->createDefaultRenderPass(&rp->rp, + if (!rhiD->createDefaultRenderPass(rp, m_depthStencil != nullptr, samples, colorFormat)) diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index d0e1e6758b..ffa8c59ed5 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -171,10 +171,16 @@ struct QVkRenderPassDescriptor : public QRhiRenderPassDescriptor QVkRenderPassDescriptor(QRhiImplementation *rhi); ~QVkRenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; const QRhiNativeHandles *nativeHandles() override; VkRenderPass rp = VK_NULL_HANDLE; bool ownsRp = false; + QVarLengthArray attDescs; + QVarLengthArray colorRefs; + QVarLengthArray resolveRefs; + bool hasDepthStencil = false; + VkAttachmentReference dsRef; QRhiVulkanRenderPassNativeHandles nativeHandlesStruct; int lastActiveFrameSlot = -1; }; @@ -727,11 +733,11 @@ public: VkFormat optimalDepthStencilFormat(); VkSampleCountFlagBits effectiveSampleCount(int sampleCount); - bool createDefaultRenderPass(VkRenderPass *rp, + bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat); - bool createOffscreenRenderPass(VkRenderPass *rp, + bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *firstColorAttachment, const QRhiColorAttachment *lastColorAttachment, bool preserveColor, -- cgit v1.2.3