BindlessSamplers

BindlessSamplers

#Overview

name: BindlessSamplers

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 13 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of BindlessSamplers is to enable the use of bindless samplers in shaders within Unreal Engine 5. Bindless samplers allow for a more flexible and efficient way of accessing sampler resources in shaders, particularly when dealing with a large number of samplers.

This setting variable is primarily used in the rendering system, specifically in the D3D12 RHI (Render Hardware Interface) and shader compilation process. The following Unreal Engine subsystems and modules rely on this setting:

  1. ShaderCompilerCommon
  2. D3D12RHI
  3. RenderCore

The value of this variable is typically set through compiler flags or configuration settings. For example, in the D3D12 RHI, it’s determined by the BindlessSamplersConfig variable.

BindlessSamplers often interacts with other variables and flags, such as:

  1. BindlessResources
  2. EShaderResourceUsageFlags
  3. EShaderCodeFeatures
  4. ED3D12RootSignatureFlags

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

  1. Mixing bindless samplers with non-bindless samplers in the same shader is not allowed and will result in compilation errors.
  2. Bindless samplers require hardware support, so it may not be available on all platforms or GPU configurations.
  3. The use of bindless samplers affects the root signature creation and shader resource binding process.

Best practices when using this variable include:

  1. Ensure that the target hardware supports bindless samplers before enabling this feature.
  2. Use bindless samplers consistently across your shaders to avoid mixing with non-bindless samplers.
  3. Be aware of the performance implications and potential benefits of using bindless samplers in your specific use case.
  4. Consider the impact on shader compilation and runtime performance when enabling this feature.
  5. Properly configure the root signature and resource binding code to accommodate bindless samplers when enabled.

#Setting Variables

#References In INI files

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

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

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

Location: <Workspace>/Engine/Config/Windows/BaseWindowsEngine.ini:27, 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:419

Scope (from outer to inner):

file
function     bool UE::ShaderCompilerCommon::ValidatePackedResourceCounts

Source code excerpt:

		}

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

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

Scope (from outer to inner):

file
function     bool CompileAndProcessD3DShaderDXC

Source code excerpt:

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

			if (bHasNoDerivativeOps)
			{
				PackedResourceCounts.UsageFlags |= EShaderResourceUsageFlags::NoDerivativeOps;
			}

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

Scope (from outer to inner):

file
function     bool CompileAndProcessD3DShaderDXC
lambda-function

Source code excerpt:

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

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

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

Scope (from outer to inner):

file
function     void FD3D12Adapter::InitializeDevices

Source code excerpt:

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

		StaticGraphicsRootSignature.InitStaticGraphicsRootSignature(GraphicsFlags);
		StaticGraphicsWithConstantsRootSignature.InitStaticGraphicsRootSignature(GraphicsFlags | ED3D12RootSignatureFlags::RootConstants);
		StaticComputeRootSignature.InitStaticComputeRootSignatureDesc(GraphicsFlags);
		StaticComputeWithConstantsRootSignature.InitStaticComputeRootSignatureDesc(GraphicsFlags | ED3D12RootSignatureFlags::RootConstants);

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

Scope (from outer to inner):

file
function     void FD3D12Adapter::InitializeDevices

Source code excerpt:

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

		StaticRayTracingGlobalRootSignature.InitStaticRayTracingGlobalRootSignatureDesc(RayTracingFlags);
		StaticRayTracingLocalRootSignature.InitStaticRayTracingLocalRootSignatureDesc(RayTracingFlags);
#endif
#endif // USE_STATIC_ROOT_SIGNATURE

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

Scope (from outer to inner):

file
function     FD3D12ResourceBinder

Source code excerpt:

#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
	void SetBindlessHandle(const FRHIDescriptorHandle& Handle, uint32 Offset)

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

Scope (from outer to inner):

file
function     bool UsesBindlessSamplers

Source code excerpt:

	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);
};

/** This represents a vertex shader that hasn't been combined with a specific declaration to create a bound shader. */

#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:20

Scope: file

Source code excerpt:

	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:208

Scope (from outer to inner):

file
namespace    D3D12ShaderUtils
function     void SetFlags

Source code excerpt:

			}

			if (EnumHasAnyFlags(InFlags, ED3D12RootSignatureFlags::BindlessSamplers))
			{
				AddRootFlag(D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED);
			}
		}

		bool HasFlags(ED3D12RootSignatureFlags InFlags) const

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

Scope (from outer to inner):

file
namespace    D3D12ShaderUtils
function     inline bool ShouldSkipType

Source code excerpt:

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

			return false;
		}
	};

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

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:766

Scope: file

Source code excerpt:

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

struct FShaderCodeFeatures