ShaderConfig.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2. using Ryujinx.Graphics.Shader.StructuredIr;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Numerics;
  7. namespace Ryujinx.Graphics.Shader.Translation
  8. {
  9. class ShaderConfig
  10. {
  11. // TODO: Non-hardcoded array size.
  12. public const int SamplerArraySize = 4;
  13. private const int ThreadsPerWarp = 32;
  14. public ShaderStage Stage { get; }
  15. public bool GpPassthrough { get; }
  16. public bool LastInPipeline { get; private set; }
  17. public bool LastInVertexPipeline { get; private set; }
  18. public int ThreadsPerInputPrimitive { get; }
  19. public OutputTopology OutputTopology { get; }
  20. public int MaxOutputVertices { get; }
  21. public int LocalMemorySize { get; }
  22. public ImapPixelType[] ImapTypes { get; }
  23. public int OmapTargets { get; }
  24. public bool OmapSampleMask { get; }
  25. public bool OmapDepth { get; }
  26. public IGpuAccessor GpuAccessor { get; }
  27. public TranslationOptions Options { get; }
  28. public bool TransformFeedbackEnabled { get; }
  29. public int Size { get; private set; }
  30. public byte ClipDistancesWritten { get; private set; }
  31. public FeatureFlags UsedFeatures { get; private set; }
  32. public int Cb1DataSize { get; private set; }
  33. public bool LayerOutputWritten { get; private set; }
  34. public int LayerOutputAttribute { get; private set; }
  35. public bool NextUsesFixedFuncAttributes { get; private set; }
  36. public int UsedInputAttributes { get; private set; }
  37. public int UsedOutputAttributes { get; private set; }
  38. public HashSet<int> UsedInputAttributesPerPatch { get; }
  39. public HashSet<int> UsedOutputAttributesPerPatch { get; }
  40. public HashSet<int> NextUsedInputAttributesPerPatch { get; private set; }
  41. public int PassthroughAttributes { get; private set; }
  42. private int _nextUsedInputAttributes;
  43. private int _thisUsedInputAttributes;
  44. private Dictionary<int, int> _perPatchAttributeLocations;
  45. public UInt128 NextInputAttributesComponents { get; private set; }
  46. public UInt128 ThisInputAttributesComponents { get; private set; }
  47. private int _usedConstantBuffers;
  48. private int _usedStorageBuffers;
  49. private int _usedStorageBuffersWrite;
  50. private readonly record struct TextureInfo(int CbufSlot, int Handle, bool Indexed, TextureFormat Format);
  51. private struct TextureMeta
  52. {
  53. public bool AccurateType;
  54. public SamplerType Type;
  55. public TextureUsageFlags UsageFlags;
  56. }
  57. private readonly Dictionary<TextureInfo, TextureMeta> _usedTextures;
  58. private readonly Dictionary<TextureInfo, TextureMeta> _usedImages;
  59. private BufferDescriptor[] _cachedConstantBufferDescriptors;
  60. private BufferDescriptor[] _cachedStorageBufferDescriptors;
  61. private TextureDescriptor[] _cachedTextureDescriptors;
  62. private TextureDescriptor[] _cachedImageDescriptors;
  63. private int _firstConstantBufferBinding;
  64. private int _firstStorageBufferBinding;
  65. public int FirstConstantBufferBinding => _firstConstantBufferBinding;
  66. public int FirstStorageBufferBinding => _firstStorageBufferBinding;
  67. public ShaderConfig(IGpuAccessor gpuAccessor, TranslationOptions options)
  68. {
  69. Stage = ShaderStage.Compute;
  70. GpuAccessor = gpuAccessor;
  71. Options = options;
  72. UsedInputAttributesPerPatch = new HashSet<int>();
  73. UsedOutputAttributesPerPatch = new HashSet<int>();
  74. _usedTextures = new Dictionary<TextureInfo, TextureMeta>();
  75. _usedImages = new Dictionary<TextureInfo, TextureMeta>();
  76. }
  77. public ShaderConfig(
  78. ShaderStage stage,
  79. OutputTopology outputTopology,
  80. int maxOutputVertices,
  81. IGpuAccessor gpuAccessor,
  82. TranslationOptions options) : this(gpuAccessor, options)
  83. {
  84. Stage = stage;
  85. ThreadsPerInputPrimitive = 1;
  86. OutputTopology = outputTopology;
  87. MaxOutputVertices = maxOutputVertices;
  88. TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
  89. }
  90. public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options)
  91. {
  92. Stage = header.Stage;
  93. GpPassthrough = header.Stage == ShaderStage.Geometry && header.GpPassthrough;
  94. ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive;
  95. OutputTopology = header.OutputTopology;
  96. MaxOutputVertices = header.MaxOutputVertexCount;
  97. LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize + (header.ShaderLocalMemoryCrsSize / ThreadsPerWarp);
  98. ImapTypes = header.ImapTypes;
  99. OmapTargets = header.OmapTargets;
  100. OmapSampleMask = header.OmapSampleMask;
  101. OmapDepth = header.OmapDepth;
  102. TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
  103. LastInPipeline = true;
  104. LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
  105. }
  106. public int GetDepthRegister()
  107. {
  108. // The depth register is always two registers after the last color output.
  109. return BitOperations.PopCount((uint)OmapTargets) + 1;
  110. }
  111. public uint ConstantBuffer1Read(int offset)
  112. {
  113. if (Cb1DataSize < offset + 4)
  114. {
  115. Cb1DataSize = offset + 4;
  116. }
  117. return GpuAccessor.ConstantBuffer1Read(offset);
  118. }
  119. public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1)
  120. {
  121. // When the formatted load extension is supported, we don't need to
  122. // specify a format, we can just declare it without a format and the GPU will handle it.
  123. if (GpuAccessor.QueryHostSupportsImageLoadFormatted())
  124. {
  125. return TextureFormat.Unknown;
  126. }
  127. var format = GpuAccessor.QueryTextureFormat(handle, cbufSlot);
  128. if (format == TextureFormat.Unknown)
  129. {
  130. GpuAccessor.Log($"Unknown format for texture {handle}.");
  131. format = TextureFormat.R8G8B8A8Unorm;
  132. }
  133. return format;
  134. }
  135. private bool FormatSupportsAtomic(TextureFormat format)
  136. {
  137. return format == TextureFormat.R32Sint || format == TextureFormat.R32Uint;
  138. }
  139. public TextureFormat GetTextureFormatAtomic(int handle, int cbufSlot = -1)
  140. {
  141. // Atomic image instructions do not support GL_EXT_shader_image_load_formatted,
  142. // and must have a type specified. Default to R32Sint if not available.
  143. var format = GpuAccessor.QueryTextureFormat(handle, cbufSlot);
  144. if (!FormatSupportsAtomic(format))
  145. {
  146. GpuAccessor.Log($"Unsupported format for texture {handle}: {format}.");
  147. format = TextureFormat.R32Sint;
  148. }
  149. return format;
  150. }
  151. public void SizeAdd(int size)
  152. {
  153. Size += size;
  154. }
  155. public void InheritFrom(ShaderConfig other)
  156. {
  157. ClipDistancesWritten |= other.ClipDistancesWritten;
  158. UsedFeatures |= other.UsedFeatures;
  159. UsedInputAttributes |= other.UsedInputAttributes;
  160. UsedOutputAttributes |= other.UsedOutputAttributes;
  161. _usedConstantBuffers |= other._usedConstantBuffers;
  162. _usedStorageBuffers |= other._usedStorageBuffers;
  163. _usedStorageBuffersWrite |= other._usedStorageBuffersWrite;
  164. foreach (var kv in other._usedTextures)
  165. {
  166. if (!_usedTextures.TryAdd(kv.Key, kv.Value))
  167. {
  168. _usedTextures[kv.Key] = MergeTextureMeta(kv.Value, _usedTextures[kv.Key]);
  169. }
  170. }
  171. foreach (var kv in other._usedImages)
  172. {
  173. if (!_usedImages.TryAdd(kv.Key, kv.Value))
  174. {
  175. _usedImages[kv.Key] = MergeTextureMeta(kv.Value, _usedImages[kv.Key]);
  176. }
  177. }
  178. }
  179. public void SetLayerOutputAttribute(int attr)
  180. {
  181. LayerOutputWritten = true;
  182. LayerOutputAttribute = attr;
  183. }
  184. public void SetInputUserAttributeFixedFunc(int index)
  185. {
  186. UsedInputAttributes |= 1 << index;
  187. }
  188. public void SetOutputUserAttributeFixedFunc(int index)
  189. {
  190. UsedOutputAttributes |= 1 << index;
  191. }
  192. public void SetInputUserAttribute(int index, int component)
  193. {
  194. int mask = 1 << index;
  195. UsedInputAttributes |= mask;
  196. _thisUsedInputAttributes |= mask;
  197. ThisInputAttributesComponents |= UInt128.One << (index * 4 + component);
  198. }
  199. public void SetInputUserAttributePerPatch(int index)
  200. {
  201. UsedInputAttributesPerPatch.Add(index);
  202. }
  203. public void SetOutputUserAttribute(int index)
  204. {
  205. UsedOutputAttributes |= 1 << index;
  206. }
  207. public void SetOutputUserAttributePerPatch(int index)
  208. {
  209. UsedOutputAttributesPerPatch.Add(index);
  210. }
  211. public void MergeFromtNextStage(ShaderConfig config)
  212. {
  213. NextInputAttributesComponents = config.ThisInputAttributesComponents;
  214. NextUsedInputAttributesPerPatch = config.UsedInputAttributesPerPatch;
  215. NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr);
  216. MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch);
  217. if (UsedOutputAttributesPerPatch.Count != 0)
  218. {
  219. // Regular and per-patch input/output locations can't overlap,
  220. // so we must assign on our location using unused regular input/output locations.
  221. Dictionary<int, int> locationsMap = new Dictionary<int, int>();
  222. int freeMask = ~UsedOutputAttributes;
  223. foreach (int attr in UsedOutputAttributesPerPatch)
  224. {
  225. int location = BitOperations.TrailingZeroCount(freeMask);
  226. if (location == 32)
  227. {
  228. config.GpuAccessor.Log($"No enough free locations for patch input/output 0x{attr:X}.");
  229. break;
  230. }
  231. locationsMap.Add(attr, location);
  232. freeMask &= ~(1 << location);
  233. }
  234. // Both stages must agree on the locations, so use the same "map" for both.
  235. _perPatchAttributeLocations = locationsMap;
  236. config._perPatchAttributeLocations = locationsMap;
  237. }
  238. LastInPipeline = false;
  239. // We don't consider geometry shaders using the geometry shader passthrough feature
  240. // as being the last because when this feature is used, it can't actually modify any of the outputs,
  241. // so the stage that comes before it is the last one that can do modifications.
  242. if (config.Stage != ShaderStage.Fragment && (config.Stage != ShaderStage.Geometry || !config.GpPassthrough))
  243. {
  244. LastInVertexPipeline = false;
  245. }
  246. }
  247. public void MergeOutputUserAttributes(int mask, IEnumerable<int> perPatch)
  248. {
  249. _nextUsedInputAttributes = mask;
  250. if (GpPassthrough)
  251. {
  252. PassthroughAttributes = mask & ~UsedOutputAttributes;
  253. }
  254. else
  255. {
  256. UsedOutputAttributes |= mask;
  257. UsedOutputAttributesPerPatch.UnionWith(perPatch);
  258. }
  259. }
  260. public int GetPerPatchAttributeLocation(int index)
  261. {
  262. if (_perPatchAttributeLocations == null || !_perPatchAttributeLocations.TryGetValue(index, out int location))
  263. {
  264. return index;
  265. }
  266. return location;
  267. }
  268. public bool IsUsedOutputAttribute(int attr)
  269. {
  270. // The check for fixed function attributes on the next stage is conservative,
  271. // returning false if the output is just not used by the next stage is also valid.
  272. if (NextUsesFixedFuncAttributes &&
  273. attr >= AttributeConsts.UserAttributeBase &&
  274. attr < AttributeConsts.UserAttributeEnd)
  275. {
  276. int index = (attr - AttributeConsts.UserAttributeBase) >> 4;
  277. return (_nextUsedInputAttributes & (1 << index)) != 0;
  278. }
  279. return true;
  280. }
  281. public int GetFreeUserAttribute(bool isOutput, int index)
  282. {
  283. int useMask = isOutput ? _nextUsedInputAttributes : _thisUsedInputAttributes;
  284. int bit = -1;
  285. while (useMask != -1)
  286. {
  287. bit = BitOperations.TrailingZeroCount(~useMask);
  288. if (bit == 32)
  289. {
  290. bit = -1;
  291. break;
  292. }
  293. else if (index < 1)
  294. {
  295. break;
  296. }
  297. useMask |= 1 << bit;
  298. index--;
  299. }
  300. return bit;
  301. }
  302. public void SetAllInputUserAttributes()
  303. {
  304. UsedInputAttributes |= Constants.AllAttributesMask;
  305. ThisInputAttributesComponents |= ~UInt128.Zero >> (128 - Constants.MaxAttributes * 4);
  306. }
  307. public void SetAllOutputUserAttributes()
  308. {
  309. UsedOutputAttributes |= Constants.AllAttributesMask;
  310. }
  311. public void SetClipDistanceWritten(int index)
  312. {
  313. ClipDistancesWritten |= (byte)(1 << index);
  314. }
  315. public void SetUsedFeature(FeatureFlags flags)
  316. {
  317. UsedFeatures |= flags;
  318. }
  319. public void SetUsedConstantBuffer(int slot)
  320. {
  321. _usedConstantBuffers |= 1 << slot;
  322. }
  323. public void SetUsedStorageBuffer(int slot, bool write)
  324. {
  325. int mask = 1 << slot;
  326. _usedStorageBuffers |= mask;
  327. if (write)
  328. {
  329. _usedStorageBuffersWrite |= mask;
  330. }
  331. }
  332. public void SetUsedTexture(
  333. Instruction inst,
  334. SamplerType type,
  335. TextureFormat format,
  336. TextureFlags flags,
  337. int cbufSlot,
  338. int handle)
  339. {
  340. inst &= Instruction.Mask;
  341. bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
  342. bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
  343. bool accurateType = inst != Instruction.Lod && inst != Instruction.TextureSize;
  344. bool coherent = flags.HasFlag(TextureFlags.Coherent);
  345. if (isImage)
  346. {
  347. SetUsedTextureOrImage(_usedImages, cbufSlot, handle, type, format, true, isWrite, false, coherent);
  348. }
  349. else
  350. {
  351. bool intCoords = flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize;
  352. SetUsedTextureOrImage(_usedTextures, cbufSlot, handle, type, TextureFormat.Unknown, intCoords, false, accurateType, coherent);
  353. }
  354. GpuAccessor.RegisterTexture(handle, cbufSlot);
  355. }
  356. private void SetUsedTextureOrImage(
  357. Dictionary<TextureInfo, TextureMeta> dict,
  358. int cbufSlot,
  359. int handle,
  360. SamplerType type,
  361. TextureFormat format,
  362. bool intCoords,
  363. bool write,
  364. bool accurateType,
  365. bool coherent)
  366. {
  367. var dimensions = type.GetDimensions();
  368. var isIndexed = type.HasFlag(SamplerType.Indexed);
  369. var usageFlags = TextureUsageFlags.None;
  370. if (intCoords)
  371. {
  372. usageFlags |= TextureUsageFlags.NeedsScaleValue;
  373. var canScale = Stage.SupportsRenderScale() && !isIndexed && !write && dimensions == 2;
  374. if (!canScale)
  375. {
  376. // Resolution scaling cannot be applied to this texture right now.
  377. // Flag so that we know to blacklist scaling on related textures when binding them.
  378. usageFlags |= TextureUsageFlags.ResScaleUnsupported;
  379. }
  380. }
  381. if (write)
  382. {
  383. usageFlags |= TextureUsageFlags.ImageStore;
  384. }
  385. if (coherent)
  386. {
  387. usageFlags |= TextureUsageFlags.ImageCoherent;
  388. }
  389. int arraySize = isIndexed ? SamplerArraySize : 1;
  390. for (int layer = 0; layer < arraySize; layer++)
  391. {
  392. var info = new TextureInfo(cbufSlot, handle + layer * 2, isIndexed, format);
  393. var meta = new TextureMeta()
  394. {
  395. AccurateType = accurateType,
  396. Type = type,
  397. UsageFlags = usageFlags
  398. };
  399. if (dict.TryGetValue(info, out var existingMeta))
  400. {
  401. dict[info] = MergeTextureMeta(meta, existingMeta);
  402. }
  403. else
  404. {
  405. dict.Add(info, meta);
  406. }
  407. }
  408. }
  409. private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
  410. {
  411. meta.UsageFlags |= existingMeta.UsageFlags;
  412. // If the texture we have has inaccurate type information, then
  413. // we prefer the most accurate one.
  414. if (existingMeta.AccurateType)
  415. {
  416. meta.AccurateType = true;
  417. meta.Type = existingMeta.Type;
  418. }
  419. return meta;
  420. }
  421. public BufferDescriptor[] GetConstantBufferDescriptors()
  422. {
  423. if (_cachedConstantBufferDescriptors != null)
  424. {
  425. return _cachedConstantBufferDescriptors;
  426. }
  427. int usedMask = _usedConstantBuffers;
  428. if (UsedFeatures.HasFlag(FeatureFlags.CbIndexing))
  429. {
  430. usedMask |= (int)GpuAccessor.QueryConstantBufferUse();
  431. }
  432. return _cachedConstantBufferDescriptors = GetBufferDescriptors(
  433. usedMask,
  434. 0,
  435. UsedFeatures.HasFlag(FeatureFlags.CbIndexing),
  436. out _firstConstantBufferBinding,
  437. GpuAccessor.QueryBindingConstantBuffer);
  438. }
  439. public BufferDescriptor[] GetStorageBufferDescriptors()
  440. {
  441. if (_cachedStorageBufferDescriptors != null)
  442. {
  443. return _cachedStorageBufferDescriptors;
  444. }
  445. return _cachedStorageBufferDescriptors = GetBufferDescriptors(
  446. _usedStorageBuffers,
  447. _usedStorageBuffersWrite,
  448. true,
  449. out _firstStorageBufferBinding,
  450. GpuAccessor.QueryBindingStorageBuffer);
  451. }
  452. private static BufferDescriptor[] GetBufferDescriptors(
  453. int usedMask,
  454. int writtenMask,
  455. bool isArray,
  456. out int firstBinding,
  457. Func<int, int> getBindingCallback)
  458. {
  459. firstBinding = 0;
  460. bool hasFirstBinding = false;
  461. var descriptors = new BufferDescriptor[BitOperations.PopCount((uint)usedMask)];
  462. int lastSlot = -1;
  463. for (int i = 0; i < descriptors.Length; i++)
  464. {
  465. int slot = BitOperations.TrailingZeroCount(usedMask);
  466. if (isArray)
  467. {
  468. // The next array entries also consumes bindings, even if they are unused.
  469. for (int j = lastSlot + 1; j < slot; j++)
  470. {
  471. int binding = getBindingCallback(j);
  472. if (!hasFirstBinding)
  473. {
  474. firstBinding = binding;
  475. hasFirstBinding = true;
  476. }
  477. }
  478. }
  479. lastSlot = slot;
  480. descriptors[i] = new BufferDescriptor(getBindingCallback(slot), slot);
  481. if (!hasFirstBinding)
  482. {
  483. firstBinding = descriptors[i].Binding;
  484. hasFirstBinding = true;
  485. }
  486. if ((writtenMask & (1 << slot)) != 0)
  487. {
  488. descriptors[i].SetFlag(BufferUsageFlags.Write);
  489. }
  490. usedMask &= ~(1 << slot);
  491. }
  492. return descriptors;
  493. }
  494. public TextureDescriptor[] GetTextureDescriptors()
  495. {
  496. return _cachedTextureDescriptors ??= GetTextureOrImageDescriptors(_usedTextures, GpuAccessor.QueryBindingTexture);
  497. }
  498. public TextureDescriptor[] GetImageDescriptors()
  499. {
  500. return _cachedImageDescriptors ??= GetTextureOrImageDescriptors(_usedImages, GpuAccessor.QueryBindingImage);
  501. }
  502. private static TextureDescriptor[] GetTextureOrImageDescriptors(Dictionary<TextureInfo, TextureMeta> dict, Func<int, bool, int> getBindingCallback)
  503. {
  504. var descriptors = new TextureDescriptor[dict.Count];
  505. int i = 0;
  506. foreach (var kv in dict.OrderBy(x => x.Key.Indexed).OrderBy(x => x.Key.Handle))
  507. {
  508. var info = kv.Key;
  509. var meta = kv.Value;
  510. bool isBuffer = (meta.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
  511. int binding = getBindingCallback(i, isBuffer);
  512. descriptors[i] = new TextureDescriptor(binding, meta.Type, info.Format, info.CbufSlot, info.Handle);
  513. descriptors[i].SetFlag(meta.UsageFlags);
  514. i++;
  515. }
  516. return descriptors;
  517. }
  518. public (TextureDescriptor, int) FindTextureDescriptor(AstTextureOperation texOp)
  519. {
  520. TextureDescriptor[] descriptors = GetTextureDescriptors();
  521. for (int i = 0; i < descriptors.Length; i++)
  522. {
  523. var descriptor = descriptors[i];
  524. if (descriptor.CbufSlot == texOp.CbufSlot &&
  525. descriptor.HandleIndex == texOp.Handle &&
  526. descriptor.Format == texOp.Format)
  527. {
  528. return (descriptor, i);
  529. }
  530. }
  531. return (default, -1);
  532. }
  533. private static int FindDescriptorIndex(TextureDescriptor[] array, AstTextureOperation texOp)
  534. {
  535. for (int i = 0; i < array.Length; i++)
  536. {
  537. var descriptor = array[i];
  538. if (descriptor.Type == texOp.Type &&
  539. descriptor.CbufSlot == texOp.CbufSlot &&
  540. descriptor.HandleIndex == texOp.Handle &&
  541. descriptor.Format == texOp.Format)
  542. {
  543. return i;
  544. }
  545. }
  546. return -1;
  547. }
  548. public int FindTextureDescriptorIndex(AstTextureOperation texOp)
  549. {
  550. return FindDescriptorIndex(GetTextureDescriptors(), texOp);
  551. }
  552. public int FindImageDescriptorIndex(AstTextureOperation texOp)
  553. {
  554. return FindDescriptorIndex(GetImageDescriptors(), texOp);
  555. }
  556. public ShaderProgramInfo CreateProgramInfo()
  557. {
  558. return new ShaderProgramInfo(
  559. GetConstantBufferDescriptors(),
  560. GetStorageBufferDescriptors(),
  561. GetTextureDescriptors(),
  562. GetImageDescriptors(),
  563. Stage,
  564. UsedFeatures.HasFlag(FeatureFlags.InstanceId),
  565. UsedFeatures.HasFlag(FeatureFlags.DrawParameters),
  566. UsedFeatures.HasFlag(FeatureFlags.RtLayer),
  567. ClipDistancesWritten,
  568. OmapTargets);
  569. }
  570. }
  571. }