/ src / Ryujinx.Graphics.Vulkan / Effects / FxaaPostProcessingEffect.cs
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  }