• 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     // A few transformations leave the tree in an inconsistent state.  For example, when unfolding
42     // the short-circuit in the following function:
43     //
44     //     mediump float f(float a) { return a > 0 ? 0.0 : 1.0; }
45     //
46     // a temp variable is created to hold the result of the expression.  Currently the precision of
47     // the return value of the function is not propagated to its return expressions.  Additionally,
48     // an expression such as
49     //
50     //     cond ? gl_NumWorkGroups.x : gl_NumWorkGroups.y
51     //
52     // does not have a precision as the built-in does not specify a precision.
53     //
54     // Precision is not applicable to HLSL so fixing these issues are deferred.
55     mValidateASTOptions.validatePrecision = false;
56 
57     const ShBuiltInResources &resources = getResources();
58     int numRenderTargets                = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
59     int maxDualSourceDrawBuffers =
60         resources.EXT_blend_func_extended ? resources.MaxDualSourceDrawBuffers : 0;
61 
62     if (!sh::AddDefaultReturnStatements(this, root))
63     {
64         return false;
65     }
66 
67     // Note that SimplifyLoopConditions needs to be run before any other AST transformations that
68     // may need to generate new statements from loop conditions or loop expressions.
69     // Note that SeparateDeclarations has already been run in TCompiler::compileTreeImpl().
70     if (!SimplifyLoopConditions(
71             this, root,
72             IntermNodePatternMatcher::kExpressionReturningArray |
73                 IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
74                 IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
75             &getSymbolTable()))
76     {
77         return false;
78     }
79 
80     if (!SplitSequenceOperator(
81             this, root,
82             IntermNodePatternMatcher::kExpressionReturningArray |
83                 IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
84                 IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
85             &getSymbolTable()))
86     {
87         return false;
88     }
89 
90     // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf.
91     if (!UnfoldShortCircuitToIf(this, root, &getSymbolTable()))
92     {
93         return false;
94     }
95 
96     if (!SeparateArrayConstructorStatements(this, root))
97     {
98         return false;
99     }
100 
101     if (!SeparateExpressionsReturningArrays(this, root, &getSymbolTable()))
102     {
103         return false;
104     }
105 
106     // Note that SeparateDeclarations needs to be run before SeparateArrayInitialization.
107     if (!SeparateArrayInitialization(this, root))
108     {
109         return false;
110     }
111 
112     // HLSL doesn't support arrays as return values, we'll need to make functions that have an array
113     // as a return value to use an out parameter to transfer the array data instead.
114     if (!ArrayReturnValueToOutParameter(this, root, &getSymbolTable()))
115     {
116         return false;
117     }
118 
119     if (!shouldRunLoopAndIndexingValidation(compileOptions))
120     {
121         // HLSL doesn't support dynamic indexing of vectors and matrices.
122         if (!RemoveDynamicIndexingOfNonSSBOVectorOrMatrix(this, root, &getSymbolTable(),
123                                                           perfDiagnostics))
124         {
125             return false;
126         }
127     }
128 
129     // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
130     // use a vertex attribute as a condition, and some related computation in the else block.
131     if (getOutputType() == SH_HLSL_3_0_OUTPUT && getShaderType() == GL_VERTEX_SHADER)
132     {
133         if (!sh::RewriteElseBlocks(this, root, &getSymbolTable()))
134         {
135             return false;
136         }
137     }
138 
139     // Work around an HLSL compiler frontend aliasing optimization bug.
140     // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed
141     // in the next release of d3dcompiler.dll, it would be nice to detect the DLL
142     // version and only apply the workaround if it is too old.
143     if (!sh::BreakVariableAliasingInInnerLoops(this, root))
144     {
145         return false;
146     }
147 
148     // WrapSwitchStatementsInBlocks should be called after any AST transformations that might
149     // introduce variable declarations inside the main scope of any switch statement. It cannot
150     // result in no-op cases at the end of switch statements, because unreferenced variables
151     // have already been pruned.
152     if (!WrapSwitchStatementsInBlocks(this, root))
153     {
154         return false;
155     }
156 
157     if ((compileOptions & SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS) != 0)
158     {
159         if (!sh::ExpandIntegerPowExpressions(this, root, &getSymbolTable()))
160         {
161             return false;
162         }
163     }
164 
165     if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
166     {
167         if (!sh::RewriteTexelFetchOffset(this, root, getSymbolTable(), getShaderVersion()))
168         {
169             return false;
170         }
171     }
172 
173     if (((compileOptions & SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR) != 0) &&
174         getShaderType() == GL_VERTEX_SHADER)
175     {
176         if (!sh::RewriteUnaryMinusOperatorInt(this, root))
177         {
178             return false;
179         }
180     }
181 
182     if (getShaderVersion() >= 310)
183     {
184         // Due to ssbo also can be used as the argument of atomic memory functions, we should put
185         // RewriteExpressionsWithShaderStorageBlock before RewriteAtomicFunctionExpressions.
186         if (!sh::RewriteExpressionsWithShaderStorageBlock(this, root, &getSymbolTable()))
187         {
188             return false;
189         }
190         if (!sh::RewriteAtomicFunctionExpressions(this, root, &getSymbolTable(),
191                                                   getShaderVersion()))
192         {
193             return false;
194         }
195     }
196 
197     mUniformBlockOptimizedMap.clear();
198     mSlowCompilingUniformBlockSet.clear();
199     // In order to get the exact maximum of slots are available for shader resources, which would
200     // been bound with StructuredBuffer, we only translate uniform block with a large array member
201     // into StructuredBuffer when shader version is 300.
202     if (getShaderVersion() == 300 &&
203         (compileOptions & SH_ALLOW_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER) != 0)
204     {
205         if (!sh::RecordUniformBlocksWithLargeArrayMember(root, mUniformBlockOptimizedMap,
206                                                          mSlowCompilingUniformBlockSet))
207         {
208             return false;
209         }
210     }
211 
212     sh::OutputHLSL outputHLSL(getShaderType(), getShaderSpec(), getShaderVersion(),
213                               getExtensionBehavior(), getSourcePath(), getOutputType(),
214                               numRenderTargets, maxDualSourceDrawBuffers, getUniforms(),
215                               compileOptions, getComputeShaderLocalSize(), &getSymbolTable(),
216                               perfDiagnostics, mUniformBlockOptimizedMap, mShaderStorageBlocks);
217 
218     outputHLSL.output(root, getInfoSink().obj);
219 
220     mShaderStorageBlockRegisterMap      = outputHLSL.getShaderStorageBlockRegisterMap();
221     mUniformBlockRegisterMap            = outputHLSL.getUniformBlockRegisterMap();
222     mUniformBlockUseStructuredBufferMap = outputHLSL.getUniformBlockUseStructuredBufferMap();
223     mUniformRegisterMap                 = outputHLSL.getUniformRegisterMap();
224     mReadonlyImage2DRegisterIndex       = outputHLSL.getReadonlyImage2DRegisterIndex();
225     mImage2DRegisterIndex               = outputHLSL.getImage2DRegisterIndex();
226     mUsedImage2DFunctionNames           = outputHLSL.getUsedImage2DFunctionNames();
227 
228     return true;
229 }
230 
shouldFlattenPragmaStdglInvariantAll()231 bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll()
232 {
233     // Not necessary when translating to HLSL.
234     return false;
235 }
236 
hasShaderStorageBlock(const std::string & uniformBlockName) const237 bool TranslatorHLSL::hasShaderStorageBlock(const std::string &uniformBlockName) const
238 {
239     return (mShaderStorageBlockRegisterMap.count(uniformBlockName) > 0);
240 }
241 
getShaderStorageBlockRegister(const std::string & shaderStorageBlockName) const242 unsigned int TranslatorHLSL::getShaderStorageBlockRegister(
243     const std::string &shaderStorageBlockName) const
244 {
245     ASSERT(hasShaderStorageBlock(shaderStorageBlockName));
246     return mShaderStorageBlockRegisterMap.find(shaderStorageBlockName)->second;
247 }
248 
hasUniformBlock(const std::string & uniformBlockName) const249 bool TranslatorHLSL::hasUniformBlock(const std::string &uniformBlockName) const
250 {
251     return (mUniformBlockRegisterMap.count(uniformBlockName) > 0);
252 }
253 
getUniformBlockRegister(const std::string & uniformBlockName) const254 unsigned int TranslatorHLSL::getUniformBlockRegister(const std::string &uniformBlockName) const
255 {
256     ASSERT(hasUniformBlock(uniformBlockName));
257     return mUniformBlockRegisterMap.find(uniformBlockName)->second;
258 }
259 
getUniformRegisterMap() const260 const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const
261 {
262     return &mUniformRegisterMap;
263 }
264 
getSlowCompilingUniformBlockSet() const265 const std::set<std::string> *TranslatorHLSL::getSlowCompilingUniformBlockSet() const
266 {
267     return &mSlowCompilingUniformBlockSet;
268 }
269 
getReadonlyImage2DRegisterIndex() const270 unsigned int TranslatorHLSL::getReadonlyImage2DRegisterIndex() const
271 {
272     return mReadonlyImage2DRegisterIndex;
273 }
274 
getImage2DRegisterIndex() const275 unsigned int TranslatorHLSL::getImage2DRegisterIndex() const
276 {
277     return mImage2DRegisterIndex;
278 }
279 
getUsedImage2DFunctionNames() const280 const std::set<std::string> *TranslatorHLSL::getUsedImage2DFunctionNames() const
281 {
282     return &mUsedImage2DFunctionNames;
283 }
284 
shouldUniformBlockUseStructuredBuffer(const std::string & uniformBlockName) const285 bool TranslatorHLSL::shouldUniformBlockUseStructuredBuffer(
286     const std::string &uniformBlockName) const
287 {
288     auto uniformBlockIter = mUniformBlockUseStructuredBufferMap.find(uniformBlockName);
289     return uniformBlockIter != mUniformBlockUseStructuredBufferMap.end() &&
290            uniformBlockIter->second;
291 }
292 
293 }  // namespace sh
294