1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */ /*!
20  * \file
21  * \brief
22  */ /*-------------------------------------------------------------------*/
23 
24 #include "esextcTessellationShaderIsolines.hpp"
25 #include "esextcTessellationShaderUtils.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "glwFunctions.hpp"
30 #include "tcuTestLog.hpp"
31 
32 namespace glcts
33 {
34 
35 /** Constructor
36  *
37  * @param context Test context
38  **/
TessellationShadersIsolines(Context & context,const ExtParameters & extParams)39 TessellationShadersIsolines::TessellationShadersIsolines(Context &context, const ExtParameters &extParams)
40     : TestCaseBase(context, extParams, "isolines_tessellation",
41                    "Verifies that the number of isolines generated during tessellation is "
42                    "derived from the first outer tessellation level.\n"
43                    "Makes sure that the number of segments in each isoline is derived from "
44                    "the second outer tessellation level.\n"
45                    "Makes sure that both inner tessellation levels and the 3rd and the 4th "
46                    "outer tessellation levels do not affect the tessellation process.\n"
47                    "Makes sure that equal_spacing vertex spacing mode does not affect amount"
48                    " of generated isolines.\n"
49                    "Makes sure no line is drawn between (0, 1) and (1, 1) in (u, v) domain.")
50     , m_irrelevant_tess_value_1(0.0f)
51     , m_irrelevant_tess_value_2(0.0f)
52     , m_utils_ptr(DE_NULL)
53     , m_vao_id(0)
54 {
55     /* Left blank on purpose */
56 }
57 
58 /** Checks that amount of isolines generated during tessellation corresponds to the
59  *  first outer tessellation level.
60  *
61  *  This check needs not to operate over all test results generated for a particular
62  *  vertex spacing mode.
63  *
64  *  @param test_result Value of MAX_TESS_GEN_LEVEL token. For ES3.1 it will be equal to
65  *                     GL_MAX_TESS_GEN_LEVEL_EXT and for ES3.2 to GL_MAX_TESS_GEN_LEVEL.
66  *
67  **/
checkFirstOuterTessellationLevelEffect(_test_result & test_result,const glw::GLenum glMaxTessGenLevelToken)68 void TessellationShadersIsolines::checkFirstOuterTessellationLevelEffect(_test_result &test_result,
69                                                                          const glw::GLenum glMaxTessGenLevelToken)
70 {
71     glcts::Context &context                = test_result.parent->parent->getContext();
72     const glw::Functions &gl               = context.getRenderContext().getFunctions();
73     glw::GLint gl_max_tess_gen_level_value = 0;
74     unsigned int n_isolines_expected       = 0;
75 
76     if (test_result.n_vertices != 0)
77     {
78         /* Calculate how many isolines we're expecting */
79         gl.getIntegerv(glMaxTessGenLevelToken, &gl_max_tess_gen_level_value);
80         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
81 
82         /* NOTE: Amount of isolines should always be based on TESSELLATION_SHADER_VERTEX_SPACING_EQUAL
83          *       vertex spacing mode, even if a different one is defined in TE stage.
84          */
85         float outer_zero_tess_level_clamped_rounded = 0.0f;
86 
87         TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
88             TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, test_result.parent->outer_tess_levels[0],
89             gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
90             &outer_zero_tess_level_clamped_rounded);
91 
92         n_isolines_expected = (unsigned int)outer_zero_tess_level_clamped_rounded;
93 
94         if (test_result.n_isolines != n_isolines_expected)
95         {
96             tcu::TestContext &test = test_result.parent->parent->getTestContext();
97 
98             test.getLog() << tcu::TestLog::Message
99                           << "Tessellator generated an invalid amount of isolines:" << test_result.n_isolines
100                           << " instead of the expected amount:" << n_isolines_expected
101                           << " for the following inner tessellation level configuration:"
102                           << " (" << test_result.parent->inner_tess_levels[0] << ", "
103                           << test_result.parent->inner_tess_levels[1] << ")"
104                           << " and the following outer tesellation level configuration:"
105                           << " (" << test_result.parent->outer_tess_levels[0] << ", "
106                           << test_result.parent->outer_tess_levels[1] << ", "
107                           << test_result.parent->outer_tess_levels[2] << ", "
108                           << test_result.parent->outer_tess_levels[3] << ")" << tcu::TestLog::EndMessage;
109 
110             TCU_FAIL("Invalid amount of isolines generated by tessellator");
111         }
112     } /* if (test_run.n_vertices != 0) */
113 }
114 
115 /** Makes sure that tessellation coordinates generated for inner+outer tessellation level
116  *  configurations, between which irrelevant levels have been defined, are exactly the same.
117  *
118  *  This check needs to operate over all test results generated for a particular
119  *  vertex spacing mode.
120  *
121  *  This function throws a TestError exception if the check fails.
122  **/
checkIrrelevantTessellationLevelsHaveNoEffect()123 void TessellationShadersIsolines::checkIrrelevantTessellationLevelsHaveNoEffect()
124 {
125     /* Make sure that two example data sets, for which irrelevant tessellation levels have
126      * been changed, are exactly the same
127      */
128     DE_ASSERT(m_test_results.find(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL) != m_test_results.end());
129 
130     const float epsilon                          = 1e-5f;
131     float irrelevant_tess_level1_rounded_clamped = 0.0f;
132     int irrelevant_tess_level1                   = 0;
133     float irrelevant_tess_level2_rounded_clamped = 0.0f;
134     int irrelevant_tess_level2                   = 0;
135     _test_results_iterator test_result_iterator_start =
136         m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].begin();
137     _test_results_iterator test_result_iterator_end = m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].end();
138 
139     /* Calculate two tessellation level values that we've used in init() */
140     const glw::Functions &gl               = m_context.getRenderContext().getFunctions();
141     glw::GLint gl_max_tess_gen_level_value = 0;
142 
143     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
144     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
145 
146     TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
147         TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, m_irrelevant_tess_value_1, gl_max_tess_gen_level_value,
148         DE_NULL, /* out_clamped */
149         &irrelevant_tess_level1_rounded_clamped);
150     TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
151         TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, m_irrelevant_tess_value_2, gl_max_tess_gen_level_value,
152         DE_NULL, /* out_clamped */
153         &irrelevant_tess_level2_rounded_clamped);
154 
155     irrelevant_tess_level1 = (int)irrelevant_tess_level1_rounded_clamped;
156     irrelevant_tess_level2 = (int)irrelevant_tess_level2_rounded_clamped;
157 
158     DE_ASSERT(de::abs(irrelevant_tess_level1 - irrelevant_tess_level2) > 0);
159 
160     /* Iterate through all test runs for equal spacing */
161     for (_test_results_iterator test_result_iterator = test_result_iterator_start;
162          test_result_iterator != test_result_iterator_end; test_result_iterator++)
163     {
164         _test_result test_result = *test_result_iterator;
165 
166         if (test_result.irrelevant_tess_level == irrelevant_tess_level1)
167         {
168             _test_result test_result_reference =
169                 findTestResult(irrelevant_tess_level2, test_result.outer1_tess_level, test_result.outer2_tess_level,
170                                TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
171 
172             /* data for current test run and the reference one should match */
173             DE_ASSERT(test_result.n_vertices == test_result_reference.n_vertices);
174 
175             for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex)
176             {
177                 const float *vertex_data_1 = (&test_result.rendered_data[0]) + n_vertex * 3;           /* components */
178                 const float *vertex_data_2 = (&test_result_reference.rendered_data[0]) + n_vertex * 3; /* components */
179 
180                 if (de::abs(vertex_data_1[0] - vertex_data_2[0]) > epsilon ||
181                     de::abs(vertex_data_1[1] - vertex_data_2[1]) > epsilon ||
182                     de::abs(vertex_data_1[2] - vertex_data_2[2]) > epsilon)
183                 {
184                     tcu::TestContext &test = test_result_iterator->parent->parent->getTestContext();
185 
186                     test.getLog()
187                         << tcu::TestLog::Message
188                         << "Tessellator generated non-matching data for different tessellation level configurations, "
189                            "where only irrelevant tessellation levels have been changed; "
190                         << " data generated for {inner:"
191                         << " (" << test_result.parent->inner_tess_levels[0] << ", "
192                         << test_result.parent->inner_tess_levels[1] << ")"
193                         << " outer:"
194                         << " (" << test_result.parent->outer_tess_levels[0] << ", "
195                         << test_result.parent->outer_tess_levels[1] << ", " << test_result.parent->outer_tess_levels[2]
196                         << ", " << test_result.parent->outer_tess_levels[3] << ")"
197                         << "}:"
198                         << " (" << vertex_data_1[0] << ", " << vertex_data_1[1] << ", " << vertex_data_1[2] << ")"
199                         << ", data generated for {inner:"
200                         << " (" << test_result_reference.parent->inner_tess_levels[0] << ", "
201                         << test_result_reference.parent->inner_tess_levels[1] << ")"
202                         << " outer:"
203                         << " (" << test_result_reference.parent->outer_tess_levels[0] << ", "
204                         << test_result_reference.parent->outer_tess_levels[1] << ", "
205                         << test_result_reference.parent->outer_tess_levels[2] << ", "
206                         << test_result_reference.parent->outer_tess_levels[3] << ")"
207                         << "}:"
208                         << " (" << vertex_data_2[0] << ", " << vertex_data_2[1] << ", " << vertex_data_2[2] << ")"
209                         << tcu::TestLog::EndMessage;
210 
211                     TCU_FAIL("Invalid amount of unique line segments generated by tessellator");
212                 } /* if (equal and fractional_even data mismatch) */
213             }     /* for (all vertices) */
214         }         /* if (current test result's irrelelvant tessellation levels match what we're after) */
215     }             /* for (all test runs) */
216 }
217 
218 /** Checks that the amount of line segments generated per isoline is as defined by
219  *  second outer tessellation level.
220  *
221  *  This check needs not to operate over all test results generated for a particular
222  *  vertex spacing mode.
223  *
224  *  This function throws a TestError exception if the check fails.
225  *
226  *  @param test_result Test result descriptor to perform the check on.
227  *
228  **/
checkSecondOuterTessellationLevelEffect(_test_result & test_result,const glw::GLenum glMaxTessGenLevelToken)229 void TessellationShadersIsolines::checkSecondOuterTessellationLevelEffect(_test_result &test_result,
230                                                                           const glw::GLenum glMaxTessGenLevelToken)
231 {
232     typedef float _line_segment_x;
233     typedef std::pair<_line_segment_x, _line_segment_x> _line_segment;
234     typedef std::vector<_line_segment> _line_segments;
235     typedef _line_segments::iterator _line_segments_iterator;
236 
237     glcts::Context &context = test_result.parent->parent->getContext();
238     const float epsilon     = 1e-5f;
239     _line_segments found_line_segments;
240     const glw::Functions &gl                          = context.getRenderContext().getFunctions();
241     glw::GLint gl_max_tess_gen_level_value            = 0;
242     float outer_tess_levels1_clamped_rounded          = 0.0f;
243     unsigned int n_line_segments_per_isoline_expected = 0;
244     unsigned int n_unique_line_segments_found         = 0;
245 
246     if (test_result.n_vertices != 0)
247     {
248         /* Calculate how many isolines we're expecting */
249         gl.getIntegerv(glMaxTessGenLevelToken, &gl_max_tess_gen_level_value);
250         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
251 
252         TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
253             test_result.parent->vertex_spacing_mode, test_result.parent->outer_tess_levels[1],
254             gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
255             &outer_tess_levels1_clamped_rounded);
256 
257         n_line_segments_per_isoline_expected = (unsigned int)outer_tess_levels1_clamped_rounded;
258 
259         /* Count unique line segments found in all the line segments making up the result data set.  */
260         for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices;
261              n_vertex += 2 /* vertices per line segment */)
262         {
263             bool was_line_segment_found = false;
264             const float *vertex1        = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */
265             float vertex1_x             = vertex1[0];
266             const float *vertex2        = (&test_result.rendered_data[0]) + (n_vertex + 1) * 3; /* components */
267             float vertex2_x             = vertex2[0];
268 
269             for (_line_segments_iterator found_line_segments_iterator = found_line_segments.begin();
270                  found_line_segments_iterator != found_line_segments.end(); found_line_segments_iterator++)
271             {
272                 float &found_vertex1_x = found_line_segments_iterator->first;
273                 float &found_vertex2_x = found_line_segments_iterator->second;
274 
275                 if (de::abs(found_vertex1_x - vertex1_x) < epsilon && de::abs(found_vertex2_x - vertex2_x) < epsilon)
276                 {
277                     was_line_segment_found = true;
278 
279                     break;
280                 }
281             } /* for (all found Ys) */
282 
283             if (!was_line_segment_found)
284             {
285                 found_line_segments.push_back(_line_segment(vertex1_x, vertex2_x));
286             }
287         } /* for (all vertices) */
288 
289         /* Compare the values */
290         n_unique_line_segments_found = (unsigned int)found_line_segments.size();
291 
292         if (n_unique_line_segments_found != n_line_segments_per_isoline_expected)
293         {
294             tcu::TestContext &test = test_result.parent->parent->getTestContext();
295 
296             test.getLog() << tcu::TestLog::Message << "Tessellator generated an invalid amount of unique line segments:"
297                           << n_unique_line_segments_found
298                           << " instead of the expected amount:" << n_line_segments_per_isoline_expected
299                           << " for the following inner tessellation level configuration:"
300                           << " (" << test_result.parent->inner_tess_levels[0] << ", "
301                           << test_result.parent->inner_tess_levels[1] << ")"
302                           << " and the following outer tesellation level configuration:"
303                           << " (" << test_result.parent->outer_tess_levels[0] << ", "
304                           << test_result.parent->outer_tess_levels[1] << ", "
305                           << test_result.parent->outer_tess_levels[2] << ", "
306                           << test_result.parent->outer_tess_levels[3] << ")"
307                           << " and the following vertex spacing mode: " << test_result.parent->vertex_spacing_mode
308                           << tcu::TestLog::EndMessage;
309 
310             TCU_FAIL("Invalid amount of unique line segments generated by tessellator");
311         }
312     } /* if (test_run.n_vertices != 0) */
313 }
314 
315 /** Verifies that no vertex making up any of the line segments outputted by the
316  *  tessellator is located at height equal to -1.
317  *
318  *  This check needs not to operate over all test results generated for a particular
319  *  vertex spacing mode.
320  *
321  *  This function throws a TestError exception if the check fails.
322  *
323  *  @param test_result Test result descriptor to perform the check on.
324  *
325  **/
checkNoLineSegmentIsDefinedAtHeightOne(_test_result & test_result,glw::GLenum unused)326 void TessellationShadersIsolines::checkNoLineSegmentIsDefinedAtHeightOne(_test_result &test_result, glw::GLenum unused)
327 {
328     (void)unused; // suppress warning
329 
330     const float epsilon = 1e-5f;
331 
332     for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex)
333     {
334         const float *vertex = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */
335 
336         if (de::abs(vertex[1] - 1.0f) < epsilon)
337         {
338             tcu::TestContext &test = test_result.parent->parent->getTestContext();
339 
340             test.getLog() << tcu::TestLog::Message << "Tessellator generated the following coordinate:"
341                           << " (" << vertex[0] << ", " << vertex[1] << ", " << vertex[2] << ")"
342                           << " for the following inner tessellation level configuration:"
343                           << " (" << test_result.parent->inner_tess_levels[0] << ", "
344                           << test_result.parent->inner_tess_levels[1] << ")"
345                           << " and the following outer tesellation level configuration:"
346                           << " (" << test_result.parent->outer_tess_levels[0] << ", "
347                           << test_result.parent->outer_tess_levels[1] << ", "
348                           << test_result.parent->outer_tess_levels[2] << ", "
349                           << test_result.parent->outer_tess_levels[3] << ")"
350                           << " which is invalid: Y must never be equal to 1." << tcu::TestLog::EndMessage;
351 
352             TCU_FAIL("Invalid line segment generated by tessellator");
353         } /* If the Y coordinate is set at 1 */
354     }     /* for (all vertices) */
355 }
356 
357 /** Verifies that amount of isolines generated for the same inner+outer level
358  *  configurations but for different vertex spacing modes is exactly the same.
359  *
360  *  This check needs to operate over all test results generated for a particular
361  *  vertex spacing mode.
362  *
363  *  This function throws a TestError exception if the check fails.
364  *
365  **/
checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines()366 void TessellationShadersIsolines::checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines()
367 {
368     DE_ASSERT(m_tests.find(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL) != m_tests.end());
369 
370     _test_results_iterator test_result_iterator_start =
371         m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].begin();
372     _test_results_iterator test_result_iterator_end = m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].end();
373 
374     for (_test_results_iterator test_result_iterator = test_result_iterator_start;
375          test_result_iterator != test_result_iterator_end; test_result_iterator++)
376     {
377         _test_result &test_result_equal = *test_result_iterator;
378         _test_result test_result_fe;
379         _test_result test_result_fo;
380 
381         /* Find a corresponding fractional_even test run descriptor */
382         test_result_fe =
383             findTestResult(test_result_equal.irrelevant_tess_level, test_result_equal.outer1_tess_level,
384                            test_result_equal.outer2_tess_level, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN);
385         test_result_fo =
386             findTestResult(test_result_equal.irrelevant_tess_level, test_result_equal.outer1_tess_level,
387                            test_result_equal.outer2_tess_level, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
388 
389         /* Make sure the amounts match */
390         if (test_result_equal.n_isolines != test_result_fe.n_isolines ||
391             test_result_fe.n_isolines != test_result_fo.n_isolines)
392         {
393             tcu::TestContext &test = test_result_iterator->parent->parent->getTestContext();
394 
395             test.getLog() << tcu::TestLog::Message
396                           << "Tessellator generated different amount of isolines for EQUAL/"
397                              "FRACTIONAL_EVEN/FRACTIONAL_ODD vertex spacing modes which is "
398                              "invalid."
399                           << tcu::TestLog::EndMessage;
400 
401             TCU_FAIL("Invalid amount of unique isolines generated by tessellator");
402         } /* if (amount of generated isolines does not match) */
403     }     /* for (all test runs) */
404 }
405 
406 /** Counts amount of unique isolines in the captured data set and updates
407  *  n_isolines field of user-provided @param test_result instance.
408  *
409  *  @param test_result Test result instance to update.
410  */
countIsolines(_test_result & test_result)411 void TessellationShadersIsolines::countIsolines(_test_result &test_result)
412 {
413     const float epsilon = 1e-5f;
414     std::vector<float> found_ys;
415 
416     for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex)
417     {
418         bool was_y_found    = false;
419         const float *vertex = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */
420         float vertex_y      = vertex[1];
421 
422         for (std::vector<float>::iterator found_ys_iterator = found_ys.begin(); found_ys_iterator != found_ys.end();
423              found_ys_iterator++)
424         {
425             float &found_y = *found_ys_iterator;
426 
427             if (de::abs(vertex_y - found_y) < epsilon)
428             {
429                 was_y_found = true;
430 
431                 break;
432             }
433         } /* for (all found Ys) */
434 
435         if (!was_y_found)
436         {
437             found_ys.push_back(vertex_y);
438         }
439     } /* for (all vertices) */
440 
441     /* Store the value */
442     test_result.n_isolines = (unsigned int)found_ys.size();
443 }
444 
445 /** Deinitializes ES objects created for the test. */
deinit()446 void TessellationShadersIsolines::deinit()
447 {
448     /* Call base class' deinit() */
449     TestCaseBase::deinit();
450 
451     if (!m_is_tessellation_shader_supported)
452     {
453         return;
454     }
455 
456     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
457 
458     /* Reset GL_PATCH_VERTICES_EXT to default value */
459     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
460 
461     /* Disable GL_RASTERIZER_DISCARD mode */
462     gl.disable(GL_RASTERIZER_DISCARD);
463 
464     /* Unbind vertex array object */
465     gl.bindVertexArray(0);
466 
467     /* Release Utilities instance */
468     if (m_utils_ptr != NULL)
469     {
470         delete m_utils_ptr;
471 
472         m_utils_ptr = DE_NULL;
473     }
474 
475     if (m_vao_id != 0)
476     {
477         gl.deleteVertexArrays(1, &m_vao_id);
478 
479         m_vao_id = 0;
480     }
481 
482     /* Free the data structures we allocated for the test */
483     m_tests.clear();
484 }
485 
486 /** Retrieves test result structure for a particular set of properties.
487  *
488  *  @param irrelevant_tess_level Irrelevant tessellation level the test result descriptor should be using.
489  *  @param outer1_tess_level     First outer tessellation level value  the test result descriptor should be using.
490  *  @param outer2_tess_level     Second outer tessellation level value the test result descriptor should be using.
491  *  @param vertex_spacing_mode   Vertex spacing mode the test result descriptor should be using.
492  *
493  *  This function throws a TestError exception if the test result descriptor the caller is after is not found.
494  *
495  *  @return Test result descriptor of interest.
496  **/
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)497 TessellationShadersIsolines::_test_result TessellationShadersIsolines::findTestResult(
498     _irrelevant_tess_level irrelevant_tess_level, _outer1_tess_level outer1_tess_level,
499     _outer2_tess_level outer2_tess_level, _tessellation_shader_vertex_spacing vertex_spacing_mode)
500 {
501     DE_ASSERT(m_tests.find(vertex_spacing_mode) != m_tests.end());
502 
503     _test_results &test_results = m_test_results[vertex_spacing_mode];
504     bool has_found              = false;
505     TessellationShadersIsolines::_test_result result;
506 
507     for (_test_results_iterator test_results_iterator = test_results.begin();
508          test_results_iterator != test_results.end(); test_results_iterator++)
509     {
510         if (test_results_iterator->irrelevant_tess_level == irrelevant_tess_level &&
511             test_results_iterator->outer1_tess_level == outer1_tess_level &&
512             test_results_iterator->outer2_tess_level == outer2_tess_level)
513         {
514             has_found = true;
515             result    = *test_results_iterator;
516 
517             break;
518         }
519     } /* for (all test runs) */
520 
521     if (!has_found)
522     {
523         TCU_FAIL("Requested test run was not found.");
524     }
525 
526     return result;
527 }
528 
529 /** Retrieves rendering context associated with the test instance.
530  *
531  *  @return Rendering context.
532  *
533  **/
getContext()534 Context &TessellationShadersIsolines::getContext()
535 {
536     return m_context;
537 }
538 
539 /** Initializes ES objects necessary to run the test. */
initTest()540 void TessellationShadersIsolines::initTest()
541 {
542     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
543 
544     /* Skip if required extensions are not supported. */
545     if (!m_is_tessellation_shader_supported)
546     {
547         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
548     }
549 
550     /* Generate Utilities instance */
551     m_utils_ptr = new TessellationShaderUtils(gl, this);
552 
553     /* Set up vertex array object */
554     gl.genVertexArrays(1, &m_vao_id);
555     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
556 
557     gl.bindVertexArray(m_vao_id);
558     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
559 
560     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
561     glw::GLint gl_max_tess_gen_level_value = 0;
562 
563     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
564     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
565 
566     /* Initialize reference tessellation values */
567     const glw::GLfloat tess_levels[] = {-1.0f, 4.0f, float(gl_max_tess_gen_level_value) * 0.5f,
568                                         float(gl_max_tess_gen_level_value)};
569     const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]);
570 
571     m_irrelevant_tess_value_1 = tess_levels[0];
572     m_irrelevant_tess_value_2 = tess_levels[1];
573 
574     /* Initialize all test passes.
575      *
576      * Make sure each relevant outer tessellation level iterates through values
577      * of our interest
578      */
579     for (unsigned int outer1_tess_level_index = 0; outer1_tess_level_index < n_tess_levels; ++outer1_tess_level_index)
580     {
581         for (unsigned int outer2_tess_level_index = 0; outer2_tess_level_index < n_tess_levels;
582              ++outer2_tess_level_index)
583         {
584             /* To make the test execute in a reasonable time frame, just use
585              * two different levels for the outer tessellation levels */
586             DE_STATIC_ASSERT(n_tess_levels >= 2);
587 
588             for (unsigned int other_tess_level_index = 0; other_tess_level_index < 2 /* see comment */;
589                  ++other_tess_level_index)
590             {
591                 float inner_tess_levels[2] = {tess_levels[other_tess_level_index], tess_levels[other_tess_level_index]};
592                 float outer_tess_levels[4] = {tess_levels[outer1_tess_level_index],
593                                               tess_levels[outer2_tess_level_index], tess_levels[other_tess_level_index],
594                                               tess_levels[other_tess_level_index]};
595 
596                 /* Finally, iterate over three vertex spacing modes */
597                 _tessellation_shader_vertex_spacing vertex_spacing_mode;
598 
599                 const _tessellation_shader_vertex_spacing vs_modes[] = {
600                     TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
601                     TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD};
602                 const int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
603 
604                 for (int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
605                 {
606                     vertex_spacing_mode = vs_modes[n_vs_mode];
607 
608                     _test_descriptor test;
609 
610                     initTestDescriptor(vertex_spacing_mode, inner_tess_levels, outer_tess_levels,
611                                        tess_levels[other_tess_level_index], test);
612 
613                     m_tests[vertex_spacing_mode].push_back(test);
614                 } /* for (all available vertex spacing modes) */
615             }     /* for (all irrelevant tessellation levels) */
616         }         /* for (all defined second outer tessellation levels) */
617     }             /* for (all defined first outer tessellation levels) */
618 }
619 
620 /** Initializes all ES objects necessary to run a specific test pass.
621  *
622  *  @param vertex_spacing        Vertex spacing mode to initialize the test descriptor with.
623  *  @param inner_tess_levels     Two FP values defining subsequent inner tessellation levels
624  *                               to be used for initializing the test descriptor. Must NOT be
625  *                               NULL.
626  *  @param outer_tess_levels     Four FP values defining subsequent outer tessellation levels
627  *                               to be used for initializing the test descriptor. Must NOT be
628  *                               NULL.
629  *  @param irrelevant_tess_level Value to be used to set irrelevant tessellation level values.
630  *  @param test                  Test descriptor to fill with IDs of initialized objects.
631  **/
initTestDescriptor(_tessellation_shader_vertex_spacing vertex_spacing,const float * inner_tess_levels,const float * outer_tess_levels,float irrelevant_tess_level,_test_descriptor & test)632 void TessellationShadersIsolines::initTestDescriptor(_tessellation_shader_vertex_spacing vertex_spacing,
633                                                      const float *inner_tess_levels, const float *outer_tess_levels,
634                                                      float irrelevant_tess_level, _test_descriptor &test)
635 {
636     memcpy(test.inner_tess_levels, inner_tess_levels, sizeof(test.inner_tess_levels));
637     memcpy(test.outer_tess_levels, outer_tess_levels, sizeof(test.outer_tess_levels));
638 
639     test.parent                = this;
640     test.irrelevant_tess_level = irrelevant_tess_level;
641     test.vertex_spacing_mode   = vertex_spacing;
642 }
643 
644 /** Executes the test.
645  *
646  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
647  *
648  *  Note the function throws exception should an error occur!
649  *
650  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
651  **/
iterate(void)652 tcu::TestNode::IterateResult TessellationShadersIsolines::iterate(void)
653 {
654     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
655 
656     initTest();
657 
658     /* We only need to use one vertex per so go for it */
659     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
660     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
661 
662     /* We don't need to rasterize anything in this test */
663     gl.enable(GL_RASTERIZER_DISCARD);
664     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
665 
666     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value before we continue */
667     glw::GLint gl_max_tess_gen_level_value = 0;
668 
669     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
670     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname.");
671 
672     /* To perform actual tests, we need to first retrieve the tessellated coordinates data.
673      * Run all tests configured and fill per-test buffer with the information.
674      **/
675     for (_tests_per_vertex_spacing_map_iterator vs_key_iterator = m_tests.begin(); vs_key_iterator != m_tests.end();
676          vs_key_iterator++)
677     {
678         for (_tests_const_iterator test_iterator = vs_key_iterator->second.begin();
679              test_iterator != vs_key_iterator->second.end(); test_iterator++)
680         {
681             const _test_descriptor &test = *test_iterator;
682 
683             /* Capture tessellation data for considered configuration */
684             unsigned int n_rendered_vertices = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
685                 TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, test.inner_tess_levels, test.outer_tess_levels,
686                 test.vertex_spacing_mode, false); /* is_point_mode_enabled */
687             std::vector<char> rendered_data = m_utils_ptr->getDataGeneratedByTessellator(
688                 test.inner_tess_levels, false, /* point mode */
689                 TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
690                 test.vertex_spacing_mode, test.outer_tess_levels);
691 
692             /* Store the data in a test result descriptor */
693             _test_result result;
694 
695             result.n_vertices            = n_rendered_vertices;
696             result.parent                = &test;
697             result.irrelevant_tess_level = (int)test.irrelevant_tess_level;
698             result.outer1_tess_level     = (int)test.outer_tess_levels[0];
699             result.outer2_tess_level     = (int)test.outer_tess_levels[1];
700             result.rendered_data.resize(rendered_data.size() / sizeof(float));
701             if (0 != rendered_data.size())
702             {
703                 memcpy(&result.rendered_data[0], &rendered_data[0], rendered_data.size());
704             }
705             if (result.rendered_data.size() > 0)
706             {
707                 countIsolines(result);
708             }
709 
710             /* Store the test run descriptor. */
711             m_test_results[test.vertex_spacing_mode].push_back(result);
712         }
713     }
714 
715     /* Now we can proceed with actual tests */
716     /* (test 1): Make sure amount of isolines is determined by first outer tessellation level */
717     runForAllTestResults(checkFirstOuterTessellationLevelEffect);
718 
719     /* (test 2): Make sure amount of line segments per height is determined by second outer
720      *           tessellation level.
721      */
722     runForAllTestResults(checkSecondOuterTessellationLevelEffect);
723 
724     /* (test 3): Make sure 3rd, 4th outer tessellation levels, as well as all inner tessellation
725      *           levels have no impact on the tessellated coordinates */
726     checkIrrelevantTessellationLevelsHaveNoEffect();
727 
728     /* (test 4): Make sure no matter what vertex spacing is requested in TC stage, it is always
729      *           equal_spacing that is applied.
730      */
731     checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines();
732 
733     /* (test 5): Make sure that no data set features a line segment at height of 1. */
734     runForAllTestResults(checkNoLineSegmentIsDefinedAtHeightOne);
735 
736     /* All done */
737     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
738     return STOP;
739 }
740 
741 /** Calls the caller-provided function provided for each test result descriptor
742  *  created during pre-computation stage.
743  *
744  *  @param pProcessTestRun Function pointer to call. The function will be called
745  *                         exactly once for each cached test result descriptor.
746  *
747  **/
runForAllTestResults(PFNTESTRESULTPROCESSORPROC pProcessTestResult)748 void TessellationShadersIsolines::runForAllTestResults(PFNTESTRESULTPROCESSORPROC pProcessTestResult)
749 {
750     for (_test_results_per_vertex_spacing_map_iterator vs_key_iterator = m_test_results.begin();
751          vs_key_iterator != m_test_results.end(); vs_key_iterator++)
752     {
753         for (_test_results_iterator test_results_iterator = vs_key_iterator->second.begin();
754              test_results_iterator != vs_key_iterator->second.end(); test_results_iterator++)
755         {
756             _test_result &test_result = *test_results_iterator;
757 
758             pProcessTestResult(test_result, m_glExtTokens.MAX_TESS_GEN_LEVEL);
759         } /* for (all level3 keys) */
760     }     /* for (all vertex spacing modes) */
761 }
762 
763 } /* namespace glcts */
764