blob: d6cc5b407acb08d543329b5304eb25efb29c0b57 [file] [log] [blame] [edit]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2014-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
*/ /*-------------------------------------------------------------------*/
#include "esextcTessellationShaderProperties.hpp"
#include "gluContextInfo.hpp"
#include "gluDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
#include <cmath>
#include <cstring>
namespace glcts
{
/** Constructor
*
* @param context Test context
**/
TessellationShaderPropertiesDefaultContextWideValues::TessellationShaderPropertiesDefaultContextWideValues(
Context &context, const ExtParameters &extParams)
: TestCaseBase(context, extParams, "default_values_of_context_wide_properties",
"Verifies default values of context-wide tessellation stage properties")
{
/* Left blank on purpose */
}
/** Executes the test.
*
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
*
* Note the function throws exception should an error occur!
*
* @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
**/
tcu::TestNode::IterateResult TessellationShaderPropertiesDefaultContextWideValues::iterate(void)
{
/* Do not execute if required extensions are not supported. */
if (!m_is_tessellation_shader_supported)
{
throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
}
/* Iterate through all context-wide properties and compare expected values
* against the reference ones
*/
const float epsilon = (float)1e-5;
const glw::Functions &gl = m_context.getRenderContext().getFunctions();
const glw::GLint property_value_data[] = {/* pname */ /* n components */ /* default value */
static_cast<glw::GLint>(m_glExtTokens.PATCH_VERTICES), 1, 3,
/* The following values are only applicable to Desktop OpenGL. */
GL_PATCH_DEFAULT_OUTER_LEVEL, 4, 1, GL_PATCH_DEFAULT_INNER_LEVEL, 2, 1};
const unsigned int n_properties = (glu::isContextTypeES(m_context.getRenderContext().getType())) ? 1 : 3;
for (unsigned int n_property = 0; n_property < n_properties; ++n_property)
{
glw::GLboolean bool_value[4] = {GL_FALSE};
glw::GLfloat float_value[4] = {0.0f};
glw::GLint int_value[4] = {0};
glw::GLenum pname = property_value_data[n_property * 3 + 0];
glw::GLint n_components = property_value_data[n_property * 3 + 1];
glw::GLint expected_value = property_value_data[n_property * 3 + 2];
/* Call all relevant getters */
gl.getBooleanv(pname, bool_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() failed.");
gl.getFloatv(pname, float_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() failed.");
gl.getIntegerv(pname, int_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed.");
/* Compare retrieved vector value components against expected value */
glw::GLboolean expected_bool_value[4] = {
(expected_value != 0) ? (glw::GLboolean)GL_TRUE : (glw::GLboolean)GL_FALSE,
(expected_value != 0) ? (glw::GLboolean)GL_TRUE : (glw::GLboolean)GL_FALSE,
(expected_value != 0) ? (glw::GLboolean)GL_TRUE : (glw::GLboolean)GL_FALSE,
(expected_value != 0) ? (glw::GLboolean)GL_TRUE : (glw::GLboolean)GL_FALSE};
glw::GLint expected_int_value[4] = {expected_value, expected_value, expected_value, expected_value};
if (memcmp(expected_bool_value, bool_value, sizeof(bool) * n_components) != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "glGetBooleanv() called for pname " << pname
<< " reported invalid value." << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value reported by glGetBooleanv()");
}
if (memcmp(expected_int_value, int_value, sizeof(int) * n_components) != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() called for pname " << pname
<< " reported invalid value." << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value reported by glGetIntegerv()");
}
if ((n_components >= 1 && de::abs(float_value[0] - (float)expected_value) > epsilon) ||
(n_components >= 2 && de::abs(float_value[1] - (float)expected_value) > epsilon) ||
(n_components >= 3 && de::abs(float_value[2] - (float)expected_value) > epsilon) ||
(n_components >= 4 && de::abs(float_value[3] - (float)expected_value) > epsilon))
{
m_testCtx.getLog() << tcu::TestLog::Message << "glGetFloatv() called for pname " << pname
<< " reported invalid value." << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value reported by glGetFloatv()");
}
} /* for (all properties) */
/* All done */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
/** Constructor
*
* @param context Test context
**/
TessellationShaderPropertiesProgramObject::TessellationShaderPropertiesProgramObject(Context &context,
const ExtParameters &extParams)
: TestCaseBase(context, extParams, "program_object_properties",
"Verifies tessellation-specific properties of program objects are reported correctly.")
, m_fs_id(0)
, m_po_id(0)
, m_tc_id(0)
, m_te_id(0)
, m_vs_id(0)
{
/* Left blank on purpose */
}
/** Deinitializes ES objects created for the test */
void TessellationShaderPropertiesProgramObject::deinit(void)
{
/* Call base class' deinit() */
TestCaseBase::deinit();
/* Release any ES objects created */
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_tc_id != 0)
{
gl.deleteShader(m_tc_id);
m_tc_id = 0;
}
if (m_te_id != 0)
{
gl.deleteShader(m_te_id);
m_te_id = 0;
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
}
/** Initializes ES objects necessary to execute the test */
void TessellationShaderPropertiesProgramObject::initTest(void)
{
const glw::Functions &gl = m_context.getRenderContext().getFunctions();
/* Do not execute if required extension is not supported */
if (!m_is_tessellation_shader_supported)
{
return;
}
/* Generate all objects */
m_po_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
m_te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
/* Attach the shader to the program object */
gl.attachShader(m_po_id, m_fs_id);
gl.attachShader(m_po_id, m_tc_id);
gl.attachShader(m_po_id, m_te_id);
gl.attachShader(m_po_id, m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
/* Since this test does not care much about fragment & vertex shaders, set
* their bodies and compile these shaders now */
const char *fs_body = "${VERSION}\n"
"\n"
"void main()\n"
"{\n"
"}\n";
const char *vs_body = "${VERSION}\n"
"\n"
"void main()\n"
"{\n"
"}\n";
glw::GLint fs_compile_status = GL_FALSE;
glw::GLint vs_compile_status = GL_FALSE;
shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed");
gl.compileShader(m_fs_id);
gl.compileShader(m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
gl.getShaderiv(m_fs_id, GL_COMPILE_STATUS, &fs_compile_status);
gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &vs_compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
if (fs_compile_status != GL_TRUE)
{
TCU_FAIL("Could not compile fragment shader");
}
if (vs_compile_status != GL_TRUE)
{
TCU_FAIL("Could not compile vertex shader");
}
}
/** Executes the test.
*
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
*
* Note the function throws exception should an error occur!
*
* @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
**/
tcu::TestNode::IterateResult TessellationShaderPropertiesProgramObject::iterate(void)
{
const glw::Functions &gl = m_context.getRenderContext().getFunctions();
/* Do not execute if required extensions are not supported. */
if (!m_is_tessellation_shader_supported)
{
throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
}
/* Initialize ES test objects */
initTest();
/* Test 1: Default values. Values as per spec, define as little qualifiers as possible */
_test_descriptor test_1;
test_1.expected_control_output_vertices_value = 4;
test_1.expected_gen_mode_value = m_glExtTokens.QUADS;
test_1.expected_gen_point_mode_value = GL_FALSE;
test_1.expected_gen_spacing_value = GL_EQUAL;
test_1.expected_gen_vertex_order_value = GL_CCW;
test_1.tc_body = "${VERSION}\n"
"${TESSELLATION_SHADER_REQUIRE}\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";
test_1.te_body = "${VERSION}\n"
"${TESSELLATION_SHADER_REQUIRE}\n"
"\n"
"layout(quads) in;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_in[0].gl_Position;\n"
"}\n";
/* Test 2: 16 vertices per patch + isolines + fractional_even_spacing + cw combination */
_test_descriptor test_2;
test_2.expected_control_output_vertices_value = 16;
test_2.expected_gen_mode_value = m_glExtTokens.ISOLINES;
test_2.expected_gen_point_mode_value = GL_FALSE;
test_2.expected_gen_spacing_value = m_glExtTokens.FRACTIONAL_EVEN;
test_2.expected_gen_vertex_order_value = GL_CW;
test_2.tc_body = "${VERSION}\n"
"${TESSELLATION_SHADER_REQUIRE}\n"
"\n"
"layout(vertices=16) out;\n"
"\n"
"void main()\n"
"{\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n";
test_2.te_body = "${VERSION}\n"
"${TESSELLATION_SHADER_REQUIRE}\n"
"\n"
"layout(isolines, fractional_even_spacing, cw) in;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_in[0].gl_Position;\n"
"}\n";
/* Test 3: 32 vertices per patch + triangles + fractional_odd_spacing + ccw combination + point mode*/
_test_descriptor test_3;
test_3.expected_control_output_vertices_value = 32;
test_3.expected_gen_mode_value = GL_TRIANGLES;
test_3.expected_gen_point_mode_value = GL_TRUE;
test_3.expected_gen_spacing_value = m_glExtTokens.FRACTIONAL_ODD;
test_3.expected_gen_vertex_order_value = GL_CCW;
test_3.tc_body = "${VERSION}\n"
"${TESSELLATION_SHADER_REQUIRE}\n"
"\n"
"layout(vertices=32) out;\n"
"\n"
"void main()\n"
"{\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n";
test_3.te_body = "${VERSION}\n"
"${TESSELLATION_SHADER_REQUIRE}\n"
"\n"
"layout(triangles, fractional_odd_spacing, ccw, point_mode) in;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_in[0].gl_Position;\n"
"}\n";
/* Test 4: 8 vertices per patch + quads + equal_spacing + ccw combination + point mode*/
_test_descriptor test_4;
test_4.expected_control_output_vertices_value = 8;
test_4.expected_gen_mode_value = m_glExtTokens.QUADS;
test_4.expected_gen_point_mode_value = GL_TRUE;
test_4.expected_gen_spacing_value = GL_EQUAL;
test_4.expected_gen_vertex_order_value = GL_CCW;
test_4.tc_body = "${VERSION}\n"
"${TESSELLATION_SHADER_REQUIRE}\n"
"\n"
"layout(vertices=8) out;\n"
"\n"
"void main()\n"
"{\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n";
test_4.te_body = "${VERSION}\n"
"${TESSELLATION_SHADER_REQUIRE}\n"
"\n"
"layout(quads, equal_spacing, ccw, point_mode) in;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_in[0].gl_Position;\n"
"}\n";
/* Store all tests in a single vector */
_tests tests;
tests.push_back(test_1);
tests.push_back(test_2);
tests.push_back(test_3);
tests.push_back(test_4);
/* Iterate through all the tests and verify the values reported */
for (_tests_const_iterator test_iterator = tests.begin(); test_iterator != tests.end(); test_iterator++)
{
const _test_descriptor &test = *test_iterator;
/* Set tessellation control & evaluation shader bodies. */
shaderSourceSpecialized(m_tc_id, 1 /* count */, &test.tc_body);
shaderSourceSpecialized(m_te_id, 1 /* count */, &test.te_body);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed");
/* Compile the shaders */
gl.compileShader(m_tc_id);
gl.compileShader(m_te_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
/* Make sure the shaders compiled */
glw::GLint tc_compile_status = GL_FALSE;
glw::GLint te_compile_status = GL_FALSE;
gl.getShaderiv(m_tc_id, GL_COMPILE_STATUS, &tc_compile_status);
gl.getShaderiv(m_te_id, GL_COMPILE_STATUS, &te_compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
if (tc_compile_status != GL_TRUE)
{
TCU_FAIL("Could not compile tessellation control shader");
}
if (te_compile_status != GL_TRUE)
{
TCU_FAIL("Could not compile tessellation evaluation shader");
}
/* Try to link the program object */
glw::GLint link_status = GL_FALSE;
gl.linkProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
if (link_status != GL_TRUE)
{
TCU_FAIL("Program linking failed");
}
/* Query the tessellation properties of the program object and make sure
* the values reported are valid */
glw::GLint control_output_vertices_value = 0;
glw::GLint gen_mode_value = GL_NONE;
glw::GLint gen_spacing_value = GL_NONE;
glw::GLint gen_vertex_order_value = GL_NONE;
glw::GLint gen_point_mode_value = GL_NONE;
gl.getProgramiv(m_po_id, m_glExtTokens.TESS_CONTROL_OUTPUT_VERTICES, &control_output_vertices_value);
gl.getProgramiv(m_po_id, m_glExtTokens.TESS_GEN_MODE, &gen_mode_value);
gl.getProgramiv(m_po_id, m_glExtTokens.TESS_GEN_SPACING, &gen_spacing_value);
gl.getProgramiv(m_po_id, m_glExtTokens.TESS_GEN_POINT_MODE, &gen_point_mode_value);
gl.getProgramiv(m_po_id, m_glExtTokens.TESS_GEN_VERTEX_ORDER, &gen_vertex_order_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() for tessellation-specific properties failed.");
if (control_output_vertices_value != test.expected_control_output_vertices_value)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid value reported for GL_TESS_CONTROL_OUTPUT_VERTICES_EXT property; "
<< " expected: " << test.expected_control_output_vertices_value
<< ", retrieved: " << control_output_vertices_value << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value reported for GL_TESS_CONTROL_OUTPUT_VERTICES_EXT property.");
}
if ((glw::GLuint)gen_mode_value != test.expected_gen_mode_value)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported for GL_TESS_GEN_MODE_EXT property; "
<< " expected: " << test.expected_gen_mode_value << ", retrieved: " << gen_mode_value
<< tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value reported for GL_TESS_GEN_MODE_EXT property.");
}
if ((glw::GLuint)gen_spacing_value != test.expected_gen_spacing_value)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid value reported for GL_TESS_GEN_SPACING_EXT property; "
<< " expected: " << test.expected_gen_spacing_value
<< ", retrieved: " << gen_spacing_value << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value reported for GL_TESS_GEN_SPACING_EXT property.");
}
if ((glw::GLuint)gen_point_mode_value != test.expected_gen_point_mode_value)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid value reported for GL_TESS_GEN_POINT_MODE_EXT property; "
<< " expected: " << test.expected_gen_point_mode_value
<< ", retrieved: " << gen_point_mode_value << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value reported for GL_TESS_GEN_POINT_MODE_EXT property.");
}
if ((glw::GLuint)gen_vertex_order_value != test.expected_gen_vertex_order_value)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid value reported for GL_TESS_GEN_VERTEX_ORDER_EXT property; "
<< " expected: " << test.expected_gen_vertex_order_value
<< ", retrieved: " << gen_vertex_order_value << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value reported for GL_TESS_GEN_VERTEX_ORDER_EXT property.");
}
} /* for (all test descriptors) */
/* All done */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
} /* namespace glcts */