fsr.cpp 8.2 KB

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