Added a traverser for detecting gradient operations.

TRAC #20737
Signed-off-by: Daniel Koch
Author: Nicolas Capens

git-svn-id: https://angleproject.googlecode.com/svn/trunk@1121 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/DetectDiscontinuity.cpp b/src/compiler/DetectDiscontinuity.cpp
index 0d28e4b..472232a 100644
--- a/src/compiler/DetectDiscontinuity.cpp
+++ b/src/compiler/DetectDiscontinuity.cpp
@@ -10,29 +10,110 @@
 
 #include "compiler/DetectDiscontinuity.h"
 
+#include "compiler/ParseHelper.h"
+
 namespace sh
 {
-bool DetectDiscontinuity::traverse(TIntermNode *node)
+bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
 {
-    mDiscontinuity = false;
+    mLoopDiscontinuity = false;
     node->traverse(this);
-    return mDiscontinuity;
+    return mLoopDiscontinuity;
 }
 
-bool DetectDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
+bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
 {
+    if (mLoopDiscontinuity)
+    {
+        return false;
+    }
+
     switch (node->getFlowOp())
     {
       case EOpKill:
         break;
       case EOpBreak:
       case EOpContinue:
-        mDiscontinuity = true;
+        mLoopDiscontinuity = true;
       case EOpReturn:
         break;
       default: UNREACHABLE();
     }
 
-    return !mDiscontinuity;
+    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);
 }
 }