Add partial handling for doing WithoutDraw/OnlyDraw log replays

* WithoutDraw still assumes it's replaying from the start. I'm not sure
  if it's worth handling WithoutDraw from an arbitrary point. Might move
  the only use of that (InitPostVSBuffers for a whole pass) into the
  driver for implementation, it would be easier.
This commit is contained in:
baldurk committed 2016-02-07 18:44:10 +01:00
1 parent fb65217a10
commit 07777e0e41
8 files changed
+256 -17

No files matched your search

+135 -10
View File
@@ -337,6 +337,7 @@ WrappedVulkan::WrappedVulkan(const char *logFilename)
m_PartialReplayData.renderPassActive = false;
m_PartialReplayData.resultPartialCmdBuffer = VK_NULL_HANDLE;
m_PartialReplayData.singleDrawCmdBuffer = VK_NULL_HANDLE;
m_PartialReplayData.partialParent = ResourceId();
m_PartialReplayData.baseEvent = 0;
@@ -835,12 +836,6 @@ void WrappedVulkan::ContextReplayLog(LogState readType, uint32_t startEventID, u
m_FirstEventID = startEventID;
m_LastEventID = endEventID;
m_PartialReplayData.renderPassActive = false;
RDCASSERT(m_PartialReplayData.resultPartialCmdBuffer == VK_NULL_HANDLE);
m_PartialReplayData.partialParent = ResourceId();
m_PartialReplayData.baseEvent = 0;
m_PartialReplayData.state = PartialReplayData::StateVector();
}
else if(m_State == READING)
{
@@ -873,6 +868,10 @@ void WrappedVulkan::ContextReplayLog(LogState readType, uint32_t startEventID, u
// but for now this will do.
if(context == CONTEXT_CAPTURE_FOOTER)
break;
// break out if we were only executing one event
if(m_State == EXECUTING && startEventID == endEventID)
break;
if(m_LastCmdBufferID != ResourceId())
{
@@ -1329,10 +1328,6 @@ void WrappedVulkan::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t
{
RDCASSERT(frameID < (uint32_t)m_FrameRecord.size());
// VKTODOHIGH figure out how replaying only a draw will work.
if(replayType == eReplay_OnlyDraw) return;
if(replayType == eReplay_WithoutDraw) { replayType = eReplay_Full; }
uint64_t offs = m_FrameRecord[frameID].frameInfo.fileOffset;
m_pSerialiser->SetOffset(offs);
@@ -1401,12 +1396,142 @@ void WrappedVulkan::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t
}
{
if(!partial)
{
m_PartialReplayData.renderPassActive = false;
RDCASSERT(m_PartialReplayData.resultPartialCmdBuffer == VK_NULL_HANDLE);
m_PartialReplayData.partialParent = ResourceId();
m_PartialReplayData.baseEvent = 0;
m_PartialReplayData.state = PartialReplayData::StateVector();
}
if(replayType == eReplay_Full)
{
ContextReplayLog(EXECUTING, startEventID, endEventID, partial);
}
else if(replayType == eReplay_WithoutDraw)
{
ContextReplayLog(EXECUTING, startEventID, RDCMAX(1U,endEventID)-1, partial);
}
else if(replayType == eReplay_OnlyDraw)
{
VkCmdBuffer cmd = m_PartialReplayData.singleDrawCmdBuffer = GetNextCmd();
VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT };
VkResult vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
RDCASSERT(vkr == VK_SUCCESS);
// if a render pass was active, begin it and set up the partial replay state
if(m_PartialReplayData.renderPassActive)
{
auto &s = m_PartialReplayData.state;
RDCASSERT(s.renderPass != ResourceId());
// clear values don't matter as we're using the load renderpass here, that
// has all load ops set to load (as we're doing a partial replay - can't
// just clear the targets that are partially written to).
VkClearValue empty[16] = {0};
RDCASSERT(ARRAY_COUNT(empty) >= m_CreationInfo.m_RenderPass[s.renderPass].attachCount);
VkRenderPassBeginInfo rpbegin = {
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL,
Unwrap(m_CreationInfo.m_RenderPass[s.renderPass].loadRP),
Unwrap(GetResourceManager()->GetCurrentHandle<VkFramebuffer>(s.framebuffer)),
s.renderArea,
m_CreationInfo.m_RenderPass[s.renderPass].attachCount, empty,
};
ObjDisp(cmd)->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_RENDER_PASS_CONTENTS_INLINE);
if(s.graphics.pipeline != ResourceId())
{
ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(GetResourceManager()->GetCurrentHandle<VkPipeline>(s.graphics.pipeline)));
ResourceId pipeLayoutId = m_CreationInfo.m_Pipeline[s.graphics.pipeline].layout;
VkPipelineLayout layout = GetResourceManager()->GetCurrentHandle<VkPipelineLayout>(pipeLayoutId);
const vector<ResourceId> &descSetLayouts = m_CreationInfo.m_PipelineLayout[pipeLayoutId].descSetLayouts;
// only iterate over the desc sets that this layout actually uses, not all that were bound
for(size_t i=0; i < descSetLayouts.size(); i++)
{
const DescSetLayout &descLayout = m_CreationInfo.m_DescSetLayout[ descSetLayouts[i] ];
if(s.graphics.descSets[i] != ResourceId())
{
// if there are dynamic buffers, pass along the offsets
ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(layout), (uint32_t)i,
1, UnwrapPtr(GetResourceManager()->GetCurrentHandle<VkDescriptorSet>(s.graphics.descSets[i])),
descLayout.dynamicCount, descLayout.dynamicCount == 0 ? NULL : &s.graphics.offsets[i][0]);
}
else
{
RDCERR("Descriptor set is not bound but pipeline layout expects one");
}
}
}
if(s.compute.pipeline != ResourceId())
{
ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, Unwrap(GetResourceManager()->GetCurrentHandle<VkPipeline>(s.compute.pipeline)));
ResourceId pipeLayoutId = m_CreationInfo.m_Pipeline[s.compute.pipeline].layout;
VkPipelineLayout layout = GetResourceManager()->GetCurrentHandle<VkPipelineLayout>(pipeLayoutId);
const vector<ResourceId> &descSetLayouts = m_CreationInfo.m_PipelineLayout[pipeLayoutId].descSetLayouts;
for(size_t i=0; i < descSetLayouts.size(); i++)
{
const DescSetLayout &descLayout = m_CreationInfo.m_DescSetLayout[ descSetLayouts[i] ];
if(s.compute.descSets[i] != ResourceId())
{
ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(layout), (uint32_t)i,
1, UnwrapPtr(GetResourceManager()->GetCurrentHandle<VkDescriptorSet>(s.compute.descSets[i])),
descLayout.dynamicCount, descLayout.dynamicCount == 0 ? NULL : &s.compute.offsets[i][0]);
}
}
}
if(!s.views.empty())
ObjDisp(cmd)->CmdSetViewport(Unwrap(cmd), (uint32_t)s.views.size(), &s.views[0]);
if(!s.scissors.empty())
ObjDisp(cmd)->CmdSetScissor(Unwrap(cmd), (uint32_t)s.scissors.size(), &s.scissors[0]);
ObjDisp(cmd)->CmdSetBlendConstants(Unwrap(cmd), s.blendConst);
ObjDisp(cmd)->CmdSetDepthBounds(Unwrap(cmd), s.mindepth, s.maxdepth);
ObjDisp(cmd)->CmdSetLineWidth(Unwrap(cmd), s.lineWidth);
ObjDisp(cmd)->CmdSetDepthBias(Unwrap(cmd), s.bias.depth, s.bias.biasclamp, s.bias.slope);
ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, s.back.ref);
ObjDisp(cmd)->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, s.back.compare);
ObjDisp(cmd)->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, s.back.write);
ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, s.front.ref);
ObjDisp(cmd)->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, s.front.compare);
ObjDisp(cmd)->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, s.front.write);
if(s.ibuffer.buf != ResourceId())
ObjDisp(cmd)->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(GetResourceManager()->GetCurrentHandle<VkBuffer>(s.ibuffer.buf)), s.ibuffer.offs, s.ibuffer.bytewidth == 4 ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
for(size_t i=0; i < s.vbuffers.size(); i++)
ObjDisp(cmd)->CmdBindVertexBuffers(Unwrap(cmd), (uint32_t)i, 1, UnwrapPtr(GetResourceManager()->GetCurrentHandle<VkBuffer>(s.vbuffers[i].buf)), &s.vbuffers[i].offs);
}
ContextReplayLog(EXECUTING, endEventID, endEventID, partial);
if(m_PartialReplayData.renderPassActive)
ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd));
ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd));
SubmitCmds();
m_PartialReplayData.singleDrawCmdBuffer = VK_NULL_HANDLE;
}
else
RDCFATAL("Unexpected replay type");
}
+24 -3
View File
@@ -239,6 +239,11 @@ private:
VkCmdBuffer resultPartialCmdBuffer;
VkDevice partialDevice; // device for above cmd buffer
// if we're replaying just a single draw we don't go through the
// whole original command buffers to set up the partial replay,
// so we just set this command buffer
VkCmdBuffer singleDrawCmdBuffer;
// this records where in the frame a command buffer was submitted,
// so that we know if our replay range ends in one of these ranges
// we need to construct a partial command buffer for future
@@ -286,6 +291,8 @@ private:
compute.pipeline = graphics.pipeline = renderPass = framebuffer = ResourceId();
compute.descSets.clear();
graphics.descSets.clear();
compute.offsets.clear();
graphics.offsets.clear();
lineWidth = 1.0f;
RDCEraseEl(bias);
@@ -317,6 +324,7 @@ private:
{
ResourceId pipeline;
vector<ResourceId> descSets;
vector< vector<uint32_t> > offsets;
} compute, graphics;
struct IdxBuffer
@@ -335,9 +343,22 @@ private:
} state;
} m_PartialReplayData;
bool IsPartialCmd(ResourceId cmdid) { return cmdid == m_PartialReplayData.partialParent; }
bool InPartialRange() { return m_BakedCmdBufferInfo[m_PartialReplayData.partialParent].curEventID <= m_LastEventID - m_PartialReplayData.baseEvent; }
VkCmdBuffer PartialCmdBuf() { return m_PartialReplayData.resultPartialCmdBuffer; }
bool IsPartialCmd(ResourceId cmdid)
{
return m_PartialReplayData.singleDrawCmdBuffer != VK_NULL_HANDLE ||
cmdid == m_PartialReplayData.partialParent;
}
bool InPartialRange()
{
return m_PartialReplayData.singleDrawCmdBuffer != VK_NULL_HANDLE ||
m_BakedCmdBufferInfo[m_PartialReplayData.partialParent].curEventID <= m_LastEventID - m_PartialReplayData.baseEvent;
}
VkCmdBuffer PartialCmdBuf()
{
if(m_PartialReplayData.singleDrawCmdBuffer != VK_NULL_HANDLE)
return m_PartialReplayData.singleDrawCmdBuffer;
return m_PartialReplayData.resultPartialCmdBuffer;
}
// this info is stored in the record on capture, but we
+19
View File
@@ -26,6 +26,8 @@
void DescSetLayout::Init(const VkDescriptorSetLayoutCreateInfo* pCreateInfo)
{
dynamicCount = 0;
bindings.resize(pCreateInfo->count);
for(uint32_t i=0; i < pCreateInfo->count; i++)
{
@@ -33,6 +35,10 @@ void DescSetLayout::Init(const VkDescriptorSetLayoutCreateInfo* pCreateInfo)
bindings[i].descriptorType = pCreateInfo->pBinding[i].descriptorType;
bindings[i].stageFlags = pCreateInfo->pBinding[i].stageFlags;
if(bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
dynamicCount++;
if(pCreateInfo->pBinding[i].pImmutableSamplers)
{
bindings[i].immutableSampler = new ResourceId[bindings[i].arraySize];
@@ -57,6 +63,8 @@ void VulkanCreationInfo::Pipeline::Init(const VkGraphicsPipelineCreateInfo* pCre
{
flags = pCreateInfo->flags;
layout = VKMGR()->GetNonDispWrapper(pCreateInfo->layout)->id;
// need to figure out which states are valid to be NULL
// VkPipelineShaderStageCreateInfo
@@ -171,6 +179,8 @@ void VulkanCreationInfo::Pipeline::Init(const VkComputePipelineCreateInfo* pCrea
{
flags = pCreateInfo->flags;
layout = VKMGR()->GetNonDispWrapper(pCreateInfo->layout)->id;
// need to figure out which states are valid to be NULL
// VkPipelineShaderStageCreateInfo
@@ -212,8 +222,17 @@ void VulkanCreationInfo::Pipeline::Init(const VkComputePipelineCreateInfo* pCrea
logicOp = VK_LOGIC_OP_NOOP;
}
void VulkanCreationInfo::PipelineLayout::Init(const VkPipelineLayoutCreateInfo* pCreateInfo)
{
descSetLayouts.resize(pCreateInfo->descriptorSetCount);
for(uint32_t i=0; i < pCreateInfo->descriptorSetCount; i++)
descSetLayouts[i] = VKMGR()->GetNonDispWrapper(pCreateInfo->pSetLayouts[i])->id;
}
void VulkanCreationInfo::RenderPass::Init(const VkRenderPassCreateInfo* pCreateInfo)
{
attachCount = pCreateInfo->attachmentCount;
// VKTODOMED figure out how subpasses work
RDCASSERT(pCreateInfo->subpassCount > 0);
const VkSubpassDescription &subp = pCreateInfo->pSubpasses[0];
+16
View File
@@ -46,6 +46,8 @@ struct DescSetLayout
ResourceId *immutableSampler;
};
vector<Binding> bindings;
uint32_t dynamicCount;
};
struct VulkanCreationInfo
{
@@ -53,6 +55,8 @@ struct VulkanCreationInfo
{
void Init(const VkGraphicsPipelineCreateInfo* pCreateInfo);
void Init(const VkComputePipelineCreateInfo* pCreateInfo);
ResourceId layout;
// VkGraphicsPipelineCreateInfo
VkPipelineCreateFlags flags;
@@ -146,6 +150,14 @@ struct VulkanCreationInfo
};
map<ResourceId, Pipeline> m_Pipeline;
struct PipelineLayout
{
void Init(const VkPipelineLayoutCreateInfo* pCreateInfo);
vector<ResourceId> descSetLayouts;
};
map<ResourceId, PipelineLayout> m_PipelineLayout;
struct RenderPass
{
void Init(const VkRenderPassCreateInfo* pCreateInfo);
@@ -153,6 +165,10 @@ struct VulkanCreationInfo
vector<uint32_t> inputAttachments;
vector<uint32_t> colorAttachments;
int32_t depthstencilAttachment;
uint32_t attachCount;
VkRenderPass loadRP;
};
map<ResourceId, RenderPass> m_RenderPass;
@@ -191,7 +191,7 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(
for(auto it=baseEvents.begin(); it != baseEvents.end(); ++it)
{
if(*it < m_LastEventID && m_LastEventID < (*it + length))
if(*it <= m_LastEventID && m_LastEventID < (*it + length))
{
RDCDEBUG("vkBegin - partial detected %u < %u < %u, %llu -> %llu", *it, m_LastEventID, *it + length, cmdId, bakeId);
@@ -929,13 +929,33 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets(
(bind == VK_PIPELINE_BIND_POINT_GRAPHICS)
? m_PartialReplayData.state.graphics.descSets
: m_PartialReplayData.state.compute.descSets;
vector< vector<uint32_t> > &offsets =
(bind == VK_PIPELINE_BIND_POINT_GRAPHICS)
? m_PartialReplayData.state.graphics.offsets
: m_PartialReplayData.state.compute.offsets;
// expand as necessary
if(descsets.size() < first + numSets)
{
descsets.resize(first + numSets);
offsets.resize(first + numSets);
}
const vector<ResourceId> &descSetLayouts = m_CreationInfo.m_PipelineLayout[GetResID(layout)].descSetLayouts;
uint32_t *offsIter = offs;
uint32_t dynConsumed = 0;
// consume the offsets linearly along the descriptor set layouts
for(uint32_t i=0; i < numSets; i++)
{
descsets[first+i] = descriptorIDs[i];
uint32_t dynCount = m_CreationInfo.m_DescSetLayout[ descSetLayouts[first+i] ].dynamicCount;
offsets[first+i].assign(offsIter, offsIter+dynCount);
dynConsumed += dynCount;
RDCASSERT(dynConsumed <= offsCount);
}
// if there are dynamic offsets, bake them into the current bindings by alias'ing
// the image layout member (which is never used for buffer views).
@@ -385,6 +385,18 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(
device = GetResourceManager()->GetLiveHandle<VkDevice>(devId);
VkRenderPass rp = VK_NULL_HANDLE;
VulkanCreationInfo::RenderPass rpinfo;
rpinfo.Init(&info);
// we want to store off the data so we can display it after the pass.
// override any user-specified DONT_CARE.
VkAttachmentDescription *att = (VkAttachmentDescription *)info.pAttachments;
for(uint32_t i=0; i < info.attachmentCount; i++)
{
att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
}
VkResult ret = ObjDisp(device)->CreateRenderPass(Unwrap(device), &info, &rp);
if(ret != VK_SUCCESS)
@@ -395,8 +407,22 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(
{
ResourceId live = GetResourceManager()->WrapResource(Unwrap(device), rp);
GetResourceManager()->AddLiveResource(id, rp);
// 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.
for(uint32_t i=0; i < info.attachmentCount; i++)
{
att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
}
ret = ObjDisp(device)->CreateRenderPass(Unwrap(device), &info, &rpinfo.loadRP);
RDCASSERT(ret == VK_SUCCESS);
GetResourceManager()->WrapResource(Unwrap(device), rpinfo.loadRP);
m_CreationInfo.m_RenderPass[live].Init(&info);
m_CreationInfo.m_RenderPass[live] = rpinfo;
}
}
@@ -234,7 +234,11 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(
m_RootEventID--;
if(m_LastEventID < m_RootEventID)
if(m_LastEventID == startEID)
{
RDCDEBUG("Queue Submit no replay %u == %u", m_LastEventID, startEID);
}
else if(m_LastEventID > startEID && m_LastEventID < m_RootEventID)
{
RDCDEBUG("Queue Submit partial replay %u < %u", m_LastEventID, m_RootEventID);
@@ -272,7 +276,7 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(
ObjDisp(queue)->QueueSubmit(Unwrap(queue), (uint32_t)trimmedCmds.size(), &trimmedCmds[0], Unwrap(fence));
for(uint32_t i=0; i < numCmds; i++)
for(uint32_t i=0; i < trimmedCmdIds.size(); i++)
{
ResourceId cmd = trimmedCmdIds[i];
GetResourceManager()->ApplyTransitions(m_BakedCmdBufferInfo[cmd].imgtransitions, m_ImageLayouts);
@@ -53,6 +53,8 @@ bool WrappedVulkan::Serialise_vkCreatePipelineLayout(
{
ResourceId live = GetResourceManager()->WrapResource(Unwrap(device), layout);
GetResourceManager()->AddLiveResource(id, layout);
m_CreationInfo.m_PipelineLayout[live].Init(&info);
}
}
@@ -101,6 +103,8 @@ VkResult WrappedVulkan::vkCreatePipelineLayout(
else
{
GetResourceManager()->AddLiveResource(id, *pPipelineLayout);
m_CreationInfo.m_PipelineLayout[id].Init(pCreateInfo);
}
}
@@ -428,6 +432,8 @@ VkResult WrappedVulkan::vkCreateGraphicsPipelines(
else
{
GetResourceManager()->AddLiveResource(id, pPipelines[i]);
m_CreationInfo.m_Pipeline[id].Init(&pCreateInfos[i]);
}
}
}
@@ -526,6 +532,8 @@ VkResult WrappedVulkan::vkCreateComputePipelines(
else
{
GetResourceManager()->AddLiveResource(id, pPipelines[i]);
m_CreationInfo.m_Pipeline[id].Init(&pCreateInfos[i]);
}
}
}