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