BufferManager.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. using Ryujinx.Common;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Gpu.Image;
  4. using Ryujinx.Graphics.Shader;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Collections.ObjectModel;
  8. using System.Runtime.CompilerServices;
  9. namespace Ryujinx.Graphics.Gpu.Memory
  10. {
  11. /// <summary>
  12. /// Buffer manager.
  13. /// </summary>
  14. class BufferManager
  15. {
  16. private readonly GpuContext _context;
  17. private readonly GpuChannel _channel;
  18. private IndexBuffer _indexBuffer;
  19. private readonly VertexBuffer[] _vertexBuffers;
  20. private readonly BufferBounds[] _transformFeedbackBuffers;
  21. private readonly List<BufferTextureBinding> _bufferTextures;
  22. private readonly BufferRange[] _ranges;
  23. /// <summary>
  24. /// Holds shader stage buffer state and binding information.
  25. /// </summary>
  26. private class BuffersPerStage
  27. {
  28. /// <summary>
  29. /// Shader buffer binding information.
  30. /// </summary>
  31. public BufferDescriptor[] Bindings { get; }
  32. /// <summary>
  33. /// Buffer regions.
  34. /// </summary>
  35. public BufferBounds[] Buffers { get; }
  36. /// <summary>
  37. /// Total amount of buffers used on the shader.
  38. /// </summary>
  39. public int Count { get; private set; }
  40. /// <summary>
  41. /// Creates a new instance of the shader stage buffer information.
  42. /// </summary>
  43. /// <param name="count">Maximum amount of buffers that the shader stage can use</param>
  44. public BuffersPerStage(int count)
  45. {
  46. Bindings = new BufferDescriptor[count];
  47. Buffers = new BufferBounds[count];
  48. }
  49. /// <summary>
  50. /// Sets the region of a buffer at a given slot.
  51. /// </summary>
  52. /// <param name="index">Buffer slot</param>
  53. /// <param name="address">Region virtual address</param>
  54. /// <param name="size">Region size in bytes</param>
  55. /// <param name="flags">Buffer usage flags</param>
  56. public void SetBounds(int index, ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None)
  57. {
  58. Buffers[index] = new BufferBounds(address, size, flags);
  59. }
  60. /// <summary>
  61. /// Sets shader buffer binding information.
  62. /// </summary>
  63. /// <param name="descriptors">Buffer binding information</param>
  64. public void SetBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
  65. {
  66. if (descriptors == null)
  67. {
  68. Count = 0;
  69. return;
  70. }
  71. descriptors.CopyTo(Bindings, 0);
  72. Count = descriptors.Count;
  73. }
  74. }
  75. private readonly BuffersPerStage _cpStorageBuffers;
  76. private readonly BuffersPerStage _cpUniformBuffers;
  77. private readonly BuffersPerStage[] _gpStorageBuffers;
  78. private readonly BuffersPerStage[] _gpUniformBuffers;
  79. private bool _gpStorageBuffersDirty;
  80. private bool _gpUniformBuffersDirty;
  81. private bool _indexBufferDirty;
  82. private bool _vertexBuffersDirty;
  83. private uint _vertexBuffersEnableMask;
  84. private bool _transformFeedbackBuffersDirty;
  85. private bool _rebind;
  86. /// <summary>
  87. /// Creates a new instance of the buffer manager.
  88. /// </summary>
  89. /// <param name="context">GPU context that the buffer manager belongs to</param>
  90. /// <param name="channel">GPU channel that the buffer manager belongs to</param>
  91. public BufferManager(GpuContext context, GpuChannel channel)
  92. {
  93. _context = context;
  94. _channel = channel;
  95. _vertexBuffers = new VertexBuffer[Constants.TotalVertexBuffers];
  96. _transformFeedbackBuffers = new BufferBounds[Constants.TotalTransformFeedbackBuffers];
  97. _cpStorageBuffers = new BuffersPerStage(Constants.TotalCpStorageBuffers);
  98. _cpUniformBuffers = new BuffersPerStage(Constants.TotalCpUniformBuffers);
  99. _gpStorageBuffers = new BuffersPerStage[Constants.ShaderStages];
  100. _gpUniformBuffers = new BuffersPerStage[Constants.ShaderStages];
  101. for (int index = 0; index < Constants.ShaderStages; index++)
  102. {
  103. _gpStorageBuffers[index] = new BuffersPerStage(Constants.TotalGpStorageBuffers);
  104. _gpUniformBuffers[index] = new BuffersPerStage(Constants.TotalGpUniformBuffers);
  105. }
  106. _bufferTextures = new List<BufferTextureBinding>();
  107. _ranges = new BufferRange[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
  108. }
  109. /// <summary>
  110. /// Sets the memory range with the index buffer data, to be used for subsequent draw calls.
  111. /// </summary>
  112. /// <param name="gpuVa">Start GPU virtual address of the index buffer</param>
  113. /// <param name="size">Size, in bytes, of the index buffer</param>
  114. /// <param name="type">Type of each index buffer element</param>
  115. public void SetIndexBuffer(ulong gpuVa, ulong size, IndexType type)
  116. {
  117. ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
  118. _indexBuffer.Address = address;
  119. _indexBuffer.Size = size;
  120. _indexBuffer.Type = type;
  121. _indexBufferDirty = true;
  122. }
  123. /// <summary>
  124. /// Sets a new index buffer that overrides the one set on the call to <see cref="CommitGraphicsBindings"/>.
  125. /// </summary>
  126. /// <param name="buffer">Buffer to be used as index buffer</param>
  127. /// <param name="type">Type of each index buffer element</param>
  128. public void SetIndexBuffer(BufferRange buffer, IndexType type)
  129. {
  130. _context.Renderer.Pipeline.SetIndexBuffer(buffer, type);
  131. _indexBufferDirty = true;
  132. }
  133. /// <summary>
  134. /// Sets the memory range with vertex buffer data, to be used for subsequent draw calls.
  135. /// </summary>
  136. /// <param name="index">Index of the vertex buffer (up to 16)</param>
  137. /// <param name="gpuVa">GPU virtual address of the buffer</param>
  138. /// <param name="size">Size in bytes of the buffer</param>
  139. /// <param name="stride">Stride of the buffer, defined as the number of bytes of each vertex</param>
  140. /// <param name="divisor">Vertex divisor of the buffer, for instanced draws</param>
  141. public void SetVertexBuffer(int index, ulong gpuVa, ulong size, int stride, int divisor)
  142. {
  143. ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
  144. _vertexBuffers[index].Address = address;
  145. _vertexBuffers[index].Size = size;
  146. _vertexBuffers[index].Stride = stride;
  147. _vertexBuffers[index].Divisor = divisor;
  148. _vertexBuffersDirty = true;
  149. if (address != 0)
  150. {
  151. _vertexBuffersEnableMask |= 1u << index;
  152. }
  153. else
  154. {
  155. _vertexBuffersEnableMask &= ~(1u << index);
  156. }
  157. }
  158. /// <summary>
  159. /// Sets a transform feedback buffer on the graphics pipeline.
  160. /// The output from the vertex transformation stages are written into the feedback buffer.
  161. /// </summary>
  162. /// <param name="index">Index of the transform feedback buffer</param>
  163. /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
  164. /// <param name="size">Size in bytes of the transform feedback buffer</param>
  165. public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size)
  166. {
  167. ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
  168. _transformFeedbackBuffers[index] = new BufferBounds(address, size);
  169. _transformFeedbackBuffersDirty = true;
  170. }
  171. /// <summary>
  172. /// Sets a storage buffer on the compute pipeline.
  173. /// Storage buffers can be read and written to on shaders.
  174. /// </summary>
  175. /// <param name="index">Index of the storage buffer</param>
  176. /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
  177. /// <param name="size">Size in bytes of the storage buffer</param>
  178. /// <param name="flags">Buffer usage flags</param>
  179. public void SetComputeStorageBuffer(int index, ulong gpuVa, ulong size, BufferUsageFlags flags)
  180. {
  181. size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
  182. gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
  183. ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
  184. _cpStorageBuffers.SetBounds(index, address, size, flags);
  185. }
  186. /// <summary>
  187. /// Sets a storage buffer on the graphics pipeline.
  188. /// Storage buffers can be read and written to on shaders.
  189. /// </summary>
  190. /// <param name="stage">Index of the shader stage</param>
  191. /// <param name="index">Index of the storage buffer</param>
  192. /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
  193. /// <param name="size">Size in bytes of the storage buffer</param>
  194. /// <param name="flags">Buffer usage flags</param>
  195. public void SetGraphicsStorageBuffer(int stage, int index, ulong gpuVa, ulong size, BufferUsageFlags flags)
  196. {
  197. size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
  198. gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
  199. ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
  200. if (_gpStorageBuffers[stage].Buffers[index].Address != address ||
  201. _gpStorageBuffers[stage].Buffers[index].Size != size)
  202. {
  203. _gpStorageBuffersDirty = true;
  204. }
  205. _gpStorageBuffers[stage].SetBounds(index, address, size, flags);
  206. }
  207. /// <summary>
  208. /// Sets a uniform buffer on the compute pipeline.
  209. /// Uniform buffers are read-only from shaders, and have a small capacity.
  210. /// </summary>
  211. /// <param name="index">Index of the uniform buffer</param>
  212. /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
  213. /// <param name="size">Size in bytes of the storage buffer</param>
  214. public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size)
  215. {
  216. ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
  217. _cpUniformBuffers.SetBounds(index, address, size);
  218. }
  219. /// <summary>
  220. /// Sets a uniform buffer on the graphics pipeline.
  221. /// Uniform buffers are read-only from shaders, and have a small capacity.
  222. /// </summary>
  223. /// <param name="stage">Index of the shader stage</param>
  224. /// <param name="index">Index of the uniform buffer</param>
  225. /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
  226. /// <param name="size">Size in bytes of the storage buffer</param>
  227. public void SetGraphicsUniformBuffer(int stage, int index, ulong gpuVa, ulong size)
  228. {
  229. ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
  230. _gpUniformBuffers[stage].SetBounds(index, address, size);
  231. _gpUniformBuffersDirty = true;
  232. }
  233. /// <summary>
  234. /// Sets the binding points for the storage buffers bound on the compute pipeline.
  235. /// </summary>
  236. /// <param name="descriptors">Buffer descriptors with the binding point values</param>
  237. public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
  238. {
  239. _cpStorageBuffers.SetBindings(descriptors);
  240. }
  241. /// <summary>
  242. /// Sets the binding points for the storage buffers bound on the graphics pipeline.
  243. /// </summary>
  244. /// <param name="stage">Index of the shader stage</param>
  245. /// <param name="descriptors">Buffer descriptors with the binding point values</param>
  246. public void SetGraphicsStorageBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
  247. {
  248. _gpStorageBuffers[stage].SetBindings(descriptors);
  249. _gpStorageBuffersDirty = true;
  250. }
  251. /// <summary>
  252. /// Sets the binding points for the uniform buffers bound on the compute pipeline.
  253. /// </summary>
  254. /// <param name="descriptors">Buffer descriptors with the binding point values</param>
  255. public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
  256. {
  257. _cpUniformBuffers.SetBindings(descriptors);
  258. }
  259. /// <summary>
  260. /// Sets the enabled uniform buffers mask on the graphics pipeline.
  261. /// Each bit set on the mask indicates that the respective buffer index is enabled.
  262. /// </summary>
  263. /// <param name="stage">Index of the shader stage</param>
  264. /// <param name="descriptors">Buffer descriptors with the binding point values</param>
  265. public void SetGraphicsUniformBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
  266. {
  267. _gpUniformBuffers[stage].SetBindings(descriptors);
  268. _gpUniformBuffersDirty = true;
  269. }
  270. /// <summary>
  271. /// Gets a bit mask indicating which compute uniform buffers are currently bound.
  272. /// </summary>
  273. /// <returns>Mask where each bit set indicates a bound constant buffer</returns>
  274. public uint GetComputeUniformBufferUseMask()
  275. {
  276. uint mask = 0;
  277. for (int i = 0; i < _cpUniformBuffers.Buffers.Length; i++)
  278. {
  279. if (_cpUniformBuffers.Buffers[i].Address != 0)
  280. {
  281. mask |= 1u << i;
  282. }
  283. }
  284. return mask;
  285. }
  286. /// <summary>
  287. /// Gets a bit mask indicating which graphics uniform buffers are currently bound.
  288. /// </summary>
  289. /// <param name="stage">Index of the shader stage</param>
  290. /// <returns>Mask where each bit set indicates a bound constant buffer</returns>
  291. public uint GetGraphicsUniformBufferUseMask(int stage)
  292. {
  293. uint mask = 0;
  294. for (int i = 0; i < _gpUniformBuffers[stage].Buffers.Length; i++)
  295. {
  296. if (_gpUniformBuffers[stage].Buffers[i].Address != 0)
  297. {
  298. mask |= 1u << i;
  299. }
  300. }
  301. return mask;
  302. }
  303. /// <summary>
  304. /// Gets the address of the compute uniform buffer currently bound at the given index.
  305. /// </summary>
  306. /// <param name="index">Index of the uniform buffer binding</param>
  307. /// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns>
  308. public ulong GetComputeUniformBufferAddress(int index)
  309. {
  310. return _cpUniformBuffers.Buffers[index].Address;
  311. }
  312. /// <summary>
  313. /// Gets the address of the graphics uniform buffer currently bound at the given index.
  314. /// </summary>
  315. /// <param name="stage">Index of the shader stage</param>
  316. /// <param name="index">Index of the uniform buffer binding</param>
  317. /// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns>
  318. public ulong GetGraphicsUniformBufferAddress(int stage, int index)
  319. {
  320. return _gpUniformBuffers[stage].Buffers[index].Address;
  321. }
  322. /// <summary>
  323. /// Ensures that the compute engine bindings are visible to the host GPU.
  324. /// Note: this actually performs the binding using the host graphics API.
  325. /// </summary>
  326. public void CommitComputeBindings()
  327. {
  328. var bufferCache = _channel.MemoryManager.Physical.BufferCache;
  329. BindBuffers(bufferCache, _cpStorageBuffers, isStorage: true);
  330. BindBuffers(bufferCache, _cpUniformBuffers, isStorage: false);
  331. CommitBufferTextureBindings();
  332. // Force rebind after doing compute work.
  333. Rebind();
  334. }
  335. /// <summary>
  336. /// Commit any queued buffer texture bindings.
  337. /// </summary>
  338. private void CommitBufferTextureBindings()
  339. {
  340. if (_bufferTextures.Count > 0)
  341. {
  342. foreach (var binding in _bufferTextures)
  343. {
  344. var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
  345. var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
  346. binding.Texture.SetStorage(range);
  347. // The texture must be rebound to use the new storage if it was updated.
  348. if (binding.IsImage)
  349. {
  350. _context.Renderer.Pipeline.SetImage(binding.BindingInfo.Binding, binding.Texture, binding.Format);
  351. }
  352. else
  353. {
  354. _context.Renderer.Pipeline.SetTexture(binding.BindingInfo.Binding, binding.Texture);
  355. }
  356. }
  357. _bufferTextures.Clear();
  358. }
  359. }
  360. /// <summary>
  361. /// Ensures that the graphics engine bindings are visible to the host GPU.
  362. /// Note: this actually performs the binding using the host graphics API.
  363. /// </summary>
  364. public void CommitGraphicsBindings()
  365. {
  366. var bufferCache = _channel.MemoryManager.Physical.BufferCache;
  367. if (_indexBufferDirty || _rebind)
  368. {
  369. _indexBufferDirty = false;
  370. if (_indexBuffer.Address != 0)
  371. {
  372. BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
  373. _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
  374. }
  375. }
  376. else if (_indexBuffer.Address != 0)
  377. {
  378. bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
  379. }
  380. uint vbEnableMask = _vertexBuffersEnableMask;
  381. if (_vertexBuffersDirty || _rebind)
  382. {
  383. _vertexBuffersDirty = false;
  384. Span<VertexBufferDescriptor> vertexBuffers = stackalloc VertexBufferDescriptor[Constants.TotalVertexBuffers];
  385. for (int index = 0; (vbEnableMask >> index) != 0; index++)
  386. {
  387. VertexBuffer vb = _vertexBuffers[index];
  388. if (vb.Address == 0)
  389. {
  390. continue;
  391. }
  392. BufferRange buffer = bufferCache.GetBufferRange(vb.Address, vb.Size);
  393. vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
  394. }
  395. _context.Renderer.Pipeline.SetVertexBuffers(vertexBuffers);
  396. }
  397. else
  398. {
  399. for (int index = 0; (vbEnableMask >> index) != 0; index++)
  400. {
  401. VertexBuffer vb = _vertexBuffers[index];
  402. if (vb.Address == 0)
  403. {
  404. continue;
  405. }
  406. bufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
  407. }
  408. }
  409. if (_transformFeedbackBuffersDirty || _rebind)
  410. {
  411. _transformFeedbackBuffersDirty = false;
  412. Span<BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];
  413. for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
  414. {
  415. BufferBounds tfb = _transformFeedbackBuffers[index];
  416. if (tfb.Address == 0)
  417. {
  418. tfbs[index] = BufferRange.Empty;
  419. continue;
  420. }
  421. tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size);
  422. }
  423. _context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
  424. }
  425. else
  426. {
  427. for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
  428. {
  429. BufferBounds tfb = _transformFeedbackBuffers[index];
  430. if (tfb.Address == 0)
  431. {
  432. continue;
  433. }
  434. bufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
  435. }
  436. }
  437. if (_gpStorageBuffersDirty || _rebind)
  438. {
  439. _gpStorageBuffersDirty = false;
  440. BindBuffers(bufferCache, _gpStorageBuffers, isStorage: true);
  441. }
  442. else
  443. {
  444. UpdateBuffers(_gpStorageBuffers);
  445. }
  446. if (_gpUniformBuffersDirty || _rebind)
  447. {
  448. _gpUniformBuffersDirty = false;
  449. BindBuffers(bufferCache, _gpUniformBuffers, isStorage: false);
  450. }
  451. else
  452. {
  453. UpdateBuffers(_gpUniformBuffers);
  454. }
  455. CommitBufferTextureBindings();
  456. _rebind = false;
  457. }
  458. /// <summary>
  459. /// Bind respective buffer bindings on the host API.
  460. /// </summary>
  461. /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
  462. /// <param name="bindings">Buffer memory ranges to bind</param>
  463. /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
  464. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  465. private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
  466. {
  467. int rangesFirst = 0;
  468. int rangesCount = 0;
  469. Span<BufferRange> ranges = _ranges;
  470. for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
  471. {
  472. ref var buffers = ref bindings[(int)stage - 1];
  473. for (int index = 0; index < buffers.Count; index++)
  474. {
  475. ref var bindingInfo = ref buffers.Bindings[index];
  476. BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
  477. if (bounds.Address != 0)
  478. {
  479. var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
  480. var range = isStorage
  481. ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
  482. : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
  483. if (rangesCount == 0)
  484. {
  485. rangesFirst = bindingInfo.Binding;
  486. }
  487. else if (bindingInfo.Binding != rangesFirst + rangesCount)
  488. {
  489. SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
  490. rangesFirst = bindingInfo.Binding;
  491. rangesCount = 0;
  492. }
  493. ranges[rangesCount++] = range;
  494. }
  495. }
  496. }
  497. if (rangesCount != 0)
  498. {
  499. SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
  500. }
  501. }
  502. /// <summary>
  503. /// Bind respective buffer bindings on the host API.
  504. /// </summary>
  505. /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
  506. /// <param name="buffers">Buffer memory ranges to bind</param>
  507. /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
  508. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  509. private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage)
  510. {
  511. int rangesFirst = 0;
  512. int rangesCount = 0;
  513. Span<BufferRange> ranges = _ranges;
  514. for (int index = 0; index < buffers.Count; index++)
  515. {
  516. ref var bindingInfo = ref buffers.Bindings[index];
  517. BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
  518. if (bounds.Address != 0)
  519. {
  520. var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
  521. var range = isStorage
  522. ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
  523. : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
  524. if (rangesCount == 0)
  525. {
  526. rangesFirst = bindingInfo.Binding;
  527. }
  528. else if (bindingInfo.Binding != rangesFirst + rangesCount)
  529. {
  530. SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
  531. rangesFirst = bindingInfo.Binding;
  532. rangesCount = 0;
  533. }
  534. ranges[rangesCount++] = range;
  535. }
  536. }
  537. if (rangesCount != 0)
  538. {
  539. SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
  540. }
  541. }
  542. /// <summary>
  543. /// Bind respective buffer bindings on the host API.
  544. /// </summary>
  545. /// <param name="ranges">Host buffers to bind, with their offsets and sizes</param>
  546. /// <param name="first">First binding point</param>
  547. /// <param name="count">Number of bindings</param>
  548. /// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
  549. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  550. private void SetHostBuffers(ReadOnlySpan<BufferRange> ranges, int first, int count, bool isStorage)
  551. {
  552. if (isStorage)
  553. {
  554. _context.Renderer.Pipeline.SetStorageBuffers(first, ranges.Slice(0, count));
  555. }
  556. else
  557. {
  558. _context.Renderer.Pipeline.SetUniformBuffers(first, ranges.Slice(0, count));
  559. }
  560. }
  561. /// <summary>
  562. /// Updates data for the already bound buffer bindings.
  563. /// </summary>
  564. /// <param name="bindings">Bindings to update</param>
  565. private void UpdateBuffers(BuffersPerStage[] bindings)
  566. {
  567. for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
  568. {
  569. ref var buffers = ref bindings[(int)stage - 1];
  570. for (int index = 0; index < buffers.Count; index++)
  571. {
  572. ref var binding = ref buffers.Bindings[index];
  573. BufferBounds bounds = buffers.Buffers[binding.Slot];
  574. if (bounds.Address == 0)
  575. {
  576. continue;
  577. }
  578. _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size);
  579. }
  580. }
  581. }
  582. /// <summary>
  583. /// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings.
  584. /// </summary>
  585. /// <param name="texture">Buffer texture</param>
  586. /// <param name="address">Address of the buffer in memory</param>
  587. /// <param name="size">Size of the buffer in bytes</param>
  588. /// <param name="bindingInfo">Binding info for the buffer texture</param>
  589. /// <param name="format">Format of the buffer texture</param>
  590. /// <param name="isImage">Whether the binding is for an image or a sampler</param>
  591. public void SetBufferTextureStorage(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
  592. {
  593. _channel.MemoryManager.Physical.BufferCache.CreateBuffer(address, size);
  594. _bufferTextures.Add(new BufferTextureBinding(texture, address, size, bindingInfo, format, isImage));
  595. }
  596. /// <summary>
  597. /// Force all bound textures and images to be rebound the next time CommitBindings is called.
  598. /// </summary>
  599. public void Rebind()
  600. {
  601. _rebind = true;
  602. }
  603. }
  604. }