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.
8 //   The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side).
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/OutputVulkanGLSL.h"
20 #include "compiler/translator/StaticType.h"
21 #include "compiler/translator/tree_ops/NameEmbeddedUniformStructs.h"
22 #include "compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.h"
23 #include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
24 #include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
25 #include "compiler/translator/tree_ops/RewriteCubeMapSamplersAs2DArray.h"
26 #include "compiler/translator/tree_ops/RewriteDfdy.h"
27 #include "compiler/translator/tree_ops/RewriteStructSamplers.h"
28 #include "compiler/translator/tree_util/BuiltIn.h"
29 #include "compiler/translator/tree_util/FindFunction.h"
30 #include "compiler/translator/tree_util/FindMain.h"
31 #include "compiler/translator/tree_util/IntermNode_util.h"
32 #include "compiler/translator/tree_util/ReplaceVariable.h"
33 #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
34 #include "compiler/translator/util.h"
35 
36 namespace sh
37 {
38 
39 namespace
40 {
41 // This traverses nodes, find the struct ones and add their declarations to the sink. It also
42 // removes the nodes from the tree as it processes them.
43 class DeclareStructTypesTraverser : public TIntermTraverser
44 {
45   public:
DeclareStructTypesTraverser(TOutputVulkanGLSL * outputVulkanGLSL)46     explicit DeclareStructTypesTraverser(TOutputVulkanGLSL *outputVulkanGLSL)
47         : TIntermTraverser(true, false, false), mOutputVulkanGLSL(outputVulkanGLSL)
48     {}
49 
visitDeclaration(Visit visit,TIntermDeclaration * node)50     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
51     {
52         ASSERT(visit == PreVisit);
53 
54         if (!mInGlobalScope)
55         {
56             return false;
57         }
58 
59         const TIntermSequence &sequence = *(node->getSequence());
60         TIntermTyped *declarator        = sequence.front()->getAsTyped();
61         const TType &type               = declarator->getType();
62 
63         if (type.isStructSpecifier())
64         {
65             const TStructure *structure = type.getStruct();
66 
67             // Embedded structs should be parsed away by now.
68             ASSERT(structure->symbolType() != SymbolType::Empty);
69             mOutputVulkanGLSL->writeStructType(structure);
70 
71             TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
72             if (symbolNode && symbolNode->variable().symbolType() == SymbolType::Empty)
73             {
74                 // Remove the struct specifier declaration from the tree so it isn't parsed again.
75                 TIntermSequence emptyReplacement;
76                 mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
77                                                 emptyReplacement);
78             }
79         }
80 
81         return false;
82     }
83 
84   private:
85     TOutputVulkanGLSL *mOutputVulkanGLSL;
86 };
87 
88 class DeclareDefaultUniformsTraverser : public TIntermTraverser
89 {
90   public:
DeclareDefaultUniformsTraverser(TInfoSinkBase * sink,ShHashFunction64 hashFunction,NameMap * nameMap)91     DeclareDefaultUniformsTraverser(TInfoSinkBase *sink,
92                                     ShHashFunction64 hashFunction,
93                                     NameMap *nameMap)
94         : TIntermTraverser(true, true, true),
95           mSink(sink),
96           mHashFunction(hashFunction),
97           mNameMap(nameMap),
98           mInDefaultUniform(false)
99     {}
100 
visitDeclaration(Visit visit,TIntermDeclaration * node)101     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
102     {
103         const TIntermSequence &sequence = *(node->getSequence());
104 
105         // TODO(jmadill): Compound declarations.
106         ASSERT(sequence.size() == 1);
107 
108         TIntermTyped *variable = sequence.front()->getAsTyped();
109         const TType &type      = variable->getType();
110         bool isUniform         = type.getQualifier() == EvqUniform && !type.isInterfaceBlock() &&
111                          !IsOpaqueType(type.getBasicType());
112 
113         if (visit == PreVisit)
114         {
115             if (isUniform)
116             {
117                 (*mSink) << "    " << GetTypeName(type, mHashFunction, mNameMap) << " ";
118                 mInDefaultUniform = true;
119             }
120         }
121         else if (visit == InVisit)
122         {
123             mInDefaultUniform = isUniform;
124         }
125         else if (visit == PostVisit)
126         {
127             if (isUniform)
128             {
129                 (*mSink) << ";\n";
130 
131                 // Remove the uniform declaration from the tree so it isn't parsed again.
132                 TIntermSequence emptyReplacement;
133                 mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
134                                                 emptyReplacement);
135             }
136 
137             mInDefaultUniform = false;
138         }
139         return true;
140     }
141 
visitSymbol(TIntermSymbol * symbol)142     void visitSymbol(TIntermSymbol *symbol) override
143     {
144         if (mInDefaultUniform)
145         {
146             const ImmutableString &name = symbol->variable().name();
147             ASSERT(!name.beginsWith("gl_"));
148             (*mSink) << HashName(&symbol->variable(), mHashFunction, mNameMap)
149                      << ArrayString(symbol->getType());
150         }
151     }
152 
153   private:
154     TInfoSinkBase *mSink;
155     ShHashFunction64 mHashFunction;
156     NameMap *mNameMap;
157     bool mInDefaultUniform;
158 };
159 
160 constexpr ImmutableString kFlippedPointCoordName    = ImmutableString("flippedPointCoord");
161 constexpr ImmutableString kFlippedFragCoordName     = ImmutableString("flippedFragCoord");
162 constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
163 
164 constexpr gl::ShaderMap<const char *> kDefaultUniformNames = {
165     {gl::ShaderType::Vertex, vk::kDefaultUniformsNameVS},
166     {gl::ShaderType::Geometry, vk::kDefaultUniformsNameGS},
167     {gl::ShaderType::Fragment, vk::kDefaultUniformsNameFS},
168     {gl::ShaderType::Compute, vk::kDefaultUniformsNameCS},
169 };
170 
171 // Specialization constant names
172 constexpr ImmutableString kLineRasterEmulationSpecConstVarName =
173     ImmutableString("ANGLELineRasterEmulation");
174 
175 constexpr const char kViewport[]             = "viewport";
176 constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight";
177 constexpr const char kViewportYScale[]       = "viewportYScale";
178 constexpr const char kNegViewportYScale[]    = "negViewportYScale";
179 constexpr const char kXfbActiveUnpaused[]    = "xfbActiveUnpaused";
180 constexpr const char kXfbVerticesPerDraw[]   = "xfbVerticesPerDraw";
181 constexpr const char kXfbBufferOffsets[]     = "xfbBufferOffsets";
182 constexpr const char kAcbBufferOffsets[]     = "acbBufferOffsets";
183 constexpr const char kDepthRange[]           = "depthRange";
184 constexpr const char kPreRotation[]          = "preRotation";
185 
186 constexpr size_t kNumGraphicsDriverUniforms                                                = 10;
187 constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {
188     {kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, kXfbActiveUnpaused,
189      kXfbVerticesPerDraw, kXfbBufferOffsets, kAcbBufferOffsets, kDepthRange, kPreRotation}};
190 
191 constexpr size_t kNumComputeDriverUniforms                                               = 1;
192 constexpr std::array<const char *, kNumComputeDriverUniforms> kComputeDriverUniformNames = {
193     {kAcbBufferOffsets}};
194 
FindFieldIndex(const TFieldList & fieldList,const char * fieldName)195 size_t FindFieldIndex(const TFieldList &fieldList, const char *fieldName)
196 {
197     for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex)
198     {
199         if (strcmp(fieldList[fieldIndex]->name().data(), fieldName) == 0)
200         {
201             return fieldIndex;
202         }
203     }
204     UNREACHABLE();
205     return 0;
206 }
207 
CreateDriverUniformRef(const TVariable * driverUniforms,const char * fieldName)208 TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, const char *fieldName)
209 {
210     size_t fieldIndex =
211         FindFieldIndex(driverUniforms->getType().getInterfaceBlock()->fields(), fieldName);
212 
213     TIntermSymbol *angleUniformsRef = new TIntermSymbol(driverUniforms);
214     TConstantUnion *uniformIndex    = new TConstantUnion;
215     uniformIndex->setIConst(static_cast<int>(fieldIndex));
216     TIntermConstantUnion *indexRef =
217         new TIntermConstantUnion(uniformIndex, *StaticType::GetBasic<EbtInt>());
218     return new TIntermBinary(EOpIndexDirectInterfaceBlock, angleUniformsRef, indexRef);
219 }
220 
221 // Replaces a builtin variable with a version that corrects the Y coordinate.
FlipBuiltinVariable(TCompiler * compiler,TIntermBlock * root,TIntermSequence * insertSequence,TIntermTyped * viewportYScale,TSymbolTable * symbolTable,const TVariable * builtin,const ImmutableString & flippedVariableName,TIntermTyped * pivot)222 ANGLE_NO_DISCARD bool FlipBuiltinVariable(TCompiler *compiler,
223                                           TIntermBlock *root,
224                                           TIntermSequence *insertSequence,
225                                           TIntermTyped *viewportYScale,
226                                           TSymbolTable *symbolTable,
227                                           const TVariable *builtin,
228                                           const ImmutableString &flippedVariableName,
229                                           TIntermTyped *pivot)
230 {
231     // Create a symbol reference to 'builtin'.
232     TIntermSymbol *builtinRef = new TIntermSymbol(builtin);
233 
234     // Create a swizzle to "builtin.y"
235     TVector<int> swizzleOffsetY = {1};
236     TIntermSwizzle *builtinY    = new TIntermSwizzle(builtinRef, swizzleOffsetY);
237 
238     // Create a symbol reference to our new variable that will hold the modified builtin.
239     const TType *type = StaticType::GetForVec<EbtFloat>(
240         EvqGlobal, static_cast<unsigned char>(builtin->getType().getNominalSize()));
241     TVariable *replacementVar =
242         new TVariable(symbolTable, flippedVariableName, type, SymbolType::AngleInternal);
243     DeclareGlobalVariable(root, replacementVar);
244     TIntermSymbol *flippedBuiltinRef = new TIntermSymbol(replacementVar);
245 
246     // Use this new variable instead of 'builtin' everywhere.
247     if (!ReplaceVariable(compiler, root, builtin, replacementVar))
248     {
249         return false;
250     }
251 
252     // Create the expression "(builtin.y - pivot) * viewportYScale + pivot
253     TIntermBinary *removePivot = new TIntermBinary(EOpSub, builtinY, pivot);
254     TIntermBinary *inverseY    = new TIntermBinary(EOpMul, removePivot, viewportYScale);
255     TIntermBinary *plusPivot   = new TIntermBinary(EOpAdd, inverseY, pivot->deepCopy());
256 
257     // Create the corrected variable and copy the value of the original builtin.
258     TIntermSequence *sequence = new TIntermSequence();
259     sequence->push_back(builtinRef->deepCopy());
260     TIntermAggregate *aggregate = TIntermAggregate::CreateConstructor(builtin->getType(), sequence);
261     TIntermBinary *assignment   = new TIntermBinary(EOpInitialize, flippedBuiltinRef, aggregate);
262 
263     // Create an assignment to the replaced variable's y.
264     TIntermSwizzle *correctedY = new TIntermSwizzle(flippedBuiltinRef->deepCopy(), swizzleOffsetY);
265     TIntermBinary *assignToY   = new TIntermBinary(EOpAssign, correctedY, plusPivot);
266 
267     // Add this assigment at the beginning of the main function
268     insertSequence->insert(insertSequence->begin(), assignToY);
269     insertSequence->insert(insertSequence->begin(), assignment);
270 
271     return compiler->validateAST(root);
272 }
273 
GetMainSequence(TIntermBlock * root)274 TIntermSequence *GetMainSequence(TIntermBlock *root)
275 {
276     TIntermFunctionDefinition *main = FindMain(root);
277     return main->getBody()->getSequence();
278 }
279 
280 // Declares a new variable to replace gl_DepthRange, its values are fed from a driver uniform.
ReplaceGLDepthRangeWithDriverUniform(TCompiler * compiler,TIntermBlock * root,const TVariable * driverUniforms,TSymbolTable * symbolTable)281 ANGLE_NO_DISCARD bool ReplaceGLDepthRangeWithDriverUniform(TCompiler *compiler,
282                                                            TIntermBlock *root,
283                                                            const TVariable *driverUniforms,
284                                                            TSymbolTable *symbolTable)
285 {
286     // Create a symbol reference to "gl_DepthRange"
287     const TVariable *depthRangeVar = static_cast<const TVariable *>(
288         symbolTable->findBuiltIn(ImmutableString("gl_DepthRange"), 0));
289 
290     // ANGLEUniforms.depthRange
291     TIntermBinary *angleEmulatedDepthRangeRef = CreateDriverUniformRef(driverUniforms, kDepthRange);
292 
293     // Use this variable instead of gl_DepthRange everywhere.
294     return ReplaceVariableWithTyped(compiler, root, depthRangeVar, angleEmulatedDepthRangeRef);
295 }
296 
297 // This operation performs the viewport depth translation needed by Vulkan. In GL the viewport
298 // transformation is slightly different - see the GL 2.0 spec section "2.12.1 Controlling the
299 // Viewport". In Vulkan the corresponding spec section is currently "23.4. Coordinate
300 // Transformations".
301 // The equations reduce to an expression:
302 //
303 //     z_vk = 0.5 * (w_gl + z_gl)
304 //
305 // where z_vk is the depth output of a Vulkan vertex shader and z_gl is the same for GL.
AppendVertexShaderDepthCorrectionToMain(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)306 ANGLE_NO_DISCARD bool AppendVertexShaderDepthCorrectionToMain(TCompiler *compiler,
307                                                               TIntermBlock *root,
308                                                               TSymbolTable *symbolTable)
309 {
310     // Create a symbol reference to "gl_Position"
311     const TVariable *position  = BuiltInVariable::gl_Position();
312     TIntermSymbol *positionRef = new TIntermSymbol(position);
313 
314     // Create a swizzle to "gl_Position.z"
315     TVector<int> swizzleOffsetZ = {2};
316     TIntermSwizzle *positionZ   = new TIntermSwizzle(positionRef, swizzleOffsetZ);
317 
318     // Create a constant "0.5"
319     TIntermConstantUnion *oneHalf = CreateFloatNode(0.5f);
320 
321     // Create a swizzle to "gl_Position.w"
322     TVector<int> swizzleOffsetW = {3};
323     TIntermSwizzle *positionW   = new TIntermSwizzle(positionRef->deepCopy(), swizzleOffsetW);
324 
325     // Create the expression "(gl_Position.z + gl_Position.w) * 0.5".
326     TIntermBinary *zPlusW = new TIntermBinary(EOpAdd, positionZ->deepCopy(), positionW->deepCopy());
327     TIntermBinary *halfZPlusW = new TIntermBinary(EOpMul, zPlusW, oneHalf->deepCopy());
328 
329     // Create the assignment "gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5"
330     TIntermTyped *positionZLHS = positionZ->deepCopy();
331     TIntermBinary *assignment  = new TIntermBinary(TOperator::EOpAssign, positionZLHS, halfZPlusW);
332 
333     // Append the assignment as a statement at the end of the shader.
334     return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
335 }
336 
337 // This operation performs Android pre-rotation and y-flip.  For Android (and potentially other
338 // platforms), the device may rotate, such that the orientation of the application is rotated
339 // relative to the native orientation of the device.  This is corrected in part by multiplying
340 // gl_Position by a mat2.
341 // The equations reduce to an expression:
342 //
343 //     gl_Position.xy = gl_Position.xy * preRotation
AppendPreRotation(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const TVariable * driverUniforms)344 ANGLE_NO_DISCARD bool AppendPreRotation(TCompiler *compiler,
345                                         TIntermBlock *root,
346                                         TSymbolTable *symbolTable,
347                                         const TVariable *driverUniforms)
348 {
349     TIntermBinary *preRotationRef = CreateDriverUniformRef(driverUniforms, kPreRotation);
350     TIntermSymbol *glPos          = new TIntermSymbol(BuiltInVariable::gl_Position());
351     TVector<int> swizzleOffsetXY  = {0, 1};
352     TIntermSwizzle *glPosXY       = new TIntermSwizzle(glPos, swizzleOffsetXY);
353 
354     // Create the expression "(gl_Position.xy * preRotation)"
355     TIntermBinary *zRotated =
356         new TIntermBinary(EOpMatrixTimesVector, preRotationRef->deepCopy(), glPosXY->deepCopy());
357 
358     // Create the assignment "gl_Position.xy = (gl_Position.xy * preRotation)"
359     TIntermBinary *assignment =
360         new TIntermBinary(TOperator::EOpAssign, glPosXY->deepCopy(), zRotated);
361 
362     // Append the assignment as a statement at the end of the shader.
363     return RunAtTheEndOfShader(compiler, root, assignment, symbolTable);
364 }
365 
AppendVertexShaderTransformFeedbackOutputToMain(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)366 ANGLE_NO_DISCARD bool AppendVertexShaderTransformFeedbackOutputToMain(TCompiler *compiler,
367                                                                       TIntermBlock *root,
368                                                                       TSymbolTable *symbolTable)
369 {
370     TVariable *xfbPlaceholder = new TVariable(symbolTable, ImmutableString("@@ XFB-OUT @@"),
371                                               new TType(), SymbolType::AngleInternal);
372 
373     // Append the assignment as a statement at the end of the shader.
374     return RunAtTheEndOfShader(compiler, root, new TIntermSymbol(xfbPlaceholder), symbolTable);
375 }
376 
377 // The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver
378 // block is used to implement Vulkan-specific features and workarounds. Returns the driver uniforms
379 // variable.
380 //
381 // There are Graphics and Compute variations as they require different uniforms.
AddGraphicsDriverUniformsToShader(TIntermBlock * root,TSymbolTable * symbolTable)382 const TVariable *AddGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
383 {
384     // Init the depth range type.
385     TFieldList *depthRangeParamsFields = new TFieldList();
386     depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
387                                                  ImmutableString("near"), TSourceLoc(),
388                                                  SymbolType::AngleInternal));
389     depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
390                                                  ImmutableString("far"), TSourceLoc(),
391                                                  SymbolType::AngleInternal));
392     depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
393                                                  ImmutableString("diff"), TSourceLoc(),
394                                                  SymbolType::AngleInternal));
395     // This additional field might be used by subclass such as TranslatorMetal.
396     depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
397                                                  ImmutableString("reserved"), TSourceLoc(),
398                                                  SymbolType::AngleInternal));
399     TStructure *emulatedDepthRangeParams = new TStructure(
400         symbolTable, kEmulatedDepthRangeParams, depthRangeParamsFields, SymbolType::AngleInternal);
401     TType *emulatedDepthRangeType = new TType(emulatedDepthRangeParams, false);
402 
403     // Declare a global depth range variable.
404     TVariable *depthRangeVar =
405         new TVariable(symbolTable->nextUniqueId(), kEmptyImmutableString, SymbolType::Empty,
406                       TExtension::UNDEFINED, emulatedDepthRangeType);
407 
408     DeclareGlobalVariable(root, depthRangeVar);
409 
410     // This field list mirrors the structure of GraphicsDriverUniforms in ContextVk.cpp.
411     TFieldList *driverFieldList = new TFieldList;
412 
413     const std::array<TType *, kNumGraphicsDriverUniforms> kDriverUniformTypes = {{
414         new TType(EbtFloat, 4),
415         new TType(EbtFloat),
416         new TType(EbtFloat),
417         new TType(EbtFloat),
418         new TType(EbtUInt),
419         new TType(EbtUInt),
420         // NOTE: There's a vec3 gap here that can be used in the future
421         new TType(EbtInt, 4),
422         new TType(EbtUInt, 4),
423         emulatedDepthRangeType,
424         new TType(EbtFloat, 2, 2),
425     }};
426 
427     for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniforms; ++uniformIndex)
428     {
429         TField *driverUniformField =
430             new TField(kDriverUniformTypes[uniformIndex],
431                        ImmutableString(kGraphicsDriverUniformNames[uniformIndex]), TSourceLoc(),
432                        SymbolType::AngleInternal);
433         driverFieldList->push_back(driverUniformField);
434     }
435 
436     // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
437     return DeclareInterfaceBlock(
438         root, symbolTable, driverFieldList, EvqUniform, TMemoryQualifier::Create(), 0,
439         ImmutableString(vk::kDriverUniformsBlockName), ImmutableString(vk::kDriverUniformsVarName));
440 }
441 
AddComputeDriverUniformsToShader(TIntermBlock * root,TSymbolTable * symbolTable)442 const TVariable *AddComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
443 {
444     // This field list mirrors the structure of ComputeDriverUniforms in ContextVk.cpp.
445     TFieldList *driverFieldList = new TFieldList;
446 
447     const std::array<TType *, kNumComputeDriverUniforms> kDriverUniformTypes = {{
448         new TType(EbtUInt, 4),
449     }};
450 
451     for (size_t uniformIndex = 0; uniformIndex < kNumComputeDriverUniforms; ++uniformIndex)
452     {
453         TField *driverUniformField =
454             new TField(kDriverUniformTypes[uniformIndex],
455                        ImmutableString(kComputeDriverUniformNames[uniformIndex]), TSourceLoc(),
456                        SymbolType::AngleInternal);
457         driverFieldList->push_back(driverUniformField);
458     }
459 
460     // Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
461     return DeclareInterfaceBlock(
462         root, symbolTable, driverFieldList, EvqUniform, TMemoryQualifier::Create(), 0,
463         ImmutableString(vk::kDriverUniformsBlockName), ImmutableString(vk::kDriverUniformsVarName));
464 }
465 
GenerateLineRasterSpecConstRef(TSymbolTable * symbolTable)466 TIntermSymbol *GenerateLineRasterSpecConstRef(TSymbolTable *symbolTable)
467 {
468     TVariable *specConstVar =
469         new TVariable(symbolTable, kLineRasterEmulationSpecConstVarName,
470                       StaticType::GetBasic<EbtBool>(), SymbolType::AngleInternal);
471     return new TIntermSymbol(specConstVar);
472 }
473 
AddANGLEPositionVaryingDeclaration(TIntermBlock * root,TSymbolTable * symbolTable,TQualifier qualifier)474 TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root,
475                                               TSymbolTable *symbolTable,
476                                               TQualifier qualifier)
477 {
478     // Define a vec2 driver varying to hold the line rasterization emulation position.
479     TType *varyingType = new TType(EbtFloat, EbpMedium, qualifier, 2);
480     TVariable *varyingVar =
481         new TVariable(symbolTable, ImmutableString(vk::kLineRasterEmulationPosition), varyingType,
482                       SymbolType::AngleInternal);
483     TIntermSymbol *varyingDeclarator = new TIntermSymbol(varyingVar);
484     TIntermDeclaration *varyingDecl  = new TIntermDeclaration;
485     varyingDecl->appendDeclarator(varyingDeclarator);
486 
487     TIntermSequence *insertSequence = new TIntermSequence;
488     insertSequence->push_back(varyingDecl);
489 
490     // Insert the declarations before Main.
491     size_t mainIndex = FindMainIndex(root);
492     root->insertChildNodes(mainIndex, *insertSequence);
493 
494     return varyingVar;
495 }
496 
AddBresenhamEmulationVS(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const TVariable * driverUniforms)497 ANGLE_NO_DISCARD bool AddBresenhamEmulationVS(TCompiler *compiler,
498                                               TIntermBlock *root,
499                                               TSymbolTable *symbolTable,
500                                               const TVariable *driverUniforms)
501 {
502     TVariable *anglePosition = AddANGLEPositionVaryingDeclaration(root, symbolTable, EvqVaryingOut);
503 
504     // Clamp position to subpixel grid.
505     // Do perspective divide (get normalized device coords)
506     // "vec2 ndc = gl_Position.xy / gl_Position.w"
507     const TType *vec2Type        = StaticType::GetBasic<EbtFloat, 2>();
508     TIntermBinary *viewportRef   = CreateDriverUniformRef(driverUniforms, kViewport);
509     TIntermSymbol *glPos         = new TIntermSymbol(BuiltInVariable::gl_Position());
510     TIntermSwizzle *glPosXY      = CreateSwizzle(glPos, 0, 1);
511     TIntermSwizzle *glPosW       = CreateSwizzle(glPos->deepCopy(), 3);
512     TVariable *ndc               = CreateTempVariable(symbolTable, vec2Type);
513     TIntermBinary *noPerspective = new TIntermBinary(EOpDiv, glPosXY, glPosW);
514     TIntermDeclaration *ndcDecl  = CreateTempInitDeclarationNode(ndc, noPerspective);
515 
516     // Convert NDC to window coordinates. According to Vulkan spec.
517     // "vec2 window = 0.5 * viewport.wh * (ndc + 1) + viewport.xy"
518     TIntermBinary *ndcPlusOne =
519         new TIntermBinary(EOpAdd, CreateTempSymbolNode(ndc), CreateFloatNode(1.0f));
520     TIntermSwizzle *viewportZW = CreateSwizzle(viewportRef, 2, 3);
521     TIntermBinary *ndcViewport = new TIntermBinary(EOpMul, viewportZW, ndcPlusOne);
522     TIntermBinary *ndcViewportHalf =
523         new TIntermBinary(EOpVectorTimesScalar, ndcViewport, CreateFloatNode(0.5f));
524     TIntermSwizzle *viewportXY     = CreateSwizzle(viewportRef->deepCopy(), 0, 1);
525     TIntermBinary *ndcToWindow     = new TIntermBinary(EOpAdd, ndcViewportHalf, viewportXY);
526     TVariable *windowCoords        = CreateTempVariable(symbolTable, vec2Type);
527     TIntermDeclaration *windowDecl = CreateTempInitDeclarationNode(windowCoords, ndcToWindow);
528 
529     // Clamp to subpixel grid.
530     // "vec2 clamped = round(window * 2^{subpixelBits}) / 2^{subpixelBits}"
531     int subpixelBits                    = compiler->getResources().SubPixelBits;
532     TIntermConstantUnion *scaleConstant = CreateFloatNode(static_cast<float>(1 << subpixelBits));
533     TIntermBinary *windowScaled =
534         new TIntermBinary(EOpVectorTimesScalar, CreateTempSymbolNode(windowCoords), scaleConstant);
535     TIntermUnary *windowRounded = new TIntermUnary(EOpRound, windowScaled, nullptr);
536     TIntermBinary *windowRoundedBack =
537         new TIntermBinary(EOpDiv, windowRounded, scaleConstant->deepCopy());
538     TVariable *clampedWindowCoords = CreateTempVariable(symbolTable, vec2Type);
539     TIntermDeclaration *clampedDecl =
540         CreateTempInitDeclarationNode(clampedWindowCoords, windowRoundedBack);
541 
542     // Set varying.
543     // "ANGLEPosition = 2 * (clamped - viewport.xy) / viewport.wh - 1"
544     TIntermBinary *clampedOffset = new TIntermBinary(
545         EOpSub, CreateTempSymbolNode(clampedWindowCoords), viewportXY->deepCopy());
546     TIntermBinary *clampedOff2x =
547         new TIntermBinary(EOpVectorTimesScalar, clampedOffset, CreateFloatNode(2.0f));
548     TIntermBinary *clampedDivided = new TIntermBinary(EOpDiv, clampedOff2x, viewportZW->deepCopy());
549     TIntermBinary *clampedNDC    = new TIntermBinary(EOpSub, clampedDivided, CreateFloatNode(1.0f));
550     TIntermSymbol *varyingRef    = new TIntermSymbol(anglePosition);
551     TIntermBinary *varyingAssign = new TIntermBinary(EOpAssign, varyingRef, clampedNDC);
552 
553     TIntermBlock *emulationBlock = new TIntermBlock;
554     emulationBlock->appendStatement(ndcDecl);
555     emulationBlock->appendStatement(windowDecl);
556     emulationBlock->appendStatement(clampedDecl);
557     emulationBlock->appendStatement(varyingAssign);
558     TIntermIfElse *ifEmulation =
559         new TIntermIfElse(GenerateLineRasterSpecConstRef(symbolTable), emulationBlock, nullptr);
560 
561     // Ensure the statements run at the end of the main() function.
562     TIntermFunctionDefinition *main = FindMain(root);
563     TIntermBlock *mainBody          = main->getBody();
564     mainBody->appendStatement(ifEmulation);
565     return compiler->validateAST(root);
566 }
567 
InsertFragCoordCorrection(TCompiler * compiler,TIntermBlock * root,TIntermSequence * insertSequence,TSymbolTable * symbolTable,const TVariable * driverUniforms)568 ANGLE_NO_DISCARD bool InsertFragCoordCorrection(TCompiler *compiler,
569                                                 TIntermBlock *root,
570                                                 TIntermSequence *insertSequence,
571                                                 TSymbolTable *symbolTable,
572                                                 const TVariable *driverUniforms)
573 {
574     TIntermBinary *viewportYScale = CreateDriverUniformRef(driverUniforms, kViewportYScale);
575     TIntermBinary *pivot          = CreateDriverUniformRef(driverUniforms, kHalfRenderAreaHeight);
576     return FlipBuiltinVariable(compiler, root, insertSequence, viewportYScale, symbolTable,
577                                BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName, pivot);
578 }
579 
580 // This block adds OpenGL line segment rasterization emulation behind a specialization constant
581 // guard.  OpenGL's simple rasterization algorithm is a strict subset of the pixels generated by the
582 // Vulkan algorithm. Thus we can implement a shader patch that rejects pixels if they would not be
583 // generated by the OpenGL algorithm. OpenGL's algorithm is similar to Bresenham's line algorithm.
584 // It is implemented for each pixel by testing if the line segment crosses a small diamond inside
585 // the pixel. See the OpenGL ES 2.0 spec section "3.4.1 Basic Line Segment Rasterization". Also
586 // see the Vulkan spec section "24.6.1. Basic Line Segment Rasterization":
587 // https://khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#primsrast-lines-basic
588 //
589 // Using trigonometric math and the fact that we know the size of the diamond we can derive a
590 // formula to test if the line segment crosses the pixel center. gl_FragCoord is used along with an
591 // internal position varying to determine the inputs to the formula.
592 //
593 // The implementation of the test is similar to the following pseudocode:
594 //
595 // void main()
596 // {
597 //    vec2 p  = (((((ANGLEPosition.xy) * 0.5) + 0.5) * viewport.zw) + viewport.xy);
598 //    vec2 d  = dFdx(p) + dFdy(p);
599 //    vec2 f  = gl_FragCoord.xy;
600 //    vec2 p_ = p.yx;
601 //    vec2 d_ = d.yx;
602 //    vec2 f_ = f.yx;
603 //
604 //    vec2 i = abs(p - f + (d / d_) * (f_ - p_));
605 //
606 //    if (i.x > (0.5 + e) && i.y > (0.5 + e))
607 //        discard;
608 //     <otherwise run fragment shader main>
609 // }
610 //
611 // Note this emulation can not provide fully correct rasterization. See the docs more more info.
612 
AddBresenhamEmulationFS(TCompiler * compiler,TInfoSinkBase & sink,TIntermBlock * root,TSymbolTable * symbolTable,const TVariable * driverUniforms,bool usesFragCoord)613 ANGLE_NO_DISCARD bool AddBresenhamEmulationFS(TCompiler *compiler,
614                                               TInfoSinkBase &sink,
615                                               TIntermBlock *root,
616                                               TSymbolTable *symbolTable,
617                                               const TVariable *driverUniforms,
618                                               bool usesFragCoord)
619 {
620     TVariable *anglePosition = AddANGLEPositionVaryingDeclaration(root, symbolTable, EvqVaryingIn);
621     const TType *vec2Type    = StaticType::GetBasic<EbtFloat, 2>();
622     TIntermBinary *viewportRef = CreateDriverUniformRef(driverUniforms, kViewport);
623 
624     // vec2 p = ((ANGLEPosition * 0.5) + 0.5) * viewport.zw + viewport.xy
625     TIntermSwizzle *viewportXY    = CreateSwizzle(viewportRef->deepCopy(), 0, 1);
626     TIntermSwizzle *viewportZW    = CreateSwizzle(viewportRef, 2, 3);
627     TIntermSymbol *position       = new TIntermSymbol(anglePosition);
628     TIntermConstantUnion *oneHalf = CreateFloatNode(0.5f);
629     TIntermBinary *halfPosition   = new TIntermBinary(EOpVectorTimesScalar, position, oneHalf);
630     TIntermBinary *offsetHalfPosition =
631         new TIntermBinary(EOpAdd, halfPosition, oneHalf->deepCopy());
632     TIntermBinary *scaledPosition = new TIntermBinary(EOpMul, offsetHalfPosition, viewportZW);
633     TIntermBinary *windowPosition = new TIntermBinary(EOpAdd, scaledPosition, viewportXY);
634     TVariable *p                  = CreateTempVariable(symbolTable, vec2Type);
635     TIntermDeclaration *pDecl     = CreateTempInitDeclarationNode(p, windowPosition);
636 
637     // vec2 d = dFdx(p) + dFdy(p)
638     TIntermUnary *dfdx        = new TIntermUnary(EOpDFdx, new TIntermSymbol(p), nullptr);
639     TIntermUnary *dfdy        = new TIntermUnary(EOpDFdy, new TIntermSymbol(p), nullptr);
640     TIntermBinary *dfsum      = new TIntermBinary(EOpAdd, dfdx, dfdy);
641     TVariable *d              = CreateTempVariable(symbolTable, vec2Type);
642     TIntermDeclaration *dDecl = CreateTempInitDeclarationNode(d, dfsum);
643 
644     // vec2 f = gl_FragCoord.xy
645     const TVariable *fragCoord  = BuiltInVariable::gl_FragCoord();
646     TIntermSwizzle *fragCoordXY = CreateSwizzle(new TIntermSymbol(fragCoord), 0, 1);
647     TVariable *f                = CreateTempVariable(symbolTable, vec2Type);
648     TIntermDeclaration *fDecl   = CreateTempInitDeclarationNode(f, fragCoordXY);
649 
650     // vec2 p_ = p.yx
651     TIntermSwizzle *pyx        = CreateSwizzle(new TIntermSymbol(p), 1, 0);
652     TVariable *p_              = CreateTempVariable(symbolTable, vec2Type);
653     TIntermDeclaration *p_decl = CreateTempInitDeclarationNode(p_, pyx);
654 
655     // vec2 d_ = d.yx
656     TIntermSwizzle *dyx        = CreateSwizzle(new TIntermSymbol(d), 1, 0);
657     TVariable *d_              = CreateTempVariable(symbolTable, vec2Type);
658     TIntermDeclaration *d_decl = CreateTempInitDeclarationNode(d_, dyx);
659 
660     // vec2 f_ = f.yx
661     TIntermSwizzle *fyx        = CreateSwizzle(new TIntermSymbol(f), 1, 0);
662     TVariable *f_              = CreateTempVariable(symbolTable, vec2Type);
663     TIntermDeclaration *f_decl = CreateTempInitDeclarationNode(f_, fyx);
664 
665     // vec2 i = abs(p - f + (d/d_) * (f_ - p_))
666     TIntermBinary *dd   = new TIntermBinary(EOpDiv, new TIntermSymbol(d), new TIntermSymbol(d_));
667     TIntermBinary *fp   = new TIntermBinary(EOpSub, new TIntermSymbol(f_), new TIntermSymbol(p_));
668     TIntermBinary *ddfp = new TIntermBinary(EOpMul, dd, fp);
669     TIntermBinary *pf   = new TIntermBinary(EOpSub, new TIntermSymbol(p), new TIntermSymbol(f));
670     TIntermBinary *expr = new TIntermBinary(EOpAdd, pf, ddfp);
671     TIntermUnary *absd  = new TIntermUnary(EOpAbs, expr, nullptr);
672     TVariable *i        = CreateTempVariable(symbolTable, vec2Type);
673     TIntermDeclaration *iDecl = CreateTempInitDeclarationNode(i, absd);
674 
675     // Using a small epsilon value ensures that we don't suffer from numerical instability when
676     // lines are exactly vertical or horizontal.
677     static constexpr float kEpsilon   = 0.0001f;
678     static constexpr float kThreshold = 0.5 + kEpsilon;
679     TIntermConstantUnion *threshold   = CreateFloatNode(kThreshold);
680 
681     // if (i.x > (0.5 + e) && i.y > (0.5 + e))
682     TIntermSwizzle *ix     = CreateSwizzle(new TIntermSymbol(i), 0);
683     TIntermBinary *checkX  = new TIntermBinary(EOpGreaterThan, ix, threshold);
684     TIntermSwizzle *iy     = CreateSwizzle(new TIntermSymbol(i), 1);
685     TIntermBinary *checkY  = new TIntermBinary(EOpGreaterThan, iy, threshold->deepCopy());
686     TIntermBinary *checkXY = new TIntermBinary(EOpLogicalAnd, checkX, checkY);
687 
688     // discard
689     TIntermBranch *discard     = new TIntermBranch(EOpKill, nullptr);
690     TIntermBlock *discardBlock = new TIntermBlock;
691     discardBlock->appendStatement(discard);
692     TIntermIfElse *ifStatement = new TIntermIfElse(checkXY, discardBlock, nullptr);
693 
694     TIntermBlock *emulationBlock       = new TIntermBlock;
695     TIntermSequence *emulationSequence = emulationBlock->getSequence();
696 
697     std::array<TIntermNode *, 8> nodes = {
698         {pDecl, dDecl, fDecl, p_decl, d_decl, f_decl, iDecl, ifStatement}};
699     emulationSequence->insert(emulationSequence->begin(), nodes.begin(), nodes.end());
700 
701     TIntermIfElse *ifEmulation =
702         new TIntermIfElse(GenerateLineRasterSpecConstRef(symbolTable), emulationBlock, nullptr);
703 
704     // Ensure the line raster code runs at the beginning of main().
705     TIntermFunctionDefinition *main = FindMain(root);
706     TIntermSequence *mainSequence   = main->getBody()->getSequence();
707     ASSERT(mainSequence);
708 
709     mainSequence->insert(mainSequence->begin(), ifEmulation);
710 
711     // If the shader does not use frag coord, we should insert it inside the emulation if.
712     if (!usesFragCoord)
713     {
714         if (!InsertFragCoordCorrection(compiler, root, emulationSequence, symbolTable,
715                                        driverUniforms))
716         {
717             return false;
718         }
719     }
720 
721     return compiler->validateAST(root);
722 }
723 
724 }  // anonymous namespace
725 
TranslatorVulkan(sh::GLenum type,ShShaderSpec spec)726 TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec)
727     : TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT)
728 {}
729 
translateImpl(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics *,const TVariable ** driverUniformsOut,TOutputVulkanGLSL * outputGLSL)730 bool TranslatorVulkan::translateImpl(TIntermBlock *root,
731                                      ShCompileOptions compileOptions,
732                                      PerformanceDiagnostics * /*perfDiagnostics*/,
733                                      const TVariable **driverUniformsOut,
734                                      TOutputVulkanGLSL *outputGLSL)
735 {
736     TInfoSinkBase &sink = getInfoSink().obj;
737 
738     if (getShaderType() == GL_VERTEX_SHADER)
739     {
740         if (!ShaderBuiltinsWorkaround(this, root, &getSymbolTable(), compileOptions))
741         {
742             return false;
743         }
744     }
745 
746     sink << "#version 450 core\n";
747 
748     // Write out default uniforms into a uniform block assigned to a specific set/binding.
749     int defaultUniformCount           = 0;
750     int aggregateTypesUsedForUniforms = 0;
751     int atomicCounterCount            = 0;
752     for (const auto &uniform : getUniforms())
753     {
754         if (!uniform.isBuiltIn() && uniform.active && !gl::IsOpaqueType(uniform.type))
755         {
756             ++defaultUniformCount;
757         }
758 
759         if (uniform.isStruct() || uniform.isArrayOfArrays())
760         {
761             ++aggregateTypesUsedForUniforms;
762         }
763 
764         if (uniform.active && gl::IsAtomicCounterType(uniform.type))
765         {
766             ++atomicCounterCount;
767         }
768     }
769 
770     // Remove declarations of inactive shader interface variables so glslang wrapper doesn't need to
771     // replace them.  Note: this is done before extracting samplers from structs, as removing such
772     // inactive samplers is not yet supported.  Note also that currently, CollectVariables marks
773     // every field of an active uniform that's of struct type as active, i.e. no extracted sampler
774     // is inactive.
775     if (!RemoveInactiveInterfaceVariables(this, root, getAttributes(), getInputVaryings(),
776                                           getOutputVariables(), getUniforms(),
777                                           getInterfaceBlocks()))
778     {
779         return false;
780     }
781 
782     // TODO(lucferron): Refactor this function to do fewer tree traversals.
783     // http://anglebug.com/2461
784     if (aggregateTypesUsedForUniforms > 0)
785     {
786         if (!NameEmbeddedStructUniforms(this, root, &getSymbolTable()))
787         {
788             return false;
789         }
790 
791         bool rewriteStructSamplersResult;
792         int removedUniformsCount;
793 
794         if (compileOptions & SH_USE_OLD_REWRITE_STRUCT_SAMPLERS)
795         {
796             rewriteStructSamplersResult =
797                 RewriteStructSamplersOld(this, root, &getSymbolTable(), &removedUniformsCount);
798         }
799         else
800         {
801             rewriteStructSamplersResult =
802                 RewriteStructSamplers(this, root, &getSymbolTable(), &removedUniformsCount);
803         }
804 
805         if (!rewriteStructSamplersResult)
806         {
807             return false;
808         }
809         defaultUniformCount -= removedUniformsCount;
810 
811         // We must declare the struct types before using them.
812         DeclareStructTypesTraverser structTypesTraverser(outputGLSL);
813         root->traverse(&structTypesTraverser);
814         if (!structTypesTraverser.updateTree(this, root))
815         {
816             return false;
817         }
818     }
819 
820     // Rewrite samplerCubes as sampler2DArrays.  This must be done after rewriting struct samplers
821     // as it doesn't expect that.
822     if (compileOptions & SH_EMULATE_SEAMFUL_CUBE_MAP_SAMPLING)
823     {
824         if (!RewriteCubeMapSamplersAs2DArray(this, root, &getSymbolTable(),
825                                              getShaderType() == GL_FRAGMENT_SHADER))
826         {
827             return false;
828         }
829     }
830 
831     if (defaultUniformCount > 0)
832     {
833         gl::ShaderType shaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
834         sink << "\nlayout(set=0, binding=" << outputGLSL->nextUnusedBinding()
835              << ", std140) uniform " << kDefaultUniformNames[shaderType] << "\n{\n";
836 
837         DeclareDefaultUniformsTraverser defaultTraverser(&sink, getHashFunction(), &getNameMap());
838         root->traverse(&defaultTraverser);
839         if (!defaultTraverser.updateTree(this, root))
840         {
841             return false;
842         }
843 
844         sink << "};\n";
845     }
846 
847     const TVariable *driverUniforms;
848     if (getShaderType() == GL_COMPUTE_SHADER)
849     {
850         driverUniforms = AddComputeDriverUniformsToShader(root, &getSymbolTable());
851     }
852     else
853     {
854         driverUniforms = AddGraphicsDriverUniformsToShader(root, &getSymbolTable());
855     }
856 
857     if (atomicCounterCount > 0)
858     {
859         // ANGLEUniforms.acbBufferOffsets
860         const TIntermBinary *acbBufferOffsets =
861             CreateDriverUniformRef(driverUniforms, kAcbBufferOffsets);
862 
863         if (!RewriteAtomicCounters(this, root, &getSymbolTable(), acbBufferOffsets))
864         {
865             return false;
866         }
867     }
868     else if (getShaderVersion() >= 310)
869     {
870         // Vulkan doesn't support Atomic Storage as a Storage Class, but we've seen
871         // cases where builtins are using it even with no active atomic counters.
872         // This pass simply removes those builtins in that scenario.
873         if (!RemoveAtomicCounterBuiltins(this, root))
874         {
875             return false;
876         }
877     }
878 
879     if (getShaderType() != GL_COMPUTE_SHADER)
880     {
881         if (!ReplaceGLDepthRangeWithDriverUniform(this, root, driverUniforms, &getSymbolTable()))
882         {
883             return false;
884         }
885 
886         // Add specialization constant declarations.  The default value of the specialization
887         // constant is irrelevant, as it will be set when creating the pipeline.
888         if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
889         {
890             sink << "layout(constant_id="
891                  << static_cast<uint32_t>(vk::SpecializationConstantId::LineRasterEmulation)
892                  << ") const bool " << kLineRasterEmulationSpecConstVarName << " = false;\n\n";
893         }
894     }
895 
896     // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
897     // if it's core profile shaders and they are used.
898     if (getShaderType() == GL_FRAGMENT_SHADER)
899     {
900         bool usesPointCoord = false;
901         bool usesFragCoord  = false;
902 
903         // Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate.
904         for (const ShaderVariable &inputVarying : mInputVaryings)
905         {
906             if (!inputVarying.isBuiltIn())
907             {
908                 continue;
909             }
910 
911             if (inputVarying.name == "gl_PointCoord")
912             {
913                 usesPointCoord = true;
914                 break;
915             }
916 
917             if (inputVarying.name == "gl_FragCoord")
918             {
919                 usesFragCoord = true;
920                 break;
921             }
922         }
923 
924         if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
925         {
926             if (!AddBresenhamEmulationFS(this, sink, root, &getSymbolTable(), driverUniforms,
927                                          usesFragCoord))
928             {
929                 return false;
930             }
931         }
932 
933         bool hasGLFragColor = false;
934         bool hasGLFragData  = false;
935 
936         for (const ShaderVariable &outputVar : mOutputVariables)
937         {
938             if (outputVar.name == "gl_FragColor")
939             {
940                 ASSERT(!hasGLFragColor);
941                 hasGLFragColor = true;
942                 continue;
943             }
944             else if (outputVar.name == "gl_FragData")
945             {
946                 ASSERT(!hasGLFragData);
947                 hasGLFragData = true;
948                 continue;
949             }
950         }
951         ASSERT(!(hasGLFragColor && hasGLFragData));
952         if (hasGLFragColor)
953         {
954             sink << "layout(location = 0) out vec4 webgl_FragColor;\n";
955         }
956         if (hasGLFragData)
957         {
958             sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
959         }
960 
961         if (usesPointCoord)
962         {
963             TIntermBinary *viewportYScale =
964                 CreateDriverUniformRef(driverUniforms, kNegViewportYScale);
965             TIntermConstantUnion *pivot = CreateFloatNode(0.5f);
966             if (!FlipBuiltinVariable(this, root, GetMainSequence(root), viewportYScale,
967                                      &getSymbolTable(), BuiltInVariable::gl_PointCoord(),
968                                      kFlippedPointCoordName, pivot))
969             {
970                 return false;
971             }
972         }
973 
974         if (usesFragCoord)
975         {
976             if (!InsertFragCoordCorrection(this, root, GetMainSequence(root), &getSymbolTable(),
977                                            driverUniforms))
978             {
979                 return false;
980             }
981         }
982 
983         {
984             TIntermBinary *viewportYScale = CreateDriverUniformRef(driverUniforms, kViewportYScale);
985             if (!RewriteDfdy(this, root, getSymbolTable(), getShaderVersion(), viewportYScale))
986             {
987                 return false;
988             }
989         }
990 
991         EmitEarlyFragmentTestsGLSL(*this, sink);
992     }
993     else if (getShaderType() == GL_VERTEX_SHADER)
994     {
995         if (compileOptions & SH_ADD_BRESENHAM_LINE_RASTER_EMULATION)
996         {
997             if (!AddBresenhamEmulationVS(this, root, &getSymbolTable(), driverUniforms))
998             {
999                 return false;
1000             }
1001         }
1002 
1003         // Add a macro to declare transform feedback buffers.
1004         sink << "@@ XFB-DECL @@\n\n";
1005 
1006         // Append a macro for transform feedback substitution prior to modifying depth.
1007         if (!AppendVertexShaderTransformFeedbackOutputToMain(this, root, &getSymbolTable()))
1008         {
1009             return false;
1010         }
1011 
1012         // Append depth range translation to main.
1013         if (!transformDepthBeforeCorrection(root, driverUniforms))
1014         {
1015             return false;
1016         }
1017         if (!AppendVertexShaderDepthCorrectionToMain(this, root, &getSymbolTable()))
1018         {
1019             return false;
1020         }
1021         if (!AppendPreRotation(this, root, &getSymbolTable(), driverUniforms))
1022         {
1023             return false;
1024         }
1025     }
1026     else if (getShaderType() == GL_GEOMETRY_SHADER)
1027     {
1028         WriteGeometryShaderLayoutQualifiers(
1029             sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
1030             getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
1031     }
1032     else
1033     {
1034         ASSERT(getShaderType() == GL_COMPUTE_SHADER);
1035         EmitWorkGroupSizeGLSL(*this, sink);
1036     }
1037 
1038     if (!validateAST(root))
1039     {
1040         return false;
1041     }
1042 
1043     if (driverUniformsOut)
1044     {
1045         *driverUniformsOut = driverUniforms;
1046     }
1047 
1048     return true;
1049 }
1050 
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics * perfDiagnostics)1051 bool TranslatorVulkan::translate(TIntermBlock *root,
1052                                  ShCompileOptions compileOptions,
1053                                  PerformanceDiagnostics *perfDiagnostics)
1054 {
1055 
1056     TInfoSinkBase &sink = getInfoSink().obj;
1057 
1058     bool precisionEmulation = false;
1059     if (!emulatePrecisionIfNeeded(root, sink, &precisionEmulation, SH_GLSL_VULKAN_OUTPUT))
1060         return false;
1061 
1062     bool enablePrecision = ((compileOptions & SH_IGNORE_PRECISION_QUALIFIERS) == 0);
1063 
1064     TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(),
1065                                  getNameMap(), &getSymbolTable(), getShaderType(),
1066                                  getShaderVersion(), getOutputType(), precisionEmulation,
1067                                  enablePrecision, compileOptions);
1068 
1069     if (!translateImpl(root, compileOptions, perfDiagnostics, nullptr, &outputGLSL))
1070     {
1071         return false;
1072     }
1073 
1074     // Write translated shader.
1075     root->traverse(&outputGLSL);
1076 
1077     return true;
1078 }
1079 
shouldFlattenPragmaStdglInvariantAll()1080 bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
1081 {
1082     // Not necessary.
1083     return false;
1084 }
1085 
getDriverUniformNegViewportYScaleRef(const TVariable * driverUniforms) const1086 TIntermBinary *TranslatorVulkan::getDriverUniformNegViewportYScaleRef(
1087     const TVariable *driverUniforms) const
1088 {
1089     return CreateDriverUniformRef(driverUniforms, kNegViewportYScale);
1090 }
1091 
getDriverUniformDepthRangeReservedFieldRef(const TVariable * driverUniforms) const1092 TIntermBinary *TranslatorVulkan::getDriverUniformDepthRangeReservedFieldRef(
1093     const TVariable *driverUniforms) const
1094 {
1095     TIntermBinary *depthRange = CreateDriverUniformRef(driverUniforms, kDepthRange);
1096 
1097     return new TIntermBinary(EOpIndexDirectStruct, depthRange, CreateIndexNode(3));
1098 }
1099 
1100 }  // namespace sh
1101