r.Forward.MaxCulledLightsPerCell

r.Forward.MaxCulledLightsPerCell

#Overview

name: r.Forward.MaxCulledLightsPerCell

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

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

It is referenced in 6 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of r.Forward.MaxCulledLightsPerCell is to control the memory allocation for light culling in each cell of the light grid used in forward rendering. This setting is part of Unreal Engine’s rendering system, specifically the forward rendering pipeline.

The Unreal Engine subsystem that relies on this setting variable is the Renderer module, particularly the light culling and injection system for forward rendering. This can be seen from the file path “Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp”.

The value of this variable is set through the Unreal Engine console variable system. It’s initialized with a default value of 32 and can be modified at runtime using console commands.

This variable interacts closely with GMaxCulledLightsPerCell, which is the associated C++ variable that directly holds the value set by r.Forward.MaxCulledLightsPerCell. It also interacts with GLightLinkedListCulling, which affects how the MaxCulledLightsPerCell value is used.

Developers must be aware that:

  1. This variable affects memory allocation, so setting it too high might lead to excessive memory usage.
  2. When r.Forward.LightLinkedListCulling is enabled, this variable is used to compute a global maximum instead of a per-cell limit on culled lights.
  3. The value of this variable impacts performance and visual quality, as it determines how many lights can be considered for each cell in the light grid.

Best practices when using this variable include:

  1. Balancing between performance and visual quality. Higher values allow more lights per cell but increase memory usage and potentially processing time.
  2. Monitoring performance and memory usage when adjusting this value.
  3. Considering the target hardware capabilities when setting this value, especially for games targeting a wide range of devices.

Regarding the associated variable GMaxCulledLightsPerCell:

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/Android/AndroidEngine.ini:84, section: [ConsoleVariables]

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp:64

Scope: file

Source code excerpt:

int32 GMaxCulledLightsPerCell = 32;
FAutoConsoleVariableRef CVarMaxCulledLightsPerCell(
	TEXT("r.Forward.MaxCulledLightsPerCell"),
	GMaxCulledLightsPerCell,
	TEXT("Controls how much memory is allocated for each cell for light culling.  When r.Forward.LightLinkedListCulling is enabled, this is used to compute a global max instead of a per-cell limit on culled lights."),
	ECVF_Scalability | ECVF_RenderThreadSafe
);

int32 GLightLinkedListCulling = 1;

#Associated Variable and Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp:62

Scope: file

Source code excerpt:

);

int32 GMaxCulledLightsPerCell = 32;
FAutoConsoleVariableRef CVarMaxCulledLightsPerCell(
	TEXT("r.Forward.MaxCulledLightsPerCell"),
	GMaxCulledLightsPerCell,
	TEXT("Controls how much memory is allocated for each cell for light culling.  When r.Forward.LightLinkedListCulling is enabled, this is used to compute a global max instead of a per-cell limit on culled lights."),
	ECVF_Scalability | ECVF_RenderThreadSafe
);

int32 GLightLinkedListCulling = 1;
FAutoConsoleVariableRef CVarLightLinkedListCulling(

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp:756

Scope: file

Source code excerpt:

		ForwardLightData->NumGridCells = LightGridSizeXY.X * LightGridSizeXY.Y * GLightGridSizeZ;
		ForwardLightData->CulledGridSize = FIntVector(LightGridSizeXY.X, LightGridSizeXY.Y, GLightGridSizeZ);
		ForwardLightData->MaxCulledLightsPerCell = GLightLinkedListCulling ? NumLocalLightsFinal: GMaxCulledLightsPerCell;
		ForwardLightData->LightGridPixelSizeShift = FMath::FloorLog2(GLightGridPixelSize);
		ForwardLightData->SimpleLightsEndIndex = SimpleLightsEnd;
		ForwardLightData->ClusteredDeferredSupportedEndIndex = ClusteredSupportedEnd;
		ForwardLightData->ManyLightsSupportedStartIndex = FMath::Min<int32>(ManyLightsSupportedStart, NumLocalLightsFinal);
		ForwardLightData->DirectLightingShowFlag = ViewFamily.EngineShowFlags.DirectLighting ? 1 : 0;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp:815

Scope: file

Source code excerpt:

				ForwardLightData->NumReflectionCaptures);

			const uint32 CulledLightLinksElements = MaxNumCells * GMaxCulledLightsPerCell * LightLinkStride;


			FRDGBufferRef CulledLightLinksBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), CulledLightLinksElements), TEXT("CulledLightLinks"));
			FRDGBufferRef StartOffsetGridBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), MaxNumCells), TEXT("StartOffsetGrid"));
			FRDGBufferRef NextCulledLightLinkBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), 1), TEXT("NextCulledLightLink"));
			FRDGBufferRef NextCulledLightDataBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), 1), TEXT("NextCulledLightData"));

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp:832

Scope: file

Source code excerpt:

				const SIZE_T LightIndexTypeSize = sizeof(FLightIndexType);
				const EPixelFormat CulledLightDataGridFormat = PF_R16_UINT;
				FRDGBufferRef CulledLightDataGrid = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(LightIndexTypeSize, MaxNumCells * GMaxCulledLightsPerCell), TEXT("CulledLightDataGrid"));
				CulledLightDataGridSRV = GraphBuilder.CreateSRV(CulledLightDataGrid, CulledLightDataGridFormat);
				CulledLightDataGridUAV = GraphBuilder.CreateUAV(CulledLightDataGrid, CulledLightDataGridFormat);
			}
			else
			{
				const SIZE_T LightIndexTypeSize = sizeof(FLightIndexType32);
				const EPixelFormat CulledLightDataGridFormat = PF_R32_UINT;
				FRDGBufferRef CulledLightDataGrid = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(LightIndexTypeSize, MaxNumCells * GMaxCulledLightsPerCell), TEXT("CulledLightDataGrid"));
				CulledLightDataGridSRV = GraphBuilder.CreateSRV(CulledLightDataGrid);
				CulledLightDataGridUAV = GraphBuilder.CreateUAV(CulledLightDataGrid);
			}

			FLightGridInjectionCS::FParameters *PassParameters = GraphBuilder.AllocParameters<FLightGridInjectionCS::FParameters>();

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp:869

Scope: file

Source code excerpt:

			PassParameters->NumReflectionCaptures   = ForwardLightData->NumReflectionCaptures;
			PassParameters->NumLocalLights          = ForwardLightData->NumLocalLights;
			PassParameters->MaxCulledLightsPerCell  = GMaxCulledLightsPerCell;
			PassParameters->NumGridCells            = ForwardLightData->NumGridCells;
			PassParameters->LightGridPixelSizeShift = ForwardLightData->LightGridPixelSizeShift;

#if ENABLE_LIGHT_CULLING_VIEW_SPACE_BUILD_DATA
			check(ViewSpacePosAndRadiusData.Num() == ForwardLocalLightData.Num());
			check(ViewSpaceDirAndPreprocAngleData.Num() == ForwardLocalLightData.Num());