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