Scale.cpp 16 KB

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