GlslGenerator.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. using Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using Ryujinx.Graphics.Shader.StructuredIr;
  4. using System;
  5. using static Ryujinx.Graphics.Shader.CodeGen.Glsl.TypeConversion;
  6. namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
  7. {
  8. static class GlslGenerator
  9. {
  10. public static GlslProgram Generate(StructuredProgramInfo info, ShaderConfig config)
  11. {
  12. CodeGenContext context = new CodeGenContext(config);
  13. Declarations.Declare(context, info);
  14. PrintMainBlock(context, info);
  15. return new GlslProgram(
  16. context.CBufferDescriptors.ToArray(),
  17. context.SBufferDescriptors.ToArray(),
  18. context.TextureDescriptors.ToArray(),
  19. context.ImageDescriptors.ToArray(),
  20. context.GetCode());
  21. }
  22. private static void PrintMainBlock(CodeGenContext context, StructuredProgramInfo info)
  23. {
  24. context.AppendLine("void main()");
  25. context.EnterScope();
  26. Declarations.DeclareLocals(context, info);
  27. // Some games will leave some elements of gl_Position uninitialized,
  28. // in those cases, the elements will contain undefined values according
  29. // to the spec, but on NVIDIA they seems to be always initialized to (0, 0, 0, 1),
  30. // so we do explicit initialization to avoid UB on non-NVIDIA gpus.
  31. if (context.Config.Stage == ShaderStage.Vertex)
  32. {
  33. context.AppendLine("gl_Position = vec4(0.0, 0.0, 0.0, 1.0);");
  34. }
  35. // Ensure that unused attributes are set, otherwise the downstream
  36. // compiler may eliminate them.
  37. // (Not needed for fragment shader as it is the last stage).
  38. if (context.Config.Stage != ShaderStage.Compute &&
  39. context.Config.Stage != ShaderStage.Fragment)
  40. {
  41. for (int attr = 0; attr < Declarations.MaxAttributes; attr++)
  42. {
  43. if (info.OAttributes.Contains(attr))
  44. {
  45. continue;
  46. }
  47. context.AppendLine($"{DefaultNames.OAttributePrefix}{attr} = vec4(0);");
  48. }
  49. }
  50. PrintBlock(context, info.MainBlock);
  51. context.LeaveScope();
  52. }
  53. private static void PrintBlock(CodeGenContext context, AstBlock block)
  54. {
  55. AstBlockVisitor visitor = new AstBlockVisitor(block);
  56. visitor.BlockEntered += (sender, e) =>
  57. {
  58. switch (e.Block.Type)
  59. {
  60. case AstBlockType.DoWhile:
  61. context.AppendLine("do");
  62. break;
  63. case AstBlockType.Else:
  64. context.AppendLine("else");
  65. break;
  66. case AstBlockType.ElseIf:
  67. context.AppendLine($"else if ({GetCondExpr(context, e.Block.Condition)})");
  68. break;
  69. case AstBlockType.If:
  70. context.AppendLine($"if ({GetCondExpr(context, e.Block.Condition)})");
  71. break;
  72. default: throw new InvalidOperationException($"Found unexpected block type \"{e.Block.Type}\".");
  73. }
  74. context.EnterScope();
  75. };
  76. visitor.BlockLeft += (sender, e) =>
  77. {
  78. context.LeaveScope();
  79. if (e.Block.Type == AstBlockType.DoWhile)
  80. {
  81. context.AppendLine($"while ({GetCondExpr(context, e.Block.Condition)});");
  82. }
  83. };
  84. foreach (IAstNode node in visitor.Visit())
  85. {
  86. if (node is AstOperation operation)
  87. {
  88. context.AppendLine(InstGen.GetExpression(context, operation) + ";");
  89. }
  90. else if (node is AstAssignment assignment)
  91. {
  92. VariableType srcType = OperandManager.GetNodeDestType(assignment.Source);
  93. VariableType dstType = OperandManager.GetNodeDestType(assignment.Destination);
  94. string dest;
  95. if (assignment.Destination is AstOperand operand && operand.Type == OperandType.Attribute)
  96. {
  97. dest = OperandManager.GetOutAttributeName(operand, context.Config.Stage);
  98. }
  99. else
  100. {
  101. dest = InstGen.GetExpression(context, assignment.Destination);
  102. }
  103. string src = ReinterpretCast(context, assignment.Source, srcType, dstType);
  104. context.AppendLine(dest + " = " + src + ";");
  105. }
  106. else if (node is AstComment comment)
  107. {
  108. context.AppendLine("// " + comment.Comment);
  109. }
  110. else
  111. {
  112. throw new InvalidOperationException($"Found unexpected node type \"{node?.GetType().Name ?? "null"}\".");
  113. }
  114. }
  115. }
  116. private static string GetCondExpr(CodeGenContext context, IAstNode cond)
  117. {
  118. VariableType srcType = OperandManager.GetNodeDestType(cond);
  119. return ReinterpretCast(context, cond, srcType, VariableType.Bool);
  120. }
  121. }
  122. }