TranslatorContext.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using System.Collections.Generic;
  4. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  5. using static Ryujinx.Graphics.Shader.Translation.Translator;
  6. namespace Ryujinx.Graphics.Shader.Translation
  7. {
  8. public class TranslatorContext
  9. {
  10. private readonly DecodedProgram _program;
  11. private ShaderConfig _config;
  12. public ulong Address { get; }
  13. public ShaderStage Stage => _config.Stage;
  14. public int Size => _config.Size;
  15. public int Cb1DataSize => _config.Cb1DataSize;
  16. public IGpuAccessor GpuAccessor => _config.GpuAccessor;
  17. internal TranslatorContext(ulong address, DecodedProgram program, ShaderConfig config)
  18. {
  19. Address = address;
  20. _program = program;
  21. _config = config;
  22. }
  23. private static bool IsUserAttribute(Operand operand)
  24. {
  25. if (operand != null && operand.Type.IsAttribute())
  26. {
  27. int value = operand.Value & AttributeConsts.Mask;
  28. return value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd;
  29. }
  30. return false;
  31. }
  32. private static FunctionCode[] Combine(FunctionCode[] a, FunctionCode[] b, int aStart)
  33. {
  34. // Here we combine two shaders.
  35. // For shader A:
  36. // - All user attribute stores on shader A are turned into copies to a
  37. // temporary variable. It's assumed that shader B will consume them.
  38. // - All return instructions are turned into branch instructions, the
  39. // branch target being the start of the shader B code.
  40. // For shader B:
  41. // - All user attribute loads on shader B are turned into copies from a
  42. // temporary variable, as long that attribute is written by shader A.
  43. FunctionCode[] output = new FunctionCode[a.Length + b.Length - 1];
  44. List<Operation> ops = new List<Operation>(a.Length + b.Length);
  45. Operand[] temps = new Operand[AttributeConsts.UserAttributesCount * 4];
  46. Operand lblB = Label();
  47. for (int index = aStart; index < a[0].Code.Length; index++)
  48. {
  49. Operation operation = a[0].Code[index];
  50. if (IsUserAttribute(operation.Dest))
  51. {
  52. int tIndex = (operation.Dest.Value - AttributeConsts.UserAttributeBase) / 4;
  53. Operand temp = temps[tIndex];
  54. if (temp == null)
  55. {
  56. temp = Local();
  57. temps[tIndex] = temp;
  58. }
  59. operation.Dest = temp;
  60. }
  61. if (operation.Inst == Instruction.Return)
  62. {
  63. ops.Add(new Operation(Instruction.Branch, lblB));
  64. }
  65. else
  66. {
  67. ops.Add(operation);
  68. }
  69. }
  70. ops.Add(new Operation(Instruction.MarkLabel, lblB));
  71. for (int index = 0; index < b[0].Code.Length; index++)
  72. {
  73. Operation operation = b[0].Code[index];
  74. for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
  75. {
  76. Operand src = operation.GetSource(srcIndex);
  77. if (IsUserAttribute(src))
  78. {
  79. Operand temp = temps[(src.Value - AttributeConsts.UserAttributeBase) / 4];
  80. if (temp != null)
  81. {
  82. operation.SetSource(srcIndex, temp);
  83. }
  84. }
  85. }
  86. ops.Add(operation);
  87. }
  88. output[0] = new FunctionCode(ops.ToArray());
  89. for (int i = 1; i < a.Length; i++)
  90. {
  91. output[i] = a[i];
  92. }
  93. for (int i = 1; i < b.Length; i++)
  94. {
  95. output[a.Length + i - 1] = b[i];
  96. }
  97. return output;
  98. }
  99. public void SetNextStage(TranslatorContext nextStage)
  100. {
  101. _config.MergeFromtNextStage(nextStage._config);
  102. }
  103. public ShaderProgram Translate(TranslatorContext other = null)
  104. {
  105. FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);
  106. if (other != null)
  107. {
  108. other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, 0);
  109. FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
  110. code = Combine(otherCode, code, aStart);
  111. _config.InheritFrom(other._config);
  112. }
  113. return Translator.Translate(code, _config);
  114. }
  115. }
  116. }