ShaderSpecializationState.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. using Ryujinx.Common.Memory;
  2. using Ryujinx.Graphics.Gpu.Image;
  3. using Ryujinx.Graphics.Gpu.Memory;
  4. using Ryujinx.Graphics.GAL;
  5. using Ryujinx.Graphics.Gpu.Shader.DiskCache;
  6. using Ryujinx.Graphics.Shader;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Numerics;
  11. using System.Runtime.CompilerServices;
  12. using System.Runtime.InteropServices;
  13. namespace Ryujinx.Graphics.Gpu.Shader
  14. {
  15. class ShaderSpecializationState
  16. {
  17. private const uint ComsMagic = (byte)'C' | ((byte)'O' << 8) | ((byte)'M' << 16) | ((byte)'S' << 24);
  18. private const uint GfxsMagic = (byte)'G' | ((byte)'F' << 8) | ((byte)'X' << 16) | ((byte)'S' << 24);
  19. private const uint TfbdMagic = (byte)'T' | ((byte)'F' << 8) | ((byte)'B' << 16) | ((byte)'D' << 24);
  20. private const uint TexkMagic = (byte)'T' | ((byte)'E' << 8) | ((byte)'X' << 16) | ((byte)'K' << 24);
  21. private const uint TexsMagic = (byte)'T' | ((byte)'E' << 8) | ((byte)'X' << 16) | ((byte)'S' << 24);
  22. private const uint PgpsMagic = (byte)'P' | ((byte)'G' << 8) | ((byte)'P' << 16) | ((byte)'S' << 24);
  23. /// <summary>
  24. /// Flags indicating GPU state that is used by the shader.
  25. /// </summary>
  26. [Flags]
  27. private enum QueriedStateFlags
  28. {
  29. EarlyZForce = 1 << 0,
  30. PrimitiveTopology = 1 << 1,
  31. TessellationMode = 1 << 2,
  32. TransformFeedback = 1 << 3
  33. }
  34. private QueriedStateFlags _queriedState;
  35. private bool _compute;
  36. private byte _constantBufferUsePerStage;
  37. /// <summary>
  38. /// Compute engine state.
  39. /// </summary>
  40. public GpuChannelComputeState ComputeState;
  41. /// <summary>
  42. /// 3D engine state.
  43. /// </summary>
  44. public GpuChannelGraphicsState GraphicsState;
  45. /// <summary>
  46. /// Contant buffers bound at the time the shader was compiled, per stage.
  47. /// </summary>
  48. public Array5<uint> ConstantBufferUse;
  49. /// <summary>
  50. /// Pipeline state captured at the time of shader use.
  51. /// </summary>
  52. public ProgramPipelineState? PipelineState;
  53. /// <summary>
  54. /// Transform feedback buffers active at the time the shader was compiled.
  55. /// </summary>
  56. public TransformFeedbackDescriptor[] TransformFeedbackDescriptors;
  57. /// <summary>
  58. /// Flags indicating texture state that is used by the shader.
  59. /// </summary>
  60. [Flags]
  61. private enum QueriedTextureStateFlags
  62. {
  63. TextureFormat = 1 << 0,
  64. SamplerType = 1 << 1,
  65. CoordNormalized = 1 << 2
  66. }
  67. /// <summary>
  68. /// Reference type wrapping a value.
  69. /// </summary>
  70. private class Box<T>
  71. {
  72. /// <summary>
  73. /// Wrapped value.
  74. /// </summary>
  75. public T Value;
  76. }
  77. /// <summary>
  78. /// State of a texture or image that is accessed by the shader.
  79. /// </summary>
  80. private struct TextureSpecializationState
  81. {
  82. // New fields should be added to the end of the struct to keep disk shader cache compatibility.
  83. /// <summary>
  84. /// Flags indicating which state of the texture the shader depends on.
  85. /// </summary>
  86. public QueriedTextureStateFlags QueriedFlags;
  87. /// <summary>
  88. /// Encoded texture format value.
  89. /// </summary>
  90. public uint Format;
  91. /// <summary>
  92. /// True if the texture format is sRGB, false otherwise.
  93. /// </summary>
  94. public bool FormatSrgb;
  95. /// <summary>
  96. /// Texture target.
  97. /// </summary>
  98. public Image.TextureTarget TextureTarget;
  99. /// <summary>
  100. /// Indicates if the coordinates used to sample the texture are normalized or not (0.0..1.0 or 0..Width/Height).
  101. /// </summary>
  102. public bool CoordNormalized;
  103. }
  104. /// <summary>
  105. /// Texture binding information, used to identify each texture accessed by the shader.
  106. /// </summary>
  107. private struct TextureKey : IEquatable<TextureKey>
  108. {
  109. // New fields should be added to the end of the struct to keep disk shader cache compatibility.
  110. /// <summary>
  111. /// Shader stage where the texture is used.
  112. /// </summary>
  113. public readonly int StageIndex;
  114. /// <summary>
  115. /// Texture handle offset in words on the texture buffer.
  116. /// </summary>
  117. public readonly int Handle;
  118. /// <summary>
  119. /// Constant buffer slot of the texture buffer (-1 to use the texture buffer index GPU register).
  120. /// </summary>
  121. public readonly int CbufSlot;
  122. /// <summary>
  123. /// Creates a new texture key.
  124. /// </summary>
  125. /// <param name="stageIndex">Shader stage where the texture is used</param>
  126. /// <param name="handle">Texture handle offset in words on the texture buffer</param>
  127. /// <param name="cbufSlot">Constant buffer slot of the texture buffer (-1 to use the texture buffer index GPU register)</param>
  128. public TextureKey(int stageIndex, int handle, int cbufSlot)
  129. {
  130. StageIndex = stageIndex;
  131. Handle = handle;
  132. CbufSlot = cbufSlot;
  133. }
  134. public override bool Equals(object obj)
  135. {
  136. return obj is TextureKey textureKey && Equals(textureKey);
  137. }
  138. public bool Equals(TextureKey other)
  139. {
  140. return StageIndex == other.StageIndex && Handle == other.Handle && CbufSlot == other.CbufSlot;
  141. }
  142. public override int GetHashCode()
  143. {
  144. return HashCode.Combine(StageIndex, Handle, CbufSlot);
  145. }
  146. }
  147. private readonly Dictionary<TextureKey, Box<TextureSpecializationState>> _textureSpecialization;
  148. private KeyValuePair<TextureKey, Box<TextureSpecializationState>>[] _allTextures;
  149. private Box<TextureSpecializationState>[][] _textureByBinding;
  150. private Box<TextureSpecializationState>[][] _imageByBinding;
  151. /// <summary>
  152. /// Creates a new instance of the shader specialization state.
  153. /// </summary>
  154. private ShaderSpecializationState()
  155. {
  156. _textureSpecialization = new Dictionary<TextureKey, Box<TextureSpecializationState>>();
  157. }
  158. /// <summary>
  159. /// Creates a new instance of the shader specialization state.
  160. /// </summary>
  161. /// <param name="state">Current compute engine state</param>
  162. public ShaderSpecializationState(ref GpuChannelComputeState state) : this()
  163. {
  164. ComputeState = state;
  165. _compute = true;
  166. }
  167. /// <summary>
  168. /// Creates a new instance of the shader specialization state.
  169. /// </summary>
  170. /// <param name="state">Current 3D engine state</param>
  171. /// <param name="descriptors">Optional transform feedback buffers in use, if any</param>
  172. private ShaderSpecializationState(ref GpuChannelGraphicsState state, TransformFeedbackDescriptor[] descriptors) : this()
  173. {
  174. GraphicsState = state;
  175. _compute = false;
  176. if (descriptors != null)
  177. {
  178. TransformFeedbackDescriptors = descriptors;
  179. _queriedState |= QueriedStateFlags.TransformFeedback;
  180. }
  181. }
  182. /// <summary>
  183. /// Prepare the shader specialization state for quick binding lookups.
  184. /// </summary>
  185. /// <param name="stages">The shader stages</param>
  186. public void Prepare(CachedShaderStage[] stages)
  187. {
  188. _allTextures = _textureSpecialization.ToArray();
  189. _textureByBinding = new Box<TextureSpecializationState>[stages.Length][];
  190. _imageByBinding = new Box<TextureSpecializationState>[stages.Length][];
  191. for (int i = 0; i < stages.Length; i++)
  192. {
  193. CachedShaderStage stage = stages[i];
  194. if (stage?.Info != null)
  195. {
  196. var textures = stage.Info.Textures;
  197. var images = stage.Info.Images;
  198. var texBindings = new Box<TextureSpecializationState>[textures.Count];
  199. var imageBindings = new Box<TextureSpecializationState>[images.Count];
  200. int stageIndex = Math.Max(i - 1, 0); // Don't count VertexA for looking up spec state. No-Op for compute.
  201. for (int j = 0; j < textures.Count; j++)
  202. {
  203. var texture = textures[j];
  204. texBindings[j] = GetTextureSpecState(stageIndex, texture.HandleIndex, texture.CbufSlot);
  205. }
  206. for (int j = 0; j < images.Count; j++)
  207. {
  208. var image = images[j];
  209. imageBindings[j] = GetTextureSpecState(stageIndex, image.HandleIndex, image.CbufSlot);
  210. }
  211. _textureByBinding[i] = texBindings;
  212. _imageByBinding[i] = imageBindings;
  213. }
  214. }
  215. }
  216. /// <summary>
  217. /// Creates a new instance of the shader specialization state.
  218. /// </summary>
  219. /// <param name="state">Current 3D engine state</param>
  220. /// <param name="pipelineState">Current program pipeline state</param>
  221. /// <param name="descriptors">Optional transform feedback buffers in use, if any</param>
  222. public ShaderSpecializationState(
  223. ref GpuChannelGraphicsState state,
  224. ref ProgramPipelineState pipelineState,
  225. TransformFeedbackDescriptor[] descriptors) : this(ref state, descriptors)
  226. {
  227. PipelineState = pipelineState;
  228. }
  229. /// <summary>
  230. /// Creates a new instance of the shader specialization state.
  231. /// </summary>
  232. /// <param name="state">Current 3D engine state</param>
  233. /// <param name="pipelineState">Current program pipeline state</param>
  234. /// <param name="descriptors">Optional transform feedback buffers in use, if any</param>
  235. public ShaderSpecializationState(
  236. ref GpuChannelGraphicsState state,
  237. ProgramPipelineState? pipelineState,
  238. TransformFeedbackDescriptor[] descriptors) : this(ref state, descriptors)
  239. {
  240. PipelineState = pipelineState;
  241. }
  242. /// <summary>
  243. /// Indicates that the shader accesses the early Z force state.
  244. /// </summary>
  245. public void RecordEarlyZForce()
  246. {
  247. _queriedState |= QueriedStateFlags.EarlyZForce;
  248. }
  249. /// <summary>
  250. /// Indicates that the shader accesses the primitive topology state.
  251. /// </summary>
  252. public void RecordPrimitiveTopology()
  253. {
  254. _queriedState |= QueriedStateFlags.PrimitiveTopology;
  255. }
  256. /// <summary>
  257. /// Indicates that the shader accesses the tessellation mode state.
  258. /// </summary>
  259. public void RecordTessellationMode()
  260. {
  261. _queriedState |= QueriedStateFlags.TessellationMode;
  262. }
  263. /// <summary>
  264. /// Indicates that the shader accesses the constant buffer use state.
  265. /// </summary>
  266. /// <param name="stageIndex">Shader stage index</param>
  267. /// <param name="useMask">Mask indicating the constant buffers bound at the time of the shader compilation</param>
  268. public void RecordConstantBufferUse(int stageIndex, uint useMask)
  269. {
  270. ConstantBufferUse[stageIndex] = useMask;
  271. _constantBufferUsePerStage |= (byte)(1 << stageIndex);
  272. }
  273. /// <summary>
  274. /// Indicates that a given texture is accessed by the shader.
  275. /// </summary>
  276. /// <param name="stageIndex">Shader stage where the texture is used</param>
  277. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  278. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  279. /// <param name="descriptor">Descriptor of the texture</param>
  280. public void RegisterTexture(int stageIndex, int handle, int cbufSlot, Image.TextureDescriptor descriptor)
  281. {
  282. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  283. state.Value.Format = descriptor.UnpackFormat();
  284. state.Value.FormatSrgb = descriptor.UnpackSrgb();
  285. state.Value.TextureTarget = descriptor.UnpackTextureTarget();
  286. state.Value.CoordNormalized = descriptor.UnpackTextureCoordNormalized();
  287. }
  288. /// <summary>
  289. /// Indicates that a given texture is accessed by the shader.
  290. /// </summary>
  291. /// <param name="stageIndex">Shader stage where the texture is used</param>
  292. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  293. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  294. /// <param name="format">Maxwell texture format value</param>
  295. /// <param name="formatSrgb">Whenever the texture format is a sRGB format</param>
  296. /// <param name="target">Texture target type</param>
  297. /// <param name="coordNormalized">Whenever the texture coordinates used on the shader are considered normalized</param>
  298. public void RegisterTexture(
  299. int stageIndex,
  300. int handle,
  301. int cbufSlot,
  302. uint format,
  303. bool formatSrgb,
  304. Image.TextureTarget target,
  305. bool coordNormalized)
  306. {
  307. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  308. state.Value.Format = format;
  309. state.Value.FormatSrgb = formatSrgb;
  310. state.Value.TextureTarget = target;
  311. state.Value.CoordNormalized = coordNormalized;
  312. }
  313. /// <summary>
  314. /// Indicates that the format of a given texture was used during the shader translation process.
  315. /// </summary>
  316. /// <param name="stageIndex">Shader stage where the texture is used</param>
  317. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  318. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  319. public void RecordTextureFormat(int stageIndex, int handle, int cbufSlot)
  320. {
  321. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  322. state.Value.QueriedFlags |= QueriedTextureStateFlags.TextureFormat;
  323. }
  324. /// <summary>
  325. /// Indicates that the target of a given texture was used during the shader translation process.
  326. /// </summary>
  327. /// <param name="stageIndex">Shader stage where the texture is used</param>
  328. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  329. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  330. public void RecordTextureSamplerType(int stageIndex, int handle, int cbufSlot)
  331. {
  332. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  333. state.Value.QueriedFlags |= QueriedTextureStateFlags.SamplerType;
  334. }
  335. /// <summary>
  336. /// Indicates that the coordinate normalization state of a given texture was used during the shader translation process.
  337. /// </summary>
  338. /// <param name="stageIndex">Shader stage where the texture is used</param>
  339. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  340. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  341. public void RecordTextureCoordNormalized(int stageIndex, int handle, int cbufSlot)
  342. {
  343. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  344. state.Value.QueriedFlags |= QueriedTextureStateFlags.CoordNormalized;
  345. }
  346. /// <summary>
  347. /// Checks if primitive topology was queried by the shader.
  348. /// </summary>
  349. /// <returns>True if queried, false otherwise</returns>
  350. public bool IsPrimitiveTopologyQueried()
  351. {
  352. return _queriedState.HasFlag(QueriedStateFlags.PrimitiveTopology);
  353. }
  354. /// <summary>
  355. /// Checks if a given texture was registerd on this specialization state.
  356. /// </summary>
  357. /// <param name="stageIndex">Shader stage where the texture is used</param>
  358. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  359. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  360. public bool TextureRegistered(int stageIndex, int handle, int cbufSlot)
  361. {
  362. return GetTextureSpecState(stageIndex, handle, cbufSlot) != null;
  363. }
  364. /// <summary>
  365. /// Gets the recorded format of a given texture.
  366. /// </summary>
  367. /// <param name="stageIndex">Shader stage where the texture is used</param>
  368. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  369. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  370. public (uint, bool) GetFormat(int stageIndex, int handle, int cbufSlot)
  371. {
  372. TextureSpecializationState state = GetTextureSpecState(stageIndex, handle, cbufSlot).Value;
  373. return (state.Format, state.FormatSrgb);
  374. }
  375. /// <summary>
  376. /// Gets the recorded target of a given texture.
  377. /// </summary>
  378. /// <param name="stageIndex">Shader stage where the texture is used</param>
  379. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  380. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  381. public Image.TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot)
  382. {
  383. return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget;
  384. }
  385. /// <summary>
  386. /// Gets the recorded coordinate normalization state of a given texture.
  387. /// </summary>
  388. /// <param name="stageIndex">Shader stage where the texture is used</param>
  389. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  390. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  391. public bool GetCoordNormalized(int stageIndex, int handle, int cbufSlot)
  392. {
  393. return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.CoordNormalized;
  394. }
  395. /// <summary>
  396. /// Gets texture specialization state for a given texture, or create a new one if not present.
  397. /// </summary>
  398. /// <param name="stageIndex">Shader stage where the texture is used</param>
  399. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  400. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  401. /// <returns>Texture specialization state</returns>
  402. private Box<TextureSpecializationState> GetOrCreateTextureSpecState(int stageIndex, int handle, int cbufSlot)
  403. {
  404. TextureKey key = new TextureKey(stageIndex, handle, cbufSlot);
  405. if (!_textureSpecialization.TryGetValue(key, out Box<TextureSpecializationState> state))
  406. {
  407. _textureSpecialization.Add(key, state = new Box<TextureSpecializationState>());
  408. }
  409. return state;
  410. }
  411. /// <summary>
  412. /// Gets texture specialization state for a given texture.
  413. /// </summary>
  414. /// <param name="stageIndex">Shader stage where the texture is used</param>
  415. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  416. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  417. /// <returns>Texture specialization state</returns>
  418. private Box<TextureSpecializationState> GetTextureSpecState(int stageIndex, int handle, int cbufSlot)
  419. {
  420. TextureKey key = new TextureKey(stageIndex, handle, cbufSlot);
  421. if (_textureSpecialization.TryGetValue(key, out Box<TextureSpecializationState> state))
  422. {
  423. return state;
  424. }
  425. return null;
  426. }
  427. /// <summary>
  428. /// Checks if the recorded state matches the current GPU 3D engine state.
  429. /// </summary>
  430. /// <param name="channel">GPU channel</param>
  431. /// <param name="poolState">Texture pool state</param>
  432. /// <param name="graphicsState">Graphics state</param>
  433. /// <param name="usesDrawParameters">Indicates whether the vertex shader accesses draw parameters</param>
  434. /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
  435. /// <returns>True if the state matches, false otherwise</returns>
  436. public bool MatchesGraphics(
  437. GpuChannel channel,
  438. ref GpuChannelPoolState poolState,
  439. ref GpuChannelGraphicsState graphicsState,
  440. bool usesDrawParameters,
  441. bool checkTextures)
  442. {
  443. if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
  444. {
  445. return false;
  446. }
  447. bool thisA2cDitherEnable = GraphicsState.AlphaToCoverageEnable && GraphicsState.AlphaToCoverageDitherEnable;
  448. bool otherA2cDitherEnable = graphicsState.AlphaToCoverageEnable && graphicsState.AlphaToCoverageDitherEnable;
  449. if (otherA2cDitherEnable != thisA2cDitherEnable)
  450. {
  451. return false;
  452. }
  453. if (graphicsState.DepthMode != GraphicsState.DepthMode)
  454. {
  455. return false;
  456. }
  457. if (graphicsState.AlphaTestEnable != GraphicsState.AlphaTestEnable)
  458. {
  459. return false;
  460. }
  461. if (graphicsState.AlphaTestEnable &&
  462. (graphicsState.AlphaTestCompare != GraphicsState.AlphaTestCompare ||
  463. graphicsState.AlphaTestReference != GraphicsState.AlphaTestReference))
  464. {
  465. return false;
  466. }
  467. if (!graphicsState.AttributeTypes.AsSpan().SequenceEqual(GraphicsState.AttributeTypes.AsSpan()))
  468. {
  469. return false;
  470. }
  471. if (usesDrawParameters && graphicsState.HasConstantBufferDrawParameters != GraphicsState.HasConstantBufferDrawParameters)
  472. {
  473. return false;
  474. }
  475. if (graphicsState.HasUnalignedStorageBuffer != GraphicsState.HasUnalignedStorageBuffer)
  476. {
  477. return false;
  478. }
  479. return Matches(channel, ref poolState, checkTextures, isCompute: false);
  480. }
  481. /// <summary>
  482. /// Checks if the recorded state matches the current GPU compute engine state.
  483. /// </summary>
  484. /// <param name="channel">GPU channel</param>
  485. /// <param name="poolState">Texture pool state</param>
  486. /// <param name="computeState">Compute state</param>
  487. /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
  488. /// <returns>True if the state matches, false otherwise</returns>
  489. public bool MatchesCompute(GpuChannel channel, ref GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures)
  490. {
  491. if (computeState.HasUnalignedStorageBuffer != ComputeState.HasUnalignedStorageBuffer)
  492. {
  493. return false;
  494. }
  495. return Matches(channel, ref poolState, checkTextures, isCompute: true);
  496. }
  497. /// <summary>
  498. /// Fetch the constant buffers used for a texture to cache.
  499. /// </summary>
  500. /// <param name="channel">GPU channel</param>
  501. /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
  502. /// <param name="cachedTextureBufferIndex">The currently cached texture buffer index</param>
  503. /// <param name="cachedSamplerBufferIndex">The currently cached sampler buffer index</param>
  504. /// <param name="cachedTextureBuffer">The currently cached texture buffer data</param>
  505. /// <param name="cachedSamplerBuffer">The currently cached sampler buffer data</param>
  506. /// <param name="cachedStageIndex">The currently cached stage</param>
  507. /// <param name="textureBufferIndex">The new texture buffer index</param>
  508. /// <param name="samplerBufferIndex">The new sampler buffer index</param>
  509. /// <param name="stageIndex">Stage index of the constant buffer</param>
  510. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  511. private static void UpdateCachedBuffer(
  512. GpuChannel channel,
  513. bool isCompute,
  514. scoped ref int cachedTextureBufferIndex,
  515. scoped ref int cachedSamplerBufferIndex,
  516. scoped ref ReadOnlySpan<int> cachedTextureBuffer,
  517. scoped ref ReadOnlySpan<int> cachedSamplerBuffer,
  518. scoped ref int cachedStageIndex,
  519. int textureBufferIndex,
  520. int samplerBufferIndex,
  521. int stageIndex)
  522. {
  523. bool stageChange = stageIndex != cachedStageIndex;
  524. if (stageChange || textureBufferIndex != cachedTextureBufferIndex)
  525. {
  526. ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex);
  527. cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
  528. cachedTextureBufferIndex = textureBufferIndex;
  529. if (samplerBufferIndex == textureBufferIndex)
  530. {
  531. cachedSamplerBuffer = cachedTextureBuffer;
  532. cachedSamplerBufferIndex = samplerBufferIndex;
  533. }
  534. }
  535. if (stageChange || samplerBufferIndex != cachedSamplerBufferIndex)
  536. {
  537. ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex);
  538. cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
  539. cachedSamplerBufferIndex = samplerBufferIndex;
  540. }
  541. cachedStageIndex = stageIndex;
  542. }
  543. /// <summary>
  544. /// Checks if the recorded state matches the current GPU state.
  545. /// </summary>
  546. /// <param name="channel">GPU channel</param>
  547. /// <param name="poolState">Texture pool state</param>
  548. /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
  549. /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
  550. /// <returns>True if the state matches, false otherwise</returns>
  551. private bool Matches(GpuChannel channel, ref GpuChannelPoolState poolState, bool checkTextures, bool isCompute)
  552. {
  553. int constantBufferUsePerStageMask = _constantBufferUsePerStage;
  554. while (constantBufferUsePerStageMask != 0)
  555. {
  556. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  557. uint useMask = isCompute
  558. ? channel.BufferManager.GetComputeUniformBufferUseMask()
  559. : channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
  560. if (ConstantBufferUse[index] != useMask)
  561. {
  562. return false;
  563. }
  564. constantBufferUsePerStageMask &= ~(1 << index);
  565. }
  566. if (checkTextures)
  567. {
  568. TexturePool pool = channel.TextureManager.GetTexturePool(poolState.TexturePoolGpuVa, poolState.TexturePoolMaximumId);
  569. int cachedTextureBufferIndex = -1;
  570. int cachedSamplerBufferIndex = -1;
  571. int cachedStageIndex = -1;
  572. ReadOnlySpan<int> cachedTextureBuffer = Span<int>.Empty;
  573. ReadOnlySpan<int> cachedSamplerBuffer = Span<int>.Empty;
  574. foreach (var kv in _allTextures)
  575. {
  576. TextureKey textureKey = kv.Key;
  577. (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(textureKey.CbufSlot, poolState.TextureBufferIndex);
  578. UpdateCachedBuffer(channel,
  579. isCompute,
  580. ref cachedTextureBufferIndex,
  581. ref cachedSamplerBufferIndex,
  582. ref cachedTextureBuffer,
  583. ref cachedSamplerBuffer,
  584. ref cachedStageIndex,
  585. textureBufferIndex,
  586. samplerBufferIndex,
  587. textureKey.StageIndex);
  588. int packedId = TextureHandle.ReadPackedId(textureKey.Handle, cachedTextureBuffer, cachedSamplerBuffer);
  589. int textureId = TextureHandle.UnpackTextureId(packedId);
  590. if (pool.IsValidId(textureId))
  591. {
  592. ref readonly Image.TextureDescriptor descriptor = ref pool.GetDescriptorRef(textureId);
  593. if (!MatchesTexture(kv.Value, descriptor))
  594. {
  595. return false;
  596. }
  597. }
  598. }
  599. }
  600. return true;
  601. }
  602. /// <summary>
  603. /// Checks if the recorded texture state matches the given texture descriptor.
  604. /// </summary>
  605. /// <param name="specializationState">Texture specialization state</param>
  606. /// <param name="descriptor">Texture descriptor</param>
  607. /// <returns>True if the state matches, false otherwise</returns>
  608. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  609. private bool MatchesTexture(Box<TextureSpecializationState> specializationState, in Image.TextureDescriptor descriptor)
  610. {
  611. if (specializationState != null)
  612. {
  613. if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
  614. specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
  615. {
  616. return false;
  617. }
  618. }
  619. return true;
  620. }
  621. /// <summary>
  622. /// Checks if the recorded texture state for a given texture binding matches a texture descriptor.
  623. /// </summary>
  624. /// <param name="stage">The shader stage</param>
  625. /// <param name="index">The texture index</param>
  626. /// <param name="descriptor">Texture descriptor</param>
  627. /// <returns>True if the state matches, false otherwise</returns>
  628. public bool MatchesTexture(ShaderStage stage, int index, in Image.TextureDescriptor descriptor)
  629. {
  630. Box<TextureSpecializationState> specializationState = _textureByBinding[(int)stage][index];
  631. return MatchesTexture(specializationState, descriptor);
  632. }
  633. /// <summary>
  634. /// Checks if the recorded texture state for a given image binding matches a texture descriptor.
  635. /// </summary>
  636. /// <param name="stage">The shader stage</param>
  637. /// <param name="index">The texture index</param>
  638. /// <param name="descriptor">Texture descriptor</param>
  639. /// <returns>True if the state matches, false otherwise</returns>
  640. public bool MatchesImage(ShaderStage stage, int index, in Image.TextureDescriptor descriptor)
  641. {
  642. Box<TextureSpecializationState> specializationState = _imageByBinding[(int)stage][index];
  643. return MatchesTexture(specializationState, descriptor);
  644. }
  645. /// <summary>
  646. /// Reads shader specialization state that has been serialized.
  647. /// </summary>
  648. /// <param name="dataReader">Data reader</param>
  649. /// <returns>Shader specialization state</returns>
  650. public static ShaderSpecializationState Read(ref BinarySerializer dataReader)
  651. {
  652. ShaderSpecializationState specState = new ShaderSpecializationState();
  653. dataReader.Read(ref specState._queriedState);
  654. dataReader.Read(ref specState._compute);
  655. if (specState._compute)
  656. {
  657. dataReader.ReadWithMagicAndSize(ref specState.ComputeState, ComsMagic);
  658. }
  659. else
  660. {
  661. dataReader.ReadWithMagicAndSize(ref specState.GraphicsState, GfxsMagic);
  662. }
  663. dataReader.Read(ref specState._constantBufferUsePerStage);
  664. int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
  665. while (constantBufferUsePerStageMask != 0)
  666. {
  667. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  668. dataReader.Read(ref specState.ConstantBufferUse[index]);
  669. constantBufferUsePerStageMask &= ~(1 << index);
  670. }
  671. bool hasPipelineState = false;
  672. dataReader.Read(ref hasPipelineState);
  673. if (hasPipelineState)
  674. {
  675. ProgramPipelineState pipelineState = default;
  676. dataReader.ReadWithMagicAndSize(ref pipelineState, PgpsMagic);
  677. specState.PipelineState = pipelineState;
  678. }
  679. if (specState._queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
  680. {
  681. ushort tfCount = 0;
  682. dataReader.Read(ref tfCount);
  683. specState.TransformFeedbackDescriptors = new TransformFeedbackDescriptor[tfCount];
  684. for (int index = 0; index < tfCount; index++)
  685. {
  686. dataReader.ReadWithMagicAndSize(ref specState.TransformFeedbackDescriptors[index], TfbdMagic);
  687. }
  688. }
  689. ushort count = 0;
  690. dataReader.Read(ref count);
  691. for (int index = 0; index < count; index++)
  692. {
  693. TextureKey textureKey = default;
  694. Box<TextureSpecializationState> textureState = new Box<TextureSpecializationState>();
  695. dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic);
  696. dataReader.ReadWithMagicAndSize(ref textureState.Value, TexsMagic);
  697. specState._textureSpecialization[textureKey] = textureState;
  698. }
  699. return specState;
  700. }
  701. /// <summary>
  702. /// Serializes the shader specialization state.
  703. /// </summary>
  704. /// <param name="dataWriter">Data writer</param>
  705. public void Write(ref BinarySerializer dataWriter)
  706. {
  707. dataWriter.Write(ref _queriedState);
  708. dataWriter.Write(ref _compute);
  709. if (_compute)
  710. {
  711. dataWriter.WriteWithMagicAndSize(ref ComputeState, ComsMagic);
  712. }
  713. else
  714. {
  715. dataWriter.WriteWithMagicAndSize(ref GraphicsState, GfxsMagic);
  716. }
  717. dataWriter.Write(ref _constantBufferUsePerStage);
  718. int constantBufferUsePerStageMask = _constantBufferUsePerStage;
  719. while (constantBufferUsePerStageMask != 0)
  720. {
  721. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  722. dataWriter.Write(ref ConstantBufferUse[index]);
  723. constantBufferUsePerStageMask &= ~(1 << index);
  724. }
  725. bool hasPipelineState = PipelineState.HasValue;
  726. dataWriter.Write(ref hasPipelineState);
  727. if (hasPipelineState)
  728. {
  729. ProgramPipelineState pipelineState = PipelineState.Value;
  730. dataWriter.WriteWithMagicAndSize(ref pipelineState, PgpsMagic);
  731. }
  732. if (_queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
  733. {
  734. ushort tfCount = (ushort)TransformFeedbackDescriptors.Length;
  735. dataWriter.Write(ref tfCount);
  736. for (int index = 0; index < TransformFeedbackDescriptors.Length; index++)
  737. {
  738. dataWriter.WriteWithMagicAndSize(ref TransformFeedbackDescriptors[index], TfbdMagic);
  739. }
  740. }
  741. ushort count = (ushort)_textureSpecialization.Count;
  742. dataWriter.Write(ref count);
  743. foreach (var kv in _textureSpecialization)
  744. {
  745. var textureKey = kv.Key;
  746. var textureState = kv.Value;
  747. dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic);
  748. dataWriter.WriteWithMagicAndSize(ref textureState.Value, TexsMagic);
  749. }
  750. }
  751. }
  752. }