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