A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using Unity.Burst;
4using Unity.Collections;
5using Unity.Jobs;
6using UnityEngine.Assertions;
7using static UnityEngine.Rendering.RenderersParameters;
8
9namespace UnityEngine.Rendering
10{
11 internal struct GPUInstanceComponentDesc
12 {
13 public int propertyID;
14 public int byteSize;
15 public bool isOverriden;
16 public bool isPerInstance;
17 public InstanceType instanceType;
18 public InstanceComponentGroup componentGroup;
19
20 public GPUInstanceComponentDesc(int inPropertyID, int inByteSize, bool inIsOverriden, bool inPerInstance, InstanceType inInstanceType, InstanceComponentGroup inComponentType)
21 {
22 propertyID = inPropertyID;
23 byteSize = inByteSize;
24 isOverriden = inIsOverriden;
25 isPerInstance = inPerInstance;
26 instanceType = inInstanceType;
27 componentGroup = inComponentType;
28 }
29 }
30
31 internal class GPUInstanceDataBuffer : IDisposable
32 {
33 private static int s_NextLayoutVersion = 0;
34 public static int NextVersion() { return ++s_NextLayoutVersion; }
35
36 public InstanceNumInfo instanceNumInfo;
37 public NativeArray<int> instancesNumPrefixSum;
38 public NativeArray<int> instancesSpan;
39 public int byteSize;
40 public int perInstanceComponentCount;
41 public int version;
42 public int layoutVersion;
43 public GraphicsBuffer gpuBuffer;
44 public GraphicsBuffer validComponentsIndicesGpuBuffer;
45 public GraphicsBuffer componentAddressesGpuBuffer;
46 public GraphicsBuffer componentInstanceIndexRangesGpuBuffer;
47 public GraphicsBuffer componentByteCountsGpuBuffer;
48 public NativeArray<GPUInstanceComponentDesc> descriptions;
49 public NativeArray<MetadataValue> defaultMetadata;
50 public NativeArray<int> gpuBufferComponentAddress;
51 public NativeParallelHashMap<int, int> nameToMetadataMap;
52
53 public bool valid => instancesSpan.IsCreated;
54
55 private static GPUInstanceIndex CPUInstanceToGPUInstance(in NativeArray<int> instancesNumPrefixSum, InstanceHandle instance)
56 {
57 bool valid = instance.valid && instance.type < InstanceType.Count;
58#if DEBUG
59 Assert.IsTrue(valid);
60#endif
61
62 if (!valid)
63 return GPUInstanceIndex.Invalid;
64
65 int instanceType = (int)instance.type;
66 int perTypeInstanceIndex = instance.instanceIndex;
67 int gpuInstanceIndex = instancesNumPrefixSum[instanceType] + perTypeInstanceIndex;
68
69 return new GPUInstanceIndex { index = gpuInstanceIndex };
70 }
71
72 public int GetPropertyIndex(int propertyID, bool assertOnFail = true)
73 {
74 if (nameToMetadataMap.TryGetValue(propertyID, out int componentIndex))
75 {
76 return componentIndex;
77 }
78
79 if (assertOnFail)
80 Assert.IsTrue(false, "Count not find gpu address for parameter specified: " + propertyID);
81 return -1;
82 }
83
84 public int GetGpuAddress(string strName, bool assertOnFail = true)
85 {
86 int componentIndex = GetPropertyIndex(Shader.PropertyToID(strName), false);
87 if (assertOnFail && componentIndex == -1)
88 Assert.IsTrue(false, "Count not find gpu address for parameter specified: " + strName);
89
90 return componentIndex != -1 ? gpuBufferComponentAddress[componentIndex] : -1;
91 }
92
93 public int GetGpuAddress(int propertyID, bool assertOnFail = true)
94 {
95 int componentIndex = GetPropertyIndex(propertyID, assertOnFail);
96 return componentIndex != -1 ? gpuBufferComponentAddress[componentIndex] : -1;
97 }
98
99 public GPUInstanceIndex CPUInstanceToGPUInstance(InstanceHandle instance)
100 {
101 return CPUInstanceToGPUInstance(instancesNumPrefixSum, instance);
102 }
103
104 public unsafe InstanceHandle GPUInstanceToCPUInstance(GPUInstanceIndex gpuInstanceIndex)
105 {
106 var instanceIndex = gpuInstanceIndex.index;
107 InstanceType instanceType = InstanceType.Count;
108
109 for(int i = 0; i < (int)InstanceType.Count; ++i)
110 {
111 int instanceNum = instanceNumInfo.GetInstanceNum((InstanceType)i);
112 if(instanceIndex < instanceNum)
113 {
114 instanceType = (InstanceType)i;
115 break;
116 }
117 instanceIndex -= instanceNum;
118 }
119
120 if(instanceType == InstanceType.Count)
121 return InstanceHandle.Invalid;
122
123 Assert.IsTrue(instanceIndex < instanceNumInfo.GetInstanceNum(instanceType));
124 return InstanceHandle.Create(instanceIndex, instanceType);
125 }
126
127 public void CPUInstanceArrayToGPUInstanceArray(NativeArray<InstanceHandle> instances, NativeArray<GPUInstanceIndex> gpuInstanceIndices)
128 {
129 Assert.AreEqual(instances.Length, gpuInstanceIndices.Length);
130
131 Profiling.Profiler.BeginSample("CPUInstanceArrayToGPUInstanceArray");
132
133 new ConvertCPUInstancesToGPUInstancesJob { instancesNumPrefixSum = instancesNumPrefixSum, instances = instances, gpuInstanceIndices = gpuInstanceIndices }
134 .Schedule(instances.Length, ConvertCPUInstancesToGPUInstancesJob.k_BatchSize).Complete();
135
136 Profiling.Profiler.EndSample();
137 }
138
139 public void Dispose()
140 {
141 if(instancesSpan.IsCreated)
142 instancesSpan.Dispose();
143
144 if(instancesNumPrefixSum.IsCreated)
145 instancesNumPrefixSum.Dispose();
146
147 if (descriptions.IsCreated)
148 descriptions.Dispose();
149
150 if (defaultMetadata.IsCreated)
151 defaultMetadata.Dispose();
152
153 if (gpuBufferComponentAddress.IsCreated)
154 gpuBufferComponentAddress.Dispose();
155
156 if (nameToMetadataMap.IsCreated)
157 nameToMetadataMap.Dispose();
158
159 if (gpuBuffer != null)
160 gpuBuffer.Release();
161
162 if (validComponentsIndicesGpuBuffer != null)
163 validComponentsIndicesGpuBuffer.Release();
164
165 if (componentAddressesGpuBuffer != null)
166 componentAddressesGpuBuffer.Release();
167
168 if (componentInstanceIndexRangesGpuBuffer != null)
169 componentInstanceIndexRangesGpuBuffer.Release();
170
171 if (componentByteCountsGpuBuffer != null)
172 componentByteCountsGpuBuffer.Release();
173 }
174
175 public ReadOnly AsReadOnly()
176 {
177 return new ReadOnly(this);
178 }
179
180 internal readonly struct ReadOnly
181 {
182 private readonly NativeArray<int> instancesNumPrefixSum;
183
184 public ReadOnly(GPUInstanceDataBuffer buffer)
185 {
186 instancesNumPrefixSum = buffer.instancesNumPrefixSum;
187 }
188
189 public GPUInstanceIndex CPUInstanceToGPUInstance(InstanceHandle instance)
190 {
191 return GPUInstanceDataBuffer.CPUInstanceToGPUInstance(instancesNumPrefixSum, instance);
192 }
193
194 public void CPUInstanceArrayToGPUInstanceArray(NativeArray<InstanceHandle> instances, NativeArray<GPUInstanceIndex> gpuInstanceIndices)
195 {
196 Assert.AreEqual(instances.Length, gpuInstanceIndices.Length);
197
198 Profiling.Profiler.BeginSample("CPUInstanceArrayToGPUInstanceArray");
199
200 new ConvertCPUInstancesToGPUInstancesJob { instancesNumPrefixSum = instancesNumPrefixSum, instances = instances, gpuInstanceIndices = gpuInstanceIndices }
201 .Schedule(instances.Length, ConvertCPUInstancesToGPUInstancesJob.k_BatchSize).Complete();
202
203 Profiling.Profiler.EndSample();
204 }
205 }
206
207 [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
208 struct ConvertCPUInstancesToGPUInstancesJob : IJobParallelFor
209 {
210 public const int k_BatchSize = 512;
211
212 [ReadOnly] public NativeArray<int> instancesNumPrefixSum;
213 [ReadOnly] public NativeArray<InstanceHandle> instances;
214
215 [WriteOnly] public NativeArray<GPUInstanceIndex> gpuInstanceIndices;
216
217 public void Execute(int index)
218 {
219 gpuInstanceIndices[index] = CPUInstanceToGPUInstance(instancesNumPrefixSum, instances[index]);
220 }
221 }
222 }
223}