DescriptorSetUpdater.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. using Ryujinx.Graphics.GAL;
  2. using Ryujinx.Graphics.Shader;
  3. using Silk.NET.Vulkan;
  4. using System;
  5. using System.Numerics;
  6. using System.Runtime.CompilerServices;
  7. namespace Ryujinx.Graphics.Vulkan
  8. {
  9. class DescriptorSetUpdater
  10. {
  11. private readonly VulkanRenderer _gd;
  12. private readonly PipelineBase _pipeline;
  13. private ShaderCollection _program;
  14. private Auto<DisposableBuffer>[] _uniformBufferRefs;
  15. private Auto<DisposableBuffer>[] _storageBufferRefs;
  16. private Auto<DisposableImageView>[] _textureRefs;
  17. private Auto<DisposableSampler>[] _samplerRefs;
  18. private Auto<DisposableImageView>[] _imageRefs;
  19. private TextureBuffer[] _bufferTextureRefs;
  20. private TextureBuffer[] _bufferImageRefs;
  21. private GAL.Format[] _bufferImageFormats;
  22. private DescriptorBufferInfo[] _uniformBuffers;
  23. private DescriptorBufferInfo[] _storageBuffers;
  24. private DescriptorImageInfo[] _textures;
  25. private DescriptorImageInfo[] _images;
  26. private BufferView[] _bufferTextures;
  27. private BufferView[] _bufferImages;
  28. private bool[] _uniformSet;
  29. private bool[] _storageSet;
  30. private Silk.NET.Vulkan.Buffer _cachedSupportBuffer;
  31. [Flags]
  32. private enum DirtyFlags
  33. {
  34. None = 0,
  35. Uniform = 1 << 0,
  36. Storage = 1 << 1,
  37. Texture = 1 << 2,
  38. Image = 1 << 3,
  39. All = Uniform | Storage | Texture | Image
  40. }
  41. private DirtyFlags _dirty;
  42. private readonly BufferHolder _dummyBuffer;
  43. private readonly TextureView _dummyTexture;
  44. private readonly SamplerHolder _dummySampler;
  45. public DescriptorSetUpdater(VulkanRenderer gd, PipelineBase pipeline)
  46. {
  47. _gd = gd;
  48. _pipeline = pipeline;
  49. // Some of the bindings counts needs to be multiplied by 2 because we have buffer and
  50. // regular textures/images interleaved on the same descriptor set.
  51. _uniformBufferRefs = new Auto<DisposableBuffer>[Constants.MaxUniformBufferBindings];
  52. _storageBufferRefs = new Auto<DisposableBuffer>[Constants.MaxStorageBufferBindings];
  53. _textureRefs = new Auto<DisposableImageView>[Constants.MaxTextureBindings * 2];
  54. _samplerRefs = new Auto<DisposableSampler>[Constants.MaxTextureBindings * 2];
  55. _imageRefs = new Auto<DisposableImageView>[Constants.MaxImageBindings * 2];
  56. _bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2];
  57. _bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2];
  58. _bufferImageFormats = new GAL.Format[Constants.MaxImageBindings * 2];
  59. _uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings];
  60. _storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings];
  61. _textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage];
  62. _images = new DescriptorImageInfo[Constants.MaxImagesPerStage];
  63. _bufferTextures = new BufferView[Constants.MaxTexturesPerStage];
  64. _bufferImages = new BufferView[Constants.MaxImagesPerStage];
  65. var initialImageInfo = new DescriptorImageInfo()
  66. {
  67. ImageLayout = ImageLayout.General
  68. };
  69. _textures.AsSpan().Fill(initialImageInfo);
  70. _images.AsSpan().Fill(initialImageInfo);
  71. _uniformSet = new bool[Constants.MaxUniformBufferBindings];
  72. _storageSet = new bool[Constants.MaxStorageBufferBindings];
  73. if (gd.Capabilities.SupportsNullDescriptors)
  74. {
  75. // If null descriptors are supported, we can pass null as the handle.
  76. _dummyBuffer = null;
  77. }
  78. else
  79. {
  80. // If null descriptors are not supported, we need to pass the handle of a dummy buffer on unused bindings.
  81. _dummyBuffer = gd.BufferManager.Create(gd, 0x10000, forConditionalRendering: false, deviceLocal: true);
  82. }
  83. _dummyTexture = gd.CreateTextureView(new TextureCreateInfo(
  84. 1,
  85. 1,
  86. 1,
  87. 1,
  88. 1,
  89. 1,
  90. 1,
  91. 4,
  92. GAL.Format.R8G8B8A8Unorm,
  93. DepthStencilMode.Depth,
  94. Target.Texture2D,
  95. SwizzleComponent.Red,
  96. SwizzleComponent.Green,
  97. SwizzleComponent.Blue,
  98. SwizzleComponent.Alpha), 1f);
  99. _dummySampler = (SamplerHolder)gd.CreateSampler(new GAL.SamplerCreateInfo(
  100. MinFilter.Nearest,
  101. MagFilter.Nearest,
  102. false,
  103. AddressMode.Repeat,
  104. AddressMode.Repeat,
  105. AddressMode.Repeat,
  106. CompareMode.None,
  107. GAL.CompareOp.Always,
  108. new ColorF(0, 0, 0, 0),
  109. 0,
  110. 0,
  111. 0,
  112. 1f));
  113. }
  114. public void Initialize()
  115. {
  116. Span<byte> dummyTextureData = stackalloc byte[4];
  117. _dummyTexture.SetData(dummyTextureData);
  118. }
  119. public void SetProgram(ShaderCollection program)
  120. {
  121. _program = program;
  122. _dirty = DirtyFlags.All;
  123. }
  124. public void SetImage(int binding, ITexture image, GAL.Format imageFormat)
  125. {
  126. if (image is TextureBuffer imageBuffer)
  127. {
  128. _bufferImageRefs[binding] = imageBuffer;
  129. _bufferImageFormats[binding] = imageFormat;
  130. }
  131. else if (image is TextureView view)
  132. {
  133. _imageRefs[binding] = view.GetView(imageFormat).GetIdentityImageView();
  134. }
  135. else
  136. {
  137. _imageRefs[binding] = null;
  138. _bufferImageRefs[binding] = null;
  139. _bufferImageFormats[binding] = default;
  140. }
  141. SignalDirty(DirtyFlags.Image);
  142. }
  143. public void SetStorageBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
  144. {
  145. for (int i = 0; i < buffers.Length; i++)
  146. {
  147. var assignment = buffers[i];
  148. var buffer = assignment.Range;
  149. int index = assignment.Binding;
  150. Auto<DisposableBuffer> vkBuffer = _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false);
  151. ref Auto<DisposableBuffer> currentVkBuffer = ref _storageBufferRefs[index];
  152. DescriptorBufferInfo info = new DescriptorBufferInfo()
  153. {
  154. Offset = (ulong)buffer.Offset,
  155. Range = (ulong)buffer.Size
  156. };
  157. ref DescriptorBufferInfo currentInfo = ref _storageBuffers[index];
  158. if (vkBuffer != currentVkBuffer || currentInfo.Offset != info.Offset || currentInfo.Range != info.Range)
  159. {
  160. _storageSet[index] = false;
  161. currentInfo = info;
  162. currentVkBuffer = vkBuffer;
  163. }
  164. }
  165. SignalDirty(DirtyFlags.Storage);
  166. }
  167. public void SetStorageBuffers(CommandBuffer commandBuffer, int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
  168. {
  169. for (int i = 0; i < buffers.Length; i++)
  170. {
  171. var vkBuffer = buffers[i];
  172. int index = first + i;
  173. ref Auto<DisposableBuffer> currentVkBuffer = ref _storageBufferRefs[index];
  174. DescriptorBufferInfo info = new DescriptorBufferInfo()
  175. {
  176. Offset = 0,
  177. Range = Vk.WholeSize
  178. };
  179. ref DescriptorBufferInfo currentInfo = ref _storageBuffers[index];
  180. if (vkBuffer != currentVkBuffer || currentInfo.Offset != info.Offset || currentInfo.Range != info.Range)
  181. {
  182. _storageSet[index] = false;
  183. currentInfo = info;
  184. currentVkBuffer = vkBuffer;
  185. }
  186. }
  187. SignalDirty(DirtyFlags.Storage);
  188. }
  189. public void SetTextureAndSampler(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture texture, ISampler sampler)
  190. {
  191. if (texture is TextureBuffer textureBuffer)
  192. {
  193. _bufferTextureRefs[binding] = textureBuffer;
  194. }
  195. else if (texture is TextureView view)
  196. {
  197. view.Storage.InsertBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
  198. _textureRefs[binding] = view.GetImageView();
  199. _samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
  200. }
  201. else
  202. {
  203. _textureRefs[binding] = null;
  204. _samplerRefs[binding] = null;
  205. _bufferTextureRefs[binding] = null;
  206. }
  207. SignalDirty(DirtyFlags.Texture);
  208. }
  209. public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
  210. {
  211. for (int i = 0; i < buffers.Length; i++)
  212. {
  213. var assignment = buffers[i];
  214. var buffer = assignment.Range;
  215. int index = assignment.Binding;
  216. Auto<DisposableBuffer> vkBuffer = _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false);
  217. ref Auto<DisposableBuffer> currentVkBuffer = ref _uniformBufferRefs[index];
  218. DescriptorBufferInfo info = new DescriptorBufferInfo()
  219. {
  220. Offset = (ulong)buffer.Offset,
  221. Range = (ulong)buffer.Size
  222. };
  223. ref DescriptorBufferInfo currentInfo = ref _uniformBuffers[index];
  224. if (vkBuffer != currentVkBuffer || currentInfo.Offset != info.Offset || currentInfo.Range != info.Range)
  225. {
  226. _uniformSet[index] = false;
  227. currentInfo = info;
  228. currentVkBuffer = vkBuffer;
  229. }
  230. }
  231. SignalDirty(DirtyFlags.Uniform);
  232. }
  233. private void SignalDirty(DirtyFlags flag)
  234. {
  235. _dirty |= flag;
  236. }
  237. public void UpdateAndBindDescriptorSets(CommandBufferScoped cbs, PipelineBindPoint pbp)
  238. {
  239. if ((_dirty & DirtyFlags.All) == 0)
  240. {
  241. return;
  242. }
  243. if (_dirty.HasFlag(DirtyFlags.Uniform))
  244. {
  245. if (_program.UsePushDescriptors)
  246. {
  247. UpdateAndBindUniformBufferPd(cbs, pbp);
  248. }
  249. else
  250. {
  251. UpdateAndBind(cbs, PipelineBase.UniformSetIndex, pbp);
  252. }
  253. }
  254. if (_dirty.HasFlag(DirtyFlags.Storage))
  255. {
  256. UpdateAndBind(cbs, PipelineBase.StorageSetIndex, pbp);
  257. }
  258. if (_dirty.HasFlag(DirtyFlags.Texture))
  259. {
  260. UpdateAndBind(cbs, PipelineBase.TextureSetIndex, pbp);
  261. }
  262. if (_dirty.HasFlag(DirtyFlags.Image))
  263. {
  264. UpdateAndBind(cbs, PipelineBase.ImageSetIndex, pbp);
  265. }
  266. _dirty = DirtyFlags.None;
  267. }
  268. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  269. private static void UpdateBuffer(
  270. CommandBufferScoped cbs,
  271. ref DescriptorBufferInfo info,
  272. Auto<DisposableBuffer> buffer,
  273. Auto<DisposableBuffer> dummyBuffer)
  274. {
  275. info.Buffer = buffer?.Get(cbs, (int)info.Offset, (int)info.Range).Value ?? default;
  276. // The spec requires that buffers with null handle have offset as 0 and range as VK_WHOLE_SIZE.
  277. if (info.Buffer.Handle == 0)
  278. {
  279. info.Buffer = dummyBuffer?.Get(cbs).Value ?? default;
  280. info.Offset = 0;
  281. info.Range = Vk.WholeSize;
  282. }
  283. }
  284. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  285. private void UpdateAndBind(CommandBufferScoped cbs, int setIndex, PipelineBindPoint pbp)
  286. {
  287. var program = _program;
  288. int stagesCount = program.Bindings[setIndex].Length;
  289. if (stagesCount == 0 && setIndex != PipelineBase.UniformSetIndex)
  290. {
  291. return;
  292. }
  293. var dummyBuffer = _dummyBuffer?.GetBuffer();
  294. var dsc = program.GetNewDescriptorSetCollection(_gd, cbs.CommandBufferIndex, setIndex, out var isNew).Get(cbs);
  295. if (!program.HasMinimalLayout)
  296. {
  297. if (isNew)
  298. {
  299. Initialize(cbs, setIndex, dsc);
  300. }
  301. if (setIndex == PipelineBase.UniformSetIndex)
  302. {
  303. Span<DescriptorBufferInfo> uniformBuffer = stackalloc DescriptorBufferInfo[1];
  304. if (!_uniformSet[0])
  305. {
  306. _cachedSupportBuffer = _gd.BufferManager.GetBuffer(cbs.CommandBuffer, _pipeline.SupportBufferUpdater.Handle, false).Get(cbs, 0, SupportBuffer.RequiredSize).Value;
  307. _uniformSet[0] = true;
  308. }
  309. uniformBuffer[0] = new DescriptorBufferInfo()
  310. {
  311. Offset = 0,
  312. Range = (ulong)SupportBuffer.RequiredSize,
  313. Buffer = _cachedSupportBuffer
  314. };
  315. dsc.UpdateBuffers(0, 0, uniformBuffer, DescriptorType.UniformBuffer);
  316. }
  317. }
  318. for (int stageIndex = 0; stageIndex < stagesCount; stageIndex++)
  319. {
  320. var stageBindings = program.Bindings[setIndex][stageIndex];
  321. int bindingsCount = stageBindings.Length;
  322. int count;
  323. for (int bindingIndex = 0; bindingIndex < bindingsCount; bindingIndex += count)
  324. {
  325. int binding = stageBindings[bindingIndex];
  326. count = 1;
  327. while (bindingIndex + count < bindingsCount && stageBindings[bindingIndex + count] == binding + count)
  328. {
  329. count++;
  330. }
  331. if (setIndex == PipelineBase.UniformSetIndex)
  332. {
  333. for (int i = 0; i < count; i++)
  334. {
  335. int index = binding + i;
  336. if (!_uniformSet[index])
  337. {
  338. UpdateBuffer(cbs, ref _uniformBuffers[index], _uniformBufferRefs[index], dummyBuffer);
  339. _uniformSet[index] = true;
  340. }
  341. }
  342. ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
  343. dsc.UpdateBuffers(0, binding, uniformBuffers.Slice(binding, count), DescriptorType.UniformBuffer);
  344. }
  345. else if (setIndex == PipelineBase.StorageSetIndex)
  346. {
  347. for (int i = 0; i < count; i++)
  348. {
  349. int index = binding + i;
  350. if (!_storageSet[index])
  351. {
  352. UpdateBuffer(cbs, ref _storageBuffers[index], _storageBufferRefs[index], dummyBuffer);
  353. _storageSet[index] = true;
  354. }
  355. }
  356. ReadOnlySpan<DescriptorBufferInfo> storageBuffers = _storageBuffers;
  357. if (program.HasMinimalLayout)
  358. {
  359. dsc.UpdateBuffers(0, binding, storageBuffers.Slice(binding, count), DescriptorType.StorageBuffer);
  360. }
  361. else
  362. {
  363. dsc.UpdateStorageBuffers(0, binding, storageBuffers.Slice(binding, count));
  364. }
  365. }
  366. else if (setIndex == PipelineBase.TextureSetIndex)
  367. {
  368. if (((uint)binding % (Constants.MaxTexturesPerStage * 2)) < Constants.MaxTexturesPerStage || program.HasMinimalLayout)
  369. {
  370. Span<DescriptorImageInfo> textures = _textures;
  371. for (int i = 0; i < count; i++)
  372. {
  373. ref var texture = ref textures[i];
  374. texture.ImageView = _textureRefs[binding + i]?.Get(cbs).Value ?? default;
  375. texture.Sampler = _samplerRefs[binding + i]?.Get(cbs).Value ?? default;
  376. if (texture.ImageView.Handle == 0)
  377. {
  378. texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value;
  379. }
  380. if (texture.Sampler.Handle == 0)
  381. {
  382. texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value;
  383. }
  384. }
  385. dsc.UpdateImages(0, binding, textures.Slice(0, count), DescriptorType.CombinedImageSampler);
  386. }
  387. else
  388. {
  389. Span<BufferView> bufferTextures = _bufferTextures;
  390. for (int i = 0; i < count; i++)
  391. {
  392. bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs) ?? default;
  393. }
  394. dsc.UpdateBufferImages(0, binding, bufferTextures.Slice(0, count), DescriptorType.UniformTexelBuffer);
  395. }
  396. }
  397. else if (setIndex == PipelineBase.ImageSetIndex)
  398. {
  399. if (((uint)binding % (Constants.MaxImagesPerStage * 2)) < Constants.MaxImagesPerStage || program.HasMinimalLayout)
  400. {
  401. Span<DescriptorImageInfo> images = _images;
  402. for (int i = 0; i < count; i++)
  403. {
  404. images[i].ImageView = _imageRefs[binding + i]?.Get(cbs).Value ?? default;
  405. }
  406. dsc.UpdateImages(0, binding, images.Slice(0, count), DescriptorType.StorageImage);
  407. }
  408. else
  409. {
  410. Span<BufferView> bufferImages = _bufferImages;
  411. for (int i = 0; i < count; i++)
  412. {
  413. bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, _bufferImageFormats[binding + i]) ?? default;
  414. }
  415. dsc.UpdateBufferImages(0, binding, bufferImages.Slice(0, count), DescriptorType.StorageTexelBuffer);
  416. }
  417. }
  418. }
  419. }
  420. var sets = dsc.GetSets();
  421. _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
  422. }
  423. private unsafe void UpdateBuffers(
  424. CommandBufferScoped cbs,
  425. PipelineBindPoint pbp,
  426. int baseBinding,
  427. ReadOnlySpan<DescriptorBufferInfo> bufferInfo,
  428. DescriptorType type)
  429. {
  430. if (bufferInfo.Length == 0)
  431. {
  432. return;
  433. }
  434. fixed (DescriptorBufferInfo* pBufferInfo = bufferInfo)
  435. {
  436. var writeDescriptorSet = new WriteDescriptorSet
  437. {
  438. SType = StructureType.WriteDescriptorSet,
  439. DstBinding = (uint)baseBinding,
  440. DescriptorType = type,
  441. DescriptorCount = (uint)bufferInfo.Length,
  442. PBufferInfo = pBufferInfo
  443. };
  444. _gd.PushDescriptorApi.CmdPushDescriptorSet(cbs.CommandBuffer, pbp, _program.PipelineLayout, 0, 1, &writeDescriptorSet);
  445. }
  446. }
  447. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  448. private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs, PipelineBindPoint pbp)
  449. {
  450. var dummyBuffer = _dummyBuffer?.GetBuffer();
  451. int stagesCount = _program.Bindings[PipelineBase.UniformSetIndex].Length;
  452. if (!_uniformSet[0])
  453. {
  454. Span<DescriptorBufferInfo> uniformBuffer = stackalloc DescriptorBufferInfo[1];
  455. uniformBuffer[0] = new DescriptorBufferInfo()
  456. {
  457. Offset = 0,
  458. Range = (ulong)SupportBuffer.RequiredSize,
  459. Buffer = _gd.BufferManager.GetBuffer(cbs.CommandBuffer, _pipeline.SupportBufferUpdater.Handle, false).Get(cbs, 0, SupportBuffer.RequiredSize).Value
  460. };
  461. _uniformSet[0] = true;
  462. UpdateBuffers(cbs, pbp, 0, uniformBuffer, DescriptorType.UniformBuffer);
  463. }
  464. for (int stageIndex = 0; stageIndex < stagesCount; stageIndex++)
  465. {
  466. var stageBindings = _program.Bindings[PipelineBase.UniformSetIndex][stageIndex];
  467. int bindingsCount = stageBindings.Length;
  468. int count;
  469. for (int bindingIndex = 0; bindingIndex < bindingsCount; bindingIndex += count)
  470. {
  471. int binding = stageBindings[bindingIndex];
  472. count = 1;
  473. while (bindingIndex + count < bindingsCount && stageBindings[bindingIndex + count] == binding + count)
  474. {
  475. count++;
  476. }
  477. bool doUpdate = false;
  478. for (int i = 0; i < count; i++)
  479. {
  480. int index = binding + i;
  481. if (!_uniformSet[index])
  482. {
  483. UpdateBuffer(cbs, ref _uniformBuffers[index], _uniformBufferRefs[index], dummyBuffer);
  484. _uniformSet[index] = true;
  485. doUpdate = true;
  486. }
  487. }
  488. if (doUpdate)
  489. {
  490. ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
  491. UpdateBuffers(cbs, pbp, binding, uniformBuffers.Slice(binding, count), DescriptorType.UniformBuffer);
  492. }
  493. }
  494. }
  495. }
  496. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  497. private void Initialize(CommandBufferScoped cbs, int setIndex, DescriptorSetCollection dsc)
  498. {
  499. var dummyBuffer = _dummyBuffer?.GetBuffer().Get(cbs).Value ?? default;
  500. uint stages = _program.Stages;
  501. while (stages != 0)
  502. {
  503. int stage = BitOperations.TrailingZeroCount(stages);
  504. stages &= ~(1u << stage);
  505. if (setIndex == PipelineBase.UniformSetIndex)
  506. {
  507. dsc.InitializeBuffers(
  508. 0,
  509. 1 + stage * Constants.MaxUniformBuffersPerStage,
  510. Constants.MaxUniformBuffersPerStage,
  511. DescriptorType.UniformBuffer,
  512. dummyBuffer);
  513. }
  514. else if (setIndex == PipelineBase.StorageSetIndex)
  515. {
  516. dsc.InitializeBuffers(
  517. 0,
  518. stage * Constants.MaxStorageBuffersPerStage,
  519. Constants.MaxStorageBuffersPerStage,
  520. DescriptorType.StorageBuffer,
  521. dummyBuffer);
  522. }
  523. }
  524. }
  525. public void SignalCommandBufferChange()
  526. {
  527. _dirty = DirtyFlags.All;
  528. Array.Clear(_uniformSet);
  529. Array.Clear(_storageSet);
  530. }
  531. protected virtual void Dispose(bool disposing)
  532. {
  533. if (disposing)
  534. {
  535. _dummyTexture.Dispose();
  536. _dummySampler.Dispose();
  537. }
  538. }
  539. public void Dispose()
  540. {
  541. Dispose(true);
  542. }
  543. }
  544. }