TextureCopy.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. using Ryujinx.Common;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Graphics.GAL;
  4. using SharpMetal.Metal;
  5. using System;
  6. using System.Runtime.Versioning;
  7. namespace Ryujinx.Graphics.Metal
  8. {
  9. [SupportedOSPlatform("macos")]
  10. static class TextureCopy
  11. {
  12. public static ulong CopyFromOrToBuffer(
  13. CommandBufferScoped cbs,
  14. MTLBuffer buffer,
  15. MTLTexture image,
  16. TextureCreateInfo info,
  17. bool to,
  18. int dstLayer,
  19. int dstLevel,
  20. int x,
  21. int y,
  22. int width,
  23. int height,
  24. ulong offset = 0)
  25. {
  26. MTLBlitCommandEncoder blitCommandEncoder = cbs.Encoders.EnsureBlitEncoder();
  27. bool is3D = info.Target == Target.Texture3D;
  28. int blockWidth = BitUtils.DivRoundUp(width, info.BlockWidth);
  29. int blockHeight = BitUtils.DivRoundUp(height, info.BlockHeight);
  30. ulong bytesPerRow = (ulong)BitUtils.AlignUp(blockWidth * info.BytesPerPixel, 4);
  31. ulong bytesPerImage = bytesPerRow * (ulong)blockHeight;
  32. MTLOrigin origin = new MTLOrigin { x = (ulong)x, y = (ulong)y, z = is3D ? (ulong)dstLayer : 0 };
  33. MTLSize region = new MTLSize { width = (ulong)width, height = (ulong)height, depth = 1 };
  34. uint layer = is3D ? 0 : (uint)dstLayer;
  35. if (to)
  36. {
  37. blitCommandEncoder.CopyFromTexture(
  38. image,
  39. layer,
  40. (ulong)dstLevel,
  41. origin,
  42. region,
  43. buffer,
  44. offset,
  45. bytesPerRow,
  46. bytesPerImage);
  47. }
  48. else
  49. {
  50. blitCommandEncoder.CopyFromBuffer(buffer, offset, bytesPerRow, bytesPerImage, region, image, layer, (ulong)dstLevel, origin);
  51. }
  52. return offset + bytesPerImage;
  53. }
  54. public static void Copy(
  55. CommandBufferScoped cbs,
  56. MTLTexture srcImage,
  57. MTLTexture dstImage,
  58. TextureCreateInfo srcInfo,
  59. TextureCreateInfo dstInfo,
  60. int srcLayer,
  61. int dstLayer,
  62. int srcLevel,
  63. int dstLevel)
  64. {
  65. int srcDepth = srcInfo.GetDepthOrLayers();
  66. int srcLevels = srcInfo.Levels;
  67. int dstDepth = dstInfo.GetDepthOrLayers();
  68. int dstLevels = dstInfo.Levels;
  69. if (dstInfo.Target == Target.Texture3D)
  70. {
  71. dstDepth = Math.Max(1, dstDepth >> dstLevel);
  72. }
  73. int depth = Math.Min(srcDepth, dstDepth);
  74. int levels = Math.Min(srcLevels, dstLevels);
  75. Copy(
  76. cbs,
  77. srcImage,
  78. dstImage,
  79. srcInfo,
  80. dstInfo,
  81. srcLayer,
  82. dstLayer,
  83. srcLevel,
  84. dstLevel,
  85. depth,
  86. levels);
  87. }
  88. public static void Copy(
  89. CommandBufferScoped cbs,
  90. MTLTexture srcImage,
  91. MTLTexture dstImage,
  92. TextureCreateInfo srcInfo,
  93. TextureCreateInfo dstInfo,
  94. int srcDepthOrLayer,
  95. int dstDepthOrLayer,
  96. int srcLevel,
  97. int dstLevel,
  98. int depthOrLayers,
  99. int levels)
  100. {
  101. MTLBlitCommandEncoder blitCommandEncoder = cbs.Encoders.EnsureBlitEncoder();
  102. int srcZ;
  103. int srcLayer;
  104. int srcDepth;
  105. int srcLayers;
  106. if (srcInfo.Target == Target.Texture3D)
  107. {
  108. srcZ = srcDepthOrLayer;
  109. srcLayer = 0;
  110. srcDepth = depthOrLayers;
  111. srcLayers = 1;
  112. }
  113. else
  114. {
  115. srcZ = 0;
  116. srcLayer = srcDepthOrLayer;
  117. srcDepth = 1;
  118. srcLayers = depthOrLayers;
  119. }
  120. int dstZ;
  121. int dstLayer;
  122. int dstLayers;
  123. if (dstInfo.Target == Target.Texture3D)
  124. {
  125. dstZ = dstDepthOrLayer;
  126. dstLayer = 0;
  127. dstLayers = 1;
  128. }
  129. else
  130. {
  131. dstZ = 0;
  132. dstLayer = dstDepthOrLayer;
  133. dstLayers = depthOrLayers;
  134. }
  135. int srcWidth = srcInfo.Width;
  136. int srcHeight = srcInfo.Height;
  137. int dstWidth = dstInfo.Width;
  138. int dstHeight = dstInfo.Height;
  139. srcWidth = Math.Max(1, srcWidth >> srcLevel);
  140. srcHeight = Math.Max(1, srcHeight >> srcLevel);
  141. dstWidth = Math.Max(1, dstWidth >> dstLevel);
  142. dstHeight = Math.Max(1, dstHeight >> dstLevel);
  143. int blockWidth = 1;
  144. int blockHeight = 1;
  145. bool sizeInBlocks = false;
  146. MTLBuffer tempBuffer = default;
  147. if (srcInfo.Format != dstInfo.Format && (srcInfo.IsCompressed || dstInfo.IsCompressed))
  148. {
  149. // Compressed alias copies need to happen through a temporary buffer.
  150. // The data is copied from the source to the buffer, then the buffer to the destination.
  151. // The length of the buffer should be the maximum slice size for the destination.
  152. tempBuffer = blitCommandEncoder.Device.NewBuffer((ulong)dstInfo.GetMipSize2D(0), MTLResourceOptions.ResourceStorageModePrivate);
  153. }
  154. // When copying from a compressed to a non-compressed format,
  155. // the non-compressed texture will have the size of the texture
  156. // in blocks (not in texels), so we must adjust that size to
  157. // match the size in texels of the compressed texture.
  158. if (!srcInfo.IsCompressed && dstInfo.IsCompressed)
  159. {
  160. srcWidth *= dstInfo.BlockWidth;
  161. srcHeight *= dstInfo.BlockHeight;
  162. blockWidth = dstInfo.BlockWidth;
  163. blockHeight = dstInfo.BlockHeight;
  164. sizeInBlocks = true;
  165. }
  166. else if (srcInfo.IsCompressed && !dstInfo.IsCompressed)
  167. {
  168. dstWidth *= srcInfo.BlockWidth;
  169. dstHeight *= srcInfo.BlockHeight;
  170. blockWidth = srcInfo.BlockWidth;
  171. blockHeight = srcInfo.BlockHeight;
  172. }
  173. int width = Math.Min(srcWidth, dstWidth);
  174. int height = Math.Min(srcHeight, dstHeight);
  175. for (int level = 0; level < levels; level++)
  176. {
  177. // Stop copy if we are already out of the levels range.
  178. if (level >= srcInfo.Levels || dstLevel + level >= dstInfo.Levels)
  179. {
  180. break;
  181. }
  182. int copyWidth = sizeInBlocks ? BitUtils.DivRoundUp(width, blockWidth) : width;
  183. int copyHeight = sizeInBlocks ? BitUtils.DivRoundUp(height, blockHeight) : height;
  184. int layers = Math.Max(dstLayers - dstLayer, srcLayers);
  185. for (int layer = 0; layer < layers; layer++)
  186. {
  187. if (tempBuffer.NativePtr != 0)
  188. {
  189. // Copy through the temp buffer
  190. CopyFromOrToBuffer(cbs, tempBuffer, srcImage, srcInfo, true, srcLayer + layer, srcLevel + level, 0, 0, copyWidth, copyHeight);
  191. int dstBufferWidth = sizeInBlocks ? copyWidth * blockWidth : BitUtils.DivRoundUp(copyWidth, blockWidth);
  192. int dstBufferHeight = sizeInBlocks ? copyHeight * blockHeight : BitUtils.DivRoundUp(copyHeight, blockHeight);
  193. CopyFromOrToBuffer(cbs, tempBuffer, dstImage, dstInfo, false, dstLayer + layer, dstLevel + level, 0, 0, dstBufferWidth, dstBufferHeight);
  194. }
  195. else if (srcInfo.Samples > 1 && srcInfo.Samples != dstInfo.Samples)
  196. {
  197. // TODO
  198. Logger.Warning?.PrintMsg(LogClass.Gpu, "Unsupported mismatching sample count copy");
  199. }
  200. else
  201. {
  202. blitCommandEncoder.CopyFromTexture(
  203. srcImage,
  204. (ulong)(srcLayer + layer),
  205. (ulong)(srcLevel + level),
  206. new MTLOrigin { z = (ulong)srcZ },
  207. new MTLSize { width = (ulong)copyWidth, height = (ulong)copyHeight, depth = (ulong)srcDepth },
  208. dstImage,
  209. (ulong)(dstLayer + layer),
  210. (ulong)(dstLevel + level),
  211. new MTLOrigin { z = (ulong)dstZ });
  212. }
  213. }
  214. width = Math.Max(1, width >> 1);
  215. height = Math.Max(1, height >> 1);
  216. if (srcInfo.Target == Target.Texture3D)
  217. {
  218. srcDepth = Math.Max(1, srcDepth >> 1);
  219. }
  220. }
  221. if (tempBuffer.NativePtr != 0)
  222. {
  223. tempBuffer.Dispose();
  224. }
  225. }
  226. }
  227. }