mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-26 08:26:50 +00:00
Implement resource usage tracking by versioned readback
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ®ion);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user