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