ShaderSpecializationState.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. using Ryujinx.Common.Memory;
  2. using Ryujinx.Graphics.Gpu.Shader.DiskCache;
  3. using Ryujinx.Graphics.Shader;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Numerics;
  7. namespace Ryujinx.Graphics.Gpu.Shader
  8. {
  9. class ShaderSpecializationState
  10. {
  11. private const uint ComsMagic = (byte)'C' | ((byte)'O' << 8) | ((byte)'M' << 16) | ((byte)'S' << 24);
  12. private const uint GfxsMagic = (byte)'G' | ((byte)'F' << 8) | ((byte)'X' << 16) | ((byte)'S' << 24);
  13. private const uint TfbdMagic = (byte)'T' | ((byte)'F' << 8) | ((byte)'B' << 16) | ((byte)'D' << 24);
  14. private const uint TexkMagic = (byte)'T' | ((byte)'E' << 8) | ((byte)'X' << 16) | ((byte)'K' << 24);
  15. private const uint TexsMagic = (byte)'T' | ((byte)'E' << 8) | ((byte)'X' << 16) | ((byte)'S' << 24);
  16. /// <summary>
  17. /// Flags indicating GPU state that is used by the shader.
  18. /// </summary>
  19. [Flags]
  20. private enum QueriedStateFlags
  21. {
  22. EarlyZForce = 1 << 0,
  23. PrimitiveTopology = 1 << 1,
  24. TessellationMode = 1 << 2,
  25. TransformFeedback = 1 << 3
  26. }
  27. private QueriedStateFlags _queriedState;
  28. private bool _compute;
  29. private byte _constantBufferUsePerStage;
  30. /// <summary>
  31. /// Compute engine state.
  32. /// </summary>
  33. public GpuChannelComputeState ComputeState;
  34. /// <summary>
  35. /// 3D engine state.
  36. /// </summary>
  37. public GpuChannelGraphicsState GraphicsState;
  38. /// <summary>
  39. /// Contant buffers bound at the time the shader was compiled, per stage.
  40. /// </summary>
  41. public Array5<uint> ConstantBufferUse;
  42. /// <summary>
  43. /// Transform feedback buffers active at the time the shader was compiled.
  44. /// </summary>
  45. public TransformFeedbackDescriptor[] TransformFeedbackDescriptors;
  46. /// <summary>
  47. /// Flags indicating texture state that is used by the shader.
  48. /// </summary>
  49. [Flags]
  50. private enum QueriedTextureStateFlags
  51. {
  52. TextureFormat = 1 << 0,
  53. SamplerType = 1 << 1,
  54. CoordNormalized = 1 << 2
  55. }
  56. /// <summary>
  57. /// Reference type wrapping a value.
  58. /// </summary>
  59. private class Box<T>
  60. {
  61. /// <summary>
  62. /// Wrapped value.
  63. /// </summary>
  64. public T Value;
  65. }
  66. /// <summary>
  67. /// State of a texture or image that is accessed by the shader.
  68. /// </summary>
  69. private struct TextureSpecializationState
  70. {
  71. // New fields should be added to the end of the struct to keep disk shader cache compatibility.
  72. /// <summary>
  73. /// Flags indicating which state of the texture the shader depends on.
  74. /// </summary>
  75. public QueriedTextureStateFlags QueriedFlags;
  76. /// <summary>
  77. /// Encoded texture format value.
  78. /// </summary>
  79. public uint Format;
  80. /// <summary>
  81. /// True if the texture format is sRGB, false otherwise.
  82. /// </summary>
  83. public bool FormatSrgb;
  84. /// <summary>
  85. /// Texture target.
  86. /// </summary>
  87. public Image.TextureTarget TextureTarget;
  88. /// <summary>
  89. /// Indicates if the coordinates used to sample the texture are normalized or not (0.0..1.0 or 0..Width/Height).
  90. /// </summary>
  91. public bool CoordNormalized;
  92. }
  93. /// <summary>
  94. /// Texture binding information, used to identify each texture accessed by the shader.
  95. /// </summary>
  96. private struct TextureKey : IEquatable<TextureKey>
  97. {
  98. // New fields should be added to the end of the struct to keep disk shader cache compatibility.
  99. /// <summary>
  100. /// Shader stage where the texture is used.
  101. /// </summary>
  102. public readonly int StageIndex;
  103. /// <summary>
  104. /// Texture handle offset in words on the texture buffer.
  105. /// </summary>
  106. public readonly int Handle;
  107. /// <summary>
  108. /// Constant buffer slot of the texture buffer (-1 to use the texture buffer index GPU register).
  109. /// </summary>
  110. public readonly int CbufSlot;
  111. /// <summary>
  112. /// Creates a new texture key.
  113. /// </summary>
  114. /// <param name="stageIndex">Shader stage where the texture is used</param>
  115. /// <param name="handle">Texture handle offset in words on the texture buffer</param>
  116. /// <param name="cbufSlot">Constant buffer slot of the texture buffer (-1 to use the texture buffer index GPU register)</param>
  117. public TextureKey(int stageIndex, int handle, int cbufSlot)
  118. {
  119. StageIndex = stageIndex;
  120. Handle = handle;
  121. CbufSlot = cbufSlot;
  122. }
  123. public override bool Equals(object obj)
  124. {
  125. return obj is TextureKey textureKey && Equals(textureKey);
  126. }
  127. public bool Equals(TextureKey other)
  128. {
  129. return StageIndex == other.StageIndex && Handle == other.Handle && CbufSlot == other.CbufSlot;
  130. }
  131. public override int GetHashCode()
  132. {
  133. return HashCode.Combine(StageIndex, Handle, CbufSlot);
  134. }
  135. }
  136. private readonly Dictionary<TextureKey, Box<TextureSpecializationState>> _textureSpecialization;
  137. /// <summary>
  138. /// Creates a new instance of the shader specialization state.
  139. /// </summary>
  140. private ShaderSpecializationState()
  141. {
  142. _textureSpecialization = new Dictionary<TextureKey, Box<TextureSpecializationState>>();
  143. }
  144. /// <summary>
  145. /// Creates a new instance of the shader specialization state.
  146. /// </summary>
  147. /// <param name="state">Current compute engine state</param>
  148. public ShaderSpecializationState(GpuChannelComputeState state) : this()
  149. {
  150. ComputeState = state;
  151. _compute = true;
  152. }
  153. /// <summary>
  154. /// Creates a new instance of the shader specialization state.
  155. /// </summary>
  156. /// <param name="state">Current 3D engine state</param>
  157. /// <param name="descriptors">Optional transform feedback buffers in use, if any</param>
  158. public ShaderSpecializationState(GpuChannelGraphicsState state, TransformFeedbackDescriptor[] descriptors) : this()
  159. {
  160. GraphicsState = state;
  161. _compute = false;
  162. if (descriptors != null)
  163. {
  164. TransformFeedbackDescriptors = descriptors;
  165. _queriedState |= QueriedStateFlags.TransformFeedback;
  166. }
  167. }
  168. /// <summary>
  169. /// Indicates that the shader accesses the early Z force state.
  170. /// </summary>
  171. public void RecordEarlyZForce()
  172. {
  173. _queriedState |= QueriedStateFlags.EarlyZForce;
  174. }
  175. /// <summary>
  176. /// Indicates that the shader accesses the primitive topology state.
  177. /// </summary>
  178. public void RecordPrimitiveTopology()
  179. {
  180. _queriedState |= QueriedStateFlags.PrimitiveTopology;
  181. }
  182. /// <summary>
  183. /// Indicates that the shader accesses the tessellation mode state.
  184. /// </summary>
  185. public void RecordTessellationMode()
  186. {
  187. _queriedState |= QueriedStateFlags.TessellationMode;
  188. }
  189. /// <summary>
  190. /// Indicates that the shader accesses the constant buffer use state.
  191. /// </summary>
  192. /// <param name="stageIndex">Shader stage index</param>
  193. /// <param name="useMask">Mask indicating the constant buffers bound at the time of the shader compilation</param>
  194. public void RecordConstantBufferUse(int stageIndex, uint useMask)
  195. {
  196. ConstantBufferUse[stageIndex] = useMask;
  197. _constantBufferUsePerStage |= (byte)(1 << stageIndex);
  198. }
  199. /// <summary>
  200. /// Indicates that a given texture is accessed by the shader.
  201. /// </summary>
  202. /// <param name="stageIndex">Shader stage where the texture is used</param>
  203. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  204. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  205. /// <param name="descriptor">Descriptor of the texture</param>
  206. public void RegisterTexture(int stageIndex, int handle, int cbufSlot, Image.TextureDescriptor descriptor)
  207. {
  208. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  209. state.Value.Format = descriptor.UnpackFormat();
  210. state.Value.FormatSrgb = descriptor.UnpackSrgb();
  211. state.Value.TextureTarget = descriptor.UnpackTextureTarget();
  212. state.Value.CoordNormalized = descriptor.UnpackTextureCoordNormalized();
  213. }
  214. /// <summary>
  215. /// Indicates that a given texture is accessed by the shader.
  216. /// </summary>
  217. /// <param name="stageIndex">Shader stage where the texture is used</param>
  218. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  219. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  220. /// <param name="format">Maxwell texture format value</param>
  221. /// <param name="formatSrgb">Whenever the texture format is a sRGB format</param>
  222. /// <param name="target">Texture target type</param>
  223. /// <param name="coordNormalized">Whenever the texture coordinates used on the shader are considered normalized</param>
  224. public void RegisterTexture(
  225. int stageIndex,
  226. int handle,
  227. int cbufSlot,
  228. uint format,
  229. bool formatSrgb,
  230. Image.TextureTarget target,
  231. bool coordNormalized)
  232. {
  233. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  234. state.Value.Format = format;
  235. state.Value.FormatSrgb = formatSrgb;
  236. state.Value.TextureTarget = target;
  237. state.Value.CoordNormalized = coordNormalized;
  238. }
  239. /// <summary>
  240. /// Indicates that the format of a given texture was used during the shader translation process.
  241. /// </summary>
  242. /// <param name="stageIndex">Shader stage where the texture is used</param>
  243. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  244. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  245. public void RecordTextureFormat(int stageIndex, int handle, int cbufSlot)
  246. {
  247. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  248. state.Value.QueriedFlags |= QueriedTextureStateFlags.TextureFormat;
  249. }
  250. /// <summary>
  251. /// Indicates that the target of a given texture was used during the shader translation process.
  252. /// </summary>
  253. /// <param name="stageIndex">Shader stage where the texture is used</param>
  254. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  255. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  256. public void RecordTextureSamplerType(int stageIndex, int handle, int cbufSlot)
  257. {
  258. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  259. state.Value.QueriedFlags |= QueriedTextureStateFlags.SamplerType;
  260. }
  261. /// <summary>
  262. /// Indicates that the coordinate normalization state of a given texture was used during the shader translation process.
  263. /// </summary>
  264. /// <param name="stageIndex">Shader stage where the texture is used</param>
  265. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  266. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  267. public void RecordTextureCoordNormalized(int stageIndex, int handle, int cbufSlot)
  268. {
  269. Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
  270. state.Value.QueriedFlags |= QueriedTextureStateFlags.CoordNormalized;
  271. }
  272. /// <summary>
  273. /// Checks if a given texture was registerd on this specialization state.
  274. /// </summary>
  275. /// <param name="stageIndex">Shader stage where the texture is used</param>
  276. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  277. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  278. public bool TextureRegistered(int stageIndex, int handle, int cbufSlot)
  279. {
  280. return GetTextureSpecState(stageIndex, handle, cbufSlot) != null;
  281. }
  282. /// <summary>
  283. /// Gets the recorded format of a given texture.
  284. /// </summary>
  285. /// <param name="stageIndex">Shader stage where the texture is used</param>
  286. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  287. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  288. public (uint, bool) GetFormat(int stageIndex, int handle, int cbufSlot)
  289. {
  290. TextureSpecializationState state = GetTextureSpecState(stageIndex, handle, cbufSlot).Value;
  291. return (state.Format, state.FormatSrgb);
  292. }
  293. /// <summary>
  294. /// Gets the recorded target of a given texture.
  295. /// </summary>
  296. /// <param name="stageIndex">Shader stage where the texture is used</param>
  297. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  298. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  299. public Image.TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot)
  300. {
  301. return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget;
  302. }
  303. /// <summary>
  304. /// Gets the recorded coordinate normalization state of a given texture.
  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 bool GetCoordNormalized(int stageIndex, int handle, int cbufSlot)
  310. {
  311. return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.CoordNormalized;
  312. }
  313. /// <summary>
  314. /// Gets texture specialization state for a given texture, or create a new one if not present.
  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. /// <returns>Texture specialization state</returns>
  320. private Box<TextureSpecializationState> GetOrCreateTextureSpecState(int stageIndex, int handle, int cbufSlot)
  321. {
  322. TextureKey key = new TextureKey(stageIndex, handle, cbufSlot);
  323. if (!_textureSpecialization.TryGetValue(key, out Box<TextureSpecializationState> state))
  324. {
  325. _textureSpecialization.Add(key, state = new Box<TextureSpecializationState>());
  326. }
  327. return state;
  328. }
  329. /// <summary>
  330. /// Gets texture specialization state for a given texture.
  331. /// </summary>
  332. /// <param name="stageIndex">Shader stage where the texture is used</param>
  333. /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
  334. /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
  335. /// <returns>Texture specialization state</returns>
  336. private Box<TextureSpecializationState> GetTextureSpecState(int stageIndex, int handle, int cbufSlot)
  337. {
  338. TextureKey key = new TextureKey(stageIndex, handle, cbufSlot);
  339. if (_textureSpecialization.TryGetValue(key, out Box<TextureSpecializationState> state))
  340. {
  341. return state;
  342. }
  343. return null;
  344. }
  345. /// <summary>
  346. /// Checks if the recorded state matches the current GPU 3D engine state.
  347. /// </summary>
  348. /// <param name="channel">GPU channel</param>
  349. /// <param name="poolState">Texture pool state</param>
  350. /// <param name="graphicsState">Graphics state</param>
  351. /// <returns>True if the state matches, false otherwise</returns>
  352. public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelGraphicsState graphicsState)
  353. {
  354. if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
  355. {
  356. return false;
  357. }
  358. return Matches(channel, poolState, isCompute: false);
  359. }
  360. /// <summary>
  361. /// Checks if the recorded state matches the current GPU compute engine state.
  362. /// </summary>
  363. /// <param name="channel">GPU channel</param>
  364. /// <param name="poolState">Texture pool state</param>
  365. /// <returns>True if the state matches, false otherwise</returns>
  366. public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState)
  367. {
  368. return Matches(channel, poolState, isCompute: true);
  369. }
  370. /// <summary>
  371. /// Checks if the recorded state matches the current GPU state.
  372. /// </summary>
  373. /// <param name="channel">GPU channel</param>
  374. /// <param name="poolState">Texture pool state</param>
  375. /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
  376. /// <returns>True if the state matches, false otherwise</returns>
  377. private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool isCompute)
  378. {
  379. int constantBufferUsePerStageMask = _constantBufferUsePerStage;
  380. while (constantBufferUsePerStageMask != 0)
  381. {
  382. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  383. uint useMask = isCompute
  384. ? channel.BufferManager.GetComputeUniformBufferUseMask()
  385. : channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
  386. if (ConstantBufferUse[index] != useMask)
  387. {
  388. return false;
  389. }
  390. constantBufferUsePerStageMask &= ~(1 << index);
  391. }
  392. foreach (var kv in _textureSpecialization)
  393. {
  394. TextureKey textureKey = kv.Key;
  395. (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(textureKey.CbufSlot, poolState.TextureBufferIndex);
  396. ulong textureCbAddress;
  397. ulong samplerCbAddress;
  398. if (isCompute)
  399. {
  400. textureCbAddress = channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex);
  401. samplerCbAddress = channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex);
  402. }
  403. else
  404. {
  405. textureCbAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(textureKey.StageIndex, textureBufferIndex);
  406. samplerCbAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(textureKey.StageIndex, samplerBufferIndex);
  407. }
  408. if (!channel.MemoryManager.Physical.IsMapped(textureCbAddress) || !channel.MemoryManager.Physical.IsMapped(samplerCbAddress))
  409. {
  410. continue;
  411. }
  412. Image.TextureDescriptor descriptor;
  413. if (isCompute)
  414. {
  415. descriptor = channel.TextureManager.GetComputeTextureDescriptor(
  416. poolState.TexturePoolGpuVa,
  417. poolState.TextureBufferIndex,
  418. poolState.TexturePoolMaximumId,
  419. textureKey.Handle,
  420. textureKey.CbufSlot);
  421. }
  422. else
  423. {
  424. descriptor = channel.TextureManager.GetGraphicsTextureDescriptor(
  425. poolState.TexturePoolGpuVa,
  426. poolState.TextureBufferIndex,
  427. poolState.TexturePoolMaximumId,
  428. textureKey.StageIndex,
  429. textureKey.Handle,
  430. textureKey.CbufSlot);
  431. }
  432. Box<TextureSpecializationState> specializationState = kv.Value;
  433. if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
  434. specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
  435. {
  436. return false;
  437. }
  438. }
  439. return true;
  440. }
  441. /// <summary>
  442. /// Reads shader specialization state that has been serialized.
  443. /// </summary>
  444. /// <param name="dataReader">Data reader</param>
  445. /// <returns>Shader specialization state</returns>
  446. public static ShaderSpecializationState Read(ref BinarySerializer dataReader)
  447. {
  448. ShaderSpecializationState specState = new ShaderSpecializationState();
  449. dataReader.Read(ref specState._queriedState);
  450. dataReader.Read(ref specState._compute);
  451. if (specState._compute)
  452. {
  453. dataReader.ReadWithMagicAndSize(ref specState.ComputeState, ComsMagic);
  454. }
  455. else
  456. {
  457. dataReader.ReadWithMagicAndSize(ref specState.GraphicsState, GfxsMagic);
  458. }
  459. dataReader.Read(ref specState._constantBufferUsePerStage);
  460. int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
  461. while (constantBufferUsePerStageMask != 0)
  462. {
  463. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  464. dataReader.Read(ref specState.ConstantBufferUse[index]);
  465. constantBufferUsePerStageMask &= ~(1 << index);
  466. }
  467. if (specState._queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
  468. {
  469. ushort tfCount = 0;
  470. dataReader.Read(ref tfCount);
  471. specState.TransformFeedbackDescriptors = new TransformFeedbackDescriptor[tfCount];
  472. for (int index = 0; index < tfCount; index++)
  473. {
  474. dataReader.ReadWithMagicAndSize(ref specState.TransformFeedbackDescriptors[index], TfbdMagic);
  475. }
  476. }
  477. ushort count = 0;
  478. dataReader.Read(ref count);
  479. for (int index = 0; index < count; index++)
  480. {
  481. TextureKey textureKey = default;
  482. Box<TextureSpecializationState> textureState = new Box<TextureSpecializationState>();
  483. dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic);
  484. dataReader.ReadWithMagicAndSize(ref textureState.Value, TexsMagic);
  485. specState._textureSpecialization[textureKey] = textureState;
  486. }
  487. return specState;
  488. }
  489. /// <summary>
  490. /// Serializes the shader specialization state.
  491. /// </summary>
  492. /// <param name="dataWriter">Data writer</param>
  493. public void Write(ref BinarySerializer dataWriter)
  494. {
  495. dataWriter.Write(ref _queriedState);
  496. dataWriter.Write(ref _compute);
  497. if (_compute)
  498. {
  499. dataWriter.WriteWithMagicAndSize(ref ComputeState, ComsMagic);
  500. }
  501. else
  502. {
  503. dataWriter.WriteWithMagicAndSize(ref GraphicsState, GfxsMagic);
  504. }
  505. dataWriter.Write(ref _constantBufferUsePerStage);
  506. int constantBufferUsePerStageMask = _constantBufferUsePerStage;
  507. while (constantBufferUsePerStageMask != 0)
  508. {
  509. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  510. dataWriter.Write(ref ConstantBufferUse[index]);
  511. constantBufferUsePerStageMask &= ~(1 << index);
  512. }
  513. if (_queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
  514. {
  515. ushort tfCount = (ushort)TransformFeedbackDescriptors.Length;
  516. dataWriter.Write(ref tfCount);
  517. for (int index = 0; index < TransformFeedbackDescriptors.Length; index++)
  518. {
  519. dataWriter.WriteWithMagicAndSize(ref TransformFeedbackDescriptors[index], TfbdMagic);
  520. }
  521. }
  522. ushort count = (ushort)_textureSpecialization.Count;
  523. dataWriter.Write(ref count);
  524. foreach (var kv in _textureSpecialization)
  525. {
  526. var textureKey = kv.Key;
  527. var textureState = kv.Value;
  528. dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic);
  529. dataWriter.WriteWithMagicAndSize(ref textureState.Value, TexsMagic);
  530. }
  531. }
  532. }
  533. }