BsPostProcessing.cpp 57 KB

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