• 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 // TranslatorVulkan:
7 //   A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl and feeds them into
8 //   glslang to spit out SPIR-V.
9 //   See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
10 //
11 
12 #include "compiler/translator/TranslatorVulkan.h"
13 
14 #include "angle_gl.h"
15 #include "common/PackedEnums.h"
16 #include "common/utilities.h"
17 #include "compiler/translator/BuiltinsWorkaroundGLSL.h"
18 #include "compiler/translator/ImmutableStringBuilder.h"
19 #include "compiler/translator/IntermNode.h"
20 #include "compiler/translator/OutputSPIRV.h"
21 #include "compiler/translator/OutputVulkanGLSL.h"
22 #include "compiler/translator/StaticType.h"
23 #include "compiler/translator/glslang_wrapper.h"
24 #include "compiler/translator/tree_ops/MonomorphizeUnsupportedFunctions.h"
25 #include "compiler/translator/tree_ops/RecordConstantPrecision.h"
26 #include "compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.h"
27 #include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
28 #include "compiler/translator/tree_ops/RewriteArrayOfArrayOfOpaqueUniforms.h"
29 #include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
30 #include "compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h"
31 #include "compiler/translator/tree_ops/RewriteDfdy.h"
32 #include "compiler/translator/tree_ops/RewriteStructSamplers.h"
33 #include "compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.h"
34 #include "compiler/translator/tree_ops/vulkan/DeclarePerVertexBlocks.h"
35 #include "compiler/translator/tree_ops/vulkan/EmulateAdvancedBlendEquations.h"
36 #include "compiler/translator/tree_ops/vulkan/EmulateDithering.h"
37 #include "compiler/translator/tree_ops/vulkan/EmulateFragColorData.h"
38 #include "compiler/translator/tree_ops/vulkan/FlagSamplersWithTexelFetch.h"
39 #include "compiler/translator/tree_ops/vulkan/ReplaceForShaderFramebufferFetch.h"
40 #include "compiler/translator/tree_ops/vulkan/RewriteInterpolateAtOffset.h"
41 #include "compiler/translator/tree_ops/vulkan/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/IntermNode_util.h"
47 #include "compiler/translator/tree_util/ReplaceClipCullDistanceVariable.h"
48 #include "compiler/translator/tree_util/ReplaceVariable.h"
49 #include "compiler/translator/tree_util/RewriteSampleMaskVariable.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 
62 constexpr gl::ShaderMap<const char *> kDefaultUniformNames = {
63     {gl::ShaderType::Vertex, vk::kDefaultUniformsNameVS},
64     {gl::ShaderType::TessControl, vk::kDefaultUniformsNameTCS},
65     {gl::ShaderType::TessEvaluation, vk::kDefaultUniformsNameTES},
66     {gl::ShaderType::Geometry, vk::kDefaultUniformsNameGS},
67     {gl::ShaderType::Fragment, vk::kDefaultUniformsNameFS},
68     {gl::ShaderType::Compute, vk::kDefaultUniformsNameCS},
69 };
70 
IsDefaultUniform(const TType & type)71 bool IsDefaultUniform(const TType &type)
72 {
73     return type.getQualifier() == EvqUniform && type.getInterfaceBlock() == nullptr &&
74            !IsOpaqueType(type.getBasicType());
75 }
76 
77 class ReplaceDefaultUniformsTraverser : public TIntermTraverser
78 {
79   public:
ReplaceDefaultUniformsTraverser(const VariableReplacementMap & variableMap)80     ReplaceDefaultUniformsTraverser(const VariableReplacementMap &variableMap)
81         : TIntermTraverser(true, false, false), mVariableMap(variableMap)
82     {}
83 
visitDeclaration(Visit visit,TIntermDeclaration * node)84     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
85     {
86         const TIntermSequence &sequence = *(node->getSequence());
87 
88         TIntermTyped *variable = sequence.front()->getAsTyped();
89         const TType &type      = variable->getType();
90 
91         if (IsDefaultUniform(type))
92         {
93             // Remove the uniform declaration.
94             TIntermSequence emptyReplacement;
95             mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
96                                             std::move(emptyReplacement));
97 
98             return false;
99         }
100 
101         return true;
102     }
103 
visitSymbol(TIntermSymbol * symbol)104     void visitSymbol(TIntermSymbol *symbol) override
105     {
106         const TVariable &variable = symbol->variable();
107         const TType &type         = variable.getType();
108 
109         if (!IsDefaultUniform(type) || gl::IsBuiltInName(variable.name().data()))
110         {
111             return;
112         }
113 
114         ASSERT(mVariableMap.count(&variable) > 0);
115 
116         queueReplacement(mVariableMap.at(&variable)->deepCopy(), OriginalNode::IS_DROPPED);
117     }
118 
119   private:
120     const VariableReplacementMap &mVariableMap;
121 };
122 
DeclareDefaultUniforms(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,gl::ShaderType shaderType)123 bool DeclareDefaultUniforms(TCompiler *compiler,
124                             TIntermBlock *root,
125                             TSymbolTable *symbolTable,
126                             gl::ShaderType shaderType)
127 {
128     // First, collect all default uniforms and declare a uniform block.
129     TFieldList *uniformList = new TFieldList;
130     TVector<const TVariable *> uniformVars;
131 
132     for (TIntermNode *node : *root->getSequence())
133     {
134         TIntermDeclaration *decl = node->getAsDeclarationNode();
135         if (decl == nullptr)
136         {
137             continue;
138         }
139 
140         const TIntermSequence &sequence = *(decl->getSequence());
141 
142         TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
143         if (symbol == nullptr)
144         {
145             continue;
146         }
147 
148         const TType &type = symbol->getType();
149         if (IsDefaultUniform(type))
150         {
151             TType *fieldType = new TType(type);
152 
153             uniformList->push_back(new TField(fieldType, symbol->getName(), symbol->getLine(),
154                                               symbol->variable().symbolType()));
155             uniformVars.push_back(&symbol->variable());
156         }
157     }
158 
159     TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
160     layoutQualifier.blockStorage     = EbsStd140;
161     const TVariable *uniformBlock    = DeclareInterfaceBlock(
162         root, symbolTable, uniformList, EvqUniform, layoutQualifier, TMemoryQualifier::Create(), 0,
163         ImmutableString(kDefaultUniformNames[shaderType]), ImmutableString(""));
164 
165     // Create a map from the uniform variables to new variables that reference the fields of the
166     // block.
167     VariableReplacementMap variableMap;
168     for (size_t fieldIndex = 0; fieldIndex < uniformVars.size(); ++fieldIndex)
169     {
170         const TVariable *variable = uniformVars[fieldIndex];
171 
172         TType *replacementType = new TType(variable->getType());
173         replacementType->setInterfaceBlockField(uniformBlock->getType().getInterfaceBlock(),
174                                                 fieldIndex);
175 
176         TVariable *replacementVariable =
177             new TVariable(symbolTable, variable->name(), replacementType, variable->symbolType());
178 
179         variableMap[variable] = new TIntermSymbol(replacementVariable);
180     }
181 
182     // Finally transform the AST and make sure references to the uniforms are replaced with the new
183     // variables.
184     ReplaceDefaultUniformsTraverser defaultTraverser(variableMap);
185     root->traverse(&defaultTraverser);
186     return defaultTraverser.updateTree(compiler, root);
187 }
188 
189 // 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 * flipXY,TSymbolTable * symbolTable,const TVariable * builtin,const ImmutableString & flippedVariableName,TIntermTyped * pivot,TIntermTyped * fragRotation)190 ANGLE_NO_DISCARD bool RotateAndFlipBuiltinVariable(TCompiler *compiler,
191                                                    TIntermBlock *root,
192                                                    TIntermSequence *insertSequence,
193                                                    TIntermTyped *flipXY,
194                                                    TSymbolTable *symbolTable,
195                                                    const TVariable *builtin,
196                                                    const ImmutableString &flippedVariableName,
197                                                    TIntermTyped *pivot,
198                                                    TIntermTyped *fragRotation)
199 {
200     // Create a symbol reference to 'builtin'.
201     TIntermSymbol *builtinRef = new TIntermSymbol(builtin);
202 
203     // Create a swizzle to "builtin.xy"
204     TVector<int> swizzleOffsetXY = {0, 1};
205     TIntermSwizzle *builtinXY    = new TIntermSwizzle(builtinRef, swizzleOffsetXY);
206 
207     // Create a symbol reference to our new variable that will hold the modified builtin.
208     TType *type = new TType(builtin->getType());
209     type->setQualifier(EvqGlobal);
210     type->setPrimarySize(builtin->getType().getNominalSize());
211     TVariable *replacementVar =
212         new TVariable(symbolTable, flippedVariableName, type, SymbolType::AngleInternal);
213     DeclareGlobalVariable(root, replacementVar);
214     TIntermSymbol *flippedBuiltinRef = new TIntermSymbol(replacementVar);
215 
216     // Use this new variable instead of 'builtin' everywhere.
217     if (!ReplaceVariable(compiler, root, builtin, replacementVar))
218     {
219         return false;
220     }
221 
222     // Create the expression "(builtin.xy * fragRotation)"
223     TIntermTyped *rotatedXY;
224     if (fragRotation)
225     {
226         rotatedXY = new TIntermBinary(EOpMatrixTimesVector, fragRotation, builtinXY);
227     }
228     else
229     {
230         // No rotation applied, use original variable.
231         rotatedXY = builtinXY;
232     }
233 
234     // Create the expression "(builtin.xy - pivot) * flipXY + pivot
235     TIntermBinary *removePivot = new TIntermBinary(EOpSub, rotatedXY, pivot);
236     TIntermBinary *inverseXY   = new TIntermBinary(EOpMul, removePivot, flipXY);
237     TIntermBinary *plusPivot   = new TIntermBinary(EOpAdd, inverseXY, pivot->deepCopy());
238 
239     // Create the corrected variable and copy the value of the original builtin.
240     TIntermBinary *assignment =
241         new TIntermBinary(EOpAssign, flippedBuiltinRef, builtinRef->deepCopy());
242 
243     // Create an assignment to the replaced variable's .xy.
244     TIntermSwizzle *correctedXY =
245         new TIntermSwizzle(flippedBuiltinRef->deepCopy(), swizzleOffsetXY);
246     TIntermBinary *assignToY = new TIntermBinary(EOpAssign, correctedXY, plusPivot);
247 
248     // Add this assigment at the beginning of the main function
249     insertSequence->insert(insertSequence->begin(), assignToY);
250     insertSequence->insert(insertSequence->begin(), assignment);
251 
252     return compiler->validateAST(root);
253 }
254 
GetMainSequence(TIntermBlock * root)255 TIntermSequence *GetMainSequence(TIntermBlock *root)
256 {
257     TIntermFunctionDefinition *main = FindMain(root);
258     return main->getBody()->getSequence();
259 }
260 
261 // 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)262 ANGLE_NO_DISCARD bool ReplaceGLDepthRangeWithDriverUniform(TCompiler *compiler,
263                                                            TIntermBlock *root,
264                                                            const DriverUniform *driverUniforms,
265                                                            TSymbolTable *symbolTable)
266 {
267     // Create a symbol reference to "gl_DepthRange"
268     const TVariable *depthRangeVar = static_cast<const TVariable *>(
269         symbolTable->findBuiltIn(ImmutableString("gl_DepthRange"), 0));
270 
271     // ANGLEUniforms.depthRange
272     TIntermTyped *angleEmulatedDepthRangeRef = driverUniforms->getDepthRangeRef();
273 
274     // Use this variable instead of gl_DepthRange everywhere.
275     return ReplaceVariableWithTyped(compiler, root, depthRangeVar, angleEmulatedDepthRangeRef);
276 }
277 
278 // Declares a new variable to replace gl_BoundingBoxEXT, its values are fed from a global temporary
279 // variable.
ReplaceGLBoundingBoxWithGlobal(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,int shaderVersion)280 ANGLE_NO_DISCARD bool ReplaceGLBoundingBoxWithGlobal(TCompiler *compiler,
281                                                      TIntermBlock *root,
282                                                      TSymbolTable *symbolTable,
283                                                      int shaderVersion)
284 {
285     // Declare the replacement bounding box variable type
286     TType *emulatedBoundingBoxDeclType = new TType(EbtFloat, EbpHigh, EvqGlobal, 4);
287     emulatedBoundingBoxDeclType->makeArray(2u);
288 
289     TVariable *ANGLEBoundingBoxVar = new TVariable(
290         symbolTable->nextUniqueId(), ImmutableString("ANGLEBoundingBox"), SymbolType::AngleInternal,
291         TExtension::EXT_primitive_bounding_box, emulatedBoundingBoxDeclType);
292 
293     DeclareGlobalVariable(root, ANGLEBoundingBoxVar);
294 
295     const TVariable *builtinBoundingBoxVar;
296     bool replacementResult = true;
297 
298     // Create a symbol reference to "gl_BoundingBoxEXT"
299     builtinBoundingBoxVar = static_cast<const TVariable *>(
300         symbolTable->findBuiltIn(ImmutableString("gl_BoundingBoxEXT"), shaderVersion));
301     if (builtinBoundingBoxVar != nullptr)
302     {
303         // Use the replacement variable instead of builtin gl_BoundingBoxEXT everywhere.
304         replacementResult &=
305             ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
306     }
307 
308     // Create a symbol reference to "gl_BoundingBoxOES"
309     builtinBoundingBoxVar = static_cast<const TVariable *>(
310         symbolTable->findBuiltIn(ImmutableString("gl_BoundingBoxOES"), shaderVersion));
311     if (builtinBoundingBoxVar != nullptr)
312     {
313         // Use the replacement variable instead of builtin gl_BoundingBoxOES everywhere.
314         replacementResult &=
315             ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
316     }
317 
318     if (shaderVersion >= 320)
319     {
320         // Create a symbol reference to "gl_BoundingBox"
321         builtinBoundingBoxVar = static_cast<const TVariable *>(
322             symbolTable->findBuiltIn(ImmutableString("gl_BoundingBox"), shaderVersion));
323         if (builtinBoundingBoxVar != nullptr)
324         {
325             // Use the replacement variable instead of builtin gl_BoundingBox everywhere.
326             replacementResult &=
327                 ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
328         }
329     }
330     return replacementResult;
331 }
332 
AddANGLEPositionVaryingDeclaration(TIntermBlock * root,TSymbolTable * symbolTable,TQualifier qualifier)333 TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root,
334                                               TSymbolTable *symbolTable,
335                                               TQualifier qualifier)
336 {
337     // Define a vec2 driver varying to hold the line rasterization emulation position.
338     TType *varyingType = new TType(EbtFloat, EbpMedium, qualifier, 2);
339     TVariable *varyingVar =
340         new TVariable(symbolTable, ImmutableString(vk::kLineRasterEmulationPosition), varyingType,
341                       SymbolType::AngleInternal);
342     TIntermSymbol *varyingDeclarator = new TIntermSymbol(varyingVar);
343     TIntermDeclaration *varyingDecl  = new TIntermDeclaration;
344     varyingDecl->appendDeclarator(varyingDeclarator);
345 
346     TIntermSequence insertSequence;
347     insertSequence.push_back(varyingDecl);
348 
349     // Insert the declarations before Main.
350     size_t mainIndex = FindMainIndex(root);
351     root->insertChildNodes(mainIndex, insertSequence);
352 
353     return varyingVar;
354 }
355 
AddBresenhamEmulationVS(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms)356 ANGLE_NO_DISCARD bool AddBresenhamEmulationVS(TCompiler *compiler,
357                                               TIntermBlock *root,
358                                               TSymbolTable *symbolTable,
359                                               SpecConst *specConst,
360                                               const DriverUniform *driverUniforms)
361 {
362     TVariable *anglePosition = AddANGLEPositionVaryingDeclaration(root, symbolTable, EvqVaryingOut);
363 
364     // Clamp position to subpixel grid.
365     // Do perspective divide (get normalized device coords)
366     // "vec2 ndc = gl_Position.xy / gl_Position.w"
367     const TType *vec2Type        = StaticType::GetTemporary<EbtFloat, EbpHigh, 2>();
368     TIntermTyped *viewportRef    = driverUniforms->getViewportRef();
369     TIntermSymbol *glPos         = new TIntermSymbol(BuiltInVariable::gl_Position());
370     TIntermSwizzle *glPosXY      = CreateSwizzle(glPos, 0, 1);
371     TIntermSwizzle *glPosW       = CreateSwizzle(glPos->deepCopy(), 3);
372     TVariable *ndc               = CreateTempVariable(symbolTable, vec2Type);
373     TIntermBinary *noPerspective = new TIntermBinary(EOpDiv, glPosXY, glPosW);
374     TIntermDeclaration *ndcDecl  = CreateTempInitDeclarationNode(ndc, noPerspective);
375 
376     // Convert NDC to window coordinates. According to Vulkan spec.
377     // "vec2 window = 0.5 * viewport.wh * (ndc + 1) + viewport.xy"
378     TIntermBinary *ndcPlusOne =
379         new TIntermBinary(EOpAdd, CreateTempSymbolNode(ndc), CreateFloatNode(1.0f, EbpMedium));
380     TIntermSwizzle *viewportZW = CreateSwizzle(viewportRef, 2, 3);
381     TIntermBinary *ndcViewport = new TIntermBinary(EOpMul, viewportZW, ndcPlusOne);
382     TIntermBinary *ndcViewportHalf =
383         new TIntermBinary(EOpVectorTimesScalar, ndcViewport, CreateFloatNode(0.5f, EbpMedium));
384     TIntermSwizzle *viewportXY     = CreateSwizzle(viewportRef->deepCopy(), 0, 1);
385     TIntermBinary *ndcToWindow     = new TIntermBinary(EOpAdd, ndcViewportHalf, viewportXY);
386     TVariable *windowCoords        = CreateTempVariable(symbolTable, vec2Type);
387     TIntermDeclaration *windowDecl = CreateTempInitDeclarationNode(windowCoords, ndcToWindow);
388 
389     // Clamp to subpixel grid.
390     // "vec2 clamped = round(window * 2^{subpixelBits}) / 2^{subpixelBits}"
391     int subpixelBits = compiler->getResources().SubPixelBits;
392     TIntermConstantUnion *scaleConstant =
393         CreateFloatNode(static_cast<float>(1 << subpixelBits), EbpHigh);
394     TIntermBinary *windowScaled =
395         new TIntermBinary(EOpVectorTimesScalar, CreateTempSymbolNode(windowCoords), scaleConstant);
396     TIntermTyped *windowRounded =
397         CreateBuiltInUnaryFunctionCallNode("round", windowScaled, *symbolTable, 300);
398     TIntermBinary *windowRoundedBack =
399         new TIntermBinary(EOpDiv, windowRounded, scaleConstant->deepCopy());
400     TVariable *clampedWindowCoords = CreateTempVariable(symbolTable, vec2Type);
401     TIntermDeclaration *clampedDecl =
402         CreateTempInitDeclarationNode(clampedWindowCoords, windowRoundedBack);
403 
404     // Set varying.
405     // "ANGLEPosition = 2 * (clamped - viewport.xy) / viewport.wh - 1"
406     TIntermBinary *clampedOffset = new TIntermBinary(
407         EOpSub, CreateTempSymbolNode(clampedWindowCoords), viewportXY->deepCopy());
408     TIntermBinary *clampedOff2x =
409         new TIntermBinary(EOpVectorTimesScalar, clampedOffset, CreateFloatNode(2.0f, EbpMedium));
410     TIntermBinary *clampedDivided = new TIntermBinary(EOpDiv, clampedOff2x, viewportZW->deepCopy());
411     TIntermBinary *clampedNDC =
412         new TIntermBinary(EOpSub, clampedDivided, CreateFloatNode(1.0f, EbpMedium));
413     TIntermSymbol *varyingRef    = new TIntermSymbol(anglePosition);
414     TIntermBinary *varyingAssign = new TIntermBinary(EOpAssign, varyingRef, clampedNDC);
415 
416     TIntermBlock *emulationBlock = new TIntermBlock;
417     emulationBlock->appendStatement(ndcDecl);
418     emulationBlock->appendStatement(windowDecl);
419     emulationBlock->appendStatement(clampedDecl);
420     emulationBlock->appendStatement(varyingAssign);
421     TIntermIfElse *ifEmulation =
422         new TIntermIfElse(specConst->getLineRasterEmulation(), emulationBlock, nullptr);
423 
424     // Ensure the statements run at the end of the main() function.
425     return RunAtTheEndOfShader(compiler, root, ifEmulation, symbolTable);
426 }
427 
AddXfbEmulationSupport(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const DriverUniform * driverUniforms)428 ANGLE_NO_DISCARD bool AddXfbEmulationSupport(TCompiler *compiler,
429                                              TIntermBlock *root,
430                                              TSymbolTable *symbolTable,
431                                              const DriverUniform *driverUniforms)
432 {
433     // Generate the following function and place it before main().  This function takes a "strides"
434     // parameter that is determined at link time, and calculates for each transform feedback buffer
435     // (of which there are a maximum of four) what the starting index is to write to the output
436     // buffer.
437     //
438     //     ivec4 ANGLEGetXfbOffsets(ivec4 strides)
439     //     {
440     //         int xfbIndex = gl_VertexIndex
441     //                      + gl_InstanceIndex * ANGLEUniforms.xfbVerticesPerInstance;
442     //         return ANGLEUniforms.xfbBufferOffsets + xfbIndex * strides;
443     //     }
444 
445     constexpr uint32_t kMaxXfbBuffers = 4;
446 
447     const TType *ivec4Type = StaticType::GetBasic<EbtInt, EbpHigh, kMaxXfbBuffers>();
448     TType *stridesType     = new TType(*ivec4Type);
449     stridesType->setQualifier(EvqParamConst);
450 
451     // Create the parameter variable.
452     TVariable *stridesVar = new TVariable(symbolTable, ImmutableString("strides"), stridesType,
453                                           SymbolType::AngleInternal);
454     TIntermSymbol *stridesSymbol = new TIntermSymbol(stridesVar);
455 
456     // Create references to gl_VertexIndex, gl_InstanceIndex, ANGLEUniforms.xfbVerticesPerInstance
457     // and ANGLEUniforms.xfbBufferOffsets.
458     TIntermSymbol *vertexIndex           = new TIntermSymbol(BuiltInVariable::gl_VertexIndex());
459     TIntermSymbol *instanceIndex         = new TIntermSymbol(BuiltInVariable::gl_InstanceIndex());
460     TIntermTyped *xfbVerticesPerInstance = driverUniforms->getXfbVerticesPerInstance();
461     TIntermTyped *xfbBufferOffsets       = driverUniforms->getXfbBufferOffsets();
462 
463     // gl_InstanceIndex * ANGLEUniforms.xfbVerticesPerInstance
464     TIntermBinary *xfbInstanceIndex =
465         new TIntermBinary(EOpMul, instanceIndex, xfbVerticesPerInstance);
466 
467     // gl_VertexIndex + |xfbInstanceIndex|
468     TIntermBinary *xfbIndex = new TIntermBinary(EOpAdd, vertexIndex, xfbInstanceIndex);
469 
470     // |xfbIndex| * |strides|
471     TIntermBinary *xfbStrides = new TIntermBinary(EOpVectorTimesScalar, xfbIndex, stridesSymbol);
472 
473     // ANGLEUniforms.xfbBufferOffsets + |xfbStrides|
474     TIntermBinary *xfbOffsets = new TIntermBinary(EOpAdd, xfbBufferOffsets, xfbStrides);
475 
476     // Create the function body, which has a single return statement.  Note that the `xfbIndex`
477     // variable declared in the comment at the beginning of this function is simply replaced in the
478     // return statement for brevity.
479     TIntermBlock *body = new TIntermBlock;
480     body->appendStatement(new TIntermBranch(EOpReturn, xfbOffsets));
481 
482     // Declare the function
483     TFunction *getOffsetsFunction =
484         new TFunction(symbolTable, ImmutableString(vk::kXfbEmulationGetOffsetsFunctionName),
485                       SymbolType::AngleInternal, ivec4Type, true);
486     getOffsetsFunction->addParameter(stridesVar);
487 
488     TIntermFunctionDefinition *functionDef =
489         CreateInternalFunctionDefinitionNode(*getOffsetsFunction, body);
490 
491     // Insert the function declaration before main().
492     const size_t mainIndex = FindMainIndex(root);
493     root->insertChildNodes(mainIndex, {functionDef});
494 
495     // Generate the following function and place it before main().  This function will be filled
496     // with transform feedback capture code at link time.
497     //
498     //     void ANGLECaptureXfb()
499     //     {
500     //     }
501     const TType *voidType = StaticType::GetBasic<EbtVoid, EbpUndefined>();
502 
503     // Create the function body, which is empty.
504     body = new TIntermBlock;
505 
506     // Declare the function
507     TFunction *xfbCaptureFunction =
508         new TFunction(symbolTable, ImmutableString(vk::kXfbEmulationCaptureFunctionName),
509                       SymbolType::AngleInternal, voidType, false);
510 
511     // Insert the function declaration before main().
512     root->insertChildNodes(mainIndex,
513                            {CreateInternalFunctionDefinitionNode(*xfbCaptureFunction, body)});
514 
515     // Create the following logic and add it at the end of main():
516     //
517     //     ANGLECaptureXfb();
518     //
519 
520     // Create the function call
521     TIntermAggregate *captureXfbCall =
522         TIntermAggregate::CreateFunctionCall(*xfbCaptureFunction, {});
523 
524     TIntermBlock *captureXfbBlock = new TIntermBlock;
525     captureXfbBlock->appendStatement(captureXfbCall);
526 
527     // Create a call to ANGLEGetXfbOffsets too, for the sole purpose of preventing it from being
528     // culled as unused by glslang.
529     TIntermSequence ivec4Zero;
530     ivec4Zero.push_back(CreateZeroNode(*ivec4Type));
531     TIntermAggregate *getOffsetsCall =
532         TIntermAggregate::CreateFunctionCall(*getOffsetsFunction, &ivec4Zero);
533     captureXfbBlock->appendStatement(getOffsetsCall);
534 
535     // Run it at the end of the shader.
536     if (!RunAtTheEndOfShader(compiler, root, captureXfbBlock, symbolTable))
537     {
538         return false;
539     }
540 
541     // Additionally, generate the following storage buffer declarations used to capture transform
542     // feedback output.  Again, there's a maximum of four buffers.
543     //
544     //     buffer ANGLEXfbBuffer0
545     //     {
546     //         float xfbOut[];
547     //     } ANGLEXfb0;
548     //     buffer ANGLEXfbBuffer1
549     //     {
550     //         float xfbOut[];
551     //     } ANGLEXfb1;
552     //     ...
553 
554     for (uint32_t bufferIndex = 0; bufferIndex < kMaxXfbBuffers; ++bufferIndex)
555     {
556         TFieldList *fieldList = new TFieldList;
557         TType *xfbOutType     = new TType(EbtFloat, EbpHigh, EvqGlobal);
558         xfbOutType->makeArray(0);
559 
560         TField *field = new TField(xfbOutType, ImmutableString(vk::kXfbEmulationBufferFieldName),
561                                    TSourceLoc(), SymbolType::AngleInternal);
562 
563         fieldList->push_back(field);
564 
565         static_assert(
566             kMaxXfbBuffers < 10,
567             "ImmutableStringBuilder memory size below needs to accomodate the number of buffers");
568 
569         ImmutableStringBuilder blockName(strlen(vk::kXfbEmulationBufferBlockName) + 2);
570         blockName << vk::kXfbEmulationBufferBlockName;
571         blockName.appendDecimal(bufferIndex);
572 
573         ImmutableStringBuilder varName(strlen(vk::kXfbEmulationBufferName) + 2);
574         varName << vk::kXfbEmulationBufferName;
575         varName.appendDecimal(bufferIndex);
576 
577         TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
578         layoutQualifier.blockStorage     = EbsStd430;
579 
580         DeclareInterfaceBlock(root, symbolTable, fieldList, EvqBuffer, layoutQualifier,
581                               TMemoryQualifier::Create(), 0, blockName, varName);
582     }
583 
584     return compiler->validateAST(root);
585 }
586 
AddXfbExtensionSupport(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const DriverUniform * driverUniforms)587 ANGLE_NO_DISCARD bool AddXfbExtensionSupport(TCompiler *compiler,
588                                              TIntermBlock *root,
589                                              TSymbolTable *symbolTable,
590                                              const DriverUniform *driverUniforms)
591 {
592     // Generate the following output varying declaration used to capture transform feedback output
593     // from gl_Position, as it can't be captured directly due to changes that are applied to it for
594     // clip-space correction and pre-rotation.
595     //
596     //     out vec4 ANGLEXfbPosition;
597 
598     const TType *vec4Type = nullptr;
599 
600     switch (compiler->getShaderType())
601     {
602         case GL_VERTEX_SHADER:
603             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqVertexOut, 4, 1>();
604             break;
605         case GL_TESS_EVALUATION_SHADER_EXT:
606             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqTessEvaluationOut, 4, 1>();
607             break;
608         case GL_GEOMETRY_SHADER_EXT:
609             vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqGeometryOut, 4, 1>();
610             break;
611         default:
612             UNREACHABLE();
613     }
614 
615     TVariable *varyingVar =
616         new TVariable(symbolTable, ImmutableString(vk::kXfbExtensionPositionOutName), vec4Type,
617                       SymbolType::AngleInternal);
618 
619     TIntermDeclaration *varyingDecl = new TIntermDeclaration();
620     varyingDecl->appendDeclarator(new TIntermSymbol(varyingVar));
621 
622     // Insert the varying declaration before the first function.
623     const size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
624     root->insertChildNodes(firstFunctionIndex, {varyingDecl});
625 
626     return compiler->validateAST(root);
627 }
628 
InsertFragCoordCorrection(TCompiler * compiler,ShCompileOptions compileOptions,TIntermBlock * root,TIntermSequence * insertSequence,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms)629 ANGLE_NO_DISCARD bool InsertFragCoordCorrection(TCompiler *compiler,
630                                                 ShCompileOptions compileOptions,
631                                                 TIntermBlock *root,
632                                                 TIntermSequence *insertSequence,
633                                                 TSymbolTable *symbolTable,
634                                                 SpecConst *specConst,
635                                                 const DriverUniform *driverUniforms)
636 {
637     TIntermTyped *flipXY = specConst->getFlipXY();
638     if (!flipXY)
639     {
640         flipXY = driverUniforms->getFlipXYRef();
641     }
642 
643     TIntermTyped *pivot = specConst->getHalfRenderArea();
644     if (!pivot)
645     {
646         pivot = driverUniforms->getHalfRenderAreaRef();
647     }
648 
649     TIntermTyped *fragRotation = nullptr;
650     if ((compileOptions & SH_ADD_PRE_ROTATION) != 0)
651     {
652         fragRotation = specConst->getFragRotationMatrix();
653         if (!fragRotation)
654         {
655             fragRotation = driverUniforms->getFragRotationMatrixRef();
656         }
657     }
658     const TVariable *fragCoord = static_cast<const TVariable *>(
659         symbolTable->findBuiltIn(ImmutableString("gl_FragCoord"), compiler->getShaderVersion()));
660     return RotateAndFlipBuiltinVariable(compiler, root, insertSequence, flipXY, symbolTable,
661                                         fragCoord, kFlippedFragCoordName, pivot, fragRotation);
662 }
663 
664 // This block adds OpenGL line segment rasterization emulation behind a specialization constant
665 // guard.  OpenGL's simple rasterization algorithm is a strict subset of the pixels generated by the
666 // Vulkan algorithm. Thus we can implement a shader patch that rejects pixels if they would not be
667 // generated by the OpenGL algorithm. OpenGL's algorithm is similar to Bresenham's line algorithm.
668 // It is implemented for each pixel by testing if the line segment crosses a small diamond inside
669 // the pixel. See the OpenGL ES 2.0 spec section "3.4.1 Basic Line Segment Rasterization". Also
670 // see the Vulkan spec section "24.6.1. Basic Line Segment Rasterization":
671 // https://khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#primsrast-lines-basic
672 //
673 // Using trigonometric math and the fact that we know the size of the diamond we can derive a
674 // formula to test if the line segment crosses the pixel center. gl_FragCoord is used along with an
675 // internal position varying to determine the inputs to the formula.
676 //
677 // The implementation of the test is similar to the following pseudocode:
678 //
679 // void main()
680 // {
681 //    vec2 p  = (((((ANGLEPosition.xy) * 0.5) + 0.5) * viewport.zw) + viewport.xy);
682 //    vec2 d  = dFdx(p) + dFdy(p);
683 //    vec2 f  = gl_FragCoord.xy;
684 //    vec2 p_ = p.yx;
685 //    vec2 d_ = d.yx;
686 //    vec2 f_ = f.yx;
687 //
688 //    vec2 i = abs(p - f + (d / d_) * (f_ - p_));
689 //
690 //    if (i.x > (0.5 + e) && i.y > (0.5 + e))
691 //        discard;
692 //     <otherwise run fragment shader main>
693 // }
694 //
695 // Note this emulation can not provide fully correct rasterization. See the docs more more info.
696 
AddBresenhamEmulationFS(TCompiler * compiler,ShCompileOptions compileOptions,TIntermBlock * root,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms,bool usesFragCoord)697 ANGLE_NO_DISCARD bool AddBresenhamEmulationFS(TCompiler *compiler,
698                                               ShCompileOptions compileOptions,
699                                               TIntermBlock *root,
700                                               TSymbolTable *symbolTable,
701                                               SpecConst *specConst,
702                                               const DriverUniform *driverUniforms,
703                                               bool usesFragCoord)
704 {
705     TVariable *anglePosition = AddANGLEPositionVaryingDeclaration(root, symbolTable, EvqVaryingIn);
706     const TType *vec2Type    = StaticType::GetTemporary<EbtFloat, EbpHigh, 2>();
707 
708     TIntermTyped *viewportRef = driverUniforms->getViewportRef();
709 
710     // vec2 p = ((ANGLEPosition * 0.5) + 0.5) * viewport.zw + viewport.xy
711     TIntermSwizzle *viewportXY    = CreateSwizzle(viewportRef->deepCopy(), 0, 1);
712     TIntermSwizzle *viewportZW    = CreateSwizzle(viewportRef, 2, 3);
713     TIntermSymbol *position       = new TIntermSymbol(anglePosition);
714     TIntermConstantUnion *oneHalf = CreateFloatNode(0.5f, EbpMedium);
715     TIntermBinary *halfPosition   = new TIntermBinary(EOpVectorTimesScalar, position, oneHalf);
716     TIntermBinary *offsetHalfPosition =
717         new TIntermBinary(EOpAdd, halfPosition, oneHalf->deepCopy());
718     TIntermBinary *scaledPosition = new TIntermBinary(EOpMul, offsetHalfPosition, viewportZW);
719     TIntermBinary *windowPosition = new TIntermBinary(EOpAdd, scaledPosition, viewportXY);
720     TVariable *p                  = CreateTempVariable(symbolTable, vec2Type);
721     TIntermDeclaration *pDecl     = CreateTempInitDeclarationNode(p, windowPosition);
722 
723     // vec2 d = dFdx(p) + dFdy(p)
724     TIntermTyped *dfdx =
725         CreateBuiltInUnaryFunctionCallNode("dFdx", new TIntermSymbol(p), *symbolTable, 300);
726     TIntermTyped *dfdy =
727         CreateBuiltInUnaryFunctionCallNode("dFdy", new TIntermSymbol(p), *symbolTable, 300);
728     TIntermBinary *dfsum      = new TIntermBinary(EOpAdd, dfdx, dfdy);
729     TVariable *d              = CreateTempVariable(symbolTable, vec2Type);
730     TIntermDeclaration *dDecl = CreateTempInitDeclarationNode(d, dfsum);
731 
732     // vec2 f = gl_FragCoord.xy
733     const TVariable *fragCoord = static_cast<const TVariable *>(
734         symbolTable->findBuiltIn(ImmutableString("gl_FragCoord"), compiler->getShaderVersion()));
735     TIntermSwizzle *fragCoordXY = CreateSwizzle(new TIntermSymbol(fragCoord), 0, 1);
736     TVariable *f                = CreateTempVariable(symbolTable, vec2Type);
737     TIntermDeclaration *fDecl   = CreateTempInitDeclarationNode(f, fragCoordXY);
738 
739     // vec2 p_ = p.yx
740     TIntermSwizzle *pyx        = CreateSwizzle(new TIntermSymbol(p), 1, 0);
741     TVariable *p_              = CreateTempVariable(symbolTable, vec2Type);
742     TIntermDeclaration *p_decl = CreateTempInitDeclarationNode(p_, pyx);
743 
744     // vec2 d_ = d.yx
745     TIntermSwizzle *dyx        = CreateSwizzle(new TIntermSymbol(d), 1, 0);
746     TVariable *d_              = CreateTempVariable(symbolTable, vec2Type);
747     TIntermDeclaration *d_decl = CreateTempInitDeclarationNode(d_, dyx);
748 
749     // vec2 f_ = f.yx
750     TIntermSwizzle *fyx        = CreateSwizzle(new TIntermSymbol(f), 1, 0);
751     TVariable *f_              = CreateTempVariable(symbolTable, vec2Type);
752     TIntermDeclaration *f_decl = CreateTempInitDeclarationNode(f_, fyx);
753 
754     // vec2 i = abs(p - f + (d/d_) * (f_ - p_))
755     TIntermBinary *dd   = new TIntermBinary(EOpDiv, new TIntermSymbol(d), new TIntermSymbol(d_));
756     TIntermBinary *fp   = new TIntermBinary(EOpSub, new TIntermSymbol(f_), new TIntermSymbol(p_));
757     TIntermBinary *ddfp = new TIntermBinary(EOpMul, dd, fp);
758     TIntermBinary *pf   = new TIntermBinary(EOpSub, new TIntermSymbol(p), new TIntermSymbol(f));
759     TIntermBinary *expr = new TIntermBinary(EOpAdd, pf, ddfp);
760 
761     TIntermTyped *absd        = CreateBuiltInUnaryFunctionCallNode("abs", expr, *symbolTable, 100);
762     TVariable *i              = CreateTempVariable(symbolTable, vec2Type);
763     TIntermDeclaration *iDecl = CreateTempInitDeclarationNode(i, absd);
764 
765     // Using a small epsilon value ensures that we don't suffer from numerical instability when
766     // lines are exactly vertical or horizontal.
767     static constexpr float kEpsilon   = 0.0001f;
768     static constexpr float kThreshold = 0.5 + kEpsilon;
769     TIntermConstantUnion *threshold   = CreateFloatNode(kThreshold, EbpHigh);
770 
771     // if (i.x > (0.5 + e) && i.y > (0.5 + e))
772     TIntermSwizzle *ix     = CreateSwizzle(new TIntermSymbol(i), 0);
773     TIntermBinary *checkX  = new TIntermBinary(EOpGreaterThan, ix, threshold);
774     TIntermSwizzle *iy     = CreateSwizzle(new TIntermSymbol(i), 1);
775     TIntermBinary *checkY  = new TIntermBinary(EOpGreaterThan, iy, threshold->deepCopy());
776     TIntermBinary *checkXY = new TIntermBinary(EOpLogicalAnd, checkX, checkY);
777 
778     // discard
779     TIntermBranch *discard     = new TIntermBranch(EOpKill, nullptr);
780     TIntermBlock *discardBlock = new TIntermBlock;
781     discardBlock->appendStatement(discard);
782     TIntermIfElse *ifStatement = new TIntermIfElse(checkXY, discardBlock, nullptr);
783 
784     TIntermBlock *emulationBlock       = new TIntermBlock;
785     TIntermSequence *emulationSequence = emulationBlock->getSequence();
786 
787     std::array<TIntermNode *, 8> nodes = {
788         {pDecl, dDecl, fDecl, p_decl, d_decl, f_decl, iDecl, ifStatement}};
789     emulationSequence->insert(emulationSequence->begin(), nodes.begin(), nodes.end());
790 
791     TIntermIfElse *ifEmulation =
792         new TIntermIfElse(specConst->getLineRasterEmulation(), emulationBlock, nullptr);
793 
794     // Ensure the line raster code runs at the beginning of main().
795     TIntermFunctionDefinition *main = FindMain(root);
796     TIntermSequence *mainSequence   = main->getBody()->getSequence();
797     ASSERT(mainSequence);
798 
799     mainSequence->insert(mainSequence->begin(), ifEmulation);
800 
801     // If the shader does not use frag coord, we should insert it inside the emulation if.
802     if (!usesFragCoord)
803     {
804         if (!InsertFragCoordCorrection(compiler, compileOptions, root, emulationSequence,
805                                        symbolTable, specConst, driverUniforms))
806         {
807             return false;
808         }
809     }
810 
811     return compiler->validateAST(root);
812 }
813 
HasFramebufferFetch(const TExtensionBehavior & extBehavior)814 bool HasFramebufferFetch(const TExtensionBehavior &extBehavior)
815 {
816     return IsExtensionEnabled(extBehavior, TExtension::EXT_shader_framebuffer_fetch) ||
817            IsExtensionEnabled(extBehavior, TExtension::EXT_shader_framebuffer_fetch_non_coherent) ||
818            IsExtensionEnabled(extBehavior, TExtension::ARM_shader_framebuffer_fetch) ||
819            IsExtensionEnabled(extBehavior, TExtension::NV_shader_framebuffer_fetch);
820 }
821 }  // anonymous namespace
822 
TranslatorVulkan(sh::GLenum type,ShShaderSpec spec)823 TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec)
824     : TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT)
825 {}
826 
translateImpl(TInfoSinkBase & sink,TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics *,SpecConst * specConst,DriverUniform * driverUniforms)827 bool TranslatorVulkan::translateImpl(TInfoSinkBase &sink,
828                                      TIntermBlock *root,
829                                      ShCompileOptions compileOptions,
830                                      PerformanceDiagnostics * /*perfDiagnostics*/,
831                                      SpecConst *specConst,
832                                      DriverUniform *driverUniforms)
833 {
834     if (getShaderType() == GL_VERTEX_SHADER)
835     {
836         if (!ShaderBuiltinsWorkaround(this, root, &getSymbolTable(), compileOptions))
837         {
838             return false;
839         }
840     }
841 
842     sink << "#version 450 core\n";
843     writeExtensionBehavior(compileOptions, sink);
844     WritePragma(sink, compileOptions, getPragma());
845 
846     // Write out default uniforms into a uniform block assigned to a specific set/binding.
847     int defaultUniformCount           = 0;
848     int aggregateTypesUsedForUniforms = 0;
849     int r32fImageCount                = 0;
850     int atomicCounterCount            = 0;
851     for (const auto &uniform : getUniforms())
852     {
853         if (!uniform.isBuiltIn() && uniform.active && !gl::IsOpaqueType(uniform.type))
854         {
855             ++defaultUniformCount;
856         }
857 
858         if (uniform.isStruct() || uniform.isArrayOfArrays())
859         {
860             ++aggregateTypesUsedForUniforms;
861         }
862 
863         if (uniform.active && gl::IsImageType(uniform.type) && uniform.imageUnitFormat == GL_R32F)
864         {
865             ++r32fImageCount;
866         }
867 
868         if (uniform.active && gl::IsAtomicCounterType(uniform.type))
869         {
870             ++atomicCounterCount;
871         }
872     }
873 
874     // Remove declarations of inactive shader interface variables so glslang wrapper doesn't need to
875     // replace them.  Note: this is done before extracting samplers from structs, as removing such
876     // inactive samplers is not yet supported.  Note also that currently, CollectVariables marks
877     // every field of an active uniform that's of struct type as active, i.e. no extracted sampler
878     // is inactive.
879     if (!RemoveInactiveInterfaceVariables(this, root, &getSymbolTable(), getAttributes(),
880                                           getInputVaryings(), getOutputVariables(), getUniforms(),
881                                           getInterfaceBlocks(), true))
882     {
883         return false;
884     }
885 
886     // If there are any function calls that take array-of-array of opaque uniform parameters, or
887     // other opaque uniforms that need special handling in Vulkan, such as atomic counters,
888     // monomorphize the functions by removing said parameters and replacing them in the function
889     // body with the call arguments.
890     //
891     // This has a few benefits:
892     //
893     // - It dramatically simplifies future transformations w.r.t to samplers in structs, array of
894     //   arrays of opaque types, atomic counters etc.
895     // - Avoids the need for shader*ArrayDynamicIndexing Vulkan features.
896     if (!MonomorphizeUnsupportedFunctions(this, root, &getSymbolTable(), compileOptions))
897     {
898         return false;
899     }
900 
901     if (aggregateTypesUsedForUniforms > 0)
902     {
903         if (!SeparateStructFromUniformDeclarations(this, root, &getSymbolTable()))
904         {
905             return false;
906         }
907 
908         int removedUniformsCount;
909 
910         if (!RewriteStructSamplers(this, root, &getSymbolTable(), &removedUniformsCount))
911         {
912             return false;
913         }
914         defaultUniformCount -= removedUniformsCount;
915     }
916 
917     // Replace array of array of opaque uniforms with a flattened array.  This is run after
918     // MonomorphizeUnsupportedFunctions and RewriteStructSamplers so that it's not possible for an
919     // array of array of opaque type to be partially subscripted and passed to a function.
920     if (!RewriteArrayOfArrayOfOpaqueUniforms(this, root, &getSymbolTable()))
921     {
922         return false;
923     }
924 
925     // Rewrite samplerCubes as sampler2DArrays.  This must be done after rewriting struct samplers
926     // as it doesn't expect that.
927     if ((compileOptions & SH_EMULATE_SEAMFUL_CUBE_MAP_SAMPLING) != 0)
928     {
929         if (!RewriteCubeMapSamplersAs2DArray(this, root, &getSymbolTable(),
930                                              getShaderType() == GL_FRAGMENT_SHADER))
931         {
932             return false;
933         }
934     }
935 
936     if (!FlagSamplersForTexelFetch(this, root, &getSymbolTable(), &mUniforms))
937     {
938         return false;
939     }
940 
941     gl::ShaderType packedShaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
942 
943     if (defaultUniformCount > 0)
944     {
945         if (!DeclareDefaultUniforms(this, root, &getSymbolTable(), packedShaderType))
946         {
947             return false;
948         }
949     }
950 
951     if (getShaderType() == GL_COMPUTE_SHADER)
952     {
953         driverUniforms->addComputeDriverUniformsToShader(root, &getSymbolTable());
954     }
955     else
956     {
957         driverUniforms->addGraphicsDriverUniformsToShader(root, &getSymbolTable());
958     }
959 
960     if (r32fImageCount > 0)
961     {
962         if (!RewriteR32fImages(this, root, &getSymbolTable()))
963         {
964             return false;
965         }
966     }
967 
968     if (atomicCounterCount > 0)
969     {
970         // ANGLEUniforms.acbBufferOffsets
971         const TIntermTyped *acbBufferOffsets = driverUniforms->getAbcBufferOffsets();
972         if (!RewriteAtomicCounters(this, root, &getSymbolTable(), acbBufferOffsets))
973         {
974             return false;
975         }
976     }
977     else if (getShaderVersion() >= 310)
978     {
979         // Vulkan doesn't support Atomic Storage as a Storage Class, but we've seen
980         // cases where builtins are using it even with no active atomic counters.
981         // This pass simply removes those builtins in that scenario.
982         if (!RemoveAtomicCounterBuiltins(this, root))
983         {
984             return false;
985         }
986     }
987 
988     if (packedShaderType != gl::ShaderType::Compute)
989     {
990         if (!ReplaceGLDepthRangeWithDriverUniform(this, root, driverUniforms, &getSymbolTable()))
991         {
992             return false;
993         }
994 
995         // Search for the gl_ClipDistance/gl_CullDistance usage, if its used, we need to do some
996         // replacements.
997         bool useClipDistance = false;
998         bool useCullDistance = false;
999         for (const ShaderVariable &outputVarying : mOutputVaryings)
1000         {
1001             if (outputVarying.name == "gl_ClipDistance")
1002             {
1003                 useClipDistance = true;
1004             }
1005             else if (outputVarying.name == "gl_CullDistance")
1006             {
1007                 useCullDistance = true;
1008             }
1009         }
1010         for (const ShaderVariable &inputVarying : mInputVaryings)
1011         {
1012             if (inputVarying.name == "gl_ClipDistance")
1013             {
1014                 useClipDistance = true;
1015             }
1016             else if (inputVarying.name == "gl_CullDistance")
1017             {
1018                 useCullDistance = true;
1019             }
1020         }
1021 
1022         if (useClipDistance &&
1023             !ReplaceClipDistanceAssignments(this, root, &getSymbolTable(), getShaderType(),
1024                                             driverUniforms->getClipDistancesEnabled()))
1025         {
1026             return false;
1027         }
1028         if (useCullDistance &&
1029             !ReplaceCullDistanceAssignments(this, root, &getSymbolTable(), getShaderType()))
1030         {
1031             return false;
1032         }
1033     }
1034 
1035     if (gl::ShaderTypeSupportsTransformFeedback(packedShaderType))
1036     {
1037         if ((compileOptions & SH_ADD_VULKAN_XFB_EXTENSION_SUPPORT_CODE) != 0)
1038         {
1039             // Add support code for transform feedback extension.
1040             if (!AddXfbExtensionSupport(this, root, &getSymbolTable(), driverUniforms))
1041             {
1042                 return false;
1043             }
1044         }
1045     }
1046 
1047     switch (packedShaderType)
1048     {
1049         case gl::ShaderType::Fragment:
1050         {
1051             bool usesPointCoord    = false;
1052             bool usesFragCoord     = false;
1053             bool usesSampleMaskIn  = false;
1054             bool useSamplePosition = false;
1055 
1056             // Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate.
1057             for (const ShaderVariable &inputVarying : mInputVaryings)
1058             {
1059                 if (!inputVarying.isBuiltIn())
1060                 {
1061                     continue;
1062                 }
1063 
1064                 if (inputVarying.name == "gl_SampleMaskIn")
1065                 {
1066                     usesSampleMaskIn = true;
1067                     continue;
1068                 }
1069 
1070                 if (inputVarying.name == "gl_SamplePosition")
1071                 {
1072                     useSamplePosition = true;
1073                     continue;
1074                 }
1075 
1076                 if (inputVarying.name == "gl_PointCoord")
1077                 {
1078                     usesPointCoord = true;
1079                     break;
1080                 }
1081 
1082                 if (inputVarying.name == "gl_FragCoord")
1083                 {
1084                     usesFragCoord = true;
1085                     break;
1086                 }
1087             }
1088 
1089             if ((compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION) != 0)
1090             {
1091                 if (!AddBresenhamEmulationFS(this, compileOptions, root, &getSymbolTable(),
1092                                              specConst, driverUniforms, usesFragCoord))
1093                 {
1094                     return false;
1095                 }
1096             }
1097 
1098             bool usePreRotation  = (compileOptions & SH_ADD_PRE_ROTATION) != 0;
1099             bool hasGLSampleMask = false;
1100 
1101             for (const ShaderVariable &outputVar : mOutputVariables)
1102             {
1103                 if (outputVar.name == "gl_SampleMask")
1104                 {
1105                     ASSERT(!hasGLSampleMask);
1106                     hasGLSampleMask = true;
1107                     continue;
1108                 }
1109             }
1110 
1111             if (usesPointCoord)
1112             {
1113                 TIntermTyped *flipNegXY = specConst->getNegFlipXY();
1114                 if (!flipNegXY)
1115                 {
1116                     flipNegXY = driverUniforms->getNegFlipXYRef();
1117                 }
1118                 TIntermConstantUnion *pivot = CreateFloatNode(0.5f, EbpMedium);
1119                 TIntermTyped *fragRotation  = nullptr;
1120                 if (usePreRotation)
1121                 {
1122                     fragRotation = specConst->getFragRotationMatrix();
1123                     if (!fragRotation)
1124                     {
1125                         fragRotation = driverUniforms->getFragRotationMatrixRef();
1126                     }
1127                 }
1128                 if (!RotateAndFlipBuiltinVariable(this, root, GetMainSequence(root), flipNegXY,
1129                                                   &getSymbolTable(),
1130                                                   BuiltInVariable::gl_PointCoord(),
1131                                                   kFlippedPointCoordName, pivot, fragRotation))
1132                 {
1133                     return false;
1134                 }
1135             }
1136 
1137             if (useSamplePosition)
1138             {
1139                 TIntermTyped *flipXY = specConst->getFlipXY();
1140                 if (!flipXY)
1141                 {
1142                     flipXY = driverUniforms->getFlipXYRef();
1143                 }
1144                 TIntermConstantUnion *pivot = CreateFloatNode(0.5f, EbpMedium);
1145                 TIntermTyped *fragRotation  = nullptr;
1146                 if (usePreRotation)
1147                 {
1148                     fragRotation = specConst->getFragRotationMatrix();
1149                     if (!fragRotation)
1150                     {
1151                         fragRotation = driverUniforms->getFragRotationMatrixRef();
1152                     }
1153                 }
1154 
1155                 const TVariable *samplePositionBuiltin =
1156                     static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
1157                         ImmutableString("gl_SamplePosition"), getShaderVersion()));
1158                 if (!RotateAndFlipBuiltinVariable(this, root, GetMainSequence(root), flipXY,
1159                                                   &getSymbolTable(), samplePositionBuiltin,
1160                                                   kFlippedPointCoordName, pivot, fragRotation))
1161                 {
1162                     return false;
1163                 }
1164             }
1165 
1166             if (usesFragCoord)
1167             {
1168                 if (!InsertFragCoordCorrection(this, compileOptions, root, GetMainSequence(root),
1169                                                &getSymbolTable(), specConst, driverUniforms))
1170                 {
1171                     return false;
1172                 }
1173             }
1174 
1175             if (HasFramebufferFetch(getExtensionBehavior()))
1176             {
1177                 if (getShaderVersion() == 100)
1178                 {
1179                     if (!ReplaceLastFragData(this, root, &getSymbolTable(), &mUniforms))
1180                     {
1181                         return false;
1182                     }
1183                 }
1184                 else
1185                 {
1186                     if (!ReplaceInOutVariables(this, root, &getSymbolTable(), &mUniforms))
1187                     {
1188                         return false;
1189                     }
1190                 }
1191             }
1192 
1193             // Emulate gl_FragColor and gl_FragData with normal output variables.
1194             if (!EmulateFragColorData(this, root, &getSymbolTable()))
1195             {
1196                 return false;
1197             }
1198 
1199             // This should be operated after doing ReplaceLastFragData and ReplaceInOutVariables,
1200             // because they will create the input attachment variables. AddBlendMainCaller will
1201             // check the existing input attachment variables and if there is no existing input
1202             // attachment variable then create a new one.
1203             if (getAdvancedBlendEquations().any() &&
1204                 (compileOptions & SH_ADD_ADVANCED_BLEND_EQUATIONS_EMULATION) != 0 &&
1205                 !EmulateAdvancedBlendEquations(this, root, &getSymbolTable(), driverUniforms,
1206                                                &mUniforms, getAdvancedBlendEquations()))
1207             {
1208                 return false;
1209             }
1210 
1211             if (!RewriteDfdy(this, compileOptions, root, getSymbolTable(), getShaderVersion(),
1212                              specConst, driverUniforms))
1213             {
1214                 return false;
1215             }
1216 
1217             if (!RewriteInterpolateAtOffset(this, compileOptions, root, getSymbolTable(),
1218                                             getShaderVersion(), specConst, driverUniforms))
1219             {
1220                 return false;
1221             }
1222 
1223             if (usesSampleMaskIn && !RewriteSampleMaskIn(this, root, &getSymbolTable()))
1224             {
1225                 return false;
1226             }
1227 
1228             if (hasGLSampleMask)
1229             {
1230                 TIntermTyped *numSamples = driverUniforms->getNumSamplesRef();
1231                 if (!RewriteSampleMask(this, root, &getSymbolTable(), numSamples))
1232                 {
1233                     return false;
1234                 }
1235             }
1236 
1237             {
1238                 const TVariable *numSamplesVar =
1239                     static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
1240                         ImmutableString("gl_NumSamples"), getShaderVersion()));
1241                 TIntermTyped *numSamples = driverUniforms->getNumSamplesRef();
1242                 if (!ReplaceVariableWithTyped(this, root, numSamplesVar, numSamples))
1243                 {
1244                     return false;
1245                 }
1246             }
1247 
1248             if (!EmulateDithering(this, root, &getSymbolTable(), specConst, driverUniforms))
1249             {
1250                 return false;
1251             }
1252 
1253             EmitEarlyFragmentTestsGLSL(*this, sink);
1254             break;
1255         }
1256 
1257         case gl::ShaderType::Vertex:
1258         {
1259             if ((compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION) != 0)
1260             {
1261                 if (!AddBresenhamEmulationVS(this, root, &getSymbolTable(), specConst,
1262                                              driverUniforms))
1263                 {
1264                     return false;
1265                 }
1266             }
1267 
1268             if ((compileOptions & SH_ADD_VULKAN_XFB_EMULATION_SUPPORT_CODE) != 0)
1269             {
1270                 // Add support code for transform feedback emulation.  Only applies to vertex shader
1271                 // as tessellation and geometry shader transform feedback capture require
1272                 // VK_EXT_transform_feedback.
1273                 if (!AddXfbEmulationSupport(this, root, &getSymbolTable(), driverUniforms))
1274                 {
1275                     return false;
1276                 }
1277             }
1278 
1279             // Append depth range translation to main.
1280             if (!transformDepthBeforeCorrection(root, driverUniforms))
1281             {
1282                 return false;
1283             }
1284 
1285             break;
1286         }
1287 
1288         case gl::ShaderType::Geometry:
1289         {
1290             int maxVertices = getGeometryShaderMaxVertices();
1291 
1292             // max_vertices=0 is not valid in Vulkan
1293             maxVertices = std::max(1, maxVertices);
1294 
1295             WriteGeometryShaderLayoutQualifiers(
1296                 sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
1297                 getGeometryShaderOutputPrimitiveType(), maxVertices);
1298             break;
1299         }
1300 
1301         case gl::ShaderType::TessControl:
1302         {
1303             if (!ReplaceGLBoundingBoxWithGlobal(this, root, &getSymbolTable(), getShaderVersion()))
1304             {
1305                 return false;
1306             }
1307             WriteTessControlShaderLayoutQualifiers(sink, getTessControlShaderOutputVertices());
1308             break;
1309         }
1310 
1311         case gl::ShaderType::TessEvaluation:
1312         {
1313             WriteTessEvaluationShaderLayoutQualifiers(
1314                 sink, getTessEvaluationShaderInputPrimitiveType(),
1315                 getTessEvaluationShaderInputVertexSpacingType(),
1316                 getTessEvaluationShaderInputOrderingType(),
1317                 getTessEvaluationShaderInputPointType());
1318             break;
1319         }
1320 
1321         case gl::ShaderType::Compute:
1322         {
1323             EmitWorkGroupSizeGLSL(*this, sink);
1324             break;
1325         }
1326 
1327         default:
1328             UNREACHABLE();
1329             break;
1330     }
1331 
1332     specConst->declareSpecConsts(root);
1333     mValidateASTOptions.validateSpecConstReferences = true;
1334 
1335     // Gather specialization constant usage bits so that we can feedback to context.
1336     mSpecConstUsageBits = specConst->getSpecConstUsageBits();
1337 
1338     if (!validateAST(root))
1339     {
1340         return false;
1341     }
1342 
1343     // Make sure function call validation is not accidentally left off anywhere.
1344     ASSERT(mValidateASTOptions.validateFunctionCall);
1345     ASSERT(mValidateASTOptions.validateNoRawFunctionCalls);
1346 
1347     return true;
1348 }
1349 
writeExtensionBehavior(ShCompileOptions compileOptions,TInfoSinkBase & sink)1350 void TranslatorVulkan::writeExtensionBehavior(ShCompileOptions compileOptions, TInfoSinkBase &sink)
1351 {
1352     const TExtensionBehavior &extBehavior = getExtensionBehavior();
1353     TBehavior multiviewBehavior           = EBhUndefined;
1354     TBehavior multiview2Behavior          = EBhUndefined;
1355     for (const auto &iter : extBehavior)
1356     {
1357         if (iter.second == EBhUndefined || iter.second == EBhDisable)
1358         {
1359             continue;
1360         }
1361 
1362         switch (iter.first)
1363         {
1364             case TExtension::OVR_multiview:
1365                 multiviewBehavior = iter.second;
1366                 break;
1367             case TExtension::OVR_multiview2:
1368                 multiviewBehavior = iter.second;
1369                 break;
1370             default:
1371                 break;
1372         }
1373     }
1374 
1375     if (multiviewBehavior != EBhUndefined || multiview2Behavior != EBhUndefined)
1376     {
1377         // Only either OVR_multiview or OVR_multiview2 should be emitted.
1378         TExtension ext     = TExtension::OVR_multiview;
1379         TBehavior behavior = multiviewBehavior;
1380         if (multiview2Behavior != EBhUndefined)
1381         {
1382             ext      = TExtension::OVR_multiview2;
1383             behavior = multiview2Behavior;
1384         }
1385         EmitMultiviewGLSL(*this, compileOptions, ext, behavior, sink);
1386     }
1387 }
1388 
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics * perfDiagnostics)1389 bool TranslatorVulkan::translate(TIntermBlock *root,
1390                                  ShCompileOptions compileOptions,
1391                                  PerformanceDiagnostics *perfDiagnostics)
1392 {
1393     TInfoSinkBase sink;
1394 
1395     SpecConst specConst(&getSymbolTable(), compileOptions, getShaderType());
1396 
1397     if ((compileOptions & SH_USE_SPECIALIZATION_CONSTANT) != 0)
1398     {
1399         DriverUniform driverUniforms(DriverUniformMode::InterfaceBlock);
1400         if (!translateImpl(sink, root, compileOptions, perfDiagnostics, &specConst,
1401                            &driverUniforms))
1402         {
1403             return false;
1404         }
1405     }
1406     else
1407     {
1408         DriverUniformExtended driverUniformsExt(DriverUniformMode::InterfaceBlock);
1409         if (!translateImpl(sink, root, compileOptions, perfDiagnostics, &specConst,
1410                            &driverUniformsExt))
1411         {
1412             return false;
1413         }
1414     }
1415 
1416 #if defined(ANGLE_ENABLE_SPIRV_GENERATION_THROUGH_GLSLANG)
1417     if ((compileOptions & SH_GENERATE_SPIRV_THROUGH_GLSLANG) != 0)
1418     {
1419         // When generating text, glslang cannot know the precision of folded constants so it may
1420         // infer the wrong precisions.  The following transformation gives constants names with
1421         // precision to guide glslang.  This is not an issue for SPIR-V generation because the
1422         // precision information is present in the tree already.
1423         if (!RecordConstantPrecision(this, root, &getSymbolTable()))
1424         {
1425             return false;
1426         }
1427 
1428         const bool enablePrecision = (compileOptions & SH_IGNORE_PRECISION_QUALIFIERS) == 0;
1429 
1430         // Write translated shader.
1431         TOutputVulkanGLSL outputGLSL(this, sink, enablePrecision, compileOptions);
1432         root->traverse(&outputGLSL);
1433 
1434         return compileToSpirv(sink);
1435     }
1436 #endif
1437 
1438     // Declare the implicitly defined gl_PerVertex I/O blocks if not already.  This will help SPIR-V
1439     // generation treat them mostly like usual I/O blocks.
1440     if (!DeclarePerVertexBlocks(this, root, &getSymbolTable()))
1441     {
1442         return false;
1443     }
1444 
1445     return OutputSPIRV(this, root, compileOptions);
1446 }
1447 
shouldFlattenPragmaStdglInvariantAll()1448 bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
1449 {
1450     // Not necessary.
1451     return false;
1452 }
1453 
compileToSpirv(const TInfoSinkBase & glsl)1454 bool TranslatorVulkan::compileToSpirv(const TInfoSinkBase &glsl)
1455 {
1456     angle::spirv::Blob spirvBlob;
1457     if (!GlslangCompileToSpirv(getResources(), getShaderType(), glsl.str(), &spirvBlob))
1458     {
1459         return false;
1460     }
1461 
1462     getInfoSink().obj.setBinary(std::move(spirvBlob));
1463     return true;
1464 }
1465 }  // namespace sh
1466