| /*------------------------------------------------------------------------- |
| * 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 gl3cCommonBugsTests.cpp |
| * \brief Short conformance tests which verify functionality which has either |
| * been found to be broken on one publically available driver, or whose |
| * behavior varies between vendors. |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl3cCommonBugsTests.hpp" |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "gluRenderContext.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include <cstring> |
| #include <string> |
| #include <vector> |
| |
| #ifndef GL_SPARSE_BUFFER_PAGE_SIZE_ARB |
| #define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8 |
| #endif |
| #ifndef GL_SPARSE_STORAGE_BIT_ARB |
| #define GL_SPARSE_STORAGE_BIT_ARB 0x0400 |
| #endif |
| |
| namespace gl3cts |
| { |
| /** Constructor. |
| * |
| * @param context Rendering context |
| * @param name Test name |
| * @param description Test description |
| */ |
| GetProgramivActiveUniformBlockMaxNameLengthTest::GetProgramivActiveUniformBlockMaxNameLengthTest(deqp::Context& context) |
| : TestCase(context, "CommonBug_GetProgramivActiveUniformBlockMaxNameLength", |
| "Verifies GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH pname is recognized by glGetProgramiv()") |
| , m_fs_id(0) |
| , m_po_id(0) |
| , m_vs_id(0) |
| { |
| /* Left blank intentionally */ |
| } |
| |
| /** Tears down any GL objects set up to run the test. */ |
| void GetProgramivActiveUniformBlockMaxNameLengthTest::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_fs_id != 0) |
| { |
| gl.deleteShader(m_fs_id); |
| |
| m_fs_id = 0; |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| |
| m_po_id = 0; |
| } |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| } |
| |
| /** Stub init method */ |
| void GetProgramivActiveUniformBlockMaxNameLengthTest::init() |
| { |
| /* Nothing to do here */ |
| } |
| |
| /** Initializes all GL objects required to run the test */ |
| bool GetProgramivActiveUniformBlockMaxNameLengthTest::initTest() |
| { |
| glw::GLint compile_status = false; |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| glw::GLint link_status = false; |
| bool result = true; |
| |
| const char* fs_body = "#version 140\n" |
| "\n" |
| "uniform data\n" |
| "{\n" |
| " vec4 temp;\n" |
| "};\n" |
| "\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " result = temp;\n" |
| "}\n"; |
| |
| const char* vs_body = "#version 140\n" |
| "\n" |
| "uniform data2\n" |
| "{\n" |
| " vec4 temp2;\n" |
| "};\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = temp2;\n" |
| "}\n"; |
| |
| m_po_id = gl.createProgram(); |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed."); |
| |
| gl.attachShader(m_po_id, m_fs_id); |
| gl.attachShader(m_po_id, m_vs_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed."); |
| |
| gl.shaderSource(m_fs_id, 1, /* count */ |
| &fs_body, DE_NULL); /* length */ |
| gl.shaderSource(m_vs_id, 1, /* count */ |
| &vs_body, DE_NULL); /* length */ |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed."); |
| |
| gl.compileShader(m_fs_id); |
| gl.compileShader(m_vs_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call(s) failed."); |
| |
| /* Have the shaders compiled successfully? */ |
| const glw::GLuint shader_ids[] = { m_fs_id, m_vs_id }; |
| const unsigned int n_shader_ids = static_cast<unsigned int>(sizeof(shader_ids) / sizeof(shader_ids[0])); |
| |
| for (unsigned int n_shader_id = 0; n_shader_id < n_shader_ids; ++n_shader_id) |
| { |
| gl.getShaderiv(shader_ids[n_shader_id], GL_COMPILE_STATUS, &compile_status); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status != GL_TRUE) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation failure" |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| goto end; |
| } |
| } /* for (all shader IDs) */ |
| |
| /* Link the PO */ |
| gl.linkProgram(m_po_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); |
| |
| gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); |
| |
| if (link_status != GL_TRUE) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linking failure" |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| goto end; |
| } |
| |
| end: |
| return result; |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult GetProgramivActiveUniformBlockMaxNameLengthTest::iterate() |
| { |
| bool result = true; |
| |
| /* Execute the query */ |
| glw::GLenum error_code = GL_NO_ERROR; |
| const glw::GLint expected_result_value = static_cast<glw::GLint>(strlen("data2") + 1 /* terminator */); |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| glw::GLint result_value = 0; |
| |
| /* Only execute if we're daeling with GL 3.1 or newer.. */ |
| if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 1))) |
| { |
| goto end; |
| } |
| |
| /* Set up the test program object */ |
| if (!initTest()) |
| { |
| result = false; |
| |
| goto end; |
| } |
| |
| gl.getProgramiv(m_po_id, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &result_value); |
| |
| error_code = gl.getError(); |
| |
| if (error_code != GL_NO_ERROR) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() generated error [" << error_code |
| << "] for GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH" << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| else if (result_value != expected_result_value) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned an invalid value of " << result_value |
| << " instead of the expected value of " << (strlen("data2") + 1 /* terminator */) |
| << " for the GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, " |
| "where the longest uniform block name is data2." |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| end: |
| m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); |
| |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| * @param name Test name |
| * @param description Test description |
| */ |
| InputVariablesCannotBeModifiedTest::InputVariablesCannotBeModifiedTest(deqp::Context& context) |
| : TestCase(context, "CommonBug_InputVariablesCannotBeModified", "Verifies that input variables cannot be modified.") |
| , m_fs_id(0) |
| , m_gs_id(0) |
| , m_tc_id(0) |
| , m_te_id(0) |
| , m_vs_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes all GL objects created for the purpose of running the test, |
| * as well as any client-side buffers allocated at initialization time |
| */ |
| void InputVariablesCannotBeModifiedTest::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| glw::GLuint* so_id_ptrs[] = { |
| &m_fs_id, &m_gs_id, &m_tc_id, &m_te_id, &m_vs_id, |
| }; |
| const unsigned int n_so_id_ptrs = static_cast<unsigned int>(sizeof(so_id_ptrs) / sizeof(so_id_ptrs[0])); |
| |
| for (unsigned int n_so_id_ptr = 0; n_so_id_ptr < n_so_id_ptrs; ++n_so_id_ptr) |
| { |
| gl.deleteShader(*so_id_ptrs[n_so_id_ptr]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed."); |
| |
| *so_id_ptrs[n_so_id_ptr] = 0; |
| } /* for (all created shader objects) */ |
| } |
| |
| /** Dummy init function */ |
| void InputVariablesCannotBeModifiedTest::init() |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Retrieves a literal corresponding to the test iteration enum. |
| * |
| * @param iteration Enum to retrieve the string for. |
| * |
| * @return Requested object. |
| **/ |
| std::string InputVariablesCannotBeModifiedTest::getIterationName(_test_iteration iteration) const |
| { |
| std::string result; |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_INPUT_FS_VARIABLE: |
| result = "Fragment shader input variable"; |
| break; |
| case TEST_ITERATION_INPUT_FS_VARIABLE_IN_INPUT_BLOCK: |
| result = "Fragment shader input variable wrapped in an input block"; |
| break; |
| case TEST_ITERATION_INPUT_FS_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| result = "Fragment shader input variable passed to an inout function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_FS_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| result = "Fragment shader input variable passed to an out function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_GS_VARIABLE: |
| result = "Geometry shader input variable"; |
| break; |
| case TEST_ITERATION_INPUT_GS_VARIABLE_IN_INPUT_BLOCK: |
| result = "Geometry shader input variable wrapped in an input block"; |
| break; |
| case TEST_ITERATION_INPUT_GS_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| result = "Geometry shader input variable passed to an inout function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_GS_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| result = "Geometry shader input variable passed to an out function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_TC_VARIABLE_IN_INPUT_BLOCK: |
| result = "Tessellation control shader variable wrapped in an input block"; |
| break; |
| case TEST_ITERATION_INPUT_TC_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| result = "Tessellation control shader variable passed to an inout function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_TC_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| result = "Tessellation control shader variable passed to an out function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_TE_PATCH_VARIABLE: |
| result = "Tessellation evaluation shader patch input variable"; |
| break; |
| case TEST_ITERATION_INPUT_TE_VARIABLE: |
| result = "Tessellation evaluation shader input variable"; |
| break; |
| case TEST_ITERATION_INPUT_TE_VARIABLE_IN_INPUT_BLOCK: |
| result = "Tessellation evaluation shader patch input variable wrapped in an input block"; |
| break; |
| case TEST_ITERATION_INPUT_TE_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| result = "Tessellation evlauation shader patch input variable passed to an inout function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_TE_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| result = "Tessellation evaluation shader patch input variable passed to an out function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_VS_VARIABLE: |
| result = "Vertex shader input variable"; |
| break; |
| case TEST_ITERATION_INPUT_VS_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| result = "Vertex shader input variable passed to an inout function parameter"; |
| break; |
| case TEST_ITERATION_INPUT_VS_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| result = "Vertex shader input variable passed to an out function parameter"; |
| break; |
| |
| default: |
| TCU_FAIL("Unrecognized test iteration type."); |
| } /* switch (iteration) */ |
| |
| return result; |
| } |
| |
| /** Retrieves a vertex shader body for the user-specified iteration enum. |
| * |
| * @param iteration Iteration to retrieve the shader body for. |
| * |
| * @return Requested string object. |
| */ |
| void InputVariablesCannotBeModifiedTest::getIterationData(_test_iteration iteration, |
| glu::ApiType* out_required_min_context_type_ptr, |
| _shader_stage* out_target_shader_stage_ptr, |
| std::string* out_body_ptr) const |
| { |
| switch (iteration) |
| { |
| case TEST_ITERATION_INPUT_FS_VARIABLE: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 1); |
| *out_target_shader_stage_ptr = SHADER_STAGE_FRAGMENT; |
| |
| *out_body_ptr = "#version 140\n" |
| "\n" |
| "in vec4 data;\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " data += vec4(1.0);\n" |
| " result = data;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_FS_VARIABLE_IN_INPUT_BLOCK: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_FRAGMENT; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "in inputBlock\n" |
| "{\n" |
| " vec4 data;\n" |
| "};\n" |
| "\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " data += vec4(1.0);\n" |
| " result = data;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_FS_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 1); |
| *out_target_shader_stage_ptr = SHADER_STAGE_FRAGMENT; |
| |
| *out_body_ptr = "#version 140\n" |
| "\n" |
| "in vec4 data;\n" |
| "out vec4 result;\n" |
| "\n" |
| "void testFunc(inout vec4 arg)\n" |
| "{\n" |
| " arg += vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data);\n" |
| "\n" |
| " result = data;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_FS_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 1); |
| *out_target_shader_stage_ptr = SHADER_STAGE_FRAGMENT; |
| |
| *out_body_ptr = "#version 140\n" |
| "\n" |
| "in vec4 data;\n" |
| "out vec4 result;\n" |
| "\n" |
| "void testFunc(out vec4 arg)\n" |
| "{\n" |
| " arg = vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data);\n" |
| "\n" |
| " result = data;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_GS_VARIABLE: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 2); |
| *out_target_shader_stage_ptr = SHADER_STAGE_GEOMETRY; |
| |
| *out_body_ptr = "#version 150\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(points, max_vertices = 1) out;\n" |
| "\n" |
| "in vec4 data[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " data[0] += vec4(1.0);\n" |
| " gl_Position = data[0];\n" |
| "\n" |
| " EmitVertex();\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_GS_VARIABLE_IN_INPUT_BLOCK: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_GEOMETRY; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(points, max_vertices = 1) out;\n" |
| "\n" |
| "in inputBlock\n" |
| "{\n" |
| " vec4 data[];\n" |
| "};\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " data[0] += vec4(1.0);\n" |
| " gl_Position = data[0];\n" |
| "\n" |
| " EmitVertex();\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_GS_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 2); |
| *out_target_shader_stage_ptr = SHADER_STAGE_GEOMETRY; |
| |
| *out_body_ptr = "#version 150\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(points, max_vertices = 1) out;\n" |
| "\n" |
| "in vec4 data[];\n" |
| "\n" |
| "void testFunc(inout vec4 arg)\n" |
| "{\n" |
| " arg += vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data[0]);\n" |
| "\n" |
| " gl_Position = data[0];\n" |
| "\n" |
| " EmitVertex();\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_GS_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 2); |
| *out_target_shader_stage_ptr = SHADER_STAGE_GEOMETRY; |
| |
| *out_body_ptr = "#version 150\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(points, max_vertices = 1) out;\n" |
| "\n" |
| "in vec4 data[];\n" |
| "\n" |
| "void testFunc(out vec4 arg)\n" |
| "{\n" |
| " arg = vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data[0]);\n" |
| "\n" |
| " gl_Position = data[0];\n" |
| "\n" |
| " EmitVertex();\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_TC_VARIABLE: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_TESSELLATION_CONTROL; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "layout(vertices = 4) out;\n" |
| "\n" |
| "in vec4 data[];\n" |
| "out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " data[0] += vec4(1.0);\n" |
| " result = data[0];\n" |
| "\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_TC_VARIABLE_IN_INPUT_BLOCK: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_TESSELLATION_CONTROL; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "layout(vertices = 4) out;\n" |
| "\n" |
| "in inputBlock\n" |
| "{\n" |
| " vec4 data;\n" |
| "} inData[];\n" |
| "\n" |
| "patch out vec4 result[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " inData[0].data += vec4(1.0);\n" |
| " result[gl_InvocationID] = inData[0].data;\n" |
| "\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_TC_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_TESSELLATION_CONTROL; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "layout(vertices = 4) out;\n" |
| "\n" |
| "in vec4 data[];\n" |
| "out vec4 result;\n" |
| "\n" |
| "void testFunc(inout vec4 arg)\n" |
| "{\n" |
| " arg += vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data[0]);\n" |
| "\n" |
| " result = data[0];\n" |
| "\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_TC_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_TESSELLATION_CONTROL; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "layout(vertices = 4) out;\n" |
| "\n" |
| "in vec4 data[];\n" |
| "out vec4 result;\n" |
| "\n" |
| "void testFunc(out vec4 arg)\n" |
| "{\n" |
| " arg = vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data[0]);\n" |
| "\n" |
| " result = data[0];\n" |
| "\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_TE_PATCH_VARIABLE: |
| case TEST_ITERATION_INPUT_TE_VARIABLE: |
| { |
| std::stringstream body_sstream; |
| |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_TESSELLATION_EVALUATION; |
| |
| body_sstream << "#version 400\n" |
| "\n" |
| "layout(triangles) in;\n" |
| "\n" |
| << ((iteration == TEST_ITERATION_INPUT_TE_PATCH_VARIABLE) ? "patch " : "") << "in vec4 data[];\n" |
| << " out vec4 result;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " data[0] += vec4(1.0);\n" |
| " gl_Position = data[0];\n" |
| "}\n"; |
| |
| *out_body_ptr = body_sstream.str(); |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_TE_VARIABLE_IN_INPUT_BLOCK: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_TESSELLATION_EVALUATION; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "layout(triangles) in;\n" |
| "\n" |
| "in inputBlock\n" |
| "{\n" |
| " vec4 data;\n" |
| "} inData[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " inData[0].data += vec4(1.0);\n" |
| " gl_Position = inData[0].data;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_TE_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_TESSELLATION_EVALUATION; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "layout(triangles) in;\n" |
| "\n" |
| "in vec4 data[];\n" |
| "out vec4 result;\n" |
| "\n" |
| "void testFunc(inout vec4 arg)\n" |
| "{\n" |
| " arg += vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data[0]);\n" |
| "\n" |
| " gl_Position = data[0];\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_TE_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(4, 0); |
| *out_target_shader_stage_ptr = SHADER_STAGE_TESSELLATION_EVALUATION; |
| |
| *out_body_ptr = "#version 400\n" |
| "\n" |
| "layout(triangles) in;\n" |
| "\n" |
| "in vec4 data[];\n" |
| "out vec4 result;\n" |
| "\n" |
| "void testFunc(out vec4 arg)\n" |
| "{\n" |
| " arg = vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data[0]);\n" |
| "\n" |
| " gl_Position = data[0];\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_VS_VARIABLE: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 1); |
| *out_target_shader_stage_ptr = SHADER_STAGE_VERTEX; |
| |
| *out_body_ptr = "#version 140\n" |
| "\n" |
| "in vec4 data;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " data += vec4(1.0);\n" |
| " gl_Position = data;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_VS_VARIABLE_PASSED_TO_INOUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 1); |
| *out_target_shader_stage_ptr = SHADER_STAGE_VERTEX; |
| |
| *out_body_ptr = "#version 140\n" |
| "\n" |
| "in vec4 data;\n" |
| "\n" |
| "void testFunc(inout vec4 argument)\n" |
| "{\n" |
| " argument += vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data);\n" |
| "\n" |
| " gl_Position = data;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INPUT_VS_VARIABLE_PASSED_TO_OUT_FUNCTION_PARAMETER: |
| { |
| *out_required_min_context_type_ptr = glu::ApiType::core(3, 1); |
| *out_target_shader_stage_ptr = SHADER_STAGE_VERTEX; |
| |
| *out_body_ptr = "#version 140\n" |
| "\n" |
| "in vec4 data;\n" |
| "\n" |
| "void testFunc(out vec4 argument)\n" |
| "{\n" |
| " argument = vec4(1.0);\n" |
| "}\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " testFunc(data);\n" |
| "\n" |
| " gl_Position = data;\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Unrecognized test iteration type"); |
| } /* switch (iteration) */ |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult InputVariablesCannotBeModifiedTest::iterate() |
| { |
| const glu::ContextType context_type = m_context.getRenderContext().getType(); |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = true; |
| |
| /* Create shader objects */ |
| if (glu::contextSupports(context_type, glu::ApiType::core(3, 2))) |
| { |
| m_gs_id = gl.createShader(GL_GEOMETRY_SHADER); |
| } |
| |
| if (glu::contextSupports(context_type, glu::ApiType::core(4, 0))) |
| { |
| m_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER); |
| m_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER); |
| } |
| |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed."); |
| |
| /* Execute all test iterations.. */ |
| for (int current_iteration = static_cast<int>(TEST_ITERATION_FIRST); |
| current_iteration < static_cast<int>(TEST_ITERATION_COUNT); current_iteration++) |
| { |
| glw::GLint compile_status = GL_FALSE; |
| std::string current_iteration_body; |
| const char* current_iteration_body_raw_ptr = NULL; |
| glu::ApiType current_iteration_min_context_type; |
| _shader_stage current_iteration_shader_stage; |
| glw::GLuint so_id = 0; |
| |
| getIterationData(static_cast<_test_iteration>(current_iteration), ¤t_iteration_min_context_type, |
| ¤t_iteration_shader_stage, ¤t_iteration_body); |
| |
| current_iteration_body_raw_ptr = current_iteration_body.c_str(); |
| |
| /* Determine shader ID for the iteration. If the shader stage is not supported |
| * for the running context, skip it. */ |
| if (!glu::contextSupports(context_type, current_iteration_min_context_type)) |
| { |
| continue; |
| } |
| |
| switch (current_iteration_shader_stage) |
| { |
| case SHADER_STAGE_FRAGMENT: |
| so_id = m_fs_id; |
| break; |
| case SHADER_STAGE_GEOMETRY: |
| so_id = m_gs_id; |
| break; |
| case SHADER_STAGE_TESSELLATION_CONTROL: |
| so_id = m_tc_id; |
| break; |
| case SHADER_STAGE_TESSELLATION_EVALUATION: |
| so_id = m_te_id; |
| break; |
| case SHADER_STAGE_VERTEX: |
| so_id = m_vs_id; |
| break; |
| |
| default: |
| { |
| TCU_FAIL("Unrecognized shader stage type"); |
| } |
| } /* switch (current_iteration_shader_stage) */ |
| |
| DE_ASSERT(so_id != 0); |
| |
| /* Assign the source code to the SO */ |
| gl.shaderSource(so_id, 1, /* count */ |
| ¤t_iteration_body_raw_ptr, DE_NULL); /* length */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Try to compile the shader object. */ |
| gl.compileShader(so_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| char temp[1024]; |
| |
| gl.getShaderInfoLog(so_id, 1024, NULL, temp); |
| |
| if (compile_status == GL_TRUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "The following " |
| << getShaderStageName(current_iteration_shader_stage) |
| << " shader, used for test iteration [" |
| << getIterationName(static_cast<_test_iteration>(current_iteration)) |
| << "] " |
| "was compiled successfully, even though it is invalid. Body:" |
| "\n>>\n" |
| << current_iteration_body << "\n<<\n" |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| } /* for (all test iterations) */ |
| |
| m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); |
| |
| return STOP; |
| } |
| |
| /** Returns a literal corresponding to the shader stage enum used by the test. |
| * |
| * @param stage Shader stage to use for the query. |
| * |
| * @return Requested string. |
| **/ |
| std::string InputVariablesCannotBeModifiedTest::getShaderStageName(_shader_stage stage) const |
| { |
| std::string result = "?!"; |
| |
| switch (stage) |
| { |
| case SHADER_STAGE_FRAGMENT: |
| result = "fragment shader"; |
| break; |
| case SHADER_STAGE_GEOMETRY: |
| result = "geometry shader"; |
| break; |
| case SHADER_STAGE_TESSELLATION_CONTROL: |
| result = "tessellation control shader"; |
| break; |
| case SHADER_STAGE_TESSELLATION_EVALUATION: |
| result = "tessellation evaluation shader"; |
| break; |
| case SHADER_STAGE_VERTEX: |
| result = "vertex shader"; |
| break; |
| } /* switch (stage) */ |
| |
| return result; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| * @param name Test name |
| * @param description Test description |
| */ |
| InvalidUseCasesForAllNotFuncsAndExclMarkOpTest::InvalidUseCasesForAllNotFuncsAndExclMarkOpTest(deqp::Context& context) |
| : deqp::TestCase(context, "CommonBug_InvalidUseCasesForAllNotFuncsAndExclMarkOp", |
| "Verifies that ! operator does not accept bvec{2,3,4} arguments, " |
| "all() and not() functions do not accept a bool argument.") |
| , m_vs_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes all GL objects created for the purpose of running the test, |
| * as well as any client-side buffers allocated at initialization time |
| */ |
| void InvalidUseCasesForAllNotFuncsAndExclMarkOpTest::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| } |
| |
| /** Dummy init function */ |
| void InvalidUseCasesForAllNotFuncsAndExclMarkOpTest::init() |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Retrieves a literal corresponding to the test iteration enum. |
| * |
| * @param iteration Enum to retrieve the string for. |
| * |
| * @return Requested object. |
| **/ |
| std::string InvalidUseCasesForAllNotFuncsAndExclMarkOpTest::getIterationName(_test_iteration iteration) const |
| { |
| std::string result; |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_EXCL_MARK_OP_MUST_NOT_ACCEPT_BVEC2: |
| result = "! operator must not accept bvec2 arg"; |
| break; |
| case TEST_ITERATION_EXCL_MARK_OP_MUST_NOT_ACCEPT_BVEC3: |
| result = "! operator must not accept bvec3 arg"; |
| break; |
| case TEST_ITERATION_EXCL_MARK_OP_MUST_NOT_ACCEPT_BVEC4: |
| result = "! operator must not accept bvec4 arg"; |
| break; |
| case TEST_ITERATION_ALL_FUNC_MUST_NOT_ACCEPT_BOOL: |
| result = "all() function must not accept bool arg"; |
| break; |
| case TEST_ITERATION_NOT_FUNC_MUST_NOT_ACCEPT_BOOL: |
| result = "not() function must not accept bool arg"; |
| break; |
| default: |
| { |
| TCU_FAIL("Unrecognized test iteration type."); |
| } |
| } /* switch (iteration) */ |
| |
| return result; |
| } |
| |
| /** Retrieves a vertex shader body for the user-specified iteration enum. |
| * |
| * @param iteration Iteration to retrieve the shader body for. |
| * |
| * @return Requested string object. |
| */ |
| std::string InvalidUseCasesForAllNotFuncsAndExclMarkOpTest::getShaderBody(_test_iteration iteration) const |
| { |
| std::string result; |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_EXCL_MARK_OP_MUST_NOT_ACCEPT_BVEC2: |
| case TEST_ITERATION_EXCL_MARK_OP_MUST_NOT_ACCEPT_BVEC3: |
| case TEST_ITERATION_EXCL_MARK_OP_MUST_NOT_ACCEPT_BVEC4: |
| { |
| /* From GL SL spec: |
| * |
| * The logical unary operator not (!). It operates only on a Boolean expression and results in a Boolean |
| * expression. To operate on a vector, use the built-in function not. |
| */ |
| std::stringstream result_sstream; |
| std::string type_string; |
| |
| type_string = (iteration == TEST_ITERATION_EXCL_MARK_OP_MUST_NOT_ACCEPT_BVEC2) ? |
| "bvec2" : |
| (iteration == TEST_ITERATION_EXCL_MARK_OP_MUST_NOT_ACCEPT_BVEC3) ? "bvec3" : "bvec4"; |
| |
| result_sstream << "#version 140\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (!" |
| << type_string << "(false))\n" |
| " {\n" |
| " gl_Position = vec4(1.0, 2.0, 3.0, 4.0);\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " gl_Position = vec4(2.0, 3.0, 4.0, 5.0);\n" |
| " }\n" |
| "}\n"; |
| |
| result = result_sstream.str(); |
| break; |
| } |
| |
| case TEST_ITERATION_ALL_FUNC_MUST_NOT_ACCEPT_BOOL: |
| case TEST_ITERATION_NOT_FUNC_MUST_NOT_ACCEPT_BOOL: |
| { |
| std::string op_string; |
| std::stringstream result_sstream; |
| |
| /* From GLSL spec, all() and not() functions are defined as: |
| * |
| * bool all(bvec x) |
| * bvec not(bvec x) |
| * |
| * where bvec is bvec2, bvec3 or bvec4. |
| */ |
| op_string = (iteration == TEST_ITERATION_ALL_FUNC_MUST_NOT_ACCEPT_BOOL) ? "all" : "not"; |
| |
| result_sstream << "#version 140\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(" |
| << op_string << "(false, true) ? 1.0 : 2.0);\n" |
| "}\n"; |
| |
| result = result_sstream.str(); |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Unrecognized test iteration type"); |
| } /* switch (iteration) */ |
| |
| return result; |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult InvalidUseCasesForAllNotFuncsAndExclMarkOpTest::iterate() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = true; |
| |
| /* Create a vertex shader object */ |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed."); |
| |
| /* Execute all test iterations.. */ |
| for (int current_iteration = static_cast<int>(TEST_ITERATION_FIRST); |
| current_iteration < static_cast<int>(TEST_ITERATION_COUNT); ++current_iteration) |
| { |
| const std::string body = getShaderBody(static_cast<_test_iteration>(current_iteration)); |
| const char* body_raw_ptr = body.c_str(); |
| glw::GLint compile_status = GL_FALSE; |
| |
| /* Assign the source code to the SO */ |
| gl.shaderSource(m_vs_id, 1, /* count */ |
| &body_raw_ptr, DE_NULL); /* length */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Try to compile the shader object. */ |
| gl.compileShader(m_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status == GL_TRUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "The following vertex shader, used for test iteration [" |
| << getIterationName(static_cast<_test_iteration>(current_iteration)) |
| << "] " |
| "was compiled successfully, even though it is invalid. Body:" |
| "\n>>\n" |
| << body << "\n<<\n" |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| } /* for (all test iterations) */ |
| |
| m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); |
| |
| return STOP; |
| } |
| |
| InvalidVSInputsTest::InvalidVSInputsTest(deqp::Context& context) |
| : TestCase(context, "CommonBug_InvalidVSInputs", |
| "Verifies that invalid types, as well as incompatible qualifiers, are " |
| "not accepted for vertex shader input variable declarations") |
| , m_vs_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes all GL objects created for the purpose of running the test, |
| * as well as any client-side buffers allocated at initialization time |
| */ |
| void InvalidVSInputsTest::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_vs_id != 0) |
| { |
| gl.deleteShader(m_vs_id); |
| |
| m_vs_id = 0; |
| } |
| } |
| |
| /** Dummy init function */ |
| void InvalidVSInputsTest::init() |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Retrieves a literal corresponding to the test iteration enum. |
| * |
| * @param iteration Enum to retrieve the string for. |
| * |
| * @return Requested object. |
| **/ |
| std::string InvalidVSInputsTest::getIterationName(_test_iteration iteration) const |
| { |
| std::string result; |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_INVALID_BOOL_INPUT: |
| result = "Invalid bool input"; |
| break; |
| case TEST_ITERATION_INVALID_BVEC2_INPUT: |
| result = "Invalid bvec2 input"; |
| break; |
| case TEST_ITERATION_INVALID_BVEC3_INPUT: |
| result = "Invalid bvec3 input"; |
| break; |
| case TEST_ITERATION_INVALID_BVEC4_INPUT: |
| result = "Invalid bvec4 input"; |
| break; |
| case TEST_ITERATION_INVALID_CENTROID_QUALIFIED_INPUT: |
| result = "Invalid centroid-qualified input"; |
| break; |
| case TEST_ITERATION_INVALID_PATCH_QUALIFIED_INPUT: |
| result = "Invalid patch-qualified input"; |
| break; |
| case TEST_ITERATION_INVALID_OPAQUE_TYPE_INPUT: |
| result = "Invalid opaque type input"; |
| break; |
| case TEST_ITERATION_INVALID_STRUCTURE_INPUT: |
| result = "Invalid structure input"; |
| break; |
| case TEST_ITERATION_INVALID_SAMPLE_QUALIFIED_INPUT: |
| result = "Invalid sample-qualified input"; |
| break; |
| |
| default: |
| TCU_FAIL("Unrecognized test iteration type."); |
| } /* switch (iteration) */ |
| |
| return result; |
| } |
| |
| /** Retrieves a vertex shader body for the user-specified iteration enum. |
| * |
| * @param iteration Iteration to retrieve the shader body for. |
| * |
| * @return Requested string object. |
| */ |
| std::string InvalidVSInputsTest::getShaderBody(_test_iteration iteration) const |
| { |
| std::string result; |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_INVALID_BOOL_INPUT: |
| case TEST_ITERATION_INVALID_BVEC2_INPUT: |
| case TEST_ITERATION_INVALID_BVEC3_INPUT: |
| case TEST_ITERATION_INVALID_BVEC4_INPUT: |
| { |
| std::stringstream body_sstream; |
| const char* type = (iteration == TEST_ITERATION_INVALID_BOOL_INPUT) ? |
| "bool" : |
| (iteration == TEST_ITERATION_INVALID_BVEC2_INPUT) ? |
| "bvec2" : |
| (iteration == TEST_ITERATION_INVALID_BVEC3_INPUT) ? "bvec3" : "bvec4"; |
| |
| body_sstream << "#version 140\n" |
| "\n" |
| "in " |
| << type << " data;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "}\n"; |
| |
| result = body_sstream.str(); |
| break; |
| } |
| |
| case TEST_ITERATION_INVALID_OPAQUE_TYPE_INPUT: |
| { |
| result = "#version 140\n" |
| "\n" |
| "in sampler2D data;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INVALID_STRUCTURE_INPUT: |
| { |
| result = "#version 140\n" |
| "\n" |
| "in struct\n" |
| "{\n" |
| " vec4 test;\n" |
| "} data;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_INVALID_CENTROID_QUALIFIED_INPUT: |
| case TEST_ITERATION_INVALID_PATCH_QUALIFIED_INPUT: |
| case TEST_ITERATION_INVALID_SAMPLE_QUALIFIED_INPUT: |
| { |
| std::stringstream body_sstream; |
| const char* qualifier = (iteration == TEST_ITERATION_INVALID_CENTROID_QUALIFIED_INPUT) ? |
| "centroid" : |
| (iteration == TEST_ITERATION_INVALID_PATCH_QUALIFIED_INPUT) ? "patch" : "sample"; |
| |
| body_sstream << "#version 140\n" |
| "\n" |
| << qualifier << " in vec4 data;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "}\n"; |
| |
| result = body_sstream.str(); |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Unrecognized test iteration type"); |
| } /* switch (iteration) */ |
| |
| return result; |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult InvalidVSInputsTest::iterate() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = true; |
| |
| /* Create a vertex shader object */ |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed."); |
| |
| /* Execute all test iterations.. */ |
| for (int current_iteration = static_cast<int>(TEST_ITERATION_FIRST); |
| current_iteration < static_cast<int>(TEST_ITERATION_COUNT); current_iteration++) |
| { |
| const std::string body = getShaderBody(static_cast<_test_iteration>(current_iteration)); |
| const char* body_raw_ptr = body.c_str(); |
| glw::GLint compile_status = GL_FALSE; |
| |
| /* Assign the source code to the SO */ |
| gl.shaderSource(m_vs_id, 1, /* count */ |
| &body_raw_ptr, DE_NULL); /* length */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Try to compile the shader object. */ |
| gl.compileShader(m_vs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status == GL_TRUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "The following vertex shader, used for test iteration [" |
| << getIterationName(static_cast<_test_iteration>(current_iteration)) |
| << "] " |
| "was compiled successfully, even though it is invalid. Body:" |
| "\n>>\n" |
| << body << "\n<<\n" |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| } /* for (all test iterations) */ |
| |
| m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); |
| |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| * @param name Test name |
| * @param description Test description |
| */ |
| ParenthesisInLayoutQualifierIntegerValuesTest::ParenthesisInLayoutQualifierIntegerValuesTest(deqp::Context& context) |
| : TestCase(context, "CommonBug_ParenthesisInLayoutQualifierIntegerValue", |
| "Verifies parenthesis are not accepted in compute shaders, prior to GL4.4, " |
| "unless GL_ARB_enhanced_layouts is supported.") |
| , m_cs_id(0) |
| , m_po_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes all GL objects created for the purpose of running the test, |
| * as well as any client-side buffers allocated at initialization time |
| */ |
| void ParenthesisInLayoutQualifierIntegerValuesTest::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_cs_id != 0) |
| { |
| gl.deleteShader(m_cs_id); |
| |
| m_cs_id = 0; |
| } |
| |
| if (m_po_id != 0) |
| { |
| gl.deleteProgram(m_po_id); |
| |
| m_po_id = 0; |
| } |
| } |
| |
| /** Dummy init function */ |
| void ParenthesisInLayoutQualifierIntegerValuesTest::init() |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult ParenthesisInLayoutQualifierIntegerValuesTest::iterate() |
| { |
| /* Only execute the test on implementations supporting GL_ARB_compute_shader */ |
| const glu::ContextType context_type = m_context.getRenderContext().getType(); |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = true; |
| |
| glw::GLint link_status = GL_TRUE; |
| glw::GLint compile_status = GL_TRUE; |
| bool expected_outcome = glu::contextSupports(context_type, glu::ApiType::core(4, 4)); |
| |
| /* Prepare a compute shader program */ |
| static const char* cs_body_core = "\n" |
| "layout(local_size_x = (4) ) in;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "}\n"; |
| |
| const char* cs_body_parts[] = { (!glu::contextSupports(context_type, glu::ApiType::core(4, 3))) ? |
| "#version 420 core\n" |
| "#extension GL_ARB_compute_shader : enable\n" : |
| (!glu::contextSupports(context_type, glu::ApiType::core(4, 4))) ? |
| "#version 430 core\n" : |
| "#version 440 core\n", |
| cs_body_core }; |
| const unsigned int n_cs_body_parts = |
| static_cast<unsigned int>(sizeof(cs_body_parts) / sizeof(cs_body_parts[0])); |
| |
| if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader")) |
| { |
| goto end; |
| } |
| |
| m_cs_id = gl.createShader(GL_COMPUTE_SHADER); |
| m_po_id = gl.createProgram(); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() and/or glCraeteProgram() call(s) failed."); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); |
| |
| gl.shaderSource(m_cs_id, n_cs_body_parts, cs_body_parts, DE_NULL); /* length */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Try to compile the shader object. |
| * |
| * For GL contexts BEFORE 4.40, the test passes if either |
| * the compilation or the linking process fails. |
| * |
| * For GL contexts OF VERSION 4.40 or newer, the test passes |
| * if both the compilation and the linking process succeed. |
| * |
| * If GL_ARB_enhanced_layouts is supported, the latter holds for <= GL4.4 contexts. |
| **/ |
| if (m_context.getContextInfo().isExtensionSupported("GL_ARB_enhanced_layouts")) |
| { |
| expected_outcome = true; |
| } |
| |
| gl.compileShader(m_cs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| gl.getShaderiv(m_cs_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status == GL_FALSE && !expected_outcome) |
| { |
| goto end; |
| } |
| |
| gl.attachShader(m_po_id, m_cs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed."); |
| |
| gl.linkProgram(m_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); |
| |
| gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); |
| |
| if (link_status == GL_FALSE && !expected_outcome) |
| { |
| goto end; |
| } |
| |
| if (expected_outcome && (compile_status == GL_FALSE || link_status == GL_FALSE)) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "A compute program was expected to link successfully, but either the " |
| "compilation and/or linking process has/have failed" |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| else if (!expected_outcome && (compile_status == GL_TRUE && link_status == GL_TRUE)) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "A compute program was expected not to compile and link, but both processes " |
| "have been executed successfully." |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| end: |
| m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); |
| |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| * @param name Test name |
| * @param description Test description |
| */ |
| PerVertexValidationTest::PerVertexValidationTest(deqp::Context& context) |
| : TestCase(context, "CommonBug_PerVertexValidation", |
| "Conformance test which verifies that various requirements regarding gl_PerVertex block re-declarations," |
| " as described by the spec, are followed by the implementation") |
| , m_fs_id(0) |
| , m_fs_po_id(0) |
| , m_gs_id(0) |
| , m_gs_po_id(0) |
| , m_pipeline_id(0) |
| , m_tc_id(0) |
| , m_tc_po_id(0) |
| , m_te_id(0) |
| , m_te_po_id(0) |
| , m_vs_id(0) |
| , m_vs_po_id(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Deinitializes all GL objects created for the purpose of running the test, |
| * as well as any client-side buffers allocated at initialization time |
| */ |
| void PerVertexValidationTest::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Release the pipeline object */ |
| if (m_pipeline_id != 0) |
| { |
| gl.deleteProgramPipelines(1, &m_pipeline_id); |
| |
| m_pipeline_id = 0; |
| } |
| |
| /* Release all dangling shader and shader program objects */ |
| destroyPOsAndSOs(); |
| } |
| |
| /** Releases any allocated program and shader objects. */ |
| void PerVertexValidationTest::destroyPOsAndSOs() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| glw::GLuint* po_id_ptrs[] = { &m_fs_po_id, &m_gs_po_id, &m_tc_po_id, &m_te_po_id, &m_vs_po_id }; |
| glw::GLuint* so_id_ptrs[] = { &m_fs_id, &m_gs_id, &m_tc_id, &m_te_id, &m_vs_id }; |
| const unsigned int n_po_id_ptrs = static_cast<unsigned int>(sizeof(po_id_ptrs) / sizeof(po_id_ptrs[0])); |
| const unsigned int n_so_id_ptrs = static_cast<unsigned int>(sizeof(so_id_ptrs) / sizeof(so_id_ptrs[0])); |
| |
| for (unsigned int n_po_id = 0; n_po_id < n_po_id_ptrs; ++n_po_id) |
| { |
| glw::GLuint* po_id_ptr = po_id_ptrs[n_po_id]; |
| |
| if (*po_id_ptr != 0) |
| { |
| gl.deleteProgram(*po_id_ptr); |
| |
| *po_id_ptr = 0; |
| } |
| } /* for (all shader program object ids) */ |
| |
| for (unsigned int n_so_id = 0; n_so_id < n_so_id_ptrs; ++n_so_id) |
| { |
| glw::GLuint* so_id_ptr = so_id_ptrs[n_so_id]; |
| |
| if (*so_id_ptr != 0) |
| { |
| gl.deleteShader(*so_id_ptr); |
| |
| *so_id_ptr = 0; |
| } |
| } /* for (all shader object ids) */ |
| } |
| |
| /** Tells whether the program pipeline validation process should fail for specified test iteration. |
| * |
| * @return VALIDATION_RESULT_TRUE if the pipeline validation process should be positive, |
| * VALIDATION_RESULT_FALSE if the validation should be negative |
| * VALIDATION_RESULT_UNDEFINED when the validation result is not defined */ |
| PerVertexValidationTest::_validation PerVertexValidationTest::getProgramPipelineValidationExpectedResult(void) const |
| { |
| /** All "undeclared in.." and "undeclared out.." test shaders are expected not to link successfully |
| * when used as separate programs - which leaves pipeline in undefined state. |
| * All "declaration mismatch" shaders should link, but the results are undefined. |
| * |
| * Currently the test does not exercise any defined case |
| */ |
| return VALIDATION_RESULT_UNDEFINED; |
| } |
| |
| /** Returns a literal corresponding to the shader stage enum. |
| * |
| * @param shader_stage Enum to return the string for. |
| * |
| * @return As per description. |
| */ |
| std::string PerVertexValidationTest::getShaderStageName(_shader_stage shader_stage) const |
| { |
| std::string result = "?!"; |
| |
| switch (shader_stage) |
| { |
| case SHADER_STAGE_FRAGMENT: |
| result = "fragment shader"; |
| break; |
| case SHADER_STAGE_GEOMETRY: |
| result = "geometry shader"; |
| break; |
| case SHADER_STAGE_TESSELLATION_CONTROL: |
| result = "tessellation control shader"; |
| break; |
| case SHADER_STAGE_TESSELLATION_EVALUATION: |
| result = "tessellation evaluation shader"; |
| break; |
| case SHADER_STAGE_VERTEX: |
| result = "vertex shader"; |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Returns a literal corresponding to the test iteration enum. |
| * |
| * @param iteration Enum to return the string for. |
| * |
| * @return As per description. |
| **/ |
| std::string PerVertexValidationTest::getTestIterationName(_test_iteration iteration) const |
| { |
| std::string result = "?!"; |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE: |
| result = "Input gl_ClipDistance usage in Geometry Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CULLDISTANCE_USAGE: |
| result = "Input gl_CullDistance usage in Geometry Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POINTSIZE_USAGE: |
| result = "Input gl_PointSize usage in a separable Geometry Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POSITION_USAGE: |
| result = "Input gl_Position usage in a separable Geometry Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE: |
| result = "Input gl_ClipDistance usage in a separable Tessellation Control Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CULLDISTANCE_USAGE: |
| result = "Input gl_CullDistance usage in a separable Tessellation Control Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POINTSIZE_USAGE: |
| result = "Input gl_PointSize usage in a separable Tessellation Control Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POSITION_USAGE: |
| result = "Input gl_Position usage in a separable Tessellation Control Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE: |
| result = "Input gl_ClipDistance usage in a separable Tessellation Evaluation Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CULLDISTANCE_USAGE: |
| result = "Input gl_CullDistance usage in a separable Tessellation Evaluation Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POINTSIZE_USAGE: |
| result = "Input gl_PointSize usage in a separable Tessellation Evaluation Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POSITION_USAGE: |
| result = "Input gl_Position usage in a separable Tessellation Evaluation Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE: |
| result = "Output gl_ClipDistance usage in Geometry Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CULLDISTANCE_USAGE: |
| result = "Output gl_CullDistance usage in Geometry Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POINTSIZE_USAGE: |
| result = "Output gl_PointSize usage in a separable Geometry Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POSITION_USAGE: |
| result = "Output gl_Position usage in a separable Geometry Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE: |
| result = "Output gl_ClipDistance usage in a separable Tessellation Control Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CULLDISTANCE_USAGE: |
| result = "Output gl_CullDistance usage in a separable Tessellation Control Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POINTSIZE_USAGE: |
| result = "Output gl_PointSize usage in a separable Tessellation Control Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POSITION_USAGE: |
| result = "Output gl_Position usage in a separable Tessellation Control Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE: |
| result = "Output gl_ClipDistance usage in a separable Tessellation Evaluation Shader without gl_PerVertex " |
| "block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CULLDISTANCE_USAGE: |
| result = "Output gl_CullDistance usage in a separable Tessellation Evaluation Shader without gl_PerVertex " |
| "block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POINTSIZE_USAGE: |
| result = "Output gl_PointSize usage in a separable Tessellation Evaluation Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POSITION_USAGE: |
| result = "Output gl_Position usage in a separable Tessellation Evaluation Shader without gl_PerVertex block " |
| "redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CLIPDISTANCE_USAGE: |
| result = "Output gl_ClipDistance usage in a separable Vertex Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CULLDISTANCE_USAGE: |
| result = "Output gl_CullDistance usage in a separable Vertex Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_POINTSIZE_USAGE: |
| result = "Output gl_PointSize usage in a separable Vertex Shader without gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_POSITION_USAGE: |
| result = "Output gl_Position usage in a separable Vertex Shader without gl_PerVertex block redeclaration"; |
| break; |
| |
| case TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_GS_VS: |
| result = "Geometry and Vertex Shaders use different gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_GS_TC_TE_VS: |
| result = "Geometry, Tessellation Control, Tessellation Evaluation and Vertex Shaders use a different " |
| "gl_PerVertex block redeclaration"; |
| break; |
| case TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_TC_TE_VS: |
| result = "Tesselation Control, Tessellation Evaluation and Vertex Shaders use a different gl_PerVertex block " |
| "redeclaration"; |
| break; |
| |
| case TEST_ITERATION_PERVERTEX_BLOCK_UNDEFINED: |
| result = "No gl_PerVertex block defined in shader programs for all shader stages supported by the running " |
| "context"; |
| break; |
| default: |
| result = "Unknown"; |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Returns shader bodies, minimum context type and a bitfield describing shader stages used for the |
| * user-specified test iteration enum. |
| * |
| * @param context_type Running context's type. |
| * @param iteration Test iteration enum to return the properties for. |
| * @param out_min_context_type_ptr Deref will be set to the minimum context type supported by the |
| * specified test iteration. |
| * @param out_used_shader_stages_ptr Deref will be set to a combination of _shader_stage enum values, |
| * describing which shader stages are used by the test iteration. |
| * @param out_gs_body_ptr Deref will be updated with the geometry shader body, if used by the |
| * test iteration. |
| * @param out_tc_body_ptr Deref will be updated with the tessellation control shader body, if |
| * used by the test iteration. |
| * @param out_te_body_ptr Deref will be updated with the tessellation evaluation shader body, if |
| * used by the test iteration. |
| * @param out_vs_body_ptr Deref will be updated with the vertex shader body, if used by the |
| * test iteration. |
| * |
| */ |
| void PerVertexValidationTest::getTestIterationProperties(glu::ContextType context_type, _test_iteration iteration, |
| glu::ContextType* out_min_context_type_ptr, |
| _shader_stage* out_used_shader_stages_ptr, |
| std::string* out_gs_body_ptr, std::string* out_tc_body_ptr, |
| std::string* out_te_body_ptr, |
| std::string* out_vs_body_ptr) const |
| { |
| const bool include_cull_distance = glu::contextSupports(context_type, glu::ApiType::core(4, 5)); |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CULLDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POINTSIZE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POSITION_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CULLDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POINTSIZE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POSITION_USAGE: |
| { |
| const bool is_cull_distance_iteration = |
| (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CULLDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CULLDISTANCE_USAGE); |
| std::stringstream gs_body_sstream; |
| |
| *out_min_context_type_ptr = (is_cull_distance_iteration) ? glu::ContextType(4, 5, glu::PROFILE_CORE) : |
| glu::ContextType(4, 1, glu::PROFILE_CORE); |
| *out_used_shader_stages_ptr = (_shader_stage)(SHADER_STAGE_GEOMETRY | SHADER_STAGE_VERTEX); |
| |
| /* Form the geometry shader body */ |
| gs_body_sstream << ((!is_cull_distance_iteration) ? "#version 410\n" : "version 450\n") |
| << "\n" |
| "layout(points) in;\n" |
| "layout(points, max_vertices = 1) out;\n" |
| "\n" |
| "in gl_PerVertex\n" |
| "{\n"; |
| |
| gs_body_sstream << ((iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE) ? |
| "float gl_ClipDistance[];\n" : |
| ""); |
| gs_body_sstream << ((iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POINTSIZE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POINTSIZE_USAGE) ? |
| "float gl_PointSize;\n" : |
| ""); |
| gs_body_sstream << ((iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POSITION_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POSITION_USAGE) ? |
| "vec4 gl_Position;\n" : |
| ""); |
| |
| if (include_cull_distance) |
| { |
| gs_body_sstream << "float gl_CullDistance[];\n"; |
| } |
| |
| gs_body_sstream << "} gl_in[];\n" |
| "\n" |
| "out gl_PerVertex\n" |
| "{\n"; |
| |
| gs_body_sstream << ((iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE) ? |
| "float gl_ClipDistance[];\n" : |
| ""); |
| gs_body_sstream << ((iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POINTSIZE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POINTSIZE_USAGE) ? |
| "float gl_PointSize;\n" : |
| ""); |
| gs_body_sstream << ((iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POSITION_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POSITION_USAGE) ? |
| "vec4 gl_Position;\n" : |
| ""); |
| |
| if (include_cull_distance) |
| { |
| gs_body_sstream << "float gl_CullDistance[];\n"; |
| } |
| |
| gs_body_sstream << "};\n" |
| "\n" |
| "void main()\n" |
| "{\n"; |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE: |
| gs_body_sstream << "gl_Position = vec4(gl_in[0].gl_ClipDistance[0]);\n"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CULLDISTANCE_USAGE: |
| gs_body_sstream << "gl_Position = vec4(gl_in[0].gl_CullDistance[0]);\n"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POINTSIZE_USAGE: |
| gs_body_sstream << "gl_Position = vec4(gl_in[0].gl_PointSize);\n"; |
| break; |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POSITION_USAGE: |
| gs_body_sstream << "gl_Position = gl_in[0].gl_Position;\n"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE: |
| gs_body_sstream << "gl_ClipDistance[0] = gl_in[0].gl_Position.x;\n"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CULLDISTANCE_USAGE: |
| gs_body_sstream << "gl_CullDistance[0] = gl_in[0].gl_Position.x;\n"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POINTSIZE_USAGE: |
| gs_body_sstream << "gl_PointSize = gl_in[0].gl_Position.x;\n"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POSITION_USAGE: |
| gs_body_sstream << "gl_Position = vec4(gl_in[0].gl_PointSize);\n"; |
| break; |
| default: |
| gs_body_sstream << "\n"; |
| break; |
| } /* switch (iteration) */ |
| |
| gs_body_sstream << " EmitVertex();\n" |
| "}\n"; |
| |
| /* Store geometry & vertex shader bodies */ |
| *out_gs_body_ptr = gs_body_sstream.str(); |
| *out_vs_body_ptr = getVertexShaderBody(context_type, iteration); |
| |
| break; |
| } |
| |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CULLDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POINTSIZE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POSITION_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CULLDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POINTSIZE_USAGE: |
| case TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POSITION_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CULLDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POINTSIZE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POSITION_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CULLDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POINTSIZE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POSITION_USAGE: |
| { |
| std::stringstream tc_sstream; |
| std::stringstream te_sstream; |
| |
| const bool is_clip_distance_iteration = |
| (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE); |
| const bool is_cull_distance_iteration = |
| (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CULLDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CULLDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CULLDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CULLDISTANCE_USAGE); |
| const bool is_pointsize_iteration = |
| (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POINTSIZE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POINTSIZE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POINTSIZE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POINTSIZE_USAGE); |
| const bool is_position_iteration = (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POSITION_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POSITION_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POSITION_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POSITION_USAGE); |
| |
| *out_min_context_type_ptr = (is_cull_distance_iteration) ? glu::ContextType(4, 5, glu::PROFILE_CORE) : |
| glu::ContextType(4, 0, glu::PROFILE_CORE); |
| *out_used_shader_stages_ptr = (_shader_stage)(SHADER_STAGE_TESSELLATION_CONTROL | |
| SHADER_STAGE_TESSELLATION_EVALUATION | SHADER_STAGE_VERTEX); |
| |
| /* Form tessellation control & tessellation evaluation shader bodies */ |
| for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration) |
| { |
| const bool is_tc_stage = (n_iteration == 0); |
| std::stringstream* current_sstream_ptr = (is_tc_stage) ? &tc_sstream : &te_sstream; |
| |
| *current_sstream_ptr << ((is_cull_distance_iteration) ? "#version 450 core\n" : "#version 410\n") << "\n"; |
| |
| if (is_tc_stage) |
| { |
| *current_sstream_ptr << "layout (vertices = 4) out;\n"; |
| } |
| else |
| { |
| *current_sstream_ptr << "layout (isolines) in;\n"; |
| } |
| |
| *current_sstream_ptr << "\n" |
| "in gl_PerVertex\n" |
| "{\n"; |
| |
| if (is_position_iteration) |
| { |
| *current_sstream_ptr << "vec4 gl_Position;\n"; |
| } |
| |
| if (!is_pointsize_iteration) |
| { |
| *current_sstream_ptr << "float gl_PointSize\n"; |
| } |
| |
| if (!is_clip_distance_iteration) |
| { |
| *current_sstream_ptr << "float gl_ClipDistance[];\n"; |
| } |
| |
| if (!is_cull_distance_iteration && include_cull_distance) |
| { |
| *current_sstream_ptr << "float gl_CullDistance[];\n"; |
| } |
| |
| *current_sstream_ptr << "} gl_in[gl_MaxPatchVertices];\n" |
| "\n" |
| "out gl_PerVertex\n" |
| "{\n"; |
| |
| if (!is_position_iteration) |
| { |
| *current_sstream_ptr << "vec4 gl_Position;\n"; |
| } |
| |
| if (!is_pointsize_iteration) |
| { |
| *current_sstream_ptr << "float gl_PointSize\n"; |
| } |
| |
| if (!is_clip_distance_iteration) |
| { |
| *current_sstream_ptr << "float gl_ClipDistance[];\n"; |
| } |
| |
| if (!is_cull_distance_iteration && include_cull_distance) |
| { |
| *current_sstream_ptr << "float gl_CullDistance[];\n"; |
| } |
| |
| if (is_tc_stage) |
| { |
| *current_sstream_ptr << "} gl_out[];\n"; |
| } |
| else |
| { |
| *current_sstream_ptr << "};\n"; |
| } |
| |
| *current_sstream_ptr << "\n" |
| "void main()\n" |
| "{\n"; |
| |
| if (is_tc_stage) |
| { |
| *current_sstream_ptr << "gl_out[gl_InvocationID]."; |
| } |
| |
| if (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE) |
| { |
| *current_sstream_ptr << "gl_Position = vec4(gl_in[0].gl_ClipDistance[0]);\n"; |
| } |
| else if (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CULLDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CULLDISTANCE_USAGE) |
| { |
| *current_sstream_ptr << "gl_Position = vec4(gl_in[0].gl_CullDistance[0]);\n"; |
| } |
| else if (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POINTSIZE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POINTSIZE_USAGE) |
| { |
| *current_sstream_ptr << "gl_Position = vec4(gl_in[0].gl_PointSize);\n"; |
| } |
| else if (iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POSITION_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POSITION_USAGE) |
| { |
| *current_sstream_ptr << "gl_Position = gl_in[0].gl_Position;\n"; |
| } |
| else if (iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE) |
| { |
| *current_sstream_ptr << "gl_ClipDistance[0] = gl_in[0].gl_Position.x;\n"; |
| } |
| else if (iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CULLDISTANCE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CULLDISTANCE_USAGE) |
| { |
| *current_sstream_ptr << "gl_CullDistance[0] = gl_in[0].gl_Position.x;\n"; |
| } |
| else if (iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POINTSIZE_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POINTSIZE_USAGE) |
| { |
| *current_sstream_ptr << "gl_PointSize = gl_in[0].gl_Position.x;\n"; |
| } |
| else if (iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POSITION_USAGE || |
| iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POSITION_USAGE) |
| { |
| *current_sstream_ptr << "gl_Position = vec4(gl_in[0].gl_PointSize);\n"; |
| } |
| |
| tc_sstream << "}\n"; |
| } /* for (both TC and TE stages) */ |
| |
| /* Store the bodies */ |
| *out_tc_body_ptr = tc_sstream.str(); |
| *out_te_body_ptr = te_sstream.str(); |
| *out_vs_body_ptr = getVertexShaderBody(context_type, iteration); |
| |
| break; |
| } |
| |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CLIPDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CULLDISTANCE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_POINTSIZE_USAGE: |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_POSITION_USAGE: |
| { |
| const bool is_cull_distance_iteration = |
| (iteration == TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CULLDISTANCE_USAGE); |
| |
| *out_min_context_type_ptr = (is_cull_distance_iteration) ? glu::ContextType(4, 5, glu::PROFILE_CORE) : |
| glu::ContextType(4, 1, glu::PROFILE_CORE); |
| *out_used_shader_stages_ptr = (_shader_stage)(SHADER_STAGE_VERTEX); |
| |
| /* Determine what the main() body contents should be. */ |
| std::string vs_main_body; |
| |
| switch (iteration) |
| { |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CLIPDISTANCE_USAGE: |
| vs_main_body = "gl_ClipDistance[0] = 1.0;"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CULLDISTANCE_USAGE: |
| vs_main_body = "gl_CullDistance[0] = 2.0;"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_POINTSIZE_USAGE: |
| vs_main_body = "gl_PointSize = 1.0;"; |
| break; |
| case TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_POSITION_USAGE: |
| vs_main_body = "gl_Position = vec4(1.0f, 2.0, 3.0, 4.0);"; |
| break; |
| default: |
| vs_main_body = ""; |
| break; |
| } |
| |
| /* Store the body */ |
| *out_vs_body_ptr = getVertexShaderBody(context_type, iteration, vs_main_body); |
| |
| break; |
| } |
| |
| case TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_GS_VS: |
| case TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_GS_TC_TE_VS: |
| case TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_TC_TE_VS: |
| { |
| *out_min_context_type_ptr = glu::ContextType(4, 1, glu::PROFILE_CORE); |
| int used_shader_stages = SHADER_STAGE_VERTEX; |
| |
| if (iteration == TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_GS_TC_TE_VS || |
| iteration == TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_GS_VS) |
| { |
| used_shader_stages |= SHADER_STAGE_GEOMETRY; |
| } |
| |
| if (iteration == TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_GS_TC_TE_VS || |
| iteration == TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_TC_TE_VS) |
| { |
| used_shader_stages |= |
| SHADER_STAGE_TESSELLATION_CONTROL | SHADER_STAGE_TESSELLATION_EVALUATION; |
| } |
| |
| *out_used_shader_stages_ptr = (_shader_stage) used_shader_stages; |
| |
| /* Shader bodies are predefined in this case. */ |
| *out_gs_body_ptr = "#version 410\n" |
| "\n" |
| "layout (points) in;\n" |
| "layout (points, max_vertices = 4) out;\n" |
| "\n" |
| "in gl_PerVertex\n" |
| "{\n" |
| " float gl_ClipDistance[];\n" |
| "} gl_in[];\n" |
| "\n" |
| "out gl_PerVertex\n" |
| "{\n" |
| " float gl_ClipDistance[];\n" |
| "};\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_ClipDistance[0] = 0.5;\n" |
| " EmitVertex();\n" |
| "}\n"; |
| *out_tc_body_ptr = "#version 410\n" |
| "\n" |
| "layout (vertices = 4) out;\n" |
| "\n" |
| "in gl_PerVertex\n" |
| "{\n" |
| " float gl_PointSize;\n" |
| "} gl_in[];\n" |
| "\n" |
| "out gl_PerVertex\n" |
| "{\n" |
| " float gl_PointSize;\n" |
| "} gl_out[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_out[gl_InvocationID].gl_PointSize = gl_in[0].gl_PointSize + 1.0;\n" |
| "}\n"; |
| *out_te_body_ptr = "#version 410\n" |
| "\n" |
| "layout (isolines) in;\n" |
| "\n" |
| "in gl_PerVertex\n" |
| "{\n" |
| " float gl_PointSize;\n" |
| " vec4 gl_Position;\n" |
| "} gl_in[gl_MaxPatchVertices];\n" |
| "\n" |
| "out gl_PerVertex\n" |
| "{\n" |
| " float gl_PointSize;\n" |
| " vec4 gl_Position;\n" |
| "};\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(gl_in[0].gl_PointSize) + gl_in[1].gl_Position;\n" |
| "}\n"; |
| *out_vs_body_ptr = "#version 410\n" |
| "\n" |
| "out gl_PerVertex\n" |
| "{\n" |
| " vec4 gl_Position;\n" |
| "};\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(2.0);\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| case TEST_ITERATION_PERVERTEX_BLOCK_UNDEFINED: |
| { |
| *out_min_context_type_ptr = glu::ContextType(4, 1, glu::PROFILE_CORE); |
| int used_shader_stages = SHADER_STAGE_VERTEX; |
| |
| if (glu::contextSupports(context_type, glu::ApiType::core(3, 2))) |
| { |
| used_shader_stages |= SHADER_STAGE_GEOMETRY; |
| } |
| |
| if (glu::contextSupports(context_type, glu::ApiType::core(4, 0))) |
| { |
| used_shader_stages |= |
| SHADER_STAGE_TESSELLATION_CONTROL | SHADER_STAGE_TESSELLATION_EVALUATION; |
| } |
| |
| *out_used_shader_stages_ptr = (_shader_stage) used_shader_stages; |
| |
| *out_gs_body_ptr = "#version 410\n" |
| "\n" |
| "layout (points) in;\n" |
| "layout (points, max_vertices = 4) out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(1.0, 2.0, 3.0, 4.0);\n" |
| " EmitVertex();\n" |
| "}\n"; |
| *out_tc_body_ptr = "#version 410\n" |
| "\n" |
| "layout(vertices = 4) out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" |
| "}\n"; |
| *out_te_body_ptr = "#version 410\n" |
| "\n" |
| "layout (isolines) in;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = gl_in[0].gl_Position;\n" |
| "}\n"; |
| *out_vs_body_ptr = "#version 410\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(1.0, 2.0, 3.0, 4.0);\n" |
| "}\n"; |
| |
| break; |
| } |
| |
| default: |
| TCU_FAIL("Unrecognized test iteration"); |
| } /* switch (iteration) */ |
| } |
| |
| /** Returns a dummy vertex shader body, with main() entry-point using code passed by |
| * the @param main_body argument. |
| * |
| * @param context_type Running rendering context's type. |
| * @param iteration Test iteration to return the vertex shader body for. |
| * @param main_body Body to use for the main() entry-point. |
| * |
| * @return Requested object. |
| **/ |
| std::string PerVertexValidationTest::getVertexShaderBody(glu::ContextType context_type, _test_iteration iteration, |
| std::string main_body) const |
| { |
| const bool include_clip_distance = (iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CLIPDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CLIPDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CLIPDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CLIPDISTANCE_USAGE); |
| const bool include_cull_distance = (iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_CULLDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_CULLDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_CULLDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_CULLDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_CULLDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_CULLDISTANCE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_CULLDISTANCE_USAGE && |
| glu::contextSupports(context_type, glu::ApiType::core(4, 5))); |
| const bool include_pointsize = (iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POINTSIZE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POINTSIZE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POINTSIZE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POINTSIZE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POINTSIZE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POINTSIZE_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_POINTSIZE_USAGE); |
| const bool include_position = (iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_GS_GL_POSITION_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TC_GL_POSITION_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_IN_PERVERTEX_TE_GL_POSITION_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_GS_GL_POSITION_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TC_GL_POSITION_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_TE_GL_POSITION_USAGE && |
| iteration != TEST_ITERATION_UNDECLARED_OUT_PERVERTEX_VS_GL_POSITION_USAGE); |
| std::stringstream vs_body_sstream; |
| |
| vs_body_sstream << "#version " << ((include_cull_distance) ? "450" : "410") << "\n" |
| << "\n" |
| "in gl_PerVertex\n" |
| "{\n"; |
| |
| vs_body_sstream << ((include_clip_distance) ? "float gl_ClipDistance[];\n" : ""); |
| vs_body_sstream << ((include_pointsize) ? "float gl_PointSize;\n" : ""); |
| vs_body_sstream << ((include_position) ? "vec4 gl_Position;\n" : ""); |
| vs_body_sstream << ((include_cull_distance) ? "float gl_CullDistance[];\n" : ""); |
| |
| vs_body_sstream << "};\n" |
| "\n" |
| "out gl_PerVertex\n" |
| "{\n"; |
| |
| vs_body_sstream << ((include_clip_distance) ? "float gl_ClipDistance[];\n" : ""); |
| vs_body_sstream << ((include_pointsize) ? "float gl_PointSize;\n" : ""); |
| vs_body_sstream << ((include_position) ? "vec4 gl_Position;\n" : ""); |
| vs_body_sstream << ((include_cull_distance) ? "float gl_CullDistance[];\n" : ""); |
| |
| vs_body_sstream << "};\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " " |
| << main_body << "\n" |
| "}\n"; |
| |
| return vs_body_sstream.str(); |
| } |
| |
| /** Dummy init function */ |
| void PerVertexValidationTest::init() |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Executes test iteration. |
| * |
| * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. |
| */ |
| tcu::TestNode::IterateResult PerVertexValidationTest::iterate() |
| { |
| const glu::ContextType context_type = m_context.getRenderContext().getType(); |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = true; |
| |
| /* Separable program objects went into core in GL 4.1 */ |
| if (!glu::contextSupports(context_type, glu::ApiType::core(4, 1))) |
| { |
| throw tcu::NotSupportedError("Test implemented for OpenGL 4.1 contexts or newer."); |
| } |
| |
| /* Each test iteration is going to be executed in two different modes: |
| * |
| * 1) Create separate shader programs for each stage. They should link just fine. |
| * Then create a pipeline and attach to it all the programs. At this stage, the |
| * validation should report failure. |
| * |
| * 2) Create a single separate shader program, holding all stages. Try to link it. |
| * This process should report failure. |
| */ |
| for (int test_iteration = static_cast<int>(TEST_ITERATION_FIRST); |
| test_iteration != static_cast<int>(TEST_ITERATION_COUNT); test_iteration++) |
| { |
| for (unsigned int n_test_mode = 0; n_test_mode < 2; ++n_test_mode) |
| { |
| /* Skip the second iteration if any of the shaders is expected not to compile. */ |
| if (isShaderProgramLinkingFailureExpected(static_cast<_test_iteration>(test_iteration))) |
| { |
| continue; |
| } |
| |
| /* Execute the actual test iteration */ |
| switch (n_test_mode) |
| { |
| case 0: |
| result &= runPipelineObjectValidationTestMode(static_cast<_test_iteration>(test_iteration)); |
| break; |
| case 1: |
| result &= runSeparateShaderTestMode(static_cast<_test_iteration>(test_iteration)); |
| break; |
| } |
| |
| /* Clean up */ |
| destroyPOsAndSOs(); |
| |
| if (m_pipeline_id != 0) |
| { |
| gl.deleteProgramPipelines(1, /* n */ |
| &m_pipeline_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgramPipelines() call failed"); |
| } |
| } /* for (both test modes) */ |
| } /* for (all test iterations) */ |
| m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail"); |
| |
| return STOP; |
| } |
| |
| /** Tells whether the linking process should fail for specified test iteration. |
| * |
| * @param iteration Test iteration to query. |
| * |
| * @return true if the linking process should fail, false otherwise */ |
| bool PerVertexValidationTest::isShaderProgramLinkingFailureExpected(_test_iteration iteration) const |
| { |
| /** All "undeclared in.." and "undeclared out.." test shaders are expected not to link successfully |
| * when used as separate programs. |
| * Shaders built as a part of the remaining test iterations should compile and link successfully |
| * for separate programs implementing only a single shader stage. Later on, however, pipeline |
| * objects built of these programs should fail to validate, as they use incompatible gl_PerVertex |
| * block redeclarations. |
| */ |
| return (iteration < TEST_ITERATION_PERVERTEX_DECLARATION_MISMATCH_GS_VS) || |
| iteration == TEST_ITERATION_PERVERTEX_BLOCK_UNDEFINED; |
| } |
| |
| /** Runs the specified test iteration in the following mode: |
| * |
| * >> |
| * A pipeline object is created and shader programs are attached to it. It is expected that validation |
| * should fail. |
| * << |
| * |
| * @param iteration Test iteration to execute. |
| * |
| * @return true if the test passed, false otherwise. |
| */ |
| bool PerVertexValidationTest::runPipelineObjectValidationTestMode(_test_iteration iteration) |
| { |
| const glu::ContextType context_type = m_context.getRenderContext().getType(); |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = false; |
| |
| const char* body_raw_ptr = NULL; |
| glw::GLenum expected_result = getProgramPipelineValidationExpectedResult(); |
| std::string fs_body; |
| std::string gs_body; |
| glw::GLint link_status; |
| glu::ContextType min_context_type; |
| std::string tc_body; |
| std::string te_body; |
| _shader_stage used_shader_stages; |
| glw::GLint validate_status; |
| glw::GLint validate_expected_status; |
| std::string vs_body; |
| |
| struct _shader_program |
| { |
| std::string* body_ptr; |
| glw::GLuint* po_id_ptr; |
| _shader_stage shader_stage; |
| glw::GLenum shader_stage_bit_gl; |
| glw::GLenum shader_stage_gl; |
| } shader_programs[] = { |
| { &fs_body, &m_fs_po_id, SHADER_STAGE_FRAGMENT, GL_FRAGMENT_SHADER_BIT, GL_FRAGMENT_SHADER }, |
| { &gs_body, &m_gs_po_id, SHADER_STAGE_GEOMETRY, GL_GEOMETRY_SHADER_BIT, GL_GEOMETRY_SHADER }, |
| { &tc_body, &m_tc_po_id, SHADER_STAGE_TESSELLATION_CONTROL, GL_TESS_CONTROL_SHADER_BIT, |
| GL_TESS_CONTROL_SHADER }, |
| { &te_body, &m_te_po_id, SHADER_STAGE_TESSELLATION_EVALUATION, GL_TESS_EVALUATION_SHADER_BIT, |
| GL_TESS_EVALUATION_SHADER }, |
| { &vs_body, &m_vs_po_id, SHADER_STAGE_VERTEX, GL_VERTEX_SHADER_BIT, GL_VERTEX_SHADER }, |
| }; |
| const unsigned int n_shader_programs = |
| static_cast<unsigned int>(sizeof(shader_programs) / sizeof(shader_programs[0])); |
| |
| /* Make sure the test iteration can actually be run under the running rendering context |
| * version. |
| */ |
| getTestIterationProperties(context_type, iteration, &min_context_type, &used_shader_stages, &gs_body, &tc_body, |
| &te_body, &vs_body); |
| |
| if (!glu::contextSupports(context_type, min_context_type.getAPI())) |
| { |
| result = true; |
| |
| goto end; |
| } |
| |
| /* Set up shader program objects. All shader bodies by themselves are valid, so all shaders should |
| * link just fine. */ |
| for (unsigned int n_shader_program = 0; n_shader_program < n_shader_programs; ++n_shader_program) |
| { |
| _shader_program& current_shader_program = shader_programs[n_shader_program]; |
| |
| if ((used_shader_stages & current_shader_program.shader_stage) != 0) |
| { |
| body_raw_ptr = current_shader_program.body_ptr->c_str(); |
| *current_shader_program.po_id_ptr = |
| gl.createShaderProgramv(current_shader_program.shader_stage_gl, 1, /* count */ |
| &body_raw_ptr); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed."); |
| |
| gl.getProgramiv(*current_shader_program.po_id_ptr, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); |
| |
| if (link_status != GL_TRUE) |
| { |
| char info_log[4096]; |
| |
| if (!isShaderProgramLinkingFailureExpected(iteration)) |
| { |
| gl.getProgramInfoLog(*current_shader_program.po_id_ptr, sizeof(info_log), DE_NULL, /* length */ |
| info_log); |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << "The separate " |
| << getShaderStageName(current_shader_program.shader_stage) |
| << " program " |
| "failed to link, even though the shader body is valid.\n" |
| "\n" |
| "Body:\n>>\n" |
| << *current_shader_program.body_ptr << "<<\nInfo log\n>>\n" |
| << info_log << "<<\n" |
| << tcu::TestLog::EndMessage; |
| } |
| else |
| { |
| result = true; |
| } |
| |
| goto end; |
| } /* if (link_status != GL_TRUE) */ |
| } /* for (all shader programs) */ |
| } /* for (all shader stages) */ |
| |
| /* Now that all shader programs are ready, set up a test-specific pipeline object and validate it. */ |
| gl.genProgramPipelines(1, &m_pipeline_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed."); |
| |
| gl.bindProgramPipeline(m_pipeline_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed."); |
| |
| for (unsigned int n_shader_program = 0; n_shader_program < n_shader_programs; ++n_shader_program) |
| { |
| _shader_program& current_shader_program = shader_programs[n_shader_program]; |
| |
| if ((used_shader_stages & current_shader_program.shader_stage) != 0) |
| { |
| gl.useProgramStages(m_pipeline_id, current_shader_program.shader_stage_bit_gl, |
| *current_shader_program.po_id_ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed."); |
| } |
| } /* for (all shader programs) */ |
| |
| gl.validateProgramPipeline(m_pipeline_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed."); |
| |
| gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed."); |
| |
| if (VALIDATION_RESULT_UNDEFINED != expected_result) |
| { |
| switch (expected_result) |
| { |
| case VALIDATION_RESULT_FALSE: |
| validate_expected_status = GL_FALSE; |
| break; |
| case VALIDATION_RESULT_TRUE: |
| validate_expected_status = GL_TRUE; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| if (validate_status != validate_expected_status) |
| { |
| tcu::MessageBuilder message = m_testCtx.getLog().message(); |
| |
| if (GL_FALSE == validate_expected_status) |
| { |
| message << "A pipeline object was validated successfully, even though one"; |
| } |
| else |
| { |
| message << "A pipeline object was validated negatively, even though none"; |
| } |
| |
| message << " of the failure reasons given by spec was applicable.\n" |
| << "\n" |
| "Fragment shader body:\n>>\n" |
| << ((shader_programs[0].body_ptr->length() > 0) ? *shader_programs[0].body_ptr : "[not used]") |
| << "\n<<\nGeometry shader body:\n>>\n" |
| << ((shader_programs[1].body_ptr->length() > 0) ? *shader_programs[1].body_ptr : "[not used]") |
| << "\n<<\nTessellation control shader body:\n>>\n" |
| << ((shader_programs[2].body_ptr->length() > 0) ? *shader_programs[2].body_ptr : "[not used]") |
| << "\n<<\nTessellation evaluation shader body:\n>>\n" |
| << ((shader_programs[3].body_ptr->length() > 0) ? *shader_programs[3].body_ptr : "[not used]") |
| << "\n<<\nVertex shader body:\n>>\n" |
| << ((shader_programs[4].body_ptr->length() > 0) ? *shader_programs[4].body_ptr : "[not used]") |
| << tcu::TestLog::EndMessage; |
| } /* if (validate_status != validate_expected_status) */ |
| else |
| { |
| result = true; |
| } |
| } |
| else |
| { |
| result = true; |
| } |
| |
| end: |
| return result; |
| } |
| |
| /** Runs the specified test iteration in the following mode: |
| * |
| * >> |
| * A single separate shader program, to which all shader stages used by the test are attached, is linked. |
| * It is expected the linking process should fail. |
| * << |
| * |
| * @param iteration Test iteration to execute. |
| * |
| * @return true if the test passed, false otherwise. |
| */ |
| bool PerVertexValidationTest::runSeparateShaderTestMode(_test_iteration iteration) |
| { |
| glw::GLint compile_status; |
| glu::ContextType context_type = m_context.getRenderContext().getType(); |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| glw::GLint link_status; |
| glu::ContextType min_context_type; |
| bool result = false; |
| _shader_stage used_shader_stages; |
| |
| std::string fs_body; |
| std::string gs_body; |
| std::string tc_body; |
| std::string te_body; |
| std::string vs_body; |
| |
| struct _shader |
| { |
| std::string* body_ptr; |
| glw::GLuint* so_id_ptr; |
| _shader_stage shader_stage; |
| glw::GLenum shader_stage_bit_gl; |
| glw::GLenum shader_stage_gl; |
| } shaders[] = { { &fs_body, &m_fs_id, SHADER_STAGE_FRAGMENT, GL_FRAGMENT_SHADER_BIT, GL_FRAGMENT_SHADER }, |
| { &gs_body, &m_gs_id, SHADER_STAGE_GEOMETRY, GL_GEOMETRY_SHADER_BIT, GL_GEOMETRY_SHADER }, |
| { &tc_body, &m_tc_id, SHADER_STAGE_TESSELLATION_CONTROL, GL_TESS_CONTROL_SHADER_BIT, |
| GL_TESS_CONTROL_SHADER }, |
| { &te_body, &m_te_id, SHADER_STAGE_TESSELLATION_EVALUATION, GL_TESS_EVALUATION_SHADER_BIT, |
| GL_TESS_EVALUATION_SHADER }, |
| { &vs_body, &m_vs_id, SHADER_STAGE_VERTEX, GL_VERTEX_SHADER_BIT, GL_VERTEX_SHADER } }; |
| const unsigned int n_shaders = static_cast<unsigned int>(sizeof(shaders) / sizeof(shaders[0])); |
| |
| /* Retrieve iteration properties */ |
| getTestIterationProperties(context_type, iteration, &min_context_type, &used_shader_stages, &gs_body, &tc_body, |
| &te_body, &vs_body); |
| |
| if (!glu::contextSupports(context_type, min_context_type.getAPI())) |
| { |
| result = true; |
| |
| goto end; |
| } |
| |
| /* Bake a single shader with separate programs defined for all shader stages defined by the iteration |
| * and see what happens. |
| * |
| * For simplicity, we re-use m_vs_po_id to store the program object ID. |
| */ |
| m_vs_po_id = gl.createProgram(); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); |
| |
| for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader) |
| { |
| const char* body_raw_ptr = DE_NULL; |
| const std::string& current_body = *shaders[n_shader].body_ptr; |
| const _shader_stage& current_shader_stage = shaders[n_shader].shader_stage; |
| glw::GLuint& current_so_id = *shaders[n_shader].so_id_ptr; |
| const glw::GLenum& current_so_type_gl = shaders[n_shader].shader_stage_gl; |
| |
| if ((used_shader_stages & current_shader_stage) != 0) |
| { |
| body_raw_ptr = current_body.c_str(); |
| current_so_id = gl.createShader(current_so_type_gl); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed."); |
| |
| gl.shaderSource(current_so_id, 1, /* count */ |
| &body_raw_ptr, DE_NULL); /* length */ |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); |
| |
| /* Ensure the shader compiled successfully. */ |
| gl.compileShader(current_so_id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); |
| |
| gl.getShaderiv(current_so_id, GL_COMPILE_STATUS, &compile_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); |
| |
| if (compile_status != GL_TRUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << getShaderStageName(current_shader_stage) |
| << " unexpectedly failed to compile.\n" |
| "\nBody:\n>>\n" |
| << current_body << "\n<<\n" |
| << tcu::TestLog::EndMessage; |
| |
| goto end; |
| } |
| |
| /* Attach the shader object to the test program object */ |
| gl.attachShader(m_vs_po_id, current_so_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed."); |
| } /* if ((used_shader_stages & current_shader_stage) != 0) */ |
| } /* for (all shader objects) */ |
| |
| /* Mark the program as separable */ |
| gl.programParameteri(m_vs_po_id, GL_PROGRAM_SEPARABLE, GL_TRUE); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed."); |
| |
| /* Try to link the program and check the result. */ |
| gl.linkProgram(m_vs_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); |
| |
| gl.getProgramiv(m_vs_po_id, GL_LINK_STATUS, &link_status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); |
| |
| if (link_status == GL_TRUE) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Separable program, consisting of the following separate shaders, was linked " |
| "successfully, despite incompatible or missing gl_PerVertex block re-declarations.\n" |
| "\n" |
| "Fragment shader program:\n>>\n" |
| << ((fs_body.length() > 0) ? fs_body : "[not used]") |
| << "\n<<\nGeometry shader program:\n>>\n" |
| << ((gs_body.length() > 0) ? gs_body : "[not used]") |
| << "\n<<\nTessellation control shader program:\n>>\n" |
| << ((tc_body.length() > 0) ? tc_body : "[not used]") |
| << "\n<<\nTessellation evaluation shader program:\n>>\n" |
| << ((te_body.length() > 0) ? te_body : "[not used]") << "\n<<\nVertex shader program:\n>>\n" |
| << ((vs_body.length() > 0) ? vs_body : "[not used]") << tcu::TestLog::EndMessage; |
| |
| goto end; |
| } /* if (link_status == GL_TRUE) */ |
| |
| /* All done */ |
| result = true; |
| end: |
| if (!result) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Failed test description: " << getTestIterationName(iteration) |
| << tcu::TestLog::EndMessage; |
| } |
| return result; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| * @param name Test name |
| * @param description Test description |
| */ |
| ReservedNamesTest::ReservedNamesTest(deqp::Context& context) |
| : TestCase(context, "CommonBug_ReservedNames", |
| "Verifies that reserved variable names are rejected by the GL SL compiler" |
| " at the compilation time.") |
| , m_max_fs_ssbos(0) |
| , m_max_gs_acs(0) |
| , m_max_gs_ssbos(0) |
| , m_max_tc_acs(0) |
| , m_max_tc_ssbos(0) |
| , m_max_te_acs(0) |
| , m_max_te_ssbos(0) |
| , m_max_vs_acs(0) |
| , m_max_vs_ssbos(0) |
| { |
| memset(m_so_ids, 0, sizeof(m_so_ids)); |
| } |
| |
| /** Deinitializes all GL objects created for the purpose of running the test, |
| * as well as any client-side buffers allocated at initialization time |
| */ |
| void ReservedNamesTest::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| for (unsigned int n_so_id = 0; n_so_id < sizeof(m_so_ids) / sizeof(m_so_ids[0]); ++n_so_id) |
| { |
| const glw::GLuint current_so_id = m_so_ids[n_so_id]; |
| |
| if (current_so_id != 0) |
| { |
| gl.deleteShader(current_so_id); |
| } |
| } /* for (all usedshader object IDs) */ |
| } |
| |
| /** Returns a literal corresponding to the specified @param language_feature value. |
| * |
| * @param language_feature Enum to return the string object for. |
| * |
| * @return As specified. |
| */ |
| std::string ReservedNamesTest::getLanguageFeatureName(_language_feature language_feature) const |
| { |
| std::string result = "[?!]"; |
| |
| switch (language_feature) |
| { |
| case LANGUAGE_FEATURE_ATOMIC_COUNTER: |
| result = "atomic counter"; |
| break; |
| case LANGUAGE_FEATURE_ATTRIBUTE: |
| result = "attribute"; |
| break; |
| case LANGUAGE_FEATURE_CONSTANT: |
| result = "constant"; |
| break; |
| case LANGUAGE_FEATURE_FUNCTION_ARGUMENT_NAME: |
| result = "function argument name"; |
| break; |
| case LANGUAGE_FEATURE_FUNCTION_NAME: |
| result = "function name"; |
| break; |
| case LANGUAGE_FEATURE_INPUT: |
| result = "input variable"; |
| break; |
| case LANGUAGE_FEATURE_INPUT_BLOCK_INSTANCE_NAME: |
| result = "input block instance name"; |
| break; |
| case LANGUAGE_FEATURE_INPUT_BLOCK_MEMBER_NAME: |
| result = "input block member name"; |
| break; |
| case LANGUAGE_FEATURE_INPUT_BLOCK_NAME: |
| result = "input block name"; |
| break; |
| case LANGUAGE_FEATURE_OUTPUT: |
| result = "output variable"; |
| break; |
| case LANGUAGE_FEATURE_OUTPUT_BLOCK_INSTANCE_NAME: |
| result = "output block instance name"; |
| break; |
| case LANGUAGE_FEATURE_OUTPUT_BLOCK_MEMBER_NAME: |
| result = "output block member name"; |
| break; |
| case LANGUAGE_FEATURE_OUTPUT_BLOCK_NAME: |
| result = "output block name"; |
| break; |
| case LANGUAGE_FEATURE_SHADER_STORAGE_BLOCK_INSTANCE_NAME: |
| result = "shader storage block instance name"; |
| break; |
| case LANGUAGE_FEATURE_SHADER_STORAGE_BLOCK_MEMBER_NAME: |
| result = "shader storage block member name"; |
| break; |
| case LANGUAGE_FEATURE_SHADER_STORAGE_BLOCK_NAME: |
| result = "shader storage block name"; |
| break; |
| case LANGUAGE_FEATURE_SHARED_VARIABLE: |
| result = "shared variable"; |
| break; |
| case LANGUAGE_FEATURE_STRUCTURE_MEMBER: |
| result = "structure member"; |
| break; |
| case LANGUAGE_FEATURE_STRUCTURE_INSTANCE_NAME: |
| result = "structure instance name"; |
| break; |
| case LANGUAGE_FEATURE_STRUCTURE_NAME: |
| result = "structure name"; |
| break; |
| case LANGUAGE_FEATURE_SUBROUTINE_FUNCTION_NAME: |
| result = "subroutine function name"; |
| break; |
| case LANGUAGE_FEATURE_SUBROUTINE_TYPE: |
| result = "subroutine type"; |
| break; |
| case LANGUAGE_FEATURE_SUBROUTINE_UNIFORM: |
| result = "subroutine uniform"; |
| break; |
| case LANGUAGE_FEATURE_UNIFORM: |
| result = "uniform"; |
| break; |
| case LANGUAGE_FEATURE_UNIFORM_BLOCK_INSTANCE_NAME: |
| result = "uniform block instance name"; |
| break; |
| case LANGUAGE_FEATURE_UNIFORM_BLOCK_MEMBER_NAME: |
| result = "uniform block member name"; |
| break; |
| case LANGUAGE_FEATURE_UNIFORM_BLOCK_NAME: |
| result = "uniform block name"; |
| break; |
| case LANGUAGE_FEATURE_VARIABLE: |
| result = "variable"; |
| break; |
| case LANGUAGE_FEATURE_VARYING: |
| result = "varying"; |
| break; |
| default: |
| result = "unknown"; |
| break; |
| } /* switch (language_feature) */ |
| |
| return result; |
| } |
| |
| /** Returns keywords and reserved names, specific to the running context version. */ |
| std::vector<std::string> ReservedNamesTest::getReservedNames() const |
| { |
| const glu::ContextType context_type = m_context.getRenderContext().getType(); |
| std::vector<std::string> result; |
| |
| const char** context_keywords = NULL; |
| unsigned int context_n_keywords = 0; |
| unsigned int context_n_reserved = 0; |
| const char** context_reserved = NULL; |
| |
| /* Keywords and reserved names were taken straight from relevant shading language specification documents */ |
| static const char* keywords_gl31[] = { |
| "attribute", |
| "const", |
| "uniform", |
| "varying", |
| "layout", |
| "centroid", |
| "flat", |
| "smooth", |
| "noperspective", |
| "break", |
| "continue", |
| "do", |
| "for", |
| "while", |
| "switch", |
| "case", |
| "default", |
| "if", |
| "else", |
| "in", |
| "out", |
| "inout", |
| "float", |
| "int", |
| "void", |
| "bool", |
| "true", |
| "false", |
| "invariant", |
| "discard", |
| "return", |
| "mat2", |
| "mat3", |
| "mat4", |
| "mat2x2", |
| "mat2x3", |
| "mat2x4", |
| "mat3x2", |
| "mat3x3", |
| "mat3x4", |
| "mat4x2", |
| "mat4x3", |
| "mat4x4", |
| "vec2", |
| "vec3", |
| "vec4", |
| "ivec2", |
| "ivec3", |
| "ivec4", |
| "bvec2", |
| "bvec3", |
| "bvec4", |
| "uint", |
| "uvec2", |
| "uvec3", |
| "uvec4", |
| "lowp", |
| "mediump", |
| "highp", |
| "precision", |
| "sampler1D", |
| "sampler2D", |
| "sampler3D", |
| "samplerCube", |
| "sampler1DShadow", |
| "sampler2DShadow", |
| "samplerCubeShadow", |
| "sampler1DArray", |
| "sampler2DArray", |
| "sampler1DArrayShadow", |
| "sampler2DArrayShadow", |
| "isampler1D", |
| "isampler2D", |
| "isampler3D", |
| "isamplerCube", |
| "isampler1DArray", |
| "isampler2DArray", |
| "usampler1D", |
| "usampler2D", |
| "usampler3D", |
| "usamplerCube", |
| "usampler1DArray", |
| "usampler2DArray", |
| "sampler2DRect", |
| "sampler2DRectShadow", |
| "isampler2DRect", |
| "usampler2DRect", |
| "samplerBuffer", |
| "isamplerBuffer", |
| "usamplerBuffer", |
| }; |
| static const char* keywords_gl32[] = { |
| "attribute", |
| "const", |
| "uniform", |
| "varying", |
| "layout", |
| "centroid", |
| "flat", |
| "smooth", |
| "noperspective", |
| "break", |
| "continue", |
| "do", |
| "for", |
| "while", |
| "switch", |
| "case", |
| "default", |
| "if", |
| "else", |
| "in", |
| "out", |
| "inout", |
| "float", |
| "int", |
| "void", |
| "bool", |
| "true", |
| "false", |
| "invariant", |
| "discard", |
| "return", |
| "mat2", |
| "mat3", |
| "mat4", |
| "mat2x2", |
| "mat2x3", |
| "mat2x4", |
| "mat3x2", |
| "mat3x3", |
| "mat3x4", |
| "mat4x2", |
| "mat4x3", |
| "mat4x4", |
| "vec2", |
| "vec3", |
| "vec4", |
| "ivec2", |
| "ivec3", |
| "ivec4", |
| "bvec2", |
| "bvec3", |
| "bvec4", |
| "uint", |
| "uvec2", |
| "uvec3", |
| "uvec4", |
| "lowp", |
| "mediump", |
| "highp", |
| "precision", |
| "sampler1D", |
| "sampler2D", |
| "sampler3D", |
| "samplerCube", |
| "sampler1DShadow", |
| "sampler2DShadow", |
| "samplerCubeShadow", |
| "sampler1DArray", |
| "sampler2DArray", |
| "sampler1DArrayShadow", |
| "sampler2DArrayShadow", |
| "isampler1D", |
| "isampler2D", |
| "isampler3D", |
| "isamplerCube", |
| "isampler1DArray", |
| "isampler2DArray", |
| "usampler1D", |
| "usampler2D", |
| "usampler3D", |
| "usamplerCube", |
| "usampler1DArray", |
| "usampler2DArray", |
| "sampler2DRect", |
| "sampler2DRectShadow", |
| "isampler2DRect", |
| "usampler2DRect", |
| "samplerBuffer", |
| "isamplerBuffer", |
| "usamplerBuffer", |
| "sampler2DMS", |
| "isampler2DMS", |
| "usampler2DMS", |
| "sampler2DMSArray", |
| "isampler2DMSArray", |
| "usampler2DMSArray", |
| }; |
| static const char* keywords_gl33[] = { |
| "attribute", |
| "const", |
| "uniform", |
| "varying", |
| "layout", |
| "centroid", |
| "flat", |
| "smooth", |
| "noperspective", |
| "break", |
| "continue", |
| "do", |
| "for", |
| "while", |
| "switch", |
| "case", |
| "default", |
| "if", |
| "else", |
| "in", |
| "out", |
| "inout", |
| "float", |
| "int", |
| "void", |
| "bool", |
| "true", |
| "false", |
| "invariant", |
| "discard", |
|