BindlessResources

BindlessResources

#Overview

name: BindlessResources

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

It is referenced in 15 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of BindlessResources is to enable bindless resource access in shaders, which allows for more flexible and efficient use of GPU resources. This feature is part of Unreal Engine’s rendering system and is particularly important for modern GPU architectures that support bindless rendering.

Unreal Engine subsystems that rely on this setting variable include:

  1. Shader Compiler
  2. D3D12 Renderer
  3. Ray Tracing System

The value of this variable is typically set through compiler flags and configuration settings. In the D3D12 renderer, it’s controlled by the BindlessResourcesConfig variable.

Other variables that interact with BindlessResources include:

  1. BindlessSamplers
  2. ResourceCounts.UsageFlags
  3. EShaderCodeFeatures
  4. ED3D12RootSignatureFlags

Developers must be aware of the following when using this variable:

  1. Mixing bindless and non-bindless resources in the same shader is not allowed and will result in compilation errors.
  2. It affects root signature creation and resource binding in D3D12.
  3. It’s only supported on platforms that support bindless rendering (PLATFORM_SUPPORTS_BINDLESS_RENDERING).
  4. It may have different behavior for different shader frequencies (e.g., graphics vs. ray tracing shaders).

Best practices when using this variable include:

  1. Ensure that the target platform supports bindless rendering before enabling it.
  2. Use it consistently across related shaders and resources to avoid mixing bindless and non-bindless access.
  3. Be aware of the performance implications and potential increased shader complexity when using bindless resources.
  4. Consider the impact on root signature design and descriptor heap management when enabling bindless resources.
  5. Test thoroughly on all target platforms to ensure compatibility and performance.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/Windows/BaseWindowsEngine.ini:14, section: [PCD3D_SM5]

Location: <Workspace>/Engine/Config/Windows/BaseWindowsEngine.ini:18, section: [PCD3D_SM6]

Location: <Workspace>/Engine/Config/Windows/BaseWindowsEngine.ini:22, section: [SF_VULKAN_SM5]

Location: <Workspace>/Engine/Config/Windows/BaseWindowsEngine.ini:26, section: [SF_VULKAN_SM6]

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Developer/ShaderCompilerCommon/Private/ShaderCompilerCommon.cpp:405

Scope (from outer to inner):

file
function     bool UE::ShaderCompilerCommon::ValidatePackedResourceCounts

Source code excerpt:

		};

		if (EnumHasAnyFlags(PackedResourceCounts.UsageFlags, EShaderResourceUsageFlags::BindlessResources) && PackedResourceCounts.NumSRVs > 0)
		{
			const FString Names = GetAllResourcesOfType(EShaderParameterType::SRV);
			Output.Errors.Add(FString::Printf(TEXT("Shader is mixing bindless resources with non-bindless resources. %d SRV slots were detected: %s"), PackedResourceCounts.NumSRVs, *Names));
			Output.bSucceeded = false;
		}

		if (EnumHasAnyFlags(PackedResourceCounts.UsageFlags, EShaderResourceUsageFlags::BindlessResources) && PackedResourceCounts.NumUAVs > 0)
		{
			const FString Names = GetAllResourcesOfType(EShaderParameterType::UAV);
			Output.Errors.Add(FString::Printf(TEXT("Shader is mixing bindless resources with non-bindless resources. %d UAV slots were detected: %s"), PackedResourceCounts.NumUAVs, *Names));
			Output.bSucceeded = false;
		}

#Loc: <Workspace>/Engine/Source/Developer/Windows/ShaderFormatD3D/Private/D3DShaderCompilerDXC.cpp:1150

Scope (from outer to inner):

file
function     bool CompileAndProcessD3DShaderDXC

Source code excerpt:

			if (Input.Environment.CompilerFlags.Contains(CFLAG_BindlessResources))
			{
				PackedResourceCounts.UsageFlags |= EShaderResourceUsageFlags::BindlessResources;
			}

			if (Input.Environment.CompilerFlags.Contains(CFLAG_BindlessSamplers))
			{
				PackedResourceCounts.UsageFlags |= EShaderResourceUsageFlags::BindlessSamplers;
			}

#Loc: <Workspace>/Engine/Source/Developer/Windows/ShaderFormatD3D/Private/D3DShaderCompilerDXC.cpp:1231

Scope (from outer to inner):

file
function     bool CompileAndProcessD3DShaderDXC
lambda-function

Source code excerpt:

				if ((ShaderRequiresFlags & D3D_SHADER_REQUIRES_RESOURCE_DESCRIPTOR_HEAP_INDEXING) != 0)
				{
					EnumAddFlags(CodeFeatures.CodeFeatures, EShaderCodeFeatures::BindlessResources);
				}

				if ((ShaderRequiresFlags & D3D_SHADER_REQUIRES_SAMPLER_DESCRIPTOR_HEAP_INDEXING) != 0)
				{
					EnumAddFlags(CodeFeatures.CodeFeatures, EShaderCodeFeatures::BindlessSamplers);
				}

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.cpp:1332

Scope (from outer to inner):

file
function     void FD3D12Adapter::InitializeDevices

Source code excerpt:

		if (BindlessResourcesConfig == ERHIBindlessConfiguration::AllShaders)
		{
			EnumAddFlags(GraphicsFlags, ED3D12RootSignatureFlags::BindlessResources);
		}
		if (BindlessSamplersConfig == ERHIBindlessConfiguration::AllShaders)
		{
			EnumAddFlags(GraphicsFlags, ED3D12RootSignatureFlags::BindlessSamplers);
		}

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.cpp:1348

Scope (from outer to inner):

file
function     void FD3D12Adapter::InitializeDevices

Source code excerpt:

		if (BindlessResourcesConfig != ERHIBindlessConfiguration::Disabled)
		{
			EnumAddFlags(RayTracingFlags, ED3D12RootSignatureFlags::BindlessResources);
		}
		if (BindlessSamplersConfig != ERHIBindlessConfiguration::Disabled)
		{
			EnumAddFlags(RayTracingFlags, ED3D12RootSignatureFlags::BindlessSamplers);
		}

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/D3D12Commands.cpp:932

Scope (from outer to inner):

file
function     FD3D12ResourceBinder

Source code excerpt:

		, Frequency(InFrequency)
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
		, bBindlessResources(EnumHasAnyFlags(ShaderData->ResourceCounts.UsageFlags, EShaderResourceUsageFlags::BindlessResources))
		, bBindlessSamplers(EnumHasAnyFlags(ShaderData->ResourceCounts.UsageFlags, EShaderResourceUsageFlags::BindlessSamplers))
#endif
	{
	}

#if PLATFORM_SUPPORTS_BINDLESS_RENDERING

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/D3D12RayTracing.cpp:4462

Scope (from outer to inner):

file
function     static bool SetRayTracingShaderResources

Source code excerpt:

	{
	#if D3D12RHI_USE_CONSTANT_BUFFER_VIEWS
		if (!EnumHasAllFlags(Shader->ResourceCounts.UsageFlags, EShaderResourceUsageFlags::BindlessResources))
		{
			const uint32 DescriptorTableBaseIndex = DescriptorCache.AllocateDeduplicated(Bindings.CBVVersions, Bindings.LocalCBVs, NumCBVs, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, WorkerIndex);
			const uint32 BindSlot = RootSignature->CBVRDTBindSlot(SF_Compute);
			check(BindSlot != 0xFF);

			const D3D12_GPU_DESCRIPTOR_HANDLE ResourceDescriptorTableBaseGPU = DescriptorCache.ViewHeap.GetDescriptorGPU(DescriptorTableBaseIndex);

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/D3D12Shader.h:114

Scope (from outer to inner):

file
function     bool UsesBindlessResources

Source code excerpt:

	FORCEINLINE bool UsesDiagnosticBuffer() const { return EnumHasAnyFlags(GetFeatures(), EShaderCodeFeatures::DiagnosticBuffer); }
	FORCEINLINE bool UsesGlobalUniformBuffer() const { return EnumHasAnyFlags(ResourceCounts.UsageFlags, EShaderResourceUsageFlags::GlobalUniformBuffer); }
	FORCEINLINE bool UsesBindlessResources() const { return EnumHasAnyFlags(ResourceCounts.UsageFlags, EShaderResourceUsageFlags::BindlessResources); }
	FORCEINLINE bool UsesBindlessSamplers() const { return EnumHasAnyFlags(ResourceCounts.UsageFlags, EShaderResourceUsageFlags::BindlessSamplers); }
	FORCEINLINE bool UsesRootConstants() const { return EnumHasAnyFlags(ResourceCounts.UsageFlags, EShaderResourceUsageFlags::RootConstants); }

	bool InitCommon(TArrayView<const uint8> InCode);
};

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Private/D3D12Shaders.cpp:73

Scope (from outer to inner):

file
function     static bool ValidateShaderIsUsable

Source code excerpt:

	}

	if (EnumHasAnyFlags(InShader->Features, EShaderCodeFeatures::BindlessResources | EShaderCodeFeatures::BindlessSamplers))
	{
		if (GRHIBindlessSupport == ERHIBindlessSupport::Unsupported ||
			(GRHIBindlessSupport == ERHIBindlessSupport::RayTracingOnly && !IsRayTracingShaderFrequency(InFrequency)))
		{
			return false;
		}

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Public/D3D12RootSignatureDefinitions.h:19

Scope: file

Source code excerpt:

	AllowMeshShaders = 1 << 0,
	InputAssembler = 1 << 1,
	BindlessResources = 1 << 2,
	BindlessSamplers = 1 << 3,
	RootConstants = 1 << 4,
};
ENUM_CLASS_FLAGS(ED3D12RootSignatureFlags)

namespace D3D12ShaderUtils

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Public/D3D12RootSignatureDefinitions.h:203

Scope (from outer to inner):

file
namespace    D3D12ShaderUtils
function     void SetFlags

Source code excerpt:

			}

			if (EnumHasAnyFlags(InFlags, ED3D12RootSignatureFlags::BindlessResources))
			{
				AddRootFlag(D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED);
			}

			if (EnumHasAnyFlags(InFlags, ED3D12RootSignatureFlags::BindlessSamplers))
			{

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Public/D3D12RootSignatureDefinitions.h:233

Scope (from outer to inner):

file
namespace    D3D12ShaderUtils
function     inline bool ShouldSkipType

Source code excerpt:

			if (Type == ERootSignatureRangeType::SRV || Type == ERootSignatureRangeType::UAV)
			{
				return EnumHasAnyFlags(Flags, ED3D12RootSignatureFlags::BindlessResources);
			}

			if (Type == ERootSignatureRangeType::Sampler)
			{
				return EnumHasAnyFlags(Flags, ED3D12RootSignatureFlags::BindlessSamplers);
			}

#Loc: <Workspace>/Engine/Source/Runtime/D3D12RHI/Public/D3D12RootSignatureDefinitions.h:454

Scope (from outer to inner):

file
namespace    D3D12ShaderUtils
function     inline void CreateRayTracingSignature

Source code excerpt:

		}

		if (Creator.HasFlags(ED3D12RootSignatureFlags::BindlessResources))
		{
			for (uint32 Index = 0; Index < MAX_CBS; Index++)
			{
				Creator.AddConstantBufferViewParameter(Index, Creator.GetRegisterSpace());
			}
		}

#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Public/ShaderCore.h:727

Scope: file

Source code excerpt:

{
	GlobalUniformBuffer   = 1 << 0,
	BindlessResources     = 1 << 1,
	BindlessSamplers      = 1 << 2,
	RootConstants         = 1 << 3,
	NoDerivativeOps       = 1 << 4,
	ShaderBundle          = 1 << 5,
};
ENUM_CLASS_FLAGS(EShaderResourceUsageFlags)

#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Public/ShaderCore.h:765

Scope: file

Source code excerpt:

	Atomic64                = 1 << 3,
	DiagnosticBuffer        = 1 << 4,
	BindlessResources       = 1 << 5,
	BindlessSamplers        = 1 << 6,
	StencilRef              = 1 << 7,
	BarycentricsSemantic    = 1 << 8,
};
ENUM_CLASS_FLAGS(EShaderCodeFeatures);