/*------------------------------------------------------------------------- * 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 #include 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(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 */