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