177 lines
7.6 KiB
C#
177 lines
7.6 KiB
C#
|
using OpenTK.Graphics.OpenGL;
|
||
|
using Ryujinx.Common;
|
||
|
using Ryujinx.Graphics.GAL;
|
||
|
using Ryujinx.Graphics.OpenGL.Image;
|
||
|
using System;
|
||
|
using static Ryujinx.Graphics.OpenGL.Effects.ShaderHelper;
|
||
|
|
||
|
namespace Ryujinx.Graphics.OpenGL.Effects
|
||
|
{
|
||
|
internal class FsrScalingFilter : IScalingFilter
|
||
|
{
|
||
|
private readonly OpenGLRenderer _renderer;
|
||
|
private int _inputUniform;
|
||
|
private int _outputUniform;
|
||
|
private int _sharpeningUniform;
|
||
|
private int _srcX0Uniform;
|
||
|
private int _srcX1Uniform;
|
||
|
private int _srcY0Uniform;
|
||
|
private int _scalingShaderProgram;
|
||
|
private int _sharpeningShaderProgram;
|
||
|
private float _scale = 1;
|
||
|
private int _srcY1Uniform;
|
||
|
private int _dstX0Uniform;
|
||
|
private int _dstX1Uniform;
|
||
|
private int _dstY0Uniform;
|
||
|
private int _dstY1Uniform;
|
||
|
private int _scaleXUniform;
|
||
|
private int _scaleYUniform;
|
||
|
private TextureStorage _intermediaryTexture;
|
||
|
|
||
|
public float Level
|
||
|
{
|
||
|
get => _scale;
|
||
|
set
|
||
|
{
|
||
|
_scale = MathF.Max(0.01f, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public FsrScalingFilter(OpenGLRenderer renderer, IPostProcessingEffect filter)
|
||
|
{
|
||
|
Initialize();
|
||
|
|
||
|
_renderer = renderer;
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
if (_scalingShaderProgram != 0)
|
||
|
{
|
||
|
GL.DeleteProgram(_scalingShaderProgram);
|
||
|
GL.DeleteProgram(_sharpeningShaderProgram);
|
||
|
}
|
||
|
|
||
|
_intermediaryTexture?.Dispose();
|
||
|
}
|
||
|
|
||
|
private void Initialize()
|
||
|
{
|
||
|
var scalingShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/fsr_scaling.glsl");
|
||
|
var sharpeningShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/fsr_sharpening.glsl");
|
||
|
var fsrA = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/ffx_a.h");
|
||
|
var fsr1 = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/ffx_fsr1.h");
|
||
|
|
||
|
scalingShader = scalingShader.Replace("#include \"ffx_a.h\"", fsrA);
|
||
|
scalingShader = scalingShader.Replace("#include \"ffx_fsr1.h\"", fsr1);
|
||
|
sharpeningShader = sharpeningShader.Replace("#include \"ffx_a.h\"", fsrA);
|
||
|
sharpeningShader = sharpeningShader.Replace("#include \"ffx_fsr1.h\"", fsr1);
|
||
|
|
||
|
_scalingShaderProgram = CompileProgram(scalingShader, ShaderType.ComputeShader);
|
||
|
_sharpeningShaderProgram = CompileProgram(sharpeningShader, ShaderType.ComputeShader);
|
||
|
|
||
|
_inputUniform = GL.GetUniformLocation(_scalingShaderProgram, "Source");
|
||
|
_outputUniform = GL.GetUniformLocation(_scalingShaderProgram, "imgOutput");
|
||
|
_sharpeningUniform = GL.GetUniformLocation(_sharpeningShaderProgram, "sharpening");
|
||
|
|
||
|
_srcX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX0");
|
||
|
_srcX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX1");
|
||
|
_srcY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY0");
|
||
|
_srcY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY1");
|
||
|
_dstX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX0");
|
||
|
_dstX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX1");
|
||
|
_dstY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY0");
|
||
|
_dstY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY1");
|
||
|
_scaleXUniform = GL.GetUniformLocation(_scalingShaderProgram, "scaleX");
|
||
|
_scaleYUniform = GL.GetUniformLocation(_scalingShaderProgram, "scaleY");
|
||
|
}
|
||
|
|
||
|
public void Run(
|
||
|
TextureView view,
|
||
|
TextureView destinationTexture,
|
||
|
int width,
|
||
|
int height,
|
||
|
Extents2D source,
|
||
|
Extents2D destination)
|
||
|
{
|
||
|
if (_intermediaryTexture == null || _intermediaryTexture.Info.Width != width || _intermediaryTexture.Info.Height != height)
|
||
|
{
|
||
|
_intermediaryTexture?.Dispose();
|
||
|
var originalInfo = view.Info;
|
||
|
var info = new TextureCreateInfo(width,
|
||
|
height,
|
||
|
originalInfo.Depth,
|
||
|
originalInfo.Levels,
|
||
|
originalInfo.Samples,
|
||
|
originalInfo.BlockWidth,
|
||
|
originalInfo.BlockHeight,
|
||
|
originalInfo.BytesPerPixel,
|
||
|
originalInfo.Format,
|
||
|
originalInfo.DepthStencilMode,
|
||
|
originalInfo.Target,
|
||
|
originalInfo.SwizzleR,
|
||
|
originalInfo.SwizzleG,
|
||
|
originalInfo.SwizzleB,
|
||
|
originalInfo.SwizzleA);
|
||
|
|
||
|
_intermediaryTexture = new TextureStorage(_renderer, info, view.ScaleFactor);
|
||
|
_intermediaryTexture.CreateDefaultView();
|
||
|
}
|
||
|
|
||
|
var textureView = _intermediaryTexture.CreateView(_intermediaryTexture.Info, 0, 0) as TextureView;
|
||
|
|
||
|
int previousProgram = GL.GetInteger(GetPName.CurrentProgram);
|
||
|
int previousUnit = GL.GetInteger(GetPName.ActiveTexture);
|
||
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||
|
int previousTextureBinding = GL.GetInteger(GetPName.TextureBinding2D);
|
||
|
|
||
|
GL.BindImageTexture(0, textureView.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
||
|
|
||
|
int threadGroupWorkRegionDim = 16;
|
||
|
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||
|
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||
|
|
||
|
// Scaling pass
|
||
|
float srcWidth = Math.Abs(source.X2 - source.X1);
|
||
|
float srcHeight = Math.Abs(source.Y2 - source.Y1);
|
||
|
float scaleX = srcWidth / view.Width;
|
||
|
float scaleY = srcHeight / view.Height;
|
||
|
GL.UseProgram(_scalingShaderProgram);
|
||
|
view.Bind(0);
|
||
|
GL.Uniform1(_inputUniform, 0);
|
||
|
GL.Uniform1(_outputUniform, 0);
|
||
|
GL.Uniform1(_srcX0Uniform, (float)source.X1);
|
||
|
GL.Uniform1(_srcX1Uniform, (float)source.X2);
|
||
|
GL.Uniform1(_srcY0Uniform, (float)source.Y1);
|
||
|
GL.Uniform1(_srcY1Uniform, (float)source.Y2);
|
||
|
GL.Uniform1(_dstX0Uniform, (float)destination.X1);
|
||
|
GL.Uniform1(_dstX1Uniform, (float)destination.X2);
|
||
|
GL.Uniform1(_dstY0Uniform, (float)destination.Y1);
|
||
|
GL.Uniform1(_dstY1Uniform, (float)destination.Y2);
|
||
|
GL.Uniform1(_scaleXUniform, scaleX);
|
||
|
GL.Uniform1(_scaleYUniform, scaleY);
|
||
|
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
||
|
|
||
|
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||
|
|
||
|
// Sharpening Pass
|
||
|
GL.UseProgram(_sharpeningShaderProgram);
|
||
|
GL.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
||
|
textureView.Bind(0);
|
||
|
GL.Uniform1(_inputUniform, 0);
|
||
|
GL.Uniform1(_outputUniform, 0);
|
||
|
GL.Uniform1(_sharpeningUniform, 1.5f - (Level * 0.01f * 1.5f));
|
||
|
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
||
|
|
||
|
GL.UseProgram(previousProgram);
|
||
|
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||
|
|
||
|
(_renderer.Pipeline as Pipeline).RestoreImages1And2();
|
||
|
|
||
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||
|
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
||
|
|
||
|
GL.ActiveTexture((TextureUnit)previousUnit);
|
||
|
}
|
||
|
}
|
||
|
}
|