HelperShader.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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. public HelperShader(VulkanRenderer gd, Device device)
  19. {
  20. _pipeline = new PipelineHelperShader(gd, device);
  21. _pipeline.Initialize();
  22. _samplerLinear = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
  23. _samplerNearest = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest));
  24. var vertexBindings = new ShaderBindings(
  25. new[] { 1 },
  26. Array.Empty<int>(),
  27. Array.Empty<int>(),
  28. Array.Empty<int>());
  29. var fragmentBindings = new ShaderBindings(
  30. Array.Empty<int>(),
  31. Array.Empty<int>(),
  32. new[] { 0 },
  33. Array.Empty<int>());
  34. _programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
  35. {
  36. new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
  37. new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
  38. });
  39. _programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
  40. {
  41. new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
  42. new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
  43. });
  44. var fragmentBindings2 = new ShaderBindings(
  45. Array.Empty<int>(),
  46. Array.Empty<int>(),
  47. Array.Empty<int>(),
  48. Array.Empty<int>());
  49. _programColorClear = gd.CreateProgramWithMinimalLayout(new[]
  50. {
  51. new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
  52. new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Glsl),
  53. });
  54. }
  55. public void Blit(
  56. VulkanRenderer gd,
  57. TextureView src,
  58. Auto<DisposableImageView> dst,
  59. int dstWidth,
  60. int dstHeight,
  61. VkFormat dstFormat,
  62. Extents2D srcRegion,
  63. Extents2D dstRegion,
  64. bool linearFilter,
  65. bool clearAlpha = false)
  66. {
  67. gd.FlushAllCommands();
  68. using var cbs = gd.CommandBufferPool.Rent();
  69. Blit(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion, linearFilter, clearAlpha);
  70. }
  71. public void Blit(
  72. VulkanRenderer gd,
  73. CommandBufferScoped cbs,
  74. TextureView src,
  75. Auto<DisposableImageView> dst,
  76. int dstWidth,
  77. int dstHeight,
  78. VkFormat dstFormat,
  79. Extents2D srcRegion,
  80. Extents2D dstRegion,
  81. bool linearFilter,
  82. bool clearAlpha = false)
  83. {
  84. _pipeline.SetCommandBuffer(cbs);
  85. const int RegionBufferSize = 16;
  86. var sampler = linearFilter ? _samplerLinear : _samplerNearest;
  87. _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, sampler);
  88. Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
  89. region[0] = (float)srcRegion.X1 / src.Width;
  90. region[1] = (float)srcRegion.X2 / src.Width;
  91. region[2] = (float)srcRegion.Y1 / src.Height;
  92. region[3] = (float)srcRegion.Y2 / src.Height;
  93. if (dstRegion.X1 > dstRegion.X2)
  94. {
  95. (region[0], region[1]) = (region[1], region[0]);
  96. }
  97. if (dstRegion.Y1 > dstRegion.Y2)
  98. {
  99. (region[2], region[3]) = (region[3], region[2]);
  100. }
  101. var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize, false);
  102. gd.BufferManager.SetData<float>(bufferHandle, 0, region);
  103. Span<BufferRange> bufferRanges = stackalloc BufferRange[1];
  104. bufferRanges[0] = new BufferRange(bufferHandle, 0, RegionBufferSize);
  105. _pipeline.SetUniformBuffers(1, bufferRanges);
  106. Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
  107. var rect = new Rectangle<float>(
  108. MathF.Min(dstRegion.X1, dstRegion.X2),
  109. MathF.Min(dstRegion.Y1, dstRegion.Y2),
  110. MathF.Abs(dstRegion.X2 - dstRegion.X1),
  111. MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
  112. viewports[0] = new GAL.Viewport(
  113. rect,
  114. ViewportSwizzle.PositiveX,
  115. ViewportSwizzle.PositiveY,
  116. ViewportSwizzle.PositiveZ,
  117. ViewportSwizzle.PositiveW,
  118. 0f,
  119. 1f);
  120. Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
  121. scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
  122. _pipeline.SetProgram(clearAlpha ? _programColorBlitClearAlpha : _programColorBlit);
  123. _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
  124. _pipeline.SetRenderTargetColorMasks(new uint[] { 0xf });
  125. _pipeline.SetScissors(scissors);
  126. if (clearAlpha)
  127. {
  128. _pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f));
  129. }
  130. _pipeline.SetViewports(viewports, false);
  131. _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
  132. _pipeline.Draw(4, 1, 0, 0);
  133. _pipeline.Finish();
  134. gd.BufferManager.Delete(bufferHandle);
  135. }
  136. public void Clear(
  137. VulkanRenderer gd,
  138. Auto<DisposableImageView> dst,
  139. ReadOnlySpan<float> clearColor,
  140. uint componentMask,
  141. int dstWidth,
  142. int dstHeight,
  143. VkFormat dstFormat,
  144. Rectangle<int> scissor)
  145. {
  146. const int ClearColorBufferSize = 16;
  147. gd.FlushAllCommands();
  148. using var cbs = gd.CommandBufferPool.Rent();
  149. _pipeline.SetCommandBuffer(cbs);
  150. var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize, false);
  151. gd.BufferManager.SetData<float>(bufferHandle, 0, clearColor);
  152. Span<BufferRange> bufferRanges = stackalloc BufferRange[1];
  153. bufferRanges[0] = new BufferRange(bufferHandle, 0, ClearColorBufferSize);
  154. _pipeline.SetUniformBuffers(1, bufferRanges);
  155. Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
  156. viewports[0] = new GAL.Viewport(
  157. new Rectangle<float>(0, 0, dstWidth, dstHeight),
  158. ViewportSwizzle.PositiveX,
  159. ViewportSwizzle.PositiveY,
  160. ViewportSwizzle.PositiveZ,
  161. ViewportSwizzle.PositiveW,
  162. 0f,
  163. 1f);
  164. Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
  165. scissors[0] = scissor;
  166. _pipeline.SetProgram(_programColorClear);
  167. _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
  168. _pipeline.SetRenderTargetColorMasks(new uint[] { componentMask });
  169. _pipeline.SetViewports(viewports, false);
  170. _pipeline.SetScissors(scissors);
  171. _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
  172. _pipeline.Draw(4, 1, 0, 0);
  173. _pipeline.Finish();
  174. gd.BufferManager.Delete(bufferHandle);
  175. }
  176. public void DrawTexture(
  177. VulkanRenderer gd,
  178. PipelineBase pipeline,
  179. TextureView src,
  180. ISampler srcSampler,
  181. Extents2DF srcRegion,
  182. Extents2DF dstRegion)
  183. {
  184. const int RegionBufferSize = 16;
  185. pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, srcSampler);
  186. Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
  187. region[0] = srcRegion.X1 / src.Width;
  188. region[1] = srcRegion.X2 / src.Width;
  189. region[2] = srcRegion.Y1 / src.Height;
  190. region[3] = srcRegion.Y2 / src.Height;
  191. if (dstRegion.X1 > dstRegion.X2)
  192. {
  193. (region[0], region[1]) = (region[1], region[0]);
  194. }
  195. if (dstRegion.Y1 > dstRegion.Y2)
  196. {
  197. (region[2], region[3]) = (region[3], region[2]);
  198. }
  199. var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize, false);
  200. gd.BufferManager.SetData<float>(bufferHandle, 0, region);
  201. Span<BufferRange> bufferRanges = stackalloc BufferRange[1];
  202. bufferRanges[0] = new BufferRange(bufferHandle, 0, RegionBufferSize);
  203. pipeline.SetUniformBuffers(1, bufferRanges);
  204. Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
  205. var rect = new Rectangle<float>(
  206. MathF.Min(dstRegion.X1, dstRegion.X2),
  207. MathF.Min(dstRegion.Y1, dstRegion.Y2),
  208. MathF.Abs(dstRegion.X2 - dstRegion.X1),
  209. MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
  210. viewports[0] = new GAL.Viewport(
  211. rect,
  212. ViewportSwizzle.PositiveX,
  213. ViewportSwizzle.PositiveY,
  214. ViewportSwizzle.PositiveZ,
  215. ViewportSwizzle.PositiveW,
  216. 0f,
  217. 1f);
  218. Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
  219. pipeline.SetProgram(_programColorBlit);
  220. pipeline.SetViewports(viewports, false);
  221. pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
  222. pipeline.Draw(4, 1, 0, 0);
  223. gd.BufferManager.Delete(bufferHandle);
  224. }
  225. public unsafe void ConvertI8ToI16(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
  226. {
  227. // TODO: Do this with a compute shader?
  228. var srcBuffer = src.GetBuffer().Get(cbs, srcOffset, size).Value;
  229. var dstBuffer = dst.GetBuffer().Get(cbs, 0, size * 2).Value;
  230. gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0);
  231. var bufferCopy = new BufferCopy[size];
  232. for (ulong i = 0; i < (ulong)size; i++)
  233. {
  234. bufferCopy[i] = new BufferCopy((ulong)srcOffset + i, i * 2, 1);
  235. }
  236. BufferHolder.InsertBufferBarrier(
  237. gd,
  238. cbs.CommandBuffer,
  239. dstBuffer,
  240. BufferHolder.DefaultAccessFlags,
  241. AccessFlags.AccessTransferWriteBit,
  242. PipelineStageFlags.PipelineStageAllCommandsBit,
  243. PipelineStageFlags.PipelineStageTransferBit,
  244. 0,
  245. size * 2);
  246. fixed (BufferCopy* pBufferCopy = bufferCopy)
  247. {
  248. gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)size, pBufferCopy);
  249. }
  250. BufferHolder.InsertBufferBarrier(
  251. gd,
  252. cbs.CommandBuffer,
  253. dstBuffer,
  254. AccessFlags.AccessTransferWriteBit,
  255. BufferHolder.DefaultAccessFlags,
  256. PipelineStageFlags.PipelineStageTransferBit,
  257. PipelineStageFlags.PipelineStageAllCommandsBit,
  258. 0,
  259. size * 2);
  260. }
  261. protected virtual void Dispose(bool disposing)
  262. {
  263. if (disposing)
  264. {
  265. _programColorBlitClearAlpha.Dispose();
  266. _programColorBlit.Dispose();
  267. _samplerNearest.Dispose();
  268. _samplerLinear.Dispose();
  269. _pipeline.Dispose();
  270. }
  271. }
  272. public void Dispose()
  273. {
  274. Dispose(true);
  275. }
  276. }
  277. }