1e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com//
2e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
3e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com// Use of this source code is governed by a BSD-style license that can be
4e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com// found in the LICENSE file.
5e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com//
6e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com// Contains analysis utilities for dealing with HLSL's lack of support for
7e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com// the use of intrinsic functions which (implicitly or explicitly) compute
8e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com// gradients of functions with discontinuities.
9e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com//
10e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com
11dcefb75e81f3eec28fb1d2d3b3847682659e7378Geoff Lang#include "compiler/translator/DetectDiscontinuity.h"
12e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com
13dcefb75e81f3eec28fb1d2d3b3847682659e7378Geoff Lang#include "compiler/translator/ParseContext.h"
1479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
15e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.comnamespace sh
16e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com{
1779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.combool DetectLoopDiscontinuity::traverse(TIntermNode *node)
18e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com{
19e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    mLoopDepth = 0;
2079744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    mLoopDiscontinuity = false;
21e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com    node->traverse(this);
2279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    return mLoopDiscontinuity;
23e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com}
24e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com
25e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.combool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop)
26e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com{
27e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    if (visit == PreVisit)
28e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    {
29e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com        ++mLoopDepth;
30e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    }
31e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    else if (visit == PostVisit)
32e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    {
33e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com        --mLoopDepth;
34e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    }
35e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com
36e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    return true;
37e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com}
38e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com
3979744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.combool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
40e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com{
4179744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    if (mLoopDiscontinuity)
4279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    {
4379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        return false;
4479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    }
4579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
46e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    if (!mLoopDepth)
47e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    {
48e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com        return true;
49e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com    }
50e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com
51e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com    switch (node->getFlowOp())
52e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com    {
53e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com      case EOpKill:
54e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com        break;
55e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com      case EOpBreak:
56e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com      case EOpContinue:
57e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com      case EOpReturn:
58e91615cb0765069a6317c84787e10d9ecd7b2359shannon.woods@transgaming.com        mLoopDiscontinuity = true;
59e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com        break;
60e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com      default: UNREACHABLE();
61e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com    }
62e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com
6379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    return !mLoopDiscontinuity;
6479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com}
6579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
6679744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.combool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)
6779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com{
6879744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    return !mLoopDiscontinuity;
6979744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com}
7079744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
7179744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.combool containsLoopDiscontinuity(TIntermNode *node)
7279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com{
7379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    DetectLoopDiscontinuity detectLoopDiscontinuity;
7479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    return detectLoopDiscontinuity.traverse(node);
7579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com}
7679744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
7779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.combool DetectGradientOperation::traverse(TIntermNode *node)
7879744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com{
7979744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    mGradientOperation = false;
8079744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    node->traverse(this);
8179744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    return mGradientOperation;
8279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com}
8379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
8479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.combool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node)
8579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com{
8679744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    if (mGradientOperation)
8779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    {
8879744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        return false;
8979744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    }
9079744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
9179744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    switch (node->getOp())
9279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    {
9379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com      case EOpDFdx:
9479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com      case EOpDFdy:
9579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        mGradientOperation = true;
9679744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com      default:
9779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        break;
9879744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    }
9979744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
10079744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    return !mGradientOperation;
10179744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com}
10279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
10379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.combool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node)
10479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com{
10579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    if (mGradientOperation)
10679744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    {
10779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        return false;
10879744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    }
10979744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
11079744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    if (node->getOp() == EOpFunctionCall)
11179744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    {
11279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        if (!node->isUserDefined())
11379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        {
11479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com            TString name = TFunction::unmangleName(node->getName());
11579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
11679744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com            if (name == "texture2D" ||
11779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com                name == "texture2DProj" ||
11879744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com                name == "textureCube")
11979744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com            {
12079744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com                mGradientOperation = true;
12179744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com            }
12279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        }
12379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        else
12479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        {
12579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com            // When a user defined function is called, we have to
12679744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com            // conservatively assume it to contain gradient operations
12779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com            mGradientOperation = true;
12879744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com        }
12979744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    }
13079744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
13179744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    return !mGradientOperation;
13279744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com}
13379744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com
13479744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.combool containsGradientOperation(TIntermNode *node)
13579744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com{
13679744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    DetectGradientOperation detectGradientOperation;
13779744f226551bae5dfa69bc5588311d7100ef991daniel@transgaming.com    return detectGradientOperation.traverse(node);
138e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com}
139e209564280f9733853b2b0a9c8e8467af20ce05bdaniel@transgaming.com}
140