Implement resource usage tracking by versioned readback

This commit is contained in:
baldurk
2025-07-30 22:10:25 +01:00
parent 52fa006beb
commit 2fe13e8cdf
10 changed files with 460 additions and 77 deletions
+21
View File
@@ -700,6 +700,27 @@ void DoPipelineBarrier(VkCommandBuffer cmd, size_t count, const VkMemoryBarrier
0, NULL); // image memory barriers
}
VkDescriptorType MakeVkDescriptorType(DescriptorType type, bool inputAttachment)
{
switch(type)
{
case DescriptorType::Unknown: return VK_DESCRIPTOR_TYPE_MAX_ENUM;
case DescriptorType::Buffer: return VK_DESCRIPTOR_TYPE_MAX_ENUM;
case DescriptorType::ConstantBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
case DescriptorType::Sampler: return VK_DESCRIPTOR_TYPE_SAMPLER;
case DescriptorType::ImageSampler: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
case DescriptorType::Image:
return inputAttachment ? VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
case DescriptorType::TypedBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
case DescriptorType::ReadWriteImage: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
case DescriptorType::ReadWriteTypedBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
case DescriptorType::ReadWriteBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
case DescriptorType::AccelerationStructure:
return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
}
return VK_DESCRIPTOR_TYPE_MAX_ENUM;
}
Topology MakePrimitiveTopology(VkPrimitiveTopology Topo, uint32_t patchControlPoints)
{
switch(Topo)
+1
View File
@@ -106,6 +106,7 @@ typedef VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDevice
ResourceFormat MakeResourceFormat(VkFormat fmt);
VkFormat MakeVkFormat(ResourceFormat fmt);
VkDescriptorType MakeVkDescriptorType(DescriptorType type, bool inputAttachment);
Topology MakePrimitiveTopology(VkPrimitiveTopology Topo, uint32_t patchControlPoints);
VkPrimitiveTopology MakeVkPrimitiveTopology(Topology Topo);
AddressMode MakeAddressMode(VkSamplerAddressMode addr);
+216 -26
View File
@@ -7091,7 +7091,6 @@ void WrappedVulkan::AddUsage(VulkanActionTreeNode &actionNode, rdcarray<DebugMes
ActionDescription &action = actionNode.action;
const VulkanRenderState &state = m_BakedCmdBufferInfo[m_LastCmdBufferID].state;
VulkanCreationInfo &c = m_CreationInfo;
uint32_t eid = action.eventId;
ActionFlags DrawMask = ActionFlags::MeshDispatch | ActionFlags::Drawcall | ActionFlags::Dispatch;
@@ -7127,29 +7126,227 @@ void WrappedVulkan::AddUsage(VulkanActionTreeNode &actionNode, rdcarray<DebugMes
}
}
//////////////////////////////
// Framebuffer/renderpass
bool compute = bool(action.flags & ActionFlags::Dispatch);
if(!compute)
AddFramebufferUsage(actionNode, state);
const VulkanStatePipeline &pipeState = (compute ? state.compute : state.graphics);
//////////////////////////////
// Shaders
rdcarray<int> shaderStages;
if(pipeState.UsingDescBufs())
{
actionNode.deferredResourceUsage.push_back({});
VulkanActionTreeNode::DeferredResourceUsage &def = actionNode.deferredResourceUsage.back();
def.descBufVersionIdx = m_BakedCmdBufferInfo[m_LastCmdBufferID].descBufVersionIdx;
def.pipeline = pipeState.shaderObject ? ResourceId() : pipeState.pipeline;
if(pipeState.shaderObject)
memcpy(def.shaderObjects, state.shaderObjects, sizeof(state.shaderObjects));
def.descSets = pipeState.descSets;
bool usesPush = false;
// bake the recorded descriptor buffer offsets in so we don't have to track them separately
for(VulkanStatePipeline::DescriptorAndOffsets &desc : def.descSets)
{
if(desc.push)
{
usesPush = true;
continue;
}
// gaps in descriptor sets are possible
if(desc.descBufferIdx == ~0U)
continue;
desc.descBufferOffset +=
m_BakedCmdBufferInfo[m_LastCmdBufferID].descBufOffsets[desc.descBufferIdx];
}
if(!usesPush)
return;
}
AddUsageForDescriptorSets(actionNode, debugMessages);
}
static rdcarray<int> ShaderStagesForAction(ActionDescription &action)
{
if(action.flags & ActionFlags::Dispatch)
{
shaderStages = {5};
}
return {5};
else if(action.flags & ActionFlags::Drawcall)
{
shaderStages = {0, 1, 2, 3, 4};
}
return {0, 1, 2, 3, 4};
else if(action.flags & ActionFlags::MeshDispatch)
return {4, 6, 7};
return {};
}
void WrappedVulkan::AddUsageForDescriptorBuffers(VulkanActionTreeNode &actionNode,
rdcarray<DebugMessage> &debugMessages,
const VulkanActionTreeNode::DeferredResourceUsage &def)
{
if(def.descBufVersionIdx >= m_DescriptorBufferVersions.size())
{
shaderStages = {4, 6, 7};
RDCERR("Invalid deferred resource usage buffer reference");
return;
}
ActionDescription &action = actionNode.action;
VulkanCreationInfo &c = m_CreationInfo;
rdcarray<int> shaderStages = ShaderStagesForAction(action);
GPUBuffer &buf = m_DescriptorBufferVersions[def.descBufVersionIdx];
byte *descriptorBytes = (byte *)buf.Map();
for(int shad : shaderStages)
{
bool compute = (shad == 5);
ResourceId pipe = (compute ? state.compute.pipeline : state.graphics.pipeline);
ResourceId pipe = def.pipeline;
bool shaderObject = pipe == ResourceId();
bool shaderObject = (compute ? state.compute.shaderObject : state.graphics.shaderObject);
VulkanCreationInfo::ShaderEntry &sh = shaderObject
? c.m_ShaderObject[def.shaderObjects[shad]].shad
: c.m_Pipeline[pipe].shaders[shad];
if(sh.module == ResourceId())
continue;
ResourceId origPipe = GetResourceManager()->GetOriginalID(pipe);
ResourceId origShad = GetResourceManager()->GetOriginalID(sh.module);
for(const ConstantBlock &constantBlock : sh.refl->constantBlocks)
{
// ignore push constants
if(!constantBlock.bufferBacked)
continue;
AddUsageForDescriptorBufferBind(
actionNode, debugMessages, def, descriptorBytes,
DescriptorDataSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER), DescriptorType::ConstantBuffer,
constantBlock.fixedBindSetOrSpace, constantBlock.fixedBindNumber,
ResourceUsage(uint32_t(ResourceUsage::VS_Constants) + shad));
}
for(const ShaderResource &res : sh.refl->readOnlyResources)
{
AddUsageForDescriptorBufferBind(
actionNode, debugMessages, def, descriptorBytes,
DescriptorDataSize(MakeVkDescriptorType(res.descriptorType, res.isInputAttachment)),
res.descriptorType, res.fixedBindSetOrSpace, res.fixedBindNumber,
ResourceUsage(uint32_t(ResourceUsage::VS_Resource) + shad));
}
for(const ShaderResource &res : sh.refl->readWriteResources)
{
AddUsageForDescriptorBufferBind(
actionNode, debugMessages, def, descriptorBytes,
DescriptorDataSize(MakeVkDescriptorType(res.descriptorType, false)), res.descriptorType,
res.fixedBindSetOrSpace, res.fixedBindNumber,
ResourceUsage(uint32_t(ResourceUsage::VS_RWResource) + shad));
}
}
buf.Unmap();
}
void WrappedVulkan::AddUsageForDescriptorBufferBind(
VulkanActionTreeNode &actionNode, rdcarray<DebugMessage> &debugMessages,
const VulkanActionTreeNode::DeferredResourceUsage &def, byte *descriptorBytes,
size_t descriptorSize, DescriptorType type, uint32_t bindset, uint32_t bind, ResourceUsage usage)
{
static bool hugeRangeWarned = false;
uint32_t eid = actionNode.action.eventId;
const rdcarray<VulkanStatePipeline::DescriptorAndOffsets> &descSets = def.descSets;
VulkanCreationInfo &c = m_CreationInfo;
DebugMessage msg;
msg.eventId = eid;
msg.category = MessageCategory::Execution;
msg.messageID = 0;
msg.source = MessageSource::IncorrectAPIUse;
msg.severity = MessageSeverity::High;
if(bindset >= descSets.size() || !descSets[bindset].IsBound())
{
msg.description =
StringFormat::Fmt("Shader referenced a descriptor set %i that was not bound", bindset);
debugMessages.push_back(msg);
return;
}
// ignore push sets, these were handled normally
if(descSets[bindset].push)
return;
const VulkanCreationInfo::PipelineLayout &pipeLayout =
c.m_PipelineLayout[descSets[bindset].pipeLayout];
const DescSetLayout &layout = c.m_DescSetLayout[pipeLayout.descSetLayouts[bindset]];
if(layout.bindings.empty())
{
msg.description =
StringFormat::Fmt("Shader referenced a descriptor set %i that was not bound", bindset);
debugMessages.push_back(msg);
return;
}
if(bind >= layout.bindings.size())
{
msg.description = StringFormat::Fmt(
"Shader referenced a bind %i in descriptor set %i that does not exist. Mismatched "
"descriptor set?",
bind, bindset);
debugMessages.push_back(msg);
return;
}
// no object to mark for usage with inline blocks
if(layout.bindings[bind].layoutDescType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
return;
uint32_t descriptorCount = layout.bindings[bind].descriptorCount;
// completely skip variable size or arrayed bindings as it is too spammy to look up uninitialised
// descriptors and there is a chance of false positives
if(layout.bindings[bind].variableSize || descriptorCount > 1)
return;
for(uint32_t a = 0; a < descriptorCount; a++)
{
DescriptorSetSlot tmp = {};
LookupDescriptor(descriptorBytes + descSets[bindset].descBufferOffset +
layout.bindings[bind].elemOffset + descriptorSize * a,
descriptorSize, type, tmp);
AddUsageForDescriptor(actionNode, tmp, usage);
}
}
void WrappedVulkan::AddUsageForDescriptorSets(VulkanActionTreeNode &actionNode,
rdcarray<DebugMessage> &debugMessages)
{
ActionDescription &action = actionNode.action;
const VulkanRenderState &state = m_BakedCmdBufferInfo[m_LastCmdBufferID].state;
const VulkanStatePipeline &pipeState =
(action.flags & ActionFlags::Dispatch ? state.compute : state.graphics);
VulkanCreationInfo &c = m_CreationInfo;
rdcarray<int> shaderStages = ShaderStagesForAction(action);
for(int shad : shaderStages)
{
ResourceId pipe = pipeState.pipeline;
bool shaderObject = pipeState.shaderObject;
VulkanCreationInfo::ShaderEntry &sh = shaderObject
? c.m_ShaderObject[state.shaderObjects[shad]].shad
@@ -7185,12 +7382,6 @@ void WrappedVulkan::AddUsage(VulkanActionTreeNode &actionNode, rdcarray<DebugMes
ResourceUsage(uint32_t(ResourceUsage::VS_RWResource) + shad));
}
}
//////////////////////////////
// Framebuffer/renderpass
if(!(action.flags & ActionFlags::Dispatch))
AddFramebufferUsage(actionNode, state);
}
void WrappedVulkan::AddUsageForDescriptorSetBind(VulkanActionTreeNode &actionNode,
@@ -7216,20 +7407,18 @@ void WrappedVulkan::AddUsageForDescriptorSetBind(VulkanActionTreeNode &actionNod
if(bindset >= descSets.size() || !descSets[bindset].IsBound())
{
// can't generate usage for descriptor buffers
if(!state.descBufs.empty())
return;
msg.description =
StringFormat::Fmt("Shader referenced a descriptor set %i that was not bound", bindset);
debugMessages.push_back(msg);
return;
}
DescriptorSetInfo &descset = m_DescriptorSetState[descSets[bindset].descSet];
DescSetLayout &layout = c.m_DescSetLayout[descset.layout];
// can't generate usage for descriptor buffers
if(descSets[bindset].descBufferIdx != ~0U)
return;
ResourceId layoutId = GetResourceManager()->GetOriginalID(descset.layout);
const DescriptorSetInfo &descset = m_DescriptorSetState[descSets[bindset].descSet];
const DescSetLayout &layout = c.m_DescSetLayout[descset.layout];
if(layout.bindings.empty())
{
@@ -7314,7 +7503,8 @@ void WrappedVulkan::AddUsageForDescriptor(VulkanActionTreeNode &actionNode,
break;
case DescriptorSlotType::UniformTexelBuffer:
case DescriptorSlotType::StorageTexelBuffer:
if(slot.resource != ResourceId())
id = slot.resource;
if(c.m_BufferView.find(slot.resource) != c.m_BufferView.end())
id = c.m_BufferView[slot.resource].buffer;
break;
case DescriptorSlotType::UniformBuffer:
+29
View File
@@ -143,6 +143,15 @@ struct VulkanActionTreeNode
rdcarray<ResourceId> executedCmds;
struct DeferredResourceUsage
{
uint32_t descBufVersionIdx;
ResourceId pipeline;
ResourceId shaderObjects[NumShaderStages];
rdcarray<VulkanStatePipeline::DescriptorAndOffsets> descSets;
};
rdcarray<DeferredResourceUsage> deferredResourceUsage;
VulkanActionTreeNode &operator=(const ActionDescription &a)
{
*this = VulkanActionTreeNode(a);
@@ -840,6 +849,11 @@ private:
uint32_t eventCount; // how many events are in this cmd buffer, for quick skipping
uint32_t curEventID; // current event ID while reading or executing
uint32_t actionCount; // similar to above
// the index in m_DescriptorBufferVersions for the current GPUBuffer containing the descriptor buffer snapshot
uint32_t descBufVersionIdx = ~0U;
// when multiple buffers are bound, the offsets of each in the single GPUBuffer where they are
rdcarray<uint64_t> descBufOffsets;
};
uint64_t m_FakePushSetID = 0;
@@ -1071,6 +1085,9 @@ private:
// immutable creation data
VulkanCreationInfo m_CreationInfo;
rdcarray<GPUBuffer> m_DescriptorBufferVersions;
void VersionDescriptorBuffers(VkCommandBuffer cmd);
std::map<ResourceId, rdcarray<EventUsage>> m_ResourceUses;
std::map<uint32_t, EventFlags> m_EventFlags;
rdcarray<ResourceId> m_FeedbackRPs;
@@ -1239,9 +1256,21 @@ private:
void AddEvent();
void AddUsage(VulkanActionTreeNode &actionNode, rdcarray<DebugMessage> &debugMessages);
void AddUsageForDescriptorSets(VulkanActionTreeNode &actionNode,
rdcarray<DebugMessage> &debugMessages);
void AddUsageForDescriptorSetBind(VulkanActionTreeNode &actionNode,
rdcarray<DebugMessage> &debugMessages, uint32_t bindset,
uint32_t bind, ResourceUsage usage);
void AddUsageForDescriptorBuffers(VulkanActionTreeNode &actionNode,
rdcarray<DebugMessage> &debugMessages,
const VulkanActionTreeNode::DeferredResourceUsage &def);
void AddUsageForDescriptorBufferBind(VulkanActionTreeNode &actionNode,
rdcarray<DebugMessage> &debugMessages,
const VulkanActionTreeNode::DeferredResourceUsage &def,
byte *descriptorBytes, size_t descriptorSize,
DescriptorType type, uint32_t bindset, uint32_t bind,
ResourceUsage usage);
void AddUsageForDescriptor(VulkanActionTreeNode &actionNode, const DescriptorSetSlot &slot,
ResourceUsage usage);
+4 -17
View File
@@ -1016,17 +1016,8 @@ void ProcessStaticDescriptorAccess(VulkanResourceManager *resourceMan, ShaderRef
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT)
{
access.descriptorStore = VulkanCreationInfo::descriptorBufferStorage[bind.fixedBindSetOrSpace];
if(bind.isInputAttachment)
access.byteSize = resourceMan->DescriptorDataSize(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
else if(bind.hasSampler)
access.byteSize = resourceMan->DescriptorDataSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
else if(bind.isTexture)
access.byteSize = resourceMan->DescriptorDataSize(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
else if(bind.descriptorType == DescriptorType::AccelerationStructure)
access.byteSize =
resourceMan->DescriptorDataSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
else
access.byteSize = resourceMan->DescriptorDataSize(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
access.byteSize = resourceMan->DescriptorDataSize(
MakeVkDescriptorType(bind.descriptorType, bind.isInputAttachment));
// we are only handling non-arrays here
access.byteOffset = setLayout->bindings[bind.fixedBindNumber].elemOffset;
@@ -1073,12 +1064,8 @@ void ProcessStaticDescriptorAccess(VulkanResourceManager *resourceMan, ShaderRef
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT)
{
access.descriptorStore = VulkanCreationInfo::descriptorBufferStorage[bind.fixedBindSetOrSpace];
if(bind.isTexture)
access.byteSize = resourceMan->DescriptorDataSize(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
else if(bind.descriptorType == DescriptorType::ReadWriteTypedBuffer)
access.byteSize = resourceMan->DescriptorDataSize(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
else
access.byteSize = resourceMan->DescriptorDataSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
access.byteSize =
resourceMan->DescriptorDataSize(MakeVkDescriptorType(bind.descriptorType, false));
// we are only handling non-arrays here
access.byteOffset = setLayout->bindings[bind.fixedBindNumber].elemOffset;
@@ -45,27 +45,6 @@ RDOC_CONFIG(uint32_t, Vulkan_Debug_PrintfBufferSize, 64 * 1024,
static const uint32_t ShaderStageHeaderBitShift = 28U;
static const uint32_t ShaderFeedbackReservedBindings = 1;
VkDescriptorType MakeVkDescriptorType(DescriptorType type, bool inputAttachment)
{
switch(type)
{
case DescriptorType::Unknown: return VK_DESCRIPTOR_TYPE_MAX_ENUM;
case DescriptorType::Buffer: return VK_DESCRIPTOR_TYPE_MAX_ENUM;
case DescriptorType::ConstantBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
case DescriptorType::Sampler: return VK_DESCRIPTOR_TYPE_SAMPLER;
case DescriptorType::ImageSampler: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
case DescriptorType::Image:
return inputAttachment ? VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
case DescriptorType::TypedBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
case DescriptorType::ReadWriteImage: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
case DescriptorType::ReadWriteTypedBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
case DescriptorType::ReadWriteBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
case DescriptorType::AccelerationStructure:
return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
}
return VK_DESCRIPTOR_TYPE_MAX_ENUM;
}
struct BindKey
{
bool operator<(const BindKey &o) const
+1
View File
@@ -45,6 +45,7 @@ struct VulkanStatePipeline
struct DescriptorAndOffsets
{
ResourceId pipeLayout;
bool push = false;
// if descriptor set bound
ResourceId descSet;
@@ -55,6 +55,62 @@ static rdcstr ToHumanStr(const VkAttachmentStoreOp &el)
END_ENUM_STRINGISE();
}
void WrappedVulkan::VersionDescriptorBuffers(VkCommandBuffer cmd)
{
VulkanRenderState &renderstate = m_BakedCmdBufferInfo[m_LastCmdBufferID].state;
uint32_t &version = m_BakedCmdBufferInfo[m_LastCmdBufferID].descBufVersionIdx;
rdcarray<uint64_t> &offsets = m_BakedCmdBufferInfo[m_LastCmdBufferID].descBufOffsets;
uint64_t neededBytes = 0;
for(uint32_t i = 0; i < renderstate.descBufs.size(); i++)
{
offsets.push_back(neededBytes);
ResourceId id;
uint64_t offs;
GetResIDFromAddr(renderstate.descBufs[i].address, id, offs);
neededBytes += m_CreationInfo.m_Buffer[id].size - offs;
}
uint32_t nextUnusedVersion = (version == ~0U ? 0 : version + 1);
version = ~0U;
for(uint32_t ver = nextUnusedVersion; ver < m_DescriptorBufferVersions.size(); ver++)
{
if(m_DescriptorBufferVersions[ver].TotalSize() >= neededBytes)
{
// use this version and copy into it
version = ver;
break;
}
}
if(version == ~0U)
{
version = (uint32_t)m_DescriptorBufferVersions.size();
m_DescriptorBufferVersions.push_back(GPUBuffer());
m_DescriptorBufferVersions.back().Create(this, m_Device, neededBytes, 1,
GPUBuffer::eGPUBufferReadback);
}
for(uint32_t i = 0; i < renderstate.descBufs.size(); i++)
{
ResourceId id;
uint64_t offs;
GetResIDFromAddr(renderstate.descBufs[i].address, id, offs);
const VkBufferCopy region = {
offs,
offsets[i],
m_CreationInfo.m_Buffer[id].size - offs,
};
ObjDisp(cmd)->CmdCopyBuffer(Unwrap(cmd),
Unwrap(GetResourceManager()->GetCurrentHandle<VkBuffer>(id)),
m_DescriptorBufferVersions[version].UnwrappedBuffer(), 1, &region);
}
}
void WrappedVulkan::AddImplicitResolveResourceUsage(uint32_t subpass)
{
ResourceId rp = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.GetRenderPass();
@@ -3572,6 +3628,7 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets(
{
descsets[firstSet + i].pipeLayout = GetResID(layout);
descsets[firstSet + i].descSet = GetResID(pDescriptorSets[i]);
descsets[firstSet + i].push = false;
descsets[firstSet + i].offsets.clear();
if(descSetLayouts[firstSet + i] == ResourceId())
@@ -3593,12 +3650,22 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets(
rdcarray<VulkanStatePipeline::DescriptorAndOffsets> &descsets =
m_BakedCmdBufferInfo[m_LastCmdBufferID].state.GetPipeline(pipelineBindPoint).descSets;
// descriptor buffers and descriptor sets can't co-exist, each invalidates the other
if(m_BakedCmdBufferInfo[m_LastCmdBufferID].state.GetPipeline(pipelineBindPoint).UsingDescBufs())
{
m_BakedCmdBufferInfo[m_LastCmdBufferID].state.descBufs.clear();
descsets.clear();
}
// expand as necessary
if(descsets.size() < firstSet + setCount)
descsets.resize(firstSet + setCount);
for(uint32_t i = 0; i < setCount; i++)
{
descsets[firstSet + i].descSet = GetResID(pDescriptorSets[i]);
descsets[firstSet + i].push = false;
}
ObjDisp(commandBuffer)
->CmdBindDescriptorSets(Unwrap(commandBuffer), pipelineBindPoint, Unwrap(layout),
@@ -4371,6 +4438,24 @@ bool WrappedVulkan::Serialise_vkCmdPipelineBarrier2(SerialiserType &ser,
if(commandBuffer != VK_NULL_HANDLE)
{
if(IsLoading(m_State))
{
bool descBarrier = false;
for(uint32_t i = 0; i < DependencyInfo.bufferMemoryBarrierCount; i++)
if(DependencyInfo.pBufferMemoryBarriers[i].dstAccessMask &
VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT)
descBarrier = true;
for(uint32_t i = 0; i < DependencyInfo.memoryBarrierCount; i++)
if(DependencyInfo.pMemoryBarriers[i].dstAccessMask &
VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT)
descBarrier = true;
if(descBarrier)
VersionDescriptorBuffers(commandBuffer);
}
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[m_LastCmdBufferID].imageStates,
FindCommandQueueFamily(m_LastCmdBufferID),
(uint32_t)imgBarriers.size(), imgBarriers.data());
@@ -5612,6 +5697,7 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetKHR(SerialiserType &ser,
descsets[set].pipeLayout = GetResID(layout);
descsets[set].descSet = setId;
descsets[set].push = true;
}
// actual replay of the command will happen below
@@ -5634,6 +5720,7 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetKHR(SerialiserType &ser,
// we use a 'special' ID for the push descriptor at this index, since there's no actual
// allocated object corresponding to it.
descsets[set].descSet = setId;
descsets[set].push = true;
}
if(commandBuffer != VK_NULL_HANDLE)
@@ -5985,6 +6072,7 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetWithTemplateKHR(
descsets[set].pipeLayout = GetResID(layout);
descsets[set].descSet = setId;
descsets[set].push = true;
}
// actual replay of the command will happen below
@@ -6007,6 +6095,7 @@ bool WrappedVulkan::Serialise_vkCmdPushDescriptorSetWithTemplateKHR(
// we use a 'special' ID for the push descriptor at this index, since there's no actual
// allocated object corresponding to it.
descsets[set].descSet = setId;
descsets[set].push = true;
}
if(commandBuffer != VK_NULL_HANDLE)
@@ -8766,9 +8855,32 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorBuffersEXT(
}
else
{
// track while reading, as while we can't track resource usage for descriptor buffers we want
// to know we're using them
m_BakedCmdBufferInfo[m_LastCmdBufferID].state.descBufs.resize(bufferCount);
// track while reading, for resource usage
{
VulkanRenderState &renderstate = m_BakedCmdBufferInfo[m_LastCmdBufferID].state;
// all descriptor buffers above bufferCount are unbound
renderstate.descBufs.resize(bufferCount);
for(uint32_t i = 0; i < bufferCount; i++)
renderstate.descBufs[i].address = pBindingInfos[i].address;
// any offsets that refer to these buffers are invalidated, but then also other buffers
// are unbound meaning those are invalid - we can clear all bindings that refer to
// descriptor buffers however normal descriptor sets must remain as they are *not*
// invalidated and could still be used
for(VkPipelineBindPoint bindPoint :
{VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE,
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR})
{
VulkanStatePipeline &pipe = renderstate.GetPipeline(bindPoint);
for(uint32_t i = 0; i < pipe.descSets.size(); i++)
if(pipe.descSets[i].descSet == ResourceId())
pipe.descSets[i] = {};
}
VersionDescriptorBuffers(commandBuffer);
}
ObjDisp(commandBuffer)
->CmdBindDescriptorBuffersEXT(Unwrap(commandBuffer), bufferCount, unwrappedInfos.data());
@@ -8874,13 +8986,35 @@ bool WrappedVulkan::Serialise_vkCmdSetDescriptorBufferOffsetsEXT(
}
else
{
// track while reading, as while we can't track resource usage for descriptor buffers we want
// to know we're using them
for(VkPipelineBindPoint bindPoint :
{VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE,
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR})
// track while reading, for resource usage
{
m_BakedCmdBufferInfo[m_LastCmdBufferID].state.GetPipeline(bindPoint).descSets.clear();
VulkanRenderState &renderstate = m_BakedCmdBufferInfo[m_LastCmdBufferID].state;
VulkanStatePipeline &pipeline = renderstate.GetPipeline(pipelineBindPoint);
pipeline.lastBoundSet = firstSet;
// descriptor set bindings are overwritten/cleared by descriptor buffer bindings
for(uint32_t set = 0; set < setCount; set++)
{
pipeline.descSets.resize_for_index(firstSet + set);
pipeline.descSets[firstSet + set].pipeLayout = GetResID(layout);
pipeline.descSets[firstSet + set].descBufferIdx = pBufferIndices[set];
pipeline.descSets[firstSet + set].descBufferOffset = pOffsets[set];
pipeline.descSets[firstSet + set].descBufferEmbeddedSamplers = false;
}
// any normal descriptor set bindings are invalidated
for(VkPipelineBindPoint bindPoint :
{VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE,
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR})
{
VulkanStatePipeline &pipe = renderstate.GetPipeline(bindPoint);
for(uint32_t i = 0; i < pipe.descSets.size(); i++)
if(pipe.descSets[i].descSet != ResourceId())
pipe.descSets[i] = {};
}
}
ObjDisp(commandBuffer)
@@ -281,8 +281,6 @@ void WrappedVulkan::ReplayQueueSubmit(VkQueue queue, VkSubmitInfo2 submitInfo, r
{
if(IsLoading(m_State))
{
DoSubmit(queue, submitInfo);
AddEvent();
// we're adding multiple events, need to increment ourselves
@@ -290,6 +288,8 @@ void WrappedVulkan::ReplayQueueSubmit(VkQueue queue, VkSubmitInfo2 submitInfo, r
if(submitInfo.commandBufferInfoCount == 0)
{
DoSubmit(queue, submitInfo);
rdcstr name = StringFormat::Fmt("=> %s: No Command Buffers", basename.c_str());
ActionDescription action;
@@ -304,10 +304,18 @@ void WrappedVulkan::ReplayQueueSubmit(VkQueue queue, VkSubmitInfo2 submitInfo, r
m_RootEventID++;
}
for(uint32_t c = 0; c < submitInfo.commandBufferInfoCount; c++)
// submit command buffers one by one
uint32_t numCmds = submitInfo.commandBufferInfoCount;
submitInfo.commandBufferInfoCount = 1;
for(uint32_t c = 0; c < numCmds; c++)
{
DoSubmit(queue, submitInfo);
FlushQ();
ResourceId cmd = GetResourceManager()->GetOriginalID(
GetResID(submitInfo.pCommandBufferInfos[c].commandBuffer));
GetResID(submitInfo.pCommandBufferInfos[0].commandBuffer));
submitInfo.pCommandBufferInfos++;
BakedCmdBufferInfo &cmdBufInfo = m_BakedCmdBufferInfo[cmd];
@@ -637,6 +645,18 @@ void WrappedVulkan::InsertActionsAndRefreshIDs(BakedCmdBufferInfo &cmdBufInfo)
for(size_t i = 0; i < cmdBufNodes.size(); i++)
{
VulkanActionTreeNode n = cmdBufNodes[i];
for(VulkanActionTreeNode::DeferredResourceUsage &def : n.deferredResourceUsage)
{
if(def.descBufVersionIdx >= m_DescriptorBufferVersions.size())
{
RDCERR("Invalid deferred resource usage buffer reference");
continue;
}
AddUsageForDescriptorBuffers(n, cmdBufInfo.debugMessages, def);
}
n.action.eventId += m_RootEventID;
n.action.actionId += m_RootActionID;
@@ -1361,6 +1361,27 @@ bool WrappedVulkan::Serialise_vkCmdWaitEvents2(SerialiserType &ser, VkCommandBuf
if(commandBuffer != VK_NULL_HANDLE)
{
if(IsLoading(m_State) && evIdx == 0)
{
bool descBarrier = false;
for(uint32_t ev = 0; ev < eventCount; ev++)
{
for(uint32_t i = 0; i < pDependencyInfos[ev].bufferMemoryBarrierCount; i++)
if(pDependencyInfos[ev].pBufferMemoryBarriers[i].dstAccessMask &
VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT)
descBarrier = true;
for(uint32_t i = 0; i < pDependencyInfos[ev].memoryBarrierCount; i++)
if(pDependencyInfos[ev].pMemoryBarriers[i].dstAccessMask &
VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT)
descBarrier = true;
}
if(descBarrier)
VersionDescriptorBuffers(commandBuffer);
}
VkEventCreateInfo evInfo = {
VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
NULL,