Bloom.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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. namespace anki {
  10. Error Bloom::init()
  11. {
  12. // Pyramid
  13. {
  14. const UVec2 pyramidSize = getRenderer().getInternalResolution() / 2;
  15. const U32 pyramidMipCount = computeMaxMipmapCount2d(pyramidSize.x(), pyramidSize.y(), g_bloomPyramidLowLimit);
  16. ANKI_R_LOGV("Initializing bloom downscale pyramid. Resolution %ux%u, mip count %u", pyramidSize.x(), pyramidSize.y(), pyramidMipCount);
  17. const Bool preferCompute = g_preferComputeCVar;
  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 = U8(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_bloomUpscaleDivisor;
  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_preferComputeCVar;
  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 = 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. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  95. cmdb.bindShaderProgram(m_downscaleGrProg.get());
  96. const U32 vpWidth = m_pyramidTex->getWidth() >> passIdx;
  97. const U32 vpHeight = m_pyramidTex->getHeight() >> passIdx;
  98. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  99. if(passIdx > 0)
  100. {
  101. rgraphCtx.bindSrv(0, 0, m_runCtx.m_pyramidRt, TextureSubresourceDesc::surface(passIdx - 1, 0, 0));
  102. }
  103. else
  104. {
  105. rgraphCtx.bindSrv(0, 0, getRenderer().getLightShading().getRt());
  106. }
  107. if(g_preferComputeCVar)
  108. {
  109. const Vec4 fbSize(F32(vpWidth), F32(vpHeight), 0.0f, 0.0f);
  110. cmdb.setFastConstants(&fbSize, sizeof(fbSize));
  111. rgraphCtx.bindUav(1, 0, m_runCtx.m_pyramidRt, TextureSubresourceDesc::surface(passIdx, 0, 0));
  112. dispatchPPCompute(cmdb, 8, 8, vpWidth, vpHeight);
  113. }
  114. else
  115. {
  116. cmdb.setViewport(0, 0, vpWidth, vpHeight);
  117. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  118. }
  119. });
  120. }
  121. }
  122. // Exposure
  123. RenderTargetHandle exposureRt;
  124. {
  125. // Ask for render target
  126. exposureRt = rgraph.newRenderTarget(m_exposureRtDesc);
  127. // Set the render pass
  128. const TextureSubresourceDesc inputTexSubresource = TextureSubresourceDesc::surface(m_pyramidTex->getMipmapCount() - 1, 0, 0);
  129. RenderPassBase* prpass;
  130. if(preferCompute)
  131. {
  132. NonGraphicsRenderPass& rpass = rgraph.newNonGraphicsRenderPass("Bloom Main");
  133. rpass.newTextureDependency(m_runCtx.m_pyramidRt, TextureUsageBit::kSrvCompute, inputTexSubresource);
  134. rpass.newTextureDependency(exposureRt, TextureUsageBit::kUavCompute);
  135. prpass = &rpass;
  136. }
  137. else
  138. {
  139. GraphicsRenderPass& rpass = rgraph.newGraphicsRenderPass("Bloom Main");
  140. rpass.setRenderpassInfo({GraphicsRenderPassTargetDesc(exposureRt)});
  141. rpass.newTextureDependency(m_runCtx.m_pyramidRt, TextureUsageBit::kSrvPixel, inputTexSubresource);
  142. rpass.newTextureDependency(exposureRt, TextureUsageBit::kRtvDsvWrite);
  143. prpass = &rpass;
  144. }
  145. prpass->setWork([this, exposureRt](RenderPassWorkContext& rgraphCtx) {
  146. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  147. cmdb.bindShaderProgram(m_exposureGrProg.get());
  148. const TextureSubresourceDesc inputTexSubresource = TextureSubresourceDesc::surface(m_pyramidTex->getMipmapCount() - 1, 0, 0);
  149. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  150. rgraphCtx.bindSrv(0, 0, m_runCtx.m_pyramidRt, inputTexSubresource);
  151. rgraphCtx.bindUav(0, 0, getRenderer().getTonemapping().getRt());
  152. const Vec4 consts(g_bloomThresholdCVar, g_bloomScaleCVar, 0.0f, 0.0f);
  153. cmdb.setFastConstants(&consts, sizeof(consts));
  154. if(g_preferComputeCVar)
  155. {
  156. rgraphCtx.bindUav(1, 0, exposureRt);
  157. dispatchPPCompute(cmdb, 8, 8, m_exposureRtDesc.m_width, m_exposureRtDesc.m_height);
  158. }
  159. else
  160. {
  161. cmdb.setViewport(0, 0, m_exposureRtDesc.m_width, m_exposureRtDesc.m_height);
  162. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  163. }
  164. });
  165. }
  166. // Upscale & SSLF pass
  167. RenderTargetHandle upscaledRt;
  168. {
  169. // Ask for render target
  170. upscaledRt = rgraph.newRenderTarget(m_finalRtDesc);
  171. m_runCtx.m_finalRt = upscaledRt;
  172. // Set the render pass
  173. RenderPassBase* prpass;
  174. if(preferCompute)
  175. {
  176. NonGraphicsRenderPass& rpass = rgraph.newNonGraphicsRenderPass("Bloom Upscale");
  177. rpass.newTextureDependency(exposureRt, TextureUsageBit::kSrvCompute);
  178. rpass.newTextureDependency(upscaledRt, TextureUsageBit::kUavCompute);
  179. prpass = &rpass;
  180. }
  181. else
  182. {
  183. GraphicsRenderPass& rpass = rgraph.newGraphicsRenderPass("Bloom Upscale");
  184. rpass.setRenderpassInfo({GraphicsRenderPassTargetDesc(upscaledRt)});
  185. rpass.newTextureDependency(exposureRt, TextureUsageBit::kSrvPixel);
  186. rpass.newTextureDependency(upscaledRt, TextureUsageBit::kRtvDsvWrite);
  187. prpass = &rpass;
  188. }
  189. prpass->setWork([this, exposureRt, upscaledRt](RenderPassWorkContext& rgraphCtx) {
  190. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  191. cmdb.bindShaderProgram(m_upscaleGrProg.get());
  192. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  193. rgraphCtx.bindSrv(0, 0, exposureRt);
  194. cmdb.bindSrv(1, 0, TextureView(&m_lensDirtImg->getTexture(), TextureSubresourceDesc::all()));
  195. if(g_preferComputeCVar)
  196. {
  197. rgraphCtx.bindUav(0, 0, upscaledRt);
  198. dispatchPPCompute(cmdb, 8, 8, m_finalRtDesc.m_width, m_finalRtDesc.m_height);
  199. }
  200. else
  201. {
  202. cmdb.setViewport(0, 0, m_finalRtDesc.m_width, m_finalRtDesc.m_height);
  203. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  204. }
  205. });
  206. }
  207. }
  208. } // end namespace anki