ShaderConfig.cs 25 KB

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