• 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/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, EbpHigh, 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 // Adds a branch to write int(ViewID_OVR) to either gl_ViewportIndex or gl_Layer. The branch 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_ViewportIndex node.
92     TIntermSymbol *viewportIndexSymbol = new TIntermSymbol(BuiltInVariable::gl_ViewportIndex());
93 
94     // Create a { gl_ViewportIndex = int(ViewID_OVR) } node.
95     TIntermBlock *viewportIndexInitializerInBlock = new TIntermBlock();
96     viewportIndexInitializerInBlock->appendStatement(
97         new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt));
98 
99     // Create a gl_Layer node.
100     TIntermSymbol *layerSymbol = new TIntermSymbol(BuiltInVariable::gl_LayerVS());
101 
102     // Create an int(ViewID_OVR) + multiviewBaseViewLayerIndex node
103     TIntermBinary *sumOfViewIDAndBaseViewIndex = new TIntermBinary(
104         EOpAdd, viewIDAsInt->deepCopy(), new TIntermSymbol(multiviewBaseViewLayerIndex));
105 
106     // Create a { gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex } node.
107     TIntermBlock *layerInitializerInBlock = new TIntermBlock();
108     layerInitializerInBlock->appendStatement(
109         new TIntermBinary(EOpAssign, layerSymbol, sumOfViewIDAndBaseViewIndex));
110 
111     // Create a node to compare whether the base view index uniform is less than zero.
112     TIntermBinary *multiviewBaseViewLayerIndexZeroComparison =
113         new TIntermBinary(EOpLessThan, new TIntermSymbol(multiviewBaseViewLayerIndex),
114                           CreateZeroNode(TType(EbtInt, EbpHigh, EvqConst)));
115 
116     // Create an if-else statement to select the code path.
117     TIntermIfElse *multiviewBranch =
118         new TIntermIfElse(multiviewBaseViewLayerIndexZeroComparison,
119                           viewportIndexInitializerInBlock, layerInitializerInBlock);
120 
121     initializers->push_back(multiviewBranch);
122 }
123 
124 }  // namespace
125 
DeclareAndInitBuiltinsForInstancedMultiview(TCompiler * compiler,TIntermBlock * root,unsigned numberOfViews,GLenum shaderType,ShCompileOptions compileOptions,ShShaderOutput shaderOutput,TSymbolTable * symbolTable)126 bool DeclareAndInitBuiltinsForInstancedMultiview(TCompiler *compiler,
127                                                  TIntermBlock *root,
128                                                  unsigned numberOfViews,
129                                                  GLenum shaderType,
130                                                  ShCompileOptions compileOptions,
131                                                  ShShaderOutput shaderOutput,
132                                                  TSymbolTable *symbolTable)
133 {
134     ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER);
135 
136     TQualifier viewIDQualifier = (shaderType == GL_VERTEX_SHADER) ? EvqFlatOut : EvqFlatIn;
137     const TVariable *viewID =
138         new TVariable(symbolTable, kViewIDVariableName,
139                       new TType(EbtUInt, EbpHigh, viewIDQualifier), SymbolType::AngleInternal);
140 
141     DeclareGlobalVariable(root, viewID);
142     if (!ReplaceVariable(compiler, root, BuiltInVariable::gl_ViewID_OVR(), viewID))
143     {
144         return false;
145     }
146     if (shaderType == GL_VERTEX_SHADER)
147     {
148         // Replacing gl_InstanceID with InstanceID should happen before adding the initializers of
149         // InstanceID and ViewID.
150         const TType *instanceIDVariableType = StaticType::Get<EbtInt, EbpHigh, EvqGlobal, 1, 1>();
151         const TVariable *instanceID =
152             new TVariable(symbolTable, kInstanceIDVariableName, instanceIDVariableType,
153                           SymbolType::AngleInternal);
154         DeclareGlobalVariable(root, instanceID);
155         if (!ReplaceVariable(compiler, root, BuiltInVariable::gl_InstanceID(), instanceID))
156         {
157             return false;
158         }
159 
160         TIntermSequence initializers;
161         InitializeViewIDAndInstanceID(viewID, instanceID, numberOfViews, *symbolTable,
162                                       &initializers);
163 
164         // The AST transformation which adds the expression to select the viewport index should
165         // be done only for the GLSL and ESSL output.
166         const bool selectView = (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0;
167         // Assert that if the view is selected in the vertex shader, then the output is
168         // either GLSL or ESSL.
169         ASSERT(!selectView || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput));
170         if (selectView)
171         {
172             // Add a uniform to switch between side-by-side and layered rendering.
173             const TType *baseLayerIndexVariableType =
174                 StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
175             const TVariable *multiviewBaseViewLayerIndex =
176                 new TVariable(symbolTable, kMultiviewBaseViewLayerIndexVariableName,
177                               baseLayerIndexVariableType, SymbolType::AngleInternal);
178             DeclareGlobalVariable(root, multiviewBaseViewLayerIndex);
179 
180             // Setting a value to gl_ViewportIndex or gl_Layer should happen after ViewID_OVR's
181             // initialization.
182             SelectViewIndexInVertexShader(viewID, multiviewBaseViewLayerIndex, &initializers,
183                                           *symbolTable);
184         }
185 
186         // Insert initializers at the beginning of main().
187         TIntermBlock *initializersBlock = new TIntermBlock();
188         initializersBlock->getSequence()->swap(initializers);
189         TIntermBlock *mainBody = FindMainBody(root);
190         mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initializersBlock);
191     }
192 
193     return compiler->validateAST(root);
194 }
195 
196 }  // namespace sh
197