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) > epsilon);
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 << "Tessellator generated different amount of isolines for EQUAL/"
396 "FRACTIONAL_EVEN/FRACTIONAL_ODD vertex spacing modes which is "
397 "invalid."
398 << tcu::TestLog::EndMessage;
399
400 TCU_FAIL("Invalid amount of unique isolines generated by tessellator");
401 } /* if (amount of generated isolines does not match) */
402 } /* for (all test runs) */
403 }
404
405 /** Counts amount of unique isolines in the captured data set and updates
406 * n_isolines field of user-provided @param test_result instance.
407 *
408 * @param test_result Test result instance to update.
409 */
countIsolines(_test_result & test_result)410 void TessellationShadersIsolines::countIsolines(_test_result& test_result)
411 {
412 const float epsilon = 1e-5f;
413 std::vector<float> found_ys;
414
415 for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex)
416 {
417 bool was_y_found = false;
418 const float* vertex = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */
419 float vertex_y = vertex[1];
420
421 for (std::vector<float>::iterator found_ys_iterator = found_ys.begin(); found_ys_iterator != found_ys.end();
422 found_ys_iterator++)
423 {
424 float& found_y = *found_ys_iterator;
425
426 if (de::abs(vertex_y - found_y) < epsilon)
427 {
428 was_y_found = true;
429
430 break;
431 }
432 } /* for (all found Ys) */
433
434 if (!was_y_found)
435 {
436 found_ys.push_back(vertex_y);
437 }
438 } /* for (all vertices) */
439
440 /* Store the value */
441 test_result.n_isolines = (unsigned int)found_ys.size();
442 }
443
444 /** Deinitializes ES objects created for the test. */
deinit()445 void TessellationShadersIsolines::deinit()
446 {
447 /* Call base class' deinit() */
448 TestCaseBase::deinit();
449
450 if (!m_is_tessellation_shader_supported)
451 {
452 return;
453 }
454
455 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
456
457 /* Reset GL_PATCH_VERTICES_EXT to default value */
458 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
459
460 /* Disable GL_RASTERIZER_DISCARD mode */
461 gl.disable(GL_RASTERIZER_DISCARD);
462
463 /* Unbind vertex array object */
464 gl.bindVertexArray(0);
465
466 /* Release Utilities instance */
467 if (m_utils_ptr != NULL)
468 {
469 delete m_utils_ptr;
470
471 m_utils_ptr = DE_NULL;
472 }
473
474 if (m_vao_id != 0)
475 {
476 gl.deleteVertexArrays(1, &m_vao_id);
477
478 m_vao_id = 0;
479 }
480
481 /* Free the data structures we allocated for the test */
482 m_tests.clear();
483 }
484
485 /** Retrieves test result structure for a particular set of properties.
486 *
487 * @param irrelevant_tess_level Irrelevant tessellation level the test result descriptor should be using.
488 * @param outer1_tess_level First outer tessellation level value the test result descriptor should be using.
489 * @param outer2_tess_level Second outer tessellation level value the test result descriptor should be using.
490 * @param vertex_spacing_mode Vertex spacing mode the test result descriptor should be using.
491 *
492 * This function throws a TestError exception if the test result descriptor the caller is after is not found.
493 *
494 * @return Test result descriptor of interest.
495 **/
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)496 TessellationShadersIsolines::_test_result TessellationShadersIsolines::findTestResult(
497 _irrelevant_tess_level irrelevant_tess_level, _outer1_tess_level outer1_tess_level,
498 _outer2_tess_level outer2_tess_level, _tessellation_shader_vertex_spacing vertex_spacing_mode)
499 {
500 DE_ASSERT(m_tests.find(vertex_spacing_mode) != m_tests.end());
501
502 _test_results& test_results = m_test_results[vertex_spacing_mode];
503 bool has_found = false;
504 TessellationShadersIsolines::_test_result result;
505
506 for (_test_results_iterator test_results_iterator = test_results.begin();
507 test_results_iterator != test_results.end(); test_results_iterator++)
508 {
509 if (test_results_iterator->irrelevant_tess_level == irrelevant_tess_level &&
510 test_results_iterator->outer1_tess_level == outer1_tess_level &&
511 test_results_iterator->outer2_tess_level == outer2_tess_level)
512 {
513 has_found = true;
514 result = *test_results_iterator;
515
516 break;
517 }
518 } /* for (all test runs) */
519
520 if (!has_found)
521 {
522 TCU_FAIL("Requested test run was not found.");
523 }
524
525 return result;
526 }
527
528 /** Retrieves rendering context associated with the test instance.
529 *
530 * @return Rendering context.
531 *
532 **/
getContext()533 Context& TessellationShadersIsolines::getContext()
534 {
535 return m_context;
536 }
537
538 /** Initializes ES objects necessary to run the test. */
initTest()539 void TessellationShadersIsolines::initTest()
540 {
541 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
542
543 /* Skip if required extensions are not supported. */
544 if (!m_is_tessellation_shader_supported)
545 {
546 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
547 }
548
549 /* Generate Utilities instance */
550 m_utils_ptr = new TessellationShaderUtils(gl, this);
551
552 /* Set up vertex array object */
553 gl.genVertexArrays(1, &m_vao_id);
554 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
555
556 gl.bindVertexArray(m_vao_id);
557 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
558
559 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
560 glw::GLint gl_max_tess_gen_level_value = 0;
561
562 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
563 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
564
565 /* Initialize reference tessellation values */
566 const glw::GLfloat tess_levels[] = { -1.0f, 4.0f, float(gl_max_tess_gen_level_value) * 0.5f,
567 float(gl_max_tess_gen_level_value) };
568 const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]);
569
570 m_irrelevant_tess_value_1 = tess_levels[0];
571 m_irrelevant_tess_value_2 = tess_levels[1];
572
573 /* Initialize all test passes.
574 *
575 * Make sure each relevant outer tessellation level iterates through values
576 * of our interest
577 */
578 for (unsigned int outer1_tess_level_index = 0; outer1_tess_level_index < n_tess_levels; ++outer1_tess_level_index)
579 {
580 for (unsigned int outer2_tess_level_index = 0; outer2_tess_level_index < n_tess_levels;
581 ++outer2_tess_level_index)
582 {
583 /* To make the test execute in a reasonable time frame, just use
584 * two different levels for the outer tessellation levels */
585 DE_STATIC_ASSERT(n_tess_levels >= 2);
586
587 for (unsigned int other_tess_level_index = 0; other_tess_level_index < 2 /* see comment */;
588 ++other_tess_level_index)
589 {
590 float inner_tess_levels[2] = { tess_levels[other_tess_level_index],
591 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],
594 tess_levels[other_tess_level_index],
595 tess_levels[other_tess_level_index] };
596
597 /* Finally, iterate over three vertex spacing modes */
598 _tessellation_shader_vertex_spacing vertex_spacing_mode;
599
600 const _tessellation_shader_vertex_spacing vs_modes[] = {
601 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
602 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD
603 };
604 const int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
605
606 for (int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
607 {
608 vertex_spacing_mode = vs_modes[n_vs_mode];
609
610 _test_descriptor test;
611
612 initTestDescriptor(vertex_spacing_mode, inner_tess_levels, outer_tess_levels,
613 tess_levels[other_tess_level_index], test);
614
615 m_tests[vertex_spacing_mode].push_back(test);
616 } /* for (all available vertex spacing modes) */
617 } /* for (all irrelevant tessellation levels) */
618 } /* for (all defined second outer tessellation levels) */
619 } /* for (all defined first outer tessellation levels) */
620 }
621
622 /** Initializes all ES objects necessary to run a specific test pass.
623 *
624 * @param vertex_spacing Vertex spacing mode to initialize the test descriptor with.
625 * @param inner_tess_levels Two FP values defining subsequent inner tessellation levels
626 * to be used for initializing the test descriptor. Must NOT be
627 * NULL.
628 * @param outer_tess_levels Four FP values defining subsequent outer tessellation levels
629 * to be used for initializing the test descriptor. Must NOT be
630 * NULL.
631 * @param irrelevant_tess_level Value to be used to set irrelevant tessellation level values.
632 * @param test Test descriptor to fill with IDs of initialized objects.
633 **/
initTestDescriptor(_tessellation_shader_vertex_spacing vertex_spacing,const float * inner_tess_levels,const float * outer_tess_levels,float irrelevant_tess_level,_test_descriptor & test)634 void TessellationShadersIsolines::initTestDescriptor(_tessellation_shader_vertex_spacing vertex_spacing,
635 const float* inner_tess_levels, const float* outer_tess_levels,
636 float irrelevant_tess_level, _test_descriptor& test)
637 {
638 memcpy(test.inner_tess_levels, inner_tess_levels, sizeof(test.inner_tess_levels));
639 memcpy(test.outer_tess_levels, outer_tess_levels, sizeof(test.outer_tess_levels));
640
641 test.parent = this;
642 test.irrelevant_tess_level = irrelevant_tess_level;
643 test.vertex_spacing_mode = vertex_spacing;
644 }
645
646 /** Executes the test.
647 *
648 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
649 *
650 * Note the function throws exception should an error occur!
651 *
652 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
653 **/
iterate(void)654 tcu::TestNode::IterateResult TessellationShadersIsolines::iterate(void)
655 {
656 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
657
658 initTest();
659
660 /* We only need to use one vertex per so go for it */
661 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
662 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
663
664 /* We don't need to rasterize anything in this test */
665 gl.enable(GL_RASTERIZER_DISCARD);
666 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
667
668 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value before we continue */
669 glw::GLint gl_max_tess_gen_level_value = 0;
670
671 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
672 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname.");
673
674 /* To perform actual tests, we need to first retrieve the tessellated coordinates data.
675 * Run all tests configured and fill per-test buffer with the information.
676 **/
677 for (_tests_per_vertex_spacing_map_iterator vs_key_iterator = m_tests.begin(); vs_key_iterator != m_tests.end();
678 vs_key_iterator++)
679 {
680 for (_tests_const_iterator test_iterator = vs_key_iterator->second.begin();
681 test_iterator != vs_key_iterator->second.end(); test_iterator++)
682 {
683 const _test_descriptor& test = *test_iterator;
684
685 /* Capture tessellation data for considered configuration */
686 unsigned int n_rendered_vertices = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
687 TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, test.inner_tess_levels, test.outer_tess_levels,
688 test.vertex_spacing_mode, false); /* is_point_mode_enabled */
689 std::vector<char> rendered_data = m_utils_ptr->getDataGeneratedByTessellator(
690 test.inner_tess_levels, false, /* point mode */
691 TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
692 test.vertex_spacing_mode, test.outer_tess_levels);
693
694 /* Store the data in a test result descriptor */
695 _test_result result;
696
697 result.n_vertices = n_rendered_vertices;
698 result.parent = &test;
699 result.irrelevant_tess_level = (int)test.irrelevant_tess_level;
700 result.outer1_tess_level = (int)test.outer_tess_levels[0];
701 result.outer2_tess_level = (int)test.outer_tess_levels[1];
702 result.rendered_data.resize(rendered_data.size() / sizeof(float));
703 if (0 != rendered_data.size())
704 {
705 memcpy(&result.rendered_data[0], &rendered_data[0], rendered_data.size());
706 }
707 countIsolines(result);
708
709 /* Store the test run descriptor. */
710 m_test_results[test.vertex_spacing_mode].push_back(result);
711 }
712 }
713
714 /* Now we can proceed with actual tests */
715 /* (test 1): Make sure amount of isolines is determined by first outer tessellation level */
716 runForAllTestResults(checkFirstOuterTessellationLevelEffect);
717
718 /* (test 2): Make sure amount of line segments per height is determined by second outer
719 * tessellation level.
720 */
721 runForAllTestResults(checkSecondOuterTessellationLevelEffect);
722
723 /* (test 3): Make sure 3rd, 4th outer tessellation levels, as well as all inner tessellation
724 * levels have no impact on the tessellated coordinates */
725 checkIrrelevantTessellationLevelsHaveNoEffect();
726
727 /* (test 4): Make sure no matter what vertex spacing is requested in TC stage, it is always
728 * equal_spacing that is applied.
729 */
730 checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines();
731
732 /* (test 5): Make sure that no data set features a line segment at height of 1. */
733 runForAllTestResults(checkNoLineSegmentIsDefinedAtHeightOne);
734
735 /* All done */
736 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
737 return STOP;
738 }
739
740 /** Calls the caller-provided function provided for each test result descriptor
741 * created during pre-computation stage.
742 *
743 * @param pProcessTestRun Function pointer to call. The function will be called
744 * exactly once for each cached test result descriptor.
745 *
746 **/
runForAllTestResults(PFNTESTRESULTPROCESSORPROC pProcessTestResult)747 void TessellationShadersIsolines::runForAllTestResults(PFNTESTRESULTPROCESSORPROC pProcessTestResult)
748 {
749 for (_test_results_per_vertex_spacing_map_iterator vs_key_iterator = m_test_results.begin();
750 vs_key_iterator != m_test_results.end(); vs_key_iterator++)
751 {
752 for (_test_results_iterator test_results_iterator = vs_key_iterator->second.begin();
753 test_results_iterator != vs_key_iterator->second.end(); test_results_iterator++)
754 {
755 _test_result& test_result = *test_results_iterator;
756
757 pProcessTestResult(test_result, m_glExtTokens.MAX_TESS_GEN_LEVEL);
758 } /* for (all level3 keys) */
759 } /* for (all vertex spacing modes) */
760 }
761
762 } /* namespace glcts */
763