AreaScalingFilter.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 Extent2D = Ryujinx.Graphics.GAL.Extents2D; 8 using Format = Silk.NET.Vulkan.Format; 9 using SamplerCreateInfo = Ryujinx.Graphics.GAL.SamplerCreateInfo; 10 11 namespace Ryujinx.Graphics.Vulkan.Effects 12 { 13 internal class AreaScalingFilter : IScalingFilter 14 { 15 private readonly VulkanRenderer _renderer; 16 private PipelineHelperShader _pipeline; 17 private ISampler _sampler; 18 private ShaderCollection _scalingProgram; 19 private Device _device; 20 21 public float Level { get; set; } 22 23 public AreaScalingFilter(VulkanRenderer renderer, Device device) 24 { 25 _device = device; 26 _renderer = renderer; 27 28 Initialize(); 29 } 30 31 public void Dispose() 32 { 33 _pipeline.Dispose(); 34 _scalingProgram.Dispose(); 35 _sampler.Dispose(); 36 } 37 38 public void Initialize() 39 { 40 _pipeline = new PipelineHelperShader(_renderer, _device); 41 42 _pipeline.Initialize(); 43 44 var scalingShader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv"); 45 46 var scalingResourceLayout = new ResourceLayoutBuilder() 47 .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2) 48 .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1) 49 .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build(); 50 51 _sampler = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); 52 53 _scalingProgram = _renderer.CreateProgramWithMinimalLayout(new[] 54 { 55 new ShaderSource(scalingShader, ShaderStage.Compute, TargetLanguage.Spirv), 56 }, scalingResourceLayout); 57 } 58 59 public void Run( 60 TextureView view, 61 CommandBufferScoped cbs, 62 Auto<DisposableImageView> destinationTexture, 63 Format format, 64 int width, 65 int height, 66 Extent2D source, 67 Extent2D destination) 68 { 69 _pipeline.SetCommandBuffer(cbs); 70 _pipeline.SetProgram(_scalingProgram); 71 _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _sampler); 72 73 ReadOnlySpan<float> dimensionsBuffer = stackalloc float[] 74 { 75 source.X1, 76 source.X2, 77 source.Y1, 78 source.Y2, 79 destination.X1, 80 destination.X2, 81 destination.Y1, 82 destination.Y2, 83 }; 84 85 int rangeSize = dimensionsBuffer.Length * sizeof(float); 86 using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); 87 buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer); 88 89 int threadGroupWorkRegionDim = 16; 90 int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; 91 int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; 92 93 _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); 94 _pipeline.SetImage(0, destinationTexture); 95 _pipeline.DispatchCompute(dispatchX, dispatchY, 1); 96 _pipeline.ComputeBarrier(); 97 98 _pipeline.Finish(); 99 } 100 } 101 }