FsrScalingFilter.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. namespace Ryujinx.Graphics.Vulkan.Effects
  11. {
  12. internal class FsrScalingFilter : IScalingFilter
  13. {
  14. private readonly VulkanRenderer _renderer;
  15. private PipelineHelperShader _pipeline;
  16. private ISampler _sampler;
  17. private ShaderCollection _scalingProgram;
  18. private ShaderCollection _sharpeningProgram;
  19. private float _sharpeningLevel = 1;
  20. private Device _device;
  21. private TextureView _intermediaryTexture;
  22. public float Level
  23. {
  24. get => _sharpeningLevel;
  25. set
  26. {
  27. _sharpeningLevel = MathF.Max(0.01f, value);
  28. }
  29. }
  30. public FsrScalingFilter(VulkanRenderer renderer, Device device)
  31. {
  32. _device = device;
  33. _renderer = renderer;
  34. Initialize();
  35. }
  36. public void Dispose()
  37. {
  38. _pipeline.Dispose();
  39. _scalingProgram.Dispose();
  40. _sharpeningProgram.Dispose();
  41. _sampler.Dispose();
  42. _intermediaryTexture?.Dispose();
  43. }
  44. public void Initialize()
  45. {
  46. _pipeline = new PipelineHelperShader(_renderer, _device);
  47. _pipeline.Initialize();
  48. byte[] scalingShader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/FsrScaling.spv");
  49. byte[] sharpeningShader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/FsrSharpening.spv");
  50. ResourceLayout scalingResourceLayout = new ResourceLayoutBuilder()
  51. .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2)
  52. .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1)
  53. .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build();
  54. ResourceLayout sharpeningResourceLayout = new ResourceLayoutBuilder()
  55. .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2)
  56. .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 3)
  57. .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 4)
  58. .Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1)
  59. .Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build();
  60. _sampler = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
  61. _scalingProgram = _renderer.CreateProgramWithMinimalLayout(new[]
  62. {
  63. new ShaderSource(scalingShader, ShaderStage.Compute, TargetLanguage.Spirv),
  64. }, scalingResourceLayout);
  65. _sharpeningProgram = _renderer.CreateProgramWithMinimalLayout(new[]
  66. {
  67. new ShaderSource(sharpeningShader, ShaderStage.Compute, TargetLanguage.Spirv),
  68. }, sharpeningResourceLayout);
  69. }
  70. public void Run(
  71. TextureView view,
  72. CommandBufferScoped cbs,
  73. Auto<DisposableImageView> destinationTexture,
  74. Format format,
  75. int width,
  76. int height,
  77. Extent2D source,
  78. Extent2D destination)
  79. {
  80. if (_intermediaryTexture == null
  81. || _intermediaryTexture.Info.Width != width
  82. || _intermediaryTexture.Info.Height != height
  83. || !_intermediaryTexture.Info.Equals(view.Info))
  84. {
  85. TextureCreateInfo originalInfo = view.Info;
  86. TextureCreateInfo info = new TextureCreateInfo(
  87. width,
  88. height,
  89. originalInfo.Depth,
  90. originalInfo.Levels,
  91. originalInfo.Samples,
  92. originalInfo.BlockWidth,
  93. originalInfo.BlockHeight,
  94. originalInfo.BytesPerPixel,
  95. originalInfo.Format,
  96. originalInfo.DepthStencilMode,
  97. originalInfo.Target,
  98. originalInfo.SwizzleR,
  99. originalInfo.SwizzleG,
  100. originalInfo.SwizzleB,
  101. originalInfo.SwizzleA);
  102. _intermediaryTexture?.Dispose();
  103. _intermediaryTexture = _renderer.CreateTexture(info) as TextureView;
  104. }
  105. _pipeline.SetCommandBuffer(cbs);
  106. _pipeline.SetProgram(_scalingProgram);
  107. _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _sampler);
  108. float srcWidth = Math.Abs(source.X2 - source.X1);
  109. float srcHeight = Math.Abs(source.Y2 - source.Y1);
  110. float scaleX = srcWidth / view.Width;
  111. float scaleY = srcHeight / view.Height;
  112. ReadOnlySpan<float> dimensionsBuffer = stackalloc float[]
  113. {
  114. source.X1,
  115. source.X2,
  116. source.Y1,
  117. source.Y2,
  118. destination.X1,
  119. destination.X2,
  120. destination.Y1,
  121. destination.Y2,
  122. scaleX,
  123. scaleY,
  124. };
  125. int rangeSize = dimensionsBuffer.Length * sizeof(float);
  126. using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
  127. buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer);
  128. ReadOnlySpan<float> sharpeningBufferData = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) };
  129. using ScopedTemporaryBuffer sharpeningBuffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, sizeof(float));
  130. sharpeningBuffer.Holder.SetDataUnchecked(sharpeningBuffer.Offset, sharpeningBufferData);
  131. int threadGroupWorkRegionDim = 16;
  132. int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
  133. int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
  134. _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
  135. _pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
  136. _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
  137. _pipeline.ComputeBarrier();
  138. // Sharpening pass
  139. _pipeline.SetProgram(_sharpeningProgram);
  140. _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler);
  141. _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningBuffer.Range) });
  142. _pipeline.SetImage(0, destinationTexture);
  143. _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
  144. _pipeline.ComputeBarrier();
  145. _pipeline.Finish();
  146. }
  147. }
  148. }