GlslGenerator.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using Ryujinx.Graphics.Shader.StructuredIr;
  4. using Ryujinx.Graphics.Shader.Translation;
  5. using System;
  6. using static Ryujinx.Graphics.Shader.CodeGen.Glsl.TypeConversion;
  7. namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
  8. {
  9. static class GlslGenerator
  10. {
  11. private const string MainFunctionName = "main";
  12. public static string Generate(StructuredProgramInfo info, ShaderConfig config)
  13. {
  14. CodeGenContext context = new CodeGenContext(info, config);
  15. Declarations.Declare(context, info);
  16. if (info.Functions.Count != 0)
  17. {
  18. for (int i = 1; i < info.Functions.Count; i++)
  19. {
  20. context.AppendLine($"{GetFunctionSignature(info.Functions[i])};");
  21. }
  22. context.AppendLine();
  23. for (int i = 1; i < info.Functions.Count; i++)
  24. {
  25. PrintFunction(context, info, info.Functions[i]);
  26. context.AppendLine();
  27. }
  28. }
  29. PrintFunction(context, info, info.Functions[0], MainFunctionName);
  30. return context.GetCode();
  31. }
  32. private static void PrintFunction(CodeGenContext context, StructuredProgramInfo info, StructuredFunction function, string funcName = null)
  33. {
  34. context.CurrentFunction = function;
  35. context.AppendLine(GetFunctionSignature(function, funcName));
  36. context.EnterScope();
  37. Declarations.DeclareLocals(context, function);
  38. PrintBlock(context, function.MainBlock);
  39. context.LeaveScope();
  40. }
  41. private static string GetFunctionSignature(StructuredFunction function, string funcName = null)
  42. {
  43. string[] args = new string[function.InArguments.Length + function.OutArguments.Length];
  44. for (int i = 0; i < function.InArguments.Length; i++)
  45. {
  46. args[i] = $"{Declarations.GetVarTypeName(function.InArguments[i])} {OperandManager.GetArgumentName(i)}";
  47. }
  48. for (int i = 0; i < function.OutArguments.Length; i++)
  49. {
  50. int j = i + function.InArguments.Length;
  51. args[j] = $"out {Declarations.GetVarTypeName(function.OutArguments[i])} {OperandManager.GetArgumentName(j)}";
  52. }
  53. return $"{Declarations.GetVarTypeName(function.ReturnType)} {funcName ?? function.Name}({string.Join(", ", args)})";
  54. }
  55. private static void PrintBlock(CodeGenContext context, AstBlock block)
  56. {
  57. AstBlockVisitor visitor = new AstBlockVisitor(block);
  58. visitor.BlockEntered += (sender, e) =>
  59. {
  60. switch (e.Block.Type)
  61. {
  62. case AstBlockType.DoWhile:
  63. context.AppendLine("do");
  64. break;
  65. case AstBlockType.Else:
  66. context.AppendLine("else");
  67. break;
  68. case AstBlockType.ElseIf:
  69. context.AppendLine($"else if ({GetCondExpr(context, e.Block.Condition)})");
  70. break;
  71. case AstBlockType.If:
  72. context.AppendLine($"if ({GetCondExpr(context, e.Block.Condition)})");
  73. break;
  74. default: throw new InvalidOperationException($"Found unexpected block type \"{e.Block.Type}\".");
  75. }
  76. context.EnterScope();
  77. };
  78. visitor.BlockLeft += (sender, e) =>
  79. {
  80. context.LeaveScope();
  81. if (e.Block.Type == AstBlockType.DoWhile)
  82. {
  83. context.AppendLine($"while ({GetCondExpr(context, e.Block.Condition)});");
  84. }
  85. };
  86. foreach (IAstNode node in visitor.Visit())
  87. {
  88. if (node is AstOperation operation)
  89. {
  90. string expr = InstGen.GetExpression(context, operation);
  91. if (expr != null)
  92. {
  93. context.AppendLine(expr + ";");
  94. }
  95. }
  96. else if (node is AstAssignment assignment)
  97. {
  98. VariableType srcType = OperandManager.GetNodeDestType(context, assignment.Source);
  99. VariableType dstType = OperandManager.GetNodeDestType(context, assignment.Destination);
  100. string dest;
  101. if (assignment.Destination is AstOperand operand && operand.Type.IsAttribute())
  102. {
  103. bool perPatch = operand.Type == OperandType.AttributePerPatch;
  104. dest = OperandManager.GetOutAttributeName(operand.Value, context.Config, perPatch);
  105. }
  106. else
  107. {
  108. dest = InstGen.GetExpression(context, assignment.Destination);
  109. }
  110. string src = ReinterpretCast(context, assignment.Source, srcType, dstType);
  111. context.AppendLine(dest + " = " + src + ";");
  112. }
  113. else if (node is AstComment comment)
  114. {
  115. context.AppendLine("// " + comment.Comment);
  116. }
  117. else
  118. {
  119. throw new InvalidOperationException($"Found unexpected node type \"{node?.GetType().Name ?? "null"}\".");
  120. }
  121. }
  122. }
  123. private static string GetCondExpr(CodeGenContext context, IAstNode cond)
  124. {
  125. VariableType srcType = OperandManager.GetNodeDestType(context, cond);
  126. return ReinterpretCast(context, cond, srcType, VariableType.Bool);
  127. }
  128. }
  129. }