r.HairStrands.ContinuousDecimationReordering

r.HairStrands.ContinuousDecimationReordering

#Overview

name: r.HairStrands.ContinuousDecimationReordering

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

It is referenced in 10 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of r.HairStrands.ContinuousDecimationReordering is to enable strand reordering for continuous Level of Detail (LOD) in the hair rendering system of Unreal Engine 5. This is an experimental feature.

This setting variable is primarily used in the HairStrands subsystem, which is part of the rendering module in Unreal Engine 5. It affects various components related to hair rendering, including resource management, debug visualization, and buffer swapping.

The value of this variable is set through the console variable system (CVarHairStrandsContinuousDecimationReordering). It’s a read-only variable, meaning its value can’t be changed at runtime.

This variable interacts with several other components of the hair rendering system:

  1. It affects the allocation and management of hair strand buffers, particularly for deformed roots and samples.
  2. It influences the buffer swapping mechanism in the hair rendering pipeline.
  3. It impacts the debug visualization of hair strands.

Developers must be aware that:

  1. This is an experimental feature and may not be fully stable.
  2. Enabling this feature affects memory allocation and runtime behavior of the hair rendering system.
  3. It’s a read-only variable, so it can’t be changed dynamically during gameplay.

Best practices when using this variable:

  1. Only enable it if you specifically need continuous LOD for hair strands.
  2. Test thoroughly when enabled, as it may impact performance and visual quality.
  3. Be prepared for potential instability or unexpected behavior, given its experimental nature.

Regarding the associated variable CVarHairStrandsContinuousDecimationReordering:

This is the actual console variable that controls the r.HairStrands.ContinuousDecimationReordering setting. It’s an integer variable, where a value greater than 0 enables the feature. It’s defined with the ECVF_RenderThreadSafe and ECVF_ReadOnly flags, indicating it’s safe to access from the render thread and can’t be modified at runtime.

The IsHairStrandContinuousDecimationReorderingEnabled() function checks the value of this console variable to determine if the feature is enabled. This function is used throughout the hair strands rendering code to conditionally execute logic related to continuous LOD and buffer management.

When working with this feature, developers should use the IsHairStrandContinuousDecimationReorderingEnabled() function to check if the feature is enabled, rather than directly accessing the console variable.

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/HairStrands/HairStrandsInterface.cpp:68

Scope: file

Source code excerpt:


static TAutoConsoleVariable<int32> CVarHairStrandsContinuousDecimationReordering(
	TEXT("r.HairStrands.ContinuousDecimationReordering"), 0,
	TEXT("Enable strand reordering to allow Continuous LOD. Experimental"),
	ECVF_RenderThreadSafe | ECVF_ReadOnly);

static TAutoConsoleVariable<int32> CVarHairStrandsVisibilityComputeRaster(
	TEXT("r.HairStrands.Visibility.ComputeRaster"), 0,
	TEXT("Hair Visiblity uses raster compute. Experimental"),

#Loc: <Workspace>/Engine/Plugins/Runtime/HairStrands/Source/HairStrandsCore/Private/GroomDebug.cpp:200

Scope (from outer to inner):

file
function     static void AddDebugProjectionHairPass

Source code excerpt:

	}

	// Double buffering is disabled by default unless the read-only cvar r.HairStrands.ContinuousDecimationReordering is set
	if (IsHairStrandContinuousDecimationReorderingEnabled() && !DeformedLODDatas.DeformedUniqueTrianglePositionBuffer[1].Buffer)
	{
		return;
	}

	const FIntPoint Resolution(Viewport.Width(), Viewport.Height());

#Loc: <Workspace>/Engine/Plugins/Runtime/HairStrands/Source/HairStrandsCore/Private/GroomManager.cpp:2221

Scope (from outer to inner):

file
function     static void RunHairBufferSwap

Source code excerpt:

			if (Instance->Strands.DeformedResource) { Instance->Strands.DeformedResource->SwapBuffer(); }

			// Double buffering is disabled by default unless the read-only cvar r.HairStrands.ContinuousDecimationReordering is set
			if (IsHairStrandContinuousDecimationReorderingEnabled())
			{
				if (Instance->Guides.DeformedRootResource) { Instance->Guides.DeformedRootResource->SwapBuffer(); }
				if (Instance->Strands.DeformedRootResource) { Instance->Strands.DeformedRootResource->SwapBuffer(); }
			}

#Loc: <Workspace>/Engine/Plugins/Runtime/HairStrands/Source/HairStrandsCore/Private/GroomResources.cpp:1708

Scope (from outer to inner):

file
function     void FHairStrandsLODDeformedRootResource::InternalAllocate

Source code excerpt:

			InternalCreateStructuredBufferRDG<FHairStrandsMeshTrianglePositionFormat>(GraphBuilder, RBFEntryCount, MeshSampleWeightsBuffer[0], ToHairResourceDebugName(HAIRSTRANDS_RESOUCE_NAME(CurveType, Hair.StrandsRootDeformed_MeshSampleWeightsBuffer0), ResourceName), OwnerName, EHairResourceUsageType::Dynamic);

			// Double buffering is disabled by default unless the read-only cvar r.HairStrands.ContinuousDecimationReordering is set
			if (IsHairStrandContinuousDecimationReorderingEnabled())
			{
				InternalCreateStructuredBufferRDG<FHairStrandsMeshTrianglePositionFormat>(GraphBuilder, SampleCount, DeformedSamplePositionsBuffer[1], ToHairResourceDebugName(HAIRSTRANDS_RESOUCE_NAME(CurveType, Hair.StrandsRootDeformed_DeformedSamplePositionsBuffer1), ResourceName), OwnerName, EHairResourceUsageType::Dynamic);
				InternalCreateStructuredBufferRDG<FHairStrandsMeshTrianglePositionFormat>(GraphBuilder, RBFEntryCount, MeshSampleWeightsBuffer[1], ToHairResourceDebugName(HAIRSTRANDS_RESOUCE_NAME(CurveType, Hair.StrandsRootDeformed_MeshSampleWeightsBuffer1), ResourceName), OwnerName, EHairResourceUsageType::Dynamic);
			}
		}

#Loc: <Workspace>/Engine/Plugins/Runtime/HairStrands/Source/HairStrandsCore/Private/GroomResources.cpp:1718

Scope (from outer to inner):

file
function     void FHairStrandsLODDeformedRootResource::InternalAllocate

Source code excerpt:

		InternalCreateVertexBufferRDG<FHairStrandsMeshTrianglePositionFormat>(GraphBuilder, RootCount * 3, DeformedUniqueTrianglePositionBuffer[0], ToHairResourceDebugName(HAIRSTRANDS_RESOUCE_NAME(CurveType, Hair.StrandsRootDeformed_DeformedUniqueTrianglePosition0Buffer0), ResourceName), OwnerName, EHairResourceUsageType::Dynamic);

		// Double buffering is disabled by default unless the read-only cvar r.HairStrands.ContinuousDecimationReordering is set
		if (IsHairStrandContinuousDecimationReorderingEnabled())
		{
			InternalCreateVertexBufferRDG<FHairStrandsMeshTrianglePositionFormat>(GraphBuilder, RootCount * 3, DeformedUniqueTrianglePositionBuffer[1], ToHairResourceDebugName(HAIRSTRANDS_RESOUCE_NAME(CurveType, Hair.StrandsRootDeformed_DeformedUniqueTrianglePosition0Buffer1), ResourceName), OwnerName, EHairResourceUsageType::Dynamic);
		}
	}
}

#Loc: <Workspace>/Engine/Plugins/Runtime/HairStrands/Source/HairStrandsCore/Private/GroomResources.cpp:1734

Scope (from outer to inner):

file
function     void FHairStrandsLODDeformedRootResource::InternalRelease

Source code excerpt:

	MeshSampleWeightsBuffer[0].Release();

	// Double buffering is disabled by default unless the read-only cvar r.HairStrands.ContinuousDecimationReordering is set
	if (IsHairStrandContinuousDecimationReorderingEnabled())
	{
		DeformedUniqueTrianglePositionBuffer[1].Release();
		DeformedSamplePositionsBuffer[1].Release();
		MeshSampleWeightsBuffer[1].Release();
	}

#Loc: <Workspace>/Engine/Plugins/Runtime/HairStrands/Source/HairStrandsCore/Public/GroomResources.h:516

Scope (from outer to inner):

file
function     uint32 GetResourcesSize

Source code excerpt:

		Total += GetBufferTotalNumBytes(MeshSampleWeightsBuffer[0]);

		// Double buffering is disabled by default unless the read-only cvar r.HairStrands.ContinuousDecimationReordering is set
		if (IsHairStrandContinuousDecimationReorderingEnabled())
		{
			Total += GetBufferTotalNumBytes(DeformedUniqueTrianglePositionBuffer[1]);
			Total += GetBufferTotalNumBytes(DeformedSamplePositionsBuffer[1]);
			Total += GetBufferTotalNumBytes(MeshSampleWeightsBuffer[1]);
		}

#Loc: <Workspace>/Engine/Plugins/Runtime/HairStrands/Source/HairStrandsCore/Public/GroomResources.h:553

Scope: file

Source code excerpt:

	};

	// Double buffering is disabled by default unless the read-only cvar r.HairStrands.ContinuousDecimationReordering is set
	inline uint32 GetIndex(EFrameType T) const { return T == EFrameType::Current ? CurrentIndex : 1u - CurrentIndex; }
	inline const FRDGExternalBuffer& GetDeformedUniqueTrianglePositionBuffer(EFrameType T) const { return IsHairStrandContinuousDecimationReorderingEnabled() ? DeformedUniqueTrianglePositionBuffer[GetIndex(T)] : DeformedUniqueTrianglePositionBuffer[0]; }
	inline const FRDGExternalBuffer& GetDeformedSamplePositionsBuffer(EFrameType T) const { return IsHairStrandContinuousDecimationReorderingEnabled() ? DeformedSamplePositionsBuffer[GetIndex(T)] : DeformedSamplePositionsBuffer[0]; }
	inline const FRDGExternalBuffer& GetMeshSampleWeightsBuffer(EFrameType T) const { return IsHairStrandContinuousDecimationReorderingEnabled() ? MeshSampleWeightsBuffer[GetIndex(T)] : MeshSampleWeightsBuffer[0]; }
	inline void SwapBuffer() { CurrentIndex = 1u - CurrentIndex; }

#Associated Variable and Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/HairStrands/HairStrandsInterface.cpp:67

Scope: file

Source code excerpt:

	ECVF_RenderThreadSafe);

static TAutoConsoleVariable<int32> CVarHairStrandsContinuousDecimationReordering(
	TEXT("r.HairStrands.ContinuousDecimationReordering"), 0,
	TEXT("Enable strand reordering to allow Continuous LOD. Experimental"),
	ECVF_RenderThreadSafe | ECVF_ReadOnly);

static TAutoConsoleVariable<int32> CVarHairStrandsVisibilityComputeRaster(
	TEXT("r.HairStrands.Visibility.ComputeRaster"), 0,

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/HairStrands/HairStrandsInterface.cpp:313

Scope (from outer to inner):

file
function     bool IsHairStrandContinuousDecimationReorderingEnabled

Source code excerpt:

{
	//NB this is a readonly cvar - and causes changes in platform data and runtime allocations 
	return CVarHairStrandsContinuousDecimationReordering.GetValueOnAnyThread() > 0;
}

bool IsHairVisibilityComputeRasterEnabled()
{
	return CVarHairStrandsVisibilityComputeRaster.GetValueOnAnyThread() == 1;
}