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