fsr.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * Copyright 2021 Richard Schubert. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. *
  5. * AMD FidelityFX Super Resolution 1.0 (FSR)
  6. * Based on https://github.com/GPUOpen-Effects/FidelityFX-FSR/blob/master/sample/
  7. */
  8. #include "fsr.h"
  9. #include <bgfx_utils.h>
  10. struct FsrResources
  11. {
  12. void init(uint32_t _width, uint32_t _height)
  13. {
  14. resize(_width, _height);
  15. // Create uniforms for screen passes and models
  16. m_uniforms.init();
  17. // Create texture sampler uniforms (used when we bind textures)
  18. s_inputTexture = bgfx::createUniform("InputTexture", bgfx::UniformType::Sampler);
  19. // Create program from shaders.
  20. m_bilinear32Program = bgfx::createProgram(loadShader("cs_fsr_bilinear_32"), true);
  21. m_easu32Program = bgfx::createProgram(loadShader("cs_fsr_easu_32"), true);
  22. m_rcas32Program = bgfx::createProgram(loadShader("cs_fsr_rcas_32"), true);
  23. m_support16BitPrecision = (bgfx::getRendererType() != bgfx::RendererType::OpenGL);
  24. if (m_support16BitPrecision)
  25. {
  26. m_bilinear16Program = bgfx::createProgram(loadShader("cs_fsr_bilinear_16"), true);
  27. m_easu16Program = bgfx::createProgram(loadShader("cs_fsr_easu_16"), true);
  28. m_rcas16Program = bgfx::createProgram(loadShader("cs_fsr_rcas_16"), true);
  29. }
  30. }
  31. void destroy()
  32. {
  33. if (m_support16BitPrecision)
  34. {
  35. bgfx::destroy(m_bilinear16Program);
  36. m_bilinear16Program = BGFX_INVALID_HANDLE;
  37. bgfx::destroy(m_easu16Program);
  38. m_easu16Program = BGFX_INVALID_HANDLE;
  39. bgfx::destroy(m_rcas16Program);
  40. m_rcas16Program = BGFX_INVALID_HANDLE;
  41. }
  42. bgfx::destroy(m_bilinear32Program);
  43. m_bilinear32Program = BGFX_INVALID_HANDLE;
  44. bgfx::destroy(m_easu32Program);
  45. m_easu32Program = BGFX_INVALID_HANDLE;
  46. bgfx::destroy(m_rcas32Program);
  47. m_rcas32Program = BGFX_INVALID_HANDLE;
  48. m_uniforms.destroy();
  49. bgfx::destroy(s_inputTexture);
  50. s_inputTexture = BGFX_INVALID_HANDLE;
  51. if (bgfx::isValid(m_easuTexture16F) )
  52. {
  53. bgfx::destroy(m_easuTexture16F);
  54. m_easuTexture16F = BGFX_INVALID_HANDLE;
  55. bgfx::destroy(m_rcasTexture16F);
  56. m_rcasTexture16F = BGFX_INVALID_HANDLE;
  57. }
  58. if (bgfx::isValid(m_easuTexture32F) )
  59. {
  60. bgfx::destroy(m_easuTexture32F);
  61. m_easuTexture32F = BGFX_INVALID_HANDLE;
  62. bgfx::destroy(m_rcasTexture32F);
  63. m_rcasTexture32F = BGFX_INVALID_HANDLE;
  64. }
  65. }
  66. void resize(uint32_t _width, uint32_t _height)
  67. {
  68. m_width = _width;
  69. m_height = _height;
  70. if (bgfx::isValid(m_easuTexture16F) )
  71. {
  72. bgfx::destroy(m_easuTexture16F);
  73. m_easuTexture16F = BGFX_INVALID_HANDLE;
  74. bgfx::destroy(m_rcasTexture16F);
  75. m_rcasTexture16F = BGFX_INVALID_HANDLE;
  76. }
  77. if (bgfx::isValid(m_easuTexture32F) )
  78. {
  79. bgfx::destroy(m_easuTexture32F);
  80. bgfx::destroy(m_rcasTexture32F);
  81. }
  82. if (m_support16BitPrecision)
  83. {
  84. m_easuTexture16F = bgfx::createTexture2D(
  85. uint16_t(m_width)
  86. , uint16_t(m_height)
  87. , false
  88. , 1
  89. , bgfx::TextureFormat::RGBA16F
  90. , BGFX_TEXTURE_COMPUTE_WRITE | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP
  91. );
  92. bgfx::setName(m_easuTexture16F, "easuTexture16F");
  93. m_rcasTexture16F = bgfx::createTexture2D(
  94. uint16_t(m_width)
  95. , uint16_t(m_height)
  96. , false
  97. , 1
  98. , bgfx::TextureFormat::RGBA16F
  99. , BGFX_TEXTURE_COMPUTE_WRITE | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP
  100. );
  101. bgfx::setName(m_rcasTexture16F, "rcasTexture16F");
  102. }
  103. m_easuTexture32F = bgfx::createTexture2D(
  104. uint16_t(m_width)
  105. , uint16_t(m_height)
  106. , false
  107. , 1
  108. , bgfx::TextureFormat::RGBA32F
  109. , BGFX_TEXTURE_COMPUTE_WRITE | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP
  110. );
  111. bgfx::setName(m_easuTexture32F, "easuTexture32F");
  112. m_rcasTexture32F = bgfx::createTexture2D(
  113. uint16_t(m_width)
  114. , uint16_t(m_height)
  115. , false
  116. , 1
  117. , bgfx::TextureFormat::RGBA32F
  118. , BGFX_TEXTURE_COMPUTE_WRITE | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP
  119. );
  120. bgfx::setName(m_rcasTexture32F, "rcasTexture32F");
  121. }
  122. struct Uniforms
  123. {
  124. struct Vec4
  125. {
  126. float x;
  127. float y;
  128. float z;
  129. float w;
  130. };
  131. enum
  132. {
  133. NumVec4 = 3
  134. };
  135. void init()
  136. {
  137. u_params = bgfx::createUniform("u_params", bgfx::UniformType::Vec4, NumVec4);
  138. };
  139. void submit() const
  140. {
  141. bgfx::setUniform(u_params, m_params, NumVec4);
  142. }
  143. void destroy()
  144. {
  145. bgfx::destroy(u_params);
  146. }
  147. union
  148. {
  149. struct
  150. {
  151. Vec4 ViewportSizeRcasAttenuation;
  152. Vec4 SrcSize;
  153. Vec4 DstSize;
  154. };
  155. uint32_t m_params[NumVec4 * 4];
  156. };
  157. bgfx::UniformHandle u_params = BGFX_INVALID_HANDLE;
  158. };
  159. uint32_t m_width = 0;
  160. uint32_t m_height = 0;
  161. bool m_support16BitPrecision = false;
  162. // Resource handles
  163. bgfx::ProgramHandle m_bilinear16Program = BGFX_INVALID_HANDLE;
  164. bgfx::ProgramHandle m_easu16Program = BGFX_INVALID_HANDLE;
  165. bgfx::ProgramHandle m_rcas16Program = BGFX_INVALID_HANDLE;
  166. bgfx::TextureHandle m_easuTexture16F = BGFX_INVALID_HANDLE;
  167. bgfx::TextureHandle m_rcasTexture16F = BGFX_INVALID_HANDLE;
  168. bgfx::ProgramHandle m_bilinear32Program = BGFX_INVALID_HANDLE;
  169. bgfx::ProgramHandle m_easu32Program = BGFX_INVALID_HANDLE;
  170. bgfx::ProgramHandle m_rcas32Program = BGFX_INVALID_HANDLE;
  171. bgfx::TextureHandle m_easuTexture32F = BGFX_INVALID_HANDLE;
  172. bgfx::TextureHandle m_rcasTexture32F = BGFX_INVALID_HANDLE;
  173. // Shader uniforms
  174. Uniforms m_uniforms;
  175. // Uniforms to indentify texture samplers
  176. bgfx::UniformHandle s_inputTexture = BGFX_INVALID_HANDLE;
  177. };
  178. Fsr::Fsr()
  179. {
  180. m_resources = new FsrResources();
  181. }
  182. Fsr::~Fsr()
  183. {
  184. delete m_resources;
  185. }
  186. void Fsr::init(uint32_t _width, uint32_t _height)
  187. {
  188. m_resources->init(_width, _height);
  189. }
  190. void Fsr::destroy()
  191. {
  192. m_resources->destroy();
  193. }
  194. void Fsr::resize(uint32_t _width, uint32_t _height)
  195. {
  196. m_resources->resize(_width, _height);
  197. }
  198. bgfx::ViewId Fsr::computeFsr(bgfx::ViewId _pass, bgfx::TextureHandle _colorTexture)
  199. {
  200. updateUniforms();
  201. bgfx::ViewId view = _pass;
  202. // This value is the image region dimension that each thread group of the FSR shader operates on
  203. constexpr int threadGroupWorkRegionDim = 16;
  204. const int32_t dispatchX = (m_resources->m_width + (threadGroupWorkRegionDim - 1) ) / threadGroupWorkRegionDim;
  205. const int32_t dispatchY = (m_resources->m_height + (threadGroupWorkRegionDim - 1) ) / threadGroupWorkRegionDim;
  206. bgfx::TextureFormat::Enum const format = m_config.m_fsr16Bit
  207. ? bgfx::TextureFormat::RGBA16F
  208. : bgfx::TextureFormat::RGBA32F
  209. ;
  210. bgfx::TextureHandle fsrEasuTexture = m_config.m_fsr16Bit
  211. ? m_resources->m_easuTexture16F
  212. : m_resources->m_easuTexture32F
  213. ;
  214. // EASU pass (upscale)
  215. {
  216. bgfx::ProgramHandle program = m_config.m_fsr16Bit
  217. ? m_resources->m_easu16Program
  218. : m_resources->m_easu32Program
  219. ;
  220. if (!m_config.m_applyFsr)
  221. {
  222. program = m_resources->m_bilinear32Program;
  223. }
  224. bgfx::setViewName(view, "fsr easu");
  225. m_resources->m_uniforms.submit();
  226. bgfx::setTexture(0, m_resources->s_inputTexture, _colorTexture);
  227. bgfx::setImage(1, fsrEasuTexture, 0, bgfx::Access::Write, format);
  228. bgfx::dispatch(view, program, dispatchX, dispatchY, 1);
  229. ++view;
  230. }
  231. // RCAS pass (sharpening)
  232. if (m_config.m_applyFsrRcas)
  233. {
  234. bgfx::ProgramHandle program = m_config.m_fsr16Bit
  235. ? m_resources->m_rcas16Program
  236. : m_resources->m_rcas32Program
  237. ;
  238. bgfx::setViewName(view, "fsr rcas");
  239. m_resources->m_uniforms.submit();
  240. bgfx::setTexture(0, m_resources->s_inputTexture, fsrEasuTexture);
  241. bgfx::setImage(
  242. 1
  243. , m_config.m_fsr16Bit? m_resources->m_rcasTexture16F: m_resources->m_rcasTexture32F
  244. , 0
  245. , bgfx::Access::Write
  246. , format
  247. );
  248. bgfx::dispatch(view, program, dispatchX, dispatchY, 1);
  249. ++view;
  250. }
  251. return view;
  252. }
  253. bgfx::TextureHandle Fsr::getResultTexture() const
  254. {
  255. if (m_config.m_applyFsr && m_config.m_applyFsrRcas)
  256. {
  257. return m_config.m_fsr16Bit
  258. ? m_resources->m_rcasTexture16F
  259. : m_resources->m_rcasTexture32F
  260. ;
  261. }
  262. return m_config.m_fsr16Bit
  263. ? m_resources->m_easuTexture16F
  264. : m_resources->m_easuTexture32F
  265. ;
  266. }
  267. bool Fsr::supports16BitPrecision() const
  268. {
  269. return m_resources->m_support16BitPrecision;
  270. }
  271. void Fsr::updateUniforms()
  272. {
  273. const float srcWidth = float(m_resources->m_width) / m_config.m_superSamplingFactor;
  274. const float srcHeight = float(m_resources->m_height) / m_config.m_superSamplingFactor;
  275. m_resources->m_uniforms.ViewportSizeRcasAttenuation.x = srcWidth;
  276. m_resources->m_uniforms.ViewportSizeRcasAttenuation.y = srcHeight;
  277. m_resources->m_uniforms.ViewportSizeRcasAttenuation.z = m_config.m_rcasAttenuation;
  278. m_resources->m_uniforms.SrcSize.x = float(m_resources->m_width);
  279. m_resources->m_uniforms.SrcSize.y = float(m_resources->m_height);
  280. m_resources->m_uniforms.DstSize.x = float(m_resources->m_width);
  281. m_resources->m_uniforms.DstSize.y = float(m_resources->m_height);
  282. }