r.Vulkan.DynamicGlobalUBs

r.Vulkan.DynamicGlobalUBs

#Overview

name: r.Vulkan.DynamicGlobalUBs

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

It is referenced in 7 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of r.Vulkan.DynamicGlobalUBs is to control how uniform buffers are treated in the Vulkan rendering pipeline of Unreal Engine 5. It specifically determines whether uniform buffers should be handled as dynamic or regular buffers.

This setting variable is primarily used in the Vulkan RHI (Rendering Hardware Interface) subsystem of Unreal Engine 5. It affects how the engine manages uniform buffers when using the Vulkan graphics API.

The value of this variable is set through a console variable (CVar) system. It’s defined with default value 2, but can be changed at runtime or through configuration files.

The variable interacts closely with its associated variable GDynamicGlobalUBs, which is used throughout the code to actually implement the behavior defined by r.Vulkan.DynamicGlobalUBs.

Developers must be aware that this variable has three possible values:

The best practices when using this variable include:

  1. Understanding the performance implications of dynamic vs. regular uniform buffers in your specific use case.
  2. Being aware that changing this setting might affect the behavior of Vulkan bindless rendering.
  3. Considering the hardware limits (maxDescriptorSetUniformBuffersDynamic) when using dynamic uniform buffers.

Regarding the associated variable GDynamicGlobalUBs:

The purpose of GDynamicGlobalUBs is to implement the behavior defined by r.Vulkan.DynamicGlobalUBs within the engine’s C++ code.

It’s used in various parts of the Vulkan RHI implementation, including descriptor set management, pipeline state handling, and shader compilation.

The value of GDynamicGlobalUBs is set based on the r.Vulkan.DynamicGlobalUBs console variable.

This variable directly interacts with various Vulkan-specific classes and functions to determine how uniform buffers should be handled.

Developers should be aware that:

  1. Changes to r.Vulkan.DynamicGlobalUBs will be reflected in GDynamicGlobalUBs.
  2. The variable is used in performance-critical paths, so changing it can have significant performance implications.

Best practices include:

  1. Using GDynamicGlobalUBs consistently throughout the Vulkan RHI code when dealing with uniform buffer handling.
  2. Being cautious about changing its value at runtime, as it can affect ongoing rendering operations.

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp:14

Scope: file

Source code excerpt:


TAutoConsoleVariable<int32> GDynamicGlobalUBs(
	TEXT("r.Vulkan.DynamicGlobalUBs"),
	2,
	TEXT("2 to treat ALL uniform buffers as dynamic [default]\n")\
	TEXT("1 to treat global/packed uniform buffers as dynamic\n")\
	TEXT("0 to treat them as regular"),
	ECVF_ReadOnly | ECVF_RenderThreadSafe
);

#Associated Variable and Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/VulkanRHI/Private/VulkanDescriptorSets.cpp:259

Scope (from outer to inner):

file
function     bool FVulkanBindlessDescriptorManager::VerifySupport

Source code excerpt:

			if (bMeetsPropertiesRequirements)
			{
				extern TAutoConsoleVariable<int32> GDynamicGlobalUBs;
				if (GDynamicGlobalUBs->GetInt() != 0)
				{
					UE_LOG(LogRHI, Warning, TEXT("Dynamic Uniform Buffers are enabled, but they will not be used with Vulkan bindless."));
				}

				extern int32 GVulkanEnableDefrag;
				if (GVulkanEnableDefrag != 0)  // :todo-jn: to be turned back on with new defragger

#Loc: <Workspace>/Engine/Source/Runtime/VulkanRHI/Private/VulkanPipelineState.h:15

Scope: file

Source code excerpt:


class FVulkanComputePipeline;
extern TAutoConsoleVariable<int32> GDynamicGlobalUBs;


// Common Pipeline state
class FVulkanCommonPipelineDescriptorState : public VulkanRHI::FDeviceChild
{
public:

#Loc: <Workspace>/Engine/Source/Runtime/VulkanRHI/Private/VulkanPipelineState.h:191

Scope (from outer to inner):

file
class        class FVulkanComputePipelineDescriptorState : public FVulkanCommonPipelineDescriptorState
function     bool UpdateDescriptorSets

Source code excerpt:

		check(!bUseBindless);

		const bool bUseDynamicGlobalUBs = (GDynamicGlobalUBs->GetInt() > 0);
		if (bUseDynamicGlobalUBs)
		{
			return InternalUpdateDescriptorSets<true>(CmdListContext, CmdBuffer);
		}
		else
		{

#Loc: <Workspace>/Engine/Source/Runtime/VulkanRHI/Private/VulkanPipelineState.h:254

Scope (from outer to inner):

file
class        class FVulkanGraphicsPipelineDescriptorState : public FVulkanCommonPipelineDescriptorState
function     bool UpdateDescriptorSets

Source code excerpt:

		check(!bUseBindless);

		const bool bUseDynamicGlobalUBs = (GDynamicGlobalUBs->GetInt() > 0);
		if (bUseDynamicGlobalUBs)
		{
			return InternalUpdateDescriptorSets<true>(CmdListContext, CmdBuffer);
		}
		else
		{

#Loc: <Workspace>/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp:13

Scope: file

Source code excerpt:

#include "RHICoreShader.h"

TAutoConsoleVariable<int32> GDynamicGlobalUBs(
	TEXT("r.Vulkan.DynamicGlobalUBs"),
	2,
	TEXT("2 to treat ALL uniform buffers as dynamic [default]\n")\
	TEXT("1 to treat global/packed uniform buffers as dynamic\n")\
	TEXT("0 to treat them as regular"),
	ECVF_ReadOnly | ECVF_RenderThreadSafe

#Loc: <Workspace>/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp:847

Scope (from outer to inner):

file
function     void FVulkanDescriptorSetsLayoutInfo::FinalizeBindings

Source code excerpt:

	Binding.descriptorCount = 1;

	const bool bConvertAllUBsToDynamic = !Device.SupportsBindless() && (GDynamicGlobalUBs.GetValueOnAnyThread() > 1);
	const bool bConvertPackedUBsToDynamic = !Device.SupportsBindless() && (bConvertAllUBsToDynamic || (GDynamicGlobalUBs.GetValueOnAnyThread() == 1));
	const bool bConsolidateAllIntoOneSet = GDescriptorSetLayoutMode.GetValueOnAnyThread() == 2;
	const uint32 MaxDescriptorSetUniformBuffersDynamic = Device.GetLimits().maxDescriptorSetUniformBuffersDynamic;

	uint8	DescriptorStageToSetMapping[ShaderStage::NumStages];
	FMemory::Memset(DescriptorStageToSetMapping, UINT8_MAX);