DescriptorSetUpdater.cs 43 KB

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