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:
baldurk
2024-02-23 15:00:28 +00:00
parent 36f4432351
commit ec17ee5999
8 changed files with 131 additions and 71 deletions
+13 -10
View File
@@ -1092,18 +1092,20 @@ void ReplayProxy::InitPostVSBuffers(const rdcarray<uint32_t> &events)
}
template <typename ParamSerialiser, typename ReturnSerialiser>
MeshFormat ReplayProxy::Proxied_GetPostVSBuffers(ParamSerialiser &paramser, ReturnSerialiser &retser,
uint32_t eventId, uint32_t instID, uint32_t viewID,
MeshDataStage stage)
rdcarray<MeshFormat> ReplayProxy::Proxied_GetBatchPostVSBuffers(ParamSerialiser &paramser,
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 &paramser, 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 &paramser, 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;
+8 -2
View File
@@ -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,
+10 -2
View File
@@ -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;
}
+16 -2
View File
@@ -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;
}
+10 -2
View File
@@ -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;
}
+16 -2
View File
@@ -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;
}
+14
View File
@@ -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 &params, bytebuf &data) = 0;
+44 -51
View File
@@ -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;