• 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/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