Only perform attachment load/store ops for used attachments
Tracks the first subpass to touch an attachment.
Test: dEQP-VK.renderpass.suballocation.unused*
Change-Id: Idc0998da022fd4c0b1785f6020c795916ba475f7
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31308
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkFramebuffer.cpp b/src/Vulkan/VkFramebuffer.cpp
index c5bdfde..f9047c1 100644
--- a/src/Vulkan/VkFramebuffer.cpp
+++ b/src/Vulkan/VkFramebuffer.cpp
@@ -43,6 +43,11 @@
const uint32_t count = std::min(clearValueCount, attachmentCount);
for(uint32_t i = 0; i < count; i++)
{
+ if (!renderPass->isAttachmentUsed(i))
+ {
+ continue;
+ }
+
const VkAttachmentDescription attachment = renderPass->getAttachment(i);
const Format format(attachment.format);
bool isDepth = format.isDepth();
diff --git a/src/Vulkan/VkRenderPass.cpp b/src/Vulkan/VkRenderPass.cpp
index 108e797..0ebce67 100644
--- a/src/Vulkan/VkRenderPass.cpp
+++ b/src/Vulkan/VkRenderPass.cpp
@@ -15,6 +15,15 @@
#include "VkRenderPass.hpp"
#include <cstring>
+namespace
+{
+ void MarkFirstUse(int& attachment, int subpass)
+ {
+ if (attachment == -1)
+ attachment = subpass;
+ }
+}
+
namespace vk
{
@@ -39,6 +48,12 @@
attachments = reinterpret_cast<VkAttachmentDescription*>(hostMemory);
memcpy(attachments, pCreateInfo->pAttachments, attachmentSize);
hostMemory += attachmentSize;
+
+ size_t firstUseSize = pCreateInfo->attachmentCount * sizeof(int);
+ attachmentFirstUse = reinterpret_cast<int*>(hostMemory);
+ for (auto i = 0u; i < pCreateInfo->attachmentCount; i++)
+ attachmentFirstUse[i] = -1;
+ hostMemory += firstUseSize;
}
// Deep copy subpasses
@@ -58,6 +73,12 @@
memcpy(const_cast<VkAttachmentReference*>(subpasses[i].pInputAttachments),
pCreateInfo->pSubpasses[i].pInputAttachments, inputAttachmentsSize);
hostMemory += inputAttachmentsSize;
+
+ for (auto j = 0u; j < subpasses[i].inputAttachmentCount; j++)
+ {
+ if (subpass.pInputAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
+ MarkFirstUse(attachmentFirstUse[subpass.pInputAttachments[j].attachment], i);
+ }
}
if(subpass.colorAttachmentCount > 0)
@@ -65,24 +86,36 @@
size_t colorAttachmentsSize = subpass.colorAttachmentCount * sizeof(VkAttachmentReference);
subpasses[i].pColorAttachments = reinterpret_cast<VkAttachmentReference*>(hostMemory);
memcpy(const_cast<VkAttachmentReference*>(subpasses[i].pColorAttachments),
- pCreateInfo->pSubpasses[i].pColorAttachments, colorAttachmentsSize);
+ subpass.pColorAttachments, colorAttachmentsSize);
hostMemory += colorAttachmentsSize;
if(subpass.pResolveAttachments != nullptr)
{
subpasses[i].pResolveAttachments = reinterpret_cast<VkAttachmentReference*>(hostMemory);
memcpy(const_cast<VkAttachmentReference*>(subpasses[i].pResolveAttachments),
- pCreateInfo->pSubpasses[i].pResolveAttachments, colorAttachmentsSize);
+ subpass.pResolveAttachments, colorAttachmentsSize);
hostMemory += colorAttachmentsSize;
}
+
+ for (auto j = 0u; j < subpasses[i].colorAttachmentCount; j++)
+ {
+ if (subpass.pColorAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
+ MarkFirstUse(attachmentFirstUse[subpass.pColorAttachments[j].attachment], i);
+ if (subpass.pResolveAttachments &&
+ subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
+ MarkFirstUse(attachmentFirstUse[subpass.pResolveAttachments[j].attachment], i);
+ }
}
if(subpass.pDepthStencilAttachment != nullptr)
{
subpasses[i].pDepthStencilAttachment = reinterpret_cast<VkAttachmentReference*>(hostMemory);
memcpy(const_cast<VkAttachmentReference*>(subpasses[i].pDepthStencilAttachment),
- pCreateInfo->pSubpasses[i].pDepthStencilAttachment, sizeof(VkAttachmentReference));
+ subpass.pDepthStencilAttachment, sizeof(VkAttachmentReference));
hostMemory += sizeof(VkAttachmentReference);
+
+ if (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
+ MarkFirstUse(attachmentFirstUse[subpass.pDepthStencilAttachment->attachment], i);
}
if(subpass.preserveAttachmentCount > 0)
@@ -92,6 +125,12 @@
memcpy(const_cast<uint32_t*>(subpasses[i].pPreserveAttachments),
pCreateInfo->pSubpasses[i].pPreserveAttachments, preserveAttachmentSize);
hostMemory += preserveAttachmentSize;
+
+ for (auto j = 0u; j < subpasses[i].preserveAttachmentCount; j++)
+ {
+ if (subpass.pPreserveAttachments[j] != VK_ATTACHMENT_UNUSED)
+ MarkFirstUse(attachmentFirstUse[subpass.pPreserveAttachments[j]], i);
+ }
}
}
@@ -110,7 +149,8 @@
size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo* pCreateInfo)
{
- size_t attachmentSize = pCreateInfo->attachmentCount * sizeof(VkAttachmentDescription);
+ size_t attachmentSize = pCreateInfo->attachmentCount * sizeof(VkAttachmentDescription)
+ + pCreateInfo->attachmentCount * sizeof(int);
size_t subpassesSize = 0;
for(uint32_t i = 0; i < pCreateInfo->subpassCount; ++i)
{
@@ -133,11 +173,11 @@
return attachmentSize + subpassesSize + dependenciesSize;
}
-void RenderPass::getRenderAreaGranularity(VkExtent2D* pGranularity) const
-{
- pGranularity->width = 1;
- pGranularity->height = 1;
-}
+void RenderPass::getRenderAreaGranularity(VkExtent2D* pGranularity) const
+{
+ pGranularity->width = 1;
+ pGranularity->height = 1;
+}
void RenderPass::begin()
{
diff --git a/src/Vulkan/VkRenderPass.hpp b/src/Vulkan/VkRenderPass.hpp
index 8a8a63d..4b5677c 100644
--- a/src/Vulkan/VkRenderPass.hpp
+++ b/src/Vulkan/VkRenderPass.hpp
@@ -17,6 +17,8 @@
#include "VkObject.hpp"
+#include <vector>
+
namespace vk
{
@@ -29,7 +31,7 @@
static size_t ComputeRequiredAllocationSize(const VkRenderPassCreateInfo* pCreateInfo);
- void getRenderAreaGranularity(VkExtent2D* pGranularity) const;
+ void getRenderAreaGranularity(VkExtent2D* pGranularity) const;
void begin();
void nextSubpass();
@@ -70,6 +72,11 @@
return dependencies[i];
}
+ bool isAttachmentUsed(uint32_t i) const
+ {
+ return attachmentFirstUse[i] >= 0;
+ }
+
private:
uint32_t attachmentCount = 0;
VkAttachmentDescription* attachments = nullptr;
@@ -78,6 +85,7 @@
uint32_t dependencyCount = 0;
VkSubpassDependency* dependencies = nullptr;
uint32_t currentSubpass = 0;
+ int* attachmentFirstUse = nullptr;
};
static inline RenderPass* Cast(VkRenderPass object)