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