blob: cb1c3acf673007508f674b4060ee016da132d7e9 [file] [log] [blame]
//
// 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 <variant>
#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<f32>,
// };
//
// var<private> ANGLE_input_global : ANGLE_Input_Global;
//
// struct ANGLE_Input_Annotated {
// @location(@@@@@@) xy_position : vec2<f32>,
// };
//
// struct ANGLE_Output_Global {
// gl_Position_ : vec4<f32>,
// };
//
// var<private> ANGLE_output_global : ANGLE_Output_Global;
//
// struct ANGLE_Output_Annotated {
// @builtin(position) gl_Position_ : vec4<f32>,
// };
//
// // 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) const;
bool IsOutputVar(TSymbolUniqueId angleOutputVar) const;
bool OutputStructs(TInfoSinkBase &output);
bool OutputMainFunction(TInfoSinkBase &output);
private:
friend RewritePipelineVarOutputBuilder;
// The key is TSymbolUniqueId::get().
using RewrittenVarSet = TUnorderedSet<int>;
struct WgslIOBlock
{
TVector<ImmutableString> angleGlobalMembers;
TVector<ImmutableString> angleAnnotatedMembers;
TVector<ImmutableString> 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_