blob: 2aa4ab936a7caa1309c11e632872485f07e8c6dc [file] [log] [blame]
//
// Copyright 2016 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.
//
// ShaderCompileTreeTest.cpp:
// Test that shader validation results in the correct compile status.
//
#include "tests/test_utils/ShaderCompileTreeTest.h"
#include "compiler/translator/TranslatorESSL.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
// Checks that the node traversed is a zero node. It can be made out of multiple constructors and
// constant union nodes as long as there's no arithmetic involved and all constants are zero.
class OnlyContainsZeroConstantsTraverser final : public TIntermTraverser
{
public:
OnlyContainsZeroConstantsTraverser()
: TIntermTraverser(true, false, false), mOnlyContainsConstantZeros(true)
{}
bool visitUnary(Visit, TIntermUnary *node) override
{
mOnlyContainsConstantZeros = false;
return false;
}
bool visitBinary(Visit, TIntermBinary *node) override
{
mOnlyContainsConstantZeros = false;
return false;
}
bool visitTernary(Visit, TIntermTernary *node) override
{
mOnlyContainsConstantZeros = false;
return false;
}
bool visitSwizzle(Visit, TIntermSwizzle *node) override
{
mOnlyContainsConstantZeros = false;
return false;
}
bool visitAggregate(Visit, TIntermAggregate *node) override
{
if (node->getOp() != EOpConstruct)
{
mOnlyContainsConstantZeros = false;
return false;
}
return true;
}
void visitSymbol(TIntermSymbol *node) override { mOnlyContainsConstantZeros = false; }
void visitConstantUnion(TIntermConstantUnion *node) override
{
if (!mOnlyContainsConstantZeros)
{
return;
}
const TType &type = node->getType();
size_t objectSize = type.getObjectSize();
for (size_t i = 0u; i < objectSize && mOnlyContainsConstantZeros; ++i)
{
bool isZero = false;
switch (type.getBasicType())
{
case EbtFloat:
isZero = (node->getFConst(i) == 0.0f);
break;
case EbtInt:
isZero = (node->getIConst(i) == 0);
break;
case EbtUInt:
isZero = (node->getUConst(i) == 0u);
break;
case EbtBool:
isZero = (node->getBConst(i) == false);
break;
default:
// Cannot handle.
break;
}
if (!isZero)
{
mOnlyContainsConstantZeros = false;
return;
}
}
}
bool onlyContainsConstantZeros() const { return mOnlyContainsConstantZeros; }
private:
bool mOnlyContainsConstantZeros;
};
} // anonymous namespace
void ShaderCompileTreeTest::SetUp()
{
mAllocator.push();
SetGlobalPoolAllocator(&mAllocator);
ShBuiltInResources resources;
sh::InitBuiltInResources(&resources);
initResources(&resources);
mTranslator = new TranslatorESSL(getShaderType(), getShaderSpec());
ASSERT_TRUE(mTranslator->Init(resources));
}
void ShaderCompileTreeTest::TearDown()
{
delete mTranslator;
SetGlobalPoolAllocator(nullptr);
mAllocator.pop();
}
bool ShaderCompileTreeTest::compile(const std::string &shaderString)
{
const char *shaderStrings[] = {shaderString.c_str()};
mASTRoot = mTranslator->compileTreeForTesting(shaderStrings, 1, mExtraCompileOptions);
TInfoSink &infoSink = mTranslator->getInfoSink();
mInfoLog = infoSink.info.c_str();
return mASTRoot != nullptr;
}
void ShaderCompileTreeTest::compileAssumeSuccess(const std::string &shaderString)
{
if (!compile(shaderString))
{
FAIL() << "Shader compilation into ESSL failed, log:\n" << mInfoLog;
}
}
bool ShaderCompileTreeTest::hasWarning() const
{
return mInfoLog.find("WARNING: ") != std::string::npos;
}
const std::vector<sh::ShaderVariable> &ShaderCompileTreeTest::getUniforms() const
{
ASSERT(mExtraCompileOptions & SH_VARIABLES);
return mTranslator->getUniforms();
}
const std::vector<sh::ShaderVariable> &ShaderCompileTreeTest::getAttributes() const
{
ASSERT(mExtraCompileOptions & SH_VARIABLES);
return mTranslator->getAttributes();
}
bool IsZero(TIntermNode *node)
{
if (!node->getAsTyped())
{
return false;
}
OnlyContainsZeroConstantsTraverser traverser;
node->traverse(&traverser);
return traverser.onlyContainsConstantZeros();
}
} // namespace sh