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 Oct 28, 2024
1 parent 5219965 commit f1850d0
Show file tree
Hide file tree
Showing 22 changed files with 606 additions and 26 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 == rp.vkAttachmentUnused)
{
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] == rp.vkAttachmentUnused)
{
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
28 changes: 28 additions & 0 deletions renderdoc/api/replay/vk_pipestate.h
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,34 @@ 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;

DOCUMENT(R"(Alias for VK_ATTACHMENT_UNUSED, for use by the UI to know when a value above in
|colorAttachmentLocations| or |colorAttachmentInputIndices| is mapped to VK_ATTACHMENT_UNUSED.)");
uint32_t vkAttachmentUnused = ~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
48 changes: 48 additions & 0 deletions renderdoc/driver/vulkan/vk_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,46 @@ class VkDriverInfo
bool maliBrokenASDeviceSerialisation = false;
};

struct DynamicRenderingLocalRead
{
void Init(const VkBaseInStructure *infoStruct);

void UpdateLocations(const VkRenderingAttachmentLocationInfoKHR &attachmentLocationInfo);
void UpdateInputIndices(const VkRenderingInputAttachmentIndexInfoKHR &inputAttachmentIndexInfo);

void CopyLocations(const DynamicRenderingLocalRead &from);
void CopyInputIndices(const DynamicRenderingLocalRead &from);

bool AreLocationsNonDefault() { return !colorAttachmentLocations.isEmpty(); }
bool AreInputIndicesNonDefault()
{
return !colorAttachmentInputIndices.isEmpty() || !isDepthInputAttachmentIndexImplicit ||
!isStencilInputAttachmentIndexImplicit;
}

void SetLocations(VkCommandBuffer cmd);
void SetInputIndices(VkCommandBuffer cmd);

// VkRenderingAttachmentLocationInfoKHR
// Notes:
// - If the array is empty, it indicates an identity mapping.
// - If an element is VK_ATTACHMENT_UNUSED, writes to it are disabled (as if the color
// attachment is masked)
rdcarray<uint32_t> colorAttachmentLocations;

// VkRenderingInputAttachmentIndexInfoKHR
// Notes:
// - The depth/stencil indices are only set if the is..Implicit flag is false. By default, the
// depth/stencil indices are assumed to be implicit (no input_attachment_index decoration
// needed in the shader).
// - If an element is VK_ATTACHMENT_UNUSED, it won't be used as input attachment.
rdcarray<uint32_t> colorAttachmentInputIndices;
bool isDepthInputAttachmentIndexImplicit = true;
bool isStencilInputAttachmentIndexImplicit = true;
uint32_t depthInputAttachmentIndex = UINT32_MAX;
uint32_t stencilInputAttachmentIndex = UINT32_MAX;
};

enum
{
VkCheckLayer_unique_objects,
Expand Down Expand Up @@ -1091,6 +1131,8 @@ enum class VulkanChunk : uint32_t
vkCmdTraceRaysIndirectKHR,
vkCmdTraceRaysKHR,
vkCreateRayTracingPipelinesKHR,
vkCmdSetRenderingAttachmentLocationsKHR,
vkCmdSetRenderingInputAttachmentIndicesKHR,
Max,
};

Expand Down Expand Up @@ -1335,6 +1377,7 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDescriptorIndexingProperties)
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDiscardRectanglePropertiesEXT);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDriverProperties);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDynamicRenderingFeatures);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExtendedDynamicState3FeaturesEXT);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExtendedDynamicState3PropertiesEXT);
Expand Down Expand Up @@ -1519,8 +1562,10 @@ DECLARE_REFLECTION_STRUCT(VkRayTracingShaderGroupCreateInfoKHR);
DECLARE_REFLECTION_STRUCT(VkRefreshCycleDurationGOOGLE);
DECLARE_REFLECTION_STRUCT(VkReleaseSwapchainImagesInfoEXT);
DECLARE_REFLECTION_STRUCT(VkRenderingAttachmentInfo);
DECLARE_REFLECTION_STRUCT(VkRenderingAttachmentLocationInfoKHR);
DECLARE_REFLECTION_STRUCT(VkRenderingFragmentDensityMapAttachmentInfoEXT);
DECLARE_REFLECTION_STRUCT(VkRenderingFragmentShadingRateAttachmentInfoKHR);
DECLARE_REFLECTION_STRUCT(VkRenderingInputAttachmentIndexInfoKHR);
DECLARE_REFLECTION_STRUCT(VkRenderingInfo);
DECLARE_REFLECTION_STRUCT(VkRenderPassAttachmentBeginInfo);
DECLARE_REFLECTION_STRUCT(VkRenderPassBeginInfo);
Expand Down Expand Up @@ -1775,6 +1820,7 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDescriptorIndexingProperties)
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDiscardRectanglePropertiesEXT);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDriverProperties);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDynamicRenderingFeatures);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState3FeaturesEXT);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState3PropertiesEXT);
Expand Down Expand Up @@ -1957,8 +2003,10 @@ DECLARE_DESERIALISE_TYPE(VkRayTracingPipelineInterfaceCreateInfoKHR);
DECLARE_DESERIALISE_TYPE(VkRayTracingShaderGroupCreateInfoKHR);
DECLARE_DESERIALISE_TYPE(VkReleaseSwapchainImagesInfoEXT);
DECLARE_DESERIALISE_TYPE(VkRenderingAttachmentInfo);
DECLARE_DESERIALISE_TYPE(VkRenderingAttachmentLocationInfoKHR);
DECLARE_DESERIALISE_TYPE(VkRenderingFragmentDensityMapAttachmentInfoEXT);
DECLARE_DESERIALISE_TYPE(VkRenderingFragmentShadingRateAttachmentInfoKHR);
DECLARE_DESERIALISE_TYPE(VkRenderingInputAttachmentIndexInfoKHR);
DECLARE_DESERIALISE_TYPE(VkRenderingInfo);
DECLARE_DESERIALISE_TYPE(VkRenderPassAttachmentBeginInfo);
DECLARE_DESERIALISE_TYPE(VkRenderPassBeginInfo);
Expand Down
Loading

0 comments on commit f1850d0

Please sign in to comment.