FsrScalingFilter.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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. namespace Ryujinx.Graphics.Vulkan.Effects
  9. {
  10. internal partial class FsrScalingFilter : IScalingFilter
  11. {
  12. private readonly VulkanRenderer _renderer;
  13. private PipelineHelperShader _pipeline;
  14. private ISampler _sampler;
  15. private ShaderCollection _scalingProgram;
  16. private ShaderCollection _sharpeningProgram;
  17. private float _sharpeningLevel = 1;
  18. private Device _device;
  19. private TextureView _intermediaryTexture;
  20. public float Level
  21. {
  22. get => _sharpeningLevel;
  23. set
  24. {
  25. _sharpeningLevel = MathF.Max(0.01f, value);
  26. }
  27. }
  28. public FsrScalingFilter(VulkanRenderer renderer, Device device)
  29. {
  30. _device = device;
  31. _renderer = renderer;
  32. Initialize();
  33. }
  34. public void Dispose()
  35. {
  36. _pipeline.Dispose();
  37. _scalingProgram.Dispose();
  38. _sharpeningProgram.Dispose();
  39. _sampler.Dispose();
  40. _intermediaryTexture?.Dispose();
  41. }
  42. public void Initialize()
  43. {
  44. _pipeline = new PipelineHelperShader(_renderer, _device);
  45. _pipeline.Initialize();
  46. var scalingShader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/FsrScaling.spv");
  47. var sharpeningShader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/FsrSharpening.spv");
  48. var computeBindings = new ShaderBindings(
  49. new[] { 2 },
  50. Array.Empty<int>(),
  51. new[] { 1 },
  52. new[] { 0 });
  53. var sharpeningBindings = new ShaderBindings(
  54. new[] { 2, 3, 4 },
  55. Array.Empty<int>(),
  56. new[] { 1 },
  57. new[] { 0 });
  58. _sampler = _renderer.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
  59. _scalingProgram = _renderer.CreateProgramWithMinimalLayout(new[]
  60. {
  61. new ShaderSource(scalingShader, computeBindings, ShaderStage.Compute, TargetLanguage.Spirv)
  62. });
  63. _sharpeningProgram = _renderer.CreateProgramWithMinimalLayout(new[]
  64. {
  65. new ShaderSource(sharpeningShader, sharpeningBindings, ShaderStage.Compute, TargetLanguage.Spirv)
  66. });
  67. }
  68. public void Run(
  69. TextureView view,
  70. CommandBufferScoped cbs,
  71. Auto<DisposableImageView> destinationTexture,
  72. Silk.NET.Vulkan.Format format,
  73. int width,
  74. int height,
  75. Extent2D source,
  76. Extent2D destination)
  77. {
  78. if (_intermediaryTexture == null
  79. || _intermediaryTexture.Info.Width != width
  80. || _intermediaryTexture.Info.Height != height
  81. || !_intermediaryTexture.Info.Equals(view.Info))
  82. {
  83. var originalInfo = view.Info;
  84. var swapRB = originalInfo.Format.IsBgr() && originalInfo.SwizzleR == SwizzleComponent.Red;
  85. var info = new TextureCreateInfo(
  86. width,
  87. height,
  88. originalInfo.Depth,
  89. originalInfo.Levels,
  90. originalInfo.Samples,
  91. originalInfo.BlockWidth,
  92. originalInfo.BlockHeight,
  93. originalInfo.BytesPerPixel,
  94. originalInfo.Format,
  95. originalInfo.DepthStencilMode,
  96. originalInfo.Target,
  97. swapRB ? originalInfo.SwizzleB : originalInfo.SwizzleR,
  98. originalInfo.SwizzleG,
  99. swapRB ? originalInfo.SwizzleR : originalInfo.SwizzleB,
  100. originalInfo.SwizzleA);
  101. _intermediaryTexture?.Dispose();
  102. _intermediaryTexture = _renderer.CreateTexture(info, view.ScaleFactor) as TextureView;
  103. }
  104. Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
  105. Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
  106. viewports[0] = new GAL.Viewport(
  107. new Rectangle<float>(0, 0, view.Width, view.Height),
  108. ViewportSwizzle.PositiveX,
  109. ViewportSwizzle.PositiveY,
  110. ViewportSwizzle.PositiveZ,
  111. ViewportSwizzle.PositiveW,
  112. 0f,
  113. 1f);
  114. scissors[0] = new Rectangle<int>(0, 0, view.Width, view.Height);
  115. _pipeline.SetCommandBuffer(cbs);
  116. _pipeline.SetProgram(_scalingProgram);
  117. _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _sampler);
  118. float srcWidth = Math.Abs(source.X2 - source.X1);
  119. float srcHeight = Math.Abs(source.Y2 - source.Y1);
  120. float scaleX = srcWidth / view.Width;
  121. float scaleY = srcHeight / view.Height;
  122. ReadOnlySpan<float> dimensionsBuffer = stackalloc float[]
  123. {
  124. source.X1,
  125. source.X2,
  126. source.Y1,
  127. source.Y2,
  128. destination.X1,
  129. destination.X2,
  130. destination.Y1,
  131. destination.Y2,
  132. scaleX,
  133. scaleY
  134. };
  135. int rangeSize = dimensionsBuffer.Length * sizeof(float);
  136. var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
  137. _renderer.BufferManager.SetData(bufferHandle, 0, dimensionsBuffer);
  138. ReadOnlySpan<float> sharpeningBuffer = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f)};
  139. var sharpeningBufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, sizeof(float));
  140. _renderer.BufferManager.SetData(sharpeningBufferHandle, 0, sharpeningBuffer);
  141. int threadGroupWorkRegionDim = 16;
  142. int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
  143. int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
  144. var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
  145. _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
  146. _pipeline.SetScissors(scissors);
  147. _pipeline.SetViewports(viewports, false);
  148. _pipeline.SetImage(0, _intermediaryTexture, GAL.Format.R8G8B8A8Unorm);
  149. _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
  150. _pipeline.ComputeBarrier();
  151. viewports[0] = new GAL.Viewport(
  152. new Rectangle<float>(0, 0, width, height),
  153. ViewportSwizzle.PositiveX,
  154. ViewportSwizzle.PositiveY,
  155. ViewportSwizzle.PositiveZ,
  156. ViewportSwizzle.PositiveW,
  157. 0f,
  158. 1f);
  159. scissors[0] = new Rectangle<int>(0, 0, width, height);
  160. // Sharpening pass
  161. _pipeline.SetCommandBuffer(cbs);
  162. _pipeline.SetProgram(_sharpeningProgram);
  163. _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler);
  164. _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
  165. var sharpeningRange = new BufferRange(sharpeningBufferHandle, 0, sizeof(float));
  166. _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningRange) });
  167. _pipeline.SetScissors(scissors);
  168. _pipeline.SetViewports(viewports, false);
  169. _pipeline.SetImage(0, destinationTexture);
  170. _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
  171. _pipeline.ComputeBarrier();
  172. _pipeline.Finish();
  173. _renderer.BufferManager.Delete(bufferHandle);
  174. _renderer.BufferManager.Delete(sharpeningBufferHandle);
  175. }
  176. }
  177. }