1//
2// Copyright (c) 2012 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// Contains analysis utilities for dealing with HLSL's lack of support for
7// the use of intrinsic functions which (implicitly or explicitly) compute
8// gradients of functions with discontinuities.
9//
10
11#include "compiler/translator/DetectDiscontinuity.h"
12
13#include "compiler/translator/ParseContext.h"
14
15namespace sh
16{
17bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
18{
19    mLoopDepth = 0;
20    mLoopDiscontinuity = false;
21    node->traverse(this);
22    return mLoopDiscontinuity;
23}
24
25bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop)
26{
27    if (visit == PreVisit)
28    {
29        ++mLoopDepth;
30    }
31    else if (visit == PostVisit)
32    {
33        --mLoopDepth;
34    }
35
36    return true;
37}
38
39bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
40{
41    if (mLoopDiscontinuity)
42    {
43        return false;
44    }
45
46    if (!mLoopDepth)
47    {
48        return true;
49    }
50
51    switch (node->getFlowOp())
52    {
53      case EOpKill:
54        break;
55      case EOpBreak:
56      case EOpContinue:
57      case EOpReturn:
58        mLoopDiscontinuity = true;
59        break;
60      default: UNREACHABLE();
61    }
62
63    return !mLoopDiscontinuity;
64}
65
66bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)
67{
68    return !mLoopDiscontinuity;
69}
70
71bool containsLoopDiscontinuity(TIntermNode *node)
72{
73    DetectLoopDiscontinuity detectLoopDiscontinuity;
74    return detectLoopDiscontinuity.traverse(node);
75}
76
77bool DetectGradientOperation::traverse(TIntermNode *node)
78{
79    mGradientOperation = false;
80    node->traverse(this);
81    return mGradientOperation;
82}
83
84bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node)
85{
86    if (mGradientOperation)
87    {
88        return false;
89    }
90
91    switch (node->getOp())
92    {
93      case EOpDFdx:
94      case EOpDFdy:
95        mGradientOperation = true;
96      default:
97        break;
98    }
99
100    return !mGradientOperation;
101}
102
103bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node)
104{
105    if (mGradientOperation)
106    {
107        return false;
108    }
109
110    if (node->getOp() == EOpFunctionCall)
111    {
112        if (!node->isUserDefined())
113        {
114            TString name = TFunction::unmangleName(node->getName());
115
116            if (name == "texture2D" ||
117                name == "texture2DProj" ||
118                name == "textureCube")
119            {
120                mGradientOperation = true;
121            }
122        }
123        else
124        {
125            // When a user defined function is called, we have to
126            // conservatively assume it to contain gradient operations
127            mGradientOperation = true;
128        }
129    }
130
131    return !mGradientOperation;
132}
133
134bool containsGradientOperation(TIntermNode *node)
135{
136    DetectGradientOperation detectGradientOperation;
137    return detectGradientOperation.traverse(node);
138}
139}
140