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