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