blob: 6c3425f34a58127139cb6ed91922c2b2a7ee8b65 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2015-2016 The Khronos Group Inc.
*
* 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
*/ /*-------------------------------------------------------------------*/
/*!
* \file glcShaderNegativeTests.cpp
* \brief Negative tests for shaders and interface matching.
*/ /*-------------------------------------------------------------------*/
#include "glcShaderNegativeTests.hpp"
#include "deString.h"
#include "deStringUtil.hpp"
#include "gluContextInfo.hpp"
#include "gluShaderProgram.hpp"
#include "glw.h"
#include "tcuStringTemplate.hpp"
#include "tcuTestLog.hpp"
namespace deqp
{
using tcu::TestLog;
using namespace glu;
struct ShaderVariants
{
GLSLVersion minimum_supported_version;
const char* vertex_precision;
const char* vertex_body;
const char* frag_precision;
const char* frag_body;
bool should_link;
};
class ShaderUniformInitializeGlobalCase : public TestCase
{
public:
ShaderUniformInitializeGlobalCase(Context& context, const char* name, const char* description,
GLSLVersion glslVersion)
: TestCase(context, name, description), m_glslVersion(glslVersion)
{
}
~ShaderUniformInitializeGlobalCase()
{
// empty
}
IterateResult iterate()
{
qpTestResult result = QP_TEST_RESULT_PASS;
static const char vertex_source_template[] =
"${VERSION_DECL}\n"
"precision mediump float;\n"
"uniform vec4 nonconstantexpression;\n"
"vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n"
"vec4 globalconstant1 = nonconstantexpression;\n"
"\n"
"void main(void) { gl_Position = globalconstant0+globalconstant1; }\n";
static const char fragment_source_template[] = "${VERSION_DECL}\n"
"precision mediump float;\n"
"uniform vec4 nonconstantexpression;\n"
"vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n"
"vec4 globalconstant1 = nonconstantexpression;\n"
"\n"
"void main(void) { }\n";
std::map<std::string, std::string> args;
args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
std::string vertex_code = tcu::StringTemplate(vertex_source_template).specialize(args);
std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
// Setup program.
ShaderProgram program(m_context.getRenderContext(),
makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
// GLSL ES does not allow initialization of global variables with non-constant
// expressions, but GLSL does.
// Check that either compilation or linking fails for ES, and that everything
// succeeds for GL.
bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
bool linkOk = program.getProgramInfo().linkOk;
if (glslVersionIsES(m_glslVersion))
{
if (vertexOk && fragmentOk && linkOk)
result = QP_TEST_RESULT_FAIL;
}
else
{
if (!vertexOk && !fragmentOk && !linkOk)
result = QP_TEST_RESULT_FAIL;
}
m_testCtx.setTestResult(result, qpGetTestResultName(result));
return STOP;
}
protected:
GLSLVersion m_glslVersion;
};
class ShaderUniformPrecisionLinkCase : public TestCase
{
public:
ShaderUniformPrecisionLinkCase(Context& context, const char* name, const char* description,
const ShaderVariants* shaderVariants, unsigned int shaderVariantsCount,
GLSLVersion glslVersion)
: TestCase(context, name, description)
, m_glslVersion(glslVersion)
, m_shaderVariants(shaderVariants)
, m_shaderVariantsCount(shaderVariantsCount)
{
}
~ShaderUniformPrecisionLinkCase()
{
// empty
}
IterateResult iterate()
{
TestLog& log = m_testCtx.getLog();
qpTestResult result = QP_TEST_RESULT_PASS;
static const char vertex_source_template[] = "${VERSION_DECL}\n"
"uniform ${PREC_QUALIFIER} vec4 value;\n"
"\n"
"void main(void) { ${BODY} }\n";
static const char fragment_source_template[] = "${VERSION_DECL}\n"
"out highp vec4 result;\n"
"uniform ${PREC_QUALIFIER} vec4 value;\n"
"\n"
"void main(void) { ${BODY} }\n";
for (unsigned int i = 0; i < m_shaderVariantsCount; i++)
{
std::map<std::string, std::string> args;
if (m_glslVersion <= m_shaderVariants[i].minimum_supported_version)
{
continue;
}
args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
args["PREC_QUALIFIER"] = m_shaderVariants[i].vertex_precision;
args["BODY"] = m_shaderVariants[i].vertex_body;
std::string vcode = tcu::StringTemplate(vertex_source_template).specialize(args);
args["PREC_QUALIFIER"] = m_shaderVariants[i].frag_precision;
args["BODY"] = m_shaderVariants[i].frag_body;
std::string fcode = tcu::StringTemplate(fragment_source_template).specialize(args);
// Setup program.
ShaderProgram program(m_context.getRenderContext(), makeVtxFragSources(vcode.c_str(), fcode.c_str()));
// Check that compile/link results are what we expect.
bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
bool linkOk = program.getProgramInfo().linkOk;
const char* failReason = DE_NULL;
if (!vertexOk || !fragmentOk)
{
failReason = "expected shaders to compile, but failed.";
}
else if (m_shaderVariants[i].should_link && !linkOk)
{
failReason = "expected shaders to link, but failed.";
}
else if (!m_shaderVariants[i].should_link && linkOk)
{
failReason = "expected shaders to fail linking, but succeeded.";
}
if (failReason != DE_NULL)
{
log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
result = QP_TEST_RESULT_FAIL;
}
}
m_testCtx.setTestResult(result, qpGetTestResultName(result));
return STOP;
}
protected:
GLSLVersion m_glslVersion;
const ShaderVariants* m_shaderVariants;
unsigned int m_shaderVariantsCount;
};
class ShaderConstantSequenceExpressionCase : public TestCase
{
public:
ShaderConstantSequenceExpressionCase(Context& context, const char* name, const char* description,
GLSLVersion glslVersion)
: TestCase(context, name, description), m_glslVersion(glslVersion)
{
}
~ShaderConstantSequenceExpressionCase()
{
// empty
}
IterateResult iterate()
{
qpTestResult result = QP_TEST_RESULT_PASS;
static const char vertex_source_template[] = "${VERSION_DECL}\n"
"precision mediump float;\n"
"const int test = (1, 2);\n"
"\n"
"void main(void) { gl_Position = vec4(test); }\n";
static const char fragment_source_template[] = "${VERSION_DECL}\n"
"precision mediump float;\n"
"\n"
"void main(void) { }\n";
std::map<std::string, std::string> args;
args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
std::string vertex_code = tcu::StringTemplate(vertex_source_template).specialize(args);
std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
// Setup program.
ShaderProgram program(m_context.getRenderContext(),
makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
// GLSL does not allow the sequence operator in a constant expression
// Check that either compilation or linking fails
bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
bool linkOk = program.getProgramInfo().linkOk;
bool run_test_es = (glslVersionIsES(m_glslVersion) && m_glslVersion > GLSL_VERSION_100_ES);
bool run_test_desktop = (m_glslVersion > GLSL_VERSION_420);
if (run_test_es || run_test_desktop)
{
if (vertexOk && fragmentOk && linkOk)
result = QP_TEST_RESULT_FAIL;
}
m_testCtx.setTestResult(result, qpGetTestResultName(result));
return STOP;
}
protected:
GLSLVersion m_glslVersion;
};
ShaderNegativeTests::ShaderNegativeTests(Context& context, GLSLVersion glslVersion)
: TestCaseGroup(context, "negative", "Shader Negative tests"), m_glslVersion(glslVersion)
{
// empty
}
ShaderNegativeTests::~ShaderNegativeTests()
{
// empty
}
void ShaderNegativeTests::init(void)
{
addChild(new ShaderUniformInitializeGlobalCase(
m_context, "initialize", "Verify initialization of globals with non-constant expressions fails on ES.",
m_glslVersion));
addChild(new ShaderConstantSequenceExpressionCase(
m_context, "constant_sequence", "Verify that the sequence operator cannot be used as a constant expression.",
m_glslVersion));
if (isGLSLVersionSupported(m_context.getRenderContext().getType(), GLSL_VERSION_320_ES))
{
static const ShaderVariants used_variables_variants[] = {
/* These variants should pass since the precision qualifiers match.
* These variants require highp to be supported, so will not be run for GLSL_VERSION_100_ES.
*/
{ GLSL_VERSION_300_ES, "", "gl_Position = vec4(1.0) + value;", "highp", "result = value;", true },
{ GLSL_VERSION_300_ES, "highp", "gl_Position = vec4(1.0) + value;", "highp", "result = value;", true },
/* Use highp in vertex shaders, mediump in fragment shaders. Check variations as above.
* These variants should fail since the precision qualifiers do not match, and matching is done
* based on declaration - independent of static use.
*/
{ GLSL_VERSION_100_ES, "", "gl_Position = vec4(1.0) + value;", "mediump", "result = value;", false },
{ GLSL_VERSION_100_ES, "highp", "gl_Position = vec4(1.0) + value;", "mediump", "result = value;", false },
};
unsigned int used_variables_variants_count = sizeof(used_variables_variants) / sizeof(ShaderVariants);
addChild(new ShaderUniformPrecisionLinkCase(
m_context, "used_uniform_precision_matching",
"Verify that linking fails if precision qualifiers on default uniform do not match",
used_variables_variants, used_variables_variants_count, m_glslVersion));
}
}
} // deqp