TextureView.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  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 VkBuffer = Silk.NET.Vulkan.Buffer;
  7. using VkFormat = Silk.NET.Vulkan.Format;
  8. namespace Ryujinx.Graphics.Vulkan
  9. {
  10. class TextureView : ITexture, IDisposable
  11. {
  12. private readonly VulkanRenderer _gd;
  13. private readonly Device _device;
  14. private readonly Auto<DisposableImageView> _imageView;
  15. private readonly Auto<DisposableImageView> _imageViewIdentity;
  16. private readonly Auto<DisposableImageView> _imageView2dArray;
  17. private Dictionary<GAL.Format, TextureView> _selfManagedViews;
  18. private TextureCreateInfo _info;
  19. public TextureCreateInfo Info => _info;
  20. public TextureStorage Storage { get; }
  21. public int Width => Info.Width;
  22. public int Height => Info.Height;
  23. public int Layers => Info.GetDepthOrLayers();
  24. public int FirstLayer { get; }
  25. public int FirstLevel { get; }
  26. public float ScaleFactor => Storage.ScaleFactor;
  27. public VkFormat VkFormat { get; }
  28. public bool Valid { get; private set; }
  29. public TextureView(
  30. VulkanRenderer gd,
  31. Device device,
  32. TextureCreateInfo info,
  33. TextureStorage storage,
  34. int firstLayer,
  35. int firstLevel)
  36. {
  37. _gd = gd;
  38. _device = device;
  39. _info = info;
  40. Storage = storage;
  41. FirstLayer = firstLayer;
  42. FirstLevel = firstLevel;
  43. storage.IncrementViewsCount();
  44. gd.Textures.Add(this);
  45. var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format);
  46. var levels = (uint)info.Levels;
  47. var layers = (uint)info.GetLayers();
  48. VkFormat = format;
  49. var type = info.Target.ConvertView();
  50. var swizzleR = info.SwizzleR.Convert();
  51. var swizzleG = info.SwizzleG.Convert();
  52. var swizzleB = info.SwizzleB.Convert();
  53. var swizzleA = info.SwizzleA.Convert();
  54. if (info.Format == GAL.Format.R5G5B5A1Unorm ||
  55. info.Format == GAL.Format.R5G5B5X1Unorm ||
  56. info.Format == GAL.Format.R5G6B5Unorm)
  57. {
  58. var temp = swizzleR;
  59. swizzleR = swizzleB;
  60. swizzleB = temp;
  61. }
  62. else if (VkFormat == VkFormat.R4G4B4A4UnormPack16 || info.Format == GAL.Format.A1B5G5R5Unorm)
  63. {
  64. var tempB = swizzleB;
  65. var tempA = swizzleA;
  66. swizzleB = swizzleG;
  67. swizzleA = swizzleR;
  68. swizzleR = tempA;
  69. swizzleG = tempB;
  70. }
  71. var componentMapping = new ComponentMapping(swizzleR, swizzleG, swizzleB, swizzleA);
  72. var aspectFlags = info.Format.ConvertAspectFlags(info.DepthStencilMode);
  73. var aspectFlagsDepth = info.Format.ConvertAspectFlags(DepthStencilMode.Depth);
  74. var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers);
  75. var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers);
  76. unsafe Auto<DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType)
  77. {
  78. var imageCreateInfo = new ImageViewCreateInfo()
  79. {
  80. SType = StructureType.ImageViewCreateInfo,
  81. Image = storage.GetImageForViewCreation(),
  82. ViewType = viewType,
  83. Format = format,
  84. Components = cm,
  85. SubresourceRange = sr
  86. };
  87. gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError();
  88. return new Auto<DisposableImageView>(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage());
  89. }
  90. _imageView = CreateImageView(componentMapping, subresourceRange, type);
  91. // Framebuffer attachments and storage images requires a identity component mapping.
  92. var identityComponentMapping = new ComponentMapping(
  93. ComponentSwizzle.R,
  94. ComponentSwizzle.G,
  95. ComponentSwizzle.B,
  96. ComponentSwizzle.A);
  97. _imageViewIdentity = CreateImageView(identityComponentMapping, subresourceRangeDepth, type);
  98. // Framebuffer attachments also require 3D textures to be bound as 2D array.
  99. if (info.Target == Target.Texture3D)
  100. {
  101. subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
  102. _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.ImageViewType2DArray);
  103. }
  104. Valid = true;
  105. }
  106. public Auto<DisposableImage> GetImage()
  107. {
  108. return Storage.GetImage();
  109. }
  110. public Auto<DisposableImageView> GetImageView()
  111. {
  112. return _imageView;
  113. }
  114. public Auto<DisposableImageView> GetIdentityImageView()
  115. {
  116. return _imageViewIdentity;
  117. }
  118. public Auto<DisposableImageView> GetImageViewForAttachment()
  119. {
  120. return _imageView2dArray ?? _imageViewIdentity;
  121. }
  122. public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
  123. {
  124. var src = this;
  125. var dst = (TextureView)destination;
  126. if (!Valid || !dst.Valid)
  127. {
  128. return;
  129. }
  130. _gd.PipelineInternal.EndRenderPass();
  131. var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
  132. var srcImage = src.GetImage().Get(cbs).Value;
  133. var dstImage = dst.GetImage().Get(cbs).Value;
  134. if (src.Info.Target.IsMultisample())
  135. {
  136. int depth = Math.Min(src.Info.Depth, dst.Info.Depth - firstLayer);
  137. int levels = Math.Min(src.Info.Levels, dst.Info.Levels - firstLevel);
  138. CopyMSToNonMS(_gd, cbs, src, dst, srcImage, dstImage, 0, firstLayer, 0, firstLevel, depth, levels);
  139. }
  140. else
  141. {
  142. TextureCopy.Copy(
  143. _gd.Api,
  144. cbs.CommandBuffer,
  145. srcImage,
  146. dstImage,
  147. src.Info,
  148. dst.Info,
  149. src.FirstLayer,
  150. dst.FirstLayer,
  151. src.FirstLevel,
  152. dst.FirstLevel,
  153. 0,
  154. firstLayer,
  155. 0,
  156. firstLevel);
  157. }
  158. }
  159. public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
  160. {
  161. var src = this;
  162. var dst = (TextureView)destination;
  163. if (!Valid || !dst.Valid)
  164. {
  165. return;
  166. }
  167. _gd.PipelineInternal.EndRenderPass();
  168. var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
  169. var srcImage = src.GetImage().Get(cbs).Value;
  170. var dstImage = dst.GetImage().Get(cbs).Value;
  171. if (src.Info.Target.IsMultisample())
  172. {
  173. CopyMSToNonMS(_gd, cbs, src, dst, srcImage, dstImage, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
  174. }
  175. else
  176. {
  177. TextureCopy.Copy(
  178. _gd.Api,
  179. cbs.CommandBuffer,
  180. srcImage,
  181. dstImage,
  182. src.Info,
  183. dst.Info,
  184. src.FirstLayer,
  185. dst.FirstLayer,
  186. src.FirstLevel,
  187. dst.FirstLevel,
  188. srcLayer,
  189. dstLayer,
  190. srcLevel,
  191. dstLevel,
  192. 1,
  193. 1);
  194. }
  195. }
  196. private static void CopyMSToNonMS(
  197. VulkanRenderer gd,
  198. CommandBufferScoped cbs,
  199. TextureView src,
  200. TextureView dst,
  201. Image srcImage,
  202. Image dstImage,
  203. int srcLayer,
  204. int dstLayer,
  205. int srcLevel,
  206. int dstLevel,
  207. int layers,
  208. int levels)
  209. {
  210. bool differentFormats = src.Info.Format != dst.Info.Format;
  211. var target = src.Info.Target switch
  212. {
  213. Target.Texture2D => Target.Texture2DMultisample,
  214. Target.Texture2DArray => Target.Texture2DMultisampleArray,
  215. Target.Texture2DMultisampleArray => Target.Texture2DArray,
  216. _ => Target.Texture2D
  217. };
  218. var intermmediateTarget = differentFormats ? dst.Info.Target : target;
  219. using var intermmediate = CreateIntermmediateTexture(gd, src, ref dst._info, intermmediateTarget, layers, levels);
  220. var intermmediateImage = intermmediate.GetImage().Get(cbs).Value;
  221. if (differentFormats)
  222. {
  223. // If the formats are different, the resolve would perform format conversion.
  224. // So we need yet another intermmediate texture and do a copy to reinterpret the
  225. // data into the correct (destination) format, without doing any sort of conversion.
  226. using var intermmediate2 = CreateIntermmediateTexture(gd, src, ref src._info, target, layers, levels);
  227. var intermmediate2Image = intermmediate2.GetImage().Get(cbs).Value;
  228. TextureCopy.Copy(
  229. gd.Api,
  230. cbs.CommandBuffer,
  231. srcImage,
  232. intermmediate2Image,
  233. src.Info,
  234. intermmediate2.Info,
  235. src.FirstLayer,
  236. 0,
  237. src.FirstLevel,
  238. 0,
  239. srcLayer,
  240. 0,
  241. srcLevel,
  242. 0,
  243. layers,
  244. levels);
  245. TextureCopy.Copy(
  246. gd.Api,
  247. cbs.CommandBuffer,
  248. intermmediate2Image,
  249. intermmediateImage,
  250. intermmediate2.Info,
  251. intermmediate.Info,
  252. 0,
  253. 0,
  254. 0,
  255. 0,
  256. 0,
  257. 0,
  258. 0,
  259. 0,
  260. layers,
  261. levels);
  262. }
  263. else
  264. {
  265. TextureCopy.Copy(
  266. gd.Api,
  267. cbs.CommandBuffer,
  268. srcImage,
  269. intermmediateImage,
  270. src.Info,
  271. intermmediate.Info,
  272. src.FirstLayer,
  273. 0,
  274. src.FirstLevel,
  275. 0,
  276. srcLayer,
  277. 0,
  278. srcLevel,
  279. 0,
  280. layers,
  281. levels);
  282. }
  283. var srcRegion = new Extents2D(0, 0, src.Width, src.Height);
  284. var dstRegion = new Extents2D(0, 0, dst.Width, dst.Height);
  285. TextureCopy.Blit(
  286. gd.Api,
  287. cbs.CommandBuffer,
  288. intermmediateImage,
  289. dstImage,
  290. intermmediate.Info,
  291. dst.Info,
  292. srcRegion,
  293. dstRegion,
  294. 0,
  295. dst.FirstLevel + dstLevel,
  296. 0,
  297. dst.FirstLayer + dstLayer,
  298. layers,
  299. levels,
  300. true,
  301. ImageAspectFlags.ImageAspectColorBit,
  302. ImageAspectFlags.ImageAspectColorBit);
  303. }
  304. private static TextureView CreateIntermmediateTexture(VulkanRenderer gd, TextureView src, ref TextureCreateInfo formatInfo, Target target, int depth, int levels)
  305. {
  306. return gd.CreateTextureView(new GAL.TextureCreateInfo(
  307. src.Width,
  308. src.Height,
  309. depth,
  310. levels,
  311. 1,
  312. formatInfo.BlockWidth,
  313. formatInfo.BlockHeight,
  314. formatInfo.BytesPerPixel,
  315. formatInfo.Format,
  316. DepthStencilMode.Depth,
  317. target,
  318. SwizzleComponent.Red,
  319. SwizzleComponent.Green,
  320. SwizzleComponent.Blue,
  321. SwizzleComponent.Alpha), 1f);
  322. }
  323. public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  324. {
  325. var dst = (TextureView)destination;
  326. if (_gd.CommandBufferPool.OwnedByCurrentThread)
  327. {
  328. _gd.PipelineInternal.EndRenderPass();
  329. var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
  330. CopyToImpl(cbs, dst, srcRegion, dstRegion, linearFilter);
  331. }
  332. else
  333. {
  334. var cbp = _gd.BackgroundResources.Get().GetPool();
  335. using var cbs = cbp.Rent();
  336. CopyToImpl(cbs, dst, srcRegion, dstRegion, linearFilter);
  337. }
  338. }
  339. private void CopyToImpl(CommandBufferScoped cbs, TextureView dst, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  340. {
  341. var src = this;
  342. var srcFormat = GetCompatibleGalFormat(src.Info.Format);
  343. var dstFormat = GetCompatibleGalFormat(dst.Info.Format);
  344. bool srcUsesStorageFormat = src.VkFormat == src.Storage.VkFormat;
  345. bool dstUsesStorageFormat = dst.VkFormat == dst.Storage.VkFormat;
  346. int layers = Math.Min(dst.Info.GetDepthOrLayers(), src.Info.GetDepthOrLayers());
  347. int levels = Math.Min(dst.Info.Levels, src.Info.Levels);
  348. if (srcUsesStorageFormat && dstUsesStorageFormat)
  349. {
  350. if ((srcRegion.X1 | dstRegion.X1) == 0 &&
  351. (srcRegion.Y1 | dstRegion.Y1) == 0 &&
  352. srcRegion.X2 == src.Width &&
  353. srcRegion.Y2 == src.Height &&
  354. dstRegion.X2 == dst.Width &&
  355. dstRegion.Y2 == dst.Height &&
  356. src.Width == dst.Width &&
  357. src.Height == dst.Height &&
  358. src.VkFormat == dst.VkFormat)
  359. {
  360. TextureCopy.Copy(
  361. _gd.Api,
  362. cbs.CommandBuffer,
  363. src.GetImage().Get(cbs).Value,
  364. dst.GetImage().Get(cbs).Value,
  365. src.Info,
  366. dst.Info,
  367. src.FirstLayer,
  368. dst.FirstLayer,
  369. src.FirstLevel,
  370. dst.FirstLevel,
  371. 0,
  372. 0,
  373. 0,
  374. 0,
  375. layers,
  376. levels);
  377. return;
  378. }
  379. else if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
  380. _gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
  381. {
  382. TextureCopy.Blit(
  383. _gd.Api,
  384. cbs.CommandBuffer,
  385. src.GetImage().Get(cbs).Value,
  386. dst.GetImage().Get(cbs).Value,
  387. src.Info,
  388. dst.Info,
  389. srcRegion,
  390. dstRegion,
  391. src.FirstLayer,
  392. dst.FirstLayer,
  393. src.FirstLevel,
  394. dst.FirstLevel,
  395. layers,
  396. levels,
  397. linearFilter);
  398. return;
  399. }
  400. else if (srcFormat == GAL.Format.D32FloatS8Uint && srcFormat == dstFormat && SupportsBlitFromD32FS8ToD32FAndS8())
  401. {
  402. BlitDepthStencilWithBuffer(_gd, cbs, src, dst, srcRegion, dstRegion);
  403. return;
  404. }
  405. }
  406. if (VulkanConfiguration.UseSlowSafeBlitOnAmd &&
  407. _gd.Vendor == Vendor.Amd &&
  408. src.Info.Target == Target.Texture2D &&
  409. dst.Info.Target == Target.Texture2D &&
  410. !dst.Info.Format.IsDepthOrStencil())
  411. {
  412. _gd.HelperShader.Blit(
  413. _gd,
  414. src,
  415. dst.GetIdentityImageView(),
  416. dst.Width,
  417. dst.Height,
  418. dst.VkFormat,
  419. srcRegion,
  420. dstRegion,
  421. linearFilter);
  422. return;
  423. }
  424. Auto<DisposableImage> srcImage;
  425. Auto<DisposableImage> dstImage;
  426. if (dst.Info.Format.IsDepthOrStencil())
  427. {
  428. srcImage = src.Storage.CreateAliasedColorForDepthStorageUnsafe(srcFormat).GetImage();
  429. dstImage = dst.Storage.CreateAliasedColorForDepthStorageUnsafe(dstFormat).GetImage();
  430. }
  431. else
  432. {
  433. srcImage = src.Storage.CreateAliasedStorageUnsafe(srcFormat).GetImage();
  434. dstImage = dst.Storage.CreateAliasedStorageUnsafe(dstFormat).GetImage();
  435. }
  436. TextureCopy.Blit(
  437. _gd.Api,
  438. cbs.CommandBuffer,
  439. srcImage.Get(cbs).Value,
  440. dstImage.Get(cbs).Value,
  441. src.Info,
  442. dst.Info,
  443. srcRegion,
  444. dstRegion,
  445. src.FirstLayer,
  446. dst.FirstLayer,
  447. src.FirstLevel,
  448. dst.FirstLevel,
  449. layers,
  450. levels,
  451. linearFilter,
  452. ImageAspectFlags.ImageAspectColorBit,
  453. ImageAspectFlags.ImageAspectColorBit);
  454. }
  455. private static void BlitDepthStencilWithBuffer(
  456. VulkanRenderer gd,
  457. CommandBufferScoped cbs,
  458. TextureView src,
  459. TextureView dst,
  460. Extents2D srcRegion,
  461. Extents2D dstRegion)
  462. {
  463. int drBaseX = Math.Min(dstRegion.X1, dstRegion.X2);
  464. int drBaseY = Math.Min(dstRegion.Y1, dstRegion.Y2);
  465. int drWidth = Math.Abs(dstRegion.X2 - dstRegion.X1);
  466. int drHeight = Math.Abs(dstRegion.Y2 - dstRegion.Y1);
  467. var drOriginZero = new Extents2D(
  468. dstRegion.X1 - drBaseX,
  469. dstRegion.Y1 - drBaseY,
  470. dstRegion.X2 - drBaseX,
  471. dstRegion.Y2 - drBaseY);
  472. var d32SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.D32Float, 4);
  473. var d32DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.D32Float, 4, drWidth, drHeight);
  474. var s8SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.S8Uint, 1);
  475. var s8DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.S8Uint, 1, drWidth, drHeight);
  476. using var d32SrcStorage = gd.CreateTextureStorage(d32SrcStorageInfo, src.Storage.ScaleFactor);
  477. using var d32DstStorage = gd.CreateTextureStorage(d32DstStorageInfo, dst.Storage.ScaleFactor);
  478. using var s8SrcStorage = gd.CreateTextureStorage(s8SrcStorageInfo, src.Storage.ScaleFactor);
  479. using var s8DstStorage = gd.CreateTextureStorage(s8DstStorageInfo, dst.Storage.ScaleFactor);
  480. void SlowBlit(TextureStorage srcTemp, TextureStorage dstTemp, ImageAspectFlags aspectFlags)
  481. {
  482. int levels = Math.Min(src.Info.Levels, dst.Info.Levels);
  483. int srcSize = 0;
  484. int dstSize = 0;
  485. for (int l = 0; l < levels; l++)
  486. {
  487. srcSize += srcTemp.Info.GetMipSize2D(l);
  488. dstSize += dstTemp.Info.GetMipSize2D(l);
  489. }
  490. using var srcTempBuffer = gd.BufferManager.Create(gd, srcSize, deviceLocal: true);
  491. using var dstTempBuffer = gd.BufferManager.Create(gd, dstSize, deviceLocal: true);
  492. src.Storage.CopyFromOrToBuffer(
  493. cbs.CommandBuffer,
  494. srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
  495. src.GetImage().Get(cbs).Value,
  496. srcSize,
  497. to: true,
  498. 0,
  499. 0,
  500. src.FirstLayer,
  501. src.FirstLevel,
  502. 1,
  503. levels,
  504. true,
  505. aspectFlags,
  506. false);
  507. BufferHolder.InsertBufferBarrier(
  508. gd,
  509. cbs.CommandBuffer,
  510. srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
  511. AccessFlags.AccessTransferWriteBit,
  512. AccessFlags.AccessTransferReadBit,
  513. PipelineStageFlags.PipelineStageTransferBit,
  514. PipelineStageFlags.PipelineStageTransferBit,
  515. 0,
  516. srcSize);
  517. srcTemp.CopyFromOrToBuffer(
  518. cbs.CommandBuffer,
  519. srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
  520. srcTemp.GetImage().Get(cbs).Value,
  521. srcSize,
  522. to: false,
  523. 0,
  524. 0,
  525. 0,
  526. 0,
  527. 1,
  528. levels,
  529. true,
  530. aspectFlags,
  531. false);
  532. InsertImageBarrier(
  533. gd.Api,
  534. cbs.CommandBuffer,
  535. srcTemp.GetImage().Get(cbs).Value,
  536. AccessFlags.AccessTransferWriteBit,
  537. AccessFlags.AccessTransferReadBit,
  538. PipelineStageFlags.PipelineStageTransferBit,
  539. PipelineStageFlags.PipelineStageTransferBit,
  540. aspectFlags,
  541. 0,
  542. 0,
  543. 1,
  544. levels);
  545. TextureCopy.Blit(
  546. gd.Api,
  547. cbs.CommandBuffer,
  548. srcTemp.GetImage().Get(cbs).Value,
  549. dstTemp.GetImage().Get(cbs).Value,
  550. srcTemp.Info,
  551. dstTemp.Info,
  552. srcRegion,
  553. drOriginZero,
  554. 0,
  555. 0,
  556. 0,
  557. 0,
  558. 1,
  559. levels,
  560. false,
  561. aspectFlags,
  562. aspectFlags);
  563. InsertImageBarrier(
  564. gd.Api,
  565. cbs.CommandBuffer,
  566. dstTemp.GetImage().Get(cbs).Value,
  567. AccessFlags.AccessTransferWriteBit,
  568. AccessFlags.AccessTransferReadBit,
  569. PipelineStageFlags.PipelineStageTransferBit,
  570. PipelineStageFlags.PipelineStageTransferBit,
  571. aspectFlags,
  572. 0,
  573. 0,
  574. 1,
  575. levels);
  576. dstTemp.CopyFromOrToBuffer(
  577. cbs.CommandBuffer,
  578. dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
  579. dstTemp.GetImage().Get(cbs).Value,
  580. dstSize,
  581. to: true,
  582. 0,
  583. 0,
  584. 0,
  585. 0,
  586. 1,
  587. levels,
  588. true,
  589. aspectFlags,
  590. false);
  591. BufferHolder.InsertBufferBarrier(
  592. gd,
  593. cbs.CommandBuffer,
  594. dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
  595. AccessFlags.AccessTransferWriteBit,
  596. AccessFlags.AccessTransferReadBit,
  597. PipelineStageFlags.PipelineStageTransferBit,
  598. PipelineStageFlags.PipelineStageTransferBit,
  599. 0,
  600. dstSize);
  601. dst.Storage.CopyFromOrToBuffer(
  602. cbs.CommandBuffer,
  603. dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
  604. dst.GetImage().Get(cbs).Value,
  605. dstSize,
  606. to: false,
  607. drBaseX,
  608. drBaseY,
  609. dst.FirstLayer,
  610. dst.FirstLevel,
  611. 1,
  612. levels,
  613. true,
  614. aspectFlags,
  615. false);
  616. }
  617. SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.ImageAspectDepthBit);
  618. SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.ImageAspectStencilBit);
  619. }
  620. public static unsafe void InsertImageBarrier(
  621. Vk api,
  622. CommandBuffer commandBuffer,
  623. Image image,
  624. AccessFlags srcAccessMask,
  625. AccessFlags dstAccessMask,
  626. PipelineStageFlags srcStageMask,
  627. PipelineStageFlags dstStageMask,
  628. ImageAspectFlags aspectFlags,
  629. int firstLayer,
  630. int firstLevel,
  631. int layers,
  632. int levels)
  633. {
  634. ImageMemoryBarrier memoryBarrier = new ImageMemoryBarrier()
  635. {
  636. SType = StructureType.ImageMemoryBarrier,
  637. SrcAccessMask = srcAccessMask,
  638. DstAccessMask = dstAccessMask,
  639. SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
  640. DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
  641. Image = image,
  642. OldLayout = ImageLayout.General,
  643. NewLayout = ImageLayout.General,
  644. SubresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, (uint)levels, (uint)firstLayer, (uint)layers)
  645. };
  646. api.CmdPipelineBarrier(
  647. commandBuffer,
  648. srcStageMask,
  649. dstStageMask,
  650. 0,
  651. 0,
  652. null,
  653. 0,
  654. null,
  655. 1,
  656. memoryBarrier);
  657. }
  658. private bool SupportsBlitFromD32FS8ToD32FAndS8()
  659. {
  660. var formatFeatureFlags = FormatFeatureFlags.FormatFeatureBlitSrcBit | FormatFeatureFlags.FormatFeatureBlitDstBit;
  661. return _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
  662. _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
  663. }
  664. public TextureView GetView(GAL.Format format)
  665. {
  666. if (format == Info.Format)
  667. {
  668. return this;
  669. }
  670. if (_selfManagedViews != null && _selfManagedViews.TryGetValue(format, out var view))
  671. {
  672. return view;
  673. }
  674. view = CreateViewImpl(new TextureCreateInfo(
  675. Info.Width,
  676. Info.Height,
  677. Info.Depth,
  678. Info.Levels,
  679. Info.Samples,
  680. Info.BlockWidth,
  681. Info.BlockHeight,
  682. Info.BytesPerPixel,
  683. format,
  684. Info.DepthStencilMode,
  685. Info.Target,
  686. Info.SwizzleR,
  687. Info.SwizzleG,
  688. Info.SwizzleB,
  689. Info.SwizzleA), 0, 0);
  690. (_selfManagedViews ??= new Dictionary<GAL.Format, TextureView>()).Add(format, view);
  691. return view;
  692. }
  693. public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
  694. {
  695. return CreateViewImpl(info, firstLayer, firstLevel);
  696. }
  697. private TextureView CreateViewImpl(TextureCreateInfo info, int firstLayer, int firstLevel)
  698. {
  699. return new TextureView(_gd, _device, info, Storage, FirstLayer + firstLayer, FirstLevel + firstLevel);
  700. }
  701. public byte[] GetData(int x, int y, int width, int height)
  702. {
  703. int size = width * height * Info.BytesPerPixel;
  704. using var bufferHolder = _gd.BufferManager.Create(_gd, size);
  705. using (var cbs = _gd.CommandBufferPool.Rent())
  706. {
  707. var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
  708. var image = GetImage().Get(cbs).Value;
  709. CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, size, true, 0, 0, x, y, width, height);
  710. }
  711. bufferHolder.WaitForFences();
  712. byte[] bitmap = new byte[size];
  713. GetDataFromBuffer(bufferHolder.GetDataStorage(0, size), size, Span<byte>.Empty).CopyTo(bitmap);
  714. return bitmap;
  715. }
  716. public ReadOnlySpan<byte> GetData()
  717. {
  718. BackgroundResource resources = _gd.BackgroundResources.Get();
  719. if (_gd.CommandBufferPool.OwnedByCurrentThread)
  720. {
  721. _gd.FlushAllCommands();
  722. return GetData(_gd.CommandBufferPool, resources.GetFlushBuffer());
  723. }
  724. else
  725. {
  726. return GetData(resources.GetPool(), resources.GetFlushBuffer());
  727. }
  728. }
  729. public ReadOnlySpan<byte> GetData(int layer, int level)
  730. {
  731. BackgroundResource resources = _gd.BackgroundResources.Get();
  732. if (_gd.CommandBufferPool.OwnedByCurrentThread)
  733. {
  734. _gd.FlushAllCommands();
  735. return GetData(_gd.CommandBufferPool, resources.GetFlushBuffer(), layer, level);
  736. }
  737. else
  738. {
  739. return GetData(resources.GetPool(), resources.GetFlushBuffer(), layer, level);
  740. }
  741. }
  742. private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer)
  743. {
  744. int size = 0;
  745. for (int level = 0; level < Info.Levels; level++)
  746. {
  747. size += Info.GetMipSize(level);
  748. }
  749. size = GetBufferDataLength(size);
  750. Span<byte> result = flushBuffer.GetTextureData(cbp, this, size);
  751. return GetDataFromBuffer(result, size, result);
  752. }
  753. private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer, int layer, int level)
  754. {
  755. int size = GetBufferDataLength(Info.GetMipSize(level));
  756. Span<byte> result = flushBuffer.GetTextureData(cbp, this, size, layer, level);
  757. return GetDataFromBuffer(result, size, result);
  758. }
  759. public void SetData(SpanOrArray<byte> data)
  760. {
  761. SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
  762. }
  763. public void SetData(SpanOrArray<byte> data, int layer, int level)
  764. {
  765. SetData(data, layer, level, 1, 1, singleSlice: true);
  766. }
  767. public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
  768. {
  769. SetData(data, layer, level, 1, 1, singleSlice: true, region);
  770. }
  771. private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice, Rectangle<int>? region = null)
  772. {
  773. int bufferDataLength = GetBufferDataLength(data.Length);
  774. using var bufferHolder = _gd.BufferManager.Create(_gd, bufferDataLength);
  775. Auto<DisposableImage> imageAuto = GetImage();
  776. // Load texture data inline if the texture has been used on the current command buffer.
  777. bool loadInline = Storage.HasCommandBufferDependency(_gd.PipelineInternal.CurrentCommandBuffer);
  778. var cbs = loadInline ? _gd.PipelineInternal.CurrentCommandBuffer : _gd.PipelineInternal.GetPreloadCommandBuffer();
  779. if (loadInline)
  780. {
  781. _gd.PipelineInternal.EndRenderPass();
  782. }
  783. CopyDataToBuffer(bufferHolder.GetDataStorage(0, bufferDataLength), data);
  784. var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
  785. var image = imageAuto.Get(cbs).Value;
  786. if (region.HasValue)
  787. {
  788. CopyFromOrToBuffer(
  789. cbs.CommandBuffer,
  790. buffer,
  791. image,
  792. bufferDataLength,
  793. false,
  794. layer,
  795. level,
  796. region.Value.X,
  797. region.Value.Y,
  798. region.Value.Width,
  799. region.Value.Height);
  800. }
  801. else
  802. {
  803. CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
  804. }
  805. }
  806. private int GetBufferDataLength(int length)
  807. {
  808. if (NeedsD24S8Conversion())
  809. {
  810. return length * 2;
  811. }
  812. return length;
  813. }
  814. private GAL.Format GetCompatibleGalFormat(GAL.Format format)
  815. {
  816. if (NeedsD24S8Conversion())
  817. {
  818. return GAL.Format.D32FloatS8Uint;
  819. }
  820. return format;
  821. }
  822. private void CopyDataToBuffer(Span<byte> storage, ReadOnlySpan<byte> input)
  823. {
  824. if (NeedsD24S8Conversion())
  825. {
  826. FormatConverter.ConvertD24S8ToD32FS8(storage, input);
  827. return;
  828. }
  829. input.CopyTo(storage);
  830. }
  831. private ReadOnlySpan<byte> GetDataFromBuffer(ReadOnlySpan<byte> storage, int size, Span<byte> output)
  832. {
  833. if (NeedsD24S8Conversion())
  834. {
  835. if (output.IsEmpty)
  836. {
  837. output = new byte[GetBufferDataLength(size)];
  838. }
  839. FormatConverter.ConvertD32FS8ToD24S8(output, storage);
  840. return output;
  841. }
  842. return storage;
  843. }
  844. private bool NeedsD24S8Conversion()
  845. {
  846. return FormatCapabilities.IsD24S8(Info.Format) && VkFormat == VkFormat.D32SfloatS8Uint;
  847. }
  848. public void CopyFromOrToBuffer(
  849. CommandBuffer commandBuffer,
  850. VkBuffer buffer,
  851. Image image,
  852. int size,
  853. bool to,
  854. int dstLayer,
  855. int dstLevel,
  856. int dstLayers,
  857. int dstLevels,
  858. bool singleSlice)
  859. {
  860. bool is3D = Info.Target == Target.Texture3D;
  861. int width = Math.Max(1, Info.Width >> dstLevel);
  862. int height = Math.Max(1, Info.Height >> dstLevel);
  863. int depth = is3D && !singleSlice ? Math.Max(1, Info.Depth >> dstLevel) : 1;
  864. int layer = is3D ? 0 : dstLayer;
  865. int layers = dstLayers;
  866. int levels = dstLevels;
  867. int offset = 0;
  868. for (int level = 0; level < levels; level++)
  869. {
  870. int mipSize = GetBufferDataLength(Info.GetMipSize(dstLevel + level));
  871. int endOffset = offset + mipSize;
  872. if ((uint)endOffset > (uint)size)
  873. {
  874. break;
  875. }
  876. int rowLength = (Info.GetMipStride(dstLevel + level) / Info.BytesPerPixel) * Info.BlockWidth;
  877. var aspectFlags = Info.Format.ConvertAspectFlags();
  878. if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit))
  879. {
  880. aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
  881. }
  882. var sl = new ImageSubresourceLayers(
  883. aspectFlags,
  884. (uint)(FirstLevel + dstLevel + level),
  885. (uint)(FirstLayer + layer),
  886. (uint)layers);
  887. var extent = new Extent3D((uint)width, (uint)height, (uint)depth);
  888. int z = is3D ? dstLayer : 0;
  889. var region = new BufferImageCopy(
  890. (ulong)offset,
  891. (uint)AlignUpNpot(rowLength, Info.BlockWidth),
  892. (uint)AlignUpNpot(height, Info.BlockHeight),
  893. sl,
  894. new Offset3D(0, 0, z),
  895. extent);
  896. if (to)
  897. {
  898. _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
  899. }
  900. else
  901. {
  902. _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
  903. }
  904. offset += mipSize;
  905. width = Math.Max(1, width >> 1);
  906. height = Math.Max(1, height >> 1);
  907. if (Info.Target == Target.Texture3D)
  908. {
  909. depth = Math.Max(1, depth >> 1);
  910. }
  911. }
  912. }
  913. private void CopyFromOrToBuffer(
  914. CommandBuffer commandBuffer,
  915. VkBuffer buffer,
  916. Image image,
  917. int size,
  918. bool to,
  919. int dstLayer,
  920. int dstLevel,
  921. int x,
  922. int y,
  923. int width,
  924. int height)
  925. {
  926. var aspectFlags = Info.Format.ConvertAspectFlags();
  927. if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit))
  928. {
  929. aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
  930. }
  931. var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1);
  932. var extent = new Extent3D((uint)width, (uint)height, 1);
  933. int rowLengthAlignment = Info.BlockWidth;
  934. // We expect all data being written into the texture to have a stride aligned by 4.
  935. if (!to && Info.BytesPerPixel < 4)
  936. {
  937. rowLengthAlignment = 4 / Info.BytesPerPixel;
  938. }
  939. var region = new BufferImageCopy(
  940. 0,
  941. (uint)AlignUpNpot(width, rowLengthAlignment),
  942. (uint)AlignUpNpot(height, Info.BlockHeight),
  943. sl,
  944. new Offset3D(x, y, 0),
  945. extent);
  946. if (to)
  947. {
  948. _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
  949. }
  950. else
  951. {
  952. _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
  953. }
  954. }
  955. private static int AlignUpNpot(int size, int alignment)
  956. {
  957. int remainder = size % alignment;
  958. if (remainder == 0)
  959. {
  960. return size;
  961. }
  962. return size + (alignment - remainder);
  963. }
  964. public void SetStorage(BufferRange buffer)
  965. {
  966. throw new NotImplementedException();
  967. }
  968. protected virtual void Dispose(bool disposing)
  969. {
  970. if (disposing)
  971. {
  972. Valid = false;
  973. if (_gd.Textures.Remove(this))
  974. {
  975. _imageView.Dispose();
  976. _imageViewIdentity.Dispose();
  977. _imageView2dArray?.Dispose();
  978. Storage.DecrementViewsCount();
  979. }
  980. }
  981. }
  982. public void Dispose()
  983. {
  984. if (_selfManagedViews != null)
  985. {
  986. foreach (var view in _selfManagedViews.Values)
  987. {
  988. view.Dispose();
  989. }
  990. _selfManagedViews = null;
  991. }
  992. Dispose(true);
  993. }
  994. public void Release()
  995. {
  996. Dispose();
  997. }
  998. }
  999. }