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