1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "BsLightGrid.h"
4#include "RenderAPI/BsGpuBuffer.h"
5#include "Material/BsGpuParamsSet.h"
6#include "Renderer/BsRendererUtility.h"
7#include "BsRendererView.h"
8#include "BsRendererLight.h"
9#include "BsRendererReflectionProbe.h"
10#include "BsTiledDeferred.h"
11
12namespace bs { namespace ct
13{
14 static const UINT32 CELL_XY_SIZE = 64;
15 static const UINT32 NUM_Z_SUBDIVIDES = 32;
16 static const UINT32 MAX_LIGHTS_PER_CELL = 32;
17 static const UINT32 THREADGROUP_SIZE = 4;
18
19 LightGridParamDef gLightGridParamDefDef;
20
21 LightGridLLCreationMat::LightGridLLCreationMat()
22 {
23 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gLights", mLightBufferParam);
24 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsCounter", mLightsCounterParam);
25 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsLLHeads", mLightsLLHeadsParam);
26 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsLL", mLightsLLParam);
27
28 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gReflectionProbes", mProbesBufferParam);
29 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesCounter", mProbesCounterParam);
30 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesLLHeads", mProbesLLHeadsParam);
31 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesLL", mProbesLLParam);
32
33 GPU_BUFFER_DESC desc;
34 desc.elementCount = 1;
35 desc.format = BF_UNKNOWN;
36 desc.usage = GBU_LOADSTORE;
37 desc.type = GBT_STRUCTURED;
38 desc.elementSize = 4;
39
40 mLightsCounter = GpuBuffer::create(desc);
41 mLightsCounterParam.set(mLightsCounter);
42
43 mProbesCounter = GpuBuffer::create(desc);
44 mProbesCounterParam.set(mProbesCounter);
45 }
46
47 void LightGridLLCreationMat::_initDefines(ShaderDefines& defines)
48 {
49 defines.set("THREADGROUP_SIZE", THREADGROUP_SIZE);
50 }
51
52 void LightGridLLCreationMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
53 const SPtr<GpuBuffer>& lightsBuffer, const SPtr<GpuBuffer>& probesBuffer)
54 {
55 mGridSize = gridSize;
56 UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];
57
58 if(numCells > mBufferNumCells || mBufferNumCells == 0)
59 {
60 GPU_BUFFER_DESC desc;
61 desc.elementCount = numCells;
62 desc.format = BF_UNKNOWN;
63 desc.usage = GBU_LOADSTORE;
64 desc.type = GBT_STRUCTURED;
65 desc.elementSize = 4;
66
67 mLightsLLHeads = GpuBuffer::create(desc);
68 mLightsLLHeadsParam.set(mLightsLLHeads);
69
70 mProbesLLHeads = GpuBuffer::create(desc);
71 mProbesLLHeadsParam.set(mProbesLLHeads);
72
73 desc.type = GBT_STANDARD;
74 desc.format = BF_32X4U;
75 desc.elementCount = numCells * MAX_LIGHTS_PER_CELL;
76 desc.elementSize = 0;
77
78 mLightsLL = GpuBuffer::create(desc);
79 mLightsLLParam.set(mLightsLL);
80
81 desc.format = BF_32X2U;
82 mProbesLL = GpuBuffer::create(desc);
83 mProbesLLParam.set(mProbesLL);
84
85 mBufferNumCells = numCells;
86 }
87
88 ClearLoadStoreMat* clearMat = ClearLoadStoreMat::getVariation(
89 ClearLoadStoreType::StructuredBuffer, ClearLoadStoreDataType::Int, 1
90 );
91
92 clearMat->execute(mLightsCounter);
93 clearMat->execute(mProbesCounter);
94
95 UINT32 clearValue = 0xFFFFFFFF;
96 Color clearColor;
97 clearColor.r = *(float*) &clearValue;
98 clearColor.g = *(float*) &clearValue;
99 clearColor.b = *(float*) &clearValue;
100 clearColor.a = *(float*) &clearValue;
101
102 clearMat->execute(mLightsLLHeads, clearColor);
103 clearMat->execute(mProbesLLHeads, clearColor);
104
105 mParams->setParamBlockBuffer("GridParams", gridParams);
106 mLightBufferParam.set(lightsBuffer);
107 mProbesBufferParam.set(probesBuffer);
108 }
109
110 void LightGridLLCreationMat::execute(const RendererView& view)
111 {
112 BS_RENMAT_PROFILE_BLOCK
113
114 mParams->setParamBlockBuffer("PerCamera", view.getPerViewBuffer());
115
116 UINT32 numGroupsX = (mGridSize[0] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
117 UINT32 numGroupsY = (mGridSize[1] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
118 UINT32 numGroupsZ = (mGridSize[2] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
119
120 bind();
121 RenderAPI::instance().dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
122 }
123
124 void LightGridLLCreationMat::getOutputs(SPtr<GpuBuffer>& lightsLLHeads, SPtr<GpuBuffer>& lightsLL,
125 SPtr<GpuBuffer>& probesLLHeads, SPtr<GpuBuffer>& probesLL) const
126 {
127 lightsLLHeads = mLightsLLHeads;
128 lightsLL = mLightsLL;
129 probesLLHeads = mProbesLLHeads;
130 probesLL = mProbesLL;
131 }
132
133 LightGridLLReductionMat::LightGridLLReductionMat()
134 :mBufferNumCells(0)
135 {
136 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsLLHeads", mLightsLLHeadsParam);
137 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsLL", mLightsLLParam);
138
139 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesLLHeads", mProbesLLHeadsParam);
140 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesLL", mProbesLLParam);
141
142 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridDataCounter", mGridDataCounterParam);
143
144 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridLightOffsetAndSize", mGridLightOffsetAndSizeParam);
145 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridLightIndices", mGridLightIndicesParam);
146
147 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridProbeOffsetAndSize", mGridProbeOffsetAndSizeParam);
148 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridProbeIndices", mGridProbeIndicesParam);
149
150 GPU_BUFFER_DESC desc;
151 desc.elementCount = 2;
152 desc.format = BF_UNKNOWN;
153 desc.usage = GBU_LOADSTORE;
154 desc.type = GBT_STRUCTURED;
155 desc.elementSize = 4;
156
157 mGridDataCounter = GpuBuffer::create(desc);
158 mGridDataCounterParam.set(mGridDataCounter);
159 }
160
161 void LightGridLLReductionMat::_initDefines(ShaderDefines& defines)
162 {
163 defines.set("THREADGROUP_SIZE", THREADGROUP_SIZE);
164 }
165
166 void LightGridLLReductionMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
167 const SPtr<GpuBuffer>& lightsLLHeads, const SPtr<GpuBuffer>& lightsLL,
168 const SPtr<GpuBuffer>& probeLLHeads, const SPtr<GpuBuffer>& probeLL)
169 {
170 mGridSize = gridSize;
171 UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];
172
173 if (numCells > mBufferNumCells || mBufferNumCells == 0)
174 {
175 GPU_BUFFER_DESC desc;
176 desc.elementCount = numCells;
177 desc.format = BF_32X4U;
178 desc.usage = GBU_LOADSTORE;
179 desc.type = GBT_STANDARD;
180 desc.elementSize = 0;
181
182 mGridLightOffsetAndSize = GpuBuffer::create(desc);
183 mGridLightOffsetAndSizeParam.set(mGridLightOffsetAndSize);
184
185 desc.format = BF_32X2U;
186
187 mGridProbeOffsetAndSize = GpuBuffer::create(desc);
188 mGridProbeOffsetAndSizeParam.set(mGridProbeOffsetAndSize);
189
190 desc.format = BF_32X1U;
191 desc.elementCount = numCells * MAX_LIGHTS_PER_CELL;
192 mGridLightIndices = GpuBuffer::create(desc);
193 mGridLightIndicesParam.set(mGridLightIndices);
194
195 mGridProbeIndices = GpuBuffer::create(desc);
196 mGridProbeIndicesParam.set(mGridProbeIndices);
197
198 mBufferNumCells = numCells;
199 }
200
201 ClearLoadStoreMat* clearMat = ClearLoadStoreMat::getVariation(
202 ClearLoadStoreType::StructuredBuffer, ClearLoadStoreDataType::Int, 1
203 );
204 clearMat->execute(mGridDataCounter);
205
206 mParams->setParamBlockBuffer("GridParams", gridParams);
207
208 mLightsLLHeadsParam.set(lightsLLHeads);
209 mLightsLLParam.set(lightsLL);
210
211 mProbesLLHeadsParam.set(probeLLHeads);
212 mProbesLLParam.set(probeLL);
213 }
214
215 void LightGridLLReductionMat::execute(const RendererView& view)
216 {
217 BS_RENMAT_PROFILE_BLOCK
218
219 mParams->setParamBlockBuffer("PerCamera", view.getPerViewBuffer());
220
221 UINT32 numGroupsX = (mGridSize[0] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
222 UINT32 numGroupsY = (mGridSize[1] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
223 UINT32 numGroupsZ = (mGridSize[2] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
224
225 bind();
226 RenderAPI::instance().dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
227 }
228
229 void LightGridLLReductionMat::getOutputs(SPtr<GpuBuffer>& gridLightOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices,
230 SPtr<GpuBuffer>& gridProbeOffsetsAndSize, SPtr<GpuBuffer>& gridProbeIndices) const
231 {
232 gridLightOffsetsAndSize = mGridLightOffsetAndSize;
233 gridLightIndices = mGridLightIndices;
234 gridProbeOffsetsAndSize = mGridProbeOffsetAndSize;
235 gridProbeIndices = mGridProbeIndices;
236 }
237
238 LightGrid::LightGrid()
239 {
240 mGridParamBuffer = gLightGridParamDefDef.createBuffer();
241 }
242
243 void LightGrid::updateGrid(const RendererView& view, const VisibleLightData& lightData, const VisibleReflProbeData& probeData,
244 bool noLighting)
245 {
246 const RendererViewProperties& viewProps = view.getProperties();
247
248 UINT32 width = viewProps.target.viewRect.width;
249 UINT32 height = viewProps.target.viewRect.height;
250
251 Vector3I gridSize;
252 gridSize[0] = (width + CELL_XY_SIZE - 1) / CELL_XY_SIZE;
253 gridSize[1] = (height + CELL_XY_SIZE - 1) / CELL_XY_SIZE;
254 gridSize[2] = NUM_Z_SUBDIVIDES;
255
256 Vector4I lightCount;
257 Vector2I lightStrides;
258 if (!noLighting)
259 {
260 lightCount[0] = lightData.getNumLights(LightType::Directional);
261 lightCount[1] = lightData.getNumLights(LightType::Radial);
262 lightCount[2] = lightData.getNumLights(LightType::Spot);
263 lightCount[3] = lightCount[0] + lightCount[1] + lightCount[2];
264
265 lightStrides[0] = lightCount[0];
266 lightStrides[1] = lightStrides[0] + lightCount[1];
267 }
268 else
269 {
270 lightCount[0] = 0;
271 lightCount[1] = 0;
272 lightCount[2] = 0;
273 lightCount[3] = 0;
274
275 lightStrides[0] = 0;
276 lightStrides[1] = 0;
277 }
278
279 UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];
280
281 gLightGridParamDefDef.gLightCounts.set(mGridParamBuffer, lightCount);
282 gLightGridParamDefDef.gLightStrides.set(mGridParamBuffer, lightStrides);
283 gLightGridParamDefDef.gNumReflProbes.set(mGridParamBuffer, probeData.getNumProbes());
284 gLightGridParamDefDef.gNumCells.set(mGridParamBuffer, numCells);
285 gLightGridParamDefDef.gGridSize.set(mGridParamBuffer, gridSize);
286 gLightGridParamDefDef.gMaxNumLightsPerCell.set(mGridParamBuffer, MAX_LIGHTS_PER_CELL);
287 gLightGridParamDefDef.gGridPixelSize.set(mGridParamBuffer, Vector2I(CELL_XY_SIZE, CELL_XY_SIZE));
288
289 LightGridLLCreationMat* creationMat = LightGridLLCreationMat::get();
290 creationMat->setParams(gridSize, mGridParamBuffer, lightData.getLightBuffer(), probeData.getProbeBuffer());
291 creationMat->execute(view);
292
293 SPtr<GpuBuffer> lightLLHeads;
294 SPtr<GpuBuffer> lightLL;
295 SPtr<GpuBuffer> probeLLHeads;
296 SPtr<GpuBuffer> probeLL;
297 creationMat->getOutputs(lightLLHeads, lightLL, probeLLHeads, probeLL);
298
299 LightGridLLReductionMat* reductionMat = LightGridLLReductionMat::get();
300 reductionMat->setParams(gridSize, mGridParamBuffer, lightLLHeads, lightLL, probeLLHeads, probeLL);
301 reductionMat->execute(view);
302 }
303
304 LightGridOutputs LightGrid::getOutputs() const
305 {
306 LightGridOutputs outputs;
307
308 LightGridLLReductionMat* reductionMat = LightGridLLReductionMat::get();
309 reductionMat->getOutputs(
310 outputs.gridLightOffsetsAndSize,
311 outputs.gridLightIndices,
312 outputs.gridProbeOffsetsAndSize,
313 outputs.gridProbeIndices
314 );
315
316 outputs.gridParams = mGridParamBuffer;
317
318 return outputs;
319 }
320}}
321