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 }