You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
8.3 KiB
223 lines
8.3 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using UnityEngine.Assertions;
|
|
using static UnityEngine.Rendering.RenderersParameters;
|
|
|
|
namespace UnityEngine.Rendering
|
|
{
|
|
internal struct GPUInstanceComponentDesc
|
|
{
|
|
public int propertyID;
|
|
public int byteSize;
|
|
public bool isOverriden;
|
|
public bool isPerInstance;
|
|
public InstanceType instanceType;
|
|
public InstanceComponentGroup componentGroup;
|
|
|
|
public GPUInstanceComponentDesc(int inPropertyID, int inByteSize, bool inIsOverriden, bool inPerInstance, InstanceType inInstanceType, InstanceComponentGroup inComponentType)
|
|
{
|
|
propertyID = inPropertyID;
|
|
byteSize = inByteSize;
|
|
isOverriden = inIsOverriden;
|
|
isPerInstance = inPerInstance;
|
|
instanceType = inInstanceType;
|
|
componentGroup = inComponentType;
|
|
}
|
|
}
|
|
|
|
internal class GPUInstanceDataBuffer : IDisposable
|
|
{
|
|
private static int s_NextLayoutVersion = 0;
|
|
public static int NextVersion() { return ++s_NextLayoutVersion; }
|
|
|
|
public InstanceNumInfo instanceNumInfo;
|
|
public NativeArray<int> instancesNumPrefixSum;
|
|
public NativeArray<int> instancesSpan;
|
|
public int byteSize;
|
|
public int perInstanceComponentCount;
|
|
public int version;
|
|
public int layoutVersion;
|
|
public GraphicsBuffer gpuBuffer;
|
|
public GraphicsBuffer validComponentsIndicesGpuBuffer;
|
|
public GraphicsBuffer componentAddressesGpuBuffer;
|
|
public GraphicsBuffer componentInstanceIndexRangesGpuBuffer;
|
|
public GraphicsBuffer componentByteCountsGpuBuffer;
|
|
public NativeArray<GPUInstanceComponentDesc> descriptions;
|
|
public NativeArray<MetadataValue> defaultMetadata;
|
|
public NativeArray<int> gpuBufferComponentAddress;
|
|
public NativeParallelHashMap<int, int> nameToMetadataMap;
|
|
|
|
public bool valid => instancesSpan.IsCreated;
|
|
|
|
private static GPUInstanceIndex CPUInstanceToGPUInstance(in NativeArray<int> instancesNumPrefixSum, InstanceHandle instance)
|
|
{
|
|
bool valid = instance.valid && instance.type < InstanceType.Count;
|
|
#if DEBUG
|
|
Assert.IsTrue(valid);
|
|
#endif
|
|
|
|
if (!valid)
|
|
return GPUInstanceIndex.Invalid;
|
|
|
|
int instanceType = (int)instance.type;
|
|
int perTypeInstanceIndex = instance.instanceIndex;
|
|
int gpuInstanceIndex = instancesNumPrefixSum[instanceType] + perTypeInstanceIndex;
|
|
|
|
return new GPUInstanceIndex { index = gpuInstanceIndex };
|
|
}
|
|
|
|
public int GetPropertyIndex(int propertyID, bool assertOnFail = true)
|
|
{
|
|
if (nameToMetadataMap.TryGetValue(propertyID, out int componentIndex))
|
|
{
|
|
return componentIndex;
|
|
}
|
|
|
|
if (assertOnFail)
|
|
Assert.IsTrue(false, "Count not find gpu address for parameter specified: " + propertyID);
|
|
return -1;
|
|
}
|
|
|
|
public int GetGpuAddress(string strName, bool assertOnFail = true)
|
|
{
|
|
int componentIndex = GetPropertyIndex(Shader.PropertyToID(strName), false);
|
|
if (assertOnFail && componentIndex == -1)
|
|
Assert.IsTrue(false, "Count not find gpu address for parameter specified: " + strName);
|
|
|
|
return componentIndex != -1 ? gpuBufferComponentAddress[componentIndex] : -1;
|
|
}
|
|
|
|
public int GetGpuAddress(int propertyID, bool assertOnFail = true)
|
|
{
|
|
int componentIndex = GetPropertyIndex(propertyID, assertOnFail);
|
|
return componentIndex != -1 ? gpuBufferComponentAddress[componentIndex] : -1;
|
|
}
|
|
|
|
public GPUInstanceIndex CPUInstanceToGPUInstance(InstanceHandle instance)
|
|
{
|
|
return CPUInstanceToGPUInstance(instancesNumPrefixSum, instance);
|
|
}
|
|
|
|
public unsafe InstanceHandle GPUInstanceToCPUInstance(GPUInstanceIndex gpuInstanceIndex)
|
|
{
|
|
var instanceIndex = gpuInstanceIndex.index;
|
|
InstanceType instanceType = InstanceType.Count;
|
|
|
|
for(int i = 0; i < (int)InstanceType.Count; ++i)
|
|
{
|
|
int instanceNum = instanceNumInfo.GetInstanceNum((InstanceType)i);
|
|
if(instanceIndex < instanceNum)
|
|
{
|
|
instanceType = (InstanceType)i;
|
|
break;
|
|
}
|
|
instanceIndex -= instanceNum;
|
|
}
|
|
|
|
if(instanceType == InstanceType.Count)
|
|
return InstanceHandle.Invalid;
|
|
|
|
Assert.IsTrue(instanceIndex < instanceNumInfo.GetInstanceNum(instanceType));
|
|
return InstanceHandle.Create(instanceIndex, instanceType);
|
|
}
|
|
|
|
public void CPUInstanceArrayToGPUInstanceArray(NativeArray<InstanceHandle> instances, NativeArray<GPUInstanceIndex> gpuInstanceIndices)
|
|
{
|
|
Assert.AreEqual(instances.Length, gpuInstanceIndices.Length);
|
|
|
|
Profiling.Profiler.BeginSample("CPUInstanceArrayToGPUInstanceArray");
|
|
|
|
new ConvertCPUInstancesToGPUInstancesJob { instancesNumPrefixSum = instancesNumPrefixSum, instances = instances, gpuInstanceIndices = gpuInstanceIndices }
|
|
.Schedule(instances.Length, ConvertCPUInstancesToGPUInstancesJob.k_BatchSize).Complete();
|
|
|
|
Profiling.Profiler.EndSample();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if(instancesSpan.IsCreated)
|
|
instancesSpan.Dispose();
|
|
|
|
if(instancesNumPrefixSum.IsCreated)
|
|
instancesNumPrefixSum.Dispose();
|
|
|
|
if (descriptions.IsCreated)
|
|
descriptions.Dispose();
|
|
|
|
if (defaultMetadata.IsCreated)
|
|
defaultMetadata.Dispose();
|
|
|
|
if (gpuBufferComponentAddress.IsCreated)
|
|
gpuBufferComponentAddress.Dispose();
|
|
|
|
if (nameToMetadataMap.IsCreated)
|
|
nameToMetadataMap.Dispose();
|
|
|
|
if (gpuBuffer != null)
|
|
gpuBuffer.Release();
|
|
|
|
if (validComponentsIndicesGpuBuffer != null)
|
|
validComponentsIndicesGpuBuffer.Release();
|
|
|
|
if (componentAddressesGpuBuffer != null)
|
|
componentAddressesGpuBuffer.Release();
|
|
|
|
if (componentInstanceIndexRangesGpuBuffer != null)
|
|
componentInstanceIndexRangesGpuBuffer.Release();
|
|
|
|
if (componentByteCountsGpuBuffer != null)
|
|
componentByteCountsGpuBuffer.Release();
|
|
}
|
|
|
|
public ReadOnly AsReadOnly()
|
|
{
|
|
return new ReadOnly(this);
|
|
}
|
|
|
|
internal readonly struct ReadOnly
|
|
{
|
|
private readonly NativeArray<int> instancesNumPrefixSum;
|
|
|
|
public ReadOnly(GPUInstanceDataBuffer buffer)
|
|
{
|
|
instancesNumPrefixSum = buffer.instancesNumPrefixSum;
|
|
}
|
|
|
|
public GPUInstanceIndex CPUInstanceToGPUInstance(InstanceHandle instance)
|
|
{
|
|
return GPUInstanceDataBuffer.CPUInstanceToGPUInstance(instancesNumPrefixSum, instance);
|
|
}
|
|
|
|
public void CPUInstanceArrayToGPUInstanceArray(NativeArray<InstanceHandle> instances, NativeArray<GPUInstanceIndex> gpuInstanceIndices)
|
|
{
|
|
Assert.AreEqual(instances.Length, gpuInstanceIndices.Length);
|
|
|
|
Profiling.Profiler.BeginSample("CPUInstanceArrayToGPUInstanceArray");
|
|
|
|
new ConvertCPUInstancesToGPUInstancesJob { instancesNumPrefixSum = instancesNumPrefixSum, instances = instances, gpuInstanceIndices = gpuInstanceIndices }
|
|
.Schedule(instances.Length, ConvertCPUInstancesToGPUInstancesJob.k_BatchSize).Complete();
|
|
|
|
Profiling.Profiler.EndSample();
|
|
}
|
|
}
|
|
|
|
[BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
|
|
struct ConvertCPUInstancesToGPUInstancesJob : IJobParallelFor
|
|
{
|
|
public const int k_BatchSize = 512;
|
|
|
|
[ReadOnly] public NativeArray<int> instancesNumPrefixSum;
|
|
[ReadOnly] public NativeArray<InstanceHandle> instances;
|
|
|
|
[WriteOnly] public NativeArray<GPUInstanceIndex> gpuInstanceIndices;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
gpuInstanceIndices[index] = CPUInstanceToGPUInstance(instancesNumPrefixSum, instances[index]);
|
|
}
|
|
}
|
|
}
|
|
}
|