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