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 "BsTiledDeferred.h"
4#include "RenderAPI/BsGpuBuffer.h"
5#include "Renderer/BsReflectionProbe.h"
6#include "Renderer/BsRendererUtility.h"
7#include "Renderer/BsSkybox.h"
8#include "BsRenderBeast.h"
9
10namespace bs { namespace ct
11{
12 TiledLightingParamDef gTiledLightingParamDef;
13
14 const UINT32 TiledDeferredLightingMat::TILE_SIZE = 16;
15
16 TiledDeferredLightingMat::TiledDeferredLightingMat()
17 :mGBufferParams(GPT_COMPUTE_PROGRAM, mParams)
18 {
19 mSampleCount = mVariation.getUInt("MSAA_COUNT");
20
21 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gLights", mLightBufferParam);
22 mParams->getTextureParam(GPT_COMPUTE_PROGRAM, "gInColor", mInColorTextureParam);
23
24 if (mParams->hasLoadStoreTexture(GPT_COMPUTE_PROGRAM, "gOutput"))
25 mParams->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTextureParam);
26
27 if (mSampleCount > 1)
28 mParams->getTextureParam(GPT_COMPUTE_PROGRAM, "gMSAACoverage", mMSAACoverageTexParam);
29
30 mParamBuffer = gTiledLightingParamDef.createBuffer();
31 mParams->setParamBlockBuffer("Params", mParamBuffer);
32 }
33
34 void TiledDeferredLightingMat::_initDefines(ShaderDefines& defines)
35 {
36 defines.set("TILE_SIZE", TILE_SIZE);
37 }
38
39 void TiledDeferredLightingMat::execute(const RendererView& view, const VisibleLightData& lightData,
40 const GBufferTextures& gbuffer, const SPtr<Texture>& inputTexture, const SPtr<Texture>& lightAccumTex,
41 const SPtr<Texture>& lightAccumTexArray, const SPtr<Texture>& msaaCoverage)
42 {
43 BS_RENMAT_PROFILE_BLOCK
44
45 const RendererViewProperties& viewProps = view.getProperties();
46 const RenderSettings& settings = view.getRenderSettings();
47
48 mLightBufferParam.set(lightData.getLightBuffer());
49
50 UINT32 width = viewProps.target.viewRect.width;
51 UINT32 height = viewProps.target.viewRect.height;
52
53 Vector2I framebufferSize;
54 framebufferSize[0] = width;
55 framebufferSize[1] = height;
56 gTiledLightingParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
57
58 if (!settings.enableLighting)
59 {
60 Vector4I lightCounts;
61 lightCounts[0] = 0;
62 lightCounts[1] = 0;
63 lightCounts[2] = 0;
64 lightCounts[3] = 0;
65
66 Vector2I lightStrides;
67 lightStrides[0] = 0;
68 lightStrides[1] = 0;
69
70 gTiledLightingParamDef.gLightCounts.set(mParamBuffer, lightCounts);
71 gTiledLightingParamDef.gLightStrides.set(mParamBuffer, lightStrides);
72 }
73 else
74 {
75 Vector4I unshadowedLightCounts;
76 unshadowedLightCounts[0] = lightData.getNumUnshadowedLights(LightType::Directional);
77 unshadowedLightCounts[1] = lightData.getNumUnshadowedLights(LightType::Radial);
78 unshadowedLightCounts[2] = lightData.getNumUnshadowedLights(LightType::Spot);
79 unshadowedLightCounts[3] = unshadowedLightCounts[0] + unshadowedLightCounts[1] + unshadowedLightCounts[2];
80
81 Vector4I lightCounts;
82 lightCounts[0] = lightData.getNumLights(LightType::Directional);
83 lightCounts[1] = lightData.getNumLights(LightType::Radial);
84 lightCounts[2] = lightData.getNumLights(LightType::Spot);
85 lightCounts[3] = lightCounts[0] + lightCounts[1] + lightCounts[2];
86
87 Vector2I lightStrides;
88 lightStrides[0] = lightCounts[0];
89 lightStrides[1] = lightStrides[0] + lightCounts[1];
90
91 if(!settings.enableShadows)
92 gTiledLightingParamDef.gLightCounts.set(mParamBuffer, lightCounts);
93 else
94 gTiledLightingParamDef.gLightCounts.set(mParamBuffer, unshadowedLightCounts);
95
96 gTiledLightingParamDef.gLightStrides.set(mParamBuffer, lightStrides);
97 }
98
99 mParamBuffer->flushToGPU();
100
101 mGBufferParams.bind(gbuffer);
102 mParams->setParamBlockBuffer("PerCamera", view.getPerViewBuffer());
103 mInColorTextureParam.set(inputTexture);
104
105 if (mSampleCount > 1)
106 {
107 mOutputTextureParam.set(lightAccumTexArray, TextureSurface::COMPLETE);
108 mMSAACoverageTexParam.set(msaaCoverage);
109 }
110 else
111 mOutputTextureParam.set(lightAccumTex);
112
113 UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
114 UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
115
116 bind();
117 RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
118 }
119
120 TiledDeferredLightingMat* TiledDeferredLightingMat::getVariation(UINT32 msaaCount)
121 {
122 switch(msaaCount)
123 {
124 case 1:
125 return get(getVariation<1>());
126 case 2:
127 return get(getVariation<2>());
128 case 4:
129 return get(getVariation<4>());
130 case 8:
131 default:
132 return get(getVariation<8>());
133 }
134 }
135
136 TextureArrayToMSAATexture::TextureArrayToMSAATexture()
137 {
138 mParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInput", mInputParam);
139 }
140
141 void TextureArrayToMSAATexture::execute(const SPtr<Texture>& inputArray, const SPtr<Texture>& target)
142 {
143 BS_RENMAT_PROFILE_BLOCK
144
145 const TextureProperties& inputProps = inputArray->getProperties();
146 const TextureProperties& targetProps = target->getProperties();
147
148 assert(inputProps.getNumArraySlices() == targetProps.getNumSamples());
149 assert(inputProps.getWidth() == targetProps.getWidth());
150 assert(inputProps.getHeight() == targetProps.getHeight());
151
152 mInputParam.set(inputArray);
153
154 bind();
155
156 Rect2 area(0.0f, 0.0f, (float)targetProps.getWidth(), (float)targetProps.getHeight());
157 gRendererUtility().drawScreenQuad(area);
158 }
159
160 ClearLoadStoreParamDef gClearLoadStoreParamDef;
161
162 ClearLoadStoreMat::ClearLoadStoreMat()
163 {
164 INT32 objType = mVariation.getInt("OBJ_TYPE");
165
166 if(objType == 0 || objType == 1)
167 mParams->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTextureParam);
168 else
169 mParams->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBufferParam);
170
171 mParamBuffer = gClearLoadStoreParamDef.createBuffer();
172 mParams->setParamBlockBuffer(GPT_COMPUTE_PROGRAM, "Params", mParamBuffer);
173 }
174
175 void ClearLoadStoreMat::_initDefines(ShaderDefines& defines)
176 {
177 defines.set("TILE_SIZE", TILE_SIZE);
178 defines.set("NUM_THREADS", NUM_THREADS);
179 }
180
181 void ClearLoadStoreMat::execute(const SPtr<Texture>& target, const Color& clearValue,
182 const TextureSurface& surface)
183 {
184 BS_RENMAT_PROFILE_BLOCK
185
186 const TextureProperties& props = target->getProperties();
187 PixelFormat pf = props.getFormat();
188
189 assert(!PixelUtil::isCompressed(pf));
190
191 mOutputTextureParam.set(target, surface);
192
193 UINT32 width = props.getWidth();
194 UINT32 height = props.getHeight();
195 gClearLoadStoreParamDef.gSize.set(mParamBuffer, Vector2I((INT32)width, (INT32)height));
196 gClearLoadStoreParamDef.gFloatClearVal.set(mParamBuffer,
197 Vector4(clearValue.r, clearValue.g, clearValue.a, clearValue.a));
198 gClearLoadStoreParamDef.gIntClearVal.set(mParamBuffer,
199 Vector4I(*(INT32*)&clearValue.r, *(INT32*)&clearValue.g, *(INT32*)&clearValue.a, *(INT32*)&clearValue.a));
200
201 bind();
202
203 UINT32 numGroupsX = Math::divideAndRoundUp(width, NUM_THREADS * TILE_SIZE);
204 UINT32 numGroupsY = Math::divideAndRoundUp(height, NUM_THREADS * TILE_SIZE);
205
206 RenderAPI::instance().dispatchCompute(numGroupsX, numGroupsY);
207 }
208
209 void ClearLoadStoreMat::execute(const SPtr<GpuBuffer>& target, const Color& clearValue)
210 {
211 BS_RENMAT_PROFILE_BLOCK
212
213 mOutputBufferParam.set(target);
214
215 UINT32 width = target->getProperties().getElementCount();
216 UINT32 height = 1;
217 gClearLoadStoreParamDef.gSize.set(mParamBuffer, Vector2I((INT32)width, (INT32)height));
218 gClearLoadStoreParamDef.gFloatClearVal.set(mParamBuffer,
219 Vector4(clearValue.r, clearValue.g, clearValue.a, clearValue.a));
220 gClearLoadStoreParamDef.gIntClearVal.set(mParamBuffer,
221 Vector4I(*(INT32*)&clearValue.r, *(INT32*)&clearValue.g, *(INT32*)&clearValue.a, *(INT32*)&clearValue.a));
222
223 bind();
224
225 UINT32 numGroupsX = Math::divideAndRoundUp(width, NUM_THREADS * (TILE_SIZE * TILE_SIZE));
226 RenderAPI::instance().dispatchCompute(numGroupsX, 1);
227 }
228
229 /** Helper method used for initializing variations of the ClearLoadStore material. */
230 template<ClearLoadStoreType OBJ_TYPE, ClearLoadStoreDataType DATA_TYPE, UINT32 NUM_COMPONENTS>
231 static const ShaderVariation& getClearLoadStoreVariation()
232 {
233 static ShaderVariation variation = ShaderVariation(
234 {
235 ShaderVariation::Param("OBJ_TYPE", (int)OBJ_TYPE),
236 ShaderVariation::Param("DATA_TYPE", (int)DATA_TYPE),
237 ShaderVariation::Param("NUM_COMPONENTS", NUM_COMPONENTS),
238
239 });
240
241 return variation;
242 }
243
244 template<ClearLoadStoreType BUFFER_TYPE, ClearLoadStoreDataType DATA_TYPE>
245 const ShaderVariation& getClearLoadStoreVariation(UINT32 numComponents)
246 {
247 switch (numComponents)
248 {
249 default:
250 case 1:
251 return getClearLoadStoreVariation<BUFFER_TYPE, DATA_TYPE, 0>();
252 case 2:
253 return getClearLoadStoreVariation<BUFFER_TYPE, DATA_TYPE, 1>();
254 case 3:
255 return getClearLoadStoreVariation<BUFFER_TYPE, DATA_TYPE, 2>();
256 case 4:
257 return getClearLoadStoreVariation<BUFFER_TYPE, DATA_TYPE, 3>();
258 }
259 }
260
261 ClearLoadStoreMat* ClearLoadStoreMat::getVariation(ClearLoadStoreType objType, ClearLoadStoreDataType dataType,
262 UINT32 numComponents)
263 {
264 switch(objType)
265 {
266 default:
267 case ClearLoadStoreType::Texture:
268 if(dataType == ClearLoadStoreDataType::Float)
269 return get(getClearLoadStoreVariation<ClearLoadStoreType::Texture, ClearLoadStoreDataType::Float>(numComponents));
270 else
271 return get(getClearLoadStoreVariation<ClearLoadStoreType::Texture, ClearLoadStoreDataType::Int>(numComponents));
272 case ClearLoadStoreType::TextureArray:
273 if(dataType == ClearLoadStoreDataType::Float)
274 return get(getClearLoadStoreVariation<ClearLoadStoreType::TextureArray, ClearLoadStoreDataType::Float>(numComponents));
275 else
276 return get(getClearLoadStoreVariation<ClearLoadStoreType::TextureArray, ClearLoadStoreDataType::Int>(numComponents));
277 case ClearLoadStoreType::Buffer:
278 if(dataType == ClearLoadStoreDataType::Float)
279 return get(getClearLoadStoreVariation<ClearLoadStoreType::Buffer, ClearLoadStoreDataType::Float>(numComponents));
280 else
281 return get(getClearLoadStoreVariation<ClearLoadStoreType::Buffer, ClearLoadStoreDataType::Int>(numComponents));
282 case ClearLoadStoreType::StructuredBuffer:
283 if(dataType == ClearLoadStoreDataType::Float)
284 return get(getClearLoadStoreVariation<ClearLoadStoreType::StructuredBuffer, ClearLoadStoreDataType::Float>(numComponents));
285 else
286 return get(getClearLoadStoreVariation<ClearLoadStoreType::StructuredBuffer, ClearLoadStoreDataType::Int>(numComponents));
287 }
288 }
289
290 TiledImageBasedLightingParamDef gTiledImageBasedLightingParamDef;
291
292 // Note: Tile size was reduced from 32 to 16 because of macOS limitations. Ideally we should try keeping the larger
293 // size on non-macOS platforms, but currently where don't have a platform-specific way of setting this.
294 //
295 // The theory is that using larger tiles will amortize the cost of computing tile AABB's (which this shader uses,
296 // compared to the cheaper-to-compute frustums).
297 const UINT32 TiledDeferredImageBasedLightingMat::TILE_SIZE = 16;
298
299 TiledDeferredImageBasedLightingMat::TiledDeferredImageBasedLightingMat()
300 {
301 mSampleCount = mVariation.getUInt("MSAA_COUNT");
302
303 mParams->getTextureParam(GPT_COMPUTE_PROGRAM, "gGBufferATex", mGBufferA);
304 mParams->getTextureParam(GPT_COMPUTE_PROGRAM, "gGBufferBTex", mGBufferB);
305 mParams->getTextureParam(GPT_COMPUTE_PROGRAM, "gGBufferCTex", mGBufferC);
306 mParams->getTextureParam(GPT_COMPUTE_PROGRAM, "gDepthBufferTex", mGBufferDepth);
307
308 mParams->getTextureParam(GPT_COMPUTE_PROGRAM, "gInColor", mInColorTextureParam);
309 mParams->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTextureParam);
310
311 if (mSampleCount > 1)
312 mParams->getTextureParam(GPT_COMPUTE_PROGRAM, "gMSAACoverage", mMSAACoverageTexParam);
313
314 mParamBuffer = gTiledImageBasedLightingParamDef.createBuffer();
315 mParams->setParamBlockBuffer("Params", mParamBuffer);
316
317 mImageBasedParams.populate(mParams, GPT_COMPUTE_PROGRAM, false, false, true);
318
319 mParams->setParamBlockBuffer("ReflProbeParams", mReflProbeParamBuffer.buffer);
320 }
321
322 void TiledDeferredImageBasedLightingMat::_initDefines(ShaderDefines& defines)
323 {
324 defines.set("TILE_SIZE", TILE_SIZE);
325 }
326
327 void TiledDeferredImageBasedLightingMat::execute(const RendererView& view, const SceneInfo& sceneInfo,
328 const VisibleReflProbeData& probeData, const Inputs& inputs)
329 {
330 BS_RENMAT_PROFILE_BLOCK
331
332 const RendererViewProperties& viewProps = view.getProperties();
333 UINT32 width = viewProps.target.viewRect.width;
334 UINT32 height = viewProps.target.viewRect.height;
335
336 Vector2I framebufferSize;
337 framebufferSize[0] = width;
338 framebufferSize[1] = height;
339 gTiledImageBasedLightingParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
340
341 Skybox* skybox = nullptr;
342 if(view.getRenderSettings().enableSkybox)
343 skybox = sceneInfo.skybox;
344
345 mReflProbeParamBuffer.populate(skybox, probeData.getNumProbes(), sceneInfo.reflProbeCubemapsTex,
346 viewProps.capturingReflections);
347
348 mParamBuffer->flushToGPU();
349 mReflProbeParamBuffer.buffer->flushToGPU();
350
351 mGBufferA.set(inputs.gbuffer.albedo);
352 mGBufferB.set(inputs.gbuffer.normals);
353 mGBufferC.set(inputs.gbuffer.roughMetal);
354 mGBufferDepth.set(inputs.gbuffer.depth);
355
356 SPtr<Texture> skyFilteredRadiance;
357 if(skybox)
358 skyFilteredRadiance = skybox->getFilteredRadiance();
359
360 mImageBasedParams.preintegratedEnvBRDFParam.set(inputs.preIntegratedGF);
361 mImageBasedParams.reflectionProbesParam.set(probeData.getProbeBuffer());
362 mImageBasedParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
363 mImageBasedParams.skyReflectionsTexParam.set(skyFilteredRadiance);
364 mImageBasedParams.ambientOcclusionTexParam.set(inputs.ambientOcclusion);
365 mImageBasedParams.ssrTexParam.set(inputs.ssr);
366
367 mParams->setParamBlockBuffer("PerCamera", view.getPerViewBuffer());
368
369 mInColorTextureParam.set(inputs.lightAccumulation);
370 if (mSampleCount > 1)
371 {
372 mOutputTextureParam.set(inputs.sceneColorTexArray, TextureSurface::COMPLETE);
373 mMSAACoverageTexParam.set(inputs.msaaCoverage);
374 }
375 else
376 mOutputTextureParam.set(inputs.sceneColorTex);
377
378 UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
379 UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
380
381 bind();
382 RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
383 }
384
385 TiledDeferredImageBasedLightingMat* TiledDeferredImageBasedLightingMat::getVariation(UINT32 msaaCount)
386 {
387 switch(msaaCount)
388 {
389 case 1:
390 return get(getVariation<1>());
391 case 2:
392 return get(getVariation<2>());
393 case 4:
394 return get(getVariation<4>());
395 case 8:
396 default:
397 return get(getVariation<8>());
398 }
399 }
400}}
401