| // | |
| // 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) | |
| { | |
| mLoopDepth = 0; | |
| mLoopDiscontinuity = false; | |
| node->traverse(this); | |
| return mLoopDiscontinuity; | |
| } | |
| bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop) | |
| { | |
| if (visit == PreVisit) | |
| { | |
| ++mLoopDepth; | |
| } | |
| else if (visit == PostVisit) | |
| { | |
| --mLoopDepth; | |
| } | |
| return true; | |
| } | |
| bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node) | |
| { | |
| if (mLoopDiscontinuity) | |
| { | |
| return false; | |
| } | |
| if (!mLoopDepth) | |
| { | |
| return true; | |
| } | |
| switch (node->getFlowOp()) | |
| { | |
| case EOpKill: | |
| break; | |
| case EOpBreak: | |
| case EOpContinue: | |
| case EOpReturn: | |
| mLoopDiscontinuity = true; | |
| 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); | |
| } | |
| } |