DeclareAndInitBuiltinsForInstancedMultiview.cpp (9450B)
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. 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 // 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. 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 126 bool DeclareAndInitBuiltinsForInstancedMultiview(TCompiler *compiler, 127 TIntermBlock *root, 128 unsigned numberOfViews, 129 GLenum shaderType, 130 const 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.selectViewInNvGLSLVertexShader; 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