TextureView.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. using Ryujinx.Common.Memory;
  2. using Ryujinx.Graphics.GAL;
  3. using Silk.NET.Vulkan;
  4. using System;
  5. using System.Collections.Generic;
  6. using Format = Ryujinx.Graphics.GAL.Format;
  7. using VkBuffer = Silk.NET.Vulkan.Buffer;
  8. using VkFormat = Silk.NET.Vulkan.Format;
  9. namespace Ryujinx.Graphics.Vulkan
  10. {
  11. class TextureView : ITexture, IDisposable
  12. {
  13. private readonly VulkanRenderer _gd;
  14. private readonly Device _device;
  15. private readonly Auto<DisposableImageView> _imageView;
  16. private readonly Auto<DisposableImageView> _imageViewDraw;
  17. private readonly Auto<DisposableImageView> _imageViewIdentity;
  18. private readonly Auto<DisposableImageView> _imageView2dArray;
  19. private Dictionary<Format, TextureView> _selfManagedViews;
  20. private readonly TextureCreateInfo _info;
  21. public TextureCreateInfo Info => _info;
  22. public TextureStorage Storage { get; }
  23. public int Width => Info.Width;
  24. public int Height => Info.Height;
  25. public int Layers => Info.GetDepthOrLayers();
  26. public int FirstLayer { get; }
  27. public int FirstLevel { get; }
  28. public float ScaleFactor => Storage.ScaleFactor;
  29. public VkFormat VkFormat { get; }
  30. public bool Valid { get; private set; }
  31. public TextureView(
  32. VulkanRenderer gd,
  33. Device device,
  34. TextureCreateInfo info,
  35. TextureStorage storage,
  36. int firstLayer,
  37. int firstLevel)
  38. {
  39. _gd = gd;
  40. _device = device;
  41. _info = info;
  42. Storage = storage;
  43. FirstLayer = firstLayer;
  44. FirstLevel = firstLevel;
  45. storage.IncrementViewsCount();
  46. gd.Textures.Add(this);
  47. var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format);
  48. var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample);
  49. var levels = (uint)info.Levels;
  50. var layers = (uint)info.GetLayers();
  51. VkFormat = format;
  52. var type = info.Target.ConvertView();
  53. var swizzleR = info.SwizzleR.Convert();
  54. var swizzleG = info.SwizzleG.Convert();
  55. var swizzleB = info.SwizzleB.Convert();
  56. var swizzleA = info.SwizzleA.Convert();
  57. if (info.Format == Format.R5G5B5A1Unorm ||
  58. info.Format == Format.R5G5B5X1Unorm ||
  59. info.Format == Format.R5G6B5Unorm)
  60. {
  61. (swizzleB, swizzleR) = (swizzleR, swizzleB);
  62. }
  63. else if (VkFormat == VkFormat.R4G4B4A4UnormPack16 || info.Format == Format.A1B5G5R5Unorm)
  64. {
  65. var tempB = swizzleB;
  66. var tempA = swizzleA;
  67. swizzleB = swizzleG;
  68. swizzleA = swizzleR;
  69. swizzleR = tempA;
  70. swizzleG = tempB;
  71. }
  72. var componentMapping = new ComponentMapping(swizzleR, swizzleG, swizzleB, swizzleA);
  73. var aspectFlags = info.Format.ConvertAspectFlags(info.DepthStencilMode);
  74. var aspectFlagsDepth = info.Format.ConvertAspectFlags();
  75. var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers);
  76. var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers);
  77. unsafe Auto<DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType, ImageUsageFlags usageFlags)
  78. {
  79. var usage = new ImageViewUsageCreateInfo
  80. {
  81. SType = StructureType.ImageViewUsageCreateInfo,
  82. Usage = usageFlags,
  83. };
  84. var imageCreateInfo = new ImageViewCreateInfo
  85. {
  86. SType = StructureType.ImageViewCreateInfo,
  87. Image = storage.GetImageForViewCreation(),
  88. ViewType = viewType,
  89. Format = format,
  90. Components = cm,
  91. SubresourceRange = sr,
  92. PNext = &usage,
  93. };
  94. gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError();
  95. return new Auto<DisposableImageView>(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage());
  96. }
  97. _imageView = CreateImageView(componentMapping, subresourceRange, type, ImageUsageFlags.SampledBit);
  98. // Framebuffer attachments and storage images requires a identity component mapping.
  99. var identityComponentMapping = new ComponentMapping(
  100. ComponentSwizzle.R,
  101. ComponentSwizzle.G,
  102. ComponentSwizzle.B,
  103. ComponentSwizzle.A);
  104. _imageViewDraw = CreateImageView(identityComponentMapping, subresourceRangeDepth, type, usage);
  105. _imageViewIdentity = aspectFlagsDepth == aspectFlags ? _imageViewDraw : CreateImageView(identityComponentMapping, subresourceRange, type, usage);
  106. // Framebuffer attachments also require 3D textures to be bound as 2D array.
  107. if (info.Target == Target.Texture3D)
  108. {
  109. if (gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.No3DImageView))
  110. {
  111. if (levels == 1 && (info.Format.IsRtColorCompatible() || info.Format.IsDepthOrStencil()))
  112. {
  113. subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, 1);
  114. _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2D, ImageUsageFlags.ColorAttachmentBit);
  115. }
  116. }
  117. else
  118. {
  119. subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
  120. _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray, usage);
  121. }
  122. }
  123. Valid = true;
  124. }
  125. public Auto<DisposableImage> GetImage()
  126. {
  127. return Storage.GetImage();
  128. }
  129. public Auto<DisposableImageView> GetImageView()
  130. {
  131. return _imageView;
  132. }
  133. public Auto<DisposableImageView> GetIdentityImageView()
  134. {
  135. return _imageViewIdentity;
  136. }
  137. public Auto<DisposableImageView> GetImageViewForAttachment()
  138. {
  139. return _imageView2dArray ?? _imageViewDraw;
  140. }
  141. public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
  142. {
  143. var src = this;
  144. var dst = (TextureView)destination;
  145. if (!Valid || !dst.Valid)
  146. {
  147. return;
  148. }
  149. _gd.PipelineInternal.EndRenderPass();
  150. var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
  151. var srcImage = src.GetImage().Get(cbs).Value;
  152. var dstImage = dst.GetImage().Get(cbs).Value;
  153. if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
  154. {
  155. int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
  156. _gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, 0, firstLayer, layers);
  157. }
  158. else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
  159. {
  160. int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
  161. _gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, 0, firstLayer, layers);
  162. }
  163. else if (dst.Info.BytesPerPixel != Info.BytesPerPixel)
  164. {
  165. int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
  166. int levels = Math.Min(Info.Levels, dst.Info.Levels - firstLevel);
  167. _gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, 0, firstLayer, 0, firstLevel, layers, levels);
  168. }
  169. else
  170. {
  171. TextureCopy.Copy(
  172. _gd.Api,
  173. cbs.CommandBuffer,
  174. srcImage,
  175. dstImage,
  176. src.Info,
  177. dst.Info,
  178. src.FirstLayer,
  179. dst.FirstLayer,
  180. src.FirstLevel,
  181. dst.FirstLevel,
  182. 0,
  183. firstLayer,
  184. 0,
  185. firstLevel);
  186. }
  187. }
  188. public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
  189. {
  190. var src = this;
  191. var dst = (TextureView)destination;
  192. if (!Valid || !dst.Valid)
  193. {
  194. return;
  195. }
  196. _gd.PipelineInternal.EndRenderPass();
  197. var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
  198. var srcImage = src.GetImage().Get(cbs).Value;
  199. var dstImage = dst.GetImage().Get(cbs).Value;
  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
  213. {
  214. TextureCopy.Copy(
  215. _gd.Api,
  216. cbs.CommandBuffer,
  217. srcImage,
  218. dstImage,
  219. src.Info,
  220. dst.Info,
  221. src.FirstLayer,
  222. dst.FirstLayer,
  223. src.FirstLevel,
  224. dst.FirstLevel,
  225. srcLayer,
  226. dstLayer,
  227. srcLevel,
  228. dstLevel,
  229. 1,
  230. 1);
  231. }
  232. }
  233. public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  234. {
  235. var dst = (TextureView)destination;
  236. if (_gd.CommandBufferPool.OwnedByCurrentThread)
  237. {
  238. _gd.PipelineInternal.EndRenderPass();
  239. var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
  240. CopyToImpl(cbs, dst, srcRegion, dstRegion, linearFilter);
  241. }
  242. else
  243. {
  244. var cbp = _gd.BackgroundResources.Get().GetPool();
  245. using var cbs = cbp.Rent();
  246. CopyToImpl(cbs, dst, srcRegion, dstRegion, linearFilter);
  247. }
  248. }
  249. private void CopyToImpl(CommandBufferScoped cbs, TextureView dst, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  250. {
  251. var src = this;
  252. var srcFormat = GetCompatibleGalFormat(src.Info.Format);
  253. var dstFormat = GetCompatibleGalFormat(dst.Info.Format);
  254. bool srcUsesStorageFormat = src.VkFormat == src.Storage.VkFormat;
  255. bool dstUsesStorageFormat = dst.VkFormat == dst.Storage.VkFormat;
  256. int layers = Math.Min(dst.Info.GetDepthOrLayers(), src.Info.GetDepthOrLayers());
  257. int levels = Math.Min(dst.Info.Levels, src.Info.Levels);
  258. if (srcUsesStorageFormat && dstUsesStorageFormat)
  259. {
  260. if ((srcRegion.X1 | dstRegion.X1) == 0 &&
  261. (srcRegion.Y1 | dstRegion.Y1) == 0 &&
  262. srcRegion.X2 == src.Width &&
  263. srcRegion.Y2 == src.Height &&
  264. dstRegion.X2 == dst.Width &&
  265. dstRegion.Y2 == dst.Height &&
  266. src.Width == dst.Width &&
  267. src.Height == dst.Height &&
  268. src.VkFormat == dst.VkFormat)
  269. {
  270. if (src.Info.Samples > 1 && src.Info.Samples != dst.Info.Samples && src.Info.Format.IsDepthOrStencil())
  271. {
  272. // CmdResolveImage does not support depth-stencil resolve, so we need to use an alternative path
  273. // for those textures.
  274. TextureCopy.ResolveDepthStencil(_gd, _device, cbs, src, dst);
  275. }
  276. else
  277. {
  278. TextureCopy.Copy(
  279. _gd.Api,
  280. cbs.CommandBuffer,
  281. src.GetImage().Get(cbs).Value,
  282. dst.GetImage().Get(cbs).Value,
  283. src.Info,
  284. dst.Info,
  285. src.FirstLayer,
  286. dst.FirstLayer,
  287. src.FirstLevel,
  288. dst.FirstLevel,
  289. 0,
  290. 0,
  291. 0,
  292. 0,
  293. layers,
  294. levels);
  295. }
  296. return;
  297. }
  298. if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.BlitSrcBit, srcFormat) &&
  299. _gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.BlitDstBit, dstFormat))
  300. {
  301. TextureCopy.Blit(
  302. _gd.Api,
  303. cbs.CommandBuffer,
  304. src.GetImage().Get(cbs).Value,
  305. dst.GetImage().Get(cbs).Value,
  306. src.Info,
  307. dst.Info,
  308. srcRegion,
  309. dstRegion,
  310. src.FirstLayer,
  311. dst.FirstLayer,
  312. src.FirstLevel,
  313. dst.FirstLevel,
  314. layers,
  315. levels,
  316. linearFilter);
  317. return;
  318. }
  319. }
  320. bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
  321. if (VulkanConfiguration.UseSlowSafeBlitOnAmd && (_gd.Vendor == Vendor.Amd || _gd.IsMoltenVk))
  322. {
  323. _gd.HelperShader.Blit(
  324. _gd,
  325. src,
  326. dst,
  327. srcRegion,
  328. dstRegion,
  329. layers,
  330. levels,
  331. isDepthOrStencil,
  332. linearFilter);
  333. return;
  334. }
  335. Auto<DisposableImage> srcImage;
  336. Auto<DisposableImage> dstImage;
  337. if (isDepthOrStencil)
  338. {
  339. srcImage = src.Storage.CreateAliasedColorForDepthStorageUnsafe(srcFormat).GetImage();
  340. dstImage = dst.Storage.CreateAliasedColorForDepthStorageUnsafe(dstFormat).GetImage();
  341. }
  342. else
  343. {
  344. srcImage = src.Storage.CreateAliasedStorageUnsafe(srcFormat).GetImage();
  345. dstImage = dst.Storage.CreateAliasedStorageUnsafe(dstFormat).GetImage();
  346. }
  347. TextureCopy.Blit(
  348. _gd.Api,
  349. cbs.CommandBuffer,
  350. srcImage.Get(cbs).Value,
  351. dstImage.Get(cbs).Value,
  352. src.Info,
  353. dst.Info,
  354. srcRegion,
  355. dstRegion,
  356. src.FirstLayer,
  357. dst.FirstLayer,
  358. src.FirstLevel,
  359. dst.FirstLevel,
  360. layers,
  361. levels,
  362. linearFilter,
  363. ImageAspectFlags.ColorBit,
  364. ImageAspectFlags.ColorBit);
  365. }
  366. public static unsafe void InsertImageBarrier(
  367. Vk api,
  368. CommandBuffer commandBuffer,
  369. Image image,
  370. AccessFlags srcAccessMask,
  371. AccessFlags dstAccessMask,
  372. PipelineStageFlags srcStageMask,
  373. PipelineStageFlags dstStageMask,
  374. ImageAspectFlags aspectFlags,
  375. int firstLayer,
  376. int firstLevel,
  377. int layers,
  378. int levels)
  379. {
  380. ImageMemoryBarrier memoryBarrier = new()
  381. {
  382. SType = StructureType.ImageMemoryBarrier,
  383. SrcAccessMask = srcAccessMask,
  384. DstAccessMask = dstAccessMask,
  385. SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
  386. DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
  387. Image = image,
  388. OldLayout = ImageLayout.General,
  389. NewLayout = ImageLayout.General,
  390. SubresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, (uint)levels, (uint)firstLayer, (uint)layers),
  391. };
  392. api.CmdPipelineBarrier(
  393. commandBuffer,
  394. srcStageMask,
  395. dstStageMask,
  396. 0,
  397. 0,
  398. null,
  399. 0,
  400. null,
  401. 1,
  402. memoryBarrier);
  403. }
  404. public TextureView GetView(Format format)
  405. {
  406. if (format == Info.Format)
  407. {
  408. return this;
  409. }
  410. if (_selfManagedViews != null && _selfManagedViews.TryGetValue(format, out var view))
  411. {
  412. return view;
  413. }
  414. view = CreateViewImpl(new TextureCreateInfo(
  415. Info.Width,
  416. Info.Height,
  417. Info.Depth,
  418. Info.Levels,
  419. Info.Samples,
  420. Info.BlockWidth,
  421. Info.BlockHeight,
  422. Info.BytesPerPixel,
  423. format,
  424. Info.DepthStencilMode,
  425. Info.Target,
  426. Info.SwizzleR,
  427. Info.SwizzleG,
  428. Info.SwizzleB,
  429. Info.SwizzleA), 0, 0);
  430. (_selfManagedViews ??= new Dictionary<Format, TextureView>()).Add(format, view);
  431. return view;
  432. }
  433. public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
  434. {
  435. return CreateViewImpl(info, firstLayer, firstLevel);
  436. }
  437. public TextureView CreateViewImpl(TextureCreateInfo info, int firstLayer, int firstLevel)
  438. {
  439. return new TextureView(_gd, _device, info, Storage, FirstLayer + firstLayer, FirstLevel + firstLevel);
  440. }
  441. public byte[] GetData(int x, int y, int width, int height)
  442. {
  443. int size = width * height * Info.BytesPerPixel;
  444. using var bufferHolder = _gd.BufferManager.Create(_gd, size);
  445. using (var cbs = _gd.CommandBufferPool.Rent())
  446. {
  447. var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
  448. var image = GetImage().Get(cbs).Value;
  449. CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, size, true, 0, 0, x, y, width, height);
  450. }
  451. bufferHolder.WaitForFences();
  452. byte[] bitmap = new byte[size];
  453. GetDataFromBuffer(bufferHolder.GetDataStorage(0, size), size, Span<byte>.Empty).CopyTo(bitmap);
  454. return bitmap;
  455. }
  456. public PinnedSpan<byte> GetData()
  457. {
  458. BackgroundResource resources = _gd.BackgroundResources.Get();
  459. if (_gd.CommandBufferPool.OwnedByCurrentThread)
  460. {
  461. _gd.FlushAllCommands();
  462. return PinnedSpan<byte>.UnsafeFromSpan(GetData(_gd.CommandBufferPool, resources.GetFlushBuffer()));
  463. }
  464. return PinnedSpan<byte>.UnsafeFromSpan(GetData(resources.GetPool(), resources.GetFlushBuffer()));
  465. }
  466. public PinnedSpan<byte> GetData(int layer, int level)
  467. {
  468. BackgroundResource resources = _gd.BackgroundResources.Get();
  469. if (_gd.CommandBufferPool.OwnedByCurrentThread)
  470. {
  471. _gd.FlushAllCommands();
  472. return PinnedSpan<byte>.UnsafeFromSpan(GetData(_gd.CommandBufferPool, resources.GetFlushBuffer(), layer, level));
  473. }
  474. return PinnedSpan<byte>.UnsafeFromSpan(GetData(resources.GetPool(), resources.GetFlushBuffer(), layer, level));
  475. }
  476. public void CopyTo(BufferRange range, int layer, int level, int stride)
  477. {
  478. _gd.PipelineInternal.EndRenderPass();
  479. var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
  480. int outSize = Info.GetMipSize(level);
  481. int hostSize = GetBufferDataLength(outSize);
  482. var image = GetImage().Get(cbs).Value;
  483. int offset = range.Offset;
  484. Auto<DisposableBuffer> autoBuffer = _gd.BufferManager.GetBuffer(cbs.CommandBuffer, range.Handle, true);
  485. VkBuffer buffer = autoBuffer.Get(cbs, range.Offset, outSize).Value;
  486. if (PrepareOutputBuffer(cbs, hostSize, buffer, out VkBuffer copyToBuffer, out BufferHolder tempCopyHolder))
  487. {
  488. offset = 0;
  489. }
  490. CopyFromOrToBuffer(cbs.CommandBuffer, copyToBuffer, image, hostSize, true, layer, level, 1, 1, singleSlice: true, offset, stride);
  491. if (tempCopyHolder != null)
  492. {
  493. CopyDataToOutputBuffer(cbs, tempCopyHolder, autoBuffer, hostSize, range.Offset);
  494. tempCopyHolder.Dispose();
  495. }
  496. }
  497. private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer)
  498. {
  499. int size = 0;
  500. for (int level = 0; level < Info.Levels; level++)
  501. {
  502. size += Info.GetMipSize(level);
  503. }
  504. size = GetBufferDataLength(size);
  505. Span<byte> result = flushBuffer.GetTextureData(cbp, this, size);
  506. return GetDataFromBuffer(result, size, result);
  507. }
  508. private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer, int layer, int level)
  509. {
  510. int size = GetBufferDataLength(Info.GetMipSize(level));
  511. Span<byte> result = flushBuffer.GetTextureData(cbp, this, size, layer, level);
  512. return GetDataFromBuffer(result, size, result);
  513. }
  514. public void SetData(SpanOrArray<byte> data)
  515. {
  516. SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
  517. }
  518. public void SetData(SpanOrArray<byte> data, int layer, int level)
  519. {
  520. SetData(data, layer, level, 1, 1, singleSlice: true);
  521. }
  522. public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
  523. {
  524. SetData(data, layer, level, 1, 1, singleSlice: true, region);
  525. }
  526. private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice, Rectangle<int>? region = null)
  527. {
  528. int bufferDataLength = GetBufferDataLength(data.Length);
  529. using var bufferHolder = _gd.BufferManager.Create(_gd, bufferDataLength);
  530. Auto<DisposableImage> imageAuto = GetImage();
  531. // Load texture data inline if the texture has been used on the current command buffer.
  532. bool loadInline = Storage.HasCommandBufferDependency(_gd.PipelineInternal.CurrentCommandBuffer);
  533. var cbs = loadInline ? _gd.PipelineInternal.CurrentCommandBuffer : _gd.PipelineInternal.GetPreloadCommandBuffer();
  534. if (loadInline)
  535. {
  536. _gd.PipelineInternal.EndRenderPass();
  537. }
  538. CopyDataToBuffer(bufferHolder.GetDataStorage(0, bufferDataLength), data);
  539. var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
  540. var image = imageAuto.Get(cbs).Value;
  541. if (region.HasValue)
  542. {
  543. CopyFromOrToBuffer(
  544. cbs.CommandBuffer,
  545. buffer,
  546. image,
  547. bufferDataLength,
  548. false,
  549. layer,
  550. level,
  551. region.Value.X,
  552. region.Value.Y,
  553. region.Value.Width,
  554. region.Value.Height);
  555. }
  556. else
  557. {
  558. CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
  559. }
  560. }
  561. private int GetBufferDataLength(int length)
  562. {
  563. if (NeedsD24S8Conversion())
  564. {
  565. return length * 2;
  566. }
  567. return length;
  568. }
  569. private Format GetCompatibleGalFormat(Format format)
  570. {
  571. if (NeedsD24S8Conversion())
  572. {
  573. return Format.D32FloatS8Uint;
  574. }
  575. return format;
  576. }
  577. private void CopyDataToBuffer(Span<byte> storage, ReadOnlySpan<byte> input)
  578. {
  579. if (NeedsD24S8Conversion())
  580. {
  581. FormatConverter.ConvertD24S8ToD32FS8(storage, input);
  582. return;
  583. }
  584. input.CopyTo(storage);
  585. }
  586. private ReadOnlySpan<byte> GetDataFromBuffer(ReadOnlySpan<byte> storage, int size, Span<byte> output)
  587. {
  588. if (NeedsD24S8Conversion())
  589. {
  590. if (output.IsEmpty)
  591. {
  592. output = new byte[GetBufferDataLength(size)];
  593. }
  594. FormatConverter.ConvertD32FS8ToD24S8(output, storage);
  595. return output;
  596. }
  597. return storage;
  598. }
  599. private bool PrepareOutputBuffer(CommandBufferScoped cbs, int hostSize, VkBuffer target, out VkBuffer copyTarget, out BufferHolder copyTargetHolder)
  600. {
  601. if (NeedsD24S8Conversion())
  602. {
  603. copyTargetHolder = _gd.BufferManager.Create(_gd, hostSize);
  604. copyTarget = copyTargetHolder.GetBuffer().Get(cbs, 0, hostSize).Value;
  605. return true;
  606. }
  607. copyTarget = target;
  608. copyTargetHolder = null;
  609. return false;
  610. }
  611. private void CopyDataToOutputBuffer(CommandBufferScoped cbs, BufferHolder hostData, Auto<DisposableBuffer> copyTarget, int hostSize, int dstOffset)
  612. {
  613. if (NeedsD24S8Conversion())
  614. {
  615. _gd.HelperShader.ConvertD32S8ToD24S8(_gd, cbs, hostData, copyTarget, hostSize / (2 * sizeof(int)), dstOffset);
  616. }
  617. }
  618. private bool NeedsD24S8Conversion()
  619. {
  620. return FormatCapabilities.IsD24S8(Info.Format) && VkFormat == VkFormat.D32SfloatS8Uint;
  621. }
  622. public void CopyFromOrToBuffer(
  623. CommandBuffer commandBuffer,
  624. VkBuffer buffer,
  625. Image image,
  626. int size,
  627. bool to,
  628. int dstLayer,
  629. int dstLevel,
  630. int dstLayers,
  631. int dstLevels,
  632. bool singleSlice,
  633. int offset = 0,
  634. int stride = 0)
  635. {
  636. bool is3D = Info.Target == Target.Texture3D;
  637. int width = Math.Max(1, Info.Width >> dstLevel);
  638. int height = Math.Max(1, Info.Height >> dstLevel);
  639. int depth = is3D && !singleSlice ? Math.Max(1, Info.Depth >> dstLevel) : 1;
  640. int layer = is3D ? 0 : dstLayer;
  641. int layers = dstLayers;
  642. int levels = dstLevels;
  643. for (int level = 0; level < levels; level++)
  644. {
  645. int mipSize = GetBufferDataLength(Info.GetMipSize2D(dstLevel + level) * dstLayers);
  646. int endOffset = offset + mipSize;
  647. if ((uint)endOffset > (uint)size)
  648. {
  649. break;
  650. }
  651. int rowLength = ((stride == 0 ? Info.GetMipStride(dstLevel + level) : stride) / Info.BytesPerPixel) * Info.BlockWidth;
  652. var aspectFlags = Info.Format.ConvertAspectFlags();
  653. if (aspectFlags == (ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit))
  654. {
  655. aspectFlags = ImageAspectFlags.DepthBit;
  656. }
  657. var sl = new ImageSubresourceLayers(
  658. aspectFlags,
  659. (uint)(FirstLevel + dstLevel + level),
  660. (uint)(FirstLayer + layer),
  661. (uint)layers);
  662. var extent = new Extent3D((uint)width, (uint)height, (uint)depth);
  663. int z = is3D ? dstLayer : 0;
  664. var region = new BufferImageCopy(
  665. (ulong)offset,
  666. (uint)AlignUpNpot(rowLength, Info.BlockWidth),
  667. (uint)AlignUpNpot(height, Info.BlockHeight),
  668. sl,
  669. new Offset3D(0, 0, z),
  670. extent);
  671. if (to)
  672. {
  673. _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
  674. }
  675. else
  676. {
  677. _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
  678. }
  679. offset += mipSize;
  680. width = Math.Max(1, width >> 1);
  681. height = Math.Max(1, height >> 1);
  682. if (Info.Target == Target.Texture3D)
  683. {
  684. depth = Math.Max(1, depth >> 1);
  685. }
  686. }
  687. }
  688. private void CopyFromOrToBuffer(
  689. CommandBuffer commandBuffer,
  690. VkBuffer buffer,
  691. Image image,
  692. int size,
  693. bool to,
  694. int dstLayer,
  695. int dstLevel,
  696. int x,
  697. int y,
  698. int width,
  699. int height)
  700. {
  701. var aspectFlags = Info.Format.ConvertAspectFlags();
  702. if (aspectFlags == (ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit))
  703. {
  704. aspectFlags = ImageAspectFlags.DepthBit;
  705. }
  706. var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1);
  707. var extent = new Extent3D((uint)width, (uint)height, 1);
  708. int rowLengthAlignment = Info.BlockWidth;
  709. // We expect all data being written into the texture to have a stride aligned by 4.
  710. if (!to && Info.BytesPerPixel < 4)
  711. {
  712. rowLengthAlignment = 4 / Info.BytesPerPixel;
  713. }
  714. var region = new BufferImageCopy(
  715. 0,
  716. (uint)AlignUpNpot(width, rowLengthAlignment),
  717. (uint)AlignUpNpot(height, Info.BlockHeight),
  718. sl,
  719. new Offset3D(x, y, 0),
  720. extent);
  721. if (to)
  722. {
  723. _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
  724. }
  725. else
  726. {
  727. _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
  728. }
  729. }
  730. private static int AlignUpNpot(int size, int alignment)
  731. {
  732. int remainder = size % alignment;
  733. if (remainder == 0)
  734. {
  735. return size;
  736. }
  737. return size + (alignment - remainder);
  738. }
  739. public void SetStorage(BufferRange buffer)
  740. {
  741. throw new NotImplementedException();
  742. }
  743. protected virtual void Dispose(bool disposing)
  744. {
  745. if (disposing)
  746. {
  747. Valid = false;
  748. if (_gd.Textures.Remove(this))
  749. {
  750. _imageView.Dispose();
  751. _imageViewIdentity.Dispose();
  752. _imageView2dArray?.Dispose();
  753. if (_imageViewDraw != _imageViewIdentity)
  754. {
  755. _imageViewDraw.Dispose();
  756. }
  757. Storage.DecrementViewsCount();
  758. }
  759. }
  760. }
  761. public void Dispose()
  762. {
  763. if (_selfManagedViews != null)
  764. {
  765. foreach (var view in _selfManagedViews.Values)
  766. {
  767. view.Dispose();
  768. }
  769. _selfManagedViews = null;
  770. }
  771. Dispose(true);
  772. }
  773. public void Release()
  774. {
  775. Dispose();
  776. }
  777. }
  778. }