• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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.
InitializeViewIDAndInstanceID(const TVariable * viewID,const TVariable * instanceID,unsigned numberOfViews,const TSymbolTable & symbolTable,TIntermSequence * initializers)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.
SelectViewIndexInVertexShader(const TVariable * viewID,const TVariable * multiviewBaseViewLayerIndex,TIntermSequence * initializers,const TSymbolTable & symbolTable)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 
DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock * root,unsigned numberOfViews,GLenum shaderType,ShCompileOptions compileOptions,ShShaderOutput shaderOutput,TSymbolTable * symbolTable)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