Skip to content

Commit

Permalink
Support VK_KHR_dynamic_rendering_local_read
Browse files Browse the repository at this point in the history
Fixes #3341
  • Loading branch information
ShabbyX committed Nov 4, 2024
1 parent 5219965 commit 06e48e3
Show file tree
Hide file tree
Showing 22 changed files with 608 additions and 27 deletions.
94 changes: 88 additions & 6 deletions qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2614,12 +2614,32 @@ void VulkanPipelineStateViewer::setState()
{
slotname = QFormatStr("Color %1").arg(a.localIdx);

// With dynamic rendering, the API references the framebuffer index everywhere, for
// example when specifying blend state for attachments or with vkCmdClearAttachments. As
// such, RenderDoc shows the same index in Color attachments (i.e. fbIdx == localIdx) to
// avoid confusion, even when VK_KHR_dynamic_rendering_local_read maps these attachments
// to different "locations" used by the shader. In that case, the mapped location is
// shown besides the attachment index.
uint32_t location = a.localIdx;
if(a.fbIdx < rp.colorAttachmentLocations.count())
{
location = rp.colorAttachmentLocations[a.fbIdx];
if(location == VKPipe::RenderPass::AttachmentUnused)
{
slotname += QFormatStr(" [disabled]");
}
else
{
slotname += QFormatStr(" [location %1]").arg(location);
}
}

if(state.fragmentShader.reflection != NULL)
{
const rdcarray<SigParameter> &outSig = state.fragmentShader.reflection->outputSignature;
for(int s = 0; s < outSig.count(); s++)
{
if(outSig[s].regIndex == (uint32_t)a.localIdx &&
if(outSig[s].regIndex == location &&
(outSig[s].systemValue == ShaderBuiltin::Undefined ||
outSig[s].systemValue == ShaderBuiltin::ColorOutput))
{
Expand Down Expand Up @@ -2819,6 +2839,22 @@ void VulkanPipelineStateViewer::setState()

if(showNode(usedSlot, /*filledSlot*/ true))
{
QString writemask = QFormatStr("%1%2%3%4")
.arg((blend.writeMask & 0x1) == 0 ? lit("_") : lit("R"))
.arg((blend.writeMask & 0x2) == 0 ? lit("_") : lit("G"))
.arg((blend.writeMask & 0x4) == 0 ? lit("_") : lit("B"))
.arg((blend.writeMask & 0x8) == 0 ? lit("_") : lit("A"));

// With VK_KHR_dynamic_rendering_local_read, if a color attachment is mapped to
// VK_ATTACHMENT_UNUSED, it is implicitly disabled. The Slot name in the "Render Pass"
// pane already tags the attachment with [disabled], but for clarity the write mask is also
// set to DISABLED here.
if(i < rp.colorAttachmentLocations.count() &&
rp.colorAttachmentLocations[i] == VKPipe::RenderPass::AttachmentUnused)
{
writemask = lit("DISABLED");
}

RDTreeWidgetItem *node = new RDTreeWidgetItem(
{i, blend.enabled ? tr("True") : tr("False"),

Expand All @@ -2828,11 +2864,7 @@ void VulkanPipelineStateViewer::setState()
ToQStr(blend.alphaBlend.source), ToQStr(blend.alphaBlend.destination),
ToQStr(blend.alphaBlend.operation),

QFormatStr("%1%2%3%4")
.arg((blend.writeMask & 0x1) == 0 ? lit("_") : lit("R"))
.arg((blend.writeMask & 0x2) == 0 ? lit("_") : lit("G"))
.arg((blend.writeMask & 0x4) == 0 ? lit("_") : lit("B"))
.arg((blend.writeMask & 0x8) == 0 ? lit("_") : lit("A"))});
writemask});

if(!usedSlot)
setInactiveRow(node);
Expand Down Expand Up @@ -4188,6 +4220,40 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe::
xml.writeEndElement();
}

if(!pass.renderpass.colorAttachmentLocations.isEmpty())
{
QList<QVariantList> locations;

for(int i = 0; i < pass.renderpass.colorAttachmentLocations.count(); i++)
locations.push_back({pass.renderpass.colorAttachmentLocations[i]});

m_Common.exportHTMLTable(xml,
{
tr("Color Attachment Location"),
},
locations);

xml.writeStartElement(lit("p"));
xml.writeEndElement();
}

if(!pass.renderpass.colorAttachmentInputIndices.isEmpty())
{
QList<QVariantList> inputIndices;

for(int i = 0; i < pass.renderpass.colorAttachmentInputIndices.count(); i++)
inputIndices.push_back({pass.renderpass.colorAttachmentInputIndices[i]});

m_Common.exportHTMLTable(xml,
{
tr("Color Attachment Input Index"),
},
inputIndices);

xml.writeStartElement(lit("p"));
xml.writeEndElement();
}

if(!pass.renderpass.resolveAttachments.isEmpty())
{
QList<QVariantList> resolves;
Expand All @@ -4213,6 +4279,22 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe::
xml.writeEndElement();
}

if(!pass.renderpass.isDepthInputAttachmentIndexImplicit)
{
xml.writeStartElement(lit("p"));
xml.writeCharacters(
tr("Depth Input Attachment Index: %1").arg(pass.renderpass.depthInputAttachmentIndex));
xml.writeEndElement();
}

if(!pass.renderpass.isStencilInputAttachmentIndexImplicit)
{
xml.writeStartElement(lit("p"));
xml.writeCharacters(
tr("Stencil Input Attachment Index: %1").arg(pass.renderpass.stencilInputAttachmentIndex));
xml.writeEndElement();
}

if(pass.renderpass.depthstencilResolveAttachment >= 0)
{
xml.writeStartElement(lit("p"));
Expand Down
34 changes: 33 additions & 1 deletion renderdoc/api/replay/vk_pipestate.h
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,13 @@ struct DepthStencil
float maxDepthBounds = 0.0f;
};

DOCUMENT("Describes the setup of a renderpass and subpasses.");
DOCUMENT(R"(Describes the setup of a renderpass and subpasses.
.. data:: AttachmentUnused
Alias for VK_ATTACHMENT_UNUSED, for use by the UI to know when a value in colorAttachmentLocations
or colorAttachmentInputIndices is mapped to VK_ATTACHMENT_UNUSED.
)");
struct RenderPass
{
DOCUMENT("");
Expand Down Expand Up @@ -859,6 +865,32 @@ samples used to render this subpass.
If the subpass is not internally multisampled, tileOnlyMSAASampleCount is set to 0.
)");
uint32_t tileOnlyMSAASampleCount = 0;

DOCUMENT(R"(The color index->location mapping set up by dynamic rendering local read.
:type: List[int]
)");
rdcarray<uint32_t> colorAttachmentLocations;

DOCUMENT(R"(The color index->input index mapping set up by dynamic rendering local read.
:type: List[int]
)");
rdcarray<uint32_t> colorAttachmentInputIndices;

DOCUMENT("Whether or not depth input attachment index is implicit (dynamic rendering).");
bool isDepthInputAttachmentIndexImplicit = true;

DOCUMENT("Whether or not stencil input attachment index is implicit (dynamic rendering).");
bool isStencilInputAttachmentIndexImplicit = true;

DOCUMENT("Depth input attachment index if explicit (dynamic rendering).");
uint32_t depthInputAttachmentIndex = UINT32_MAX;

DOCUMENT("Stencil input attachment index if explicit (dynamic rendering).");
uint32_t stencilInputAttachmentIndex = UINT32_MAX;

static const uint32_t AttachmentUnused = ~0U;
};

DOCUMENT("Describes a framebuffer object and its attachments.");
Expand Down
2 changes: 1 addition & 1 deletion renderdoc/driver/vulkan/extension_support.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ Maintainers can update this file by updating vk.xml in this folder and running `
* `VK_KHR_draw_indirect_count`
* `VK_KHR_driver_properties`
* `VK_KHR_dynamic_rendering`
* `VK_KHR_dynamic_rendering_local_read`
* `VK_KHR_external_fence_capabilities`
* `VK_KHR_external_fence_fd`
* `VK_KHR_external_fence_win32`
Expand Down Expand Up @@ -241,7 +242,6 @@ KHR extensions will definitely be implemented at some point, though KHR extensio
## KHR Extensions

* `VK_KHR_cooperative_matrix`
* `VK_KHR_dynamic_rendering_local_read`
* `VK_KHR_maintenance5`
* `VK_KHR_maintenance6`
* `VK_KHR_map_memory2`
Expand Down
102 changes: 102 additions & 0 deletions renderdoc/driver/vulkan/vk_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,108 @@ void DescriptorSetSlot::AccumulateBindRefs(DescriptorBindRefs &refs, VulkanResou
}
}

void DynamicRenderingLocalRead::Init(const VkBaseInStructure *infoStruct)
{
const VkRenderingAttachmentLocationInfoKHR *attachmentLocationInfo =
(const VkRenderingAttachmentLocationInfoKHR *)FindNextStruct(
infoStruct, VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR);
if(attachmentLocationInfo != NULL)
{
UpdateLocations(*attachmentLocationInfo);
}

const VkRenderingInputAttachmentIndexInfoKHR *inputAttachmentIndexInfo =
(const VkRenderingInputAttachmentIndexInfoKHR *)FindNextStruct(
infoStruct, VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR);
if(inputAttachmentIndexInfo != NULL)
{
UpdateInputIndices(*inputAttachmentIndexInfo);
}
}

void DynamicRenderingLocalRead::UpdateLocations(
const VkRenderingAttachmentLocationInfoKHR &attachmentLocationInfo)
{
// If NULL is given, an identity mapping is assumed. This is indicated by an empty
// array. This works out because not providing VkRenderingAttachmentLocationInfoKHR has the
// same meaning.
if(attachmentLocationInfo.pColorAttachmentLocations == NULL)
{
colorAttachmentLocations.clear();
}
else
{
colorAttachmentLocations.assign(attachmentLocationInfo.pColorAttachmentLocations,
attachmentLocationInfo.colorAttachmentCount);
}
}

void DynamicRenderingLocalRead::UpdateInputIndices(
const VkRenderingInputAttachmentIndexInfoKHR &inputAttachmentIndexInfo)
{
// If NULL is given, an identity mapping is assumed. This is indicated by an empty
// array. This works out because not providing VkRenderingInputAttachmentIndexInfoKHR has the
// same meaning.
if(inputAttachmentIndexInfo.pColorAttachmentInputIndices == NULL)
{
colorAttachmentInputIndices.clear();
}
else
{
colorAttachmentInputIndices.assign(inputAttachmentIndexInfo.pColorAttachmentInputIndices,
inputAttachmentIndexInfo.colorAttachmentCount);
}
isDepthInputAttachmentIndexImplicit = inputAttachmentIndexInfo.pDepthInputAttachmentIndex == NULL;
isStencilInputAttachmentIndexImplicit =
inputAttachmentIndexInfo.pStencilInputAttachmentIndex == NULL;
if(!isDepthInputAttachmentIndexImplicit)
{
depthInputAttachmentIndex = *inputAttachmentIndexInfo.pDepthInputAttachmentIndex;
}
if(!isStencilInputAttachmentIndexImplicit)
{
stencilInputAttachmentIndex = *inputAttachmentIndexInfo.pStencilInputAttachmentIndex;
}
}

void DynamicRenderingLocalRead::CopyLocations(const DynamicRenderingLocalRead &from)
{
colorAttachmentLocations = from.colorAttachmentLocations;
}

void DynamicRenderingLocalRead::CopyInputIndices(const DynamicRenderingLocalRead &from)
{
colorAttachmentInputIndices = from.colorAttachmentInputIndices;
isDepthInputAttachmentIndexImplicit = from.isDepthInputAttachmentIndexImplicit;
isStencilInputAttachmentIndexImplicit = from.isStencilInputAttachmentIndexImplicit;
depthInputAttachmentIndex = from.depthInputAttachmentIndex;
stencilInputAttachmentIndex = from.stencilInputAttachmentIndex;
}

void DynamicRenderingLocalRead::SetLocations(VkCommandBuffer cmd)
{
VkRenderingAttachmentLocationInfoKHR attachmentLocations = {};
attachmentLocations.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR;
attachmentLocations.colorAttachmentCount = colorAttachmentLocations.count();
attachmentLocations.pColorAttachmentLocations = colorAttachmentLocations.data();

ObjDisp(cmd)->CmdSetRenderingAttachmentLocationsKHR(Unwrap(cmd), &attachmentLocations);
}

void DynamicRenderingLocalRead::SetInputIndices(VkCommandBuffer cmd)
{
VkRenderingInputAttachmentIndexInfoKHR inputIndices = {};
inputIndices.sType = VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR;
inputIndices.colorAttachmentCount = colorAttachmentInputIndices.count();
inputIndices.pColorAttachmentInputIndices = colorAttachmentInputIndices.data();
inputIndices.pDepthInputAttachmentIndex =
isDepthInputAttachmentIndexImplicit ? NULL : &depthInputAttachmentIndex;
inputIndices.pStencilInputAttachmentIndex =
isStencilInputAttachmentIndexImplicit ? NULL : &stencilInputAttachmentIndex;

ObjDisp(cmd)->CmdSetRenderingInputAttachmentIndicesKHR(Unwrap(cmd), &inputIndices);
}

#if ENABLED(ENABLE_UNIT_TESTS)

#undef None
Expand Down
Loading

0 comments on commit 06e48e3

Please sign in to comment.