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