• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 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 
7 #include "compiler/translator/hlsl/OutputHLSL.h"
8 
9 #include <stdio.h>
10 #include <algorithm>
11 #include <cfloat>
12 
13 #include "common/angleutils.h"
14 #include "common/debug.h"
15 #include "common/utilities.h"
16 #include "compiler/translator/BuiltInFunctionEmulator.h"
17 #include "compiler/translator/InfoSink.h"
18 #include "compiler/translator/StaticType.h"
19 #include "compiler/translator/blocklayout.h"
20 #include "compiler/translator/hlsl/AtomicCounterFunctionHLSL.h"
21 #include "compiler/translator/hlsl/BuiltInFunctionEmulatorHLSL.h"
22 #include "compiler/translator/hlsl/ImageFunctionHLSL.h"
23 #include "compiler/translator/hlsl/ResourcesHLSL.h"
24 #include "compiler/translator/hlsl/StructureHLSL.h"
25 #include "compiler/translator/hlsl/TextureFunctionHLSL.h"
26 #include "compiler/translator/hlsl/TranslatorHLSL.h"
27 #include "compiler/translator/hlsl/UtilsHLSL.h"
28 #include "compiler/translator/tree_ops/hlsl/RemoveSwitchFallThrough.h"
29 #include "compiler/translator/tree_util/FindSymbolNode.h"
30 #include "compiler/translator/tree_util/NodeSearch.h"
31 #include "compiler/translator/util.h"
32 
33 namespace sh
34 {
35 
36 namespace
37 {
38 
39 constexpr const char kImage2DFunctionString[] = "// @@ IMAGE2D DECLARATION FUNCTION STRING @@";
40 
ArrayHelperFunctionName(const char * prefix,const TType & type)41 TString ArrayHelperFunctionName(const char *prefix, const TType &type)
42 {
43     TStringStream fnName = sh::InitializeStream<TStringStream>();
44     fnName << prefix << "_";
45     if (type.isArray())
46     {
47         for (unsigned int arraySize : type.getArraySizes())
48         {
49             fnName << arraySize << "_";
50         }
51     }
52     fnName << TypeString(type);
53     return fnName.str();
54 }
55 
IsDeclarationWrittenOut(TIntermDeclaration * node)56 bool IsDeclarationWrittenOut(TIntermDeclaration *node)
57 {
58     TIntermSequence *sequence = node->getSequence();
59     TIntermTyped *variable    = (*sequence)[0]->getAsTyped();
60     ASSERT(sequence->size() == 1);
61     ASSERT(variable);
62     return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
63             variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
64 }
65 
IsInStd140UniformBlock(TIntermTyped * node)66 bool IsInStd140UniformBlock(TIntermTyped *node)
67 {
68     TIntermBinary *binaryNode = node->getAsBinaryNode();
69 
70     if (binaryNode)
71     {
72         return IsInStd140UniformBlock(binaryNode->getLeft());
73     }
74 
75     const TType &type = node->getType();
76 
77     if (type.getQualifier() == EvqUniform)
78     {
79         // determine if we are in the standard layout
80         const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
81         if (interfaceBlock)
82         {
83             return (interfaceBlock->blockStorage() == EbsStd140);
84         }
85     }
86 
87     return false;
88 }
89 
GetInterfaceBlockOfUniformBlockNearestIndexOperator(TIntermTyped * node)90 const TInterfaceBlock *GetInterfaceBlockOfUniformBlockNearestIndexOperator(TIntermTyped *node)
91 {
92     const TIntermBinary *binaryNode = node->getAsBinaryNode();
93     if (binaryNode)
94     {
95         if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
96         {
97             return binaryNode->getLeft()->getType().getInterfaceBlock();
98         }
99     }
100 
101     const TIntermSymbol *symbolNode = node->getAsSymbolNode();
102     if (symbolNode)
103     {
104         const TVariable &variable = symbolNode->variable();
105         const TType &variableType = variable.getType();
106 
107         if (variableType.getQualifier() == EvqUniform &&
108             variable.symbolType() == SymbolType::UserDefined)
109         {
110             return variableType.getInterfaceBlock();
111         }
112     }
113 
114     return nullptr;
115 }
116 
GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)117 const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
118 {
119     switch (op)
120     {
121         case EOpAtomicAdd:
122             return "InterlockedAdd(";
123         case EOpAtomicMin:
124             return "InterlockedMin(";
125         case EOpAtomicMax:
126             return "InterlockedMax(";
127         case EOpAtomicAnd:
128             return "InterlockedAnd(";
129         case EOpAtomicOr:
130             return "InterlockedOr(";
131         case EOpAtomicXor:
132             return "InterlockedXor(";
133         case EOpAtomicExchange:
134             return "InterlockedExchange(";
135         case EOpAtomicCompSwap:
136             return "InterlockedCompareExchange(";
137         default:
138             UNREACHABLE();
139             return "";
140     }
141 }
142 
IsAtomicFunctionForSharedVariableDirectAssign(const TIntermBinary & node)143 bool IsAtomicFunctionForSharedVariableDirectAssign(const TIntermBinary &node)
144 {
145     TIntermAggregate *aggregateNode = node.getRight()->getAsAggregate();
146     if (aggregateNode == nullptr)
147     {
148         return false;
149     }
150 
151     if (node.getOp() == EOpAssign && BuiltInGroup::IsAtomicMemory(aggregateNode->getOp()))
152     {
153         return !IsInShaderStorageBlock((*aggregateNode->getSequence())[0]->getAsTyped()) &&
154                !IsInShaderStorageBlock(node.getLeft());
155     }
156 
157     return false;
158 }
159 
160 const char *kZeros       = "_ANGLE_ZEROS_";
161 constexpr int kZeroCount = 256;
DefineZeroArray()162 std::string DefineZeroArray()
163 {
164     std::stringstream ss = sh::InitializeStream<std::stringstream>();
165     // For 'static', if the declaration does not include an initializer, the value is set to zero.
166     // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax
167     ss << "static uint " << kZeros << "[" << kZeroCount << "];\n";
168     return ss.str();
169 }
170 
GetZeroInitializer(size_t size)171 std::string GetZeroInitializer(size_t size)
172 {
173     std::stringstream ss = sh::InitializeStream<std::stringstream>();
174     size_t quotient      = size / kZeroCount;
175     size_t reminder      = size % kZeroCount;
176 
177     for (size_t i = 0; i < quotient; ++i)
178     {
179         if (i != 0)
180         {
181             ss << ", ";
182         }
183         ss << kZeros;
184     }
185 
186     for (size_t i = 0; i < reminder; ++i)
187     {
188         if (quotient != 0 || i != 0)
189         {
190             ss << ", ";
191         }
192         ss << "0";
193     }
194 
195     return ss.str();
196 }
197 
IsFlatInterpolant(TIntermTyped * node)198 bool IsFlatInterpolant(TIntermTyped *node)
199 {
200     TIntermTyped *interpolant = node->getAsBinaryNode() ? node->getAsBinaryNode()->getLeft() : node;
201     return interpolant->getType().getQualifier() == EvqFlatIn;
202 }
203 
204 }  // anonymous namespace
205 
TReferencedBlock(const TInterfaceBlock * aBlock,const TVariable * aInstanceVariable)206 TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
207                                    const TVariable *aInstanceVariable)
208     : block(aBlock), instanceVariable(aInstanceVariable)
209 {}
210 
needStructMapping(TIntermTyped * node)211 bool OutputHLSL::needStructMapping(TIntermTyped *node)
212 {
213     ASSERT(node->getBasicType() == EbtStruct);
214     for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
215     {
216         TIntermNode *ancestor               = getAncestorNode(n);
217         const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
218         if (ancestorBinary)
219         {
220             switch (ancestorBinary->getOp())
221             {
222                 case EOpIndexDirectStruct:
223                 {
224                     const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
225                     const TIntermConstantUnion *index =
226                         ancestorBinary->getRight()->getAsConstantUnion();
227                     const TField *field = structure->fields()[index->getIConst(0)];
228                     if (field->type()->getStruct() == nullptr)
229                     {
230                         return false;
231                     }
232                     break;
233                 }
234                 case EOpIndexDirect:
235                 case EOpIndexIndirect:
236                     break;
237                 default:
238                     return true;
239             }
240         }
241         else
242         {
243             const TIntermAggregate *ancestorAggregate = ancestor->getAsAggregate();
244             if (ancestorAggregate)
245             {
246                 return true;
247             }
248             return false;
249         }
250     }
251     return true;
252 }
253 
writeFloat(TInfoSinkBase & out,float f)254 void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
255 {
256     // This is known not to work for NaN on all drivers but make the best effort to output NaNs
257     // regardless.
258     if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
259         mOutputType == SH_HLSL_4_1_OUTPUT)
260     {
261         out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
262     }
263     else
264     {
265         out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
266     }
267 }
268 
writeSingleConstant(TInfoSinkBase & out,const TConstantUnion * const constUnion)269 void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
270 {
271     ASSERT(constUnion != nullptr);
272     switch (constUnion->getType())
273     {
274         case EbtFloat:
275             writeFloat(out, constUnion->getFConst());
276             break;
277         case EbtInt:
278             out << constUnion->getIConst();
279             break;
280         case EbtUInt:
281             out << constUnion->getUConst();
282             break;
283         case EbtBool:
284             out << constUnion->getBConst();
285             break;
286         default:
287             UNREACHABLE();
288     }
289 }
290 
writeConstantUnionArray(TInfoSinkBase & out,const TConstantUnion * const constUnion,const size_t size)291 const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
292                                                           const TConstantUnion *const constUnion,
293                                                           const size_t size)
294 {
295     const TConstantUnion *constUnionIterated = constUnion;
296     for (size_t i = 0; i < size; i++, constUnionIterated++)
297     {
298         writeSingleConstant(out, constUnionIterated);
299 
300         if (i != size - 1)
301         {
302             out << ", ";
303         }
304     }
305     return constUnionIterated;
306 }
307 
OutputHLSL(sh::GLenum shaderType,ShShaderSpec shaderSpec,int shaderVersion,const TExtensionBehavior & extensionBehavior,const char * sourcePath,ShShaderOutput outputType,int numRenderTargets,int maxDualSourceDrawBuffers,const std::vector<ShaderVariable> & uniforms,const ShCompileOptions & compileOptions,sh::WorkGroupSize workGroupSize,TSymbolTable * symbolTable,PerformanceDiagnostics * perfDiagnostics,const std::map<int,const TInterfaceBlock * > & uniformBlockOptimizedMap,const std::vector<InterfaceBlock> & shaderStorageBlocks,uint8_t clipDistanceSize,uint8_t cullDistanceSize,bool isEarlyFragmentTestsSpecified)308 OutputHLSL::OutputHLSL(sh::GLenum shaderType,
309                        ShShaderSpec shaderSpec,
310                        int shaderVersion,
311                        const TExtensionBehavior &extensionBehavior,
312                        const char *sourcePath,
313                        ShShaderOutput outputType,
314                        int numRenderTargets,
315                        int maxDualSourceDrawBuffers,
316                        const std::vector<ShaderVariable> &uniforms,
317                        const ShCompileOptions &compileOptions,
318                        sh::WorkGroupSize workGroupSize,
319                        TSymbolTable *symbolTable,
320                        PerformanceDiagnostics *perfDiagnostics,
321                        const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap,
322                        const std::vector<InterfaceBlock> &shaderStorageBlocks,
323                        uint8_t clipDistanceSize,
324                        uint8_t cullDistanceSize,
325                        bool isEarlyFragmentTestsSpecified)
326     : TIntermTraverser(true, true, true, symbolTable),
327       mShaderType(shaderType),
328       mShaderSpec(shaderSpec),
329       mShaderVersion(shaderVersion),
330       mExtensionBehavior(extensionBehavior),
331       mSourcePath(sourcePath),
332       mOutputType(outputType),
333       mCompileOptions(compileOptions),
334       mInsideFunction(false),
335       mInsideMain(false),
336       mUniformBlockOptimizedMap(uniformBlockOptimizedMap),
337       mNumRenderTargets(numRenderTargets),
338       mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers),
339       mCurrentFunctionMetadata(nullptr),
340       mWorkGroupSize(workGroupSize),
341       mPerfDiagnostics(perfDiagnostics),
342       mClipDistanceSize(clipDistanceSize),
343       mCullDistanceSize(cullDistanceSize),
344       mIsEarlyFragmentTestsSpecified(isEarlyFragmentTestsSpecified),
345       mNeedStructMapping(false)
346 {
347     mUsesFragColor        = false;
348     mUsesFragData         = false;
349     mUsesDepthRange       = false;
350     mUsesFragCoord        = false;
351     mUsesPointCoord       = false;
352     mUsesFrontFacing      = false;
353     mUsesHelperInvocation = false;
354     mUsesPointSize        = false;
355     mUsesInstanceID       = false;
356     mHasMultiviewExtensionEnabled =
357         IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview) ||
358         IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2);
359     mUsesViewID                  = false;
360     mUsesVertexID                = false;
361     mUsesFragDepth               = false;
362     mUsesSampleID                = false;
363     mUsesSamplePosition          = false;
364     mUsesSampleMaskIn            = false;
365     mUsesSampleMask              = false;
366     mUsesNumSamples              = false;
367     mUsesNumWorkGroups           = false;
368     mUsesWorkGroupID             = false;
369     mUsesLocalInvocationID       = false;
370     mUsesGlobalInvocationID      = false;
371     mUsesLocalInvocationIndex    = false;
372     mUsesXor                     = false;
373     mUsesDiscardRewriting        = false;
374     mUsesNestedBreak             = false;
375     mRequiresIEEEStrictCompiling = false;
376     mUseZeroArray                = false;
377     mUsesSecondaryColor          = false;
378 
379     mDepthLayout = EdUnspecified;
380 
381     mUniqueIndex = 0;
382 
383     mOutputLod0Function      = false;
384     mInsideDiscontinuousLoop = false;
385     mNestedLoopDepth         = 0;
386 
387     mExcessiveLoopIndex = nullptr;
388 
389     mStructureHLSL       = new StructureHLSL;
390     mTextureFunctionHLSL = new TextureFunctionHLSL;
391     mImageFunctionHLSL   = new ImageFunctionHLSL;
392     mAtomicCounterFunctionHLSL =
393         new AtomicCounterFunctionHLSL(compileOptions.forceAtomicValueResolution);
394 
395     unsigned int firstUniformRegister = compileOptions.skipD3DConstantRegisterZero ? 1u : 0u;
396     mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
397 
398     if (mOutputType == SH_HLSL_3_0_OUTPUT)
399     {
400         // Fragment shaders need dx_DepthRange, dx_ViewCoords, dx_DepthFront,
401         // and dx_FragCoordOffset.
402         // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
403         // dx_ViewAdjust.
404         if (mShaderType == GL_VERTEX_SHADER)
405         {
406             mResourcesHLSL->reserveUniformRegisters(3);
407         }
408         else
409         {
410             mResourcesHLSL->reserveUniformRegisters(4);
411         }
412     }
413 
414     // Reserve registers for the default uniform block and driver constants
415     mResourcesHLSL->reserveUniformBlockRegisters(2);
416 
417     mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, mResourcesHLSL, shaderStorageBlocks);
418 }
419 
~OutputHLSL()420 OutputHLSL::~OutputHLSL()
421 {
422     SafeDelete(mSSBOOutputHLSL);
423     SafeDelete(mStructureHLSL);
424     SafeDelete(mResourcesHLSL);
425     SafeDelete(mTextureFunctionHLSL);
426     SafeDelete(mImageFunctionHLSL);
427     SafeDelete(mAtomicCounterFunctionHLSL);
428     for (auto &eqFunction : mStructEqualityFunctions)
429     {
430         SafeDelete(eqFunction);
431     }
432     for (auto &eqFunction : mArrayEqualityFunctions)
433     {
434         SafeDelete(eqFunction);
435     }
436 }
437 
output(TIntermNode * treeRoot,TInfoSinkBase & objSink)438 void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
439 {
440     BuiltInFunctionEmulator builtInFunctionEmulator;
441     InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
442     if (mCompileOptions.emulateIsnanFloatFunction)
443     {
444         InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
445                                                            mShaderVersion);
446     }
447 
448     builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
449 
450     // Now that we are done changing the AST, do the analyses need for HLSL generation
451     CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
452     ASSERT(success == CallDAG::INITDAG_SUCCESS);
453     mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
454 
455     const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
456     // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
457     // the shader code. When we add shader storage blocks we might also consider an alternative
458     // solution, since the struct mapping won't work very well for shader storage blocks.
459 
460     // Output the body and footer first to determine what has to go in the header
461     mInfoSinkStack.push(&mBody);
462     treeRoot->traverse(this);
463     mInfoSinkStack.pop();
464 
465     mInfoSinkStack.push(&mFooter);
466     mInfoSinkStack.pop();
467 
468     mInfoSinkStack.push(&mHeader);
469     header(mHeader, std140Structs, &builtInFunctionEmulator);
470     mInfoSinkStack.pop();
471 
472     objSink << mHeader.c_str();
473     objSink << mBody.c_str();
474     objSink << mFooter.c_str();
475 
476     builtInFunctionEmulator.cleanup();
477 }
478 
getShaderStorageBlockRegisterMap() const479 const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
480 {
481     return mResourcesHLSL->getShaderStorageBlockRegisterMap();
482 }
483 
getUniformBlockRegisterMap() const484 const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
485 {
486     return mResourcesHLSL->getUniformBlockRegisterMap();
487 }
488 
getUniformBlockUseStructuredBufferMap() const489 const std::map<std::string, bool> &OutputHLSL::getUniformBlockUseStructuredBufferMap() const
490 {
491     return mResourcesHLSL->getUniformBlockUseStructuredBufferMap();
492 }
493 
getUniformRegisterMap() const494 const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
495 {
496     return mResourcesHLSL->getUniformRegisterMap();
497 }
498 
getReadonlyImage2DRegisterIndex() const499 unsigned int OutputHLSL::getReadonlyImage2DRegisterIndex() const
500 {
501     return mResourcesHLSL->getReadonlyImage2DRegisterIndex();
502 }
503 
getImage2DRegisterIndex() const504 unsigned int OutputHLSL::getImage2DRegisterIndex() const
505 {
506     return mResourcesHLSL->getImage2DRegisterIndex();
507 }
508 
getUsedImage2DFunctionNames() const509 const std::set<std::string> &OutputHLSL::getUsedImage2DFunctionNames() const
510 {
511     return mImageFunctionHLSL->getUsedImage2DFunctionNames();
512 }
513 
structInitializerString(int indent,const TType & type,const TString & name) const514 TString OutputHLSL::structInitializerString(int indent,
515                                             const TType &type,
516                                             const TString &name) const
517 {
518     TString init;
519 
520     TString indentString;
521     for (int spaces = 0; spaces < indent; spaces++)
522     {
523         indentString += "    ";
524     }
525 
526     if (type.isArray())
527     {
528         init += indentString + "{\n";
529         for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
530         {
531             TStringStream indexedString = sh::InitializeStream<TStringStream>();
532             indexedString << name << "[" << arrayIndex << "]";
533             TType elementType = type;
534             elementType.toArrayElementType();
535             init += structInitializerString(indent + 1, elementType, indexedString.str());
536             if (arrayIndex < type.getOutermostArraySize() - 1)
537             {
538                 init += ",";
539             }
540             init += "\n";
541         }
542         init += indentString + "}";
543     }
544     else if (type.getBasicType() == EbtStruct)
545     {
546         init += indentString + "{\n";
547         const TStructure &structure = *type.getStruct();
548         const TFieldList &fields    = structure.fields();
549         for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
550         {
551             const TField &field      = *fields[fieldIndex];
552             const TString &fieldName = name + "." + Decorate(field.name());
553             const TType &fieldType   = *field.type();
554 
555             init += structInitializerString(indent + 1, fieldType, fieldName);
556             if (fieldIndex < fields.size() - 1)
557             {
558                 init += ",";
559             }
560             init += "\n";
561         }
562         init += indentString + "}";
563     }
564     else
565     {
566         init += indentString + name;
567     }
568 
569     return init;
570 }
571 
generateStructMapping(const std::vector<MappedStruct> & std140Structs) const572 TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
573 {
574     TString mappedStructs;
575 
576     for (auto &mappedStruct : std140Structs)
577     {
578         const TInterfaceBlock *interfaceBlock =
579             mappedStruct.blockDeclarator->getType().getInterfaceBlock();
580         TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
581         switch (qualifier)
582         {
583             case EvqUniform:
584                 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
585                 {
586                     continue;
587                 }
588                 break;
589             case EvqBuffer:
590                 continue;
591             default:
592                 UNREACHABLE();
593                 return mappedStructs;
594         }
595 
596         unsigned int instanceCount = 1u;
597         bool isInstanceArray       = mappedStruct.blockDeclarator->isArray();
598         if (isInstanceArray)
599         {
600             instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
601         }
602 
603         for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
604              ++instanceArrayIndex)
605         {
606             TString originalName;
607             TString mappedName("map");
608 
609             if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
610             {
611                 const ImmutableString &instanceName =
612                     mappedStruct.blockDeclarator->variable().name();
613                 unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
614                 if (isInstanceArray)
615                     instanceStringArrayIndex = instanceArrayIndex;
616                 TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
617                     instanceName, instanceStringArrayIndex);
618                 originalName += instanceString;
619                 mappedName += instanceString;
620                 originalName += ".";
621                 mappedName += "_";
622             }
623 
624             TString fieldName = Decorate(mappedStruct.field->name());
625             originalName += fieldName;
626             mappedName += fieldName;
627 
628             TType *structType = mappedStruct.field->type();
629             mappedStructs +=
630                 "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
631 
632             if (structType->isArray())
633             {
634                 mappedStructs += ArrayString(*mappedStruct.field->type()).data();
635             }
636 
637             mappedStructs += " =\n";
638             mappedStructs += structInitializerString(0, *structType, originalName);
639             mappedStructs += ";\n";
640         }
641     }
642     return mappedStructs;
643 }
644 
writeReferencedAttributes(TInfoSinkBase & out) const645 void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
646 {
647     for (const auto &attribute : mReferencedAttributes)
648     {
649         const TType &type           = attribute.second->getType();
650         const ImmutableString &name = attribute.second->name();
651 
652         out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
653             << zeroInitializer(type) << ";\n";
654     }
655 }
656 
writeReferencedVaryings(TInfoSinkBase & out) const657 void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
658 {
659     for (const auto &varying : mReferencedVaryings)
660     {
661         const TType &type = varying.second->getType();
662 
663         // Program linking depends on this exact format
664         out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
665             << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
666             << zeroInitializer(type) << ";\n";
667     }
668 }
669 
header(TInfoSinkBase & out,const std::vector<MappedStruct> & std140Structs,const BuiltInFunctionEmulator * builtInFunctionEmulator) const670 void OutputHLSL::header(TInfoSinkBase &out,
671                         const std::vector<MappedStruct> &std140Structs,
672                         const BuiltInFunctionEmulator *builtInFunctionEmulator) const
673 {
674     TString mappedStructs;
675     if (mNeedStructMapping)
676     {
677         mappedStructs = generateStructMapping(std140Structs);
678     }
679 
680     // Suppress some common warnings:
681     // 3556 : Integer divides might be much slower, try using uints if possible.
682     // 3571 : The pow(f, e) intrinsic function won't work for negative f, use abs(f) or
683     //        conditionally handle negative values if you expect them.
684     out << "#pragma warning( disable: 3556 3571 )\n";
685 
686     out << mStructureHLSL->structsHeader();
687 
688     mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
689     out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks, mUniformBlockOptimizedMap);
690     mSSBOOutputHLSL->writeShaderStorageBlocksHeader(mShaderType, out);
691 
692     if (!mEqualityFunctions.empty())
693     {
694         out << "\n// Equality functions\n\n";
695         for (const auto &eqFunction : mEqualityFunctions)
696         {
697             out << eqFunction->functionDefinition << "\n";
698         }
699     }
700     if (!mArrayAssignmentFunctions.empty())
701     {
702         out << "\n// Assignment functions\n\n";
703         for (const auto &assignmentFunction : mArrayAssignmentFunctions)
704         {
705             out << assignmentFunction.functionDefinition << "\n";
706         }
707     }
708     if (!mArrayConstructIntoFunctions.empty())
709     {
710         out << "\n// Array constructor functions\n\n";
711         for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
712         {
713             out << constructIntoFunction.functionDefinition << "\n";
714         }
715     }
716     if (!mFlatEvaluateFunctions.empty())
717     {
718         out << "\n// Evaluate* functions for flat inputs\n\n";
719         for (const auto &flatEvaluateFunction : mFlatEvaluateFunctions)
720         {
721             out << flatEvaluateFunction.functionDefinition << "\n";
722         }
723     }
724 
725     if (mUsesDiscardRewriting)
726     {
727         out << "#define ANGLE_USES_DISCARD_REWRITING\n";
728     }
729 
730     if (mUsesNestedBreak)
731     {
732         out << "#define ANGLE_USES_NESTED_BREAK\n";
733     }
734 
735     if (mRequiresIEEEStrictCompiling)
736     {
737         out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
738     }
739 
740     out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
741            "#define LOOP [loop]\n"
742            "#define FLATTEN [flatten]\n"
743            "#else\n"
744            "#define LOOP\n"
745            "#define FLATTEN\n"
746            "#endif\n";
747 
748     // array stride for atomic counter buffers is always 4 per original extension
749     // ARB_shader_atomic_counters and discussion on
750     // https://github.com/KhronosGroup/OpenGL-API/issues/5
751     out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
752 
753     if (mUseZeroArray)
754     {
755         out << DefineZeroArray() << "\n";
756     }
757 
758     if (mShaderType == GL_FRAGMENT_SHADER)
759     {
760         const bool usingMRTExtension =
761             IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
762         const bool usingBFEExtension =
763             IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_blend_func_extended);
764 
765         out << "// Varyings\n";
766         writeReferencedVaryings(out);
767         out << "\n";
768 
769         if ((IsDesktopGLSpec(mShaderSpec) && mShaderVersion >= 130) ||
770             (!IsDesktopGLSpec(mShaderSpec) && mShaderVersion >= 300))
771         {
772             for (const auto &outputVariable : mReferencedOutputVariables)
773             {
774                 const ImmutableString &variableName = outputVariable.second->name();
775                 const TType &variableType           = outputVariable.second->getType();
776 
777                 out << "static " << TypeString(variableType) << " out_" << variableName
778                     << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
779             }
780         }
781         else
782         {
783             const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
784 
785             out << "static float4 gl_Color[" << numColorValues
786                 << "] =\n"
787                    "{\n";
788             for (unsigned int i = 0; i < numColorValues; i++)
789             {
790                 out << "    float4(0, 0, 0, 0)";
791                 if (i + 1 != numColorValues)
792                 {
793                     out << ",";
794                 }
795                 out << "\n";
796             }
797 
798             out << "};\n";
799 
800             if (usingBFEExtension && mUsesSecondaryColor)
801             {
802                 out << "static float4 gl_SecondaryColor[" << mMaxDualSourceDrawBuffers
803                     << "] = \n"
804                        "{\n";
805                 for (int i = 0; i < mMaxDualSourceDrawBuffers; i++)
806                 {
807                     out << "    float4(0, 0, 0, 0)";
808                     if (i + 1 != mMaxDualSourceDrawBuffers)
809                     {
810                         out << ",";
811                     }
812                     out << "\n";
813                 }
814                 out << "};\n";
815             }
816         }
817 
818         if (mUsesViewID)
819         {
820             out << "static uint ViewID_OVR = 0;\n";
821         }
822 
823         if (mUsesFragDepth)
824         {
825             out << "static float gl_Depth = 0.0;\n";
826         }
827 
828         if (mUsesSampleID)
829         {
830             out << "static int gl_SampleID = 0;\n";
831         }
832 
833         if (mUsesSamplePosition)
834         {
835             out << "static float2 gl_SamplePosition = float2(0.0, 0.0);\n";
836         }
837 
838         if (mUsesSampleMaskIn)
839         {
840             out << "static int gl_SampleMaskIn[1] = {0};\n";
841         }
842 
843         if (mUsesSampleMask)
844         {
845             out << "static int gl_SampleMask[1] = {0};\n";
846         }
847 
848         if (mUsesNumSamples)
849         {
850             out << "static int gl_NumSamples = GetRenderTargetSampleCount();\n";
851         }
852 
853         if (mUsesFragCoord)
854         {
855             out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
856         }
857 
858         if (mUsesPointCoord)
859         {
860             out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
861         }
862 
863         if (mUsesFrontFacing)
864         {
865             out << "static bool gl_FrontFacing = false;\n";
866         }
867 
868         if (mUsesHelperInvocation)
869         {
870             out << "static bool gl_HelperInvocation = false;\n";
871         }
872 
873         out << "\n";
874 
875         if (mUsesDepthRange)
876         {
877             out << "struct gl_DepthRangeParameters\n"
878                    "{\n"
879                    "    float near;\n"
880                    "    float far;\n"
881                    "    float diff;\n"
882                    "};\n"
883                    "\n";
884         }
885 
886         if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
887         {
888             out << "cbuffer DriverConstants : register(b1)\n"
889                    "{\n";
890 
891             if (mUsesDepthRange)
892             {
893                 out << "    float3 dx_DepthRange : packoffset(c0);\n";
894             }
895 
896             if (mUsesFragCoord)
897             {
898                 out << "    float4 dx_ViewCoords : packoffset(c1);\n";
899                 out << "    float2 dx_FragCoordOffset : packoffset(c3);\n";
900             }
901 
902             if (mUsesFragCoord || mUsesFrontFacing)
903             {
904                 out << "    float3 dx_DepthFront : packoffset(c2);\n";
905             }
906 
907             if (mUsesFragCoord)
908             {
909                 // dx_ViewScale is only used in the fragment shader to correct
910                 // the value for glFragCoord if necessary
911                 out << "    float2 dx_ViewScale : packoffset(c3.z);\n";
912             }
913 
914             if (mOutputType == SH_HLSL_4_1_OUTPUT)
915             {
916                 out << "    uint dx_Misc : packoffset(c2.w);\n";
917                 unsigned int registerIndex = 4;
918                 mResourcesHLSL->samplerMetadataUniforms(out, registerIndex);
919                 // Sampler metadata struct must be two 4-vec, 32 bytes.
920                 registerIndex += mResourcesHLSL->getSamplerCount() * 2;
921                 mResourcesHLSL->imageMetadataUniforms(out, registerIndex);
922             }
923 
924             out << "};\n";
925 
926             if (mOutputType == SH_HLSL_4_1_OUTPUT && mResourcesHLSL->hasImages())
927             {
928                 out << kImage2DFunctionString << "\n";
929             }
930         }
931         else
932         {
933             if (mUsesDepthRange)
934             {
935                 out << "uniform float3 dx_DepthRange : register(c0);";
936             }
937 
938             if (mUsesFragCoord)
939             {
940                 out << "uniform float4 dx_ViewCoords : register(c1);\n";
941             }
942 
943             if (mUsesFragCoord || mUsesFrontFacing)
944             {
945                 out << "uniform float3 dx_DepthFront : register(c2);\n";
946                 out << "uniform float2 dx_FragCoordOffset : register(c3);\n";
947             }
948         }
949 
950         out << "\n";
951 
952         if (mUsesDepthRange)
953         {
954             out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
955                    "dx_DepthRange.y, dx_DepthRange.z};\n"
956                    "\n";
957         }
958 
959         if (mClipDistanceSize)
960         {
961             out << "static float gl_ClipDistance[" << static_cast<int>(mClipDistanceSize)
962                 << "] = {0";
963             for (unsigned int i = 1; i < mClipDistanceSize; i++)
964             {
965                 out << ", 0";
966             }
967             out << "};\n";
968         }
969 
970         if (mCullDistanceSize)
971         {
972             out << "static float gl_CullDistance[" << static_cast<int>(mCullDistanceSize)
973                 << "] = {0";
974             for (unsigned int i = 1; i < mCullDistanceSize; i++)
975             {
976                 out << ", 0";
977             }
978             out << "};\n";
979         }
980 
981         if (usingMRTExtension && mNumRenderTargets > 1)
982         {
983             out << "#define GL_USES_MRT\n";
984         }
985 
986         if (mUsesFragColor)
987         {
988             out << "#define GL_USES_FRAG_COLOR\n";
989         }
990 
991         if (mUsesFragData)
992         {
993             out << "#define GL_USES_FRAG_DATA\n";
994         }
995 
996         if (mShaderVersion < 300 && usingBFEExtension && mUsesSecondaryColor)
997         {
998             out << "#define GL_USES_SECONDARY_COLOR\n";
999         }
1000     }
1001     else if (mShaderType == GL_VERTEX_SHADER)
1002     {
1003         out << "// Attributes\n";
1004         writeReferencedAttributes(out);
1005         out << "\n"
1006                "static float4 gl_Position = float4(0, 0, 0, 0);\n";
1007 
1008         if (mClipDistanceSize)
1009         {
1010             out << "static float gl_ClipDistance[" << static_cast<int>(mClipDistanceSize)
1011                 << "] = {0";
1012             for (size_t i = 1; i < mClipDistanceSize; i++)
1013             {
1014                 out << ", 0";
1015             }
1016             out << "};\n";
1017         }
1018 
1019         if (mCullDistanceSize)
1020         {
1021             out << "static float gl_CullDistance[" << static_cast<int>(mCullDistanceSize)
1022                 << "] = {0";
1023             for (size_t i = 1; i < mCullDistanceSize; i++)
1024             {
1025                 out << ", 0";
1026             }
1027             out << "};\n";
1028         }
1029 
1030         if (mUsesPointSize)
1031         {
1032             out << "static float gl_PointSize = float(1);\n";
1033         }
1034 
1035         if (mUsesInstanceID)
1036         {
1037             out << "static int gl_InstanceID;\n";
1038         }
1039 
1040         if (mUsesViewID)
1041         {
1042             out << "static uint ViewID_OVR;\n";
1043         }
1044 
1045         if (mUsesVertexID)
1046         {
1047             out << "static int gl_VertexID;\n";
1048         }
1049 
1050         out << "\n"
1051                "// Varyings\n";
1052         writeReferencedVaryings(out);
1053         out << "\n";
1054 
1055         if (mUsesDepthRange)
1056         {
1057             out << "struct gl_DepthRangeParameters\n"
1058                    "{\n"
1059                    "    float near;\n"
1060                    "    float far;\n"
1061                    "    float diff;\n"
1062                    "};\n"
1063                    "\n";
1064         }
1065 
1066         if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
1067         {
1068             out << "cbuffer DriverConstants : register(b1)\n"
1069                    "{\n";
1070 
1071             if (mUsesDepthRange)
1072             {
1073                 out << "    float3 dx_DepthRange : packoffset(c0);\n";
1074             }
1075 
1076             // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
1077             // shaders. However, we declare it for all shaders (including Feature Level 10+).
1078             // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
1079             // if it's unused.
1080             out << "    float4 dx_ViewAdjust : packoffset(c1);\n";
1081             out << "    float2 dx_ViewCoords : packoffset(c2);\n";
1082             out << "    float2 dx_ViewScale  : packoffset(c3);\n";
1083 
1084             out << "    float clipControlOrigin : packoffset(c3.z);\n";
1085             out << "    float clipControlZeroToOne : packoffset(c3.w);\n";
1086 
1087             if (mOutputType == SH_HLSL_4_1_OUTPUT)
1088             {
1089                 mResourcesHLSL->samplerMetadataUniforms(out, 5);
1090             }
1091 
1092             if (mUsesVertexID)
1093             {
1094                 out << "    uint dx_VertexID : packoffset(c4.x);\n";
1095             }
1096 
1097             if (mClipDistanceSize)
1098             {
1099                 out << "    uint clipDistancesEnabled : packoffset(c4.y);\n";
1100             }
1101 
1102             out << "};\n"
1103                    "\n";
1104         }
1105         else
1106         {
1107             if (mUsesDepthRange)
1108             {
1109                 out << "uniform float3 dx_DepthRange : register(c0);\n";
1110             }
1111 
1112             out << "uniform float4 dx_ViewAdjust : register(c1);\n";
1113             out << "uniform float2 dx_ViewCoords : register(c2);\n";
1114 
1115             out << "static const float clipControlOrigin = -1.0f;\n";
1116             out << "static const float clipControlZeroToOne = 0.0f;\n";
1117 
1118             out << "\n";
1119         }
1120 
1121         if (mUsesDepthRange)
1122         {
1123             out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
1124                    "dx_DepthRange.y, dx_DepthRange.z};\n"
1125                    "\n";
1126         }
1127 
1128         if (mOutputType == SH_HLSL_4_1_OUTPUT && mResourcesHLSL->hasImages())
1129         {
1130             out << kImage2DFunctionString << "\n";
1131         }
1132     }
1133     else  // Compute shader
1134     {
1135         ASSERT(mShaderType == GL_COMPUTE_SHADER);
1136 
1137         out << "cbuffer DriverConstants : register(b1)\n"
1138                "{\n";
1139         if (mUsesNumWorkGroups)
1140         {
1141             out << "    uint3 gl_NumWorkGroups : packoffset(c0);\n";
1142         }
1143         ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
1144         unsigned int registerIndex = 1;
1145         mResourcesHLSL->samplerMetadataUniforms(out, registerIndex);
1146         // Sampler metadata struct must be two 4-vec, 32 bytes.
1147         registerIndex += mResourcesHLSL->getSamplerCount() * 2;
1148         mResourcesHLSL->imageMetadataUniforms(out, registerIndex);
1149         out << "};\n";
1150 
1151         out << kImage2DFunctionString << "\n";
1152 
1153         std::ostringstream systemValueDeclaration  = sh::InitializeStream<std::ostringstream>();
1154         std::ostringstream glBuiltinInitialization = sh::InitializeStream<std::ostringstream>();
1155 
1156         systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
1157         glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n" << "{\n";
1158 
1159         if (mUsesWorkGroupID)
1160         {
1161             out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
1162             systemValueDeclaration << "    uint3 dx_WorkGroupID : " << "SV_GroupID;\n";
1163             glBuiltinInitialization << "    gl_WorkGroupID = input.dx_WorkGroupID;\n";
1164         }
1165 
1166         if (mUsesLocalInvocationID)
1167         {
1168             out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
1169             systemValueDeclaration << "    uint3 dx_LocalInvocationID : " << "SV_GroupThreadID;\n";
1170             glBuiltinInitialization << "    gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
1171         }
1172 
1173         if (mUsesGlobalInvocationID)
1174         {
1175             out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
1176             systemValueDeclaration << "    uint3 dx_GlobalInvocationID : "
1177                                    << "SV_DispatchThreadID;\n";
1178             glBuiltinInitialization << "    gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
1179         }
1180 
1181         if (mUsesLocalInvocationIndex)
1182         {
1183             out << "static uint gl_LocalInvocationIndex = uint(0);\n";
1184             systemValueDeclaration << "    uint dx_LocalInvocationIndex : " << "SV_GroupIndex;\n";
1185             glBuiltinInitialization
1186                 << "    gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
1187         }
1188 
1189         systemValueDeclaration << "};\n\n";
1190         glBuiltinInitialization << "};\n\n";
1191 
1192         out << systemValueDeclaration.str();
1193         out << glBuiltinInitialization.str();
1194     }
1195 
1196     if (!mappedStructs.empty())
1197     {
1198         out << "// Structures from std140 blocks with padding removed\n";
1199         out << "\n";
1200         out << mappedStructs;
1201         out << "\n";
1202     }
1203 
1204     bool getDimensionsIgnoresBaseLevel = mCompileOptions.HLSLGetDimensionsIgnoresBaseLevel;
1205     mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
1206     mImageFunctionHLSL->imageFunctionHeader(out);
1207     mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
1208 
1209     if (mUsesFragCoord)
1210     {
1211         out << "#define GL_USES_FRAG_COORD\n";
1212     }
1213 
1214     if (mUsesPointCoord)
1215     {
1216         out << "#define GL_USES_POINT_COORD\n";
1217     }
1218 
1219     if (mUsesFrontFacing)
1220     {
1221         out << "#define GL_USES_FRONT_FACING\n";
1222     }
1223 
1224     if (mUsesHelperInvocation)
1225     {
1226         out << "#define GL_USES_HELPER_INVOCATION\n";
1227     }
1228 
1229     if (mUsesPointSize)
1230     {
1231         out << "#define GL_USES_POINT_SIZE\n";
1232     }
1233 
1234     if (mHasMultiviewExtensionEnabled)
1235     {
1236         out << "#define GL_MULTIVIEW_ENABLED\n";
1237     }
1238 
1239     if (mUsesVertexID)
1240     {
1241         out << "#define GL_USES_VERTEX_ID\n";
1242     }
1243 
1244     if (mUsesViewID)
1245     {
1246         out << "#define GL_USES_VIEW_ID\n";
1247     }
1248 
1249     if (mUsesSampleID)
1250     {
1251         out << "#define GL_USES_SAMPLE_ID\n";
1252     }
1253 
1254     if (mUsesSamplePosition)
1255     {
1256         out << "#define GL_USES_SAMPLE_POSITION\n";
1257     }
1258 
1259     if (mUsesSampleMaskIn)
1260     {
1261         out << "#define GL_USES_SAMPLE_MASK_IN\n";
1262     }
1263 
1264     if (mUsesSampleMask)
1265     {
1266         out << "#define GL_USES_SAMPLE_MASK_OUT\n";
1267     }
1268 
1269     if (mUsesFragDepth)
1270     {
1271         switch (mDepthLayout)
1272         {
1273             case EdGreater:
1274                 out << "#define GL_USES_FRAG_DEPTH_GREATER\n";
1275                 break;
1276             case EdLess:
1277                 out << "#define GL_USES_FRAG_DEPTH_LESS\n";
1278                 break;
1279             default:
1280                 out << "#define GL_USES_FRAG_DEPTH\n";
1281                 break;
1282         }
1283     }
1284 
1285     if (mUsesDepthRange)
1286     {
1287         out << "#define GL_USES_DEPTH_RANGE\n";
1288     }
1289 
1290     if (mUsesXor)
1291     {
1292         out << "bool xor(bool p, bool q)\n"
1293                "{\n"
1294                "    return (p || q) && !(p && q);\n"
1295                "}\n"
1296                "\n";
1297     }
1298 
1299     builtInFunctionEmulator->outputEmulatedFunctions(out);
1300 }
1301 
visitSymbol(TIntermSymbol * node)1302 void OutputHLSL::visitSymbol(TIntermSymbol *node)
1303 {
1304     const TVariable &variable = node->variable();
1305 
1306     // Empty symbols can only appear in declarations and function arguments, and in either of those
1307     // cases the symbol nodes are not visited.
1308     ASSERT(variable.symbolType() != SymbolType::Empty);
1309 
1310     TInfoSinkBase &out = getInfoSink();
1311 
1312     // Handle accessing std140 structs by value
1313     if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct &&
1314         needStructMapping(node))
1315     {
1316         mNeedStructMapping = true;
1317         out << "map";
1318     }
1319 
1320     const ImmutableString &name     = variable.name();
1321     const TSymbolUniqueId &uniqueId = variable.uniqueId();
1322 
1323     if (name == "gl_DepthRange")
1324     {
1325         mUsesDepthRange = true;
1326         out << name;
1327     }
1328     else if (name == "gl_NumSamples")
1329     {
1330         mUsesNumSamples = true;
1331         out << name;
1332     }
1333     else if (IsAtomicCounter(variable.getType().getBasicType()))
1334     {
1335         const TType &variableType = variable.getType();
1336         if (variableType.getQualifier() == EvqUniform)
1337         {
1338             TLayoutQualifier layout             = variableType.getLayoutQualifier();
1339             mReferencedUniforms[uniqueId.get()] = &variable;
1340             out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
1341         }
1342         else
1343         {
1344             TString varName = DecorateVariableIfNeeded(variable);
1345             out << varName << ", " << varName << "_offset";
1346         }
1347     }
1348     else
1349     {
1350         const TType &variableType = variable.getType();
1351         TQualifier qualifier      = variable.getType().getQualifier();
1352 
1353         ensureStructDefined(variableType);
1354 
1355         if (qualifier == EvqUniform)
1356         {
1357             const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
1358 
1359             if (interfaceBlock)
1360             {
1361                 if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1362                 {
1363                     const TVariable *instanceVariable = nullptr;
1364                     if (variableType.isInterfaceBlock())
1365                     {
1366                         instanceVariable = &variable;
1367                     }
1368                     mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1369                         new TReferencedBlock(interfaceBlock, instanceVariable);
1370                 }
1371             }
1372             else
1373             {
1374                 mReferencedUniforms[uniqueId.get()] = &variable;
1375             }
1376 
1377             out << DecorateVariableIfNeeded(variable);
1378         }
1379         else if (qualifier == EvqBuffer)
1380         {
1381             UNREACHABLE();
1382         }
1383         else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
1384         {
1385             mReferencedAttributes[uniqueId.get()] = &variable;
1386             out << Decorate(name);
1387         }
1388         else if (IsVarying(qualifier))
1389         {
1390             mReferencedVaryings[uniqueId.get()] = &variable;
1391             out << DecorateVariableIfNeeded(variable);
1392         }
1393         else if (qualifier == EvqFragmentOut)
1394         {
1395             mReferencedOutputVariables[uniqueId.get()] = &variable;
1396             out << "out_" << name;
1397         }
1398         else if (qualifier == EvqViewIDOVR)
1399         {
1400             out << name;
1401             mUsesViewID = true;
1402         }
1403         else if (qualifier == EvqClipDistance)
1404         {
1405             out << name;
1406         }
1407         else if (qualifier == EvqCullDistance)
1408         {
1409             out << name;
1410         }
1411         else if (qualifier == EvqFragColor)
1412         {
1413             out << "gl_Color[0]";
1414             mUsesFragColor = true;
1415         }
1416         else if (qualifier == EvqFragData)
1417         {
1418             out << "gl_Color";
1419             mUsesFragData = true;
1420         }
1421         else if (qualifier == EvqSecondaryFragColorEXT)
1422         {
1423             out << "gl_SecondaryColor[0]";
1424             mUsesSecondaryColor = true;
1425         }
1426         else if (qualifier == EvqSecondaryFragDataEXT)
1427         {
1428             out << "gl_SecondaryColor";
1429             mUsesSecondaryColor = true;
1430         }
1431         else if (qualifier == EvqFragCoord)
1432         {
1433             mUsesFragCoord = true;
1434             out << name;
1435         }
1436         else if (qualifier == EvqPointCoord)
1437         {
1438             mUsesPointCoord = true;
1439             out << name;
1440         }
1441         else if (qualifier == EvqFrontFacing)
1442         {
1443             mUsesFrontFacing = true;
1444             out << name;
1445         }
1446         else if (qualifier == EvqHelperInvocation)
1447         {
1448             mUsesHelperInvocation = true;
1449             out << name;
1450         }
1451         else if (qualifier == EvqPointSize)
1452         {
1453             mUsesPointSize = true;
1454             out << name;
1455         }
1456         else if (qualifier == EvqInstanceID)
1457         {
1458             mUsesInstanceID = true;
1459             out << name;
1460         }
1461         else if (qualifier == EvqVertexID)
1462         {
1463             mUsesVertexID = true;
1464             out << name;
1465         }
1466         else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
1467         {
1468             mUsesFragDepth = true;
1469             mDepthLayout   = variableType.getLayoutQualifier().depth;
1470             out << "gl_Depth";
1471         }
1472         else if (qualifier == EvqSampleID)
1473         {
1474             mUsesSampleID = true;
1475             out << name;
1476         }
1477         else if (qualifier == EvqSamplePosition)
1478         {
1479             mUsesSamplePosition = true;
1480             out << name;
1481         }
1482         else if (qualifier == EvqSampleMaskIn)
1483         {
1484             mUsesSampleMaskIn = true;
1485             out << name;
1486         }
1487         else if (qualifier == EvqSampleMask)
1488         {
1489             mUsesSampleMask = true;
1490             out << name;
1491         }
1492         else if (qualifier == EvqNumWorkGroups)
1493         {
1494             mUsesNumWorkGroups = true;
1495             out << name;
1496         }
1497         else if (qualifier == EvqWorkGroupID)
1498         {
1499             mUsesWorkGroupID = true;
1500             out << name;
1501         }
1502         else if (qualifier == EvqLocalInvocationID)
1503         {
1504             mUsesLocalInvocationID = true;
1505             out << name;
1506         }
1507         else if (qualifier == EvqGlobalInvocationID)
1508         {
1509             mUsesGlobalInvocationID = true;
1510             out << name;
1511         }
1512         else if (qualifier == EvqLocalInvocationIndex)
1513         {
1514             mUsesLocalInvocationIndex = true;
1515             out << name;
1516         }
1517         else
1518         {
1519             out << DecorateVariableIfNeeded(variable);
1520         }
1521     }
1522 }
1523 
outputEqual(Visit visit,const TType & type,TOperator op,TInfoSinkBase & out)1524 void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
1525 {
1526     if (type.isScalar() && !type.isArray())
1527     {
1528         if (op == EOpEqual)
1529         {
1530             outputTriplet(out, visit, "(", " == ", ")");
1531         }
1532         else
1533         {
1534             outputTriplet(out, visit, "(", " != ", ")");
1535         }
1536     }
1537     else
1538     {
1539         if (visit == PreVisit && op == EOpNotEqual)
1540         {
1541             out << "!";
1542         }
1543 
1544         if (type.isArray())
1545         {
1546             const TString &functionName = addArrayEqualityFunction(type);
1547             outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1548         }
1549         else if (type.getBasicType() == EbtStruct)
1550         {
1551             const TStructure &structure = *type.getStruct();
1552             const TString &functionName = addStructEqualityFunction(structure);
1553             outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1554         }
1555         else
1556         {
1557             ASSERT(type.isMatrix() || type.isVector());
1558             outputTriplet(out, visit, "all(", " == ", ")");
1559         }
1560     }
1561 }
1562 
outputAssign(Visit visit,const TType & type,TInfoSinkBase & out)1563 void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
1564 {
1565     if (type.isArray())
1566     {
1567         const TString &functionName = addArrayAssignmentFunction(type);
1568         outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
1569     }
1570     else
1571     {
1572         outputTriplet(out, visit, "(", " = ", ")");
1573     }
1574 }
1575 
ancestorEvaluatesToSamplerInStruct()1576 bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
1577 {
1578     for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
1579     {
1580         TIntermNode *ancestor               = getAncestorNode(n);
1581         const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
1582         if (ancestorBinary == nullptr)
1583         {
1584             return false;
1585         }
1586         switch (ancestorBinary->getOp())
1587         {
1588             case EOpIndexDirectStruct:
1589             {
1590                 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
1591                 const TIntermConstantUnion *index =
1592                     ancestorBinary->getRight()->getAsConstantUnion();
1593                 const TField *field = structure->fields()[index->getIConst(0)];
1594                 if (IsSampler(field->type()->getBasicType()))
1595                 {
1596                     return true;
1597                 }
1598                 break;
1599             }
1600             case EOpIndexDirect:
1601                 break;
1602             default:
1603                 // Returning a sampler from indirect indexing is not supported.
1604                 return false;
1605         }
1606     }
1607     return false;
1608 }
1609 
visitSwizzle(Visit visit,TIntermSwizzle * node)1610 bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
1611 {
1612     TInfoSinkBase &out = getInfoSink();
1613     if (visit == PostVisit)
1614     {
1615         out << ".";
1616         node->writeOffsetsAsXYZW(&out);
1617     }
1618     return true;
1619 }
1620 
visitBinary(Visit visit,TIntermBinary * node)1621 bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1622 {
1623     TInfoSinkBase &out = getInfoSink();
1624 
1625     switch (node->getOp())
1626     {
1627         case EOpComma:
1628             outputTriplet(out, visit, "(", ", ", ")");
1629             break;
1630         case EOpAssign:
1631             if (node->isArray())
1632             {
1633                 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
1634                 if (rightAgg != nullptr && rightAgg->isConstructor())
1635                 {
1636                     const TString &functionName = addArrayConstructIntoFunction(node->getType());
1637                     out << functionName << "(";
1638                     node->getLeft()->traverse(this);
1639                     TIntermSequence *seq = rightAgg->getSequence();
1640                     for (auto &arrayElement : *seq)
1641                     {
1642                         out << ", ";
1643                         arrayElement->traverse(this);
1644                     }
1645                     out << ")";
1646                     return false;
1647                 }
1648                 // ArrayReturnValueToOutParameter should have eliminated expressions where a
1649                 // function call is assigned.
1650                 ASSERT(rightAgg == nullptr);
1651             }
1652             // Assignment expressions with atomic functions should be transformed into atomic
1653             // function calls in HLSL.
1654             // e.g. original_value = atomicAdd(dest, value) should be translated into
1655             //      InterlockedAdd(dest, value, original_value);
1656             else if (IsAtomicFunctionForSharedVariableDirectAssign(*node))
1657             {
1658                 TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
1659                 TOperator atomicFunctionOp           = atomicFunctionNode->getOp();
1660                 out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
1661                 TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
1662                 ASSERT(argumentSeq->size() >= 2u);
1663                 for (auto &argument : *argumentSeq)
1664                 {
1665                     argument->traverse(this);
1666                     out << ", ";
1667                 }
1668                 node->getLeft()->traverse(this);
1669                 out << ")";
1670                 return false;
1671             }
1672             else if (IsInShaderStorageBlock(node->getLeft()))
1673             {
1674                 mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
1675                 out << ", ";
1676                 if (IsInShaderStorageBlock(node->getRight()))
1677                 {
1678                     mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1679                 }
1680                 else
1681                 {
1682                     node->getRight()->traverse(this);
1683                 }
1684 
1685                 out << ")";
1686                 return false;
1687             }
1688             else if (IsInShaderStorageBlock(node->getRight()))
1689             {
1690                 node->getLeft()->traverse(this);
1691                 out << " = ";
1692                 mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1693                 return false;
1694             }
1695 
1696             outputAssign(visit, node->getType(), out);
1697             break;
1698         case EOpInitialize:
1699             if (visit == PreVisit)
1700             {
1701                 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1702                 ASSERT(symbolNode);
1703                 TIntermTyped *initializer = node->getRight();
1704 
1705                 // Global initializers must be constant at this point.
1706                 ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
1707 
1708                 // GLSL allows to write things like "float x = x;" where a new variable x is defined
1709                 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1710                 // new variable is created before the assignment is evaluated), so we need to
1711                 // convert
1712                 // this to "float t = x, x = t;".
1713                 if (writeSameSymbolInitializer(out, symbolNode, initializer))
1714                 {
1715                     // Skip initializing the rest of the expression
1716                     return false;
1717                 }
1718                 else if (writeConstantInitialization(out, symbolNode, initializer))
1719                 {
1720                     return false;
1721                 }
1722             }
1723             else if (visit == InVisit)
1724             {
1725                 out << " = ";
1726                 if (IsInShaderStorageBlock(node->getRight()))
1727                 {
1728                     mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
1729                     return false;
1730                 }
1731             }
1732             break;
1733         case EOpAddAssign:
1734             outputTriplet(out, visit, "(", " += ", ")");
1735             break;
1736         case EOpSubAssign:
1737             outputTriplet(out, visit, "(", " -= ", ")");
1738             break;
1739         case EOpMulAssign:
1740             outputTriplet(out, visit, "(", " *= ", ")");
1741             break;
1742         case EOpVectorTimesScalarAssign:
1743             outputTriplet(out, visit, "(", " *= ", ")");
1744             break;
1745         case EOpMatrixTimesScalarAssign:
1746             outputTriplet(out, visit, "(", " *= ", ")");
1747             break;
1748         case EOpVectorTimesMatrixAssign:
1749             if (visit == PreVisit)
1750             {
1751                 out << "(";
1752             }
1753             else if (visit == InVisit)
1754             {
1755                 out << " = mul(";
1756                 node->getLeft()->traverse(this);
1757                 out << ", transpose(";
1758             }
1759             else
1760             {
1761                 out << ")))";
1762             }
1763             break;
1764         case EOpMatrixTimesMatrixAssign:
1765             if (visit == PreVisit)
1766             {
1767                 out << "(";
1768             }
1769             else if (visit == InVisit)
1770             {
1771                 out << " = transpose(mul(transpose(";
1772                 node->getLeft()->traverse(this);
1773                 out << "), transpose(";
1774             }
1775             else
1776             {
1777                 out << "))))";
1778             }
1779             break;
1780         case EOpDivAssign:
1781             outputTriplet(out, visit, "(", " /= ", ")");
1782             break;
1783         case EOpIModAssign:
1784             outputTriplet(out, visit, "(", " %= ", ")");
1785             break;
1786         case EOpBitShiftLeftAssign:
1787             outputTriplet(out, visit, "(", " <<= ", ")");
1788             break;
1789         case EOpBitShiftRightAssign:
1790             outputTriplet(out, visit, "(", " >>= ", ")");
1791             break;
1792         case EOpBitwiseAndAssign:
1793             outputTriplet(out, visit, "(", " &= ", ")");
1794             break;
1795         case EOpBitwiseXorAssign:
1796             outputTriplet(out, visit, "(", " ^= ", ")");
1797             break;
1798         case EOpBitwiseOrAssign:
1799             outputTriplet(out, visit, "(", " |= ", ")");
1800             break;
1801         case EOpIndexDirect:
1802         {
1803             const TType &leftType = node->getLeft()->getType();
1804             if (leftType.isInterfaceBlock())
1805             {
1806                 if (visit == PreVisit)
1807                 {
1808                     TIntermSymbol *instanceArraySymbol    = node->getLeft()->getAsSymbolNode();
1809                     const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
1810 
1811                     ASSERT(leftType.getQualifier() == EvqUniform);
1812                     if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
1813                     {
1814                         mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
1815                             new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
1816                     }
1817                     const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
1818                     out << mResourcesHLSL->InterfaceBlockInstanceString(
1819                         instanceArraySymbol->getName(), arrayIndex);
1820                     return false;
1821                 }
1822             }
1823             else if (ancestorEvaluatesToSamplerInStruct())
1824             {
1825                 // All parts of an expression that access a sampler in a struct need to use _ as
1826                 // separator to access the sampler variable that has been moved out of the struct.
1827                 outputTriplet(out, visit, "", "_", "");
1828             }
1829             else if (IsAtomicCounter(leftType.getBasicType()))
1830             {
1831                 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1832             }
1833             else
1834             {
1835                 outputTriplet(out, visit, "", "[", "]");
1836                 if (visit == PostVisit)
1837                 {
1838                     const TInterfaceBlock *interfaceBlock =
1839                         GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft());
1840                     if (interfaceBlock &&
1841                         mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
1842                     {
1843                         // If the uniform block member's type is not structure, we had explicitly
1844                         // packed the member into a structure, so need to add an operator of field
1845                         // slection.
1846                         const TField *field    = interfaceBlock->fields()[0];
1847                         const TType *fieldType = field->type();
1848                         if (fieldType->isMatrix() || fieldType->isVectorArray() ||
1849                             fieldType->isScalarArray())
1850                         {
1851                             out << "." << Decorate(field->name());
1852                         }
1853                     }
1854                 }
1855             }
1856         }
1857         break;
1858         case EOpIndexIndirect:
1859         {
1860             // We do not currently support indirect references to interface blocks
1861             ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
1862 
1863             const TType &leftType = node->getLeft()->getType();
1864             if (IsAtomicCounter(leftType.getBasicType()))
1865             {
1866                 outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
1867             }
1868             else
1869             {
1870                 outputTriplet(out, visit, "", "[", "]");
1871                 if (visit == PostVisit)
1872                 {
1873                     const TInterfaceBlock *interfaceBlock =
1874                         GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft());
1875                     if (interfaceBlock &&
1876                         mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
1877                     {
1878                         // If the uniform block member's type is not structure, we had explicitly
1879                         // packed the member into a structure, so need to add an operator of field
1880                         // slection.
1881                         const TField *field    = interfaceBlock->fields()[0];
1882                         const TType *fieldType = field->type();
1883                         if (fieldType->isMatrix() || fieldType->isVectorArray() ||
1884                             fieldType->isScalarArray())
1885                         {
1886                             out << "." << Decorate(field->name());
1887                         }
1888                     }
1889                 }
1890             }
1891             break;
1892         }
1893         case EOpIndexDirectStruct:
1894         {
1895             const TStructure *structure       = node->getLeft()->getType().getStruct();
1896             const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1897             const TField *field               = structure->fields()[index->getIConst(0)];
1898 
1899             // In cases where indexing returns a sampler, we need to access the sampler variable
1900             // that has been moved out of the struct.
1901             bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
1902             if (visit == PreVisit && indexingReturnsSampler)
1903             {
1904                 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
1905                 // This prefix is only output at the beginning of the indexing expression, which
1906                 // may have multiple parts.
1907                 out << "angle";
1908             }
1909             if (!indexingReturnsSampler)
1910             {
1911                 // All parts of an expression that access a sampler in a struct need to use _ as
1912                 // separator to access the sampler variable that has been moved out of the struct.
1913                 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
1914             }
1915             if (visit == InVisit)
1916             {
1917                 if (indexingReturnsSampler)
1918                 {
1919                     out << "_" << field->name();
1920                 }
1921                 else
1922                 {
1923                     out << "." << DecorateField(field->name(), *structure);
1924                 }
1925 
1926                 return false;
1927             }
1928         }
1929         break;
1930         case EOpIndexDirectInterfaceBlock:
1931         {
1932             ASSERT(!IsInShaderStorageBlock(node->getLeft()));
1933             bool structInStd140UniformBlock = node->getBasicType() == EbtStruct &&
1934                                               IsInStd140UniformBlock(node->getLeft()) &&
1935                                               needStructMapping(node);
1936             if (visit == PreVisit && structInStd140UniformBlock)
1937             {
1938                 mNeedStructMapping = true;
1939                 out << "map";
1940             }
1941             if (visit == InVisit)
1942             {
1943                 const TInterfaceBlock *interfaceBlock =
1944                     node->getLeft()->getType().getInterfaceBlock();
1945                 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
1946                 const TField *field               = interfaceBlock->fields()[index->getIConst(0)];
1947                 if (structInStd140UniformBlock ||
1948                     mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
1949                 {
1950                     out << "_";
1951                 }
1952                 else
1953                 {
1954                     out << ".";
1955                 }
1956                 out << Decorate(field->name());
1957 
1958                 return false;
1959             }
1960             break;
1961         }
1962         case EOpAdd:
1963             outputTriplet(out, visit, "(", " + ", ")");
1964             break;
1965         case EOpSub:
1966             outputTriplet(out, visit, "(", " - ", ")");
1967             break;
1968         case EOpMul:
1969             outputTriplet(out, visit, "(", " * ", ")");
1970             break;
1971         case EOpDiv:
1972             outputTriplet(out, visit, "(", " / ", ")");
1973             break;
1974         case EOpIMod:
1975             outputTriplet(out, visit, "(", " % ", ")");
1976             break;
1977         case EOpBitShiftLeft:
1978             outputTriplet(out, visit, "(", " << ", ")");
1979             break;
1980         case EOpBitShiftRight:
1981             outputTriplet(out, visit, "(", " >> ", ")");
1982             break;
1983         case EOpBitwiseAnd:
1984             outputTriplet(out, visit, "(", " & ", ")");
1985             break;
1986         case EOpBitwiseXor:
1987             outputTriplet(out, visit, "(", " ^ ", ")");
1988             break;
1989         case EOpBitwiseOr:
1990             outputTriplet(out, visit, "(", " | ", ")");
1991             break;
1992         case EOpEqual:
1993         case EOpNotEqual:
1994             outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
1995             break;
1996         case EOpLessThan:
1997             outputTriplet(out, visit, "(", " < ", ")");
1998             break;
1999         case EOpGreaterThan:
2000             outputTriplet(out, visit, "(", " > ", ")");
2001             break;
2002         case EOpLessThanEqual:
2003             outputTriplet(out, visit, "(", " <= ", ")");
2004             break;
2005         case EOpGreaterThanEqual:
2006             outputTriplet(out, visit, "(", " >= ", ")");
2007             break;
2008         case EOpVectorTimesScalar:
2009             outputTriplet(out, visit, "(", " * ", ")");
2010             break;
2011         case EOpMatrixTimesScalar:
2012             outputTriplet(out, visit, "(", " * ", ")");
2013             break;
2014         case EOpVectorTimesMatrix:
2015             outputTriplet(out, visit, "mul(", ", transpose(", "))");
2016             break;
2017         case EOpMatrixTimesVector:
2018             outputTriplet(out, visit, "mul(transpose(", "), ", ")");
2019             break;
2020         case EOpMatrixTimesMatrix:
2021             outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
2022             break;
2023         case EOpLogicalOr:
2024             // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
2025             // been unfolded.
2026             ASSERT(!node->getRight()->hasSideEffects());
2027             outputTriplet(out, visit, "(", " || ", ")");
2028             return true;
2029         case EOpLogicalXor:
2030             mUsesXor = true;
2031             outputTriplet(out, visit, "xor(", ", ", ")");
2032             break;
2033         case EOpLogicalAnd:
2034             // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
2035             // been unfolded.
2036             ASSERT(!node->getRight()->hasSideEffects());
2037             outputTriplet(out, visit, "(", " && ", ")");
2038             return true;
2039         default:
2040             UNREACHABLE();
2041     }
2042 
2043     return true;
2044 }
2045 
visitUnary(Visit visit,TIntermUnary * node)2046 bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
2047 {
2048     TInfoSinkBase &out = getInfoSink();
2049 
2050     switch (node->getOp())
2051     {
2052         case EOpNegative:
2053             outputTriplet(out, visit, "(-", "", ")");
2054             break;
2055         case EOpPositive:
2056             outputTriplet(out, visit, "(+", "", ")");
2057             break;
2058         case EOpLogicalNot:
2059             outputTriplet(out, visit, "(!", "", ")");
2060             break;
2061         case EOpBitwiseNot:
2062             outputTriplet(out, visit, "(~", "", ")");
2063             break;
2064         case EOpPostIncrement:
2065             outputTriplet(out, visit, "(", "", "++)");
2066             break;
2067         case EOpPostDecrement:
2068             outputTriplet(out, visit, "(", "", "--)");
2069             break;
2070         case EOpPreIncrement:
2071             outputTriplet(out, visit, "(++", "", ")");
2072             break;
2073         case EOpPreDecrement:
2074             outputTriplet(out, visit, "(--", "", ")");
2075             break;
2076         case EOpRadians:
2077             outputTriplet(out, visit, "radians(", "", ")");
2078             break;
2079         case EOpDegrees:
2080             outputTriplet(out, visit, "degrees(", "", ")");
2081             break;
2082         case EOpSin:
2083             outputTriplet(out, visit, "sin(", "", ")");
2084             break;
2085         case EOpCos:
2086             outputTriplet(out, visit, "cos(", "", ")");
2087             break;
2088         case EOpTan:
2089             outputTriplet(out, visit, "tan(", "", ")");
2090             break;
2091         case EOpAsin:
2092             outputTriplet(out, visit, "asin(", "", ")");
2093             break;
2094         case EOpAcos:
2095             outputTriplet(out, visit, "acos(", "", ")");
2096             break;
2097         case EOpAtan:
2098             outputTriplet(out, visit, "atan(", "", ")");
2099             break;
2100         case EOpSinh:
2101             outputTriplet(out, visit, "sinh(", "", ")");
2102             break;
2103         case EOpCosh:
2104             outputTriplet(out, visit, "cosh(", "", ")");
2105             break;
2106         case EOpTanh:
2107         case EOpAsinh:
2108         case EOpAcosh:
2109         case EOpAtanh:
2110             ASSERT(node->getUseEmulatedFunction());
2111             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2112             break;
2113         case EOpExp:
2114             outputTriplet(out, visit, "exp(", "", ")");
2115             break;
2116         case EOpLog:
2117             outputTriplet(out, visit, "log(", "", ")");
2118             break;
2119         case EOpExp2:
2120             outputTriplet(out, visit, "exp2(", "", ")");
2121             break;
2122         case EOpLog2:
2123             outputTriplet(out, visit, "log2(", "", ")");
2124             break;
2125         case EOpSqrt:
2126             outputTriplet(out, visit, "sqrt(", "", ")");
2127             break;
2128         case EOpInversesqrt:
2129             outputTriplet(out, visit, "rsqrt(", "", ")");
2130             break;
2131         case EOpAbs:
2132             outputTriplet(out, visit, "abs(", "", ")");
2133             break;
2134         case EOpSign:
2135             outputTriplet(out, visit, "sign(", "", ")");
2136             break;
2137         case EOpFloor:
2138             outputTriplet(out, visit, "floor(", "", ")");
2139             break;
2140         case EOpTrunc:
2141             outputTriplet(out, visit, "trunc(", "", ")");
2142             break;
2143         case EOpRound:
2144             outputTriplet(out, visit, "round(", "", ")");
2145             break;
2146         case EOpRoundEven:
2147             ASSERT(node->getUseEmulatedFunction());
2148             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2149             break;
2150         case EOpCeil:
2151             outputTriplet(out, visit, "ceil(", "", ")");
2152             break;
2153         case EOpFract:
2154             outputTriplet(out, visit, "frac(", "", ")");
2155             break;
2156         case EOpIsnan:
2157             if (node->getUseEmulatedFunction())
2158                 writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2159             else
2160                 outputTriplet(out, visit, "isnan(", "", ")");
2161             mRequiresIEEEStrictCompiling = true;
2162             break;
2163         case EOpIsinf:
2164             outputTriplet(out, visit, "isinf(", "", ")");
2165             break;
2166         case EOpFloatBitsToInt:
2167             outputTriplet(out, visit, "asint(", "", ")");
2168             break;
2169         case EOpFloatBitsToUint:
2170             outputTriplet(out, visit, "asuint(", "", ")");
2171             break;
2172         case EOpIntBitsToFloat:
2173             outputTriplet(out, visit, "asfloat(", "", ")");
2174             break;
2175         case EOpUintBitsToFloat:
2176             outputTriplet(out, visit, "asfloat(", "", ")");
2177             break;
2178         case EOpPackSnorm2x16:
2179         case EOpPackUnorm2x16:
2180         case EOpPackHalf2x16:
2181         case EOpUnpackSnorm2x16:
2182         case EOpUnpackUnorm2x16:
2183         case EOpUnpackHalf2x16:
2184         case EOpPackUnorm4x8:
2185         case EOpPackSnorm4x8:
2186         case EOpUnpackUnorm4x8:
2187         case EOpUnpackSnorm4x8:
2188             ASSERT(node->getUseEmulatedFunction());
2189             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2190             break;
2191         case EOpLength:
2192             outputTriplet(out, visit, "length(", "", ")");
2193             break;
2194         case EOpNormalize:
2195             outputTriplet(out, visit, "normalize(", "", ")");
2196             break;
2197         case EOpTranspose:
2198             outputTriplet(out, visit, "transpose(", "", ")");
2199             break;
2200         case EOpDeterminant:
2201             outputTriplet(out, visit, "determinant(transpose(", "", "))");
2202             break;
2203         case EOpInverse:
2204             ASSERT(node->getUseEmulatedFunction());
2205             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2206             break;
2207 
2208         case EOpAny:
2209             outputTriplet(out, visit, "any(", "", ")");
2210             break;
2211         case EOpAll:
2212             outputTriplet(out, visit, "all(", "", ")");
2213             break;
2214         case EOpNotComponentWise:
2215             outputTriplet(out, visit, "(!", "", ")");
2216             break;
2217         case EOpBitfieldReverse:
2218             outputTriplet(out, visit, "reversebits(", "", ")");
2219             break;
2220         case EOpBitCount:
2221             outputTriplet(out, visit, "countbits(", "", ")");
2222             break;
2223         case EOpFindLSB:
2224             // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
2225             // in GLSLTest and results are consistent with GL.
2226             outputTriplet(out, visit, "firstbitlow(", "", ")");
2227             break;
2228         case EOpFindMSB:
2229             // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
2230             // tested in GLSLTest and results are consistent with GL.
2231             outputTriplet(out, visit, "firstbithigh(", "", ")");
2232             break;
2233         case EOpArrayLength:
2234         {
2235             TIntermTyped *operand = node->getOperand();
2236             ASSERT(IsInShaderStorageBlock(operand));
2237             mSSBOOutputHLSL->outputLengthFunctionCall(operand);
2238             return false;
2239         }
2240         default:
2241             UNREACHABLE();
2242     }
2243 
2244     return true;
2245 }
2246 
samplerNamePrefixFromStruct(TIntermTyped * node)2247 ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
2248 {
2249     if (node->getAsSymbolNode())
2250     {
2251         ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
2252         return node->getAsSymbolNode()->getName();
2253     }
2254     TIntermBinary *nodeBinary = node->getAsBinaryNode();
2255     switch (nodeBinary->getOp())
2256     {
2257         case EOpIndexDirect:
2258         {
2259             int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
2260 
2261             std::stringstream prefixSink = sh::InitializeStream<std::stringstream>();
2262             prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
2263             return ImmutableString(prefixSink.str());
2264         }
2265         case EOpIndexDirectStruct:
2266         {
2267             const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
2268             int index           = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
2269             const TField *field = s->fields()[index];
2270 
2271             std::stringstream prefixSink = sh::InitializeStream<std::stringstream>();
2272             prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
2273                        << field->name();
2274             return ImmutableString(prefixSink.str());
2275         }
2276         default:
2277             UNREACHABLE();
2278             return kEmptyImmutableString;
2279     }
2280 }
2281 
visitBlock(Visit visit,TIntermBlock * node)2282 bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
2283 {
2284     TInfoSinkBase &out = getInfoSink();
2285 
2286     bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
2287 
2288     if (mInsideFunction)
2289     {
2290         outputLineDirective(out, node->getLine().first_line);
2291         out << "{\n";
2292         if (isMainBlock)
2293         {
2294             if (mShaderType == GL_COMPUTE_SHADER)
2295             {
2296                 out << "initGLBuiltins(input);\n";
2297             }
2298             else
2299             {
2300                 out << "@@ MAIN PROLOGUE @@\n";
2301             }
2302         }
2303     }
2304 
2305     for (TIntermNode *statement : *node->getSequence())
2306     {
2307         outputLineDirective(out, statement->getLine().first_line);
2308 
2309         statement->traverse(this);
2310 
2311         // Don't output ; after case labels, they're terminated by :
2312         // This is needed especially since outputting a ; after a case statement would turn empty
2313         // case statements into non-empty case statements, disallowing fall-through from them.
2314         // Also the output code is clearer if we don't output ; after statements where it is not
2315         // needed:
2316         //  * if statements
2317         //  * switch statements
2318         //  * blocks
2319         //  * function definitions
2320         //  * loops (do-while loops output the semicolon in VisitLoop)
2321         //  * declarations that don't generate output.
2322         if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
2323             statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
2324             statement->getAsSwitchNode() == nullptr &&
2325             statement->getAsFunctionDefinition() == nullptr &&
2326             (statement->getAsDeclarationNode() == nullptr ||
2327              IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
2328             statement->getAsGlobalQualifierDeclarationNode() == nullptr)
2329         {
2330             out << ";\n";
2331         }
2332     }
2333 
2334     if (mInsideFunction)
2335     {
2336         outputLineDirective(out, node->getLine().last_line);
2337         if (isMainBlock && shaderNeedsGenerateOutput())
2338         {
2339             // We could have an empty main, a main function without a branch at the end, or a main
2340             // function with a discard statement at the end. In these cases we need to add a return
2341             // statement.
2342             bool needReturnStatement =
2343                 node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
2344                 node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
2345             if (needReturnStatement)
2346             {
2347                 out << "return " << generateOutputCall() << ";\n";
2348             }
2349         }
2350         out << "}\n";
2351     }
2352 
2353     return false;
2354 }
2355 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)2356 bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
2357 {
2358     TInfoSinkBase &out = getInfoSink();
2359 
2360     ASSERT(mCurrentFunctionMetadata == nullptr);
2361 
2362     size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
2363     ASSERT(index != CallDAG::InvalidIndex);
2364     mCurrentFunctionMetadata = &mASTMetadataList[index];
2365 
2366     const TFunction *func = node->getFunction();
2367 
2368     if (func->isMain())
2369     {
2370         // The stub strings below are replaced when shader is dynamically defined by its layout:
2371         switch (mShaderType)
2372         {
2373             case GL_VERTEX_SHADER:
2374                 out << "@@ VERTEX ATTRIBUTES @@\n\n"
2375                     << "@@ VERTEX OUTPUT @@\n\n"
2376                     << "VS_OUTPUT main(VS_INPUT input)";
2377                 break;
2378             case GL_FRAGMENT_SHADER:
2379                 out << "@@ PIXEL OUTPUT @@\n\n";
2380                 if (mIsEarlyFragmentTestsSpecified)
2381                 {
2382                     out << "[earlydepthstencil]\n";
2383                 }
2384                 out << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
2385                 break;
2386             case GL_COMPUTE_SHADER:
2387                 out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
2388                     << mWorkGroupSize[2] << ")]\n";
2389                 out << "void main(CS_INPUT input)";
2390                 break;
2391             default:
2392                 UNREACHABLE();
2393                 break;
2394         }
2395     }
2396     else
2397     {
2398         out << TypeString(node->getFunctionPrototype()->getType()) << " ";
2399         out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
2400             << (mOutputLod0Function ? "Lod0(" : "(");
2401 
2402         size_t paramCount = func->getParamCount();
2403         for (unsigned int i = 0; i < paramCount; i++)
2404         {
2405             const TVariable *param = func->getParam(i);
2406             ensureStructDefined(param->getType());
2407 
2408             writeParameter(param, out);
2409 
2410             if (i < paramCount - 1)
2411             {
2412                 out << ", ";
2413             }
2414         }
2415 
2416         out << ")\n";
2417     }
2418 
2419     mInsideFunction = true;
2420     if (func->isMain())
2421     {
2422         mInsideMain = true;
2423     }
2424     // The function body node will output braces.
2425     node->getBody()->traverse(this);
2426     mInsideFunction = false;
2427     mInsideMain     = false;
2428 
2429     mCurrentFunctionMetadata = nullptr;
2430 
2431     bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2432     if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2433     {
2434         ASSERT(!node->getFunction()->isMain());
2435         mOutputLod0Function = true;
2436         node->traverse(this);
2437         mOutputLod0Function = false;
2438     }
2439 
2440     return false;
2441 }
2442 
visitDeclaration(Visit visit,TIntermDeclaration * node)2443 bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
2444 {
2445     if (visit == PreVisit)
2446     {
2447         TIntermSequence *sequence = node->getSequence();
2448         TIntermTyped *declarator  = (*sequence)[0]->getAsTyped();
2449         ASSERT(sequence->size() == 1);
2450         ASSERT(declarator);
2451 
2452         if (IsDeclarationWrittenOut(node))
2453         {
2454             TInfoSinkBase &out = getInfoSink();
2455             ensureStructDefined(declarator->getType());
2456 
2457             if (!declarator->getAsSymbolNode() ||
2458                 declarator->getAsSymbolNode()->variable().symbolType() !=
2459                     SymbolType::Empty)  // Variable declaration
2460             {
2461                 if (declarator->getQualifier() == EvqShared)
2462                 {
2463                     out << "groupshared ";
2464                 }
2465                 else if (!mInsideFunction)
2466                 {
2467                     out << "static ";
2468                 }
2469 
2470                 out << TypeString(declarator->getType()) + " ";
2471 
2472                 TIntermSymbol *symbol = declarator->getAsSymbolNode();
2473 
2474                 if (symbol)
2475                 {
2476                     symbol->traverse(this);
2477                     out << ArrayString(symbol->getType());
2478                     // Temporarily disable shadred memory initialization. It is very slow for D3D11
2479                     // drivers to compile a compute shader if we add code to initialize a
2480                     // groupshared array variable with a large array size. And maybe produce
2481                     // incorrect result. See http://anglebug.com/3226.
2482                     if (declarator->getQualifier() != EvqShared)
2483                     {
2484                         out << " = " + zeroInitializer(symbol->getType());
2485                     }
2486                 }
2487                 else
2488                 {
2489                     declarator->traverse(this);
2490                 }
2491             }
2492         }
2493         else if (IsVaryingOut(declarator->getQualifier()))
2494         {
2495             TIntermSymbol *symbol = declarator->getAsSymbolNode();
2496             ASSERT(symbol);  // Varying declarations can't have initializers.
2497 
2498             const TVariable &variable = symbol->variable();
2499 
2500             if (variable.symbolType() != SymbolType::Empty)
2501             {
2502                 // Vertex outputs which are declared but not written to should still be declared to
2503                 // allow successful linking.
2504                 mReferencedVaryings[symbol->uniqueId().get()] = &variable;
2505             }
2506         }
2507     }
2508     return false;
2509 }
2510 
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)2511 bool OutputHLSL::visitGlobalQualifierDeclaration(Visit visit,
2512                                                  TIntermGlobalQualifierDeclaration *node)
2513 {
2514     // Do not do any translation
2515     return false;
2516 }
2517 
visitFunctionPrototype(TIntermFunctionPrototype * node)2518 void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
2519 {
2520     TInfoSinkBase &out = getInfoSink();
2521 
2522     size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
2523     // Skip the prototype if it is not implemented (and thus not used)
2524     if (index == CallDAG::InvalidIndex)
2525     {
2526         return;
2527     }
2528 
2529     const TFunction *func = node->getFunction();
2530 
2531     TString name = DecorateFunctionIfNeeded(func);
2532     out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
2533         << (mOutputLod0Function ? "Lod0(" : "(");
2534 
2535     size_t paramCount = func->getParamCount();
2536     for (unsigned int i = 0; i < paramCount; i++)
2537     {
2538         writeParameter(func->getParam(i), out);
2539 
2540         if (i < paramCount - 1)
2541         {
2542             out << ", ";
2543         }
2544     }
2545 
2546     out << ");\n";
2547 
2548     // Also prototype the Lod0 variant if needed
2549     bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
2550     if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
2551     {
2552         mOutputLod0Function = true;
2553         node->traverse(this);
2554         mOutputLod0Function = false;
2555     }
2556 }
2557 
visitAggregate(Visit visit,TIntermAggregate * node)2558 bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
2559 {
2560     TInfoSinkBase &out = getInfoSink();
2561 
2562     switch (node->getOp())
2563     {
2564         case EOpCallFunctionInAST:
2565         case EOpCallInternalRawFunction:
2566         default:
2567         {
2568             TIntermSequence *arguments = node->getSequence();
2569 
2570             bool lod0 = (mInsideDiscontinuousLoop || mOutputLod0Function) &&
2571                         mShaderType == GL_FRAGMENT_SHADER;
2572 
2573             // No raw function is expected.
2574             ASSERT(node->getOp() != EOpCallInternalRawFunction);
2575 
2576             if (node->getOp() == EOpCallFunctionInAST)
2577             {
2578                 if (node->isArray())
2579                 {
2580                     UNIMPLEMENTED();
2581                 }
2582                 size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
2583                 ASSERT(index != CallDAG::InvalidIndex);
2584                 lod0 &= mASTMetadataList[index].mNeedsLod0;
2585 
2586                 out << DecorateFunctionIfNeeded(node->getFunction());
2587                 out << DisambiguateFunctionName(node->getSequence());
2588                 out << (lod0 ? "Lod0(" : "(");
2589             }
2590             else if (node->getFunction()->isImageFunction())
2591             {
2592                 const ImmutableString &name              = node->getFunction()->name();
2593                 TType type                               = (*arguments)[0]->getAsTyped()->getType();
2594                 const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
2595                     name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
2596                     type.getMemoryQualifier().readonly);
2597                 out << imageFunctionName << "(";
2598             }
2599             else if (node->getFunction()->isAtomicCounterFunction())
2600             {
2601                 const ImmutableString &name = node->getFunction()->name();
2602                 ImmutableString atomicFunctionName =
2603                     mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
2604                 out << atomicFunctionName << "(";
2605             }
2606             else
2607             {
2608                 const ImmutableString &name = node->getFunction()->name();
2609                 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
2610                 int coords = 0;  // textureSize(gsampler2DMS) doesn't have a second argument.
2611                 if (arguments->size() > 1)
2612                 {
2613                     coords = (*arguments)[1]->getAsTyped()->getNominalSize();
2614                 }
2615                 const ImmutableString &textureFunctionName =
2616                     mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
2617                                                              arguments->size(), lod0, mShaderType);
2618                 out << textureFunctionName << "(";
2619             }
2620 
2621             for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
2622             {
2623                 TIntermTyped *typedArg = (*arg)->getAsTyped();
2624                 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
2625                 {
2626                     out << "texture_";
2627                     (*arg)->traverse(this);
2628                     out << ", sampler_";
2629                 }
2630 
2631                 (*arg)->traverse(this);
2632 
2633                 if (typedArg->getType().isStructureContainingSamplers())
2634                 {
2635                     const TType &argType = typedArg->getType();
2636                     TVector<const TVariable *> samplerSymbols;
2637                     ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
2638                     std::string namePrefix     = "angle_";
2639                     namePrefix += structName.data();
2640                     argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
2641                                                  nullptr, mSymbolTable);
2642                     for (const TVariable *sampler : samplerSymbols)
2643                     {
2644                         if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
2645                         {
2646                             out << ", texture_" << sampler->name();
2647                             out << ", sampler_" << sampler->name();
2648                         }
2649                         else
2650                         {
2651                             // In case of HLSL 4.1+, this symbol is the sampler index, and in case
2652                             // of D3D9, it's the sampler variable.
2653                             out << ", " << sampler->name();
2654                         }
2655                     }
2656                 }
2657 
2658                 if (arg < arguments->end() - 1)
2659                 {
2660                     out << ", ";
2661                 }
2662             }
2663 
2664             out << ")";
2665 
2666             return false;
2667         }
2668         case EOpConstruct:
2669             outputConstructor(out, visit, node);
2670             break;
2671         case EOpEqualComponentWise:
2672             outputTriplet(out, visit, "(", " == ", ")");
2673             break;
2674         case EOpNotEqualComponentWise:
2675             outputTriplet(out, visit, "(", " != ", ")");
2676             break;
2677         case EOpLessThanComponentWise:
2678             outputTriplet(out, visit, "(", " < ", ")");
2679             break;
2680         case EOpGreaterThanComponentWise:
2681             outputTriplet(out, visit, "(", " > ", ")");
2682             break;
2683         case EOpLessThanEqualComponentWise:
2684             outputTriplet(out, visit, "(", " <= ", ")");
2685             break;
2686         case EOpGreaterThanEqualComponentWise:
2687             outputTriplet(out, visit, "(", " >= ", ")");
2688             break;
2689         case EOpMod:
2690             ASSERT(node->getUseEmulatedFunction());
2691             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2692             break;
2693         case EOpModf:
2694             outputTriplet(out, visit, "modf(", ", ", ")");
2695             break;
2696         case EOpPow:
2697             outputTriplet(out, visit, "pow(", ", ", ")");
2698             break;
2699         case EOpAtan:
2700             ASSERT(node->getSequence()->size() == 2);  // atan(x) is a unary operator
2701             ASSERT(node->getUseEmulatedFunction());
2702             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2703             break;
2704         case EOpMin:
2705             outputTriplet(out, visit, "min(", ", ", ")");
2706             break;
2707         case EOpMax:
2708             outputTriplet(out, visit, "max(", ", ", ")");
2709             break;
2710         case EOpClamp:
2711             outputTriplet(out, visit, "clamp(", ", ", ")");
2712             break;
2713         case EOpMix:
2714         {
2715             TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
2716             if (lastParamNode->getType().getBasicType() == EbtBool)
2717             {
2718                 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
2719                 // y, genBType a)",
2720                 // so use emulated version.
2721                 ASSERT(node->getUseEmulatedFunction());
2722                 writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2723             }
2724             else
2725             {
2726                 outputTriplet(out, visit, "lerp(", ", ", ")");
2727             }
2728             break;
2729         }
2730         case EOpStep:
2731             outputTriplet(out, visit, "step(", ", ", ")");
2732             break;
2733         case EOpSmoothstep:
2734             outputTriplet(out, visit, "smoothstep(", ", ", ")");
2735             break;
2736         case EOpFma:
2737             outputTriplet(out, visit, "mad(", ", ", ")");
2738             break;
2739         case EOpFrexp:
2740         case EOpLdexp:
2741             ASSERT(node->getUseEmulatedFunction());
2742             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2743             break;
2744         case EOpDistance:
2745             outputTriplet(out, visit, "distance(", ", ", ")");
2746             break;
2747         case EOpDot:
2748             outputTriplet(out, visit, "dot(", ", ", ")");
2749             break;
2750         case EOpCross:
2751             outputTriplet(out, visit, "cross(", ", ", ")");
2752             break;
2753         case EOpFaceforward:
2754             ASSERT(node->getUseEmulatedFunction());
2755             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2756             break;
2757         case EOpReflect:
2758             outputTriplet(out, visit, "reflect(", ", ", ")");
2759             break;
2760         case EOpRefract:
2761             outputTriplet(out, visit, "refract(", ", ", ")");
2762             break;
2763         case EOpOuterProduct:
2764             ASSERT(node->getUseEmulatedFunction());
2765             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2766             break;
2767         case EOpMatrixCompMult:
2768             outputTriplet(out, visit, "(", " * ", ")");
2769             break;
2770         case EOpBitfieldExtract:
2771         case EOpBitfieldInsert:
2772         case EOpUaddCarry:
2773         case EOpUsubBorrow:
2774         case EOpUmulExtended:
2775         case EOpImulExtended:
2776             ASSERT(node->getUseEmulatedFunction());
2777             writeEmulatedFunctionTriplet(out, visit, node->getFunction());
2778             break;
2779         case EOpDFdx:
2780             if (mInsideDiscontinuousLoop || mOutputLod0Function)
2781             {
2782                 outputTriplet(out, visit, "(", "", ", 0.0)");
2783             }
2784             else
2785             {
2786                 outputTriplet(out, visit, "ddx(", "", ")");
2787             }
2788             break;
2789         case EOpDFdy:
2790             if (mInsideDiscontinuousLoop || mOutputLod0Function)
2791             {
2792                 outputTriplet(out, visit, "(", "", ", 0.0)");
2793             }
2794             else
2795             {
2796                 outputTriplet(out, visit, "ddy(", "", ")");
2797             }
2798             break;
2799         case EOpFwidth:
2800             if (mInsideDiscontinuousLoop || mOutputLod0Function)
2801             {
2802                 outputTriplet(out, visit, "(", "", ", 0.0)");
2803             }
2804             else
2805             {
2806                 outputTriplet(out, visit, "fwidth(", "", ")");
2807             }
2808             break;
2809         case EOpInterpolateAtCentroid:
2810         {
2811             TIntermTyped *interpolantNode = (*(node->getSequence()))[0]->getAsTyped();
2812             if (!IsFlatInterpolant(interpolantNode))
2813             {
2814                 outputTriplet(out, visit, "EvaluateAttributeCentroid(", "", ")");
2815             }
2816             break;
2817         }
2818         case EOpInterpolateAtSample:
2819         {
2820             TIntermTyped *interpolantNode = (*(node->getSequence()))[0]->getAsTyped();
2821             if (!IsFlatInterpolant(interpolantNode))
2822             {
2823                 mUsesNumSamples = true;
2824                 outputTriplet(out, visit, "EvaluateAttributeAtSample(", ", clamp(",
2825                               ", 0, gl_NumSamples - 1))");
2826             }
2827             else
2828             {
2829                 const TString &functionName = addFlatEvaluateFunction(
2830                     interpolantNode->getType(), *StaticType::GetBasic<EbtInt, EbpUndefined, 1>());
2831                 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
2832             }
2833             break;
2834         }
2835         case EOpInterpolateAtOffset:
2836         {
2837             TIntermTyped *interpolantNode = (*(node->getSequence()))[0]->getAsTyped();
2838             if (!IsFlatInterpolant(interpolantNode))
2839             {
2840                 outputTriplet(out, visit, "EvaluateAttributeSnapped(", ", int2((", ") * 16.0))");
2841             }
2842             else
2843             {
2844                 const TString &functionName = addFlatEvaluateFunction(
2845                     interpolantNode->getType(), *StaticType::GetBasic<EbtFloat, EbpUndefined, 2>());
2846                 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
2847             }
2848             break;
2849         }
2850         case EOpBarrier:
2851             // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
2852             // cheapest *WithGroupSync() function, without any functionality loss, but
2853             // with the potential for severe performance loss.
2854             outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
2855             break;
2856         case EOpMemoryBarrierShared:
2857             outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
2858             break;
2859         case EOpMemoryBarrierAtomicCounter:
2860         case EOpMemoryBarrierBuffer:
2861         case EOpMemoryBarrierImage:
2862             outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
2863             break;
2864         case EOpGroupMemoryBarrier:
2865         case EOpMemoryBarrier:
2866             outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
2867             break;
2868 
2869         // Single atomic function calls without return value.
2870         // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
2871         case EOpAtomicAdd:
2872         case EOpAtomicMin:
2873         case EOpAtomicMax:
2874         case EOpAtomicAnd:
2875         case EOpAtomicOr:
2876         case EOpAtomicXor:
2877         // The parameter 'original_value' of InterlockedExchange(dest, value, original_value)
2878         // and InterlockedCompareExchange(dest, compare_value, value, original_value) is not
2879         // optional.
2880         // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
2881         // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
2882         // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest,
2883         // compare_value, value) should all be modified into the form of "int temp; temp =
2884         // atomicExchange(dest, value);" and "int temp; temp = atomicCompSwap(dest,
2885         // compare_value, value);" in the intermediate tree before traversing outputHLSL.
2886         case EOpAtomicExchange:
2887         case EOpAtomicCompSwap:
2888         {
2889             ASSERT(node->getChildCount() > 1);
2890             TIntermTyped *memNode = (*node->getSequence())[0]->getAsTyped();
2891             if (IsInShaderStorageBlock(memNode))
2892             {
2893                 // Atomic memory functions for SSBO.
2894                 // "_ssbo_atomicXXX_TYPE(RWByteAddressBuffer buffer, uint loc" is written to |out|.
2895                 mSSBOOutputHLSL->outputAtomicMemoryFunctionCallPrefix(memNode, node->getOp());
2896                 // Write the rest argument list to |out|.
2897                 for (size_t i = 1; i < node->getChildCount(); i++)
2898                 {
2899                     out << ", ";
2900                     TIntermTyped *argument = (*node->getSequence())[i]->getAsTyped();
2901                     if (IsInShaderStorageBlock(argument))
2902                     {
2903                         mSSBOOutputHLSL->outputLoadFunctionCall(argument);
2904                     }
2905                     else
2906                     {
2907                         argument->traverse(this);
2908                     }
2909                 }
2910 
2911                 out << ")";
2912                 return false;
2913             }
2914             else
2915             {
2916                 // Atomic memory functions for shared variable.
2917                 if (node->getOp() != EOpAtomicExchange && node->getOp() != EOpAtomicCompSwap)
2918                 {
2919                     outputTriplet(out, visit,
2920                                   GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()), ",",
2921                                   ")");
2922                 }
2923                 else
2924                 {
2925                     UNREACHABLE();
2926                 }
2927             }
2928 
2929             break;
2930         }
2931     }
2932 
2933     return true;
2934 }
2935 
writeIfElse(TInfoSinkBase & out,TIntermIfElse * node)2936 void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
2937 {
2938     out << "if (";
2939 
2940     node->getCondition()->traverse(this);
2941 
2942     out << ")\n";
2943 
2944     outputLineDirective(out, node->getLine().first_line);
2945 
2946     bool discard = false;
2947 
2948     if (node->getTrueBlock())
2949     {
2950         // The trueBlock child node will output braces.
2951         node->getTrueBlock()->traverse(this);
2952 
2953         // Detect true discard
2954         discard = (discard || FindDiscard::search(node->getTrueBlock()));
2955     }
2956     else
2957     {
2958         // TODO(oetuaho): Check if the semicolon inside is necessary.
2959         // It's there as a result of conservative refactoring of the output.
2960         out << "{;}\n";
2961     }
2962 
2963     outputLineDirective(out, node->getLine().first_line);
2964 
2965     if (node->getFalseBlock())
2966     {
2967         out << "else\n";
2968 
2969         outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
2970 
2971         // The falseBlock child node will output braces.
2972         node->getFalseBlock()->traverse(this);
2973 
2974         outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
2975 
2976         // Detect false discard
2977         discard = (discard || FindDiscard::search(node->getFalseBlock()));
2978     }
2979 
2980     // ANGLE issue 486: Detect problematic conditional discard
2981     if (discard)
2982     {
2983         mUsesDiscardRewriting = true;
2984     }
2985 }
2986 
visitTernary(Visit,TIntermTernary *)2987 bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
2988 {
2989     // Ternary ops should have been already converted to something else in the AST. HLSL ternary
2990     // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
2991     UNREACHABLE();
2992     return false;
2993 }
2994 
visitIfElse(Visit visit,TIntermIfElse * node)2995 bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
2996 {
2997     TInfoSinkBase &out = getInfoSink();
2998 
2999     ASSERT(mInsideFunction);
3000 
3001     // D3D errors when there is a gradient operation in a loop in an unflattened if.
3002     if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
3003     {
3004         out << "FLATTEN ";
3005     }
3006 
3007     writeIfElse(out, node);
3008 
3009     return false;
3010 }
3011 
visitSwitch(Visit visit,TIntermSwitch * node)3012 bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
3013 {
3014     TInfoSinkBase &out = getInfoSink();
3015 
3016     ASSERT(node->getStatementList());
3017     if (visit == PreVisit)
3018     {
3019         node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
3020     }
3021     outputTriplet(out, visit, "switch (", ") ", "");
3022     // The curly braces get written when visiting the statementList block.
3023     return true;
3024 }
3025 
visitCase(Visit visit,TIntermCase * node)3026 bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
3027 {
3028     TInfoSinkBase &out = getInfoSink();
3029 
3030     if (node->hasCondition())
3031     {
3032         outputTriplet(out, visit, "case (", "", "):\n");
3033         return true;
3034     }
3035     else
3036     {
3037         out << "default:\n";
3038         return false;
3039     }
3040 }
3041 
visitConstantUnion(TIntermConstantUnion * node)3042 void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
3043 {
3044     TInfoSinkBase &out = getInfoSink();
3045     writeConstantUnion(out, node->getType(), node->getConstantValue());
3046 }
3047 
visitLoop(Visit visit,TIntermLoop * node)3048 bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
3049 {
3050     mNestedLoopDepth++;
3051 
3052     bool wasDiscontinuous = mInsideDiscontinuousLoop;
3053     mInsideDiscontinuousLoop =
3054         mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
3055 
3056     TInfoSinkBase &out = getInfoSink();
3057 
3058     if (mOutputType == SH_HLSL_3_0_OUTPUT)
3059     {
3060         if (handleExcessiveLoop(out, node))
3061         {
3062             mInsideDiscontinuousLoop = wasDiscontinuous;
3063             mNestedLoopDepth--;
3064 
3065             return false;
3066         }
3067     }
3068 
3069     const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
3070     if (node->getType() == ELoopDoWhile)
3071     {
3072         out << "{" << unroll << " do\n";
3073 
3074         outputLineDirective(out, node->getLine().first_line);
3075     }
3076     else
3077     {
3078         out << "{" << unroll << " for(";
3079 
3080         if (node->getInit())
3081         {
3082             node->getInit()->traverse(this);
3083         }
3084 
3085         out << "; ";
3086 
3087         if (node->getCondition())
3088         {
3089             node->getCondition()->traverse(this);
3090         }
3091 
3092         out << "; ";
3093 
3094         if (node->getExpression())
3095         {
3096             node->getExpression()->traverse(this);
3097         }
3098 
3099         out << ")\n";
3100 
3101         outputLineDirective(out, node->getLine().first_line);
3102     }
3103 
3104     // The loop body node will output braces.
3105     node->getBody()->traverse(this);
3106 
3107     outputLineDirective(out, node->getLine().first_line);
3108 
3109     if (node->getType() == ELoopDoWhile)
3110     {
3111         outputLineDirective(out, node->getCondition()->getLine().first_line);
3112         out << "while (";
3113 
3114         node->getCondition()->traverse(this);
3115 
3116         out << ");\n";
3117     }
3118 
3119     out << "}\n";
3120 
3121     mInsideDiscontinuousLoop = wasDiscontinuous;
3122     mNestedLoopDepth--;
3123 
3124     return false;
3125 }
3126 
visitBranch(Visit visit,TIntermBranch * node)3127 bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
3128 {
3129     if (visit == PreVisit)
3130     {
3131         TInfoSinkBase &out = getInfoSink();
3132 
3133         switch (node->getFlowOp())
3134         {
3135             case EOpKill:
3136                 out << "discard";
3137                 break;
3138             case EOpBreak:
3139                 if (mNestedLoopDepth > 1)
3140                 {
3141                     mUsesNestedBreak = true;
3142                 }
3143 
3144                 if (mExcessiveLoopIndex)
3145                 {
3146                     out << "{Break";
3147                     mExcessiveLoopIndex->traverse(this);
3148                     out << " = true; break;}\n";
3149                 }
3150                 else
3151                 {
3152                     out << "break";
3153                 }
3154                 break;
3155             case EOpContinue:
3156                 out << "continue";
3157                 break;
3158             case EOpReturn:
3159                 if (node->getExpression())
3160                 {
3161                     ASSERT(!mInsideMain);
3162                     out << "return ";
3163                     if (IsInShaderStorageBlock(node->getExpression()))
3164                     {
3165                         mSSBOOutputHLSL->outputLoadFunctionCall(node->getExpression());
3166                         return false;
3167                     }
3168                 }
3169                 else
3170                 {
3171                     if (mInsideMain && shaderNeedsGenerateOutput())
3172                     {
3173                         out << "return " << generateOutputCall();
3174                     }
3175                     else
3176                     {
3177                         out << "return";
3178                     }
3179                 }
3180                 break;
3181             default:
3182                 UNREACHABLE();
3183         }
3184     }
3185 
3186     return true;
3187 }
3188 
3189 // Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
3190 // (The D3D documentation says 255 iterations, but the compiler complains at anything more than
3191 // 254).
handleExcessiveLoop(TInfoSinkBase & out,TIntermLoop * node)3192 bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
3193 {
3194     const int MAX_LOOP_ITERATIONS = 254;
3195 
3196     // Parse loops of the form:
3197     // for(int index = initial; index [comparator] limit; index += increment)
3198     TIntermSymbol *index = nullptr;
3199     TOperator comparator = EOpNull;
3200     int initial          = 0;
3201     int limit            = 0;
3202     int increment        = 0;
3203 
3204     // Parse index name and intial value
3205     if (node->getInit())
3206     {
3207         TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
3208 
3209         if (init)
3210         {
3211             TIntermSequence *sequence = init->getSequence();
3212             TIntermTyped *variable    = (*sequence)[0]->getAsTyped();
3213 
3214             if (variable && variable->getQualifier() == EvqTemporary)
3215             {
3216                 TIntermBinary *assign = variable->getAsBinaryNode();
3217 
3218                 if (assign != nullptr && assign->getOp() == EOpInitialize)
3219                 {
3220                     TIntermSymbol *symbol          = assign->getLeft()->getAsSymbolNode();
3221                     TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
3222 
3223                     if (symbol && constant)
3224                     {
3225                         if (constant->getBasicType() == EbtInt && constant->isScalar())
3226                         {
3227                             index   = symbol;
3228                             initial = constant->getIConst(0);
3229                         }
3230                     }
3231                 }
3232             }
3233         }
3234     }
3235 
3236     // Parse comparator and limit value
3237     if (index != nullptr && node->getCondition())
3238     {
3239         TIntermBinary *test = node->getCondition()->getAsBinaryNode();
3240 
3241         if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
3242         {
3243             TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
3244 
3245             if (constant)
3246             {
3247                 if (constant->getBasicType() == EbtInt && constant->isScalar())
3248                 {
3249                     comparator = test->getOp();
3250                     limit      = constant->getIConst(0);
3251                 }
3252             }
3253         }
3254     }
3255 
3256     // Parse increment
3257     if (index != nullptr && comparator != EOpNull && node->getExpression())
3258     {
3259         TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
3260         TIntermUnary *unaryTerminal   = node->getExpression()->getAsUnaryNode();
3261 
3262         if (binaryTerminal)
3263         {
3264             TOperator op                   = binaryTerminal->getOp();
3265             TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
3266 
3267             if (constant)
3268             {
3269                 if (constant->getBasicType() == EbtInt && constant->isScalar())
3270                 {
3271                     int value = constant->getIConst(0);
3272 
3273                     switch (op)
3274                     {
3275                         case EOpAddAssign:
3276                             increment = value;
3277                             break;
3278                         case EOpSubAssign:
3279                             increment = -value;
3280                             break;
3281                         default:
3282                             UNIMPLEMENTED();
3283                     }
3284                 }
3285             }
3286         }
3287         else if (unaryTerminal)
3288         {
3289             TOperator op = unaryTerminal->getOp();
3290 
3291             switch (op)
3292             {
3293                 case EOpPostIncrement:
3294                     increment = 1;
3295                     break;
3296                 case EOpPostDecrement:
3297                     increment = -1;
3298                     break;
3299                 case EOpPreIncrement:
3300                     increment = 1;
3301                     break;
3302                 case EOpPreDecrement:
3303                     increment = -1;
3304                     break;
3305                 default:
3306                     UNIMPLEMENTED();
3307             }
3308         }
3309     }
3310 
3311     if (index != nullptr && comparator != EOpNull && increment != 0)
3312     {
3313         if (comparator == EOpLessThanEqual)
3314         {
3315             comparator = EOpLessThan;
3316             limit += 1;
3317         }
3318 
3319         if (comparator == EOpLessThan)
3320         {
3321             int iterations = (limit - initial) / increment;
3322 
3323             if (iterations <= MAX_LOOP_ITERATIONS)
3324             {
3325                 return false;  // Not an excessive loop
3326             }
3327 
3328             TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
3329             mExcessiveLoopIndex         = index;
3330 
3331             out << "{int ";
3332             index->traverse(this);
3333             out << ";\n"
3334                    "bool Break";
3335             index->traverse(this);
3336             out << " = false;\n";
3337 
3338             bool firstLoopFragment = true;
3339 
3340             while (iterations > 0)
3341             {
3342                 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
3343 
3344                 if (!firstLoopFragment)
3345                 {
3346                     out << "if (!Break";
3347                     index->traverse(this);
3348                     out << ") {\n";
3349                 }
3350 
3351                 if (iterations <= MAX_LOOP_ITERATIONS)  // Last loop fragment
3352                 {
3353                     mExcessiveLoopIndex = nullptr;  // Stops setting the Break flag
3354                 }
3355 
3356                 // for(int index = initial; index < clampedLimit; index += increment)
3357                 const char *unroll =
3358                     mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
3359 
3360                 out << unroll << " for(";
3361                 index->traverse(this);
3362                 out << " = ";
3363                 out << initial;
3364 
3365                 out << "; ";
3366                 index->traverse(this);
3367                 out << " < ";
3368                 out << clampedLimit;
3369 
3370                 out << "; ";
3371                 index->traverse(this);
3372                 out << " += ";
3373                 out << increment;
3374                 out << ")\n";
3375 
3376                 outputLineDirective(out, node->getLine().first_line);
3377                 out << "{\n";
3378 
3379                 node->getBody()->traverse(this);
3380 
3381                 outputLineDirective(out, node->getLine().first_line);
3382                 out << ";}\n";
3383 
3384                 if (!firstLoopFragment)
3385                 {
3386                     out << "}\n";
3387                 }
3388 
3389                 firstLoopFragment = false;
3390 
3391                 initial += MAX_LOOP_ITERATIONS * increment;
3392                 iterations -= MAX_LOOP_ITERATIONS;
3393             }
3394 
3395             out << "}";
3396 
3397             mExcessiveLoopIndex = restoreIndex;
3398 
3399             return true;
3400         }
3401         else
3402             UNIMPLEMENTED();
3403     }
3404 
3405     return false;  // Not handled as an excessive loop
3406 }
3407 
outputTriplet(TInfoSinkBase & out,Visit visit,const char * preString,const char * inString,const char * postString)3408 void OutputHLSL::outputTriplet(TInfoSinkBase &out,
3409                                Visit visit,
3410                                const char *preString,
3411                                const char *inString,
3412                                const char *postString)
3413 {
3414     if (visit == PreVisit)
3415     {
3416         out << preString;
3417     }
3418     else if (visit == InVisit)
3419     {
3420         out << inString;
3421     }
3422     else if (visit == PostVisit)
3423     {
3424         out << postString;
3425     }
3426 }
3427 
outputLineDirective(TInfoSinkBase & out,int line)3428 void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
3429 {
3430     if (mCompileOptions.lineDirectives && line > 0)
3431     {
3432         out << "\n";
3433         out << "#line " << line;
3434 
3435         if (mSourcePath)
3436         {
3437             out << " \"" << mSourcePath << "\"";
3438         }
3439 
3440         out << "\n";
3441     }
3442 }
3443 
writeParameter(const TVariable * param,TInfoSinkBase & out)3444 void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
3445 {
3446     const TType &type    = param->getType();
3447     TQualifier qualifier = type.getQualifier();
3448 
3449     TString nameStr = DecorateVariableIfNeeded(*param);
3450     ASSERT(nameStr != "");  // HLSL demands named arguments, also for prototypes
3451 
3452     if (IsSampler(type.getBasicType()))
3453     {
3454         if (mOutputType == SH_HLSL_4_1_OUTPUT)
3455         {
3456             // Samplers are passed as indices to the sampler array.
3457             ASSERT(qualifier != EvqParamOut && qualifier != EvqParamInOut);
3458             out << "const uint " << nameStr << ArrayString(type);
3459             return;
3460         }
3461         if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
3462         {
3463             out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
3464                 << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
3465                 << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
3466                 << ArrayString(type);
3467             return;
3468         }
3469     }
3470 
3471     // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
3472     // buffer offset.
3473     if (IsAtomicCounter(type.getBasicType()))
3474     {
3475         out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
3476             << nameStr << "_offset";
3477     }
3478     else
3479     {
3480         out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
3481             << ArrayString(type);
3482     }
3483 
3484     // If the structure parameter contains samplers, they need to be passed into the function as
3485     // separate parameters. HLSL doesn't natively support samplers in structs.
3486     if (type.isStructureContainingSamplers())
3487     {
3488         ASSERT(qualifier != EvqParamOut && qualifier != EvqParamInOut);
3489         TVector<const TVariable *> samplerSymbols;
3490         std::string namePrefix = "angle";
3491         namePrefix += nameStr.c_str();
3492         type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
3493                                   mSymbolTable);
3494         for (const TVariable *sampler : samplerSymbols)
3495         {
3496             const TType &samplerType = sampler->getType();
3497             if (mOutputType == SH_HLSL_4_1_OUTPUT)
3498             {
3499                 out << ", const uint " << sampler->name() << ArrayString(samplerType);
3500             }
3501             else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
3502             {
3503                 ASSERT(IsSampler(samplerType.getBasicType()));
3504                 out << ", " << QualifierString(qualifier) << " "
3505                     << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
3506                     << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
3507                     << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
3508                     << ArrayString(samplerType);
3509             }
3510             else
3511             {
3512                 ASSERT(IsSampler(samplerType.getBasicType()));
3513                 out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
3514                     << sampler->name() << ArrayString(samplerType);
3515             }
3516         }
3517     }
3518 }
3519 
zeroInitializer(const TType & type) const3520 TString OutputHLSL::zeroInitializer(const TType &type) const
3521 {
3522     TString string;
3523 
3524     size_t size = type.getObjectSize();
3525     if (size >= kZeroCount)
3526     {
3527         mUseZeroArray = true;
3528     }
3529     string = GetZeroInitializer(size).c_str();
3530 
3531     return "{" + string + "}";
3532 }
3533 
outputConstructor(TInfoSinkBase & out,Visit visit,TIntermAggregate * node)3534 void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
3535 {
3536     // Array constructors should have been already pruned from the code.
3537     ASSERT(!node->getType().isArray());
3538 
3539     if (visit == PreVisit)
3540     {
3541         TString constructorName;
3542         if (node->getBasicType() == EbtStruct)
3543         {
3544             constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
3545         }
3546         else
3547         {
3548             constructorName =
3549                 mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
3550         }
3551         out << constructorName << "(";
3552     }
3553     else if (visit == InVisit)
3554     {
3555         out << ", ";
3556     }
3557     else if (visit == PostVisit)
3558     {
3559         out << ")";
3560     }
3561 }
3562 
writeConstantUnion(TInfoSinkBase & out,const TType & type,const TConstantUnion * const constUnion)3563 const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
3564                                                      const TType &type,
3565                                                      const TConstantUnion *const constUnion)
3566 {
3567     ASSERT(!type.isArray());
3568 
3569     const TConstantUnion *constUnionIterated = constUnion;
3570 
3571     const TStructure *structure = type.getStruct();
3572     if (structure)
3573     {
3574         out << mStructureHLSL->addStructConstructor(*structure) << "(";
3575 
3576         const TFieldList &fields = structure->fields();
3577 
3578         for (size_t i = 0; i < fields.size(); i++)
3579         {
3580             const TType *fieldType = fields[i]->type();
3581             constUnionIterated     = writeConstantUnion(out, *fieldType, constUnionIterated);
3582 
3583             if (i != fields.size() - 1)
3584             {
3585                 out << ", ";
3586             }
3587         }
3588 
3589         out << ")";
3590     }
3591     else
3592     {
3593         size_t size    = type.getObjectSize();
3594         bool writeType = size > 1;
3595 
3596         if (writeType)
3597         {
3598             out << TypeString(type) << "(";
3599         }
3600         constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
3601         if (writeType)
3602         {
3603             out << ")";
3604         }
3605     }
3606 
3607     return constUnionIterated;
3608 }
3609 
writeEmulatedFunctionTriplet(TInfoSinkBase & out,Visit visit,const TFunction * function)3610 void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out,
3611                                               Visit visit,
3612                                               const TFunction *function)
3613 {
3614     if (visit == PreVisit)
3615     {
3616         ASSERT(function != nullptr);
3617         BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, function->name().data());
3618         out << "(";
3619     }
3620     else
3621     {
3622         outputTriplet(out, visit, nullptr, ", ", ")");
3623     }
3624 }
3625 
writeSameSymbolInitializer(TInfoSinkBase & out,TIntermSymbol * symbolNode,TIntermTyped * expression)3626 bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
3627                                             TIntermSymbol *symbolNode,
3628                                             TIntermTyped *expression)
3629 {
3630     ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
3631     const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
3632 
3633     if (symbolInInitializer)
3634     {
3635         // Type already printed
3636         out << "t" + str(mUniqueIndex) + " = ";
3637         expression->traverse(this);
3638         out << ", ";
3639         symbolNode->traverse(this);
3640         out << " = t" + str(mUniqueIndex);
3641 
3642         mUniqueIndex++;
3643         return true;
3644     }
3645 
3646     return false;
3647 }
3648 
writeConstantInitialization(TInfoSinkBase & out,TIntermSymbol * symbolNode,TIntermTyped * initializer)3649 bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
3650                                              TIntermSymbol *symbolNode,
3651                                              TIntermTyped *initializer)
3652 {
3653     if (initializer->hasConstantValue())
3654     {
3655         symbolNode->traverse(this);
3656         out << ArrayString(symbolNode->getType());
3657         out << " = {";
3658         writeConstantUnionArray(out, initializer->getConstantValue(),
3659                                 initializer->getType().getObjectSize());
3660         out << "}";
3661         return true;
3662     }
3663     return false;
3664 }
3665 
addStructEqualityFunction(const TStructure & structure)3666 TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
3667 {
3668     const TFieldList &fields = structure.fields();
3669 
3670     for (const auto &eqFunction : mStructEqualityFunctions)
3671     {
3672         if (eqFunction->structure == &structure)
3673         {
3674             return eqFunction->functionName;
3675         }
3676     }
3677 
3678     const TString &structNameString = StructNameString(structure);
3679 
3680     StructEqualityFunction *function = new StructEqualityFunction();
3681     function->structure              = &structure;
3682     function->functionName           = "angle_eq_" + structNameString;
3683 
3684     TInfoSinkBase fnOut;
3685 
3686     fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
3687           << structNameString + " b)\n"
3688           << "{\n"
3689              "    return ";
3690 
3691     for (size_t i = 0; i < fields.size(); i++)
3692     {
3693         const TField *field    = fields[i];
3694         const TType *fieldType = field->type();
3695 
3696         const TString &fieldNameA = "a." + Decorate(field->name());
3697         const TString &fieldNameB = "b." + Decorate(field->name());
3698 
3699         if (i > 0)
3700         {
3701             fnOut << " && ";
3702         }
3703 
3704         fnOut << "(";
3705         outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
3706         fnOut << fieldNameA;
3707         outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
3708         fnOut << fieldNameB;
3709         outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
3710         fnOut << ")";
3711     }
3712 
3713     fnOut << ";\n" << "}\n";
3714 
3715     function->functionDefinition = fnOut.c_str();
3716 
3717     mStructEqualityFunctions.push_back(function);
3718     mEqualityFunctions.push_back(function);
3719 
3720     return function->functionName;
3721 }
3722 
addArrayEqualityFunction(const TType & type)3723 TString OutputHLSL::addArrayEqualityFunction(const TType &type)
3724 {
3725     for (const auto &eqFunction : mArrayEqualityFunctions)
3726     {
3727         if (eqFunction->type == type)
3728         {
3729             return eqFunction->functionName;
3730         }
3731     }
3732 
3733     TType elementType(type);
3734     elementType.toArrayElementType();
3735 
3736     ArrayHelperFunction *function = new ArrayHelperFunction();
3737     function->type                = type;
3738 
3739     function->functionName = ArrayHelperFunctionName("angle_eq", type);
3740 
3741     TInfoSinkBase fnOut;
3742 
3743     const TString &typeName = TypeString(type);
3744     fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
3745           << ", " << typeName << " b" << ArrayString(type) << ")\n"
3746           << "{\n"
3747              "    for (int i = 0; i < "
3748           << type.getOutermostArraySize()
3749           << "; ++i)\n"
3750              "    {\n"
3751              "        if (";
3752 
3753     outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
3754     fnOut << "a[i]";
3755     outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
3756     fnOut << "b[i]";
3757     outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
3758 
3759     fnOut << ") { return false; }\n"
3760              "    }\n"
3761              "    return true;\n"
3762              "}\n";
3763 
3764     function->functionDefinition = fnOut.c_str();
3765 
3766     mArrayEqualityFunctions.push_back(function);
3767     mEqualityFunctions.push_back(function);
3768 
3769     return function->functionName;
3770 }
3771 
addArrayAssignmentFunction(const TType & type)3772 TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
3773 {
3774     for (const auto &assignFunction : mArrayAssignmentFunctions)
3775     {
3776         if (assignFunction.type == type)
3777         {
3778             return assignFunction.functionName;
3779         }
3780     }
3781 
3782     TType elementType(type);
3783     elementType.toArrayElementType();
3784 
3785     ArrayHelperFunction function;
3786     function.type = type;
3787 
3788     function.functionName = ArrayHelperFunctionName("angle_assign", type);
3789 
3790     TInfoSinkBase fnOut;
3791 
3792     const TString &typeName = TypeString(type);
3793     fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
3794           << ", " << typeName << " b" << ArrayString(type) << ")\n"
3795           << "{\n"
3796              "    for (int i = 0; i < "
3797           << type.getOutermostArraySize()
3798           << "; ++i)\n"
3799              "    {\n"
3800              "        ";
3801 
3802     outputAssign(PreVisit, elementType, fnOut);
3803     fnOut << "a[i]";
3804     outputAssign(InVisit, elementType, fnOut);
3805     fnOut << "b[i]";
3806     outputAssign(PostVisit, elementType, fnOut);
3807 
3808     fnOut << ";\n"
3809              "    }\n"
3810              "}\n";
3811 
3812     function.functionDefinition = fnOut.c_str();
3813 
3814     mArrayAssignmentFunctions.push_back(function);
3815 
3816     return function.functionName;
3817 }
3818 
addArrayConstructIntoFunction(const TType & type)3819 TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
3820 {
3821     for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
3822     {
3823         if (constructIntoFunction.type == type)
3824         {
3825             return constructIntoFunction.functionName;
3826         }
3827     }
3828 
3829     TType elementType(type);
3830     elementType.toArrayElementType();
3831 
3832     ArrayHelperFunction function;
3833     function.type = type;
3834 
3835     function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
3836 
3837     TInfoSinkBase fnOut;
3838 
3839     const TString &typeName = TypeString(type);
3840     fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
3841     for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
3842     {
3843         fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
3844     }
3845     fnOut << ")\n"
3846              "{\n";
3847 
3848     for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
3849     {
3850         fnOut << "    ";
3851         outputAssign(PreVisit, elementType, fnOut);
3852         fnOut << "a[" << i << "]";
3853         outputAssign(InVisit, elementType, fnOut);
3854         fnOut << "b" << i;
3855         outputAssign(PostVisit, elementType, fnOut);
3856         fnOut << ";\n";
3857     }
3858     fnOut << "}\n";
3859 
3860     function.functionDefinition = fnOut.c_str();
3861 
3862     mArrayConstructIntoFunctions.push_back(function);
3863 
3864     return function.functionName;
3865 }
3866 
addFlatEvaluateFunction(const TType & type,const TType & parameterType)3867 TString OutputHLSL::addFlatEvaluateFunction(const TType &type, const TType &parameterType)
3868 {
3869     for (const auto &flatEvaluateFunction : mFlatEvaluateFunctions)
3870     {
3871         if (flatEvaluateFunction.type == type &&
3872             flatEvaluateFunction.parameterType == parameterType)
3873         {
3874             return flatEvaluateFunction.functionName;
3875         }
3876     }
3877 
3878     FlatEvaluateFunction function;
3879     function.type          = type;
3880     function.parameterType = parameterType;
3881 
3882     const TString &typeName          = TypeString(type);
3883     const TString &parameterTypeName = TypeString(parameterType);
3884 
3885     function.functionName = "angle_eval_flat_" + typeName + "_" + parameterTypeName;
3886 
3887     // If <interpolant> is declared with a "flat" qualifier, the interpolated
3888     // value will have the same value everywhere for a single primitive, so
3889     // the location used for the interpolation has no effect and the functions
3890     // just return that same value.
3891     TInfoSinkBase fnOut;
3892     fnOut << typeName << " " << function.functionName << "(" << typeName << " i, "
3893           << parameterTypeName << " p)\n";
3894     fnOut << "{\n" << "    return i;\n" << "}\n";
3895     function.functionDefinition = fnOut.c_str();
3896 
3897     mFlatEvaluateFunctions.push_back(function);
3898 
3899     return function.functionName;
3900 }
3901 
ensureStructDefined(const TType & type)3902 void OutputHLSL::ensureStructDefined(const TType &type)
3903 {
3904     const TStructure *structure = type.getStruct();
3905     if (structure)
3906     {
3907         ASSERT(type.getBasicType() == EbtStruct);
3908         mStructureHLSL->ensureStructDefined(*structure);
3909     }
3910 }
3911 
shaderNeedsGenerateOutput() const3912 bool OutputHLSL::shaderNeedsGenerateOutput() const
3913 {
3914     return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
3915 }
3916 
generateOutputCall() const3917 const char *OutputHLSL::generateOutputCall() const
3918 {
3919     if (mShaderType == GL_VERTEX_SHADER)
3920     {
3921         return "generateOutput(input)";
3922     }
3923     else
3924     {
3925         return "generateOutput()";
3926     }
3927 }
3928 }  // namespace sh
3929