AttributeUsage.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Numerics;
  4. namespace Ryujinx.Graphics.Shader.Translation
  5. {
  6. class AttributeUsage
  7. {
  8. public bool NextUsesFixedFuncAttributes { get; private set; }
  9. public int UsedInputAttributes { get; private set; }
  10. public int UsedOutputAttributes { get; private set; }
  11. public HashSet<int> UsedInputAttributesPerPatch { get; }
  12. public HashSet<int> UsedOutputAttributesPerPatch { get; }
  13. public HashSet<int> NextUsedInputAttributesPerPatch { get; private set; }
  14. public int PassthroughAttributes { get; private set; }
  15. private int _nextUsedInputAttributes;
  16. private int _thisUsedInputAttributes;
  17. private Dictionary<int, int> _perPatchAttributeLocations;
  18. private readonly IGpuAccessor _gpuAccessor;
  19. public UInt128 NextInputAttributesComponents { get; private set; }
  20. public UInt128 ThisInputAttributesComponents { get; private set; }
  21. public AttributeUsage(IGpuAccessor gpuAccessor)
  22. {
  23. _gpuAccessor = gpuAccessor;
  24. UsedInputAttributesPerPatch = [];
  25. UsedOutputAttributesPerPatch = [];
  26. }
  27. public void SetInputUserAttribute(int index, int component)
  28. {
  29. int mask = 1 << index;
  30. UsedInputAttributes |= mask;
  31. _thisUsedInputAttributes |= mask;
  32. ThisInputAttributesComponents |= UInt128.One << (index * 4 + component);
  33. }
  34. public void SetInputUserAttributePerPatch(int index)
  35. {
  36. UsedInputAttributesPerPatch.Add(index);
  37. }
  38. public void SetOutputUserAttribute(int index)
  39. {
  40. UsedOutputAttributes |= 1 << index;
  41. }
  42. public void SetOutputUserAttributePerPatch(int index)
  43. {
  44. UsedOutputAttributesPerPatch.Add(index);
  45. }
  46. public void MergeFromtNextStage(bool gpPassthrough, bool nextUsesFixedFunctionAttributes, AttributeUsage nextStage)
  47. {
  48. NextInputAttributesComponents = nextStage.ThisInputAttributesComponents;
  49. NextUsedInputAttributesPerPatch = nextStage.UsedInputAttributesPerPatch;
  50. NextUsesFixedFuncAttributes = nextUsesFixedFunctionAttributes;
  51. MergeOutputUserAttributes(gpPassthrough, nextStage.UsedInputAttributes, nextStage.UsedInputAttributesPerPatch);
  52. if (UsedOutputAttributesPerPatch.Count != 0)
  53. {
  54. // Regular and per-patch input/output locations can't overlap,
  55. // so we must assign on our location using unused regular input/output locations.
  56. Dictionary<int, int> locationsMap = new();
  57. int freeMask = ~UsedOutputAttributes;
  58. foreach (int attr in UsedOutputAttributesPerPatch)
  59. {
  60. int location = BitOperations.TrailingZeroCount(freeMask);
  61. if (location == 32)
  62. {
  63. _gpuAccessor.Log($"No enough free locations for patch input/output 0x{attr:X}.");
  64. break;
  65. }
  66. locationsMap.Add(attr, location);
  67. freeMask &= ~(1 << location);
  68. }
  69. // Both stages must agree on the locations, so use the same "map" for both.
  70. _perPatchAttributeLocations = locationsMap;
  71. nextStage._perPatchAttributeLocations = locationsMap;
  72. }
  73. }
  74. private void MergeOutputUserAttributes(bool gpPassthrough, int mask, IEnumerable<int> perPatch)
  75. {
  76. _nextUsedInputAttributes = mask;
  77. if (gpPassthrough)
  78. {
  79. PassthroughAttributes = mask & ~UsedOutputAttributes;
  80. }
  81. else
  82. {
  83. UsedOutputAttributes |= mask;
  84. UsedOutputAttributesPerPatch.UnionWith(perPatch);
  85. }
  86. }
  87. public int GetPerPatchAttributeLocation(int index)
  88. {
  89. if (_perPatchAttributeLocations == null || !_perPatchAttributeLocations.TryGetValue(index, out int location))
  90. {
  91. return index;
  92. }
  93. return location;
  94. }
  95. public bool IsUsedOutputAttribute(int attr)
  96. {
  97. // The check for fixed function attributes on the next stage is conservative,
  98. // returning false if the output is just not used by the next stage is also valid.
  99. if (NextUsesFixedFuncAttributes &&
  100. attr >= AttributeConsts.UserAttributeBase &&
  101. attr < AttributeConsts.UserAttributeEnd)
  102. {
  103. int index = (attr - AttributeConsts.UserAttributeBase) >> 4;
  104. return (_nextUsedInputAttributes & (1 << index)) != 0;
  105. }
  106. return true;
  107. }
  108. public int GetFreeUserAttribute(bool isOutput, int index)
  109. {
  110. int useMask = isOutput ? _nextUsedInputAttributes : _thisUsedInputAttributes;
  111. int bit = -1;
  112. while (useMask != -1)
  113. {
  114. bit = BitOperations.TrailingZeroCount(~useMask);
  115. if (bit == 32)
  116. {
  117. bit = -1;
  118. break;
  119. }
  120. else if (index < 1)
  121. {
  122. break;
  123. }
  124. useMask |= 1 << bit;
  125. index--;
  126. }
  127. return bit;
  128. }
  129. public void SetAllInputUserAttributes()
  130. {
  131. UsedInputAttributes |= Constants.AllAttributesMask;
  132. ThisInputAttributesComponents |= ~UInt128.Zero >> (128 - Constants.MaxAttributes * 4);
  133. }
  134. public void SetAllOutputUserAttributes()
  135. {
  136. UsedOutputAttributes |= Constants.AllAttributesMask;
  137. }
  138. }
  139. }