Scale.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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/Scale.h>
  6. #include <AnKi/Renderer/Renderer.h>
  7. #include <AnKi/Renderer/TemporalAA.h>
  8. #include <AnKi/Core/ConfigSet.h>
  9. #include <AnKi/Renderer/LightShading.h>
  10. #include <AnKi/Renderer/MotionVectors.h>
  11. #include <AnKi/Renderer/GBuffer.h>
  12. #include <AnKi/Renderer/Tonemapping.h>
  13. #if ANKI_COMPILER_GCC_COMPATIBLE
  14. # pragma GCC diagnostic push
  15. # pragma GCC diagnostic ignored "-Wunused-function"
  16. # pragma GCC diagnostic ignored "-Wignored-qualifiers"
  17. #elif ANKI_COMPILER_MSVC
  18. # pragma warning(push)
  19. # pragma warning(disable : 4505)
  20. #endif
  21. #define A_CPU
  22. #include <ThirdParty/FidelityFX/ffx_a.h>
  23. #include <ThirdParty/FidelityFX/ffx_fsr1.h>
  24. #if ANKI_COMPILER_GCC_COMPATIBLE
  25. # pragma GCC diagnostic pop
  26. #elif ANKI_COMPILER_MSVC
  27. # pragma warning(pop)
  28. #endif
  29. namespace anki {
  30. static NumericCVar<U8> g_fsrQualityCVar(CVarSubsystem::kRenderer, "FsrQuality", 1, 0, 2, "0: Use bilinear, 1: FSR low quality, 2: FSR high quality");
  31. static NumericCVar<U8> g_dlssQualityCVar(CVarSubsystem::kRenderer, "DlssQuality", 2, 0, 3, "0: Disabled, 1: Performance, 2: Balanced, 3: Quality");
  32. static NumericCVar<F32> g_sharpnessCVar(CVarSubsystem::kRenderer, "Sharpness", (ANKI_PLATFORM_MOBILE) ? 0.0f : 0.8f, 0.0f, 1.0f,
  33. "Sharpen the image. It's a factor");
  34. Error Scale::init()
  35. {
  36. const Bool needsScaling = getRenderer().getPostProcessResolution() != getRenderer().getInternalResolution();
  37. const Bool needsSharpening = g_sharpnessCVar.get() > 0.0f;
  38. if(!needsScaling && !needsSharpening)
  39. {
  40. return Error::kNone;
  41. }
  42. const Bool preferCompute = g_preferComputeCVar.get();
  43. const U32 dlssQuality = g_dlssQualityCVar.get();
  44. const U32 fsrQuality = g_fsrQualityCVar.get();
  45. if(needsScaling)
  46. {
  47. if(dlssQuality > 0 && GrManager::getSingleton().getDeviceCapabilities().m_dlss)
  48. {
  49. m_upscalingMethod = UpscalingMethod::kGr;
  50. }
  51. else if(fsrQuality > 0)
  52. {
  53. m_upscalingMethod = UpscalingMethod::kFsr;
  54. }
  55. else
  56. {
  57. m_upscalingMethod = UpscalingMethod::kBilinear;
  58. }
  59. }
  60. else
  61. {
  62. m_upscalingMethod = UpscalingMethod::kNone;
  63. }
  64. m_sharpenMethod = (needsSharpening) ? SharpenMethod::kRcas : SharpenMethod::kNone;
  65. m_neeedsTonemapping = (m_upscalingMethod == UpscalingMethod::kGr); // Because GR upscaling spits HDR
  66. static constexpr Array<const Char*, U32(UpscalingMethod::kCount)> upscalingMethodNames = {"none", "bilinear", "FSR 1.0", "DLSS 2"};
  67. static constexpr Array<const Char*, U32(SharpenMethod::kCount)> sharpenMethodNames = {"none", "RCAS"};
  68. ANKI_R_LOGV("Initializing upscaling. Upscaling method %s, sharpenning method %s", upscalingMethodNames[m_upscalingMethod],
  69. sharpenMethodNames[m_sharpenMethod]);
  70. // Scale programs
  71. if(m_upscalingMethod == UpscalingMethod::kBilinear)
  72. {
  73. const CString shaderFname = (preferCompute) ? "ShaderBinaries/BlitCompute.ankiprogbin" : "ShaderBinaries/BlitRaster.ankiprogbin";
  74. ANKI_CHECK(ResourceManager::getSingleton().loadResource(shaderFname, m_scaleProg));
  75. const ShaderProgramResourceVariant* variant;
  76. m_scaleProg->getOrCreateVariant(variant);
  77. m_scaleGrProg.reset(&variant->getProgram());
  78. }
  79. else if(m_upscalingMethod == UpscalingMethod::kFsr)
  80. {
  81. const CString shaderFname = (preferCompute) ? "ShaderBinaries/FsrCompute.ankiprogbin" : "ShaderBinaries/FsrRaster.ankiprogbin";
  82. ANKI_CHECK(ResourceManager::getSingleton().loadResource(shaderFname, m_scaleProg));
  83. ShaderProgramResourceVariantInitInfo variantInitInfo(m_scaleProg);
  84. variantInitInfo.addMutation("SHARPEN", 0);
  85. variantInitInfo.addMutation("FSR_QUALITY", fsrQuality - 1);
  86. const ShaderProgramResourceVariant* variant;
  87. m_scaleProg->getOrCreateVariant(variantInitInfo, variant);
  88. m_scaleGrProg.reset(&variant->getProgram());
  89. }
  90. else if(m_upscalingMethod == UpscalingMethod::kGr)
  91. {
  92. GrUpscalerInitInfo inf;
  93. inf.m_sourceTextureResolution = getRenderer().getInternalResolution();
  94. inf.m_targetTextureResolution = getRenderer().getPostProcessResolution();
  95. inf.m_upscalerType = GrUpscalerType::kDlss2;
  96. inf.m_qualityMode = GrUpscalerQualityMode(dlssQuality - 1);
  97. m_grUpscaler = GrManager::getSingleton().newGrUpscaler(inf);
  98. }
  99. // Sharpen programs
  100. if(m_sharpenMethod == SharpenMethod::kRcas)
  101. {
  102. ANKI_CHECK(ResourceManager::getSingleton().loadResource(
  103. (preferCompute) ? "ShaderBinaries/FsrCompute.ankiprogbin" : "ShaderBinaries/FsrRaster.ankiprogbin", m_sharpenProg));
  104. ShaderProgramResourceVariantInitInfo variantInitInfo(m_sharpenProg);
  105. variantInitInfo.addMutation("SHARPEN", 1);
  106. variantInitInfo.addMutation("FSR_QUALITY", 0);
  107. const ShaderProgramResourceVariant* variant;
  108. m_sharpenProg->getOrCreateVariant(variantInitInfo, variant);
  109. m_sharpenGrProg.reset(&variant->getProgram());
  110. }
  111. // Tonemapping programs
  112. if(m_neeedsTonemapping)
  113. {
  114. ANKI_CHECK(ResourceManager::getSingleton().loadResource(
  115. (preferCompute) ? "ShaderBinaries/TonemapCompute.ankiprogbin" : "ShaderBinaries/TonemapRaster.ankiprogbin", m_tonemapProg));
  116. const ShaderProgramResourceVariant* variant;
  117. m_tonemapProg->getOrCreateVariant(variant);
  118. m_tonemapGrProg.reset(&variant->getProgram());
  119. }
  120. // Descriptors
  121. Format format;
  122. if(m_upscalingMethod == UpscalingMethod::kGr)
  123. {
  124. format = getRenderer().getHdrFormat();
  125. }
  126. else if(GrManager::getSingleton().getDeviceCapabilities().m_unalignedBbpTextureFormats)
  127. {
  128. format = Format::kR8G8B8_Unorm;
  129. }
  130. else
  131. {
  132. format = Format::kR8G8B8A8_Unorm;
  133. }
  134. m_upscaleAndSharpenRtDescr = getRenderer().create2DRenderTargetDescription(getRenderer().getPostProcessResolution().x(),
  135. getRenderer().getPostProcessResolution().y(), format, "Scaling");
  136. m_upscaleAndSharpenRtDescr.bake();
  137. if(m_neeedsTonemapping)
  138. {
  139. const Format fmt =
  140. (GrManager::getSingleton().getDeviceCapabilities().m_unalignedBbpTextureFormats) ? Format::kR8G8B8_Unorm : Format::kR8G8B8A8_Unorm;
  141. m_tonemapedRtDescr = getRenderer().create2DRenderTargetDescription(getRenderer().getPostProcessResolution().x(),
  142. getRenderer().getPostProcessResolution().y(), fmt, "Tonemapped");
  143. m_tonemapedRtDescr.bake();
  144. }
  145. m_fbDescr.m_colorAttachmentCount = 1;
  146. m_fbDescr.bake();
  147. return Error::kNone;
  148. }
  149. void Scale::populateRenderGraph(RenderingContext& ctx)
  150. {
  151. if(m_upscalingMethod == UpscalingMethod::kNone && m_sharpenMethod == SharpenMethod::kNone)
  152. {
  153. m_runCtx.m_upscaledTonemappedRt = getRenderer().getTemporalAA().getTonemappedRt();
  154. m_runCtx.m_upscaledHdrRt = getRenderer().getTemporalAA().getHdrRt();
  155. m_runCtx.m_sharpenedRt = getRenderer().getTemporalAA().getTonemappedRt();
  156. m_runCtx.m_tonemappedRt = getRenderer().getTemporalAA().getTonemappedRt();
  157. return;
  158. }
  159. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  160. const Bool preferCompute = g_preferComputeCVar.get();
  161. // Step 1: Upscaling
  162. if(m_upscalingMethod == UpscalingMethod::kGr)
  163. {
  164. m_runCtx.m_upscaledHdrRt = rgraph.newRenderTarget(m_upscaleAndSharpenRtDescr);
  165. m_runCtx.m_upscaledTonemappedRt = {};
  166. ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("DLSS");
  167. // DLSS says input textures in sampled state and out as storage image
  168. const TextureUsageBit readUsage = TextureUsageBit::kAllSampled & TextureUsageBit::kAllCompute;
  169. const TextureUsageBit writeUsage = TextureUsageBit::kAllImage & TextureUsageBit::kAllCompute;
  170. pass.newTextureDependency(getRenderer().getLightShading().getRt(), readUsage);
  171. pass.newTextureDependency(getRenderer().getMotionVectors().getMotionVectorsRt(), readUsage);
  172. pass.newTextureDependency(getRenderer().getGBuffer().getDepthRt(), readUsage, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
  173. pass.newTextureDependency(m_runCtx.m_upscaledHdrRt, writeUsage);
  174. pass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
  175. runGrUpscaling(ctx, rgraphCtx);
  176. });
  177. }
  178. else if(m_upscalingMethod == UpscalingMethod::kFsr || m_upscalingMethod == UpscalingMethod::kBilinear)
  179. {
  180. m_runCtx.m_upscaledTonemappedRt = rgraph.newRenderTarget(m_upscaleAndSharpenRtDescr);
  181. m_runCtx.m_upscaledHdrRt = {};
  182. const RenderTargetHandle inRt = getRenderer().getTemporalAA().getTonemappedRt();
  183. const RenderTargetHandle outRt = m_runCtx.m_upscaledTonemappedRt;
  184. if(preferCompute)
  185. {
  186. ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("Scale");
  187. pass.newTextureDependency(inRt, TextureUsageBit::kSampledCompute);
  188. pass.newTextureDependency(outRt, TextureUsageBit::kImageComputeWrite);
  189. pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
  190. runFsrOrBilinearScaling(rgraphCtx);
  191. });
  192. }
  193. else
  194. {
  195. GraphicsRenderPassDescription& pass = ctx.m_renderGraphDescr.newGraphicsRenderPass("Scale");
  196. pass.setFramebufferInfo(m_fbDescr, {outRt});
  197. pass.newTextureDependency(inRt, TextureUsageBit::kSampledFragment);
  198. pass.newTextureDependency(outRt, TextureUsageBit::kFramebufferWrite);
  199. pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
  200. runFsrOrBilinearScaling(rgraphCtx);
  201. });
  202. }
  203. }
  204. else
  205. {
  206. ANKI_ASSERT(m_upscalingMethod == UpscalingMethod::kNone);
  207. // Pretend that it got scaled
  208. m_runCtx.m_upscaledTonemappedRt = getRenderer().getTemporalAA().getTonemappedRt();
  209. m_runCtx.m_upscaledHdrRt = getRenderer().getTemporalAA().getHdrRt();
  210. }
  211. // Step 2: Tonemapping
  212. if(m_neeedsTonemapping)
  213. {
  214. m_runCtx.m_tonemappedRt = rgraph.newRenderTarget(m_tonemapedRtDescr);
  215. const RenderTargetHandle inRt = m_runCtx.m_upscaledHdrRt;
  216. const RenderTargetHandle outRt = m_runCtx.m_tonemappedRt;
  217. if(preferCompute)
  218. {
  219. ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("Tonemap");
  220. pass.newTextureDependency(inRt, TextureUsageBit::kSampledCompute);
  221. pass.newTextureDependency(outRt, TextureUsageBit::kImageComputeWrite);
  222. pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
  223. runTonemapping(rgraphCtx);
  224. });
  225. }
  226. else
  227. {
  228. GraphicsRenderPassDescription& pass = ctx.m_renderGraphDescr.newGraphicsRenderPass("Sharpen");
  229. pass.setFramebufferInfo(m_fbDescr, {outRt});
  230. pass.newTextureDependency(inRt, TextureUsageBit::kSampledFragment);
  231. pass.newTextureDependency(outRt, TextureUsageBit::kFramebufferWrite);
  232. pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
  233. runTonemapping(rgraphCtx);
  234. });
  235. }
  236. }
  237. else
  238. {
  239. m_runCtx.m_tonemappedRt = m_runCtx.m_upscaledTonemappedRt;
  240. }
  241. // Step 3: Sharpenning
  242. if(m_sharpenMethod == SharpenMethod::kRcas)
  243. {
  244. m_runCtx.m_sharpenedRt = rgraph.newRenderTarget(m_upscaleAndSharpenRtDescr);
  245. const RenderTargetHandle inRt = m_runCtx.m_tonemappedRt;
  246. const RenderTargetHandle outRt = m_runCtx.m_sharpenedRt;
  247. if(preferCompute)
  248. {
  249. ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("Sharpen");
  250. pass.newTextureDependency(inRt, TextureUsageBit::kSampledCompute);
  251. pass.newTextureDependency(outRt, TextureUsageBit::kImageComputeWrite);
  252. pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
  253. runRcasSharpening(rgraphCtx);
  254. });
  255. }
  256. else
  257. {
  258. GraphicsRenderPassDescription& pass = ctx.m_renderGraphDescr.newGraphicsRenderPass("Sharpen");
  259. pass.setFramebufferInfo(m_fbDescr, {outRt});
  260. pass.newTextureDependency(inRt, TextureUsageBit::kSampledFragment);
  261. pass.newTextureDependency(outRt, TextureUsageBit::kFramebufferWrite);
  262. pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
  263. runRcasSharpening(rgraphCtx);
  264. });
  265. }
  266. }
  267. else
  268. {
  269. ANKI_ASSERT(m_sharpenMethod == SharpenMethod::kNone);
  270. // Pretend that it's sharpened
  271. m_runCtx.m_sharpenedRt = m_runCtx.m_tonemappedRt;
  272. }
  273. }
  274. void Scale::runFsrOrBilinearScaling(RenderPassWorkContext& rgraphCtx)
  275. {
  276. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  277. const Bool preferCompute = g_preferComputeCVar.get();
  278. const RenderTargetHandle inRt = getRenderer().getTemporalAA().getTonemappedRt();
  279. const RenderTargetHandle outRt = m_runCtx.m_upscaledTonemappedRt;
  280. cmdb.bindShaderProgram(m_scaleGrProg.get());
  281. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  282. rgraphCtx.bindColorTexture(0, 1, inRt);
  283. if(preferCompute)
  284. {
  285. rgraphCtx.bindImage(0, 2, outRt);
  286. }
  287. if(m_upscalingMethod == UpscalingMethod::kFsr)
  288. {
  289. class
  290. {
  291. public:
  292. UVec4 m_fsrConsts0;
  293. UVec4 m_fsrConsts1;
  294. UVec4 m_fsrConsts2;
  295. UVec4 m_fsrConsts3;
  296. UVec2 m_viewportSize;
  297. UVec2 m_padding;
  298. } pc;
  299. const Vec2 inRez(getRenderer().getInternalResolution());
  300. const Vec2 outRez(getRenderer().getPostProcessResolution());
  301. FsrEasuCon(&pc.m_fsrConsts0[0], &pc.m_fsrConsts1[0], &pc.m_fsrConsts2[0], &pc.m_fsrConsts3[0], inRez.x(), inRez.y(), inRez.x(), inRez.y(),
  302. outRez.x(), outRez.y());
  303. pc.m_viewportSize = getRenderer().getPostProcessResolution();
  304. cmdb.setPushConstants(&pc, sizeof(pc));
  305. }
  306. else if(preferCompute)
  307. {
  308. class
  309. {
  310. public:
  311. Vec2 m_viewportSize;
  312. UVec2 m_viewportSizeU;
  313. } pc;
  314. pc.m_viewportSize = Vec2(getRenderer().getPostProcessResolution());
  315. pc.m_viewportSizeU = getRenderer().getPostProcessResolution();
  316. cmdb.setPushConstants(&pc, sizeof(pc));
  317. }
  318. if(preferCompute)
  319. {
  320. dispatchPPCompute(cmdb, 8, 8, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());
  321. }
  322. else
  323. {
  324. cmdb.setViewport(0, 0, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());
  325. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  326. }
  327. }
  328. void Scale::runRcasSharpening(RenderPassWorkContext& rgraphCtx)
  329. {
  330. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  331. const Bool preferCompute = g_preferComputeCVar.get();
  332. const RenderTargetHandle inRt = m_runCtx.m_tonemappedRt;
  333. const RenderTargetHandle outRt = m_runCtx.m_sharpenedRt;
  334. cmdb.bindShaderProgram(m_sharpenGrProg.get());
  335. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
  336. rgraphCtx.bindColorTexture(0, 1, inRt);
  337. if(preferCompute)
  338. {
  339. rgraphCtx.bindImage(0, 2, outRt);
  340. }
  341. class
  342. {
  343. public:
  344. UVec4 m_fsrConsts0;
  345. UVec4 m_fsrConsts1;
  346. UVec4 m_fsrConsts2;
  347. UVec4 m_fsrConsts3;
  348. UVec2 m_viewportSize;
  349. UVec2 m_padding;
  350. } pc;
  351. F32 sharpness = g_sharpnessCVar.get(); // [0, 1]
  352. sharpness *= 3.0f; // [0, 3]
  353. sharpness = 3.0f - sharpness; // [3, 0], RCAS translates 0 to max sharpness
  354. FsrRcasCon(&pc.m_fsrConsts0[0], sharpness);
  355. pc.m_viewportSize = getRenderer().getPostProcessResolution();
  356. cmdb.setPushConstants(&pc, sizeof(pc));
  357. if(preferCompute)
  358. {
  359. dispatchPPCompute(cmdb, 8, 8, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());
  360. }
  361. else
  362. {
  363. cmdb.setViewport(0, 0, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());
  364. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  365. }
  366. }
  367. void Scale::runGrUpscaling(RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
  368. {
  369. const Vec2 srcRes(getRenderer().getInternalResolution());
  370. const Bool reset = getRenderer().getFrameCount() == 0;
  371. const Vec2 mvScale = srcRes; // UV space to Pixel space factor
  372. // In [-texSize / 2, texSize / 2] -> sub-pixel space {-0.5, 0.5}
  373. const Vec2 jitterOffset = ctx.m_matrices.m_jitter.getTranslationPart().xy() * srcRes * 0.5f;
  374. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  375. TextureViewPtr srcView = rgraphCtx.createTextureView(getRenderer().getLightShading().getRt());
  376. TextureViewPtr motionVectorsView = rgraphCtx.createTextureView(getRenderer().getMotionVectors().getMotionVectorsRt());
  377. TextureViewPtr depthView = rgraphCtx.createTextureView(getRenderer().getGBuffer().getDepthRt());
  378. TextureViewPtr exposureView = rgraphCtx.createTextureView(getRenderer().getTonemapping().getRt());
  379. TextureViewPtr dstView = rgraphCtx.createTextureView(m_runCtx.m_upscaledHdrRt);
  380. cmdb.upscale(m_grUpscaler.get(), srcView.get(), dstView.get(), motionVectorsView.get(), depthView.get(), exposureView.get(), reset, jitterOffset,
  381. mvScale);
  382. }
  383. void Scale::runTonemapping(RenderPassWorkContext& rgraphCtx)
  384. {
  385. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  386. const Bool preferCompute = g_preferComputeCVar.get();
  387. const RenderTargetHandle inRt = m_runCtx.m_upscaledHdrRt;
  388. const RenderTargetHandle outRt = m_runCtx.m_tonemappedRt;
  389. cmdb.bindShaderProgram(m_tonemapGrProg.get());
  390. cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
  391. rgraphCtx.bindColorTexture(0, 1, inRt);
  392. rgraphCtx.bindImage(0, 2, getRenderer().getTonemapping().getRt());
  393. if(preferCompute)
  394. {
  395. class
  396. {
  397. public:
  398. Vec2 m_viewportSizeOverOne;
  399. UVec2 m_viewportSize;
  400. } pc;
  401. pc.m_viewportSizeOverOne = 1.0f / Vec2(getRenderer().getPostProcessResolution());
  402. pc.m_viewportSize = getRenderer().getPostProcessResolution();
  403. cmdb.setPushConstants(&pc, sizeof(pc));
  404. rgraphCtx.bindImage(0, 3, outRt);
  405. dispatchPPCompute(cmdb, 8, 8, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());
  406. }
  407. else
  408. {
  409. cmdb.setViewport(0, 0, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());
  410. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  411. }
  412. }
  413. } // end namespace anki