1 | // |
2 | // Copyright (c) 2017 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 | // Applies the necessary AST transformations to support multiview rendering through instancing. |
7 | // Check the header file For more information. |
8 | // |
9 | |
10 | #include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h" |
11 | |
12 | #include "compiler/translator/StaticType.h" |
13 | #include "compiler/translator/SymbolTable.h" |
14 | #include "compiler/translator/tree_ops/InitializeVariables.h" |
15 | #include "compiler/translator/tree_util/BuiltIn_autogen.h" |
16 | #include "compiler/translator/tree_util/FindMain.h" |
17 | #include "compiler/translator/tree_util/IntermNode_util.h" |
18 | #include "compiler/translator/tree_util/IntermTraverse.h" |
19 | #include "compiler/translator/tree_util/ReplaceVariable.h" |
20 | #include "compiler/translator/util.h" |
21 | |
22 | namespace sh |
23 | { |
24 | |
25 | namespace |
26 | { |
27 | |
28 | constexpr const ImmutableString kViewIDVariableName("ViewID_OVR" ); |
29 | constexpr const ImmutableString kInstanceIDVariableName("InstanceID" ); |
30 | constexpr const ImmutableString kMultiviewBaseViewLayerIndexVariableName( |
31 | "multiviewBaseViewLayerIndex" ); |
32 | |
33 | // Adds the InstanceID and ViewID_OVR initializers to the end of the initializers' sequence. |
34 | void InitializeViewIDAndInstanceID(const TVariable *viewID, |
35 | const TVariable *instanceID, |
36 | unsigned numberOfViews, |
37 | const TSymbolTable &symbolTable, |
38 | TIntermSequence *initializers) |
39 | { |
40 | // Create an unsigned numberOfViews node. |
41 | TConstantUnion *numberOfViewsUnsignedConstant = new TConstantUnion(); |
42 | numberOfViewsUnsignedConstant->setUConst(numberOfViews); |
43 | TIntermConstantUnion *numberOfViewsUint = |
44 | new TIntermConstantUnion(numberOfViewsUnsignedConstant, TType(EbtUInt, EbpHigh, EvqConst)); |
45 | |
46 | // Create a uint(gl_InstanceID) node. |
47 | TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence(); |
48 | glInstanceIDSymbolCastArguments->push_back(new TIntermSymbol(BuiltInVariable::gl_InstanceID())); |
49 | TIntermAggregate *glInstanceIDAsUint = TIntermAggregate::CreateConstructor( |
50 | TType(EbtUInt, EbpHigh, EvqTemporary), glInstanceIDSymbolCastArguments); |
51 | |
52 | // Create a uint(gl_InstanceID) / numberOfViews node. |
53 | TIntermBinary *normalizedInstanceID = |
54 | new TIntermBinary(EOpDiv, glInstanceIDAsUint, numberOfViewsUint); |
55 | |
56 | // Create an int(uint(gl_InstanceID) / numberOfViews) node. |
57 | TIntermSequence *normalizedInstanceIDCastArguments = new TIntermSequence(); |
58 | normalizedInstanceIDCastArguments->push_back(normalizedInstanceID); |
59 | TIntermAggregate *normalizedInstanceIDAsInt = TIntermAggregate::CreateConstructor( |
60 | TType(EbtInt, EbpHigh, EvqTemporary), normalizedInstanceIDCastArguments); |
61 | |
62 | // Create an InstanceID = int(uint(gl_InstanceID) / numberOfViews) node. |
63 | TIntermBinary *instanceIDInitializer = |
64 | new TIntermBinary(EOpAssign, new TIntermSymbol(instanceID), normalizedInstanceIDAsInt); |
65 | initializers->push_back(instanceIDInitializer); |
66 | |
67 | // Create a uint(gl_InstanceID) % numberOfViews node. |
68 | TIntermBinary *normalizedViewID = |
69 | new TIntermBinary(EOpIMod, glInstanceIDAsUint->deepCopy(), numberOfViewsUint->deepCopy()); |
70 | |
71 | // Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node. |
72 | TIntermBinary *viewIDInitializer = |
73 | new TIntermBinary(EOpAssign, new TIntermSymbol(viewID), normalizedViewID); |
74 | initializers->push_back(viewIDInitializer); |
75 | } |
76 | |
77 | // Adds a branch to write int(ViewID_OVR) to either gl_ViewportIndex or gl_Layer. The branch is |
78 | // added to the end of the initializers' sequence. |
79 | void SelectViewIndexInVertexShader(const TVariable *viewID, |
80 | const TVariable *multiviewBaseViewLayerIndex, |
81 | TIntermSequence *initializers, |
82 | const TSymbolTable &symbolTable) |
83 | { |
84 | // Create an int(ViewID_OVR) node. |
85 | TIntermSequence *viewIDSymbolCastArguments = new TIntermSequence(); |
86 | viewIDSymbolCastArguments->push_back(new TIntermSymbol(viewID)); |
87 | TIntermAggregate *viewIDAsInt = TIntermAggregate::CreateConstructor( |
88 | TType(EbtInt, EbpHigh, EvqTemporary), viewIDSymbolCastArguments); |
89 | |
90 | // Create a gl_ViewportIndex node. |
91 | TIntermSymbol *viewportIndexSymbol = new TIntermSymbol(BuiltInVariable::gl_ViewportIndex()); |
92 | |
93 | // Create a { gl_ViewportIndex = int(ViewID_OVR) } node. |
94 | TIntermBlock *viewportIndexInitializerInBlock = new TIntermBlock(); |
95 | viewportIndexInitializerInBlock->appendStatement( |
96 | new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt)); |
97 | |
98 | // Create a gl_Layer node. |
99 | TIntermSymbol *layerSymbol = new TIntermSymbol(BuiltInVariable::gl_LayerVS()); |
100 | |
101 | // Create an int(ViewID_OVR) + multiviewBaseViewLayerIndex node |
102 | TIntermBinary *sumOfViewIDAndBaseViewIndex = new TIntermBinary( |
103 | EOpAdd, viewIDAsInt->deepCopy(), new TIntermSymbol(multiviewBaseViewLayerIndex)); |
104 | |
105 | // Create a { gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex } node. |
106 | TIntermBlock *layerInitializerInBlock = new TIntermBlock(); |
107 | layerInitializerInBlock->appendStatement( |
108 | new TIntermBinary(EOpAssign, layerSymbol, sumOfViewIDAndBaseViewIndex)); |
109 | |
110 | // Create a node to compare whether the base view index uniform is less than zero. |
111 | TIntermBinary *multiviewBaseViewLayerIndexZeroComparison = |
112 | new TIntermBinary(EOpLessThan, new TIntermSymbol(multiviewBaseViewLayerIndex), |
113 | CreateZeroNode(TType(EbtInt, EbpHigh, EvqConst))); |
114 | |
115 | // Create an if-else statement to select the code path. |
116 | TIntermIfElse *multiviewBranch = |
117 | new TIntermIfElse(multiviewBaseViewLayerIndexZeroComparison, |
118 | viewportIndexInitializerInBlock, layerInitializerInBlock); |
119 | |
120 | initializers->push_back(multiviewBranch); |
121 | } |
122 | |
123 | } // namespace |
124 | |
125 | void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, |
126 | unsigned numberOfViews, |
127 | GLenum shaderType, |
128 | ShCompileOptions compileOptions, |
129 | ShShaderOutput shaderOutput, |
130 | TSymbolTable *symbolTable) |
131 | { |
132 | ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER); |
133 | |
134 | TQualifier viewIDQualifier = (shaderType == GL_VERTEX_SHADER) ? EvqFlatOut : EvqFlatIn; |
135 | const TVariable *viewID = |
136 | new TVariable(symbolTable, kViewIDVariableName, |
137 | new TType(EbtUInt, EbpHigh, viewIDQualifier), SymbolType::AngleInternal); |
138 | |
139 | DeclareGlobalVariable(root, viewID); |
140 | ReplaceVariable(root, BuiltInVariable::gl_ViewID_OVR(), viewID); |
141 | if (shaderType == GL_VERTEX_SHADER) |
142 | { |
143 | // Replacing gl_InstanceID with InstanceID should happen before adding the initializers of |
144 | // InstanceID and ViewID. |
145 | const TType *instanceIDVariableType = StaticType::Get<EbtInt, EbpHigh, EvqGlobal, 1, 1>(); |
146 | const TVariable *instanceID = |
147 | new TVariable(symbolTable, kInstanceIDVariableName, instanceIDVariableType, |
148 | SymbolType::AngleInternal); |
149 | DeclareGlobalVariable(root, instanceID); |
150 | ReplaceVariable(root, BuiltInVariable::gl_InstanceID(), instanceID); |
151 | |
152 | TIntermSequence *initializers = new TIntermSequence(); |
153 | InitializeViewIDAndInstanceID(viewID, instanceID, numberOfViews, *symbolTable, |
154 | initializers); |
155 | |
156 | // The AST transformation which adds the expression to select the viewport index should |
157 | // be done only for the GLSL and ESSL output. |
158 | const bool selectView = (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u; |
159 | // Assert that if the view is selected in the vertex shader, then the output is |
160 | // either GLSL or ESSL. |
161 | ASSERT(!selectView || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput)); |
162 | if (selectView) |
163 | { |
164 | // Add a uniform to switch between side-by-side and layered rendering. |
165 | const TType *baseLayerIndexVariableType = |
166 | StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>(); |
167 | const TVariable *multiviewBaseViewLayerIndex = |
168 | new TVariable(symbolTable, kMultiviewBaseViewLayerIndexVariableName, |
169 | baseLayerIndexVariableType, SymbolType::AngleInternal); |
170 | DeclareGlobalVariable(root, multiviewBaseViewLayerIndex); |
171 | |
172 | // Setting a value to gl_ViewportIndex or gl_Layer should happen after ViewID_OVR's |
173 | // initialization. |
174 | SelectViewIndexInVertexShader(viewID, multiviewBaseViewLayerIndex, initializers, |
175 | *symbolTable); |
176 | } |
177 | |
178 | // Insert initializers at the beginning of main(). |
179 | TIntermBlock *initializersBlock = new TIntermBlock(); |
180 | initializersBlock->getSequence()->swap(*initializers); |
181 | TIntermBlock *mainBody = FindMainBody(root); |
182 | mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initializersBlock); |
183 | } |
184 | } |
185 | |
186 | } // namespace sh |
187 | |