fx.GPUSimulationDynTextureSizeXY

fx.GPUSimulationDynTextureSizeXY

#Overview

name: fx.GPUSimulationDynTextureSizeXY

This variable is created as a Console Variable (cvar).

It is referenced in 13 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of fx.GPUSimulationDynTextureSizeXY is to define the GPU particle simulation texture XY dimension when dynamic resizing is enabled. This setting variable is primarily used in the particle system’s GPU simulation subsystem within Unreal Engine 5.

Key points about fx.GPUSimulationDynTextureSizeXY:

  1. It is used by the particle simulation module in Unreal Engine’s rendering system.

  2. The value is set through an FAutoConsoleVariableRef, which means it can be adjusted at runtime through console commands.

  3. The default value is 16, and it’s marked as read-only (ECVF_ReadOnly).

  4. This variable is used when dynamic resizing of particle simulation textures is enabled.

  5. It interacts with other variables such as GParticleSimulationTextureSizeX and GParticleSimulationTextureSizeY, which are used when dynamic resizing is not enabled.

  6. The value must be a power of two, as checked in the FParticleSimulationResources::Init() function.

  7. It’s used to calculate tile sizes, texture dimensions, and scaling factors in various parts of the particle simulation code.

Best practices when using this variable:

  1. Ensure that the value remains a power of two to avoid assertion failures.
  2. Be aware that changing this value will affect the initial size of particle simulation textures when dynamic resizing is enabled.
  3. Consider the performance implications of adjusting this value, as it directly affects texture sizes and memory usage.

Developers should be aware that:

  1. This variable is used only when dynamic resizing is enabled (controlled by GFXCascadeGpuSpriteAllowDynAllocs).
  2. Changing this value may impact performance and memory usage of GPU particle simulations.
  3. The actual texture size may grow beyond this initial value if resizing occurs during runtime.

The associated variable GParticleSimulationDynTextureSizeXY is an integer that directly holds the value set by fx.GPUSimulationDynTextureSizeXY. It’s used throughout the code to access the current dynamic texture size. The same considerations and best practices apply to this variable as well.

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:80

Scope: file

Source code excerpt:

int32 GParticleSimulationDynTextureSizeXY = 16;
FAutoConsoleVariableRef CVarParticleSimulationDynTextureSizeXY(
	TEXT("fx.GPUSimulationDynTextureSizeXY"),
	GParticleSimulationDynTextureSizeXY,
	TEXT("GPU Particle simulation texture XY dimension when dynamic resizing is enabled (default=16)"),
	ECVF_ReadOnly
);

static bool GFXCascadeGpuSpriteAllowDynAllocs = false;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:531

Scope (from outer to inner):

file
class        class FParticleSimulationResources
function     void Init

Source code excerpt:

		SimulationResourcesSize.Y = bAllowTileResizing ? GParticleSimulationDynTextureSizeXY : GParticleSimulationTextureSizeY;
		
		check((SimulationResourcesSize.X & (SimulationResourcesSize.X - 1)) == 0); // fx.GPUSimulationTextureSizeX,or fx.GPUSimulationDynTextureSizeXY is not a power of two.
		check((SimulationResourcesSize.Y & (SimulationResourcesSize.Y - 1)) == 0); // fx.GPUSimulationTextureSizeY,or fx.GPUSimulationDynTextureSizeXY is not a power of two.
		check(GParticleSimulationTileSize <= SimulationResourcesSize.X); // Particle simulation tile size is larger than fx.GPUSimulationTextureSizeX, or fx.GPUSimulationDynTextureSizeXY.
		check(GParticleSimulationTileSize <= SimulationResourcesSize.Y); // Particle simulation tile size is larger than fx.GPUSimulationTextureSizeY, or fx.GPUSimulationDynTextureSizeXY.

		/** How many tiles are in the simulation textures. */
		ParticleSimulationTileCountX = SimulationResourcesSize.X / GParticleSimulationTileSize;
		ParticleSimulationTileCountY = SimulationResourcesSize.Y / GParticleSimulationTileSize;
		ParticleSimulationTileCount = ParticleSimulationTileCountX * ParticleSimulationTileCountY;

#Associated Variable and Callsites

This variable is associated with another variable named GParticleSimulationDynTextureSizeXY. They share the same value. See the following C++ source code.

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:78

Scope: file

Source code excerpt:

);

int32 GParticleSimulationDynTextureSizeXY = 16;
FAutoConsoleVariableRef CVarParticleSimulationDynTextureSizeXY(
	TEXT("fx.GPUSimulationDynTextureSizeXY"),
	GParticleSimulationDynTextureSizeXY,
	TEXT("GPU Particle simulation texture XY dimension when dynamic resizing is enabled (default=16)"),
	ECVF_ReadOnly
);

static bool GFXCascadeGpuSpriteAllowDynAllocs = false;
static FAutoConsoleVariableRef CVarFXCascadeGpuSpriteDynamicAllocations(

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:172

Scope (from outer to inner):

file
class        class FParticleTileAllocator

Source code excerpt:

	 * Each time we resize, the associated textures width and height are multiplied by 2.
	 * This means that each time we increase the tile allocator, the tile count will grow
	 * by a 4 ^ (resizecount) factor. Ex: Initial textures is driven by GParticleSimulationDynTextureSizeXY,
	 * and contains one tile. The first resize will contain 4 tiles, the second resize will have 16 tiles, and so on.
	 * The tile allocated from a resize are allocated following a Morton Z curve pattern.
	 * 
	 */

	bool Resize()
	{
		check(bAllowResizing);

		static uint32 MaxMortonIndex = 65535;// (2 ^ 16) -1
		uint32 OldTileCount = InitialTileCount * FMath::Pow(4, (float)ResizeTileAllocCount);
		uint32 ResizedTileCount = OldTileCount * 4;

		// 1-check to make sure we dont bust the maximum tile allocation allowed (see GParticleSimulationTextureSizeX, GParticleSimulationTextureSizeY).
		// 2-check to make sure we dont bust the morton index capacity (16 bits for each X,Y coord -> 2^16 - 1) == 65535)

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:528

Scope (from outer to inner):

file
class        class FParticleSimulationResources
function     void Init

Source code excerpt:

	{
		bool bAllowTileResizing = GFXCascadeGpuSpriteAllowDynAllocs;
		SimulationResourcesSize.X = bAllowTileResizing ? GParticleSimulationDynTextureSizeXY : GParticleSimulationTextureSizeX;
		SimulationResourcesSize.Y = bAllowTileResizing ? GParticleSimulationDynTextureSizeXY : GParticleSimulationTextureSizeY;
		
		check((SimulationResourcesSize.X & (SimulationResourcesSize.X - 1)) == 0); // fx.GPUSimulationTextureSizeX,or fx.GPUSimulationDynTextureSizeXY is not a power of two.
		check((SimulationResourcesSize.Y & (SimulationResourcesSize.Y - 1)) == 0); // fx.GPUSimulationTextureSizeY,or fx.GPUSimulationDynTextureSizeXY is not a power of two.
		check(GParticleSimulationTileSize <= SimulationResourcesSize.X); // Particle simulation tile size is larger than fx.GPUSimulationTextureSizeX, or fx.GPUSimulationDynTextureSizeXY.
		check(GParticleSimulationTileSize <= SimulationResourcesSize.Y); // Particle simulation tile size is larger than fx.GPUSimulationTextureSizeY, or fx.GPUSimulationDynTextureSizeXY.

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:584

Scope (from outer to inner):

file
class        class FParticleSimulationResources
function     void Resize

Source code excerpt:


		uint32 ScaleFactor = TileAllocator.GetResizeFactor();
		SimulationResourcesSize.X = GParticleSimulationDynTextureSizeXY * ScaleFactor;
		SimulationResourcesSize.Y = GParticleSimulationDynTextureSizeXY * ScaleFactor;
		
		// resize position and velocity
		StateTextures[0].ResizeRHI(RHICmdList, SimulationResourcesSize.X, SimulationResourcesSize.Y);
		StateTextures[1].ResizeRHI(RHICmdList, SimulationResourcesSize.X, SimulationResourcesSize.Y);
		// resize attributes
		RenderAttributesTexture.ResizeRHI(RHICmdList, SimulationResourcesSize.X, SimulationResourcesSize.Y);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:1159

Scope: file

Source code excerpt:

		if(ParticleSimulationResources->SupportTileResizing())
		{ 
			Result.TilePageScale.X = (float)GParticleSimulationDynTextureSizeXY / (float)ParticleSimulationResources->SimulationResourcesSize.X;
			Result.TilePageScale.Y = (float)GParticleSimulationDynTextureSizeXY / (float)ParticleSimulationResources->SimulationResourcesSize.Y;
		}
		
		Result.TileOffsets = TileOffsetsRef;
		return Result;
	}
};

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:1765

Scope (from outer to inner):

file
class        class FParticleInjectionVS : public FGlobalShader
function     void SetParameters

Source code excerpt:

		if (ParticleSimulationResources->SupportTileResizing())
		{
			Parameters.TilePageScale.X = (float)GParticleSimulationDynTextureSizeXY / (float)ParticleSimulationResources->SimulationResourcesSize.X;
			Parameters.TilePageScale.Y = (float)GParticleSimulationDynTextureSizeXY / (float)ParticleSimulationResources->SimulationResourcesSize.Y;
		}

		FParticleInjectionBufferRef UniformBuffer = FParticleInjectionBufferRef::CreateUniformBufferImmediate( Parameters, UniformBuffer_SingleDraw );
		SetUniformBufferParameter(BatchedParameters, GetUniformBufferParameter<FParticleInjectionParameters>(), UniformBuffer );
	}
};

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:2144

Scope (from outer to inner):

file
function     static void BuildParticleVertexBuffer

Source code excerpt:

	float TileCountX = (float)ParticleSimulationResources->ParticleSimulationTileCountX;
	float TileCountY = (float)ParticleSimulationResources->ParticleSimulationTileCountY;
	float TextureSizeX = bAllowResizing ? GParticleSimulationDynTextureSizeXY: GParticleSimulationTextureSizeX;
	float TextureSizeY = bAllowResizing ? GParticleSimulationDynTextureSizeXY : GParticleSimulationTextureSizeY;

	for ( int32 Index = 0; Index < TileCount; ++Index )
	{
		// Take the mod of the tile index with the tile count of the first allocation. In case the gpu resources are resized, the 
		// tile coordinate will be ajusted by the TilePageIndex.
		const uint32 TileIndex = InTiles[Index] % ParticleSimulationResources->ParticleSimulationTileCount;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:2302

Scope (from outer to inner):

file
function     static FBox ComputeParticleBounds

Source code excerpt:

			if (bSupportTileResizing)
			{
				TilePageScale.X = (float)GParticleSimulationDynTextureSizeXY / (float)ParticleSimulationResources->SimulationResourcesSize.X;
				TilePageScale.Y = (float)GParticleSimulationDynTextureSizeXY / (float)ParticleSimulationResources->SimulationResourcesSize.Y;
			}
			
			Parameters.TilePageScale = TilePageScale;

			SetShaderParameters(RHICmdList, ParticleBoundsCS, ParticleBoundsCS.GetComputeShader(), Parameters);
		}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:3044

Scope (from outer to inner):

file
function     virtual void GetDynamicMeshElementsEmitter

Source code excerpt:


					FVector3f TilePageScale;
					TilePageScale.X = SimulationResources->SupportTileResizing() ? ((float)(GParticleSimulationDynTextureSizeXY) / (float)SimulationResources->SimulationResourcesSize.X) : 1.0f;
					TilePageScale.Y = SimulationResources->SupportTileResizing() ? ((float)(GParticleSimulationDynTextureSizeXY) / (float)SimulationResources->SimulationResourcesSize.Y) : 1.0f;
					TilePageScale.Z = SimulationResources->SupportTileResizing() ? 1.0f : 0.0f;
					VertexFactory.TilePageScale = TilePageScale;

					FMeshBatch& Mesh = Collector.AllocateMesh();
					FMeshBatchElement& BatchElement = Mesh.Elements[0];
					BatchElement.IndexBuffer = &GParticleIndexBuffer;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:4056

Scope (from outer to inner):

file
class        class FGPUSpriteParticleEmitterInstance : public FParticleEmitterInstance
function     int32 AllocateTilesForParticles

Source code excerpt:

		float TileCountX = ParticleSimulationResources->ParticleSimulationTileCountX;
		float TileCountY = ParticleSimulationResources->ParticleSimulationTileCountY;
		float TextureSizeX = bAllowResizing ? GParticleSimulationDynTextureSizeXY : GParticleSimulationTextureSizeX;
		float TextureSizeY = bAllowResizing ? GParticleSimulationDynTextureSizeXY : GParticleSimulationTextureSizeY;

		// Need to allocate space in tiles for all new particles.
		FParticleSimulationResources* SimulationResources = FXSystem->GetParticleSimulationResources();
		uint32 TileIndex = (AllocatedTiles.IsValidIndex(TileToAllocateFrom)) ? AllocatedTiles[TileToAllocateFrom] % ParticleSimulationResources->ParticleSimulationTileCount : INDEX_NONE;
		FVector2D TileOffset(
			FMath::Fractional((float)TileIndex / TileCountX),

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp:4503

Scope (from outer to inner):

file
function     void FFXSystem::InitGPUSimulation

Source code excerpt:


	check(ParticleSimulationResources == NULL);
	ensure(GParticleSimulationTextureSizeX > 0 && GParticleSimulationTextureSizeY > 0 && GParticleSimulationDynTextureSizeXY > 0);
	
	ParticleSimulationResources = new FParticleSimulationResources();

	InitGPUResources();
}