| // |
| // Copyright 2022 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. |
| // |
| // GuardFragDepthWrite: Guards use of frag depth behind the function constant |
| // ANGLEDepthWriteEnabled to ensure it is only used when a valid depth buffer |
| // is bound. |
| |
| #include "compiler/translator/TranslatorMetalDirect/GuardFragDepthWrite.h" |
| #include "compiler/translator/TranslatorMetalDirect/AstHelpers.h" |
| #include "compiler/translator/tree_util/BuiltIn.h" |
| #include "compiler/translator/tree_util/IntermRebuild.h" |
| |
| using namespace sh; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| namespace |
| { |
| |
| class Rewriter : public TIntermRebuild |
| { |
| public: |
| Rewriter(TCompiler &compiler) : TIntermRebuild(compiler, false, true) {} |
| |
| PostResult visitBinaryPost(TIntermBinary &node) override |
| { |
| if (TIntermSymbol *leftSymbolNode = node.getLeft()->getAsSymbolNode()) |
| { |
| if (leftSymbolNode->getType().getQualifier() == TQualifier::EvqFragDepth) |
| { |
| // This transformation leaves the tree in an inconsistent state by using a variable |
| // that's defined in text, outside of the knowledge of the AST. |
| // FIXME(jcunningham): remove once function constants (specconst) are implemented |
| // with the metal translator. |
| mCompiler.disableValidateVariableReferences(); |
| |
| TSymbolTable *symbolTable = &mCompiler.getSymbolTable(); |
| |
| // Create kDepthWriteEnabled variable reference. |
| TType *boolType = new TType(EbtBool); |
| boolType->setQualifier(EvqConst); |
| TVariable *depthWriteEnabledVar = new TVariable( |
| symbolTable, sh::ImmutableString(sh::mtl::kDepthWriteEnabledConstName), |
| boolType, SymbolType::AngleInternal); |
| |
| TIntermBlock *innerif = new TIntermBlock; |
| innerif->appendStatement(&node); |
| |
| TIntermSymbol *depthWriteEnabled = new TIntermSymbol(depthWriteEnabledVar); |
| TIntermIfElse *ifCall = new TIntermIfElse(depthWriteEnabled, innerif, nullptr); |
| return ifCall; |
| } |
| } |
| |
| return node; |
| } |
| }; |
| |
| } // anonymous namespace |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| bool sh::GuardFragDepthWrite(TCompiler &compiler, TIntermBlock &root) |
| { |
| Rewriter rewriter(compiler); |
| if (!rewriter.rebuildRoot(root)) |
| { |
| return false; |
| } |
| return true; |
| } |