SmaaPostProcessingEffect.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Common;
  3. using Ryujinx.Graphics.GAL;
  4. using Ryujinx.Graphics.OpenGL.Image;
  5. using System;
  6. namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
  7. {
  8. internal partial class SmaaPostProcessingEffect : IPostProcessingEffect
  9. {
  10. public const int AreaWidth = 160;
  11. public const int AreaHeight = 560;
  12. public const int SearchWidth = 64;
  13. public const int SearchHeight = 16;
  14. private readonly OpenGLRenderer _renderer;
  15. private TextureStorage _outputTexture;
  16. private TextureStorage _searchTexture;
  17. private TextureStorage _areaTexture;
  18. private int[] _edgeShaderPrograms;
  19. private int[] _blendShaderPrograms;
  20. private int[] _neighbourShaderPrograms;
  21. private TextureStorage _edgeOutputTexture;
  22. private TextureStorage _blendOutputTexture;
  23. private string[] _qualities;
  24. private int _inputUniform;
  25. private int _outputUniform;
  26. private int _samplerAreaUniform;
  27. private int _samplerSearchUniform;
  28. private int _samplerBlendUniform;
  29. private int _resolutionUniform;
  30. private int _quality = 1;
  31. public int Quality
  32. {
  33. get => _quality; set
  34. {
  35. _quality = Math.Clamp(value, 0, _qualities.Length - 1);
  36. }
  37. }
  38. public SmaaPostProcessingEffect(OpenGLRenderer renderer, int quality)
  39. {
  40. _renderer = renderer;
  41. _edgeShaderPrograms = Array.Empty<int>();
  42. _blendShaderPrograms = Array.Empty<int>();
  43. _neighbourShaderPrograms = Array.Empty<int>();
  44. _qualities = new string[] { "SMAA_PRESET_LOW", "SMAA_PRESET_MEDIUM", "SMAA_PRESET_HIGH", "SMAA_PRESET_ULTRA" };
  45. Quality = quality;
  46. Initialize();
  47. }
  48. public void Dispose()
  49. {
  50. _searchTexture?.Dispose();
  51. _areaTexture?.Dispose();
  52. _outputTexture?.Dispose();
  53. _edgeOutputTexture?.Dispose();
  54. _blendOutputTexture?.Dispose();
  55. DeleteShaders();
  56. }
  57. private void DeleteShaders()
  58. {
  59. for (int i = 0; i < _edgeShaderPrograms.Length; i++)
  60. {
  61. GL.DeleteProgram(_edgeShaderPrograms[i]);
  62. GL.DeleteProgram(_blendShaderPrograms[i]);
  63. GL.DeleteProgram(_neighbourShaderPrograms[i]);
  64. }
  65. }
  66. private unsafe void RecreateShaders(int width, int height)
  67. {
  68. string baseShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/smaa.hlsl");
  69. var pixelSizeDefine = $"#define SMAA_RT_METRICS float4(1.0 / {width}.0, 1.0 / {height}.0, {width}, {height}) \n";
  70. _edgeShaderPrograms = new int[_qualities.Length];
  71. _blendShaderPrograms = new int[_qualities.Length];
  72. _neighbourShaderPrograms = new int[_qualities.Length];
  73. for (int i = 0; i < +_edgeShaderPrograms.Length; i++)
  74. {
  75. var presets = $"#version 430 core \n#define {_qualities[i]} 1 \n{pixelSizeDefine}#define SMAA_GLSL_4 1 \nlayout (local_size_x = 16, local_size_y = 16) in;\n{baseShader}";
  76. var edgeShaderData = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/smaa_edge.glsl");
  77. var blendShaderData = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/smaa_blend.glsl");
  78. var neighbourShaderData = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/smaa_neighbour.glsl");
  79. var shaders = new string[] { presets, edgeShaderData };
  80. var edgeProgram = ShaderHelper.CompileProgram(shaders, ShaderType.ComputeShader);
  81. shaders[1] = blendShaderData;
  82. var blendProgram = ShaderHelper.CompileProgram(shaders, ShaderType.ComputeShader);
  83. shaders[1] = neighbourShaderData;
  84. var neighbourProgram = ShaderHelper.CompileProgram(shaders, ShaderType.ComputeShader);
  85. _edgeShaderPrograms[i] = edgeProgram;
  86. _blendShaderPrograms[i] = blendProgram;
  87. _neighbourShaderPrograms[i] = neighbourProgram;
  88. }
  89. _inputUniform = GL.GetUniformLocation(_edgeShaderPrograms[0], "inputTexture");
  90. _outputUniform = GL.GetUniformLocation(_edgeShaderPrograms[0], "imgOutput");
  91. _samplerAreaUniform = GL.GetUniformLocation(_blendShaderPrograms[0], "samplerArea");
  92. _samplerSearchUniform = GL.GetUniformLocation(_blendShaderPrograms[0], "samplerSearch");
  93. _samplerBlendUniform = GL.GetUniformLocation(_neighbourShaderPrograms[0], "samplerBlend");
  94. _resolutionUniform = GL.GetUniformLocation(_edgeShaderPrograms[0], "invResolution");
  95. }
  96. private void Initialize()
  97. {
  98. var areaInfo = new TextureCreateInfo(AreaWidth,
  99. AreaHeight,
  100. 1,
  101. 1,
  102. 1,
  103. 1,
  104. 1,
  105. 1,
  106. Format.R8G8Unorm,
  107. DepthStencilMode.Depth,
  108. Target.Texture2D,
  109. SwizzleComponent.Red,
  110. SwizzleComponent.Green,
  111. SwizzleComponent.Blue,
  112. SwizzleComponent.Alpha);
  113. var searchInfo = new TextureCreateInfo(SearchWidth,
  114. SearchHeight,
  115. 1,
  116. 1,
  117. 1,
  118. 1,
  119. 1,
  120. 1,
  121. Format.R8Unorm,
  122. DepthStencilMode.Depth,
  123. Target.Texture2D,
  124. SwizzleComponent.Red,
  125. SwizzleComponent.Green,
  126. SwizzleComponent.Blue,
  127. SwizzleComponent.Alpha);
  128. _areaTexture = new TextureStorage(_renderer, areaInfo, 1);
  129. _searchTexture = new TextureStorage(_renderer, searchInfo, 1);
  130. var areaTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin");
  131. var searchTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin");
  132. var areaView = _areaTexture.CreateDefaultView();
  133. var searchView = _searchTexture.CreateDefaultView();
  134. areaView.SetData(areaTexture);
  135. searchView.SetData(searchTexture);
  136. }
  137. public TextureView Run(TextureView view, int width, int height)
  138. {
  139. if (_outputTexture == null || _outputTexture.Info.Width != view.Width || _outputTexture.Info.Height != view.Height)
  140. {
  141. _outputTexture?.Dispose();
  142. _outputTexture = new TextureStorage(_renderer, view.Info, view.ScaleFactor);
  143. _outputTexture.CreateDefaultView();
  144. _edgeOutputTexture = new TextureStorage(_renderer, view.Info, view.ScaleFactor);
  145. _edgeOutputTexture.CreateDefaultView();
  146. _blendOutputTexture = new TextureStorage(_renderer, view.Info, view.ScaleFactor);
  147. _blendOutputTexture.CreateDefaultView();
  148. DeleteShaders();
  149. RecreateShaders(view.Width, view.Height);
  150. }
  151. var textureView = _outputTexture.CreateView(view.Info, 0, 0) as TextureView;
  152. var edgeOutput = _edgeOutputTexture.DefaultView as TextureView;
  153. var blendOutput = _blendOutputTexture.DefaultView as TextureView;
  154. var areaTexture = _areaTexture.DefaultView as TextureView;
  155. var searchTexture = _searchTexture.DefaultView as TextureView;
  156. var previousFramebuffer = GL.GetInteger(GetPName.FramebufferBinding);
  157. int previousUnit = GL.GetInteger(GetPName.ActiveTexture);
  158. GL.ActiveTexture(TextureUnit.Texture0);
  159. int previousTextureBinding0 = GL.GetInteger(GetPName.TextureBinding2D);
  160. GL.ActiveTexture(TextureUnit.Texture1);
  161. int previousTextureBinding1 = GL.GetInteger(GetPName.TextureBinding2D);
  162. GL.ActiveTexture(TextureUnit.Texture2);
  163. int previousTextureBinding2 = GL.GetInteger(GetPName.TextureBinding2D);
  164. var framebuffer = new Framebuffer();
  165. framebuffer.Bind();
  166. framebuffer.AttachColor(0, edgeOutput);
  167. GL.Clear(ClearBufferMask.ColorBufferBit);
  168. GL.ClearColor(0, 0, 0, 0);
  169. framebuffer.AttachColor(0, blendOutput);
  170. GL.Clear(ClearBufferMask.ColorBufferBit);
  171. GL.ClearColor(0, 0, 0, 0);
  172. GL.BindFramebuffer(FramebufferTarget.Framebuffer, previousFramebuffer);
  173. framebuffer.Dispose();
  174. var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
  175. var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
  176. int previousProgram = GL.GetInteger(GetPName.CurrentProgram);
  177. GL.BindImageTexture(0, edgeOutput.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
  178. GL.UseProgram(_edgeShaderPrograms[Quality]);
  179. view.Bind(0);
  180. GL.Uniform1(_inputUniform, 0);
  181. GL.Uniform1(_outputUniform, 0);
  182. GL.Uniform2(_resolutionUniform, (float)view.Width, (float)view.Height);
  183. GL.DispatchCompute(dispatchX, dispatchY, 1);
  184. GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
  185. GL.BindImageTexture(0, blendOutput.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
  186. GL.UseProgram(_blendShaderPrograms[Quality]);
  187. edgeOutput.Bind(0);
  188. areaTexture.Bind(1);
  189. searchTexture.Bind(2);
  190. GL.Uniform1(_inputUniform, 0);
  191. GL.Uniform1(_outputUniform, 0);
  192. GL.Uniform1(_samplerAreaUniform, 1);
  193. GL.Uniform1(_samplerSearchUniform, 2);
  194. GL.Uniform2(_resolutionUniform, (float)view.Width, (float)view.Height);
  195. GL.DispatchCompute(dispatchX, dispatchY, 1);
  196. GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
  197. GL.BindImageTexture(0, textureView.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
  198. GL.UseProgram(_neighbourShaderPrograms[Quality]);
  199. view.Bind(0);
  200. blendOutput.Bind(1);
  201. GL.Uniform1(_inputUniform, 0);
  202. GL.Uniform1(_outputUniform, 0);
  203. GL.Uniform1(_samplerBlendUniform, 1);
  204. GL.Uniform2(_resolutionUniform, (float)view.Width, (float)view.Height);
  205. GL.DispatchCompute(dispatchX, dispatchY, 1);
  206. GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
  207. (_renderer.Pipeline as Pipeline).RestoreImages1And2();
  208. GL.UseProgram(previousProgram);
  209. GL.ActiveTexture(TextureUnit.Texture0);
  210. GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding0);
  211. GL.ActiveTexture(TextureUnit.Texture1);
  212. GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding1);
  213. GL.ActiveTexture(TextureUnit.Texture2);
  214. GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding2);
  215. GL.ActiveTexture((TextureUnit)previousUnit);
  216. return textureView;
  217. }
  218. }
  219. }