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 // TranslatorSPIRV:
7 // A set of transformations that prepare the AST to be compatible with GL_KHR_vulkan_glsl followed
8 // by a pass that generates SPIR-V.
9 // See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
10 //
11
12 #include "compiler/translator/spirv/TranslatorSPIRV.h"
13
14 #include "angle_gl.h"
15 #include "common/PackedEnums.h"
16 #include "common/utilities.h"
17 #include "compiler/translator/ImmutableStringBuilder.h"
18 #include "compiler/translator/IntermNode.h"
19 #include "compiler/translator/StaticType.h"
20 #include "compiler/translator/spirv/BuiltinsWorkaround.h"
21 #include "compiler/translator/spirv/OutputSPIRV.h"
22 #include "compiler/translator/tree_ops/DeclarePerVertexBlocks.h"
23 #include "compiler/translator/tree_ops/MonomorphizeUnsupportedFunctions.h"
24 #include "compiler/translator/tree_ops/RecordConstantPrecision.h"
25 #include "compiler/translator/tree_ops/RemoveAtomicCounterBuiltins.h"
26 #include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h"
27 #include "compiler/translator/tree_ops/RewriteArrayOfArrayOfOpaqueUniforms.h"
28 #include "compiler/translator/tree_ops/RewriteAtomicCounters.h"
29 #include "compiler/translator/tree_ops/RewriteDfdy.h"
30 #include "compiler/translator/tree_ops/RewriteStructSamplers.h"
31 #include "compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.h"
32 #include "compiler/translator/tree_ops/spirv/ClampGLLayer.h"
33 #include "compiler/translator/tree_ops/spirv/EmulateAdvancedBlendEquations.h"
34 #include "compiler/translator/tree_ops/spirv/EmulateDithering.h"
35 #include "compiler/translator/tree_ops/spirv/EmulateFragColorData.h"
36 #include "compiler/translator/tree_ops/spirv/EmulateFramebufferFetch.h"
37 #include "compiler/translator/tree_ops/spirv/EmulateYUVBuiltIns.h"
38 #include "compiler/translator/tree_ops/spirv/FlagSamplersWithTexelFetch.h"
39 #include "compiler/translator/tree_ops/spirv/ReswizzleYUVOps.h"
40 #include "compiler/translator/tree_ops/spirv/RewriteInterpolateAtOffset.h"
41 #include "compiler/translator/tree_ops/spirv/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/FindSymbolNode.h"
47 #include "compiler/translator/tree_util/IntermNode_util.h"
48 #include "compiler/translator/tree_util/ReplaceClipCullDistanceVariable.h"
49 #include "compiler/translator/tree_util/ReplaceVariable.h"
50 #include "compiler/translator/tree_util/RewriteSampleMaskVariable.h"
51 #include "compiler/translator/tree_util/RunAtTheBeginningOfShader.h"
52 #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
53 #include "compiler/translator/tree_util/SpecializationConstant.h"
54 #include "compiler/translator/util.h"
55
56 namespace sh
57 {
58
59 namespace
60 {
61 constexpr ImmutableString kFlippedPointCoordName = ImmutableString("flippedPointCoord");
62 constexpr ImmutableString kFlippedFragCoordName = ImmutableString("flippedFragCoord");
63 constexpr ImmutableString kDefaultUniformsBlockName = ImmutableString("defaultUniforms");
64
IsDefaultUniform(const TType & type)65 bool IsDefaultUniform(const TType &type)
66 {
67 return type.getQualifier() == EvqUniform && type.getInterfaceBlock() == nullptr &&
68 !IsOpaqueType(type.getBasicType());
69 }
70
71 class ReplaceDefaultUniformsTraverser : public TIntermTraverser
72 {
73 public:
ReplaceDefaultUniformsTraverser(const VariableReplacementMap & variableMap)74 ReplaceDefaultUniformsTraverser(const VariableReplacementMap &variableMap)
75 : TIntermTraverser(true, false, false), mVariableMap(variableMap)
76 {}
77
visitDeclaration(Visit visit,TIntermDeclaration * node)78 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
79 {
80 const TIntermSequence &sequence = *(node->getSequence());
81
82 TIntermTyped *variable = sequence.front()->getAsTyped();
83 const TType &type = variable->getType();
84
85 if (IsDefaultUniform(type))
86 {
87 // Remove the uniform declaration.
88 TIntermSequence emptyReplacement;
89 mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
90 std::move(emptyReplacement));
91
92 return false;
93 }
94
95 return true;
96 }
97
visitSymbol(TIntermSymbol * symbol)98 void visitSymbol(TIntermSymbol *symbol) override
99 {
100 const TVariable &variable = symbol->variable();
101 const TType &type = variable.getType();
102
103 if (!IsDefaultUniform(type) || gl::IsBuiltInName(variable.name().data()))
104 {
105 return;
106 }
107
108 ASSERT(mVariableMap.count(&variable) > 0);
109
110 queueReplacement(mVariableMap.at(&variable)->deepCopy(), OriginalNode::IS_DROPPED);
111 }
112
113 private:
114 const VariableReplacementMap &mVariableMap;
115 };
116
DeclareDefaultUniforms(TranslatorSPIRV * compiler,TIntermBlock * root,TSymbolTable * symbolTable,gl::ShaderType shaderType)117 bool DeclareDefaultUniforms(TranslatorSPIRV *compiler,
118 TIntermBlock *root,
119 TSymbolTable *symbolTable,
120 gl::ShaderType shaderType)
121 {
122 // First, collect all default uniforms and declare a uniform block.
123 TFieldList *uniformList = new TFieldList;
124 TVector<const TVariable *> uniformVars;
125
126 for (TIntermNode *node : *root->getSequence())
127 {
128 TIntermDeclaration *decl = node->getAsDeclarationNode();
129 if (decl == nullptr)
130 {
131 continue;
132 }
133
134 const TIntermSequence &sequence = *(decl->getSequence());
135
136 TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
137 if (symbol == nullptr)
138 {
139 continue;
140 }
141
142 const TType &type = symbol->getType();
143 if (IsDefaultUniform(type))
144 {
145 TType *fieldType = new TType(type);
146
147 uniformList->push_back(new TField(fieldType, symbol->getName(), symbol->getLine(),
148 symbol->variable().symbolType()));
149 uniformVars.push_back(&symbol->variable());
150 }
151 }
152
153 TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
154 layoutQualifier.blockStorage = EbsStd140;
155 const TVariable *uniformBlock = DeclareInterfaceBlock(
156 root, symbolTable, uniformList, EvqUniform, layoutQualifier, TMemoryQualifier::Create(), 0,
157 kDefaultUniformsBlockName, ImmutableString(""));
158
159 compiler->assignSpirvId(uniformBlock->getType().getInterfaceBlock()->uniqueId(),
160 vk::spirv::kIdDefaultUniformsBlock);
161
162 // Create a map from the uniform variables to new variables that reference the fields of the
163 // block.
164 VariableReplacementMap variableMap;
165 for (size_t fieldIndex = 0; fieldIndex < uniformVars.size(); ++fieldIndex)
166 {
167 const TVariable *variable = uniformVars[fieldIndex];
168
169 TType *replacementType = new TType(variable->getType());
170 replacementType->setInterfaceBlockField(uniformBlock->getType().getInterfaceBlock(),
171 fieldIndex);
172
173 TVariable *replacementVariable =
174 new TVariable(symbolTable, variable->name(), replacementType, variable->symbolType());
175
176 variableMap[variable] = new TIntermSymbol(replacementVariable);
177 }
178
179 // Finally transform the AST and make sure references to the uniforms are replaced with the new
180 // variables.
181 ReplaceDefaultUniformsTraverser defaultTraverser(variableMap);
182 root->traverse(&defaultTraverser);
183 return defaultTraverser.updateTree(compiler, root);
184 }
185
186 // 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 * swapXY,TIntermTyped * flipXY,TSymbolTable * symbolTable,const TVariable * builtin,const ImmutableString & flippedVariableName,TIntermTyped * pivot)187 [[nodiscard]] bool RotateAndFlipBuiltinVariable(TCompiler *compiler,
188 TIntermBlock *root,
189 TIntermSequence *insertSequence,
190 TIntermTyped *swapXY,
191 TIntermTyped *flipXY,
192 TSymbolTable *symbolTable,
193 const TVariable *builtin,
194 const ImmutableString &flippedVariableName,
195 TIntermTyped *pivot)
196 {
197 // Create a symbol reference to 'builtin'.
198 TIntermSymbol *builtinRef = new TIntermSymbol(builtin);
199
200 // Create a symbol reference to our new variable that will hold the modified builtin.
201 TType *type = new TType(builtin->getType());
202 type->setQualifier(EvqGlobal);
203 type->setPrimarySize(builtin->getType().getNominalSize());
204 TVariable *replacementVar =
205 new TVariable(symbolTable, flippedVariableName, type, SymbolType::AngleInternal);
206 DeclareGlobalVariable(root, replacementVar);
207 TIntermSymbol *flippedBuiltinRef = new TIntermSymbol(replacementVar);
208
209 // Use this new variable instead of 'builtin' everywhere.
210 if (!ReplaceVariable(compiler, root, builtin, replacementVar))
211 {
212 return false;
213 }
214
215 // Create the expression "(swapXY ? builtin.yx : builtin.xy)"
216 TIntermTyped *builtinXY = new TIntermSwizzle(builtinRef, {0, 1});
217 TIntermTyped *builtinYX = new TIntermSwizzle(builtinRef->deepCopy(), {1, 0});
218
219 builtinXY = new TIntermTernary(swapXY, builtinYX, builtinXY);
220
221 // Create the expression "(builtin.xy - pivot) * flipXY + pivot
222 TIntermBinary *removePivot = new TIntermBinary(EOpSub, builtinXY, pivot);
223 TIntermBinary *inverseXY = new TIntermBinary(EOpMul, removePivot, flipXY);
224 TIntermBinary *plusPivot = new TIntermBinary(EOpAdd, inverseXY, pivot->deepCopy());
225
226 // Create the corrected variable and copy the value of the original builtin.
227 TIntermBinary *assignment =
228 new TIntermBinary(EOpAssign, flippedBuiltinRef, builtinRef->deepCopy());
229
230 // Create an assignment to the replaced variable's .xy.
231 TIntermSwizzle *correctedXY = new TIntermSwizzle(flippedBuiltinRef->deepCopy(), {0, 1});
232 TIntermBinary *assignToXY = new TIntermBinary(EOpAssign, correctedXY, plusPivot);
233
234 // Add this assigment at the beginning of the main function
235 insertSequence->insert(insertSequence->begin(), assignToXY);
236 insertSequence->insert(insertSequence->begin(), assignment);
237
238 return compiler->validateAST(root);
239 }
240
GetMainSequence(TIntermBlock * root)241 TIntermSequence *GetMainSequence(TIntermBlock *root)
242 {
243 TIntermFunctionDefinition *main = FindMain(root);
244 return main->getBody()->getSequence();
245 }
246
247 // 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)248 [[nodiscard]] bool ReplaceGLDepthRangeWithDriverUniform(TCompiler *compiler,
249 TIntermBlock *root,
250 const DriverUniform *driverUniforms,
251 TSymbolTable *symbolTable)
252 {
253 // Create a symbol reference to "gl_DepthRange"
254 const TVariable *depthRangeVar = static_cast<const TVariable *>(
255 symbolTable->findBuiltIn(ImmutableString("gl_DepthRange"), 0));
256
257 // ANGLEUniforms.depthRange
258 TIntermTyped *angleEmulatedDepthRangeRef = driverUniforms->getDepthRange();
259
260 // Use this variable instead of gl_DepthRange everywhere.
261 return ReplaceVariableWithTyped(compiler, root, depthRangeVar, angleEmulatedDepthRangeRef);
262 }
263
264 // Declares a new variable to replace gl_BoundingBoxEXT, its values are fed from a global temporary
265 // variable.
ReplaceGLBoundingBoxWithGlobal(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,int shaderVersion)266 [[nodiscard]] bool ReplaceGLBoundingBoxWithGlobal(TCompiler *compiler,
267 TIntermBlock *root,
268 TSymbolTable *symbolTable,
269 int shaderVersion)
270 {
271 // Declare the replacement bounding box variable type
272 TType *emulatedBoundingBoxDeclType = new TType(EbtFloat, EbpHigh, EvqGlobal, 4);
273 emulatedBoundingBoxDeclType->makeArray(2u);
274
275 TVariable *ANGLEBoundingBoxVar = new TVariable(
276 symbolTable->nextUniqueId(), ImmutableString("ANGLEBoundingBox"), SymbolType::AngleInternal,
277 TExtension::EXT_primitive_bounding_box, emulatedBoundingBoxDeclType);
278
279 DeclareGlobalVariable(root, ANGLEBoundingBoxVar);
280
281 const TVariable *builtinBoundingBoxVar;
282 bool replacementResult = true;
283
284 // Create a symbol reference to "gl_BoundingBoxEXT"
285 builtinBoundingBoxVar = static_cast<const TVariable *>(
286 symbolTable->findBuiltIn(ImmutableString("gl_BoundingBoxEXT"), shaderVersion));
287 if (builtinBoundingBoxVar != nullptr)
288 {
289 // Use the replacement variable instead of builtin gl_BoundingBoxEXT everywhere.
290 replacementResult &=
291 ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
292 }
293
294 // Create a symbol reference to "gl_BoundingBoxOES"
295 builtinBoundingBoxVar = static_cast<const TVariable *>(
296 symbolTable->findBuiltIn(ImmutableString("gl_BoundingBoxOES"), shaderVersion));
297 if (builtinBoundingBoxVar != nullptr)
298 {
299 // Use the replacement variable instead of builtin gl_BoundingBoxOES everywhere.
300 replacementResult &=
301 ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
302 }
303
304 if (shaderVersion >= 320)
305 {
306 // Create a symbol reference to "gl_BoundingBox"
307 builtinBoundingBoxVar = static_cast<const TVariable *>(
308 symbolTable->findBuiltIn(ImmutableString("gl_BoundingBox"), shaderVersion));
309 if (builtinBoundingBoxVar != nullptr)
310 {
311 // Use the replacement variable instead of builtin gl_BoundingBox everywhere.
312 replacementResult &=
313 ReplaceVariable(compiler, root, builtinBoundingBoxVar, ANGLEBoundingBoxVar);
314 }
315 }
316 return replacementResult;
317 }
318
AddXfbEmulationSupport(TranslatorSPIRV * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const DriverUniform * driverUniforms)319 [[nodiscard]] bool AddXfbEmulationSupport(TranslatorSPIRV *compiler,
320 TIntermBlock *root,
321 TSymbolTable *symbolTable,
322 const DriverUniform *driverUniforms)
323 {
324 // Generate the following function and place it before main(). This function takes a "strides"
325 // parameter that is determined at link time, and calculates for each transform feedback buffer
326 // (of which there are a maximum of four) what the starting index is to write to the output
327 // buffer.
328 //
329 // ivec4 ANGLEGetXfbOffsets(ivec4 strides)
330 // {
331 // int xfbIndex = gl_VertexIndex
332 // + gl_InstanceIndex * ANGLEUniforms.xfbVerticesPerInstance;
333 // return ANGLEUniforms.xfbBufferOffsets + xfbIndex * strides;
334 // }
335
336 constexpr uint32_t kMaxXfbBuffers = 4;
337
338 const TType *ivec4Type = StaticType::GetBasic<EbtInt, EbpHigh, kMaxXfbBuffers>();
339 TType *stridesType = new TType(*ivec4Type);
340 stridesType->setQualifier(EvqParamConst);
341
342 // Create the parameter variable.
343 TVariable *stridesVar = new TVariable(symbolTable, ImmutableString("strides"), stridesType,
344 SymbolType::AngleInternal);
345 TIntermSymbol *stridesSymbol = new TIntermSymbol(stridesVar);
346
347 // Create references to gl_VertexIndex, gl_InstanceIndex, ANGLEUniforms.xfbVerticesPerInstance
348 // and ANGLEUniforms.xfbBufferOffsets.
349 TIntermSymbol *vertexIndex = new TIntermSymbol(BuiltInVariable::gl_VertexIndex());
350 TIntermSymbol *instanceIndex = new TIntermSymbol(BuiltInVariable::gl_InstanceIndex());
351 TIntermTyped *xfbVerticesPerInstance = driverUniforms->getXfbVerticesPerInstance();
352 TIntermTyped *xfbBufferOffsets = driverUniforms->getXfbBufferOffsets();
353
354 // gl_InstanceIndex * ANGLEUniforms.xfbVerticesPerInstance
355 TIntermBinary *xfbInstanceIndex =
356 new TIntermBinary(EOpMul, instanceIndex, xfbVerticesPerInstance);
357
358 // gl_VertexIndex + |xfbInstanceIndex|
359 TIntermBinary *xfbIndex = new TIntermBinary(EOpAdd, vertexIndex, xfbInstanceIndex);
360
361 // |xfbIndex| * |strides|
362 TIntermBinary *xfbStrides = new TIntermBinary(EOpVectorTimesScalar, xfbIndex, stridesSymbol);
363
364 // ANGLEUniforms.xfbBufferOffsets + |xfbStrides|
365 TIntermBinary *xfbOffsets = new TIntermBinary(EOpAdd, xfbBufferOffsets, xfbStrides);
366
367 // Create the function body, which has a single return statement. Note that the `xfbIndex`
368 // variable declared in the comment at the beginning of this function is simply replaced in the
369 // return statement for brevity.
370 TIntermBlock *body = new TIntermBlock;
371 body->appendStatement(new TIntermBranch(EOpReturn, xfbOffsets));
372
373 // Declare the function
374 TFunction *getOffsetsFunction =
375 new TFunction(symbolTable, ImmutableString("ANGLEGetXfbOffsets"), SymbolType::AngleInternal,
376 ivec4Type, true);
377 getOffsetsFunction->addParameter(stridesVar);
378
379 compiler->assignSpirvId(getOffsetsFunction->uniqueId(),
380 vk::spirv::kIdXfbEmulationGetOffsetsFunction);
381
382 TIntermFunctionDefinition *functionDef =
383 CreateInternalFunctionDefinitionNode(*getOffsetsFunction, body);
384
385 // Insert the function declaration before main().
386 const size_t mainIndex = FindMainIndex(root);
387 root->insertChildNodes(mainIndex, {functionDef});
388
389 // Generate the following function and place it before main(). This function will be filled
390 // with transform feedback capture code at link time.
391 //
392 // void ANGLECaptureXfb()
393 // {
394 // }
395 const TType *voidType = StaticType::GetBasic<EbtVoid, EbpUndefined>();
396
397 // Create the function body, which is empty.
398 body = new TIntermBlock;
399
400 // Declare the function
401 TFunction *xfbCaptureFunction = new TFunction(symbolTable, ImmutableString("ANGLECaptureXfb"),
402 SymbolType::AngleInternal, voidType, false);
403
404 compiler->assignSpirvId(xfbCaptureFunction->uniqueId(),
405 vk::spirv::kIdXfbEmulationCaptureFunction);
406
407 // Insert the function declaration before main().
408 root->insertChildNodes(mainIndex,
409 {CreateInternalFunctionDefinitionNode(*xfbCaptureFunction, body)});
410
411 // Create the following logic and add it at the end of main():
412 //
413 // ANGLECaptureXfb();
414 //
415
416 // Create the function call
417 TIntermAggregate *captureXfbCall =
418 TIntermAggregate::CreateFunctionCall(*xfbCaptureFunction, {});
419
420 // Run it at the end of the shader.
421 if (!RunAtTheEndOfShader(compiler, root, captureXfbCall, symbolTable))
422 {
423 return false;
424 }
425
426 // Additionally, generate the following storage buffer declarations used to capture transform
427 // feedback output. Again, there's a maximum of four buffers.
428 //
429 // buffer ANGLEXfbBuffer0
430 // {
431 // float xfbOut[];
432 // } ANGLEXfb0;
433 // buffer ANGLEXfbBuffer1
434 // {
435 // float xfbOut[];
436 // } ANGLEXfb1;
437 // ...
438
439 for (uint32_t bufferIndex = 0; bufferIndex < kMaxXfbBuffers; ++bufferIndex)
440 {
441 TFieldList *fieldList = new TFieldList;
442 TType *xfbOutType = new TType(EbtFloat, EbpHigh, EvqGlobal);
443 xfbOutType->makeArray(0);
444
445 TField *field = new TField(xfbOutType, ImmutableString("xfbOut"), TSourceLoc(),
446 SymbolType::AngleInternal);
447
448 fieldList->push_back(field);
449
450 static_assert(
451 kMaxXfbBuffers < 10,
452 "ImmutableStringBuilder memory size below needs to accomodate the number of buffers");
453
454 ImmutableString blockName = BuildConcatenatedImmutableString("ANGLEXfbBuffer", bufferIndex);
455 ImmutableString varName = BuildConcatenatedImmutableString("ANGLEXfb", bufferIndex);
456
457 TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
458 layoutQualifier.blockStorage = EbsStd430;
459
460 const TVariable *xfbBuffer =
461 DeclareInterfaceBlock(root, symbolTable, fieldList, EvqBuffer, layoutQualifier,
462 TMemoryQualifier::Create(), 0, blockName, varName);
463
464 static_assert(vk::spirv::kIdXfbEmulationBufferBlockOne ==
465 vk::spirv::kIdXfbEmulationBufferBlockZero + 1);
466 static_assert(vk::spirv::kIdXfbEmulationBufferBlockTwo ==
467 vk::spirv::kIdXfbEmulationBufferBlockZero + 2);
468 static_assert(vk::spirv::kIdXfbEmulationBufferBlockThree ==
469 vk::spirv::kIdXfbEmulationBufferBlockZero + 3);
470
471 static_assert(vk::spirv::kIdXfbEmulationBufferVarOne ==
472 vk::spirv::kIdXfbEmulationBufferVarZero + 1);
473 static_assert(vk::spirv::kIdXfbEmulationBufferVarTwo ==
474 vk::spirv::kIdXfbEmulationBufferVarZero + 2);
475 static_assert(vk::spirv::kIdXfbEmulationBufferVarThree ==
476 vk::spirv::kIdXfbEmulationBufferVarZero + 3);
477
478 compiler->assignSpirvId(xfbBuffer->getType().getInterfaceBlock()->uniqueId(),
479 vk::spirv::kIdXfbEmulationBufferBlockZero + bufferIndex);
480 compiler->assignSpirvId(xfbBuffer->uniqueId(),
481 vk::spirv::kIdXfbEmulationBufferVarZero + bufferIndex);
482 }
483
484 return compiler->validateAST(root);
485 }
486
AddXfbExtensionSupport(TranslatorSPIRV * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const DriverUniform * driverUniforms)487 [[nodiscard]] bool AddXfbExtensionSupport(TranslatorSPIRV *compiler,
488 TIntermBlock *root,
489 TSymbolTable *symbolTable,
490 const DriverUniform *driverUniforms)
491 {
492 // Generate the following output varying declaration used to capture transform feedback output
493 // from gl_Position, as it can't be captured directly due to changes that are applied to it for
494 // clip-space correction and pre-rotation.
495 //
496 // out vec4 ANGLEXfbPosition;
497
498 const TType *vec4Type = nullptr;
499
500 switch (compiler->getShaderType())
501 {
502 case GL_VERTEX_SHADER:
503 vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqVertexOut, 4, 1>();
504 break;
505 case GL_TESS_EVALUATION_SHADER_EXT:
506 vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqTessEvaluationOut, 4, 1>();
507 break;
508 case GL_GEOMETRY_SHADER_EXT:
509 vec4Type = StaticType::Get<EbtFloat, EbpHigh, EvqGeometryOut, 4, 1>();
510 break;
511 default:
512 UNREACHABLE();
513 }
514
515 TVariable *varyingVar = new TVariable(symbolTable, ImmutableString("ANGLEXfbPosition"),
516 vec4Type, SymbolType::AngleInternal);
517
518 compiler->assignSpirvId(varyingVar->uniqueId(), vk::spirv::kIdXfbExtensionPosition);
519
520 TIntermDeclaration *varyingDecl = new TIntermDeclaration();
521 varyingDecl->appendDeclarator(new TIntermSymbol(varyingVar));
522
523 // Insert the varying declaration before the first function.
524 const size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root);
525 root->insertChildNodes(firstFunctionIndex, {varyingDecl});
526
527 return compiler->validateAST(root);
528 }
529
AddVertexTransformationSupport(TranslatorSPIRV * compiler,const ShCompileOptions & compileOptions,TIntermBlock * root,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms)530 [[nodiscard]] bool AddVertexTransformationSupport(TranslatorSPIRV *compiler,
531 const ShCompileOptions &compileOptions,
532 TIntermBlock *root,
533 TSymbolTable *symbolTable,
534 SpecConst *specConst,
535 const DriverUniform *driverUniforms)
536 {
537 // In GL the viewport transformation is slightly different - see the GL 2.0 spec section "2.12.1
538 // Controlling the Viewport". In Vulkan the corresponding spec section is currently "23.4.
539 // Coordinate Transformations". The following transformation needs to be done:
540 //
541 // z_vk = 0.5 * (w_gl + z_gl)
542 //
543 // where z_vk is the depth output of a Vulkan geometry-stage shader and z_gl is the same for GL.
544 //
545 // Generate the following function and place it before main(). This function takes
546 // gl_Position and rotates xy, and adjusts z (if necessary).
547 //
548 // vec4 ANGLETransformPosition(vec4 position)
549 // {
550 // return vec4((swapXY ? position.yx : position.xy) * flipXY,
551 // transformDepth ? (gl_Position.z + gl_Position.w) / 2 : gl_Position.z,
552 // gl_Postion.w);
553 // }
554
555 const TType *vec4Type = StaticType::GetBasic<EbtFloat, EbpHigh, 4>();
556 TType *positionType = new TType(*vec4Type);
557 positionType->setQualifier(EvqParamConst);
558
559 // Create the parameter variable.
560 TVariable *positionVar = new TVariable(symbolTable, ImmutableString("position"), positionType,
561 SymbolType::AngleInternal);
562 TIntermSymbol *positionSymbol = new TIntermSymbol(positionVar);
563
564 // swapXY ? position.yx : position.xy
565 TIntermTyped *swapXY = specConst->getSwapXY();
566 if (swapXY == nullptr)
567 {
568 swapXY = driverUniforms->getSwapXY();
569 }
570
571 TIntermTyped *xy = new TIntermSwizzle(positionSymbol, {0, 1});
572 TIntermTyped *swappedXY = new TIntermSwizzle(positionSymbol->deepCopy(), {1, 0});
573 TIntermTyped *rotatedXY = new TIntermTernary(swapXY, swappedXY, xy);
574
575 // (swapXY ? position.yx : position.xy) * flipXY
576 TIntermTyped *flipXY = driverUniforms->getFlipXY(symbolTable, DriverUniformFlip::PreFragment);
577 TIntermTyped *rotatedFlippedXY = new TIntermBinary(EOpMul, rotatedXY, flipXY);
578
579 // (gl_Position.z + gl_Position.w) / 2
580 TIntermTyped *z = new TIntermSwizzle(positionSymbol->deepCopy(), {2});
581 TIntermTyped *w = new TIntermSwizzle(positionSymbol->deepCopy(), {3});
582
583 TIntermTyped *transformedDepth = z;
584 if (compileOptions.addVulkanDepthCorrection)
585 {
586 TIntermBinary *zPlusW = new TIntermBinary(EOpAdd, z, w->deepCopy());
587 TIntermBinary *halfZPlusW =
588 new TIntermBinary(EOpMul, zPlusW, CreateFloatNode(0.5, EbpMedium));
589
590 // transformDepth ? (gl_Position.z + gl_Position.w) / 2 : gl_Position.z,
591 TIntermTyped *transformDepth = driverUniforms->getTransformDepth();
592 transformedDepth = new TIntermTernary(transformDepth, halfZPlusW, z->deepCopy());
593 }
594
595 // vec4(...);
596 TIntermSequence args = {
597 rotatedFlippedXY,
598 transformedDepth,
599 w,
600 };
601 TIntermTyped *transformedPosition = TIntermAggregate::CreateConstructor(*vec4Type, &args);
602
603 // Create the function body, which has a single return statement.
604 TIntermBlock *body = new TIntermBlock;
605 body->appendStatement(new TIntermBranch(EOpReturn, transformedPosition));
606
607 // Declare the function
608 TFunction *transformPositionFunction =
609 new TFunction(symbolTable, ImmutableString("ANGLETransformPosition"),
610 SymbolType::AngleInternal, vec4Type, true);
611 transformPositionFunction->addParameter(positionVar);
612
613 compiler->assignSpirvId(transformPositionFunction->uniqueId(),
614 vk::spirv::kIdTransformPositionFunction);
615
616 TIntermFunctionDefinition *functionDef =
617 CreateInternalFunctionDefinitionNode(*transformPositionFunction, body);
618
619 // Insert the function declaration before main().
620 const size_t mainIndex = FindMainIndex(root);
621 root->insertChildNodes(mainIndex, {functionDef});
622
623 return compiler->validateAST(root);
624 }
625
InsertFragCoordCorrection(TCompiler * compiler,const ShCompileOptions & compileOptions,TIntermBlock * root,TIntermSequence * insertSequence,TSymbolTable * symbolTable,SpecConst * specConst,const DriverUniform * driverUniforms)626 [[nodiscard]] bool InsertFragCoordCorrection(TCompiler *compiler,
627 const ShCompileOptions &compileOptions,
628 TIntermBlock *root,
629 TIntermSequence *insertSequence,
630 TSymbolTable *symbolTable,
631 SpecConst *specConst,
632 const DriverUniform *driverUniforms)
633 {
634 TIntermTyped *flipXY = driverUniforms->getFlipXY(symbolTable, DriverUniformFlip::Fragment);
635 TIntermTyped *pivot = driverUniforms->getHalfRenderArea();
636
637 TIntermTyped *swapXY = specConst->getSwapXY();
638 if (swapXY == nullptr)
639 {
640 swapXY = driverUniforms->getSwapXY();
641 }
642
643 const TVariable *fragCoord = static_cast<const TVariable *>(
644 symbolTable->findBuiltIn(ImmutableString("gl_FragCoord"), compiler->getShaderVersion()));
645 return RotateAndFlipBuiltinVariable(compiler, root, insertSequence, swapXY, flipXY, symbolTable,
646 fragCoord, kFlippedFragCoordName, pivot);
647 }
648
HasFramebufferFetch(const TExtensionBehavior & extBehavior,const ShCompileOptions & compileOptions)649 bool HasFramebufferFetch(const TExtensionBehavior &extBehavior,
650 const ShCompileOptions &compileOptions)
651 {
652 return IsExtensionEnabled(extBehavior, TExtension::EXT_shader_framebuffer_fetch) ||
653 IsExtensionEnabled(extBehavior, TExtension::EXT_shader_framebuffer_fetch_non_coherent) ||
654 IsExtensionEnabled(extBehavior, TExtension::ARM_shader_framebuffer_fetch) ||
655 IsExtensionEnabled(extBehavior,
656 TExtension::ARM_shader_framebuffer_fetch_depth_stencil) ||
657 IsExtensionEnabled(extBehavior, TExtension::NV_shader_framebuffer_fetch) ||
658 (compileOptions.pls.type == ShPixelLocalStorageType::FramebufferFetch &&
659 IsExtensionEnabled(extBehavior, TExtension::ANGLE_shader_pixel_local_storage));
660 }
661
662 template <typename Variable>
FindShaderVariable(std::vector<Variable> * vars,const ImmutableString & name)663 Variable *FindShaderVariable(std::vector<Variable> *vars, const ImmutableString &name)
664 {
665 for (Variable &var : *vars)
666 {
667 if (name == var.name)
668 {
669 return &var;
670 }
671 }
672 UNREACHABLE();
673 return nullptr;
674 }
675
FindIOBlockShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name)676 ShaderVariable *FindIOBlockShaderVariable(std::vector<ShaderVariable> *vars,
677 const ImmutableString &name)
678 {
679 for (ShaderVariable &var : *vars)
680 {
681 if (name == var.structOrBlockName)
682 {
683 return &var;
684 }
685 }
686 UNREACHABLE();
687 return nullptr;
688 }
689
FindUniformFieldShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name,const char * prefix)690 ShaderVariable *FindUniformFieldShaderVariable(std::vector<ShaderVariable> *vars,
691 const ImmutableString &name,
692 const char *prefix)
693 {
694 for (ShaderVariable &var : *vars)
695 {
696 // The name of the sampler is derived from the uniform name + fields
697 // that reach the uniform, concatenated with '_' per RewriteStructSamplers.
698 std::string varName = prefix;
699 varName += '_';
700 varName += var.name;
701
702 if (name == varName)
703 {
704 return &var;
705 }
706
707 ShaderVariable *field = FindUniformFieldShaderVariable(&var.fields, name, varName.c_str());
708 if (field != nullptr)
709 {
710 return field;
711 }
712 }
713 return nullptr;
714 }
715
FindUniformShaderVariable(std::vector<ShaderVariable> * vars,const ImmutableString & name)716 ShaderVariable *FindUniformShaderVariable(std::vector<ShaderVariable> *vars,
717 const ImmutableString &name)
718 {
719 for (ShaderVariable &var : *vars)
720 {
721 if (name == var.name)
722 {
723 return &var;
724 }
725
726 // Note: samplers in structs are moved out. Such samplers will be found in the fields of
727 // the struct uniform.
728 ShaderVariable *field = FindUniformFieldShaderVariable(&var.fields, name, var.name.c_str());
729 if (field != nullptr)
730 {
731 return field;
732 }
733 }
734 UNREACHABLE();
735 return nullptr;
736 }
737
SetSpirvIdInFields(uint32_t id,std::vector<ShaderVariable> * fields)738 void SetSpirvIdInFields(uint32_t id, std::vector<ShaderVariable> *fields)
739 {
740 for (ShaderVariable &field : *fields)
741 {
742 field.id = id;
743 SetSpirvIdInFields(id, &field.fields);
744 }
745 }
746 } // anonymous namespace
747
TranslatorSPIRV(sh::GLenum type,ShShaderSpec spec)748 TranslatorSPIRV::TranslatorSPIRV(sh::GLenum type, ShShaderSpec spec)
749 : TCompiler(type, spec, SH_SPIRV_VULKAN_OUTPUT), mFirstUnusedSpirvId(0)
750 {}
751
translateImpl(TIntermBlock * root,const ShCompileOptions & compileOptions,PerformanceDiagnostics *,SpecConst * specConst,DriverUniform * driverUniforms)752 bool TranslatorSPIRV::translateImpl(TIntermBlock *root,
753 const ShCompileOptions &compileOptions,
754 PerformanceDiagnostics * /*perfDiagnostics*/,
755 SpecConst *specConst,
756 DriverUniform *driverUniforms)
757 {
758 if (getShaderType() == GL_VERTEX_SHADER)
759 {
760 if (!ShaderBuiltinsWorkaround(this, root, &getSymbolTable(), compileOptions))
761 {
762 return false;
763 }
764 }
765
766 // Write out default uniforms into a uniform block assigned to a specific set/binding.
767 int defaultUniformCount = 0;
768 int aggregateTypesUsedForUniforms = 0;
769 int r32fImageCount = 0;
770 int atomicCounterCount = 0;
771 for (const auto &uniform : getUniforms())
772 {
773 if (!uniform.isBuiltIn() && uniform.active && !gl::IsOpaqueType(uniform.type))
774 {
775 ++defaultUniformCount;
776 }
777
778 if (uniform.isStruct() || uniform.isArrayOfArrays())
779 {
780 ++aggregateTypesUsedForUniforms;
781 }
782
783 if (uniform.active && gl::IsImageType(uniform.type) && uniform.imageUnitFormat == GL_R32F)
784 {
785 ++r32fImageCount;
786 }
787
788 if (uniform.active && gl::IsAtomicCounterType(uniform.type))
789 {
790 ++atomicCounterCount;
791 }
792 }
793
794 // Remove declarations of inactive shader interface variables so SPIR-V transformer doesn't need
795 // to replace them. Note that currently, CollectVariables marks every field of an active
796 // uniform that's of struct type as active, i.e. no extracted sampler is inactive, so this can
797 // be done before extracting samplers from structs.
798 if (!RemoveInactiveInterfaceVariables(this, root, &getSymbolTable(), getAttributes(),
799 getInputVaryings(), getOutputVariables(), getUniforms(),
800 getInterfaceBlocks(), true))
801 {
802 return false;
803 }
804
805 // If there are any function calls that take array-of-array of opaque uniform parameters, or
806 // other opaque uniforms that need special handling in Vulkan, such as atomic counters,
807 // monomorphize the functions by removing said parameters and replacing them in the function
808 // body with the call arguments.
809 //
810 // This has a few benefits:
811 //
812 // - It dramatically simplifies future transformations w.r.t to samplers in structs, array of
813 // arrays of opaque types, atomic counters etc.
814 // - Avoids the need for shader*ArrayDynamicIndexing Vulkan features.
815 UnsupportedFunctionArgsBitSet args{UnsupportedFunctionArgs::StructContainingSamplers,
816 UnsupportedFunctionArgs::ArrayOfArrayOfSamplerOrImage,
817 UnsupportedFunctionArgs::AtomicCounter,
818 UnsupportedFunctionArgs::Image};
819 if (!MonomorphizeUnsupportedFunctions(this, root, &getSymbolTable(), args))
820 {
821 return false;
822 }
823
824 if (aggregateTypesUsedForUniforms > 0)
825 {
826 if (!SeparateStructFromUniformDeclarations(this, root, &getSymbolTable()))
827 {
828 return false;
829 }
830
831 int removedUniformsCount;
832
833 if (!RewriteStructSamplers(this, root, &getSymbolTable(), &removedUniformsCount))
834 {
835 return false;
836 }
837 defaultUniformCount -= removedUniformsCount;
838 }
839
840 // Replace array of array of opaque uniforms with a flattened array. This is run after
841 // MonomorphizeUnsupportedFunctions and RewriteStructSamplers so that it's not possible for an
842 // array of array of opaque type to be partially subscripted and passed to a function.
843 if (!RewriteArrayOfArrayOfOpaqueUniforms(this, root, &getSymbolTable()))
844 {
845 return false;
846 }
847
848 if (!FlagSamplersForTexelFetch(this, root, &getSymbolTable(), &mUniforms))
849 {
850 return false;
851 }
852
853 gl::ShaderType packedShaderType = gl::FromGLenum<gl::ShaderType>(getShaderType());
854
855 if (defaultUniformCount > 0)
856 {
857 if (!DeclareDefaultUniforms(this, root, &getSymbolTable(), packedShaderType))
858 {
859 return false;
860 }
861 }
862
863 if (getShaderType() == GL_COMPUTE_SHADER)
864 {
865 driverUniforms->addComputeDriverUniformsToShader(root, &getSymbolTable());
866 }
867 else
868 {
869 driverUniforms->addGraphicsDriverUniformsToShader(root, &getSymbolTable());
870 }
871
872 assignSpirvId(
873 driverUniforms->getDriverUniformsVariable()->getType().getInterfaceBlock()->uniqueId(),
874 vk::spirv::kIdDriverUniformsBlock);
875
876 if (r32fImageCount > 0 && compileOptions.emulateR32fImageAtomicExchange)
877 {
878 if (!RewriteR32fImages(this, root, &getSymbolTable()))
879 {
880 return false;
881 }
882 }
883
884 if (atomicCounterCount > 0)
885 {
886 // ANGLEUniforms.acbBufferOffsets
887 const TIntermTyped *acbBufferOffsets = driverUniforms->getAcbBufferOffsets();
888 const TVariable *atomicCounters = nullptr;
889 if (!RewriteAtomicCounters(this, root, &getSymbolTable(), acbBufferOffsets,
890 &atomicCounters))
891 {
892 return false;
893 }
894 assignSpirvId(atomicCounters->getType().getInterfaceBlock()->uniqueId(),
895 vk::spirv::kIdAtomicCounterBlock);
896 }
897 else if (getShaderVersion() >= 310)
898 {
899 // Vulkan doesn't support Atomic Storage as a Storage Class, but we've seen
900 // cases where builtins are using it even with no active atomic counters.
901 // This pass simply removes those builtins in that scenario.
902 if (!RemoveAtomicCounterBuiltins(this, root))
903 {
904 return false;
905 }
906 }
907
908 if (packedShaderType != gl::ShaderType::Compute)
909 {
910 if (!ReplaceGLDepthRangeWithDriverUniform(this, root, driverUniforms, &getSymbolTable()))
911 {
912 return false;
913 }
914
915 // Search for the gl_ClipDistance/gl_CullDistance usage, if its used, we need to do some
916 // replacements.
917 bool useClipDistance = false;
918 bool useCullDistance = false;
919 for (const ShaderVariable &outputVarying : mOutputVaryings)
920 {
921 if (outputVarying.name == "gl_ClipDistance")
922 {
923 useClipDistance = true;
924 }
925 else if (outputVarying.name == "gl_CullDistance")
926 {
927 useCullDistance = true;
928 }
929 }
930 for (const ShaderVariable &inputVarying : mInputVaryings)
931 {
932 if (inputVarying.name == "gl_ClipDistance")
933 {
934 useClipDistance = true;
935 }
936 else if (inputVarying.name == "gl_CullDistance")
937 {
938 useCullDistance = true;
939 }
940 }
941
942 if (useClipDistance &&
943 !ReplaceClipDistanceAssignments(this, root, &getSymbolTable(), getShaderType(),
944 driverUniforms->getClipDistancesEnabled()))
945 {
946 return false;
947 }
948 if (useCullDistance &&
949 !ReplaceCullDistanceAssignments(this, root, &getSymbolTable(), getShaderType()))
950 {
951 return false;
952 }
953 }
954
955 if (gl::ShaderTypeSupportsTransformFeedback(packedShaderType))
956 {
957 if (compileOptions.addVulkanXfbExtensionSupportCode)
958 {
959 // Add support code for transform feedback extension.
960 if (!AddXfbExtensionSupport(this, root, &getSymbolTable(), driverUniforms))
961 {
962 return false;
963 }
964 }
965
966 // Add support code for pre-rotation and depth correction in the vertex processing stages.
967 if (!AddVertexTransformationSupport(this, compileOptions, root, &getSymbolTable(),
968 specConst, driverUniforms))
969 {
970 return false;
971 }
972 }
973
974 switch (packedShaderType)
975 {
976 case gl::ShaderType::Fragment:
977 {
978 bool usesPointCoord = false;
979 bool usesFragCoord = false;
980 bool usesSampleMaskIn = false;
981 bool useSamplePosition = false;
982
983 // Search for the gl_PointCoord usage, if its used, we need to flip the y coordinate.
984 for (const ShaderVariable &inputVarying : mInputVaryings)
985 {
986 if (!inputVarying.isBuiltIn())
987 {
988 continue;
989 }
990
991 if (inputVarying.name == "gl_SampleMaskIn")
992 {
993 usesSampleMaskIn = true;
994 continue;
995 }
996
997 if (inputVarying.name == "gl_SamplePosition")
998 {
999 useSamplePosition = true;
1000 continue;
1001 }
1002
1003 if (inputVarying.name == "gl_PointCoord")
1004 {
1005 usesPointCoord = true;
1006 break;
1007 }
1008
1009 if (inputVarying.name == "gl_FragCoord")
1010 {
1011 usesFragCoord = true;
1012 break;
1013 }
1014 }
1015
1016 bool hasGLSampleMask = false;
1017 bool hasGLSecondaryFragData = false;
1018 const TIntermSymbol *yuvOutput = nullptr;
1019
1020 for (const ShaderVariable &outputVar : mOutputVariables)
1021 {
1022 if (outputVar.name == "gl_SampleMask")
1023 {
1024 ASSERT(!hasGLSampleMask);
1025 hasGLSampleMask = true;
1026 continue;
1027 }
1028 if (outputVar.name == "gl_SecondaryFragDataEXT")
1029 {
1030 ASSERT(!hasGLSecondaryFragData);
1031 hasGLSecondaryFragData = true;
1032 continue;
1033 }
1034 if (outputVar.yuv)
1035 {
1036 // We can only have one yuv output
1037 ASSERT(yuvOutput == nullptr);
1038 yuvOutput = FindSymbolNode(root, ImmutableString(outputVar.name));
1039 continue;
1040 }
1041 }
1042
1043 if (usesPointCoord)
1044 {
1045 TIntermTyped *flipNegXY =
1046 driverUniforms->getNegFlipXY(&getSymbolTable(), DriverUniformFlip::Fragment);
1047 TIntermConstantUnion *pivot = CreateFloatNode(0.5f, EbpMedium);
1048 TIntermTyped *swapXY = specConst->getSwapXY();
1049 if (swapXY == nullptr)
1050 {
1051 swapXY = driverUniforms->getSwapXY();
1052 }
1053 if (!RotateAndFlipBuiltinVariable(
1054 this, root, GetMainSequence(root), swapXY, flipNegXY, &getSymbolTable(),
1055 BuiltInVariable::gl_PointCoord(), kFlippedPointCoordName, pivot))
1056 {
1057 return false;
1058 }
1059 }
1060
1061 if (useSamplePosition)
1062 {
1063 TIntermTyped *flipXY =
1064 driverUniforms->getFlipXY(&getSymbolTable(), DriverUniformFlip::Fragment);
1065 TIntermConstantUnion *pivot = CreateFloatNode(0.5f, EbpMedium);
1066 TIntermTyped *swapXY = specConst->getSwapXY();
1067 if (swapXY == nullptr)
1068 {
1069 swapXY = driverUniforms->getSwapXY();
1070 }
1071
1072 const TVariable *samplePositionBuiltin =
1073 static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
1074 ImmutableString("gl_SamplePosition"), getShaderVersion()));
1075 if (!RotateAndFlipBuiltinVariable(this, root, GetMainSequence(root), swapXY, flipXY,
1076 &getSymbolTable(), samplePositionBuiltin,
1077 kFlippedPointCoordName, pivot))
1078 {
1079 return false;
1080 }
1081 }
1082
1083 if (usesFragCoord)
1084 {
1085 if (!InsertFragCoordCorrection(this, compileOptions, root, GetMainSequence(root),
1086 &getSymbolTable(), specConst, driverUniforms))
1087 {
1088 return false;
1089 }
1090 }
1091
1092 // Emulate gl_FragColor and gl_FragData with normal output variables.
1093 if (!EmulateFragColorData(this, root, &getSymbolTable(), hasGLSecondaryFragData))
1094 {
1095 return false;
1096 }
1097
1098 InputAttachmentMap inputAttachmentMap;
1099
1100 // Emulate framebuffer fetch if used.
1101 if (HasFramebufferFetch(getExtensionBehavior(), compileOptions))
1102 {
1103 if (!EmulateFramebufferFetch(this, root, &inputAttachmentMap))
1104 {
1105 return false;
1106 }
1107 }
1108
1109 // This should be operated after doing ReplaceLastFragData and ReplaceInOutVariables,
1110 // because they will create the input attachment variables. AddBlendMainCaller will
1111 // check the existing input attachment variables and if there is no existing input
1112 // attachment variable then create a new one.
1113 if (getAdvancedBlendEquations().any() &&
1114 compileOptions.addAdvancedBlendEquationsEmulation &&
1115 !EmulateAdvancedBlendEquations(this, root, &getSymbolTable(),
1116 getAdvancedBlendEquations(), driverUniforms,
1117 &inputAttachmentMap))
1118 {
1119 return false;
1120 }
1121
1122 // Input attachments are potentially added in framebuffer fetch and advanced blend
1123 // emulation. Declare their SPIR-V ids.
1124 assignInputAttachmentIds(inputAttachmentMap);
1125
1126 if (!RewriteDfdy(this, root, &getSymbolTable(), getShaderVersion(), specConst,
1127 driverUniforms))
1128 {
1129 return false;
1130 }
1131
1132 if (!RewriteInterpolateAtOffset(this, root, &getSymbolTable(), getShaderVersion(),
1133 specConst, driverUniforms))
1134 {
1135 return false;
1136 }
1137
1138 if (usesSampleMaskIn && !RewriteSampleMaskIn(this, root, &getSymbolTable()))
1139 {
1140 return false;
1141 }
1142
1143 if (hasGLSampleMask)
1144 {
1145 TIntermTyped *numSamples = driverUniforms->getNumSamples();
1146 if (!RewriteSampleMask(this, root, &getSymbolTable(), numSamples))
1147 {
1148 return false;
1149 }
1150 }
1151
1152 {
1153 const TVariable *numSamplesVar =
1154 static_cast<const TVariable *>(getSymbolTable().findBuiltIn(
1155 ImmutableString("gl_NumSamples"), getShaderVersion()));
1156 TIntermTyped *numSamples = driverUniforms->getNumSamples();
1157 if (!ReplaceVariableWithTyped(this, root, numSamplesVar, numSamples))
1158 {
1159 return false;
1160 }
1161 }
1162
1163 if (IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_YUV_target))
1164 {
1165 if (!EmulateYUVBuiltIns(this, root, &getSymbolTable()))
1166 {
1167 return false;
1168 }
1169
1170 if (!ReswizzleYUVOps(this, root, &getSymbolTable(), yuvOutput))
1171 {
1172 return false;
1173 }
1174 }
1175
1176 if (!EmulateDithering(this, compileOptions, root, &getSymbolTable(), specConst,
1177 driverUniforms))
1178 {
1179 return false;
1180 }
1181
1182 break;
1183 }
1184
1185 case gl::ShaderType::Vertex:
1186 {
1187 if (compileOptions.addVulkanXfbEmulationSupportCode)
1188 {
1189 // Add support code for transform feedback emulation. Only applies to vertex shader
1190 // as tessellation and geometry shader transform feedback capture require
1191 // VK_EXT_transform_feedback.
1192 if (!AddXfbEmulationSupport(this, root, &getSymbolTable(), driverUniforms))
1193 {
1194 return false;
1195 }
1196 }
1197
1198 break;
1199 }
1200
1201 case gl::ShaderType::Geometry:
1202 if (!ClampGLLayer(this, root, &getSymbolTable(), driverUniforms))
1203 {
1204 return false;
1205 }
1206 break;
1207
1208 case gl::ShaderType::TessControl:
1209 {
1210 if (!ReplaceGLBoundingBoxWithGlobal(this, root, &getSymbolTable(), getShaderVersion()))
1211 {
1212 return false;
1213 }
1214 break;
1215 }
1216
1217 case gl::ShaderType::TessEvaluation:
1218 break;
1219
1220 case gl::ShaderType::Compute:
1221 break;
1222
1223 default:
1224 UNREACHABLE();
1225 break;
1226 }
1227
1228 specConst->declareSpecConsts(root);
1229 mValidateASTOptions.validateSpecConstReferences = true;
1230
1231 // Gather specialization constant usage bits so that we can feedback to context.
1232 mSpecConstUsageBits = specConst->getSpecConstUsageBits();
1233
1234 if (!validateAST(root))
1235 {
1236 return false;
1237 }
1238
1239 // Make sure function call validation is not accidentally left off anywhere.
1240 ASSERT(mValidateASTOptions.validateFunctionCall);
1241 ASSERT(mValidateASTOptions.validateNoRawFunctionCalls);
1242
1243 // Declare the implicitly defined gl_PerVertex I/O blocks if not already. This will help SPIR-V
1244 // generation treat them mostly like usual I/O blocks.
1245 const TVariable *inputPerVertex = nullptr;
1246 const TVariable *outputPerVertex = nullptr;
1247 if (!DeclarePerVertexBlocks(this, root, &getSymbolTable(), &inputPerVertex, &outputPerVertex))
1248 {
1249 return false;
1250 }
1251
1252 if (inputPerVertex)
1253 {
1254 assignSpirvId(inputPerVertex->getType().getInterfaceBlock()->uniqueId(),
1255 vk::spirv::kIdInputPerVertexBlock);
1256 }
1257 if (outputPerVertex)
1258 {
1259 assignSpirvId(outputPerVertex->getType().getInterfaceBlock()->uniqueId(),
1260 vk::spirv::kIdOutputPerVertexBlock);
1261 assignSpirvId(outputPerVertex->uniqueId(), vk::spirv::kIdOutputPerVertexVar);
1262 }
1263
1264 // Now that all transformations are done, assign SPIR-V ids to whatever shader variable is still
1265 // present in the shader in some form. This should be the last thing done in this function.
1266 assignSpirvIds(root);
1267
1268 return true;
1269 }
1270
translate(TIntermBlock * root,const ShCompileOptions & compileOptions,PerformanceDiagnostics * perfDiagnostics)1271 bool TranslatorSPIRV::translate(TIntermBlock *root,
1272 const ShCompileOptions &compileOptions,
1273 PerformanceDiagnostics *perfDiagnostics)
1274 {
1275 mUniqueToSpirvIdMap.clear();
1276 mFirstUnusedSpirvId = 0;
1277
1278 SpecConst specConst(&getSymbolTable(), compileOptions, getShaderType());
1279
1280 DriverUniform driverUniforms(DriverUniformMode::InterfaceBlock);
1281 DriverUniformExtended driverUniformsExt(DriverUniformMode::InterfaceBlock);
1282
1283 const bool useExtendedDriverUniforms = compileOptions.addVulkanXfbEmulationSupportCode;
1284
1285 DriverUniform *uniforms = useExtendedDriverUniforms ? &driverUniformsExt : &driverUniforms;
1286
1287 if (!translateImpl(root, compileOptions, perfDiagnostics, &specConst, uniforms))
1288 {
1289 return false;
1290 }
1291
1292 return OutputSPIRV(this, root, compileOptions, mUniqueToSpirvIdMap, mFirstUnusedSpirvId);
1293 }
1294
shouldFlattenPragmaStdglInvariantAll()1295 bool TranslatorSPIRV::shouldFlattenPragmaStdglInvariantAll()
1296 {
1297 // Not necessary.
1298 return false;
1299 }
1300
assignSpirvId(TSymbolUniqueId uniqueId,uint32_t spirvId)1301 void TranslatorSPIRV::assignSpirvId(TSymbolUniqueId uniqueId, uint32_t spirvId)
1302 {
1303 ASSERT(mUniqueToSpirvIdMap.find(uniqueId.get()) == mUniqueToSpirvIdMap.end());
1304 mUniqueToSpirvIdMap[uniqueId.get()] = spirvId;
1305 }
1306
assignInputAttachmentIds(const InputAttachmentMap & inputAttachmentMap)1307 void TranslatorSPIRV::assignInputAttachmentIds(const InputAttachmentMap &inputAttachmentMap)
1308 {
1309 for (auto &iter : inputAttachmentMap.color)
1310 {
1311 const uint32_t index = iter.first;
1312 const TVariable *var = iter.second;
1313 ASSERT(var != nullptr);
1314
1315 assignSpirvId(var->uniqueId(), vk::spirv::kIdInputAttachment0 + index);
1316
1317 const MetadataFlags flag = static_cast<MetadataFlags>(
1318 static_cast<uint32_t>(MetadataFlags::HasInputAttachment0) + index);
1319 mMetadataFlags.set(flag);
1320 }
1321
1322 if (inputAttachmentMap.depth != nullptr)
1323 {
1324 assignSpirvId(inputAttachmentMap.depth->uniqueId(), vk::spirv::kIdDepthInputAttachment);
1325 mMetadataFlags.set(MetadataFlags::HasDepthInputAttachment);
1326 }
1327
1328 if (inputAttachmentMap.stencil != nullptr)
1329 {
1330 assignSpirvId(inputAttachmentMap.stencil->uniqueId(), vk::spirv::kIdStencilInputAttachment);
1331 mMetadataFlags.set(MetadataFlags::HasStencilInputAttachment);
1332 }
1333 }
1334
assignSpirvIds(TIntermBlock * root)1335 void TranslatorSPIRV::assignSpirvIds(TIntermBlock *root)
1336 {
1337 // Match the declarations with collected variables and assign a new id to each, starting from
1338 // the first unreserved id. This makes sure that the reserved ids for internal variables and
1339 // ids for shader variables form a minimal contiguous range. The Vulkan backend takes advantage
1340 // of this fact for optimal hashing.
1341 mFirstUnusedSpirvId = vk::spirv::kIdFirstUnreserved;
1342
1343 for (TIntermNode *node : *root->getSequence())
1344 {
1345 TIntermDeclaration *decl = node->getAsDeclarationNode();
1346 if (decl == nullptr)
1347 {
1348 continue;
1349 }
1350
1351 TIntermSymbol *symbol = decl->getSequence()->front()->getAsSymbolNode();
1352 if (symbol == nullptr)
1353 {
1354 continue;
1355 }
1356
1357 const TType &type = symbol->getType();
1358 const TQualifier qualifier = type.getQualifier();
1359
1360 // Skip internal symbols, which already have a reserved id.
1361 const TSymbolUniqueId uniqueId =
1362 type.isInterfaceBlock() ? type.getInterfaceBlock()->uniqueId() : symbol->uniqueId();
1363 if (mUniqueToSpirvIdMap.find(uniqueId.get()) != mUniqueToSpirvIdMap.end())
1364 {
1365 continue;
1366 }
1367
1368 uint32_t *variableId = nullptr;
1369 std::vector<ShaderVariable> *fields = nullptr;
1370 if (type.isInterfaceBlock())
1371 {
1372 if (IsVaryingIn(qualifier))
1373 {
1374 ShaderVariable *varying =
1375 FindIOBlockShaderVariable(&mInputVaryings, type.getInterfaceBlock()->name());
1376 variableId = &varying->id;
1377 fields = &varying->fields;
1378 }
1379 else if (IsVaryingOut(qualifier))
1380 {
1381 ShaderVariable *varying =
1382 FindIOBlockShaderVariable(&mOutputVaryings, type.getInterfaceBlock()->name());
1383 variableId = &varying->id;
1384 fields = &varying->fields;
1385 }
1386 else if (IsStorageBuffer(qualifier))
1387 {
1388 InterfaceBlock *block =
1389 FindShaderVariable(&mShaderStorageBlocks, type.getInterfaceBlock()->name());
1390 variableId = &block->id;
1391 }
1392 else
1393 {
1394 InterfaceBlock *block =
1395 FindShaderVariable(&mUniformBlocks, type.getInterfaceBlock()->name());
1396 variableId = &block->id;
1397 }
1398 }
1399 else if (qualifier == EvqUniform)
1400 {
1401 ShaderVariable *uniform = FindUniformShaderVariable(&mUniforms, symbol->getName());
1402 variableId = &uniform->id;
1403 }
1404 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
1405 {
1406 ShaderVariable *attribute = FindShaderVariable(&mAttributes, symbol->getName());
1407 variableId = &attribute->id;
1408 }
1409 else if (IsShaderIn(qualifier))
1410 {
1411 ShaderVariable *varying = FindShaderVariable(&mInputVaryings, symbol->getName());
1412 variableId = &varying->id;
1413 fields = &varying->fields;
1414 }
1415 else if (qualifier == EvqFragmentOut)
1416 {
1417 // webgl_FragColor, webgl_FragData, webgl_SecondaryFragColor and webgl_SecondaryFragData
1418 // are recorded with their original names (starting with gl_)
1419 ImmutableString name(symbol->getName());
1420 if (angle::BeginsWith(name.data(), "webgl_") &&
1421 symbol->variable().symbolType() == SymbolType::AngleInternal)
1422 {
1423 name = ImmutableString(name.data() + 3, name.length() - 3);
1424 }
1425
1426 ShaderVariable *output = FindShaderVariable(&mOutputVariables, name);
1427 variableId = &output->id;
1428 }
1429 else if (IsShaderOut(qualifier))
1430 {
1431 ShaderVariable *varying = FindShaderVariable(&mOutputVaryings, symbol->getName());
1432 variableId = &varying->id;
1433 fields = &varying->fields;
1434 }
1435
1436 if (variableId == nullptr)
1437 {
1438 continue;
1439 }
1440
1441 ASSERT(variableId != nullptr);
1442 assignSpirvId(uniqueId, mFirstUnusedSpirvId);
1443 *variableId = mFirstUnusedSpirvId;
1444
1445 // Propagate the id to the first field of structs/blocks too. The front-end gathers
1446 // varyings as fields, and the transformer needs to infer the variable id (of struct type)
1447 // just by looking at the fields.
1448 if (fields != nullptr)
1449 {
1450 SetSpirvIdInFields(mFirstUnusedSpirvId, fields);
1451 }
1452
1453 ++mFirstUnusedSpirvId;
1454 }
1455 }
1456 } // namespace sh
1457