ShaderSpecializationState.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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. /// <returns>True if the state matches, false otherwise</returns>
  351. public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState)
  352. {
  353. return Matches(channel, poolState, isCompute: false);
  354. }
  355. /// <summary>
  356. /// Checks if the recorded state matches the current GPU compute engine state.
  357. /// </summary>
  358. /// <param name="channel">GPU channel</param>
  359. /// <param name="poolState">Texture pool state</param>
  360. /// <returns>True if the state matches, false otherwise</returns>
  361. public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState)
  362. {
  363. return Matches(channel, poolState, isCompute: true);
  364. }
  365. /// <summary>
  366. /// Checks if the recorded state matches the current GPU state.
  367. /// </summary>
  368. /// <param name="channel">GPU channel</param>
  369. /// <param name="poolState">Texture pool state</param>
  370. /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
  371. /// <returns>True if the state matches, false otherwise</returns>
  372. private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool isCompute)
  373. {
  374. int constantBufferUsePerStageMask = _constantBufferUsePerStage;
  375. while (constantBufferUsePerStageMask != 0)
  376. {
  377. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  378. uint useMask = isCompute
  379. ? channel.BufferManager.GetComputeUniformBufferUseMask()
  380. : channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
  381. if (ConstantBufferUse[index] != useMask)
  382. {
  383. return false;
  384. }
  385. constantBufferUsePerStageMask &= ~(1 << index);
  386. }
  387. foreach (var kv in _textureSpecialization)
  388. {
  389. TextureKey textureKey = kv.Key;
  390. (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(textureKey.CbufSlot, poolState.TextureBufferIndex);
  391. ulong textureCbAddress;
  392. ulong samplerCbAddress;
  393. if (isCompute)
  394. {
  395. textureCbAddress = channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex);
  396. samplerCbAddress = channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex);
  397. }
  398. else
  399. {
  400. textureCbAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(textureKey.StageIndex, textureBufferIndex);
  401. samplerCbAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(textureKey.StageIndex, samplerBufferIndex);
  402. }
  403. if (!channel.MemoryManager.Physical.IsMapped(textureCbAddress) || !channel.MemoryManager.Physical.IsMapped(samplerCbAddress))
  404. {
  405. continue;
  406. }
  407. Image.TextureDescriptor descriptor;
  408. if (isCompute)
  409. {
  410. descriptor = channel.TextureManager.GetComputeTextureDescriptor(
  411. poolState.TexturePoolGpuVa,
  412. poolState.TextureBufferIndex,
  413. poolState.TexturePoolMaximumId,
  414. textureKey.Handle,
  415. textureKey.CbufSlot);
  416. }
  417. else
  418. {
  419. descriptor = channel.TextureManager.GetGraphicsTextureDescriptor(
  420. poolState.TexturePoolGpuVa,
  421. poolState.TextureBufferIndex,
  422. poolState.TexturePoolMaximumId,
  423. textureKey.StageIndex,
  424. textureKey.Handle,
  425. textureKey.CbufSlot);
  426. }
  427. Box<TextureSpecializationState> specializationState = kv.Value;
  428. if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
  429. specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
  430. {
  431. return false;
  432. }
  433. }
  434. return true;
  435. }
  436. /// <summary>
  437. /// Reads shader specialization state that has been serialized.
  438. /// </summary>
  439. /// <param name="dataReader">Data reader</param>
  440. /// <returns>Shader specialization state</returns>
  441. public static ShaderSpecializationState Read(ref BinarySerializer dataReader)
  442. {
  443. ShaderSpecializationState specState = new ShaderSpecializationState();
  444. dataReader.Read(ref specState._queriedState);
  445. dataReader.Read(ref specState._compute);
  446. if (specState._compute)
  447. {
  448. dataReader.ReadWithMagicAndSize(ref specState.ComputeState, ComsMagic);
  449. }
  450. else
  451. {
  452. dataReader.ReadWithMagicAndSize(ref specState.GraphicsState, GfxsMagic);
  453. }
  454. dataReader.Read(ref specState._constantBufferUsePerStage);
  455. int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
  456. while (constantBufferUsePerStageMask != 0)
  457. {
  458. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  459. dataReader.Read(ref specState.ConstantBufferUse[index]);
  460. constantBufferUsePerStageMask &= ~(1 << index);
  461. }
  462. if (specState._queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
  463. {
  464. ushort tfCount = 0;
  465. dataReader.Read(ref tfCount);
  466. specState.TransformFeedbackDescriptors = new TransformFeedbackDescriptor[tfCount];
  467. for (int index = 0; index < tfCount; index++)
  468. {
  469. dataReader.ReadWithMagicAndSize(ref specState.TransformFeedbackDescriptors[index], TfbdMagic);
  470. }
  471. }
  472. ushort count = 0;
  473. dataReader.Read(ref count);
  474. for (int index = 0; index < count; index++)
  475. {
  476. TextureKey textureKey = default;
  477. Box<TextureSpecializationState> textureState = new Box<TextureSpecializationState>();
  478. dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic);
  479. dataReader.ReadWithMagicAndSize(ref textureState.Value, TexsMagic);
  480. specState._textureSpecialization[textureKey] = textureState;
  481. }
  482. return specState;
  483. }
  484. /// <summary>
  485. /// Serializes the shader specialization state.
  486. /// </summary>
  487. /// <param name="dataWriter">Data writer</param>
  488. public void Write(ref BinarySerializer dataWriter)
  489. {
  490. dataWriter.Write(ref _queriedState);
  491. dataWriter.Write(ref _compute);
  492. if (_compute)
  493. {
  494. dataWriter.WriteWithMagicAndSize(ref ComputeState, ComsMagic);
  495. }
  496. else
  497. {
  498. dataWriter.WriteWithMagicAndSize(ref GraphicsState, GfxsMagic);
  499. }
  500. dataWriter.Write(ref _constantBufferUsePerStage);
  501. int constantBufferUsePerStageMask = _constantBufferUsePerStage;
  502. while (constantBufferUsePerStageMask != 0)
  503. {
  504. int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
  505. dataWriter.Write(ref ConstantBufferUse[index]);
  506. constantBufferUsePerStageMask &= ~(1 << index);
  507. }
  508. if (_queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
  509. {
  510. ushort tfCount = (ushort)TransformFeedbackDescriptors.Length;
  511. dataWriter.Write(ref tfCount);
  512. for (int index = 0; index < TransformFeedbackDescriptors.Length; index++)
  513. {
  514. dataWriter.WriteWithMagicAndSize(ref TransformFeedbackDescriptors[index], TfbdMagic);
  515. }
  516. }
  517. ushort count = (ushort)_textureSpecialization.Count;
  518. dataWriter.Write(ref count);
  519. foreach (var kv in _textureSpecialization)
  520. {
  521. var textureKey = kv.Key;
  522. var textureState = kv.Value;
  523. dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic);
  524. dataWriter.WriteWithMagicAndSize(ref textureState.Value, TexsMagic);
  525. }
  526. }
  527. }
  528. }