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