зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1355321 - Part1: Revert "Bug 1347866 - Part2: Revert "translator: remove code related to for-loop unrolling""; r=jgilbert
This reverts commit 21a87c994f849488d7d6a143b93de9892e04f435. MozReview-Commit-ID: 8QKjAHW0vhq --HG-- extra : rebase_source : 416f2072b2414d91e6924f3b608c5f92a1a24029
This commit is contained in:
Родитель
0257b6738b
Коммит
e3eeba7caf
|
@ -75,12 +75,29 @@ const ShCompileOptions SH_OBJECT_CODE = UINT64_C(1) << 2;
|
|||
const ShCompileOptions SH_VARIABLES = UINT64_C(1) << 3;
|
||||
const ShCompileOptions SH_LINE_DIRECTIVES = UINT64_C(1) << 4;
|
||||
const ShCompileOptions SH_SOURCE_PATH = UINT64_C(1) << 5;
|
||||
const ShCompileOptions SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = UINT64_C(1) << 6;
|
||||
// If a sampler array index happens to be a loop index,
|
||||
// 1) if its type is integer, unroll the loop.
|
||||
// 2) if its type is float, fail the shader compile.
|
||||
// This is to work around a mac driver bug.
|
||||
const ShCompileOptions SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = UINT64_C(1) << 7;
|
||||
|
||||
// This flag will keep invariant declaration for input in fragment shader for GLSL >=4.20 on AMD.
|
||||
// From GLSL >= 4.20, it's optional to add invariant for fragment input, but GPU vendors have
|
||||
// different implementations about this. Some drivers forbid invariant in fragment for GLSL>= 4.20,
|
||||
// e.g. Linux Mesa, some drivers treat that as optional, e.g. NVIDIA, some drivers require invariant
|
||||
// must match between vertex and fragment shader, e.g. AMD. The behavior on AMD is obviously wrong.
|
||||
// Remove invariant for input in fragment shader to workaround the restriction on Intel Mesa.
|
||||
// But don't remove on AMD Linux to avoid triggering the bug on AMD.
|
||||
const ShCompileOptions SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT = UINT64_C(1) << 6;
|
||||
|
||||
// Due to spec difference between GLSL 4.1 or lower and ESSL3, some platforms (for example, Mac OSX
|
||||
// core profile) require a variable's "invariant"/"centroid" qualifiers to match between vertex and
|
||||
// fragment shader. A simple solution to allow such shaders to link is to omit the two qualifiers.
|
||||
// AMD driver in Linux requires invariant qualifier to match between vertex and fragment shaders,
|
||||
// while ESSL3 disallows invariant qualifier in fragment shader and GLSL >= 4.2 doesn't require
|
||||
// invariant qualifier to match between shaders. Remove invariant qualifier from vertex shader to
|
||||
// workaround AMD driver bug.
|
||||
// Note that the two flags take effect on ESSL3 input shaders translated to GLSL 4.1 or lower and to
|
||||
// GLSL 4.2 or newer on Linux AMD.
|
||||
// TODO(zmo): This is not a good long-term solution. Simply dropping these qualifiers may break some
|
||||
// developers' content. A more complex workaround of dynamically generating, compiling, and
|
||||
// re-linking shaders that use these qualifiers should be implemented.
|
||||
const ShCompileOptions SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3 = UINT64_C(1) << 7;
|
||||
|
||||
// This flag works around bug in Intel Mac drivers related to abs(i) where
|
||||
// i is an integer.
|
||||
|
@ -186,29 +203,6 @@ const ShCompileOptions SH_EMULATE_ISNAN_FLOAT_FUNCTION = UINT64_C(1) << 27;
|
|||
// layout qualifier to be considered active. The uniform block itself is also considered active.
|
||||
const ShCompileOptions SH_USE_UNUSED_STANDARD_SHARED_BLOCKS = UINT64_C(1) << 28;
|
||||
|
||||
// This flag will keep invariant declaration for input in fragment shader for GLSL >=4.20 on AMD.
|
||||
// From GLSL >= 4.20, it's optional to add invariant for fragment input, but GPU vendors have
|
||||
// different implementations about this. Some drivers forbid invariant in fragment for GLSL>= 4.20,
|
||||
// e.g. Linux Mesa, some drivers treat that as optional, e.g. NVIDIA, some drivers require invariant
|
||||
// must match between vertex and fragment shader, e.g. AMD. The behavior on AMD is obviously wrong.
|
||||
// Remove invariant for input in fragment shader to workaround the restriction on Intel Mesa.
|
||||
// But don't remove on AMD Linux to avoid triggering the bug on AMD.
|
||||
const ShCompileOptions SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT = UINT64_C(1) << 29;
|
||||
|
||||
// Due to spec difference between GLSL 4.1 or lower and ESSL3, some platforms (for example, Mac OSX
|
||||
// core profile) require a variable's "invariant"/"centroid" qualifiers to match between vertex and
|
||||
// fragment shader. A simple solution to allow such shaders to link is to omit the two qualifiers.
|
||||
// AMD driver in Linux requires invariant qualifier to match between vertex and fragment shaders,
|
||||
// while ESSL3 disallows invariant qualifier in fragment shader and GLSL >= 4.2 doesn't require
|
||||
// invariant qualifier to match between shaders. Remove invariant qualifier from vertex shader to
|
||||
// workaround AMD driver bug.
|
||||
// Note that the two flags take effect on ESSL3 input shaders translated to GLSL 4.1 or lower and to
|
||||
// GLSL 4.2 or newer on Linux AMD.
|
||||
// TODO(zmo): This is not a good long-term solution. Simply dropping these qualifiers may break some
|
||||
// developers' content. A more complex workaround of dynamically generating, compiling, and
|
||||
// re-linking shaders that use these qualifiers should be implemented.
|
||||
const ShCompileOptions SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3 = UINT64_C(1) << 30;
|
||||
|
||||
// Defines alternate strategies for implementing array index clamping.
|
||||
enum ShArrayIndexClampingStrategy
|
||||
{
|
||||
|
|
|
@ -50,7 +50,6 @@ UNIFIED_SOURCES += [
|
|||
'src/compiler/translator/ExpandIntegerPowExpressions.cpp',
|
||||
'src/compiler/translator/ExtensionGLSL.cpp',
|
||||
'src/compiler/translator/FlagStd140Structs.cpp',
|
||||
'src/compiler/translator/ForLoopUnroll.cpp',
|
||||
'src/compiler/translator/InfoSink.cpp',
|
||||
'src/compiler/translator/Initialize.cpp',
|
||||
'src/compiler/translator/InitializeDll.cpp',
|
||||
|
@ -61,7 +60,6 @@ UNIFIED_SOURCES += [
|
|||
'src/compiler/translator/IntermNodePatternMatcher.cpp',
|
||||
'src/compiler/translator/intermOut.cpp',
|
||||
'src/compiler/translator/IntermTraverse.cpp',
|
||||
'src/compiler/translator/LoopInfo.cpp',
|
||||
'src/compiler/translator/Operator.cpp',
|
||||
'src/compiler/translator/OutputESSL.cpp',
|
||||
'src/compiler/translator/OutputGLSL.cpp',
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
//
|
||||
// Copyright (c) 2014 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.
|
||||
//
|
||||
// commit.h:
|
||||
// This is a default commit hash header, when git is not available.
|
||||
//
|
||||
|
||||
#define ANGLE_COMMIT_HASH "unknown hash"
|
||||
#define ANGLE_COMMIT_HASH "dec065540d5f"
|
||||
#define ANGLE_COMMIT_HASH_SIZE 12
|
||||
#define ANGLE_COMMIT_DATE "unknown date"
|
||||
|
||||
#define ANGLE_DISABLE_PROGRAM_BINARY_LOAD
|
||||
#define ANGLE_COMMIT_DATE "2017-04-10 16:10:11 +0800"
|
||||
|
|
|
@ -54,8 +54,6 @@
|
|||
'compiler/translator/ExtensionBehavior.h',
|
||||
'compiler/translator/FlagStd140Structs.cpp',
|
||||
'compiler/translator/FlagStd140Structs.h',
|
||||
'compiler/translator/ForLoopUnroll.cpp',
|
||||
'compiler/translator/ForLoopUnroll.h',
|
||||
'compiler/translator/HashNames.h',
|
||||
'compiler/translator/InfoSink.cpp',
|
||||
'compiler/translator/InfoSink.h',
|
||||
|
@ -73,9 +71,6 @@
|
|||
'compiler/translator/IntermTraverse.cpp',
|
||||
'compiler/translator/Intermediate.h',
|
||||
'compiler/translator/Intermediate.cpp',
|
||||
'compiler/translator/LoopInfo.cpp',
|
||||
'compiler/translator/LoopInfo.h',
|
||||
'compiler/translator/MMap.h',
|
||||
'compiler/translator/NodeSearch.h',
|
||||
'compiler/translator/Operator.cpp',
|
||||
'compiler/translator/Operator.h',
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "compiler/translator/DeferGlobalInitializers.h"
|
||||
#include "compiler/translator/EmulateGLFragColorBroadcast.h"
|
||||
#include "compiler/translator/EmulatePrecision.h"
|
||||
#include "compiler/translator/ForLoopUnroll.h"
|
||||
#include "compiler/translator/Initialize.h"
|
||||
#include "compiler/translator/InitializeParseContext.h"
|
||||
#include "compiler/translator/InitializeVariables.h"
|
||||
|
@ -370,26 +369,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
|
|||
}
|
||||
}
|
||||
|
||||
// Unroll for-loop markup needs to happen after validateLimitations pass.
|
||||
if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
|
||||
{
|
||||
ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex,
|
||||
shouldRunLoopAndIndexingValidation(compileOptions));
|
||||
root->traverse(&marker);
|
||||
}
|
||||
if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
|
||||
{
|
||||
ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex,
|
||||
shouldRunLoopAndIndexingValidation(compileOptions));
|
||||
root->traverse(&marker);
|
||||
if (marker.samplerArrayIndexIsFloatLoopIndex())
|
||||
{
|
||||
infoSink.info.prefix(EPrefixError);
|
||||
infoSink.info << "sampler array index is float loop index";
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Built-in function emulation needs to happen after validateLimitations pass.
|
||||
if (success)
|
||||
{
|
||||
|
@ -506,17 +485,6 @@ bool TCompiler::compile(const char *const shaderStrings[],
|
|||
compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
|
||||
}
|
||||
|
||||
ShCompileOptions unrollFlags =
|
||||
SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX | SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
|
||||
if ((compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION) != 0 &&
|
||||
(compileOptions & unrollFlags) != 0)
|
||||
{
|
||||
infoSink.info.prefix(EPrefixError);
|
||||
infoSink.info
|
||||
<< "Unsupported compile flag combination: unroll & ADD_TRUE_TO_LOOP_CONDITION";
|
||||
return false;
|
||||
}
|
||||
|
||||
TScopedPoolAllocator scopedAlloc(&allocator);
|
||||
TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
|
||||
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2002-2013 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.
|
||||
//
|
||||
|
||||
#include "compiler/translator/ForLoopUnroll.h"
|
||||
|
||||
#include "compiler/translator/ValidateLimitations.h"
|
||||
#include "angle_gl.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node)
|
||||
{
|
||||
if (mUnrollCondition != kSamplerArrayIndex)
|
||||
return true;
|
||||
|
||||
// If a sampler array index is also the loop index,
|
||||
// 1) if the index type is integer, mark the loop for unrolling;
|
||||
// 2) if the index type if float, set a flag to later fail compile.
|
||||
switch (node->getOp())
|
||||
{
|
||||
case EOpIndexIndirect:
|
||||
if (node->getLeft() != NULL && node->getRight() != NULL && node->getLeft()->getAsSymbolNode())
|
||||
{
|
||||
TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode();
|
||||
if (IsSampler(symbol->getBasicType()) && symbol->isArray() && !mLoopStack.empty())
|
||||
{
|
||||
mVisitSamplerArrayIndexNodeInsideLoop = true;
|
||||
node->getRight()->traverse(this);
|
||||
mVisitSamplerArrayIndexNodeInsideLoop = false;
|
||||
// We have already visited all the children.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node)
|
||||
{
|
||||
bool canBeUnrolled = mHasRunLoopValidation;
|
||||
if (!mHasRunLoopValidation)
|
||||
{
|
||||
canBeUnrolled = ValidateLimitations::IsLimitedForLoop(node);
|
||||
}
|
||||
if (mUnrollCondition == kIntegerIndex && canBeUnrolled)
|
||||
{
|
||||
// Check if loop index type is integer.
|
||||
// This is called after ValidateLimitations pass, so the loop has the limited form specified
|
||||
// in ESSL 1.00 appendix A.
|
||||
TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
|
||||
TIntermSymbol *symbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
|
||||
if (symbol->getBasicType() == EbtInt)
|
||||
node->setUnrollFlag(true);
|
||||
}
|
||||
|
||||
TIntermNode *body = node->getBody();
|
||||
if (body != nullptr)
|
||||
{
|
||||
if (canBeUnrolled)
|
||||
{
|
||||
mLoopStack.push(node);
|
||||
body->traverse(this);
|
||||
mLoopStack.pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
body->traverse(this);
|
||||
}
|
||||
}
|
||||
// The loop is fully processed - no need to visit children.
|
||||
return false;
|
||||
}
|
||||
|
||||
void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol)
|
||||
{
|
||||
if (!mVisitSamplerArrayIndexNodeInsideLoop)
|
||||
return;
|
||||
TIntermLoop *loop = mLoopStack.findLoop(symbol);
|
||||
if (loop)
|
||||
{
|
||||
switch (symbol->getBasicType())
|
||||
{
|
||||
case EbtFloat:
|
||||
mSamplerArrayIndexIsFloatLoopIndex = true;
|
||||
break;
|
||||
case EbtInt:
|
||||
loop->setUnrollFlag(true);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sh
|
|
@ -1,58 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2011 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.
|
||||
//
|
||||
|
||||
#ifndef COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
|
||||
#define COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
|
||||
|
||||
#include "compiler/translator/LoopInfo.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
// This class detects for-loops that needs to be unrolled.
|
||||
// Currently we support two unroll conditions:
|
||||
// 1) kForLoopWithIntegerIndex: unroll if the index type is integer.
|
||||
// 2) kForLoopWithSamplerArrayIndex: unroll where a sampler array index
|
||||
// is also the loop integer index, and reject and fail a compile
|
||||
// where a sampler array index is also the loop float index.
|
||||
class ForLoopUnrollMarker : public TIntermTraverser
|
||||
{
|
||||
public:
|
||||
enum UnrollCondition
|
||||
{
|
||||
kIntegerIndex,
|
||||
kSamplerArrayIndex
|
||||
};
|
||||
|
||||
ForLoopUnrollMarker(UnrollCondition condition, bool hasRunLoopValidation)
|
||||
: TIntermTraverser(true, false, false),
|
||||
mUnrollCondition(condition),
|
||||
mSamplerArrayIndexIsFloatLoopIndex(false),
|
||||
mVisitSamplerArrayIndexNodeInsideLoop(false),
|
||||
mHasRunLoopValidation(hasRunLoopValidation)
|
||||
{
|
||||
}
|
||||
|
||||
bool visitBinary(Visit, TIntermBinary *node) override;
|
||||
bool visitLoop(Visit, TIntermLoop *node) override;
|
||||
void visitSymbol(TIntermSymbol *node) override;
|
||||
|
||||
bool samplerArrayIndexIsFloatLoopIndex() const
|
||||
{
|
||||
return mSamplerArrayIndexIsFloatLoopIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
UnrollCondition mUnrollCondition;
|
||||
TLoopStack mLoopStack;
|
||||
bool mSamplerArrayIndexIsFloatLoopIndex;
|
||||
bool mVisitSamplerArrayIndexNodeInsideLoop;
|
||||
bool mHasRunLoopValidation;
|
||||
};
|
||||
|
||||
} // namespace sh
|
||||
|
||||
#endif // COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
|
|
@ -201,7 +201,7 @@ class TIntermLoop : public TIntermNode
|
|||
TIntermTyped *cond,
|
||||
TIntermTyped *expr,
|
||||
TIntermBlock *body)
|
||||
: mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body), mUnrollFlag(false)
|
||||
: mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -219,17 +219,12 @@ class TIntermLoop : public TIntermNode
|
|||
void setExpression(TIntermTyped *expression) { mExpr = expression; }
|
||||
void setBody(TIntermBlock *body) { mBody = body; }
|
||||
|
||||
void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
|
||||
bool getUnrollFlag() const { return mUnrollFlag; }
|
||||
|
||||
protected:
|
||||
TLoopType mType;
|
||||
TIntermNode *mInit; // for-loop initialization
|
||||
TIntermTyped *mCond; // loop exit condition
|
||||
TIntermTyped *mExpr; // for-loop expression
|
||||
TIntermBlock *mBody; // loop body
|
||||
|
||||
bool mUnrollFlag; // Whether the loop should be unrolled or not.
|
||||
};
|
||||
|
||||
//
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2002-2014 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.
|
||||
//
|
||||
|
||||
#include "compiler/translator/LoopInfo.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
int EvaluateIntConstant(TIntermConstantUnion *node)
|
||||
{
|
||||
ASSERT(node && node->getUnionArrayPointer());
|
||||
return node->getIConst(0);
|
||||
}
|
||||
|
||||
int GetLoopIntIncrement(TIntermLoop *node)
|
||||
{
|
||||
TIntermNode *expr = node->getExpression();
|
||||
// for expression has one of the following forms:
|
||||
// loop_index++
|
||||
// loop_index--
|
||||
// loop_index += constant_expression
|
||||
// loop_index -= constant_expression
|
||||
// ++loop_index
|
||||
// --loop_index
|
||||
// The last two forms are not specified in the spec, but I am assuming
|
||||
// its an oversight.
|
||||
TIntermUnary *unOp = expr->getAsUnaryNode();
|
||||
TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
|
||||
|
||||
TOperator op = EOpNull;
|
||||
TIntermConstantUnion *incrementNode = NULL;
|
||||
if (unOp)
|
||||
{
|
||||
op = unOp->getOp();
|
||||
}
|
||||
else if (binOp)
|
||||
{
|
||||
op = binOp->getOp();
|
||||
ASSERT(binOp->getRight());
|
||||
incrementNode = binOp->getRight()->getAsConstantUnion();
|
||||
ASSERT(incrementNode);
|
||||
}
|
||||
|
||||
int increment = 0;
|
||||
// The operator is one of: ++ -- += -=.
|
||||
switch (op)
|
||||
{
|
||||
case EOpPostIncrement:
|
||||
case EOpPreIncrement:
|
||||
ASSERT(unOp && !binOp);
|
||||
increment = 1;
|
||||
break;
|
||||
case EOpPostDecrement:
|
||||
case EOpPreDecrement:
|
||||
ASSERT(unOp && !binOp);
|
||||
increment = -1;
|
||||
break;
|
||||
case EOpAddAssign:
|
||||
ASSERT(!unOp && binOp);
|
||||
increment = EvaluateIntConstant(incrementNode);
|
||||
break;
|
||||
case EOpSubAssign:
|
||||
ASSERT(!unOp && binOp);
|
||||
increment = - EvaluateIntConstant(incrementNode);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
return increment;
|
||||
}
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
TLoopIndexInfo::TLoopIndexInfo()
|
||||
: mId(-1),
|
||||
mType(EbtVoid),
|
||||
mInitValue(0),
|
||||
mStopValue(0),
|
||||
mIncrementValue(0),
|
||||
mOp(EOpNull),
|
||||
mCurrentValue(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TLoopIndexInfo::fillInfo(TIntermLoop *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
// Here we assume all the operations are valid, because the loop node is
|
||||
// already validated in ValidateLimitations.
|
||||
TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
|
||||
TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
|
||||
TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
|
||||
|
||||
mId = symbol->getId();
|
||||
mType = symbol->getBasicType();
|
||||
|
||||
if (mType == EbtInt)
|
||||
{
|
||||
TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
|
||||
mInitValue = EvaluateIntConstant(initNode);
|
||||
mCurrentValue = mInitValue;
|
||||
mIncrementValue = GetLoopIntIncrement(node);
|
||||
|
||||
TIntermBinary* binOp = node->getCondition()->getAsBinaryNode();
|
||||
mStopValue = EvaluateIntConstant(
|
||||
binOp->getRight()->getAsConstantUnion());
|
||||
mOp = binOp->getOp();
|
||||
}
|
||||
}
|
||||
|
||||
bool TLoopIndexInfo::satisfiesLoopCondition() const
|
||||
{
|
||||
// Relational operator is one of: > >= < <= == or !=.
|
||||
switch (mOp)
|
||||
{
|
||||
case EOpEqual:
|
||||
return (mCurrentValue == mStopValue);
|
||||
case EOpNotEqual:
|
||||
return (mCurrentValue != mStopValue);
|
||||
case EOpLessThan:
|
||||
return (mCurrentValue < mStopValue);
|
||||
case EOpGreaterThan:
|
||||
return (mCurrentValue > mStopValue);
|
||||
case EOpLessThanEqual:
|
||||
return (mCurrentValue <= mStopValue);
|
||||
case EOpGreaterThanEqual:
|
||||
return (mCurrentValue >= mStopValue);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TLoopInfo::TLoopInfo()
|
||||
: loop(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
TLoopInfo::TLoopInfo(TIntermLoop *node)
|
||||
: loop(node)
|
||||
{
|
||||
index.fillInfo(node);
|
||||
}
|
||||
|
||||
TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol)
|
||||
{
|
||||
if (!symbol)
|
||||
return NULL;
|
||||
for (iterator iter = begin(); iter != end(); ++iter)
|
||||
{
|
||||
if (iter->index.getId() == symbol->getId())
|
||||
return iter->loop;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol)
|
||||
{
|
||||
if (!symbol)
|
||||
return NULL;
|
||||
for (iterator iter = begin(); iter != end(); ++iter)
|
||||
{
|
||||
if (iter->index.getId() == symbol->getId())
|
||||
return &(iter->index);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void TLoopStack::step()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
rbegin()->index.step();
|
||||
}
|
||||
|
||||
bool TLoopStack::satisfiesLoopCondition()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return rbegin()->index.satisfiesLoopCondition();
|
||||
}
|
||||
|
||||
bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol)
|
||||
{
|
||||
TIntermLoop *loop = findLoop(symbol);
|
||||
return loop && loop->getUnrollFlag();
|
||||
}
|
||||
|
||||
int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol)
|
||||
{
|
||||
TLoopIndexInfo *info = getIndexInfo(symbol);
|
||||
ASSERT(info);
|
||||
return info->getCurrentValue();
|
||||
}
|
||||
|
||||
void TLoopStack::push(TIntermLoop *loop)
|
||||
{
|
||||
TLoopInfo info(loop);
|
||||
push_back(info);
|
||||
}
|
||||
|
||||
void TLoopStack::pop()
|
||||
{
|
||||
pop_back();
|
||||
}
|
||||
|
||||
} // namespace sh
|
|
@ -1,85 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2002-2014 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.
|
||||
//
|
||||
|
||||
#ifndef COMPILER_TRANSLATOR_LOOPINFO_H_
|
||||
#define COMPILER_TRANSLATOR_LOOPINFO_H_
|
||||
|
||||
#include "compiler/translator/IntermNode.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
class TLoopIndexInfo
|
||||
{
|
||||
public:
|
||||
TLoopIndexInfo();
|
||||
|
||||
// If type is EbtInt, fill all fields of the structure with info
|
||||
// extracted from a loop node.
|
||||
// If type is not EbtInt, only fill id and type.
|
||||
void fillInfo(TIntermLoop *node);
|
||||
|
||||
int getId() const { return mId; }
|
||||
void setId(int id) { mId = id; }
|
||||
TBasicType getType() const { return mType; }
|
||||
void setType(TBasicType type) { mType = type; }
|
||||
int getCurrentValue() const { return mCurrentValue; }
|
||||
|
||||
void step() { mCurrentValue += mIncrementValue; }
|
||||
|
||||
// Check if the current value satisfies the loop condition.
|
||||
bool satisfiesLoopCondition() const;
|
||||
|
||||
private:
|
||||
int mId;
|
||||
TBasicType mType; // Either EbtInt or EbtFloat
|
||||
|
||||
// Below fields are only valid if the index's type is int.
|
||||
int mInitValue;
|
||||
int mStopValue;
|
||||
int mIncrementValue;
|
||||
TOperator mOp;
|
||||
int mCurrentValue;
|
||||
};
|
||||
|
||||
struct TLoopInfo
|
||||
{
|
||||
TLoopIndexInfo index;
|
||||
TIntermLoop *loop;
|
||||
|
||||
TLoopInfo();
|
||||
TLoopInfo(TIntermLoop *node);
|
||||
};
|
||||
|
||||
class TLoopStack : public TVector<TLoopInfo>
|
||||
{
|
||||
public:
|
||||
// Search loop stack for a loop whose index matches the input symbol.
|
||||
TIntermLoop *findLoop(TIntermSymbol *symbol);
|
||||
|
||||
// Find the loop index info in the loop stack by the input symbol.
|
||||
TLoopIndexInfo *getIndexInfo(TIntermSymbol *symbol);
|
||||
|
||||
// Update the currentValue for the next loop iteration.
|
||||
void step();
|
||||
|
||||
// Return false if loop condition is no longer satisfied.
|
||||
bool satisfiesLoopCondition();
|
||||
|
||||
// Check if the symbol is the index of a loop that's unrolled.
|
||||
bool needsToReplaceSymbolWithValue(TIntermSymbol *symbol);
|
||||
|
||||
// Return the current value of a given loop index symbol.
|
||||
int getLoopIndexValue(TIntermSymbol *symbol);
|
||||
|
||||
void push(TIntermLoop *info);
|
||||
void pop();
|
||||
};
|
||||
|
||||
} // namespace sh
|
||||
|
||||
#endif // COMPILER_TRANSLATOR_LOOPINFO_H_
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2002-2010 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.
|
||||
//
|
||||
|
||||
#ifndef COMPILER_TRANSLATOR_MMAP_H_
|
||||
#define COMPILER_TRANSLATOR_MMAP_H_
|
||||
|
||||
//
|
||||
// Encapsulate memory mapped files
|
||||
//
|
||||
|
||||
class TMMap {
|
||||
public:
|
||||
TMMap(const char* fileName) :
|
||||
fSize(-1), // -1 is the error value returned by GetFileSize()
|
||||
fp(NULL),
|
||||
fBuff(0) // 0 is the error value returned by MapViewOfFile()
|
||||
{
|
||||
if ((fp = fopen(fileName, "r")) == NULL)
|
||||
return;
|
||||
char c = getc(fp);
|
||||
fSize = 0;
|
||||
while (c != EOF) {
|
||||
fSize++;
|
||||
c = getc(fp);
|
||||
}
|
||||
if (c == EOF)
|
||||
fSize++;
|
||||
rewind(fp);
|
||||
fBuff = (char*)malloc(sizeof(char) * fSize);
|
||||
int count = 0;
|
||||
c = getc(fp);
|
||||
while (c != EOF) {
|
||||
fBuff[count++] = c;
|
||||
c = getc(fp);
|
||||
}
|
||||
fBuff[count++] = c;
|
||||
}
|
||||
|
||||
char* getData() { return fBuff; }
|
||||
int getSize() { return fSize; }
|
||||
|
||||
~TMMap() {
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
private:
|
||||
int fSize; // size of file to map in
|
||||
FILE *fp;
|
||||
char* fBuff; // the actual data;
|
||||
};
|
||||
|
||||
#endif // COMPILER_TRANSLATOR_MMAP_H_
|
|
@ -389,10 +389,7 @@ void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
|
|||
void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
|
||||
{
|
||||
TInfoSinkBase &out = objSink();
|
||||
if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
|
||||
out << mLoopUnrollStack.getLoopIndexValue(node);
|
||||
else
|
||||
out << hashVariableName(node->getName());
|
||||
out << hashVariableName(node->getName());
|
||||
|
||||
if (mDeclaringVariables && node->getType().isArray())
|
||||
out << arrayBrackets(node->getType());
|
||||
|
@ -1137,49 +1134,22 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
|
|||
|
||||
TLoopType loopType = node->getType();
|
||||
|
||||
// Only for loops can be unrolled
|
||||
ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
|
||||
|
||||
if (loopType == ELoopFor) // for loop
|
||||
{
|
||||
if (!node->getUnrollFlag())
|
||||
{
|
||||
out << "for (";
|
||||
if (node->getInit())
|
||||
node->getInit()->traverse(this);
|
||||
out << "; ";
|
||||
out << "for (";
|
||||
if (node->getInit())
|
||||
node->getInit()->traverse(this);
|
||||
out << "; ";
|
||||
|
||||
if (node->getCondition())
|
||||
node->getCondition()->traverse(this);
|
||||
out << "; ";
|
||||
if (node->getCondition())
|
||||
node->getCondition()->traverse(this);
|
||||
out << "; ";
|
||||
|
||||
if (node->getExpression())
|
||||
node->getExpression()->traverse(this);
|
||||
out << ")\n";
|
||||
if (node->getExpression())
|
||||
node->getExpression()->traverse(this);
|
||||
out << ")\n";
|
||||
|
||||
visitCodeBlock(node->getBody());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to put a one-iteration loop here to handle break.
|
||||
TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
|
||||
TIntermSymbol *indexSymbol =
|
||||
(*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
|
||||
TString name = hashVariableName(indexSymbol->getName());
|
||||
out << "for (int " << name << " = 0; "
|
||||
<< name << " < 1; "
|
||||
<< "++" << name << ")\n";
|
||||
|
||||
out << "{\n";
|
||||
mLoopUnrollStack.push(node);
|
||||
while (mLoopUnrollStack.satisfiesLoopCondition())
|
||||
{
|
||||
visitCodeBlock(node->getBody());
|
||||
mLoopUnrollStack.step();
|
||||
}
|
||||
mLoopUnrollStack.pop();
|
||||
out << "}\n";
|
||||
}
|
||||
visitCodeBlock(node->getBody());
|
||||
}
|
||||
else if (loopType == ELoopWhile) // while loop
|
||||
{
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <set>
|
||||
|
||||
#include "compiler/translator/IntermNode.h"
|
||||
#include "compiler/translator/LoopInfo.h"
|
||||
#include "compiler/translator/ParseContext.h"
|
||||
|
||||
namespace sh
|
||||
|
@ -92,9 +91,6 @@ class TOutputGLSLBase : public TIntermTraverser
|
|||
// This set contains all the ids of the structs from every scope.
|
||||
std::set<int> mDeclaredStructs;
|
||||
|
||||
// Stack of loops that need to be unrolled.
|
||||
TLoopStack mLoopUnrollStack;
|
||||
|
||||
ShArrayIndexClampingStrategy mClampingStrategy;
|
||||
|
||||
// name hashing.
|
||||
|
|
|
@ -16,6 +16,17 @@ namespace sh
|
|||
namespace
|
||||
{
|
||||
|
||||
int GetLoopSymbolId(TIntermLoop *loop)
|
||||
{
|
||||
// Here we assume all the operations are valid, because the loop node is
|
||||
// already validated before this call.
|
||||
TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence();
|
||||
TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
|
||||
TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
|
||||
|
||||
return symbol->getId();
|
||||
}
|
||||
|
||||
// Traverses a node to check if it represents a constant index expression.
|
||||
// Definition:
|
||||
// constant-index-expressions are a superset of constant-expressions.
|
||||
|
@ -28,10 +39,8 @@ namespace
|
|||
class ValidateConstIndexExpr : public TIntermTraverser
|
||||
{
|
||||
public:
|
||||
ValidateConstIndexExpr(TLoopStack& stack)
|
||||
: TIntermTraverser(true, false, false),
|
||||
mValid(true),
|
||||
mLoopStack(stack)
|
||||
ValidateConstIndexExpr(const std::vector<int> &loopSymbols)
|
||||
: TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -44,14 +53,15 @@ class ValidateConstIndexExpr : public TIntermTraverser
|
|||
// constant index expression.
|
||||
if (mValid)
|
||||
{
|
||||
mValid = (symbol->getQualifier() == EvqConst) ||
|
||||
(mLoopStack.findLoop(symbol));
|
||||
bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(),
|
||||
symbol->getId()) != mLoopSymbolIds.end();
|
||||
mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool mValid;
|
||||
TLoopStack& mLoopStack;
|
||||
const std::vector<int> mLoopSymbolIds;
|
||||
};
|
||||
|
||||
} // namespace anonymous
|
||||
|
@ -80,9 +90,9 @@ bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop)
|
|||
TIntermNode *body = loop->getBody();
|
||||
if (body != nullptr)
|
||||
{
|
||||
validate.mLoopStack.push(loop);
|
||||
validate.mLoopSymbolIds.push_back(GetLoopSymbolId(loop));
|
||||
body->traverse(&validate);
|
||||
validate.mLoopStack.pop();
|
||||
validate.mLoopSymbolIds.pop_back();
|
||||
}
|
||||
return (validate.mNumErrors == 0);
|
||||
}
|
||||
|
@ -140,9 +150,9 @@ bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
|
|||
TIntermNode *body = node->getBody();
|
||||
if (body != NULL)
|
||||
{
|
||||
mLoopStack.push(node);
|
||||
mLoopSymbolIds.push_back(GetLoopSymbolId(node));
|
||||
body->traverse(this);
|
||||
mLoopStack.pop();
|
||||
mLoopSymbolIds.pop_back();
|
||||
}
|
||||
|
||||
// The loop is fully processed - no need to visit children.
|
||||
|
@ -163,12 +173,13 @@ void ValidateLimitations::error(TSourceLoc loc,
|
|||
|
||||
bool ValidateLimitations::withinLoopBody() const
|
||||
{
|
||||
return !mLoopStack.empty();
|
||||
return !mLoopSymbolIds.empty();
|
||||
}
|
||||
|
||||
bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
|
||||
{
|
||||
return mLoopStack.findLoop(symbol) != NULL;
|
||||
return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) !=
|
||||
mLoopSymbolIds.end();
|
||||
}
|
||||
|
||||
bool ValidateLimitations::validateLoopType(TIntermLoop *node)
|
||||
|
@ -474,7 +485,7 @@ bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
|
|||
{
|
||||
ASSERT(node != NULL);
|
||||
|
||||
ValidateConstIndexExpr validate(mLoopStack);
|
||||
ValidateConstIndexExpr validate(mLoopSymbolIds);
|
||||
node->traverse(&validate);
|
||||
return validate.isValid();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#define COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_
|
||||
|
||||
#include "compiler/translator/IntermNode.h"
|
||||
#include "compiler/translator/LoopInfo.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
@ -58,7 +57,7 @@ class ValidateLimitations : public TIntermTraverser
|
|||
sh::GLenum mShaderType;
|
||||
TInfoSinkBase *mSink;
|
||||
int mNumErrors;
|
||||
TLoopStack mLoopStack;
|
||||
std::vector<int> mLoopSymbolIds;
|
||||
bool mValidateIndexing;
|
||||
bool mValidateInnerLoops;
|
||||
};
|
||||
|
|
|
@ -51,7 +51,6 @@ UNIFIED_SOURCES += [
|
|||
'../compiler/translator/ExpandIntegerPowExpressions.cpp',
|
||||
'../compiler/translator/ExtensionGLSL.cpp',
|
||||
'../compiler/translator/FlagStd140Structs.cpp',
|
||||
'../compiler/translator/ForLoopUnroll.cpp',
|
||||
'../compiler/translator/InfoSink.cpp',
|
||||
'../compiler/translator/Initialize.cpp',
|
||||
'../compiler/translator/InitializeDll.cpp',
|
||||
|
@ -62,7 +61,6 @@ UNIFIED_SOURCES += [
|
|||
'../compiler/translator/IntermNodePatternMatcher.cpp',
|
||||
'../compiler/translator/intermOut.cpp',
|
||||
'../compiler/translator/IntermTraverse.cpp',
|
||||
'../compiler/translator/LoopInfo.cpp',
|
||||
'../compiler/translator/Operator.cpp',
|
||||
'../compiler/translator/OutputESSL.cpp',
|
||||
'../compiler/translator/OutputGLSL.cpp',
|
||||
|
|
|
@ -149,12 +149,6 @@ class MalformedComputeShaderTest : public MalformedShaderTest
|
|||
}
|
||||
};
|
||||
|
||||
class UnrollForLoopsTest : public MalformedShaderTest
|
||||
{
|
||||
public:
|
||||
UnrollForLoopsTest() { mExtraCompileOptions = SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX; }
|
||||
};
|
||||
|
||||
// This is a test for a bug that used to exist in ANGLE:
|
||||
// Calling a function with all parameters missing should not succeed.
|
||||
TEST_F(MalformedShaderTest, FunctionParameterMismatch)
|
||||
|
@ -1445,45 +1439,6 @@ TEST_F(MalformedWebGL1ShaderTest, NonConstantLoopIndex)
|
|||
}
|
||||
}
|
||||
|
||||
// Regression test for an old crash bug in ANGLE.
|
||||
// ForLoopUnroll used to crash when it encountered a while loop.
|
||||
TEST_F(UnrollForLoopsTest, WhileLoop)
|
||||
{
|
||||
const std::string &shaderString =
|
||||
"precision mediump float;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" while (true) {\n"
|
||||
" gl_FragColor = vec4(0.0);\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
if (!compile(shaderString))
|
||||
{
|
||||
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
|
||||
}
|
||||
}
|
||||
|
||||
// Regression test for an old crash bug in ANGLE.
|
||||
// ForLoopUnroll used to crash when it encountered a loop that didn't fit the ESSL 1.00
|
||||
// Appendix A limitations.
|
||||
TEST_F(UnrollForLoopsTest, UnlimitedForLoop)
|
||||
{
|
||||
const std::string &shaderString =
|
||||
"precision mediump float;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" for (;true;) {\n"
|
||||
" gl_FragColor = vec4(0.0);\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
if (!compile(shaderString))
|
||||
{
|
||||
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that indices that are not integers are rejected.
|
||||
// The check should be done even if ESSL 1.00 Appendix A limitations are not applied.
|
||||
TEST_F(MalformedShaderTest, NonIntegerIndex)
|
||||
|
|
Загрузка…
Ссылка в новой задаче