HelperShader.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. using Ryujinx.Graphics.GAL;
  2. using Ryujinx.Graphics.Shader;
  3. using Ryujinx.Graphics.Shader.Translation;
  4. using Ryujinx.Graphics.Vulkan.Shaders;
  5. using Silk.NET.Vulkan;
  6. using System;
  7. using VkFormat = Silk.NET.Vulkan.Format;
  8. namespace Ryujinx.Graphics.Vulkan
  9. {
  10. class HelperShader : IDisposable
  11. {
  12. private readonly PipelineHelperShader _pipeline;
  13. private readonly ISampler _samplerLinear;
  14. private readonly ISampler _samplerNearest;
  15. private readonly IProgram _programColorBlit;
  16. private readonly IProgram _programColorBlitClearAlpha;
  17. private readonly IProgram _programColorClear;
  18. private readonly IProgram _programStrideChange;
  19. public HelperShader(VulkanRenderer gd, Device device)
  20. {
  21. _pipeline = new PipelineHelperShader(gd, device);
  22. _pipeline.Initialize();
  23. _samplerLinear = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
  24. _samplerNearest = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest));
  25. var vertexBindings = new ShaderBindings(
  26. new[] { 1 },
  27. Array.Empty<int>(),
  28. Array.Empty<int>(),
  29. Array.Empty<int>());
  30. var fragmentBindings = new ShaderBindings(
  31. Array.Empty<int>(),
  32. Array.Empty<int>(),
  33. new[] { 0 },
  34. Array.Empty<int>());
  35. _programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
  36. {
  37. new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
  38. new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
  39. });
  40. _programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
  41. {
  42. new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
  43. new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
  44. });
  45. var fragmentBindings2 = new ShaderBindings(
  46. Array.Empty<int>(),
  47. Array.Empty<int>(),
  48. Array.Empty<int>(),
  49. Array.Empty<int>());
  50. _programColorClear = gd.CreateProgramWithMinimalLayout(new[]
  51. {
  52. new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
  53. new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Spirv),
  54. });
  55. var strideChangeBindings = new ShaderBindings(
  56. new[] { 0 },
  57. new[] { 1, 2 },
  58. Array.Empty<int>(),
  59. Array.Empty<int>());
  60. _programStrideChange = gd.CreateProgramWithMinimalLayout(new[]
  61. {
  62. new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, strideChangeBindings, ShaderStage.Compute, TargetLanguage.Spirv),
  63. });
  64. }
  65. public void Blit(
  66. VulkanRenderer gd,
  67. TextureView src,
  68. Auto<DisposableImageView> dst,
  69. int dstWidth,
  70. int dstHeight,
  71. VkFormat dstFormat,
  72. Extents2D srcRegion,
  73. Extents2D dstRegion,
  74. bool linearFilter,
  75. bool clearAlpha = false)
  76. {
  77. gd.FlushAllCommands();
  78. using var cbs = gd.CommandBufferPool.Rent();
  79. Blit(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion, linearFilter, clearAlpha);
  80. }
  81. public void Blit(
  82. VulkanRenderer gd,
  83. CommandBufferScoped cbs,
  84. TextureView src,
  85. Auto<DisposableImageView> dst,
  86. int dstWidth,
  87. int dstHeight,
  88. VkFormat dstFormat,
  89. Extents2D srcRegion,
  90. Extents2D dstRegion,
  91. bool linearFilter,
  92. bool clearAlpha = false)
  93. {
  94. _pipeline.SetCommandBuffer(cbs);
  95. const int RegionBufferSize = 16;
  96. var sampler = linearFilter ? _samplerLinear : _samplerNearest;
  97. _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, sampler);
  98. Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
  99. region[0] = (float)srcRegion.X1 / src.Width;
  100. region[1] = (float)srcRegion.X2 / src.Width;
  101. region[2] = (float)srcRegion.Y1 / src.Height;
  102. region[3] = (float)srcRegion.Y2 / src.Height;
  103. if (dstRegion.X1 > dstRegion.X2)
  104. {
  105. (region[0], region[1]) = (region[1], region[0]);
  106. }
  107. if (dstRegion.Y1 > dstRegion.Y2)
  108. {
  109. (region[2], region[3]) = (region[3], region[2]);
  110. }
  111. var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize, false);
  112. gd.BufferManager.SetData<float>(bufferHandle, 0, region);
  113. Span<BufferRange> bufferRanges = stackalloc BufferRange[1];
  114. bufferRanges[0] = new BufferRange(bufferHandle, 0, RegionBufferSize);
  115. _pipeline.SetUniformBuffers(1, bufferRanges);
  116. Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
  117. var rect = new Rectangle<float>(
  118. MathF.Min(dstRegion.X1, dstRegion.X2),
  119. MathF.Min(dstRegion.Y1, dstRegion.Y2),
  120. MathF.Abs(dstRegion.X2 - dstRegion.X1),
  121. MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
  122. viewports[0] = new GAL.Viewport(
  123. rect,
  124. ViewportSwizzle.PositiveX,
  125. ViewportSwizzle.PositiveY,
  126. ViewportSwizzle.PositiveZ,
  127. ViewportSwizzle.PositiveW,
  128. 0f,
  129. 1f);
  130. Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
  131. scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
  132. _pipeline.SetProgram(clearAlpha ? _programColorBlitClearAlpha : _programColorBlit);
  133. _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
  134. _pipeline.SetRenderTargetColorMasks(new uint[] { 0xf });
  135. _pipeline.SetScissors(scissors);
  136. if (clearAlpha)
  137. {
  138. _pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f));
  139. }
  140. _pipeline.SetViewports(viewports, false);
  141. _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
  142. _pipeline.Draw(4, 1, 0, 0);
  143. _pipeline.Finish(gd, cbs);
  144. gd.BufferManager.Delete(bufferHandle);
  145. }
  146. public void Clear(
  147. VulkanRenderer gd,
  148. Auto<DisposableImageView> dst,
  149. ReadOnlySpan<float> clearColor,
  150. uint componentMask,
  151. int dstWidth,
  152. int dstHeight,
  153. VkFormat dstFormat,
  154. Rectangle<int> scissor)
  155. {
  156. const int ClearColorBufferSize = 16;
  157. gd.FlushAllCommands();
  158. using var cbs = gd.CommandBufferPool.Rent();
  159. _pipeline.SetCommandBuffer(cbs);
  160. var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize, false);
  161. gd.BufferManager.SetData<float>(bufferHandle, 0, clearColor);
  162. Span<BufferRange> bufferRanges = stackalloc BufferRange[1];
  163. bufferRanges[0] = new BufferRange(bufferHandle, 0, ClearColorBufferSize);
  164. _pipeline.SetUniformBuffers(1, bufferRanges);
  165. Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
  166. viewports[0] = new GAL.Viewport(
  167. new Rectangle<float>(0, 0, dstWidth, dstHeight),
  168. ViewportSwizzle.PositiveX,
  169. ViewportSwizzle.PositiveY,
  170. ViewportSwizzle.PositiveZ,
  171. ViewportSwizzle.PositiveW,
  172. 0f,
  173. 1f);
  174. Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
  175. scissors[0] = scissor;
  176. _pipeline.SetProgram(_programColorClear);
  177. _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
  178. _pipeline.SetRenderTargetColorMasks(new uint[] { componentMask });
  179. _pipeline.SetViewports(viewports, false);
  180. _pipeline.SetScissors(scissors);
  181. _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
  182. _pipeline.Draw(4, 1, 0, 0);
  183. _pipeline.Finish();
  184. gd.BufferManager.Delete(bufferHandle);
  185. }
  186. public void DrawTexture(
  187. VulkanRenderer gd,
  188. PipelineBase pipeline,
  189. TextureView src,
  190. ISampler srcSampler,
  191. Extents2DF srcRegion,
  192. Extents2DF dstRegion)
  193. {
  194. const int RegionBufferSize = 16;
  195. pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, srcSampler);
  196. Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
  197. region[0] = srcRegion.X1 / src.Width;
  198. region[1] = srcRegion.X2 / src.Width;
  199. region[2] = srcRegion.Y1 / src.Height;
  200. region[3] = srcRegion.Y2 / src.Height;
  201. if (dstRegion.X1 > dstRegion.X2)
  202. {
  203. (region[0], region[1]) = (region[1], region[0]);
  204. }
  205. if (dstRegion.Y1 > dstRegion.Y2)
  206. {
  207. (region[2], region[3]) = (region[3], region[2]);
  208. }
  209. var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize, false);
  210. gd.BufferManager.SetData<float>(bufferHandle, 0, region);
  211. Span<BufferRange> bufferRanges = stackalloc BufferRange[1];
  212. bufferRanges[0] = new BufferRange(bufferHandle, 0, RegionBufferSize);
  213. pipeline.SetUniformBuffers(1, bufferRanges);
  214. Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
  215. var rect = new Rectangle<float>(
  216. MathF.Min(dstRegion.X1, dstRegion.X2),
  217. MathF.Min(dstRegion.Y1, dstRegion.Y2),
  218. MathF.Abs(dstRegion.X2 - dstRegion.X1),
  219. MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
  220. viewports[0] = new GAL.Viewport(
  221. rect,
  222. ViewportSwizzle.PositiveX,
  223. ViewportSwizzle.PositiveY,
  224. ViewportSwizzle.PositiveZ,
  225. ViewportSwizzle.PositiveW,
  226. 0f,
  227. 1f);
  228. Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
  229. pipeline.SetProgram(_programColorBlit);
  230. pipeline.SetViewports(viewports, false);
  231. pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
  232. pipeline.Draw(4, 1, 0, 0);
  233. gd.BufferManager.Delete(bufferHandle);
  234. }
  235. public unsafe void ConvertI8ToI16(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
  236. {
  237. ChangeStride(gd, cbs, src, dst, srcOffset, size, 1, 2);
  238. }
  239. public unsafe void ChangeStride(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size, int stride, int newStride)
  240. {
  241. bool supportsUint8 = gd.Capabilities.SupportsShaderInt8;
  242. int elems = size / stride;
  243. int newSize = elems * newStride;
  244. var srcBufferAuto = src.GetBuffer();
  245. var dstBufferAuto = dst.GetBuffer();
  246. var srcBuffer = srcBufferAuto.Get(cbs, srcOffset, size).Value;
  247. var dstBuffer = dstBufferAuto.Get(cbs, 0, newSize).Value;
  248. var access = supportsUint8 ? AccessFlags.AccessShaderWriteBit : AccessFlags.AccessTransferWriteBit;
  249. var stage = supportsUint8 ? PipelineStageFlags.PipelineStageComputeShaderBit : PipelineStageFlags.PipelineStageTransferBit;
  250. BufferHolder.InsertBufferBarrier(
  251. gd,
  252. cbs.CommandBuffer,
  253. dstBuffer,
  254. BufferHolder.DefaultAccessFlags,
  255. access,
  256. PipelineStageFlags.PipelineStageAllCommandsBit,
  257. stage,
  258. 0,
  259. newSize);
  260. if (supportsUint8)
  261. {
  262. const int ParamsBufferSize = 16;
  263. Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
  264. shaderParams[0] = stride;
  265. shaderParams[1] = newStride;
  266. shaderParams[2] = size;
  267. shaderParams[3] = srcOffset;
  268. var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false);
  269. gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
  270. _pipeline.SetCommandBuffer(cbs);
  271. Span<BufferRange> cbRanges = stackalloc BufferRange[1];
  272. cbRanges[0] = new BufferRange(bufferHandle, 0, ParamsBufferSize);
  273. _pipeline.SetUniformBuffers(0, cbRanges);
  274. Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
  275. sbRanges[0] = srcBufferAuto;
  276. sbRanges[1] = dstBufferAuto;
  277. _pipeline.SetStorageBuffers(1, sbRanges);
  278. _pipeline.SetProgram(_programStrideChange);
  279. _pipeline.DispatchCompute(1, 1, 1);
  280. gd.BufferManager.Delete(bufferHandle);
  281. _pipeline.Finish(gd, cbs);
  282. }
  283. else
  284. {
  285. gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0);
  286. var bufferCopy = new BufferCopy[elems];
  287. for (ulong i = 0; i < (ulong)elems; i++)
  288. {
  289. bufferCopy[i] = new BufferCopy((ulong)srcOffset + i * (ulong)stride, i * (ulong)newStride, (ulong)stride);
  290. }
  291. fixed (BufferCopy* pBufferCopy = bufferCopy)
  292. {
  293. gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)elems, pBufferCopy);
  294. }
  295. }
  296. BufferHolder.InsertBufferBarrier(
  297. gd,
  298. cbs.CommandBuffer,
  299. dstBuffer,
  300. access,
  301. BufferHolder.DefaultAccessFlags,
  302. stage,
  303. PipelineStageFlags.PipelineStageAllCommandsBit,
  304. 0,
  305. newSize);
  306. }
  307. protected virtual void Dispose(bool disposing)
  308. {
  309. if (disposing)
  310. {
  311. _programColorBlitClearAlpha.Dispose();
  312. _programColorBlit.Dispose();
  313. _samplerNearest.Dispose();
  314. _samplerLinear.Dispose();
  315. _pipeline.Dispose();
  316. }
  317. }
  318. public void Dispose()
  319. {
  320. Dispose(true);
  321. }
  322. }
  323. }