blob: 927a7d168f01196d3c3d0e4240afc6063a14921d [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2015-2016 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/ /*!
* \file
* \brief
*/ /*-------------------------------------------------------------------*/
/**
*/ /*!
* \file 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), &current_iteration_min_context_type,
&current_iteration_shader_stage, &current_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 */
&current_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",