Bloom.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Renderer/Bloom.h>
  6. #include <AnKi/Renderer/Renderer.h>
  7. #include <AnKi/Renderer/LightShading.h>
  8. #include <AnKi/Renderer/Tonemapping.h>
  9. #include <AnKi/Util/Tracer.h>
  10. namespace anki {
  11. Error Bloom::init()
  12. {
  13. // Pyramid
  14. {
  15. const UVec2 pyramidSize = getRenderer().getInternalResolution() / 2;
  16. const U8 pyramidMipCount = computeMaxMipmapCount2d(pyramidSize.x(), pyramidSize.y(), g_cvarRenderBloomPyramidLowLimit);
  17. const Bool preferCompute = g_cvarRenderPreferCompute;
  18. // Create the miped texture
  19. TextureInitInfo texinit =
  20. getRenderer().create2DRenderTargetDescription(pyramidSize.x(), pyramidSize.y(), getRenderer().getHdrFormat(), "Bloom pyramid");
  21. texinit.m_usage = TextureUsageBit::kSrvPixel | TextureUsageBit::kSrvCompute;
  22. texinit.m_usage |= (preferCompute) ? TextureUsageBit::kUavCompute : TextureUsageBit::kRtvDsvWrite;
  23. texinit.m_mipmapCount = pyramidMipCount;
  24. m_pyramidTex = getRenderer().createAndClearRenderTarget(texinit, TextureUsageBit::kSrvCompute);
  25. // Shader programs
  26. ANKI_CHECK(loadShaderProgram("ShaderBinaries/Bloom.ankiprogbin", {}, m_prog, m_downscaleGrProg, "Downscale"));
  27. }
  28. // Exposure
  29. {
  30. const UVec2 pyramidSmallerMipSize = UVec2(m_pyramidTex->getWidth(), m_pyramidTex->getHeight()) >> (m_pyramidTex->getMipmapCount() - 1);
  31. const UVec2 expSize = pyramidSmallerMipSize * 2; // Upacale a bit
  32. // Create RT info
  33. m_exposureRtDesc = getRenderer().create2DRenderTargetDescription(expSize.x(), expSize.y(), getRenderer().getHdrFormat(), "Bloom exposure");
  34. m_exposureRtDesc.bake();
  35. // init shaders
  36. ANKI_CHECK(loadShaderProgram("ShaderBinaries/Bloom.ankiprogbin", {}, m_prog, m_exposureGrProg, "Exposure"));
  37. }
  38. // Upscale
  39. {
  40. const UVec2 size = getRenderer().getPostProcessResolution() / g_cvarRenderBloomUpscaleDivisor;
  41. // Create RT descr
  42. m_finalRtDesc = getRenderer().create2DRenderTargetDescription(size.x(), size.y(), getRenderer().getHdrFormat(), "Bloom final");
  43. m_finalRtDesc.bake();
  44. // init shaders
  45. ANKI_CHECK(loadShaderProgram("ShaderBinaries/Bloom.ankiprogbin", {}, m_prog, m_upscaleGrProg, "Upscale"));
  46. // Textures
  47. ANKI_CHECK(ResourceManager::getSingleton().loadResource("EngineAssets/LensDirt.ankitex", m_lensDirtImg));
  48. }
  49. return Error::kNone;
  50. }
  51. void Bloom::importRenderTargets(RenderingContext& ctx)
  52. {
  53. RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
  54. m_runCtx.m_pyramidRt = rgraph.importRenderTarget(m_pyramidTex.get(), TextureUsageBit::kSrvCompute);
  55. }
  56. void Bloom::populateRenderGraph(RenderingContext& ctx)
  57. {
  58. RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
  59. const Bool preferCompute = g_cvarRenderPreferCompute;
  60. // Pyramid generation
  61. {
  62. const U32 passCount = m_pyramidTex->getMipmapCount();
  63. const RenderTargetHandle inRt = getRenderer().getLightShading().getRt();
  64. for(U32 i = 0; i < passCount; ++i)
  65. {
  66. RenderPassBase* ppass;
  67. if(preferCompute)
  68. {
  69. ppass = &rgraph.newNonGraphicsRenderPass(generateTempPassName("Bloom pyramid %u", i));
  70. }
  71. else
  72. {
  73. GraphicsRenderPass& pass = rgraph.newGraphicsRenderPass(generateTempPassName("Bloom pyramid %u", i));
  74. GraphicsRenderPassTargetDesc rtInf(m_runCtx.m_pyramidRt);
  75. rtInf.m_subresource.m_mipmap = U8(i);
  76. pass.setRenderpassInfo({rtInf});
  77. ppass = &pass;
  78. }
  79. const TextureUsageBit readUsage = (preferCompute) ? TextureUsageBit::kSrvCompute : TextureUsageBit::kSrvPixel;
  80. const TextureUsageBit writeUsage = (preferCompute) ? TextureUsageBit::kUavCompute : TextureUsageBit::kRtvDsvWrite;
  81. if(i > 0)
  82. {
  83. const TextureSubresourceDesc sampleSubresource = TextureSubresourceDesc::surface(i - 1, 0, 0);
  84. const TextureSubresourceDesc renderSubresource = TextureSubresourceDesc::surface(i, 0, 0);
  85. ppass->newTextureDependency(m_runCtx.m_pyramidRt, writeUsage, renderSubresource);
  86. ppass->newTextureDependency(m_runCtx.m_pyramidRt, readUsage, sampleSubresource);
  87. }
  88. else
  89. {
  90. ppass->newTextureDependency(m_runCtx.m_pyramidRt, writeUsage, TextureSubresourceDesc::firstSurface());
  91. ppass->newTextureDependency(inRt, readUsage);
  92. }
  93. ppass->setWork([this, passIdx = i](RenderPassWorkContext& rgraphCtx) {
  94. ANKI_TRACE_SCOPED_EVENT(BoomPyramid);
  95. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  96. cmdb.bindShaderProgram(m_downscaleGrProg.get());
  97. const U32 vpWidth = m_pyramidTex->getWidth() >> passIdx;
  98. const U32 vpHeight = m_pyramidTex->getHeight() >> passIdx;
  99. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  100. if(passIdx > 0)
  101. {
  102. rgraphCtx.bindSrv(0, 0, m_runCtx.m_pyramidRt, TextureSubresourceDesc::surface(passIdx - 1, 0, 0));
  103. }
  104. else
  105. {
  106. rgraphCtx.bindSrv(0, 0, getRenderer().getLightShading().getRt());
  107. }
  108. if(g_cvarRenderPreferCompute)
  109. {
  110. const Vec4 fbSize(F32(vpWidth), F32(vpHeight), 0.0f, 0.0f);
  111. cmdb.setFastConstants(&fbSize, sizeof(fbSize));
  112. rgraphCtx.bindUav(1, 0, m_runCtx.m_pyramidRt, TextureSubresourceDesc::surface(passIdx, 0, 0));
  113. dispatchPPCompute(cmdb, 8, 8, vpWidth, vpHeight);
  114. }
  115. else
  116. {
  117. cmdb.setViewport(0, 0, vpWidth, vpHeight);
  118. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  119. }
  120. });
  121. }
  122. }
  123. // Exposure
  124. RenderTargetHandle exposureRt;
  125. {
  126. // Ask for render target
  127. exposureRt = rgraph.newRenderTarget(m_exposureRtDesc);
  128. // Set the render pass
  129. const TextureSubresourceDesc inputTexSubresource = TextureSubresourceDesc::surface(m_pyramidTex->getMipmapCount() - 1, 0, 0);
  130. RenderPassBase* prpass;
  131. if(preferCompute)
  132. {
  133. NonGraphicsRenderPass& rpass = rgraph.newNonGraphicsRenderPass("Bloom Main");
  134. rpass.newTextureDependency(m_runCtx.m_pyramidRt, TextureUsageBit::kSrvCompute, inputTexSubresource);
  135. rpass.newTextureDependency(exposureRt, TextureUsageBit::kUavCompute);
  136. prpass = &rpass;
  137. }
  138. else
  139. {
  140. GraphicsRenderPass& rpass = rgraph.newGraphicsRenderPass("Bloom Main");
  141. rpass.setRenderpassInfo({GraphicsRenderPassTargetDesc(exposureRt)});
  142. rpass.newTextureDependency(m_runCtx.m_pyramidRt, TextureUsageBit::kSrvPixel, inputTexSubresource);
  143. rpass.newTextureDependency(exposureRt, TextureUsageBit::kRtvDsvWrite);
  144. prpass = &rpass;
  145. }
  146. prpass->setWork([this, exposureRt](RenderPassWorkContext& rgraphCtx) {
  147. ANKI_TRACE_SCOPED_EVENT(BoomExposure);
  148. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  149. cmdb.bindShaderProgram(m_exposureGrProg.get());
  150. const TextureSubresourceDesc inputTexSubresource = TextureSubresourceDesc::surface(m_pyramidTex->getMipmapCount() - 1, 0, 0);
  151. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  152. rgraphCtx.bindSrv(0, 0, m_runCtx.m_pyramidRt, inputTexSubresource);
  153. rgraphCtx.bindUav(0, 0, getRenderer().getTonemapping().getExposureAndAvgLuminanceRt());
  154. const Vec4 consts(g_cvarRenderBloomThreshold, g_cvarRenderBloomScale, 0.0f, 0.0f);
  155. cmdb.setFastConstants(&consts, sizeof(consts));
  156. if(g_cvarRenderPreferCompute)
  157. {
  158. rgraphCtx.bindUav(1, 0, exposureRt);
  159. dispatchPPCompute(cmdb, 8, 8, m_exposureRtDesc.m_width, m_exposureRtDesc.m_height);
  160. }
  161. else
  162. {
  163. cmdb.setViewport(0, 0, m_exposureRtDesc.m_width, m_exposureRtDesc.m_height);
  164. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  165. }
  166. });
  167. }
  168. // Upscale & SSLF pass
  169. RenderTargetHandle upscaledRt;
  170. {
  171. // Ask for render target
  172. upscaledRt = rgraph.newRenderTarget(m_finalRtDesc);
  173. m_runCtx.m_finalRt = upscaledRt;
  174. // Set the render pass
  175. RenderPassBase* prpass;
  176. if(preferCompute)
  177. {
  178. NonGraphicsRenderPass& rpass = rgraph.newNonGraphicsRenderPass("Bloom Upscale");
  179. rpass.newTextureDependency(exposureRt, TextureUsageBit::kSrvCompute);
  180. rpass.newTextureDependency(upscaledRt, TextureUsageBit::kUavCompute);
  181. prpass = &rpass;
  182. }
  183. else
  184. {
  185. GraphicsRenderPass& rpass = rgraph.newGraphicsRenderPass("Bloom Upscale");
  186. rpass.setRenderpassInfo({GraphicsRenderPassTargetDesc(upscaledRt)});
  187. rpass.newTextureDependency(exposureRt, TextureUsageBit::kSrvPixel);
  188. rpass.newTextureDependency(upscaledRt, TextureUsageBit::kRtvDsvWrite);
  189. prpass = &rpass;
  190. }
  191. prpass->setWork([this, exposureRt, upscaledRt](RenderPassWorkContext& rgraphCtx) {
  192. ANKI_TRACE_SCOPED_EVENT(BoomUpscale);
  193. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  194. cmdb.bindShaderProgram(m_upscaleGrProg.get());
  195. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  196. rgraphCtx.bindSrv(0, 0, exposureRt);
  197. cmdb.bindSrv(1, 0, TextureView(&m_lensDirtImg->getTexture(), TextureSubresourceDesc::all()));
  198. if(g_cvarRenderPreferCompute)
  199. {
  200. rgraphCtx.bindUav(0, 0, upscaledRt);
  201. dispatchPPCompute(cmdb, 8, 8, m_finalRtDesc.m_width, m_finalRtDesc.m_height);
  202. }
  203. else
  204. {
  205. cmdb.setViewport(0, 0, m_finalRtDesc.m_width, m_finalRtDesc.m_height);
  206. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  207. }
  208. });
  209. }
  210. }
  211. } // end namespace anki