// // Copyright 2024 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // #ifndef COMPILER_REWRITE_BUILTIN_VARIABLES_H_ #define COMPILER_REWRITE_BUILTIN_VARIABLES_H_ #include #include "compiler/translator/Common.h" #include "compiler/translator/Compiler.h" #include "compiler/translator/ImmutableString.h" #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" #include "compiler/translator/SymbolUniqueId.h" #include "compiler/translator/wgsl/Utils.h" namespace sh { // In WGSL, all input values are parameters to the shader's main function and all output values are // return values of the shader's main functions (the input/output values can be embedded within // struct types). So this rewrites all accesses of GLSL's input/output variables (including // builtins) to be accesses of a global struct, and writes a new main function (called wgslMain()) // that populates the global input struct with parameters of the wgslMain function, and populates // wgslMain's return value with the fields of the global output struct. // // TODO(anglebug.com/42267100): some of these WGSL builtins do not correspond exactly to GLSL // builtin values and will need modification at the beginning (resp. end) of the main function for // input values (resp. output values). E.g. normalized device coordinates in GLSL have -1.0 <= z // <= 1.0, whereas NDC in WGSL have 0.0 <= z <= 1.0. // See e.g. bool TranslatorMSL::appendVertexShaderDepthCorrectionToMain(). // // Example GLSL: // // attribute vec2 xy_position; // void setPosition() { // gl_Position = vec4(xy_position.x, xy_position.y, 0.0, 1.0); // } // void main() // { // setPosition(); // } // // The resulting WGSL: // struct ANGLE_Input_Global { // xy_position : vec2, // }; // // var ANGLE_input_global : ANGLE_Input_Global; // // struct ANGLE_Input_Annotated { // @location(@@@@@@) xy_position : vec2, // }; // // struct ANGLE_Output_Global { // gl_Position_ : vec4, // }; // // var ANGLE_output_global : ANGLE_Output_Global; // // struct ANGLE_Output_Annotated { // @builtin(position) gl_Position_ : vec4, // }; // // // Generated versions of _umain() and _usetPosition() go here. // // @vertex // fn wgslMain(ANGLE_input_annotated : ANGLE_Input_Annotated) -> ANGLE_Output_Annotated // { // ANGLE_input_global.xy_position = ANGLE_input_annotated.xy_position; // _umain(); // var ANGLE_output_annotated : ANGLE_Output_Annotated; // ANGLE_output_annotated.gl_Position_ = ANGLE_output_global.gl_Position_; // return ANGLE_output_annotated; // } // // Note the WGSL outputter should not output any declarations of global in/out variables, nor any // redeclarations of builtin variables. And all accesses to global in/out variables should be // rewritten as struct accesses of the global structs. const char kBuiltinInputStructType[] = "ANGLE_Input_Global"; const char kBuiltinOutputStructType[] = "ANGLE_Output_Global"; const char kBuiltinInputAnnotatedStructType[] = "ANGLE_Input_Annotated"; const char kBuiltinOutputAnnotatedStructType[] = "ANGLE_Output_Annotated"; const char kBuiltinInputStructName[] = "ANGLE_input_global"; const char kBuiltinOutputStructName[] = "ANGLE_output_global"; const char kBuiltinInputAnnotatedStructName[] = "ANGLE_input_annotated"; const char kBuiltinOutputAnnotatedStructName[] = "ANGLE_output_annotated"; class RewritePipelineVarOutputBuilder; struct RewritePipelineVarOutput { public: RewritePipelineVarOutput(sh::GLenum shaderType); // Every time the translator goes to output a TVariable/TSymbol it checks these functions to see // if it should generate a struct access instead. bool IsInputVar(TSymbolUniqueId angleInputVar); bool IsOutputVar(TSymbolUniqueId angleOutputVar); bool OutputStructs(TInfoSinkBase &output); bool OutputMainFunction(TInfoSinkBase &output); private: friend RewritePipelineVarOutputBuilder; // The key is TSymbolUniqueId::get(). using RewrittenVarSet = TUnorderedSet; struct WgslIOBlock { TVector angleGlobalMembers; TVector angleAnnotatedMembers; TVector angleConversionFuncs; }; static bool OutputIOStruct(TInfoSinkBase &output, WgslIOBlock &block, ImmutableString builtinStructType, ImmutableString builtinStructName, ImmutableString builtinAnnotatedStructType); // Represents the input and output structs for the WGSL main function. WgslIOBlock mInputBlock; WgslIOBlock mOutputBlock; // Tracks all symbols (attributes, output vars, builtins) that need to be rewritten into struct // accesses by the WGSL outputter. Used in `IsInputVar()` and `IsOutputVar()`. RewrittenVarSet mAngleInputVars; RewrittenVarSet mAngleOutputVars; sh::GLenum mShaderType; }; // `outVarReplacements` is a RewritePipelineVarOutput that can output the WGSL main function and the // input/output structs that represent the input and output variables of the GLSL shader, [[nodiscard]] bool GenerateMainFunctionAndIOStructs(TCompiler &compiler, TIntermBlock &root, RewritePipelineVarOutput &outVarReplacements); } // namespace sh #endif // COMPILER_REWRITE_BUILTIN_VARIABLES_H_