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