A game about forced loneliness, made by TACStudios
1using CellIndexInfo = UnityEngine.Rendering.ProbeReferenceVolume.CellIndexInfo;
2
3namespace UnityEngine.Rendering
4{
5 internal class ProbeGlobalIndirection
6 {
7 const int kUintPerEntry = 3;
8 internal int estimatedVMemCost { get; private set; }
9
10 // IMPORTANT! IF THIS VALUE CHANGES DATA NEEDS TO BE REBAKED.
11 internal const int kEntryMaxSubdivLevel = 3;
12
13 internal struct IndexMetaData
14 {
15 static uint[] s_PackedValues = new uint[kUintPerEntry];
16
17 internal Vector3Int minLocalIdx;
18 internal Vector3Int maxLocalIdxPlusOne;
19 internal int firstChunkIndex;
20 internal int minSubdiv;
21
22 internal void Pack(out uint[] vals)
23 {
24 vals = s_PackedValues;
25 for (int i = 0; i < kUintPerEntry; ++i)
26 {
27 vals[i] = 0;
28 }
29
30 // TODO: Note this packing is too generous, we can get rid of 1 uint
31 // minLocalIndex is in cell space so it has an upper bound
32 // first chunk index is also on 16bits max when using max memory budget
33 // see comment below about size of valid
34 //
35 // UINT 0:
36 // FirstChunkIndex 29 bit
37 // MinSubdiv 3 bit
38 // UINT 1:
39 // minLocalIdx.x 10 bit
40 // minLocalIdx.y 10 bit
41 // minLocalIdx.z 10 bit
42 // UINT 2:
43 // sizeOfValid.x 10 bit
44 // sizeOfValid.y 10 bit
45 // sizeOfValid.z 10 bit
46
47 // This is always less than CellSize(kEntryMaxSubdivLevel)+1 == 28. See GetEntrySubdivLevel()
48 var sizeOfValid = maxLocalIdxPlusOne - minLocalIdx;
49
50 vals[0] = (uint)firstChunkIndex & 0x1FFFFFFF;
51 vals[0] |= ((uint)minSubdiv & 0x7) << 29;
52
53 vals[1] = (uint)minLocalIdx.x & 0x3FF;
54 vals[1] |= ((uint)minLocalIdx.y & 0x3FF) << 10;
55 vals[1] |= ((uint)minLocalIdx.z & 0x3FF) << 20;
56
57 vals[2] = (uint)sizeOfValid.x & 0x3FF;
58 vals[2] |= ((uint)sizeOfValid.y & 0x3FF) << 10;
59 vals[2] |= ((uint)sizeOfValid.z & 0x3FF) << 20;
60 }
61 }
62
63 ComputeBuffer m_IndexOfIndicesBuffer;
64 uint[] m_IndexOfIndicesData;
65
66 int m_CellSizeInMinBricks;
67
68 Vector3Int m_EntriesCount;
69 Vector3Int m_EntryMin;
70 Vector3Int m_EntryMax;
71
72 internal void GetMinMaxEntry(out Vector3Int minEntry, out Vector3Int maxEntry)
73 {
74 minEntry = m_EntryMin;
75 maxEntry = m_EntryMax;
76 }
77
78 bool m_NeedUpdateComputeBuffer;
79
80 internal Vector3Int GetGlobalIndirectionDimension() => m_EntriesCount;
81 internal Vector3Int GetGlobalIndirectionMinEntry() => m_EntryMin;
82
83 int entrySizeInBricks => Mathf.Min((int)Mathf.Pow(ProbeBrickPool.kBrickCellCount, kEntryMaxSubdivLevel), m_CellSizeInMinBricks);
84 internal int entriesPerCellDimension => m_CellSizeInMinBricks / Mathf.Max(1, entrySizeInBricks);
85
86 int GetFlatIndex(Vector3Int normalizedPos)
87 {
88 return normalizedPos.z * (m_EntriesCount.x * m_EntriesCount.y) + normalizedPos.y * m_EntriesCount.x + normalizedPos.x;
89 }
90
91 internal ProbeGlobalIndirection(Vector3Int cellMin, Vector3Int cellMax, int cellSizeInMinBricks)
92 {
93 m_CellSizeInMinBricks = cellSizeInMinBricks;
94
95 Vector3Int cellCount = cellMax + Vector3Int.one - cellMin;
96 m_EntriesCount = cellCount * entriesPerCellDimension;
97 m_EntryMin = cellMin * entriesPerCellDimension;
98
99 m_EntryMax = (cellMax + Vector3Int.one) * entriesPerCellDimension - Vector3Int.one;
100
101 int flatEntryCount = m_EntriesCount.x * m_EntriesCount.y * m_EntriesCount.z;
102 int bufferSize = kUintPerEntry * flatEntryCount;
103 m_IndexOfIndicesBuffer = new ComputeBuffer(flatEntryCount, kUintPerEntry * sizeof(uint));
104 m_IndexOfIndicesData = new uint[bufferSize];
105 m_NeedUpdateComputeBuffer = false;
106 estimatedVMemCost = flatEntryCount * kUintPerEntry * sizeof(uint);
107 }
108
109
110 internal int GetFlatIdxForEntry(Vector3Int entryPosition)
111 {
112 Vector3Int normalizedPos = entryPosition - m_EntryMin;
113 Debug.Assert(normalizedPos.x >= 0 && normalizedPos.y >= 0 && normalizedPos.z >= 0);
114
115 return GetFlatIndex(normalizedPos);
116 }
117
118 internal int[] GetFlatIndicesForCell(Vector3Int cellPosition)
119 {
120 Vector3Int firstEntryPosition = cellPosition * entriesPerCellDimension;
121 int entriesPerCellDim = m_CellSizeInMinBricks / entrySizeInBricks;
122
123 int[] outListOfIndices = new int[entriesPerCellDimension * entriesPerCellDimension * entriesPerCellDimension];
124
125 int i = 0;
126 for (int x = 0; x < entriesPerCellDim; ++x)
127 {
128 for (int y = 0; y < entriesPerCellDim; ++y)
129 {
130 for (int z = 0; z < entriesPerCellDim; ++z)
131 {
132 outListOfIndices[i++] = GetFlatIdxForEntry(firstEntryPosition + new Vector3Int(x, y, z));
133 }
134 }
135 }
136
137 return outListOfIndices;
138 }
139
140 internal void UpdateCell(CellIndexInfo cellInfo)
141 {
142 for (int entry = 0; entry < cellInfo.flatIndicesInGlobalIndirection.Length; ++entry)
143 {
144 int entryIndex = cellInfo.flatIndicesInGlobalIndirection[entry];
145 ProbeBrickIndex.IndirectionEntryUpdateInfo entryUpdateInfo = cellInfo.updateInfo.entriesInfo[entry];
146
147 int minSubdivCellSize = ProbeReferenceVolume.CellSize(entryUpdateInfo.minSubdivInCell);
148 IndexMetaData metaData = new IndexMetaData();
149 metaData.minSubdiv = entryUpdateInfo.minSubdivInCell;
150 metaData.minLocalIdx = entryUpdateInfo.hasOnlyBiggerBricks ? Vector3Int.zero : entryUpdateInfo.minValidBrickIndexForCellAtMaxRes / minSubdivCellSize;
151 metaData.maxLocalIdxPlusOne = entryUpdateInfo.hasOnlyBiggerBricks ? Vector3Int.one : entryUpdateInfo.maxValidBrickIndexForCellAtMaxResPlusOne / minSubdivCellSize;
152 metaData.firstChunkIndex = entryUpdateInfo.firstChunkIndex;
153
154 metaData.Pack(out uint[] packedVals);
155
156 for (int i = 0; i < kUintPerEntry; ++i)
157 {
158 m_IndexOfIndicesData[entryIndex * kUintPerEntry + i] = packedVals[i];
159 }
160 }
161
162 m_NeedUpdateComputeBuffer = true;
163 }
164
165 internal void MarkEntriesAsUnloaded(int[] entriesFlatIndices)
166 {
167 for (int entry = 0; entry < entriesFlatIndices.Length; ++entry)
168 {
169 for (int i = 0; i < kUintPerEntry; ++i)
170 {
171 m_IndexOfIndicesData[entriesFlatIndices[entry] * kUintPerEntry + i] = 0xFFFFFFFF;
172 }
173 }
174 m_NeedUpdateComputeBuffer = true;
175 }
176
177
178 internal void PushComputeData()
179 {
180 m_IndexOfIndicesBuffer.SetData(m_IndexOfIndicesData);
181 m_NeedUpdateComputeBuffer = false;
182 }
183
184 internal void GetRuntimeResources(ref ProbeReferenceVolume.RuntimeResources rr)
185 {
186 // If we are pending an update of the actual compute buffer we do it here
187 if (m_NeedUpdateComputeBuffer)
188 {
189 PushComputeData();
190 }
191 rr.cellIndices = m_IndexOfIndicesBuffer;
192 }
193
194 internal void Cleanup()
195 {
196 CoreUtils.SafeRelease(m_IndexOfIndicesBuffer);
197 m_IndexOfIndicesBuffer = null;
198 }
199 }
200}