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