Ssao.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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/Ssao.h>
  6. #include <AnKi/Renderer/Renderer.h>
  7. #include <AnKi/Renderer/GBuffer.h>
  8. #include <AnKi/Renderer/MotionVectors.h>
  9. #include <AnKi/Renderer/DepthDownscale.h>
  10. #include <AnKi/Util/Tracer.h>
  11. namespace anki {
  12. static NumericCVar<U32> g_ssaoSampleCountCVar(CVarSubsystem::kRenderer, "SsaoSampleCount", 4, 1, 1024, "SSAO sample count");
  13. static NumericCVar<F32> g_ssaoRadiusCVar(CVarSubsystem::kRenderer, "SsaoRadius", 2.0f, 0.1f, 100.0f, "SSAO radius in meters");
  14. static BoolCVar g_ssaoQuarterRez(CVarSubsystem::kRenderer, "SsaoQuarterResolution", ANKI_PLATFORM_MOBILE, "Render SSAO in quarter rez");
  15. static NumericCVar<F32> g_ssaoPower(CVarSubsystem::kRenderer, "SsaoPower", 1.5f, 0.1f, 100.0f, "SSAO power");
  16. static NumericCVar<U8> g_ssaoSpatialQuality(CVarSubsystem::kRenderer, "SsaoSpatialQuality", (ANKI_PLATFORM_MOBILE) ? 0 : 1, 0, 1,
  17. "SSAO spatial denoise quality");
  18. Error Ssao::init()
  19. {
  20. const Error err = initInternal();
  21. if(err)
  22. {
  23. ANKI_R_LOGE("Failed to initialize SSAO");
  24. }
  25. return err;
  26. }
  27. Error Ssao::initInternal()
  28. {
  29. const UVec2 rez = (g_ssaoQuarterRez.get()) ? getRenderer().getInternalResolution() / 2 : getRenderer().getInternalResolution();
  30. ANKI_R_LOGV("Initializing SSAO. Resolution %ux%u", rez.x(), rez.y());
  31. const Bool preferCompute = g_preferComputeCVar.get();
  32. {
  33. TextureUsageBit usage = TextureUsageBit::kAllSrv;
  34. usage |= (preferCompute) ? TextureUsageBit::kUavCompute : TextureUsageBit::kRtvDsvWrite;
  35. TextureInitInfo texInit =
  36. getRenderer().create2DRenderTargetInitInfo(rez.x(), rez.y(), Format::kR8G8B8A8_Snorm, usage, "Bent normals + SSAO #1");
  37. m_tex[0] = getRenderer().createAndClearRenderTarget(texInit, TextureUsageBit::kAllSrv);
  38. texInit.setName("Bent normals + SSAO #2");
  39. m_tex[1] = getRenderer().createAndClearRenderTarget(texInit, TextureUsageBit::kAllSrv);
  40. }
  41. m_bentNormalsAndSsaoRtDescr =
  42. getRenderer().create2DRenderTargetDescription(rez.x(), rez.y(), Format::kR8G8B8A8_Snorm, "Bent normals + SSAO temp");
  43. m_bentNormalsAndSsaoRtDescr.bake();
  44. ANKI_CHECK(
  45. loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", {{"SPATIAL_DENOISE_QUALITY", g_ssaoSpatialQuality.get()}}, m_prog, m_grProg, "Ssao"));
  46. ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", {{"SPATIAL_DENOISE_QUALITY", g_ssaoSpatialQuality.get()}}, m_prog,
  47. m_spatialDenoiseGrProg, "SsaoSpatialDenoise"));
  48. ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", {{"SPATIAL_DENOISE_QUALITY", g_ssaoSpatialQuality.get()}}, m_prog,
  49. m_tempralDenoiseGrProg, "SsaoTemporalDenoise"));
  50. ANKI_CHECK(ResourceManager::getSingleton().loadResource("EngineAssets/BlueNoise_Rgba8_64x64.png", m_noiseImage));
  51. return Error::kNone;
  52. }
  53. void Ssao::populateRenderGraph(RenderingContext& ctx)
  54. {
  55. ANKI_TRACE_SCOPED_EVENT(Ssao);
  56. RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
  57. const Bool preferCompute = g_preferComputeCVar.get();
  58. const U32 readRtIdx = getRenderer().getFrameCount() & 1;
  59. const U32 writeRtIdx = !readRtIdx;
  60. RenderTargetHandle historyRt;
  61. RenderTargetHandle finalRt;
  62. if(m_texImportedOnce) [[likely]]
  63. {
  64. finalRt = rgraph.importRenderTarget(m_tex[writeRtIdx].get());
  65. historyRt = rgraph.importRenderTarget(m_tex[readRtIdx].get());
  66. }
  67. else
  68. {
  69. finalRt = rgraph.importRenderTarget(m_tex[writeRtIdx].get(), TextureUsageBit::kAllSrv);
  70. historyRt = rgraph.importRenderTarget(m_tex[readRtIdx].get(), TextureUsageBit::kAllSrv);
  71. m_texImportedOnce = true;
  72. }
  73. m_runCtx.m_finalRt = finalRt;
  74. const RenderTargetHandle bentNormalsAndSsaoTempRt = rgraph.newRenderTarget(m_bentNormalsAndSsaoRtDescr);
  75. TextureUsageBit readUsage;
  76. TextureUsageBit writeUsage;
  77. if(preferCompute)
  78. {
  79. readUsage = TextureUsageBit::kSrvCompute;
  80. writeUsage = TextureUsageBit::kUavCompute;
  81. }
  82. else
  83. {
  84. readUsage = TextureUsageBit::kSrvFragment;
  85. writeUsage = TextureUsageBit::kRtvDsvWrite;
  86. }
  87. // Main pass
  88. {
  89. RenderPassBase* ppass;
  90. if(preferCompute)
  91. {
  92. NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("SSAO");
  93. ppass = &pass;
  94. }
  95. else
  96. {
  97. GraphicsRenderPass& pass = rgraph.newGraphicsRenderPass("SSAO");
  98. pass.setRenderpassInfo({GraphicsRenderPassTargetDesc(finalRt)});
  99. ppass = &pass;
  100. }
  101. ppass->newTextureDependency(getRenderer().getGBuffer().getColorRt(2), readUsage);
  102. ppass->newTextureDependency((g_ssaoQuarterRez.get()) ? getRenderer().getDepthDownscale().getRt() : getRenderer().getGBuffer().getDepthRt(),
  103. readUsage);
  104. ppass->newTextureDependency(finalRt, writeUsage);
  105. ppass->setWork([this, &ctx, finalRt](RenderPassWorkContext& rgraphCtx) {
  106. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  107. cmdb.bindShaderProgram(m_grProg.get());
  108. rgraphCtx.bindSrv(0, 0, getRenderer().getGBuffer().getColorRt(2));
  109. rgraphCtx.bindSrv(1, 0, (g_ssaoQuarterRez.get()) ? getRenderer().getDepthDownscale().getRt() : getRenderer().getGBuffer().getDepthRt());
  110. cmdb.bindSrv(2, 0, TextureView(&m_noiseImage->getTexture(), TextureSubresourceDesc::all()));
  111. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearRepeat.get());
  112. cmdb.bindSampler(1, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  113. const UVec2 rez = (g_ssaoQuarterRez.get()) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
  114. SsaoConstants consts;
  115. consts.m_radius = g_ssaoRadiusCVar.get();
  116. consts.m_sampleCount = g_ssaoSampleCountCVar.get();
  117. consts.m_viewportSizef = Vec2(rez);
  118. consts.m_unprojectionParameters = ctx.m_matrices.m_unprojectionParameters;
  119. consts.m_projectionMat00 = ctx.m_matrices.m_projection(0, 0);
  120. consts.m_projectionMat11 = ctx.m_matrices.m_projection(1, 1);
  121. consts.m_projectionMat22 = ctx.m_matrices.m_projection(2, 2);
  122. consts.m_projectionMat23 = ctx.m_matrices.m_projection(2, 3);
  123. consts.m_frameCount = getRenderer().getFrameCount() % kMaxU32;
  124. consts.m_ssaoPower = g_ssaoPower.get();
  125. consts.m_viewMat = ctx.m_matrices.m_view;
  126. cmdb.setFastConstants(&consts, sizeof(consts));
  127. if(g_preferComputeCVar.get())
  128. {
  129. rgraphCtx.bindUav(0, 0, finalRt);
  130. dispatchPPCompute(cmdb, 8, 8, rez.x(), rez.y());
  131. }
  132. else
  133. {
  134. cmdb.setViewport(0, 0, rez.x(), rez.y());
  135. drawQuad(cmdb);
  136. }
  137. });
  138. }
  139. // Spatial denoise
  140. {
  141. RenderPassBase* ppass;
  142. if(preferCompute)
  143. {
  144. NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("SSAO spatial denoise");
  145. ppass = &pass;
  146. }
  147. else
  148. {
  149. GraphicsRenderPass& pass = rgraph.newGraphicsRenderPass("SSAO spatial denoise");
  150. pass.setRenderpassInfo({GraphicsRenderPassTargetDesc(bentNormalsAndSsaoTempRt)});
  151. ppass = &pass;
  152. }
  153. ppass->newTextureDependency(finalRt, readUsage);
  154. ppass->newTextureDependency(getRenderer().getGBuffer().getDepthRt(), readUsage);
  155. ppass->newTextureDependency(bentNormalsAndSsaoTempRt, writeUsage);
  156. ppass->setWork([this, finalRt, bentNormalsAndSsaoTempRt, &ctx](RenderPassWorkContext& rgraphCtx) {
  157. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  158. cmdb.bindShaderProgram(m_spatialDenoiseGrProg.get());
  159. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  160. rgraphCtx.bindSrv(0, 0, finalRt);
  161. rgraphCtx.bindSrv(1, 0, getRenderer().getGBuffer().getDepthRt());
  162. const UVec2 rez = (g_ssaoQuarterRez.get()) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
  163. SsaoSpatialDenoiseConstants consts;
  164. computeLinearizeDepthOptimal(ctx.m_cameraNear, ctx.m_cameraFar, consts.m_linearizeDepthParams.x(), consts.m_linearizeDepthParams.y());
  165. consts.m_viewToWorldMat = ctx.m_matrices.m_cameraTransform;
  166. cmdb.setFastConstants(&consts, sizeof(consts));
  167. if(g_preferComputeCVar.get())
  168. {
  169. rgraphCtx.bindUav(0, 0, bentNormalsAndSsaoTempRt);
  170. dispatchPPCompute(cmdb, 8, 8, rez.x(), rez.y());
  171. }
  172. else
  173. {
  174. cmdb.setViewport(0, 0, rez.x(), rez.y());
  175. drawQuad(cmdb);
  176. }
  177. });
  178. }
  179. // Temporal denoise
  180. {
  181. RenderPassBase* ppass;
  182. if(preferCompute)
  183. {
  184. NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("SSAO temporal denoise");
  185. ppass = &pass;
  186. }
  187. else
  188. {
  189. GraphicsRenderPass& pass = rgraph.newGraphicsRenderPass("SSAO temporal denoise");
  190. pass.setRenderpassInfo({GraphicsRenderPassTargetDesc(finalRt)});
  191. ppass = &pass;
  192. }
  193. ppass->newTextureDependency(bentNormalsAndSsaoTempRt, readUsage);
  194. ppass->newTextureDependency(historyRt, readUsage);
  195. ppass->newTextureDependency(getRenderer().getMotionVectors().getMotionVectorsRt(), readUsage);
  196. ppass->newTextureDependency(finalRt, writeUsage);
  197. ppass->setWork([this, bentNormalsAndSsaoTempRt, finalRt, historyRt](RenderPassWorkContext& rgraphCtx) {
  198. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  199. cmdb.bindShaderProgram(m_tempralDenoiseGrProg.get());
  200. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  201. rgraphCtx.bindSrv(0, 0, bentNormalsAndSsaoTempRt);
  202. rgraphCtx.bindSrv(1, 0, historyRt);
  203. rgraphCtx.bindSrv(2, 0, getRenderer().getMotionVectors().getMotionVectorsRt());
  204. const UVec2 rez = (g_ssaoQuarterRez.get()) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
  205. if(g_preferComputeCVar.get())
  206. {
  207. rgraphCtx.bindUav(0, 0, finalRt);
  208. dispatchPPCompute(cmdb, 8, 8, rez.x(), rez.y());
  209. }
  210. else
  211. {
  212. cmdb.setViewport(0, 0, rez.x(), rez.y());
  213. drawQuad(cmdb);
  214. }
  215. });
  216. }
  217. }
  218. } // end namespace anki