GlslGenerator.cs
1 using Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions; 2 using Ryujinx.Graphics.Shader.StructuredIr; 3 using Ryujinx.Graphics.Shader.Translation; 4 using System; 5 6 using static Ryujinx.Graphics.Shader.CodeGen.Glsl.TypeConversion; 7 8 namespace Ryujinx.Graphics.Shader.CodeGen.Glsl 9 { 10 static class GlslGenerator 11 { 12 private const string MainFunctionName = "main"; 13 14 public static string Generate(StructuredProgramInfo info, CodeGenParameters parameters) 15 { 16 CodeGenContext context = new(info, parameters); 17 18 Declarations.Declare(context, info); 19 20 if (info.Functions.Count != 0) 21 { 22 for (int i = 1; i < info.Functions.Count; i++) 23 { 24 context.AppendLine($"{GetFunctionSignature(context, info.Functions[i])};"); 25 } 26 27 context.AppendLine(); 28 29 for (int i = 1; i < info.Functions.Count; i++) 30 { 31 PrintFunction(context, info.Functions[i]); 32 33 context.AppendLine(); 34 } 35 } 36 37 PrintFunction(context, info.Functions[0], MainFunctionName); 38 39 return context.GetCode(); 40 } 41 42 private static void PrintFunction(CodeGenContext context, StructuredFunction function, string funcName = null) 43 { 44 context.CurrentFunction = function; 45 46 context.AppendLine(GetFunctionSignature(context, function, funcName)); 47 context.EnterScope(); 48 49 Declarations.DeclareLocals(context, function); 50 51 PrintBlock(context, function.MainBlock, funcName == MainFunctionName); 52 53 context.LeaveScope(); 54 } 55 56 private static string GetFunctionSignature(CodeGenContext context, StructuredFunction function, string funcName = null) 57 { 58 string[] args = new string[function.InArguments.Length + function.OutArguments.Length]; 59 60 for (int i = 0; i < function.InArguments.Length; i++) 61 { 62 args[i] = $"{Declarations.GetVarTypeName(context, function.InArguments[i])} {OperandManager.GetArgumentName(i)}"; 63 } 64 65 for (int i = 0; i < function.OutArguments.Length; i++) 66 { 67 int j = i + function.InArguments.Length; 68 69 args[j] = $"out {Declarations.GetVarTypeName(context, function.OutArguments[i])} {OperandManager.GetArgumentName(j)}"; 70 } 71 72 return $"{Declarations.GetVarTypeName(context, function.ReturnType)} {funcName ?? function.Name}({string.Join(", ", args)})"; 73 } 74 75 private static void PrintBlock(CodeGenContext context, AstBlock block, bool isMainFunction) 76 { 77 AstBlockVisitor visitor = new(block); 78 79 visitor.BlockEntered += (sender, e) => 80 { 81 switch (e.Block.Type) 82 { 83 case AstBlockType.DoWhile: 84 context.AppendLine("do"); 85 break; 86 87 case AstBlockType.Else: 88 context.AppendLine("else"); 89 break; 90 91 case AstBlockType.ElseIf: 92 context.AppendLine($"else if ({GetCondExpr(context, e.Block.Condition)})"); 93 break; 94 95 case AstBlockType.If: 96 context.AppendLine($"if ({GetCondExpr(context, e.Block.Condition)})"); 97 break; 98 99 default: 100 throw new InvalidOperationException($"Found unexpected block type \"{e.Block.Type}\"."); 101 } 102 103 context.EnterScope(); 104 }; 105 106 visitor.BlockLeft += (sender, e) => 107 { 108 context.LeaveScope(); 109 110 if (e.Block.Type == AstBlockType.DoWhile) 111 { 112 context.AppendLine($"while ({GetCondExpr(context, e.Block.Condition)});"); 113 } 114 }; 115 116 bool supportsBarrierDivergence = context.HostCapabilities.SupportsShaderBarrierDivergence; 117 bool mayHaveReturned = false; 118 119 foreach (IAstNode node in visitor.Visit()) 120 { 121 if (node is AstOperation operation) 122 { 123 if (!supportsBarrierDivergence) 124 { 125 if (operation.Inst == IntermediateRepresentation.Instruction.Barrier) 126 { 127 // Barrier on divergent control flow paths may cause the GPU to hang, 128 // so skip emitting the barrier for those cases. 129 if (visitor.Block.Type != AstBlockType.Main || mayHaveReturned || !isMainFunction) 130 { 131 context.Logger.Log("Shader has barrier on potentially divergent block, the barrier will be removed."); 132 133 continue; 134 } 135 } 136 else if (operation.Inst == IntermediateRepresentation.Instruction.Return) 137 { 138 mayHaveReturned = true; 139 } 140 } 141 142 string expr = InstGen.GetExpression(context, operation); 143 144 if (expr != null) 145 { 146 context.AppendLine(expr + ";"); 147 } 148 } 149 else if (node is AstAssignment assignment) 150 { 151 AggregateType dstType = OperandManager.GetNodeDestType(context, assignment.Destination); 152 AggregateType srcType = OperandManager.GetNodeDestType(context, assignment.Source); 153 154 string dest = InstGen.GetExpression(context, assignment.Destination); 155 string src = ReinterpretCast(context, assignment.Source, srcType, dstType); 156 157 context.AppendLine(dest + " = " + src + ";"); 158 } 159 else if (node is AstComment comment) 160 { 161 context.AppendLine("// " + comment.Comment); 162 } 163 else 164 { 165 throw new InvalidOperationException($"Found unexpected node type \"{node?.GetType().Name ?? "null"}\"."); 166 } 167 } 168 } 169 170 private static string GetCondExpr(CodeGenContext context, IAstNode cond) 171 { 172 AggregateType srcType = OperandManager.GetNodeDestType(context, cond); 173 174 return ReinterpretCast(context, cond, srcType, AggregateType.Bool); 175 } 176 } 177 }