BufferManager.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  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. /// Gets the bounds of the uniform buffer currently bound at the given index.
  324. /// </summary>
  325. /// <param name="isCompute">Indicates whenever the uniform is requested by the 3D or compute engine</param>
  326. /// <param name="stage">Index of the shader stage, if the uniform is for the 3D engine</param>
  327. /// <param name="index">Index of the uniform buffer binding</param>
  328. /// <returns>The uniform buffer bounds, or an undefined value if the buffer is not currently bound</returns>
  329. public ref BufferBounds GetUniformBufferBounds(bool isCompute, int stage, int index)
  330. {
  331. if (isCompute)
  332. {
  333. return ref _cpUniformBuffers.Buffers[index];
  334. }
  335. else
  336. {
  337. return ref _gpUniformBuffers[stage].Buffers[index];
  338. }
  339. }
  340. /// <summary>
  341. /// Ensures that the compute engine bindings are visible to the host GPU.
  342. /// Note: this actually performs the binding using the host graphics API.
  343. /// </summary>
  344. public void CommitComputeBindings()
  345. {
  346. var bufferCache = _channel.MemoryManager.Physical.BufferCache;
  347. BindBuffers(bufferCache, _cpStorageBuffers, isStorage: true);
  348. BindBuffers(bufferCache, _cpUniformBuffers, isStorage: false);
  349. CommitBufferTextureBindings();
  350. // Force rebind after doing compute work.
  351. Rebind();
  352. }
  353. /// <summary>
  354. /// Commit any queued buffer texture bindings.
  355. /// </summary>
  356. private void CommitBufferTextureBindings()
  357. {
  358. if (_bufferTextures.Count > 0)
  359. {
  360. foreach (var binding in _bufferTextures)
  361. {
  362. var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
  363. var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
  364. binding.Texture.SetStorage(range);
  365. // The texture must be rebound to use the new storage if it was updated.
  366. if (binding.IsImage)
  367. {
  368. _context.Renderer.Pipeline.SetImage(binding.BindingInfo.Binding, binding.Texture, binding.Format);
  369. }
  370. else
  371. {
  372. _context.Renderer.Pipeline.SetTextureAndSampler(binding.Stage, binding.BindingInfo.Binding, binding.Texture, null);
  373. }
  374. }
  375. _bufferTextures.Clear();
  376. }
  377. }
  378. /// <summary>
  379. /// Ensures that the graphics engine bindings are visible to the host GPU.
  380. /// Note: this actually performs the binding using the host graphics API.
  381. /// </summary>
  382. public void CommitGraphicsBindings()
  383. {
  384. var bufferCache = _channel.MemoryManager.Physical.BufferCache;
  385. if (_indexBufferDirty || _rebind)
  386. {
  387. _indexBufferDirty = false;
  388. if (_indexBuffer.Address != 0)
  389. {
  390. BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
  391. _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
  392. }
  393. }
  394. else if (_indexBuffer.Address != 0)
  395. {
  396. bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
  397. }
  398. uint vbEnableMask = _vertexBuffersEnableMask;
  399. if (_vertexBuffersDirty || _rebind)
  400. {
  401. _vertexBuffersDirty = false;
  402. Span<VertexBufferDescriptor> vertexBuffers = stackalloc VertexBufferDescriptor[Constants.TotalVertexBuffers];
  403. for (int index = 0; (vbEnableMask >> index) != 0; index++)
  404. {
  405. VertexBuffer vb = _vertexBuffers[index];
  406. if (vb.Address == 0)
  407. {
  408. continue;
  409. }
  410. BufferRange buffer = bufferCache.GetBufferRange(vb.Address, vb.Size);
  411. vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
  412. }
  413. _context.Renderer.Pipeline.SetVertexBuffers(vertexBuffers);
  414. }
  415. else
  416. {
  417. for (int index = 0; (vbEnableMask >> index) != 0; index++)
  418. {
  419. VertexBuffer vb = _vertexBuffers[index];
  420. if (vb.Address == 0)
  421. {
  422. continue;
  423. }
  424. bufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
  425. }
  426. }
  427. if (_transformFeedbackBuffersDirty || _rebind)
  428. {
  429. _transformFeedbackBuffersDirty = false;
  430. Span<BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];
  431. for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
  432. {
  433. BufferBounds tfb = _transformFeedbackBuffers[index];
  434. if (tfb.Address == 0)
  435. {
  436. tfbs[index] = BufferRange.Empty;
  437. continue;
  438. }
  439. tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size, write: true);
  440. }
  441. _context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
  442. }
  443. else
  444. {
  445. for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
  446. {
  447. BufferBounds tfb = _transformFeedbackBuffers[index];
  448. if (tfb.Address == 0)
  449. {
  450. continue;
  451. }
  452. bufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
  453. }
  454. }
  455. if (_gpStorageBuffersDirty || _rebind)
  456. {
  457. _gpStorageBuffersDirty = false;
  458. BindBuffers(bufferCache, _gpStorageBuffers, isStorage: true);
  459. }
  460. else
  461. {
  462. UpdateBuffers(_gpStorageBuffers);
  463. }
  464. if (_gpUniformBuffersDirty || _rebind)
  465. {
  466. _gpUniformBuffersDirty = false;
  467. BindBuffers(bufferCache, _gpUniformBuffers, isStorage: false);
  468. }
  469. else
  470. {
  471. UpdateBuffers(_gpUniformBuffers);
  472. }
  473. CommitBufferTextureBindings();
  474. _rebind = false;
  475. }
  476. /// <summary>
  477. /// Bind respective buffer bindings on the host API.
  478. /// </summary>
  479. /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
  480. /// <param name="bindings">Buffer memory ranges to bind</param>
  481. /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
  482. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  483. private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
  484. {
  485. int rangesFirst = 0;
  486. int rangesCount = 0;
  487. Span<BufferRange> ranges = _ranges;
  488. for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
  489. {
  490. ref var buffers = ref bindings[(int)stage - 1];
  491. for (int index = 0; index < buffers.Count; index++)
  492. {
  493. ref var bindingInfo = ref buffers.Bindings[index];
  494. BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
  495. if (bounds.Address != 0)
  496. {
  497. var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
  498. var range = isStorage
  499. ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
  500. : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
  501. if (rangesCount == 0)
  502. {
  503. rangesFirst = bindingInfo.Binding;
  504. }
  505. else if (bindingInfo.Binding != rangesFirst + rangesCount)
  506. {
  507. SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
  508. rangesFirst = bindingInfo.Binding;
  509. rangesCount = 0;
  510. }
  511. ranges[rangesCount++] = range;
  512. }
  513. }
  514. }
  515. if (rangesCount != 0)
  516. {
  517. SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
  518. }
  519. }
  520. /// <summary>
  521. /// Bind respective buffer bindings on the host API.
  522. /// </summary>
  523. /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
  524. /// <param name="buffers">Buffer memory ranges to bind</param>
  525. /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
  526. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  527. private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage)
  528. {
  529. int rangesFirst = 0;
  530. int rangesCount = 0;
  531. Span<BufferRange> ranges = _ranges;
  532. for (int index = 0; index < buffers.Count; index++)
  533. {
  534. ref var bindingInfo = ref buffers.Bindings[index];
  535. BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
  536. if (bounds.Address != 0)
  537. {
  538. var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
  539. var range = isStorage
  540. ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
  541. : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
  542. if (rangesCount == 0)
  543. {
  544. rangesFirst = bindingInfo.Binding;
  545. }
  546. else if (bindingInfo.Binding != rangesFirst + rangesCount)
  547. {
  548. SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
  549. rangesFirst = bindingInfo.Binding;
  550. rangesCount = 0;
  551. }
  552. ranges[rangesCount++] = range;
  553. }
  554. }
  555. if (rangesCount != 0)
  556. {
  557. SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
  558. }
  559. }
  560. /// <summary>
  561. /// Bind respective buffer bindings on the host API.
  562. /// </summary>
  563. /// <param name="ranges">Host buffers to bind, with their offsets and sizes</param>
  564. /// <param name="first">First binding point</param>
  565. /// <param name="count">Number of bindings</param>
  566. /// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
  567. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  568. private void SetHostBuffers(ReadOnlySpan<BufferRange> ranges, int first, int count, bool isStorage)
  569. {
  570. if (isStorage)
  571. {
  572. _context.Renderer.Pipeline.SetStorageBuffers(first, ranges.Slice(0, count));
  573. }
  574. else
  575. {
  576. _context.Renderer.Pipeline.SetUniformBuffers(first, ranges.Slice(0, count));
  577. }
  578. }
  579. /// <summary>
  580. /// Updates data for the already bound buffer bindings.
  581. /// </summary>
  582. /// <param name="bindings">Bindings to update</param>
  583. private void UpdateBuffers(BuffersPerStage[] bindings)
  584. {
  585. for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
  586. {
  587. ref var buffers = ref bindings[(int)stage - 1];
  588. for (int index = 0; index < buffers.Count; index++)
  589. {
  590. ref var binding = ref buffers.Bindings[index];
  591. BufferBounds bounds = buffers.Buffers[binding.Slot];
  592. if (bounds.Address == 0)
  593. {
  594. continue;
  595. }
  596. _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size);
  597. }
  598. }
  599. }
  600. /// <summary>
  601. /// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings.
  602. /// </summary>
  603. /// <param name="stage">Shader stage accessing the texture</param>
  604. /// <param name="texture">Buffer texture</param>
  605. /// <param name="address">Address of the buffer in memory</param>
  606. /// <param name="size">Size of the buffer in bytes</param>
  607. /// <param name="bindingInfo">Binding info for the buffer texture</param>
  608. /// <param name="format">Format of the buffer texture</param>
  609. /// <param name="isImage">Whether the binding is for an image or a sampler</param>
  610. public void SetBufferTextureStorage(
  611. ShaderStage stage,
  612. ITexture texture,
  613. ulong address,
  614. ulong size,
  615. TextureBindingInfo bindingInfo,
  616. Format format,
  617. bool isImage)
  618. {
  619. _channel.MemoryManager.Physical.BufferCache.CreateBuffer(address, size);
  620. _bufferTextures.Add(new BufferTextureBinding(stage, texture, address, size, bindingInfo, format, isImage));
  621. }
  622. /// <summary>
  623. /// Force all bound textures and images to be rebound the next time CommitBindings is called.
  624. /// </summary>
  625. public void Rebind()
  626. {
  627. _rebind = true;
  628. }
  629. }
  630. }