• 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/TranslatorHLSL.h"
8 
9 #include "compiler/translator/OutputHLSL.h"
10 #include "compiler/translator/tree_ops/RemoveDynamicIndexing.h"
11 #include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
12 #include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
13 #include "compiler/translator/tree_ops/SplitSequenceOperator.h"
14 #include "compiler/translator/tree_ops/d3d/AddDefaultReturnStatements.h"
15 #include "compiler/translator/tree_ops/d3d/ArrayReturnValueToOutParameter.h"
16 #include "compiler/translator/tree_ops/d3d/BreakVariableAliasingInInnerLoops.h"
17 #include "compiler/translator/tree_ops/d3d/ExpandIntegerPowExpressions.h"
18 #include "compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.h"
19 #include "compiler/translator/tree_ops/d3d/RewriteAtomicFunctionExpressions.h"
20 #include "compiler/translator/tree_ops/d3d/RewriteElseBlocks.h"
21 #include "compiler/translator/tree_ops/d3d/RewriteExpressionsWithShaderStorageBlock.h"
22 #include "compiler/translator/tree_ops/d3d/RewriteUnaryMinusOperatorInt.h"
23 #include "compiler/translator/tree_ops/d3d/SeparateArrayConstructorStatements.h"
24 #include "compiler/translator/tree_ops/d3d/SeparateArrayInitialization.h"
25 #include "compiler/translator/tree_ops/d3d/SeparateExpressionsReturningArrays.h"
26 #include "compiler/translator/tree_ops/d3d/UnfoldShortCircuitToIf.h"
27 #include "compiler/translator/tree_ops/d3d/WrapSwitchStatementsInBlocks.h"
28 #include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
29 
30 namespace sh
31 {
32 
TranslatorHLSL(sh::GLenum type,ShShaderSpec spec,ShShaderOutput output)33 TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
34     : TCompiler(type, spec, output)
35 {}
36 
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics * perfDiagnostics)37 bool TranslatorHLSL::translate(TIntermBlock *root,
38                                ShCompileOptions compileOptions,
39                                PerformanceDiagnostics *perfDiagnostics)
40 {
41     const ShBuiltInResources &resources = getResources();
42     int numRenderTargets                = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
43     int maxDualSourceDrawBuffers =
44         resources.EXT_blend_func_extended ? resources.MaxDualSourceDrawBuffers : 0;
45 
46     if (!sh::AddDefaultReturnStatements(this, root))
47     {
48         return false;
49     }
50 
51     // Note that SimplifyLoopConditions needs to be run before any other AST transformations that
52     // may need to generate new statements from loop conditions or loop expressions.
53     // Note that SeparateDeclarations has already been run in TCompiler::compileTreeImpl().
54     if (!SimplifyLoopConditions(
55             this, root,
56             IntermNodePatternMatcher::kExpressionReturningArray |
57                 IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
58                 IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
59             &getSymbolTable()))
60     {
61         return false;
62     }
63 
64     if (!SplitSequenceOperator(
65             this, root,
66             IntermNodePatternMatcher::kExpressionReturningArray |
67                 IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
68                 IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
69             &getSymbolTable()))
70     {
71         return false;
72     }
73 
74     // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf.
75     if (!UnfoldShortCircuitToIf(this, root, &getSymbolTable()))
76     {
77         return false;
78     }
79 
80     if (!SeparateArrayConstructorStatements(this, root))
81     {
82         return false;
83     }
84 
85     if (!SeparateExpressionsReturningArrays(this, root, &getSymbolTable()))
86     {
87         return false;
88     }
89 
90     // Note that SeparateDeclarations needs to be run before SeparateArrayInitialization.
91     if (!SeparateArrayInitialization(this, root))
92     {
93         return false;
94     }
95 
96     // HLSL doesn't support arrays as return values, we'll need to make functions that have an array
97     // as a return value to use an out parameter to transfer the array data instead.
98     if (!ArrayReturnValueToOutParameter(this, root, &getSymbolTable()))
99     {
100         return false;
101     }
102 
103     if (!shouldRunLoopAndIndexingValidation(compileOptions))
104     {
105         // HLSL doesn't support dynamic indexing of vectors and matrices.
106         if (!RemoveDynamicIndexingOfNonSSBOVectorOrMatrix(this, root, &getSymbolTable(),
107                                                           perfDiagnostics))
108         {
109             return false;
110         }
111     }
112 
113     // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
114     // use a vertex attribute as a condition, and some related computation in the else block.
115     if (getOutputType() == SH_HLSL_3_0_OUTPUT && getShaderType() == GL_VERTEX_SHADER)
116     {
117         if (!sh::RewriteElseBlocks(this, root, &getSymbolTable()))
118         {
119             return false;
120         }
121     }
122 
123     // Work around an HLSL compiler frontend aliasing optimization bug.
124     // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed
125     // in the next release of d3dcompiler.dll, it would be nice to detect the DLL
126     // version and only apply the workaround if it is too old.
127     if (!sh::BreakVariableAliasingInInnerLoops(this, root))
128     {
129         return false;
130     }
131 
132     // WrapSwitchStatementsInBlocks should be called after any AST transformations that might
133     // introduce variable declarations inside the main scope of any switch statement. It cannot
134     // result in no-op cases at the end of switch statements, because unreferenced variables
135     // have already been pruned.
136     if (!WrapSwitchStatementsInBlocks(this, root))
137     {
138         return false;
139     }
140 
141     bool precisionEmulation = false;
142     if (!emulatePrecisionIfNeeded(root, getInfoSink().obj, &precisionEmulation, getOutputType()))
143         return false;
144 
145     if ((compileOptions & SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS) != 0)
146     {
147         if (!sh::ExpandIntegerPowExpressions(this, root, &getSymbolTable()))
148         {
149             return false;
150         }
151     }
152 
153     if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
154     {
155         if (!sh::RewriteTexelFetchOffset(this, root, getSymbolTable(), getShaderVersion()))
156         {
157             return false;
158         }
159     }
160 
161     if (((compileOptions & SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR) != 0) &&
162         getShaderType() == GL_VERTEX_SHADER)
163     {
164         if (!sh::RewriteUnaryMinusOperatorInt(this, root))
165         {
166             return false;
167         }
168     }
169 
170     if (getShaderVersion() >= 310)
171     {
172         // Due to ssbo also can be used as the argument of atomic memory functions, we should put
173         // RewriteExpressionsWithShaderStorageBlock before RewriteAtomicFunctionExpressions.
174         if (!sh::RewriteExpressionsWithShaderStorageBlock(this, root, &getSymbolTable()))
175         {
176             return false;
177         }
178         if (!sh::RewriteAtomicFunctionExpressions(this, root, &getSymbolTable(),
179                                                   getShaderVersion()))
180         {
181             return false;
182         }
183     }
184 
185     mUniformBlockOptimizedMap.clear();
186     mSlowCompilingUniformBlockSet.clear();
187     // In order to get the exact maximum of slots are available for shader resources, which would
188     // been bound with StructuredBuffer, we only translate uniform block with a large array member
189     // into StructuredBuffer when shader version is 300.
190     if (getShaderVersion() == 300 &&
191         (compileOptions & SH_ALLOW_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER) != 0)
192     {
193         if (!sh::RecordUniformBlocksWithLargeArrayMember(root, mUniformBlockOptimizedMap,
194                                                          mSlowCompilingUniformBlockSet))
195         {
196             return false;
197         }
198     }
199 
200     sh::OutputHLSL outputHLSL(getShaderType(), getShaderSpec(), getShaderVersion(),
201                               getExtensionBehavior(), getSourcePath(), getOutputType(),
202                               numRenderTargets, maxDualSourceDrawBuffers, getUniforms(),
203                               compileOptions, getComputeShaderLocalSize(), &getSymbolTable(),
204                               perfDiagnostics, mUniformBlockOptimizedMap, mShaderStorageBlocks);
205 
206     outputHLSL.output(root, getInfoSink().obj);
207 
208     mShaderStorageBlockRegisterMap      = outputHLSL.getShaderStorageBlockRegisterMap();
209     mUniformBlockRegisterMap            = outputHLSL.getUniformBlockRegisterMap();
210     mUniformBlockUseStructuredBufferMap = outputHLSL.getUniformBlockUseStructuredBufferMap();
211     mUniformRegisterMap                 = outputHLSL.getUniformRegisterMap();
212     mReadonlyImage2DRegisterIndex       = outputHLSL.getReadonlyImage2DRegisterIndex();
213     mImage2DRegisterIndex               = outputHLSL.getImage2DRegisterIndex();
214     mUsedImage2DFunctionNames           = outputHLSL.getUsedImage2DFunctionNames();
215 
216     return true;
217 }
218 
shouldFlattenPragmaStdglInvariantAll()219 bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll()
220 {
221     // Not necessary when translating to HLSL.
222     return false;
223 }
224 
hasShaderStorageBlock(const std::string & uniformBlockName) const225 bool TranslatorHLSL::hasShaderStorageBlock(const std::string &uniformBlockName) const
226 {
227     return (mShaderStorageBlockRegisterMap.count(uniformBlockName) > 0);
228 }
229 
getShaderStorageBlockRegister(const std::string & shaderStorageBlockName) const230 unsigned int TranslatorHLSL::getShaderStorageBlockRegister(
231     const std::string &shaderStorageBlockName) const
232 {
233     ASSERT(hasShaderStorageBlock(shaderStorageBlockName));
234     return mShaderStorageBlockRegisterMap.find(shaderStorageBlockName)->second;
235 }
236 
hasUniformBlock(const std::string & uniformBlockName) const237 bool TranslatorHLSL::hasUniformBlock(const std::string &uniformBlockName) const
238 {
239     return (mUniformBlockRegisterMap.count(uniformBlockName) > 0);
240 }
241 
getUniformBlockRegister(const std::string & uniformBlockName) const242 unsigned int TranslatorHLSL::getUniformBlockRegister(const std::string &uniformBlockName) const
243 {
244     ASSERT(hasUniformBlock(uniformBlockName));
245     return mUniformBlockRegisterMap.find(uniformBlockName)->second;
246 }
247 
getUniformRegisterMap() const248 const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const
249 {
250     return &mUniformRegisterMap;
251 }
252 
getSlowCompilingUniformBlockSet() const253 const std::set<std::string> *TranslatorHLSL::getSlowCompilingUniformBlockSet() const
254 {
255     return &mSlowCompilingUniformBlockSet;
256 }
257 
getReadonlyImage2DRegisterIndex() const258 unsigned int TranslatorHLSL::getReadonlyImage2DRegisterIndex() const
259 {
260     return mReadonlyImage2DRegisterIndex;
261 }
262 
getImage2DRegisterIndex() const263 unsigned int TranslatorHLSL::getImage2DRegisterIndex() const
264 {
265     return mImage2DRegisterIndex;
266 }
267 
getUsedImage2DFunctionNames() const268 const std::set<std::string> *TranslatorHLSL::getUsedImage2DFunctionNames() const
269 {
270     return &mUsedImage2DFunctionNames;
271 }
272 
shouldUniformBlockUseStructuredBuffer(const std::string & uniformBlockName) const273 bool TranslatorHLSL::shouldUniformBlockUseStructuredBuffer(
274     const std::string &uniformBlockName) const
275 {
276     auto uniformBlockIter = mUniformBlockUseStructuredBufferMap.find(uniformBlockName);
277     return uniformBlockIter != mUniformBlockUseStructuredBufferMap.end() &&
278            uniformBlockIter->second;
279 }
280 
281 }  // namespace sh
282