FX.AllowAsyncTick
FX.AllowAsyncTick
#Overview
name: FX.AllowAsyncTick
This variable is created as a Console Variable (cvar).
- type:
Var
- help:
allow parallel ticking of particle systems.
It is referenced in 6
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of FX.AllowAsyncTick is to control whether particle systems in Unreal Engine 5 can be ticked (updated) asynchronously in parallel. This setting is primarily used for the particle system and effects (FX) subsystem of the engine.
The Unreal Engine subsystem that relies on this setting variable is the particle system, specifically within the Engine module. It’s used in the FXSystem, ParticleComponents, and ParticleSystemManager.
The value of this variable is set through a console variable (CVar) named “FX.AllowAsyncTick”. It’s associated with the bAllowAsyncTick
variable, which is initialized to !WITH_EDITOR
, meaning it’s enabled by default in non-editor builds.
This variable interacts with several other variables and conditions:
FXConsoleVariables::bFreezeParticleSimulation
FApp::ShouldUseThreadingForPerformance()
GDistributionType
Developers must be aware of the following when using this variable:
- It affects performance, as it determines whether particle systems can be updated in parallel.
- It’s disabled by default in the editor, which may lead to different behavior between editor and runtime.
- It’s part of a larger set of conditions that determine whether async ticking is allowed.
Best practices when using this variable include:
- Consider the impact on performance and behavior when enabling or disabling it.
- Test thoroughly in both editor and runtime environments, as the default values differ.
- Be aware of its interaction with other variables and settings that affect particle system behavior.
Regarding the associated variable bAllowAsyncTick
:
- It’s the internal representation of the FX.AllowAsyncTick console variable.
- It’s used directly in the code to check if async ticking is allowed.
- It’s initialized to
!WITH_EDITOR
, meaning it’s true (enabled) in non-editor builds by default. - It’s used in conjunction with other conditions to determine if particle systems can be ticked asynchronously.
- Developers should be aware that changing this variable directly in code might not have the desired effect, as it’s controlled by the console variable system.
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/FXSystem.cpp:164
Scope (from outer to inner):
file
namespace FXConsoleVariables
Source code excerpt:
);
FAutoConsoleVariableRef CVarAllowAsyncTick(
TEXT("FX.AllowAsyncTick"),
bAllowAsyncTick,
TEXT("allow parallel ticking of particle systems."),
ECVF_Default
);
FAutoConsoleVariableRef CVarParticleSlackGPU(
TEXT("FX.ParticleSlackGPU"),
#Associated Variable and Callsites
This variable is associated with another variable named bAllowAsyncTick
. They share the same value. See the following C++ source code.
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/FXSystem.cpp:126
Scope (from outer to inner):
file
namespace FXConsoleVariables
Source code excerpt:
int32 bFreezeGPUSimulation = false;
int32 bFreezeParticleSimulation = false;
int32 bAllowAsyncTick = !WITH_EDITOR;
float ParticleSlackGPU = 0.02f;
int32 MaxParticleTilePreAllocation = 100;
int32 MaxCPUParticlesPerEmitter = 1000;
int32 MaxGPUParticlesSpawnedPerFrame = 1024 * 1024;
int32 GPUSpawnWarningThreshold = 20000;
float GPUCollisionDepthBounds = 500.0f;
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/FXSystem.cpp:165
Scope (from outer to inner):
file
namespace FXConsoleVariables
Source code excerpt:
FAutoConsoleVariableRef CVarAllowAsyncTick(
TEXT("FX.AllowAsyncTick"),
bAllowAsyncTick,
TEXT("allow parallel ticking of particle systems."),
ECVF_Default
);
FAutoConsoleVariableRef CVarParticleSlackGPU(
TEXT("FX.ParticleSlackGPU"),
ParticleSlackGPU,
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp:5545
Scope (from outer to inner):
file
function void UParticleSystemComponent::TickComponent
Source code excerpt:
if (!IsTickManaged() || bWarmingUp)
{
if (!ThisTickFunction || !ThisTickFunction->IsCompletionHandleValid() || !CanTickInAnyThread() || FXConsoleVariables::bFreezeParticleSimulation || !FXConsoleVariables::bAllowAsyncTick || !FApp::ShouldUseThreadingForPerformance() ||
GDistributionType == 0) // this may not be absolutely required, however if you are using distributions it will be glacial anyway. If you want to get rid of this, note that some modules use this indirectly as their criteria for CanTickInAnyThread
{
bDisallowAsync = true;
}
if (bDisallowAsync)
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemManager.cpp:742
Scope (from outer to inner):
file
function void FParticleSystemWorldManager::Tick
Source code excerpt:
//UE_LOG(LogParticles, Warning, TEXT("| Queue Concurrent Ticks | TG: %s |"), *TickGroupEnum->GetNameByValue(TickGroup).ToString());
bool bAllowTickConcurrent = !FXConsoleVariables::bFreezeParticleSimulation && FXConsoleVariables::bAllowAsyncTick && FApp::ShouldUseThreadingForPerformance() && GDistributionType != 0;
if (bAllowTickConcurrent)
{
//TODO: Currently waiting on this tick group but we should be able to allow these tasks to run over the whole frame if we can implement some synchronization so they don't overrun the EOF updates.
ProcessTickList<true>(DeltaTime, TickType, TickGroup, TickLists_Concurrent, MyCompletionGraphEvent);
}
else
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/FXSystem.h:71
Scope (from outer to inner):
file
namespace FXConsoleVariables
Source code excerpt:
extern int32 bFreezeParticleSimulation;
/** true if we allow async ticks */
extern int32 bAllowAsyncTick;
/** Amount of slack to allocate for GPU particles to prevent tile churn as percentage of total particles. */
extern float ParticleSlackGPU;
/** Maximum tile preallocation for GPU particles. */
extern int32 MaxParticleTilePreAllocation;
/** Maximum number of CPU particles to allow per-emitter. */
extern int32 MaxCPUParticlesPerEmitter;