2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2018-10-19 17:36:35 -04:00
/*=============================================================================
ShaderParameterMetadata.cpp: Shader parameter metadata implementations.
=============================================================================*/
# include "ShaderParameterMetadata.h"
# include "RenderCore.h"
2018-11-21 18:45:02 -05:00
# include "ShaderCore.h"
2020-11-02 21:40:25 -04:00
# include "ShaderParameterMetadataBuilder.h"
2018-10-19 17:36:35 -04:00
2020-01-24 18:07:01 -05:00
FUniformBufferStaticSlotRegistrar : : FUniformBufferStaticSlotRegistrar ( const TCHAR * InName )
{
FUniformBufferStaticSlotRegistry : : Get ( ) . RegisterSlot ( InName ) ;
}
FUniformBufferStaticSlotRegistry & FUniformBufferStaticSlotRegistry : : Get ( )
{
static FUniformBufferStaticSlotRegistry Registry ;
return Registry ;
}
void FUniformBufferStaticSlotRegistry : : RegisterSlot ( FName SlotName )
{
// Multiple definitions with the same name resolve to the same slot.
const FUniformBufferStaticSlot Slot = FindSlotByName ( SlotName ) ;
if ( ! IsUniformBufferStaticSlotValid ( Slot ) )
{
SlotNames . Emplace ( SlotName ) ;
}
}
2019-07-24 12:45:25 -04:00
# define VALIDATE_UNIFORM_BUFFER_UNIQUE_NAME (!UE_BUILD_SHIPPING && !UE_BUILD_TEST)
# if VALIDATE_UNIFORM_BUFFER_UNIQUE_NAME
static TMap < FName , FName > GlobalShaderVariableToStructMap ;
# endif
2018-10-19 17:36:35 -04:00
static TLinkedList < FShaderParametersMetadata * > * GUniformStructList = nullptr ;
2020-01-24 18:07:01 -05:00
static TMap < uint32 , FShaderParametersMetadata * > GLayoutHashStructMap ;
2018-10-19 17:36:35 -04:00
TLinkedList < FShaderParametersMetadata * > * & FShaderParametersMetadata : : GetStructList ( )
{
return GUniformStructList ;
}
2020-02-06 13:13:41 -05:00
TMap < FHashedName , FShaderParametersMetadata * > & FShaderParametersMetadata : : GetNameStructMap ( )
2018-10-19 17:36:35 -04:00
{
2020-02-06 13:13:41 -05:00
static TMap < FHashedName , FShaderParametersMetadata * > NameStructMap ;
2020-01-24 18:07:01 -05:00
return NameStructMap ;
2018-10-19 17:36:35 -04:00
}
2020-07-06 18:58:26 -04:00
void FShaderParametersMetadata : : FMember : : GenerateShaderParameterType ( FString & Result , EShaderPlatform ShaderPlatform ) const
{
switch ( GetBaseType ( ) )
{
case UBMT_INT32 : Result = TEXT ( " int " ) ; break ;
case UBMT_UINT32 : Result = TEXT ( " uint " ) ; break ;
case UBMT_FLOAT32 :
if ( GetPrecision ( ) = = EShaderPrecisionModifier : : Float | | ! SupportShaderPrecisionModifier ( ShaderPlatform ) )
{
Result = TEXT ( " float " ) ;
}
else if ( GetPrecision ( ) = = EShaderPrecisionModifier : : Half )
{
Result = TEXT ( " half " ) ;
}
else if ( GetPrecision ( ) = = EShaderPrecisionModifier : : Fixed )
{
Result = TEXT ( " fixed " ) ;
}
break ;
default :
UE_LOG ( LogShaders , Fatal , TEXT ( " Unrecognized uniform buffer struct member base type. " ) ) ;
} ;
// Generate the type dimensions for vectors and matrices.
if ( GetNumRows ( ) > 1 )
{
Result = FString : : Printf ( TEXT ( " %s%ux%u " ) , * Result , GetNumRows ( ) , GetNumColumns ( ) ) ;
}
else if ( GetNumColumns ( ) > 1 )
{
Result = FString : : Printf ( TEXT ( " %s%u " ) , * Result , GetNumColumns ( ) ) ;
}
}
2018-10-19 17:36:35 -04:00
FShaderParametersMetadata * FindUniformBufferStructByName ( const TCHAR * StructName )
{
2020-01-24 18:07:01 -05:00
return FindUniformBufferStructByFName ( FName ( StructName , FNAME_Find ) ) ;
2018-10-19 17:36:35 -04:00
}
FShaderParametersMetadata * FindUniformBufferStructByFName ( FName StructName )
{
return FShaderParametersMetadata : : GetNameStructMap ( ) . FindRef ( StructName ) ;
}
2020-01-24 18:07:01 -05:00
FShaderParametersMetadata * FindUniformBufferStructByLayoutHash ( uint32 Hash )
{
return GLayoutHashStructMap . FindRef ( Hash ) ;
}
2020-07-06 18:58:26 -04:00
const TCHAR * const kShaderParameterMacroNames [ ] = {
TEXT ( " " ) , // UBMT_INVALID,
// Invalid type when trying to use bool, to have explicit error message to programmer on why
// they shouldn't use bool in shader parameter structures.
TEXT ( " SHADER_PARAMETER " ) , // UBMT_BOOL,
// Parameter types.
TEXT ( " SHADER_PARAMETER " ) , // UBMT_INT32,
TEXT ( " SHADER_PARAMETER " ) , // UBMT_UINT32,
TEXT ( " SHADER_PARAMETER " ) , // UBMT_FLOAT32,
// RHI resources not tracked by render graph.
TEXT ( " SHADER_PARAMETER_TEXTURE " ) , // UBMT_TEXTURE,
TEXT ( " SHADER_PARAMETER_SRV " ) , // UBMT_SRV,
TEXT ( " SHADER_PARAMETER_UAV " ) , // UBMT_UAV,
TEXT ( " SHADER_PARAMETER_SAMPLER " ) , // UBMT_SAMPLER,
// Resources tracked by render graph.
TEXT ( " SHADER_PARAMETER_RDG_TEXTURE " ) , // UBMT_RDG_TEXTURE,
2020-09-24 00:43:27 -04:00
TEXT ( " SHADER_PARAMETER_RDG_TEXTURE_ACCESS " ) , // UBMT_RDG_TEXTURE_ACCESS,
2020-07-06 18:58:26 -04:00
TEXT ( " SHADER_PARAMETER_RDG_TEXTURE_SRV " ) , // UBMT_RDG_TEXTURE_SRV,
TEXT ( " SHADER_PARAMETER_RDG_TEXTURE_UAV " ) , // UBMT_RDG_TEXTURE_UAV,
TEXT ( " SHADER_PARAMETER_RDG_BUFFER " ) , // UBMT_RDG_BUFFER,
2020-09-24 00:43:27 -04:00
TEXT ( " SHADER_PARAMETER_RDG_BUFFER_ACCESS " ) , // UBMT_RDG_BUFFER_ACCESS,
2020-07-06 18:58:26 -04:00
TEXT ( " SHADER_PARAMETER_RDG_BUFFER_SRV " ) , // UBMT_RDG_BUFFER_SRV,
TEXT ( " SHADER_PARAMETER_RDG_BUFFER_UAV " ) , // UBMT_RDG_BUFFER_UAV,
2020-09-24 00:43:27 -04:00
TEXT ( " SHADER_PARAMETER_RDG_UNIFORM_BUFFER " ) , // UBMT_RDG_UNIFORM_BUFFER,
2020-07-06 18:58:26 -04:00
// Nested structure.
TEXT ( " SHADER_PARAMETER_STRUCT " ) , // UBMT_NESTED_STRUCT,
// Structure that is nested on C++ side, but included on shader side.
TEXT ( " SHADER_PARAMETER_STRUCT_INCLUDE " ) , // UBMT_INCLUDED_STRUCT,
// GPU Indirection reference of struct, like is currently named Uniform buffer.
TEXT ( " SHADER_PARAMETER_STRUCT_REF " ) , // UBMT_REFERENCED_STRUCT,
// Structure dedicated to setup render targets for a rasterizer pass.
TEXT ( " RENDER_TARGET_BINDING_SLOTS " ) , // UBMT_RENDER_TARGET_BINDING_SLOTS,
} ;
2020-09-24 00:43:27 -04:00
static_assert ( UE_ARRAY_COUNT ( kShaderParameterMacroNames ) = = int32 ( EUniformBufferBaseType_Num ) , " Shader parameter enum does not match name macro name array. " ) ;
2020-07-06 18:58:26 -04:00
/** Returns the name of the macro that should be used for a given shader parameter base type. */
const TCHAR * GetShaderParameterMacroName ( EUniformBufferBaseType ShaderParameterBaseType )
{
check ( ShaderParameterBaseType ! = UBMT_INVALID ) ;
return kShaderParameterMacroNames [ int32 ( ShaderParameterBaseType ) ] ;
}
EShaderCodeResourceBindingType ParseShaderResourceBindingType ( const TCHAR * ShaderType )
{
bool bIsRWResource = FCString : : Strncmp ( ShaderType , TEXT ( " RW " ) , 2 ) = = 0 ;
const TCHAR * ComparedShaderType = ShaderType + ( bIsRWResource ? 2 : 0 ) ;
int32 ShaderTypeLength = 0 ;
while ( TCHAR c = ComparedShaderType [ ShaderTypeLength ] )
{
if ( c = = ' ' | | c = = ' < ' )
break ;
ShaderTypeLength + + ;
}
EShaderCodeResourceBindingType BindingType = EShaderCodeResourceBindingType : : Invalid ;
if ( ! bIsRWResource & & ShaderTypeLength = = 12 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " SamplerState " ) , ShaderTypeLength ) = = 0 )
{
BindingType = EShaderCodeResourceBindingType : : SamplerState ;
}
else if ( ! bIsRWResource & & ShaderTypeLength = = 22 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " SamplerComparisonState " ) , ShaderTypeLength ) = = 0 )
{
BindingType = EShaderCodeResourceBindingType : : SamplerState ;
}
else if ( ShaderTypeLength = = 9 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " Texture2D " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWTexture2D : EShaderCodeResourceBindingType : : Texture2D ;
}
2020-11-10 15:35:31 -04:00
else if ( ShaderTypeLength = = 15 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " TextureExternal " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWTexture2D : EShaderCodeResourceBindingType : : Texture2D ;
}
2020-07-06 18:58:26 -04:00
else if ( ShaderTypeLength = = 14 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " Texture2DArray " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWTexture2DArray : EShaderCodeResourceBindingType : : Texture2DArray ;
}
else if ( ! bIsRWResource & & ShaderTypeLength = = 11 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " Texture2DMS " ) , ShaderTypeLength ) = = 0 )
{
BindingType = EShaderCodeResourceBindingType : : Texture2DMS ;
}
else if ( ShaderTypeLength = = 9 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " Texture3D " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWTexture3D : EShaderCodeResourceBindingType : : Texture3D ;
}
else if ( ShaderTypeLength = = 11 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " TextureCube " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWTextureCube : EShaderCodeResourceBindingType : : TextureCube ;
}
else if ( ! bIsRWResource & & ShaderTypeLength = = 16 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " TextureCubeArray " ) , ShaderTypeLength ) = = 0 )
{
BindingType = EShaderCodeResourceBindingType : : TextureCubeArray ;
}
else if ( ShaderTypeLength = = 15 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " TextureMetadata " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWTextureMetadata : EShaderCodeResourceBindingType : : TextureMetadata ;
}
else if ( ShaderTypeLength = = 6 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " Buffer " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWBuffer : EShaderCodeResourceBindingType : : Buffer ;
}
else if ( ShaderTypeLength = = 16 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " StructuredBuffer " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWStructuredBuffer : EShaderCodeResourceBindingType : : StructuredBuffer ;
}
else if ( ShaderTypeLength = = 17 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " ByteAddressBuffer " ) , ShaderTypeLength ) = = 0 )
{
BindingType = bIsRWResource ? EShaderCodeResourceBindingType : : RWByteAddressBuffer : EShaderCodeResourceBindingType : : ByteAddressBuffer ;
}
else if ( ! bIsRWResource & & ShaderTypeLength = = 31 & & FCString : : Strncmp ( ComparedShaderType , TEXT ( " RaytracingAccelerationStructure " ) , ShaderTypeLength ) = = 0 )
{
BindingType = EShaderCodeResourceBindingType : : RaytracingAccelerationStructure ;
}
return BindingType ;
}
const TCHAR * const kShaderCodeResourceBindingTypeNames [ ] = {
TEXT ( " Invalid " ) ,
TEXT ( " SamplerState " ) ,
TEXT ( " Texture2D " ) ,
TEXT ( " Texture2DArray " ) ,
TEXT ( " Texture2DMS " ) ,
TEXT ( " Texture3D " ) ,
TEXT ( " TextureCube " ) ,
TEXT ( " TextureCubeArray " ) ,
TEXT ( " TextureMetadata " ) ,
TEXT ( " Buffer " ) ,
TEXT ( " StructuredBuffer " ) ,
TEXT ( " ByteAddressBuffer " ) ,
TEXT ( " RaytracingAccelerationStructure " ) ,
TEXT ( " RWTexture2D " ) ,
TEXT ( " RWTexture2DArray " ) ,
TEXT ( " RWTexture3D " ) ,
TEXT ( " RWTextureCube " ) ,
TEXT ( " RWTextureMetadata " ) ,
TEXT ( " RWBuffer " ) ,
TEXT ( " RWStructuredBuffer " ) ,
TEXT ( " RWByteAddressBuffer " ) ,
} ;
static_assert ( UE_ARRAY_COUNT ( kShaderCodeResourceBindingTypeNames ) = = int32 ( EShaderCodeResourceBindingType : : MAX ) , " TODO. " ) ;
const TCHAR * GetShaderCodeResourceBindingTypeName ( EShaderCodeResourceBindingType BindingType )
{
check ( BindingType ! = EShaderCodeResourceBindingType : : Invalid ) ;
check ( int32 ( BindingType ) < int32 ( EShaderCodeResourceBindingType : : MAX ) ) ;
return kShaderCodeResourceBindingTypeNames [ int32 ( BindingType ) ] ;
}
2018-10-19 17:36:35 -04:00
class FUniformBufferMemberAndOffset
{
public :
FUniformBufferMemberAndOffset ( const FShaderParametersMetadata & InContainingStruct , const FShaderParametersMetadata : : FMember & InMember , int32 InStructOffset ) :
ContainingStruct ( InContainingStruct ) ,
Member ( InMember ) ,
StructOffset ( InStructOffset )
{ }
const FShaderParametersMetadata & ContainingStruct ;
const FShaderParametersMetadata : : FMember & Member ;
int32 StructOffset ;
} ;
FShaderParametersMetadata : : FShaderParametersMetadata (
EUseCase InUseCase ,
2020-12-07 17:42:32 -04:00
EUniformBufferBindingFlags InBindingFlags ,
2020-02-06 13:13:41 -05:00
const TCHAR * InLayoutName ,
2018-10-19 17:36:35 -04:00
const TCHAR * InStructTypeName ,
const TCHAR * InShaderVariableName ,
2020-01-24 18:07:01 -05:00
const TCHAR * InStaticSlotName ,
2020-07-06 18:58:26 -04:00
const ANSICHAR * InFileName ,
const int32 InFileLine ,
2018-10-19 17:36:35 -04:00
uint32 InSize ,
const TArray < FMember > & InMembers )
: StructTypeName ( InStructTypeName )
, ShaderVariableName ( InShaderVariableName )
2020-01-24 18:07:01 -05:00
, StaticSlotName ( InStaticSlotName )
2020-02-06 13:13:41 -05:00
, ShaderVariableHashedName ( InShaderVariableName )
2020-07-06 18:58:26 -04:00
, FileName ( InFileName )
, FileLine ( InFileLine )
2018-10-19 17:36:35 -04:00
, Size ( InSize )
, UseCase ( InUseCase )
2020-12-07 17:42:32 -04:00
, BindingFlags ( InBindingFlags )
2018-10-19 17:36:35 -04:00
, Layout ( InLayoutName )
, Members ( InMembers )
, GlobalListLink ( this )
, bLayoutInitialized ( false )
{
2020-12-07 17:42:32 -04:00
checkf ( UseCase = = EUseCase : : UniformBuffer | | ! EnumHasAnyFlags ( BindingFlags , EUniformBufferBindingFlags : : Static ) , TEXT ( " Only uniform buffers can utilize the global binding flag. " ) ) ;
2018-10-23 19:08:17 -04:00
check ( StructTypeName ) ;
if ( UseCase = = EUseCase : : ShaderParameterStruct )
{
2020-01-24 18:07:01 -05:00
checkf ( ! StaticSlotName , TEXT ( " Only uniform buffers can be tagged with a static slot. " ) ) ;
2018-10-23 19:08:17 -04:00
check ( ShaderVariableName = = nullptr ) ;
}
else
{
check ( ShaderVariableName ) ;
}
2020-01-24 18:07:01 -05:00
if ( UseCase = = EUseCase : : UniformBuffer )
2018-10-19 17:36:35 -04:00
{
// Register this uniform buffer struct in global list.
GlobalListLink . LinkHead ( GetStructList ( ) ) ;
FName StructTypeFName ( StructTypeName ) ;
// Verify that during FName creation there's no case conversion
checkSlow ( FCString : : Strcmp ( StructTypeName , * StructTypeFName . GetPlainNameString ( ) ) = = 0 ) ;
2020-02-06 13:13:41 -05:00
GetNameStructMap ( ) . Add ( ShaderVariableHashedName , this ) ;
2019-07-24 12:45:25 -04:00
# if VALIDATE_UNIFORM_BUFFER_UNIQUE_NAME
FName ShaderVariableFName ( ShaderVariableName ) ;
// Verify that the global variable name is unique so that we can disambiguate when reflecting from shader source.
if ( FName * StructFName = GlobalShaderVariableToStructMap . Find ( ShaderVariableFName ) )
{
checkf (
false ,
TEXT ( " Found duplicate Uniform Buffer shader variable name %s defined by struct %s. Previous definition " )
TEXT ( " found on struct %s. Uniform buffer shader names must be unique to support name-based reflection of " )
TEXT ( " shader source files. " ) ,
ShaderVariableName ,
StructTypeName ,
* StructFName - > GetPlainNameString ( ) ) ;
}
GlobalShaderVariableToStructMap . Add ( ShaderVariableFName , StructTypeFName ) ;
# endif
2018-10-19 17:36:35 -04:00
}
else
{
// We cannot initialize the layout during global initialization, since we have to walk nested struct members.
// Structs created during global initialization will have bRegisterForAutoBinding==false, and are initialized during startup.
// Structs created at runtime with bRegisterForAutoBinding==true can be initialized now.
InitializeLayout ( ) ;
}
}
2019-07-24 12:45:25 -04:00
FShaderParametersMetadata : : ~ FShaderParametersMetadata ( )
{
2020-01-24 18:07:01 -05:00
if ( UseCase = = EUseCase : : UniformBuffer )
2019-07-24 12:45:25 -04:00
{
GlobalListLink . Unlink ( ) ;
2020-02-06 13:13:41 -05:00
GetNameStructMap ( ) . Remove ( ShaderVariableHashedName ) ;
2019-07-24 12:45:25 -04:00
# if VALIDATE_UNIFORM_BUFFER_UNIQUE_NAME
GlobalShaderVariableToStructMap . Remove ( FName ( ShaderVariableName , FNAME_Find ) ) ;
# endif
2020-01-24 18:07:01 -05:00
if ( bLayoutInitialized )
{
GLayoutHashStructMap . Remove ( GetLayout ( ) . GetHash ( ) ) ;
}
2019-07-24 12:45:25 -04:00
}
}
2020-01-24 18:07:01 -05:00
void FShaderParametersMetadata : : InitializeAllUniformBufferStructs ( )
2018-10-19 17:36:35 -04:00
{
for ( TLinkedList < FShaderParametersMetadata * > : : TIterator StructIt ( FShaderParametersMetadata : : GetStructList ( ) ) ; StructIt ; StructIt . Next ( ) )
{
2019-11-14 19:25:20 -05:00
if ( ! StructIt - > bLayoutInitialized )
{
StructIt - > InitializeLayout ( ) ;
}
2018-10-19 17:36:35 -04:00
}
}
void FShaderParametersMetadata : : InitializeLayout ( )
{
check ( ! bLayoutInitialized ) ;
Layout . ConstantBufferSize = Size ;
2020-01-24 18:07:01 -05:00
if ( StaticSlotName )
{
2020-12-07 17:42:32 -04:00
checkf ( EnumHasAnyFlags ( BindingFlags , EUniformBufferBindingFlags : : Static ) , TEXT ( " Uniform buffer of type '%s' and shader name '%s' attempted to reference static slot '%s', but the binding model does not contain 'Global'. " ) ,
StructTypeName , ShaderVariableName , StaticSlotName ) ;
2020-01-24 18:07:01 -05:00
checkf ( UseCase = = EUseCase : : UniformBuffer ,
TEXT ( " Attempted to assign static slot %s to uniform buffer %s. Static slots are only supported for compile-time uniform buffers. " ) ,
ShaderVariableName , StaticSlotName ) ;
const FUniformBufferStaticSlot StaticSlot = FUniformBufferStaticSlotRegistry : : Get ( ) . FindSlotByName ( StaticSlotName ) ;
checkf ( IsUniformBufferStaticSlotValid ( StaticSlot ) ,
TEXT ( " Uniform buffer of type '%s' and shader name '%s' attempted to reference static slot '%s', but the slot could not be found in the registry. " ) ,
StructTypeName , ShaderVariableName , StaticSlotName ) ;
Layout . StaticSlot = StaticSlot ;
2020-12-07 17:42:32 -04:00
Layout . BindingFlags = BindingFlags ;
}
else
{
checkf ( ! EnumHasAnyFlags ( BindingFlags , EUniformBufferBindingFlags : : Static ) , TEXT ( " Uniform buffer of type '%s' and shader name '%s' has no binding slot specified, but the binding model specifies 'Global'. " ) ,
StructTypeName , ShaderVariableName , StaticSlotName ) ;
2020-01-24 18:07:01 -05:00
}
2018-10-19 17:36:35 -04:00
TArray < FUniformBufferMemberAndOffset > MemberStack ;
MemberStack . Reserve ( Members . Num ( ) ) ;
for ( int32 MemberIndex = 0 ; MemberIndex < Members . Num ( ) ; MemberIndex + + )
{
MemberStack . Push ( FUniformBufferMemberAndOffset ( * this , Members [ MemberIndex ] , 0 ) ) ;
}
2018-12-18 21:41:17 -05:00
/** Uniform buffer references are only allowed in shader parameter structures that may be used as a root shader parameter
* structure.
*/
2020-01-24 18:07:01 -05:00
const bool bAllowUniformBufferReferences = UseCase = = EUseCase : : ShaderParameterStruct ;
2018-12-18 21:41:17 -05:00
2019-03-07 11:25:32 -05:00
/** Resource array are currently only supported for shader parameter structures. */
2020-01-24 18:07:01 -05:00
const bool bAllowResourceArrays = UseCase = = EUseCase : : ShaderParameterStruct ;
2019-03-07 11:25:32 -05:00
2018-12-18 21:41:17 -05:00
/** White list all use cases that inline a structure within another. Data driven are not known to inline structures. */
2020-01-24 18:07:01 -05:00
const bool bAllowStructureInlining = UseCase = = EUseCase : : ShaderParameterStruct | | UseCase = = EUseCase : : UniformBuffer ;
2018-12-18 21:41:17 -05:00
2018-10-19 17:36:35 -04:00
for ( int32 i = 0 ; i < MemberStack . Num ( ) ; + + i )
{
const FShaderParametersMetadata & CurrentStruct = MemberStack [ i ] . ContainingStruct ;
const FMember & CurrentMember = MemberStack [ i ] . Member ;
2019-03-07 11:25:32 -05:00
EUniformBufferBaseType BaseType = CurrentMember . GetBaseType ( ) ;
const uint32 ArraySize = CurrentMember . GetNumElements ( ) ;
2019-03-06 23:59:18 -05:00
const FShaderParametersMetadata * ChildStruct = CurrentMember . GetStructMetadata ( ) ;
2020-07-06 18:58:26 -04:00
const TCHAR * ShaderType = CurrentMember . GetShaderType ( ) ;
2019-03-06 23:42:45 -05:00
2019-03-07 11:25:32 -05:00
const bool bIsArray = ArraySize > 0 ;
const bool bIsRHIResource = (
BaseType = = UBMT_TEXTURE | |
BaseType = = UBMT_SRV | |
BaseType = = UBMT_SAMPLER ) ;
const bool bIsRDGResource = IsRDGResourceReferenceShaderParameterType ( BaseType ) ;
const bool bIsVariableNativeType = (
BaseType = = UBMT_INT32 | |
BaseType = = UBMT_UINT32 | |
BaseType = = UBMT_FLOAT32 ) ;
2018-10-19 17:36:35 -04:00
if ( DO_CHECK )
{
2020-07-06 18:58:26 -04:00
auto GetMemberErrorPrefix = [ & ] ( )
{
return FString : : Printf (
TEXT ( " %s(%i): Shader parameter %s::%s error: \n " ) ,
ANSI_TO_TCHAR ( CurrentStruct . GetFileName ( ) ) ,
CurrentMember . GetFileLine ( ) ,
CurrentStruct . GetStructTypeName ( ) ,
CurrentMember . GetName ( ) ) ;
} ;
2018-10-19 17:36:35 -04:00
2019-10-01 13:03:04 -04:00
if ( BaseType = = UBMT_BOOL )
{
UE_LOG ( LogRendererCore , Fatal ,
2020-07-06 18:58:26 -04:00
TEXT ( " %sbool are actually illegal in shader parameter structure, " )
2019-10-01 13:03:04 -04:00
TEXT ( " because bool type in HLSL means using scalar register to store binary information. " )
TEXT ( " Boolean information should always be packed explicitly in bitfield to reduce memory footprint, " )
2020-07-06 18:58:26 -04:00
TEXT ( " and use HLSL comparison operators to translate into clean SGPR, to have minimal VGPR footprint. " ) , * GetMemberErrorPrefix ( ) ) ;
2019-10-01 13:03:04 -04:00
}
2020-09-24 00:43:27 -04:00
if ( BaseType = = UBMT_REFERENCED_STRUCT | | BaseType = = UBMT_RDG_UNIFORM_BUFFER )
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
check ( ChildStruct ) ;
2018-12-18 21:41:17 -05:00
if ( ! bAllowUniformBufferReferences )
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
UE_LOG ( LogRendererCore , Fatal , TEXT ( " %sShader parameter struct reference can only be done in shader parameter structs. " ) , * GetMemberErrorPrefix ( ) ) ;
2018-10-19 17:36:35 -04:00
}
}
2018-12-18 21:41:17 -05:00
else if ( BaseType = = UBMT_NESTED_STRUCT | | BaseType = = UBMT_INCLUDED_STRUCT )
2018-10-22 14:48:33 -04:00
{
check ( ChildStruct ) ;
2018-12-18 21:41:17 -05:00
if ( ! bAllowStructureInlining )
{
2020-07-06 18:58:26 -04:00
UE_LOG ( LogRendererCore , Fatal , TEXT ( " %sShader parameter struct is not known inline other structures. " ) , * GetMemberErrorPrefix ( ) ) ;
2018-12-18 21:41:17 -05:00
}
else if ( ChildStruct - > GetUseCase ( ) ! = EUseCase : : ShaderParameterStruct & & UseCase = = EUseCase : : ShaderParameterStruct )
{
2020-07-06 18:58:26 -04:00
UE_LOG ( LogRendererCore , Fatal , TEXT ( " %sCan only nests or include shader parameter struct define with BEGIN_SHADER_PARAMETER_STRUCT(), but %s is not. " ) , * GetMemberErrorPrefix ( ) , ChildStruct - > GetStructTypeName ( ) ) ;
2018-12-18 21:41:17 -05:00
}
2018-10-19 17:36:35 -04:00
}
2019-03-07 11:25:32 -05:00
2020-09-24 00:43:27 -04:00
if ( UseCase ! = EUseCase : : ShaderParameterStruct & & IsShaderParameterTypeIgnoredByRHI ( BaseType ) )
{
UE_LOG ( LogRendererCore , Fatal , TEXT ( " Shader parameter %s is not allowed in a uniform buffer. " ) , * GetMemberErrorPrefix ( ) ) ;
}
2019-06-11 18:27:07 -04:00
const bool bTypeCanBeArray = ( bAllowResourceArrays & & ( bIsRHIResource | | bIsRDGResource ) ) | | bIsVariableNativeType | | BaseType = = UBMT_NESTED_STRUCT ;
2019-03-07 11:25:32 -05:00
if ( bIsArray & & ! bTypeCanBeArray )
{
2020-07-06 18:58:26 -04:00
UE_LOG ( LogRendererCore , Fatal , TEXT ( " %sNot allowed to be an array. " ) , * GetMemberErrorPrefix ( ) ) ;
}
// Validate the shader binding type.
2020-09-24 00:43:27 -04:00
if ( bIsRHIResource | | ( bIsRDGResource & & ( BaseType ! = UBMT_RDG_BUFFER & & BaseType ! = UBMT_RDG_TEXTURE_ACCESS & & BaseType ! = UBMT_RDG_BUFFER_ACCESS & & BaseType ! = UBMT_RDG_UNIFORM_BUFFER ) ) )
2020-07-06 18:58:26 -04:00
{
EShaderCodeResourceBindingType BindingType = ParseShaderResourceBindingType ( ShaderType ) ;
if ( BindingType = = EShaderCodeResourceBindingType : : Invalid )
{
UE_LOG ( LogRendererCore , Warning , TEXT ( " %sUnknown shader parameter type %s. " ) , * GetMemberErrorPrefix ( ) , ShaderType ) ;
}
bool bIsValidBindingType = false ;
if ( BindingType = = EShaderCodeResourceBindingType : : SamplerState )
{
bIsValidBindingType = ( BaseType = = UBMT_SAMPLER ) ;
}
else if (
BindingType = = EShaderCodeResourceBindingType : : Texture2D | |
BindingType = = EShaderCodeResourceBindingType : : Texture2DArray | |
BindingType = = EShaderCodeResourceBindingType : : Texture2DMS | |
BindingType = = EShaderCodeResourceBindingType : : Texture3D | |
BindingType = = EShaderCodeResourceBindingType : : TextureCube | |
BindingType = = EShaderCodeResourceBindingType : : TextureCubeArray )
{
bIsValidBindingType = (
BaseType = = UBMT_TEXTURE | |
BaseType = = UBMT_SRV | |
BaseType = = UBMT_RDG_TEXTURE | |
BaseType = = UBMT_RDG_TEXTURE_SRV ) ;
}
else if ( BindingType = = EShaderCodeResourceBindingType : : TextureMetadata )
{
bIsValidBindingType = (
BaseType = = UBMT_SRV | |
BaseType = = UBMT_RDG_TEXTURE_SRV ) ;
}
else if (
BindingType = = EShaderCodeResourceBindingType : : Buffer | |
BindingType = = EShaderCodeResourceBindingType : : StructuredBuffer | |
BindingType = = EShaderCodeResourceBindingType : : ByteAddressBuffer )
{
bIsValidBindingType = (
BaseType = = UBMT_SRV | |
BaseType = = UBMT_RDG_BUFFER_SRV ) ;
}
else if ( BindingType = = EShaderCodeResourceBindingType : : RaytracingAccelerationStructure )
{
bIsValidBindingType = (
BaseType = = UBMT_SRV | |
BaseType = = UBMT_RDG_BUFFER_SRV ) ;
}
else if (
BindingType = = EShaderCodeResourceBindingType : : RWTexture2D | |
BindingType = = EShaderCodeResourceBindingType : : RWTexture2DArray | |
BindingType = = EShaderCodeResourceBindingType : : RWTexture3D | |
BindingType = = EShaderCodeResourceBindingType : : RWTextureCube | |
BindingType = = EShaderCodeResourceBindingType : : RWTextureMetadata )
{
bIsValidBindingType = (
BaseType = = UBMT_UAV | |
BaseType = = UBMT_RDG_TEXTURE_UAV ) ;
}
else if (
BindingType = = EShaderCodeResourceBindingType : : RWBuffer | |
BindingType = = EShaderCodeResourceBindingType : : RWStructuredBuffer | |
BindingType = = EShaderCodeResourceBindingType : : RWByteAddressBuffer )
{
bIsValidBindingType = (
BaseType = = UBMT_UAV | |
BaseType = = UBMT_RDG_BUFFER_UAV ) ;
}
else
{
//unimplemented();
}
if ( ! bIsValidBindingType )
{
const TCHAR * CurrentMacroName = GetShaderParameterMacroName ( BaseType ) ;
UE_LOG (
LogRendererCore , Warning ,
TEXT ( " %sUnable to bind a shader parameter type %s with a %s. " ) ,
* GetMemberErrorPrefix ( ) , ShaderType , CurrentMacroName ) ;
}
2019-03-07 11:25:32 -05:00
}
2018-10-19 17:36:35 -04:00
}
2018-12-18 21:41:17 -05:00
if ( IsShaderParameterTypeForUniformBufferLayout ( BaseType ) )
2018-10-19 17:36:35 -04:00
{
2019-03-07 11:25:32 -05:00
for ( uint32 ArrayElementId = 0 ; ArrayElementId < ( bIsArray ? ArraySize : 1u ) ; ArrayElementId + + )
{
const uint32 AbsoluteMemberOffset = CurrentMember . GetOffset ( ) + MemberStack [ i ] . StructOffset + ArrayElementId * SHADER_PARAMETER_POINTER_ALIGNMENT ;
check ( AbsoluteMemberOffset < ( 1u < < ( sizeof ( FRHIUniformBufferLayout : : FResourceParameter : : MemberOffset ) * 8 ) ) ) ;
2020-07-06 18:58:26 -04:00
const FRHIUniformBufferLayout : : FResourceParameter ResourceParameter { uint16 ( AbsoluteMemberOffset ) , BaseType } ;
Layout . Resources . Add ( ResourceParameter ) ;
if ( IsRDGTextureReferenceShaderParameterType ( BaseType ) | | BaseType = = UBMT_RENDER_TARGET_BINDING_SLOTS )
{
Layout . GraphResources . Add ( ResourceParameter ) ;
Layout . GraphTextures . Add ( ResourceParameter ) ;
if ( BaseType = = UBMT_RENDER_TARGET_BINDING_SLOTS )
{
checkf ( ! Layout . HasRenderTargets ( ) , TEXT ( " Shader parameter struct %s has multiple render target binding slots. " ) , GetStructTypeName ( ) ) ;
Layout . RenderTargetsOffset = ResourceParameter . MemberOffset ;
}
}
else if ( IsRDGBufferReferenceShaderParameterType ( BaseType ) )
{
Layout . GraphResources . Add ( ResourceParameter ) ;
Layout . GraphBuffers . Add ( ResourceParameter ) ;
}
2020-09-24 00:43:27 -04:00
else if ( BaseType = = UBMT_RDG_UNIFORM_BUFFER )
{
Layout . GraphResources . Add ( ResourceParameter ) ;
Layout . GraphUniformBuffers . Add ( ResourceParameter ) ;
}
else if ( BaseType = = UBMT_REFERENCED_STRUCT )
{
Layout . UniformBuffers . Add ( ResourceParameter ) ;
}
2020-07-06 18:58:26 -04:00
}
}
if ( BaseType = = UBMT_UAV )
{
Layout . bHasNonGraphOutputs = true ;
}
2020-09-24 00:43:27 -04:00
else if ( BaseType = = UBMT_REFERENCED_STRUCT | | BaseType = = UBMT_RDG_UNIFORM_BUFFER )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( ChildStruct )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
for ( const FShaderParametersMetadata : : FMember & Member : ChildStruct - > GetMembers ( ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( Member . GetBaseType ( ) = = UBMT_UAV )
{
Layout . bHasNonGraphOutputs = true ;
}
2020-07-06 18:58:26 -04:00
}
2019-03-07 11:25:32 -05:00
}
2018-10-19 17:36:35 -04:00
}
2020-09-24 00:43:27 -04:00
if ( ChildStruct & & BaseType ! = UBMT_REFERENCED_STRUCT & & BaseType ! = UBMT_RDG_UNIFORM_BUFFER )
2018-10-19 17:36:35 -04:00
{
2019-06-11 18:27:07 -04:00
for ( uint32 ArrayElementId = 0 ; ArrayElementId < ( bIsArray ? ArraySize : 1u ) ; ArrayElementId + + )
2018-10-19 17:36:35 -04:00
{
2019-06-11 18:27:07 -04:00
int32 AbsoluteStructOffset = CurrentMember . GetOffset ( ) + MemberStack [ i ] . StructOffset + ArrayElementId * ChildStruct - > GetSize ( ) ;
for ( int32 StructMemberIndex = 0 ; StructMemberIndex < ChildStruct - > Members . Num ( ) ; StructMemberIndex + + )
{
const FMember & StructMember = ChildStruct - > Members [ StructMemberIndex ] ;
MemberStack . Insert ( FUniformBufferMemberAndOffset ( * ChildStruct , StructMember , AbsoluteStructOffset ) , i + 1 + StructMemberIndex ) ;
}
2018-10-19 17:36:35 -04:00
}
}
2020-09-24 00:43:27 -04:00
}
2018-10-19 17:36:35 -04:00
2020-07-06 18:58:26 -04:00
const auto ByMemberOffset = [ ] (
const FRHIUniformBufferLayout : : FResourceParameter & A ,
const FRHIUniformBufferLayout : : FResourceParameter & B )
{
return A . MemberOffset < B . MemberOffset ;
} ;
const auto ByTypeThenMemberOffset = [ ] (
2018-12-18 21:41:17 -05:00
const FRHIUniformBufferLayout : : FResourceParameter & A ,
const FRHIUniformBufferLayout : : FResourceParameter & B )
{
if ( A . MemberType = = B . MemberType )
{
return A . MemberOffset < B . MemberOffset ;
}
return A . MemberType < B . MemberType ;
2020-07-06 18:58:26 -04:00
} ;
Layout . Resources . Sort ( ByMemberOffset ) ;
Layout . GraphResources . Sort ( ByMemberOffset ) ;
Layout . GraphTextures . Sort ( ByTypeThenMemberOffset ) ;
Layout . GraphBuffers . Sort ( ByTypeThenMemberOffset ) ;
2020-09-24 00:43:27 -04:00
Layout . GraphUniformBuffers . Sort ( ByMemberOffset ) ;
Layout . UniformBuffers . Sort ( ByMemberOffset ) ;
2018-12-18 21:41:17 -05:00
2020-09-24 00:43:27 -04:00
// Compute the hash of the RHI layout.
2018-10-19 17:36:35 -04:00
Layout . ComputeHash ( ) ;
2019-11-14 19:25:20 -05:00
// Compute the hash about the entire layout of the structure.
{
uint32 RootStructureHash = 0 ;
RootStructureHash = HashCombine ( RootStructureHash , GetTypeHash ( int32 ( GetSize ( ) ) ) ) ;
2018-10-19 17:36:35 -04:00
2019-11-14 19:25:20 -05:00
for ( const FMember & CurrentMember : Members )
{
EUniformBufferBaseType BaseType = CurrentMember . GetBaseType ( ) ;
const FShaderParametersMetadata * ChildStruct = CurrentMember . GetStructMetadata ( ) ;
uint32 MemberHash = 0 ;
MemberHash = HashCombine ( MemberHash , GetTypeHash ( int32 ( CurrentMember . GetOffset ( ) ) ) ) ;
MemberHash = HashCombine ( MemberHash , GetTypeHash ( uint8 ( BaseType ) ) ) ;
static_assert ( EUniformBufferBaseType_NumBits < = 8 , " Invalid EUniformBufferBaseType_NumBits " ) ;
MemberHash = HashCombine ( MemberHash , GetTypeHash ( CurrentMember . GetName ( ) ) ) ;
MemberHash = HashCombine ( MemberHash , GetTypeHash ( int32 ( CurrentMember . GetNumElements ( ) ) ) ) ;
2020-07-06 18:58:26 -04:00
const bool bIsRHIResource = (
BaseType = = UBMT_TEXTURE | |
BaseType = = UBMT_SRV | |
BaseType = = UBMT_SAMPLER ) ;
const bool bIsRDGResource = IsRDGResourceReferenceShaderParameterType ( BaseType ) ;
2019-11-14 19:25:20 -05:00
if ( BaseType = = UBMT_INT32 | |
BaseType = = UBMT_UINT32 | |
BaseType = = UBMT_FLOAT32 )
{
MemberHash = HashCombine ( MemberHash , GetTypeHash ( uint8 ( CurrentMember . GetNumRows ( ) ) ) ) ;
MemberHash = HashCombine ( MemberHash , GetTypeHash ( uint8 ( CurrentMember . GetNumColumns ( ) ) ) ) ;
}
else if ( BaseType = = UBMT_INCLUDED_STRUCT | | BaseType = = UBMT_NESTED_STRUCT )
{
if ( ! ChildStruct - > bLayoutInitialized )
{
const_cast < FShaderParametersMetadata * > ( ChildStruct ) - > InitializeLayout ( ) ;
}
MemberHash = HashCombine ( MemberHash , ChildStruct - > GetLayoutHash ( ) ) ;
}
2020-07-06 18:58:26 -04:00
else if ( bIsRHIResource | | bIsRDGResource )
{
MemberHash = HashCombine ( MemberHash , GetTypeHash ( CurrentMember . GetShaderType ( ) ) ) ;
}
2019-11-14 19:25:20 -05:00
RootStructureHash = HashCombine ( RootStructureHash , MemberHash ) ;
}
LayoutHash = RootStructureHash ;
}
2020-01-24 18:07:01 -05:00
if ( UseCase = = EUseCase : : UniformBuffer )
{
GLayoutHashStructMap . Emplace ( Layout . GetHash ( ) , this ) ;
}
2018-10-19 17:36:35 -04:00
bLayoutInitialized = true ;
}
void FShaderParametersMetadata : : GetNestedStructs ( TArray < const FShaderParametersMetadata * > & OutNestedStructs ) const
{
for ( int32 i = 0 ; i < Members . Num ( ) ; + + i )
{
const FMember & CurrentMember = Members [ i ] ;
const FShaderParametersMetadata * MemberStruct = CurrentMember . GetStructMetadata ( ) ;
if ( MemberStruct )
{
OutNestedStructs . Add ( MemberStruct ) ;
MemberStruct - > GetNestedStructs ( OutNestedStructs ) ;
}
}
}
2020-12-07 17:42:32 -04:00
void FShaderParametersMetadata : : AddResourceTableEntries ( TMap < FString , FResourceTableEntry > & ResourceTableMap , TMap < FString , FUniformBufferEntry > & UniformBufferMap ) const
2018-10-19 17:36:35 -04:00
{
uint16 ResourceIndex = 0 ;
FString Prefix = FString : : Printf ( TEXT ( " %s_ " ) , ShaderVariableName ) ;
AddResourceTableEntriesRecursive ( ShaderVariableName , * Prefix , ResourceIndex , ResourceTableMap ) ;
2020-12-07 17:42:32 -04:00
FUniformBufferEntry UniformBufferEntry ;
UniformBufferEntry . StaticSlotName = StaticSlotName ;
UniformBufferEntry . LayoutHash = Layout . GetHash ( ) ;
UniformBufferEntry . BindingFlags = BindingFlags ;
UniformBufferMap . Add ( ShaderVariableName , UniformBufferEntry ) ;
2018-10-19 17:36:35 -04:00
}
void FShaderParametersMetadata : : AddResourceTableEntriesRecursive ( const TCHAR * UniformBufferName , const TCHAR * Prefix , uint16 & ResourceIndex , TMap < FString , FResourceTableEntry > & ResourceTableMap ) const
{
for ( int32 MemberIndex = 0 ; MemberIndex < Members . Num ( ) ; + + MemberIndex )
{
const FMember & Member = Members [ MemberIndex ] ;
2019-06-11 18:27:07 -04:00
uint32 NumElements = Member . GetNumElements ( ) ;
2018-12-18 21:41:17 -05:00
if ( IsShaderParameterTypeForUniformBufferLayout ( Member . GetBaseType ( ) ) )
2018-10-19 17:36:35 -04:00
{
FResourceTableEntry & Entry = ResourceTableMap . FindOrAdd ( FString : : Printf ( TEXT ( " %s%s " ) , Prefix , Member . GetName ( ) ) ) ;
if ( Entry . UniformBufferName . IsEmpty ( ) )
{
Entry . UniformBufferName = UniformBufferName ;
Entry . Type = Member . GetBaseType ( ) ;
Entry . ResourceIndex = ResourceIndex + + ;
}
}
2019-06-11 18:27:07 -04:00
else if ( Member . GetBaseType ( ) = = UBMT_NESTED_STRUCT & & NumElements = = 0 )
2018-10-19 17:36:35 -04:00
{
check ( Member . GetStructMetadata ( ) ) ;
FString MemberPrefix = FString : : Printf ( TEXT ( " %s%s_ " ) , Prefix , Member . GetName ( ) ) ;
Member . GetStructMetadata ( ) - > AddResourceTableEntriesRecursive ( UniformBufferName , * MemberPrefix , ResourceIndex , ResourceTableMap ) ;
}
2019-06-11 18:27:07 -04:00
else if ( Member . GetBaseType ( ) = = UBMT_NESTED_STRUCT & & NumElements > 0 )
{
for ( uint32 ArrayElementId = 0 ; ArrayElementId < NumElements ; ArrayElementId + + )
{
check ( Member . GetStructMetadata ( ) ) ;
FString MemberPrefix = FString : : Printf ( TEXT ( " %s%s_%u_ " ) , Prefix , Member . GetName ( ) , ArrayElementId ) ;
Member . GetStructMetadata ( ) - > AddResourceTableEntriesRecursive ( UniformBufferName , * MemberPrefix , ResourceIndex , ResourceTableMap ) ;
}
}
2018-10-19 17:36:35 -04:00
else if ( Member . GetBaseType ( ) = = UBMT_INCLUDED_STRUCT )
{
check ( Member . GetStructMetadata ( ) ) ;
2019-06-11 18:27:07 -04:00
check ( NumElements = = 0 ) ;
2018-10-19 17:36:35 -04:00
Member . GetStructMetadata ( ) - > AddResourceTableEntriesRecursive ( UniformBufferName , Prefix , ResourceIndex , ResourceTableMap ) ;
}
}
}
2019-03-07 11:25:32 -05:00
void FShaderParametersMetadata : : FindMemberFromOffset ( uint16 MemberOffset , const FShaderParametersMetadata * * OutContainingStruct , const FShaderParametersMetadata : : FMember * * OutMember , int32 * ArrayElementId , FString * NamePrefix ) const
2018-10-19 17:36:35 -04:00
{
check ( MemberOffset < GetSize ( ) ) ;
for ( const FMember & Member : Members )
{
EUniformBufferBaseType BaseType = Member . GetBaseType ( ) ;
2019-06-11 18:27:07 -04:00
uint32 NumElements = Member . GetNumElements ( ) ;
if ( ( BaseType = = UBMT_NESTED_STRUCT & & NumElements = = 0 ) | | BaseType = = UBMT_INCLUDED_STRUCT )
2018-10-19 17:36:35 -04:00
{
const FShaderParametersMetadata * SubStruct = Member . GetStructMetadata ( ) ;
2019-06-11 18:27:07 -04:00
if ( MemberOffset < ( Member . GetOffset ( ) + SubStruct - > GetSize ( ) ) )
2018-10-19 17:36:35 -04:00
{
2019-03-07 11:25:32 -05:00
if ( NamePrefix )
{
* NamePrefix = FString : : Printf ( TEXT ( " %s%s:: " ) , * * NamePrefix , Member . GetName ( ) ) ;
}
return SubStruct - > FindMemberFromOffset ( MemberOffset - Member . GetOffset ( ) , OutContainingStruct , OutMember , ArrayElementId , NamePrefix ) ;
}
}
2019-06-11 18:27:07 -04:00
else if ( BaseType = = UBMT_NESTED_STRUCT & & NumElements > 0 )
{
const FShaderParametersMetadata * SubStruct = Member . GetStructMetadata ( ) ;
uint32 StructSize = SubStruct - > GetSize ( ) ;
uint16 ArrayStartOffset = Member . GetOffset ( ) ;
uint16 ArrayEndOffset = ArrayStartOffset + SubStruct - > GetSize ( ) * NumElements ;
if ( MemberOffset > = ArrayStartOffset & & MemberOffset < ArrayEndOffset )
{
uint32 MemberOffsetInArray = MemberOffset - ArrayStartOffset ;
check ( ( MemberOffsetInArray % StructSize ) = = 0 ) ;
uint32 MemberPosInStructArray = MemberOffsetInArray / StructSize ;
uint32 MemberOffsetInStructElement = MemberOffsetInArray - MemberPosInStructArray * StructSize ;
if ( NamePrefix )
{
* NamePrefix = FString : : Printf ( TEXT ( " %s%s[%u]:: " ) , * * NamePrefix , Member . GetName ( ) , MemberPosInStructArray ) ;
}
return SubStruct - > FindMemberFromOffset ( MemberOffsetInStructElement , OutContainingStruct , OutMember , ArrayElementId , NamePrefix ) ;
}
}
else if ( NumElements > 0 & & (
2019-03-07 11:25:32 -05:00
BaseType = = UBMT_TEXTURE | |
BaseType = = UBMT_SRV | |
BaseType = = UBMT_SAMPLER | |
IsRDGResourceReferenceShaderParameterType ( BaseType ) ) )
{
uint16 ArrayStartOffset = Member . GetOffset ( ) ;
2019-06-11 18:27:07 -04:00
uint16 ArrayEndOffset = ArrayStartOffset + SHADER_PARAMETER_POINTER_ALIGNMENT * NumElements ;
2019-03-07 11:25:32 -05:00
if ( MemberOffset > = ArrayStartOffset & & MemberOffset < ArrayEndOffset )
{
check ( ( MemberOffset % SHADER_PARAMETER_POINTER_ALIGNMENT ) = = 0 ) ;
* OutContainingStruct = this ;
* OutMember = & Member ;
* ArrayElementId = ( MemberOffset - ArrayStartOffset ) / SHADER_PARAMETER_POINTER_ALIGNMENT ;
return ;
2018-10-19 17:36:35 -04:00
}
}
else if ( Member . GetOffset ( ) = = MemberOffset )
{
* OutContainingStruct = this ;
* OutMember = & Member ;
2019-03-07 11:25:32 -05:00
* ArrayElementId = 0 ;
2018-10-19 17:36:35 -04:00
return ;
}
}
checkf ( 0 , TEXT ( " Looks like this offset is invalid. " ) ) ;
}
2019-10-01 13:03:04 -04:00
FString FShaderParametersMetadata : : GetFullMemberCodeName ( uint16 MemberOffset ) const
{
const FShaderParametersMetadata * MemberContainingStruct = nullptr ;
const FShaderParametersMetadata : : FMember * Member = nullptr ;
int32 ArrayElementId = 0 ;
FString NamePrefix ;
FindMemberFromOffset ( MemberOffset , & MemberContainingStruct , & Member , & ArrayElementId , & NamePrefix ) ;
FString MemberName = FString : : Printf ( TEXT ( " %s%s " ) , * NamePrefix , Member - > GetName ( ) ) ;
if ( Member - > GetNumElements ( ) > 0 )
{
MemberName = FString : : Printf ( TEXT ( " %s%s[%d] " ) , * NamePrefix , Member - > GetName ( ) , ArrayElementId ) ;
}
return MemberName ;
}
2020-11-02 21:40:25 -04:00
void FShaderParametersMetadataBuilder : : AddRDGBufferSRV (
const TCHAR * Name ,
const TCHAR * ShaderType ,
EShaderPrecisionModifier : : Type Precision /* = EShaderPrecisionModifier::Float */
)
{
NextMemberOffset = Align ( NextMemberOffset , SHADER_PARAMETER_POINTER_ALIGNMENT ) ;
new ( Members ) FShaderParametersMetadata : : FMember (
Name ,
ShaderType ,
__LINE__ ,
NextMemberOffset ,
UBMT_RDG_BUFFER_SRV ,
Precision ,
TShaderResourceParameterTypeInfo < FRDGBufferSRV * > : : NumRows ,
TShaderResourceParameterTypeInfo < FRDGBufferSRV * > : : NumColumns ,
TShaderResourceParameterTypeInfo < FRDGBufferSRV * > : : NumElements ,
TShaderResourceParameterTypeInfo < FRDGBufferSRV * > : : GetStructMetadata ( )
) ;
NextMemberOffset + = SHADER_PARAMETER_POINTER_ALIGNMENT ;
}
void FShaderParametersMetadataBuilder : : AddRDGBufferUAV (
const TCHAR * Name ,
const TCHAR * ShaderType ,
EShaderPrecisionModifier : : Type Precision /* = EShaderPrecisionModifier::Float */
)
{
NextMemberOffset = Align ( NextMemberOffset , SHADER_PARAMETER_POINTER_ALIGNMENT ) ;
new ( Members ) FShaderParametersMetadata : : FMember (
Name ,
ShaderType ,
__LINE__ ,
NextMemberOffset ,
UBMT_RDG_BUFFER_UAV ,
Precision ,
TShaderResourceParameterTypeInfo < FRDGBufferUAV * > : : NumRows ,
TShaderResourceParameterTypeInfo < FRDGBufferUAV * > : : NumColumns ,
TShaderResourceParameterTypeInfo < FRDGBufferUAV * > : : NumElements ,
TShaderResourceParameterTypeInfo < FRDGBufferUAV * > : : GetStructMetadata ( )
) ;
NextMemberOffset + = SHADER_PARAMETER_POINTER_ALIGNMENT ;
}
FShaderParametersMetadata * FShaderParametersMetadataBuilder : : Build (
FShaderParametersMetadata : : EUseCase UseCase ,
const TCHAR * ShaderParameterName
)
{
const uint32 StructSize = Align ( NextMemberOffset , SHADER_PARAMETER_STRUCT_ALIGNMENT ) ;
FShaderParametersMetadata * ShaderParameterMetadata = new FShaderParametersMetadata (
UseCase ,
2020-12-07 17:42:32 -04:00
EUniformBufferBindingFlags : : Shader ,
2020-11-02 21:40:25 -04:00
ShaderParameterName ,
ShaderParameterName ,
nullptr ,
nullptr ,
__FILE__ ,
__LINE__ ,
StructSize ,
Members
) ;
return ShaderParameterMetadata ;
}