1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081 |
- using System;
- using System.Threading;
- using UnityEngine.Assertions;
- using Unity.Collections;
- using Unity.Jobs;
- using Unity.Jobs.LowLevel.Unsafe;
- using Unity.Collections.LowLevel.Unsafe;
- using Unity.Burst;
- using UnityEngine.Profiling;
-
- [assembly: RegisterGenericJobType(typeof(UnityEngine.Rendering.RegisterNewInstancesJob<UnityEngine.Rendering.BatchMeshID>))]
- [assembly: RegisterGenericJobType(typeof(UnityEngine.Rendering.RegisterNewInstancesJob<UnityEngine.Rendering.BatchMaterialID>))]
- [assembly: RegisterGenericJobType(typeof(UnityEngine.Rendering.FindNonRegisteredInstancesJob<UnityEngine.Rendering.BatchMeshID>))]
- [assembly: RegisterGenericJobType(typeof(UnityEngine.Rendering.FindNonRegisteredInstancesJob<UnityEngine.Rendering.BatchMaterialID>))]
-
- namespace UnityEngine.Rendering
- {
- internal delegate void OnCullingCompleteCallback(JobHandle jobHandle, in BatchCullingContext cullingContext, in BatchCullingOutput cullingOutput);
-
- internal struct InstanceCullingBatcherDesc
- {
- public OnCullingCompleteCallback onCompleteCallback;
-
- #if UNITY_EDITOR
- public Shader brgPicking;
- public Shader brgLoading;
- public Shader brgError;
- #endif
-
- public static InstanceCullingBatcherDesc NewDefault()
- {
- return new InstanceCullingBatcherDesc()
- {
- onCompleteCallback = null
- #if UNITY_EDITOR
- ,brgPicking = null
- ,brgLoading = null
- ,brgError = null
- #endif
- };
- }
- }
-
- internal struct MeshProceduralInfo
- {
- public MeshTopology topology;
- public uint baseVertex;
- public uint firstIndex;
- public uint indexCount;
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal struct PrefixSumDrawInstancesJob : IJob
- {
- [ReadOnly] public NativeParallelHashMap<RangeKey, int> rangeHash;
-
- public NativeList<DrawRange> drawRanges;
- public NativeList<DrawBatch> drawBatches;
- public NativeArray<int> drawBatchIndices;
-
- public void Execute()
- {
- Assert.AreEqual(rangeHash.Count(), drawRanges.Length);
- Assert.AreEqual(drawBatchIndices.Length, drawBatches.Length);
-
- // Prefix sum to calculate draw offsets for each DrawRange
- int drawPrefixSum = 0;
-
- for (int i = 0; i < drawRanges.Length; ++i)
- {
- ref DrawRange drawRange = ref drawRanges.ElementAt(i);
- drawRange.drawOffset = drawPrefixSum;
- drawPrefixSum += drawRange.drawCount;
- }
-
- // Generate DrawBatch index ranges for each DrawRange
- var internalRangeIndex = new NativeArray<int>(drawRanges.Length, Allocator.Temp);
-
- for (int i = 0; i < drawBatches.Length; ++i)
- {
- ref DrawBatch drawBatch = ref drawBatches.ElementAt(i);
- Assert.IsTrue(drawBatch.instanceCount > 0);
-
- if (rangeHash.TryGetValue(drawBatch.key.range, out int drawRangeIndex))
- {
- ref DrawRange drawRange = ref drawRanges.ElementAt(drawRangeIndex);
- drawBatchIndices[drawRange.drawOffset + internalRangeIndex[drawRangeIndex]] = i;
- internalRangeIndex[drawRangeIndex]++;
- }
- }
-
- // Prefix sum to calculate instance offsets for each DrawCommand
- int drawInstancesPrefixSum = 0;
-
- for (int i = 0; i < drawBatchIndices.Length; ++i)
- {
- // DrawIndices remap to get DrawCommands ordered by DrawRange
- var drawBatchIndex = drawBatchIndices[i];
- ref DrawBatch drawBatch = ref drawBatches.ElementAt(drawBatchIndex);
- drawBatch.instanceOffset = drawInstancesPrefixSum;
- drawInstancesPrefixSum += drawBatch.instanceCount;
- }
-
- internalRangeIndex.Dispose();
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal unsafe struct BuildDrawListsJob : IJobParallelFor
- {
- public const int k_BatchSize = 128;
- public const int k_IntsPerCacheLine = JobsUtility.CacheLineSize / sizeof(int);
-
- [ReadOnly] public NativeParallelHashMap<DrawKey, int> batchHash;
- [NativeDisableContainerSafetyRestriction, NoAlias] [ReadOnly] public NativeList<DrawInstance> drawInstances;
- [NativeDisableContainerSafetyRestriction, NoAlias] [ReadOnly] public NativeList<DrawBatch> drawBatches;
-
- [NativeDisableContainerSafetyRestriction, NoAlias] [WriteOnly] public NativeArray<int> internalDrawIndex;
- [NativeDisableContainerSafetyRestriction, NoAlias] [WriteOnly] public NativeArray<int> drawInstanceIndices;
-
- private unsafe static int IncrementCounter(int* counter)
- {
- return Interlocked.Increment(ref UnsafeUtility.AsRef<int>(counter)) - 1;
- }
-
- public void Execute(int index)
- {
- // Generate instance index ranges for each DrawCommand
- ref DrawInstance drawInstance = ref drawInstances.ElementAt(index);
- int drawBatchIndex = batchHash[drawInstance.key];
-
- ref DrawBatch drawBatch = ref drawBatches.ElementAt(drawBatchIndex);
- var offset = IncrementCounter((int*)internalDrawIndex.GetUnsafePtr() + drawBatchIndex * k_IntsPerCacheLine);
- var writeIndex = drawBatch.instanceOffset + offset;
- drawInstanceIndices[writeIndex] = drawInstance.instanceIndex;
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal unsafe struct FindDrawInstancesJob : IJobParallelForBatch
- {
- public const int k_BatchSize = 128;
-
- [ReadOnly] public NativeArray<InstanceHandle> instancesSorted;
- [NativeDisableContainerSafetyRestriction, NoAlias] [ReadOnly] public NativeList<DrawInstance> drawInstances;
-
- [WriteOnly] public NativeList<int>.ParallelWriter outDrawInstanceIndicesWriter;
-
- public void Execute(int startIndex, int count)
- {
- int* instancesToRemove = stackalloc int[k_BatchSize];
- int length = 0;
-
- for (int i = startIndex; i < startIndex + count; ++i)
- {
- ref DrawInstance drawInstance = ref drawInstances.ElementAt(i);
-
- if (instancesSorted.BinarySearch(InstanceHandle.FromInt(drawInstance.instanceIndex)) >= 0)
- instancesToRemove[length++] = i;
- }
-
- outDrawInstanceIndicesWriter.AddRangeNoResize(instancesToRemove, length);
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal unsafe struct FindMaterialDrawInstancesJob : IJobParallelForBatch
- {
- public const int k_BatchSize = 128;
-
- [ReadOnly] public NativeArray<uint> materialsSorted;
- [NativeDisableContainerSafetyRestriction, NoAlias] [ReadOnly] public NativeList<DrawInstance> drawInstances;
-
- [WriteOnly] public NativeList<int>.ParallelWriter outDrawInstanceIndicesWriter;
-
- public void Execute(int startIndex, int count)
- {
- int* instancesToRemove = stackalloc int[k_BatchSize];
- int length = 0;
-
- for (int i = startIndex; i < startIndex + count; ++i)
- {
- ref DrawInstance drawInstance = ref drawInstances.ElementAt(i);
-
- if (materialsSorted.BinarySearch(drawInstance.key.materialID.value) >= 0)
- instancesToRemove[length++] = i;
- }
-
- outDrawInstanceIndicesWriter.AddRangeNoResize(instancesToRemove, length);
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal struct FindNonRegisteredInstancesJob<T> : IJobParallelForBatch where T : unmanaged
- {
- public const int k_BatchSize = 128;
-
- [ReadOnly] public NativeArray<int> instanceIDs;
- [ReadOnly] public NativeParallelHashMap<int, T> hashMap;
-
- [WriteOnly] public NativeList<int>.ParallelWriter outInstancesWriter;
-
- public unsafe void Execute(int startIndex, int count)
- {
- int* notFoundinstanceIDs = stackalloc int[k_BatchSize];
- int length = 0;
-
- for (int i = startIndex; i < startIndex + count; ++i)
- {
- int instanceID = instanceIDs[i];
-
- if (!hashMap.ContainsKey(instanceID))
- notFoundinstanceIDs[length++] = instanceID;
- }
-
- outInstancesWriter.AddRangeNoResize(notFoundinstanceIDs, length);
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal struct RegisterNewInstancesJob<T> : IJobParallelFor where T : unmanaged
- {
- public const int k_BatchSize = 128;
-
- [ReadOnly] public NativeArray<int> instanceIDs;
- [ReadOnly] public NativeArray<T> batchIDs;
-
- [WriteOnly] public NativeParallelHashMap<int, T>.ParallelWriter hashMap;
-
- public unsafe void Execute(int index)
- {
- hashMap.TryAdd(instanceIDs[index], batchIDs[index]);
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal struct RemoveDrawInstanceIndicesJob : IJob
- {
- [NativeDisableContainerSafetyRestriction, NoAlias] [ReadOnly] public NativeArray<int> drawInstanceIndices;
-
- public NativeList<DrawInstance> drawInstances;
- public NativeParallelHashMap<RangeKey, int> rangeHash;
- public NativeParallelHashMap<DrawKey, int> batchHash;
- public NativeList<DrawRange> drawRanges;
- public NativeList<DrawBatch> drawBatches;
-
- public void RemoveDrawRange(in RangeKey key)
- {
- int drawRangeIndex = rangeHash[key];
-
- ref DrawRange lastDrawRange = ref drawRanges.ElementAt(drawRanges.Length - 1);
- rangeHash[lastDrawRange.key] = drawRangeIndex;
-
- rangeHash.Remove(key);
- drawRanges.RemoveAtSwapBack(drawRangeIndex);
- }
-
- public void RemoveDrawBatch(in DrawKey key)
- {
- int drawBatchIndex = batchHash[key];
-
- ref DrawBatch drawBatch = ref drawBatches.ElementAt(drawBatchIndex);
-
- int drawRangeIndex = rangeHash[key.range];
- ref DrawRange drawRange = ref drawRanges.ElementAt(drawRangeIndex);
-
- Assert.IsTrue(drawRange.drawCount > 0);
-
- if (--drawRange.drawCount == 0)
- RemoveDrawRange(drawRange.key);
-
- ref DrawBatch lastDrawBatch = ref drawBatches.ElementAt(drawBatches.Length - 1);
- batchHash[lastDrawBatch.key] = drawBatchIndex;
-
- batchHash.Remove(key);
- drawBatches.RemoveAtSwapBack(drawBatchIndex);
- }
-
- public unsafe void Execute()
- {
- var drawInstancesPtr = (DrawInstance*)drawInstances.GetUnsafePtr();
- var drawInstancesNewBack = drawInstances.Length - 1;
-
- for (int indexRev = drawInstanceIndices.Length - 1; indexRev >= 0; --indexRev)
- {
- int indexToRemove = drawInstanceIndices[indexRev];
- DrawInstance* drawInstance = drawInstancesPtr + indexToRemove;
-
- int drawBatchIndex = batchHash[drawInstance->key];
- ref DrawBatch drawBatch = ref drawBatches.ElementAt(drawBatchIndex);
-
- Assert.IsTrue(drawBatch.instanceCount > 0);
-
- if (--drawBatch.instanceCount == 0)
- RemoveDrawBatch(drawBatch.key);
-
- UnsafeUtility.MemCpy(drawInstance, drawInstancesPtr + drawInstancesNewBack--, sizeof(DrawInstance));
- }
-
- drawInstances.ResizeUninitialized(drawInstancesNewBack + 1);
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal struct CreateDrawBatchesJob : IJob
- {
- [ReadOnly] public bool implicitInstanceIndices;
- [ReadOnly] public NativeArray<InstanceHandle> instances;
- [ReadOnly] public GPUDrivenRendererGroupData rendererData;
- [ReadOnly] public NativeParallelHashMap<int, BatchMeshID> batchMeshHash;
- [ReadOnly] public NativeParallelHashMap<int, BatchMaterialID> batchMaterialHash;
-
- public NativeParallelHashMap<RangeKey, int> rangeHash;
- public NativeList<DrawRange> drawRanges;
- public NativeParallelHashMap<DrawKey, int> batchHash;
- public NativeList<DrawBatch> drawBatches;
-
- [WriteOnly] public NativeList<DrawInstance> drawInstances;
-
- private ref DrawRange EditDrawRange(in RangeKey key)
- {
- int drawRangeIndex;
-
- if (!rangeHash.TryGetValue(key, out drawRangeIndex))
- {
- var drawRange = new DrawRange { key = key, drawCount = 0, drawOffset = 0 };
- drawRangeIndex = drawRanges.Length;
- rangeHash.Add(key, drawRangeIndex);
- drawRanges.Add(drawRange);
- }
-
- ref DrawRange data = ref drawRanges.ElementAt(drawRangeIndex);
- Assert.IsTrue(data.key.Equals(key));
-
- return ref data;
- }
-
- private ref DrawBatch EditDrawBatch(in DrawKey key, in SubMeshDescriptor subMeshDescriptor)
- {
- var procInfo = new MeshProceduralInfo();
- procInfo.topology = subMeshDescriptor.topology;
- procInfo.baseVertex = (uint)subMeshDescriptor.baseVertex;
- procInfo.firstIndex = (uint)subMeshDescriptor.indexStart;
- procInfo.indexCount = (uint)subMeshDescriptor.indexCount;
-
- int drawBatchIndex;
-
- if (!batchHash.TryGetValue(key, out drawBatchIndex))
- {
- var drawBatch = new DrawBatch() { key = key, instanceCount = 0, instanceOffset = 0, procInfo = procInfo };
- drawBatchIndex = drawBatches.Length;
- batchHash.Add(key, drawBatchIndex);
- drawBatches.Add(drawBatch);
- }
-
- ref DrawBatch data = ref drawBatches.ElementAt(drawBatchIndex);
- Assert.IsTrue(data.key.Equals(key));
-
- return ref data;
- }
-
- public void ProcessRenderer(int i)
- {
- var meshIndex = rendererData.meshIndex[i];
- var meshID = rendererData.meshID[meshIndex];
- var submeshCount = rendererData.subMeshCount[meshIndex];
- var subMeshDescOffset = rendererData.subMeshDescOffset[meshIndex];
- var batchMeshID = batchMeshHash[meshID];
- var rendererGroupID = rendererData.rendererGroupID[i];
- var startSubMesh = rendererData.subMeshStartIndex[i];
- var gameObjectLayer = rendererData.gameObjectLayer[i];
- var renderingLayerMask = rendererData.renderingLayerMask[i];
- var materialsOffset = rendererData.materialsOffset[i];
- var materialsCount = rendererData.materialsCount[i];
- var lightmapIndex = rendererData.lightmapIndex[i];
- var packedRendererData = rendererData.packedRendererData[i];
- var rendererPriority = rendererData.rendererPriority[i];
- var lodGroupID = rendererData.lodGroupID[i];
-
- int instanceCount;
- int instanceOffset;
-
- if (implicitInstanceIndices)
- {
- instanceCount = 1;
- instanceOffset = i;
- }
- else
- {
- instanceCount = rendererData.instancesCount[i];
- instanceOffset = rendererData.instancesOffset[i];
- }
-
- if (instanceCount == 0)
- return;
-
- const int kLightmapIndexMask = 0xffff;
- const int kLightmapIndexInfluenceOnly = 0xfffe;
-
- var overridenComponents = InstanceComponentGroup.Default;
-
- // Add per-instance wind parameters
- if(packedRendererData.hasTree)
- overridenComponents |= InstanceComponentGroup.Wind;
-
- var lmIndexMasked = lightmapIndex & kLightmapIndexMask;
-
- // Object doesn't have a valid lightmap Index, -> uses probes for lighting
- if (lmIndexMasked >= kLightmapIndexInfluenceOnly)
- {
- // Only add the component when needed to store blended results (shader will use the ambient probe when not present)
- if (packedRendererData.lightProbeUsage == LightProbeUsage.BlendProbes)
- overridenComponents |= InstanceComponentGroup.LightProbe;
- }
- else
- {
- // Add per-instance lightmap parameters
- overridenComponents |= InstanceComponentGroup.Lightmap;
- }
-
- // Scan all materials once to retrieve whether this renderer is indirect-compatible or not (and store it in the RangeKey).
- var supportsIndirect = true;
- for (int matIndex = 0; matIndex < materialsCount; ++matIndex)
- {
- if (matIndex >= submeshCount)
- {
- Debug.LogWarning("Material count in the shared material list is higher than sub mesh count for the mesh. Object may be corrupted.");
- continue;
- }
-
- var materialIndex = rendererData.materialIndex[materialsOffset + matIndex];
- var packedMaterialData = rendererData.packedMaterialData[materialIndex];
- supportsIndirect &= packedMaterialData.isIndirectSupported;
- }
-
- var rangeKey = new RangeKey
- {
- layer = (byte)gameObjectLayer,
- renderingLayerMask = renderingLayerMask,
- motionMode = packedRendererData.motionVecGenMode,
- shadowCastingMode = packedRendererData.shadowCastingMode,
- staticShadowCaster = packedRendererData.staticShadowCaster,
- rendererPriority = rendererPriority,
- supportsIndirect = supportsIndirect
- };
-
- ref DrawRange drawRange = ref EditDrawRange(rangeKey);
-
- for (int matIndex = 0; matIndex < materialsCount; ++matIndex)
- {
- if (matIndex >= submeshCount)
- {
- Debug.LogWarning("Material count in the shared material list is higher than sub mesh count for the mesh. Object may be corrupted.");
- continue;
- }
-
- var materialIndex = rendererData.materialIndex[materialsOffset + matIndex];
- var materialID = rendererData.materialID[materialIndex];
- var packedMaterialData = rendererData.packedMaterialData[materialIndex];
-
- if (materialID == 0)
- {
- Debug.LogWarning("Material in the shared materials list is null. Object will be partially rendered.");
- continue;
- }
-
- batchMaterialHash.TryGetValue(materialID, out BatchMaterialID batchMaterialID);
-
- // We always provide crossfade value packed in instance index. We don't use None even if there is no LOD to not split the batch.
- var flags = BatchDrawCommandFlags.LODCrossFadeValuePacked;
-
- // Let the engine know if we've opted out of lightmap texture arrays
- flags |= BatchDrawCommandFlags.UseLegacyLightmapsKeyword;
-
- // assume that a custom motion vectors pass contains deformation motion, so should always output motion vectors
- // (otherwise this flag is set dynamically during culling only when the transform is changing)
- if (packedMaterialData.isMotionVectorsPassEnabled)
- flags |= BatchDrawCommandFlags.HasMotion;
-
- if (packedMaterialData.isTransparent)
- flags |= BatchDrawCommandFlags.HasSortingPosition;
-
- {
- var submeshIndex = startSubMesh + matIndex;
- var subMeshDesc = rendererData.subMeshDesc[subMeshDescOffset + submeshIndex];
-
- var drawKey = new DrawKey
- {
- materialID = batchMaterialID,
- meshID = batchMeshID,
- submeshIndex = submeshIndex,
- flags = flags,
- transparentInstanceId = packedMaterialData.isTransparent ? rendererGroupID : 0,
- range = rangeKey,
- overridenComponents = (uint)overridenComponents,
- // When we've opted out of lightmap texture arrays, we
- // need to pass in a valid lightmap index. The engine
- // uses this index for sorting and for breaking the
- // batch when lightmaps change across draw calls, and
- // for binding the correct light map.
- lightmapIndex = lightmapIndex
- };
-
- ref DrawBatch drawBatch = ref EditDrawBatch(drawKey, subMeshDesc);
-
- if (drawBatch.instanceCount == 0)
- ++drawRange.drawCount;
-
- drawBatch.instanceCount += instanceCount;
-
- for (int j = 0; j < instanceCount; ++j)
- {
- var instanceIndex = instanceOffset + j;
- InstanceHandle instance = instances[instanceIndex];
- drawInstances.Add(new DrawInstance { key = drawKey, instanceIndex = instance.index });
- }
- }
- }
- }
-
- public void Execute()
- {
- {
- for (int i = 0; i < rendererData.rendererGroupID.Length; ++i)
- ProcessRenderer(i);
- }
- }
- }
-
- internal class CPUDrawInstanceData
- {
- public NativeList<DrawInstance> drawInstances => m_DrawInstances;
- public NativeParallelHashMap<DrawKey, int> batchHash => m_BatchHash;
- public NativeList<DrawBatch> drawBatches => m_DrawBatches;
- public NativeParallelHashMap<RangeKey, int> rangeHash => m_RangeHash;
- public NativeList<DrawRange> drawRanges => m_DrawRanges;
- public NativeArray<int> drawBatchIndices => m_DrawBatchIndices.AsArray();
- public NativeArray<int> drawInstanceIndices => m_DrawInstanceIndices.AsArray();
-
- private NativeParallelHashMap<RangeKey, int> m_RangeHash; // index in m_DrawRanges, hashes by range state
- private NativeList<DrawRange> m_DrawRanges;
- private NativeParallelHashMap<DrawKey, int> m_BatchHash; // index in m_DrawBatches, hashed by draw state
- private NativeList<DrawBatch> m_DrawBatches;
- private NativeList<DrawInstance> m_DrawInstances;
- private NativeList<int> m_DrawInstanceIndices; // DOTS instance index, arranged in contiguous blocks in m_DrawBatches order (see DrawBatch.instanceOffset, DrawBatch.instanceCount)
- private NativeList<int> m_DrawBatchIndices; // index in m_DrawBatches, arranged in contiguous blocks in m_DrawRanges order (see DrawRange.drawOffset, DrawRange.drawCount)
-
- private bool m_NeedsRebuild;
-
- public bool valid => m_DrawInstances.IsCreated;
-
- public void Initialize()
- {
- Assert.IsTrue(!valid);
- m_RangeHash = new NativeParallelHashMap<RangeKey, int>(1024, Allocator.Persistent);
- m_DrawRanges = new NativeList<DrawRange>(Allocator.Persistent);
- m_BatchHash = new NativeParallelHashMap<DrawKey, int>(1024, Allocator.Persistent);
- m_DrawBatches = new NativeList<DrawBatch>(Allocator.Persistent);
- m_DrawInstances = new NativeList<DrawInstance>(1024, Allocator.Persistent);
- m_DrawInstanceIndices = new NativeList<int>(1024, Allocator.Persistent);
- m_DrawBatchIndices = new NativeList<int>(1024, Allocator.Persistent);
- }
-
- public void Dispose()
- {
- if (m_DrawBatchIndices.IsCreated)
- m_DrawBatchIndices.Dispose();
-
- if (m_DrawInstanceIndices.IsCreated)
- m_DrawInstanceIndices.Dispose();
-
- if (m_DrawInstances.IsCreated)
- m_DrawInstances.Dispose();
-
- if (m_DrawBatches.IsCreated)
- m_DrawBatches.Dispose();
-
- if (m_BatchHash.IsCreated)
- m_BatchHash.Dispose();
-
- if (m_DrawRanges.IsCreated)
- m_DrawRanges.Dispose();
-
- if (m_RangeHash.IsCreated)
- m_RangeHash.Dispose();
- }
-
- public void RebuildDrawListsIfNeeded()
- {
- if (!m_NeedsRebuild)
- return;
-
- m_NeedsRebuild = false;
-
- Assert.IsTrue(m_RangeHash.Count() == m_DrawRanges.Length);
- Assert.IsTrue(m_BatchHash.Count() == m_DrawBatches.Length);
-
- m_DrawInstanceIndices.ResizeUninitialized(m_DrawInstances.Length);
- m_DrawBatchIndices.ResizeUninitialized(m_DrawBatches.Length);
-
- var internalDrawIndex = new NativeArray<int>(drawBatches.Length * BuildDrawListsJob.k_IntsPerCacheLine, Allocator.TempJob, NativeArrayOptions.ClearMemory);
-
- var prefixSumDrawInstancesJob = new PrefixSumDrawInstancesJob()
- {
- rangeHash = m_RangeHash,
- drawRanges = m_DrawRanges,
- drawBatches = m_DrawBatches,
- drawBatchIndices = m_DrawBatchIndices.AsArray()
- };
-
- var prefixSumJobHandle = prefixSumDrawInstancesJob.Schedule();
-
- var buildDrawListsJob = new BuildDrawListsJob()
- {
- drawInstances = m_DrawInstances,
- batchHash = m_BatchHash,
- drawBatches = m_DrawBatches,
- internalDrawIndex = internalDrawIndex,
- drawInstanceIndices = m_DrawInstanceIndices.AsArray(),
- };
-
- buildDrawListsJob.Schedule(m_DrawInstances.Length, BuildDrawListsJob.k_BatchSize, prefixSumJobHandle).Complete();
-
- internalDrawIndex.Dispose();
- }
-
- public unsafe void DestroyDrawInstanceIndices(NativeArray<int> drawInstanceIndicesToDestroy)
- {
- Profiler.BeginSample("DestroyDrawInstanceIndices.ParallelSort");
- drawInstanceIndicesToDestroy.ParallelSort().Complete();
- Profiler.EndSample();
-
- var removeDrawInstanceIndicesJob = new RemoveDrawInstanceIndicesJob
- {
- drawInstanceIndices = drawInstanceIndicesToDestroy,
- drawInstances = m_DrawInstances,
- drawBatches = m_DrawBatches,
- drawRanges = m_DrawRanges,
- batchHash = m_BatchHash,
- rangeHash = m_RangeHash
- };
-
- removeDrawInstanceIndicesJob.Run();
- }
-
- public unsafe void DestroyDrawInstances(NativeArray<InstanceHandle> destroyedInstances)
- {
- if (m_DrawInstances.IsEmpty || destroyedInstances.Length == 0)
- return;
-
- NeedsRebuild();
-
- var destroyedInstancesSorted = new NativeArray<InstanceHandle>(destroyedInstances, Allocator.TempJob);
- Assert.AreEqual(UnsafeUtility.SizeOf<InstanceHandle>(), UnsafeUtility.SizeOf<int>());
-
- Profiler.BeginSample("DestroyDrawInstances.ParallelSort");
- destroyedInstancesSorted.Reinterpret<int>().ParallelSort().Complete();
- Profiler.EndSample();
-
- var drawInstanceIndicesToDestroy = new NativeList<int>(m_DrawInstances.Length, Allocator.TempJob);
-
- var findDrawInstancesJobHandle = new FindDrawInstancesJob()
- {
- instancesSorted = destroyedInstancesSorted,
- drawInstances = m_DrawInstances,
- outDrawInstanceIndicesWriter = drawInstanceIndicesToDestroy.AsParallelWriter()
- };
-
- findDrawInstancesJobHandle.ScheduleBatch(m_DrawInstances.Length, FindDrawInstancesJob.k_BatchSize).Complete();
-
- DestroyDrawInstanceIndices(drawInstanceIndicesToDestroy.AsArray());
-
- destroyedInstancesSorted.Dispose();
- drawInstanceIndicesToDestroy.Dispose();
- }
-
- public unsafe void DestroyMaterialDrawInstances(NativeArray<uint> destroyedBatchMaterials)
- {
- if (m_DrawInstances.IsEmpty || destroyedBatchMaterials.Length == 0)
- return;
-
- NeedsRebuild();
-
- var destroyedBatchMaterialsSorted = new NativeArray<uint>(destroyedBatchMaterials, Allocator.TempJob);
-
- Profiler.BeginSample("DestroyedBatchMaterials.ParallelSort");
- destroyedBatchMaterialsSorted.Reinterpret<int>().ParallelSort().Complete();
- Profiler.EndSample();
-
- var drawInstanceIndicesToDestroy = new NativeList<int>(m_DrawInstances.Length, Allocator.TempJob);
-
- var findDrawInstancesJobHandle = new FindMaterialDrawInstancesJob()
- {
- materialsSorted = destroyedBatchMaterialsSorted,
- drawInstances = m_DrawInstances,
- outDrawInstanceIndicesWriter = drawInstanceIndicesToDestroy.AsParallelWriter()
- };
-
- findDrawInstancesJobHandle.ScheduleBatch(m_DrawInstances.Length, FindMaterialDrawInstancesJob.k_BatchSize).Complete();
-
- DestroyDrawInstanceIndices(drawInstanceIndicesToDestroy.AsArray());
-
- destroyedBatchMaterialsSorted.Dispose();
- drawInstanceIndicesToDestroy.Dispose();
- }
-
- public void NeedsRebuild()
- {
- m_NeedsRebuild = true;
- }
- }
-
- internal class InstanceCullingBatcher : IDisposable
- {
- private RenderersBatchersContext m_BatchersContext;
- private CPUDrawInstanceData m_DrawInstanceData;
- private BatchRendererGroup m_BRG;
- private NativeParallelHashMap<uint, BatchID> m_GlobalBatchIDs;
- private InstanceCuller m_Culler;
- private NativeParallelHashMap<int, BatchMaterialID> m_BatchMaterialHash;
- private NativeParallelHashMap<int, BatchMeshID> m_BatchMeshHash;
-
- private int m_CachedInstanceDataBufferLayoutVersion;
-
- private OnCullingCompleteCallback m_OnCompleteCallback;
-
- public InstanceCullingBatcher(RenderersBatchersContext batcherContext, InstanceCullingBatcherDesc desc, BatchRendererGroup.OnFinishedCulling onFinishedCulling)
- {
- m_BatchersContext = batcherContext;
- m_DrawInstanceData = new CPUDrawInstanceData();
- m_DrawInstanceData.Initialize();
-
- m_BRG = new BatchRendererGroup(new BatchRendererGroupCreateInfo()
- {
- cullingCallback = OnPerformCulling,
- finishedCullingCallback = onFinishedCulling,
- userContext = IntPtr.Zero
- });
-
- #if UNITY_EDITOR
- if (desc.brgPicking != null)
- {
- var mat = new Material(desc.brgPicking);
- mat.hideFlags = HideFlags.HideAndDontSave;
- m_BRG.SetPickingMaterial(mat);
- }
- if (desc.brgLoading != null)
- {
- var mat = new Material(desc.brgLoading);
- mat.hideFlags = HideFlags.HideAndDontSave;
- m_BRG.SetLoadingMaterial(mat);
- }
- if (desc.brgError != null)
- {
- var mat = new Material(desc.brgError);
- mat.hideFlags = HideFlags.HideAndDontSave;
- m_BRG.SetErrorMaterial(mat);
- }
- var viewTypes = new BatchCullingViewType[] {
- BatchCullingViewType.Light,
- BatchCullingViewType.Camera,
- BatchCullingViewType.Picking,
- BatchCullingViewType.SelectionOutline,
- BatchCullingViewType.Filtering
- };
- m_BRG.SetEnabledViewTypes(viewTypes);
- #endif
-
- m_Culler = new InstanceCuller();
- m_Culler.Init(batcherContext.resources, batcherContext.debugStats);
-
- m_CachedInstanceDataBufferLayoutVersion = -1;
- m_OnCompleteCallback = desc.onCompleteCallback;
- m_BatchMaterialHash = new NativeParallelHashMap<int, BatchMaterialID>(64, Allocator.Persistent);
- m_BatchMeshHash = new NativeParallelHashMap<int, BatchMeshID>(64, Allocator.Persistent);
-
- m_GlobalBatchIDs = new NativeParallelHashMap<uint, BatchID>(6, Allocator.Persistent);
- m_GlobalBatchIDs.Add((uint)InstanceComponentGroup.Default, GetBatchID(InstanceComponentGroup.Default));
- m_GlobalBatchIDs.Add((uint)InstanceComponentGroup.DefaultWind, GetBatchID(InstanceComponentGroup.DefaultWind));
- m_GlobalBatchIDs.Add((uint)InstanceComponentGroup.DefaultLightProbe, GetBatchID(InstanceComponentGroup.DefaultLightProbe));
- m_GlobalBatchIDs.Add((uint)InstanceComponentGroup.DefaultLightmap, GetBatchID(InstanceComponentGroup.DefaultLightmap));
- m_GlobalBatchIDs.Add((uint)InstanceComponentGroup.DefaultWindLightProbe, GetBatchID(InstanceComponentGroup.DefaultWindLightProbe));
- m_GlobalBatchIDs.Add((uint)InstanceComponentGroup.DefaultWindLightmap, GetBatchID(InstanceComponentGroup.DefaultWindLightmap));
- }
-
- internal ref InstanceCuller culler => ref m_Culler;
-
- public void Dispose()
- {
- m_OnCompleteCallback = null;
- m_Culler.Dispose();
-
- foreach (var batchID in m_GlobalBatchIDs)
- {
- if (!batchID.Value.Equals(BatchID.Null))
- m_BRG.RemoveBatch(batchID.Value);
- }
- m_GlobalBatchIDs.Dispose();
-
- if (m_BRG != null)
- m_BRG.Dispose();
-
- m_DrawInstanceData.Dispose();
- m_DrawInstanceData = null;
-
- m_BatchMaterialHash.Dispose();
- m_BatchMeshHash.Dispose();
- }
-
- private BatchID GetBatchID(InstanceComponentGroup componentsOverriden)
- {
- if (m_CachedInstanceDataBufferLayoutVersion != m_BatchersContext.instanceDataBufferLayoutVersion)
- return BatchID.Null;
-
- Assert.IsTrue(m_BatchersContext.defaultDescriptions.Length == m_BatchersContext.defaultMetadata.Length);
-
- const uint kClearIsOverriddenBit = 0x4FFFFFFF;
- var tempMetadata = new NativeList<MetadataValue>(m_BatchersContext.defaultMetadata.Length, Allocator.Temp);
-
- for(int i = 0; i < m_BatchersContext.defaultDescriptions.Length; ++i)
- {
- var componentGroup = m_BatchersContext.defaultDescriptions[i].componentGroup;
- var metadata = m_BatchersContext.defaultMetadata[i];
- var value = metadata.Value;
-
- // if instances in this batch do not override the component, clear the override bit
- if ((componentsOverriden & componentGroup) == 0)
- value &= kClearIsOverriddenBit;
-
- tempMetadata.Add(new MetadataValue
- {
- NameID = metadata.NameID,
- Value = value
- });
- }
-
- return m_BRG.AddBatch(tempMetadata.AsArray(), m_BatchersContext.gpuInstanceDataBuffer.bufferHandle);
- }
-
- private void UpdateInstanceDataBufferLayoutVersion()
- {
- if (m_CachedInstanceDataBufferLayoutVersion != m_BatchersContext.instanceDataBufferLayoutVersion)
- {
- m_CachedInstanceDataBufferLayoutVersion = m_BatchersContext.instanceDataBufferLayoutVersion;
-
- foreach (var componentsToBatchID in m_GlobalBatchIDs)
- {
- var batchID = componentsToBatchID.Value;
- if (!batchID.Equals(BatchID.Null))
- m_BRG.RemoveBatch(batchID);
-
- var componentsOverriden = (InstanceComponentGroup)componentsToBatchID.Key;
- componentsToBatchID.Value = GetBatchID(componentsOverriden);
- }
- }
- }
-
- public CPUDrawInstanceData GetDrawInstanceData()
- {
- return m_DrawInstanceData;
- }
-
- public unsafe JobHandle OnPerformCulling(
- BatchRendererGroup rendererGroup,
- BatchCullingContext cc,
- BatchCullingOutput cullingOutput,
- IntPtr userContext)
- {
- foreach (var batchID in m_GlobalBatchIDs)
- {
- if (batchID.Value.Equals(BatchID.Null))
- return new JobHandle();
- }
-
- m_DrawInstanceData.RebuildDrawListsIfNeeded();
-
- bool allowOcclusionCulling = m_BatchersContext.hasBoundingSpheres;
- JobHandle jobHandle = m_Culler.CreateCullJobTree(
- cc,
- cullingOutput,
- m_BatchersContext.instanceData,
- m_BatchersContext.sharedInstanceData,
- m_BatchersContext.instanceDataBuffer,
- m_BatchersContext.lodGroupCullingData,
- m_DrawInstanceData,
- m_GlobalBatchIDs,
- m_BatchersContext.crossfadedRendererCount,
- m_BatchersContext.smallMeshScreenPercentage,
- allowOcclusionCulling ? m_BatchersContext.occlusionCullingCommon : null);
-
- if (m_OnCompleteCallback != null)
- m_OnCompleteCallback(jobHandle, cc, cullingOutput);
-
- return jobHandle;
- }
-
- public void OnFinishedCulling(IntPtr customCullingResult)
- {
- int viewInstanceID = (int)customCullingResult;
- m_Culler.EnsureValidOcclusionTestResults(viewInstanceID);
- }
-
- public void DestroyInstances(NativeArray<InstanceHandle> instances)
- {
- if (instances.Length == 0)
- return;
-
- Profiler.BeginSample("DestroyInstances");
-
- m_DrawInstanceData.DestroyDrawInstances(instances);
-
- Profiler.EndSample();
- }
-
- public void DestroyMaterials(NativeArray<int> destroyedMaterials)
- {
- if (destroyedMaterials.Length == 0)
- return;
-
- Profiler.BeginSample("DestroyMaterials");
-
- var destroyedBatchMaterials = new NativeList<uint>(destroyedMaterials.Length, Allocator.TempJob);
-
- foreach (int destroyedMaterial in destroyedMaterials)
- {
- if (m_BatchMaterialHash.TryGetValue(destroyedMaterial, out var destroyedBatchMaterial))
- {
- destroyedBatchMaterials.Add(destroyedBatchMaterial.value);
- m_BatchMaterialHash.Remove(destroyedMaterial);
- m_BRG.UnregisterMaterial(destroyedBatchMaterial);
- }
- }
-
- m_DrawInstanceData.DestroyMaterialDrawInstances(destroyedBatchMaterials.AsArray());
-
- destroyedBatchMaterials.Dispose();
-
- Profiler.EndSample();
- }
-
- public void DestroyMeshes(NativeArray<int> destroyedMeshes)
- {
- if (destroyedMeshes.Length == 0)
- return;
-
- Profiler.BeginSample("DestroyMeshes");
-
- foreach (int destroyedMesh in destroyedMeshes)
- {
- if (m_BatchMeshHash.TryGetValue(destroyedMesh, out var destroyedBatchMesh))
- {
- m_BatchMeshHash.Remove(destroyedMesh);
- m_BRG.UnregisterMesh(destroyedBatchMesh);
- }
- }
-
- Profiler.EndSample();
- }
-
- public void PostCullBeginCameraRendering(RenderRequestBatcherContext context)
- {
- }
-
- private void RegisterBatchMeshes(NativeArray<int> meshIDs)
- {
- var newMeshIDs = new NativeList<int>(meshIDs.Length, Allocator.TempJob);
- new FindNonRegisteredInstancesJob<BatchMeshID>
- {
- instanceIDs = meshIDs,
- hashMap = m_BatchMeshHash,
- outInstancesWriter = newMeshIDs.AsParallelWriter()
- }
- .ScheduleBatch(meshIDs.Length, FindNonRegisteredInstancesJob<BatchMeshID>.k_BatchSize).Complete();
- var newBatchMeshIDs = new NativeArray<BatchMeshID>(newMeshIDs.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
- m_BRG.RegisterMeshes(newMeshIDs.AsArray(), newBatchMeshIDs);
-
- int totalMeshesNum = m_BatchMeshHash.Count() + newBatchMeshIDs.Length;
- m_BatchMeshHash.Capacity = Math.Max(m_BatchMeshHash.Capacity, Mathf.CeilToInt(totalMeshesNum / 1023.0f) * 1024);
-
- new RegisterNewInstancesJob<BatchMeshID>
- {
- instanceIDs = newMeshIDs.AsArray(),
- batchIDs = newBatchMeshIDs,
- hashMap = m_BatchMeshHash.AsParallelWriter()
- }
- .Schedule(newMeshIDs.Length, RegisterNewInstancesJob<BatchMeshID>.k_BatchSize).Complete();
-
- newMeshIDs.Dispose();
- newBatchMeshIDs.Dispose();
- }
-
- private void RegisterBatchMaterials(in NativeArray<int> usedMaterialIDs)
- {
- var newMaterialIDs = new NativeList<int>(usedMaterialIDs.Length, Allocator.TempJob);
- new FindNonRegisteredInstancesJob<BatchMaterialID>
- {
- instanceIDs = usedMaterialIDs,
- hashMap = m_BatchMaterialHash,
- outInstancesWriter = newMaterialIDs.AsParallelWriter()
- }
- .ScheduleBatch(usedMaterialIDs.Length, FindNonRegisteredInstancesJob<BatchMaterialID>.k_BatchSize).Complete();
-
- var newBatchMaterialIDs = new NativeArray<BatchMaterialID>(newMaterialIDs.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
- m_BRG.RegisterMaterials(newMaterialIDs.AsArray(), newBatchMaterialIDs);
-
- int totalMaterialsNum = m_BatchMaterialHash.Count() + newMaterialIDs.Length;
- m_BatchMaterialHash.Capacity = Math.Max(m_BatchMaterialHash.Capacity, Mathf.CeilToInt(totalMaterialsNum / 1023.0f) * 1024);
-
- new RegisterNewInstancesJob<BatchMaterialID>
- {
- instanceIDs = newMaterialIDs.AsArray(),
- batchIDs = newBatchMaterialIDs,
- hashMap = m_BatchMaterialHash.AsParallelWriter()
- }
- .Schedule(newMaterialIDs.Length, RegisterNewInstancesJob<BatchMaterialID>.k_BatchSize).Complete();
-
- newMaterialIDs.Dispose();
- newBatchMaterialIDs.Dispose();
- }
-
- public void BuildBatch(
- NativeArray<InstanceHandle> instances,
- NativeArray<int> usedMaterialIDs,
- NativeArray<int> usedMeshIDs,
- in GPUDrivenRendererGroupData rendererData)
- {
- RegisterBatchMaterials(usedMaterialIDs);
- RegisterBatchMeshes(usedMeshIDs);
-
- new CreateDrawBatchesJob
- {
- implicitInstanceIndices = rendererData.instancesCount.Length == 0,
- instances = instances,
- rendererData = rendererData,
- batchMeshHash = m_BatchMeshHash,
- batchMaterialHash = m_BatchMaterialHash,
- rangeHash = m_DrawInstanceData.rangeHash,
- drawRanges = m_DrawInstanceData.drawRanges,
- batchHash = m_DrawInstanceData.batchHash,
- drawBatches = m_DrawInstanceData.drawBatches,
- drawInstances = m_DrawInstanceData.drawInstances
- }.Run();
-
- m_DrawInstanceData.NeedsRebuild();
- UpdateInstanceDataBufferLayoutVersion();
- }
-
- public void InstanceOccludersUpdated(int viewInstanceID, int subviewMask)
- {
- m_Culler.InstanceOccludersUpdated(viewInstanceID, subviewMask, m_BatchersContext);
- }
-
- public void UpdateFrame()
- {
- m_Culler.UpdateFrame();
- }
-
- public ParallelBitArray GetCompactedVisibilityMasks(bool syncCullingJobs)
- {
- return m_Culler.GetCompactedVisibilityMasks(syncCullingJobs);
- }
-
- public void OnEndContextRendering()
- {
- ParallelBitArray compactedVisibilityMasks = GetCompactedVisibilityMasks(syncCullingJobs: true);
-
- if(compactedVisibilityMasks.IsCreated)
- m_BatchersContext.UpdatePerFrameInstanceVisibility(compactedVisibilityMasks);
- }
-
- public void OnBeginCameraRendering(Camera camera)
- {
- m_Culler.OnBeginCameraRendering(camera);
- }
-
- public void OnEndCameraRendering(Camera camera)
- {
- m_Culler.OnEndCameraRendering(camera);
- }
- }
- }
|