BufferManager.cs 30 KB

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