Texture.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Common.Memory;
  3. using Ryujinx.Graphics.GAL;
  4. using SharpMetal.Foundation;
  5. using SharpMetal.Metal;
  6. using System;
  7. using System.Runtime.Versioning;
  8. namespace Ryujinx.Graphics.Metal
  9. {
  10. [SupportedOSPlatform("macos")]
  11. class Texture : TextureBase, ITexture
  12. {
  13. private MTLTexture _identitySwizzleHandle;
  14. private readonly bool _identityIsDifferent;
  15. public Texture(MTLDevice device, MetalRenderer renderer, Pipeline pipeline, TextureCreateInfo info) : base(device, renderer, pipeline, info)
  16. {
  17. MTLPixelFormat pixelFormat = FormatTable.GetFormat(Info.Format);
  18. MTLTextureDescriptor descriptor = new()
  19. {
  20. PixelFormat = pixelFormat,
  21. Usage = MTLTextureUsage.Unknown,
  22. SampleCount = (ulong)Info.Samples,
  23. TextureType = Info.Target.Convert(),
  24. Width = (ulong)Info.Width,
  25. Height = (ulong)Info.Height,
  26. MipmapLevelCount = (ulong)Info.Levels
  27. };
  28. if (info.Target == Target.Texture3D)
  29. {
  30. descriptor.Depth = (ulong)Info.Depth;
  31. }
  32. else if (info.Target != Target.Cubemap)
  33. {
  34. if (info.Target == Target.CubemapArray)
  35. {
  36. descriptor.ArrayLength = (ulong)(Info.Depth / 6);
  37. }
  38. else
  39. {
  40. descriptor.ArrayLength = (ulong)Info.Depth;
  41. }
  42. }
  43. MTLTextureSwizzleChannels swizzle = GetSwizzle(info, descriptor.PixelFormat);
  44. _identitySwizzleHandle = Device.NewTexture(descriptor);
  45. if (SwizzleIsIdentity(swizzle))
  46. {
  47. MtlTexture = _identitySwizzleHandle;
  48. }
  49. else
  50. {
  51. MtlTexture = CreateDefaultView(_identitySwizzleHandle, swizzle, descriptor);
  52. _identityIsDifferent = true;
  53. }
  54. MtlFormat = pixelFormat;
  55. descriptor.Dispose();
  56. }
  57. public Texture(MTLDevice device, MetalRenderer renderer, Pipeline pipeline, TextureCreateInfo info, MTLTexture sourceTexture, int firstLayer, int firstLevel) : base(device, renderer, pipeline, info)
  58. {
  59. MTLPixelFormat pixelFormat = FormatTable.GetFormat(Info.Format);
  60. if (info.DepthStencilMode == DepthStencilMode.Stencil)
  61. {
  62. pixelFormat = pixelFormat switch
  63. {
  64. MTLPixelFormat.Depth32FloatStencil8 => MTLPixelFormat.X32Stencil8,
  65. MTLPixelFormat.Depth24UnormStencil8 => MTLPixelFormat.X24Stencil8,
  66. _ => pixelFormat
  67. };
  68. }
  69. MTLTextureType textureType = Info.Target.Convert();
  70. NSRange levels;
  71. levels.location = (ulong)firstLevel;
  72. levels.length = (ulong)Info.Levels;
  73. NSRange slices;
  74. slices.location = (ulong)firstLayer;
  75. slices.length = textureType == MTLTextureType.Type3D ? 1 : (ulong)info.GetDepthOrLayers();
  76. MTLTextureSwizzleChannels swizzle = GetSwizzle(info, pixelFormat);
  77. _identitySwizzleHandle = sourceTexture.NewTextureView(pixelFormat, textureType, levels, slices);
  78. if (SwizzleIsIdentity(swizzle))
  79. {
  80. MtlTexture = _identitySwizzleHandle;
  81. }
  82. else
  83. {
  84. MtlTexture = sourceTexture.NewTextureView(pixelFormat, textureType, levels, slices, swizzle);
  85. _identityIsDifferent = true;
  86. }
  87. MtlFormat = pixelFormat;
  88. FirstLayer = firstLayer;
  89. FirstLevel = firstLevel;
  90. }
  91. public void PopulateRenderPassAttachment(MTLRenderPassColorAttachmentDescriptor descriptor)
  92. {
  93. descriptor.Texture = _identitySwizzleHandle;
  94. }
  95. private MTLTexture CreateDefaultView(MTLTexture texture, MTLTextureSwizzleChannels swizzle, MTLTextureDescriptor descriptor)
  96. {
  97. NSRange levels;
  98. levels.location = 0;
  99. levels.length = (ulong)Info.Levels;
  100. NSRange slices;
  101. slices.location = 0;
  102. slices.length = Info.Target == Target.Texture3D ? 1 : (ulong)Info.GetDepthOrLayers();
  103. return texture.NewTextureView(descriptor.PixelFormat, descriptor.TextureType, levels, slices, swizzle);
  104. }
  105. private bool SwizzleIsIdentity(MTLTextureSwizzleChannels swizzle)
  106. {
  107. return swizzle.red == MTLTextureSwizzle.Red &&
  108. swizzle.green == MTLTextureSwizzle.Green &&
  109. swizzle.blue == MTLTextureSwizzle.Blue &&
  110. swizzle.alpha == MTLTextureSwizzle.Alpha;
  111. }
  112. private MTLTextureSwizzleChannels GetSwizzle(TextureCreateInfo info, MTLPixelFormat pixelFormat)
  113. {
  114. MTLTextureSwizzle swizzleR = Info.SwizzleR.Convert();
  115. MTLTextureSwizzle swizzleG = Info.SwizzleG.Convert();
  116. MTLTextureSwizzle swizzleB = Info.SwizzleB.Convert();
  117. MTLTextureSwizzle swizzleA = Info.SwizzleA.Convert();
  118. if (info.Format == Format.R5G5B5A1Unorm ||
  119. info.Format == Format.R5G5B5X1Unorm ||
  120. info.Format == Format.R5G6B5Unorm)
  121. {
  122. (swizzleB, swizzleR) = (swizzleR, swizzleB);
  123. }
  124. else if (pixelFormat == MTLPixelFormat.ABGR4Unorm || info.Format == Format.A1B5G5R5Unorm)
  125. {
  126. MTLTextureSwizzle tempB = swizzleB;
  127. MTLTextureSwizzle tempA = swizzleA;
  128. swizzleB = swizzleG;
  129. swizzleA = swizzleR;
  130. swizzleR = tempA;
  131. swizzleG = tempB;
  132. }
  133. return new MTLTextureSwizzleChannels
  134. {
  135. red = swizzleR,
  136. green = swizzleG,
  137. blue = swizzleB,
  138. alpha = swizzleA
  139. };
  140. }
  141. public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
  142. {
  143. CommandBufferScoped cbs = Pipeline.Cbs;
  144. TextureBase src = this;
  145. TextureBase dst = (TextureBase)destination;
  146. if (!Valid || !dst.Valid)
  147. {
  148. return;
  149. }
  150. MTLTexture srcImage = GetHandle();
  151. MTLTexture dstImage = dst.GetHandle();
  152. if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
  153. {
  154. // int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
  155. // _gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, 0, firstLayer, layers);
  156. }
  157. else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
  158. {
  159. // int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
  160. // _gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, 0, firstLayer, layers);
  161. }
  162. else if (dst.Info.BytesPerPixel != Info.BytesPerPixel)
  163. {
  164. // int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
  165. // int levels = Math.Min(Info.Levels, dst.Info.Levels - firstLevel);
  166. // _gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, 0, firstLayer, 0, firstLevel, layers, levels);
  167. }
  168. else if (src.Info.Format.IsDepthOrStencil() != dst.Info.Format.IsDepthOrStencil())
  169. {
  170. // int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
  171. // int levels = Math.Min(Info.Levels, dst.Info.Levels - firstLevel);
  172. // TODO: depth copy?
  173. // _gd.HelperShader.CopyColor(_gd, cbs, src, dst, 0, firstLayer, 0, FirstLevel, layers, levels);
  174. }
  175. else
  176. {
  177. TextureCopy.Copy(
  178. cbs,
  179. srcImage,
  180. dstImage,
  181. src.Info,
  182. dst.Info,
  183. 0,
  184. firstLayer,
  185. 0,
  186. firstLevel);
  187. }
  188. }
  189. public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
  190. {
  191. CommandBufferScoped cbs = Pipeline.Cbs;
  192. TextureBase src = this;
  193. TextureBase dst = (TextureBase)destination;
  194. if (!Valid || !dst.Valid)
  195. {
  196. return;
  197. }
  198. MTLTexture srcImage = GetHandle();
  199. MTLTexture dstImage = dst.GetHandle();
  200. if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
  201. {
  202. // _gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1);
  203. }
  204. else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
  205. {
  206. // _gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1);
  207. }
  208. else if (dst.Info.BytesPerPixel != Info.BytesPerPixel)
  209. {
  210. // _gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
  211. }
  212. else if (src.Info.Format.IsDepthOrStencil() != dst.Info.Format.IsDepthOrStencil())
  213. {
  214. // _gd.HelperShader.CopyColor(_gd, cbs, src, dst, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
  215. }
  216. else
  217. {
  218. TextureCopy.Copy(
  219. cbs,
  220. srcImage,
  221. dstImage,
  222. src.Info,
  223. dst.Info,
  224. srcLayer,
  225. dstLayer,
  226. srcLevel,
  227. dstLevel,
  228. 1,
  229. 1);
  230. }
  231. }
  232. public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  233. {
  234. if (!Renderer.CommandBufferPool.OwnedByCurrentThread)
  235. {
  236. Logger.Warning?.PrintMsg(LogClass.Gpu, "Metal doesn't currently support scaled blit on background thread.");
  237. return;
  238. }
  239. Texture dst = (Texture)destination;
  240. bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
  241. Pipeline.Blit(this, dst, srcRegion, dstRegion, isDepthOrStencil, linearFilter);
  242. }
  243. public void CopyTo(BufferRange range, int layer, int level, int stride)
  244. {
  245. CommandBufferScoped cbs = Pipeline.Cbs;
  246. int outSize = Info.GetMipSize(level);
  247. int hostSize = GetBufferDataLength(outSize);
  248. int offset = range.Offset;
  249. Auto<DisposableBuffer> autoBuffer = Renderer.BufferManager.GetBuffer(range.Handle, true);
  250. MTLBuffer mtlBuffer = autoBuffer.Get(cbs, range.Offset, outSize).Value;
  251. if (PrepareOutputBuffer(cbs, hostSize, mtlBuffer, out MTLBuffer copyToBuffer, out BufferHolder tempCopyHolder))
  252. {
  253. offset = 0;
  254. }
  255. CopyFromOrToBuffer(cbs, copyToBuffer, MtlTexture, hostSize, true, layer, level, 1, 1, singleSlice: true, offset, stride);
  256. if (tempCopyHolder != null)
  257. {
  258. CopyDataToOutputBuffer(cbs, tempCopyHolder, autoBuffer, hostSize, range.Offset);
  259. tempCopyHolder.Dispose();
  260. }
  261. }
  262. public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
  263. {
  264. return new Texture(Device, Renderer, Pipeline, info, _identitySwizzleHandle, firstLayer, firstLevel);
  265. }
  266. private void CopyDataToBuffer(Span<byte> storage, ReadOnlySpan<byte> input)
  267. {
  268. if (NeedsD24S8Conversion())
  269. {
  270. FormatConverter.ConvertD24S8ToD32FS8(storage, input);
  271. return;
  272. }
  273. input.CopyTo(storage);
  274. }
  275. private ReadOnlySpan<byte> GetDataFromBuffer(ReadOnlySpan<byte> storage, int size, Span<byte> output)
  276. {
  277. if (NeedsD24S8Conversion())
  278. {
  279. if (output.IsEmpty)
  280. {
  281. output = new byte[GetBufferDataLength(size)];
  282. }
  283. FormatConverter.ConvertD32FS8ToD24S8(output, storage);
  284. return output;
  285. }
  286. return storage;
  287. }
  288. private bool PrepareOutputBuffer(CommandBufferScoped cbs, int hostSize, MTLBuffer target, out MTLBuffer copyTarget, out BufferHolder copyTargetHolder)
  289. {
  290. if (NeedsD24S8Conversion())
  291. {
  292. copyTargetHolder = Renderer.BufferManager.Create(hostSize);
  293. copyTarget = copyTargetHolder.GetBuffer().Get(cbs, 0, hostSize).Value;
  294. return true;
  295. }
  296. copyTarget = target;
  297. copyTargetHolder = null;
  298. return false;
  299. }
  300. private void CopyDataToOutputBuffer(CommandBufferScoped cbs, BufferHolder hostData, Auto<DisposableBuffer> copyTarget, int hostSize, int dstOffset)
  301. {
  302. if (NeedsD24S8Conversion())
  303. {
  304. Renderer.HelperShader.ConvertD32S8ToD24S8(cbs, hostData, copyTarget, hostSize / (2 * sizeof(int)), dstOffset);
  305. }
  306. }
  307. private bool NeedsD24S8Conversion()
  308. {
  309. return FormatTable.IsD24S8(Info.Format) && MtlFormat == MTLPixelFormat.Depth32FloatStencil8;
  310. }
  311. public void CopyFromOrToBuffer(
  312. CommandBufferScoped cbs,
  313. MTLBuffer buffer,
  314. MTLTexture image,
  315. int size,
  316. bool to,
  317. int dstLayer,
  318. int dstLevel,
  319. int dstLayers,
  320. int dstLevels,
  321. bool singleSlice,
  322. int offset = 0,
  323. int stride = 0)
  324. {
  325. MTLBlitCommandEncoder blitCommandEncoder = cbs.Encoders.EnsureBlitEncoder();
  326. bool is3D = Info.Target == Target.Texture3D;
  327. int width = Math.Max(1, Info.Width >> dstLevel);
  328. int height = Math.Max(1, Info.Height >> dstLevel);
  329. int depth = is3D && !singleSlice ? Math.Max(1, Info.Depth >> dstLevel) : 1;
  330. int layers = dstLayers;
  331. int levels = dstLevels;
  332. for (int oLevel = 0; oLevel < levels; oLevel++)
  333. {
  334. int level = oLevel + dstLevel;
  335. int mipSize = Info.GetMipSize2D(level);
  336. int mipSizeLevel = GetBufferDataLength(is3D && !singleSlice
  337. ? Info.GetMipSize(level)
  338. : mipSize * dstLayers);
  339. int endOffset = offset + mipSizeLevel;
  340. if ((uint)endOffset > (uint)size)
  341. {
  342. break;
  343. }
  344. for (int oLayer = 0; oLayer < layers; oLayer++)
  345. {
  346. int layer = !is3D ? dstLayer + oLayer : 0;
  347. int z = is3D ? dstLayer + oLayer : 0;
  348. if (to)
  349. {
  350. blitCommandEncoder.CopyFromTexture(
  351. image,
  352. (ulong)layer,
  353. (ulong)level,
  354. new MTLOrigin { z = (ulong)z },
  355. new MTLSize { width = (ulong)width, height = (ulong)height, depth = 1 },
  356. buffer,
  357. (ulong)offset,
  358. (ulong)Info.GetMipStride(level),
  359. (ulong)mipSize
  360. );
  361. }
  362. else
  363. {
  364. blitCommandEncoder.CopyFromBuffer(
  365. buffer,
  366. (ulong)offset,
  367. (ulong)Info.GetMipStride(level),
  368. (ulong)mipSize,
  369. new MTLSize { width = (ulong)width, height = (ulong)height, depth = 1 },
  370. image,
  371. (ulong)(layer + oLayer),
  372. (ulong)level,
  373. new MTLOrigin { z = (ulong)z }
  374. );
  375. }
  376. offset += mipSize;
  377. }
  378. width = Math.Max(1, width >> 1);
  379. height = Math.Max(1, height >> 1);
  380. if (Info.Target == Target.Texture3D)
  381. {
  382. depth = Math.Max(1, depth >> 1);
  383. }
  384. }
  385. }
  386. private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer)
  387. {
  388. int size = 0;
  389. for (int level = 0; level < Info.Levels; level++)
  390. {
  391. size += Info.GetMipSize(level);
  392. }
  393. size = GetBufferDataLength(size);
  394. Span<byte> result = flushBuffer.GetTextureData(cbp, this, size);
  395. return GetDataFromBuffer(result, size, result);
  396. }
  397. private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer, int layer, int level)
  398. {
  399. int size = GetBufferDataLength(Info.GetMipSize(level));
  400. Span<byte> result = flushBuffer.GetTextureData(cbp, this, size, layer, level);
  401. return GetDataFromBuffer(result, size, result);
  402. }
  403. public PinnedSpan<byte> GetData()
  404. {
  405. BackgroundResource resources = Renderer.BackgroundResources.Get();
  406. if (Renderer.CommandBufferPool.OwnedByCurrentThread)
  407. {
  408. Renderer.FlushAllCommands();
  409. return PinnedSpan<byte>.UnsafeFromSpan(GetData(Renderer.CommandBufferPool, resources.GetFlushBuffer()));
  410. }
  411. return PinnedSpan<byte>.UnsafeFromSpan(GetData(resources.GetPool(), resources.GetFlushBuffer()));
  412. }
  413. public PinnedSpan<byte> GetData(int layer, int level)
  414. {
  415. BackgroundResource resources = Renderer.BackgroundResources.Get();
  416. if (Renderer.CommandBufferPool.OwnedByCurrentThread)
  417. {
  418. Renderer.FlushAllCommands();
  419. return PinnedSpan<byte>.UnsafeFromSpan(GetData(Renderer.CommandBufferPool, resources.GetFlushBuffer(), layer, level));
  420. }
  421. return PinnedSpan<byte>.UnsafeFromSpan(GetData(resources.GetPool(), resources.GetFlushBuffer(), layer, level));
  422. }
  423. public void SetData(MemoryOwner<byte> data)
  424. {
  425. MTLBlitCommandEncoder blitCommandEncoder = Pipeline.GetOrCreateBlitEncoder();
  426. Span<byte> dataSpan = data.Memory.Span;
  427. BufferHolder buffer = Renderer.BufferManager.Create(dataSpan.Length);
  428. buffer.SetDataUnchecked(0, dataSpan);
  429. MTLBuffer mtlBuffer = buffer.GetBuffer(false).Get(Pipeline.Cbs).Value;
  430. int width = Info.Width;
  431. int height = Info.Height;
  432. int depth = Info.Depth;
  433. int levels = Info.Levels;
  434. int layers = Info.GetLayers();
  435. bool is3D = Info.Target == Target.Texture3D;
  436. int offset = 0;
  437. for (int level = 0; level < levels; level++)
  438. {
  439. int mipSize = Info.GetMipSize2D(level);
  440. int endOffset = offset + mipSize;
  441. if ((uint)endOffset > (uint)dataSpan.Length)
  442. {
  443. return;
  444. }
  445. for (int layer = 0; layer < layers; layer++)
  446. {
  447. blitCommandEncoder.CopyFromBuffer(
  448. mtlBuffer,
  449. (ulong)offset,
  450. (ulong)Info.GetMipStride(level),
  451. (ulong)mipSize,
  452. new MTLSize { width = (ulong)width, height = (ulong)height, depth = is3D ? (ulong)depth : 1 },
  453. MtlTexture,
  454. (ulong)layer,
  455. (ulong)level,
  456. new MTLOrigin()
  457. );
  458. offset += mipSize;
  459. }
  460. width = Math.Max(1, width >> 1);
  461. height = Math.Max(1, height >> 1);
  462. if (is3D)
  463. {
  464. depth = Math.Max(1, depth >> 1);
  465. }
  466. }
  467. // Cleanup
  468. buffer.Dispose();
  469. }
  470. private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice)
  471. {
  472. int bufferDataLength = GetBufferDataLength(data.Length);
  473. using BufferHolder bufferHolder = Renderer.BufferManager.Create(bufferDataLength);
  474. // TODO: loadInline logic
  475. CommandBufferScoped cbs = Pipeline.Cbs;
  476. CopyDataToBuffer(bufferHolder.GetDataStorage(0, bufferDataLength), data);
  477. MTLBuffer buffer = bufferHolder.GetBuffer().Get(cbs).Value;
  478. MTLTexture image = GetHandle();
  479. CopyFromOrToBuffer(cbs, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
  480. }
  481. public void SetData(MemoryOwner<byte> data, int layer, int level)
  482. {
  483. SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true);
  484. data.Dispose();
  485. }
  486. public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
  487. {
  488. MTLBlitCommandEncoder blitCommandEncoder = Pipeline.GetOrCreateBlitEncoder();
  489. ulong bytesPerRow = (ulong)Info.GetMipStride(level);
  490. ulong bytesPerImage = 0;
  491. if (MtlTexture.TextureType == MTLTextureType.Type3D)
  492. {
  493. bytesPerImage = bytesPerRow * (ulong)Info.Height;
  494. }
  495. Span<byte> dataSpan = data.Memory.Span;
  496. BufferHolder buffer = Renderer.BufferManager.Create(dataSpan.Length);
  497. buffer.SetDataUnchecked(0, dataSpan);
  498. MTLBuffer mtlBuffer = buffer.GetBuffer(false).Get(Pipeline.Cbs).Value;
  499. blitCommandEncoder.CopyFromBuffer(
  500. mtlBuffer,
  501. 0,
  502. bytesPerRow,
  503. bytesPerImage,
  504. new MTLSize { width = (ulong)region.Width, height = (ulong)region.Height, depth = 1 },
  505. MtlTexture,
  506. (ulong)layer,
  507. (ulong)level,
  508. new MTLOrigin { x = (ulong)region.X, y = (ulong)region.Y }
  509. );
  510. // Cleanup
  511. buffer.Dispose();
  512. }
  513. private int GetBufferDataLength(int length)
  514. {
  515. if (NeedsD24S8Conversion())
  516. {
  517. return length * 2;
  518. }
  519. return length;
  520. }
  521. public void SetStorage(BufferRange buffer)
  522. {
  523. throw new NotImplementedException();
  524. }
  525. public override void Release()
  526. {
  527. if (_identityIsDifferent)
  528. {
  529. _identitySwizzleHandle.Dispose();
  530. }
  531. base.Release();
  532. }
  533. }
  534. }