DescriptorSetUpdater.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  1. using Ryujinx.Common.Memory;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Shader;
  4. using Silk.NET.Vulkan;
  5. using System;
  6. using System.Buffers;
  7. using System.Collections.Generic;
  8. using System.Runtime.CompilerServices;
  9. using System.Runtime.InteropServices;
  10. using Buffer = Silk.NET.Vulkan.Buffer;
  11. using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
  12. using Format = Ryujinx.Graphics.GAL.Format;
  13. using SamplerCreateInfo = Ryujinx.Graphics.GAL.SamplerCreateInfo;
  14. namespace Ryujinx.Graphics.Vulkan
  15. {
  16. class DescriptorSetUpdater
  17. {
  18. private const ulong StorageBufferMaxMirrorable = 0x2000;
  19. private const int ArrayGrowthSize = 16;
  20. private record struct BufferRef
  21. {
  22. public Auto<DisposableBuffer> Buffer;
  23. public int Offset;
  24. public bool Write;
  25. public BufferRef(Auto<DisposableBuffer> buffer)
  26. {
  27. Buffer = buffer;
  28. Offset = 0;
  29. Write = true;
  30. }
  31. public BufferRef(Auto<DisposableBuffer> buffer, ref BufferRange range)
  32. {
  33. Buffer = buffer;
  34. Offset = range.Offset;
  35. Write = range.Write;
  36. }
  37. }
  38. private record struct TextureRef
  39. {
  40. public ShaderStage Stage;
  41. public TextureView View;
  42. public Auto<DisposableImageView> ImageView;
  43. public Auto<DisposableSampler> Sampler;
  44. public TextureRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView, Auto<DisposableSampler> sampler)
  45. {
  46. Stage = stage;
  47. View = view;
  48. ImageView = imageView;
  49. Sampler = sampler;
  50. }
  51. }
  52. private record struct ImageRef
  53. {
  54. public ShaderStage Stage;
  55. public TextureView View;
  56. public Auto<DisposableImageView> ImageView;
  57. public ImageRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView)
  58. {
  59. Stage = stage;
  60. View = view;
  61. ImageView = imageView;
  62. }
  63. }
  64. private readonly record struct ArrayRef<T>(ShaderStage Stage, T Array);
  65. private readonly VulkanRenderer _gd;
  66. private readonly Device _device;
  67. private ShaderCollection _program;
  68. private readonly BufferRef[] _uniformBufferRefs;
  69. private readonly BufferRef[] _storageBufferRefs;
  70. private readonly TextureRef[] _textureRefs;
  71. private readonly ImageRef[] _imageRefs;
  72. private readonly TextureBuffer[] _bufferTextureRefs;
  73. private readonly TextureBuffer[] _bufferImageRefs;
  74. private ArrayRef<TextureArray>[] _textureArrayRefs;
  75. private ArrayRef<ImageArray>[] _imageArrayRefs;
  76. private ArrayRef<TextureArray>[] _textureArrayExtraRefs;
  77. private ArrayRef<ImageArray>[] _imageArrayExtraRefs;
  78. private readonly DescriptorBufferInfo[] _uniformBuffers;
  79. private readonly DescriptorBufferInfo[] _storageBuffers;
  80. private readonly DescriptorImageInfo[] _textures;
  81. private readonly DescriptorImageInfo[] _images;
  82. private readonly BufferView[] _bufferTextures;
  83. private readonly BufferView[] _bufferImages;
  84. private readonly DescriptorSetTemplateUpdater _templateUpdater;
  85. private BitMapStruct<Array2<long>> _uniformSet;
  86. private BitMapStruct<Array2<long>> _storageSet;
  87. private BitMapStruct<Array2<long>> _uniformMirrored;
  88. private BitMapStruct<Array2<long>> _storageMirrored;
  89. private readonly int[] _uniformSetPd;
  90. private int _pdSequence = 1;
  91. private bool _updateDescriptorCacheCbIndex;
  92. [Flags]
  93. private enum DirtyFlags
  94. {
  95. None = 0,
  96. Uniform = 1 << 0,
  97. Storage = 1 << 1,
  98. Texture = 1 << 2,
  99. Image = 1 << 3,
  100. All = Uniform | Storage | Texture | Image,
  101. }
  102. private DirtyFlags _dirty;
  103. private readonly BufferHolder _dummyBuffer;
  104. private readonly TextureView _dummyTexture;
  105. private readonly SamplerHolder _dummySampler;
  106. public List<TextureView> FeedbackLoopHazards { get; private set; }
  107. public DescriptorSetUpdater(VulkanRenderer gd, Device device)
  108. {
  109. _gd = gd;
  110. _device = device;
  111. // Some of the bindings counts needs to be multiplied by 2 because we have buffer and
  112. // regular textures/images interleaved on the same descriptor set.
  113. _uniformBufferRefs = new BufferRef[Constants.MaxUniformBufferBindings];
  114. _storageBufferRefs = new BufferRef[Constants.MaxStorageBufferBindings];
  115. _textureRefs = new TextureRef[Constants.MaxTextureBindings * 2];
  116. _imageRefs = new ImageRef[Constants.MaxImageBindings * 2];
  117. _bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2];
  118. _bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2];
  119. _textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
  120. _imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
  121. _textureArrayExtraRefs = Array.Empty<ArrayRef<TextureArray>>();
  122. _imageArrayExtraRefs = Array.Empty<ArrayRef<ImageArray>>();
  123. _uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings];
  124. _storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings];
  125. _textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage];
  126. _images = new DescriptorImageInfo[Constants.MaxImagesPerStage];
  127. _bufferTextures = new BufferView[Constants.MaxTexturesPerStage];
  128. _bufferImages = new BufferView[Constants.MaxImagesPerStage];
  129. _uniformSetPd = new int[Constants.MaxUniformBufferBindings];
  130. DescriptorImageInfo initialImageInfo = new DescriptorImageInfo
  131. {
  132. ImageLayout = ImageLayout.General,
  133. };
  134. _textures.AsSpan().Fill(initialImageInfo);
  135. _images.AsSpan().Fill(initialImageInfo);
  136. if (gd.Capabilities.SupportsNullDescriptors)
  137. {
  138. // If null descriptors are supported, we can pass null as the handle.
  139. _dummyBuffer = null;
  140. }
  141. else
  142. {
  143. // If null descriptors are not supported, we need to pass the handle of a dummy buffer on unused bindings.
  144. _dummyBuffer = gd.BufferManager.Create(gd, 0x10000, forConditionalRendering: false, baseType: BufferAllocationType.DeviceLocal);
  145. }
  146. _dummyTexture = gd.CreateTextureView(new TextureCreateInfo(
  147. 1,
  148. 1,
  149. 1,
  150. 1,
  151. 1,
  152. 1,
  153. 1,
  154. 4,
  155. Format.R8G8B8A8Unorm,
  156. DepthStencilMode.Depth,
  157. Target.Texture2D,
  158. SwizzleComponent.Red,
  159. SwizzleComponent.Green,
  160. SwizzleComponent.Blue,
  161. SwizzleComponent.Alpha));
  162. _dummySampler = (SamplerHolder)gd.CreateSampler(new SamplerCreateInfo(
  163. MinFilter.Nearest,
  164. MagFilter.Nearest,
  165. false,
  166. AddressMode.Repeat,
  167. AddressMode.Repeat,
  168. AddressMode.Repeat,
  169. CompareMode.None,
  170. CompareOp.Always,
  171. new ColorF(0, 0, 0, 0),
  172. 0,
  173. 0,
  174. 0,
  175. 1f));
  176. _templateUpdater = new();
  177. }
  178. public void Initialize(bool isMainPipeline)
  179. {
  180. MemoryOwner<byte> dummyTextureData = MemoryOwner<byte>.RentCleared(4);
  181. _dummyTexture.SetData(dummyTextureData);
  182. if (isMainPipeline)
  183. {
  184. FeedbackLoopHazards = new();
  185. }
  186. }
  187. private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size)
  188. {
  189. return offset < bindingOffset + (int)info.Range && (offset + size) > bindingOffset;
  190. }
  191. internal void Rebind(Auto<DisposableBuffer> buffer, int offset, int size)
  192. {
  193. if (_program == null)
  194. {
  195. return;
  196. }
  197. // Check stage bindings
  198. _uniformMirrored.Union(_uniformSet).SignalSet((int binding, int count) =>
  199. {
  200. for (int i = 0; i < count; i++)
  201. {
  202. ref BufferRef bufferRef = ref _uniformBufferRefs[binding];
  203. if (bufferRef.Buffer == buffer)
  204. {
  205. ref DescriptorBufferInfo info = ref _uniformBuffers[binding];
  206. int bindingOffset = bufferRef.Offset;
  207. if (BindingOverlaps(ref info, bindingOffset, offset, size))
  208. {
  209. _uniformSet.Clear(binding);
  210. _uniformSetPd[binding] = 0;
  211. SignalDirty(DirtyFlags.Uniform);
  212. }
  213. }
  214. binding++;
  215. }
  216. });
  217. _storageMirrored.Union(_storageSet).SignalSet((int binding, int count) =>
  218. {
  219. for (int i = 0; i < count; i++)
  220. {
  221. ref BufferRef bufferRef = ref _storageBufferRefs[binding];
  222. if (bufferRef.Buffer == buffer)
  223. {
  224. ref DescriptorBufferInfo info = ref _storageBuffers[binding];
  225. int bindingOffset = bufferRef.Offset;
  226. if (BindingOverlaps(ref info, bindingOffset, offset, size))
  227. {
  228. _storageSet.Clear(binding);
  229. SignalDirty(DirtyFlags.Storage);
  230. }
  231. }
  232. binding++;
  233. }
  234. });
  235. }
  236. public void InsertBindingBarriers(CommandBufferScoped cbs)
  237. {
  238. if ((FeedbackLoopHazards?.Count ?? 0) > 0)
  239. {
  240. // Clear existing hazards - they will be rebuilt.
  241. foreach (TextureView hazard in FeedbackLoopHazards)
  242. {
  243. hazard.DecrementHazardUses();
  244. }
  245. FeedbackLoopHazards.Clear();
  246. }
  247. foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex])
  248. {
  249. if (segment.Type == ResourceType.TextureAndSampler)
  250. {
  251. if (!segment.IsArray)
  252. {
  253. for (int i = 0; i < segment.Count; i++)
  254. {
  255. ref TextureRef texture = ref _textureRefs[segment.Binding + i];
  256. texture.View?.PrepareForUsage(cbs, texture.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
  257. }
  258. }
  259. else
  260. {
  261. ref ArrayRef<TextureArray> arrayRef = ref _textureArrayRefs[segment.Binding];
  262. PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
  263. arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
  264. }
  265. }
  266. }
  267. foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.ImageSetIndex])
  268. {
  269. if (segment.Type == ResourceType.Image)
  270. {
  271. if (!segment.IsArray)
  272. {
  273. for (int i = 0; i < segment.Count; i++)
  274. {
  275. ref ImageRef image = ref _imageRefs[segment.Binding + i];
  276. image.View?.PrepareForUsage(cbs, image.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
  277. }
  278. }
  279. else
  280. {
  281. ref ArrayRef<ImageArray> arrayRef = ref _imageArrayRefs[segment.Binding];
  282. PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
  283. arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
  284. }
  285. }
  286. }
  287. for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < _program.BindingSegments.Length; setIndex++)
  288. {
  289. ResourceBindingSegment[] bindingSegments = _program.BindingSegments[setIndex];
  290. if (bindingSegments.Length == 0)
  291. {
  292. continue;
  293. }
  294. ResourceBindingSegment segment = bindingSegments[0];
  295. if (segment.IsArray)
  296. {
  297. if (segment.Type == ResourceType.Texture ||
  298. segment.Type == ResourceType.Sampler ||
  299. segment.Type == ResourceType.TextureAndSampler ||
  300. segment.Type == ResourceType.BufferTexture)
  301. {
  302. ref ArrayRef<TextureArray> arrayRef = ref _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts];
  303. PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
  304. arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
  305. }
  306. else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage)
  307. {
  308. ref ArrayRef<ImageArray> arrayRef = ref _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts];
  309. PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
  310. arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
  311. }
  312. }
  313. }
  314. }
  315. public void AdvancePdSequence()
  316. {
  317. if (++_pdSequence == 0)
  318. {
  319. _pdSequence = 1;
  320. }
  321. }
  322. public void SetProgram(CommandBufferScoped cbs, ShaderCollection program, bool isBound)
  323. {
  324. if (!program.HasSameLayout(_program))
  325. {
  326. // When the pipeline layout changes, push descriptor bindings are invalidated.
  327. AdvancePdSequence();
  328. }
  329. _program = program;
  330. _updateDescriptorCacheCbIndex = true;
  331. _dirty = DirtyFlags.All;
  332. }
  333. public void SetImage(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture image)
  334. {
  335. if (image is TextureBuffer imageBuffer)
  336. {
  337. _bufferImageRefs[binding] = imageBuffer;
  338. }
  339. else if (image is TextureView view)
  340. {
  341. ref ImageRef iRef = ref _imageRefs[binding];
  342. iRef.View?.ClearUsage(FeedbackLoopHazards);
  343. view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
  344. iRef = new(stage, view, view.GetIdentityImageView());
  345. }
  346. else
  347. {
  348. _imageRefs[binding] = default;
  349. _bufferImageRefs[binding] = null;
  350. }
  351. SignalDirty(DirtyFlags.Image);
  352. }
  353. public void SetImage(int binding, Auto<DisposableImageView> image)
  354. {
  355. _imageRefs[binding] = new(ShaderStage.Compute, null, image);
  356. SignalDirty(DirtyFlags.Image);
  357. }
  358. public void SetStorageBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
  359. {
  360. for (int i = 0; i < buffers.Length; i++)
  361. {
  362. BufferAssignment assignment = buffers[i];
  363. BufferRange buffer = assignment.Range;
  364. int index = assignment.Binding;
  365. Auto<DisposableBuffer> vkBuffer = buffer.Handle == BufferHandle.Null
  366. ? null
  367. : _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, buffer.Write, isSSBO: true);
  368. ref BufferRef currentBufferRef = ref _storageBufferRefs[index];
  369. DescriptorBufferInfo info = new()
  370. {
  371. Offset = (ulong)buffer.Offset,
  372. Range = (ulong)buffer.Size,
  373. };
  374. BufferRef newRef = new BufferRef(vkBuffer, ref buffer);
  375. ref DescriptorBufferInfo currentInfo = ref _storageBuffers[index];
  376. if (!currentBufferRef.Equals(newRef) || currentInfo.Range != info.Range)
  377. {
  378. _storageSet.Clear(index);
  379. currentInfo = info;
  380. currentBufferRef = newRef;
  381. }
  382. }
  383. SignalDirty(DirtyFlags.Storage);
  384. }
  385. public void SetStorageBuffers(CommandBuffer commandBuffer, int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
  386. {
  387. for (int i = 0; i < buffers.Length; i++)
  388. {
  389. Auto<DisposableBuffer> vkBuffer = buffers[i];
  390. int index = first + i;
  391. ref BufferRef currentBufferRef = ref _storageBufferRefs[index];
  392. DescriptorBufferInfo info = new()
  393. {
  394. Offset = 0,
  395. Range = Vk.WholeSize,
  396. };
  397. BufferRef newRef = new(vkBuffer);
  398. ref DescriptorBufferInfo currentInfo = ref _storageBuffers[index];
  399. if (!currentBufferRef.Equals(newRef) || currentInfo.Range != info.Range)
  400. {
  401. _storageSet.Clear(index);
  402. currentInfo = info;
  403. currentBufferRef = newRef;
  404. }
  405. }
  406. SignalDirty(DirtyFlags.Storage);
  407. }
  408. public void SetTextureAndSampler(
  409. CommandBufferScoped cbs,
  410. ShaderStage stage,
  411. int binding,
  412. ITexture texture,
  413. ISampler sampler)
  414. {
  415. if (texture is TextureBuffer textureBuffer)
  416. {
  417. _bufferTextureRefs[binding] = textureBuffer;
  418. }
  419. else if (texture is TextureView view)
  420. {
  421. ref TextureRef iRef = ref _textureRefs[binding];
  422. iRef.View?.ClearUsage(FeedbackLoopHazards);
  423. view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
  424. iRef = new(stage, view, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
  425. }
  426. else
  427. {
  428. _textureRefs[binding] = default;
  429. _bufferTextureRefs[binding] = null;
  430. }
  431. SignalDirty(DirtyFlags.Texture);
  432. }
  433. public void SetTextureAndSamplerIdentitySwizzle(
  434. CommandBufferScoped cbs,
  435. ShaderStage stage,
  436. int binding,
  437. ITexture texture,
  438. ISampler sampler)
  439. {
  440. if (texture is TextureView view)
  441. {
  442. view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
  443. _textureRefs[binding] = new(stage, view, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
  444. SignalDirty(DirtyFlags.Texture);
  445. }
  446. else
  447. {
  448. SetTextureAndSampler(cbs, stage, binding, texture, sampler);
  449. }
  450. }
  451. public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int binding, ITextureArray array)
  452. {
  453. ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayRefs, binding, ArrayGrowthSize);
  454. if (arrayRef.Stage != stage || arrayRef.Array != array)
  455. {
  456. arrayRef.Array?.DecrementBindCount();
  457. if (array is TextureArray textureArray)
  458. {
  459. textureArray.IncrementBindCount();
  460. textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
  461. }
  462. arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
  463. SignalDirty(DirtyFlags.Texture);
  464. }
  465. }
  466. public void SetTextureArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, ITextureArray array)
  467. {
  468. ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
  469. if (arrayRef.Stage != stage || arrayRef.Array != array)
  470. {
  471. arrayRef.Array?.DecrementBindCount();
  472. if (array is TextureArray textureArray)
  473. {
  474. textureArray.IncrementBindCount();
  475. textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
  476. }
  477. arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
  478. SignalDirty(DirtyFlags.Texture);
  479. }
  480. }
  481. public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array)
  482. {
  483. ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayRefs, binding, ArrayGrowthSize);
  484. if (arrayRef.Stage != stage || arrayRef.Array != array)
  485. {
  486. arrayRef.Array?.DecrementBindCount();
  487. if (array is ImageArray imageArray)
  488. {
  489. imageArray.IncrementBindCount();
  490. imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
  491. }
  492. arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
  493. SignalDirty(DirtyFlags.Image);
  494. }
  495. }
  496. public void SetImageArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, IImageArray array)
  497. {
  498. ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
  499. if (arrayRef.Stage != stage || arrayRef.Array != array)
  500. {
  501. arrayRef.Array?.DecrementBindCount();
  502. if (array is ImageArray imageArray)
  503. {
  504. imageArray.IncrementBindCount();
  505. imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
  506. }
  507. arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
  508. SignalDirty(DirtyFlags.Image);
  509. }
  510. }
  511. private static ref ArrayRef<T> GetArrayRef<T>(ref ArrayRef<T>[] array, int index, int growthSize = 1)
  512. {
  513. ArgumentOutOfRangeException.ThrowIfNegative(index);
  514. if (array.Length <= index)
  515. {
  516. Array.Resize(ref array, index + growthSize);
  517. }
  518. return ref array[index];
  519. }
  520. public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
  521. {
  522. for (int i = 0; i < buffers.Length; i++)
  523. {
  524. BufferAssignment assignment = buffers[i];
  525. BufferRange buffer = assignment.Range;
  526. int index = assignment.Binding;
  527. Auto<DisposableBuffer> vkBuffer = buffer.Handle == BufferHandle.Null
  528. ? null
  529. : _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false);
  530. ref BufferRef currentBufferRef = ref _uniformBufferRefs[index];
  531. DescriptorBufferInfo info = new()
  532. {
  533. Offset = (ulong)buffer.Offset,
  534. Range = (ulong)buffer.Size,
  535. };
  536. BufferRef newRef = new(vkBuffer, ref buffer);
  537. ref DescriptorBufferInfo currentInfo = ref _uniformBuffers[index];
  538. if (!currentBufferRef.Equals(newRef) || currentInfo.Range != info.Range)
  539. {
  540. _uniformSet.Clear(index);
  541. _uniformSetPd[index] = 0;
  542. currentInfo = info;
  543. currentBufferRef = newRef;
  544. }
  545. }
  546. SignalDirty(DirtyFlags.Uniform);
  547. }
  548. private void SignalDirty(DirtyFlags flag)
  549. {
  550. _dirty |= flag;
  551. }
  552. public void UpdateAndBindDescriptorSets(CommandBufferScoped cbs, PipelineBindPoint pbp)
  553. {
  554. if ((_dirty & DirtyFlags.All) == 0)
  555. {
  556. return;
  557. }
  558. ShaderCollection program = _program;
  559. if (_dirty.HasFlag(DirtyFlags.Uniform))
  560. {
  561. if (program.UsePushDescriptors)
  562. {
  563. UpdateAndBindUniformBufferPd(cbs);
  564. }
  565. else
  566. {
  567. UpdateAndBind(cbs, program, PipelineBase.UniformSetIndex, pbp);
  568. }
  569. }
  570. if (_dirty.HasFlag(DirtyFlags.Storage))
  571. {
  572. UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
  573. }
  574. if (_dirty.HasFlag(DirtyFlags.Texture))
  575. {
  576. if (program.UpdateTexturesWithoutTemplate)
  577. {
  578. UpdateAndBindTexturesWithoutTemplate(cbs, program, pbp);
  579. }
  580. else
  581. {
  582. UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
  583. }
  584. }
  585. if (_dirty.HasFlag(DirtyFlags.Image))
  586. {
  587. UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp);
  588. }
  589. if (program.BindingSegments.Length > PipelineBase.DescriptorSetLayouts)
  590. {
  591. // Program is using extra sets, we need to bind those too.
  592. BindExtraSets(cbs, program, pbp);
  593. }
  594. _dirty = DirtyFlags.None;
  595. }
  596. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  597. private static bool UpdateBuffer(
  598. CommandBufferScoped cbs,
  599. ref DescriptorBufferInfo info,
  600. ref BufferRef buffer,
  601. Auto<DisposableBuffer> dummyBuffer,
  602. bool mirrorable)
  603. {
  604. int offset = buffer.Offset;
  605. bool mirrored = false;
  606. if (mirrorable)
  607. {
  608. info.Buffer = buffer.Buffer?.GetMirrorable(cbs, ref offset, (int)info.Range, out mirrored).Value ?? default;
  609. }
  610. else
  611. {
  612. info.Buffer = buffer.Buffer?.Get(cbs, offset, (int)info.Range, buffer.Write).Value ?? default;
  613. }
  614. info.Offset = (ulong)offset;
  615. // The spec requires that buffers with null handle have offset as 0 and range as VK_WHOLE_SIZE.
  616. if (info.Buffer.Handle == 0)
  617. {
  618. info.Buffer = dummyBuffer?.Get(cbs).Value ?? default;
  619. info.Offset = 0;
  620. info.Range = Vk.WholeSize;
  621. }
  622. return mirrored;
  623. }
  624. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  625. private void UpdateAndBind(CommandBufferScoped cbs, ShaderCollection program, int setIndex, PipelineBindPoint pbp)
  626. {
  627. ResourceBindingSegment[] bindingSegments = program.BindingSegments[setIndex];
  628. if (bindingSegments.Length == 0)
  629. {
  630. return;
  631. }
  632. Auto<DisposableBuffer> dummyBuffer = _dummyBuffer?.GetBuffer();
  633. if (_updateDescriptorCacheCbIndex)
  634. {
  635. _updateDescriptorCacheCbIndex = false;
  636. program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex);
  637. }
  638. DescriptorSetCollection dsc = program.GetNewDescriptorSetCollection(setIndex, out bool isNew).Get(cbs);
  639. if (!program.HasMinimalLayout)
  640. {
  641. if (isNew)
  642. {
  643. Initialize(cbs, setIndex, dsc);
  644. }
  645. }
  646. DescriptorSetTemplate template = program.Templates[setIndex];
  647. DescriptorSetTemplateWriter tu = _templateUpdater.Begin(template);
  648. foreach (ResourceBindingSegment segment in bindingSegments)
  649. {
  650. int binding = segment.Binding;
  651. int count = segment.Count;
  652. if (setIndex == PipelineBase.UniformSetIndex)
  653. {
  654. for (int i = 0; i < count; i++)
  655. {
  656. int index = binding + i;
  657. if (_uniformSet.Set(index))
  658. {
  659. ref BufferRef buffer = ref _uniformBufferRefs[index];
  660. bool mirrored = UpdateBuffer(cbs, ref _uniformBuffers[index], ref buffer, dummyBuffer, true);
  661. _uniformMirrored.Set(index, mirrored);
  662. }
  663. }
  664. ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
  665. tu.Push(uniformBuffers.Slice(binding, count));
  666. }
  667. else if (setIndex == PipelineBase.StorageSetIndex)
  668. {
  669. for (int i = 0; i < count; i++)
  670. {
  671. int index = binding + i;
  672. ref BufferRef buffer = ref _storageBufferRefs[index];
  673. if (_storageSet.Set(index))
  674. {
  675. ref DescriptorBufferInfo info = ref _storageBuffers[index];
  676. bool mirrored = UpdateBuffer(cbs,
  677. ref info,
  678. ref _storageBufferRefs[index],
  679. dummyBuffer,
  680. !buffer.Write && info.Range <= StorageBufferMaxMirrorable);
  681. _storageMirrored.Set(index, mirrored);
  682. }
  683. }
  684. ReadOnlySpan<DescriptorBufferInfo> storageBuffers = _storageBuffers;
  685. tu.Push(storageBuffers.Slice(binding, count));
  686. }
  687. else if (setIndex == PipelineBase.TextureSetIndex)
  688. {
  689. if (!segment.IsArray)
  690. {
  691. if (segment.Type != ResourceType.BufferTexture)
  692. {
  693. Span<DescriptorImageInfo> textures = _textures;
  694. for (int i = 0; i < count; i++)
  695. {
  696. ref DescriptorImageInfo texture = ref textures[i];
  697. ref TextureRef refs = ref _textureRefs[binding + i];
  698. texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
  699. texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
  700. if (texture.ImageView.Handle == 0)
  701. {
  702. texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value;
  703. }
  704. if (texture.Sampler.Handle == 0)
  705. {
  706. texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value;
  707. }
  708. }
  709. tu.Push<DescriptorImageInfo>(textures[..count]);
  710. }
  711. else
  712. {
  713. Span<BufferView> bufferTextures = _bufferTextures;
  714. for (int i = 0; i < count; i++)
  715. {
  716. bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default;
  717. }
  718. tu.Push<BufferView>(bufferTextures[..count]);
  719. }
  720. }
  721. else
  722. {
  723. if (segment.Type != ResourceType.BufferTexture)
  724. {
  725. tu.Push(_textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler));
  726. }
  727. else
  728. {
  729. tu.Push(_textureArrayRefs[binding].Array.GetBufferViews(cbs));
  730. }
  731. }
  732. }
  733. else if (setIndex == PipelineBase.ImageSetIndex)
  734. {
  735. if (!segment.IsArray)
  736. {
  737. if (segment.Type != ResourceType.BufferImage)
  738. {
  739. Span<DescriptorImageInfo> images = _images;
  740. for (int i = 0; i < count; i++)
  741. {
  742. images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default;
  743. }
  744. tu.Push<DescriptorImageInfo>(images[..count]);
  745. }
  746. else
  747. {
  748. Span<BufferView> bufferImages = _bufferImages;
  749. for (int i = 0; i < count; i++)
  750. {
  751. bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default;
  752. }
  753. tu.Push<BufferView>(bufferImages[..count]);
  754. }
  755. }
  756. else
  757. {
  758. if (segment.Type != ResourceType.BufferTexture)
  759. {
  760. tu.Push(_imageArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture));
  761. }
  762. else
  763. {
  764. tu.Push(_imageArrayRefs[binding].Array.GetBufferViews(cbs));
  765. }
  766. }
  767. }
  768. }
  769. DescriptorSet[] sets = dsc.GetSets();
  770. _templateUpdater.Commit(_gd, _device, sets[0]);
  771. _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
  772. }
  773. private void UpdateAndBindTexturesWithoutTemplate(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
  774. {
  775. int setIndex = PipelineBase.TextureSetIndex;
  776. ResourceBindingSegment[] bindingSegments = program.BindingSegments[setIndex];
  777. if (bindingSegments.Length == 0)
  778. {
  779. return;
  780. }
  781. if (_updateDescriptorCacheCbIndex)
  782. {
  783. _updateDescriptorCacheCbIndex = false;
  784. program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex);
  785. }
  786. DescriptorSetCollection dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs);
  787. foreach (ResourceBindingSegment segment in bindingSegments)
  788. {
  789. int binding = segment.Binding;
  790. int count = segment.Count;
  791. if (!segment.IsArray)
  792. {
  793. if (segment.Type != ResourceType.BufferTexture)
  794. {
  795. Span<DescriptorImageInfo> textures = _textures;
  796. for (int i = 0; i < count; i++)
  797. {
  798. ref DescriptorImageInfo texture = ref textures[i];
  799. ref TextureRef refs = ref _textureRefs[binding + i];
  800. texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
  801. texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
  802. if (texture.ImageView.Handle == 0)
  803. {
  804. texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value;
  805. }
  806. if (texture.Sampler.Handle == 0)
  807. {
  808. texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value;
  809. }
  810. }
  811. dsc.UpdateImages(0, binding, textures[..count], DescriptorType.CombinedImageSampler);
  812. }
  813. else
  814. {
  815. Span<BufferView> bufferTextures = _bufferTextures;
  816. for (int i = 0; i < count; i++)
  817. {
  818. bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default;
  819. }
  820. dsc.UpdateBufferImages(0, binding, bufferTextures[..count], DescriptorType.UniformTexelBuffer);
  821. }
  822. }
  823. else
  824. {
  825. if (segment.Type != ResourceType.BufferTexture)
  826. {
  827. dsc.UpdateImages(0, binding, _textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler), DescriptorType.CombinedImageSampler);
  828. }
  829. else
  830. {
  831. dsc.UpdateBufferImages(0, binding, _textureArrayRefs[binding].Array.GetBufferViews(cbs), DescriptorType.UniformTexelBuffer);
  832. }
  833. }
  834. }
  835. DescriptorSet[] sets = dsc.GetSets();
  836. _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
  837. }
  838. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  839. private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs)
  840. {
  841. int sequence = _pdSequence;
  842. ResourceBindingSegment[] bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex];
  843. Auto<DisposableBuffer> dummyBuffer = _dummyBuffer?.GetBuffer();
  844. long updatedBindings = 0;
  845. DescriptorSetTemplateWriter writer = _templateUpdater.Begin(32 * Unsafe.SizeOf<DescriptorBufferInfo>());
  846. foreach (ResourceBindingSegment segment in bindingSegments)
  847. {
  848. int binding = segment.Binding;
  849. int count = segment.Count;
  850. ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
  851. for (int i = 0; i < count; i++)
  852. {
  853. int index = binding + i;
  854. if (_uniformSet.Set(index))
  855. {
  856. ref BufferRef buffer = ref _uniformBufferRefs[index];
  857. bool mirrored = UpdateBuffer(cbs, ref _uniformBuffers[index], ref buffer, dummyBuffer, true);
  858. _uniformMirrored.Set(index, mirrored);
  859. }
  860. if (_uniformSetPd[index] != sequence)
  861. {
  862. // Need to set this push descriptor (even if the buffer binding has not changed)
  863. _uniformSetPd[index] = sequence;
  864. updatedBindings |= 1L << index;
  865. writer.Push(MemoryMarshal.CreateReadOnlySpan(ref _uniformBuffers[index], 1));
  866. }
  867. }
  868. }
  869. if (updatedBindings > 0)
  870. {
  871. DescriptorSetTemplate template = _program.GetPushDescriptorTemplate(updatedBindings);
  872. _templateUpdater.CommitPushDescriptor(_gd, cbs, template, _program.PipelineLayout);
  873. }
  874. }
  875. private void Initialize(CommandBufferScoped cbs, int setIndex, DescriptorSetCollection dsc)
  876. {
  877. // We don't support clearing texture descriptors currently.
  878. if (setIndex != PipelineBase.UniformSetIndex && setIndex != PipelineBase.StorageSetIndex)
  879. {
  880. return;
  881. }
  882. Buffer dummyBuffer = _dummyBuffer?.GetBuffer().Get(cbs).Value ?? default;
  883. foreach (ResourceBindingSegment segment in _program.ClearSegments[setIndex])
  884. {
  885. dsc.InitializeBuffers(0, segment.Binding, segment.Count, segment.Type.Convert(), dummyBuffer);
  886. }
  887. }
  888. private void BindExtraSets(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
  889. {
  890. for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < program.BindingSegments.Length; setIndex++)
  891. {
  892. ResourceBindingSegment[] bindingSegments = program.BindingSegments[setIndex];
  893. if (bindingSegments.Length == 0)
  894. {
  895. continue;
  896. }
  897. ResourceBindingSegment segment = bindingSegments[0];
  898. if (segment.IsArray)
  899. {
  900. DescriptorSet[] sets = null;
  901. if (segment.Type == ResourceType.Texture ||
  902. segment.Type == ResourceType.Sampler ||
  903. segment.Type == ResourceType.TextureAndSampler ||
  904. segment.Type == ResourceType.BufferTexture)
  905. {
  906. sets = _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
  907. _device,
  908. cbs,
  909. _templateUpdater,
  910. program,
  911. setIndex,
  912. _dummyTexture,
  913. _dummySampler);
  914. }
  915. else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage)
  916. {
  917. sets = _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
  918. _device,
  919. cbs,
  920. _templateUpdater,
  921. program,
  922. setIndex,
  923. _dummyTexture);
  924. }
  925. if (sets != null)
  926. {
  927. _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
  928. }
  929. }
  930. }
  931. }
  932. public void SignalCommandBufferChange()
  933. {
  934. _updateDescriptorCacheCbIndex = true;
  935. _dirty = DirtyFlags.All;
  936. _uniformSet.Clear();
  937. _storageSet.Clear();
  938. AdvancePdSequence();
  939. }
  940. public void ForceTextureDirty()
  941. {
  942. SignalDirty(DirtyFlags.Texture);
  943. }
  944. public void ForceImageDirty()
  945. {
  946. SignalDirty(DirtyFlags.Image);
  947. }
  948. private static void SwapBuffer(BufferRef[] list, Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
  949. {
  950. for (int i = 0; i < list.Length; i++)
  951. {
  952. if (list[i].Buffer == from)
  953. {
  954. list[i].Buffer = to;
  955. }
  956. }
  957. }
  958. public void SwapBuffer(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
  959. {
  960. SwapBuffer(_uniformBufferRefs, from, to);
  961. SwapBuffer(_storageBufferRefs, from, to);
  962. }
  963. protected virtual void Dispose(bool disposing)
  964. {
  965. if (disposing)
  966. {
  967. _dummyTexture.Dispose();
  968. _dummySampler.Dispose();
  969. _templateUpdater.Dispose();
  970. }
  971. }
  972. public void Dispose()
  973. {
  974. Dispose(true);
  975. }
  976. }
  977. }