1 // 2 // Copyright 2024 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #ifndef COMPILER_REWRITE_BUILTIN_VARIABLES_H_ 8 #define COMPILER_REWRITE_BUILTIN_VARIABLES_H_ 9 10 #include <variant> 11 12 #include "compiler/translator/Common.h" 13 #include "compiler/translator/Compiler.h" 14 #include "compiler/translator/ImmutableString.h" 15 #include "compiler/translator/InfoSink.h" 16 #include "compiler/translator/IntermNode.h" 17 #include "compiler/translator/SymbolUniqueId.h" 18 #include "compiler/translator/wgsl/Utils.h" 19 20 namespace sh 21 { 22 23 // In WGSL, all input values are parameters to the shader's main function and all output values are 24 // return values of the shader's main functions (the input/output values can be embedded within 25 // struct types). So this rewrites all accesses of GLSL's input/output variables (including 26 // builtins) to be accesses of a global struct, and writes a new main function (called wgslMain()) 27 // that populates the global input struct with parameters of the wgslMain function, and populates 28 // wgslMain's return value with the fields of the global output struct. 29 // 30 // TODO(anglebug.com/42267100): some of these WGSL builtins do not correspond exactly to GLSL 31 // builtin values and will need modification at the beginning (resp. end) of the main function for 32 // input values (resp. output values). E.g. normalized device coordinates in GLSL have -1.0 <= z 33 // <= 1.0, whereas NDC in WGSL have 0.0 <= z <= 1.0. 34 // See e.g. bool TranslatorMSL::appendVertexShaderDepthCorrectionToMain(). 35 // 36 // Example GLSL: 37 // 38 // attribute vec2 xy_position; 39 // void setPosition() { 40 // gl_Position = vec4(xy_position.x, xy_position.y, 0.0, 1.0); 41 // } 42 // void main() 43 // { 44 // setPosition(); 45 // } 46 // 47 // The resulting WGSL: 48 // struct ANGLE_Input_Global { 49 // xy_position : vec2<f32>, 50 // }; 51 // 52 // var<private> ANGLE_input_global : ANGLE_Input_Global; 53 // 54 // struct ANGLE_Input_Annotated { 55 // @location(@@@@@@) xy_position : vec2<f32>, 56 // }; 57 // 58 // struct ANGLE_Output_Global { 59 // gl_Position_ : vec4<f32>, 60 // }; 61 // 62 // var<private> ANGLE_output_global : ANGLE_Output_Global; 63 // 64 // struct ANGLE_Output_Annotated { 65 // @builtin(position) gl_Position_ : vec4<f32>, 66 // }; 67 // 68 // // Generated versions of _umain() and _usetPosition() go here. 69 // 70 // @vertex 71 // fn wgslMain(ANGLE_input_annotated : ANGLE_Input_Annotated) -> ANGLE_Output_Annotated 72 // { 73 // ANGLE_input_global.xy_position = ANGLE_input_annotated.xy_position; 74 // _umain(); 75 // var ANGLE_output_annotated : ANGLE_Output_Annotated; 76 // ANGLE_output_annotated.gl_Position_ = ANGLE_output_global.gl_Position_; 77 // return ANGLE_output_annotated; 78 // } 79 // 80 // Note the WGSL outputter should not output any declarations of global in/out variables, nor any 81 // redeclarations of builtin variables. And all accesses to global in/out variables should be 82 // rewritten as struct accesses of the global structs. 83 84 const char kBuiltinInputStructType[] = "ANGLE_Input_Global"; 85 const char kBuiltinOutputStructType[] = "ANGLE_Output_Global"; 86 const char kBuiltinInputAnnotatedStructType[] = "ANGLE_Input_Annotated"; 87 const char kBuiltinOutputAnnotatedStructType[] = "ANGLE_Output_Annotated"; 88 const char kBuiltinInputStructName[] = "ANGLE_input_global"; 89 const char kBuiltinOutputStructName[] = "ANGLE_output_global"; 90 const char kBuiltinInputAnnotatedStructName[] = "ANGLE_input_annotated"; 91 const char kBuiltinOutputAnnotatedStructName[] = "ANGLE_output_annotated"; 92 93 class RewritePipelineVarOutputBuilder; 94 95 struct RewritePipelineVarOutput 96 { 97 public: 98 RewritePipelineVarOutput(sh::GLenum shaderType); 99 100 // Every time the translator goes to output a TVariable/TSymbol it checks these functions to see 101 // if it should generate a struct access instead. 102 bool IsInputVar(TSymbolUniqueId angleInputVar); 103 bool IsOutputVar(TSymbolUniqueId angleOutputVar); 104 105 bool OutputStructs(TInfoSinkBase &output); 106 bool OutputMainFunction(TInfoSinkBase &output); 107 108 private: 109 friend RewritePipelineVarOutputBuilder; 110 111 // The key is TSymbolUniqueId::get(). 112 using RewrittenVarSet = TUnorderedSet<int>; 113 114 struct WgslIOBlock 115 { 116 TVector<ImmutableString> angleGlobalMembers; 117 TVector<ImmutableString> angleAnnotatedMembers; 118 TVector<ImmutableString> angleConversionFuncs; 119 }; 120 121 static bool OutputIOStruct(TInfoSinkBase &output, 122 WgslIOBlock &block, 123 ImmutableString builtinStructType, 124 ImmutableString builtinStructName, 125 ImmutableString builtinAnnotatedStructType); 126 127 // Represents the input and output structs for the WGSL main function. 128 WgslIOBlock mInputBlock; 129 WgslIOBlock mOutputBlock; 130 131 // Tracks all symbols (attributes, output vars, builtins) that need to be rewritten into struct 132 // accesses by the WGSL outputter. Used in `IsInputVar()` and `IsOutputVar()`. 133 RewrittenVarSet mAngleInputVars; 134 RewrittenVarSet mAngleOutputVars; 135 136 sh::GLenum mShaderType; 137 }; 138 139 // `outVarReplacements` is a RewritePipelineVarOutput that can output the WGSL main function and the 140 // input/output structs that represent the input and output variables of the GLSL shader, 141 [[nodiscard]] bool GenerateMainFunctionAndIOStructs(TCompiler &compiler, 142 TIntermBlock &root, 143 RewritePipelineVarOutput &outVarReplacements); 144 145 } // namespace sh 146 147 #endif // COMPILER_REWRITE_BUILTIN_VARIABLES_H_ 148