fsr.cpp 8.0 KB

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