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 "esextcTessellationShaderVertexOrdering.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 /** Constructor
35 *
36 * @param context Test context
37 **/
TessellationShaderVertexOrdering(Context & context,const ExtParameters & extParams)38 TessellationShaderVertexOrdering::TessellationShaderVertexOrdering(Context &context, const ExtParameters &extParams)
39 : TestCaseBase(context, extParams, "vertex_ordering",
40 "Verifies vertex ordering property affects the tessellation"
41 " process as per extension specification")
42 , m_bo_id(0)
43 , m_fs_id(0)
44 , m_tc_id(0)
45 , m_vs_id(0)
46 , m_vao_id(0)
47 , m_utils(DE_NULL)
48 {
49 /* Left blank on purpose */
50 }
51
52 /** Deinitializes ES objects created for the test. */
deinit()53 void TessellationShaderVertexOrdering::deinit()
54 {
55 /* Call base class' deinit() */
56 TestCaseBase::deinit();
57
58 if (!m_is_tessellation_shader_supported)
59 {
60 return;
61 }
62
63 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
64
65 /* Reset TF buffer object bindings */
66 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
67 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
68
69 /* Restore GL_PATCH_VERTICES_EXT value */
70 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
71
72 /* Disable GL_RASTERIZER_DISCARD rendering mode */
73 gl.disable(GL_RASTERIZER_DISCARD);
74
75 /* Reset active program object */
76 gl.useProgram(0);
77
78 /* Unbind vertex array object */
79 gl.bindVertexArray(0);
80
81 /* Free all ES objects we allocated for the test */
82 if (m_bo_id != 0)
83 {
84 gl.deleteBuffers(1, &m_bo_id);
85
86 m_bo_id = 0;
87 }
88
89 if (m_fs_id != 0)
90 {
91 gl.deleteShader(m_fs_id);
92
93 m_fs_id = 0;
94 }
95
96 if (m_tc_id != 0)
97 {
98 gl.deleteShader(m_tc_id);
99
100 m_tc_id = 0;
101 }
102
103 if (m_vs_id != 0)
104 {
105 gl.deleteShader(m_vs_id);
106
107 m_vs_id = 0;
108 }
109
110 if (m_vao_id != 0)
111 {
112 gl.deleteVertexArrays(1, &m_vao_id);
113
114 m_vao_id = 0;
115 }
116
117 /* Denitialize utils instance */
118 if (m_utils != DE_NULL)
119 {
120 delete m_utils;
121
122 m_utils = DE_NULL;
123 }
124
125 /* Deinitialize all test descriptors */
126 _test_iterations::iterator it;
127 for (it = m_tests.begin(); it != m_tests.end(); ++it)
128 {
129 deinitTestIteration(*it);
130 }
131 m_tests.clear();
132
133 for (it = m_tests_points.begin(); it != m_tests_points.end(); ++it)
134 {
135 deinitTestIteration(*it);
136 }
137 m_tests_points.clear();
138 }
139
140 /** Deinitialize all test pass-specific ES objects.
141 *
142 * @param test Descriptor of a test pass to deinitialize.
143 **/
deinitTestIteration(_test_iteration & test_iteration)144 void TessellationShaderVertexOrdering::deinitTestIteration(_test_iteration &test_iteration)
145 {
146 if (test_iteration.data != DE_NULL)
147 {
148 delete[] test_iteration.data;
149
150 test_iteration.data = DE_NULL;
151 }
152 }
153
154 /** Initializes ES objects necessary to run the test. */
initTest()155 void TessellationShaderVertexOrdering::initTest()
156 {
157 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
158
159 /* Skip if required extensions are not supported. */
160 if (!m_is_tessellation_shader_supported)
161 {
162 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
163 }
164
165 /* Initialize vertex array object */
166 gl.genVertexArrays(1, &m_vao_id);
167 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
168
169 gl.bindVertexArray(m_vao_id);
170 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
171
172 /* Set up patch size */
173 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
174 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed for GL_PATCH_VERTICES_EXT pname");
175
176 /* Disable rasterization */
177 gl.enable(GL_RASTERIZER_DISCARD);
178 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed");
179
180 /* Initialize utils instance */
181 m_utils = new TessellationShaderUtils(gl, this);
182
183 /* Generate all test-wide objects needed for test execution */
184 gl.genBuffers(1, &m_bo_id);
185 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
186
187 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
188 m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
189 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
190 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
191
192 /* Configure buffer object bindings */
193 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
194 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
195
196 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
197 m_bo_id);
198 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
199
200 /* Configure fragment shader body */
201 const char *fs_body = "${VERSION}\n"
202 "\n"
203 "void main()\n"
204 "{\n"
205 "}\n";
206
207 shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
208 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
209
210 /* Configure tessellation control shader body */
211 std::string tc_body =
212 TessellationShaderUtils::getGenericTCCode(4, /* n_patch_vertices */
213 false); /* should_use_glInvocationID_indexed_input */
214 const char *tc_body_ptr = tc_body.c_str();
215
216 shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body_ptr);
217 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
218
219 /* Configure vertex shader body */
220 const char *vs_body = "${VERSION}\n"
221 "\n"
222 "void main()\n"
223 "{\n"
224 " gl_Position = vec4(1.0, 0.0, 0.0, 0.0);\n"
225 "}\n";
226
227 shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
228 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
229
230 /* Compile all the shaders */
231 const glw::GLuint shaders[] = {m_fs_id, m_tc_id, m_vs_id};
232 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
233
234 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
235 {
236 glw::GLuint shader = shaders[n_shader];
237
238 if (shader != 0)
239 {
240 glw::GLint compile_status = GL_FALSE;
241
242 gl.compileShader(shader);
243 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
244
245 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
246 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
247
248 if (compile_status != GL_TRUE)
249 {
250 TCU_FAIL("Shader compilation failed");
251 }
252 }
253 } /* for (all shaders) */
254
255 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
256 glw::GLint gl_max_tess_gen_level_value = 0;
257
258 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
259 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
260
261 /* Initialize all test iterations */
262 bool point_mode_statuses[] = {false, true};
263 const unsigned int n_point_mode_statuses = sizeof(point_mode_statuses) / sizeof(point_mode_statuses[0]);
264
265 const _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
266 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
267 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
268 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
269
270 const _tessellation_shader_vertex_ordering vertex_orderings[] = {TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
271 TESSELLATION_SHADER_VERTEX_ORDERING_CW,
272 TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT};
273 const unsigned int n_vertex_orderings = sizeof(vertex_orderings) / sizeof(vertex_orderings[0]);
274
275 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
276 {
277 _tessellation_levels_set levels_set;
278 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
279
280 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
281 primitive_mode, gl_max_tess_gen_level_value,
282 TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES);
283
284 for (unsigned int n_vertex_ordering = 0; n_vertex_ordering < n_vertex_orderings; ++n_vertex_ordering)
285 {
286 _tessellation_shader_vertex_ordering vertex_ordering = vertex_orderings[n_vertex_ordering];
287
288 for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin();
289 levels_set_iterator != levels_set.end(); levels_set_iterator++)
290 {
291 const _tessellation_levels &levels = *levels_set_iterator;
292
293 for (unsigned int n_point_mode_status = 0; n_point_mode_status < n_point_mode_statuses;
294 ++n_point_mode_status)
295 {
296 bool point_mode_status = point_mode_statuses[n_point_mode_status];
297
298 /* Initialize a test run descriptor for the iteration-specific properties */
299 _test_iteration test_iteration = initTestIteration(levels.inner, levels.outer, primitive_mode,
300 vertex_ordering, point_mode_status, m_utils);
301
302 /* Store the test iteration descriptor */
303 if (!point_mode_status)
304 {
305 m_tests.push_back(test_iteration);
306 }
307 else
308 {
309 m_tests_points.push_back(test_iteration);
310 }
311 } /* for (all point mode statuses) */
312 } /* for (all level sets) */
313 } /* for (all vertex orderings) */
314 } /* for (all primitive modes) */
315
316 /* Set up buffer object bindings */
317 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
318 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
319
320 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
321 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
322 }
323
324 /** Initializes all ES objects, runs the test, captures all vertices
325 * generated by the tessellator and stores them in the result
326 * descriptor.
327 *
328 * NOTE: This function throws a TestError exception, should an error occur.
329 *
330 * @param inner_tess_levels Two FP values describing inner tessellation level values to be used
331 * for the test run. Must not be NULL.
332 * @param outer_tess_levels Four FP values describing outer tessellation level values to be used
333 * for the test run. Must not be NULL.
334 * @param primitive_mode Primitive mode to be used for the test run.
335 * @param vertex_ordering Vertex ordering to be used for the test run.
336 * @param is_point_mode_enabled true if points mode should be used for the test run, false otherwise.
337 *
338 * @return _test_iteration instance containing all described data.
339 *
340 **/
initTestIteration(const float * inner_tess_levels,const float * outer_tess_levels,_tessellation_primitive_mode primitive_mode,_tessellation_shader_vertex_ordering vertex_ordering,bool is_point_mode_enabled,TessellationShaderUtils * utils)341 TessellationShaderVertexOrdering::_test_iteration TessellationShaderVertexOrdering::initTestIteration(
342 const float *inner_tess_levels, const float *outer_tess_levels, _tessellation_primitive_mode primitive_mode,
343 _tessellation_shader_vertex_ordering vertex_ordering, bool is_point_mode_enabled, TessellationShaderUtils *utils)
344 {
345 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
346 _test_iteration test_iteration;
347
348 /* Create & configure a tessellation evaluation shader for the iteration */
349 const std::string te_code = TessellationShaderUtils::getGenericTECode(
350 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode, vertex_ordering, is_point_mode_enabled);
351 const char *te_code_ptr = te_code.c_str();
352
353 glw::GLuint te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
354 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for GL_TESS_EVALUATION_SHADER_EXT pname");
355
356 shaderSourceSpecialized(te_id, 1, /* count */
357 &te_code_ptr);
358 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
359
360 utils->compileShaders(1, /* n_shaders */
361 &te_id, true); /* should_succeed */
362
363 /* Create & form iteration-specific program object */
364 glw::GLuint po_id = gl.createProgram();
365 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed");
366
367 gl.attachShader(po_id, m_fs_id);
368 gl.attachShader(po_id, m_tc_id);
369 gl.attachShader(po_id, te_id);
370 gl.attachShader(po_id, m_vs_id);
371 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed");
372
373 /* Set up XFB */
374 const char *varyings[] = {"result_uvw"};
375
376 gl.transformFeedbackVaryings(po_id, 1, /* count */
377 varyings, GL_INTERLEAVED_ATTRIBS);
378 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
379
380 /* Link the program object */
381 glw::GLint link_status = GL_FALSE;
382
383 gl.linkProgram(po_id);
384 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
385
386 gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
387 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
388
389 if (link_status != GL_TRUE)
390 {
391 TCU_FAIL("Program linking failed");
392 }
393
394 gl.deleteShader(te_id);
395 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed");
396
397 /* Fill the remaining test iteration descriptor fields */
398 memcpy(test_iteration.inner_tess_levels, inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
399 memcpy(test_iteration.outer_tess_levels, outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
400
401 test_iteration.is_point_mode_enabled = is_point_mode_enabled;
402 test_iteration.primitive_mode = primitive_mode;
403 test_iteration.vertex_ordering = vertex_ordering;
404 test_iteration.n_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
405 primitive_mode, inner_tess_levels, outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
406 is_point_mode_enabled);
407
408 /* Configure the buffer object storage to hold required amount of data */
409 glw::GLuint bo_size = static_cast<glw::GLuint>(test_iteration.n_vertices * 3 /* components */ * sizeof(float));
410
411 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, /* data */
412 GL_STATIC_DRAW);
413 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
414
415 /* Also configure the storage in the descriptor */
416 test_iteration.data = new char[bo_size];
417
418 /* Render the data set */
419 glw::GLint inner_tess_level_uniform_location = gl.getUniformLocation(po_id, "inner_tess_level");
420 glw::GLint outer_tess_level_uniform_location = gl.getUniformLocation(po_id, "outer_tess_level");
421 glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(primitive_mode, is_point_mode_enabled);
422
423 DE_ASSERT(inner_tess_level_uniform_location != -1);
424 DE_ASSERT(outer_tess_level_uniform_location != -1);
425
426 gl.useProgram(po_id);
427 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
428
429 gl.uniform2fv(inner_tess_level_uniform_location, 1 /* count */, test_iteration.inner_tess_levels);
430 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
431
432 gl.uniform4fv(outer_tess_level_uniform_location, 1 /* count */, test_iteration.outer_tess_levels);
433 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
434
435 gl.beginTransformFeedback(tf_mode);
436 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
437
438 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
439 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
440
441 gl.endTransformFeedback();
442 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
443
444 /* Map the XFB buffer object and copy the rendered data */
445 const float *xfb_data = (const float *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
446 bo_size, GL_MAP_READ_BIT);
447
448 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
449
450 memcpy(test_iteration.data, xfb_data, bo_size);
451
452 /* Unmap the buffer object, now that we're done retrieving the captured data */
453 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
454 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
455
456 gl.deleteProgram(po_id);
457 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram() call failed");
458
459 return test_iteration;
460 }
461
462 /** Executes the test.
463 *
464 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
465 *
466 * Note the function throws exception should an error occur!
467 *
468 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
469 **/
iterate(void)470 tcu::TestNode::IterateResult TessellationShaderVertexOrdering::iterate(void)
471 {
472 initTest();
473
474 /* Do not execute if required extensions are not supported. */
475 if (!m_is_tessellation_shader_supported)
476 {
477 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
478 }
479
480 /* There are two main separate cases to consider here:
481 *
482 * a) for runs executed in "points" mode, we need to verify that vertex
483 * ordering does not modify the order in which the points are generated.
484 * b) for both run types, for all primitives but isolines we need to verify
485 * that the vertex ordering is actually taken into account.
486 */
487 const float epsilon = 1e-5f;
488
489 for (_test_iterations_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end();
490 test_iterator++)
491 {
492 if (test_iterator->primitive_mode != TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
493 {
494 verifyVertexOrderingCorrectness(*test_iterator);
495 }
496 } /* for (all non-points runs) */
497
498 for (_test_iterations_const_iterator test_iterator = m_tests_points.begin(); test_iterator != m_tests_points.end();
499 test_iterator++)
500 {
501 const _test_iteration &test = *test_iterator;
502
503 /* For points_mode checks, we need to find a corresponding cw+ccw test pairs */
504 if (test.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CCW ||
505 test.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT)
506 {
507 /* Find a corresponding CW test descriptor */
508 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
509 bool has_paired_test_been_found = false;
510 #endif
511 _test_iteration paired_test;
512
513 for (_test_iterations_const_iterator paired_test_iterator = m_tests_points.begin();
514 paired_test_iterator != m_tests_points.end(); ++paired_test_iterator)
515 {
516 if (de::abs(paired_test_iterator->inner_tess_levels[0] - test_iterator->inner_tess_levels[0]) <
517 epsilon &&
518 de::abs(paired_test_iterator->inner_tess_levels[1] - test_iterator->inner_tess_levels[1]) <
519 epsilon &&
520 de::abs(paired_test_iterator->outer_tess_levels[0] - test_iterator->outer_tess_levels[0]) <
521 epsilon &&
522 de::abs(paired_test_iterator->outer_tess_levels[1] - test_iterator->outer_tess_levels[1]) <
523 epsilon &&
524 de::abs(paired_test_iterator->outer_tess_levels[2] - test_iterator->outer_tess_levels[2]) <
525 epsilon &&
526 de::abs(paired_test_iterator->outer_tess_levels[3] - test_iterator->outer_tess_levels[3]) <
527 epsilon &&
528 paired_test_iterator->n_vertices == test_iterator->n_vertices &&
529 paired_test_iterator->primitive_mode == test_iterator->primitive_mode &&
530 paired_test_iterator->vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CW)
531 {
532 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
533 has_paired_test_been_found = true;
534 #endif
535 paired_test = *paired_test_iterator;
536
537 break;
538 }
539 }
540
541 DE_ASSERT(has_paired_test_been_found);
542
543 /* Good to call the verification routine */
544 verifyVertexOrderingDoesNotChangeGeneratedPoints(test, paired_test);
545 } /* if (base test 's vertex ordering is CCW) */
546 } /* for (all other runs) */
547
548 /* All done */
549 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
550 return STOP;
551 }
552
553 /** Verifies that vertex ordering in the data set stored in user-provided
554 * test iteration descriptor matches the setting that was used in the
555 * tessellation evaluation stage.
556 *
557 * @param test_iteration Test iteration descriptor
558 *
559 **/
verifyVertexOrderingCorrectness(const _test_iteration & test_iteration)560 void TessellationShaderVertexOrdering::verifyVertexOrderingCorrectness(const _test_iteration &test_iteration)
561 {
562 /* Quick check */
563 DE_ASSERT(test_iteration.primitive_mode != TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES);
564
565 /* Iterate through all vertices */
566 const float epsilon = 1e-5f;
567 const unsigned int n_vertices_per_primitive = 3;
568
569 for (unsigned int n_primitive = 0; n_primitive < test_iteration.n_vertices / n_vertices_per_primitive;
570 ++n_primitive)
571 {
572 const float *primitive_data =
573 (const float *)test_iteration.data + 3 /* components */ * n_primitive * n_vertices_per_primitive;
574 const float *primitive_vertex1_data = primitive_data;
575 const float *primitive_vertex2_data = primitive_vertex1_data + 3; /* components */
576 const float *primitive_vertex3_data = primitive_vertex2_data + 3; /* components */
577
578 float cartesian_vertex_data[6] = {primitive_vertex1_data[0], primitive_vertex1_data[1],
579 primitive_vertex2_data[0], primitive_vertex2_data[1],
580 primitive_vertex3_data[0], primitive_vertex3_data[1]};
581
582 if (test_iteration.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
583 {
584 /* Triangles are described in barycentric coordinate. Convert to
585 * cartesian coordinates before we continue with actual test.
586 */
587 const float barycentric_vertex_data[] = {
588 primitive_vertex1_data[0], primitive_vertex1_data[1], primitive_vertex1_data[2],
589 primitive_vertex2_data[0], primitive_vertex2_data[1], primitive_vertex2_data[2],
590 primitive_vertex3_data[0], primitive_vertex3_data[1], primitive_vertex3_data[2],
591 };
592
593 /* Quick checks .. */
594 DE_UNREF(epsilon);
595 DE_ASSERT(de::abs(barycentric_vertex_data[0] + barycentric_vertex_data[1] + barycentric_vertex_data[2] -
596 1.0f) < epsilon);
597 DE_ASSERT(de::abs(barycentric_vertex_data[3] + barycentric_vertex_data[4] + barycentric_vertex_data[5] -
598 1.0f) < epsilon);
599 DE_ASSERT(de::abs(barycentric_vertex_data[6] + barycentric_vertex_data[7] + barycentric_vertex_data[8] -
600 1.0f) < epsilon);
601
602 for (unsigned int n_vertex = 0; n_vertex < 3; ++n_vertex)
603 {
604 TessellationShaderUtils::convertBarycentricCoordinatesToCartesian(
605 barycentric_vertex_data + n_vertex * 3, cartesian_vertex_data + n_vertex * 2);
606 }
607 } /* if (test_iteration.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) */
608
609 /* Compute result of eq 3.6.1 */
610 float determinant = 0.0f;
611
612 for (unsigned int n_vertex = 0; n_vertex < n_vertices_per_primitive; ++n_vertex)
613 {
614 int i_op_1 = (n_vertex + 1) % n_vertices_per_primitive;
615
616 determinant += (cartesian_vertex_data[n_vertex * 2 /* components */ + 0] *
617 cartesian_vertex_data[i_op_1 * 2 /* components */ + 1] -
618 cartesian_vertex_data[i_op_1 * 2 /* components */ + 0] *
619 cartesian_vertex_data[n_vertex * 2 /* components */ + 1]);
620 } /* for (all vertices) */
621
622 determinant *= 0.5f;
623
624 /* Positive determinant implies counterclockwise ordering */
625 if (((test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CCW ||
626 test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT) &&
627 determinant < 0.0f) ||
628 (test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CW && determinant >= 0.0f))
629 {
630 std::string primitive_mode =
631 TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration.primitive_mode);
632 std::string vertex_ordering =
633 TessellationShaderUtils::getESTokenForVertexOrderingMode(test_iteration.vertex_ordering);
634
635 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode: [" << primitive_mode.c_str()
636 << "] "
637 "and inner tessellation levels:"
638 " ["
639 << test_iteration.inner_tess_levels[0] << ", " << test_iteration.inner_tess_levels[1]
640 << "] "
641 "and outer tessellation levels:"
642 " ["
643 << test_iteration.outer_tess_levels[0] << ", " << test_iteration.outer_tess_levels[1]
644 << ", " << test_iteration.outer_tess_levels[2] << ", "
645 << test_iteration.outer_tess_levels[3] << "] "
646 << "and vertex ordering: [" << vertex_ordering.c_str()
647 << "] "
648 ", vertex orientation has been found to be incompatible with the ordering requested."
649 << tcu::TestLog::EndMessage;
650
651 if (test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CCW ||
652 test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT)
653 {
654 TCU_FAIL("Counter-clockwise ordering was expected but retrieved tessellation coordinates are laid out "
655 "in clockwise order");
656 }
657 else
658 {
659 TCU_FAIL("Clockwise ordering was expected but retrieved tessellation coordinates are laid out in "
660 "counter-clockwise order");
661 }
662 }
663 } /* for (all triangles) */
664 }
665
666 /** Verifies that vertices generated by the tessellator do not differ when run for exactly
667 * the same tessellation evaluation shaders configure to run in point mode, with an exception
668 * that one invokation used CW ordering and the other one used CCW ordering.
669 *
670 * Note: this function throws a TestError exception, should an error occur.
671 *
672 * @param test_iteration_a Test iteration which was run in point mode and uses CCW vertex
673 * ordering.
674 * @param test_iteration_b Test iteration which was run in point mode and uses CW vertex
675 * ordering.
676 *
677 **/
verifyVertexOrderingDoesNotChangeGeneratedPoints(const _test_iteration & test_iteration_a,const _test_iteration & test_iteration_b)678 void TessellationShaderVertexOrdering::verifyVertexOrderingDoesNotChangeGeneratedPoints(
679 const _test_iteration &test_iteration_a, const _test_iteration &test_iteration_b)
680 {
681 const float epsilon = 1e-5f;
682
683 /* Quick checks */
684 DE_ASSERT(test_iteration_a.is_point_mode_enabled);
685 DE_ASSERT(test_iteration_b.is_point_mode_enabled);
686 DE_ASSERT(test_iteration_a.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CCW ||
687 test_iteration_a.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT);
688 DE_ASSERT(test_iteration_b.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CW);
689
690 /* Iterate through all points in test set A and make sure they can be found in test set B */
691 for (unsigned int n_vertex_a = 0; n_vertex_a < test_iteration_a.n_vertices; ++n_vertex_a)
692 {
693 bool has_been_found = false;
694 const float *vertex_a_data = (const float *)test_iteration_a.data + n_vertex_a * 3 /* components */;
695
696 for (unsigned int n_vertex_b = 0; n_vertex_b < test_iteration_b.n_vertices; ++n_vertex_b)
697 {
698 const float *vertex_b_data = (const float *)test_iteration_b.data + n_vertex_b * 3 /* components */;
699
700 if (de::abs(vertex_a_data[0] - vertex_b_data[0]) < epsilon &&
701 de::abs(vertex_a_data[1] - vertex_b_data[1]) < epsilon &&
702 de::abs(vertex_a_data[2] - vertex_b_data[2]) < epsilon)
703 {
704 has_been_found = true;
705
706 break;
707 }
708 } /* for (all B set vertices) */
709
710 if (!has_been_found)
711 {
712 std::string primitive_mode =
713 TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration_a.primitive_mode);
714 std::string vertex_ordering =
715 TessellationShaderUtils::getESTokenForVertexOrderingMode(test_iteration_a.vertex_ordering);
716
717 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode: [" << primitive_mode.c_str()
718 << "] "
719 "and inner tessellation levels:"
720 " ["
721 << test_iteration_a.inner_tess_levels[0] << ", " << test_iteration_a.inner_tess_levels[1]
722 << "] "
723 "and outer tessellation levels:"
724 " ["
725 << test_iteration_a.outer_tess_levels[0] << ", " << test_iteration_a.outer_tess_levels[1]
726 << ", " << test_iteration_a.outer_tess_levels[2] << ", "
727 << test_iteration_a.outer_tess_levels[3] << "] "
728 << ", vertices generated for CW and CCW orientations do not match."
729 << tcu::TestLog::EndMessage;
730
731 TCU_FAIL("For runs in which only vertex ordering setting differs, vertex from one run was not found in the "
732 "other run.");
733 }
734 } /* for (all A set vertices) */
735 }
736
737 } /* namespace glcts */
738