FxaaPostProcessingEffect.cs
1 using Ryujinx.Common; 2 using Ryujinx.Graphics.GAL; 3 using Ryujinx.Graphics.Shader; 4 using Ryujinx.Graphics.Shader.Translation; 5 using Silk.NET.Vulkan; 6 using System; 7 using SamplerCreateInfo = Ryujinx.Graphics.GAL.SamplerCreateInfo; 8 9 namespace Ryujinx.Graphics.Vulkan.Effects 10 { 11 internal class FxaaPostProcessingEffect : IPostProcessingEffect 12 { 13 private readonly VulkanRenderer _renderer; 14 private ISampler _samplerLinear; 15 private ShaderCollection _shaderProgram; 16 17 private readonly PipelineHelperShader _pipeline; 18 private TextureView _texture; 19 20 public FxaaPostProcessingEffect(VulkanRenderer renderer, Device device) 21 { 22 _renderer = renderer; 23 _pipeline = new PipelineHelperShader(renderer, device); 24 25 Initialize(); 26 } 27 28 public void Dispose() 29 { 30 _shaderProgram.Dispose(); 31 _pipeline.Dispose(); 32 _samplerLinear.Dispose(); 33 _texture?.Dispose(); 34 } 35 36 private void Initialize() 37 { 38 _pipeline.Initialize(); 39 40 var shader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/Fxaa.spv"); 41 42 var resourceLayout = new ResourceLayoutBuilder() 43 .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) 44 .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) 45 .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); 46 47 _samplerLinear = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); 48 49 _shaderProgram = _renderer.CreateProgramWithMinimalLayout(new[] 50 { 51 new ShaderSource(shader, ShaderStage.Compute, TargetLanguage.Spirv), 52 }, resourceLayout); 53 } 54 55 public TextureView Run(TextureView view, CommandBufferScoped cbs, int width, int height) 56 { 57 if (_texture == null || _texture.Width != view.Width || _texture.Height != view.Height) 58 { 59 _texture?.Dispose(); 60 _texture = _renderer.CreateTexture(view.Info) as TextureView; 61 } 62 63 _pipeline.SetCommandBuffer(cbs); 64 _pipeline.SetProgram(_shaderProgram); 65 _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear); 66 67 ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height }; 68 int rangeSize = resolutionBuffer.Length * sizeof(float); 69 using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); 70 71 buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer); 72 73 _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); 74 75 var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize); 76 var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize); 77 78 _pipeline.SetImage(ShaderStage.Compute, 0, _texture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format))); 79 _pipeline.DispatchCompute(dispatchX, dispatchY, 1); 80 81 _pipeline.ComputeBarrier(); 82 83 _pipeline.Finish(); 84 85 return _texture; 86 } 87 } 88 }