BsPostProcessing.cpp 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsPostProcessing.h"
  4. #include "BsRenderTexture.h"
  5. #include "BsGpuResourcePool.h"
  6. #include "BsRendererUtility.h"
  7. #include "BsTextureManager.h"
  8. #include "BsCamera.h"
  9. #include "BsGpuParamsSet.h"
  10. #include "BsRendererView.h"
  11. #include "BsRenderTargets.h"
  12. #include "BsPixelUtil.h"
  13. #include "BsBitwise.h"
  14. namespace bs { namespace ct
  15. {
  16. DownsampleParamDef gDownsampleParamDef;
  17. template<int Quality, bool MSAA>
  18. DownsampleMat<Quality, MSAA>::DownsampleMat()
  19. {
  20. mParamBuffer = gDownsampleParamDef.createBuffer();
  21. SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
  22. if(gpuParams->hasParamBlock(GPT_FRAGMENT_PROGRAM, "Input"))
  23. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  24. mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
  25. }
  26. template<int Quality, bool MSAA>
  27. void DownsampleMat<Quality, MSAA>::_initDefines(ShaderDefines& defines)
  28. {
  29. defines.set("QUALITY", Quality);
  30. defines.set("MSAA", MSAA ? 1 : 0);
  31. }
  32. template<int Quality, bool MSAA>
  33. void DownsampleMat<Quality, MSAA>::execute(const SPtr<Texture>& target, PostProcessInfo& ppInfo)
  34. {
  35. // Set parameters
  36. mInputTexture.set(target);
  37. const TextureProperties& rtProps = target->getProperties();
  38. if(MSAA)
  39. {
  40. gDownsampleParamDef.gOffsets.set(mParamBuffer, Vector2(-1.0f, -1.0f));
  41. gDownsampleParamDef.gOffsets.set(mParamBuffer, Vector2(1.0f, -1.0f));
  42. gDownsampleParamDef.gOffsets.set(mParamBuffer, Vector2(-1.0f, 1.0f));
  43. gDownsampleParamDef.gOffsets.set(mParamBuffer, Vector2(1.0f, 1.0f));
  44. }
  45. else
  46. {
  47. Vector2 invTextureSize(1.0f / rtProps.getWidth(), 1.0f / rtProps.getHeight());
  48. gDownsampleParamDef.gOffsets.set(mParamBuffer, invTextureSize * Vector2(-1.0f, -1.0f));
  49. gDownsampleParamDef.gOffsets.set(mParamBuffer, invTextureSize * Vector2(1.0f, -1.0f));
  50. gDownsampleParamDef.gOffsets.set(mParamBuffer, invTextureSize * Vector2(-1.0f, 1.0f));
  51. gDownsampleParamDef.gOffsets.set(mParamBuffer, invTextureSize * Vector2(1.0f, 1.0f));
  52. }
  53. // Set output
  54. UINT32 width = std::max(1, Math::ceilToInt(rtProps.getWidth() * 0.5f));
  55. UINT32 height = std::max(1, Math::ceilToInt(rtProps.getHeight() * 0.5f));
  56. mOutputDesc = POOLED_RENDER_TEXTURE_DESC::create2D(rtProps.getFormat(), width, height, TU_RENDERTARGET);
  57. // Render
  58. ppInfo.downsampledSceneTex = GpuResourcePool::instance().get(mOutputDesc);
  59. RenderAPI& rapi = RenderAPI::instance();
  60. rapi.setRenderTarget(ppInfo.downsampledSceneTex->renderTexture, FBT_DEPTH | FBT_STENCIL);
  61. gRendererUtility().setPass(mMaterial);
  62. gRendererUtility().setPassParams(mParamsSet);
  63. if (MSAA)
  64. gRendererUtility().drawScreenQuad(Rect2(0.0f, 0.0f, (float)rtProps.getWidth(), (float)rtProps.getHeight()));
  65. else
  66. gRendererUtility().drawScreenQuad();
  67. rapi.setRenderTarget(nullptr);
  68. mOutput = ppInfo.downsampledSceneTex->renderTexture;
  69. }
  70. template<int Quality, bool MSAA>
  71. void DownsampleMat<Quality, MSAA>::release(PostProcessInfo& ppInfo)
  72. {
  73. GpuResourcePool::instance().release(ppInfo.downsampledSceneTex);
  74. mOutput = nullptr;
  75. }
  76. void DownsampleMaterials::execute(UINT32 quality, bool msaa, const SPtr<Texture>& target, PostProcessInfo& ppInfo)
  77. {
  78. if(quality == 0)
  79. {
  80. if(msaa)
  81. m0_MSAA.execute(target, ppInfo);
  82. else
  83. m0_NoMSAA.execute(target, ppInfo);
  84. }
  85. else
  86. {
  87. if (msaa)
  88. m1_MSAA.execute(target, ppInfo);
  89. else
  90. m1_NoMSAA.execute(target, ppInfo);
  91. }
  92. }
  93. void DownsampleMaterials::release(UINT32 quality, bool msaa, PostProcessInfo& ppInfo)
  94. {
  95. if(quality == 0)
  96. {
  97. if(msaa)
  98. m0_MSAA.release(ppInfo);
  99. else
  100. m0_NoMSAA.release(ppInfo);
  101. }
  102. else
  103. {
  104. if (msaa)
  105. m1_MSAA.release(ppInfo);
  106. else
  107. m1_NoMSAA.release(ppInfo);
  108. }
  109. }
  110. template class DownsampleMat<0, false>;
  111. template class DownsampleMat<0, true>;
  112. template class DownsampleMat<1, false>;
  113. template class DownsampleMat<1, true>;
  114. EyeAdaptHistogramParamDef gEyeAdaptHistogramParamDef;
  115. EyeAdaptHistogramMat::EyeAdaptHistogramMat()
  116. {
  117. mParamBuffer = gEyeAdaptHistogramParamDef.createBuffer();
  118. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  119. SPtr<GpuParams> params = mParamsSet->getGpuParams();
  120. params->getTextureParam(GPT_COMPUTE_PROGRAM, "gSceneColorTex", mSceneColor);
  121. params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutputTex", mOutputTex);
  122. }
  123. void EyeAdaptHistogramMat::_initDefines(ShaderDefines& defines)
  124. {
  125. defines.set("THREADGROUP_SIZE_X", THREAD_GROUP_SIZE_X);
  126. defines.set("THREADGROUP_SIZE_Y", THREAD_GROUP_SIZE_Y);
  127. defines.set("LOOP_COUNT_X", LOOP_COUNT_X);
  128. defines.set("LOOP_COUNT_Y", LOOP_COUNT_Y);
  129. }
  130. void EyeAdaptHistogramMat::execute(PostProcessInfo& ppInfo)
  131. {
  132. // Set parameters
  133. SPtr<RenderTexture> target = ppInfo.downsampledSceneTex->renderTexture;
  134. mSceneColor.set(ppInfo.downsampledSceneTex->texture);
  135. const RenderTextureProperties& props = target->getProperties();
  136. int offsetAndSize[4] = { 0, 0, (INT32)props.getWidth(), (INT32)props.getHeight() };
  137. gEyeAdaptHistogramParamDef.gHistogramParams.set(mParamBuffer, getHistogramScaleOffset(ppInfo));
  138. gEyeAdaptHistogramParamDef.gPixelOffsetAndSize.set(mParamBuffer, Vector4I(offsetAndSize));
  139. Vector2I threadGroupCount = getThreadGroupCount(target);
  140. gEyeAdaptHistogramParamDef.gThreadGroupCount.set(mParamBuffer, threadGroupCount);
  141. // Set output
  142. UINT32 numHistograms = threadGroupCount.x * threadGroupCount.y;
  143. mOutputDesc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, HISTOGRAM_NUM_TEXELS, numHistograms,
  144. TU_LOADSTORE);
  145. // Dispatch
  146. ppInfo.histogramTex = GpuResourcePool::instance().get(mOutputDesc);
  147. mOutputTex.set(ppInfo.histogramTex->texture);
  148. RenderAPI& rapi = RenderAPI::instance();
  149. gRendererUtility().setComputePass(mMaterial);
  150. gRendererUtility().setPassParams(mParamsSet);
  151. rapi.dispatchCompute(threadGroupCount.x, threadGroupCount.y);
  152. mOutput = ppInfo.histogramTex->renderTexture;
  153. }
  154. void EyeAdaptHistogramMat::release(PostProcessInfo& ppInfo)
  155. {
  156. GpuResourcePool::instance().release(ppInfo.histogramTex);
  157. mOutput = nullptr;
  158. }
  159. Vector2I EyeAdaptHistogramMat::getThreadGroupCount(const SPtr<RenderTexture>& target)
  160. {
  161. const UINT32 texelsPerThreadGroupX = THREAD_GROUP_SIZE_X * LOOP_COUNT_X;
  162. const UINT32 texelsPerThreadGroupY = THREAD_GROUP_SIZE_Y * LOOP_COUNT_Y;
  163. const RenderTextureProperties& props = target->getProperties();
  164. Vector2I threadGroupCount;
  165. threadGroupCount.x = ((INT32)props.getWidth() + texelsPerThreadGroupX - 1) / texelsPerThreadGroupX;
  166. threadGroupCount.y = ((INT32)props.getHeight() + texelsPerThreadGroupY - 1) / texelsPerThreadGroupY;
  167. return threadGroupCount;
  168. }
  169. Vector2 EyeAdaptHistogramMat::getHistogramScaleOffset(const PostProcessInfo& ppInfo)
  170. {
  171. const StandardPostProcessSettings& settings = *ppInfo.settings;
  172. float diff = settings.autoExposure.histogramLog2Max - settings.autoExposure.histogramLog2Min;
  173. float scale = 1.0f / diff;
  174. float offset = -settings.autoExposure.histogramLog2Min * scale;
  175. return Vector2(scale, offset);
  176. }
  177. EyeAdaptHistogramReduceParamDef gEyeAdaptHistogramReduceParamDef;
  178. EyeAdaptHistogramReduceMat::EyeAdaptHistogramReduceMat()
  179. {
  180. mParamBuffer = gEyeAdaptHistogramReduceParamDef.createBuffer();
  181. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  182. SPtr<GpuParams> params = mParamsSet->getGpuParams();
  183. params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gHistogramTex", mHistogramTex);
  184. params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gEyeAdaptationTex", mEyeAdaptationTex);
  185. }
  186. void EyeAdaptHistogramReduceMat::_initDefines(ShaderDefines& defines)
  187. {
  188. // Do nothing
  189. }
  190. void EyeAdaptHistogramReduceMat::execute(PostProcessInfo& ppInfo)
  191. {
  192. // Set parameters
  193. mHistogramTex.set(ppInfo.histogramTex->texture);
  194. SPtr<PooledRenderTexture> eyeAdaptationRT = ppInfo.eyeAdaptationTex[ppInfo.lastEyeAdaptationTex];
  195. SPtr<Texture> eyeAdaptationTex;
  196. if (eyeAdaptationRT != nullptr) // Could be that this is the first run
  197. eyeAdaptationTex = eyeAdaptationRT->texture;
  198. else
  199. eyeAdaptationTex = Texture::WHITE;
  200. mEyeAdaptationTex.set(eyeAdaptationTex);
  201. Vector2I threadGroupCount = EyeAdaptHistogramMat::getThreadGroupCount(ppInfo.downsampledSceneTex->renderTexture);
  202. UINT32 numHistograms = threadGroupCount.x * threadGroupCount.y;
  203. gEyeAdaptHistogramReduceParamDef.gThreadGroupCount.set(mParamBuffer, numHistograms);
  204. // Set output
  205. mOutputDesc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, EyeAdaptHistogramMat::HISTOGRAM_NUM_TEXELS, 2,
  206. TU_RENDERTARGET);
  207. // Render
  208. ppInfo.histogramReduceTex = GpuResourcePool::instance().get(mOutputDesc);
  209. RenderAPI& rapi = RenderAPI::instance();
  210. rapi.setRenderTarget(ppInfo.histogramReduceTex->renderTexture, FBT_DEPTH | FBT_STENCIL);
  211. gRendererUtility().setPass(mMaterial);
  212. gRendererUtility().setPassParams(mParamsSet);
  213. Rect2 drawUV(0.0f, 0.0f, (float)EyeAdaptHistogramMat::HISTOGRAM_NUM_TEXELS, 2.0f);
  214. gRendererUtility().drawScreenQuad(drawUV);
  215. rapi.setRenderTarget(nullptr);
  216. mOutput = ppInfo.histogramReduceTex->renderTexture;
  217. }
  218. void EyeAdaptHistogramReduceMat::release(PostProcessInfo& ppInfo)
  219. {
  220. GpuResourcePool::instance().release(ppInfo.histogramReduceTex);
  221. mOutput = nullptr;
  222. }
  223. EyeAdaptationParamDef gEyeAdaptationParamDef;
  224. EyeAdaptationMat::EyeAdaptationMat()
  225. {
  226. mParamBuffer = gEyeAdaptationParamDef.createBuffer();
  227. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  228. mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gHistogramTex", mReducedHistogramTex);
  229. }
  230. void EyeAdaptationMat::_initDefines(ShaderDefines& defines)
  231. {
  232. defines.set("THREADGROUP_SIZE_X", EyeAdaptHistogramMat::THREAD_GROUP_SIZE_X);
  233. defines.set("THREADGROUP_SIZE_Y", EyeAdaptHistogramMat::THREAD_GROUP_SIZE_Y);
  234. }
  235. void EyeAdaptationMat::execute(PostProcessInfo& ppInfo, float frameDelta)
  236. {
  237. bool texturesInitialized = ppInfo.eyeAdaptationTex[0] != nullptr && ppInfo.eyeAdaptationTex[1] != nullptr;
  238. if(!texturesInitialized)
  239. {
  240. POOLED_RENDER_TEXTURE_DESC outputDesc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT32_R, 1, 1, TU_RENDERTARGET);
  241. ppInfo.eyeAdaptationTex[0] = GpuResourcePool::instance().get(outputDesc);
  242. ppInfo.eyeAdaptationTex[1] = GpuResourcePool::instance().get(outputDesc);
  243. }
  244. ppInfo.lastEyeAdaptationTex = (ppInfo.lastEyeAdaptationTex + 1) % 2; // TODO - Do I really need two targets?
  245. // Set parameters
  246. mReducedHistogramTex.set(ppInfo.histogramReduceTex->texture);
  247. Vector2 histogramScaleAndOffset = EyeAdaptHistogramMat::getHistogramScaleOffset(ppInfo);
  248. const StandardPostProcessSettings& settings = *ppInfo.settings;
  249. Vector4 eyeAdaptationParams[3];
  250. eyeAdaptationParams[0].x = histogramScaleAndOffset.x;
  251. eyeAdaptationParams[0].y = histogramScaleAndOffset.y;
  252. float histogramPctHigh = Math::clamp01(settings.autoExposure.histogramPctHigh);
  253. eyeAdaptationParams[0].z = std::min(Math::clamp01(settings.autoExposure.histogramPctLow), histogramPctHigh);
  254. eyeAdaptationParams[0].w = histogramPctHigh;
  255. eyeAdaptationParams[1].x = std::min(settings.autoExposure.minEyeAdaptation, settings.autoExposure.maxEyeAdaptation);
  256. eyeAdaptationParams[1].y = settings.autoExposure.maxEyeAdaptation;
  257. eyeAdaptationParams[1].z = settings.autoExposure.eyeAdaptationSpeedUp;
  258. eyeAdaptationParams[1].w = settings.autoExposure.eyeAdaptationSpeedDown;
  259. eyeAdaptationParams[2].x = Math::pow(2.0f, settings.exposureScale);
  260. eyeAdaptationParams[2].y = frameDelta;
  261. eyeAdaptationParams[2].z = 0.0f; // Unused
  262. eyeAdaptationParams[2].w = 0.0f; // Unused
  263. gEyeAdaptationParamDef.gEyeAdaptationParams.set(mParamBuffer, eyeAdaptationParams[0], 0);
  264. gEyeAdaptationParamDef.gEyeAdaptationParams.set(mParamBuffer, eyeAdaptationParams[1], 1);
  265. gEyeAdaptationParamDef.gEyeAdaptationParams.set(mParamBuffer, eyeAdaptationParams[2], 2);
  266. // Render
  267. SPtr<PooledRenderTexture> eyeAdaptationRT = ppInfo.eyeAdaptationTex[ppInfo.lastEyeAdaptationTex];
  268. RenderAPI& rapi = RenderAPI::instance();
  269. rapi.setRenderTarget(eyeAdaptationRT->renderTexture, FBT_DEPTH | FBT_STENCIL);
  270. gRendererUtility().setPass(mMaterial);
  271. gRendererUtility().setPassParams(mParamsSet);
  272. gRendererUtility().drawScreenQuad();
  273. rapi.setRenderTarget(nullptr);
  274. }
  275. CreateTonemapLUTParamDef gCreateTonemapLUTParamDef;
  276. WhiteBalanceParamDef gWhiteBalanceParamDef;
  277. CreateTonemapLUTMat::CreateTonemapLUTMat()
  278. {
  279. mParamBuffer = gCreateTonemapLUTParamDef.createBuffer();
  280. mWhiteBalanceParamBuffer = gWhiteBalanceParamDef.createBuffer();
  281. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  282. mParamsSet->setParamBlockBuffer("WhiteBalanceInput", mWhiteBalanceParamBuffer);
  283. SPtr<GpuParams> params = mParamsSet->getGpuParams();
  284. params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutputTex", mOutputTex);
  285. }
  286. void CreateTonemapLUTMat::_initDefines(ShaderDefines& defines)
  287. {
  288. defines.set("LUT_SIZE", LUT_SIZE);
  289. }
  290. void CreateTonemapLUTMat::execute(PostProcessInfo& ppInfo)
  291. {
  292. const StandardPostProcessSettings& settings = *ppInfo.settings;
  293. // Set parameters
  294. gCreateTonemapLUTParamDef.gGammaAdjustment.set(mParamBuffer, 2.2f / settings.gamma);
  295. // Note: Assuming sRGB (PC monitor) for now, change to Rec.709 when running on console (value 1), or to raw 2.2
  296. // gamma when running on Mac (value 2)
  297. gCreateTonemapLUTParamDef.gGammaCorrectionType.set(mParamBuffer, 0);
  298. Vector4 tonemapParams[2];
  299. tonemapParams[0].x = settings.tonemapping.filmicCurveShoulderStrength;
  300. tonemapParams[0].y = settings.tonemapping.filmicCurveLinearStrength;
  301. tonemapParams[0].z = settings.tonemapping.filmicCurveLinearAngle;
  302. tonemapParams[0].w = settings.tonemapping.filmicCurveToeStrength;
  303. tonemapParams[1].x = settings.tonemapping.filmicCurveToeNumerator;
  304. tonemapParams[1].y = settings.tonemapping.filmicCurveToeDenominator;
  305. tonemapParams[1].z = settings.tonemapping.filmicCurveLinearWhitePoint;
  306. tonemapParams[1].w = 0.0f; // Unused
  307. gCreateTonemapLUTParamDef.gTonemapParams.set(mParamBuffer, tonemapParams[0], 0);
  308. gCreateTonemapLUTParamDef.gTonemapParams.set(mParamBuffer, tonemapParams[1], 1);
  309. // Set color grading params
  310. gCreateTonemapLUTParamDef.gSaturation.set(mParamBuffer, settings.colorGrading.saturation);
  311. gCreateTonemapLUTParamDef.gContrast.set(mParamBuffer, settings.colorGrading.contrast);
  312. gCreateTonemapLUTParamDef.gGain.set(mParamBuffer, settings.colorGrading.gain);
  313. gCreateTonemapLUTParamDef.gOffset.set(mParamBuffer, settings.colorGrading.offset);
  314. // Set white balance params
  315. gWhiteBalanceParamDef.gWhiteTemp.set(mWhiteBalanceParamBuffer, settings.whiteBalance.temperature);
  316. gWhiteBalanceParamDef.gWhiteOffset.set(mWhiteBalanceParamBuffer, settings.whiteBalance.tint);
  317. // Set output
  318. POOLED_RENDER_TEXTURE_DESC outputDesc = POOLED_RENDER_TEXTURE_DESC::create3D(PF_R8G8B8A8,
  319. LUT_SIZE, LUT_SIZE, LUT_SIZE, TU_LOADSTORE);
  320. // Dispatch
  321. ppInfo.colorLUT = GpuResourcePool::instance().get(outputDesc);
  322. mOutputTex.set(ppInfo.colorLUT->texture);
  323. RenderAPI& rapi = RenderAPI::instance();
  324. gRendererUtility().setComputePass(mMaterial);
  325. gRendererUtility().setPassParams(mParamsSet);
  326. rapi.dispatchCompute(LUT_SIZE / 8, LUT_SIZE / 8, LUT_SIZE);
  327. }
  328. void CreateTonemapLUTMat::release(PostProcessInfo& ppInfo)
  329. {
  330. GpuResourcePool::instance().release(ppInfo.colorLUT);
  331. }
  332. TonemappingParamDef gTonemappingParamDef;
  333. template<bool GammaOnly, bool AutoExposure, bool MSAA>
  334. TonemappingMat<GammaOnly, AutoExposure, MSAA>::TonemappingMat()
  335. {
  336. mParamBuffer = gTonemappingParamDef.createBuffer();
  337. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  338. SPtr<GpuParams> params = mParamsSet->getGpuParams();
  339. params->getTextureParam(GPT_VERTEX_PROGRAM, "gEyeAdaptationTex", mEyeAdaptationTex);
  340. params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTex);
  341. if(!GammaOnly)
  342. params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gColorLUT", mColorLUT);
  343. }
  344. template<bool GammaOnly, bool AutoExposure, bool MSAA>
  345. void TonemappingMat<GammaOnly, AutoExposure, MSAA>::_initDefines(ShaderDefines& defines)
  346. {
  347. if(GammaOnly)
  348. defines.set("GAMMA_ONLY", 1);
  349. if (AutoExposure)
  350. defines.set("AUTO_EXPOSURE", 1);
  351. defines.set("MSAA", MSAA ? 1 : 0);
  352. defines.set("LUT_SIZE", CreateTonemapLUTMat::LUT_SIZE);
  353. }
  354. template<bool GammaOnly, bool AutoExposure, bool MSAA>
  355. void TonemappingMat<GammaOnly, AutoExposure, MSAA>::execute(const SPtr<Texture>& sceneColor,
  356. const SPtr<RenderTarget>& outputRT, const Rect2& outputRect, PostProcessInfo& ppInfo)
  357. {
  358. const TextureProperties& texProps = sceneColor->getProperties();
  359. gTonemappingParamDef.gRawGamma.set(mParamBuffer, 1.0f / ppInfo.settings->gamma);
  360. gTonemappingParamDef.gManualExposureScale.set(mParamBuffer, Math::pow(2.0f, ppInfo.settings->exposureScale));
  361. gTonemappingParamDef.gNumSamples.set(mParamBuffer, texProps.getNumSamples());
  362. // Set parameters
  363. mInputTex.set(sceneColor);
  364. SPtr<Texture> colorLUT;
  365. if(ppInfo.colorLUT != nullptr)
  366. colorLUT = ppInfo.colorLUT->texture;
  367. mColorLUT.set(colorLUT);
  368. SPtr<Texture> eyeAdaptationTexture;
  369. if(ppInfo.eyeAdaptationTex[ppInfo.lastEyeAdaptationTex] != nullptr)
  370. eyeAdaptationTexture = ppInfo.eyeAdaptationTex[ppInfo.lastEyeAdaptationTex]->texture;
  371. mEyeAdaptationTex.set(eyeAdaptationTexture);
  372. // Render
  373. RenderAPI& rapi = RenderAPI::instance();
  374. rapi.setRenderTarget(outputRT);
  375. rapi.setViewport(outputRect);
  376. gRendererUtility().setPass(mMaterial);
  377. gRendererUtility().setPassParams(mParamsSet);
  378. if (MSAA)
  379. gRendererUtility().drawScreenQuad(Rect2(0.0f, 0.0f, (float)texProps.getWidth(), (float)texProps.getHeight()));
  380. else
  381. gRendererUtility().drawScreenQuad();
  382. }
  383. template class TonemappingMat<false, false, false>;
  384. template class TonemappingMat<false, false, true>;
  385. template class TonemappingMat<false, true, false>;
  386. template class TonemappingMat<false, true, true>;
  387. template class TonemappingMat<true, false, false>;
  388. template class TonemappingMat<true, false, true>;
  389. template class TonemappingMat<true, true, false>;
  390. template class TonemappingMat<true, true, true>;
  391. void TonemappingMaterials::execute(bool gammaOnly, bool autoExposure, bool MSAA, const SPtr<Texture>& sceneColor,
  392. const SPtr<RenderTarget>& outputRT, const Rect2& outputRect, PostProcessInfo& ppInfo)
  393. {
  394. if (gammaOnly)
  395. {
  396. if (autoExposure)
  397. {
  398. if (MSAA)
  399. mTTT.execute(sceneColor, outputRT, outputRect, ppInfo);
  400. else
  401. mTTF.execute(sceneColor, outputRT, outputRect, ppInfo);
  402. }
  403. else
  404. {
  405. if (MSAA)
  406. mTFT.execute(sceneColor, outputRT, outputRect, ppInfo);
  407. else
  408. mTFF.execute(sceneColor, outputRT, outputRect, ppInfo);
  409. }
  410. }
  411. else
  412. {
  413. if (autoExposure)
  414. {
  415. if (MSAA)
  416. mFTT.execute(sceneColor, outputRT, outputRect, ppInfo);
  417. else
  418. mFTF.execute(sceneColor, outputRT, outputRect, ppInfo);
  419. }
  420. else
  421. {
  422. if (MSAA)
  423. mFFT.execute(sceneColor, outputRT, outputRect, ppInfo);
  424. else
  425. mFFF.execute(sceneColor, outputRT, outputRect, ppInfo);
  426. }
  427. }
  428. }
  429. GaussianBlurParamDef gGaussianBlurParamDef;
  430. GaussianBlurMat::GaussianBlurMat()
  431. {
  432. mParamBuffer = gGaussianBlurParamDef.createBuffer();
  433. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  434. mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
  435. }
  436. void GaussianBlurMat::_initDefines(ShaderDefines& defines)
  437. {
  438. defines.set("MAX_NUM_SAMPLES", MAX_BLUR_SAMPLES);
  439. }
  440. void GaussianBlurMat::execute(const SPtr<Texture>& source, float filterSize, const SPtr<RenderTexture>& destination)
  441. {
  442. const TextureProperties& srcProps = source->getProperties();
  443. const RenderTextureProperties& dstProps = destination->getProperties();
  444. Vector2 invTexSize(1.0f / srcProps.getWidth(), 1.0f / srcProps.getHeight());
  445. std::array<float, MAX_BLUR_SAMPLES> sampleOffsets;
  446. std::array<float, MAX_BLUR_SAMPLES> sampleWeights;
  447. POOLED_RENDER_TEXTURE_DESC tempTextureDesc = POOLED_RENDER_TEXTURE_DESC::create2D(srcProps.getFormat(),
  448. dstProps.getWidth(), dstProps.getHeight(), TU_RENDERTARGET);
  449. SPtr<PooledRenderTexture> tempTexture = GpuResourcePool::instance().get(tempTextureDesc);
  450. auto updateParamBuffer = [&](Direction direction)
  451. {
  452. float kernelRadius = calcKernelRadius(source, filterSize, direction);
  453. UINT32 numSamples = calcStdDistribution(kernelRadius, sampleWeights, sampleOffsets);
  454. for(UINT32 i = 0; i < (numSamples + 3) / 4; ++i)
  455. {
  456. UINT32 remainder = std::min(4U, numSamples - i * 4);
  457. Vector4 weights;
  458. for (UINT32 j = 0; j < remainder; ++j)
  459. weights[j] = sampleWeights[i * 4 + j];
  460. gGaussianBlurParamDef.gSampleWeights.set(mParamBuffer, weights, i);
  461. }
  462. UINT32 axis0 = direction == DirHorizontal ? 0 : 1;
  463. UINT32 axis1 = (axis0 + 1) % 2;
  464. for(UINT32 i = 0; i < (numSamples + 1) / 2; ++i)
  465. {
  466. UINT32 remainder = std::min(2U, numSamples - i * 2);
  467. Vector4 offset;
  468. offset[axis0] = sampleOffsets[i * 2 + 0] * invTexSize[axis0];
  469. offset[axis1] = 0.0f;
  470. if(remainder == 2)
  471. {
  472. offset[axis0 + 2] = sampleOffsets[i * 2 + 1] * invTexSize[axis0];
  473. offset[axis1 + 2] = 0.0f;
  474. }
  475. else
  476. {
  477. offset[axis0 + 2] = 0.0f;
  478. offset[axis1 + 2] = 0.0f;
  479. }
  480. gGaussianBlurParamDef.gSampleOffsets.set(mParamBuffer, offset, i);
  481. }
  482. gGaussianBlurParamDef.gNumSamples.set(mParamBuffer, numSamples);
  483. };
  484. // Horizontal pass
  485. {
  486. updateParamBuffer(DirHorizontal);
  487. mInputTexture.set(source);
  488. RenderAPI& rapi = RenderAPI::instance();
  489. rapi.setRenderTarget(tempTexture->renderTexture);
  490. gRendererUtility().setPass(mMaterial);
  491. gRendererUtility().setPassParams(mParamsSet);
  492. gRendererUtility().drawScreenQuad();
  493. }
  494. // Vertical pass
  495. {
  496. updateParamBuffer(DirVertical);
  497. mInputTexture.set(tempTexture->texture);
  498. RenderAPI& rapi = RenderAPI::instance();
  499. rapi.setRenderTarget(destination);
  500. gRendererUtility().setPass(mMaterial);
  501. gRendererUtility().setPassParams(mParamsSet);
  502. gRendererUtility().drawScreenQuad();
  503. }
  504. GpuResourcePool::instance().release(tempTexture);
  505. }
  506. UINT32 GaussianBlurMat::calcStdDistribution(float filterRadius, std::array<float, MAX_BLUR_SAMPLES>& weights,
  507. std::array<float, MAX_BLUR_SAMPLES>& offsets)
  508. {
  509. filterRadius = Math::clamp(filterRadius, 0.00001f, (float)(MAX_BLUR_SAMPLES - 1));
  510. INT32 intFilterRadius = std::min(Math::ceilToInt(filterRadius), MAX_BLUR_SAMPLES - 1);
  511. auto normalDistribution = [](int i, float scale)
  512. {
  513. float samplePos = fabs((float)i) * scale;
  514. return exp(samplePos * samplePos);
  515. };
  516. // We make use of the hardware linear filtering, and therefore only generate half the number of samples.
  517. // The weights and the sampling location needs to be adjusted in order to get the same results as if we
  518. // perform two samples separately:
  519. //
  520. // Original formula is: t1*w1 + t2*w2
  521. // With hardware filtering it's: (t1 + (t2 - t1) * o) * w3
  522. // Or expanded: t1*w3 - t1*o*w3 + t2*o*w3 = t1 * (w3 - o*w3) + t2 * (o*w3)
  523. //
  524. // These two need to equal, which means this follows:
  525. // w1 = w3 - o*w3
  526. // w2 = o*w3
  527. //
  528. // From the second equation get the offset o:
  529. // o = w2/w3
  530. //
  531. // From the first equation and o, get w3:
  532. // w1 = w3 - w2
  533. // w3 = w1 + w2
  534. float scale = 1.0f / filterRadius;
  535. UINT32 numSamples = 0;
  536. float totalWeight = 0.0f;
  537. for(int i = -intFilterRadius; i < intFilterRadius; i += 2)
  538. {
  539. float w1 = normalDistribution(i, scale);
  540. float w2 = normalDistribution(i + 1, scale);
  541. float w3 = w1 + w2;
  542. float o = w2/w3; // Relative to first sample
  543. weights[numSamples] = w3;
  544. offsets[numSamples] = o;
  545. numSamples++;
  546. totalWeight += w3;
  547. }
  548. // Special case for last weight, as it doesn't have a matching pair
  549. float w = normalDistribution(intFilterRadius, scale);
  550. weights[numSamples] = w;
  551. offsets[numSamples] = 0.0f;
  552. numSamples++;
  553. totalWeight += w;
  554. // Normalize weights
  555. float invTotalWeight = 1.0f / totalWeight;
  556. for(UINT32 i = 0; i < numSamples; i++)
  557. weights[i] *= invTotalWeight;
  558. return numSamples;
  559. }
  560. float GaussianBlurMat::calcKernelRadius(const SPtr<Texture>& source, float scale, Direction filterDir)
  561. {
  562. scale = Math::clamp01(scale);
  563. UINT32 length;
  564. if (filterDir == DirHorizontal)
  565. length = source->getProperties().getWidth();
  566. else
  567. length = source->getProperties().getHeight();
  568. // Divide by two because we need the radius
  569. return std::min(length * scale / 2, (float)MAX_BLUR_SAMPLES - 1);
  570. }
  571. GaussianDOFParamDef gGaussianDOFParamDef;
  572. template<bool Near, bool Far>
  573. GaussianDOFSeparateMat<Near, Far>::GaussianDOFSeparateMat()
  574. {
  575. mParamBuffer = gGaussianDOFParamDef.createBuffer();
  576. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  577. mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gColorTex", mColorTexture);
  578. mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mDepthTexture);
  579. GpuParamSampState colorSampState;
  580. mParamsSet->getGpuParams()->getSamplerStateParam(GPT_FRAGMENT_PROGRAM, "gColorSamp", colorSampState);
  581. SAMPLER_STATE_DESC desc;
  582. desc.minFilter = FO_POINT;
  583. desc.magFilter = FO_POINT;
  584. desc.mipFilter = FO_POINT;
  585. desc.addressMode.u = TAM_CLAMP;
  586. desc.addressMode.v = TAM_CLAMP;
  587. desc.addressMode.w = TAM_CLAMP;
  588. SPtr<SamplerState> samplerState = SamplerState::create(desc);
  589. colorSampState.set(samplerState);
  590. }
  591. template<bool Near, bool Far>
  592. void GaussianDOFSeparateMat<Near, Far>::_initDefines(ShaderDefines& defines)
  593. {
  594. defines.set("NEAR", Near ? 1 : 0);
  595. defines.set("FAR", Far ? 1 : 0);
  596. defines.set("NEAR_AND_FAR", (Near && Far) ? 1 : 0);
  597. }
  598. template<bool Near, bool Far>
  599. void GaussianDOFSeparateMat<Near, Far>::execute(const SPtr<Texture>& color, const SPtr<Texture>& depth,
  600. const RendererView& view, const DepthOfFieldSettings& settings)
  601. {
  602. const TextureProperties& srcProps = color->getProperties();
  603. UINT32 outputWidth = std::max(1U, srcProps.getWidth() / 2);
  604. UINT32 outputHeight = std::max(1U, srcProps.getHeight() / 2);
  605. POOLED_RENDER_TEXTURE_DESC outputTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(srcProps.getFormat(),
  606. outputWidth, outputHeight, TU_RENDERTARGET);
  607. mOutput0 = GpuResourcePool::instance().get(outputTexDesc);
  608. SPtr<RenderTexture> rt;
  609. if (Near && Far)
  610. {
  611. mOutput1 = GpuResourcePool::instance().get(outputTexDesc);
  612. RENDER_TEXTURE_DESC rtDesc;
  613. rtDesc.colorSurfaces[0].texture = mOutput0->texture;
  614. rtDesc.colorSurfaces[1].texture = mOutput1->texture;
  615. rt = RenderTexture::create(rtDesc);
  616. }
  617. else
  618. rt = mOutput0->renderTexture;
  619. Vector2 invTexSize(1.0f / srcProps.getWidth(), 1.0f / srcProps.getHeight());
  620. gGaussianDOFParamDef.gHalfPixelOffset.set(mParamBuffer, invTexSize * 0.5f);
  621. gGaussianDOFParamDef.gNearBlurPlane.set(mParamBuffer, settings.focalDistance - settings.focalRange * 0.5f);
  622. gGaussianDOFParamDef.gFarBlurPlane.set(mParamBuffer, settings.focalDistance + settings.focalRange * 0.5f);
  623. gGaussianDOFParamDef.gInvNearBlurRange.set(mParamBuffer, 1.0f / settings.nearTransitionRange);
  624. gGaussianDOFParamDef.gInvFarBlurRange.set(mParamBuffer, 1.0f / settings.farTransitionRange);
  625. mColorTexture.set(color);
  626. mDepthTexture.set(depth);
  627. SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
  628. mParamsSet->setParamBlockBuffer("PerCamera", perView);
  629. RenderAPI& rapi = RenderAPI::instance();
  630. rapi.setRenderTarget(rt);
  631. gRendererUtility().setPass(mMaterial);
  632. gRendererUtility().setPassParams(mParamsSet);
  633. gRendererUtility().drawScreenQuad();
  634. }
  635. template <bool Near, bool Far>
  636. SPtr<PooledRenderTexture> GaussianDOFSeparateMat<Near, Far>::getOutput(UINT32 idx)
  637. {
  638. if (idx == 0)
  639. return mOutput0;
  640. else if (idx == 1)
  641. return mOutput1;
  642. return nullptr;
  643. }
  644. template<bool Near, bool Far>
  645. void GaussianDOFSeparateMat<Near, Far>::release()
  646. {
  647. if (mOutput0 != nullptr)
  648. GpuResourcePool::instance().release(mOutput0);
  649. if (mOutput1 != nullptr)
  650. GpuResourcePool::instance().release(mOutput1);
  651. }
  652. template class GaussianDOFSeparateMat<true, true>;
  653. template class GaussianDOFSeparateMat<true, false>;
  654. template class GaussianDOFSeparateMat<false, true>;
  655. template<bool Near, bool Far>
  656. GaussianDOFCombineMat<Near, Far>::GaussianDOFCombineMat()
  657. {
  658. mParamBuffer = gGaussianDOFParamDef.createBuffer();
  659. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  660. SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
  661. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gFocusedTex", mFocusedTexture);
  662. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mDepthTexture);
  663. if(gpuParams->hasTexture(GPT_FRAGMENT_PROGRAM, "gNearTex"))
  664. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gNearTex", mNearTexture);
  665. if(gpuParams->hasTexture(GPT_FRAGMENT_PROGRAM, "gFarTex"))
  666. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gFarTex", mFarTexture);
  667. }
  668. template<bool Near, bool Far>
  669. void GaussianDOFCombineMat<Near, Far>::_initDefines(ShaderDefines& defines)
  670. {
  671. defines.set("NEAR", Near ? 1 : 0);
  672. defines.set("FAR", Far ? 1 : 0);
  673. defines.set("NEAR_AND_FAR", (Near && Far) ? 1 : 0);
  674. }
  675. template<bool Near, bool Far>
  676. void GaussianDOFCombineMat<Near, Far>::execute(const SPtr<Texture>& focused, const SPtr<Texture>& near,
  677. const SPtr<Texture>& far, const SPtr<Texture>& depth, const SPtr<RenderTarget>& output,
  678. const RendererView& view, const DepthOfFieldSettings& settings)
  679. {
  680. const TextureProperties& srcProps = focused->getProperties();
  681. Vector2 invTexSize(1.0f / srcProps.getWidth(), 1.0f / srcProps.getHeight());
  682. gGaussianDOFParamDef.gHalfPixelOffset.set(mParamBuffer, invTexSize * 0.5f);
  683. gGaussianDOFParamDef.gNearBlurPlane.set(mParamBuffer, settings.focalDistance - settings.focalRange * 0.5f);
  684. gGaussianDOFParamDef.gFarBlurPlane.set(mParamBuffer, settings.focalDistance + settings.focalRange * 0.5f);
  685. gGaussianDOFParamDef.gInvNearBlurRange.set(mParamBuffer, 1.0f / settings.nearTransitionRange);
  686. gGaussianDOFParamDef.gInvFarBlurRange.set(mParamBuffer, 1.0f / settings.farTransitionRange);
  687. mFocusedTexture.set(focused);
  688. mNearTexture.set(near);
  689. mFarTexture.set(far);
  690. mDepthTexture.set(depth);
  691. SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
  692. mParamsSet->setParamBlockBuffer("PerCamera", perView);
  693. RenderAPI& rapi = RenderAPI::instance();
  694. rapi.setRenderTarget(output);
  695. gRendererUtility().setPass(mMaterial);
  696. gRendererUtility().setPassParams(mParamsSet);
  697. gRendererUtility().drawScreenQuad();
  698. }
  699. template class GaussianDOFCombineMat<true, true>;
  700. template class GaussianDOFCombineMat<true, false>;
  701. template class GaussianDOFCombineMat<false, true>;
  702. void GaussianDOF::execute(const SPtr<Texture>& sceneColor, const SPtr<Texture>& sceneDepth,
  703. const SPtr<RenderTarget>& output, const RendererView& view, const DepthOfFieldSettings& settings)
  704. {
  705. bool near = settings.nearBlurAmount > 0.0f;
  706. bool far = settings.farBlurAmount > 0.0f;
  707. // This shouldn't have been called if both are false
  708. assert(near || far);
  709. IGaussianDOFSeparateMat* separateMat;
  710. IGaussianDOFCombineMat* combineMat;
  711. if (near && far)
  712. {
  713. separateMat = &mSeparateNF;
  714. combineMat = &mCombineNF;
  715. }
  716. else
  717. {
  718. if(near)
  719. {
  720. separateMat = &mSeparateN;
  721. combineMat = &mCombineN;
  722. }
  723. else
  724. {
  725. separateMat = &mSeparateF;
  726. combineMat = &mCombineF;
  727. }
  728. }
  729. separateMat->execute(sceneColor, sceneDepth, view, settings);
  730. SPtr<PooledRenderTexture> nearTex, farTex;
  731. if(near && far)
  732. {
  733. nearTex = separateMat->getOutput(0);
  734. farTex = separateMat->getOutput(1);
  735. }
  736. else
  737. {
  738. if (near)
  739. nearTex = separateMat->getOutput(0);
  740. else
  741. farTex = separateMat->getOutput(0);
  742. }
  743. // Blur the out of focus pixels
  744. // Note: Perhaps set up stencil so I can avoid performing blur on unused parts of the textures?
  745. const TextureProperties& texProps = nearTex ? nearTex->texture->getProperties() : farTex->texture->getProperties();
  746. POOLED_RENDER_TEXTURE_DESC tempTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(texProps.getFormat(),
  747. texProps.getWidth(), texProps.getHeight(), TU_RENDERTARGET);
  748. SPtr<PooledRenderTexture> tempTexture = GpuResourcePool::instance().get(tempTexDesc);
  749. SPtr<Texture> blurredNearTex;
  750. if(nearTex)
  751. {
  752. mBlur.execute(nearTex->texture, settings.nearBlurAmount, tempTexture->renderTexture);
  753. blurredNearTex = tempTexture->texture;
  754. }
  755. SPtr<Texture> blurredFarTex;
  756. if(farTex)
  757. {
  758. // If temporary texture is used up, re-use the original near texture for the blurred result
  759. if(blurredNearTex)
  760. {
  761. mBlur.execute(farTex->texture, settings.farBlurAmount, nearTex->renderTexture);
  762. blurredFarTex = nearTex->texture;
  763. }
  764. else // Otherwise just use the temporary
  765. {
  766. mBlur.execute(farTex->texture, settings.farBlurAmount, tempTexture->renderTexture);
  767. blurredFarTex = tempTexture->texture;
  768. }
  769. }
  770. combineMat->execute(sceneColor, blurredNearTex, blurredFarTex, sceneDepth, output, view, settings);
  771. separateMat->release();
  772. GpuResourcePool::instance().release(tempTexture);
  773. }
  774. bool GaussianDOF::requiresDOF(const DepthOfFieldSettings& settings)
  775. {
  776. bool near = settings.nearBlurAmount > 0.0f;
  777. bool far = settings.farBlurAmount > 0.0f;
  778. return settings.enabled && (near || far);
  779. }
  780. BuildHiZMat::BuildHiZMat()
  781. {
  782. SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
  783. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mInputTexture);
  784. }
  785. void BuildHiZMat::_initDefines(ShaderDefines& defines)
  786. {
  787. // Do nothing
  788. }
  789. void BuildHiZMat::execute(const SPtr<Texture>& source, UINT32 srcMip, const Rect2& srcRect, const Rect2& dstRect,
  790. const SPtr<RenderTexture>& output)
  791. {
  792. RenderAPI& rapi = RenderAPI::instance();
  793. const TextureProperties& srcProps = source->getProperties();
  794. mInputTexture.set(source, TextureSurface(srcMip));
  795. rapi.setRenderTarget(output);
  796. rapi.setViewport(dstRect);
  797. gRendererUtility().setPass(mMaterial);
  798. gRendererUtility().setPassParams(mParamsSet);
  799. gRendererUtility().drawScreenQuad(srcRect);
  800. rapi.setViewport(Rect2(0, 0, 1, 1));
  801. }
  802. void BuildHiZ::execute(const RendererViewTargetData& viewInfo, const SPtr<Texture>& source, const SPtr<Texture>& output)
  803. {
  804. GpuResourcePool& pool = GpuResourcePool::instance();
  805. // First resolve if MSAA if required
  806. SPtr<PooledRenderTexture> resolvedDepth;
  807. Rect2 srcRect = viewInfo.nrmViewRect;
  808. // Generate first mip
  809. RENDER_TEXTURE_DESC rtDesc;
  810. rtDesc.colorSurfaces[0].texture = output;
  811. rtDesc.colorSurfaces[0].mipLevel = 0;
  812. // Make sure that 1 pixel in HiZ maps to a 2x2 block in source
  813. const TextureProperties& outProps = output->getProperties();
  814. Rect2 destRect(0, 0,
  815. Math::ceilToInt(viewInfo.viewRect.width / 2.0f) / (float)outProps.getWidth(),
  816. Math::ceilToInt(viewInfo.viewRect.height / 2.0f) / (float)outProps.getHeight());
  817. // If viewport size is odd, adjust UV
  818. srcRect.width += (viewInfo.viewRect.width % 2) * (1.0f / viewInfo.viewRect.width);
  819. srcRect.height += (viewInfo.viewRect.height % 2) * (1.0f / viewInfo.viewRect.height);
  820. SPtr<RenderTexture> rt = RenderTexture::create(rtDesc);
  821. mHiZMat.execute(source, 0, srcRect, destRect, rt);
  822. // Generate remaining mip levels
  823. for(UINT32 i = 1; i <= outProps.getNumMipmaps(); i++)
  824. {
  825. rtDesc.colorSurfaces[0].mipLevel = i;
  826. rt = RenderTexture::create(rtDesc);
  827. mHiZMat.execute(output, i - 1, destRect, destRect, rt);
  828. }
  829. if (resolvedDepth)
  830. pool.release(resolvedDepth);
  831. }
  832. POOLED_RENDER_TEXTURE_DESC BuildHiZ::getHiZTextureDesc(UINT32 viewWidth, UINT32 viewHeight)
  833. {
  834. UINT32 size = Bitwise::nextPow2(std::max(viewWidth, viewHeight));
  835. UINT32 numMips = PixelUtil::getMaxMipmaps(size, size, 1, PF_FLOAT32_R);
  836. size = 1 << numMips;
  837. // Note: Use the 32-bit buffer here as 16-bit causes too much banding (most of the scene gets assigned 4-5 different
  838. // depth values).
  839. // - When I add UNORM 16-bit format I should be able to switch to that
  840. return POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT32_R, size, size, TU_RENDERTARGET, 1, false, 1, numMips);
  841. }
  842. FXAAParamDef gFXAAParamDef;
  843. FXAAMat::FXAAMat()
  844. {
  845. mParamBuffer = gFXAAParamDef.createBuffer();
  846. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  847. mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
  848. }
  849. void FXAAMat::_initDefines(ShaderDefines& defines)
  850. {
  851. // Do nothing
  852. }
  853. void FXAAMat::execute(const SPtr<Texture>& source, const SPtr<RenderTarget>& destination)
  854. {
  855. const TextureProperties& srcProps = source->getProperties();
  856. Vector2 invTexSize(1.0f / srcProps.getWidth(), 1.0f / srcProps.getHeight());
  857. gFXAAParamDef.gInvTexSize.set(mParamBuffer, invTexSize);
  858. mInputTexture.set(source);
  859. RenderAPI& rapi = RenderAPI::instance();
  860. rapi.setRenderTarget(destination);
  861. gRendererUtility().setPass(mMaterial);
  862. gRendererUtility().setPassParams(mParamsSet);
  863. gRendererUtility().drawScreenQuad();
  864. }
  865. SSAOParamDef gSSAOParamDef;
  866. template<bool UPSAMPLE, bool FINAL_PASS, int QUALITY>
  867. SSAOMat<UPSAMPLE, FINAL_PASS, QUALITY>::SSAOMat()
  868. {
  869. mParamBuffer = gSSAOParamDef.createBuffer();
  870. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  871. SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
  872. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mDepthTexture);
  873. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gNormalsTex", mNormalsTexture);
  874. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDownsampledAO", mDownsampledAOTexture);
  875. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gSetupAO", mSetupAOTexture);
  876. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gRandomTex", mRandomTexture);
  877. SAMPLER_STATE_DESC inputSampDesc;
  878. inputSampDesc.minFilter = FO_POINT;
  879. inputSampDesc.magFilter = FO_POINT;
  880. inputSampDesc.mipFilter = FO_POINT;
  881. inputSampDesc.addressMode.u = TAM_CLAMP;
  882. inputSampDesc.addressMode.v = TAM_CLAMP;
  883. inputSampDesc.addressMode.w = TAM_CLAMP;
  884. SPtr<SamplerState> inputSampState = SamplerState::create(inputSampDesc);
  885. gpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gInputSamp", inputSampState);
  886. SAMPLER_STATE_DESC randomSampDesc;
  887. randomSampDesc.minFilter = FO_POINT;
  888. randomSampDesc.magFilter = FO_POINT;
  889. randomSampDesc.mipFilter = FO_POINT;
  890. randomSampDesc.addressMode.u = TAM_WRAP;
  891. randomSampDesc.addressMode.v = TAM_WRAP;
  892. randomSampDesc.addressMode.w = TAM_WRAP;
  893. SPtr<SamplerState> randomSampState = SamplerState::create(randomSampDesc);
  894. gpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gRandomSamp", randomSampState);
  895. }
  896. template<bool UPSAMPLE, bool FINAL_PASS, int QUALITY>
  897. void SSAOMat<UPSAMPLE, FINAL_PASS, QUALITY>::_initDefines(ShaderDefines& defines)
  898. {
  899. defines.set("MIX_WITH_UPSAMPLED", UPSAMPLE ? 1 : 0);
  900. defines.set("FINAL_AO", FINAL_PASS ? 1 : 0);
  901. defines.set("QUALITY", QUALITY);
  902. }
  903. template <bool UPSAMPLE, bool FINAL_PASS, int QUALITY>
  904. void SSAOMat<UPSAMPLE, FINAL_PASS, QUALITY>::execute(const RendererView& view, const SSAOTextureInputs& textures,
  905. const SPtr<RenderTexture>& destination, const AmbientOcclusionSettings& settings)
  906. {
  907. // Scale that can be used to adjust how quickly does AO radius increase with downsampled AO. This yields a very
  908. // small AO radius at highest level, and very large radius at lowest level
  909. static const float DOWNSAMPLE_SCALE = 4.0f;
  910. const RendererViewProperties& viewProps = view.getProperties();
  911. const RenderTargetProperties& rtProps = destination->getProperties();
  912. Vector2 tanHalfFOV;
  913. tanHalfFOV.x = 1.0f / viewProps.projTransform[0][0];
  914. tanHalfFOV.y = 1.0f / viewProps.projTransform[1][1];
  915. float cotHalfFOV = viewProps.projTransform[0][0];
  916. // Downsampled AO uses a larger AO radius (in higher resolutions this would cause too much cache trashing). This
  917. // means if only full res AO is used, then only AO from nearby geometry will be calculated.
  918. float viewScale = viewProps.viewRect.width / (float)rtProps.getWidth();
  919. // Ramp up the radius exponentially. c^log2(x) function chosen arbitrarily, as it ramps up the radius in a nice way
  920. float scale = pow(DOWNSAMPLE_SCALE, Math::log2(viewScale));
  921. // Determine maximum radius scale (division by 4 because we don't downsample more than quarter-size)
  922. float maxScale = pow(DOWNSAMPLE_SCALE, Math::log2(4.0f));
  923. // Normalize the scale in [0, 1] range
  924. scale /= maxScale;
  925. float radius = settings.radius * scale;
  926. // Factors used for scaling the AO contribution with range
  927. Vector2 fadeMultiplyAdd;
  928. fadeMultiplyAdd.x = 1.0f / settings.fadeRange;
  929. fadeMultiplyAdd.y = -settings.fadeDistance / settings.fadeRange;
  930. gSSAOParamDef.gSampleRadius.set(mParamBuffer, radius);
  931. gSSAOParamDef.gCotHalfFOV.set(mParamBuffer, cotHalfFOV);
  932. gSSAOParamDef.gTanHalfFOV.set(mParamBuffer, tanHalfFOV);
  933. gSSAOParamDef.gWorldSpaceRadiusMask.set(mParamBuffer, 1.0f);
  934. gSSAOParamDef.gBias.set(mParamBuffer, (settings.bias * viewScale) / 1000.0f);
  935. gSSAOParamDef.gFadeMultiplyAdd.set(mParamBuffer, fadeMultiplyAdd);
  936. gSSAOParamDef.gPower.set(mParamBuffer, settings.power);
  937. gSSAOParamDef.gIntensity.set(mParamBuffer, settings.intensity);
  938. if(UPSAMPLE)
  939. {
  940. const TextureProperties& props = textures.aoDownsampled->getProperties();
  941. Vector2 downsampledPixelSize;
  942. downsampledPixelSize.x = 1.0f / props.getWidth();
  943. downsampledPixelSize.y = 1.0f / props.getHeight();
  944. gSSAOParamDef.gDownsampledPixelSize.set(mParamBuffer, downsampledPixelSize);
  945. }
  946. // Generate a scale which we need to use in order to achieve tiling
  947. const TextureProperties& rndProps = textures.randomRotations->getProperties();
  948. UINT32 rndWidth = rndProps.getWidth();
  949. UINT32 rndHeight = rndProps.getHeight();
  950. //// Multiple of random texture size, rounded up
  951. UINT32 scaleWidth = (rtProps.getWidth() + rndWidth - 1) / rndWidth;
  952. UINT32 scaleHeight = (rtProps.getHeight() + rndHeight - 1) / rndHeight;
  953. Vector2 randomTileScale((float)scaleWidth, (float)scaleHeight);
  954. gSSAOParamDef.gRandomTileScale.set(mParamBuffer, randomTileScale);
  955. mSetupAOTexture.set(textures.aoSetup);
  956. if (FINAL_PASS)
  957. {
  958. mDepthTexture.set(textures.sceneDepth);
  959. mNormalsTexture.set(textures.sceneNormals);
  960. }
  961. if (UPSAMPLE)
  962. mDownsampledAOTexture.set(textures.aoDownsampled);
  963. mRandomTexture.set(textures.randomRotations);
  964. SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
  965. mParamsSet->setParamBlockBuffer("PerCamera", perView);
  966. RenderAPI& rapi = RenderAPI::instance();
  967. rapi.setRenderTarget(destination);
  968. gRendererUtility().setPass(mMaterial);
  969. gRendererUtility().setPassParams(mParamsSet);
  970. gRendererUtility().drawScreenQuad();
  971. }
  972. SSAODownsampleParamDef gSSAODownsampleParamDef;
  973. SSAODownsampleMat::SSAODownsampleMat()
  974. {
  975. mParamBuffer = gSSAODownsampleParamDef.createBuffer();
  976. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  977. SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
  978. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mDepthTexture);
  979. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gNormalsTex", mNormalsTexture);
  980. SAMPLER_STATE_DESC inputSampDesc;
  981. inputSampDesc.minFilter = FO_LINEAR;
  982. inputSampDesc.magFilter = FO_LINEAR;
  983. inputSampDesc.mipFilter = FO_LINEAR;
  984. inputSampDesc.addressMode.u = TAM_CLAMP;
  985. inputSampDesc.addressMode.v = TAM_CLAMP;
  986. inputSampDesc.addressMode.w = TAM_CLAMP;
  987. SPtr<SamplerState> inputSampState = SamplerState::create(inputSampDesc);
  988. gpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gInputSamp", inputSampState);
  989. }
  990. void SSAODownsampleMat::_initDefines(ShaderDefines& defines)
  991. {
  992. // Do nothing
  993. }
  994. void SSAODownsampleMat::execute(const RendererView& view, const SPtr<Texture>& depth, const SPtr<Texture>& normals,
  995. const SPtr<RenderTexture>& destination, float depthRange)
  996. {
  997. const RendererViewProperties& viewProps = view.getProperties();
  998. const RenderTargetProperties& rtProps = destination->getProperties();
  999. Vector2 pixelSize;
  1000. pixelSize.x = 1.0f / rtProps.getWidth();
  1001. pixelSize.y = 1.0f / rtProps.getHeight();
  1002. float scale = viewProps.viewRect.width / (float)rtProps.getWidth();
  1003. gSSAODownsampleParamDef.gPixelSize.set(mParamBuffer, pixelSize);
  1004. gSSAODownsampleParamDef.gInvDepthThreshold.set(mParamBuffer, (1.0f / depthRange) / scale);
  1005. mDepthTexture.set(depth);
  1006. mNormalsTexture.set(normals);
  1007. SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
  1008. mParamsSet->setParamBlockBuffer("PerCamera", perView);
  1009. RenderAPI& rapi = RenderAPI::instance();
  1010. rapi.setRenderTarget(destination);
  1011. gRendererUtility().setPass(mMaterial);
  1012. gRendererUtility().setPassParams(mParamsSet);
  1013. gRendererUtility().drawScreenQuad();
  1014. }
  1015. SSAOBlurParamDef gSSAOBlurParamDef;
  1016. template<bool HORIZONTAL>
  1017. SSAOBlurMat<HORIZONTAL>::SSAOBlurMat()
  1018. {
  1019. mParamBuffer = gSSAOBlurParamDef.createBuffer();
  1020. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  1021. SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
  1022. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mAOTexture);
  1023. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mDepthTexture);
  1024. SAMPLER_STATE_DESC inputSampDesc;
  1025. inputSampDesc.minFilter = FO_POINT;
  1026. inputSampDesc.magFilter = FO_POINT;
  1027. inputSampDesc.mipFilter = FO_POINT;
  1028. inputSampDesc.addressMode.u = TAM_CLAMP;
  1029. inputSampDesc.addressMode.v = TAM_CLAMP;
  1030. inputSampDesc.addressMode.w = TAM_CLAMP;
  1031. SPtr<SamplerState> inputSampState = SamplerState::create(inputSampDesc);
  1032. gpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gInputSamp", inputSampState);
  1033. }
  1034. template<bool HORIZONTAL>
  1035. void SSAOBlurMat<HORIZONTAL>::_initDefines(ShaderDefines& defines)
  1036. {
  1037. defines.set("DIR_HORZ", HORIZONTAL ? 1 : 0);
  1038. }
  1039. template<bool HORIZONTAL>
  1040. void SSAOBlurMat<HORIZONTAL>::execute(const RendererView& view, const SPtr<Texture>& ao, const SPtr<Texture>& depth,
  1041. const SPtr<RenderTexture>& destination, float depthRange)
  1042. {
  1043. const RendererViewProperties& viewProps = view.getProperties();
  1044. const TextureProperties& texProps = ao->getProperties();
  1045. Vector2 pixelSize;
  1046. pixelSize.x = 1.0f / texProps.getWidth();
  1047. pixelSize.y = 1.0f / texProps.getHeight();
  1048. Vector2 pixelOffset(BsZero);
  1049. if (HORIZONTAL)
  1050. pixelOffset.x = pixelSize.x;
  1051. else
  1052. pixelOffset.y = pixelSize.y;
  1053. float scale = viewProps.viewRect.width / (float)texProps.getWidth();
  1054. gSSAOBlurParamDef.gPixelSize.set(mParamBuffer, pixelSize);
  1055. gSSAOBlurParamDef.gPixelOffset.set(mParamBuffer, pixelOffset);
  1056. gSSAOBlurParamDef.gInvDepthThreshold.set(mParamBuffer, (1.0f / depthRange) / scale);
  1057. mAOTexture.set(ao);
  1058. mDepthTexture.set(depth);
  1059. SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
  1060. mParamsSet->setParamBlockBuffer("PerCamera", perView);
  1061. RenderAPI& rapi = RenderAPI::instance();
  1062. rapi.setRenderTarget(destination);
  1063. gRendererUtility().setPass(mMaterial);
  1064. gRendererUtility().setPassParams(mParamsSet);
  1065. gRendererUtility().drawScreenQuad();
  1066. }
  1067. SSAO::SSAO()
  1068. {
  1069. mSSAORandomizationTex = generate4x4RandomizationTexture();
  1070. }
  1071. void SSAO::execute(const RendererView& view, const SPtr<RenderTexture>& destination,
  1072. const AmbientOcclusionSettings& settings)
  1073. {
  1074. /** Maximum valid depth range within samples in a sample set. In meters. */
  1075. static const float DEPTH_RANGE = 1.0f;
  1076. const RendererViewProperties& viewProps = view.getProperties();
  1077. SPtr<RenderTargets> renderTargets = view.getRenderTargets();
  1078. SPtr<Texture> sceneDepth = renderTargets->get(RTT_ResolvedDepth);
  1079. SPtr<Texture> sceneNormals = renderTargets->get(RTT_GBuffer, RT_COLOR1);
  1080. const TextureProperties& normalsProps = sceneNormals->getProperties();
  1081. SPtr<PooledRenderTexture> resolvedNormals;
  1082. if(sceneNormals->getProperties().getNumSamples() > 1)
  1083. {
  1084. POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(normalsProps.getFormat(),
  1085. normalsProps.getWidth(), normalsProps.getHeight(), TU_RENDERTARGET);
  1086. resolvedNormals = GpuResourcePool::instance().get(desc);
  1087. RenderAPI::instance().setRenderTarget(resolvedNormals->renderTexture);
  1088. gRendererUtility().blit(sceneNormals);
  1089. sceneNormals = resolvedNormals->texture;
  1090. }
  1091. // Multiple downsampled AO levels are used to minimize cache trashing. Downsampled AO targets use larger radius,
  1092. // whose contents are then blended with the higher level.
  1093. UINT32 quality = settings.quality;
  1094. UINT32 numDownsampleLevels = 0;
  1095. if (quality > 1)
  1096. numDownsampleLevels = 1;
  1097. else if (quality > 2)
  1098. numDownsampleLevels = 2;
  1099. SPtr<PooledRenderTexture> setupTex0;
  1100. if(numDownsampleLevels > 0)
  1101. {
  1102. Vector2I downsampledSize(
  1103. std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 2)),
  1104. std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 2))
  1105. );
  1106. POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, downsampledSize.x,
  1107. downsampledSize.y, TU_RENDERTARGET);
  1108. setupTex0 = GpuResourcePool::instance().get(desc);
  1109. mDownsample.execute(view, sceneDepth, sceneNormals, setupTex0->renderTexture, DEPTH_RANGE);
  1110. }
  1111. SPtr<PooledRenderTexture> setupTex1;
  1112. if(numDownsampleLevels > 1)
  1113. {
  1114. Vector2I downsampledSize(
  1115. std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 4)),
  1116. std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 4))
  1117. );
  1118. POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, downsampledSize.x,
  1119. downsampledSize.y, TU_RENDERTARGET);
  1120. setupTex1 = GpuResourcePool::instance().get(desc);
  1121. mDownsample.execute(view, sceneDepth, sceneNormals, setupTex1->renderTexture, DEPTH_RANGE);
  1122. }
  1123. SSAOTextureInputs textures;
  1124. textures.sceneDepth = sceneDepth;
  1125. textures.sceneNormals = sceneNormals;
  1126. textures.randomRotations = mSSAORandomizationTex;
  1127. SPtr<PooledRenderTexture> downAOTex1;
  1128. if(numDownsampleLevels > 1)
  1129. {
  1130. textures.aoSetup = setupTex1->texture;
  1131. Vector2I downsampledSize(
  1132. std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 4)),
  1133. std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 4))
  1134. );
  1135. POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, downsampledSize.x,
  1136. downsampledSize.y, TU_RENDERTARGET);
  1137. downAOTex1 = GpuResourcePool::instance().get(desc);
  1138. executeSSAOMat(false, false, quality, view, textures, downAOTex1->renderTexture, settings);
  1139. GpuResourcePool::instance().release(setupTex1);
  1140. setupTex1 = nullptr;
  1141. }
  1142. SPtr<PooledRenderTexture> downAOTex0;
  1143. if(numDownsampleLevels > 0)
  1144. {
  1145. textures.aoSetup = setupTex0->texture;
  1146. if(downAOTex1)
  1147. textures.aoDownsampled = downAOTex1->texture;
  1148. Vector2I downsampledSize(
  1149. std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 2)),
  1150. std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 2))
  1151. );
  1152. POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, downsampledSize.x,
  1153. downsampledSize.y, TU_RENDERTARGET);
  1154. downAOTex0 = GpuResourcePool::instance().get(desc);
  1155. bool upsample = numDownsampleLevels > 1;
  1156. executeSSAOMat(upsample, false, quality, view, textures, downAOTex0->renderTexture, settings);
  1157. if(upsample)
  1158. {
  1159. GpuResourcePool::instance().release(downAOTex1);
  1160. downAOTex1 = nullptr;
  1161. }
  1162. }
  1163. {
  1164. if(setupTex0)
  1165. textures.aoSetup = setupTex0->texture;
  1166. if(downAOTex0)
  1167. textures.aoDownsampled = downAOTex0->texture;
  1168. bool upsample = numDownsampleLevels > 0;
  1169. executeSSAOMat(upsample, true, quality, view, textures, destination, settings);
  1170. }
  1171. if(resolvedNormals)
  1172. {
  1173. GpuResourcePool::instance().release(resolvedNormals);
  1174. resolvedNormals = nullptr;
  1175. }
  1176. if(numDownsampleLevels > 0)
  1177. {
  1178. GpuResourcePool::instance().release(setupTex0);
  1179. GpuResourcePool::instance().release(downAOTex0);
  1180. }
  1181. // Blur the output
  1182. // Note: If I implement temporal AA then this can probably be avoided. I can instead jitter the sample offsets
  1183. // each frame, and averaging them out should yield blurred AO.
  1184. if(quality > 1) // On level 0 we don't blur at all, on level 1 we use the ad-hoc blur in shader
  1185. {
  1186. const RenderTargetProperties& rtProps = destination->getProperties();
  1187. POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, rtProps.getWidth(),
  1188. rtProps.getHeight(), TU_RENDERTARGET);
  1189. SPtr<PooledRenderTexture> blurIntermediateTex = GpuResourcePool::instance().get(desc);
  1190. mBlurHorz.execute(view, destination->getColorTexture(0), sceneDepth, blurIntermediateTex->renderTexture,
  1191. DEPTH_RANGE);
  1192. mBlurVert.execute(view, blurIntermediateTex->texture, sceneDepth, destination, DEPTH_RANGE);
  1193. GpuResourcePool::instance().release(blurIntermediateTex);
  1194. }
  1195. }
  1196. void SSAO::executeSSAOMat(bool upsample, bool final, int quality, const RendererView& view,
  1197. const SSAOTextureInputs& textures, const SPtr<RenderTexture>& destination, const AmbientOcclusionSettings& settings)
  1198. {
  1199. #define PICK_MATERIAL(QUALITY) \
  1200. if(upsample) \
  1201. if(final) \
  1202. mSSAO_TT_##QUALITY.execute(view, textures, destination, settings); \
  1203. else \
  1204. mSSAO_TF_##QUALITY.execute(view, textures, destination, settings); \
  1205. else \
  1206. if(final) \
  1207. mSSAO_FT_##QUALITY.execute(view, textures, destination, settings); \
  1208. else \
  1209. mSSAO_FF_##QUALITY.execute(view, textures, destination, settings); \
  1210. switch(quality)
  1211. {
  1212. case 0:
  1213. PICK_MATERIAL(0)
  1214. break;
  1215. case 1:
  1216. PICK_MATERIAL(1)
  1217. break;
  1218. case 2:
  1219. PICK_MATERIAL(2)
  1220. break;
  1221. case 3:
  1222. PICK_MATERIAL(3)
  1223. break;
  1224. default:
  1225. case 4:
  1226. PICK_MATERIAL(4)
  1227. break;
  1228. }
  1229. #undef PICK_MATERIAL
  1230. }
  1231. SPtr<Texture> SSAO::generate4x4RandomizationTexture() const
  1232. {
  1233. UINT32 mapping[16] = { 13, 5, 1, 9, 14, 3, 7, 11, 15, 2, 6, 12, 4, 8, 0, 10 };
  1234. Vector2 bases[16];
  1235. for (UINT32 i = 0; i < 16; ++i)
  1236. {
  1237. float angle = (mapping[i] / 16.0f) * Math::PI;
  1238. bases[i].x = cos(angle);
  1239. bases[i].y = sin(angle);
  1240. }
  1241. SPtr<PixelData> pixelData = PixelData::create(4, 4, 1, PF_R8G8);
  1242. for(UINT32 y = 0; y < 4; ++y)
  1243. for(UINT32 x = 0; x < 4; ++x)
  1244. {
  1245. UINT32 base = (y * 4) + x;
  1246. Color color;
  1247. color.r = bases[base].x * 0.5f + 0.5f;
  1248. color.g = bases[base].y * 0.5f + 0.5f;
  1249. pixelData->setColorAt(color, x, y);
  1250. }
  1251. return Texture::create(pixelData);
  1252. }
  1253. SSRStencilParamDef gSSRStencilParamDef;
  1254. SSRStencilMat::SSRStencilMat()
  1255. :mGBufferParams(mMaterial, mParamsSet)
  1256. {
  1257. mParamBuffer = gSSRStencilParamDef.createBuffer();
  1258. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  1259. }
  1260. void SSRStencilMat::_initDefines(ShaderDefines& defines)
  1261. {
  1262. // Do nothing
  1263. }
  1264. void SSRStencilMat::execute(const RendererView& view, const ScreenSpaceReflectionsSettings& settings)
  1265. {
  1266. const RendererViewProperties& viewProps = view.getProperties();
  1267. RenderTargets& renderTargets = *view.getRenderTargets();
  1268. mGBufferParams.bind(renderTargets);
  1269. Vector2 roughnessScaleBias = SSRTraceMat::calcRoughnessFadeScaleBias(settings.maxRoughness);
  1270. gSSRStencilParamDef.gRoughnessScaleBias.set(mParamBuffer, roughnessScaleBias);
  1271. SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
  1272. mParamsSet->setParamBlockBuffer("PerCamera", perView);
  1273. gRendererUtility().setPass(mMaterial);
  1274. gRendererUtility().setPassParams(mParamsSet);
  1275. gRendererUtility().drawScreenQuad();
  1276. }
  1277. SSRTraceParamDef gSSRTraceParamDef;
  1278. SSRTraceMat::SSRTraceMat()
  1279. :mGBufferParams(mMaterial, mParamsSet)
  1280. {
  1281. mParamBuffer = gSSRTraceParamDef.createBuffer();
  1282. mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
  1283. SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
  1284. gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gSceneColor", mSceneColorTexture);
  1285. }
  1286. void SSRTraceMat::_initDefines(ShaderDefines& defines)
  1287. {
  1288. // Do nothing
  1289. }
  1290. void SSRTraceMat::execute(const RendererView& view, const ScreenSpaceReflectionsSettings& settings,
  1291. const SPtr<RenderTexture>& destination)
  1292. {
  1293. const RendererViewProperties& viewProps = view.getProperties();
  1294. RenderTargets& renderTargets = *view.getRenderTargets();
  1295. mGBufferParams.bind(renderTargets);
  1296. mSceneColorTexture.set(renderTargets.get(RTT_ResolvedSceneColor));
  1297. SPtr<Texture> hiZ = renderTargets.get(RTT_HiZ);
  1298. const TextureProperties& hiZProps = hiZ->getProperties();
  1299. Rect2I viewRect = viewProps.viewRect;
  1300. // Maps from NDC to UV [0, 1]
  1301. Vector4 ndcToUVMapping;
  1302. ndcToUVMapping.x = 0.5f;
  1303. ndcToUVMapping.y = -0.5f;
  1304. ndcToUVMapping.z = 0.5f;
  1305. ndcToUVMapping.w = 0.5f;
  1306. // Either of these flips the Y axis, but if they're both true they cancel out
  1307. RenderAPI& rapi = RenderAPI::instance();
  1308. const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
  1309. if (rapiInfo.isFlagSet(RenderAPIFeatureFlag::UVYAxisUp) ^ rapiInfo.isFlagSet(RenderAPIFeatureFlag::NDCYAxisDown))
  1310. ndcToUVMapping.y = -ndcToUVMapping.y;
  1311. // Maps from [0, 1] to are of HiZ where depth is stored in
  1312. ndcToUVMapping.x *= (float)viewRect.width / hiZProps.getWidth();
  1313. ndcToUVMapping.y *= (float)viewRect.height / hiZProps.getHeight();
  1314. Vector2I bufferSize(hiZProps.getWidth(), hiZProps.getHeight());
  1315. gSSRTraceParamDef.gHiZSize.set(mParamBuffer, bufferSize);
  1316. gSSRTraceParamDef.gHiZNumMips.set(mParamBuffer, hiZProps.getNumMipmaps());
  1317. gSSRTraceParamDef.gHiZUVMapping.set(mParamBuffer, ndcToUVMapping);
  1318. SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
  1319. mParamsSet->setParamBlockBuffer("PerCamera", perView);
  1320. rapi.setRenderTarget(destination);
  1321. gRendererUtility().setPass(mMaterial);
  1322. gRendererUtility().setPassParams(mParamsSet);
  1323. gRendererUtility().drawScreenQuad();
  1324. }
  1325. Vector2 SSRTraceMat::calcRoughnessFadeScaleBias(float maxRoughness)
  1326. {
  1327. const static float RANGE_SCALE = 2.0f;
  1328. Vector2 scaleBias;
  1329. scaleBias.x = -RANGE_SCALE / (-1.0f + maxRoughness);
  1330. scaleBias.y = (RANGE_SCALE * maxRoughness) / (-1.0f + maxRoughness);
  1331. return scaleBias;
  1332. }
  1333. void PostProcessing::postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta)
  1334. {
  1335. auto& viewProps = viewInfo->getProperties();
  1336. PostProcessInfo& ppInfo = viewInfo->getPPInfo();
  1337. const StandardPostProcessSettings& settings = *ppInfo.settings;
  1338. SPtr<Texture> sceneColor = renderTargets->get(RTT_SceneColor);
  1339. Rect2 viewportRect = viewProps.nrmViewRect;
  1340. bool hdr = viewProps.isHDR;
  1341. bool msaa = viewProps.numSamples > 1;
  1342. if(hdr && settings.enableAutoExposure)
  1343. {
  1344. mDownsample.execute(1, msaa, sceneColor, ppInfo);
  1345. mEyeAdaptHistogram.execute(ppInfo);
  1346. mDownsample.release(1, msaa, ppInfo);
  1347. mEyeAdaptHistogramReduce.execute(ppInfo);
  1348. mEyeAdaptHistogram.release(ppInfo);
  1349. mEyeAdaptation.execute(ppInfo, frameDelta);
  1350. mEyeAdaptHistogramReduce.release(ppInfo);
  1351. }
  1352. bool gammaOnly;
  1353. bool autoExposure;
  1354. if (hdr)
  1355. {
  1356. if (settings.enableTonemapping)
  1357. {
  1358. if (ppInfo.settingDirty) // Rebuild LUT if PP settings changed
  1359. mCreateLUT.execute(ppInfo);
  1360. gammaOnly = false;
  1361. }
  1362. else
  1363. gammaOnly = true;
  1364. autoExposure = settings.enableAutoExposure;
  1365. }
  1366. else
  1367. {
  1368. gammaOnly = true;
  1369. autoExposure = false;
  1370. }
  1371. bool performDOF = GaussianDOF::requiresDOF(settings.depthOfField);
  1372. SPtr<RenderTarget> tonemapTarget;
  1373. if (!performDOF && !settings.enableFXAA)
  1374. tonemapTarget = viewProps.target;
  1375. else
  1376. {
  1377. renderTargets->allocate(RTT_ResolvedSceneColorSecondary);
  1378. tonemapTarget = renderTargets->getRT(RTT_ResolvedSceneColorSecondary);
  1379. }
  1380. mTonemapping.execute(gammaOnly, autoExposure, msaa, sceneColor, tonemapTarget, viewportRect, ppInfo);
  1381. if(performDOF)
  1382. {
  1383. SPtr<RenderTarget> dofTarget;
  1384. // If DOF is the final effect, output to final target, otherwise use a temporary
  1385. if (settings.enableFXAA)
  1386. {
  1387. renderTargets->allocate(RTT_ResolvedSceneColor);
  1388. dofTarget = renderTargets->getRT(RTT_ResolvedSceneColor);
  1389. }
  1390. else
  1391. dofTarget = viewProps.target;
  1392. SPtr<Texture> sceneDepth = renderTargets->get(RTT_ResolvedDepth);
  1393. mGaussianDOF.execute(renderTargets->get(RTT_ResolvedSceneColorSecondary), sceneDepth, dofTarget, *viewInfo,
  1394. settings.depthOfField);
  1395. renderTargets->release(RTT_ResolvedSceneColorSecondary);
  1396. }
  1397. if(settings.enableFXAA)
  1398. {
  1399. SPtr<Texture> fxaaSource;
  1400. if (performDOF)
  1401. fxaaSource = renderTargets->get(RTT_ResolvedSceneColor);
  1402. else
  1403. fxaaSource = renderTargets->get(RTT_ResolvedSceneColorSecondary);
  1404. // Note: I could skip executing FXAA over DOF and motion blurred pixels
  1405. mFXAA.execute(fxaaSource, viewProps.target);
  1406. if (performDOF)
  1407. renderTargets->release(RTT_ResolvedSceneColor);
  1408. else
  1409. renderTargets->release(RTT_ResolvedSceneColorSecondary);
  1410. }
  1411. if (ppInfo.settingDirty)
  1412. ppInfo.settingDirty = false;
  1413. }
  1414. void PostProcessing::buildSSAO(const RendererView& view)
  1415. {
  1416. const SPtr<RenderTargets> renderTargets = view.getRenderTargets();
  1417. const PostProcessInfo& ppInfo = view.getPPInfo();
  1418. mSSAO.execute(view, renderTargets->getRT(RTT_AmbientOcclusion), ppInfo.settings->ambientOcclusion);
  1419. }
  1420. }}