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 #ifndef COMPILER_TRANSLATOR_OUTPUTHLSL_H_
8 #define COMPILER_TRANSLATOR_OUTPUTHLSL_H_
9 
10 #include <list>
11 #include <map>
12 #include <stack>
13 
14 #include "angle_gl.h"
15 #include "compiler/translator/ASTMetadataHLSL.h"
16 #include "compiler/translator/Compiler.h"
17 #include "compiler/translator/FlagStd140Structs.h"
18 #include "compiler/translator/ImmutableString.h"
19 #include "compiler/translator/ShaderStorageBlockOutputHLSL.h"
20 #include "compiler/translator/tree_util/IntermTraverse.h"
21 
22 class BuiltInFunctionEmulator;
23 
24 namespace sh
25 {
26 class AtomicCounterFunctionHLSL;
27 class ImageFunctionHLSL;
28 class ResourcesHLSL;
29 class StructureHLSL;
30 class TextureFunctionHLSL;
31 class TSymbolTable;
32 class TVariable;
33 class UnfoldShortCircuit;
34 
35 using ReferencedVariables = std::map<int, const TVariable *>;
36 
37 class OutputHLSL : public TIntermTraverser
38 {
39   public:
40     OutputHLSL(sh::GLenum shaderType,
41                ShShaderSpec shaderSpec,
42                int shaderVersion,
43                const TExtensionBehavior &extensionBehavior,
44                const char *sourcePath,
45                ShShaderOutput outputType,
46                int numRenderTargets,
47                int maxDualSourceDrawBuffers,
48                const std::vector<ShaderVariable> &uniforms,
49                ShCompileOptions compileOptions,
50                sh::WorkGroupSize workGroupSize,
51                TSymbolTable *symbolTable,
52                PerformanceDiagnostics *perfDiagnostics,
53                const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap,
54                const std::vector<InterfaceBlock> &shaderStorageBlocks);
55 
56     ~OutputHLSL() override;
57 
58     void output(TIntermNode *treeRoot, TInfoSinkBase &objSink);
59 
60     const std::map<std::string, unsigned int> &getShaderStorageBlockRegisterMap() const;
61     const std::map<std::string, unsigned int> &getUniformBlockRegisterMap() const;
62     const std::map<std::string, bool> &getUniformBlockUseStructuredBufferMap() const;
63     const std::map<std::string, unsigned int> &getUniformRegisterMap() const;
64     unsigned int getReadonlyImage2DRegisterIndex() const;
65     unsigned int getImage2DRegisterIndex() const;
66     const std::set<std::string> &getUsedImage2DFunctionNames() const;
67 
getInfoSink()68     TInfoSinkBase &getInfoSink()
69     {
70         ASSERT(!mInfoSinkStack.empty());
71         return *mInfoSinkStack.top();
72     }
73 
74   protected:
75     friend class ShaderStorageBlockOutputHLSL;
76 
77     TString zeroInitializer(const TType &type) const;
78 
79     void writeReferencedAttributes(TInfoSinkBase &out) const;
80     void writeReferencedVaryings(TInfoSinkBase &out) const;
81     void header(TInfoSinkBase &out,
82                 const std::vector<MappedStruct> &std140Structs,
83                 const BuiltInFunctionEmulator *builtInFunctionEmulator) const;
84 
85     void writeFloat(TInfoSinkBase &out, float f);
86     void writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion);
87     const TConstantUnion *writeConstantUnionArray(TInfoSinkBase &out,
88                                                   const TConstantUnion *const constUnion,
89                                                   const size_t size);
90 
91     // Visit AST nodes and output their code to the body stream
92     void visitSymbol(TIntermSymbol *) override;
93     void visitConstantUnion(TIntermConstantUnion *) override;
94     bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
95     bool visitBinary(Visit visit, TIntermBinary *) override;
96     bool visitUnary(Visit visit, TIntermUnary *) override;
97     bool visitTernary(Visit visit, TIntermTernary *) override;
98     bool visitIfElse(Visit visit, TIntermIfElse *) override;
99     bool visitSwitch(Visit visit, TIntermSwitch *) override;
100     bool visitCase(Visit visit, TIntermCase *) override;
101     void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
102     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
103     bool visitAggregate(Visit visit, TIntermAggregate *) override;
104     bool visitBlock(Visit visit, TIntermBlock *node) override;
105     bool visitGlobalQualifierDeclaration(Visit visit,
106                                          TIntermGlobalQualifierDeclaration *node) override;
107     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
108     bool visitLoop(Visit visit, TIntermLoop *) override;
109     bool visitBranch(Visit visit, TIntermBranch *) override;
110 
111     bool handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node);
112 
113     // Emit one of three strings depending on traverse phase. Called with literal strings so using
114     // const char* instead of TString.
115     void outputTriplet(TInfoSinkBase &out,
116                        Visit visit,
117                        const char *preString,
118                        const char *inString,
119                        const char *postString);
120     void outputLineDirective(TInfoSinkBase &out, int line);
121     void writeParameter(const TVariable *param, TInfoSinkBase &out);
122 
123     void outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node);
124     const TConstantUnion *writeConstantUnion(TInfoSinkBase &out,
125                                              const TType &type,
126                                              const TConstantUnion *constUnion);
127 
128     void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out);
129     void outputAssign(Visit visit, const TType &type, TInfoSinkBase &out);
130 
131     void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op);
132 
133     // Returns true if it found a 'same symbol' initializer (initializer that references the
134     // variable it's initting)
135     bool writeSameSymbolInitializer(TInfoSinkBase &out,
136                                     TIntermSymbol *symbolNode,
137                                     TIntermTyped *expression);
138     // Returns true if variable initializer could be written using literal {} notation.
139     bool writeConstantInitialization(TInfoSinkBase &out,
140                                      TIntermSymbol *symbolNode,
141                                      TIntermTyped *expression);
142 
143     void writeIfElse(TInfoSinkBase &out, TIntermIfElse *node);
144 
145     // Returns the function name
146     TString addStructEqualityFunction(const TStructure &structure);
147     TString addArrayEqualityFunction(const TType &type);
148     TString addArrayAssignmentFunction(const TType &type);
149     TString addArrayConstructIntoFunction(const TType &type);
150 
151     // Ensures if the type is a struct, the struct is defined
152     void ensureStructDefined(const TType &type);
153 
154     bool shaderNeedsGenerateOutput() const;
155     const char *generateOutputCall() const;
156 
157     sh::GLenum mShaderType;
158     ShShaderSpec mShaderSpec;
159     int mShaderVersion;
160     const TExtensionBehavior &mExtensionBehavior;
161     const char *mSourcePath;
162     const ShShaderOutput mOutputType;
163     ShCompileOptions mCompileOptions;
164 
165     bool mInsideFunction;
166     bool mInsideMain;
167 
168     // Output streams
169     TInfoSinkBase mHeader;
170     TInfoSinkBase mBody;
171     TInfoSinkBase mFooter;
172 
173     // A stack is useful when we want to traverse in the header, or in helper functions, but not
174     // always write to the body. Instead use an InfoSink stack to keep our current state intact.
175     // TODO (jmadill): Just passing an InfoSink in function parameters would be simpler.
176     std::stack<TInfoSinkBase *> mInfoSinkStack;
177 
178     ReferencedVariables mReferencedUniforms;
179 
180     // Indexed by block id, not instance id.
181     ReferencedInterfaceBlocks mReferencedUniformBlocks;
182 
183     std::map<int, const TInterfaceBlock *> mUniformBlockOptimizedMap;
184 
185     ReferencedVariables mReferencedAttributes;
186     ReferencedVariables mReferencedVaryings;
187     ReferencedVariables mReferencedOutputVariables;
188 
189     StructureHLSL *mStructureHLSL;
190     ResourcesHLSL *mResourcesHLSL;
191     TextureFunctionHLSL *mTextureFunctionHLSL;
192     ImageFunctionHLSL *mImageFunctionHLSL;
193     AtomicCounterFunctionHLSL *mAtomicCounterFunctionHLSL;
194 
195     // Parameters determining what goes in the header output
196     bool mUsesFragColor;
197     bool mUsesFragData;
198     bool mUsesDepthRange;
199     bool mUsesFragCoord;
200     bool mUsesPointCoord;
201     bool mUsesFrontFacing;
202     bool mUsesHelperInvocation;
203     bool mUsesPointSize;
204     bool mUsesInstanceID;
205     bool mHasMultiviewExtensionEnabled;
206     bool mUsesViewID;
207     bool mUsesVertexID;
208     bool mUsesFragDepth;
209     bool mUsesNumWorkGroups;
210     bool mUsesWorkGroupID;
211     bool mUsesLocalInvocationID;
212     bool mUsesGlobalInvocationID;
213     bool mUsesLocalInvocationIndex;
214     bool mUsesXor;
215     bool mUsesDiscardRewriting;
216     bool mUsesNestedBreak;
217     bool mRequiresIEEEStrictCompiling;
218     mutable bool mUseZeroArray;
219     bool mUsesSecondaryColor;
220 
221     int mNumRenderTargets;
222     int mMaxDualSourceDrawBuffers;
223 
224     int mUniqueIndex;  // For creating unique names
225 
226     CallDAG mCallDag;
227     MetadataList mASTMetadataList;
228     ASTMetadataHLSL *mCurrentFunctionMetadata;
229     bool mOutputLod0Function;
230     bool mInsideDiscontinuousLoop;
231     int mNestedLoopDepth;
232 
233     TIntermSymbol *mExcessiveLoopIndex;
234 
235     TString structInitializerString(int indent, const TType &type, const TString &name) const;
236 
237     struct HelperFunction
238     {
239         TString functionName;
240         TString functionDefinition;
241 
~HelperFunctionHelperFunction242         virtual ~HelperFunction() {}
243     };
244 
245     // A list of all equality comparison functions. It's important to preserve the order at
246     // which we add the functions, since nested structures call each other recursively, and
247     // structure equality functions may need to call array equality functions and vice versa.
248     // The ownership of the pointers is maintained by the type-specific arrays.
249     std::vector<HelperFunction *> mEqualityFunctions;
250 
251     struct StructEqualityFunction : public HelperFunction
252     {
253         const TStructure *structure;
254     };
255     std::vector<StructEqualityFunction *> mStructEqualityFunctions;
256 
257     struct ArrayHelperFunction : public HelperFunction
258     {
259         TType type;
260     };
261     std::vector<ArrayHelperFunction *> mArrayEqualityFunctions;
262 
263     std::vector<ArrayHelperFunction> mArrayAssignmentFunctions;
264 
265     // The construct-into functions are functions that fill an N-element array passed as an out
266     // parameter with the other N parameters of the function. This is used to work around that
267     // arrays can't be return values in HLSL.
268     std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions;
269 
270     sh::WorkGroupSize mWorkGroupSize;
271 
272     PerformanceDiagnostics *mPerfDiagnostics;
273 
274   private:
275     TString generateStructMapping(const std::vector<MappedStruct> &std140Structs) const;
276     ImmutableString samplerNamePrefixFromStruct(TIntermTyped *node);
277     bool ancestorEvaluatesToSamplerInStruct();
278     // We need to do struct mapping when pass the struct to a function or copy the struct via
279     // assignment.
280     bool needStructMapping(TIntermTyped *node);
281 
282     ShaderStorageBlockOutputHLSL *mSSBOOutputHLSL;
283     bool mNeedStructMapping;
284 };
285 }  // namespace sh
286 
287 #endif  // COMPILER_TRANSLATOR_OUTPUTHLSL_H_
288