summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp
blob: 472232a75d2567171bfb4f708bb28960ae5ab181 (plain)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//
// Copyright (c) 2012 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.
//
// Contains analysis utilities for dealing with HLSL's lack of support for
// the use of intrinsic functions which (implicitly or explicitly) compute
// gradients of functions with discontinuities. 
//

#include "compiler/DetectDiscontinuity.h"

#include "compiler/ParseHelper.h"

namespace sh
{
bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
{
    mLoopDiscontinuity = false;
    node->traverse(this);
    return mLoopDiscontinuity;
}

bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
{
    if (mLoopDiscontinuity)
    {
        return false;
    }

    switch (node->getFlowOp())
    {
      case EOpKill:
        break;
      case EOpBreak:
      case EOpContinue:
        mLoopDiscontinuity = true;
      case EOpReturn:
        break;
      default: UNREACHABLE();
    }

    return !mLoopDiscontinuity;
}

bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)
{
    return !mLoopDiscontinuity;
}

bool containsLoopDiscontinuity(TIntermNode *node)
{
    DetectLoopDiscontinuity detectLoopDiscontinuity;
    return detectLoopDiscontinuity.traverse(node);
}

bool DetectGradientOperation::traverse(TIntermNode *node)
{
    mGradientOperation = false;
    node->traverse(this);
    return mGradientOperation;
}

bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node)
{
    if (mGradientOperation)
    {
        return false;
    }

    switch (node->getOp())
    {
      case EOpDFdx:
      case EOpDFdy:
        mGradientOperation = true;
      default:
        break;
    }

    return !mGradientOperation;
}

bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node)
{
    if (mGradientOperation)
    {
        return false;
    }

    if (node->getOp() == EOpFunctionCall)
    {
        if (!node->isUserDefined())
        {
            TString name = TFunction::unmangleName(node->getName());

            if (name == "texture2D" ||
                name == "texture2DProj" ||
                name == "textureCube")
            {
                mGradientOperation = true;
            }
        }
        else
        {
            // When a user defined function is called, we have to
            // conservatively assume it to contain gradient operations
            mGradientOperation = true;
        }
    }

    return !mGradientOperation;
}

bool containsGradientOperation(TIntermNode *node)
{
    DetectGradientOperation detectGradientOperation;
    return detectGradientOperation.traverse(node);
}
}