A game about forced loneliness, made by TACStudios
1#ifndef UNITY_DOTS_INSTANCING_INCLUDED
2#define UNITY_DOTS_INSTANCING_INCLUDED
3
4#ifdef UNITY_DOTS_INSTANCING_ENABLED
5
6#if UNITY_OLD_PREPROCESSOR
7#error DOTS Instancing requires the new shader preprocessor. Please enable Caching Preprocessor in the Editor settings!
8#endif
9
10// Config defines
11// ==========================================================================================
12// #define UNITY_DOTS_INSTANCED_PROP_OVERRIDE_DISABLED_BY_DEFAULT
13
14
15
16
17
18/*
19Here's a bit of python code to generate these repetitive typespecs without
20a lot of C macro magic
21
22def print_dots_instancing_typespecs(elem_type, id_char, elem_size):
23 print(f"#define UNITY_DOTS_INSTANCING_TYPESPEC_{elem_type} {id_char}{elem_size}")
24 for y in range(1, 5):
25 for x in range(1, 5):
26 rows = "" if y == 1 else f"x{y}"
27 size = elem_size * x * y
28 print(f"#define UNITY_DOTS_INSTANCING_TYPESPEC_{elem_type}{x}{rows} {id_char}{size}")
29
30for t, c, sz in (
31 ('float', 'F', 4),
32 ('int', 'I', 4),
33 ('uint', 'U', 4),
34 ('half', 'H', 2)
35 ):
36 print_dots_instancing_typespecs(t, c, sz)
37*/
38
39#define UNITY_DOTS_INSTANCING_TYPESPEC_float F4
40#define UNITY_DOTS_INSTANCING_TYPESPEC_float1 F4
41#define UNITY_DOTS_INSTANCING_TYPESPEC_float2 F8
42#define UNITY_DOTS_INSTANCING_TYPESPEC_float3 F12
43#define UNITY_DOTS_INSTANCING_TYPESPEC_float4 F16
44#define UNITY_DOTS_INSTANCING_TYPESPEC_float1x2 F8
45#define UNITY_DOTS_INSTANCING_TYPESPEC_float2x2 F16
46#define UNITY_DOTS_INSTANCING_TYPESPEC_float3x2 F24
47#define UNITY_DOTS_INSTANCING_TYPESPEC_float4x2 F32
48#define UNITY_DOTS_INSTANCING_TYPESPEC_float1x3 F12
49#define UNITY_DOTS_INSTANCING_TYPESPEC_float2x3 F24
50#define UNITY_DOTS_INSTANCING_TYPESPEC_float3x3 F36
51#define UNITY_DOTS_INSTANCING_TYPESPEC_float4x3 F48
52#define UNITY_DOTS_INSTANCING_TYPESPEC_float1x4 F16
53#define UNITY_DOTS_INSTANCING_TYPESPEC_float2x4 F32
54#define UNITY_DOTS_INSTANCING_TYPESPEC_float3x4 F48
55#define UNITY_DOTS_INSTANCING_TYPESPEC_float4x4 F64
56#define UNITY_DOTS_INSTANCING_TYPESPEC_int I4
57#define UNITY_DOTS_INSTANCING_TYPESPEC_int1 I4
58#define UNITY_DOTS_INSTANCING_TYPESPEC_int2 I8
59#define UNITY_DOTS_INSTANCING_TYPESPEC_int3 I12
60#define UNITY_DOTS_INSTANCING_TYPESPEC_int4 I16
61#define UNITY_DOTS_INSTANCING_TYPESPEC_int1x2 I8
62#define UNITY_DOTS_INSTANCING_TYPESPEC_int2x2 I16
63#define UNITY_DOTS_INSTANCING_TYPESPEC_int3x2 I24
64#define UNITY_DOTS_INSTANCING_TYPESPEC_int4x2 I32
65#define UNITY_DOTS_INSTANCING_TYPESPEC_int1x3 I12
66#define UNITY_DOTS_INSTANCING_TYPESPEC_int2x3 I24
67#define UNITY_DOTS_INSTANCING_TYPESPEC_int3x3 I36
68#define UNITY_DOTS_INSTANCING_TYPESPEC_int4x3 I48
69#define UNITY_DOTS_INSTANCING_TYPESPEC_int1x4 I16
70#define UNITY_DOTS_INSTANCING_TYPESPEC_int2x4 I32
71#define UNITY_DOTS_INSTANCING_TYPESPEC_int3x4 I48
72#define UNITY_DOTS_INSTANCING_TYPESPEC_int4x4 I64
73#define UNITY_DOTS_INSTANCING_TYPESPEC_uint U4
74#define UNITY_DOTS_INSTANCING_TYPESPEC_uint1 U4
75#define UNITY_DOTS_INSTANCING_TYPESPEC_uint2 U8
76#define UNITY_DOTS_INSTANCING_TYPESPEC_uint3 U12
77#define UNITY_DOTS_INSTANCING_TYPESPEC_uint4 U16
78#define UNITY_DOTS_INSTANCING_TYPESPEC_uint1x2 U8
79#define UNITY_DOTS_INSTANCING_TYPESPEC_uint2x2 U16
80#define UNITY_DOTS_INSTANCING_TYPESPEC_uint3x2 U24
81#define UNITY_DOTS_INSTANCING_TYPESPEC_uint4x2 U32
82#define UNITY_DOTS_INSTANCING_TYPESPEC_uint1x3 U12
83#define UNITY_DOTS_INSTANCING_TYPESPEC_uint2x3 U24
84#define UNITY_DOTS_INSTANCING_TYPESPEC_uint3x3 U36
85#define UNITY_DOTS_INSTANCING_TYPESPEC_uint4x3 U48
86#define UNITY_DOTS_INSTANCING_TYPESPEC_uint1x4 U16
87#define UNITY_DOTS_INSTANCING_TYPESPEC_uint2x4 U32
88#define UNITY_DOTS_INSTANCING_TYPESPEC_uint3x4 U48
89#define UNITY_DOTS_INSTANCING_TYPESPEC_uint4x4 U64
90#define UNITY_DOTS_INSTANCING_TYPESPEC_half H2
91#define UNITY_DOTS_INSTANCING_TYPESPEC_half1 H2
92#define UNITY_DOTS_INSTANCING_TYPESPEC_half2 H4
93#define UNITY_DOTS_INSTANCING_TYPESPEC_half3 H6
94#define UNITY_DOTS_INSTANCING_TYPESPEC_half4 H8
95#define UNITY_DOTS_INSTANCING_TYPESPEC_half1x2 H4
96#define UNITY_DOTS_INSTANCING_TYPESPEC_half2x2 H8
97#define UNITY_DOTS_INSTANCING_TYPESPEC_half3x2 H12
98#define UNITY_DOTS_INSTANCING_TYPESPEC_half4x2 H16
99#define UNITY_DOTS_INSTANCING_TYPESPEC_half1x3 H6
100#define UNITY_DOTS_INSTANCING_TYPESPEC_half2x3 H12
101#define UNITY_DOTS_INSTANCING_TYPESPEC_half3x3 H18
102#define UNITY_DOTS_INSTANCING_TYPESPEC_half4x3 H24
103#define UNITY_DOTS_INSTANCING_TYPESPEC_half1x4 H8
104#define UNITY_DOTS_INSTANCING_TYPESPEC_half2x4 H16
105#define UNITY_DOTS_INSTANCING_TYPESPEC_half3x4 H24
106#define UNITY_DOTS_INSTANCING_TYPESPEC_half4x4 H32
107#define UNITY_DOTS_INSTANCING_TYPESPEC_min16float H2
108#define UNITY_DOTS_INSTANCING_TYPESPEC_min16float4 H8
109#define UNITY_DOTS_INSTANCING_TYPESPEC_SH F128
110
111static const int kDotsInstancedPropOverrideDisabled = 0;
112static const int kDotsInstancedPropOverrideSupported = 1;
113static const int kDotsInstancedPropOverrideRequired = 2;
114
115#define UNITY_DOTS_INSTANCING_CONCAT2(a, b) a ## b
116#define UNITY_DOTS_INSTANCING_CONCAT4(a, b, c, d) a ## b ## c ## d
117#define UNITY_DOTS_INSTANCING_CONCAT_WITH_METADATA(metadata_prefix, typespec, name) UNITY_DOTS_INSTANCING_CONCAT4(metadata_prefix, typespec, _Metadata, name)
118
119// Metadata constants for properties have the following name format:
120// unity_DOTSInstancing<Type><Size>_Metadata<Name>
121// where
122// <Type> is a single character element type specifier (e.g. F for float4x4)
123// F = float, I = int, U = uint, H = half
124// <Size> is the total size of the property in bytes (e.g. 64 for float4x4)
125// <Name> is the name of the property
126// NOTE: There is no underscore between 'Metadata' and <Name> to avoid a double
127// underscore in the common case where the property name starts with an underscore.
128// A prefix double underscore is illegal on some platforms like OpenGL.
129#define UNITY_DOTS_INSTANCED_METADATA_NAME(type, name) UNITY_DOTS_INSTANCING_CONCAT_WITH_METADATA(unity_DOTSInstancing, UNITY_DOTS_INSTANCING_CONCAT2(UNITY_DOTS_INSTANCING_TYPESPEC_, type), name)
130#define UNITY_DOTS_INSTANCED_PROP_OVERRIDE_MODE_NAME(name) UNITY_DOTS_INSTANCING_CONCAT2(name, _DOTSInstancingOverrideMode)
131
132#define UNITY_DOTS_INSTANCING_START(name) cbuffer UnityDOTSInstancing_##name {
133#define UNITY_DOTS_INSTANCING_END(name) }
134
135#define UNITY_DOTS_INSTANCED_PROP_OVERRIDE_DISABLED(type, name) static const uint UNITY_DOTS_INSTANCED_METADATA_NAME(type, name) = 0; \
136static const int UNITY_DOTS_INSTANCED_PROP_OVERRIDE_MODE_NAME(name) = kDotsInstancedPropOverrideDisabled;
137
138#define UNITY_DOTS_INSTANCED_PROP_OVERRIDE_SUPPORTED(type, name) uint UNITY_DOTS_INSTANCED_METADATA_NAME(type, name); \
139static const int UNITY_DOTS_INSTANCED_PROP_OVERRIDE_MODE_NAME(name) = kDotsInstancedPropOverrideSupported;
140
141#define UNITY_DOTS_INSTANCED_PROP_OVERRIDE_REQUIRED(type, name) uint UNITY_DOTS_INSTANCED_METADATA_NAME(type, name); \
142static const int UNITY_DOTS_INSTANCED_PROP_OVERRIDE_MODE_NAME(name) = kDotsInstancedPropOverrideRequired;
143
144#ifdef UNITY_DOTS_INSTANCED_PROP_OVERRIDE_DISABLED_BY_DEFAULT
145#define UNITY_DOTS_INSTANCED_PROP(type, name) UNITY_DOTS_INSTANCED_PROP_OVERRIDE_DISABLED(type, name)
146#else
147#define UNITY_DOTS_INSTANCED_PROP(type, name) UNITY_DOTS_INSTANCED_PROP_OVERRIDE_SUPPORTED(type, name)
148#endif
149
150#define UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_DISABLED(name) (UNITY_DOTS_INSTANCED_PROP_OVERRIDE_MODE_NAME(name) == kDotsInstancedPropOverrideDisabled)
151#define UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_ENABLED(name) (UNITY_DOTS_INSTANCED_PROP_OVERRIDE_MODE_NAME(name) == kDotsInstancedPropOverrideSupported)
152#define UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_REQUIRED(name) (UNITY_DOTS_INSTANCED_PROP_OVERRIDE_MODE_NAME(name) == kDotsInstancedPropOverrideRequired)
153
154#define UNITY_ACCESS_DOTS_INSTANCED_PROP(type, var) ( /* Compile-time branches */ \
155UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_ENABLED(var) ? LoadDOTSInstancedData_##type(UNITY_DOTS_INSTANCED_METADATA_NAME(type, var)) \
156: UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_REQUIRED(var) ? LoadDOTSInstancedDataOverridden_##type(UNITY_DOTS_INSTANCED_METADATA_NAME(type, var)) \
157: ((type)0) \
158)
159
160#define UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(type, var) ( /* Compile-time branches */ \
161UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_ENABLED(var) ? LoadDOTSInstancedData_##type(var, UNITY_DOTS_INSTANCED_METADATA_NAME(type, var)) \
162: UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_REQUIRED(var) ? LoadDOTSInstancedDataOverridden_##type(UNITY_DOTS_INSTANCED_METADATA_NAME(type, var)) \
163: (var) \
164)
165
166#define UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_CUSTOM_DEFAULT(type, var, default_value) ( /* Compile-time branches */ \
167UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_ENABLED(var) ? LoadDOTSInstancedData_##type(default_value, UNITY_DOTS_INSTANCED_METADATA_NAME(type, var)) \
168: UNITY_DOTS_INSTANCED_PROP_IS_OVERRIDE_REQUIRED(var) ? LoadDOTSInstancedDataOverridden_##type(UNITY_DOTS_INSTANCED_METADATA_NAME(type, var)) \
169: (default_value) \
170)
171
172#define UNITY_ACCESS_DOTS_AND_TRADITIONAL_INSTANCED_PROP(type, arr, var) UNITY_ACCESS_DOTS_INSTANCED_PROP(type, var)
173#define UNITY_ACCESS_DOTS_AND_TRADITIONAL_INSTANCED_PROP_WITH_DEFAULT(type, arr, var) UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(type, var)
174#define UNITY_ACCESS_DOTS_AND_TRADITIONAL_INSTANCED_PROP_WITH_CUSTOM_DEFAULT(type, arr, var, default_value) UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_CUSTOM_DEFAULT(type, var, default_value)
175
176#define UNITY_SETUP_DOTS_MATERIAL_PROPERTY_CACHES() // No-op by default
177
178#ifdef UNITY_DOTS_INSTANCING_UNIFORM_BUFFER
179CBUFFER_START(unity_DOTSInstanceData)
180 float4 unity_DOTSInstanceDataRaw[1024]; // warning: if you change 1024 value, you should also change BatchRendererGroup::GetConstantBufferMaxWindowSize() function in the c++ code base
181CBUFFER_END
182#else
183ByteAddressBuffer unity_DOTSInstanceData;
184#endif
185
186// DOTS instanced shaders do not get globals from UnityPerDraw automatically.
187// Instead, the BatchRendererGroup user must provide this cbuffer and/or
188// set up DOTS instanced properties for the values.
189// NOTE: Do *NOT* use the string "Globals" in this cbuffer name, cbuffers
190// with those kinds of names will be automatically renamed.
191CBUFFER_START(unity_DOTSInstanceGlobalValues)
192 float4 unity_DOTS_ProbesOcclusion;
193 float4 unity_DOTS_SpecCube0_HDR;
194 float4 unity_DOTS_SpecCube1_HDR;
195 float4 unity_DOTS_SHAr;
196 float4 unity_DOTS_SHAg;
197 float4 unity_DOTS_SHAb;
198 float4 unity_DOTS_SHBr;
199 float4 unity_DOTS_SHBg;
200 float4 unity_DOTS_SHBb;
201 float4 unity_DOTS_SHC;
202CBUFFER_END
203
204// The data has to be wrapped inside a struct, otherwise the instancing code path
205// on some platforms does not trigger.
206struct DOTSVisibleData
207{
208 uint4 VisibleData;
209};
210
211// The name of this cbuffer has to start with "UnityInstancing" and a struct so it's
212// detected as an "instancing cbuffer" by some platforms that use string matching
213// to detect this.
214CBUFFER_START(UnityInstancingDOTS_InstanceVisibility)
215 DOTSVisibleData unity_DOTSVisibleInstances[256]; // warning: if you change this value you should also change kBRGVisibilityUBOShaderArraySize in c++ code base
216CBUFFER_END
217
218// Keep these in sync with SRP Batcher DOTSInstancingFlags
219static const uint kDOTSInstancingFlagFlipWinding = (1 << 0); // Flip triangle winding when rendering, e.g. when the scale is negative
220static const uint kDOTSInstancingFlagForceZeroMotion = (1 << 1); // Object should produce zero motion vectors when rendered in the motion pass
221static const uint kDOTSInstancingFlagCameraMotion = (1 << 2); // Object uses Camera motion (i.e. not per-Object motion)
222static const uint kDOTSInstancingFlagHasPrevPosition = (1 << 3); // Object has a separate previous frame position vertex streams (e.g. for deformed objects)
223static const uint kDOTSInstancingFlagMainLightEnabled = (1 << 4); // Object should receive direct lighting from the main light (e.g. light not baked into lightmap)
224static const uint kDOTSInstancingFlagLODCrossFadeValuePacked = (1 << 5); // Object's cross fade value is encoded in the higher 8 bits of the instance index
225
226static const uint kPerInstanceDataBit = 0x80000000;
227static const uint kAddressMask = 0x7fffffff;
228
229static const uint kIndirectVisibleOffsetEnabledBit = 0x80000000;
230static uint unity_SampledDOTSIndirectVisibleIndex;
231static uint unity_SampledDOTSInstanceIndex;
232static int unity_SampledLODCrossfade;
233static real4 unity_DOTS_Sampled_SHAr;
234static real4 unity_DOTS_Sampled_SHAg;
235static real4 unity_DOTS_Sampled_SHAb;
236static real4 unity_DOTS_Sampled_SHBr;
237static real4 unity_DOTS_Sampled_SHBg;
238static real4 unity_DOTS_Sampled_SHBb;
239static real4 unity_DOTS_Sampled_SHC;
240static real4 unity_DOTS_Sampled_ProbesOcclusion;
241static float3 unity_DOTS_RendererBounds_Min;
242static float3 unity_DOTS_RendererBounds_Max;
243
244uint GetDOTSIndirectVisibleIndex()
245{
246 return unity_SampledDOTSIndirectVisibleIndex;
247}
248
249uint GetDOTSInstanceIndex()
250{
251 return unity_SampledDOTSInstanceIndex;
252}
253
254#ifdef UNITY_DOTS_INSTANCING_UNIFORM_BUFFER
255// In UBO mode we precompute our select masks based on our instance index.
256// All base addresses are aligned by 16, so we already know which offsets
257// the instance index will load (modulo 16).
258// All float1 loads will share the select4 masks, and all float2 loads
259// will share the select2 mask.
260// These variables are single assignment only, and should hopefully be well
261// optimizable and dead code eliminatable for the compiler.
262static uint unity_DOTSInstanceData_Select4_Mask0;
263static uint unity_DOTSInstanceData_Select4_Mask1;
264static uint unity_DOTSInstanceData_Select2_Mask;
265
266// The compiler should dead code eliminate the parts of this that are not used by the shader.
267void SetupDOTSInstanceSelectMasks()
268{
269 uint instanceIndex = GetDOTSInstanceIndex();
270 uint offsetSingleChannel = instanceIndex << 2; // float: stride 4 bytes
271
272 // x = 0 = 00
273 // y = 1 = 01
274 // z = 2 = 10
275 // w = 3 = 11
276 // Lowest 2 bits are zero, all accesses are aligned,
277 // and base addresses are aligned by 16.
278 // Bits 29 and 28 give the channel index.
279 // NOTE: Mask generation was rewritten to this form specifically to avoid codegen
280 // correctness issues on GLES.
281 unity_DOTSInstanceData_Select4_Mask0 = (offsetSingleChannel & 0x4) ? 0xffffffff : 0;
282 unity_DOTSInstanceData_Select4_Mask1 = (offsetSingleChannel & 0x8) ? 0xffffffff : 0;
283 // Select2 mask is the same as the low bit mask of select4, since
284 // (x << 3) << 28 == (x << 2) << 29
285 unity_DOTSInstanceData_Select2_Mask = unity_DOTSInstanceData_Select4_Mask0;
286}
287
288#else
289
290// This is a no-op in SSBO mode
291void SetupDOTSInstanceSelectMasks() {}
292
293#endif
294
295#ifdef UNITY_DOTS_INSTANCING_UNIFORM_BUFFER
296CBUFFER_START(unity_DOTSInstancing_IndirectInstanceVisibility)
297 float4 unity_DOTSInstancing_IndirectInstanceVisibilityRaw[4096];
298CBUFFER_END
299#else
300ByteAddressBuffer unity_DOTSInstancing_IndirectInstanceVisibility;
301#endif
302
303uint LoadDOTSIndirectInstanceIndex(uint indirectIndex)
304{
305#ifdef UNITY_DOTS_INSTANCING_UNIFORM_BUFFER
306 uint4 raw = asuint(unity_DOTSInstancing_IndirectInstanceVisibilityRaw[indirectIndex >> 2]);
307 uint2 tmp = (indirectIndex & 0x2) ? raw.zw : raw.xy;
308 return (indirectIndex & 0x1) ? tmp.y : tmp.x;
309#else
310 return unity_DOTSInstancing_IndirectInstanceVisibility.Load(indirectIndex << 2);
311#endif
312}
313
314void SetupDOTSVisibleInstancingData()
315{
316 uint packedIndirectVisibleOffset = unity_DOTSVisibleInstances[0].VisibleData.y;
317 uint crossFadeValuePacked = unity_DOTSVisibleInstances[0].VisibleData.w & kDOTSInstancingFlagLODCrossFadeValuePacked;
318 unity_SampledDOTSIndirectVisibleIndex = (packedIndirectVisibleOffset & ~kIndirectVisibleOffsetEnabledBit) + unity_InstanceID;
319
320 if (packedIndirectVisibleOffset != 0)
321 unity_SampledDOTSInstanceIndex = LoadDOTSIndirectInstanceIndex(unity_SampledDOTSIndirectVisibleIndex);
322 else
323 unity_SampledDOTSInstanceIndex = unity_DOTSVisibleInstances[unity_InstanceID].VisibleData.x;
324
325 if(crossFadeValuePacked != 0)
326 {
327 unity_SampledLODCrossfade = int(unity_SampledDOTSInstanceIndex) >> 24;
328 unity_SampledDOTSInstanceIndex &= 0x00ffffff;
329 }
330 else
331 {
332 unity_SampledLODCrossfade = 0;
333 }
334
335 SetupDOTSInstanceSelectMasks();
336}
337
338int GetDOTSInstanceCrossfadeSnorm8()
339{
340 return unity_SampledLODCrossfade;
341}
342
343bool IsDOTSInstancedProperty(uint metadata)
344{
345 return (metadata & kPerInstanceDataBit) != 0;
346}
347
348// Stride is typically expected to be a compile-time literal here, so this should
349// be optimized into shifts and other cheap ALU ops by the compiler.
350uint ComputeDOTSInstanceOffset(uint instanceIndex, uint stride)
351{
352 return instanceIndex * stride;
353}
354
355uint ComputeDOTSInstanceDataAddress(uint metadata, uint stride)
356{
357 uint isOverridden = metadata & kPerInstanceDataBit;
358 // Sign extend per-instance data bit so it can just be ANDed with the offset
359 uint offsetMask = (uint)((int)isOverridden >> 31);
360 uint baseAddress = metadata & kAddressMask;
361 uint offset = ComputeDOTSInstanceOffset(GetDOTSInstanceIndex(), stride);
362 offset &= offsetMask;
363 return baseAddress + offset;
364}
365
366// This version assumes that the high bit of the metadata is set (= per instance data).
367// Useful if the call site has already branched over this.
368uint ComputeDOTSInstanceDataAddressOverridden(uint metadata, uint stride)
369{
370 uint baseAddress = metadata & kAddressMask;
371 uint offset = ComputeDOTSInstanceOffset(GetDOTSInstanceIndex(), stride);
372 return baseAddress + offset;
373}
374
375#ifdef UNITY_DOTS_INSTANCING_UNIFORM_BUFFER
376uint DOTSInstanceData_Select(uint addressOrOffset, uint4 v)
377{
378 uint mask0 = unity_DOTSInstanceData_Select4_Mask0;
379 uint mask1 = unity_DOTSInstanceData_Select4_Mask1;
380 return
381 (((v.w & mask0) | (v.z & ~mask0)) & mask1) |
382 (((v.y & mask0) | (v.x & ~mask0)) & ~mask1);
383}
384
385uint2 DOTSInstanceData_Select2(uint addressOrOffset, uint4 v)
386{
387 uint mask0 = unity_DOTSInstanceData_Select2_Mask;
388 return (v.zw & mask0) | (v.xy & ~mask0);
389}
390
391uint DOTSInstanceData_Load(uint address)
392{
393 uint float4Index = address >> 4;
394 uint4 raw = asuint(unity_DOTSInstanceDataRaw[float4Index]);
395 return DOTSInstanceData_Select(address, raw);
396}
397uint2 DOTSInstanceData_Load2(uint address)
398{
399 uint float4Index = address >> 4;
400 uint4 raw = asuint(unity_DOTSInstanceDataRaw[float4Index]);
401 return DOTSInstanceData_Select2(address, raw);
402}
403uint4 DOTSInstanceData_Load4(uint address)
404{
405 uint float4Index = address >> 4;
406 return asuint(unity_DOTSInstanceDataRaw[float4Index]);
407}
408uint3 DOTSInstanceData_Load3(uint address)
409{
410 // This is likely to be slow, tightly packed float3s are tricky
411 switch (address & 0xf)
412 {
413 default:
414 case 0:
415 return DOTSInstanceData_Load4(address).xyz;
416 case 4:
417 return DOTSInstanceData_Load4(address).yzw;
418 case 8:
419 {
420 uint float4Index = address >> 4;
421 uint4 raw0 = asuint(unity_DOTSInstanceDataRaw[float4Index]);
422 uint4 raw1 = asuint(unity_DOTSInstanceDataRaw[float4Index + 1]);
423 uint3 v;
424 v.xy = raw0.zw;
425 v.z = raw1.x;
426 return v;
427 }
428 case 12:
429 {
430 uint float4Index = address >> 4;
431 uint4 raw0 = asuint(unity_DOTSInstanceDataRaw[float4Index]);
432 uint4 raw1 = asuint(unity_DOTSInstanceDataRaw[float4Index + 1]);
433 uint3 v;
434 v.x = raw0.w;
435 v.yz = raw1.xy;
436 return v;
437 }
438 }
439}
440#else
441uint DOTSInstanceData_Load(uint address)
442{
443 return unity_DOTSInstanceData.Load(address);
444}
445uint2 DOTSInstanceData_Load2(uint address)
446{
447 return unity_DOTSInstanceData.Load2(address);
448}
449uint3 DOTSInstanceData_Load3(uint address)
450{
451 return unity_DOTSInstanceData.Load3(address);
452}
453uint4 DOTSInstanceData_Load4(uint address)
454{
455 return unity_DOTSInstanceData.Load4(address);
456}
457#endif
458
459#define DEFINE_DOTS_LOAD_INSTANCE_SCALAR(type, conv, sizeof_type) \
460type LoadDOTSInstancedData_##type(uint metadata) \
461{ \
462 uint address = ComputeDOTSInstanceDataAddress(metadata, sizeof_type); \
463 return conv(DOTSInstanceData_Load(address)); \
464} \
465type LoadDOTSInstancedDataOverridden_##type(uint metadata) \
466{ \
467 uint address = ComputeDOTSInstanceDataAddressOverridden(metadata, sizeof_type); \
468 return conv(DOTSInstanceData_Load(address)); \
469} \
470type LoadDOTSInstancedData_##type(type default_value, uint metadata) \
471{ \
472 uint address = ComputeDOTSInstanceDataAddressOverridden(metadata, sizeof_type); \
473 return IsDOTSInstancedProperty(metadata) ? \
474 conv(DOTSInstanceData_Load(address)) : default_value; \
475}
476
477#define DEFINE_DOTS_LOAD_INSTANCE_VECTOR(type, width, conv, sizeof_type) \
478type##width LoadDOTSInstancedData_##type##width(uint metadata) \
479{ \
480 uint address = ComputeDOTSInstanceDataAddress(metadata, sizeof_type * width); \
481 return conv(DOTSInstanceData_Load##width(address)); \
482} \
483type##width LoadDOTSInstancedDataOverridden_##type##width(uint metadata) \
484{ \
485 uint address = ComputeDOTSInstanceDataAddressOverridden(metadata, sizeof_type * width); \
486 return conv(DOTSInstanceData_Load##width(address)); \
487} \
488type##width LoadDOTSInstancedData_##type##width(type##width default_value, uint metadata) \
489{ \
490 uint address = ComputeDOTSInstanceDataAddressOverridden(metadata, sizeof_type * width); \
491 return IsDOTSInstancedProperty(metadata) ? \
492 conv(DOTSInstanceData_Load##width(address)) : default_value; \
493}
494
495DEFINE_DOTS_LOAD_INSTANCE_SCALAR(float, asfloat, 4)
496DEFINE_DOTS_LOAD_INSTANCE_SCALAR(int, int, 4)
497DEFINE_DOTS_LOAD_INSTANCE_SCALAR(uint, uint, 4)
498//DEFINE_DOTS_LOAD_INSTANCE_SCALAR(half, half, 2)
499
500DEFINE_DOTS_LOAD_INSTANCE_VECTOR(float, 2, asfloat, 4)
501DEFINE_DOTS_LOAD_INSTANCE_VECTOR(float, 3, asfloat, 4)
502DEFINE_DOTS_LOAD_INSTANCE_VECTOR(float, 4, asfloat, 4)
503DEFINE_DOTS_LOAD_INSTANCE_VECTOR(int, 2, int2, 4)
504DEFINE_DOTS_LOAD_INSTANCE_VECTOR(int, 3, int3, 4)
505DEFINE_DOTS_LOAD_INSTANCE_VECTOR(int, 4, int4, 4)
506DEFINE_DOTS_LOAD_INSTANCE_VECTOR(uint, 2, uint2, 4)
507DEFINE_DOTS_LOAD_INSTANCE_VECTOR(uint, 3, uint3, 4)
508DEFINE_DOTS_LOAD_INSTANCE_VECTOR(uint, 4, uint4, 4)
509//DEFINE_DOTS_LOAD_INSTANCE_VECTOR(half, 2, half2, 2)
510//DEFINE_DOTS_LOAD_INSTANCE_VECTOR(half, 3, half3, 2)
511//DEFINE_DOTS_LOAD_INSTANCE_VECTOR(half, 4, half4, 2)
512
513half LoadDOTSInstancedData_half(uint metadata)
514{
515 float f = LoadDOTSInstancedData_float(metadata);
516 min16float f16 = min16float(f);
517 return f16;
518}
519half LoadDOTSInstancedDataOverridden_half(uint metadata)
520{
521 float f = LoadDOTSInstancedDataOverridden_float(metadata);
522 min16float f16 = min16float(f);
523 return f16;
524}
525
526half4 LoadDOTSInstancedData_half4(uint metadata)
527{
528 float4 f = LoadDOTSInstancedData_float4(metadata);
529 min16float4 f16x4 = min16float4(f.x, f.y, f.z, f.w);
530 return f16x4;
531}
532half4 LoadDOTSInstancedDataOverridden_half4(uint metadata)
533{
534 float4 f = LoadDOTSInstancedDataOverridden_float4(metadata);
535 min16float4 f16x4 = min16float4(f.x, f.y, f.z, f.w);
536 return f16x4;
537}
538
539min16float LoadDOTSInstancedData_min16float(uint metadata)
540{
541 return min16float(LoadDOTSInstancedData_half(metadata));
542}
543min16float LoadDOTSInstancedDataOverridden_min16float(uint metadata)
544{
545 return min16float(LoadDOTSInstancedDataOverridden_half(metadata));
546}
547
548min16float4 LoadDOTSInstancedData_min16float4(uint metadata)
549{
550 return min16float4(LoadDOTSInstancedData_half4(metadata));
551}
552min16float4 LoadDOTSInstancedDataOverridden_min16float4(uint metadata)
553{
554 return min16float4(LoadDOTSInstancedDataOverridden_half4(metadata));
555}
556
557min16float LoadDOTSInstancedData_min16float(min16float default_value, uint metadata)
558{
559 return IsDOTSInstancedProperty(metadata) ?
560 LoadDOTSInstancedData_min16float(metadata) : default_value;
561}
562
563min16float4 LoadDOTSInstancedData_min16float4(min16float4 default_value, uint metadata)
564{
565 return IsDOTSInstancedProperty(metadata) ?
566 LoadDOTSInstancedData_min16float4(metadata) : default_value;
567}
568
569// TODO: Other matrix sizes
570float4x4 LoadDOTSInstancedData_float4x4(uint metadata)
571{
572 uint address = ComputeDOTSInstanceDataAddress(metadata, 4 * 16);
573 float4 p1 = asfloat(DOTSInstanceData_Load4(address + 0 * 16));
574 float4 p2 = asfloat(DOTSInstanceData_Load4(address + 1 * 16));
575 float4 p3 = asfloat(DOTSInstanceData_Load4(address + 2 * 16));
576 float4 p4 = asfloat(DOTSInstanceData_Load4(address + 3 * 16));
577 return float4x4(
578 p1.x, p2.x, p3.x, p4.x,
579 p1.y, p2.y, p3.y, p4.y,
580 p1.z, p2.z, p3.z, p4.z,
581 p1.w, p2.w, p3.w, p4.w);
582}
583float4x4 LoadDOTSInstancedDataOverridden_float4x4(uint metadata)
584{
585 uint address = ComputeDOTSInstanceDataAddressOverridden(metadata, 4 * 16);
586 float4 p1 = asfloat(DOTSInstanceData_Load4(address + 0 * 16));
587 float4 p2 = asfloat(DOTSInstanceData_Load4(address + 1 * 16));
588 float4 p3 = asfloat(DOTSInstanceData_Load4(address + 2 * 16));
589 float4 p4 = asfloat(DOTSInstanceData_Load4(address + 3 * 16));
590 return float4x4(
591 p1.x, p2.x, p3.x, p4.x,
592 p1.y, p2.y, p3.y, p4.y,
593 p1.z, p2.z, p3.z, p4.z,
594 p1.w, p2.w, p3.w, p4.w);
595}
596
597float4x4 LoadDOTSInstancedData_float4x4_from_float3x4(uint metadata)
598{
599 uint address = ComputeDOTSInstanceDataAddress(metadata, 3 * 16);
600 float4 p1 = asfloat(DOTSInstanceData_Load4(address + 0 * 16));
601 float4 p2 = asfloat(DOTSInstanceData_Load4(address + 1 * 16));
602 float4 p3 = asfloat(DOTSInstanceData_Load4(address + 2 * 16));
603
604 return float4x4(
605 p1.x, p1.w, p2.z, p3.y,
606 p1.y, p2.x, p2.w, p3.z,
607 p1.z, p2.y, p3.x, p3.w,
608 0.0, 0.0, 0.0, 1.0
609 );
610}
611float4x4 LoadDOTSInstancedDataOverridden_float4x4_from_float3x4(uint metadata)
612{
613 uint address = ComputeDOTSInstanceDataAddressOverridden(metadata, 3 * 16);
614 float4 p1 = asfloat(DOTSInstanceData_Load4(address + 0 * 16));
615 float4 p2 = asfloat(DOTSInstanceData_Load4(address + 1 * 16));
616 float4 p3 = asfloat(DOTSInstanceData_Load4(address + 2 * 16));
617
618 return float4x4(
619 p1.x, p1.w, p2.z, p3.y,
620 p1.y, p2.x, p2.w, p3.z,
621 p1.z, p2.y, p3.x, p3.w,
622 0.0, 0.0, 0.0, 1.0
623 );
624}
625
626float2x4 LoadDOTSInstancedData_float2x4(uint metadata)
627{
628 uint address = ComputeDOTSInstanceDataAddress(metadata, 4 * 8);
629 return float2x4(
630 asfloat(DOTSInstanceData_Load4(address + 0 * 8)),
631 asfloat(DOTSInstanceData_Load4(address + 1 * 8)));
632}
633float2x4 LoadDOTSInstancedDataOverridden_float2x4(uint metadata)
634{
635 uint address = ComputeDOTSInstanceDataAddressOverridden(metadata, 4 * 8);
636 return float2x4(
637 asfloat(DOTSInstanceData_Load4(address + 0 * 8)),
638 asfloat(DOTSInstanceData_Load4(address + 1 * 8)));
639}
640
641float4x4 LoadDOTSInstancedData_float4x4(float4x4 default_value, uint metadata)
642{
643 return IsDOTSInstancedProperty(metadata) ?
644 LoadDOTSInstancedData_float4x4(metadata) : default_value;
645}
646
647float4x4 LoadDOTSInstancedData_float4x4_from_float3x4(float4x4 default_value, uint metadata)
648{
649 return IsDOTSInstancedProperty(metadata) ?
650 LoadDOTSInstancedData_float4x4_from_float3x4(metadata) : default_value;
651}
652
653float2x4 LoadDOTSInstancedData_float2x4(float4 default_value[2], uint metadata)
654{
655 return IsDOTSInstancedProperty(metadata) ?
656 LoadDOTSInstancedData_float2x4(metadata) : float2x4(default_value[0], default_value[1]);
657}
658
659float2x4 LoadDOTSInstancedData_float2x4(float2x4 default_value, uint metadata)
660{
661 return IsDOTSInstancedProperty(metadata) ?
662 LoadDOTSInstancedData_float2x4(metadata) : default_value;
663}
664
665float4 LoadDOTSInstancedData_RenderingLayer()
666{
667 return float4(asfloat(unity_DOTSVisibleInstances[0].VisibleData.z), 0,0,0);
668}
669
670float3 LoadDOTSInstancedData_MeshLocalBoundCenter()
671{
672 return float3(asfloat(unity_DOTSVisibleInstances[1].VisibleData.z), asfloat(unity_DOTSVisibleInstances[1].VisibleData.w), asfloat(unity_DOTSVisibleInstances[2].VisibleData.z));
673}
674
675float3 LoadDOTSInstancedData_MeshLocalBoundExtent()
676{
677 return float3(asfloat(unity_DOTSVisibleInstances[2].VisibleData.w), asfloat(unity_DOTSVisibleInstances[3].VisibleData.z), asfloat(unity_DOTSVisibleInstances[3].VisibleData.w));
678}
679
680float4 LoadDOTSInstancedData_MotionVectorsParams()
681{
682 // See MotionVectorRendererLoop.cpp
683 static const float s_bias = -0.001;
684 uint flags = unity_DOTSVisibleInstances[0].VisibleData.w;
685 return float4(0, flags & kDOTSInstancingFlagForceZeroMotion ? 0.0f : 1.0f, s_bias, flags & kDOTSInstancingFlagCameraMotion ? 0.0f : 1.0f);
686}
687
688float4 LoadDOTSInstancedData_WorldTransformParams()
689{
690 uint flags = unity_DOTSVisibleInstances[0].VisibleData.w;
691 return float4(0, 0, 0, flags & kDOTSInstancingFlagFlipWinding ? -1.0f : 1.0f);
692}
693
694float4 LoadDOTSInstancedData_LightData()
695{
696 uint flags = unity_DOTSVisibleInstances[0].VisibleData.w;
697 // X channel = light start index (not supported in DOTS instancing)
698 // Y channel = light count (not supported in DOTS instancing)
699 // Z channel = main light strength
700 return float4(0, 0, flags & kDOTSInstancingFlagMainLightEnabled ? 1.0f : 0.0f, 0);
701}
702
703float4 LoadDOTSInstancedData_LODFade()
704{
705 int crossfadeSNorm8 = GetDOTSInstanceCrossfadeSnorm8();
706 float crossfade = clamp((float)crossfadeSNorm8, -127, 127);
707 crossfade *= 1.0 / 127;
708 return crossfade;
709}
710
711
712void SetupDOTSRendererBounds(float4x4 objectToWorld)
713{
714 float3 vCenter = mul(objectToWorld, float4(LoadDOTSInstancedData_MeshLocalBoundCenter(), 1.0f)).xyz;
715 float3 vInputExt = LoadDOTSInstancedData_MeshLocalBoundExtent();
716 float3 vExtent = abs(objectToWorld[0].xyz * vInputExt.x) +
717 abs(objectToWorld[1].xyz * vInputExt.y) +
718 abs(objectToWorld[2].xyz * vInputExt.z);
719
720 unity_DOTS_RendererBounds_Min = vCenter - vExtent;
721 unity_DOTS_RendererBounds_Max = vCenter + vExtent;
722}
723
724void SetupDOTSSHCoeffs(uint shMetadata)
725{
726 if (IsDOTSInstancedProperty(shMetadata))
727 {
728 uint address = ComputeDOTSInstanceDataAddressOverridden(shMetadata, 8 * 16);
729 unity_DOTS_Sampled_SHAr = real4(asfloat(DOTSInstanceData_Load4(address + 0 * 16)));
730 unity_DOTS_Sampled_SHAg = real4(asfloat(DOTSInstanceData_Load4(address + 1 * 16)));
731 unity_DOTS_Sampled_SHAb = real4(asfloat(DOTSInstanceData_Load4(address + 2 * 16)));
732 unity_DOTS_Sampled_SHBr = real4(asfloat(DOTSInstanceData_Load4(address + 3 * 16)));
733 unity_DOTS_Sampled_SHBg = real4(asfloat(DOTSInstanceData_Load4(address + 4 * 16)));
734 unity_DOTS_Sampled_SHBb = real4(asfloat(DOTSInstanceData_Load4(address + 5 * 16)));
735 unity_DOTS_Sampled_SHC = real4(asfloat(DOTSInstanceData_Load4(address + 6 * 16)));
736 unity_DOTS_Sampled_ProbesOcclusion = real4(asfloat(DOTSInstanceData_Load4(address + 7 * 16)));
737 }
738 else
739 {
740 unity_DOTS_Sampled_SHAr = real4(unity_DOTS_SHAr);
741 unity_DOTS_Sampled_SHAg = real4(unity_DOTS_SHAg);
742 unity_DOTS_Sampled_SHAb = real4(unity_DOTS_SHAb);
743 unity_DOTS_Sampled_SHBr = real4(unity_DOTS_SHBr);
744 unity_DOTS_Sampled_SHBg = real4(unity_DOTS_SHBg);
745 unity_DOTS_Sampled_SHBb = real4(unity_DOTS_SHBb);
746 unity_DOTS_Sampled_SHC = real4(unity_DOTS_SHC);
747 unity_DOTS_Sampled_ProbesOcclusion = real4(unity_DOTS_ProbesOcclusion);
748 }
749}
750
751real4 LoadDOTSInstancedData_SHAr() { return unity_DOTS_Sampled_SHAr; }
752real4 LoadDOTSInstancedData_SHAg() { return unity_DOTS_Sampled_SHAg; }
753real4 LoadDOTSInstancedData_SHAb() { return unity_DOTS_Sampled_SHAb; }
754real4 LoadDOTSInstancedData_SHBr() { return unity_DOTS_Sampled_SHBr; }
755real4 LoadDOTSInstancedData_SHBg() { return unity_DOTS_Sampled_SHBg; }
756real4 LoadDOTSInstancedData_SHBb() { return unity_DOTS_Sampled_SHBb; }
757real4 LoadDOTSInstancedData_SHC() { return unity_DOTS_Sampled_SHC; }
758real4 LoadDOTSInstancedData_ProbesOcclusion() { return unity_DOTS_Sampled_ProbesOcclusion; }
759float3 LoadDOTSInstancedData_RendererBounds_Min() { return unity_DOTS_RendererBounds_Min; }
760float3 LoadDOTSInstancedData_RendererBounds_Max() { return unity_DOTS_RendererBounds_Max; }
761
762float4 LoadDOTSInstancedData_SelectionValue(uint metadata, uint submeshIndex, float4 globalSelectionID)
763{
764 // If there is a DOTS instanced per-instance ID, get that.
765 if (IsDOTSInstancedProperty(metadata))
766 {
767 // Add 1 to the EntityID, so the EntityID 0 gets a value that is not equal to the clear value.
768 uint selectionID = LoadDOTSInstancedData_uint2(metadata).x;
769 uint idValue = selectionID + 1;
770
771 // 26 bits for the entity index.
772 // 5 bits for the submesh index.
773 // 1 bit which must be set when outputting an EntityID/SubmeshIndex bitpack to let Unity know that it is not a regular selection ID.
774 // When the high-bit is set, Unity will internally interpret the data as a 26-5-1 encoded bitmask and extract the EntityIndex/SubmeshIndex accordingly.
775
776 // Encode entity index with 26 bits. idValue & ((1 << 26) - 1) == idValue % (1 << 26)
777 uint idValueBits = idValue & ((1 << 26) - 1);
778
779 // Encode submesh index with 5 bits. submeshIndex & ((1 << 5) - 1) == submeshIndex % (1 << 5)
780 uint submeshBits = submeshIndex & ((1 << 5) - 1);
781 // Shift to high-bits. The 26 first bits are used by the entity index.
782 submeshBits <<= 26;
783
784 uint pickingID = (1 << 31) | submeshBits | idValueBits;
785
786 // Pack a 32-bit integer into four 8-bit color channels such that the integer can be exactly reconstructed afterwards.
787 return float4(uint4(pickingID >> 0, pickingID >> 8, pickingID >> 16, pickingID >> 24) & 0xFF) / 255.0f;
788 }
789 else
790 {
791 return globalSelectionID;
792 }
793}
794#define UNITY_ACCESS_DOTS_INSTANCED_SELECTION_VALUE(name, submesh, selectionID) \
795 LoadDOTSInstancedData_SelectionValue(UNITY_DOTS_INSTANCED_METADATA_NAME(uint2, name), submesh, selectionID)
796
797#undef DEFINE_DOTS_LOAD_INSTANCE_SCALAR
798#undef DEFINE_DOTS_LOAD_INSTANCE_VECTOR
799
800#endif // UNITY_DOTS_INSTANCING_ENABLED
801
802#endif // UNITY_DOTS_INSTANCING_INCLUDED