• 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/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         ImmutableStringBuilder blockName(strlen("ANGLEXfbBuffer") + 2);
455         blockName << "ANGLEXfbBuffer";
456         blockName.appendDecimal(bufferIndex);
457 
458         ImmutableStringBuilder varName(strlen("ANGLEXfb") + 2);
459         varName << "ANGLEXfb";
460         varName.appendDecimal(bufferIndex);
461 
462         TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
463         layoutQualifier.blockStorage     = EbsStd430;
464 
465         const TVariable *xfbBuffer =
466             DeclareInterfaceBlock(root, symbolTable, fieldList, EvqBuffer, layoutQualifier,
467                                   TMemoryQualifier::Create(), 0, blockName, varName);
468 
469         static_assert(vk::spirv::kIdXfbEmulationBufferBlockOne ==
470                       vk::spirv::kIdXfbEmulationBufferBlockZero + 1);
471         static_assert(vk::spirv::kIdXfbEmulationBufferBlockTwo ==
472                       vk::spirv::kIdXfbEmulationBufferBlockZero + 2);
473         static_assert(vk::spirv::kIdXfbEmulationBufferBlockThree ==
474                       vk::spirv::kIdXfbEmulationBufferBlockZero + 3);
475 
476         static_assert(vk::spirv::kIdXfbEmulationBufferVarOne ==
477                       vk::spirv::kIdXfbEmulationBufferVarZero + 1);
478         static_assert(vk::spirv::kIdXfbEmulationBufferVarTwo ==
479                       vk::spirv::kIdXfbEmulationBufferVarZero + 2);
480         static_assert(vk::spirv::kIdXfbEmulationBufferVarThree ==
481                       vk::spirv::kIdXfbEmulationBufferVarZero + 3);
482 
483         compiler->assignSpirvId(xfbBuffer->getType().getInterfaceBlock()->uniqueId(),
484                                 vk::spirv::kIdXfbEmulationBufferBlockZero + bufferIndex);
485         compiler->assignSpirvId(xfbBuffer->uniqueId(),
486                                 vk::spirv::kIdXfbEmulationBufferVarZero + bufferIndex);
487     }
488 
489     return compiler->validateAST(root);
490 }
491 
AddXfbExtensionSupport(TranslatorSPIRV * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const DriverUniform * driverUniforms)492 [[nodiscard]] bool AddXfbExtensionSupport(TranslatorSPIRV *compiler,
493                                           TIntermBlock *root,
494                                           TSymbolTable *symbolTable,
495                                           const DriverUniform *driverUniforms)
496 {
497     // Generate the following output varying declaration used to capture transform feedback output
498     // from gl_Position, as it can't be captured directly due to changes that are applied to it for
499     // clip-space correction and pre-rotation.
500     //
501     //     out vec4 ANGLEXfbPosition;
502 
503     const TType *vec4Type = nullptr;
504 
505     switch (compiler->getShaderType())
506     {
507         case GL_VERTEX_SHADER:
508             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqVertexOut, 4, 1>();
509             break;
510         case GL_TESS_EVALUATION_SHADER_EXT:
511             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqTessEvaluationOut, 4, 1>();
512             break;
513         case GL_GEOMETRY_SHADER_EXT:
514             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqGeometryOut, 4, 1>();
515             break;
516         default:
517             UNREACHABLE();
518     }
519 
520     TVariable *varyingVar = new TVariable(symbolTable, ImmutableString("ANGLEXfbPosition"),
521                                           vec4Type, SymbolType::AngleInternal);
522 
523     compiler->assignSpirvId(varyingVar->uniqueId(), vk::spirv::kIdXfbExtensionPosition);
524 
525     TIntermDeclaration *varyingDecl = new TIntermDeclaration();
526     varyingDecl->appendDeclarator(new TIntermSymbol(varyingVar));
527 
528     // Insert the varying declaration before the first function.
529     const size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
530     root->insertChildNodes(firstFunctionIndex, {varyingDecl});
531 
532     return compiler->validateAST(root);
533 }
534 
AddVertexTransformationSupport(TranslatorSPIRV * compiler,const ShCompileOptions & compileOptions,TIntermBlock * root,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms)535 [[nodiscard]] bool AddVertexTransformationSupport(TranslatorSPIRV *compiler,
536                                                   const ShCompileOptions &compileOptions,
537                                                   TIntermBlock *root,
538                                                   TSymbolTable *symbolTable,
539                                                   SpecConst *specConst,
540                                                   const DriverUniform *driverUniforms)
541 {
542     // In GL the viewport transformation is slightly different - see the GL 2.0 spec section "2.12.1
543     // Controlling the Viewport".  In Vulkan the corresponding spec section is currently "23.4.
544     // Coordinate Transformations".  The following transformation needs to be done:
545     //
546     //     z_vk = 0.5 * (w_gl + z_gl)
547     //
548     // where z_vk is the depth output of a Vulkan geometry-stage shader and z_gl is the same for GL.
549     //
550     // Generate the following function and place it before main().  This function takes
551     // gl_Position and rotates xy, and adjusts z (if necessary).
552     //
553     //     vec4 ANGLETransformPosition(vec4 position)
554     //     {
555     //         return vec4((swapXY ? position.yx : position.xy) * flipXY,
556     //                     transformDepth ? (gl_Position.z + gl_Position.w) / 2 : gl_Position.z,
557     //                     gl_Postion.w);
558     //     }
559 
560     const TType *vec4Type = StaticType::GetBasic<EbtFloat, EbpHigh, 4>();
561     TType *positionType   = new TType(*vec4Type);
562     positionType->setQualifier(EvqParamConst);
563 
564     // Create the parameter variable.
565     TVariable *positionVar = new TVariable(symbolTable, ImmutableString("position"), positionType,
566                                            SymbolType::AngleInternal);
567     TIntermSymbol *positionSymbol = new TIntermSymbol(positionVar);
568 
569     // swapXY ? position.yx : position.xy
570     TIntermTyped *swapXY = specConst->getSwapXY();
571     if (swapXY == nullptr)
572     {
573         swapXY = driverUniforms->getSwapXY();
574     }
575 
576     TIntermTyped *xy        = new TIntermSwizzle(positionSymbol, {0, 1});
577     TIntermTyped *swappedXY = new TIntermSwizzle(positionSymbol->deepCopy(), {1, 0});
578     TIntermTyped *rotatedXY = new TIntermTernary(swapXY, swappedXY, xy);
579 
580     // (swapXY ? position.yx : position.xy) * flipXY
581     TIntermTyped *flipXY = driverUniforms->getFlipXY(symbolTable, DriverUniformFlip::PreFragment);
582     TIntermTyped *rotatedFlippedXY = new TIntermBinary(EOpMul, rotatedXY, flipXY);
583 
584     // (gl_Position.z + gl_Position.w) / 2
585     TIntermTyped *z = new TIntermSwizzle(positionSymbol->deepCopy(), {2});
586     TIntermTyped *w = new TIntermSwizzle(positionSymbol->deepCopy(), {3});
587 
588     TIntermTyped *transformedDepth = z;
589     if (compileOptions.addVulkanDepthCorrection)
590     {
591         TIntermBinary *zPlusW = new TIntermBinary(EOpAdd, z, w->deepCopy());
592         TIntermBinary *halfZPlusW =
593             new TIntermBinary(EOpMul, zPlusW, CreateFloatNode(0.5, EbpMedium));
594 
595         // transformDepth ? (gl_Position.z + gl_Position.w) / 2 : gl_Position.z,
596         TIntermTyped *transformDepth = driverUniforms->getTransformDepth();
597         transformedDepth = new TIntermTernary(transformDepth, halfZPlusW, z->deepCopy());
598     }
599 
600     // vec4(...);
601     TIntermSequence args = {
602         rotatedFlippedXY,
603         transformedDepth,
604         w,
605     };
606     TIntermTyped *transformedPosition = TIntermAggregate::CreateConstructor(*vec4Type, &args);
607 
608     // Create the function body, which has a single return statement.
609     TIntermBlock *body = new TIntermBlock;
610     body->appendStatement(new TIntermBranch(EOpReturn, transformedPosition));
611 
612     // Declare the function
613     TFunction *transformPositionFunction =
614         new TFunction(symbolTable, ImmutableString("ANGLETransformPosition"),
615                       SymbolType::AngleInternal, vec4Type, true);
616     transformPositionFunction->addParameter(positionVar);
617 
618     compiler->assignSpirvId(transformPositionFunction->uniqueId(),
619                             vk::spirv::kIdTransformPositionFunction);
620 
621     TIntermFunctionDefinition *functionDef =
622         CreateInternalFunctionDefinitionNode(*transformPositionFunction, body);
623 
624     // Insert the function declaration before main().
625     const size_t mainIndex = FindMainIndex(root);
626     root->insertChildNodes(mainIndex, {functionDef});
627 
628     return compiler->validateAST(root);
629 }
630 
InsertFragCoordCorrection(TCompiler * compiler,const ShCompileOptions & compileOptions,TIntermBlock * root,TIntermSequence * insertSequence,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms)631 [[nodiscard]] bool InsertFragCoordCorrection(TCompiler *compiler,
632                                              const ShCompileOptions &compileOptions,
633                                              TIntermBlock *root,
634                                              TIntermSequence *insertSequence,
635                                              TSymbolTable *symbolTable,
636                                              SpecConst *specConst,
637                                              const DriverUniform *driverUniforms)
638 {
639     TIntermTyped *flipXY = driverUniforms->getFlipXY(symbolTable, DriverUniformFlip::Fragment);
640     TIntermTyped *pivot  = driverUniforms->getHalfRenderArea();
641 
642     TIntermTyped *swapXY = specConst->getSwapXY();
643     if (swapXY == nullptr)
644     {
645         swapXY = driverUniforms->getSwapXY();
646     }
647 
648     const TVariable *fragCoord = static_cast<const TVariable *>(
649         symbolTable->findBuiltIn(ImmutableString("gl_FragCoord"), compiler->getShaderVersion()));
650     return RotateAndFlipBuiltinVariable(compiler, root, insertSequence, swapXY, flipXY, symbolTable,
651                                         fragCoord, kFlippedFragCoordName, pivot);
652 }
653 
HasFramebufferFetch(const TExtensionBehavior & extBehavior,const ShCompileOptions & compileOptions)654 bool HasFramebufferFetch(const TExtensionBehavior &extBehavior,
655                          const ShCompileOptions &compileOptions)
656 {
657     return IsExtensionEnabled(extBehavior, TExtension::EXT_shader_framebuffer_fetch) ||
658            IsExtensionEnabled(extBehavior, TExtension::EXT_shader_framebuffer_fetch_non_coherent) ||
659            IsExtensionEnabled(extBehavior, TExtension::ARM_shader_framebuffer_fetch) ||
660            IsExtensionEnabled(extBehavior, TExtension::NV_shader_framebuffer_fetch) ||
661            (compileOptions.pls.type == ShPixelLocalStorageType::FramebufferFetch &&
662             IsExtensionEnabled(extBehavior, TExtension::ANGLE_shader_pixel_local_storage));
663 }
664 
665 template <typename Variable>
FindShaderVariable(std::vector<Variable> * vars,const ImmutableString & name)666 Variable *FindShaderVariable(std::vector<Variable> *vars, const ImmutableString &name)
667 {
668     for (Variable &var : *vars)
669     {
670         if (name == var.name)
671         {
672             return &var;
673         }
674     }
675     UNREACHABLE();
676     return nullptr;
677 }
678 
FindIOBlockShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name)679 ShaderVariable *FindIOBlockShaderVariable(std::vector<ShaderVariable> *vars,
680                                           const ImmutableString &name)
681 {
682     for (ShaderVariable &var : *vars)
683     {
684         if (name == var.structOrBlockName)
685         {
686             return &var;
687         }
688     }
689     UNREACHABLE();
690     return nullptr;
691 }
692 
FindUniformFieldShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name,const char * prefix)693 ShaderVariable *FindUniformFieldShaderVariable(std::vector<ShaderVariable> *vars,
694                                                const ImmutableString &name,
695                                                const char *prefix)
696 {
697     for (ShaderVariable &var : *vars)
698     {
699         // The name of the sampler is derived from the uniform name + fields
700         // that reach the uniform, concatenated with '_' per RewriteStructSamplers.
701         std::string varName = prefix;
702         varName += '_';
703         varName += var.name;
704 
705         if (name == varName)
706         {
707             return &var;
708         }
709 
710         ShaderVariable *field = FindUniformFieldShaderVariable(&var.fields, name, varName.c_str());
711         if (field != nullptr)
712         {
713             return field;
714         }
715     }
716     return nullptr;
717 }
718 
FindUniformShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name)719 ShaderVariable *FindUniformShaderVariable(std::vector<ShaderVariable> *vars,
720                                           const ImmutableString &name)
721 {
722     for (ShaderVariable &var : *vars)
723     {
724         if (name == var.name)
725         {
726             return &var;
727         }
728 
729         // Note: samplers in structs are moved out.  Such samplers will be found in the fields of
730         // the struct uniform.
731         ShaderVariable *field = FindUniformFieldShaderVariable(&var.fields, name, var.name.c_str());
732         if (field != nullptr)
733         {
734             return field;
735         }
736     }
737     UNREACHABLE();
738     return nullptr;
739 }
740 
SetSpirvIdInFields(uint32_t id,std::vector<ShaderVariable> * fields)741 void SetSpirvIdInFields(uint32_t id, std::vector<ShaderVariable> *fields)
742 {
743     for (ShaderVariable &field : *fields)
744     {
745         field.id = id;
746         SetSpirvIdInFields(id, &field.fields);
747     }
748 }
749 }  // anonymous namespace
750 
TranslatorSPIRV(sh::GLenum type,ShShaderSpec spec)751 TranslatorSPIRV::TranslatorSPIRV(sh::GLenum type, ShShaderSpec spec)
752     : TCompiler(type, spec, SH_SPIRV_VULKAN_OUTPUT), mFirstUnusedSpirvId(0)
753 {}
754 
translateImpl(TIntermBlock * root,const ShCompileOptions & compileOptions,PerformanceDiagnostics *,SpecConst * specConst,DriverUniform * driverUniforms)755 bool TranslatorSPIRV::translateImpl(TIntermBlock *root,
756                                     const ShCompileOptions &compileOptions,
757                                     PerformanceDiagnostics * /*perfDiagnostics*/,
758                                     SpecConst *specConst,
759                                     DriverUniform *driverUniforms)
760 {
761     if (getShaderType() == GL_VERTEX_SHADER)
762     {
763         if (!ShaderBuiltinsWorkaround(this, root, &getSymbolTable(), compileOptions))
764         {
765             return false;
766         }
767     }
768 
769     // Write out default uniforms into a uniform block assigned to a specific set/binding.
770     int defaultUniformCount           = 0;
771     int aggregateTypesUsedForUniforms = 0;
772     int r32fImageCount                = 0;
773     int atomicCounterCount            = 0;
774     for (const auto &uniform : getUniforms())
775     {
776         if (!uniform.isBuiltIn() && uniform.active && !gl::IsOpaqueType(uniform.type))
777         {
778             ++defaultUniformCount;
779         }
780 
781         if (uniform.isStruct() || uniform.isArrayOfArrays())
782         {
783             ++aggregateTypesUsedForUniforms;
784         }
785 
786         if (uniform.active && gl::IsImageType(uniform.type) && uniform.imageUnitFormat == GL_R32F)
787         {
788             ++r32fImageCount;
789         }
790 
791         if (uniform.active && gl::IsAtomicCounterType(uniform.type))
792         {
793             ++atomicCounterCount;
794         }
795     }
796 
797     // Remove declarations of inactive shader interface variables so SPIR-V transformer doesn't need
798     // to replace them.  Note that currently, CollectVariables marks every field of an active
799     // uniform that's of struct type as active, i.e. no extracted sampler is inactive, so this can
800     // be done before extracting samplers from structs.
801     if (!RemoveInactiveInterfaceVariables(this, root, &getSymbolTable(), getAttributes(),
802                                           getInputVaryings(), getOutputVariables(), getUniforms(),
803                                           getInterfaceBlocks(), true))
804     {
805         return false;
806     }
807 
808     // If there are any function calls that take array-of-array of opaque uniform parameters, or
809     // other opaque uniforms that need special handling in Vulkan, such as atomic counters,
810     // monomorphize the functions by removing said parameters and replacing them in the function
811     // body with the call arguments.
812     //
813     // This has a few benefits:
814     //
815     // - It dramatically simplifies future transformations w.r.t to samplers in structs, array of
816     //   arrays of opaque types, atomic counters etc.
817     // - Avoids the need for shader*ArrayDynamicIndexing Vulkan features.
818     UnsupportedFunctionArgsBitSet args{UnsupportedFunctionArgs::StructContainingSamplers,
819                                        UnsupportedFunctionArgs::ArrayOfArrayOfSamplerOrImage,
820                                        UnsupportedFunctionArgs::AtomicCounter,
821                                        UnsupportedFunctionArgs::SamplerCubeEmulation,
822                                        UnsupportedFunctionArgs::Image};
823     if (!MonomorphizeUnsupportedFunctions(this, root, &getSymbolTable(), compileOptions, args))
824     {
825         return false;
826     }
827 
828     if (aggregateTypesUsedForUniforms > 0)
829     {
830         if (!SeparateStructFromUniformDeclarations(this, root, &getSymbolTable()))
831         {
832             return false;
833         }
834 
835         int removedUniformsCount;
836 
837         if (!RewriteStructSamplers(this, root, &getSymbolTable(), &removedUniformsCount))
838         {
839             return false;
840         }
841         defaultUniformCount -= removedUniformsCount;
842     }
843 
844     // Replace array of array of opaque uniforms with a flattened array.  This is run after
845     // MonomorphizeUnsupportedFunctions and RewriteStructSamplers so that it's not possible for an
846     // array of array of opaque type to be partially subscripted and passed to a function.
847     if (!RewriteArrayOfArrayOfOpaqueUniforms(this, root, &getSymbolTable()))
848     {
849         return false;
850     }
851 
852     // Rewrite samplerCubes as sampler2DArrays.  This must be done after rewriting struct samplers
853     // as it doesn't expect that.
854     if (compileOptions.emulateSeamfulCubeMapSampling)
855     {
856         if (!RewriteCubeMapSamplersAs2DArray(this, root, &getSymbolTable(),
857                                              getShaderType() == GL_FRAGMENT_SHADER))
858         {
859             return false;
860         }
861     }
862 
863     if (!FlagSamplersForTexelFetch(this, root, &getSymbolTable(), &mUniforms))
864     {
865         return false;
866     }
867 
868     gl::ShaderType packedShaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
869 
870     if (defaultUniformCount > 0)
871     {
872         if (!DeclareDefaultUniforms(this, root, &getSymbolTable(), packedShaderType))
873         {
874             return false;
875         }
876     }
877 
878     if (getShaderType() == GL_COMPUTE_SHADER)
879     {
880         driverUniforms->addComputeDriverUniformsToShader(root, &getSymbolTable());
881     }
882     else
883     {
884         driverUniforms->addGraphicsDriverUniformsToShader(root, &getSymbolTable());
885     }
886 
887     assignSpirvId(
888         driverUniforms->getDriverUniformsVariable()->getType().getInterfaceBlock()->uniqueId(),
889         vk::spirv::kIdDriverUniformsBlock);
890 
891     if (r32fImageCount > 0)
892     {
893         if (!RewriteR32fImages(this, root, &getSymbolTable()))
894         {
895             return false;
896         }
897     }
898 
899     if (atomicCounterCount > 0)
900     {
901         // ANGLEUniforms.acbBufferOffsets
902         const TIntermTyped *acbBufferOffsets = driverUniforms->getAcbBufferOffsets();
903         const TVariable *atomicCounters      = nullptr;
904         if (!RewriteAtomicCounters(this, root, &getSymbolTable(), acbBufferOffsets,
905                                    &atomicCounters))
906         {
907             return false;
908         }
909         assignSpirvId(atomicCounters->getType().getInterfaceBlock()->uniqueId(),
910                       vk::spirv::kIdAtomicCounterBlock);
911     }
912     else if (getShaderVersion() >= 310)
913     {
914         // Vulkan doesn't support Atomic Storage as a Storage Class, but we've seen
915         // cases where builtins are using it even with no active atomic counters.
916         // This pass simply removes those builtins in that scenario.
917         if (!RemoveAtomicCounterBuiltins(this, root))
918         {
919             return false;
920         }
921     }
922 
923     if (packedShaderType != gl::ShaderType::Compute)
924     {
925         if (!ReplaceGLDepthRangeWithDriverUniform(this, root, driverUniforms, &getSymbolTable()))
926         {
927             return false;
928         }
929 
930         // Search for the gl_ClipDistance/gl_CullDistance usage, if its used, we need to do some
931         // replacements.
932         bool useClipDistance = false;
933         bool useCullDistance = false;
934         for (const ShaderVariable &outputVarying : mOutputVaryings)
935         {
936             if (outputVarying.name == "gl_ClipDistance")
937             {
938                 useClipDistance = true;
939             }
940             else if (outputVarying.name == "gl_CullDistance")
941             {
942                 useCullDistance = true;
943             }
944         }
945         for (const ShaderVariable &inputVarying : mInputVaryings)
946         {
947             if (inputVarying.name == "gl_ClipDistance")
948             {
949                 useClipDistance = true;
950             }
951             else if (inputVarying.name == "gl_CullDistance")
952             {
953                 useCullDistance = true;
954             }
955         }
956 
957         if (useClipDistance &&
958             !ReplaceClipDistanceAssignments(this, root, &getSymbolTable(), getShaderType(),
959                                             driverUniforms->getClipDistancesEnabled()))
960         {
961             return false;
962         }
963         if (useCullDistance &&
964             !ReplaceCullDistanceAssignments(this, root, &getSymbolTable(), getShaderType()))
965         {
966             return false;
967         }
968     }
969 
970     if (gl::ShaderTypeSupportsTransformFeedback(packedShaderType))
971     {
972         if (compileOptions.addVulkanXfbExtensionSupportCode)
973         {
974             // Add support code for transform feedback extension.
975             if (!AddXfbExtensionSupport(this, root, &getSymbolTable(), driverUniforms))
976             {
977                 return false;
978             }
979         }
980 
981         // Add support code for pre-rotation and depth correction in the vertex processing stages.
982         if (!AddVertexTransformationSupport(this, compileOptions, root, &getSymbolTable(),
983                                             specConst, driverUniforms))
984         {
985             return false;
986         }
987     }
988 
989     switch (packedShaderType)
990     {
991         case gl::ShaderType::Fragment:
992         {
993             bool usesPointCoord    = false;
994             bool usesFragCoord     = false;
995             bool usesSampleMaskIn  = false;
996             bool useSamplePosition = false;
997 
998             // Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate.
999             for (const ShaderVariable &inputVarying : mInputVaryings)
1000             {
1001                 if (!inputVarying.isBuiltIn())
1002                 {
1003                     continue;
1004                 }
1005 
1006                 if (inputVarying.name == "gl_SampleMaskIn")
1007                 {
1008                     usesSampleMaskIn = true;
1009                     continue;
1010                 }
1011 
1012                 if (inputVarying.name == "gl_SamplePosition")
1013                 {
1014                     useSamplePosition = true;
1015                     continue;
1016                 }
1017 
1018                 if (inputVarying.name == "gl_PointCoord")
1019                 {
1020                     usesPointCoord = true;
1021                     break;
1022                 }
1023 
1024                 if (inputVarying.name == "gl_FragCoord")
1025                 {
1026                     usesFragCoord = true;
1027                     break;
1028                 }
1029             }
1030 
1031             bool hasGLSampleMask           = false;
1032             bool hasGLSecondaryFragData    = false;
1033             const TIntermSymbol *yuvOutput = nullptr;
1034 
1035             for (const ShaderVariable &outputVar : mOutputVariables)
1036             {
1037                 if (outputVar.name == "gl_SampleMask")
1038                 {
1039                     ASSERT(!hasGLSampleMask);
1040                     hasGLSampleMask = true;
1041                     continue;
1042                 }
1043                 if (outputVar.name == "gl_SecondaryFragDataEXT")
1044                 {
1045                     ASSERT(!hasGLSecondaryFragData);
1046                     hasGLSecondaryFragData = true;
1047                     continue;
1048                 }
1049                 if (outputVar.yuv)
1050                 {
1051                     // We can only have one yuv output
1052                     ASSERT(yuvOutput == nullptr);
1053                     yuvOutput = FindSymbolNode(root, ImmutableString(outputVar.name));
1054                     continue;
1055                 }
1056             }
1057 
1058             if (usesPointCoord)
1059             {
1060                 TIntermTyped *flipNegXY =
1061                     driverUniforms->getNegFlipXY(&getSymbolTable(), DriverUniformFlip::Fragment);
1062                 TIntermConstantUnion *pivot = CreateFloatNode(0.5f, EbpMedium);
1063                 TIntermTyped *swapXY        = specConst->getSwapXY();
1064                 if (swapXY == nullptr)
1065                 {
1066                     swapXY = driverUniforms->getSwapXY();
1067                 }
1068                 if (!RotateAndFlipBuiltinVariable(
1069                         this, root, GetMainSequence(root), swapXY, flipNegXY, &getSymbolTable(),
1070                         BuiltInVariable::gl_PointCoord(), kFlippedPointCoordName, pivot))
1071                 {
1072                     return false;
1073                 }
1074             }
1075 
1076             if (useSamplePosition)
1077             {
1078                 TIntermTyped *flipXY =
1079                     driverUniforms->getFlipXY(&getSymbolTable(), DriverUniformFlip::Fragment);
1080                 TIntermConstantUnion *pivot = CreateFloatNode(0.5f, EbpMedium);
1081                 TIntermTyped *swapXY        = specConst->getSwapXY();
1082                 if (swapXY == nullptr)
1083                 {
1084                     swapXY = driverUniforms->getSwapXY();
1085                 }
1086 
1087                 const TVariable *samplePositionBuiltin =
1088                     static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
1089                         ImmutableString("gl_SamplePosition"), getShaderVersion()));
1090                 if (!RotateAndFlipBuiltinVariable(this, root, GetMainSequence(root), swapXY, flipXY,
1091                                                   &getSymbolTable(), samplePositionBuiltin,
1092                                                   kFlippedPointCoordName, pivot))
1093                 {
1094                     return false;
1095                 }
1096             }
1097 
1098             if (usesFragCoord)
1099             {
1100                 if (!InsertFragCoordCorrection(this, compileOptions, root, GetMainSequence(root),
1101                                                &getSymbolTable(), specConst, driverUniforms))
1102                 {
1103                     return false;
1104                 }
1105             }
1106 
1107             // Emulate gl_FragColor and gl_FragData with normal output variables.
1108             if (!EmulateFragColorData(this, root, &getSymbolTable(), hasGLSecondaryFragData))
1109             {
1110                 return false;
1111             }
1112 
1113             InputAttachmentMap inputAttachmentMap;
1114 
1115             // Emulate framebuffer fetch if used.
1116             if (HasFramebufferFetch(getExtensionBehavior(), compileOptions))
1117             {
1118                 if (!EmulateFramebufferFetch(this, root, &inputAttachmentMap))
1119                 {
1120                     return false;
1121                 }
1122             }
1123 
1124             // This should be operated after doing ReplaceLastFragData and ReplaceInOutVariables,
1125             // because they will create the input attachment variables. AddBlendMainCaller will
1126             // check the existing input attachment variables and if there is no existing input
1127             // attachment variable then create a new one.
1128             if (getAdvancedBlendEquations().any() &&
1129                 compileOptions.addAdvancedBlendEquationsEmulation &&
1130                 !EmulateAdvancedBlendEquations(this, root, &getSymbolTable(),
1131                                                getAdvancedBlendEquations(), driverUniforms,
1132                                                &inputAttachmentMap))
1133             {
1134                 return false;
1135             }
1136 
1137             // Input attachments are potentially added in framebuffer fetch and advanced blend
1138             // emulation.  Declare their SPIR-V ids.
1139             assignInputAttachmentIds(inputAttachmentMap);
1140 
1141             if (!RewriteDfdy(this, root, &getSymbolTable(), getShaderVersion(), specConst,
1142                              driverUniforms))
1143             {
1144                 return false;
1145             }
1146 
1147             if (!RewriteInterpolateAtOffset(this, root, &getSymbolTable(), getShaderVersion(),
1148                                             specConst, driverUniforms))
1149             {
1150                 return false;
1151             }
1152 
1153             if (usesSampleMaskIn && !RewriteSampleMaskIn(this, root, &getSymbolTable()))
1154             {
1155                 return false;
1156             }
1157 
1158             if (hasGLSampleMask)
1159             {
1160                 TIntermTyped *numSamples = driverUniforms->getNumSamples();
1161                 if (!RewriteSampleMask(this, root, &getSymbolTable(), numSamples))
1162                 {
1163                     return false;
1164                 }
1165             }
1166 
1167             {
1168                 const TVariable *numSamplesVar =
1169                     static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
1170                         ImmutableString("gl_NumSamples"), getShaderVersion()));
1171                 TIntermTyped *numSamples = driverUniforms->getNumSamples();
1172                 if (!ReplaceVariableWithTyped(this, root, numSamplesVar, numSamples))
1173                 {
1174                     return false;
1175                 }
1176             }
1177 
1178             if (IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_YUV_target))
1179             {
1180                 if (!EmulateYUVBuiltIns(this, root, &getSymbolTable()))
1181                 {
1182                     return false;
1183                 }
1184 
1185                 if (!ReswizzleYUVOps(this, root, &getSymbolTable(), yuvOutput))
1186                 {
1187                     return false;
1188                 }
1189             }
1190 
1191             if (!EmulateDithering(this, compileOptions, root, &getSymbolTable(), specConst,
1192                                   driverUniforms))
1193             {
1194                 return false;
1195             }
1196 
1197             break;
1198         }
1199 
1200         case gl::ShaderType::Vertex:
1201         {
1202             if (compileOptions.addVulkanXfbEmulationSupportCode)
1203             {
1204                 // Add support code for transform feedback emulation.  Only applies to vertex shader
1205                 // as tessellation and geometry shader transform feedback capture require
1206                 // VK_EXT_transform_feedback.
1207                 if (!AddXfbEmulationSupport(this, root, &getSymbolTable(), driverUniforms))
1208                 {
1209                     return false;
1210                 }
1211             }
1212 
1213             break;
1214         }
1215 
1216         case gl::ShaderType::Geometry:
1217             break;
1218 
1219         case gl::ShaderType::TessControl:
1220         {
1221             if (!ReplaceGLBoundingBoxWithGlobal(this, root, &getSymbolTable(), getShaderVersion()))
1222             {
1223                 return false;
1224             }
1225             break;
1226         }
1227 
1228         case gl::ShaderType::TessEvaluation:
1229             break;
1230 
1231         case gl::ShaderType::Compute:
1232             break;
1233 
1234         default:
1235             UNREACHABLE();
1236             break;
1237     }
1238 
1239     specConst->declareSpecConsts(root);
1240     mValidateASTOptions.validateSpecConstReferences = true;
1241 
1242     // Gather specialization constant usage bits so that we can feedback to context.
1243     mSpecConstUsageBits = specConst->getSpecConstUsageBits();
1244 
1245     if (!validateAST(root))
1246     {
1247         return false;
1248     }
1249 
1250     // Make sure function call validation is not accidentally left off anywhere.
1251     ASSERT(mValidateASTOptions.validateFunctionCall);
1252     ASSERT(mValidateASTOptions.validateNoRawFunctionCalls);
1253 
1254     // Declare the implicitly defined gl_PerVertex I/O blocks if not already.  This will help SPIR-V
1255     // generation treat them mostly like usual I/O blocks.
1256     const TVariable *inputPerVertex  = nullptr;
1257     const TVariable *outputPerVertex = nullptr;
1258     if (!DeclarePerVertexBlocks(this, root, &getSymbolTable(), &inputPerVertex, &outputPerVertex))
1259     {
1260         return false;
1261     }
1262 
1263     if (inputPerVertex)
1264     {
1265         assignSpirvId(inputPerVertex->getType().getInterfaceBlock()->uniqueId(),
1266                       vk::spirv::kIdInputPerVertexBlock);
1267     }
1268     if (outputPerVertex)
1269     {
1270         assignSpirvId(outputPerVertex->getType().getInterfaceBlock()->uniqueId(),
1271                       vk::spirv::kIdOutputPerVertexBlock);
1272         assignSpirvId(outputPerVertex->uniqueId(), vk::spirv::kIdOutputPerVertexVar);
1273     }
1274 
1275     // Now that all transformations are done, assign SPIR-V ids to whatever shader variable is still
1276     // present in the shader in some form.  This should be the last thing done in this function.
1277     assignSpirvIds(root);
1278 
1279     return true;
1280 }
1281 
translate(TIntermBlock * root,const ShCompileOptions & compileOptions,PerformanceDiagnostics * perfDiagnostics)1282 bool TranslatorSPIRV::translate(TIntermBlock *root,
1283                                 const ShCompileOptions &compileOptions,
1284                                 PerformanceDiagnostics *perfDiagnostics)
1285 {
1286     mUniqueToSpirvIdMap.clear();
1287     mFirstUnusedSpirvId = 0;
1288 
1289     SpecConst specConst(&getSymbolTable(), compileOptions, getShaderType());
1290 
1291     DriverUniform driverUniforms(DriverUniformMode::InterfaceBlock);
1292     DriverUniformExtended driverUniformsExt(DriverUniformMode::InterfaceBlock);
1293 
1294     const bool useExtendedDriverUniforms = compileOptions.addVulkanXfbEmulationSupportCode;
1295 
1296     DriverUniform *uniforms = useExtendedDriverUniforms ? &driverUniformsExt : &driverUniforms;
1297 
1298     if (!translateImpl(root, compileOptions, perfDiagnostics, &specConst, uniforms))
1299     {
1300         return false;
1301     }
1302 
1303     return OutputSPIRV(this, root, compileOptions, mUniqueToSpirvIdMap, mFirstUnusedSpirvId);
1304 }
1305 
shouldFlattenPragmaStdglInvariantAll()1306 bool TranslatorSPIRV::shouldFlattenPragmaStdglInvariantAll()
1307 {
1308     // Not necessary.
1309     return false;
1310 }
1311 
assignSpirvId(TSymbolUniqueId uniqueId,uint32_t spirvId)1312 void TranslatorSPIRV::assignSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId)
1313 {
1314     ASSERT(mUniqueToSpirvIdMap.find(uniqueId.get()) == mUniqueToSpirvIdMap.end());
1315     mUniqueToSpirvIdMap[uniqueId.get()] = spirvId;
1316 }
1317 
assignInputAttachmentIds(const InputAttachmentMap & inputAttachmentMap)1318 void TranslatorSPIRV::assignInputAttachmentIds(const InputAttachmentMap &inputAttachmentMap)
1319 {
1320     for (auto &iter : inputAttachmentMap)
1321     {
1322         const uint32_t index = iter.first;
1323         const TVariable *var = iter.second;
1324         ASSERT(var != nullptr);
1325 
1326         assignSpirvId(var->uniqueId(), vk::spirv::kIdInputAttachment0 + index);
1327 
1328         const MetadataFlags flag = static_cast<MetadataFlags>(
1329             static_cast<uint32_t>(MetadataFlags::HasInputAttachment0) + index);
1330         mMetadataFlags.set(flag);
1331     }
1332 }
1333 
assignSpirvIds(TIntermBlock * root)1334 void TranslatorSPIRV::assignSpirvIds(TIntermBlock *root)
1335 {
1336     // Match the declarations with collected variables and assign a new id to each, starting from
1337     // the first unreserved id.  This makes sure that the reserved ids for internal variables and
1338     // ids for shader variables form a minimal contiguous range.  The Vulkan backend takes advantage
1339     // of this fact for optimal hashing.
1340     mFirstUnusedSpirvId = vk::spirv::kIdFirstUnreserved;
1341 
1342     for (TIntermNode *node : *root->getSequence())
1343     {
1344         TIntermDeclaration *decl = node->getAsDeclarationNode();
1345         if (decl == nullptr)
1346         {
1347             continue;
1348         }
1349 
1350         TIntermSymbol *symbol = decl->getSequence()->front()->getAsSymbolNode();
1351         if (symbol == nullptr)
1352         {
1353             continue;
1354         }
1355 
1356         const TType &type          = symbol->getType();
1357         const TQualifier qualifier = type.getQualifier();
1358 
1359         // Skip internal symbols, which already have a reserved id.
1360         const TSymbolUniqueId uniqueId =
1361             type.isInterfaceBlock() ? type.getInterfaceBlock()->uniqueId() : symbol->uniqueId();
1362         if (mUniqueToSpirvIdMap.find(uniqueId.get()) != mUniqueToSpirvIdMap.end())
1363         {
1364             continue;
1365         }
1366 
1367         uint32_t *variableId                = nullptr;
1368         std::vector<ShaderVariable> *fields = nullptr;
1369         if (type.isInterfaceBlock())
1370         {
1371             if (IsVaryingIn(qualifier))
1372             {
1373                 ShaderVariable *varying =
1374                     FindIOBlockShaderVariable(&mInputVaryings, type.getInterfaceBlock()->name());
1375                 variableId = &varying->id;
1376                 fields     = &varying->fields;
1377             }
1378             else if (IsVaryingOut(qualifier))
1379             {
1380                 ShaderVariable *varying =
1381                     FindIOBlockShaderVariable(&mOutputVaryings, type.getInterfaceBlock()->name());
1382                 variableId = &varying->id;
1383                 fields     = &varying->fields;
1384             }
1385             else if (IsStorageBuffer(qualifier))
1386             {
1387                 InterfaceBlock *block =
1388                     FindShaderVariable(&mShaderStorageBlocks, type.getInterfaceBlock()->name());
1389                 variableId = &block->id;
1390             }
1391             else
1392             {
1393                 InterfaceBlock *block =
1394                     FindShaderVariable(&mUniformBlocks, type.getInterfaceBlock()->name());
1395                 variableId = &block->id;
1396             }
1397         }
1398         else if (qualifier == EvqUniform)
1399         {
1400             ShaderVariable *uniform = FindUniformShaderVariable(&mUniforms, symbol->getName());
1401             variableId              = &uniform->id;
1402         }
1403         else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
1404         {
1405             ShaderVariable *attribute = FindShaderVariable(&mAttributes, symbol->getName());
1406             variableId                = &attribute->id;
1407         }
1408         else if (IsShaderIn(qualifier))
1409         {
1410             ShaderVariable *varying = FindShaderVariable(&mInputVaryings, symbol->getName());
1411             variableId              = &varying->id;
1412             fields                  = &varying->fields;
1413         }
1414         else if (qualifier == EvqFragmentOut)
1415         {
1416             // webgl_FragColor, webgl_FragData, webgl_SecondaryFragColor and webgl_SecondaryFragData
1417             // are recorded with their original names (starting with gl_)
1418             ImmutableString name(symbol->getName());
1419             if (angle::BeginsWith(name.data(), "webgl_") &&
1420                 symbol->variable().symbolType() == SymbolType::AngleInternal)
1421             {
1422                 name = ImmutableString(name.data() + 3, name.length() - 3);
1423             }
1424 
1425             ShaderVariable *output = FindShaderVariable(&mOutputVariables, name);
1426             variableId             = &output->id;
1427         }
1428         else if (IsShaderOut(qualifier))
1429         {
1430             ShaderVariable *varying = FindShaderVariable(&mOutputVaryings, symbol->getName());
1431             variableId              = &varying->id;
1432             fields                  = &varying->fields;
1433         }
1434 
1435         if (variableId == nullptr)
1436         {
1437             continue;
1438         }
1439 
1440         ASSERT(variableId != nullptr);
1441         assignSpirvId(uniqueId, mFirstUnusedSpirvId);
1442         *variableId = mFirstUnusedSpirvId;
1443 
1444         // Propagate the id to the first field of structs/blocks too.  The front-end gathers
1445         // varyings as fields, and the transformer needs to infer the variable id (of struct type)
1446         // just by looking at the fields.
1447         if (fields != nullptr)
1448         {
1449             SetSpirvIdInFields(mFirstUnusedSpirvId, fields);
1450         }
1451 
1452         ++mFirstUnusedSpirvId;
1453     }
1454 }
1455 }  // namespace sh
1456