GpuAccessor.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Gpu.Image;
  4. using Ryujinx.Graphics.Gpu.State;
  5. using Ryujinx.Graphics.Shader;
  6. using System;
  7. namespace Ryujinx.Graphics.Gpu.Shader
  8. {
  9. /// <summary>
  10. /// Represents a GPU state and memory accessor.
  11. /// </summary>
  12. class GpuAccessor : IGpuAccessor
  13. {
  14. private readonly GpuContext _context;
  15. private readonly GpuState _state;
  16. private readonly int _stageIndex;
  17. private readonly bool _compute;
  18. private readonly int _localSizeX;
  19. private readonly int _localSizeY;
  20. private readonly int _localSizeZ;
  21. private readonly int _localMemorySize;
  22. private readonly int _sharedMemorySize;
  23. /// <summary>
  24. /// Creates a new instance of the GPU state accessor for graphics shader translation.
  25. /// </summary>
  26. /// <param name="context">GPU context</param>
  27. /// <param name="state">Current GPU state</param>
  28. /// <param name="stageIndex">Graphics shader stage index (0 = Vertex, 4 = Fragment)</param>
  29. public GpuAccessor(GpuContext context, GpuState state, int stageIndex)
  30. {
  31. _context = context;
  32. _state = state;
  33. _stageIndex = stageIndex;
  34. }
  35. /// <summary>
  36. /// Creates a new instance of the GPU state accessor for compute shader translation.
  37. /// </summary>
  38. /// <param name="context">GPU context</param>
  39. /// <param name="state">Current GPU state</param>
  40. /// <param name="localSizeX">Local group size X of the compute shader</param>
  41. /// <param name="localSizeY">Local group size Y of the compute shader</param>
  42. /// <param name="localSizeZ">Local group size Z of the compute shader</param>
  43. /// <param name="localMemorySize">Local memory size of the compute shader</param>
  44. /// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
  45. public GpuAccessor(
  46. GpuContext context,
  47. GpuState state,
  48. int localSizeX,
  49. int localSizeY,
  50. int localSizeZ,
  51. int localMemorySize,
  52. int sharedMemorySize)
  53. {
  54. _context = context;
  55. _state = state;
  56. _compute = true;
  57. _localSizeX = localSizeX;
  58. _localSizeY = localSizeY;
  59. _localSizeZ = localSizeZ;
  60. _localMemorySize = localMemorySize;
  61. _sharedMemorySize = sharedMemorySize;
  62. }
  63. /// <summary>
  64. /// Prints a log message.
  65. /// </summary>
  66. /// <param name="message">Message to print</param>
  67. public void Log(string message)
  68. {
  69. Logger.Warning?.Print(LogClass.Gpu, $"Shader translator: {message}");
  70. }
  71. /// <summary>
  72. /// Reads data from GPU memory.
  73. /// </summary>
  74. /// <typeparam name="T">Type of the data to be read</typeparam>
  75. /// <param name="address">GPU virtual address of the data</param>
  76. /// <returns>Data at the memory location</returns>
  77. public T MemoryRead<T>(ulong address) where T : unmanaged
  78. {
  79. return _context.MemoryManager.Read<T>(address);
  80. }
  81. /// <summary>
  82. /// Queries Local Size X for compute shaders.
  83. /// </summary>
  84. /// <returns>Local Size X</returns>
  85. public int QueryComputeLocalSizeX() => _localSizeX;
  86. /// <summary>
  87. /// Queries Local Size Y for compute shaders.
  88. /// </summary>
  89. /// <returns>Local Size Y</returns>
  90. public int QueryComputeLocalSizeY() => _localSizeY;
  91. /// <summary>
  92. /// Queries Local Size Z for compute shaders.
  93. /// </summary>
  94. /// <returns>Local Size Z</returns>
  95. public int QueryComputeLocalSizeZ() => _localSizeZ;
  96. /// <summary>
  97. /// Queries Local Memory size in bytes for compute shaders.
  98. /// </summary>
  99. /// <returns>Local Memory size in bytes</returns>
  100. public int QueryComputeLocalMemorySize() => _localMemorySize;
  101. /// <summary>
  102. /// Queries Shared Memory size in bytes for compute shaders.
  103. /// </summary>
  104. /// <returns>Shared Memory size in bytes</returns>
  105. public int QueryComputeSharedMemorySize() => _sharedMemorySize;
  106. /// <summary>
  107. /// Queries texture target information.
  108. /// </summary>
  109. /// <param name="handle">Texture handle</param>
  110. /// <returns>True if the texture is a buffer texture, false otherwise</returns>
  111. public bool QueryIsTextureBuffer(int handle)
  112. {
  113. return GetTextureDescriptor(handle).UnpackTextureTarget() == TextureTarget.TextureBuffer;
  114. }
  115. /// <summary>
  116. /// Queries texture target information.
  117. /// </summary>
  118. /// <param name="handle">Texture handle</param>
  119. /// <returns>True if the texture is a rectangle texture, false otherwise</returns>
  120. public bool QueryIsTextureRectangle(int handle)
  121. {
  122. var descriptor = GetTextureDescriptor(handle);
  123. TextureTarget target = descriptor.UnpackTextureTarget();
  124. bool is2DTexture = target == TextureTarget.Texture2D ||
  125. target == TextureTarget.Texture2DRect;
  126. return !descriptor.UnpackTextureCoordNormalized() && is2DTexture;
  127. }
  128. /// <summary>
  129. /// Queries current primitive topology for geometry shaders.
  130. /// </summary>
  131. /// <returns>Current primitive topology</returns>
  132. public InputTopology QueryPrimitiveTopology()
  133. {
  134. switch (_context.Methods.PrimitiveType)
  135. {
  136. case PrimitiveType.Points:
  137. return InputTopology.Points;
  138. case PrimitiveType.Lines:
  139. case PrimitiveType.LineLoop:
  140. case PrimitiveType.LineStrip:
  141. return InputTopology.Lines;
  142. case PrimitiveType.LinesAdjacency:
  143. case PrimitiveType.LineStripAdjacency:
  144. return InputTopology.LinesAdjacency;
  145. case PrimitiveType.Triangles:
  146. case PrimitiveType.TriangleStrip:
  147. case PrimitiveType.TriangleFan:
  148. return InputTopology.Triangles;
  149. case PrimitiveType.TrianglesAdjacency:
  150. case PrimitiveType.TriangleStripAdjacency:
  151. return InputTopology.TrianglesAdjacency;
  152. }
  153. return InputTopology.Points;
  154. }
  155. /// <summary>
  156. /// Queries host storage buffer alignment required.
  157. /// </summary>
  158. /// <returns>Host storage buffer alignment in bytes</returns>
  159. public int QueryStorageBufferOffsetAlignment() => _context.Capabilities.StorageBufferOffsetAlignment;
  160. /// <summary>
  161. /// Queries host support for readable images without a explicit format declaration on the shader.
  162. /// </summary>
  163. /// <returns>True if formatted image load is supported, false otherwise</returns>
  164. public bool QuerySupportsImageLoadFormatted() => _context.Capabilities.SupportsImageLoadFormatted;
  165. /// <summary>
  166. /// Queries host GPU non-constant texture offset support.
  167. /// </summary>
  168. /// <returns>True if the GPU and driver supports non-constant texture offsets, false otherwise</returns>
  169. public bool QuerySupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
  170. /// <summary>
  171. /// Queries host GPU viewport swizzle support.
  172. /// </summary>
  173. /// <returns>True if the GPU and driver supports viewport swizzle, false otherwise</returns>
  174. public bool QuerySupportsViewportSwizzle() => _context.Capabilities.SupportsViewportSwizzle;
  175. /// <summary>
  176. /// Queries texture format information, for shaders using image load or store.
  177. /// </summary>
  178. /// <remarks>
  179. /// This only returns non-compressed color formats.
  180. /// If the format of the texture is a compressed, depth or unsupported format, then a default value is returned.
  181. /// </remarks>
  182. /// <param name="handle">Texture handle</param>
  183. /// <returns>Color format of the non-compressed texture</returns>
  184. public TextureFormat QueryTextureFormat(int handle)
  185. {
  186. var descriptor = GetTextureDescriptor(handle);
  187. if (!FormatTable.TryGetTextureFormat(descriptor.UnpackFormat(), descriptor.UnpackSrgb(), out FormatInfo formatInfo))
  188. {
  189. return TextureFormat.Unknown;
  190. }
  191. return formatInfo.Format switch
  192. {
  193. Format.R8Unorm => TextureFormat.R8Unorm,
  194. Format.R8Snorm => TextureFormat.R8Snorm,
  195. Format.R8Uint => TextureFormat.R8Uint,
  196. Format.R8Sint => TextureFormat.R8Sint,
  197. Format.R16Float => TextureFormat.R16Float,
  198. Format.R16Unorm => TextureFormat.R16Unorm,
  199. Format.R16Snorm => TextureFormat.R16Snorm,
  200. Format.R16Uint => TextureFormat.R16Uint,
  201. Format.R16Sint => TextureFormat.R16Sint,
  202. Format.R32Float => TextureFormat.R32Float,
  203. Format.R32Uint => TextureFormat.R32Uint,
  204. Format.R32Sint => TextureFormat.R32Sint,
  205. Format.R8G8Unorm => TextureFormat.R8G8Unorm,
  206. Format.R8G8Snorm => TextureFormat.R8G8Snorm,
  207. Format.R8G8Uint => TextureFormat.R8G8Uint,
  208. Format.R8G8Sint => TextureFormat.R8G8Sint,
  209. Format.R16G16Float => TextureFormat.R16G16Float,
  210. Format.R16G16Unorm => TextureFormat.R16G16Unorm,
  211. Format.R16G16Snorm => TextureFormat.R16G16Snorm,
  212. Format.R16G16Uint => TextureFormat.R16G16Uint,
  213. Format.R16G16Sint => TextureFormat.R16G16Sint,
  214. Format.R32G32Float => TextureFormat.R32G32Float,
  215. Format.R32G32Uint => TextureFormat.R32G32Uint,
  216. Format.R32G32Sint => TextureFormat.R32G32Sint,
  217. Format.R8G8B8A8Unorm => TextureFormat.R8G8B8A8Unorm,
  218. Format.R8G8B8A8Snorm => TextureFormat.R8G8B8A8Snorm,
  219. Format.R8G8B8A8Uint => TextureFormat.R8G8B8A8Uint,
  220. Format.R8G8B8A8Sint => TextureFormat.R8G8B8A8Sint,
  221. Format.R16G16B16A16Float => TextureFormat.R16G16B16A16Float,
  222. Format.R16G16B16A16Unorm => TextureFormat.R16G16B16A16Unorm,
  223. Format.R16G16B16A16Snorm => TextureFormat.R16G16B16A16Snorm,
  224. Format.R16G16B16A16Uint => TextureFormat.R16G16B16A16Uint,
  225. Format.R16G16B16A16Sint => TextureFormat.R16G16B16A16Sint,
  226. Format.R32G32B32A32Float => TextureFormat.R32G32B32A32Float,
  227. Format.R32G32B32A32Uint => TextureFormat.R32G32B32A32Uint,
  228. Format.R32G32B32A32Sint => TextureFormat.R32G32B32A32Sint,
  229. Format.R10G10B10A2Unorm => TextureFormat.R10G10B10A2Unorm,
  230. Format.R10G10B10A2Uint => TextureFormat.R10G10B10A2Uint,
  231. Format.R11G11B10Float => TextureFormat.R11G11B10Float,
  232. _ => TextureFormat.Unknown
  233. };
  234. }
  235. public int QueryViewportSwizzle(int component)
  236. {
  237. YControl yControl = _state.Get<YControl>(MethodOffset.YControl);
  238. bool flipY = yControl.HasFlag(YControl.NegateY) ^ !yControl.HasFlag(YControl.TriangleRastFlip);
  239. ViewportTransform transform = _state.Get<ViewportTransform>(MethodOffset.ViewportTransform, 0);
  240. return component switch
  241. {
  242. 0 => (int)(transform.UnpackSwizzleX() ^ (transform.ScaleX < 0 ? ViewportSwizzle.NegativeFlag : 0)),
  243. 1 => (int)(transform.UnpackSwizzleY() ^ (transform.ScaleY < 0 ? ViewportSwizzle.NegativeFlag : 0) ^ (flipY ? ViewportSwizzle.NegativeFlag : 0)),
  244. 2 => (int)(transform.UnpackSwizzleZ() ^ (transform.ScaleZ < 0 ? ViewportSwizzle.NegativeFlag : 0)),
  245. 3 => (int)transform.UnpackSwizzleW(),
  246. _ => throw new ArgumentOutOfRangeException(nameof(component))
  247. };
  248. }
  249. /// <summary>
  250. /// Gets the texture descriptor for a given texture on the pool.
  251. /// </summary>
  252. /// <param name="handle">Index of the texture (this is the shader "fake" handle)</param>
  253. /// <returns>Texture descriptor</returns>
  254. private Image.TextureDescriptor GetTextureDescriptor(int handle)
  255. {
  256. if (_compute)
  257. {
  258. return _context.Methods.TextureManager.GetComputeTextureDescriptor(_state, handle);
  259. }
  260. else
  261. {
  262. return _context.Methods.TextureManager.GetGraphicsTextureDescriptor(_state, _stageIndex, handle);
  263. }
  264. }
  265. }
  266. }