michael@0: // michael@0: // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: // Contains analysis utilities for dealing with HLSL's lack of support for michael@0: // the use of intrinsic functions which (implicitly or explicitly) compute michael@0: // gradients of functions with discontinuities. michael@0: // michael@0: michael@0: #include "compiler/DetectDiscontinuity.h" michael@0: michael@0: #include "compiler/ParseHelper.h" michael@0: michael@0: namespace sh michael@0: { michael@0: bool DetectLoopDiscontinuity::traverse(TIntermNode *node) michael@0: { michael@0: mLoopDepth = 0; michael@0: mLoopDiscontinuity = false; michael@0: node->traverse(this); michael@0: return mLoopDiscontinuity; michael@0: } michael@0: michael@0: bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop) michael@0: { michael@0: if (visit == PreVisit) michael@0: { michael@0: ++mLoopDepth; michael@0: } michael@0: else if (visit == PostVisit) michael@0: { michael@0: --mLoopDepth; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node) michael@0: { michael@0: if (mLoopDiscontinuity) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (!mLoopDepth) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: switch (node->getFlowOp()) michael@0: { michael@0: case EOpKill: michael@0: break; michael@0: case EOpBreak: michael@0: case EOpContinue: michael@0: case EOpReturn: michael@0: mLoopDiscontinuity = true; michael@0: break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: michael@0: return !mLoopDiscontinuity; michael@0: } michael@0: michael@0: bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node) michael@0: { michael@0: return !mLoopDiscontinuity; michael@0: } michael@0: michael@0: bool containsLoopDiscontinuity(TIntermNode *node) michael@0: { michael@0: DetectLoopDiscontinuity detectLoopDiscontinuity; michael@0: return detectLoopDiscontinuity.traverse(node); michael@0: } michael@0: michael@0: bool DetectGradientOperation::traverse(TIntermNode *node) michael@0: { michael@0: mGradientOperation = false; michael@0: node->traverse(this); michael@0: return mGradientOperation; michael@0: } michael@0: michael@0: bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node) michael@0: { michael@0: if (mGradientOperation) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: switch (node->getOp()) michael@0: { michael@0: case EOpDFdx: michael@0: case EOpDFdy: michael@0: mGradientOperation = true; michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: return !mGradientOperation; michael@0: } michael@0: michael@0: bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node) michael@0: { michael@0: if (mGradientOperation) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (node->getOp() == EOpFunctionCall) michael@0: { michael@0: if (!node->isUserDefined()) michael@0: { michael@0: TString name = TFunction::unmangleName(node->getName()); michael@0: michael@0: if (name == "texture2D" || michael@0: name == "texture2DProj" || michael@0: name == "textureCube") michael@0: { michael@0: mGradientOperation = true; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: // When a user defined function is called, we have to michael@0: // conservatively assume it to contain gradient operations michael@0: mGradientOperation = true; michael@0: } michael@0: } michael@0: michael@0: return !mGradientOperation; michael@0: } michael@0: michael@0: bool containsGradientOperation(TIntermNode *node) michael@0: { michael@0: DetectGradientOperation detectGradientOperation; michael@0: return detectGradientOperation.traverse(node); michael@0: } michael@0: }