// Number of instances in current drawcall/dispatch #define instancingCurrentCount asuint(instancingConstants.x) // Number of instances that are active at the time of the drawcall/dispatch // ContextData // instancingCurrentCount <= instancingActiveCount #define instancingActiveCount asuint(instancingConstants.y) // Number of instances that this batch can hold // instancingActiveCount <= instancingBatchSize #define instancingBatchSize asuint(instancingConstants.z) // Current instance offset for rendering #define instancingCurrentOffset asuint(instancingConstants.w) #define instancingActiveIndirectOffset instancingBufferOffsets.x #ifndef instancingPrefixSumOffset // Already defined in VFXInit.template because it is always 0 for Init. #define instancingPrefixSumOffset instancingBufferOffsets.y #endif #if VFX_INSTANCING_VARIABLE_SIZE // Prefix sum with particle counts for each active instance StructuredBuffer instancingPrefixSum; #endif #if VFX_INSTANCING_BATCH_INDIRECTION // Indirection buffer, the first section contains the active -> batch index indirection. One entry for each active instance, holding the instance index in the batch // The next sections contains current -> active index indirection, for each split. One entry for each instance in current drawcall/dispatch, holding the index in the active instances StructuredBuffer instancingIndirectAndActiveIndirect; #endif #define DEAD_LIST_COUNT_COPY_OFFSET instancingBatchSize #define DEAD_LIST_OFFSET (2 * instancingBatchSize) #if defined(VFX_INSTANCING_VARIABLE_SIZE) // Get instance index in current drawcall/dispatch, for variable size instances uint VFXGetVariableSizeInstanceIndex(inout uint index) { uint startIndex = instancingCurrentOffset + instancingPrefixSumOffset; uint endIndex = instancingCurrentCount + instancingCurrentOffset + instancingPrefixSumOffset; return BinarySearchPrefixSum(index, instancingPrefixSum, startIndex, endIndex, index) - instancingPrefixSumOffset; } #elif defined(VFX_INSTANCING_FIXED_SIZE) // Get instance index in current drawcall/dispatch, for fixed size instances uint VFXGetFixedSizeInstanceIndex(inout uint index) { uint instanceIndex = index / VFX_INSTANCING_FIXED_SIZE; instanceIndex = min(instanceIndex, instancingCurrentCount - 1); index -= instanceIndex * VFX_INSTANCING_FIXED_SIZE; return instanceIndex + instancingCurrentOffset; } #endif // Get instance index in current drawcall/dispatch, from particle index uint VFXGetInstanceCurrentIndex(inout uint index) { #if defined(VFX_INSTANCING_VARIABLE_SIZE) return VFXGetVariableSizeInstanceIndex(index); #elif defined(VFX_INSTANCING_FIXED_SIZE) return VFXGetFixedSizeInstanceIndex(index); #else return 0; #endif } // Get instance index in the active instances, from instance index in current drawcall/dispatch uint VFXGetInstanceActiveIndex(uint instanceCurrentIndex) { uint instanceActiveIndex = instanceCurrentIndex; #if VFX_INSTANCING_ACTIVE_INDIRECTION if (instancingCurrentCount < instancingActiveCount) { instanceActiveIndex = instancingIndirectAndActiveIndirect[instancingActiveIndirectOffset + instanceActiveIndex]; } #endif return instanceActiveIndex; } // Get instance index in the batch, from instance index in the active instances uint VFXGetInstanceBatchIndex(uint instanceActiveIndex) { uint instanceBatchIndex = instanceActiveIndex; #if VFX_INSTANCING_BATCH_INDIRECTION if (instancingActiveCount < instancingBatchSize) { instanceBatchIndex = instancingIndirectAndActiveIndirect[instanceBatchIndex]; } #endif return instanceBatchIndex; } uint VFXInitInstancing(uint index, out uint instanceIndex, out uint instanceActiveIndex, out uint instanceCurrentIndex) { instanceIndex = instanceActiveIndex = instanceCurrentIndex = 0; #if VFX_USE_INSTANCING #if SHADER_STAGE_COMPUTE // In compute shaders instanceCurrentIndex = VFXGetInstanceCurrentIndex(index); instanceActiveIndex = VFXGetInstanceActiveIndex(instanceCurrentIndex); instanceIndex = VFXGetInstanceBatchIndex(instanceActiveIndex); #else // In VS shaders #ifdef UNITY_INSTANCING_ENABLED { instanceCurrentIndex = VFXGetInstanceCurrentIndex(index); unity_InstanceID = instanceCurrentIndex; } #endif instanceActiveIndex = asuint(UNITY_ACCESS_INSTANCED_PROP(PerInstance, _InstanceActiveIndex)); instanceIndex = asuint(UNITY_ACCESS_INSTANCED_PROP(PerInstance, _InstanceIndex)); #endif #endif return index; } #if VFX_HAS_INDIRECT_DRAW uint VFXGetIndirectBufferIndex(uint index, uint instanceActiveIndex) { return RAW_CAPACITY * instanceActiveIndex + instancingBatchSize + index; } #endif #define VFX_GPU_EVENT_SUPPORT_INSTANCING 0 uint VFXGetEventListBufferIndex(uint index, uint instanceActiveIndex) { #if VFX_GPU_EVENT_SUPPORT_INSTANCING return RAW_CAPACITY * instanceActiveIndex + instancingBatchSize * 2u + index; #else return 2u + index; #endif } uint VFXGetEventListBufferElementCount(uint instanceActiveIndex) { #if VFX_GPU_EVENT_SUPPORT_INSTANCING return instancingBatchSize * 0u + instanceActiveIndex; #else return 0u; #endif } uint VFXGetEventListBufferAccumulatedCount(uint instanceActiveIndex) { #if VFX_GPU_EVENT_SUPPORT_INSTANCING return instancingBatchSize * 1u + instanceActiveIndex; #else return 1u; #endif } void AppendEventTotalCount(RWStructuredBuffer outputBuffer, uint totalCount, uint instanceActiveIndex) { uint localInstancingBatchSize = instancingBatchSize; #if !VFX_GPU_EVENT_SUPPORT_INSTANCING instanceActiveIndex = 0u; localInstancingBatchSize = 1u; #endif InterlockedAdd(outputBuffer[localInstancingBatchSize + instanceActiveIndex], totalCount); } void AppendEventBuffer(RWStructuredBuffer outputBuffer, uint sourceIndex, uint outputCapacity, uint instanceActiveIndex) { uint eventIndex; uint localInstancingBatchSize = instancingBatchSize; #if !VFX_GPU_EVENT_SUPPORT_INSTANCING instanceActiveIndex = 0u; localInstancingBatchSize = 1u; #endif InterlockedAdd(outputBuffer[instanceActiveIndex], 1u, eventIndex); [branch] if (eventIndex < outputCapacity) { eventIndex += localInstancingBatchSize * 2u + instanceActiveIndex * outputCapacity; outputBuffer[eventIndex] = sourceIndex; } }