xref: /aosp_15_r20/external/angle/src/compiler/translator/spirv/TranslatorSPIRV.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 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 // TranslatorSPIRV:
7 //   A set of transformations that prepare the AST to be compatible with GL_KHR_vulkan_glsl followed
8 //   by a pass that generates SPIR-V.
9 //   See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
10 //
11 
12 #include "compiler/translator/spirv/TranslatorSPIRV.h"
13 
14 #include "angle_gl.h"
15 #include "common/PackedEnums.h"
16 #include "common/utilities.h"
17 #include "compiler/translator/ImmutableStringBuilder.h"
18 #include "compiler/translator/IntermNode.h"
19 #include "compiler/translator/StaticType.h"
20 #include "compiler/translator/spirv/BuiltinsWorkaround.h"
21 #include "compiler/translator/spirv/OutputSPIRV.h"
22 #include "compiler/translator/tree_ops/DeclarePerVertexBlocks.h"
23 #include "compiler/translator/tree_ops/MonomorphizeUnsupportedFunctions.h"
24 #include "compiler/translator/tree_ops/RecordConstantPrecision.h"
25 #include "compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.h"
26 #include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
27 #include "compiler/translator/tree_ops/RewriteArrayOfArrayOfOpaqueUniforms.h"
28 #include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
29 #include "compiler/translator/tree_ops/RewriteDfdy.h"
30 #include "compiler/translator/tree_ops/RewriteStructSamplers.h"
31 #include "compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.h"
32 #include "compiler/translator/tree_ops/spirv/ClampGLLayer.h"
33 #include "compiler/translator/tree_ops/spirv/EmulateAdvancedBlendEquations.h"
34 #include "compiler/translator/tree_ops/spirv/EmulateDithering.h"
35 #include "compiler/translator/tree_ops/spirv/EmulateFragColorData.h"
36 #include "compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.h"
37 #include "compiler/translator/tree_ops/spirv/EmulateYUVBuiltIns.h"
38 #include "compiler/translator/tree_ops/spirv/FlagSamplersWithTexelFetch.h"
39 #include "compiler/translator/tree_ops/spirv/ReswizzleYUVOps.h"
40 #include "compiler/translator/tree_ops/spirv/RewriteInterpolateAtOffset.h"
41 #include "compiler/translator/tree_ops/spirv/RewriteR32fImages.h"
42 #include "compiler/translator/tree_util/BuiltIn.h"
43 #include "compiler/translator/tree_util/DriverUniform.h"
44 #include "compiler/translator/tree_util/FindFunction.h"
45 #include "compiler/translator/tree_util/FindMain.h"
46 #include "compiler/translator/tree_util/FindSymbolNode.h"
47 #include "compiler/translator/tree_util/IntermNode_util.h"
48 #include "compiler/translator/tree_util/ReplaceClipCullDistanceVariable.h"
49 #include "compiler/translator/tree_util/ReplaceVariable.h"
50 #include "compiler/translator/tree_util/RewriteSampleMaskVariable.h"
51 #include "compiler/translator/tree_util/RunAtTheBeginningOfShader.h"
52 #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
53 #include "compiler/translator/tree_util/SpecializationConstant.h"
54 #include "compiler/translator/util.h"
55 
56 namespace sh
57 {
58 
59 namespace
60 {
61 constexpr ImmutableString kFlippedPointCoordName    = ImmutableString("flippedPointCoord");
62 constexpr ImmutableString kFlippedFragCoordName     = ImmutableString("flippedFragCoord");
63 constexpr ImmutableString kDefaultUniformsBlockName = ImmutableString("defaultUniforms");
64 
IsDefaultUniform(const TType & type)65 bool IsDefaultUniform(const TType &type)
66 {
67     return type.getQualifier() == EvqUniform && type.getInterfaceBlock() == nullptr &&
68            !IsOpaqueType(type.getBasicType());
69 }
70 
71 class ReplaceDefaultUniformsTraverser : public TIntermTraverser
72 {
73   public:
ReplaceDefaultUniformsTraverser(const VariableReplacementMap & variableMap)74     ReplaceDefaultUniformsTraverser(const VariableReplacementMap &variableMap)
75         : TIntermTraverser(true, false, false), mVariableMap(variableMap)
76     {}
77 
visitDeclaration(Visit visit,TIntermDeclaration * node)78     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
79     {
80         const TIntermSequence &sequence = *(node->getSequence());
81 
82         TIntermTyped *variable = sequence.front()->getAsTyped();
83         const TType &type      = variable->getType();
84 
85         if (IsDefaultUniform(type))
86         {
87             // Remove the uniform declaration.
88             TIntermSequence emptyReplacement;
89             mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
90                                             std::move(emptyReplacement));
91 
92             return false;
93         }
94 
95         return true;
96     }
97 
visitSymbol(TIntermSymbol * symbol)98     void visitSymbol(TIntermSymbol *symbol) override
99     {
100         const TVariable &variable = symbol->variable();
101         const TType &type         = variable.getType();
102 
103         if (!IsDefaultUniform(type) || gl::IsBuiltInName(variable.name().data()))
104         {
105             return;
106         }
107 
108         ASSERT(mVariableMap.count(&variable) > 0);
109 
110         queueReplacement(mVariableMap.at(&variable)->deepCopy(), OriginalNode::IS_DROPPED);
111     }
112 
113   private:
114     const VariableReplacementMap &mVariableMap;
115 };
116 
DeclareDefaultUniforms(TranslatorSPIRV * compiler,TIntermBlock * root,TSymbolTable * symbolTable,gl::ShaderType shaderType)117 bool DeclareDefaultUniforms(TranslatorSPIRV *compiler,
118                             TIntermBlock *root,
119                             TSymbolTable *symbolTable,
120                             gl::ShaderType shaderType)
121 {
122     // First, collect all default uniforms and declare a uniform block.
123     TFieldList *uniformList = new TFieldList;
124     TVector<const TVariable *> uniformVars;
125 
126     for (TIntermNode *node : *root->getSequence())
127     {
128         TIntermDeclaration *decl = node->getAsDeclarationNode();
129         if (decl == nullptr)
130         {
131             continue;
132         }
133 
134         const TIntermSequence &sequence = *(decl->getSequence());
135 
136         TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
137         if (symbol == nullptr)
138         {
139             continue;
140         }
141 
142         const TType &type = symbol->getType();
143         if (IsDefaultUniform(type))
144         {
145             TType *fieldType = new TType(type);
146 
147             uniformList->push_back(new TField(fieldType, symbol->getName(), symbol->getLine(),
148                                               symbol->variable().symbolType()));
149             uniformVars.push_back(&symbol->variable());
150         }
151     }
152 
153     TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
154     layoutQualifier.blockStorage     = EbsStd140;
155     const TVariable *uniformBlock    = DeclareInterfaceBlock(
156         root, symbolTable, uniformList, EvqUniform, layoutQualifier, TMemoryQualifier::Create(), 0,
157         kDefaultUniformsBlockName, ImmutableString(""));
158 
159     compiler->assignSpirvId(uniformBlock->getType().getInterfaceBlock()->uniqueId(),
160                             vk::spirv::kIdDefaultUniformsBlock);
161 
162     // Create a map from the uniform variables to new variables that reference the fields of the
163     // block.
164     VariableReplacementMap variableMap;
165     for (size_t fieldIndex = 0; fieldIndex < uniformVars.size(); ++fieldIndex)
166     {
167         const TVariable *variable = uniformVars[fieldIndex];
168 
169         TType *replacementType = new TType(variable->getType());
170         replacementType->setInterfaceBlockField(uniformBlock->getType().getInterfaceBlock(),
171                                                 fieldIndex);
172 
173         TVariable *replacementVariable =
174             new TVariable(symbolTable, variable->name(), replacementType, variable->symbolType());
175 
176         variableMap[variable] = new TIntermSymbol(replacementVariable);
177     }
178 
179     // Finally transform the AST and make sure references to the uniforms are replaced with the new
180     // variables.
181     ReplaceDefaultUniformsTraverser defaultTraverser(variableMap);
182     root->traverse(&defaultTraverser);
183     return defaultTraverser.updateTree(compiler, root);
184 }
185 
186 // Replaces a builtin variable with a version that is rotated and corrects the X and Y coordinates.
RotateAndFlipBuiltinVariable(TCompiler * compiler,TIntermBlock * root,TIntermSequence * insertSequence,TIntermTyped * swapXY,TIntermTyped * flipXY,TSymbolTable * symbolTable,const TVariable * builtin,const ImmutableString & flippedVariableName,TIntermTyped * pivot)187 [[nodiscard]] bool RotateAndFlipBuiltinVariable(TCompiler *compiler,
188                                                 TIntermBlock *root,
189                                                 TIntermSequence *insertSequence,
190                                                 TIntermTyped *swapXY,
191                                                 TIntermTyped *flipXY,
192                                                 TSymbolTable *symbolTable,
193                                                 const TVariable *builtin,
194                                                 const ImmutableString &flippedVariableName,
195                                                 TIntermTyped *pivot)
196 {
197     // Create a symbol reference to 'builtin'.
198     TIntermSymbol *builtinRef = new TIntermSymbol(builtin);
199 
200     // Create a symbol reference to our new variable that will hold the modified builtin.
201     TType *type = new TType(builtin->getType());
202     type->setQualifier(EvqGlobal);
203     type->setPrimarySize(builtin->getType().getNominalSize());
204     TVariable *replacementVar =
205         new TVariable(symbolTable, flippedVariableName, type, SymbolType::AngleInternal);
206     DeclareGlobalVariable(root, replacementVar);
207     TIntermSymbol *flippedBuiltinRef = new TIntermSymbol(replacementVar);
208 
209     // Use this new variable instead of 'builtin' everywhere.
210     if (!ReplaceVariable(compiler, root, builtin, replacementVar))
211     {
212         return false;
213     }
214 
215     // Create the expression "(swapXY ? builtin.yx : builtin.xy)"
216     TIntermTyped *builtinXY = new TIntermSwizzle(builtinRef, {0, 1});
217     TIntermTyped *builtinYX = new TIntermSwizzle(builtinRef->deepCopy(), {1, 0});
218 
219     builtinXY = new TIntermTernary(swapXY, builtinYX, builtinXY);
220 
221     // Create the expression "(builtin.xy - pivot) * flipXY + pivot
222     TIntermBinary *removePivot = new TIntermBinary(EOpSub, builtinXY, pivot);
223     TIntermBinary *inverseXY   = new TIntermBinary(EOpMul, removePivot, flipXY);
224     TIntermBinary *plusPivot   = new TIntermBinary(EOpAdd, inverseXY, pivot->deepCopy());
225 
226     // Create the corrected variable and copy the value of the original builtin.
227     TIntermBinary *assignment =
228         new TIntermBinary(EOpAssign, flippedBuiltinRef, builtinRef->deepCopy());
229 
230     // Create an assignment to the replaced variable's .xy.
231     TIntermSwizzle *correctedXY = new TIntermSwizzle(flippedBuiltinRef->deepCopy(), {0, 1});
232     TIntermBinary *assignToXY   = new TIntermBinary(EOpAssign, correctedXY, plusPivot);
233 
234     // Add this assigment at the beginning of the main function
235     insertSequence->insert(insertSequence->begin(), assignToXY);
236     insertSequence->insert(insertSequence->begin(), assignment);
237 
238     return compiler->validateAST(root);
239 }
240 
GetMainSequence(TIntermBlock * root)241 TIntermSequence *GetMainSequence(TIntermBlock *root)
242 {
243     TIntermFunctionDefinition *main = FindMain(root);
244     return main->getBody()->getSequence();
245 }
246 
247 // Declares a new variable to replace gl_DepthRange, its values are fed from a driver uniform.
ReplaceGLDepthRangeWithDriverUniform(TCompiler * compiler,TIntermBlock * root,const DriverUniform * driverUniforms,TSymbolTable * symbolTable)248 [[nodiscard]] bool ReplaceGLDepthRangeWithDriverUniform(TCompiler *compiler,
249                                                         TIntermBlock *root,
250                                                         const DriverUniform *driverUniforms,
251                                                         TSymbolTable *symbolTable)
252 {
253     // Create a symbol reference to "gl_DepthRange"
254     const TVariable *depthRangeVar = static_cast<const TVariable *>(
255         symbolTable->findBuiltIn(ImmutableString("gl_DepthRange"), 0));
256 
257     // ANGLEUniforms.depthRange
258     TIntermTyped *angleEmulatedDepthRangeRef = driverUniforms->getDepthRange();
259 
260     // Use this variable instead of gl_DepthRange everywhere.
261     return ReplaceVariableWithTyped(compiler, root, depthRangeVar, angleEmulatedDepthRangeRef);
262 }
263 
264 // Declares a new variable to replace gl_BoundingBoxEXT, its values are fed from a global temporary
265 // variable.
ReplaceGLBoundingBoxWithGlobal(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,int shaderVersion)266 [[nodiscard]] bool ReplaceGLBoundingBoxWithGlobal(TCompiler *compiler,
267                                                   TIntermBlock *root,
268                                                   TSymbolTable *symbolTable,
269                                                   int shaderVersion)
270 {
271     // Declare the replacement bounding box variable type
272     TType *emulatedBoundingBoxDeclType = new TType(EbtFloat, EbpHigh, EvqGlobal, 4);
273     emulatedBoundingBoxDeclType->makeArray(2u);
274 
275     TVariable *ANGLEBoundingBoxVar = new TVariable(
276         symbolTable->nextUniqueId(), ImmutableString("ANGLEBoundingBox"), SymbolType::AngleInternal,
277         TExtension::EXT_primitive_bounding_box, emulatedBoundingBoxDeclType);
278 
279     DeclareGlobalVariable(root, ANGLEBoundingBoxVar);
280 
281     const TVariable *builtinBoundingBoxVar;
282     bool replacementResult = true;
283 
284     // Create a symbol reference to "gl_BoundingBoxEXT"
285     builtinBoundingBoxVar = static_cast<const TVariable *>(
286         symbolTable->findBuiltIn(ImmutableString("gl_BoundingBoxEXT"), shaderVersion));
287     if (builtinBoundingBoxVar != nullptr)
288     {
289         // Use the replacement variable instead of builtin gl_BoundingBoxEXT everywhere.
290         replacementResult &=
291             ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
292     }
293 
294     // Create a symbol reference to "gl_BoundingBoxOES"
295     builtinBoundingBoxVar = static_cast<const TVariable *>(
296         symbolTable->findBuiltIn(ImmutableString("gl_BoundingBoxOES"), shaderVersion));
297     if (builtinBoundingBoxVar != nullptr)
298     {
299         // Use the replacement variable instead of builtin gl_BoundingBoxOES everywhere.
300         replacementResult &=
301             ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
302     }
303 
304     if (shaderVersion >= 320)
305     {
306         // Create a symbol reference to "gl_BoundingBox"
307         builtinBoundingBoxVar = static_cast<const TVariable *>(
308             symbolTable->findBuiltIn(ImmutableString("gl_BoundingBox"), shaderVersion));
309         if (builtinBoundingBoxVar != nullptr)
310         {
311             // Use the replacement variable instead of builtin gl_BoundingBox everywhere.
312             replacementResult &=
313                 ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
314         }
315     }
316     return replacementResult;
317 }
318 
AddXfbEmulationSupport(TranslatorSPIRV * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const DriverUniform * driverUniforms)319 [[nodiscard]] bool AddXfbEmulationSupport(TranslatorSPIRV *compiler,
320                                           TIntermBlock *root,
321                                           TSymbolTable *symbolTable,
322                                           const DriverUniform *driverUniforms)
323 {
324     // Generate the following function and place it before main().  This function takes a "strides"
325     // parameter that is determined at link time, and calculates for each transform feedback buffer
326     // (of which there are a maximum of four) what the starting index is to write to the output
327     // buffer.
328     //
329     //     ivec4 ANGLEGetXfbOffsets(ivec4 strides)
330     //     {
331     //         int xfbIndex = gl_VertexIndex
332     //                      + gl_InstanceIndex * ANGLEUniforms.xfbVerticesPerInstance;
333     //         return ANGLEUniforms.xfbBufferOffsets + xfbIndex * strides;
334     //     }
335 
336     constexpr uint32_t kMaxXfbBuffers = 4;
337 
338     const TType *ivec4Type = StaticType::GetBasic<EbtInt, EbpHigh, kMaxXfbBuffers>();
339     TType *stridesType     = new TType(*ivec4Type);
340     stridesType->setQualifier(EvqParamConst);
341 
342     // Create the parameter variable.
343     TVariable *stridesVar = new TVariable(symbolTable, ImmutableString("strides"), stridesType,
344                                           SymbolType::AngleInternal);
345     TIntermSymbol *stridesSymbol = new TIntermSymbol(stridesVar);
346 
347     // Create references to gl_VertexIndex, gl_InstanceIndex, ANGLEUniforms.xfbVerticesPerInstance
348     // and ANGLEUniforms.xfbBufferOffsets.
349     TIntermSymbol *vertexIndex           = new TIntermSymbol(BuiltInVariable::gl_VertexIndex());
350     TIntermSymbol *instanceIndex         = new TIntermSymbol(BuiltInVariable::gl_InstanceIndex());
351     TIntermTyped *xfbVerticesPerInstance = driverUniforms->getXfbVerticesPerInstance();
352     TIntermTyped *xfbBufferOffsets       = driverUniforms->getXfbBufferOffsets();
353 
354     // gl_InstanceIndex * ANGLEUniforms.xfbVerticesPerInstance
355     TIntermBinary *xfbInstanceIndex =
356         new TIntermBinary(EOpMul, instanceIndex, xfbVerticesPerInstance);
357 
358     // gl_VertexIndex + |xfbInstanceIndex|
359     TIntermBinary *xfbIndex = new TIntermBinary(EOpAdd, vertexIndex, xfbInstanceIndex);
360 
361     // |xfbIndex| * |strides|
362     TIntermBinary *xfbStrides = new TIntermBinary(EOpVectorTimesScalar, xfbIndex, stridesSymbol);
363 
364     // ANGLEUniforms.xfbBufferOffsets + |xfbStrides|
365     TIntermBinary *xfbOffsets = new TIntermBinary(EOpAdd, xfbBufferOffsets, xfbStrides);
366 
367     // Create the function body, which has a single return statement.  Note that the `xfbIndex`
368     // variable declared in the comment at the beginning of this function is simply replaced in the
369     // return statement for brevity.
370     TIntermBlock *body = new TIntermBlock;
371     body->appendStatement(new TIntermBranch(EOpReturn, xfbOffsets));
372 
373     // Declare the function
374     TFunction *getOffsetsFunction =
375         new TFunction(symbolTable, ImmutableString("ANGLEGetXfbOffsets"), SymbolType::AngleInternal,
376                       ivec4Type, true);
377     getOffsetsFunction->addParameter(stridesVar);
378 
379     compiler->assignSpirvId(getOffsetsFunction->uniqueId(),
380                             vk::spirv::kIdXfbEmulationGetOffsetsFunction);
381 
382     TIntermFunctionDefinition *functionDef =
383         CreateInternalFunctionDefinitionNode(*getOffsetsFunction, body);
384 
385     // Insert the function declaration before main().
386     const size_t mainIndex = FindMainIndex(root);
387     root->insertChildNodes(mainIndex, {functionDef});
388 
389     // Generate the following function and place it before main().  This function will be filled
390     // with transform feedback capture code at link time.
391     //
392     //     void ANGLECaptureXfb()
393     //     {
394     //     }
395     const TType *voidType = StaticType::GetBasic<EbtVoid, EbpUndefined>();
396 
397     // Create the function body, which is empty.
398     body = new TIntermBlock;
399 
400     // Declare the function
401     TFunction *xfbCaptureFunction = new TFunction(symbolTable, ImmutableString("ANGLECaptureXfb"),
402                                                   SymbolType::AngleInternal, voidType, false);
403 
404     compiler->assignSpirvId(xfbCaptureFunction->uniqueId(),
405                             vk::spirv::kIdXfbEmulationCaptureFunction);
406 
407     // Insert the function declaration before main().
408     root->insertChildNodes(mainIndex,
409                            {CreateInternalFunctionDefinitionNode(*xfbCaptureFunction, body)});
410 
411     // Create the following logic and add it at the end of main():
412     //
413     //     ANGLECaptureXfb();
414     //
415 
416     // Create the function call
417     TIntermAggregate *captureXfbCall =
418         TIntermAggregate::CreateFunctionCall(*xfbCaptureFunction, {});
419 
420     // Run it at the end of the shader.
421     if (!RunAtTheEndOfShader(compiler, root, captureXfbCall, symbolTable))
422     {
423         return false;
424     }
425 
426     // Additionally, generate the following storage buffer declarations used to capture transform
427     // feedback output.  Again, there's a maximum of four buffers.
428     //
429     //     buffer ANGLEXfbBuffer0
430     //     {
431     //         float xfbOut[];
432     //     } ANGLEXfb0;
433     //     buffer ANGLEXfbBuffer1
434     //     {
435     //         float xfbOut[];
436     //     } ANGLEXfb1;
437     //     ...
438 
439     for (uint32_t bufferIndex = 0; bufferIndex < kMaxXfbBuffers; ++bufferIndex)
440     {
441         TFieldList *fieldList = new TFieldList;
442         TType *xfbOutType     = new TType(EbtFloat, EbpHigh, EvqGlobal);
443         xfbOutType->makeArray(0);
444 
445         TField *field = new TField(xfbOutType, ImmutableString("xfbOut"), TSourceLoc(),
446                                    SymbolType::AngleInternal);
447 
448         fieldList->push_back(field);
449 
450         static_assert(
451             kMaxXfbBuffers < 10,
452             "ImmutableStringBuilder memory size below needs to accomodate the number of buffers");
453 
454         ImmutableString blockName = BuildConcatenatedImmutableString("ANGLEXfbBuffer", bufferIndex);
455         ImmutableString varName   = BuildConcatenatedImmutableString("ANGLEXfb", bufferIndex);
456 
457         TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
458         layoutQualifier.blockStorage     = EbsStd430;
459 
460         const TVariable *xfbBuffer =
461             DeclareInterfaceBlock(root, symbolTable, fieldList, EvqBuffer, layoutQualifier,
462                                   TMemoryQualifier::Create(), 0, blockName, varName);
463 
464         static_assert(vk::spirv::kIdXfbEmulationBufferBlockOne ==
465                       vk::spirv::kIdXfbEmulationBufferBlockZero + 1);
466         static_assert(vk::spirv::kIdXfbEmulationBufferBlockTwo ==
467                       vk::spirv::kIdXfbEmulationBufferBlockZero + 2);
468         static_assert(vk::spirv::kIdXfbEmulationBufferBlockThree ==
469                       vk::spirv::kIdXfbEmulationBufferBlockZero + 3);
470 
471         static_assert(vk::spirv::kIdXfbEmulationBufferVarOne ==
472                       vk::spirv::kIdXfbEmulationBufferVarZero + 1);
473         static_assert(vk::spirv::kIdXfbEmulationBufferVarTwo ==
474                       vk::spirv::kIdXfbEmulationBufferVarZero + 2);
475         static_assert(vk::spirv::kIdXfbEmulationBufferVarThree ==
476                       vk::spirv::kIdXfbEmulationBufferVarZero + 3);
477 
478         compiler->assignSpirvId(xfbBuffer->getType().getInterfaceBlock()->uniqueId(),
479                                 vk::spirv::kIdXfbEmulationBufferBlockZero + bufferIndex);
480         compiler->assignSpirvId(xfbBuffer->uniqueId(),
481                                 vk::spirv::kIdXfbEmulationBufferVarZero + bufferIndex);
482     }
483 
484     return compiler->validateAST(root);
485 }
486 
AddXfbExtensionSupport(TranslatorSPIRV * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const DriverUniform * driverUniforms)487 [[nodiscard]] bool AddXfbExtensionSupport(TranslatorSPIRV *compiler,
488                                           TIntermBlock *root,
489                                           TSymbolTable *symbolTable,
490                                           const DriverUniform *driverUniforms)
491 {
492     // Generate the following output varying declaration used to capture transform feedback output
493     // from gl_Position, as it can't be captured directly due to changes that are applied to it for
494     // clip-space correction and pre-rotation.
495     //
496     //     out vec4 ANGLEXfbPosition;
497 
498     const TType *vec4Type = nullptr;
499 
500     switch (compiler->getShaderType())
501     {
502         case GL_VERTEX_SHADER:
503             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqVertexOut, 4, 1>();
504             break;
505         case GL_TESS_EVALUATION_SHADER_EXT:
506             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqTessEvaluationOut, 4, 1>();
507             break;
508         case GL_GEOMETRY_SHADER_EXT:
509             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqGeometryOut, 4, 1>();
510             break;
511         default:
512             UNREACHABLE();
513     }
514 
515     TVariable *varyingVar = new TVariable(symbolTable, ImmutableString("ANGLEXfbPosition"),
516                                           vec4Type, SymbolType::AngleInternal);
517 
518     compiler->assignSpirvId(varyingVar->uniqueId(), vk::spirv::kIdXfbExtensionPosition);
519 
520     TIntermDeclaration *varyingDecl = new TIntermDeclaration();
521     varyingDecl->appendDeclarator(new TIntermSymbol(varyingVar));
522 
523     // Insert the varying declaration before the first function.
524     const size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
525     root->insertChildNodes(firstFunctionIndex, {varyingDecl});
526 
527     return compiler->validateAST(root);
528 }
529 
AddVertexTransformationSupport(TranslatorSPIRV * compiler,const ShCompileOptions & compileOptions,TIntermBlock * root,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms)530 [[nodiscard]] bool AddVertexTransformationSupport(TranslatorSPIRV *compiler,
531                                                   const ShCompileOptions &compileOptions,
532                                                   TIntermBlock *root,
533                                                   TSymbolTable *symbolTable,
534                                                   SpecConst *specConst,
535                                                   const DriverUniform *driverUniforms)
536 {
537     // In GL the viewport transformation is slightly different - see the GL 2.0 spec section "2.12.1
538     // Controlling the Viewport".  In Vulkan the corresponding spec section is currently "23.4.
539     // Coordinate Transformations".  The following transformation needs to be done:
540     //
541     //     z_vk = 0.5 * (w_gl + z_gl)
542     //
543     // where z_vk is the depth output of a Vulkan geometry-stage shader and z_gl is the same for GL.
544     //
545     // Generate the following function and place it before main().  This function takes
546     // gl_Position and rotates xy, and adjusts z (if necessary).
547     //
548     //     vec4 ANGLETransformPosition(vec4 position)
549     //     {
550     //         return vec4((swapXY ? position.yx : position.xy) * flipXY,
551     //                     transformDepth ? (gl_Position.z + gl_Position.w) / 2 : gl_Position.z,
552     //                     gl_Postion.w);
553     //     }
554 
555     const TType *vec4Type = StaticType::GetBasic<EbtFloat, EbpHigh, 4>();
556     TType *positionType   = new TType(*vec4Type);
557     positionType->setQualifier(EvqParamConst);
558 
559     // Create the parameter variable.
560     TVariable *positionVar = new TVariable(symbolTable, ImmutableString("position"), positionType,
561                                            SymbolType::AngleInternal);
562     TIntermSymbol *positionSymbol = new TIntermSymbol(positionVar);
563 
564     // swapXY ? position.yx : position.xy
565     TIntermTyped *swapXY = specConst->getSwapXY();
566     if (swapXY == nullptr)
567     {
568         swapXY = driverUniforms->getSwapXY();
569     }
570 
571     TIntermTyped *xy        = new TIntermSwizzle(positionSymbol, {0, 1});
572     TIntermTyped *swappedXY = new TIntermSwizzle(positionSymbol->deepCopy(), {1, 0});
573     TIntermTyped *rotatedXY = new TIntermTernary(swapXY, swappedXY, xy);
574 
575     // (swapXY ? position.yx : position.xy) * flipXY
576     TIntermTyped *flipXY = driverUniforms->getFlipXY(symbolTable, DriverUniformFlip::PreFragment);
577     TIntermTyped *rotatedFlippedXY = new TIntermBinary(EOpMul, rotatedXY, flipXY);
578 
579     // (gl_Position.z + gl_Position.w) / 2
580     TIntermTyped *z = new TIntermSwizzle(positionSymbol->deepCopy(), {2});
581     TIntermTyped *w = new TIntermSwizzle(positionSymbol->deepCopy(), {3});
582 
583     TIntermTyped *transformedDepth = z;
584     if (compileOptions.addVulkanDepthCorrection)
585     {
586         TIntermBinary *zPlusW = new TIntermBinary(EOpAdd, z, w->deepCopy());
587         TIntermBinary *halfZPlusW =
588             new TIntermBinary(EOpMul, zPlusW, CreateFloatNode(0.5, EbpMedium));
589 
590         // transformDepth ? (gl_Position.z + gl_Position.w) / 2 : gl_Position.z,
591         TIntermTyped *transformDepth = driverUniforms->getTransformDepth();
592         transformedDepth = new TIntermTernary(transformDepth, halfZPlusW, z->deepCopy());
593     }
594 
595     // vec4(...);
596     TIntermSequence args = {
597         rotatedFlippedXY,
598         transformedDepth,
599         w,
600     };
601     TIntermTyped *transformedPosition = TIntermAggregate::CreateConstructor(*vec4Type, &args);
602 
603     // Create the function body, which has a single return statement.
604     TIntermBlock *body = new TIntermBlock;
605     body->appendStatement(new TIntermBranch(EOpReturn, transformedPosition));
606 
607     // Declare the function
608     TFunction *transformPositionFunction =
609         new TFunction(symbolTable, ImmutableString("ANGLETransformPosition"),
610                       SymbolType::AngleInternal, vec4Type, true);
611     transformPositionFunction->addParameter(positionVar);
612 
613     compiler->assignSpirvId(transformPositionFunction->uniqueId(),
614                             vk::spirv::kIdTransformPositionFunction);
615 
616     TIntermFunctionDefinition *functionDef =
617         CreateInternalFunctionDefinitionNode(*transformPositionFunction, body);
618 
619     // Insert the function declaration before main().
620     const size_t mainIndex = FindMainIndex(root);
621     root->insertChildNodes(mainIndex, {functionDef});
622 
623     return compiler->validateAST(root);
624 }
625 
InsertFragCoordCorrection(TCompiler * compiler,const ShCompileOptions & compileOptions,TIntermBlock * root,TIntermSequence * insertSequence,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms)626 [[nodiscard]] bool InsertFragCoordCorrection(TCompiler *compiler,
627                                              const ShCompileOptions &compileOptions,
628                                              TIntermBlock *root,
629                                              TIntermSequence *insertSequence,
630                                              TSymbolTable *symbolTable,
631                                              SpecConst *specConst,
632                                              const DriverUniform *driverUniforms)
633 {
634     TIntermTyped *flipXY = driverUniforms->getFlipXY(symbolTable, DriverUniformFlip::Fragment);
635     TIntermTyped *pivot  = driverUniforms->getHalfRenderArea();
636 
637     TIntermTyped *swapXY = specConst->getSwapXY();
638     if (swapXY == nullptr)
639     {
640         swapXY = driverUniforms->getSwapXY();
641     }
642 
643     const TVariable *fragCoord = static_cast<const TVariable *>(
644         symbolTable->findBuiltIn(ImmutableString("gl_FragCoord"), compiler->getShaderVersion()));
645     return RotateAndFlipBuiltinVariable(compiler, root, insertSequence, swapXY, flipXY, symbolTable,
646                                         fragCoord, kFlippedFragCoordName, pivot);
647 }
648 
HasFramebufferFetch(const TExtensionBehavior & extBehavior,const ShCompileOptions & compileOptions)649 bool HasFramebufferFetch(const TExtensionBehavior &extBehavior,
650                          const ShCompileOptions &compileOptions)
651 {
652     return IsExtensionEnabled(extBehavior, TExtension::EXT_shader_framebuffer_fetch) ||
653            IsExtensionEnabled(extBehavior, TExtension::EXT_shader_framebuffer_fetch_non_coherent) ||
654            IsExtensionEnabled(extBehavior, TExtension::ARM_shader_framebuffer_fetch) ||
655            IsExtensionEnabled(extBehavior,
656                               TExtension::ARM_shader_framebuffer_fetch_depth_stencil) ||
657            IsExtensionEnabled(extBehavior, TExtension::NV_shader_framebuffer_fetch) ||
658            (compileOptions.pls.type == ShPixelLocalStorageType::FramebufferFetch &&
659             IsExtensionEnabled(extBehavior, TExtension::ANGLE_shader_pixel_local_storage));
660 }
661 
662 template <typename Variable>
FindShaderVariable(std::vector<Variable> * vars,const ImmutableString & name)663 Variable *FindShaderVariable(std::vector<Variable> *vars, const ImmutableString &name)
664 {
665     for (Variable &var : *vars)
666     {
667         if (name == var.name)
668         {
669             return &var;
670         }
671     }
672     UNREACHABLE();
673     return nullptr;
674 }
675 
FindIOBlockShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name)676 ShaderVariable *FindIOBlockShaderVariable(std::vector<ShaderVariable> *vars,
677                                           const ImmutableString &name)
678 {
679     for (ShaderVariable &var : *vars)
680     {
681         if (name == var.structOrBlockName)
682         {
683             return &var;
684         }
685     }
686     UNREACHABLE();
687     return nullptr;
688 }
689 
FindUniformFieldShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name,const char * prefix)690 ShaderVariable *FindUniformFieldShaderVariable(std::vector<ShaderVariable> *vars,
691                                                const ImmutableString &name,
692                                                const char *prefix)
693 {
694     for (ShaderVariable &var : *vars)
695     {
696         // The name of the sampler is derived from the uniform name + fields
697         // that reach the uniform, concatenated with '_' per RewriteStructSamplers.
698         std::string varName = prefix;
699         varName += '_';
700         varName += var.name;
701 
702         if (name == varName)
703         {
704             return &var;
705         }
706 
707         ShaderVariable *field = FindUniformFieldShaderVariable(&var.fields, name, varName.c_str());
708         if (field != nullptr)
709         {
710             return field;
711         }
712     }
713     return nullptr;
714 }
715 
FindUniformShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name)716 ShaderVariable *FindUniformShaderVariable(std::vector<ShaderVariable> *vars,
717                                           const ImmutableString &name)
718 {
719     for (ShaderVariable &var : *vars)
720     {
721         if (name == var.name)
722         {
723             return &var;
724         }
725 
726         // Note: samplers in structs are moved out.  Such samplers will be found in the fields of
727         // the struct uniform.
728         ShaderVariable *field = FindUniformFieldShaderVariable(&var.fields, name, var.name.c_str());
729         if (field != nullptr)
730         {
731             return field;
732         }
733     }
734     UNREACHABLE();
735     return nullptr;
736 }
737 
SetSpirvIdInFields(uint32_t id,std::vector<ShaderVariable> * fields)738 void SetSpirvIdInFields(uint32_t id, std::vector<ShaderVariable> *fields)
739 {
740     for (ShaderVariable &field : *fields)
741     {
742         field.id = id;
743         SetSpirvIdInFields(id, &field.fields);
744     }
745 }
746 }  // anonymous namespace
747 
TranslatorSPIRV(sh::GLenum type,ShShaderSpec spec)748 TranslatorSPIRV::TranslatorSPIRV(sh::GLenum type, ShShaderSpec spec)
749     : TCompiler(type, spec, SH_SPIRV_VULKAN_OUTPUT), mFirstUnusedSpirvId(0)
750 {}
751 
translateImpl(TIntermBlock * root,const ShCompileOptions & compileOptions,PerformanceDiagnostics *,SpecConst * specConst,DriverUniform * driverUniforms)752 bool TranslatorSPIRV::translateImpl(TIntermBlock *root,
753                                     const ShCompileOptions &compileOptions,
754                                     PerformanceDiagnostics * /*perfDiagnostics*/,
755                                     SpecConst *specConst,
756                                     DriverUniform *driverUniforms)
757 {
758     if (getShaderType() == GL_VERTEX_SHADER)
759     {
760         if (!ShaderBuiltinsWorkaround(this, root, &getSymbolTable(), compileOptions))
761         {
762             return false;
763         }
764     }
765 
766     // Write out default uniforms into a uniform block assigned to a specific set/binding.
767     int defaultUniformCount           = 0;
768     int aggregateTypesUsedForUniforms = 0;
769     int r32fImageCount                = 0;
770     int atomicCounterCount            = 0;
771     for (const auto &uniform : getUniforms())
772     {
773         if (!uniform.isBuiltIn() && uniform.active && !gl::IsOpaqueType(uniform.type))
774         {
775             ++defaultUniformCount;
776         }
777 
778         if (uniform.isStruct() || uniform.isArrayOfArrays())
779         {
780             ++aggregateTypesUsedForUniforms;
781         }
782 
783         if (uniform.active && gl::IsImageType(uniform.type) && uniform.imageUnitFormat == GL_R32F)
784         {
785             ++r32fImageCount;
786         }
787 
788         if (uniform.active && gl::IsAtomicCounterType(uniform.type))
789         {
790             ++atomicCounterCount;
791         }
792     }
793 
794     // Remove declarations of inactive shader interface variables so SPIR-V transformer doesn't need
795     // to replace them.  Note that currently, CollectVariables marks every field of an active
796     // uniform that's of struct type as active, i.e. no extracted sampler is inactive, so this can
797     // be done before extracting samplers from structs.
798     if (!RemoveInactiveInterfaceVariables(this, root, &getSymbolTable(), getAttributes(),
799                                           getInputVaryings(), getOutputVariables(), getUniforms(),
800                                           getInterfaceBlocks(), true))
801     {
802         return false;
803     }
804 
805     // If there are any function calls that take array-of-array of opaque uniform parameters, or
806     // other opaque uniforms that need special handling in Vulkan, such as atomic counters,
807     // monomorphize the functions by removing said parameters and replacing them in the function
808     // body with the call arguments.
809     //
810     // This has a few benefits:
811     //
812     // - It dramatically simplifies future transformations w.r.t to samplers in structs, array of
813     //   arrays of opaque types, atomic counters etc.
814     // - Avoids the need for shader*ArrayDynamicIndexing Vulkan features.
815     UnsupportedFunctionArgsBitSet args{UnsupportedFunctionArgs::StructContainingSamplers,
816                                        UnsupportedFunctionArgs::ArrayOfArrayOfSamplerOrImage,
817                                        UnsupportedFunctionArgs::AtomicCounter,
818                                        UnsupportedFunctionArgs::Image};
819     if (!MonomorphizeUnsupportedFunctions(this, root, &getSymbolTable(), args))
820     {
821         return false;
822     }
823 
824     if (aggregateTypesUsedForUniforms > 0)
825     {
826         if (!SeparateStructFromUniformDeclarations(this, root, &getSymbolTable()))
827         {
828             return false;
829         }
830 
831         int removedUniformsCount;
832 
833         if (!RewriteStructSamplers(this, root, &getSymbolTable(), &removedUniformsCount))
834         {
835             return false;
836         }
837         defaultUniformCount -= removedUniformsCount;
838     }
839 
840     // Replace array of array of opaque uniforms with a flattened array.  This is run after
841     // MonomorphizeUnsupportedFunctions and RewriteStructSamplers so that it's not possible for an
842     // array of array of opaque type to be partially subscripted and passed to a function.
843     if (!RewriteArrayOfArrayOfOpaqueUniforms(this, root, &getSymbolTable()))
844     {
845         return false;
846     }
847 
848     if (!FlagSamplersForTexelFetch(this, root, &getSymbolTable(), &mUniforms))
849     {
850         return false;
851     }
852 
853     gl::ShaderType packedShaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
854 
855     if (defaultUniformCount > 0)
856     {
857         if (!DeclareDefaultUniforms(this, root, &getSymbolTable(), packedShaderType))
858         {
859             return false;
860         }
861     }
862 
863     if (getShaderType() == GL_COMPUTE_SHADER)
864     {
865         driverUniforms->addComputeDriverUniformsToShader(root, &getSymbolTable());
866     }
867     else
868     {
869         driverUniforms->addGraphicsDriverUniformsToShader(root, &getSymbolTable());
870     }
871 
872     assignSpirvId(
873         driverUniforms->getDriverUniformsVariable()->getType().getInterfaceBlock()->uniqueId(),
874         vk::spirv::kIdDriverUniformsBlock);
875 
876     if (r32fImageCount > 0 && compileOptions.emulateR32fImageAtomicExchange)
877     {
878         if (!RewriteR32fImages(this, root, &getSymbolTable()))
879         {
880             return false;
881         }
882     }
883 
884     if (atomicCounterCount > 0)
885     {
886         // ANGLEUniforms.acbBufferOffsets
887         const TIntermTyped *acbBufferOffsets = driverUniforms->getAcbBufferOffsets();
888         const TVariable *atomicCounters      = nullptr;
889         if (!RewriteAtomicCounters(this, root, &getSymbolTable(), acbBufferOffsets,
890                                    &atomicCounters))
891         {
892             return false;
893         }
894         assignSpirvId(atomicCounters->getType().getInterfaceBlock()->uniqueId(),
895                       vk::spirv::kIdAtomicCounterBlock);
896     }
897     else if (getShaderVersion() >= 310)
898     {
899         // Vulkan doesn't support Atomic Storage as a Storage Class, but we've seen
900         // cases where builtins are using it even with no active atomic counters.
901         // This pass simply removes those builtins in that scenario.
902         if (!RemoveAtomicCounterBuiltins(this, root))
903         {
904             return false;
905         }
906     }
907 
908     if (packedShaderType != gl::ShaderType::Compute)
909     {
910         if (!ReplaceGLDepthRangeWithDriverUniform(this, root, driverUniforms, &getSymbolTable()))
911         {
912             return false;
913         }
914 
915         // Search for the gl_ClipDistance/gl_CullDistance usage, if its used, we need to do some
916         // replacements.
917         bool useClipDistance = false;
918         bool useCullDistance = false;
919         for (const ShaderVariable &outputVarying : mOutputVaryings)
920         {
921             if (outputVarying.name == "gl_ClipDistance")
922             {
923                 useClipDistance = true;
924             }
925             else if (outputVarying.name == "gl_CullDistance")
926             {
927                 useCullDistance = true;
928             }
929         }
930         for (const ShaderVariable &inputVarying : mInputVaryings)
931         {
932             if (inputVarying.name == "gl_ClipDistance")
933             {
934                 useClipDistance = true;
935             }
936             else if (inputVarying.name == "gl_CullDistance")
937             {
938                 useCullDistance = true;
939             }
940         }
941 
942         if (useClipDistance &&
943             !ReplaceClipDistanceAssignments(this, root, &getSymbolTable(), getShaderType(),
944                                             driverUniforms->getClipDistancesEnabled()))
945         {
946             return false;
947         }
948         if (useCullDistance &&
949             !ReplaceCullDistanceAssignments(this, root, &getSymbolTable(), getShaderType()))
950         {
951             return false;
952         }
953     }
954 
955     if (gl::ShaderTypeSupportsTransformFeedback(packedShaderType))
956     {
957         if (compileOptions.addVulkanXfbExtensionSupportCode)
958         {
959             // Add support code for transform feedback extension.
960             if (!AddXfbExtensionSupport(this, root, &getSymbolTable(), driverUniforms))
961             {
962                 return false;
963             }
964         }
965 
966         // Add support code for pre-rotation and depth correction in the vertex processing stages.
967         if (!AddVertexTransformationSupport(this, compileOptions, root, &getSymbolTable(),
968                                             specConst, driverUniforms))
969         {
970             return false;
971         }
972     }
973 
974     switch (packedShaderType)
975     {
976         case gl::ShaderType::Fragment:
977         {
978             bool usesPointCoord    = false;
979             bool usesFragCoord     = false;
980             bool usesSampleMaskIn  = false;
981             bool useSamplePosition = false;
982 
983             // Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate.
984             for (const ShaderVariable &inputVarying : mInputVaryings)
985             {
986                 if (!inputVarying.isBuiltIn())
987                 {
988                     continue;
989                 }
990 
991                 if (inputVarying.name == "gl_SampleMaskIn")
992                 {
993                     usesSampleMaskIn = true;
994                     continue;
995                 }
996 
997                 if (inputVarying.name == "gl_SamplePosition")
998                 {
999                     useSamplePosition = true;
1000                     continue;
1001                 }
1002 
1003                 if (inputVarying.name == "gl_PointCoord")
1004                 {
1005                     usesPointCoord = true;
1006                     break;
1007                 }
1008 
1009                 if (inputVarying.name == "gl_FragCoord")
1010                 {
1011                     usesFragCoord = true;
1012                     break;
1013                 }
1014             }
1015 
1016             bool hasGLSampleMask           = false;
1017             bool hasGLSecondaryFragData    = false;
1018             const TIntermSymbol *yuvOutput = nullptr;
1019 
1020             for (const ShaderVariable &outputVar : mOutputVariables)
1021             {
1022                 if (outputVar.name == "gl_SampleMask")
1023                 {
1024                     ASSERT(!hasGLSampleMask);
1025                     hasGLSampleMask = true;
1026                     continue;
1027                 }
1028                 if (outputVar.name == "gl_SecondaryFragDataEXT")
1029                 {
1030                     ASSERT(!hasGLSecondaryFragData);
1031                     hasGLSecondaryFragData = true;
1032                     continue;
1033                 }
1034                 if (outputVar.yuv)
1035                 {
1036                     // We can only have one yuv output
1037                     ASSERT(yuvOutput == nullptr);
1038                     yuvOutput = FindSymbolNode(root, ImmutableString(outputVar.name));
1039                     continue;
1040                 }
1041             }
1042 
1043             if (usesPointCoord)
1044             {
1045                 TIntermTyped *flipNegXY =
1046                     driverUniforms->getNegFlipXY(&getSymbolTable(), DriverUniformFlip::Fragment);
1047                 TIntermConstantUnion *pivot = CreateFloatNode(0.5f, EbpMedium);
1048                 TIntermTyped *swapXY        = specConst->getSwapXY();
1049                 if (swapXY == nullptr)
1050                 {
1051                     swapXY = driverUniforms->getSwapXY();
1052                 }
1053                 if (!RotateAndFlipBuiltinVariable(
1054                         this, root, GetMainSequence(root), swapXY, flipNegXY, &getSymbolTable(),
1055                         BuiltInVariable::gl_PointCoord(), kFlippedPointCoordName, pivot))
1056                 {
1057                     return false;
1058                 }
1059             }
1060 
1061             if (useSamplePosition)
1062             {
1063                 TIntermTyped *flipXY =
1064                     driverUniforms->getFlipXY(&getSymbolTable(), DriverUniformFlip::Fragment);
1065                 TIntermConstantUnion *pivot = CreateFloatNode(0.5f, EbpMedium);
1066                 TIntermTyped *swapXY        = specConst->getSwapXY();
1067                 if (swapXY == nullptr)
1068                 {
1069                     swapXY = driverUniforms->getSwapXY();
1070                 }
1071 
1072                 const TVariable *samplePositionBuiltin =
1073                     static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
1074                         ImmutableString("gl_SamplePosition"), getShaderVersion()));
1075                 if (!RotateAndFlipBuiltinVariable(this, root, GetMainSequence(root), swapXY, flipXY,
1076                                                   &getSymbolTable(), samplePositionBuiltin,
1077                                                   kFlippedPointCoordName, pivot))
1078                 {
1079                     return false;
1080                 }
1081             }
1082 
1083             if (usesFragCoord)
1084             {
1085                 if (!InsertFragCoordCorrection(this, compileOptions, root, GetMainSequence(root),
1086                                                &getSymbolTable(), specConst, driverUniforms))
1087                 {
1088                     return false;
1089                 }
1090             }
1091 
1092             // Emulate gl_FragColor and gl_FragData with normal output variables.
1093             if (!EmulateFragColorData(this, root, &getSymbolTable(), hasGLSecondaryFragData))
1094             {
1095                 return false;
1096             }
1097 
1098             InputAttachmentMap inputAttachmentMap;
1099 
1100             // Emulate framebuffer fetch if used.
1101             if (HasFramebufferFetch(getExtensionBehavior(), compileOptions))
1102             {
1103                 if (!EmulateFramebufferFetch(this, root, &inputAttachmentMap))
1104                 {
1105                     return false;
1106                 }
1107             }
1108 
1109             // This should be operated after doing ReplaceLastFragData and ReplaceInOutVariables,
1110             // because they will create the input attachment variables. AddBlendMainCaller will
1111             // check the existing input attachment variables and if there is no existing input
1112             // attachment variable then create a new one.
1113             if (getAdvancedBlendEquations().any() &&
1114                 compileOptions.addAdvancedBlendEquationsEmulation &&
1115                 !EmulateAdvancedBlendEquations(this, root, &getSymbolTable(),
1116                                                getAdvancedBlendEquations(), driverUniforms,
1117                                                &inputAttachmentMap))
1118             {
1119                 return false;
1120             }
1121 
1122             // Input attachments are potentially added in framebuffer fetch and advanced blend
1123             // emulation.  Declare their SPIR-V ids.
1124             assignInputAttachmentIds(inputAttachmentMap);
1125 
1126             if (!RewriteDfdy(this, root, &getSymbolTable(), getShaderVersion(), specConst,
1127                              driverUniforms))
1128             {
1129                 return false;
1130             }
1131 
1132             if (!RewriteInterpolateAtOffset(this, root, &getSymbolTable(), getShaderVersion(),
1133                                             specConst, driverUniforms))
1134             {
1135                 return false;
1136             }
1137 
1138             if (usesSampleMaskIn && !RewriteSampleMaskIn(this, root, &getSymbolTable()))
1139             {
1140                 return false;
1141             }
1142 
1143             if (hasGLSampleMask)
1144             {
1145                 TIntermTyped *numSamples = driverUniforms->getNumSamples();
1146                 if (!RewriteSampleMask(this, root, &getSymbolTable(), numSamples))
1147                 {
1148                     return false;
1149                 }
1150             }
1151 
1152             {
1153                 const TVariable *numSamplesVar =
1154                     static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
1155                         ImmutableString("gl_NumSamples"), getShaderVersion()));
1156                 TIntermTyped *numSamples = driverUniforms->getNumSamples();
1157                 if (!ReplaceVariableWithTyped(this, root, numSamplesVar, numSamples))
1158                 {
1159                     return false;
1160                 }
1161             }
1162 
1163             if (IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_YUV_target))
1164             {
1165                 if (!EmulateYUVBuiltIns(this, root, &getSymbolTable()))
1166                 {
1167                     return false;
1168                 }
1169 
1170                 if (!ReswizzleYUVOps(this, root, &getSymbolTable(), yuvOutput))
1171                 {
1172                     return false;
1173                 }
1174             }
1175 
1176             if (!EmulateDithering(this, compileOptions, root, &getSymbolTable(), specConst,
1177                                   driverUniforms))
1178             {
1179                 return false;
1180             }
1181 
1182             break;
1183         }
1184 
1185         case gl::ShaderType::Vertex:
1186         {
1187             if (compileOptions.addVulkanXfbEmulationSupportCode)
1188             {
1189                 // Add support code for transform feedback emulation.  Only applies to vertex shader
1190                 // as tessellation and geometry shader transform feedback capture require
1191                 // VK_EXT_transform_feedback.
1192                 if (!AddXfbEmulationSupport(this, root, &getSymbolTable(), driverUniforms))
1193                 {
1194                     return false;
1195                 }
1196             }
1197 
1198             break;
1199         }
1200 
1201         case gl::ShaderType::Geometry:
1202             if (!ClampGLLayer(this, root, &getSymbolTable(), driverUniforms))
1203             {
1204                 return false;
1205             }
1206             break;
1207 
1208         case gl::ShaderType::TessControl:
1209         {
1210             if (!ReplaceGLBoundingBoxWithGlobal(this, root, &getSymbolTable(), getShaderVersion()))
1211             {
1212                 return false;
1213             }
1214             break;
1215         }
1216 
1217         case gl::ShaderType::TessEvaluation:
1218             break;
1219 
1220         case gl::ShaderType::Compute:
1221             break;
1222 
1223         default:
1224             UNREACHABLE();
1225             break;
1226     }
1227 
1228     specConst->declareSpecConsts(root);
1229     mValidateASTOptions.validateSpecConstReferences = true;
1230 
1231     // Gather specialization constant usage bits so that we can feedback to context.
1232     mSpecConstUsageBits = specConst->getSpecConstUsageBits();
1233 
1234     if (!validateAST(root))
1235     {
1236         return false;
1237     }
1238 
1239     // Make sure function call validation is not accidentally left off anywhere.
1240     ASSERT(mValidateASTOptions.validateFunctionCall);
1241     ASSERT(mValidateASTOptions.validateNoRawFunctionCalls);
1242 
1243     // Declare the implicitly defined gl_PerVertex I/O blocks if not already.  This will help SPIR-V
1244     // generation treat them mostly like usual I/O blocks.
1245     const TVariable *inputPerVertex  = nullptr;
1246     const TVariable *outputPerVertex = nullptr;
1247     if (!DeclarePerVertexBlocks(this, root, &getSymbolTable(), &inputPerVertex, &outputPerVertex))
1248     {
1249         return false;
1250     }
1251 
1252     if (inputPerVertex)
1253     {
1254         assignSpirvId(inputPerVertex->getType().getInterfaceBlock()->uniqueId(),
1255                       vk::spirv::kIdInputPerVertexBlock);
1256     }
1257     if (outputPerVertex)
1258     {
1259         assignSpirvId(outputPerVertex->getType().getInterfaceBlock()->uniqueId(),
1260                       vk::spirv::kIdOutputPerVertexBlock);
1261         assignSpirvId(outputPerVertex->uniqueId(), vk::spirv::kIdOutputPerVertexVar);
1262     }
1263 
1264     // Now that all transformations are done, assign SPIR-V ids to whatever shader variable is still
1265     // present in the shader in some form.  This should be the last thing done in this function.
1266     assignSpirvIds(root);
1267 
1268     return true;
1269 }
1270 
translate(TIntermBlock * root,const ShCompileOptions & compileOptions,PerformanceDiagnostics * perfDiagnostics)1271 bool TranslatorSPIRV::translate(TIntermBlock *root,
1272                                 const ShCompileOptions &compileOptions,
1273                                 PerformanceDiagnostics *perfDiagnostics)
1274 {
1275     mUniqueToSpirvIdMap.clear();
1276     mFirstUnusedSpirvId = 0;
1277 
1278     SpecConst specConst(&getSymbolTable(), compileOptions, getShaderType());
1279 
1280     DriverUniform driverUniforms(DriverUniformMode::InterfaceBlock);
1281     DriverUniformExtended driverUniformsExt(DriverUniformMode::InterfaceBlock);
1282 
1283     const bool useExtendedDriverUniforms = compileOptions.addVulkanXfbEmulationSupportCode;
1284 
1285     DriverUniform *uniforms = useExtendedDriverUniforms ? &driverUniformsExt : &driverUniforms;
1286 
1287     if (!translateImpl(root, compileOptions, perfDiagnostics, &specConst, uniforms))
1288     {
1289         return false;
1290     }
1291 
1292     return OutputSPIRV(this, root, compileOptions, mUniqueToSpirvIdMap, mFirstUnusedSpirvId);
1293 }
1294 
shouldFlattenPragmaStdglInvariantAll()1295 bool TranslatorSPIRV::shouldFlattenPragmaStdglInvariantAll()
1296 {
1297     // Not necessary.
1298     return false;
1299 }
1300 
assignSpirvId(TSymbolUniqueId uniqueId,uint32_t spirvId)1301 void TranslatorSPIRV::assignSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId)
1302 {
1303     ASSERT(mUniqueToSpirvIdMap.find(uniqueId.get()) == mUniqueToSpirvIdMap.end());
1304     mUniqueToSpirvIdMap[uniqueId.get()] = spirvId;
1305 }
1306 
assignInputAttachmentIds(const InputAttachmentMap & inputAttachmentMap)1307 void TranslatorSPIRV::assignInputAttachmentIds(const InputAttachmentMap &inputAttachmentMap)
1308 {
1309     for (auto &iter : inputAttachmentMap.color)
1310     {
1311         const uint32_t index = iter.first;
1312         const TVariable *var = iter.second;
1313         ASSERT(var != nullptr);
1314 
1315         assignSpirvId(var->uniqueId(), vk::spirv::kIdInputAttachment0 + index);
1316 
1317         const MetadataFlags flag = static_cast<MetadataFlags>(
1318             static_cast<uint32_t>(MetadataFlags::HasInputAttachment0) + index);
1319         mMetadataFlags.set(flag);
1320     }
1321 
1322     if (inputAttachmentMap.depth != nullptr)
1323     {
1324         assignSpirvId(inputAttachmentMap.depth->uniqueId(), vk::spirv::kIdDepthInputAttachment);
1325         mMetadataFlags.set(MetadataFlags::HasDepthInputAttachment);
1326     }
1327 
1328     if (inputAttachmentMap.stencil != nullptr)
1329     {
1330         assignSpirvId(inputAttachmentMap.stencil->uniqueId(), vk::spirv::kIdStencilInputAttachment);
1331         mMetadataFlags.set(MetadataFlags::HasStencilInputAttachment);
1332     }
1333 }
1334 
assignSpirvIds(TIntermBlock * root)1335 void TranslatorSPIRV::assignSpirvIds(TIntermBlock *root)
1336 {
1337     // Match the declarations with collected variables and assign a new id to each, starting from
1338     // the first unreserved id.  This makes sure that the reserved ids for internal variables and
1339     // ids for shader variables form a minimal contiguous range.  The Vulkan backend takes advantage
1340     // of this fact for optimal hashing.
1341     mFirstUnusedSpirvId = vk::spirv::kIdFirstUnreserved;
1342 
1343     for (TIntermNode *node : *root->getSequence())
1344     {
1345         TIntermDeclaration *decl = node->getAsDeclarationNode();
1346         if (decl == nullptr)
1347         {
1348             continue;
1349         }
1350 
1351         TIntermSymbol *symbol = decl->getSequence()->front()->getAsSymbolNode();
1352         if (symbol == nullptr)
1353         {
1354             continue;
1355         }
1356 
1357         const TType &type          = symbol->getType();
1358         const TQualifier qualifier = type.getQualifier();
1359 
1360         // Skip internal symbols, which already have a reserved id.
1361         const TSymbolUniqueId uniqueId =
1362             type.isInterfaceBlock() ? type.getInterfaceBlock()->uniqueId() : symbol->uniqueId();
1363         if (mUniqueToSpirvIdMap.find(uniqueId.get()) != mUniqueToSpirvIdMap.end())
1364         {
1365             continue;
1366         }
1367 
1368         uint32_t *variableId                = nullptr;
1369         std::vector<ShaderVariable> *fields = nullptr;
1370         if (type.isInterfaceBlock())
1371         {
1372             if (IsVaryingIn(qualifier))
1373             {
1374                 ShaderVariable *varying =
1375                     FindIOBlockShaderVariable(&mInputVaryings, type.getInterfaceBlock()->name());
1376                 variableId = &varying->id;
1377                 fields     = &varying->fields;
1378             }
1379             else if (IsVaryingOut(qualifier))
1380             {
1381                 ShaderVariable *varying =
1382                     FindIOBlockShaderVariable(&mOutputVaryings, type.getInterfaceBlock()->name());
1383                 variableId = &varying->id;
1384                 fields     = &varying->fields;
1385             }
1386             else if (IsStorageBuffer(qualifier))
1387             {
1388                 InterfaceBlock *block =
1389                     FindShaderVariable(&mShaderStorageBlocks, type.getInterfaceBlock()->name());
1390                 variableId = &block->id;
1391             }
1392             else
1393             {
1394                 InterfaceBlock *block =
1395                     FindShaderVariable(&mUniformBlocks, type.getInterfaceBlock()->name());
1396                 variableId = &block->id;
1397             }
1398         }
1399         else if (qualifier == EvqUniform)
1400         {
1401             ShaderVariable *uniform = FindUniformShaderVariable(&mUniforms, symbol->getName());
1402             variableId              = &uniform->id;
1403         }
1404         else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
1405         {
1406             ShaderVariable *attribute = FindShaderVariable(&mAttributes, symbol->getName());
1407             variableId                = &attribute->id;
1408         }
1409         else if (IsShaderIn(qualifier))
1410         {
1411             ShaderVariable *varying = FindShaderVariable(&mInputVaryings, symbol->getName());
1412             variableId              = &varying->id;
1413             fields                  = &varying->fields;
1414         }
1415         else if (qualifier == EvqFragmentOut)
1416         {
1417             // webgl_FragColor, webgl_FragData, webgl_SecondaryFragColor and webgl_SecondaryFragData
1418             // are recorded with their original names (starting with gl_)
1419             ImmutableString name(symbol->getName());
1420             if (angle::BeginsWith(name.data(), "webgl_") &&
1421                 symbol->variable().symbolType() == SymbolType::AngleInternal)
1422             {
1423                 name = ImmutableString(name.data() + 3, name.length() - 3);
1424             }
1425 
1426             ShaderVariable *output = FindShaderVariable(&mOutputVariables, name);
1427             variableId             = &output->id;
1428         }
1429         else if (IsShaderOut(qualifier))
1430         {
1431             ShaderVariable *varying = FindShaderVariable(&mOutputVaryings, symbol->getName());
1432             variableId              = &varying->id;
1433             fields                  = &varying->fields;
1434         }
1435 
1436         if (variableId == nullptr)
1437         {
1438             continue;
1439         }
1440 
1441         ASSERT(variableId != nullptr);
1442         assignSpirvId(uniqueId, mFirstUnusedSpirvId);
1443         *variableId = mFirstUnusedSpirvId;
1444 
1445         // Propagate the id to the first field of structs/blocks too.  The front-end gathers
1446         // varyings as fields, and the transformer needs to infer the variable id (of struct type)
1447         // just by looking at the fields.
1448         if (fields != nullptr)
1449         {
1450             SetSpirvIdInFields(mFirstUnusedSpirvId, fields);
1451         }
1452 
1453         ++mFirstUnusedSpirvId;
1454     }
1455 }
1456 }  // namespace sh
1457