A game about forced loneliness, made by TACStudios
at master 802 lines 34 kB view raw
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