TextureCopy.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. using Ryujinx.Common;
  2. using Ryujinx.Graphics.GAL;
  3. using Silk.NET.Vulkan;
  4. using System;
  5. using System.Numerics;
  6. namespace Ryujinx.Graphics.Vulkan
  7. {
  8. static class TextureCopy
  9. {
  10. public static void Blit(
  11. Vk api,
  12. CommandBuffer commandBuffer,
  13. Image srcImage,
  14. Image dstImage,
  15. TextureCreateInfo srcInfo,
  16. TextureCreateInfo dstInfo,
  17. Extents2D srcRegion,
  18. Extents2D dstRegion,
  19. int srcLayer,
  20. int dstLayer,
  21. int srcLevel,
  22. int dstLevel,
  23. int layers,
  24. int levels,
  25. bool linearFilter,
  26. ImageAspectFlags srcAspectFlags = 0,
  27. ImageAspectFlags dstAspectFlags = 0)
  28. {
  29. static (Offset3D, Offset3D) ExtentsToOffset3D(Extents2D extents, int width, int height, int level)
  30. {
  31. static int Clamp(int value, int max)
  32. {
  33. return Math.Clamp(value, 0, max);
  34. }
  35. var xy1 = new Offset3D(Clamp(extents.X1, width) >> level, Clamp(extents.Y1, height) >> level, 0);
  36. var xy2 = new Offset3D(Clamp(extents.X2, width) >> level, Clamp(extents.Y2, height) >> level, 1);
  37. return (xy1, xy2);
  38. }
  39. if (srcAspectFlags == 0)
  40. {
  41. srcAspectFlags = srcInfo.Format.ConvertAspectFlags();
  42. }
  43. if (dstAspectFlags == 0)
  44. {
  45. dstAspectFlags = dstInfo.Format.ConvertAspectFlags();
  46. }
  47. var srcOffsets = new ImageBlit.SrcOffsetsBuffer();
  48. var dstOffsets = new ImageBlit.DstOffsetsBuffer();
  49. var filter = linearFilter && !dstInfo.Format.IsDepthOrStencil() ? Filter.Linear : Filter.Nearest;
  50. TextureView.InsertImageBarrier(
  51. api,
  52. commandBuffer,
  53. srcImage,
  54. TextureStorage.DefaultAccessMask,
  55. AccessFlags.TransferReadBit,
  56. PipelineStageFlags.AllCommandsBit,
  57. PipelineStageFlags.TransferBit,
  58. srcAspectFlags,
  59. srcLayer,
  60. srcLevel,
  61. layers,
  62. levels);
  63. uint copySrcLevel = (uint)srcLevel;
  64. uint copyDstLevel = (uint)dstLevel;
  65. for (int level = 0; level < levels; level++)
  66. {
  67. var srcSl = new ImageSubresourceLayers(srcAspectFlags, copySrcLevel, (uint)srcLayer, (uint)layers);
  68. var dstSl = new ImageSubresourceLayers(dstAspectFlags, copyDstLevel, (uint)dstLayer, (uint)layers);
  69. (srcOffsets.Element0, srcOffsets.Element1) = ExtentsToOffset3D(srcRegion, srcInfo.Width, srcInfo.Height, level);
  70. (dstOffsets.Element0, dstOffsets.Element1) = ExtentsToOffset3D(dstRegion, dstInfo.Width, dstInfo.Height, level);
  71. var region = new ImageBlit()
  72. {
  73. SrcSubresource = srcSl,
  74. SrcOffsets = srcOffsets,
  75. DstSubresource = dstSl,
  76. DstOffsets = dstOffsets
  77. };
  78. api.CmdBlitImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region, filter);
  79. copySrcLevel++;
  80. copyDstLevel++;
  81. if (srcInfo.Target == Target.Texture3D || dstInfo.Target == Target.Texture3D)
  82. {
  83. layers = Math.Max(1, layers >> 1);
  84. }
  85. }
  86. TextureView.InsertImageBarrier(
  87. api,
  88. commandBuffer,
  89. dstImage,
  90. AccessFlags.TransferWriteBit,
  91. TextureStorage.DefaultAccessMask,
  92. PipelineStageFlags.TransferBit,
  93. PipelineStageFlags.AllCommandsBit,
  94. dstAspectFlags,
  95. dstLayer,
  96. dstLevel,
  97. layers,
  98. levels);
  99. }
  100. public static void Copy(
  101. Vk api,
  102. CommandBuffer commandBuffer,
  103. Image srcImage,
  104. Image dstImage,
  105. TextureCreateInfo srcInfo,
  106. TextureCreateInfo dstInfo,
  107. int srcViewLayer,
  108. int dstViewLayer,
  109. int srcViewLevel,
  110. int dstViewLevel,
  111. int srcLayer,
  112. int dstLayer,
  113. int srcLevel,
  114. int dstLevel)
  115. {
  116. int srcDepth = srcInfo.GetDepthOrLayers();
  117. int srcLevels = srcInfo.Levels;
  118. int dstDepth = dstInfo.GetDepthOrLayers();
  119. int dstLevels = dstInfo.Levels;
  120. if (dstInfo.Target == Target.Texture3D)
  121. {
  122. dstDepth = Math.Max(1, dstDepth >> dstLevel);
  123. }
  124. int depth = Math.Min(srcDepth, dstDepth);
  125. int levels = Math.Min(srcLevels, dstLevels);
  126. Copy(
  127. api,
  128. commandBuffer,
  129. srcImage,
  130. dstImage,
  131. srcInfo,
  132. dstInfo,
  133. srcViewLayer,
  134. dstViewLayer,
  135. srcViewLevel,
  136. dstViewLevel,
  137. srcLayer,
  138. dstLayer,
  139. srcLevel,
  140. dstLevel,
  141. depth,
  142. levels);
  143. }
  144. private static int ClampLevels(TextureCreateInfo info, int levels)
  145. {
  146. int width = info.Width;
  147. int height = info.Height;
  148. int depth = info.Target == Target.Texture3D ? info.Depth : 1;
  149. int maxLevels = 1 + BitOperations.Log2((uint)Math.Max(Math.Max(width, height), depth));
  150. if (levels > maxLevels)
  151. {
  152. levels = maxLevels;
  153. }
  154. return levels;
  155. }
  156. public static void Copy(
  157. Vk api,
  158. CommandBuffer commandBuffer,
  159. Image srcImage,
  160. Image dstImage,
  161. TextureCreateInfo srcInfo,
  162. TextureCreateInfo dstInfo,
  163. int srcViewLayer,
  164. int dstViewLayer,
  165. int srcViewLevel,
  166. int dstViewLevel,
  167. int srcDepthOrLayer,
  168. int dstDepthOrLayer,
  169. int srcLevel,
  170. int dstLevel,
  171. int depthOrLayers,
  172. int levels)
  173. {
  174. int srcZ;
  175. int srcLayer;
  176. int srcDepth;
  177. int srcLayers;
  178. if (srcInfo.Target == Target.Texture3D)
  179. {
  180. srcZ = srcDepthOrLayer;
  181. srcLayer = 0;
  182. srcDepth = depthOrLayers;
  183. srcLayers = 1;
  184. }
  185. else
  186. {
  187. srcZ = 0;
  188. srcLayer = srcDepthOrLayer;
  189. srcDepth = 1;
  190. srcLayers = depthOrLayers;
  191. }
  192. int dstZ;
  193. int dstLayer;
  194. int dstDepth;
  195. int dstLayers;
  196. if (dstInfo.Target == Target.Texture3D)
  197. {
  198. dstZ = dstDepthOrLayer;
  199. dstLayer = 0;
  200. dstDepth = depthOrLayers;
  201. dstLayers = 1;
  202. }
  203. else
  204. {
  205. dstZ = 0;
  206. dstLayer = dstDepthOrLayer;
  207. dstDepth = 1;
  208. dstLayers = depthOrLayers;
  209. }
  210. int srcWidth = srcInfo.Width;
  211. int srcHeight = srcInfo.Height;
  212. int dstWidth = dstInfo.Width;
  213. int dstHeight = dstInfo.Height;
  214. srcWidth = Math.Max(1, srcWidth >> srcLevel);
  215. srcHeight = Math.Max(1, srcHeight >> srcLevel);
  216. dstWidth = Math.Max(1, dstWidth >> dstLevel);
  217. dstHeight = Math.Max(1, dstHeight >> dstLevel);
  218. int blockWidth = 1;
  219. int blockHeight = 1;
  220. bool sizeInBlocks = false;
  221. // When copying from a compressed to a non-compressed format,
  222. // the non-compressed texture will have the size of the texture
  223. // in blocks (not in texels), so we must adjust that size to
  224. // match the size in texels of the compressed texture.
  225. if (!srcInfo.IsCompressed && dstInfo.IsCompressed)
  226. {
  227. srcWidth *= dstInfo.BlockWidth;
  228. srcHeight *= dstInfo.BlockHeight;
  229. blockWidth = dstInfo.BlockWidth;
  230. blockHeight = dstInfo.BlockHeight;
  231. sizeInBlocks = true;
  232. }
  233. else if (srcInfo.IsCompressed && !dstInfo.IsCompressed)
  234. {
  235. dstWidth *= srcInfo.BlockWidth;
  236. dstHeight *= srcInfo.BlockHeight;
  237. blockWidth = srcInfo.BlockWidth;
  238. blockHeight = srcInfo.BlockHeight;
  239. }
  240. int width = Math.Min(srcWidth, dstWidth);
  241. int height = Math.Min(srcHeight, dstHeight);
  242. ImageAspectFlags srcAspect = srcInfo.Format.ConvertAspectFlags();
  243. ImageAspectFlags dstAspect = dstInfo.Format.ConvertAspectFlags();
  244. TextureView.InsertImageBarrier(
  245. api,
  246. commandBuffer,
  247. srcImage,
  248. TextureStorage.DefaultAccessMask,
  249. AccessFlags.TransferReadBit,
  250. PipelineStageFlags.AllCommandsBit,
  251. PipelineStageFlags.TransferBit,
  252. srcAspect,
  253. srcViewLayer + srcLayer,
  254. srcViewLevel + srcLevel,
  255. srcLayers,
  256. levels);
  257. for (int level = 0; level < levels; level++)
  258. {
  259. // Stop copy if we are already out of the levels range.
  260. if (level >= srcInfo.Levels || dstLevel + level >= dstInfo.Levels)
  261. {
  262. break;
  263. }
  264. var srcSl = new ImageSubresourceLayers(
  265. srcAspect,
  266. (uint)(srcViewLevel + srcLevel + level),
  267. (uint)(srcViewLayer + srcLayer),
  268. (uint)srcLayers);
  269. var dstSl = new ImageSubresourceLayers(
  270. dstAspect,
  271. (uint)(dstViewLevel + dstLevel + level),
  272. (uint)(dstViewLayer + dstLayer),
  273. (uint)dstLayers);
  274. int copyWidth = sizeInBlocks ? BitUtils.DivRoundUp(width, blockWidth) : width;
  275. int copyHeight = sizeInBlocks ? BitUtils.DivRoundUp(height, blockHeight) : height;
  276. var extent = new Extent3D((uint)copyWidth, (uint)copyHeight, (uint)srcDepth);
  277. if (srcInfo.Samples > 1 && srcInfo.Samples != dstInfo.Samples)
  278. {
  279. var region = new ImageResolve(srcSl, new Offset3D(0, 0, srcZ), dstSl, new Offset3D(0, 0, dstZ), extent);
  280. api.CmdResolveImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region);
  281. }
  282. else
  283. {
  284. var region = new ImageCopy(srcSl, new Offset3D(0, 0, srcZ), dstSl, new Offset3D(0, 0, dstZ), extent);
  285. api.CmdCopyImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region);
  286. }
  287. width = Math.Max(1, width >> 1);
  288. height = Math.Max(1, height >> 1);
  289. if (srcInfo.Target == Target.Texture3D)
  290. {
  291. srcDepth = Math.Max(1, srcDepth >> 1);
  292. }
  293. }
  294. TextureView.InsertImageBarrier(
  295. api,
  296. commandBuffer,
  297. dstImage,
  298. AccessFlags.TransferWriteBit,
  299. TextureStorage.DefaultAccessMask,
  300. PipelineStageFlags.TransferBit,
  301. PipelineStageFlags.AllCommandsBit,
  302. dstAspect,
  303. dstViewLayer + dstLayer,
  304. dstViewLevel + dstLevel,
  305. dstLayers,
  306. levels);
  307. }
  308. public unsafe static void ResolveDepthStencil(
  309. VulkanRenderer gd,
  310. Device device,
  311. CommandBufferScoped cbs,
  312. TextureView src,
  313. TextureView dst)
  314. {
  315. var dsAttachmentReference = new AttachmentReference2(StructureType.AttachmentReference2, null, 0, ImageLayout.General);
  316. var dsResolveAttachmentReference = new AttachmentReference2(StructureType.AttachmentReference2, null, 1, ImageLayout.General);
  317. var subpassDsResolve = new SubpassDescriptionDepthStencilResolve()
  318. {
  319. SType = StructureType.SubpassDescriptionDepthStencilResolve,
  320. PDepthStencilResolveAttachment = &dsResolveAttachmentReference,
  321. DepthResolveMode = ResolveModeFlags.SampleZeroBit,
  322. StencilResolveMode = ResolveModeFlags.SampleZeroBit
  323. };
  324. var subpass = new SubpassDescription2()
  325. {
  326. SType = StructureType.SubpassDescription2,
  327. PipelineBindPoint = PipelineBindPoint.Graphics,
  328. PDepthStencilAttachment = &dsAttachmentReference,
  329. PNext = &subpassDsResolve
  330. };
  331. AttachmentDescription2[] attachmentDescs = new AttachmentDescription2[2];
  332. attachmentDescs[0] = new AttachmentDescription2(
  333. StructureType.AttachmentDescription2,
  334. null,
  335. 0,
  336. src.VkFormat,
  337. TextureStorage.ConvertToSampleCountFlags((uint)src.Info.Samples),
  338. AttachmentLoadOp.Load,
  339. AttachmentStoreOp.Store,
  340. AttachmentLoadOp.Load,
  341. AttachmentStoreOp.Store,
  342. ImageLayout.General,
  343. ImageLayout.General);
  344. attachmentDescs[1] = new AttachmentDescription2(
  345. StructureType.AttachmentDescription2,
  346. null,
  347. 0,
  348. dst.VkFormat,
  349. TextureStorage.ConvertToSampleCountFlags((uint)dst.Info.Samples),
  350. AttachmentLoadOp.Load,
  351. AttachmentStoreOp.Store,
  352. AttachmentLoadOp.Load,
  353. AttachmentStoreOp.Store,
  354. ImageLayout.General,
  355. ImageLayout.General);
  356. var subpassDependency = PipelineConverter.CreateSubpassDependency2();
  357. fixed (AttachmentDescription2* pAttachmentDescs = attachmentDescs)
  358. {
  359. var renderPassCreateInfo = new RenderPassCreateInfo2()
  360. {
  361. SType = StructureType.RenderPassCreateInfo2,
  362. PAttachments = pAttachmentDescs,
  363. AttachmentCount = (uint)attachmentDescs.Length,
  364. PSubpasses = &subpass,
  365. SubpassCount = 1,
  366. PDependencies = &subpassDependency,
  367. DependencyCount = 1
  368. };
  369. gd.Api.CreateRenderPass2(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError();
  370. using var rp = new Auto<DisposableRenderPass>(new DisposableRenderPass(gd.Api, device, renderPass));
  371. ImageView* attachments = stackalloc ImageView[2];
  372. var srcView = src.GetImageViewForAttachment();
  373. var dstView = dst.GetImageViewForAttachment();
  374. attachments[0] = srcView.Get(cbs).Value;
  375. attachments[1] = dstView.Get(cbs).Value;
  376. var framebufferCreateInfo = new FramebufferCreateInfo()
  377. {
  378. SType = StructureType.FramebufferCreateInfo,
  379. RenderPass = rp.Get(cbs).Value,
  380. AttachmentCount = 2,
  381. PAttachments = attachments,
  382. Width = (uint)src.Width,
  383. Height = (uint)src.Height,
  384. Layers = (uint)src.Layers
  385. };
  386. gd.Api.CreateFramebuffer(device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
  387. using var fb = new Auto<DisposableFramebuffer>(new DisposableFramebuffer(gd.Api, device, framebuffer), null, new[] { srcView, dstView });
  388. var renderArea = new Rect2D(null, new Extent2D((uint)src.Info.Width, (uint)src.Info.Height));
  389. var clearValue = new ClearValue();
  390. var renderPassBeginInfo = new RenderPassBeginInfo()
  391. {
  392. SType = StructureType.RenderPassBeginInfo,
  393. RenderPass = rp.Get(cbs).Value,
  394. Framebuffer = fb.Get(cbs).Value,
  395. RenderArea = renderArea,
  396. PClearValues = &clearValue,
  397. ClearValueCount = 1
  398. };
  399. // The resolve operation happens at the end of the subpass, so let's just do a begin/end
  400. // to resolve the depth-stencil texture.
  401. // TODO: Do speculative resolve and part of the same render pass as the draw to avoid
  402. // ending the current render pass?
  403. gd.Api.CmdBeginRenderPass(cbs.CommandBuffer, renderPassBeginInfo, SubpassContents.Inline);
  404. gd.Api.CmdEndRenderPass(cbs.CommandBuffer);
  405. }
  406. }
  407. }
  408. }