123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- using System;
- using UnityEngine.Assertions;
- using Unity.Collections;
- using Unity.Jobs;
- using Unity.Collections.LowLevel.Unsafe;
- using Unity.Burst;
- using Unity.Mathematics;
-
- namespace UnityEngine.Rendering
- {
- internal unsafe struct LODGroupData
- {
- public const int k_MaxLODLevelsCount = 8;
-
- public bool valid;
- public int lodCount;
- public int rendererCount;
- public fixed float screenRelativeTransitionHeights[k_MaxLODLevelsCount];
- public fixed float fadeTransitionWidth[k_MaxLODLevelsCount];
- }
-
- internal unsafe struct LODGroupCullingData
- {
- public float3 worldSpaceReferencePoint;
- public int lodCount;
- public fixed float sqrDistances[LODGroupData.k_MaxLODLevelsCount]; // we use square distance to get rid of a sqrt in gpu culling..
- public fixed float transitionDistances[LODGroupData.k_MaxLODLevelsCount]; // todo - make this a separate data struct (CPUOnly, as we do not support dithering on GPU..)
- public float worldSpaceSize;// SpeedTree crossfade.
- public fixed bool percentageFlags[LODGroupData.k_MaxLODLevelsCount];// SpeedTree crossfade.
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal struct UpdateLODGroupTransformJob : IJobParallelFor
- {
- public const int k_BatchSize = 256;
-
- [ReadOnly] public NativeParallelHashMap<int, GPUInstanceIndex> lodGroupDataHash;
- [ReadOnly] public NativeArray<int> lodGroupIDs;
- [ReadOnly] public NativeArray<Vector3> worldSpaceReferencePoints;
- [ReadOnly] public NativeArray<float> worldSpaceSizes;
- [ReadOnly] public bool requiresGPUUpload;
- [ReadOnly] public bool supportDitheringCrossFade;
-
- [NativeDisableContainerSafetyRestriction, NoAlias, ReadOnly] public NativeList<LODGroupData> lodGroupData;
-
- [NativeDisableContainerSafetyRestriction, NoAlias, WriteOnly] public NativeList<LODGroupCullingData> lodGroupCullingData;
-
- [NativeDisableUnsafePtrRestriction] public UnsafeAtomicCounter32 atomicUpdateCount;
-
- public unsafe void Execute(int index)
- {
- int lodGroupID = lodGroupIDs[index];
-
- if (lodGroupDataHash.TryGetValue(lodGroupID, out var lodGroupInstance))
- {
- var worldSpaceSize = worldSpaceSizes[index];
-
- LODGroupData* lodGroup = (LODGroupData*)lodGroupData.GetUnsafePtr() + lodGroupInstance.index;
- LODGroupCullingData* lodGroupTransformResult = (LODGroupCullingData*)lodGroupCullingData.GetUnsafePtr() + lodGroupInstance.index;
- lodGroupTransformResult->worldSpaceSize = worldSpaceSize;
- lodGroupTransformResult->worldSpaceReferencePoint = worldSpaceReferencePoints[index];
-
- for (int i = 0; i < lodGroup->lodCount; ++i)
- {
- float lodHeight = lodGroup->screenRelativeTransitionHeights[i];
-
- var lodDist = LODGroupRenderingUtils.CalculateLODDistance(lodHeight, worldSpaceSize);
- lodGroupTransformResult->sqrDistances[i] = lodDist * lodDist;
-
- if (supportDitheringCrossFade && !lodGroupTransformResult->percentageFlags[i])
- {
- float prevLODHeight = i != 0 ? lodGroup->screenRelativeTransitionHeights[i - 1] : 1.0f;
- float transitionHeight = lodHeight + lodGroup->fadeTransitionWidth[i] * (prevLODHeight - lodHeight);
- var transitionDistance = lodDist - LODGroupRenderingUtils.CalculateLODDistance(transitionHeight, worldSpaceSize);
- transitionDistance = Mathf.Max(0.0f, transitionDistance);
- lodGroupTransformResult->transitionDistances[i] = transitionDistance;
- }
- else
- {
- lodGroupTransformResult->transitionDistances[i] = 0f;
- }
-
- }
- }
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal unsafe struct AllocateOrGetLODGroupDataInstancesJob : IJob
- {
- [ReadOnly] public NativeArray<int> lodGroupsID;
-
- public NativeList<LODGroupData> lodGroupsData;
- public NativeList<LODGroupCullingData> lodGroupCullingData;
- public NativeParallelHashMap<int, GPUInstanceIndex> lodGroupDataHash;
- public NativeList<GPUInstanceIndex> freeLODGroupDataHandles;
-
- [WriteOnly] public NativeArray<GPUInstanceIndex> lodGroupInstances;
-
- [NativeDisableUnsafePtrRestriction] public int* previousRendererCount;
-
- public void Execute()
- {
- int freeHandlesCount = freeLODGroupDataHandles.Length;
- int lodDataLength = lodGroupsData.Length;
-
- for (int i = 0; i < lodGroupsID.Length; ++i)
- {
- int lodGroupID = lodGroupsID[i];
-
- if (!lodGroupDataHash.TryGetValue(lodGroupID, out var lodGroupInstance))
- {
- if (freeHandlesCount == 0)
- lodGroupInstance = new GPUInstanceIndex() { index = lodDataLength++ };
- else
- lodGroupInstance = freeLODGroupDataHandles[--freeHandlesCount];
-
- lodGroupDataHash.TryAdd(lodGroupID, lodGroupInstance);
- }
- else
- {
- *previousRendererCount += lodGroupsData.ElementAt(lodGroupInstance.index).rendererCount;
- }
-
- lodGroupInstances[i] = lodGroupInstance;
- }
-
- freeLODGroupDataHandles.ResizeUninitialized(freeHandlesCount);
- lodGroupsData.ResizeUninitialized(lodDataLength);
- lodGroupCullingData.ResizeUninitialized(lodDataLength);
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal unsafe struct UpdateLODGroupDataJob : IJobParallelFor
- {
- public const int k_BatchSize = 256;
-
- [ReadOnly] public NativeArray<GPUInstanceIndex> lodGroupInstances;
- [ReadOnly] public GPUDrivenLODGroupData inputData;
- [ReadOnly] public bool supportDitheringCrossFade;
-
- public NativeArray<LODGroupData> lodGroupsData;
- public NativeArray<LODGroupCullingData> lodGroupsCullingData;
-
- [NativeDisableUnsafePtrRestriction] public UnsafeAtomicCounter32 rendererCount;
-
- public void Execute(int index)
- {
- var lodGroupInstance = lodGroupInstances[index];
- var fadeMode = inputData.fadeMode[index];
- var lodOffset = inputData.lodOffset[index];
- var lodCount = inputData.lodCount[index];
- var renderersCount = inputData.renderersCount[index];
- var worldReferencePoint = inputData.worldSpaceReferencePoint[index];
- var worldSpaceSize = inputData.worldSpaceSize[index];
- var lastLODIsBillboard = inputData.lastLODIsBillboard[index];
- var useDitheringCrossFade = fadeMode != LODFadeMode.None && supportDitheringCrossFade;
- var useSpeedTreeCrossFade = fadeMode == LODFadeMode.SpeedTree;
-
- LODGroupData* lodGroupData = (LODGroupData*)lodGroupsData.GetUnsafePtr() + lodGroupInstance.index;
- LODGroupCullingData* lodGroupCullingData = (LODGroupCullingData*)lodGroupsCullingData.GetUnsafePtr() + lodGroupInstance.index;
-
- lodGroupData->valid = true;
- lodGroupData->lodCount = lodCount;
- lodGroupData->rendererCount = useDitheringCrossFade ? renderersCount : 0;
- lodGroupCullingData->worldSpaceSize = worldSpaceSize;
- lodGroupCullingData->worldSpaceReferencePoint = worldReferencePoint;
- lodGroupCullingData->lodCount = lodCount;
-
- rendererCount.Add(lodGroupData->rendererCount);
-
- var crossFadeLODBegin = 0;
-
- if (useSpeedTreeCrossFade)
- {
- var lastLODIndex = lodOffset + (lodCount - 1);
- var hasBillboardLOD = lodCount > 0 && inputData.lodRenderersCount[lastLODIndex] == 1 && lastLODIsBillboard;
-
- if (lodCount == 0)
- crossFadeLODBegin = 0;
- else if (hasBillboardLOD)
- crossFadeLODBegin = Math.Max(lodCount, 2) - 2;
- else
- crossFadeLODBegin = lodCount - 1;
- }
-
- for (int i = 0; i < lodCount; ++i)
- {
- var lodIndex = lodOffset + i;
- var lodHeight = inputData.lodScreenRelativeTransitionHeight[lodIndex];
- var lodDist = LODGroupRenderingUtils.CalculateLODDistance(lodHeight, worldSpaceSize);
-
- lodGroupData->screenRelativeTransitionHeights[i] = lodHeight;
- lodGroupData->fadeTransitionWidth[i] = 0.0f;
- lodGroupCullingData->sqrDistances[i] = lodDist * lodDist;
- lodGroupCullingData->percentageFlags[i] = false;
- lodGroupCullingData->transitionDistances[i] = 0.0f;
-
- if (useSpeedTreeCrossFade && i < crossFadeLODBegin)
- {
- lodGroupCullingData->percentageFlags[i] = true;
- }
- else if (useDitheringCrossFade && i >= crossFadeLODBegin)
- {
- var fadeTransitionWidth = inputData.lodFadeTransitionWidth[lodIndex];
- var prevLODHeight = i != 0 ? inputData.lodScreenRelativeTransitionHeight[lodIndex - 1] : 1.0f;
- var transitionHeight = lodHeight + fadeTransitionWidth * (prevLODHeight - lodHeight);
- var transitionDistance = lodDist - LODGroupRenderingUtils.CalculateLODDistance(transitionHeight, worldSpaceSize);
- transitionDistance = Mathf.Max(0.0f, transitionDistance);
-
- lodGroupData->fadeTransitionWidth[i] = fadeTransitionWidth;
- lodGroupCullingData->transitionDistances[i] = transitionDistance;
- }
- }
- }
- }
-
- [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
- internal unsafe struct FreeLODGroupDataJob : IJob
- {
- [ReadOnly] public NativeArray<int> destroyedLODGroupsID;
-
- public NativeList<LODGroupData> lodGroupsData;
- public NativeParallelHashMap<int, GPUInstanceIndex> lodGroupDataHash;
- public NativeList<GPUInstanceIndex> freeLODGroupDataHandles;
-
- [NativeDisableUnsafePtrRestriction] public int* removedRendererCount;
-
- public void Execute()
- {
- foreach (int lodGroupID in destroyedLODGroupsID)
- {
- if (lodGroupDataHash.TryGetValue(lodGroupID, out var lodGroupInstance))
- {
- Assert.IsTrue(lodGroupInstance.valid);
-
- lodGroupDataHash.Remove(lodGroupID);
- freeLODGroupDataHandles.Add(lodGroupInstance);
-
- ref LODGroupData lodGroupData = ref lodGroupsData.ElementAt(lodGroupInstance.index);
- Assert.IsTrue(lodGroupData.valid);
-
- *removedRendererCount += lodGroupData.rendererCount;
- lodGroupData.valid = false;
- }
- }
- }
- }
-
- internal class LODGroupDataPool : IDisposable
- {
- private NativeList<LODGroupData> m_LODGroupData;
- private NativeParallelHashMap<int, GPUInstanceIndex> m_LODGroupDataHash;
- public NativeParallelHashMap<int, GPUInstanceIndex> lodGroupDataHash => m_LODGroupDataHash;
-
- private NativeList<LODGroupCullingData> m_LODGroupCullingData;
- private NativeList<GPUInstanceIndex> m_FreeLODGroupDataHandles;
-
- private int m_CrossfadedRendererCount;
- private bool m_SupportDitheringCrossFade;
-
- public NativeList<LODGroupCullingData> lodGroupCullingData => m_LODGroupCullingData;
- public int crossfadedRendererCount => m_CrossfadedRendererCount;
-
- public int activeLodGroupCount => m_LODGroupData.Length;
-
- private static class LodGroupShaderIDs
- {
- public static readonly int _SupportDitheringCrossFade = Shader.PropertyToID("_SupportDitheringCrossFade");
- public static readonly int _LodGroupCullingDataGPUByteSize = Shader.PropertyToID("_LodGroupCullingDataGPUByteSize");
- public static readonly int _LodGroupCullingDataStartOffset = Shader.PropertyToID("_LodGroupCullingDataStartOffset");
- public static readonly int _LodCullingDataQueueCount = Shader.PropertyToID("_LodCullingDataQueueCount");
- public static readonly int _InputLodCullingDataIndices = Shader.PropertyToID("_InputLodCullingDataIndices");
- public static readonly int _InputLodCullingDataBuffer = Shader.PropertyToID("_InputLodCullingDataBuffer");
- public static readonly int _LodGroupCullingData = Shader.PropertyToID("_LodGroupCullingData");
- }
-
- public LODGroupDataPool(GPUResidentDrawerResources resources, int initialInstanceCount, bool supportDitheringCrossFade)
- {
- m_LODGroupData = new NativeList<LODGroupData>(Allocator.Persistent);
- m_LODGroupDataHash = new NativeParallelHashMap<int, GPUInstanceIndex>(64, Allocator.Persistent);
-
- m_LODGroupCullingData = new NativeList<LODGroupCullingData>(Allocator.Persistent);
- m_FreeLODGroupDataHandles = new NativeList<GPUInstanceIndex>(Allocator.Persistent);
-
- m_SupportDitheringCrossFade = supportDitheringCrossFade;
- }
-
- public void Dispose()
- {
- m_LODGroupData.Dispose();
- m_LODGroupDataHash.Dispose();
-
- m_LODGroupCullingData.Dispose();
- m_FreeLODGroupDataHandles.Dispose();
- }
-
- public unsafe void UpdateLODGroupTransformData(in GPUDrivenLODGroupData inputData)
- {
- var lodGroupCount = inputData.lodGroupID.Length;
-
- var updateCount = 0;
-
- var jobData = new UpdateLODGroupTransformJob()
- {
- lodGroupDataHash = m_LODGroupDataHash,
- lodGroupIDs = inputData.lodGroupID,
- worldSpaceReferencePoints = inputData.worldSpaceReferencePoint,
- worldSpaceSizes = inputData.worldSpaceSize,
- lodGroupData = m_LODGroupData,
- lodGroupCullingData = m_LODGroupCullingData,
- supportDitheringCrossFade = m_SupportDitheringCrossFade,
- atomicUpdateCount = new UnsafeAtomicCounter32(&updateCount),
- };
-
- if (lodGroupCount >= UpdateLODGroupTransformJob.k_BatchSize)
- jobData.Schedule(lodGroupCount, UpdateLODGroupTransformJob.k_BatchSize).Complete();
- else
- jobData.Run(lodGroupCount);
- }
-
- public unsafe void UpdateLODGroupData(in GPUDrivenLODGroupData inputData)
- {
- FreeLODGroupData(inputData.invalidLODGroupID);
-
- var lodGroupInstances = new NativeArray<GPUInstanceIndex>(inputData.lodGroupID.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
-
- int previousRendererCount = 0;
-
- new AllocateOrGetLODGroupDataInstancesJob
- {
- lodGroupsID = inputData.lodGroupID,
- lodGroupsData = m_LODGroupData,
- lodGroupCullingData = m_LODGroupCullingData,
- lodGroupDataHash = m_LODGroupDataHash,
- freeLODGroupDataHandles = m_FreeLODGroupDataHandles,
- lodGroupInstances = lodGroupInstances,
- previousRendererCount = &previousRendererCount
- }.Run();
-
- m_CrossfadedRendererCount -= previousRendererCount;
- Assert.IsTrue(m_CrossfadedRendererCount >= 0);
-
- int rendererCount = 0;
-
- var updateLODGroupDataJobData = new UpdateLODGroupDataJob
- {
- lodGroupInstances = lodGroupInstances,
- inputData = inputData,
- supportDitheringCrossFade = m_SupportDitheringCrossFade,
- lodGroupsData = m_LODGroupData.AsArray(),
- lodGroupsCullingData = m_LODGroupCullingData.AsArray(),
- rendererCount = new UnsafeAtomicCounter32(&rendererCount),
- };
-
- if (lodGroupInstances.Length >= UpdateLODGroupTransformJob.k_BatchSize)
- updateLODGroupDataJobData.Schedule(lodGroupInstances.Length, UpdateLODGroupTransformJob.k_BatchSize).Complete();
- else
- updateLODGroupDataJobData.Run(lodGroupInstances.Length);
-
- m_CrossfadedRendererCount += rendererCount;
-
- lodGroupInstances.Dispose();
- }
-
- public unsafe void FreeLODGroupData(NativeArray<int> destroyedLODGroupsID)
- {
- if (destroyedLODGroupsID.Length == 0)
- return;
-
- int removedRendererCount = 0;
-
- new FreeLODGroupDataJob
- {
- destroyedLODGroupsID = destroyedLODGroupsID,
- lodGroupsData = m_LODGroupData,
- lodGroupDataHash = m_LODGroupDataHash,
- freeLODGroupDataHandles = m_FreeLODGroupDataHandles,
- removedRendererCount = &removedRendererCount
- }.Run();
-
- m_CrossfadedRendererCount -= removedRendererCount;
- Assert.IsTrue(m_CrossfadedRendererCount >= 0);
- }
- }
- }
|