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