Hash :
dee4d7a5
Author :
Date :
2020-04-10T10:22:56
Vulkan: Early fragment tests optimization Checks if early fragment tests as an optimization is feasible and enable it if we can. In the link time, if context state diagrees with optimization (in rare case), then remove the ExecutionModeEarlyFragmentTests sprv op code. Bug: angleproject:4508 Change-Id: Ifbb06c0ffb050a9f3ddb16ab50362e908b4b9cf6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2136490 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: Tim Van Patten <timvp@google.com> Reviewed-by: Courtney Goeltzenleuchter <courtneygo@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
//
// Copyright 2020 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.
//
// CheckEarlyFragmentTestOptimization is an AST traverser to check if early fragment
// test as an optimization is feasible.
//
#include "compiler/translator/tree_ops/EarlyFragmentTestsOptimization.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/Symbol.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
// Traverser that check conditions that would prevent early fragment tests optmization.
class CheckEFTOptimizationTraverser : public TIntermTraverser
{
public:
CheckEFTOptimizationTraverser();
void visitSymbol(TIntermSymbol *node) override;
bool visitBranch(Visit visit, TIntermBranch *node) override;
bool isFragDepthUsed() { return mFragDepthUsed; }
bool isDiscardOpUsed() { return mDiscardOpUsed; }
protected:
bool mFragDepthUsed;
bool mDiscardOpUsed;
};
CheckEFTOptimizationTraverser::CheckEFTOptimizationTraverser()
: TIntermTraverser(true, false, false), mFragDepthUsed(false), mDiscardOpUsed(false)
{}
void CheckEFTOptimizationTraverser::visitSymbol(TIntermSymbol *node)
{
// Check the qualifier from the variable, not from the symbol node. The node may have a
// different qualifier if it's the result of a folded ternary node.
TQualifier qualifier = node->variable().getType().getQualifier();
if (qualifier == EvqFragDepth || qualifier == EvqFragDepthEXT)
{
mFragDepthUsed = true;
}
}
bool CheckEFTOptimizationTraverser::visitBranch(Visit visit, TIntermBranch *node)
{
if (node->getFlowOp() == EOpKill)
{
mDiscardOpUsed = true;
}
return true;
}
} // namespace
bool CheckEarlyFragmentTestsFeasible(TCompiler *compiler, TIntermNode *root)
{
CheckEFTOptimizationTraverser traverser;
root->traverse(&traverser);
if (traverser.isFragDepthUsed() || traverser.isDiscardOpUsed())
{
return false;
}
return true;
}
} // namespace sh