GlslGenerator.cs 6.0 KB

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