mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-21 23:11:38 +00:00
Batch calls to GetPostVSBuffers to work around Android being awful
* On Android the end-to-end latency of a single call is large enough that doing a call per-instance in a draw with a high number of instances is a real problem
This commit is contained in:
@@ -1092,18 +1092,20 @@ void ReplayProxy::InitPostVSBuffers(const rdcarray<uint32_t> &events)
|
||||
}
|
||||
|
||||
template <typename ParamSerialiser, typename ReturnSerialiser>
|
||||
MeshFormat ReplayProxy::Proxied_GetPostVSBuffers(ParamSerialiser ¶mser, ReturnSerialiser &retser,
|
||||
uint32_t eventId, uint32_t instID, uint32_t viewID,
|
||||
MeshDataStage stage)
|
||||
rdcarray<MeshFormat> ReplayProxy::Proxied_GetBatchPostVSBuffers(ParamSerialiser ¶mser,
|
||||
ReturnSerialiser &retser,
|
||||
uint32_t eventId,
|
||||
const rdcarray<uint32_t> &instIDs,
|
||||
uint32_t viewID, MeshDataStage stage)
|
||||
{
|
||||
const ReplayProxyPacket expectedPacket = eReplayProxy_GetPostVS;
|
||||
ReplayProxyPacket packet = eReplayProxy_GetPostVS;
|
||||
MeshFormat ret = {};
|
||||
rdcarray<MeshFormat> ret = {};
|
||||
|
||||
{
|
||||
BEGIN_PARAMS();
|
||||
SERIALISE_ELEMENT(eventId);
|
||||
SERIALISE_ELEMENT(instID);
|
||||
SERIALISE_ELEMENT(instIDs);
|
||||
SERIALISE_ELEMENT(viewID);
|
||||
SERIALISE_ELEMENT(stage);
|
||||
END_PARAMS();
|
||||
@@ -1112,7 +1114,7 @@ MeshFormat ReplayProxy::Proxied_GetPostVSBuffers(ParamSerialiser ¶mser, Retu
|
||||
{
|
||||
REMOTE_EXECUTION();
|
||||
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
|
||||
ret = m_Remote->GetPostVSBuffers(eventId, instID, viewID, stage);
|
||||
ret = m_Remote->GetBatchPostVSBuffers(eventId, instIDs, viewID, stage);
|
||||
}
|
||||
|
||||
SERIALISE_RETURN(ret);
|
||||
@@ -1120,10 +1122,11 @@ MeshFormat ReplayProxy::Proxied_GetPostVSBuffers(ParamSerialiser ¶mser, Retu
|
||||
return ret;
|
||||
}
|
||||
|
||||
MeshFormat ReplayProxy::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_t viewID,
|
||||
MeshDataStage stage)
|
||||
rdcarray<MeshFormat> ReplayProxy::GetBatchPostVSBuffers(uint32_t eventId,
|
||||
const rdcarray<uint32_t> &instIDs,
|
||||
uint32_t viewID, MeshDataStage stage)
|
||||
{
|
||||
PROXY_FUNCTION(GetPostVSBuffers, eventId, instID, viewID, stage);
|
||||
PROXY_FUNCTION(GetBatchPostVSBuffers, eventId, instIDs, viewID, stage);
|
||||
}
|
||||
|
||||
template <typename ParamSerialiser, typename ReturnSerialiser>
|
||||
@@ -2932,7 +2935,7 @@ bool ReplayProxy::Tick(int type)
|
||||
InitPostVSBuffers(dummy);
|
||||
break;
|
||||
}
|
||||
case eReplayProxy_GetPostVS: GetPostVSBuffers(0, 0, 0, MeshDataStage::VSIn); break;
|
||||
case eReplayProxy_GetPostVS: GetBatchPostVSBuffers(0, {}, 0, MeshDataStage::VSIn); break;
|
||||
case eReplayProxy_BuildTargetShader:
|
||||
{
|
||||
rdcstr entry;
|
||||
|
||||
@@ -504,8 +504,14 @@ public:
|
||||
|
||||
IMPLEMENT_FUNCTION_PROXIED(void, InitPostVSBuffers, uint32_t eventId);
|
||||
IMPLEMENT_FUNCTION_PROXIED(void, InitPostVSBuffers, const rdcarray<uint32_t> &passEvents);
|
||||
IMPLEMENT_FUNCTION_PROXIED(MeshFormat, GetPostVSBuffers, uint32_t eventId, uint32_t instID,
|
||||
uint32_t viewID, MeshDataStage stage);
|
||||
IMPLEMENT_FUNCTION_PROXIED(rdcarray<MeshFormat>, GetBatchPostVSBuffers, uint32_t eventId,
|
||||
const rdcarray<uint32_t> &instIDs, uint32_t viewID, MeshDataStage stage);
|
||||
|
||||
// if this gets called individually, just forward to the batch implementation for simplicity
|
||||
MeshFormat GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_t viewID, MeshDataStage stage)
|
||||
{
|
||||
return GetBatchPostVSBuffers(eventId, {instID}, viewID, stage)[0];
|
||||
}
|
||||
|
||||
IMPLEMENT_FUNCTION_PROXIED(ResourceId, RenderOverlay, ResourceId texid, FloatVector clearCol,
|
||||
DebugOverlay overlay, uint32_t eventId,
|
||||
|
||||
@@ -82,8 +82,16 @@ struct D3D11PostVSData
|
||||
return vsout;
|
||||
else if(type == MeshDataStage::GSOut)
|
||||
return gsout;
|
||||
else
|
||||
RDCERR("Unexpected mesh data stage!");
|
||||
|
||||
if(type == MeshDataStage::Count)
|
||||
{
|
||||
if(gsout.buf)
|
||||
return gsout;
|
||||
|
||||
return vsout;
|
||||
}
|
||||
|
||||
RDCERR("Unexpected mesh data stage!");
|
||||
|
||||
return vsin;
|
||||
}
|
||||
|
||||
@@ -366,8 +366,22 @@ private:
|
||||
return ampout;
|
||||
else if(type == MeshDataStage::MeshOut)
|
||||
return meshout;
|
||||
else
|
||||
RDCERR("Unexpected mesh data stage!");
|
||||
|
||||
if(type == MeshDataStage::Count)
|
||||
{
|
||||
if(gsout.buf)
|
||||
return gsout;
|
||||
|
||||
if(vsout.buf)
|
||||
return vsout;
|
||||
|
||||
if(meshout.buf)
|
||||
return meshout;
|
||||
|
||||
return vsout;
|
||||
}
|
||||
|
||||
RDCERR("Unexpected mesh data stage!");
|
||||
|
||||
return vsout;
|
||||
}
|
||||
|
||||
@@ -79,8 +79,16 @@ struct GLPostVSData
|
||||
return vsout;
|
||||
else if(type == MeshDataStage::GSOut)
|
||||
return gsout;
|
||||
else
|
||||
RDCERR("Unexpected mesh data stage!");
|
||||
|
||||
if(type == MeshDataStage::Count)
|
||||
{
|
||||
if(gsout.buf)
|
||||
return gsout;
|
||||
|
||||
return vsout;
|
||||
}
|
||||
|
||||
RDCERR("Unexpected mesh data stage!");
|
||||
|
||||
return vsin;
|
||||
}
|
||||
|
||||
@@ -231,8 +231,22 @@ struct VulkanPostVSData
|
||||
return taskout;
|
||||
else if(type == MeshDataStage::MeshOut)
|
||||
return meshout;
|
||||
else
|
||||
RDCERR("Unexpected mesh data stage!");
|
||||
|
||||
if(type == MeshDataStage::Count)
|
||||
{
|
||||
if(gsout.buf != VK_NULL_HANDLE)
|
||||
return gsout;
|
||||
|
||||
if(vsout.buf != VK_NULL_HANDLE)
|
||||
return vsout;
|
||||
|
||||
if(meshout.buf != VK_NULL_HANDLE)
|
||||
return meshout;
|
||||
|
||||
return vsout;
|
||||
}
|
||||
|
||||
RDCERR("Unexpected mesh data stage!");
|
||||
|
||||
return vsout;
|
||||
}
|
||||
|
||||
@@ -178,6 +178,20 @@ public:
|
||||
virtual MeshFormat GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_t viewID,
|
||||
MeshDataStage stage) = 0;
|
||||
|
||||
// this is a helper/batch query for the above, that's only necessary because Android is a shit
|
||||
// platform and its proxying has significant per-call overhead. This is overridden in the proxy,
|
||||
// but otherwise will call to this default implementation
|
||||
virtual rdcarray<MeshFormat> GetBatchPostVSBuffers(uint32_t eventId,
|
||||
const rdcarray<uint32_t> &instIDs,
|
||||
uint32_t viewID, MeshDataStage stage)
|
||||
{
|
||||
rdcarray<MeshFormat> ret;
|
||||
ret.reserve(instIDs.size());
|
||||
for(uint32_t instID : instIDs)
|
||||
ret.push_back(GetPostVSBuffers(eventId, instID, viewID, stage));
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData) = 0;
|
||||
virtual void GetTextureData(ResourceId tex, const Subresource &sub,
|
||||
const GetTextureDataParams ¶ms, bytebuf &data) = 0;
|
||||
|
||||
@@ -595,23 +595,26 @@ rdcpair<uint32_t, uint32_t> ReplayOutput::PickVertex(uint32_t x, uint32_t y)
|
||||
maxInst = RDCMAX(1U, action->numInstances);
|
||||
}
|
||||
|
||||
// used for post-VS output, calculate the offset of the element we're using as position,
|
||||
// relative to 0
|
||||
MeshFormat fmt =
|
||||
m_pDevice->GetPostVSBuffers(action->eventId, m_RenderData.meshDisplay.curInstance,
|
||||
m_RenderData.meshDisplay.curView, m_RenderData.meshDisplay.type);
|
||||
rdcarray<uint32_t> instIDs;
|
||||
instIDs.reserve(maxInst - firstInst + 1);
|
||||
for(uint32_t inst = firstInst; inst < maxInst; inst++)
|
||||
instIDs.push_back(inst);
|
||||
instIDs.push_back(m_RenderData.meshDisplay.curInstance);
|
||||
|
||||
rdcarray<MeshFormat> fmts = m_pDevice->GetBatchPostVSBuffers(
|
||||
action->eventId, instIDs, m_RenderData.meshDisplay.curView, m_RenderData.meshDisplay.type);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
uint64_t elemOffset = cfg.position.vertexByteOffset - fmt.vertexByteOffset;
|
||||
// used for post-VS output, calculate the offset of the element we're using as position,
|
||||
// relative to 0
|
||||
// the last element in fmts corresponds to curInstance
|
||||
const uint64_t elemOffset = cfg.position.vertexByteOffset - fmts.back().vertexByteOffset;
|
||||
fmts.pop_back();
|
||||
|
||||
for(uint32_t inst = firstInst; inst < maxInst; inst++)
|
||||
uint32_t inst = firstInst;
|
||||
for(MeshFormat &fmt : fmts)
|
||||
{
|
||||
// find the start of this buffer, and apply the element offset, then pick in that instance
|
||||
fmt = m_pDevice->GetPostVSBuffers(action->eventId, inst, m_RenderData.meshDisplay.curView,
|
||||
m_RenderData.meshDisplay.type);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
if(fmt.vertexResourceId != ResourceId())
|
||||
cfg.position.vertexByteOffset = fmt.vertexByteOffset + elemOffset;
|
||||
|
||||
@@ -619,9 +622,9 @@ rdcpair<uint32_t, uint32_t> ReplayOutput::PickVertex(uint32_t x, uint32_t y)
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
if(vert != ~0U)
|
||||
{
|
||||
return make_rdcpair(vert, inst);
|
||||
}
|
||||
|
||||
inst++;
|
||||
}
|
||||
|
||||
return errorReturn;
|
||||
@@ -1072,34 +1075,22 @@ void ReplayOutput::DisplayMesh()
|
||||
|
||||
if(d)
|
||||
{
|
||||
rdcarray<uint32_t> instIDs;
|
||||
instIDs.reserve(RDCMAX(1U, d->numInstances));
|
||||
for(uint32_t inst = 0; inst < RDCMAX(1U, d->numInstances); inst++)
|
||||
{
|
||||
// get the 'most final' stage
|
||||
MeshFormat fmt = m_pDevice->GetPostVSBuffers(
|
||||
passEvents[i], inst, m_RenderData.meshDisplay.curView, MeshDataStage::GSOut);
|
||||
m_pController->FatalErrorCheck();
|
||||
if(fmt.vertexResourceId == ResourceId())
|
||||
{
|
||||
fmt = m_pDevice->GetPostVSBuffers(passEvents[i], inst, m_RenderData.meshDisplay.curView,
|
||||
MeshDataStage::VSOut);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
if(fmt.vertexResourceId == ResourceId())
|
||||
{
|
||||
fmt = m_pDevice->GetPostVSBuffers(passEvents[i], inst, m_RenderData.meshDisplay.curView,
|
||||
MeshDataStage::MeshOut);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
instIDs.push_back(inst);
|
||||
|
||||
fmt.meshColor = passDraws;
|
||||
|
||||
// if unproject is marked, this output had a 'real' system position output
|
||||
if(fmt.unproject)
|
||||
secondaryDraws.push_back(fmt);
|
||||
}
|
||||
// pass MeshDataStage::Count to get the 'most final' stage
|
||||
secondaryDraws.append(m_pDevice->GetBatchPostVSBuffers(
|
||||
passEvents[i], instIDs, m_RenderData.meshDisplay.curView, MeshDataStage::Count));
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
}
|
||||
|
||||
// all secondary draws so far are previous pass elements
|
||||
for(MeshFormat &fmt : secondaryDraws)
|
||||
fmt.meshColor = passDraws;
|
||||
|
||||
// action previous instances in the current action
|
||||
if(action->flags & ActionFlags::Instanced)
|
||||
{
|
||||
@@ -1109,26 +1100,28 @@ void ReplayOutput::DisplayMesh()
|
||||
if(m_RenderData.meshDisplay.showAllInstances)
|
||||
maxInst = RDCMAX(1U, action->numInstances);
|
||||
|
||||
for(uint32_t inst = 0; inst < maxInst; inst++)
|
||||
if(maxInst > 0)
|
||||
{
|
||||
// get the 'most final' stage
|
||||
MeshFormat fmt = m_pDevice->GetPostVSBuffers(
|
||||
action->eventId, inst, m_RenderData.meshDisplay.curView, MeshDataStage::GSOut);
|
||||
rdcarray<uint32_t> instIDs;
|
||||
instIDs.reserve(maxInst);
|
||||
for(uint32_t inst = 0; inst < maxInst; inst++)
|
||||
instIDs.push_back(inst);
|
||||
|
||||
size_t prevInstancesStart = secondaryDraws.size();
|
||||
|
||||
// pass MeshDataStage::Count to get the 'most final' stage
|
||||
secondaryDraws.append(m_pDevice->GetBatchPostVSBuffers(
|
||||
action->eventId, instIDs, m_RenderData.meshDisplay.curView, MeshDataStage::Count));
|
||||
m_pController->FatalErrorCheck();
|
||||
if(fmt.vertexResourceId == ResourceId())
|
||||
{
|
||||
fmt = m_pDevice->GetPostVSBuffers(action->eventId, inst, m_RenderData.meshDisplay.curView,
|
||||
MeshDataStage::VSOut);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
fmt.meshColor = otherInstances;
|
||||
|
||||
// if unproject is marked, this output had a 'real' system position output
|
||||
if(fmt.unproject)
|
||||
secondaryDraws.push_back(fmt);
|
||||
// set the colour for other instances
|
||||
for(size_t i = prevInstancesStart; i < secondaryDraws.size(); i++)
|
||||
secondaryDraws[i].meshColor = otherInstances;
|
||||
}
|
||||
}
|
||||
|
||||
// only if unproject is marked did this output have a 'real' system position output
|
||||
secondaryDraws.removeIf([](const MeshFormat &fmt) { return fmt.unproject == false; });
|
||||
}
|
||||
|
||||
mesh.position.meshColor = drawItself;
|
||||
|
||||
Reference in New Issue
Block a user