/*------------------------------------------------------------------------- * 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 "esextcTessellationShaderIsolines.hpp" #include "esextcTessellationShaderUtils.hpp" #include "gluContextInfo.hpp" #include "gluDefs.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include "tcuTestLog.hpp" namespace glcts { /** Constructor * * @param context Test context **/ TessellationShadersIsolines::TessellationShadersIsolines(Context& context, const ExtParameters& extParams) : TestCaseBase(context, extParams, "isolines_tessellation", "Verifies that the number of isolines generated during tessellation is " "derived from the first outer tessellation level.\n" "Makes sure that the number of segments in each isoline is derived from " "the second outer tessellation level.\n" "Makes sure that both inner tessellation levels and the 3rd and the 4th " "outer tessellation levels do not affect the tessellation process.\n" "Makes sure that equal_spacing vertex spacing mode does not affect amount" " of generated isolines.\n" "Makes sure no line is drawn between (0, 1) and (1, 1) in (u, v) domain.") , m_irrelevant_tess_value_1(0.0f) , m_irrelevant_tess_value_2(0.0f) , m_utils_ptr(DE_NULL) , m_vao_id(0) { /* Left blank on purpose */ } /** Checks that amount of isolines generated during tessellation corresponds to the * first outer tessellation level. * * This check needs not to operate over all test results generated for a particular * vertex spacing mode. * * @param test_result Value of MAX_TESS_GEN_LEVEL token. For ES3.1 it will be equal to * GL_MAX_TESS_GEN_LEVEL_EXT and for ES3.2 to GL_MAX_TESS_GEN_LEVEL. * **/ void TessellationShadersIsolines::checkFirstOuterTessellationLevelEffect(_test_result& test_result, const glw::GLenum glMaxTessGenLevelToken) { glcts::Context& context = test_result.parent->parent->getContext(); const glw::Functions& gl = context.getRenderContext().getFunctions(); glw::GLint gl_max_tess_gen_level_value = 0; unsigned int n_isolines_expected = 0; if (test_result.n_vertices != 0) { /* Calculate how many isolines we're expecting */ gl.getIntegerv(glMaxTessGenLevelToken, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); /* NOTE: Amount of isolines should always be based on TESSELLATION_SHADER_VERTEX_SPACING_EQUAL * vertex spacing mode, even if a different one is defined in TE stage. */ float outer_zero_tess_level_clamped_rounded = 0.0f; TessellationShaderUtils::getTessellationLevelAfterVertexSpacing( TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, test_result.parent->outer_tess_levels[0], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */ &outer_zero_tess_level_clamped_rounded); n_isolines_expected = (unsigned int)outer_zero_tess_level_clamped_rounded; if (test_result.n_isolines != n_isolines_expected) { tcu::TestContext& test = test_result.parent->parent->getTestContext(); test.getLog() << tcu::TestLog::Message << "Tessellator generated an invalid amount of isolines:" << test_result.n_isolines << " instead of the expected amount:" << n_isolines_expected << " for the following inner tessellation level configuration:" << " (" << test_result.parent->inner_tess_levels[0] << ", " << test_result.parent->inner_tess_levels[1] << ")" << " and the following outer tesellation level configuration:" << " (" << test_result.parent->outer_tess_levels[0] << ", " << test_result.parent->outer_tess_levels[1] << ", " << test_result.parent->outer_tess_levels[2] << ", " << test_result.parent->outer_tess_levels[3] << ")" << tcu::TestLog::EndMessage; TCU_FAIL("Invalid amount of isolines generated by tessellator"); } } /* if (test_run.n_vertices != 0) */ } /** Makes sure that tessellation coordinates generated for inner+outer tessellation level * configurations, between which irrelevant levels have been defined, are exactly the same. * * This check needs to operate over all test results generated for a particular * vertex spacing mode. * * This function throws a TestError exception if the check fails. **/ void TessellationShadersIsolines::checkIrrelevantTessellationLevelsHaveNoEffect() { /* Make sure that two example data sets, for which irrelevant tessellation levels have * been changed, are exactly the same */ DE_ASSERT(m_test_results.find(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL) != m_test_results.end()); const float epsilon = 1e-5f; float irrelevant_tess_level1_rounded_clamped = 0.0f; int irrelevant_tess_level1 = 0; float irrelevant_tess_level2_rounded_clamped = 0.0f; int irrelevant_tess_level2 = 0; _test_results_iterator test_result_iterator_start = m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].begin(); _test_results_iterator test_result_iterator_end = m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].end(); /* Calculate two tessellation level values that we've used in init() */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLint gl_max_tess_gen_level_value = 0; gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); TessellationShaderUtils::getTessellationLevelAfterVertexSpacing( TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, m_irrelevant_tess_value_1, gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */ &irrelevant_tess_level1_rounded_clamped); TessellationShaderUtils::getTessellationLevelAfterVertexSpacing( TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, m_irrelevant_tess_value_2, gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */ &irrelevant_tess_level2_rounded_clamped); irrelevant_tess_level1 = (int)irrelevant_tess_level1_rounded_clamped; irrelevant_tess_level2 = (int)irrelevant_tess_level2_rounded_clamped; DE_ASSERT(de::abs(irrelevant_tess_level1 - irrelevant_tess_level2) > 0); /* Iterate through all test runs for equal spacing */ for (_test_results_iterator test_result_iterator = test_result_iterator_start; test_result_iterator != test_result_iterator_end; test_result_iterator++) { _test_result test_result = *test_result_iterator; if (test_result.irrelevant_tess_level == irrelevant_tess_level1) { _test_result test_result_reference = findTestResult(irrelevant_tess_level2, test_result.outer1_tess_level, test_result.outer2_tess_level, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL); /* data for current test run and the reference one should match */ DE_ASSERT(test_result.n_vertices == test_result_reference.n_vertices); for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex) { const float* vertex_data_1 = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */ const float* vertex_data_2 = (&test_result_reference.rendered_data[0]) + n_vertex * 3; /* components */ if (de::abs(vertex_data_1[0] - vertex_data_2[0]) > epsilon || de::abs(vertex_data_1[1] - vertex_data_2[1]) > epsilon || de::abs(vertex_data_1[2] - vertex_data_2[2]) > epsilon) { tcu::TestContext& test = test_result_iterator->parent->parent->getTestContext(); test.getLog() << tcu::TestLog::Message << "Tessellator generated non-matching data for different tessellation level configurations, " "where only irrelevant tessellation levels have been changed; " << " data generated for {inner:" << " (" << test_result.parent->inner_tess_levels[0] << ", " << test_result.parent->inner_tess_levels[1] << ")" << " outer:" << " (" << test_result.parent->outer_tess_levels[0] << ", " << test_result.parent->outer_tess_levels[1] << ", " << test_result.parent->outer_tess_levels[2] << ", " << test_result.parent->outer_tess_levels[3] << ")" << "}:" << " (" << vertex_data_1[0] << ", " << vertex_data_1[1] << ", " << vertex_data_1[2] << ")" << ", data generated for {inner:" << " (" << test_result_reference.parent->inner_tess_levels[0] << ", " << test_result_reference.parent->inner_tess_levels[1] << ")" << " outer:" << " (" << test_result_reference.parent->outer_tess_levels[0] << ", " << test_result_reference.parent->outer_tess_levels[1] << ", " << test_result_reference.parent->outer_tess_levels[2] << ", " << test_result_reference.parent->outer_tess_levels[3] << ")" << "}:" << " (" << vertex_data_2[0] << ", " << vertex_data_2[1] << ", " << vertex_data_2[2] << ")" << tcu::TestLog::EndMessage; TCU_FAIL("Invalid amount of unique line segments generated by tessellator"); } /* if (equal and fractional_even data mismatch) */ } /* for (all vertices) */ } /* if (current test result's irrelelvant tessellation levels match what we're after) */ } /* for (all test runs) */ } /** Checks that the amount of line segments generated per isoline is as defined by * second outer tessellation level. * * This check needs not to operate over all test results generated for a particular * vertex spacing mode. * * This function throws a TestError exception if the check fails. * * @param test_result Test result descriptor to perform the check on. * **/ void TessellationShadersIsolines::checkSecondOuterTessellationLevelEffect(_test_result& test_result, const glw::GLenum glMaxTessGenLevelToken) { typedef float _line_segment_x; typedef std::pair<_line_segment_x, _line_segment_x> _line_segment; typedef std::vector<_line_segment> _line_segments; typedef _line_segments::iterator _line_segments_iterator; glcts::Context& context = test_result.parent->parent->getContext(); const float epsilon = 1e-5f; _line_segments found_line_segments; const glw::Functions& gl = context.getRenderContext().getFunctions(); glw::GLint gl_max_tess_gen_level_value = 0; float outer_tess_levels1_clamped_rounded = 0.0f; unsigned int n_line_segments_per_isoline_expected = 0; unsigned int n_unique_line_segments_found = 0; if (test_result.n_vertices != 0) { /* Calculate how many isolines we're expecting */ gl.getIntegerv(glMaxTessGenLevelToken, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); TessellationShaderUtils::getTessellationLevelAfterVertexSpacing( test_result.parent->vertex_spacing_mode, test_result.parent->outer_tess_levels[1], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */ &outer_tess_levels1_clamped_rounded); n_line_segments_per_isoline_expected = (unsigned int)outer_tess_levels1_clamped_rounded; /* Count unique line segments found in all the line segments making up the result data set. */ for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; n_vertex += 2 /* vertices per line segment */) { bool was_line_segment_found = false; const float* vertex1 = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */ float vertex1_x = vertex1[0]; const float* vertex2 = (&test_result.rendered_data[0]) + (n_vertex + 1) * 3; /* components */ float vertex2_x = vertex2[0]; for (_line_segments_iterator found_line_segments_iterator = found_line_segments.begin(); found_line_segments_iterator != found_line_segments.end(); found_line_segments_iterator++) { float& found_vertex1_x = found_line_segments_iterator->first; float& found_vertex2_x = found_line_segments_iterator->second; if (de::abs(found_vertex1_x - vertex1_x) < epsilon && de::abs(found_vertex2_x - vertex2_x) < epsilon) { was_line_segment_found = true; break; } } /* for (all found Ys) */ if (!was_line_segment_found) { found_line_segments.push_back(_line_segment(vertex1_x, vertex2_x)); } } /* for (all vertices) */ /* Compare the values */ n_unique_line_segments_found = (unsigned int)found_line_segments.size(); if (n_unique_line_segments_found != n_line_segments_per_isoline_expected) { tcu::TestContext& test = test_result.parent->parent->getTestContext(); test.getLog() << tcu::TestLog::Message << "Tessellator generated an invalid amount of unique line segments:" << n_unique_line_segments_found << " instead of the expected amount:" << n_line_segments_per_isoline_expected << " for the following inner tessellation level configuration:" << " (" << test_result.parent->inner_tess_levels[0] << ", " << test_result.parent->inner_tess_levels[1] << ")" << " and the following outer tesellation level configuration:" << " (" << test_result.parent->outer_tess_levels[0] << ", " << test_result.parent->outer_tess_levels[1] << ", " << test_result.parent->outer_tess_levels[2] << ", " << test_result.parent->outer_tess_levels[3] << ")" << " and the following vertex spacing mode: " << test_result.parent->vertex_spacing_mode << tcu::TestLog::EndMessage; TCU_FAIL("Invalid amount of unique line segments generated by tessellator"); } } /* if (test_run.n_vertices != 0) */ } /** Verifies that no vertex making up any of the line segments outputted by the * tessellator is located at height equal to -1. * * This check needs not to operate over all test results generated for a particular * vertex spacing mode. * * This function throws a TestError exception if the check fails. * * @param test_result Test result descriptor to perform the check on. * **/ void TessellationShadersIsolines::checkNoLineSegmentIsDefinedAtHeightOne(_test_result& test_result, glw::GLenum unused) { (void)unused; // suppress warning const float epsilon = 1e-5f; for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex) { const float* vertex = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */ if (de::abs(vertex[1] - 1.0f) < epsilon) { tcu::TestContext& test = test_result.parent->parent->getTestContext(); test.getLog() << tcu::TestLog::Message << "Tessellator generated the following coordinate:" << " (" << vertex[0] << ", " << vertex[1] << ", " << vertex[2] << ")" << " for the following inner tessellation level configuration:" << " (" << test_result.parent->inner_tess_levels[0] << ", " << test_result.parent->inner_tess_levels[1] << ")" << " and the following outer tesellation level configuration:" << " (" << test_result.parent->outer_tess_levels[0] << ", " << test_result.parent->outer_tess_levels[1] << ", " << test_result.parent->outer_tess_levels[2] << ", " << test_result.parent->outer_tess_levels[3] << ")" << " which is invalid: Y must never be equal to 1." << tcu::TestLog::EndMessage; TCU_FAIL("Invalid line segment generated by tessellator"); } /* If the Y coordinate is set at 1 */ } /* for (all vertices) */ } /** Verifies that amount of isolines generated for the same inner+outer level * configurations but for different vertex spacing modes is exactly the same. * * This check needs to operate over all test results generated for a particular * vertex spacing mode. * * This function throws a TestError exception if the check fails. * **/ void TessellationShadersIsolines::checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines() { DE_ASSERT(m_tests.find(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL) != m_tests.end()); _test_results_iterator test_result_iterator_start = m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].begin(); _test_results_iterator test_result_iterator_end = m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].end(); for (_test_results_iterator test_result_iterator = test_result_iterator_start; test_result_iterator != test_result_iterator_end; test_result_iterator++) { _test_result& test_result_equal = *test_result_iterator; _test_result test_result_fe; _test_result test_result_fo; /* Find a corresponding fractional_even test run descriptor */ test_result_fe = findTestResult(test_result_equal.irrelevant_tess_level, test_result_equal.outer1_tess_level, test_result_equal.outer2_tess_level, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN); test_result_fo = findTestResult(test_result_equal.irrelevant_tess_level, test_result_equal.outer1_tess_level, test_result_equal.outer2_tess_level, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD); /* Make sure the amounts match */ if (test_result_equal.n_isolines != test_result_fe.n_isolines || test_result_fe.n_isolines != test_result_fo.n_isolines) { tcu::TestContext& test = test_result_iterator->parent->parent->getTestContext(); test.getLog() << tcu::TestLog::Message << "Tessellator generated different amount of isolines for EQUAL/" "FRACTIONAL_EVEN/FRACTIONAL_ODD vertex spacing modes which is " "invalid." << tcu::TestLog::EndMessage; TCU_FAIL("Invalid amount of unique isolines generated by tessellator"); } /* if (amount of generated isolines does not match) */ } /* for (all test runs) */ } /** Counts amount of unique isolines in the captured data set and updates * n_isolines field of user-provided @param test_result instance. * * @param test_result Test result instance to update. */ void TessellationShadersIsolines::countIsolines(_test_result& test_result) { const float epsilon = 1e-5f; std::vector found_ys; for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex) { bool was_y_found = false; const float* vertex = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */ float vertex_y = vertex[1]; for (std::vector::iterator found_ys_iterator = found_ys.begin(); found_ys_iterator != found_ys.end(); found_ys_iterator++) { float& found_y = *found_ys_iterator; if (de::abs(vertex_y - found_y) < epsilon) { was_y_found = true; break; } } /* for (all found Ys) */ if (!was_y_found) { found_ys.push_back(vertex_y); } } /* for (all vertices) */ /* Store the value */ test_result.n_isolines = (unsigned int)found_ys.size(); } /** Deinitializes ES objects created for the test. */ void TessellationShadersIsolines::deinit() { /* Call base class' deinit() */ TestCaseBase::deinit(); if (!m_is_tessellation_shader_supported) { return; } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Reset GL_PATCH_VERTICES_EXT to default value */ gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3); /* Disable GL_RASTERIZER_DISCARD mode */ gl.disable(GL_RASTERIZER_DISCARD); /* Unbind vertex array object */ gl.bindVertexArray(0); /* Release Utilities instance */ if (m_utils_ptr != NULL) { delete m_utils_ptr; m_utils_ptr = DE_NULL; } if (m_vao_id != 0) { gl.deleteVertexArrays(1, &m_vao_id); m_vao_id = 0; } /* Free the data structures we allocated for the test */ m_tests.clear(); } /** Retrieves test result structure for a particular set of properties. * * @param irrelevant_tess_level Irrelevant tessellation level the test result descriptor should be using. * @param outer1_tess_level First outer tessellation level value the test result descriptor should be using. * @param outer2_tess_level Second outer tessellation level value the test result descriptor should be using. * @param vertex_spacing_mode Vertex spacing mode the test result descriptor should be using. * * This function throws a TestError exception if the test result descriptor the caller is after is not found. * * @return Test result descriptor of interest. **/ TessellationShadersIsolines::_test_result TessellationShadersIsolines::findTestResult( _irrelevant_tess_level irrelevant_tess_level, _outer1_tess_level outer1_tess_level, _outer2_tess_level outer2_tess_level, _tessellation_shader_vertex_spacing vertex_spacing_mode) { DE_ASSERT(m_tests.find(vertex_spacing_mode) != m_tests.end()); _test_results& test_results = m_test_results[vertex_spacing_mode]; bool has_found = false; TessellationShadersIsolines::_test_result result; for (_test_results_iterator test_results_iterator = test_results.begin(); test_results_iterator != test_results.end(); test_results_iterator++) { if (test_results_iterator->irrelevant_tess_level == irrelevant_tess_level && test_results_iterator->outer1_tess_level == outer1_tess_level && test_results_iterator->outer2_tess_level == outer2_tess_level) { has_found = true; result = *test_results_iterator; break; } } /* for (all test runs) */ if (!has_found) { TCU_FAIL("Requested test run was not found."); } return result; } /** Retrieves rendering context associated with the test instance. * * @return Rendering context. * **/ Context& TessellationShadersIsolines::getContext() { return m_context; } /** Initializes ES objects necessary to run the test. */ void TessellationShadersIsolines::initTest() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Skip if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Generate Utilities instance */ m_utils_ptr = new TessellationShaderUtils(gl, this); /* Set up vertex array object */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ glw::GLint gl_max_tess_gen_level_value = 0; gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); /* Initialize reference tessellation values */ const glw::GLfloat tess_levels[] = { -1.0f, 4.0f, float(gl_max_tess_gen_level_value) * 0.5f, float(gl_max_tess_gen_level_value) }; const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]); m_irrelevant_tess_value_1 = tess_levels[0]; m_irrelevant_tess_value_2 = tess_levels[1]; /* Initialize all test passes. * * Make sure each relevant outer tessellation level iterates through values * of our interest */ for (unsigned int outer1_tess_level_index = 0; outer1_tess_level_index < n_tess_levels; ++outer1_tess_level_index) { for (unsigned int outer2_tess_level_index = 0; outer2_tess_level_index < n_tess_levels; ++outer2_tess_level_index) { /* To make the test execute in a reasonable time frame, just use * two different levels for the outer tessellation levels */ DE_STATIC_ASSERT(n_tess_levels >= 2); for (unsigned int other_tess_level_index = 0; other_tess_level_index < 2 /* see comment */; ++other_tess_level_index) { float inner_tess_levels[2] = { tess_levels[other_tess_level_index], tess_levels[other_tess_level_index] }; float outer_tess_levels[4] = { tess_levels[outer1_tess_level_index], tess_levels[outer2_tess_level_index], tess_levels[other_tess_level_index], tess_levels[other_tess_level_index] }; /* Finally, iterate over three vertex spacing modes */ _tessellation_shader_vertex_spacing vertex_spacing_mode; const _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD }; const int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]); for (int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode) { vertex_spacing_mode = vs_modes[n_vs_mode]; _test_descriptor test; initTestDescriptor(vertex_spacing_mode, inner_tess_levels, outer_tess_levels, tess_levels[other_tess_level_index], test); m_tests[vertex_spacing_mode].push_back(test); } /* for (all available vertex spacing modes) */ } /* for (all irrelevant tessellation levels) */ } /* for (all defined second outer tessellation levels) */ } /* for (all defined first outer tessellation levels) */ } /** Initializes all ES objects necessary to run a specific test pass. * * @param vertex_spacing Vertex spacing mode to initialize the test descriptor with. * @param inner_tess_levels Two FP values defining subsequent inner tessellation levels * to be used for initializing the test descriptor. Must NOT be * NULL. * @param outer_tess_levels Four FP values defining subsequent outer tessellation levels * to be used for initializing the test descriptor. Must NOT be * NULL. * @param irrelevant_tess_level Value to be used to set irrelevant tessellation level values. * @param test Test descriptor to fill with IDs of initialized objects. **/ void TessellationShadersIsolines::initTestDescriptor(_tessellation_shader_vertex_spacing vertex_spacing, const float* inner_tess_levels, const float* outer_tess_levels, float irrelevant_tess_level, _test_descriptor& test) { memcpy(test.inner_tess_levels, inner_tess_levels, sizeof(test.inner_tess_levels)); memcpy(test.outer_tess_levels, outer_tess_levels, sizeof(test.outer_tess_levels)); test.parent = this; test.irrelevant_tess_level = irrelevant_tess_level; test.vertex_spacing_mode = vertex_spacing; } /** 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 TessellationShadersIsolines::iterate(void) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); initTest(); /* We only need to use one vertex per so go for it */ gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1); GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname"); /* We don't need to rasterize anything in this test */ gl.enable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed"); /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value before we continue */ glw::GLint gl_max_tess_gen_level_value = 0; gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname."); /* To perform actual tests, we need to first retrieve the tessellated coordinates data. * Run all tests configured and fill per-test buffer with the information. **/ for (_tests_per_vertex_spacing_map_iterator vs_key_iterator = m_tests.begin(); vs_key_iterator != m_tests.end(); vs_key_iterator++) { for (_tests_const_iterator test_iterator = vs_key_iterator->second.begin(); test_iterator != vs_key_iterator->second.end(); test_iterator++) { const _test_descriptor& test = *test_iterator; /* Capture tessellation data for considered configuration */ unsigned int n_rendered_vertices = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator( TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, test.inner_tess_levels, test.outer_tess_levels, test.vertex_spacing_mode, false); /* is_point_mode_enabled */ std::vector rendered_data = m_utils_ptr->getDataGeneratedByTessellator( test.inner_tess_levels, false, /* point mode */ TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, test.vertex_spacing_mode, test.outer_tess_levels); /* Store the data in a test result descriptor */ _test_result result; result.n_vertices = n_rendered_vertices; result.parent = &test; result.irrelevant_tess_level = (int)test.irrelevant_tess_level; result.outer1_tess_level = (int)test.outer_tess_levels[0]; result.outer2_tess_level = (int)test.outer_tess_levels[1]; result.rendered_data.resize(rendered_data.size() / sizeof(float)); if (0 != rendered_data.size()) { memcpy(&result.rendered_data[0], &rendered_data[0], rendered_data.size()); } if (result.rendered_data.size() > 0) { countIsolines(result); } /* Store the test run descriptor. */ m_test_results[test.vertex_spacing_mode].push_back(result); } } /* Now we can proceed with actual tests */ /* (test 1): Make sure amount of isolines is determined by first outer tessellation level */ runForAllTestResults(checkFirstOuterTessellationLevelEffect); /* (test 2): Make sure amount of line segments per height is determined by second outer * tessellation level. */ runForAllTestResults(checkSecondOuterTessellationLevelEffect); /* (test 3): Make sure 3rd, 4th outer tessellation levels, as well as all inner tessellation * levels have no impact on the tessellated coordinates */ checkIrrelevantTessellationLevelsHaveNoEffect(); /* (test 4): Make sure no matter what vertex spacing is requested in TC stage, it is always * equal_spacing that is applied. */ checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines(); /* (test 5): Make sure that no data set features a line segment at height of 1. */ runForAllTestResults(checkNoLineSegmentIsDefinedAtHeightOne); /* All done */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } /** Calls the caller-provided function provided for each test result descriptor * created during pre-computation stage. * * @param pProcessTestRun Function pointer to call. The function will be called * exactly once for each cached test result descriptor. * **/ void TessellationShadersIsolines::runForAllTestResults(PFNTESTRESULTPROCESSORPROC pProcessTestResult) { for (_test_results_per_vertex_spacing_map_iterator vs_key_iterator = m_test_results.begin(); vs_key_iterator != m_test_results.end(); vs_key_iterator++) { for (_test_results_iterator test_results_iterator = vs_key_iterator->second.begin(); test_results_iterator != vs_key_iterator->second.end(); test_results_iterator++) { _test_result& test_result = *test_results_iterator; pProcessTestResult(test_result, m_glExtTokens.MAX_TESS_GEN_LEVEL); } /* for (all level3 keys) */ } /* for (all vertex spacing modes) */ } } /* namespace glcts */