Fix handling of implicit barriers around renderpasses when replaying

* When we replay a draw and artificially call our loadRP renderpasses, we need
  to be careful to handle the barriers to and from the expected image layouts
  when the renderpass itself has layout transitions.
This commit is contained in:
baldurk
2018-12-06 13:59:10 +00:00
parent ae3fbe2085
commit d4e4a31dc1
3 changed files with 68 additions and 44 deletions
+7 -40
View File
@@ -2781,6 +2781,8 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay
// it back again afterwards.
std::vector<VkImageMemoryBarrier> loadRPImgBarriers;
m_RenderState.rpBarriers.clear();
// we'll need our own command buffer if we're replaying just a subsection
// of events within a single command buffer record - always if it's only
// one drawcall, or if start event ID is > 0 we assume the outside code
@@ -2802,31 +2804,6 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay
if(m_Partial[Primary].renderPassActive)
{
// first apply implicit transitions to the right subpass
loadRPImgBarriers = GetImplicitRenderPassBarriers();
// don't transition from undefined, or contents will be discarded, instead transition from
// the current state.
for(size_t i = 0; i < loadRPImgBarriers.size(); i++)
{
if(loadRPImgBarriers[i].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
// TODO find overlapping range and transition that instead
loadRPImgBarriers[i].oldLayout =
m_ImageLayouts[GetResourceManager()->GetNonDispWrapper(loadRPImgBarriers[i].image)->id]
.subresourceStates[0]
.newLayout;
}
}
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[GetResID(cmd)].imgbarriers,
m_ImageLayouts, (uint32_t)loadRPImgBarriers.size(),
&loadRPImgBarriers[0]);
ObjDisp(cmd)->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 0, NULL, 0, NULL,
(uint32_t)loadRPImgBarriers.size(), &loadRPImgBarriers[0]);
const DrawcallDescription *draw = GetDrawcall(endEventID);
bool rpUnneeded = false;
@@ -2878,23 +2855,13 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay
m_RenderState.EndTransformFeedback(cmd);
// check if the render pass is active - it could have become active
// even if it wasn't before (if the above event was a CmdBeginRenderPass)
// even if it wasn't before (if the above event was a CmdBeginRenderPass).
// If we began our own custom single-draw loadrp, and it was ended by a CmdEndRenderPass,
// we need to reverse the virtual transitions we did above, as it won't happen otherwise
if(m_Partial[Primary].renderPassActive)
m_RenderState.EndRenderPass(cmd);
// reverse the loadRPImgBarriers
for(size_t i = 0; i < loadRPImgBarriers.size(); i++)
{
std::swap(loadRPImgBarriers[i].oldLayout, loadRPImgBarriers[i].newLayout);
}
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[GetResID(cmd)].imgbarriers,
m_ImageLayouts, (uint32_t)loadRPImgBarriers.size(),
&loadRPImgBarriers[0]);
ObjDisp(cmd)->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 0, NULL, 0, NULL,
(uint32_t)loadRPImgBarriers.size(), &loadRPImgBarriers[0]);
else if(rpWasActive)
m_RenderState.DoRenderpassEndTransitions(cmd);
// we might have replayed a CmdBeginRenderPass or CmdEndRenderPass,
// but we want to keep the partial replay data state intact, so restore
+53 -2
View File
@@ -85,6 +85,8 @@ VulkanRenderState &VulkanRenderState::operator=(const VulkanRenderState &o)
void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd, PipelineBinding binding)
{
DoRenderPassBeginTransitions(cmd);
RDCASSERT(renderPass != ResourceId());
// clear values don't matter as we're using the load renderpass here, that
@@ -151,6 +153,12 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd, Pipeli
}
}
void VulkanRenderState::EndRenderPass(VkCommandBuffer cmd)
{
ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd));
DoRenderpassEndTransitions(cmd);
}
void VulkanRenderState::EndTransformFeedback(VkCommandBuffer cmd)
{
if(!xfbcounters.empty())
@@ -467,9 +475,52 @@ void VulkanRenderState::BindDescriptorSet(const DescSetLayout &descLayout, VkCom
}
}
void VulkanRenderState::EndRenderPass(VkCommandBuffer cmd)
void VulkanRenderState::DoRenderPassBeginTransitions(VkCommandBuffer cmd)
{
ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd));
// first apply implicit transitions to the right subpass
rpBarriers = m_pDriver->GetImplicitRenderPassBarriers();
if(!rpBarriers.empty())
{
// don't transition from undefined, or contents will be discarded, instead transition from
// the current state.
for(size_t i = 0; i < rpBarriers.size(); i++)
{
if(rpBarriers[i].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
ResourceId imgid = GetResourceManager()->GetNonDispWrapper(rpBarriers[i].image)->id;
// TODO find overlapping range and transition that instead
rpBarriers[i].oldLayout = m_pDriver->m_ImageLayouts[imgid].subresourceStates[0].newLayout;
}
}
GetResourceManager()->RecordBarriers(m_pDriver->m_BakedCmdBufferInfo[GetResID(cmd)].imgbarriers,
m_pDriver->m_ImageLayouts, (uint32_t)rpBarriers.size(),
rpBarriers.data());
ObjDisp(cmd)->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 0, NULL, 0, NULL,
(uint32_t)rpBarriers.size(), rpBarriers.data());
}
}
void VulkanRenderState::DoRenderpassEndTransitions(VkCommandBuffer cmd)
{
if(!rpBarriers.empty())
{
// reverse the rpBarriers that we applied at the start
for(size_t i = 0; i < rpBarriers.size(); i++)
std::swap(rpBarriers[i].oldLayout, rpBarriers[i].newLayout);
GetResourceManager()->RecordBarriers(m_pDriver->m_BakedCmdBufferInfo[GetResID(cmd)].imgbarriers,
m_pDriver->m_ImageLayouts, (uint32_t)rpBarriers.size(),
rpBarriers.data());
ObjDisp(cmd)->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 0, NULL, 0, NULL,
(uint32_t)rpBarriers.size(), rpBarriers.data());
}
}
VulkanResourceManager *VulkanRenderState::GetResourceManager()
+8 -2
View File
@@ -44,10 +44,14 @@ struct VulkanRenderState
VulkanRenderState(WrappedVulkan *driver, VulkanCreationInfo *createInfo);
VulkanRenderState &operator=(const VulkanRenderState &o);
void BeginRenderPassAndApplyState(VkCommandBuffer cmd, PipelineBinding binding);
void EndTransformFeedback(VkCommandBuffer cmd);
void EndRenderPass(VkCommandBuffer cmd);
void BindPipeline(VkCommandBuffer cmd, PipelineBinding binding, bool subpass0);
void DoRenderPassBeginTransitions(VkCommandBuffer cmd);
void DoRenderpassEndTransitions(VkCommandBuffer cmd);
void EndTransformFeedback(VkCommandBuffer cmd);
void BindPipeline(VkCommandBuffer cmd, PipelineBinding binding, bool subpass0);
void BindDescriptorSet(const DescSetLayout &descLayout, VkCommandBuffer cmd,
VkPipelineLayout layout, VkPipelineBindPoint bindPoint, uint32_t setIndex,
uint32_t *dynamicOffsets);
@@ -123,4 +127,6 @@ struct VulkanRenderState
VulkanResourceManager *GetResourceManager();
VulkanCreationInfo *m_CreationInfo;
WrappedVulkan *m_pDriver;
std::vector<VkImageMemoryBarrier> rpBarriers;
};