GpuAccessorBase.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Gpu.Engine.Threed;
  4. using Ryujinx.Graphics.Gpu.Image;
  5. using Ryujinx.Graphics.Shader;
  6. using Ryujinx.Graphics.Shader.Translation;
  7. namespace Ryujinx.Graphics.Gpu.Shader
  8. {
  9. /// <summary>
  10. /// GPU accessor.
  11. /// </summary>
  12. class GpuAccessorBase
  13. {
  14. private readonly GpuContext _context;
  15. private readonly ResourceCounts _resourceCounts;
  16. private readonly int _stageIndex;
  17. /// <summary>
  18. /// Creates a new GPU accessor.
  19. /// </summary>
  20. /// <param name="context">GPU context</param>
  21. public GpuAccessorBase(GpuContext context, ResourceCounts resourceCounts, int stageIndex)
  22. {
  23. _context = context;
  24. _resourceCounts = resourceCounts;
  25. _stageIndex = stageIndex;
  26. }
  27. /// <inheritdoc/>
  28. public int QueryBindingConstantBuffer(int index)
  29. {
  30. if (_context.Capabilities.Api == TargetApi.Vulkan)
  31. {
  32. // We need to start counting from 1 since binding 0 is reserved for the support uniform buffer.
  33. return GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer") + 1;
  34. }
  35. else
  36. {
  37. return _resourceCounts.UniformBuffersCount++;
  38. }
  39. }
  40. /// <inheritdoc/>
  41. public int QueryBindingStorageBuffer(int index)
  42. {
  43. if (_context.Capabilities.Api == TargetApi.Vulkan)
  44. {
  45. return GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
  46. }
  47. else
  48. {
  49. return _resourceCounts.StorageBuffersCount++;
  50. }
  51. }
  52. /// <inheritdoc/>
  53. public int QueryBindingTexture(int index, bool isBuffer)
  54. {
  55. if (_context.Capabilities.Api == TargetApi.Vulkan)
  56. {
  57. if (isBuffer)
  58. {
  59. index += (int)_context.Capabilities.MaximumTexturesPerStage;
  60. }
  61. return GetBindingFromIndex(index, _context.Capabilities.MaximumTexturesPerStage * 2, "Texture");
  62. }
  63. else
  64. {
  65. return _resourceCounts.TexturesCount++;
  66. }
  67. }
  68. /// <inheritdoc/>
  69. public int QueryBindingImage(int index, bool isBuffer)
  70. {
  71. if (_context.Capabilities.Api == TargetApi.Vulkan)
  72. {
  73. if (isBuffer)
  74. {
  75. index += (int)_context.Capabilities.MaximumImagesPerStage;
  76. }
  77. return GetBindingFromIndex(index, _context.Capabilities.MaximumImagesPerStage * 2, "Image");
  78. }
  79. else
  80. {
  81. return _resourceCounts.ImagesCount++;
  82. }
  83. }
  84. private int GetBindingFromIndex(int index, uint maxPerStage, string resourceName)
  85. {
  86. if ((uint)index >= maxPerStage)
  87. {
  88. Logger.Error?.Print(LogClass.Gpu, $"{resourceName} index {index} exceeds per stage limit of {maxPerStage}.");
  89. }
  90. return GetStageIndex() * (int)maxPerStage + index;
  91. }
  92. private int GetStageIndex()
  93. {
  94. // This is just a simple remapping to ensure that most frequently used shader stages
  95. // have the lowest binding numbers.
  96. // This is useful because if we need to run on a system with a low limit on the bindings,
  97. // then we can still get most games working as the most common shaders will have low binding numbers.
  98. return _stageIndex switch
  99. {
  100. 4 => 1, // Fragment
  101. 3 => 2, // Geometry
  102. 1 => 3, // Tessellation control
  103. 2 => 4, // Tessellation evaluation
  104. _ => 0 // Vertex/Compute
  105. };
  106. }
  107. /// <inheritdoc/>
  108. public bool QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
  109. /// <inheritdoc/>
  110. public bool QueryHostHasVectorIndexingBug() => _context.Capabilities.HasVectorIndexingBug;
  111. /// <inheritdoc/>
  112. public int QueryHostStorageBufferOffsetAlignment() => _context.Capabilities.StorageBufferOffsetAlignment;
  113. /// <inheritdoc/>
  114. public bool QueryHostSupportsBgraFormat() => _context.Capabilities.SupportsBgraFormat;
  115. /// <inheritdoc/>
  116. public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
  117. /// <inheritdoc/>
  118. public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
  119. /// <inheritdoc/>
  120. public bool QueryHostSupportsGeometryShaderPassthrough() => _context.Capabilities.SupportsGeometryShaderPassthrough;
  121. /// <inheritdoc/>
  122. public bool QueryHostSupportsImageLoadFormatted() => _context.Capabilities.SupportsImageLoadFormatted;
  123. /// <inheritdoc/>
  124. public bool QueryHostSupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
  125. /// <inheritdoc/>
  126. public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
  127. /// <inheritdoc/>
  128. public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
  129. /// <summary>
  130. /// Converts a packed Maxwell texture format to the shader translator texture format.
  131. /// </summary>
  132. /// <param name="format">Packed maxwell format</param>
  133. /// <param name="formatSrgb">Indicates if the format is sRGB</param>
  134. /// <returns>Shader translator texture format</returns>
  135. protected static TextureFormat ConvertToTextureFormat(uint format, bool formatSrgb)
  136. {
  137. if (!FormatTable.TryGetTextureFormat(format, formatSrgb, out FormatInfo formatInfo))
  138. {
  139. return TextureFormat.Unknown;
  140. }
  141. return formatInfo.Format switch
  142. {
  143. Format.R8Unorm => TextureFormat.R8Unorm,
  144. Format.R8Snorm => TextureFormat.R8Snorm,
  145. Format.R8Uint => TextureFormat.R8Uint,
  146. Format.R8Sint => TextureFormat.R8Sint,
  147. Format.R16Float => TextureFormat.R16Float,
  148. Format.R16Unorm => TextureFormat.R16Unorm,
  149. Format.R16Snorm => TextureFormat.R16Snorm,
  150. Format.R16Uint => TextureFormat.R16Uint,
  151. Format.R16Sint => TextureFormat.R16Sint,
  152. Format.R32Float => TextureFormat.R32Float,
  153. Format.R32Uint => TextureFormat.R32Uint,
  154. Format.R32Sint => TextureFormat.R32Sint,
  155. Format.R8G8Unorm => TextureFormat.R8G8Unorm,
  156. Format.R8G8Snorm => TextureFormat.R8G8Snorm,
  157. Format.R8G8Uint => TextureFormat.R8G8Uint,
  158. Format.R8G8Sint => TextureFormat.R8G8Sint,
  159. Format.R16G16Float => TextureFormat.R16G16Float,
  160. Format.R16G16Unorm => TextureFormat.R16G16Unorm,
  161. Format.R16G16Snorm => TextureFormat.R16G16Snorm,
  162. Format.R16G16Uint => TextureFormat.R16G16Uint,
  163. Format.R16G16Sint => TextureFormat.R16G16Sint,
  164. Format.R32G32Float => TextureFormat.R32G32Float,
  165. Format.R32G32Uint => TextureFormat.R32G32Uint,
  166. Format.R32G32Sint => TextureFormat.R32G32Sint,
  167. Format.R8G8B8A8Unorm => TextureFormat.R8G8B8A8Unorm,
  168. Format.R8G8B8A8Snorm => TextureFormat.R8G8B8A8Snorm,
  169. Format.R8G8B8A8Uint => TextureFormat.R8G8B8A8Uint,
  170. Format.R8G8B8A8Sint => TextureFormat.R8G8B8A8Sint,
  171. Format.R8G8B8A8Srgb => TextureFormat.R8G8B8A8Unorm,
  172. Format.R16G16B16A16Float => TextureFormat.R16G16B16A16Float,
  173. Format.R16G16B16A16Unorm => TextureFormat.R16G16B16A16Unorm,
  174. Format.R16G16B16A16Snorm => TextureFormat.R16G16B16A16Snorm,
  175. Format.R16G16B16A16Uint => TextureFormat.R16G16B16A16Uint,
  176. Format.R16G16B16A16Sint => TextureFormat.R16G16B16A16Sint,
  177. Format.R32G32B32A32Float => TextureFormat.R32G32B32A32Float,
  178. Format.R32G32B32A32Uint => TextureFormat.R32G32B32A32Uint,
  179. Format.R32G32B32A32Sint => TextureFormat.R32G32B32A32Sint,
  180. Format.R10G10B10A2Unorm => TextureFormat.R10G10B10A2Unorm,
  181. Format.R10G10B10A2Uint => TextureFormat.R10G10B10A2Uint,
  182. Format.R11G11B10Float => TextureFormat.R11G11B10Float,
  183. _ => TextureFormat.Unknown
  184. };
  185. }
  186. /// <summary>
  187. /// Converts the Maxwell primitive topology to the shader translator topology.
  188. /// </summary>
  189. /// <param name="topology">Maxwell primitive topology</param>
  190. /// <param name="tessellationMode">Maxwell tessellation mode</param>
  191. /// <returns>Shader translator topology</returns>
  192. protected static InputTopology ConvertToInputTopology(PrimitiveTopology topology, TessMode tessellationMode)
  193. {
  194. return topology switch
  195. {
  196. PrimitiveTopology.Points => InputTopology.Points,
  197. PrimitiveTopology.Lines or
  198. PrimitiveTopology.LineLoop or
  199. PrimitiveTopology.LineStrip => InputTopology.Lines,
  200. PrimitiveTopology.LinesAdjacency or
  201. PrimitiveTopology.LineStripAdjacency => InputTopology.LinesAdjacency,
  202. PrimitiveTopology.Triangles or
  203. PrimitiveTopology.TriangleStrip or
  204. PrimitiveTopology.TriangleFan => InputTopology.Triangles,
  205. PrimitiveTopology.TrianglesAdjacency or
  206. PrimitiveTopology.TriangleStripAdjacency => InputTopology.TrianglesAdjacency,
  207. PrimitiveTopology.Patches => tessellationMode.UnpackPatchType() == TessPatchType.Isolines
  208. ? InputTopology.Lines
  209. : InputTopology.Triangles,
  210. _ => InputTopology.Points
  211. };
  212. }
  213. }
  214. }