DescriptorSetUpdater.cs 43 KB

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