/ src / Ryujinx.Graphics.OpenGL / Effects / FsrScalingFilter.cs
FsrScalingFilter.cs
  1  using OpenTK.Graphics.OpenGL;
  2  using Ryujinx.Common;
  3  using Ryujinx.Graphics.GAL;
  4  using Ryujinx.Graphics.OpenGL.Image;
  5  using System;
  6  using static Ryujinx.Graphics.OpenGL.Effects.ShaderHelper;
  7  
  8  namespace Ryujinx.Graphics.OpenGL.Effects
  9  {
 10      internal class FsrScalingFilter : IScalingFilter
 11      {
 12          private readonly OpenGLRenderer _renderer;
 13          private int _inputUniform;
 14          private int _outputUniform;
 15          private int _sharpeningUniform;
 16          private int _srcX0Uniform;
 17          private int _srcX1Uniform;
 18          private int _srcY0Uniform;
 19          private int _scalingShaderProgram;
 20          private int _sharpeningShaderProgram;
 21          private float _sharpeningLevel = 1;
 22          private int _srcY1Uniform;
 23          private int _dstX0Uniform;
 24          private int _dstX1Uniform;
 25          private int _dstY0Uniform;
 26          private int _dstY1Uniform;
 27          private int _scaleXUniform;
 28          private int _scaleYUniform;
 29          private TextureStorage _intermediaryTexture;
 30  
 31          public float Level
 32          {
 33              get => _sharpeningLevel;
 34              set
 35              {
 36                  _sharpeningLevel = MathF.Max(0.01f, value);
 37              }
 38          }
 39  
 40          public FsrScalingFilter(OpenGLRenderer renderer)
 41          {
 42              Initialize();
 43  
 44              _renderer = renderer;
 45          }
 46  
 47          public void Dispose()
 48          {
 49              if (_scalingShaderProgram != 0)
 50              {
 51                  GL.DeleteProgram(_scalingShaderProgram);
 52                  GL.DeleteProgram(_sharpeningShaderProgram);
 53              }
 54  
 55              _intermediaryTexture?.Dispose();
 56          }
 57  
 58          private void Initialize()
 59          {
 60              var scalingShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/fsr_scaling.glsl");
 61              var sharpeningShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/fsr_sharpening.glsl");
 62              var fsrA = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/ffx_a.h");
 63              var fsr1 = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/ffx_fsr1.h");
 64  
 65              scalingShader = scalingShader.Replace("#include \"ffx_a.h\"", fsrA);
 66              scalingShader = scalingShader.Replace("#include \"ffx_fsr1.h\"", fsr1);
 67              sharpeningShader = sharpeningShader.Replace("#include \"ffx_a.h\"", fsrA);
 68              sharpeningShader = sharpeningShader.Replace("#include \"ffx_fsr1.h\"", fsr1);
 69  
 70              _scalingShaderProgram = CompileProgram(scalingShader, ShaderType.ComputeShader);
 71              _sharpeningShaderProgram = CompileProgram(sharpeningShader, ShaderType.ComputeShader);
 72  
 73              _inputUniform = GL.GetUniformLocation(_scalingShaderProgram, "Source");
 74              _outputUniform = GL.GetUniformLocation(_scalingShaderProgram, "imgOutput");
 75              _sharpeningUniform = GL.GetUniformLocation(_sharpeningShaderProgram, "sharpening");
 76  
 77              _srcX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX0");
 78              _srcX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX1");
 79              _srcY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY0");
 80              _srcY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY1");
 81              _dstX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX0");
 82              _dstX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX1");
 83              _dstY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY0");
 84              _dstY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY1");
 85              _scaleXUniform = GL.GetUniformLocation(_scalingShaderProgram, "scaleX");
 86              _scaleYUniform = GL.GetUniformLocation(_scalingShaderProgram, "scaleY");
 87          }
 88  
 89          public void Run(
 90              TextureView view,
 91              TextureView destinationTexture,
 92              int width,
 93              int height,
 94              Extents2D source,
 95              Extents2D destination)
 96          {
 97              if (_intermediaryTexture == null || _intermediaryTexture.Info.Width != width || _intermediaryTexture.Info.Height != height)
 98              {
 99                  _intermediaryTexture?.Dispose();
100                  var originalInfo = view.Info;
101                  var info = new TextureCreateInfo(width,
102                      height,
103                      originalInfo.Depth,
104                      originalInfo.Levels,
105                      originalInfo.Samples,
106                      originalInfo.BlockWidth,
107                      originalInfo.BlockHeight,
108                      originalInfo.BytesPerPixel,
109                      originalInfo.Format,
110                      originalInfo.DepthStencilMode,
111                      originalInfo.Target,
112                      originalInfo.SwizzleR,
113                      originalInfo.SwizzleG,
114                      originalInfo.SwizzleB,
115                      originalInfo.SwizzleA);
116  
117                  _intermediaryTexture = new TextureStorage(_renderer, info);
118                  _intermediaryTexture.CreateDefaultView();
119              }
120  
121              var textureView = _intermediaryTexture.CreateView(_intermediaryTexture.Info, 0, 0) as TextureView;
122  
123              int previousProgram = GL.GetInteger(GetPName.CurrentProgram);
124              int previousUnit = GL.GetInteger(GetPName.ActiveTexture);
125              GL.ActiveTexture(TextureUnit.Texture0);
126              int previousTextureBinding = GL.GetInteger(GetPName.TextureBinding2D);
127  
128              GL.BindImageTexture(0, textureView.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
129  
130              int threadGroupWorkRegionDim = 16;
131              int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
132              int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
133  
134              // Scaling pass
135              float srcWidth = Math.Abs(source.X2 - source.X1);
136              float srcHeight = Math.Abs(source.Y2 - source.Y1);
137              float scaleX = srcWidth / view.Width;
138              float scaleY = srcHeight / view.Height;
139              GL.UseProgram(_scalingShaderProgram);
140              view.Bind(0);
141              GL.Uniform1(_inputUniform, 0);
142              GL.Uniform1(_outputUniform, 0);
143              GL.Uniform1(_srcX0Uniform, (float)source.X1);
144              GL.Uniform1(_srcX1Uniform, (float)source.X2);
145              GL.Uniform1(_srcY0Uniform, (float)source.Y1);
146              GL.Uniform1(_srcY1Uniform, (float)source.Y2);
147              GL.Uniform1(_dstX0Uniform, (float)destination.X1);
148              GL.Uniform1(_dstX1Uniform, (float)destination.X2);
149              GL.Uniform1(_dstY0Uniform, (float)destination.Y1);
150              GL.Uniform1(_dstY1Uniform, (float)destination.Y2);
151              GL.Uniform1(_scaleXUniform, scaleX);
152              GL.Uniform1(_scaleYUniform, scaleY);
153              GL.DispatchCompute(dispatchX, dispatchY, 1);
154  
155              GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
156  
157              // Sharpening Pass
158              GL.UseProgram(_sharpeningShaderProgram);
159              GL.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
160              textureView.Bind(0);
161              GL.Uniform1(_inputUniform, 0);
162              GL.Uniform1(_outputUniform, 0);
163              GL.Uniform1(_sharpeningUniform, 1.5f - (Level * 0.01f * 1.5f));
164              GL.DispatchCompute(dispatchX, dispatchY, 1);
165  
166              GL.UseProgram(previousProgram);
167              GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
168  
169              (_renderer.Pipeline as Pipeline).RestoreImages1And2();
170  
171              GL.ActiveTexture(TextureUnit.Texture0);
172              GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
173  
174              GL.ActiveTexture((TextureUnit)previousUnit);
175          }
176      }
177  }