VrsSriGeneration.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright (C) 2009-2023, 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/VrsSriGeneration.h>
  6. #include <AnKi/Renderer/Renderer.h>
  7. #include <AnKi/Renderer/LightShading.h>
  8. #include <AnKi/Core/CVarSet.h>
  9. #include <AnKi/Util/Tracer.h>
  10. namespace anki {
  11. static NumericCVar<F32> g_vrsThresholdCVar(CVarSubsystem::kRenderer, "VrsThreshold", 0.1f, 0.0f, 1.0f,
  12. "Threshold under which a lower shading rate will be applied");
  13. Error VrsSriGeneration::init()
  14. {
  15. const Error err = initInternal();
  16. if(err)
  17. {
  18. ANKI_R_LOGE("Failed to initialize VRS SRI generation");
  19. }
  20. return err;
  21. }
  22. Error VrsSriGeneration::initInternal()
  23. {
  24. if(!GrManager::getSingleton().getDeviceCapabilities().m_vrs)
  25. {
  26. return Error::kNone;
  27. }
  28. m_sriTexelDimension = GrManager::getSingleton().getDeviceCapabilities().m_minShadingRateImageTexelSize;
  29. ANKI_ASSERT(m_sriTexelDimension == 8 || m_sriTexelDimension == 16);
  30. const UVec2 rez = (getRenderer().getInternalResolution() + m_sriTexelDimension - 1) / m_sriTexelDimension;
  31. ANKI_R_LOGV("Intializing VRS SRI generation. SRI resolution %ux%u", rez.x(), rez.y());
  32. // Create textures
  33. const TextureUsageBit texUsage = TextureUsageBit::kFramebufferShadingRate | TextureUsageBit::kStorageComputeWrite | TextureUsageBit::kAllSampled;
  34. TextureInitInfo sriInitInfo = getRenderer().create2DRenderTargetInitInfo(rez.x(), rez.y(), Format::kR8_Uint, texUsage, "VrsSri");
  35. m_sriTex = getRenderer().createAndClearRenderTarget(sriInitInfo, TextureUsageBit::kFramebufferShadingRate);
  36. const UVec2 rezDownscaled = (getRenderer().getInternalResolution() / 2 + m_sriTexelDimension - 1) / m_sriTexelDimension;
  37. sriInitInfo = getRenderer().create2DRenderTargetInitInfo(rezDownscaled.x(), rezDownscaled.y(), Format::kR8_Uint, texUsage, "VrsSriDownscaled");
  38. m_downscaledSriTex = getRenderer().createAndClearRenderTarget(sriInitInfo, TextureUsageBit::kFramebufferShadingRate);
  39. // Load programs
  40. ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/VrsSriGenerationCompute.ankiprogbin", m_prog));
  41. ShaderProgramResourceVariantInitInfo variantInit(m_prog);
  42. variantInit.addMutation("SRI_TEXEL_DIMENSION", m_sriTexelDimension);
  43. if(m_sriTexelDimension == 16 && GrManager::getSingleton().getDeviceCapabilities().m_minSubgroupSize >= 32)
  44. {
  45. // Algorithm's workgroup size is 32, GPU's subgroup size is min 32 -> each workgroup has 1 subgroup -> No need for shared mem
  46. variantInit.addMutation("SHARED_MEMORY", 0);
  47. }
  48. else if(m_sriTexelDimension == 8 && GrManager::getSingleton().getDeviceCapabilities().m_minSubgroupSize >= 16)
  49. {
  50. // Algorithm's workgroup size is 16, GPU's subgroup size is min 16 -> each workgroup has 1 subgroup -> No need for shared mem
  51. variantInit.addMutation("SHARED_MEMORY", 0);
  52. }
  53. else
  54. {
  55. variantInit.addMutation("SHARED_MEMORY", 1);
  56. }
  57. variantInit.addMutation("LIMIT_RATE_TO_2X2", g_vrsLimitTo2x2CVar.get());
  58. const ShaderProgramResourceVariant* variant;
  59. m_prog->getOrCreateVariant(variantInit, variant);
  60. m_grProg.reset(&variant->getProgram());
  61. ANKI_CHECK(loadShaderProgram("ShaderBinaries/VrsSriVisualizeRenderTarget.ankiprogbin", m_visualizeProg, m_visualizeGrProg));
  62. ANKI_CHECK(loadShaderProgram("ShaderBinaries/VrsSriDownscale.ankiprogbin", m_downscaleProg, m_downscaleGrProg));
  63. return Error::kNone;
  64. }
  65. void VrsSriGeneration::getDebugRenderTarget(CString rtName, Array<RenderTargetHandle, kMaxDebugRenderTargets>& handles,
  66. ShaderProgramPtr& optionalShaderProgram) const
  67. {
  68. if(rtName == "VrsSri")
  69. {
  70. handles[0] = m_runCtx.m_rt;
  71. }
  72. else
  73. {
  74. ANKI_ASSERT(rtName == "VrsSriDownscaled");
  75. handles[0] = m_runCtx.m_downscaledRt;
  76. }
  77. optionalShaderProgram = m_visualizeGrProg;
  78. }
  79. void VrsSriGeneration::importRenderTargets(RenderingContext& ctx)
  80. {
  81. const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_vrsCVar.get();
  82. if(!enableVrs)
  83. {
  84. return;
  85. }
  86. if(m_sriTexImportedOnce)
  87. {
  88. m_runCtx.m_rt = ctx.m_renderGraphDescr.importRenderTarget(m_sriTex.get());
  89. m_runCtx.m_downscaledRt = ctx.m_renderGraphDescr.importRenderTarget(m_downscaledSriTex.get());
  90. }
  91. else
  92. {
  93. m_runCtx.m_rt = ctx.m_renderGraphDescr.importRenderTarget(m_sriTex.get(), TextureUsageBit::kFramebufferShadingRate);
  94. m_runCtx.m_downscaledRt = ctx.m_renderGraphDescr.importRenderTarget(m_downscaledSriTex.get(), TextureUsageBit::kFramebufferShadingRate);
  95. m_sriTexImportedOnce = true;
  96. }
  97. }
  98. void VrsSriGeneration::populateRenderGraph(RenderingContext& ctx)
  99. {
  100. const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_vrsCVar.get();
  101. if(!enableVrs)
  102. {
  103. return;
  104. }
  105. ANKI_TRACE_SCOPED_EVENT(VrsSriGeneration);
  106. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  107. // SRI generation
  108. {
  109. ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("VRS SRI generation");
  110. pass.newTextureDependency(m_runCtx.m_rt, TextureUsageBit::kStorageComputeWrite);
  111. pass.newTextureDependency(getRenderer().getLightShading().getRt(), TextureUsageBit::kSampledCompute);
  112. pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
  113. ANKI_TRACE_SCOPED_EVENT(VrsSriGeneration);
  114. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  115. cmdb.bindShaderProgram(m_grProg.get());
  116. rgraphCtx.bindColorTexture(0, 0, getRenderer().getLightShading().getRt());
  117. cmdb.bindSampler(0, 1, getRenderer().getSamplers().m_nearestNearestClamp.get());
  118. rgraphCtx.bindStorageTexture(0, 2, m_runCtx.m_rt);
  119. const Vec4 pc(1.0f / Vec2(getRenderer().getInternalResolution()), g_vrsThresholdCVar.get(), 0.0f);
  120. cmdb.setPushConstants(&pc, sizeof(pc));
  121. const U32 fakeWorkgroupSizeXorY = m_sriTexelDimension;
  122. dispatchPPCompute(cmdb, fakeWorkgroupSizeXorY, fakeWorkgroupSizeXorY, getRenderer().getInternalResolution().x(),
  123. getRenderer().getInternalResolution().y());
  124. });
  125. }
  126. // Downscale
  127. {
  128. ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("VRS SRI downscale");
  129. pass.newTextureDependency(m_runCtx.m_rt, TextureUsageBit::kSampledCompute);
  130. pass.newTextureDependency(m_runCtx.m_downscaledRt, TextureUsageBit::kStorageComputeWrite);
  131. pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
  132. ANKI_TRACE_SCOPED_EVENT(VrsSriGeneration);
  133. const UVec2 rezDownscaled = (getRenderer().getInternalResolution() / 2 + m_sriTexelDimension - 1) / m_sriTexelDimension;
  134. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  135. cmdb.bindShaderProgram(m_downscaleGrProg.get());
  136. rgraphCtx.bindColorTexture(0, 0, m_runCtx.m_rt);
  137. cmdb.bindSampler(0, 1, getRenderer().getSamplers().m_nearestNearestClamp.get());
  138. rgraphCtx.bindStorageTexture(0, 2, m_runCtx.m_downscaledRt);
  139. const Vec4 pc(1.0f / Vec2(rezDownscaled), 0.0f, 0.0f);
  140. cmdb.setPushConstants(&pc, sizeof(pc));
  141. dispatchPPCompute(cmdb, 8, 8, rezDownscaled.x(), rezDownscaled.y());
  142. });
  143. }
  144. }
  145. } // end namespace anki