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