1 //
2 // Copyright (c) 2002-2013 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/AddDefaultReturnStatements.h"
10 #include "compiler/translator/ArrayReturnValueToOutParameter.h"
11 #include "compiler/translator/BreakVariableAliasingInInnerLoops.h"
12 #include "compiler/translator/EmulatePrecision.h"
13 #include "compiler/translator/ExpandIntegerPowExpressions.h"
14 #include "compiler/translator/IntermNodePatternMatcher.h"
15 #include "compiler/translator/OutputHLSL.h"
16 #include "compiler/translator/RemoveDynamicIndexing.h"
17 #include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h"
18 #include "compiler/translator/RewriteElseBlocks.h"
19 #include "compiler/translator/RewriteTexelFetchOffset.h"
20 #include "compiler/translator/RewriteUnaryMinusOperatorInt.h"
21 #include "compiler/translator/SeparateArrayInitialization.h"
22 #include "compiler/translator/SeparateDeclarations.h"
23 #include "compiler/translator/SeparateExpressionsReturningArrays.h"
24 #include "compiler/translator/SimplifyLoopConditions.h"
25 #include "compiler/translator/SplitSequenceOperator.h"
26 #include "compiler/translator/UnfoldShortCircuitToIf.h"
27 #include "compiler/translator/WrapSwitchStatementsInBlocks.h"
28 
29 namespace sh
30 {
31 
TranslatorHLSL(sh::GLenum type,ShShaderSpec spec,ShShaderOutput output)32 TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
33     : TCompiler(type, spec, output)
34 {
35 }
36 
translate(TIntermBlock * root,ShCompileOptions compileOptions,PerformanceDiagnostics * perfDiagnostics)37 void 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 
44     sh::AddDefaultReturnStatements(root);
45 
46     // Note that SimplifyLoopConditions needs to be run before any other AST transformations that
47     // may need to generate new statements from loop conditions or loop expressions.
48     // Note that SeparateDeclarations has already been run in TCompiler::compileTreeImpl().
49     SimplifyLoopConditions(root,
50                            IntermNodePatternMatcher::kExpressionReturningArray |
51                                IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
52                                IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
53                            &getSymbolTable(), getShaderVersion());
54 
55     SplitSequenceOperator(root,
56                           IntermNodePatternMatcher::kExpressionReturningArray |
57                               IntermNodePatternMatcher::kUnfoldedShortCircuitExpression |
58                               IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue,
59                           &getSymbolTable(), getShaderVersion());
60 
61     // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf.
62     UnfoldShortCircuitToIf(root, &getSymbolTable());
63 
64     SeparateExpressionsReturningArrays(root, &getSymbolTable());
65 
66     // Note that SeparateDeclarations needs to be run before SeparateArrayInitialization.
67     SeparateArrayInitialization(root);
68 
69     // HLSL doesn't support arrays as return values, we'll need to make functions that have an array
70     // as a return value to use an out parameter to transfer the array data instead.
71     ArrayReturnValueToOutParameter(root, &getSymbolTable());
72 
73     if (!shouldRunLoopAndIndexingValidation(compileOptions))
74     {
75         // HLSL doesn't support dynamic indexing of vectors and matrices.
76         RemoveDynamicIndexing(root, &getSymbolTable(), getShaderVersion(), perfDiagnostics);
77     }
78 
79     // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
80     // use a vertex attribute as a condition, and some related computation in the else block.
81     if (getOutputType() == SH_HLSL_3_0_OUTPUT && getShaderType() == GL_VERTEX_SHADER)
82     {
83         sh::RewriteElseBlocks(root, &getSymbolTable());
84     }
85 
86     // Work around an HLSL compiler frontend aliasing optimization bug.
87     // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed
88     // in the next release of d3dcompiler.dll, it would be nice to detect the DLL
89     // version and only apply the workaround if it is too old.
90     sh::BreakVariableAliasingInInnerLoops(root);
91 
92     // WrapSwitchStatementsInBlocks should be called after any AST transformations that might
93     // introduce variable declarations inside the main scope of any switch statement.
94     if (WrapSwitchStatementsInBlocks(root))
95     {
96         // The WrapSwitchStatementsInBlocks step might introduce new no-op cases to the end of
97         // switch statements, so make sure to clean up the AST.
98         RemoveNoOpCasesFromEndOfSwitchStatements(root, &getSymbolTable());
99     }
100 
101     bool precisionEmulation =
102         getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
103 
104     if (precisionEmulation)
105     {
106         EmulatePrecision emulatePrecision(&getSymbolTable(), getShaderVersion());
107         root->traverse(&emulatePrecision);
108         emulatePrecision.updateTree();
109         emulatePrecision.writeEmulationHelpers(getInfoSink().obj, getShaderVersion(),
110                                                getOutputType());
111     }
112 
113     if ((compileOptions & SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS) != 0)
114     {
115         sh::ExpandIntegerPowExpressions(root, &getSymbolTable());
116     }
117 
118     if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
119     {
120         sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion());
121     }
122 
123     if (((compileOptions & SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR) != 0) &&
124         getShaderType() == GL_VERTEX_SHADER)
125     {
126         sh::RewriteUnaryMinusOperatorInt(root);
127     }
128 
129     sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
130                               getSourcePath(), getOutputType(), numRenderTargets, getUniforms(),
131                               compileOptions, &getSymbolTable(), perfDiagnostics);
132 
133     outputHLSL.output(root, getInfoSink().obj);
134 
135     mUniformBlockRegisterMap   = outputHLSL.getUniformBlockRegisterMap();
136     mUniformRegisterMap        = outputHLSL.getUniformRegisterMap();
137 }
138 
shouldFlattenPragmaStdglInvariantAll()139 bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll()
140 {
141     // Not necessary when translating to HLSL.
142     return false;
143 }
144 
hasUniformBlock(const std::string & uniformBlockName) const145 bool TranslatorHLSL::hasUniformBlock(const std::string &uniformBlockName) const
146 {
147     return (mUniformBlockRegisterMap.count(uniformBlockName) > 0);
148 }
149 
getUniformBlockRegister(const std::string & uniformBlockName) const150 unsigned int TranslatorHLSL::getUniformBlockRegister(const std::string &uniformBlockName) const
151 {
152     ASSERT(hasUniformBlock(uniformBlockName));
153     return mUniformBlockRegisterMap.find(uniformBlockName)->second;
154 }
155 
getUniformRegisterMap() const156 const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const
157 {
158     return &mUniformRegisterMap;
159 }
160 
161 }  // namespace sh
162