UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ShaderCompilerDefinitions.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "HAL/Platform.h"
7#include "UObject/NameTypes.h"
8#include "ShaderCore.h"
10
11#define SHADER_COMPILER_FLOAT32_FORMAT_STRING TEXT("%#.9gf")
12
14{
15 None = 0,
16 Integer,
18 Float,
19 String
20};
21
24{
25public:
28
30 template <typename ValueType>
31 void SetDefine(FName Name, ValueType Value) { InternalSetValue(FindOrAddMapIndex(Name), Value); }
32 void SetDefine(FName Name, const TCHAR* Value) { InternalSetValue(FindOrAddMapIndex(Name), Value); }
33 void SetDefine(FName Name, const FString& Value) { InternalSetValue(FindOrAddMapIndex(Name), *Value); }
34
35 template <typename ValueType>
36 void SetDefine(FShaderCompilerDefineNameCache& Name, ValueType Value) { InternalSetValue(FindOrAddMapIndex(Name), Value); }
37 void SetDefine(FShaderCompilerDefineNameCache& Name, const TCHAR* Value) { InternalSetValue(FindOrAddMapIndex(Name), Value); }
38 void SetDefine(FShaderCompilerDefineNameCache& Name, const FString& Value) { InternalSetValue(FindOrAddMapIndex(Name), *Value); }
39
41 {
42 int32 Result = 0;
43 int32 KeyIndex = FindMapIndex(Name, GetTypeHash(Name));
44 if (KeyIndex != INDEX_NONE)
45 {
46 // For None, Integer, or Unsigned, return ValueInteger (None will have a default of zero)
47 if (ValueTypes[KeyIndex] <= EShaderCompilerDefineVariant::Unsigned)
48 {
49 Result = Pairs[KeyIndex].ValueInteger;
50 }
51 else if (ValueTypes[KeyIndex] == EShaderCompilerDefineVariant::String)
52 {
53 Result = FCString::Atoi(*StringValues[Pairs[KeyIndex].ValueInteger]);
54 }
55 else
56 {
57 // EShaderCompilerDefineVariant::Float
58 Result = (int32)Pairs[KeyIndex].ValueFloat;
59 }
60 }
61 return Result;
62 }
63
65 {
66 int32 Result = ResultIfNotFound;
67 int32 KeyIndex;
68
69 // Check if this is an initial define, meaning it has a fixed map index. If Name.MapIndex is INDEX_NONE
70 // (MapIndex not initialized yet) or InitialDefineCount is zero (FShaderCompilerDefinitions constructed without
71 // initial state), this condition will be false, and continue to the rest of the function.
72 if ((uint32)NameCache.MapIndex < InitialDefineCount)
73 {
74 KeyIndex = NameCache.MapIndex;
75 }
76 else
77 {
78 KeyIndex = FindMapIndex(NameCache.Name, GetTypeHash(NameCache.Name));
79 }
80
81 if (KeyIndex != INDEX_NONE)
82 {
83 // Initialize MapIndex if necessary. If the define is not an initial define, its index will be greater than
84 // or equal to InitialDefineCount, indicating that it doesn't have a fixed map index.
85 if (InitialDefineCount && NameCache.MapIndex == INDEX_NONE)
86 {
87 NameCache.MapIndex = KeyIndex;
88 }
89
90 EShaderCompilerDefineVariant ValueType = ValueTypes[KeyIndex];
93 {
94 Result = Pairs[KeyIndex].ValueInteger;
95 }
96 else if (ValueType == EShaderCompilerDefineVariant::String)
97 {
98 Result = FCString::Atoi(*StringValues[Pairs[KeyIndex].ValueInteger]);
99 }
100 else if (ValueType == EShaderCompilerDefineVariant::Float)
101 {
102 // EShaderCompilerDefineVariant::Float
103 Result = (int32)Pairs[KeyIndex].ValueFloat;
104 }
105 }
106 return Result;
107 }
108
109 bool Contains(FName Name) const
110 {
111 int32 KeyIndex = FindMapIndex(Name, GetTypeHash(Name));
112 return KeyIndex != INDEX_NONE && ValueTypes[KeyIndex] != EShaderCompilerDefineVariant::None;
113 }
114
116 {
117 return ValueCount;
118 }
119
120 void Empty()
121 {
122 if (ValueCount)
123 {
124 KeyHashTable.Free();
125 Pairs.Empty();
126 ValueTypes.Empty();
127 StringValues.Empty();
128 ValueCount = 0;
129
130 // Re-copy initial defines if originally constructed with initial defines
131 if (InitialDefineCount)
132 {
133 *this = *GInitialDefines;
134 }
135 }
136 }
137
139 {
141 {
142 int32 OtherIndex = OtherIt.GetIndex();
143 switch (Other.ValueTypes[OtherIndex])
144 {
146 SetDefine(OtherIt.KeyFName(), Other.Pairs[OtherIndex].ValueInteger);
147 break;
149 SetDefine(OtherIt.KeyFName(), Other.Pairs[OtherIndex].ValueUnsigned);
150 break;
152 SetDefine(OtherIt.KeyFName(), Other.Pairs[OtherIndex].ValueFloat);
153 break;
155 SetDefine(OtherIt.KeyFName(), OtherIt.Value());
156 break;
157 }
158 }
159 }
160
162 {
163 KeyHashTable = Other.KeyHashTable;
164 Pairs = Other.Pairs;
165 ValueTypes = Other.ValueTypes;
166 StringValues = Other.StringValues;
167 InitialDefineCount = Other.InitialDefineCount;
168 ValueCount = Other.ValueCount;
169 return *this;
170 }
171
173 {
174 if (Ar.IsSaving())
175 {
176 // Only write set values in the map
177 Ar << Defs.ValueCount;
179 {
180 int32 Index = DefineIt.GetIndex();
181 Ar << Defs.Pairs[Index];
182 Ar << Defs.ValueTypes[Index];
183 }
184 Ar << Defs.StringValues;
185 }
186 else if (Ar.IsLoading())
187 {
188 Ar << Defs.ValueCount;
189 for (uint32 ValueIndex = 0; ValueIndex < Defs.ValueCount; ValueIndex++)
190 {
191 FShaderCompilerDefinitions::FPairType Pair;
192 Ar << Pair;
193 int32 Index = Defs.FindOrAddMapIndex(Pair.Key);
194 Defs.Pairs[Index] = Pair;
195 Ar << Defs.ValueTypes[Index];
196 }
197 Ar << Defs.StringValues;
198 }
199 return Ar;
200 }
201
203 {
204 public:
206 : Defines(InDefines), Index(-1)
207 {
208 // NULL terminate these strings to start
209 KeyStringBuffer[0] = 0;
210 ValueStringBuffer[0] = 0;
211
212 // Index set to -1 above, advance to first valid element
213 ++(*this);
214 }
215
217 FORCEINLINE explicit operator bool() const
218 {
219 return Index < Defines.Pairs.Num();
220 }
223 {
224 return !(bool)*this;
225 }
226
228 {
229 Index++;
230
231 // Skip over None values in the map
232 int32 PairNum = Defines.Pairs.Num();
233 while (Index < PairNum && Defines.ValueTypes[Index] == EShaderCompilerDefineVariant::None)
234 {
235 Index++;
236 }
237 return *this;
238 }
239
240 // Note that the output of Key() is transient, only valid until the iterator is incremented!
242 {
243 Defines.Pairs[Index].Key.ToString(KeyStringBuffer);
244 return KeyStringBuffer;
245 }
246
248 {
249 return Defines.Pairs[Index].Key;
250 }
251
252 // Note that the output of Value() is transient, only valid until the iterator is incremented!
254 {
255 const TCHAR* Result;
256
257 if (Defines.ValueTypes[Index] == EShaderCompilerDefineVariant::Integer)
258 {
259 int32 ValueInteger = Defines.Pairs[Index].ValueInteger;
260 if (ValueInteger >= 0 && ValueInteger <= 9)
261 {
262 ValueStringBuffer[0] = (TCHAR)ValueInteger + '0';
263 ValueStringBuffer[1] = 0;
264 }
265 else
266 {
267 FCString::Sprintf(ValueStringBuffer, TEXT("%d"), ValueInteger);
268 }
269 Result = ValueStringBuffer;
270 }
271 else if (Defines.ValueTypes[Index] == EShaderCompilerDefineVariant::Unsigned)
272 {
273 uint32 ValueUnsigned = Defines.Pairs[Index].ValueUnsigned;
274 if (ValueUnsigned >= 0 && ValueUnsigned <= 9)
275 {
276 ValueStringBuffer[0] = (TCHAR)ValueUnsigned + '0';
277 ValueStringBuffer[1] = 0;
278 }
279 else
280 {
281 FCString::Sprintf(ValueStringBuffer, TEXT("%u"), ValueUnsigned);
282 }
283 Result = ValueStringBuffer;
284 }
285 else if (Defines.ValueTypes[Index] == EShaderCompilerDefineVariant::Float)
286 {
287 // Make sure the printed value perfectly matches the given number
288 FCString::Sprintf(ValueStringBuffer, SHADER_COMPILER_FLOAT32_FORMAT_STRING, Defines.Pairs[Index].ValueFloat);
289 Result = ValueStringBuffer;
290 }
291 else
292 {
293 check(Defines.ValueTypes[Index] == EShaderCompilerDefineVariant::String);
294 Result = *Defines.StringValues[Defines.Pairs[Index].ValueInteger];
295 }
296
297 return Result;
298 }
299
301 {
302 return Index;
303 }
304
305 private:
306 const FShaderCompilerDefinitions& Defines;
307 int32 Index;
308 TCHAR KeyStringBuffer[FName::StringBufferSize];
309 TCHAR ValueStringBuffer[32];
310 };
311
312
313private:
314 int32 FindMapIndex(FName Key, uint32 KeyHash) const
315 {
316 for (uint32 KeyIndex = KeyHashTable.First(KeyHash); KeyHashTable.IsValid(KeyIndex); KeyIndex = KeyHashTable.Next(KeyIndex))
317 {
318 if (Pairs[KeyIndex].Key == Key)
319 {
320 return KeyIndex;
321 }
322 }
323 return INDEX_NONE;
324 }
325
326 int32 FindOrAddMapIndex(FName Name)
327 {
328 uint32 KeyHash = GetTypeHash(Name);
329 int32 KeyIndex = FindMapIndex(Name, KeyHash);
330 if (KeyIndex == INDEX_NONE)
331 {
332 KeyIndex = Pairs.Add(FPairType({ Name, {0} }));
334 KeyHashTable.Add(KeyHash, KeyIndex);
335 }
336 return KeyIndex;
337 }
338
340 {
341 // Check if this is an initial define, meaning it has a fixed map index. If Name.MapIndex is INDEX_NONE
342 // (MapIndex not initialized yet) or InitialDefineCount is zero (FShaderCompilerDefinitions constructed without
343 // initial state), this condition will be false, and continue to the rest of the function.
344 if ((uint32)NameCache.MapIndex < InitialDefineCount)
345 {
346 return NameCache.MapIndex;
347 }
348
349 uint32 KeyHash = GetTypeHash(NameCache.Name);
350 int32 KeyIndex = FindMapIndex(NameCache.Name, KeyHash);
351 if (KeyIndex == INDEX_NONE)
352 {
353 KeyIndex = Pairs.Add(FPairType({ NameCache.Name, {0} }));
355 KeyHashTable.Add(KeyHash, KeyIndex);
356 }
357
358 // Initialize MapIndex if necessary.
359 if (InitialDefineCount && NameCache.MapIndex == INDEX_NONE)
360 {
361 NameCache.MapIndex = KeyIndex;
362 }
363 return KeyIndex;
364 }
365
366 void InternalSetValue(int32 Index, const TCHAR* Value)
367 {
368 if (Value[0] >= '0' && Value[0] <= '9' && Value[1] == 0)
369 {
370 // If the string is a single digit integer, treat it as an integer. Most usages of string define values are cases where
371 // clients inadvertently pass bools as text, like TEXT("0") or TEXT("1"), and we can trivially optimize that.
373 Pairs[Index].ValueInteger = Value[0] - '0';
374 }
375 else if (ValueTypes[Index] == EShaderCompilerDefineVariant::String)
376 {
377 // Value was already a string variant, overwrite it with new value, rather than allocating new string
378 StringValues[Pairs[Index].ValueInteger] = Value;
379 }
380 else
381 {
382 // Set to string variant type, allocate and fill in the string
384 Pairs[Index].ValueInteger = StringValues.Add(Value);
385 }
386 }
387
388 void InternalSetValue(int32 Index, bool Value)
389 {
391 Pairs[Index].ValueInteger = Value ? 1 : 0;
392 }
393
394 void InternalSetValue(int32 Index, int32 Value)
395 {
397 Pairs[Index].ValueInteger = Value;
398 }
399
400 void InternalSetValue(int32 Index, uint32 Value)
401 {
403 Pairs[Index].ValueUnsigned = Value;
404 }
405
406 void InternalSetValue(int32 Index, float Value)
407 {
409 Pairs[Index].ValueFloat = Value;
410 }
411
413 {
414 EShaderCompilerDefineVariant& ValueType = ValueTypes[Index];
415 if (ValueType == EShaderCompilerDefineVariant::None)
416 {
417 ValueCount++;
418 }
419 ValueType = InValueType;
420 }
421
423 RENDERCORE_API static void InitializeInitialDefines(const FShaderCompilerDefinitions& InDefines);
424
425 struct FPairType
426 {
427 FName Key;
428 union
429 {
430 int32 ValueInteger;
431 uint32 ValueUnsigned;
432 float ValueFloat;
433 };
434
435 FORCEINLINE friend FArchive& operator<<(FArchive& Ar, FPairType& Pair)
436 {
437 // Avoid dynamic allocation when serializing keys. We need to serialize the FName as a string, because the index in the FName is
438 // non-deterministic (serialization generates hash values that need to be deterministic) and process specific (data needs to be
439 // serialized to worker processes). Compiler defines must be ANSI text, so serialize as such to save memory.
443
444 if (Ar.IsLoading())
445 {
446 Ar << StringLength;
447 check(StringLength < FName::StringBufferSize);
448 Ar.Serialize(KeyBufferAnsi, StringLength + 1);
449 Pair.Key = FName(KeyBufferAnsi);
450 }
451 else
452 {
453 StringLength = Pair.Key.ToString(KeyBuffer);
455 {
457 }
458 Ar << StringLength;
459 Ar.Serialize(KeyBufferAnsi, StringLength + 1);
460 }
461 Ar << Pair.ValueInteger;
462 return Ar;
463 }
464 };
465 FHashTable KeyHashTable;
466 TArray<FPairType> Pairs;
468 TArray<FString> StringValues;
469 uint32 InitialDefineCount; // Number of items that came from GInitialDefines
470 uint32 ValueCount; // Number of valid values (ValueType != EShaderCompilerDefineVariant::None)
471
472 RENDERCORE_API static FShaderCompilerDefinitions* GInitialDefines;
473
475};
#define FORCEINLINE
Definition AndroidPlatform.h:140
#define check(expr)
Definition AssertionMacros.h:314
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::ANSICHAR ANSICHAR
An ANSI character. Normally a signed type.
Definition Platform.h:1131
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
FArchive & operator<<(FArchive &Ar, FEnvQueryDebugProfileData::FStep &Data)
Definition EnvQueryTypes.cpp:489
const bool
Definition NetworkReplayStreaming.h:178
#define SHADER_COMPILER_FLOAT32_FORMAT_STRING
Definition ShaderCompilerDefinitions.h:11
EShaderCompilerDefineVariant
Definition ShaderCompilerDefinitions.h:14
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Archive.h:1208
virtual void Serialize(void *V, int64 Length)
Definition Archive.h:1689
UE_FORCEINLINE_HINT bool IsLoading() const
Definition Archive.h:236
UE_FORCEINLINE_HINT bool IsSaving() const
Definition Archive.h:248
Definition HashTable.h:210
void Free()
Definition HashTable.h:379
bool IsValid(uint32 Index) const
Definition HashTable.h:409
void Add(uint32 Key, uint32 Index)
Definition HashTable.h:414
uint32 First(uint32 Key) const
Definition HashTable.h:395
uint32 Next(uint32 Index) const
Definition HashTable.h:402
Definition NameTypes.h:617
static constexpr uint32 StringBufferSize
Definition NameTypes.h:708
Definition ShaderCore.h:519
Definition ShaderCompilerDefinitions.h:203
FORCEINLINE const TCHAR * Value()
Definition ShaderCompilerDefinitions.h:253
FORCEINLINE bool operator!() const
Definition ShaderCompilerDefinitions.h:222
FORCEINLINE FConstIterator(const FShaderCompilerDefinitions &InDefines)
Definition ShaderCompilerDefinitions.h:205
FORCEINLINE const FName & KeyFName() const
Definition ShaderCompilerDefinitions.h:247
FORCEINLINE const TCHAR * Key()
Definition ShaderCompilerDefinitions.h:241
FORCEINLINE int32 GetIndex() const
Definition ShaderCompilerDefinitions.h:300
FORCEINLINE FConstIterator & operator++()
Definition ShaderCompilerDefinitions.h:227
Definition ShaderCompilerDefinitions.h:24
int32 GetIntegerValue(FName Name) const
Definition ShaderCompilerDefinitions.h:40
void Empty()
Definition ShaderCompilerDefinitions.h:120
bool Contains(FName Name) const
Definition ShaderCompilerDefinitions.h:109
void SetDefine(FName Name, const FString &Value)
Definition ShaderCompilerDefinitions.h:33
friend FArchive & operator<<(FArchive &Ar, FShaderCompilerDefinitions &Defs)
Definition ShaderCompilerDefinitions.h:172
void SetDefine(FName Name, ValueType Value)
Definition ShaderCompilerDefinitions.h:31
void SetDefine(FShaderCompilerDefineNameCache &Name, const FString &Value)
Definition ShaderCompilerDefinitions.h:38
int32 GetIntegerValue(FShaderCompilerDefineNameCache &NameCache, int32 ResultIfNotFound) const
Definition ShaderCompilerDefinitions.h:64
FORCEINLINE int32 Num() const
Definition ShaderCompilerDefinitions.h:115
RENDERCORE_API FShaderCompilerDefinitions(const FShaderCompilerDefinitions &)
void SetDefine(FShaderCompilerDefineNameCache &Name, const TCHAR *Value)
Definition ShaderCompilerDefinitions.h:37
FShaderCompilerDefinitions & operator=(const FShaderCompilerDefinitions &Other)
Definition ShaderCompilerDefinitions.h:161
void Merge(const FShaderCompilerDefinitions &Other)
Definition ShaderCompilerDefinitions.h:138
friend struct FShaderInitialDefinesInitializer
Definition ShaderCompilerDefinitions.h:474
void SetDefine(FName Name, const TCHAR *Value)
Definition ShaderCompilerDefinitions.h:32
void SetDefine(FShaderCompilerDefineNameCache &Name, ValueType Value)
Definition ShaderCompilerDefinitions.h:36
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
void ToString(const FPlatformTypeLayoutParameters &LayoutParams, FMemoryToStringContext &OutContext) const
Definition Array.h:3618
void Empty(SizeType Slack=0)
Definition Array.h:2273
uint32 GetTypeHash(const FKey &Key)
Definition BlackboardKey.h:35
constexpr int32 StringLength(const CharType *InString)
Definition StringView.h:38
U16 Index
Definition radfft.cpp:71
static UE_FORCEINLINE_HINT int32 Atoi(const CharType *String)
Definition CString.h:1173
static int32 Sprintf(CharType *Dest, const FmtType &Fmt, Types... Args)
Definition CString.h:569