ShaderSpecializationState.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  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. return Matches(channel, poolState, checkTextures, isCompute: false);
  402. }
  403. /// <summary>
  404. /// Checks if the recorded state matches the current GPU compute engine state.
  405. /// </summary>
  406. /// <param name="channel">GPU channel</param>
  407. /// <param name="poolState">Texture pool state</param>
  408. /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
  409. /// <returns>True if the state matches, false otherwise</returns>
  410. public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures)
  411. {
  412. return Matches(channel, poolState, checkTextures, isCompute: true);
  413. }
  414. /// <summary>
  415. /// Fetch the constant buffers used for a texture to cache.
  416. /// </summary>
  417. /// <param name="channel">GPU channel</param>
  418. /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
  419. /// <param name="cachedTextureBufferIndex">The currently cached texture buffer index</param>
  420. /// <param name="cachedSamplerBufferIndex">The currently cached sampler buffer index</param>
  421. /// <param name="cachedTextureBuffer">The currently cached texture buffer data</param>
  422. /// <param name="cachedSamplerBuffer">The currently cached sampler buffer data</param>
  423. /// <param name="cachedStageIndex">The currently cached stage</param>
  424. /// <param name="textureBufferIndex">The new texture buffer index</param>
  425. /// <param name="samplerBufferIndex">The new sampler buffer index</param>
  426. /// <param name="stageIndex">Stage index of the constant buffer</param>
  427. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  428. private static void UpdateCachedBuffer(
  429. GpuChannel channel,
  430. bool isCompute,
  431. ref int cachedTextureBufferIndex,
  432. ref int cachedSamplerBufferIndex,
  433. ref ReadOnlySpan<int> cachedTextureBuffer,
  434. ref ReadOnlySpan<int> cachedSamplerBuffer,
  435. ref int cachedStageIndex,
  436. int textureBufferIndex,
  437. int samplerBufferIndex,
  438. int stageIndex)
  439. {
  440. bool stageChange = stageIndex != cachedStageIndex;
  441. if (stageChange || textureBufferIndex != cachedTextureBufferIndex)
  442. {
  443. ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex);
  444. cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
  445. cachedTextureBufferIndex = textureBufferIndex;
  446. if (samplerBufferIndex == textureBufferIndex)
  447. {
  448. cachedSamplerBuffer = cachedTextureBuffer;
  449. cachedSamplerBufferIndex = samplerBufferIndex;
  450. }
  451. }
  452. if (stageChange || samplerBufferIndex != cachedSamplerBufferIndex)
  453. {
  454. ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex);
  455. cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
  456. cachedSamplerBufferIndex = samplerBufferIndex;
  457. }
  458. cachedStageIndex = stageIndex;
  459. }
  460. /// <summary>
  461. /// Checks if the recorded state matches the current GPU state.
  462. /// </summary>
  463. /// <param name="channel">GPU channel</param>
  464. /// <param name="poolState">Texture pool state</param>
  465. /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
  466. /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
  467. /// <returns>True if the state matches, false otherwise</returns>
  468. private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures, bool isCompute)
  469. {
  470. int constantBufferUsePerStageMask = _constantBufferUsePerStage;
  471. while (constantBufferUsePerStageMask != 0)
  472. {
  473. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  474. uint useMask = isCompute
  475. ? channel.BufferManager.GetComputeUniformBufferUseMask()
  476. : channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
  477. if (ConstantBufferUse[index] != useMask)
  478. {
  479. return false;
  480. }
  481. constantBufferUsePerStageMask &= ~(1 << index);
  482. }
  483. if (checkTextures)
  484. {
  485. TexturePool pool = channel.TextureManager.GetTexturePool(poolState.TexturePoolGpuVa, poolState.TexturePoolMaximumId);
  486. int cachedTextureBufferIndex = -1;
  487. int cachedSamplerBufferIndex = -1;
  488. int cachedStageIndex = -1;
  489. ReadOnlySpan<int> cachedTextureBuffer = Span<int>.Empty;
  490. ReadOnlySpan<int> cachedSamplerBuffer = Span<int>.Empty;
  491. foreach (var kv in _allTextures)
  492. {
  493. TextureKey textureKey = kv.Key;
  494. (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(textureKey.CbufSlot, poolState.TextureBufferIndex);
  495. UpdateCachedBuffer(channel,
  496. isCompute,
  497. ref cachedTextureBufferIndex,
  498. ref cachedSamplerBufferIndex,
  499. ref cachedTextureBuffer,
  500. ref cachedSamplerBuffer,
  501. ref cachedStageIndex,
  502. textureBufferIndex,
  503. samplerBufferIndex,
  504. textureKey.StageIndex);
  505. int packedId = TextureHandle.ReadPackedId(textureKey.Handle, cachedTextureBuffer, cachedSamplerBuffer);
  506. int textureId = TextureHandle.UnpackTextureId(packedId);
  507. if (pool.IsValidId(textureId))
  508. {
  509. ref readonly Image.TextureDescriptor descriptor = ref pool.GetDescriptorRef(textureId);
  510. if (!MatchesTexture(kv.Value, descriptor))
  511. {
  512. return false;
  513. }
  514. }
  515. }
  516. }
  517. return true;
  518. }
  519. /// <summary>
  520. /// Checks if the recorded texture state matches the given texture descriptor.
  521. /// </summary>
  522. /// <param name="specializationState">Texture specialization state</param>
  523. /// <param name="descriptor">Texture descriptor</param>
  524. /// <returns>True if the state matches, false otherwise</returns>
  525. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  526. private bool MatchesTexture(Box<TextureSpecializationState> specializationState, in Image.TextureDescriptor descriptor)
  527. {
  528. if (specializationState != null)
  529. {
  530. if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
  531. specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
  532. {
  533. return false;
  534. }
  535. }
  536. return true;
  537. }
  538. /// <summary>
  539. /// Checks if the recorded texture state for a given texture binding matches a texture descriptor.
  540. /// </summary>
  541. /// <param name="stage">The shader stage</param>
  542. /// <param name="index">The texture index</param>
  543. /// <param name="descriptor">Texture descriptor</param>
  544. /// <returns>True if the state matches, false otherwise</returns>
  545. public bool MatchesTexture(ShaderStage stage, int index, in Image.TextureDescriptor descriptor)
  546. {
  547. Box<TextureSpecializationState> specializationState = _textureByBinding[(int)stage][index];
  548. return MatchesTexture(specializationState, descriptor);
  549. }
  550. /// <summary>
  551. /// Checks if the recorded texture state for a given image binding matches a texture descriptor.
  552. /// </summary>
  553. /// <param name="stage">The shader stage</param>
  554. /// <param name="index">The texture index</param>
  555. /// <param name="descriptor">Texture descriptor</param>
  556. /// <returns>True if the state matches, false otherwise</returns>
  557. public bool MatchesImage(ShaderStage stage, int index, in Image.TextureDescriptor descriptor)
  558. {
  559. Box<TextureSpecializationState> specializationState = _imageByBinding[(int)stage][index];
  560. return MatchesTexture(specializationState, descriptor);
  561. }
  562. /// <summary>
  563. /// Reads shader specialization state that has been serialized.
  564. /// </summary>
  565. /// <param name="dataReader">Data reader</param>
  566. /// <returns>Shader specialization state</returns>
  567. public static ShaderSpecializationState Read(ref BinarySerializer dataReader)
  568. {
  569. ShaderSpecializationState specState = new ShaderSpecializationState();
  570. dataReader.Read(ref specState._queriedState);
  571. dataReader.Read(ref specState._compute);
  572. if (specState._compute)
  573. {
  574. dataReader.ReadWithMagicAndSize(ref specState.ComputeState, ComsMagic);
  575. }
  576. else
  577. {
  578. dataReader.ReadWithMagicAndSize(ref specState.GraphicsState, GfxsMagic);
  579. }
  580. dataReader.Read(ref specState._constantBufferUsePerStage);
  581. int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
  582. while (constantBufferUsePerStageMask != 0)
  583. {
  584. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  585. dataReader.Read(ref specState.ConstantBufferUse[index]);
  586. constantBufferUsePerStageMask &= ~(1 << index);
  587. }
  588. if (specState._queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
  589. {
  590. ushort tfCount = 0;
  591. dataReader.Read(ref tfCount);
  592. specState.TransformFeedbackDescriptors = new TransformFeedbackDescriptor[tfCount];
  593. for (int index = 0; index < tfCount; index++)
  594. {
  595. dataReader.ReadWithMagicAndSize(ref specState.TransformFeedbackDescriptors[index], TfbdMagic);
  596. }
  597. }
  598. ushort count = 0;
  599. dataReader.Read(ref count);
  600. for (int index = 0; index < count; index++)
  601. {
  602. TextureKey textureKey = default;
  603. Box<TextureSpecializationState> textureState = new Box<TextureSpecializationState>();
  604. dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic);
  605. dataReader.ReadWithMagicAndSize(ref textureState.Value, TexsMagic);
  606. specState._textureSpecialization[textureKey] = textureState;
  607. }
  608. return specState;
  609. }
  610. /// <summary>
  611. /// Serializes the shader specialization state.
  612. /// </summary>
  613. /// <param name="dataWriter">Data writer</param>
  614. public void Write(ref BinarySerializer dataWriter)
  615. {
  616. dataWriter.Write(ref _queriedState);
  617. dataWriter.Write(ref _compute);
  618. if (_compute)
  619. {
  620. dataWriter.WriteWithMagicAndSize(ref ComputeState, ComsMagic);
  621. }
  622. else
  623. {
  624. dataWriter.WriteWithMagicAndSize(ref GraphicsState, GfxsMagic);
  625. }
  626. dataWriter.Write(ref _constantBufferUsePerStage);
  627. int constantBufferUsePerStageMask = _constantBufferUsePerStage;
  628. while (constantBufferUsePerStageMask != 0)
  629. {
  630. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  631. dataWriter.Write(ref ConstantBufferUse[index]);
  632. constantBufferUsePerStageMask &= ~(1 << index);
  633. }
  634. if (_queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
  635. {
  636. ushort tfCount = (ushort)TransformFeedbackDescriptors.Length;
  637. dataWriter.Write(ref tfCount);
  638. for (int index = 0; index < TransformFeedbackDescriptors.Length; index++)
  639. {
  640. dataWriter.WriteWithMagicAndSize(ref TransformFeedbackDescriptors[index], TfbdMagic);
  641. }
  642. }
  643. ushort count = (ushort)_textureSpecialization.Count;
  644. dataWriter.Write(ref count);
  645. foreach (var kv in _textureSpecialization)
  646. {
  647. var textureKey = kv.Key;
  648. var textureState = kv.Value;
  649. dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic);
  650. dataWriter.WriteWithMagicAndSize(ref textureState.Value, TexsMagic);
  651. }
  652. }
  653. }
  654. }