Optimize GPU particles simulation by scheduling larger sims first to overlap more work
This commit is contained in:
@@ -1333,7 +1333,19 @@ void UpdateGPU(RenderTask* task, GPUContext* context)
|
|||||||
ParticleEffect* Effect;
|
ParticleEffect* Effect;
|
||||||
ParticleEmitter* Emitter;
|
ParticleEmitter* Emitter;
|
||||||
int32 EmitterIndex;
|
int32 EmitterIndex;
|
||||||
ParticleEmitterInstance& Data;
|
ParticleEmitterInstance* Data;
|
||||||
|
|
||||||
|
bool operator<(const GPUSim& other) const
|
||||||
|
{
|
||||||
|
// Sort by particle count (larger effects start first)
|
||||||
|
if (Data->Buffer->GPU.ParticlesCountMax != other.Data->Buffer->GPU.ParticlesCountMax)
|
||||||
|
return Data->Buffer->GPU.ParticlesCountMax > other.Data->Buffer->GPU.ParticlesCountMax;
|
||||||
|
if (Emitter->Capacity != other.Emitter->Capacity)
|
||||||
|
return Emitter->Capacity > other.Emitter->Capacity;
|
||||||
|
|
||||||
|
// Merge emitters together (compute pipeline switches)
|
||||||
|
return (uintptr)Emitter < (uintptr)other.Emitter;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Array<GPUSim, RendererAllocation> sims;
|
Array<GPUSim, RendererAllocation> sims;
|
||||||
sims.EnsureCapacity(Math::AlignUp(GpuUpdateList.Count(), 64)); // Preallocate with some slack
|
sims.EnsureCapacity(Math::AlignUp(GpuUpdateList.Count(), 64)); // Preallocate with some slack
|
||||||
@@ -1364,11 +1376,14 @@ void UpdateGPU(RenderTask* task, GPUContext* context)
|
|||||||
emitter->GPU.PreSim(context, emitter, effect, emitterIndex, data);
|
emitter->GPU.PreSim(context, emitter, effect, emitterIndex, data);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sims.Add({ effect, emitter, emitterIndex, data });
|
sims.Add({ effect, emitter, emitterIndex, &data });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GpuUpdateList.Clear();
|
GpuUpdateList.Clear();
|
||||||
|
|
||||||
|
// Sort particles by emitter type to reduce compute pipeline switches
|
||||||
|
Sorting::QuickSort(sims);
|
||||||
|
|
||||||
// Pre-pass with buffers setup
|
// Pre-pass with buffers setup
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("PreSim");
|
PROFILE_CPU_NAMED("PreSim");
|
||||||
@@ -1376,14 +1391,14 @@ void UpdateGPU(RenderTask* task, GPUContext* context)
|
|||||||
GPUMemoryPass pass(context);
|
GPUMemoryPass pass(context);
|
||||||
for (GPUSim& sim : sims)
|
for (GPUSim& sim : sims)
|
||||||
{
|
{
|
||||||
if (sim.Data.Buffer->GPU.PendingClear)
|
if (sim.Data->Buffer->GPU.PendingClear)
|
||||||
pass.Transition(sim.Data.Buffer->GPU.Buffer, GPUResourceAccess::CopyWrite);
|
pass.Transition(sim.Data->Buffer->GPU.Buffer, GPUResourceAccess::CopyWrite);
|
||||||
pass.Transition(sim.Data.Buffer->GPU.BufferSecondary, GPUResourceAccess::CopyWrite);
|
pass.Transition(sim.Data->Buffer->GPU.BufferSecondary, GPUResourceAccess::CopyWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GPUSim& sim : sims)
|
for (GPUSim& sim : sims)
|
||||||
{
|
{
|
||||||
sim.Emitter->GPU.PreSim(context, sim.Emitter, sim.Effect, sim.EmitterIndex, sim.Data);
|
sim.Emitter->GPU.PreSim(context, sim.Emitter, sim.Effect, sim.EmitterIndex, *sim.Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1394,13 +1409,13 @@ void UpdateGPU(RenderTask* task, GPUContext* context)
|
|||||||
GPUComputePass pass(context);
|
GPUComputePass pass(context);
|
||||||
for (GPUSim& sim : sims)
|
for (GPUSim& sim : sims)
|
||||||
{
|
{
|
||||||
pass.Transition(sim.Data.Buffer->GPU.Buffer, GPUResourceAccess::ShaderReadCompute);
|
pass.Transition(sim.Data->Buffer->GPU.Buffer, GPUResourceAccess::ShaderReadCompute);
|
||||||
pass.Transition(sim.Data.Buffer->GPU.BufferSecondary, GPUResourceAccess::UnorderedAccess);
|
pass.Transition(sim.Data->Buffer->GPU.BufferSecondary, GPUResourceAccess::UnorderedAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GPUSim& sim : sims)
|
for (GPUSim& sim : sims)
|
||||||
{
|
{
|
||||||
sim.Emitter->GPU.Sim(context, sim.Emitter, sim.Effect, sim.EmitterIndex, sim.Data);
|
sim.Emitter->GPU.Sim(context, sim.Emitter, sim.Effect, sim.EmitterIndex, *sim.Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1411,16 +1426,16 @@ void UpdateGPU(RenderTask* task, GPUContext* context)
|
|||||||
GPUMemoryPass pass(context);
|
GPUMemoryPass pass(context);
|
||||||
for (GPUSim& sim : sims)
|
for (GPUSim& sim : sims)
|
||||||
{
|
{
|
||||||
if (sim.Data.CustomData.HasItems())
|
if (sim.Data->CustomData.HasItems())
|
||||||
{
|
{
|
||||||
pass.Transition(sim.Data.Buffer->GPU.BufferSecondary, GPUResourceAccess::CopyRead);
|
pass.Transition(sim.Data->Buffer->GPU.BufferSecondary, GPUResourceAccess::CopyRead);
|
||||||
pass.Transition(sim.Data.Buffer->GPU.Buffer, GPUResourceAccess::CopyWrite);
|
pass.Transition(sim.Data->Buffer->GPU.Buffer, GPUResourceAccess::CopyWrite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GPUSim& sim : sims)
|
for (GPUSim& sim : sims)
|
||||||
{
|
{
|
||||||
sim.Emitter->GPU.PostSim(context, sim.Emitter, sim.Effect, sim.EmitterIndex, sim.Data);
|
sim.Emitter->GPU.PostSim(context, sim.Emitter, sim.Effect, sim.EmitterIndex, *sim.Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user