mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 17:10:47 +00:00
Queue any indirect data fetches to happen outside of a renderpass
* Since vkCmdCopyBuffer can't run inside a renderpass we have to delay it until the renderpass ends. Warn if there is a subpass dependency that would allow writing the indirect args inside the RP (which we would then miss)
This commit is contained in:
@@ -72,6 +72,17 @@ enum class VkIndirectPatchType
|
||||
DrawIndirectByteCount,
|
||||
};
|
||||
|
||||
struct VkIndirectRecordData
|
||||
{
|
||||
VkBufferMemoryBarrier paramsBarrier, countBarrier;
|
||||
|
||||
struct
|
||||
{
|
||||
VkBuffer src, dst;
|
||||
VkBufferCopy copy;
|
||||
} paramsCopy, countCopy;
|
||||
};
|
||||
|
||||
struct VkIndirectPatchData
|
||||
{
|
||||
VkIndirectPatchType type = VkIndirectPatchType::NoPatch;
|
||||
@@ -509,6 +520,8 @@ private:
|
||||
vector<DebugMessage> debugMessages;
|
||||
std::list<VulkanDrawcallTreeNode *> drawStack;
|
||||
|
||||
std::vector<VkIndirectRecordData> indirectCopies;
|
||||
|
||||
uint32_t beginChunk = 0;
|
||||
uint32_t endChunk = 0;
|
||||
|
||||
@@ -732,6 +745,8 @@ private:
|
||||
VkBuffer dataBuffer, VkDeviceSize dataOffset, uint32_t count,
|
||||
uint32_t stride = 0, VkBuffer counterBuffer = VK_NULL_HANDLE,
|
||||
VkDeviceSize counterOffset = 0);
|
||||
void ExecuteIndirectReadback(VkCommandBuffer commandBuffer,
|
||||
const VkIndirectRecordData &indirectcopy);
|
||||
|
||||
WriteSerialiser &GetThreadSerialiser();
|
||||
template <typename SerialiserType>
|
||||
|
||||
@@ -1298,6 +1298,11 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(SerialiserType &ser, VkCommandB
|
||||
{
|
||||
ObjDisp(commandBuffer)->CmdEndRenderPass(Unwrap(commandBuffer));
|
||||
|
||||
// fetch any queued indirect readbacks here
|
||||
for(const VkIndirectRecordData &indirectcopy :
|
||||
m_BakedCmdBufferInfo[m_LastCmdBufferID].indirectCopies)
|
||||
ExecuteIndirectReadback(commandBuffer, indirectcopy);
|
||||
|
||||
std::vector<VkImageMemoryBarrier> imgBarriers = GetImplicitRenderPassBarriers(~0U);
|
||||
|
||||
ResourceId cmd = GetResID(commandBuffer);
|
||||
|
||||
@@ -84,13 +84,15 @@ VkIndirectPatchData WrappedVulkan::FetchIndirectData(VkIndirectPatchType type,
|
||||
if(type == VkIndirectPatchType::DrawIndirectByteCount)
|
||||
buf.srcAccessMask |= VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT;
|
||||
|
||||
ObjDisp(commandBuffer)
|
||||
->CmdPipelineBarrier(Unwrap(commandBuffer), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 1, &buf, 0, NULL);
|
||||
VkIndirectRecordData indirectcopy = {};
|
||||
|
||||
indirectcopy.paramsBarrier = buf;
|
||||
|
||||
VkBufferCopy copy = {dataOffset, 0, dataSize};
|
||||
ObjDisp(commandBuffer)
|
||||
->CmdCopyBuffer(Unwrap(commandBuffer), Unwrap(dataBuffer), Unwrap(paramsbuf), 1, ©);
|
||||
|
||||
indirectcopy.paramsCopy.src = dataBuffer;
|
||||
indirectcopy.paramsCopy.dst = paramsbuf;
|
||||
indirectcopy.paramsCopy.copy = copy;
|
||||
|
||||
if(counterBuffer != VK_NULL_HANDLE)
|
||||
{
|
||||
@@ -98,17 +100,23 @@ VkIndirectPatchData WrappedVulkan::FetchIndirectData(VkIndirectPatchType type,
|
||||
buf.offset = counterOffset;
|
||||
buf.size = 4;
|
||||
|
||||
ObjDisp(commandBuffer)
|
||||
->CmdPipelineBarrier(Unwrap(commandBuffer), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 1, &buf, 0, NULL);
|
||||
indirectcopy.countBarrier = buf;
|
||||
|
||||
copy.srcOffset = counterOffset;
|
||||
copy.dstOffset = bufInfo.size - 16;
|
||||
copy.size = 4;
|
||||
ObjDisp(commandBuffer)
|
||||
->CmdCopyBuffer(Unwrap(commandBuffer), Unwrap(counterBuffer), Unwrap(paramsbuf), 1, ©);
|
||||
|
||||
indirectcopy.countCopy.src = counterBuffer;
|
||||
indirectcopy.countCopy.dst = paramsbuf;
|
||||
indirectcopy.countCopy.copy = copy;
|
||||
}
|
||||
|
||||
// if it's a dispatch we can do it immediately, otherwise we delay to the end of the renderpass
|
||||
if(type == VkIndirectPatchType::DispatchIndirect)
|
||||
ExecuteIndirectReadback(commandBuffer, indirectcopy);
|
||||
else
|
||||
m_BakedCmdBufferInfo[m_LastCmdBufferID].indirectCopies.push_back(indirectcopy);
|
||||
|
||||
VkIndirectPatchData indirectPatch;
|
||||
indirectPatch.type = type;
|
||||
indirectPatch.alloc = alloc;
|
||||
@@ -119,6 +127,31 @@ VkIndirectPatchData WrappedVulkan::FetchIndirectData(VkIndirectPatchType type,
|
||||
return indirectPatch;
|
||||
}
|
||||
|
||||
void WrappedVulkan::ExecuteIndirectReadback(VkCommandBuffer commandBuffer,
|
||||
const VkIndirectRecordData &indirectcopy)
|
||||
{
|
||||
ObjDisp(commandBuffer)
|
||||
->CmdPipelineBarrier(Unwrap(commandBuffer), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 1,
|
||||
&indirectcopy.paramsBarrier, 0, NULL);
|
||||
|
||||
ObjDisp(commandBuffer)
|
||||
->CmdCopyBuffer(Unwrap(commandBuffer), Unwrap(indirectcopy.paramsCopy.src),
|
||||
Unwrap(indirectcopy.paramsCopy.dst), 1, &indirectcopy.paramsCopy.copy);
|
||||
|
||||
if(indirectcopy.countCopy.src != VK_NULL_HANDLE)
|
||||
{
|
||||
ObjDisp(commandBuffer)
|
||||
->CmdPipelineBarrier(Unwrap(commandBuffer), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 1,
|
||||
&indirectcopy.countBarrier, 0, NULL);
|
||||
|
||||
ObjDisp(commandBuffer)
|
||||
->CmdCopyBuffer(Unwrap(commandBuffer), Unwrap(indirectcopy.countCopy.src),
|
||||
Unwrap(indirectcopy.countCopy.dst), 1, &indirectcopy.countCopy.copy);
|
||||
}
|
||||
}
|
||||
|
||||
bool WrappedVulkan::IsDrawInRenderPass()
|
||||
{
|
||||
BakedCmdBufferInfo &cmd = m_BakedCmdBufferInfo[m_LastCmdBufferID];
|
||||
|
||||
@@ -767,6 +767,22 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(SerialiserType &ser, VkDevice d
|
||||
live = GetResourceManager()->WrapResource(Unwrap(device), rp);
|
||||
GetResourceManager()->AddLiveResource(RenderPass, rp);
|
||||
|
||||
bool badIndirectArgDep = false;
|
||||
|
||||
for(uint32_t i = 0; i < CreateInfo.dependencyCount; i++)
|
||||
if(CreateInfo.pDependencies[i].dstAccessMask & VK_ACCESS_INDIRECT_COMMAND_READ_BIT)
|
||||
badIndirectArgDep = true;
|
||||
|
||||
if(badIndirectArgDep)
|
||||
AddDebugMessage(MessageCategory::State_Creation, MessageSeverity::High,
|
||||
MessageSource::RuntimeWarning,
|
||||
StringFormat::Fmt("Creating renderpass %s contains a subpass dependency "
|
||||
"that would allow writing indirect command arguments.\n"
|
||||
"Indirect command contents are read at the end of the "
|
||||
"render pass, so write-after-read overwrites will "
|
||||
"cause incorrect display of indirect arguments.",
|
||||
ToStr(RenderPass)));
|
||||
|
||||
// make a version of the render pass that loads from its attachments,
|
||||
// so it can be used for replaying a single draw after a render pass
|
||||
// without doing a clear or a DONT_CARE load.
|
||||
|
||||
Reference in New Issue
Block a user