diff options
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp')
-rw-r--r-- | src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp b/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp new file mode 100644 index 0000000000..ce9828f1f9 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp @@ -0,0 +1,221 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Applies the necessary AST transformations to support multiview rendering through instancing. +// Check the header file For more information. +// + +#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h" + +#include "compiler/translator/FindMain.h" +#include "compiler/translator/InitializeVariables.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +class ReplaceVariableTraverser : public TIntermTraverser +{ + public: + ReplaceVariableTraverser(const TString &symbolName, TIntermSymbol *newSymbol) + : TIntermTraverser(true, false, false), mSymbolName(symbolName), mNewSymbol(newSymbol) + { + } + + void visitSymbol(TIntermSymbol *node) override + { + TName &name = node->getName(); + if (name.getString() == mSymbolName) + { + queueReplacement(mNewSymbol->deepCopy(), OriginalNode::IS_DROPPED); + } + } + + private: + TString mSymbolName; + TIntermSymbol *mNewSymbol; +}; + +TIntermSymbol *CreateGLInstanceIDSymbol(const TSymbolTable &symbolTable) +{ + return ReferenceBuiltInVariable("gl_InstanceID", symbolTable, 300); +} + +// Adds the InstanceID and ViewID_OVR initializers to the end of the initializers' sequence. +void InitializeViewIDAndInstanceID(TIntermTyped *viewIDSymbol, + TIntermTyped *instanceIDSymbol, + unsigned numberOfViews, + const TSymbolTable &symbolTable, + TIntermSequence *initializers) +{ + // Create an unsigned numberOfViews node. + TConstantUnion *numberOfViewsUnsignedConstant = new TConstantUnion(); + numberOfViewsUnsignedConstant->setUConst(numberOfViews); + TIntermConstantUnion *numberOfViewsUint = + new TIntermConstantUnion(numberOfViewsUnsignedConstant, TType(EbtUInt, EbpHigh, EvqConst)); + + // Create a uint(gl_InstanceID) node. + TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence(); + glInstanceIDSymbolCastArguments->push_back(CreateGLInstanceIDSymbol(symbolTable)); + TIntermAggregate *glInstanceIDAsUint = TIntermAggregate::CreateConstructor( + TType(EbtUInt, EbpHigh, EvqTemporary), glInstanceIDSymbolCastArguments); + + // Create a uint(gl_InstanceID) / numberOfViews node. + TIntermBinary *normalizedInstanceID = + new TIntermBinary(EOpDiv, glInstanceIDAsUint, numberOfViewsUint); + + // Create an int(uint(gl_InstanceID) / numberOfViews) node. + TIntermSequence *normalizedInstanceIDCastArguments = new TIntermSequence(); + normalizedInstanceIDCastArguments->push_back(normalizedInstanceID); + TIntermAggregate *normalizedInstanceIDAsInt = TIntermAggregate::CreateConstructor( + TType(EbtInt, EbpHigh, EvqTemporary), normalizedInstanceIDCastArguments); + + // Create an InstanceID = int(uint(gl_InstanceID) / numberOfViews) node. + TIntermBinary *instanceIDInitializer = + new TIntermBinary(EOpAssign, instanceIDSymbol->deepCopy(), normalizedInstanceIDAsInt); + initializers->push_back(instanceIDInitializer); + + // Create a uint(gl_InstanceID) % numberOfViews node. + TIntermBinary *normalizedViewID = + new TIntermBinary(EOpIMod, glInstanceIDAsUint->deepCopy(), numberOfViewsUint->deepCopy()); + + // Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node. + TIntermBinary *viewIDInitializer = + new TIntermBinary(EOpAssign, viewIDSymbol->deepCopy(), normalizedViewID); + initializers->push_back(viewIDInitializer); +} + +// Replaces every occurrence of a symbol with the name specified in symbolName with newSymbolNode. +void ReplaceSymbol(TIntermBlock *root, const TString &symbolName, TIntermSymbol *newSymbolNode) +{ + ReplaceVariableTraverser traverser(symbolName, newSymbolNode); + root->traverse(&traverser); + traverser.updateTree(); +} + +void DeclareGlobalVariable(TIntermBlock *root, TIntermTyped *typedNode) +{ + TIntermSequence *globalSequence = root->getSequence(); + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->appendDeclarator(typedNode->deepCopy()); + globalSequence->insert(globalSequence->begin(), declaration); +} + +// Adds a branch to write int(ViewID_OVR) to either gl_ViewportIndex or gl_Layer. The branch is +// added to the end of the initializers' sequence. +void SelectViewIndexInVertexShader(TIntermTyped *viewIDSymbol, + TIntermTyped *multiviewBaseViewLayerIndexSymbol, + TIntermSequence *initializers, + const TSymbolTable &symbolTable) +{ + // Create an int(ViewID_OVR) node. + TIntermSequence *viewIDSymbolCastArguments = new TIntermSequence(); + viewIDSymbolCastArguments->push_back(viewIDSymbol); + TIntermAggregate *viewIDAsInt = TIntermAggregate::CreateConstructor( + TType(EbtInt, EbpHigh, EvqTemporary), viewIDSymbolCastArguments); + + // Create a gl_ViewportIndex node. + TIntermSymbol *viewportIndexSymbol = + ReferenceBuiltInVariable("gl_ViewportIndex", symbolTable, 0); + + // Create a { gl_ViewportIndex = int(ViewID_OVR) } node. + TIntermBlock *viewportIndexInitializerInBlock = new TIntermBlock(); + viewportIndexInitializerInBlock->appendStatement( + new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt)); + + // Create a gl_Layer node. + TIntermSymbol *layerSymbol = ReferenceBuiltInVariable("gl_Layer", symbolTable, 0); + + // Create an int(ViewID_OVR) + multiviewBaseViewLayerIndex node + TIntermBinary *sumOfViewIDAndBaseViewIndex = + new TIntermBinary(EOpAdd, viewIDAsInt->deepCopy(), multiviewBaseViewLayerIndexSymbol); + + // Create a { gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex } node. + TIntermBlock *layerInitializerInBlock = new TIntermBlock(); + layerInitializerInBlock->appendStatement( + new TIntermBinary(EOpAssign, layerSymbol, sumOfViewIDAndBaseViewIndex)); + + // Create a node to compare whether the base view index uniform is less than zero. + TIntermBinary *multiviewBaseViewLayerIndexZeroComparison = + new TIntermBinary(EOpLessThan, multiviewBaseViewLayerIndexSymbol->deepCopy(), + CreateZeroNode(TType(EbtInt, EbpHigh, EvqConst))); + + // Create an if-else statement to select the code path. + TIntermIfElse *multiviewBranch = + new TIntermIfElse(multiviewBaseViewLayerIndexZeroComparison, + viewportIndexInitializerInBlock, layerInitializerInBlock); + + initializers->push_back(multiviewBranch); +} + +} // namespace + +void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, + unsigned numberOfViews, + GLenum shaderType, + ShCompileOptions compileOptions, + ShShaderOutput shaderOutput, + TSymbolTable *symbolTable) +{ + ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER); + + TQualifier viewIDQualifier = (shaderType == GL_VERTEX_SHADER) ? EvqFlatOut : EvqFlatIn; + TIntermSymbol *viewIDSymbol = new TIntermSymbol(symbolTable->nextUniqueId(), "ViewID_OVR", + TType(EbtUInt, EbpHigh, viewIDQualifier)); + viewIDSymbol->setInternal(true); + + DeclareGlobalVariable(root, viewIDSymbol); + ReplaceSymbol(root, "gl_ViewID_OVR", viewIDSymbol); + if (shaderType == GL_VERTEX_SHADER) + { + // Replacing gl_InstanceID with InstanceID should happen before adding the initializers of + // InstanceID and ViewID. + TIntermSymbol *instanceIDSymbol = new TIntermSymbol( + symbolTable->nextUniqueId(), "InstanceID", TType(EbtInt, EbpHigh, EvqGlobal)); + instanceIDSymbol->setInternal(true); + DeclareGlobalVariable(root, instanceIDSymbol); + ReplaceSymbol(root, "gl_InstanceID", instanceIDSymbol); + + TIntermSequence *initializers = new TIntermSequence(); + InitializeViewIDAndInstanceID(viewIDSymbol, instanceIDSymbol, numberOfViews, *symbolTable, + initializers); + + // The AST transformation which adds the expression to select the viewport index should + // be done only for the GLSL and ESSL output. + const bool selectView = (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u; + // Assert that if the view is selected in the vertex shader, then the output is + // either GLSL or ESSL. + ASSERT(!selectView || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput)); + if (selectView) + { + // Add a uniform to switch between side-by-side and layered rendering. + TIntermSymbol *multiviewBaseViewLayerIndexSymbol = + new TIntermSymbol(symbolTable->nextUniqueId(), "multiviewBaseViewLayerIndex", + TType(EbtInt, EbpHigh, EvqUniform)); + multiviewBaseViewLayerIndexSymbol->setInternal(true); + DeclareGlobalVariable(root, multiviewBaseViewLayerIndexSymbol); + + // Setting a value to gl_ViewportIndex or gl_Layer should happen after ViewID_OVR's + // initialization. + SelectViewIndexInVertexShader(viewIDSymbol->deepCopy(), + multiviewBaseViewLayerIndexSymbol->deepCopy(), + initializers, *symbolTable); + } + + // Insert initializers at the beginning of main(). + TIntermBlock *initializersBlock = new TIntermBlock(); + initializersBlock->getSequence()->swap(*initializers); + TIntermBlock *mainBody = FindMainBody(root); + mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initializersBlock); + } +} + +} // namespace sh
\ No newline at end of file |