ConstantBufferUpdater.cs 5.7 KB

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