| /*------------------------------------------------------------------------- |
| * 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 |