ConstantBufferUpdater.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace Ryujinx.Graphics.Gpu.Engine.Threed
  4. {
  5. /// <summary>
  6. /// Constant buffer updater.
  7. /// </summary>
  8. class ConstantBufferUpdater
  9. {
  10. private const int UniformDataCacheSize = 512;
  11. private readonly GpuChannel _channel;
  12. private readonly DeviceStateWithShadow<ThreedClassState> _state;
  13. // State associated with direct uniform buffer updates.
  14. // This state is used to attempt to batch together consecutive updates.
  15. private ulong _ubBeginCpuAddress = 0;
  16. private ulong _ubFollowUpAddress = 0;
  17. private ulong _ubByteCount = 0;
  18. private int _ubIndex = 0;
  19. private int[] _ubData = new int[UniformDataCacheSize];
  20. /// <summary>
  21. /// Creates a new instance of the constant buffer updater.
  22. /// </summary>
  23. /// <param name="channel">GPU channel</param>
  24. /// <param name="state">Channel state</param>
  25. public ConstantBufferUpdater(GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state)
  26. {
  27. _channel = channel;
  28. _state = state;
  29. }
  30. /// <summary>
  31. /// Binds a uniform buffer for the vertex shader stage.
  32. /// </summary>
  33. /// <param name="argument">Method call argument</param>
  34. public void BindVertex(int argument)
  35. {
  36. Bind(argument, ShaderType.Vertex);
  37. }
  38. /// <summary>
  39. /// Binds a uniform buffer for the tessellation control shader stage.
  40. /// </summary>
  41. /// <param name="argument">Method call argument</param>
  42. public void BindTessControl(int argument)
  43. {
  44. Bind(argument, ShaderType.TessellationControl);
  45. }
  46. /// <summary>
  47. /// Binds a uniform buffer for the tessellation evaluation shader stage.
  48. /// </summary>
  49. /// <param name="argument">Method call argument</param>
  50. public void BindTessEvaluation(int argument)
  51. {
  52. Bind(argument, ShaderType.TessellationEvaluation);
  53. }
  54. /// <summary>
  55. /// Binds a uniform buffer for the geometry shader stage.
  56. /// </summary>
  57. /// <param name="argument">Method call argument</param>
  58. public void BindGeometry(int argument)
  59. {
  60. Bind(argument, ShaderType.Geometry);
  61. }
  62. /// <summary>
  63. /// Binds a uniform buffer for the fragment shader stage.
  64. /// </summary>
  65. /// <param name="argument">Method call argument</param>
  66. public void BindFragment(int argument)
  67. {
  68. Bind(argument, ShaderType.Fragment);
  69. }
  70. /// <summary>
  71. /// Binds a uniform buffer for the specified shader stage.
  72. /// </summary>
  73. /// <param name="argument">Method call argument</param>
  74. /// <param name="type">Shader stage that will access the uniform buffer</param>
  75. private void Bind(int argument, ShaderType type)
  76. {
  77. bool enable = (argument & 1) != 0;
  78. int index = (argument >> 4) & 0x1f;
  79. FlushUboDirty();
  80. if (enable)
  81. {
  82. var uniformBuffer = _state.State.UniformBufferState;
  83. ulong address = uniformBuffer.Address.Pack();
  84. _channel.BufferManager.SetGraphicsUniformBuffer((int)type, index, address, (uint)uniformBuffer.Size);
  85. }
  86. else
  87. {
  88. _channel.BufferManager.SetGraphicsUniformBuffer((int)type, index, 0, 0);
  89. }
  90. }
  91. /// <summary>
  92. /// Flushes any queued UBO updates.
  93. /// </summary>
  94. public void FlushUboDirty()
  95. {
  96. if (_ubFollowUpAddress != 0)
  97. {
  98. var memoryManager = _channel.MemoryManager;
  99. Span<byte> data = MemoryMarshal.Cast<int, byte>(_ubData.AsSpan(0, (int)(_ubByteCount / 4)));
  100. if (memoryManager.Physical.WriteWithRedundancyCheck(_ubBeginCpuAddress, data))
  101. {
  102. memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
  103. }
  104. _ubFollowUpAddress = 0;
  105. _ubIndex = 0;
  106. }
  107. }
  108. /// <summary>
  109. /// Updates the uniform buffer data with inline data.
  110. /// </summary>
  111. /// <param name="argument">New uniform buffer data word</param>
  112. public void Update(int argument)
  113. {
  114. var uniformBuffer = _state.State.UniformBufferState;
  115. ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
  116. if (_ubFollowUpAddress != address || _ubIndex == _ubData.Length)
  117. {
  118. FlushUboDirty();
  119. _ubByteCount = 0;
  120. _ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
  121. }
  122. _ubData[_ubIndex++] = argument;
  123. _ubFollowUpAddress = address + 4;
  124. _ubByteCount += 4;
  125. _state.State.UniformBufferState.Offset += 4;
  126. }
  127. /// <summary>
  128. /// Updates the uniform buffer data with inline data.
  129. /// </summary>
  130. /// <param name="data">Data to be written to the uniform buffer</param>
  131. public void Update(ReadOnlySpan<int> data)
  132. {
  133. var uniformBuffer = _state.State.UniformBufferState;
  134. ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
  135. ulong size = (ulong)data.Length * 4;
  136. if (_ubFollowUpAddress != address || _ubIndex + data.Length > _ubData.Length)
  137. {
  138. FlushUboDirty();
  139. _ubByteCount = 0;
  140. _ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
  141. }
  142. data.CopyTo(_ubData.AsSpan(_ubIndex));
  143. _ubIndex += data.Length;
  144. _ubFollowUpAddress = address + size;
  145. _ubByteCount += size;
  146. _state.State.UniformBufferState.Offset += data.Length * 4;
  147. }
  148. }
  149. }