diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.cpp | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.cpp')
-rw-r--r-- | gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.cpp | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.cpp new file mode 100644 index 0000000000..a5e20ebcb0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.cpp @@ -0,0 +1,209 @@ +// +// Copyright 2019 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. +// +// RemoveInactiveInterfaceVariables.h: +// Drop shader interface variable declarations for those that are inactive. +// + +#include "compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h" + +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +// Traverser that removes all declarations that correspond to inactive variables. +class RemoveInactiveInterfaceVariablesTraverser : public TIntermTraverser +{ + public: + RemoveInactiveInterfaceVariablesTraverser( + TSymbolTable *symbolTable, + const std::vector<sh::ShaderVariable> &attributes, + const std::vector<sh::ShaderVariable> &inputVaryings, + const std::vector<sh::ShaderVariable> &outputVariables, + const std::vector<sh::ShaderVariable> &uniforms, + const std::vector<sh::InterfaceBlock> &interfaceBlocks, + bool removeFragmentOutputs); + + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + + private: + const std::vector<sh::ShaderVariable> &mAttributes; + const std::vector<sh::ShaderVariable> &mInputVaryings; + const std::vector<sh::ShaderVariable> &mOutputVariables; + const std::vector<sh::ShaderVariable> &mUniforms; + const std::vector<sh::InterfaceBlock> &mInterfaceBlocks; + bool mRemoveFragmentOutputs; +}; + +RemoveInactiveInterfaceVariablesTraverser::RemoveInactiveInterfaceVariablesTraverser( + TSymbolTable *symbolTable, + const std::vector<sh::ShaderVariable> &attributes, + const std::vector<sh::ShaderVariable> &inputVaryings, + const std::vector<sh::ShaderVariable> &outputVariables, + const std::vector<sh::ShaderVariable> &uniforms, + const std::vector<sh::InterfaceBlock> &interfaceBlocks, + bool removeFragmentOutputs) + : TIntermTraverser(true, false, false, symbolTable), + mAttributes(attributes), + mInputVaryings(inputVaryings), + mOutputVariables(outputVariables), + mUniforms(uniforms), + mInterfaceBlocks(interfaceBlocks), + mRemoveFragmentOutputs(removeFragmentOutputs) +{} + +template <typename Variable> +bool IsVariableActive(const std::vector<Variable> &mVars, const ImmutableString &name) +{ + for (const Variable &var : mVars) + { + if (name == var.name) + { + return var.active; + } + } + UNREACHABLE(); + return true; +} + +bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit, + TIntermDeclaration *node) +{ + // SeparateDeclarations should have already been run. + ASSERT(node->getSequence()->size() == 1u); + + TIntermTyped *declarator = node->getSequence()->front()->getAsTyped(); + ASSERT(declarator); + + TIntermSymbol *asSymbol = declarator->getAsSymbolNode(); + if (!asSymbol) + { + return false; + } + + const TType &type = declarator->getType(); + + // Remove all shader interface variables except outputs, i.e. uniforms, interface blocks and + // inputs. + // + // Imagine a situation where the VS doesn't write to a varying but the FS reads from it. This + // is allowed, though the value of the varying is undefined. If the varying is removed here, + // the situation is changed to VS not declaring the varying, but the FS reading from it, which + // is not allowed. That's why inactive shader outputs are not removed. + // + // Inactive fragment shader outputs can be removed though, as there is no next stage. + bool removeDeclaration = false; + const TQualifier qualifier = type.getQualifier(); + + if (type.isInterfaceBlock()) + { + // When a member has an explicit location, interface block should not be removed. + // If the member or interface would be removed, GetProgramResource could not return the + // location. + if (!IsShaderIoBlock(type.getQualifier()) && type.getQualifier() != EvqPatchIn && + type.getQualifier() != EvqPatchOut) + { + removeDeclaration = + !IsVariableActive(mInterfaceBlocks, type.getInterfaceBlock()->name()); + } + } + else if (qualifier == EvqUniform) + { + removeDeclaration = !IsVariableActive(mUniforms, asSymbol->getName()); + } + else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) + { + removeDeclaration = !IsVariableActive(mAttributes, asSymbol->getName()); + } + else if (IsShaderIn(qualifier)) + { + removeDeclaration = !IsVariableActive(mInputVaryings, asSymbol->getName()); + } + else if (qualifier == EvqFragmentOut) + { + removeDeclaration = + !IsVariableActive(mOutputVariables, asSymbol->getName()) && mRemoveFragmentOutputs; + } + + if (removeDeclaration) + { + TIntermSequence replacement; + + // If the declaration was of a struct, keep the struct declaration itself. + if (type.isStructSpecifier()) + { + TType *structSpecifierType = new TType(type.getStruct(), true); + TVariable *emptyVariable = new TVariable(mSymbolTable, kEmptyImmutableString, + structSpecifierType, SymbolType::Empty); + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->appendDeclarator(new TIntermSymbol(emptyVariable)); + replacement.push_back(declaration); + } + + mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, + std::move(replacement)); + } + + return false; +} + +bool RemoveInactiveInterfaceVariablesTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + // Remove any code that initOutputVariables might have added corresponding to inactive + // output variables. This code is always in the form of `variable = ...;`. + if (node->getOp() != EOpAssign) + { + // Don't recurse, won't find the initialization nested in another expression. + return false; + } + + // Get the symbol being initialized, and check if it's an inactive output. If it is, this must + // necessarily be initialization code that ANGLE has added (and wasn't there in the original + // shader; if it was, the symbol wouldn't have been inactive). + TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode(); + if (symbol == nullptr) + { + return false; + } + + const TQualifier qualifier = symbol->getType().getQualifier(); + if (qualifier != EvqFragmentOut || IsVariableActive(mOutputVariables, symbol->getName())) + { + return false; + } + + // Drop the initialization code. + TIntermSequence replacement; + mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, std::move(replacement)); + return false; +} + +} // namespace + +bool RemoveInactiveInterfaceVariables(TCompiler *compiler, + TIntermBlock *root, + TSymbolTable *symbolTable, + const std::vector<sh::ShaderVariable> &attributes, + const std::vector<sh::ShaderVariable> &inputVaryings, + const std::vector<sh::ShaderVariable> &outputVariables, + const std::vector<sh::ShaderVariable> &uniforms, + const std::vector<sh::InterfaceBlock> &interfaceBlocks, + bool removeFragmentOutputs) +{ + RemoveInactiveInterfaceVariablesTraverser traverser(symbolTable, attributes, inputVaryings, + outputVariables, uniforms, interfaceBlocks, + removeFragmentOutputs); + root->traverse(&traverser); + return traverser.updateTree(compiler, root); +} + +} // namespace sh |