Track last descriptor buffer and normal descriptor set binds separately

* We need to track these separately because descriptor buffer set invalidation
  can lead to empty sets with no valid pipeline layout as the last bound set
  (since we can't _clear_ the descriptor sets when descriptor buffers are
  invalidated, as there may be a descriptor set binding there). Track these
  separately so we can pick the right set to bind from if we don't have a known
  pipeline layout, and also handle the case where there are descriptor set
  states but the last bound is not valid.
This commit is contained in:
baldurk
2026-01-24 12:48:48 +00:00
parent 55bcd77624
commit 738a5c1ea5
4 changed files with 102 additions and 22 deletions
+5 -2
View File
@@ -103,7 +103,7 @@ struct VulkanQuadOverdrawCallback : public VulkanActionCallback
const ResourceId layoutID =
(pipestate.graphics.shaderObject)
? pipestate.graphics.descSets[pipestate.graphics.lastBoundSet].pipeLayout
? pipestate.graphics.descSets[pipestate.graphics.LastBoundSet()].pipeLayout
: p.vertLayout;
const VulkanCreationInfo::PipelineLayout &layout =
@@ -292,7 +292,10 @@ struct VulkanQuadOverdrawCallback : public VulkanActionCallback
if(pipestate.graphics.shaderObject)
{
pipestate.shaderObjects[4] = GetResID(shad.shad);
pipestate.graphics.lastBoundSet = shad.descSet;
if(pipestate.graphics.UsingDescBufs())
pipestate.graphics.lastBoundDescBufSet = shad.descSet;
else
pipestate.graphics.lastBoundDescSet = shad.descSet;
pipestate.graphics.pipeline = ResourceId();
RDCASSERT(pipestate.graphics.descSets.size() >= shad.descSet);
+19 -5
View File
@@ -1002,8 +1002,15 @@ void VulkanRenderState::BindDescriptorSetsWithoutPipeline(WrappedVulkan *vk, VkC
// compatible with it. Anything not compatible by definition has been invalidated so we don't need
// to rebind it to be valid.
uint32_t lastSet = pipe.LastBoundSet();
ResourceId pipeLayoutId =
lastSet < pipe.descSets.size() ? pipe.descSets[lastSet].pipeLayout : ResourceId();
if(pipeLayoutId == ResourceId())
return;
const VulkanCreationInfo::PipelineLayout &refPipeLayout =
vk->GetDebugManager()->GetPipelineLayoutInfo(pipe.descSets[pipe.lastBoundSet].pipeLayout);
vk->GetDebugManager()->GetPipelineLayoutInfo(pipeLayoutId);
for(size_t i = 0; i < pipe.descSets.size(); i++)
{
@@ -1013,7 +1020,7 @@ void VulkanRenderState::BindDescriptorSetsWithoutPipeline(WrappedVulkan *vk, VkC
const VulkanCreationInfo::PipelineLayout &iPipeLayout =
vk->GetDebugManager()->GetPipelineLayoutInfo(pipe.descSets[i].pipeLayout);
if(i != pipe.lastBoundSet)
if(i != pipe.LastBoundSet())
{
// if we come to a descriptor set that isn't compatible with the pipeline layout used in the
// last bound set, don't bind this descriptor set
@@ -1025,10 +1032,10 @@ void VulkanRenderState::BindDescriptorSetsWithoutPipeline(WrappedVulkan *vk, VkC
// quick check, if the pipeline layout is the same as the one used to bind the reference set
// then its certainly compatible
if(pipe.descSets[i].pipeLayout != pipe.descSets[pipe.lastBoundSet].pipeLayout)
if(pipe.descSets[i].pipeLayout != pipe.descSets[pipe.LastBoundSet()].pipeLayout)
{
// are we below or above the last bound set
if(i < pipe.lastBoundSet)
if(i < pipe.LastBoundSet())
{
// we only check if this set is compatible with the pipeline layout on this set.
// Technically the set might have been perturbed still, or we might invalidate this
@@ -1129,8 +1136,15 @@ void VulkanRenderState::BindDescriptorSetsForShaders(WrappedVulkan *vk, VkComman
if(pipe.descSets.empty())
return;
uint32_t lastSet = pipe.LastBoundSet();
ResourceId pipeLayoutId =
lastSet < pipe.descSets.size() ? pipe.descSets[lastSet].pipeLayout : ResourceId();
if(pipeLayoutId == ResourceId())
return;
const rdcarray<ResourceId> &descSetLayouts =
vk->GetDebugManager()->GetPipelineLayoutInfo(pipe.descSets[pipe.lastBoundSet].pipeLayout).descSetLayouts;
vk->GetDebugManager()->GetPipelineLayoutInfo(pipeLayoutId).descSetLayouts;
for(size_t i = 0; i < descSetLayouts.size(); i++)
{
+15 -1
View File
@@ -71,7 +71,21 @@ struct VulkanStatePipeline
// the index of the last set bound. In the case where we are re-binding sets and don't have a
// valid pipeline to reference, this can help us resolve which descriptor sets to rebind in the
// event that they're not all compatible
uint32_t lastBoundSet = 0;
// we need to track the last descriptor set separately from the last descriptor buffer set,
// because if a descriptor buffer set is invalidated the previous last descriptor set may still be
// valid. There is no way to do the other direction (any descriptor set bind invalidates all
// descriptor buffer set bindings)
int32_t lastBoundDescSet = -1;
int32_t lastBoundDescBufSet = -1;
uint32_t LastBoundSet() const
{
if(UsingDescBufs() && lastBoundDescBufSet >= 0)
return lastBoundDescBufSet;
if(lastBoundDescSet >= 0)
return lastBoundDescSet;
return 0;
}
bool UsingDescBufs() const
{
@@ -3849,7 +3849,8 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets(
if(descsets.size() < firstSet + setCount)
descsets.resize(firstSet + setCount);
pipeline.lastBoundSet = firstSet;
pipeline.lastBoundDescSet = firstSet;
pipeline.lastBoundDescBufSet = -1;
const rdcarray<ResourceId> &descSetLayouts =
m_CreationInfo.m_PipelineLayout[GetResID(layout)].descSetLayouts;
@@ -3998,7 +3999,8 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets2(
// expand as necessary
descsets.resize_for_index(firstSet + BindDescriptorSetsInfo.descriptorSetCount - 1);
pipeline.lastBoundSet = firstSet;
pipeline.lastBoundDescSet = firstSet;
pipeline.lastBoundDescBufSet = -1;
const rdcarray<ResourceId> &descSetLayouts =
m_CreationInfo.m_PipelineLayout[GetResID(BindDescriptorSetsInfo.layout)].descSetLayouts;
@@ -6160,8 +6162,6 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSet(SerialiserType &ser,
if(descsets.size() < set + 1)
descsets.resize(set + 1);
pipeline.lastBoundSet = set;
descsets[set] = VulkanStatePipeline::DescriptorAndOffsets();
descsets[set].pipeLayout = GetResID(layout);
descsets[set].descSet = setId;
@@ -6171,6 +6171,17 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSet(SerialiserType &ser,
descsets[set].descBufferPush =
(m_CreationInfo.m_DescSetLayout[setLayout].flags &
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT) != 0;
if(descsets[set].descBufferPush)
{
pipeline.lastBoundDescSet = -1;
pipeline.lastBoundDescBufSet = set;
}
else
{
pipeline.lastBoundDescSet = set;
pipeline.lastBoundDescBufSet = -1;
}
}
// actual replay of the command will happen below
@@ -6445,8 +6456,6 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetWithTemplate(
if(descsets.size() < set + 1)
descsets.resize(set + 1);
pipeline.lastBoundSet = set;
descsets[set] = VulkanStatePipeline::DescriptorAndOffsets();
descsets[set].pipeLayout = GetResID(layout);
descsets[set].descSet = setId;
@@ -6456,6 +6465,17 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetWithTemplate(
descsets[set].descBufferPush =
(m_CreationInfo.m_DescSetLayout[setLayout].flags &
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT) != 0;
if(descsets[set].descBufferPush)
{
pipeline.lastBoundDescSet = -1;
pipeline.lastBoundDescBufSet = set;
}
else
{
pipeline.lastBoundDescSet = set;
pipeline.lastBoundDescBufSet = -1;
}
}
// actual replay of the command will happen below
@@ -9387,6 +9407,7 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorBuffersEXT(
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR})
{
VulkanStatePipeline &pipe = renderstate.GetPipeline(bindPoint);
pipe.lastBoundDescBufSet = -1;
for(uint32_t i = 0; i < pipe.descSets.size(); i++)
if(pipe.descSets[i].descSet == ResourceId())
@@ -9499,7 +9520,7 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsetsEXT(
VulkanRenderState &renderstate = GetCmdRenderState();
VulkanStatePipeline &pipeline = renderstate.GetPipeline(pipelineBindPoint);
pipeline.lastBoundSet = firstSet;
pipeline.lastBoundDescBufSet = firstSet;
// descriptor set bindings are overwritten/cleared by descriptor buffer bindings
for(uint32_t set = 0; set < setCount; set++)
@@ -9515,6 +9536,7 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsetsEXT(
}
// any normal descriptor set bindings are invalidated
pipeline.lastBoundDescSet = -1;
for(VkPipelineBindPoint bindPoint :
{VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE,
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR})
@@ -9535,7 +9557,7 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsetsEXT(
VulkanRenderState &renderstate = m_BakedCmdBufferInfo[m_LastCmdBufferID].state;
VulkanStatePipeline &pipeline = renderstate.GetPipeline(pipelineBindPoint);
pipeline.lastBoundSet = firstSet;
pipeline.lastBoundDescBufSet = firstSet;
// descriptor set bindings are overwritten/cleared by descriptor buffer bindings
for(uint32_t set = 0; set < setCount; set++)
@@ -9551,6 +9573,7 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsetsEXT(
}
// any normal descriptor set bindings are invalidated
pipeline.lastBoundDescSet = -1;
for(VkPipelineBindPoint bindPoint :
{VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE,
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR})
@@ -9729,7 +9752,7 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsets2EXT(
{
VulkanStatePipeline &pipeline = renderstate.GetPipeline(pipelineBindPoint);
pipeline.lastBoundSet = firstSet;
pipeline.lastBoundDescBufSet = firstSet;
// descriptor set bindings are overwritten/cleared by descriptor buffer bindings
for(uint32_t set = 0; set < SetDescriptorBufferOffsetsInfo.setCount; set++)
@@ -9754,6 +9777,7 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsets2EXT(
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR})
{
VulkanStatePipeline &pipe = renderstate.GetPipeline(bindPoint);
pipe.lastBoundDescSet = -1;
for(uint32_t i = 0; i < pipe.descSets.size(); i++)
if(!pipe.descSets[i].IsDescBufferBound())
@@ -9770,7 +9794,7 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsets2EXT(
{
VulkanStatePipeline &pipeline = renderstate.GetPipeline(pipelineBindPoint);
pipeline.lastBoundSet = firstSet;
pipeline.lastBoundDescBufSet = firstSet;
// descriptor set bindings are overwritten/cleared by descriptor buffer bindings
for(uint32_t set = 0; set < SetDescriptorBufferOffsetsInfo.setCount; set++)
@@ -9795,6 +9819,7 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsets2EXT(
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR})
{
VulkanStatePipeline &pipe = renderstate.GetPipeline(bindPoint);
pipe.lastBoundDescSet = -1;
for(uint32_t i = 0; i < pipe.descSets.size(); i++)
if(!pipe.descSets[i].IsDescBufferBound())
@@ -9982,8 +10007,6 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSet2(
if(descsets.size() < set + 1)
descsets.resize(set + 1);
pipeline.lastBoundSet = set;
descsets[set] = VulkanStatePipeline::DescriptorAndOffsets();
descsets[set].pipeLayout = GetResID(PushDescriptorSetInfo.layout);
descsets[set].descSet = setId;
@@ -9993,6 +10016,17 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSet2(
descsets[set].descBufferPush =
(m_CreationInfo.m_DescSetLayout[setLayout].flags &
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT) != 0;
if(descsets[set].descBufferPush)
{
pipeline.lastBoundDescSet = -1;
pipeline.lastBoundDescBufSet = set;
}
else
{
pipeline.lastBoundDescSet = set;
pipeline.lastBoundDescBufSet = -1;
}
}
// actual replay of the command will happen below
@@ -10151,12 +10185,27 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetWithTemplate2(
if(descsets.size() < set + 1)
descsets.resize(set + 1);
pipeline.lastBoundSet = set;
descsets[set] = VulkanStatePipeline::DescriptorAndOffsets();
descsets[set].pipeLayout = GetResID(PushDescriptorSetWithTemplateInfo.layout);
descsets[set].descSet = setId;
descsets[set].push = true;
ResourceId setLayout =
m_CreationInfo.m_PipelineLayout[GetResID(PushDescriptorSetWithTemplateInfo.layout)]
.descSetLayouts[set];
descsets[set].descBufferPush =
(m_CreationInfo.m_DescSetLayout[setLayout].flags &
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT) != 0;
if(descsets[set].descBufferPush)
{
pipeline.lastBoundDescSet = -1;
pipeline.lastBoundDescBufSet = set;
}
else
{
pipeline.lastBoundDescSet = set;
pipeline.lastBoundDescBufSet = -1;
}
}
// actual replay of the command will happen below