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