ShaderSpecializationState.cs 33 KB

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