/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL ES 3.1 Module
* -------------------------------------------------
*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Built-in function tests for uniform constants.
*//*--------------------------------------------------------------------*/
#include "es31fShaderUniformIntegerFunctionTests.hpp"
#include "glsShaderExecUtil.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
#include <iostream>
namespace deqp
{
namespace gles31
{
namespace Functional
{
using std::vector;
using std::string;
using tcu::TestLog;
using namespace gls::ShaderExecUtil;
class UniformIntegerFunctionCase : public TestCase
{
public:
UniformIntegerFunctionCase (Context& context, const char* description, int inputValue, glu::Precision precision, glu::ShaderType shaderType);
~UniformIntegerFunctionCase (void);
void init (void);
void deinit (void);
IterateResult iterate (void);
virtual const char* getFunctionName() = 0;
virtual int computeExpectedResult(deInt32 value) = 0;
protected:
UniformIntegerFunctionCase (const UniformIntegerFunctionCase& other);
UniformIntegerFunctionCase& operator= (const UniformIntegerFunctionCase& other);
private:
ShaderSpec m_spec;
glu::ShaderType m_shaderType;
int m_input;
int m_value;
ShaderExecutor* m_executor;
};
static std::string getCaseName (glu::Precision precision, glu::ShaderType shaderType);
UniformIntegerFunctionCase::UniformIntegerFunctionCase(Context& context, const char* description, int inputValue, glu::Precision precision, glu::ShaderType shaderType)
: TestCase(context, getCaseName(precision, shaderType).c_str(), description)
, m_shaderType(shaderType)
, m_input(inputValue)
, m_value(0)
, m_executor(DE_NULL)
{
m_spec.version = glu::GLSL_VERSION_310_ES;
std::ostringstream oss;
glu::VarType varType(glu::TYPE_INT, precision);
oss << "uniform " << glu::declare(varType, "value", 0) << ";\n";
m_spec.globalDeclarations = oss.str();
m_spec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_INT, glu::PRECISION_LOWP)));
m_spec.outputs.push_back(Symbol("comparison", glu::VarType(glu::TYPE_BOOL, glu::PRECISION_LAST)));
}
UniformIntegerFunctionCase::~UniformIntegerFunctionCase(void)
{
UniformIntegerFunctionCase::deinit();
}
void UniformIntegerFunctionCase::deinit(void)
{
delete m_executor;
m_executor = DE_NULL;
}
void UniformIntegerFunctionCase::init(void)
{
std::ostringstream oss;
oss <<
"result = " << getFunctionName() << "(value);\n"
"comparison = (" << getFunctionName() << "(value) == " << computeExpectedResult(m_input) << ");\n";
m_spec.source = oss.str();
DE_ASSERT(!m_executor);
m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
m_testCtx.getLog() << m_executor;
if (!m_executor->isOk())
throw tcu::TestError("Compile failed");
m_value = m_context.getRenderContext().getFunctions().getUniformLocation(m_executor->getProgram(), "value");
}
tcu::TestNode::IterateResult UniformIntegerFunctionCase::iterate(void)
{
deInt32 result;
deBool comparison;
vector<void*> outputPointers (2);
outputPointers[0]= &result;
outputPointers[1] = &comparison;
m_executor->useProgram();
m_context.getRenderContext().getFunctions().uniform1i(m_value, m_input);
m_executor->execute(1, DE_NULL, &outputPointers[0]);
int expectedResult = computeExpectedResult(m_input);
if (result != expectedResult) {
m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for " << getFunctionName() << "(" << m_input << ") == " << expectedResult << TestLog::EndMessage;
m_testCtx.getLog() << TestLog::Message << "input: " << m_input << TestLog::EndMessage;
m_testCtx.getLog() << TestLog::Message << "result: " << result << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed");
return STOP;
} else if (!comparison) {
m_testCtx.getLog() << TestLog::Message << "ERROR: result is as expected, but not when use in condition statement (" << getFunctionName() << "(" << m_input << ") == " << expectedResult << ") == true" << TestLog::EndMessage;
m_testCtx.getLog() << TestLog::Message << "input:" << m_input << TestLog::EndMessage;
m_testCtx.getLog() << TestLog::Message << "result: " << result << TestLog::EndMessage;
m_testCtx.getLog() << TestLog::Message << "comparison: " << comparison << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed");
return STOP;
}
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
static const char* getPrecisionPostfix (glu::Precision precision)
{
static const char* s_postfix[] =
{
"lowp",
"mediump",
"highp"
};
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
return s_postfix[precision];
}
static const char* getShaderTypePostfix (glu::ShaderType shaderType)
{
static const char* s_postfix[] =
{
"_vertex",
"_fragment",
"_geometry",
"_tess_control",
"_tess_eval",
"_compute"
};
DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
return s_postfix[shaderType];
}
static std::string getCaseName (glu::Precision precision, glu::ShaderType shaderType)
{
return string(getPrecisionPostfix(precision)) + getShaderTypePostfix(shaderType);
}
static int findMSB (deInt32 value)
{
if (value > 0)
return 31 - deClz32((deUint32)value);
else if (value < 0)
return 31 - deClz32(~(deUint32)value);
else
return -1;
}
class FindMSBEdgeCase : public UniformIntegerFunctionCase {
public:
FindMSBEdgeCase(Context& context, int inputValue, glu::Precision precision, glu::ShaderType shaderType)
: UniformIntegerFunctionCase(context, "findMSB", inputValue, precision, shaderType)
{
}
protected:
const char* getFunctionName() {
return "findMSB";
}
int computeExpectedResult(deInt32 input) {
return findMSB(input);
}
};
static int findLSB (deUint32 value)
{
for (int i = 0; i < 32; i++)
{
if (value & (1u<<i))
return i;
}
return -1;
}
class FindLSBEdgeCase : public UniformIntegerFunctionCase {
public:
FindLSBEdgeCase(Context& context, int inputValue, glu::Precision precision, glu::ShaderType shaderType)
: UniformIntegerFunctionCase(context, "findLSB", inputValue, precision, shaderType)
{
}
protected:
const char* getFunctionName() {
return "findLSB";
}
int computeExpectedResult(deInt32 input) {
return findLSB(input);
}
};
template<class TestClass>
static void addFunctionCases (TestCaseGroup* parent, const char* functionName, int input)
{
tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
parent->addChild(group);
for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
{
for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
{
group->addChild(new TestClass(parent->getContext(), input, glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
}
}
}
ShaderUniformIntegerFunctionTests::ShaderUniformIntegerFunctionTests(Context& context)
: TestCaseGroup(context, "uniform", "Function on uniform")
{
}
ShaderUniformIntegerFunctionTests::~ShaderUniformIntegerFunctionTests()
{
}
void ShaderUniformIntegerFunctionTests::init()
{
addFunctionCases<FindMSBEdgeCase>(this, "findMSBZero", 0);
addFunctionCases<FindMSBEdgeCase>(this, "findMSBMinusOne", -1);
addFunctionCases<FindLSBEdgeCase>(this, "findLSBZero", 0);
addFunctionCases<FindLSBEdgeCase>(this, "findLSBMinusOne", -1);
}
}
}
}