1 //
2 // Copyright 2022 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 // GuardFragDepthWrite: Guards use of frag depth behind the function constant
7 // ANGLEDepthWriteEnabled to ensure it is only used when a valid depth buffer
8 // is bound.
9
10 #include "compiler/translator/tree_ops/msl/GuardFragDepthWrite.h"
11 #include "compiler/translator/IntermRebuild.h"
12 #include "compiler/translator/msl/AstHelpers.h"
13 #include "compiler/translator/tree_util/BuiltIn.h"
14
15 using namespace sh;
16
17 ////////////////////////////////////////////////////////////////////////////////
18
19 namespace
20 {
21
22 class Rewriter : public TIntermRebuild
23 {
24 public:
Rewriter(TCompiler & compiler)25 Rewriter(TCompiler &compiler) : TIntermRebuild(compiler, false, true) {}
26
visitBinaryPost(TIntermBinary & node)27 PostResult visitBinaryPost(TIntermBinary &node) override
28 {
29 if (TIntermSymbol *leftSymbolNode = node.getLeft()->getAsSymbolNode())
30 {
31 if (leftSymbolNode->getType().getQualifier() == TQualifier::EvqFragDepth)
32 {
33 // This transformation leaves the tree in an inconsistent state by using a variable
34 // that's defined in text, outside of the knowledge of the AST.
35 // FIXME(jcunningham): remove once function constants (specconst) are implemented
36 // with the metal translator.
37 mCompiler.disableValidateVariableReferences();
38
39 TSymbolTable *symbolTable = &mCompiler.getSymbolTable();
40
41 // Create kDepthWriteEnabled variable reference.
42 TType *boolType = new TType(EbtBool);
43 boolType->setQualifier(EvqConst);
44 TVariable *depthWriteEnabledVar = new TVariable(
45 symbolTable, sh::ImmutableString(sh::mtl::kDepthWriteEnabledConstName),
46 boolType, SymbolType::AngleInternal);
47
48 TIntermBlock *innerif = new TIntermBlock;
49 innerif->appendStatement(&node);
50
51 TIntermSymbol *depthWriteEnabled = new TIntermSymbol(depthWriteEnabledVar);
52 TIntermIfElse *ifCall = new TIntermIfElse(depthWriteEnabled, innerif, nullptr);
53 return ifCall;
54 }
55 }
56
57 return node;
58 }
59 };
60
61 } // anonymous namespace
62
63 ////////////////////////////////////////////////////////////////////////////////
64
GuardFragDepthWrite(TCompiler & compiler,TIntermBlock & root)65 bool sh::GuardFragDepthWrite(TCompiler &compiler, TIntermBlock &root)
66 {
67 Rewriter rewriter(compiler);
68 if (!rewriter.rebuildRoot(root))
69 {
70 return false;
71 }
72 return true;
73 }
74