Add async particles drawing (GPU emitters are sync)
This commit is contained in:
@@ -20,6 +20,7 @@ ParticleEffect::ParticleEffect(const SpawnParams& params)
|
||||
{
|
||||
_box = BoundingBox(_transform.Translation);
|
||||
BoundingSphere::FromBox(_box, _sphere);
|
||||
_drawCategory = SceneRendering::SceneDrawAsync;
|
||||
}
|
||||
|
||||
void ParticleEffectParameter::Init(ParticleEffect* effect, int32 emitterIndex, int32 paramIndex)
|
||||
|
||||
@@ -649,8 +649,22 @@ void CleanupGPUParticlesSorting()
|
||||
GPUParticlesSorting = nullptr;
|
||||
}
|
||||
|
||||
void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices, int8 sortOrder)
|
||||
void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, const RenderModulesIndices& renderModulesIndices, int8 sortOrder)
|
||||
{
|
||||
if (!IsInMainThread())
|
||||
{
|
||||
// Clone draw call data the hard way
|
||||
byte drawCallCopy[sizeof(DrawCall)];
|
||||
Platform::MemoryCopy(&drawCallCopy, &drawCall, sizeof(DrawCall));
|
||||
|
||||
// When rendering in async, delay GPU particles drawing to be in sync by moving drawing into delayed callback post scene drawing to use GPUContext safely
|
||||
// Move drawing into delayed callback post scene drawing to use GPUContext safely
|
||||
renderContext.List->AddDelayedDraw([buffer, drawCallCopy, drawModes, staticFlags, renderModulesIndices, sortOrder](RenderContext& renderContext)
|
||||
{
|
||||
DrawEmitterGPU(renderContext, buffer, *(DrawCall*)drawCallCopy, drawModes, staticFlags, renderModulesIndices, sortOrder);
|
||||
});
|
||||
return;
|
||||
}
|
||||
const auto context = GPUDevice::Instance->GetMainContext();
|
||||
auto emitter = buffer->Emitter;
|
||||
|
||||
@@ -1092,7 +1106,7 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe
|
||||
break;
|
||||
#if COMPILE_WITH_GPU_PARTICLES
|
||||
case ParticlesSimulationMode::GPU:
|
||||
DrawEmitterGPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices, sortOrder);
|
||||
DrawEmitterGPU(renderContext, buffer, drawCall, drawModes, staticFlags, renderModulesIndices, sortOrder);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -255,6 +255,20 @@ void RenderList::AddSettingsBlend(IPostFxSettingsProvider* provider, float weigh
|
||||
Blendable.Add(blend);
|
||||
}
|
||||
|
||||
void RenderList::AddDelayedDraw(DelayedDraw&& func)
|
||||
{
|
||||
MemPoolLocker.Lock(); // TODO: convert _delayedDraws into RenderListBuffer with usage of arena Memory for fast alloc
|
||||
_delayedDraws.Add(MoveTemp(func));
|
||||
MemPoolLocker.Unlock();
|
||||
}
|
||||
|
||||
void RenderList::DrainDelayedDraws(RenderContext& renderContext)
|
||||
{
|
||||
for (DelayedDraw& e : _delayedDraws)
|
||||
e(renderContext);
|
||||
_delayedDraws.SetCapacity(0);
|
||||
}
|
||||
|
||||
void RenderList::BlendSettings()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
@@ -459,6 +473,7 @@ RenderList::RenderList(const SpawnParams& params)
|
||||
, ObjectBuffer(0, PixelFormat::R32G32B32A32_Float, false, TEXT("Object Buffer"))
|
||||
, TempObjectBuffer(0, PixelFormat::R32G32B32A32_Float, false, TEXT("Object Buffer"))
|
||||
, _instanceBuffer(0, sizeof(ShaderObjectDrawInstanceData), TEXT("Instance Buffer"), GPUVertexLayout::Get({ { VertexElement::Types::Attribute0, 3, 0, 1, PixelFormat::R32_UInt } }))
|
||||
, _delayedDraws(&Memory)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -490,6 +505,7 @@ void RenderList::Clear()
|
||||
PostFx.Clear();
|
||||
Settings = PostProcessSettings();
|
||||
Blendable.Clear();
|
||||
_delayedDraws.Clear();
|
||||
_instanceBuffer.Clear();
|
||||
ObjectBuffer.Clear();
|
||||
TempObjectBuffer.Clear();
|
||||
|
||||
@@ -435,8 +435,24 @@ public:
|
||||
/// </summary>
|
||||
DynamicTypedBuffer TempObjectBuffer;
|
||||
|
||||
typedef Function<void(RenderContext& renderContext)> DelayedDraw;
|
||||
void AddDelayedDraw(DelayedDraw&& func);
|
||||
void DrainDelayedDraws(RenderContext& renderContext);
|
||||
|
||||
/// <summary>
|
||||
/// Adds custom callback (eg. lambda) to invoke after scene draw calls are collected on a main thread (some async draw tasks might be active). Allows for safe usage of GPUContext for draw preparations or to perform GPU-driven drawing.
|
||||
/// </summary>
|
||||
template<typename T>
|
||||
FORCE_INLINE void AddDelayedDraw(const T& lambda)
|
||||
{
|
||||
DelayedDraw func;
|
||||
func.Bind<ConcurrentArenaAllocation>(&Memory, lambda);
|
||||
AddDelayedDraw(MoveTemp(func));
|
||||
}
|
||||
|
||||
private:
|
||||
DynamicVertexBuffer _instanceBuffer;
|
||||
Array<DelayedDraw, ConcurrentArenaAllocation> _delayedDraws;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -458,6 +458,10 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont
|
||||
JobSystem::Wait(label);
|
||||
renderContextBatch.WaitLabels.Clear();
|
||||
|
||||
// Perform custom post-scene drawing (eg. GPU dispatches used by VFX)
|
||||
for (RenderContext& e : renderContextBatch.Contexts)
|
||||
e.List->DrainDelayedDraws(e);
|
||||
|
||||
#if USE_EDITOR
|
||||
GBufferPass::Instance()->OverrideDrawCalls(renderContext);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user