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 #include "compiler/translator/wgsl/RewritePipelineVariables.h"
8
9 #include <string>
10 #include <utility>
11
12 #include "GLES2/gl2.h"
13 #include "GLSLANG/ShaderLang.h"
14 #include "GLSLANG/ShaderVars.h"
15 #include "anglebase/no_destructor.h"
16 #include "common/angleutils.h"
17 #include "common/log_utils.h"
18 #include "compiler/translator/Common.h"
19 #include "compiler/translator/ImmutableString.h"
20 #include "compiler/translator/ImmutableStringBuilder.h"
21 #include "compiler/translator/IntermNode.h"
22 #include "compiler/translator/OutputTree.h"
23 #include "compiler/translator/Symbol.h"
24 #include "compiler/translator/SymbolUniqueId.h"
25 #include "compiler/translator/Types.h"
26 #include "compiler/translator/tree_util/BuiltIn_autogen.h"
27 #include "compiler/translator/tree_util/FindMain.h"
28 #include "compiler/translator/tree_util/ReplaceVariable.h"
29 #include "compiler/translator/util.h"
30 #include "compiler/translator/wgsl/Utils.h"
31
32 namespace sh
33 {
34
35 namespace
36 {
37
38 const bool kOutputVariableUses = false;
39
40 struct LocationAnnotation
41 {
42 // Most variables will not be assigned a location until link time, but some variables (like
43 // gl_FragColor) imply an output location.
44 int location = -1;
45 };
46 struct BuiltinAnnotation
47 {
48 ImmutableString wgslBuiltinName;
49 };
50 struct NoAnnotation
51 {};
52
53 using PipelineAnnotation = std::variant<LocationAnnotation, BuiltinAnnotation, NoAnnotation>;
54
55 enum class IOType
56 {
57 Input,
58 Output
59 };
60
61 struct GlslToWgslBuiltinMapping
62 {
63 ImmutableString glslBuiltinName{nullptr};
64 PipelineAnnotation wgslPipelineAnnotation;
65 IOType ioType;
66 const TVariable *builtinVar;
67 // The type from the WGSL spec that corresponds to `wgslPipelineAnnotation`.
68 ImmutableString wgslBuiltinType{nullptr};
69 // The type that is expected by the shader in the AST, i.e. the type of `builtinVar`. If
70 // nullptr, is the same as `wgslBuiltinType`.
71 // TODO(anglebug.com/42267100): delete this and convert `builtinVar`'s type to a WGSL type.
72 ImmutableString wgslTypeExpectedByShader{nullptr};
73 // A function to apply that does one of two thing:
74 // 1. for an input builtin: converts the builtin, as supplied by WGPU, into the variable that
75 // the GLSL shader expects.
76 // 2. for an output builtin: converts the output variable from the GLSL shader into the
77 // builtin supplied back to WGPU.
78 // Can be nullptr for no conversion.
79 ImmutableString conversionFunc{nullptr};
80 };
81
GetWgslBuiltinName(std::string glslBuiltinName,GLenum shaderType,GlslToWgslBuiltinMapping * outMapping)82 bool GetWgslBuiltinName(std::string glslBuiltinName,
83 GLenum shaderType,
84 GlslToWgslBuiltinMapping *outMapping)
85 {
86 static const angle::base::NoDestructor<angle::HashMap<std::string, GlslToWgslBuiltinMapping>>
87 kGlslBuiltinToWgslBuiltinVertex(
88 {{"gl_VertexID",
89 GlslToWgslBuiltinMapping{ImmutableString("gl_VertexID"),
90 BuiltinAnnotation{ImmutableString("vertex_index")},
91 IOType::Input, BuiltInVariable::gl_VertexID(),
92 ImmutableString("u32"), ImmutableString("i32"),
93 ImmutableString("i32")}},
94 {"gl_InstanceID",
95 GlslToWgslBuiltinMapping{ImmutableString("gl_InstanceID"),
96 BuiltinAnnotation{ImmutableString("instance_index")},
97 IOType::Input, BuiltInVariable::gl_InstanceID(),
98 ImmutableString("u32"), ImmutableString("i32"),
99 ImmutableString("i32")}},
100 {"gl_Position",
101 GlslToWgslBuiltinMapping{
102 ImmutableString("gl_Position"), BuiltinAnnotation{ImmutableString("position")},
103 IOType::Output, BuiltInVariable::gl_Position(), ImmutableString("vec4<f32>"),
104 ImmutableString(nullptr), ImmutableString(nullptr)}},
105 {"gl_PointSize",
106 GlslToWgslBuiltinMapping{ImmutableString("gl_PointSize"), NoAnnotation{},
107 IOType::Output, BuiltInVariable::gl_PointSize(),
108 ImmutableString("f32"), ImmutableString(nullptr),
109 ImmutableString(nullptr)}},
110 // TODO(anglebug.com/42267100): might have to emulate clip_distances, see
111 // Metal's
112 // https://source.chromium.org/chromium/chromium/src/+/main:third_party/angle/src/compiler/translator/msl/TranslatorMSL.cpp?q=symbol%3A%5Cbsh%3A%3AEmulateClipDistanceVaryings%5Cb%20case%3Ayes
113 {"gl_ClipDistance",
114 GlslToWgslBuiltinMapping{ImmutableString("gl_ClipDistance"),
115 BuiltinAnnotation{ImmutableString("clip_distances")},
116 IOType::Output, nullptr, ImmutableString("TODO"),
117 ImmutableString(nullptr), ImmutableString(nullptr)}}});
118 static const angle::base::NoDestructor<angle::HashMap<std::string, GlslToWgslBuiltinMapping>>
119 kGlslBuiltinToWgslBuiltinFragment({
120 {"gl_FragCoord",
121 GlslToWgslBuiltinMapping{ImmutableString("gl_FragCoord"),
122 BuiltinAnnotation{ImmutableString("position")}, IOType::Input,
123 BuiltInVariable::gl_FragCoord(), ImmutableString("vec4<f32>"),
124 ImmutableString(nullptr), ImmutableString(nullptr)}},
125 {"gl_FrontFacing",
126 GlslToWgslBuiltinMapping{ImmutableString("gl_FrontFacing"),
127 BuiltinAnnotation{ImmutableString("front_facing")},
128 IOType::Input, BuiltInVariable::gl_FrontFacing(),
129 ImmutableString("bool"), ImmutableString(nullptr),
130 ImmutableString(nullptr)}},
131 {"gl_SampleID",
132 GlslToWgslBuiltinMapping{
133 ImmutableString("gl_SampleID"), BuiltinAnnotation{ImmutableString("sample_index")},
134 IOType::Input, BuiltInVariable::gl_SampleID(), ImmutableString("u32"),
135 ImmutableString("i32"), ImmutableString("i32")}},
136 // TODO(anglebug.com/42267100): gl_SampleMask is GLSL 4.00 or ARB_sample_shading and
137 // requires some special handling (see Metal).
138 {"gl_SampleMaskIn",
139 GlslToWgslBuiltinMapping{ImmutableString("gl_SampleMaskIn"),
140 BuiltinAnnotation{ImmutableString("sample_mask")},
141 IOType::Input, nullptr, ImmutableString("u32"),
142 ImmutableString("i32"), ImmutableString("i32")}},
143 // Just translate FragColor into a location = 0 out variable.
144 // TODO(anglebug.com/42267100): maybe ASSERT that there are no user-defined output
145 // variables? Is it possible for there to be other output variables when using
146 // FragColor?
147 {"gl_FragColor",
148 GlslToWgslBuiltinMapping{ImmutableString("gl_FragColor"), LocationAnnotation{0},
149 IOType::Output, BuiltInVariable::gl_FragColor(),
150 ImmutableString("vec4<f32>"), ImmutableString(nullptr),
151 ImmutableString(nullptr)}},
152 {"gl_SampleMask",
153 GlslToWgslBuiltinMapping{ImmutableString("gl_SampleMask"),
154 BuiltinAnnotation{ImmutableString("sample_mask")},
155 IOType::Output, nullptr, ImmutableString("u32"),
156 ImmutableString("i32"), ImmutableString("i32")}},
157 {"gl_FragDepth",
158 GlslToWgslBuiltinMapping{
159 ImmutableString("gl_FragDepth"), BuiltinAnnotation{ImmutableString("frag_depth")},
160 IOType::Output, BuiltInVariable::gl_FragDepth(), ImmutableString("f32"),
161 ImmutableString(nullptr), ImmutableString(nullptr)}},
162 });
163 // TODO(anglebug.com/42267100): gl_FragData needs to be emulated. Need something
164 // like spir-v's
165 // third_party/angle/src/compiler/translator/tree_ops/spirv/EmulateFragColorData.h.
166
167 if (shaderType == GL_VERTEX_SHADER)
168 {
169 auto it = kGlslBuiltinToWgslBuiltinVertex->find(glslBuiltinName);
170 if (it == kGlslBuiltinToWgslBuiltinVertex->end())
171 {
172 return false;
173 }
174 *outMapping = it->second;
175 return true;
176 }
177 else if (shaderType == GL_FRAGMENT_SHADER)
178 {
179 auto it = kGlslBuiltinToWgslBuiltinFragment->find(glslBuiltinName);
180 if (it == kGlslBuiltinToWgslBuiltinFragment->end())
181 {
182 return false;
183 }
184 *outMapping = it->second;
185 return true;
186 }
187 else
188 {
189 UNREACHABLE();
190 return false;
191 }
192 }
193
CreateNameToReplaceBuiltin(ImmutableString glslBuiltinName)194 ImmutableString CreateNameToReplaceBuiltin(ImmutableString glslBuiltinName)
195 {
196 ImmutableStringBuilder newName(glslBuiltinName.length() + 1);
197 newName << glslBuiltinName << '_';
198 return newName;
199 }
200
201 } // namespace
202
203 // Friended by RewritePipelineVarOutput
204 class RewritePipelineVarOutputBuilder
205 {
206 public:
207 static bool GenerateMainFunctionAndIOStructs(TCompiler &compiler,
208 TIntermBlock &root,
209 RewritePipelineVarOutput &outVarReplacements);
210
211 private:
212 static bool GeneratePipelineStructStrings(
213 RewritePipelineVarOutput::WgslIOBlock *ioblock,
214 RewritePipelineVarOutput::RewrittenVarSet *varsToReplace,
215 ImmutableString toStruct,
216 ImmutableString fromStruct,
217 const std::vector<ShaderVariable> &shaderVars,
218 const GlobalVars &globalVars,
219 TCompiler &compiler,
220 IOType ioType,
221 const std::string &debugString);
222
GenerateForBuiltinVar(RewritePipelineVarOutput::WgslIOBlock * ioblock,RewritePipelineVarOutput::RewrittenVarSet * varsToReplace,ImmutableString toStruct,ImmutableString fromStruct,TCompiler & compiler,IOType ioType,const std::string & shaderVarName)223 static bool GenerateForBuiltinVar(RewritePipelineVarOutput::WgslIOBlock *ioblock,
224 RewritePipelineVarOutput::RewrittenVarSet *varsToReplace,
225 ImmutableString toStruct,
226 ImmutableString fromStruct,
227 TCompiler &compiler,
228 IOType ioType,
229 const std::string &shaderVarName)
230 {
231
232 GlslToWgslBuiltinMapping wgslName;
233 if (!GetWgslBuiltinName(shaderVarName, compiler.getShaderType(), &wgslName))
234 {
235 return false;
236 }
237
238 const TVariable *varToReplace = wgslName.builtinVar;
239
240 if (varToReplace == nullptr)
241 {
242 // Should be declared somewhere as a symbol.
243 // TODO(anglebug.com/42267100): Not sure if this ever actually occurs. Will this
244 // TVariable also have a declaration? Are there any gl_ variable that require or
245 // even allow declaration?
246 varToReplace = static_cast<const TVariable *>(compiler.getSymbolTable().findBuiltIn(
247 ImmutableString(wgslName.glslBuiltinName), compiler.getShaderVersion()));
248 if (kOutputVariableUses)
249 {
250 std::cout << "Var " << shaderVarName
251 << " did not have a BuiltIn var but does have a builtin in the symbol "
252 "table"
253 << std::endl;
254 }
255 }
256
257 ASSERT(ioType == wgslName.ioType);
258
259 varsToReplace->insert(varToReplace->uniqueId().get());
260
261 ImmutableString builtinReplacement = CreateNameToReplaceBuiltin(wgslName.glslBuiltinName);
262
263 // E.g. `gl_VertexID_ : i32`.
264 ImmutableString globalType = wgslName.wgslTypeExpectedByShader.empty()
265 ? wgslName.wgslBuiltinType
266 : wgslName.wgslTypeExpectedByShader;
267 ImmutableString globalStructVar =
268 BuildConcatenatedImmutableString(builtinReplacement, " : ", globalType, ",");
269 ioblock->angleGlobalMembers.push_back(globalStructVar);
270
271 if (auto *builtinAnnotation =
272 std::get_if<BuiltinAnnotation>(&wgslName.wgslPipelineAnnotation))
273 {
274 // E.g. `@builtin(vertex_index) gl_VertexID_ : u32,`.
275 const char *builtinAnnotationStart = "@builtin(";
276 const char *builtinAnnotationEnd = ") ";
277 ImmutableString annotatedStructVar = BuildConcatenatedImmutableString(
278 builtinAnnotationStart, builtinAnnotation->wgslBuiltinName, builtinAnnotationEnd,
279 builtinReplacement, " : ", wgslName.wgslBuiltinType, ",");
280 ioblock->angleAnnotatedMembers.push_back(annotatedStructVar);
281 }
282 else if (auto *locationAnnotation =
283 std::get_if<LocationAnnotation>(&wgslName.wgslPipelineAnnotation))
284 {
285 ASSERT(locationAnnotation->location == 0);
286 // E.g. `@location(0) gl_FragColor_ : vec4<f32>,`.
287 const char *locationAnnotationStr = "@location(0) ";
288 ImmutableString annotatedStructVar = BuildConcatenatedImmutableString(
289 locationAnnotationStr, builtinReplacement, " : ", wgslName.wgslBuiltinType, ",");
290 ioblock->angleAnnotatedMembers.push_back(annotatedStructVar);
291 }
292 else
293 {
294 ASSERT(std::get_if<NoAnnotation>(&wgslName.wgslPipelineAnnotation));
295 }
296
297 if (!std::get_if<NoAnnotation>(&wgslName.wgslPipelineAnnotation))
298 {
299 // E.g. `ANGLE_input_global.gl_VertexID_ = u32(ANGLE_input_annotated.gl_VertexID_);`
300 ImmutableString conversion(nullptr);
301 if (wgslName.conversionFunc.empty())
302 {
303 conversion =
304 BuildConcatenatedImmutableString(toStruct, ".", builtinReplacement, " = ",
305 fromStruct, ".", builtinReplacement, ";");
306 }
307 else
308 {
309 conversion = BuildConcatenatedImmutableString(
310 toStruct, ".", builtinReplacement, " = ", wgslName.conversionFunc, "(",
311 fromStruct, ".", builtinReplacement, ");");
312 }
313 ioblock->angleConversionFuncs.push_back(conversion);
314 }
315
316 return true;
317 }
318 };
319
320 // Given a list of `shaderVars` (as well as `compiler` and a list of global variables in the GLSL
321 // source, `globalVars`), computes the fields that should appear in the input/output pipeline
322 // structs and the annotations that should appear in the WGSL source.
323 //
324 // `ioblock` will be filled with strings that make up the resulting structs, and with the strings
325 // indicated by `fromStruct` and `toStruct`. `varsToReplace` will be filled with the symbols that
326 // should be replaced in the final WGSL source wtih struct accesses.
327 //
328 // Finally, `debugString` should describe `shaderVars` (e.g. "input varyings"), and `ioType`
329 // indicates whether `shaderVars` is meant to be an input or output variable, which is useful for
330 // debugging asserts.
GeneratePipelineStructStrings(RewritePipelineVarOutput::WgslIOBlock * ioblock,RewritePipelineVarOutput::RewrittenVarSet * varsToReplace,ImmutableString toStruct,ImmutableString fromStruct,const std::vector<ShaderVariable> & shaderVars,const GlobalVars & globalVars,TCompiler & compiler,IOType ioType,const std::string & debugString)331 [[nodiscard]] bool RewritePipelineVarOutputBuilder::GeneratePipelineStructStrings(
332 RewritePipelineVarOutput::WgslIOBlock *ioblock,
333 RewritePipelineVarOutput::RewrittenVarSet *varsToReplace,
334 ImmutableString toStruct,
335 ImmutableString fromStruct,
336 const std::vector<ShaderVariable> &shaderVars,
337 const GlobalVars &globalVars,
338 TCompiler &compiler,
339 IOType ioType,
340 const std::string &debugString)
341 {
342 for (const ShaderVariable &shaderVar : shaderVars)
343 {
344 if (shaderVar.name == "gl_FragData" || shaderVar.name == "gl_SecondaryFragColorEXT" ||
345 shaderVar.name == "gl_SecondaryFragDataEXT")
346 {
347 // TODO(anglebug.com/42267100): declare gl_FragData as multiple variables.
348 UNIMPLEMENTED();
349 return false;
350 }
351
352 if (kOutputVariableUses)
353 {
354 std::cout << "Use of " << (shaderVar.isBuiltIn() ? "builtin " : "") << debugString
355 << ": " << shaderVar.name << std::endl;
356 }
357
358 if (shaderVar.isBuiltIn())
359 {
360 if (!GenerateForBuiltinVar(ioblock, varsToReplace, toStruct, fromStruct, compiler,
361 ioType, shaderVar.name))
362 {
363 return false;
364 }
365 }
366 else
367 {
368 if (!shaderVar.active)
369 {
370 // Skip any inactive attributes as they won't be assigned a location anyway.
371 continue;
372 }
373
374 TIntermDeclaration *declNode = globalVars.find(shaderVar.name)->second;
375 const TVariable *astVar = &ViewDeclaration(*declNode).symbol.variable();
376
377 const ImmutableString &userVarName = astVar->name();
378
379 varsToReplace->insert(astVar->uniqueId().get());
380
381 // E.g. `_uuserVar : i32,`.
382 TStringStream typeStream;
383 WriteWgslType(typeStream, astVar->getType(), {});
384 TString type = typeStream.str();
385 ImmutableString globalStructVar =
386 BuildConcatenatedImmutableString(userVarName, " : ", type.c_str(), ",");
387 ioblock->angleGlobalMembers.push_back(globalStructVar);
388
389 // E.g. `@location(@@@@@@) _uuserVar : i32,`.
390 const char *locationAnnotationStr = "@location(@@@@@@) ";
391 ImmutableString annotatedStructVar =
392 BuildConcatenatedImmutableString(locationAnnotationStr, globalStructVar);
393 ioblock->angleAnnotatedMembers.push_back(annotatedStructVar);
394
395 // E.g. `ANGLE_input_global._uuserVar = ANGLE_input_annotated._uuserVar;`
396 ImmutableString conversion = BuildConcatenatedImmutableString(
397 toStruct, ".", userVarName, " = ", fromStruct, ".", userVarName, ";");
398 ioblock->angleConversionFuncs.push_back(conversion);
399 }
400 }
401
402 return true;
403 }
404
GenerateMainFunctionAndIOStructs(TCompiler & compiler,TIntermBlock & root,RewritePipelineVarOutput & outVarReplacements)405 bool RewritePipelineVarOutputBuilder::GenerateMainFunctionAndIOStructs(
406 TCompiler &compiler,
407 TIntermBlock &root,
408 RewritePipelineVarOutput &outVarReplacements)
409 {
410 GlobalVars globalVars = FindGlobalVars(&root);
411
412 // The Dawn WGSL compiler generates an error if there is no builtin(position) variable in a
413 // vertex shader, though it doesn't look like the WGSL spec requires this. GLSL doesn't require
414 // use of gl_Position (only that its value is undefined if not written to). So, generate a
415 // @builtin(position) variable by pretending gl_Position is present even if it's not.
416 if (compiler.getShaderType() == GL_VERTEX_SHADER)
417 {
418 bool hasPosition = false;
419 for (const ShaderVariable &shaderVar : compiler.getOutputVaryings())
420 {
421 if (shaderVar.name == std::string("gl_Position"))
422 {
423 hasPosition = true;
424 }
425 }
426
427 if (!hasPosition)
428 {
429 if (!GenerateForBuiltinVar(
430 &outVarReplacements.mOutputBlock, &outVarReplacements.mAngleOutputVars,
431 /*toStruct=*/ImmutableString(kBuiltinOutputAnnotatedStructName),
432 /*fromStruct=*/ImmutableString(kBuiltinOutputStructName), compiler,
433 IOType::Output, "gl_Position"))
434 {
435 return false;
436 }
437 }
438 }
439
440 if (!RewritePipelineVarOutputBuilder::GeneratePipelineStructStrings(
441 &outVarReplacements.mInputBlock, &outVarReplacements.mAngleInputVars,
442 /*toStruct=*/ImmutableString(kBuiltinInputStructName),
443 /*fromStruct=*/ImmutableString(kBuiltinInputAnnotatedStructName),
444 compiler.getInputVaryings(), globalVars, compiler, IOType::Input, "input varyings") ||
445 !RewritePipelineVarOutputBuilder::GeneratePipelineStructStrings(
446 &outVarReplacements.mInputBlock, &outVarReplacements.mAngleInputVars,
447 /*toStruct=*/ImmutableString(kBuiltinInputStructName),
448 /*fromStruct=*/ImmutableString(kBuiltinInputAnnotatedStructName),
449 compiler.getAttributes(), globalVars, compiler, IOType::Input, "input attributes") ||
450 !RewritePipelineVarOutputBuilder::GeneratePipelineStructStrings(
451 &outVarReplacements.mOutputBlock, &outVarReplacements.mAngleOutputVars,
452 /*toStruct=*/ImmutableString(kBuiltinOutputAnnotatedStructName),
453 /*fromStruct=*/ImmutableString(kBuiltinOutputStructName), compiler.getOutputVaryings(),
454 globalVars, compiler, IOType::Output, "output varyings") ||
455 !RewritePipelineVarOutputBuilder::GeneratePipelineStructStrings(
456 &outVarReplacements.mOutputBlock, &outVarReplacements.mAngleOutputVars,
457 /*toStruct=*/ImmutableString(kBuiltinOutputAnnotatedStructName),
458 /*fromStruct=*/ImmutableString(kBuiltinOutputStructName), compiler.getOutputVariables(),
459 globalVars, compiler, IOType::Output, "output variables"))
460 {
461 return false;
462 }
463
464 return true;
465 }
466
RewritePipelineVarOutput(sh::GLenum shaderType)467 RewritePipelineVarOutput::RewritePipelineVarOutput(sh::GLenum shaderType) : mShaderType(shaderType)
468 {}
469
IsInputVar(TSymbolUniqueId angleInputVar) const470 bool RewritePipelineVarOutput::IsInputVar(TSymbolUniqueId angleInputVar) const
471 {
472 return mAngleInputVars.count(angleInputVar.get()) > 0;
473 }
IsOutputVar(TSymbolUniqueId angleOutputVar) const474 bool RewritePipelineVarOutput::IsOutputVar(TSymbolUniqueId angleOutputVar) const
475 {
476 return mAngleOutputVars.count(angleOutputVar.get()) > 0;
477 }
478
479 // static
OutputIOStruct(TInfoSinkBase & output,WgslIOBlock & block,ImmutableString builtinStructType,ImmutableString builtinStructName,ImmutableString builtinAnnotatedStructType)480 bool RewritePipelineVarOutput::OutputIOStruct(TInfoSinkBase &output,
481 WgslIOBlock &block,
482 ImmutableString builtinStructType,
483 ImmutableString builtinStructName,
484 ImmutableString builtinAnnotatedStructType)
485 {
486
487 if (!block.angleGlobalMembers.empty())
488 {
489 // Output global struct definition.
490 output << "struct " << builtinStructType << " {\n";
491 for (const ImmutableString &globalMember : block.angleGlobalMembers)
492 {
493 output << " " << globalMember << "\n";
494 }
495 output << "};\n\n";
496 // Output decl of global struct.
497 output << "var<private> " << builtinStructName << " : " << builtinStructType << ";\n\n";
498 // Output annotated struct definition.
499 output << "struct " << builtinAnnotatedStructType << " {\n";
500 for (const ImmutableString &annotatedMember : block.angleAnnotatedMembers)
501 {
502 output << " " << annotatedMember << "\n";
503 }
504 output << "};\n\n";
505 }
506
507 return true;
508 }
509
OutputStructs(TInfoSinkBase & output)510 bool RewritePipelineVarOutput::OutputStructs(TInfoSinkBase &output)
511 {
512 if (!OutputIOStruct(output, mInputBlock, ImmutableString(kBuiltinInputStructType),
513 ImmutableString(kBuiltinInputStructName),
514 ImmutableString(kBuiltinInputAnnotatedStructType)) ||
515 !OutputIOStruct(output, mOutputBlock, ImmutableString(kBuiltinOutputStructType),
516 ImmutableString(kBuiltinOutputStructName),
517 ImmutableString(kBuiltinOutputAnnotatedStructType)))
518 {
519 return false;
520 }
521
522 return true;
523 }
524
525 // Could split OutputMainFunction() into the different parts of the main function.
OutputMainFunction(TInfoSinkBase & output)526 bool RewritePipelineVarOutput::OutputMainFunction(TInfoSinkBase &output)
527 {
528 if (mShaderType == GL_VERTEX_SHADER)
529 {
530 output << "@vertex\n";
531 }
532 else
533 {
534 ASSERT(mShaderType == GL_FRAGMENT_SHADER);
535 output << "@fragment\n";
536 }
537 output << "fn wgslMain(";
538 if (!mInputBlock.angleGlobalMembers.empty())
539 {
540 output << kBuiltinInputAnnotatedStructName << " : " << kBuiltinInputAnnotatedStructType;
541 }
542 output << ")";
543 if (!mOutputBlock.angleGlobalMembers.empty())
544 {
545 output << " -> " << kBuiltinOutputAnnotatedStructType;
546 }
547 output << "\n{\n";
548 for (const ImmutableString &conversionFunc : mInputBlock.angleConversionFuncs)
549 {
550 output << " " << conversionFunc << "\n";
551 }
552 output << " " << kUserDefinedNamePrefix << "main()" << ";\n";
553
554 if (!mOutputBlock.angleGlobalMembers.empty())
555 {
556 output << " var " << kBuiltinOutputAnnotatedStructName << " : "
557 << kBuiltinOutputAnnotatedStructType << ";\n";
558 for (const ImmutableString &conversionFunc : mOutputBlock.angleConversionFuncs)
559 {
560 output << " " << conversionFunc << "\n";
561 }
562 output << " return " << kBuiltinOutputAnnotatedStructName << ";\n";
563 }
564 output << "}\n";
565 return true;
566 }
567
GenerateMainFunctionAndIOStructs(TCompiler & compiler,TIntermBlock & root,RewritePipelineVarOutput & outVarReplacements)568 bool GenerateMainFunctionAndIOStructs(TCompiler &compiler,
569 TIntermBlock &root,
570 RewritePipelineVarOutput &outVarReplacements)
571 {
572 return RewritePipelineVarOutputBuilder::GenerateMainFunctionAndIOStructs(compiler, root,
573 outVarReplacements);
574 }
575 } // namespace sh
576