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 "esextcTessellationShaderInvariance.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30 
31 namespace glcts
32 {
33 
34 /* Defines a single vertex in tessellation space */
35 typedef struct _vertex
36 {
37     float u;
38     float v;
39     float w;
40 
_vertexglcts::_vertex41     _vertex()
42     {
43         u = 0.0f;
44         v = 0.0f;
45         w = 0.0f;
46     }
47 } _vertex;
48 
49 /** Constructor
50  *
51  * @param context Test context
52  **/
TessellationShaderInvarianceTests(glcts::Context & context,const ExtParameters & extParams)53 TessellationShaderInvarianceTests::TessellationShaderInvarianceTests(glcts::Context &context,
54                                                                      const ExtParameters &extParams)
55     : TestCaseGroupBase(context, extParams, "tessellation_invariance",
56                         "Verifies the implementation conforms to invariance rules.")
57 {
58     /* No implementation needed */
59 }
60 
61 /**
62  * Initializes test groups for geometry shader tests
63  **/
init(void)64 void TessellationShaderInvarianceTests::init(void)
65 {
66     addChild(new glcts::TessellationShaderInvarianceRule1Test(m_context, m_extParams));
67     addChild(new glcts::TessellationShaderInvarianceRule2Test(m_context, m_extParams));
68     addChild(new glcts::TessellationShaderInvarianceRule3Test(m_context, m_extParams));
69     addChild(new glcts::TessellationShaderInvarianceRule4Test(m_context, m_extParams));
70     addChild(new glcts::TessellationShaderInvarianceRule5Test(m_context, m_extParams));
71     addChild(new glcts::TessellationShaderInvarianceRule6Test(m_context, m_extParams));
72     addChild(new glcts::TessellationShaderInvarianceRule7Test(m_context, m_extParams));
73 }
74 
75 /** Constructor
76  *
77  * @param context     Test context
78  * @param name        Test name
79  * @param description Test description
80  **/
TessellationShaderInvarianceBaseTest(Context & context,const ExtParameters & extParams,const char * name,const char * description)81 TessellationShaderInvarianceBaseTest::TessellationShaderInvarianceBaseTest(Context &context,
82                                                                            const ExtParameters &extParams,
83                                                                            const char *name, const char *description)
84     : TestCaseBase(context, extParams, name, description)
85     , m_utils_ptr(DE_NULL)
86     , m_bo_id(0)
87     , m_qo_tfpw_id(0)
88     , m_vao_id(0)
89 {
90     /* Left blank on purpose */
91 }
92 
93 /** Deinitializes ES objects created for the test. */
deinit()94 void TessellationShaderInvarianceBaseTest::deinit()
95 {
96     /* Call base class' deinit() */
97     TestCaseBase::deinit();
98 
99     if (!m_is_tessellation_shader_supported)
100     {
101         return;
102     }
103 
104     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
105 
106     /* Revert buffer object bindings */
107     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
108     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
109 
110     /* Disable GL_RASTERIZER_DISCARD mode */
111     gl.disable(GL_RASTERIZER_DISCARD);
112 
113     /* Reset GL_PATCH_VERTICES_EXT to default value */
114     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
115 
116     /* Unbind vertex array object */
117     gl.bindVertexArray(0);
118 
119     /* Deinitialize all ES objects that were created for test purposes */
120     if (m_bo_id != 0)
121     {
122         gl.deleteBuffers(1, &m_bo_id);
123 
124         m_bo_id = 0;
125     }
126 
127     for (_programs_iterator it = m_programs.begin(); it != m_programs.end(); ++it)
128     {
129         _test_program &program = *it;
130 
131         if (program.po_id != 0)
132         {
133             gl.deleteProgram(program.po_id);
134         }
135     }
136     m_programs.clear();
137 
138     if (m_qo_tfpw_id != 0)
139     {
140         gl.deleteQueries(1, &m_qo_tfpw_id);
141 
142         m_qo_tfpw_id = 0;
143     }
144 
145     if (m_vao_id != 0)
146     {
147         gl.deleteVertexArrays(1, &m_vao_id);
148 
149         m_vao_id = 0;
150     }
151 
152     /* Deinitialize TS utils instance */
153     if (m_utils_ptr != NULL)
154     {
155         delete m_utils_ptr;
156 
157         m_utils_ptr = NULL;
158     }
159 }
160 
161 /** Executes a single-counted GL_PATCHES_EXT draw call.
162  *
163  *  Throws TestError exception if an error occurs.
164  *
165  *  @param n_iteration Not used.
166  *
167  **/
executeDrawCall(unsigned int n_iteration)168 void TessellationShaderInvarianceBaseTest::executeDrawCall(unsigned int n_iteration)
169 {
170     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
171 
172     DE_UNREF(n_iteration);
173 
174     gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, getDrawCallCountArgument());
175     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
176 }
177 
178 /** Returns a value that should be used for the draw call's "count" argument.
179  *
180  *  @param Always 1
181  **/
getDrawCallCountArgument()182 unsigned int TessellationShaderInvarianceBaseTest::getDrawCallCountArgument()
183 {
184     return 1;
185 }
186 
187 /** Returns source code for fragment shader stage which does
188  *  not do anything.
189  *
190  *  @param n_iteration Not used.
191  *
192  *  @return Requested string.
193  **/
getFSCode(unsigned int n_iteration)194 std::string TessellationShaderInvarianceBaseTest::getFSCode(unsigned int n_iteration)
195 {
196     DE_UNREF(n_iteration);
197 
198     std::string result = "${VERSION}\n"
199                          "\n"
200                          "void main()\n"
201                          "{\n"
202                          "}\n";
203 
204     return result;
205 }
206 
207 /** Retrieves name of a vec2 uniform that stores inner tesselaton level information,
208  *  later assigned to gl_TessLevelInner in tessellation evaluation shader.
209  *
210  *  @return Requested name.
211  **/
getInnerTessLevelUniformName()212 const char *TessellationShaderInvarianceBaseTest::getInnerTessLevelUniformName()
213 {
214     static const char *result = "inner_tess_level";
215 
216     return result;
217 }
218 
219 /** Retrieves name of a vec4 uniform that stores outer tesselation level information,
220  *  later assigned to gl_TessLevelOuter in tessellation evaluation shader.
221  *
222  *  @return Requested name.
223  **/
getOuterTessLevelUniformName()224 const char *TessellationShaderInvarianceBaseTest::getOuterTessLevelUniformName()
225 {
226     static const char *result = "outer_tess_level";
227 
228     return result;
229 }
230 
231 /** Returns generic tessellation control shader code, which sends 4 output patch
232  *  to tessellation evaluation shader stage and uses the very first input patch
233  *  vertex only.
234  *
235  *  @return Tessellation control source code.
236  */
getTCCode(unsigned int n_iteration)237 std::string TessellationShaderInvarianceBaseTest::getTCCode(unsigned int n_iteration)
238 {
239     DE_UNREF(n_iteration);
240 
241     /* In order to support all three primitive types, our generic tessellation
242      * control shader will pass 4 vertices to TE stage */
243     return TessellationShaderUtils::getGenericTCCode(4, /* n_patch_vertices */
244                                                      false);
245 }
246 
247 /** Retrieves XFB properties for the test pass.
248  *
249  *  @param n_iteration Not used.
250  *  @param out_n_names Deref will be used to store amount of strings @param *out_n_names
251  *                     offers.
252  *  @param out_names   Deref will be used to store pointer to an array of strings holding
253  *                     names of varyings that should be captured via transform feedback.
254  *                     Must not be NULL.
255  *
256  **/
getXFBProperties(unsigned int n_iteration,unsigned int * out_n_names,const char *** out_names)257 void TessellationShaderInvarianceBaseTest::getXFBProperties(unsigned int n_iteration, unsigned int *out_n_names,
258                                                             const char ***out_names)
259 {
260     static const char *names[] = {"result_uvw"};
261 
262     DE_UNREF(n_iteration);
263 
264     *out_n_names = 1;
265     *out_names   = names;
266 }
267 
268 /** Returns vertex shader source code. The shader sets gl_Position to
269  *  vec4(1, 2, 3, 0).
270  *
271  *  @return Vertex shader source code.
272  **/
getVSCode(unsigned int n_iteration)273 std::string TessellationShaderInvarianceBaseTest::getVSCode(unsigned int n_iteration)
274 {
275     DE_UNREF(n_iteration);
276 
277     std::string result = "${VERSION}\n"
278                          "\n"
279                          "void main()\n"
280                          "{\n"
281                          "    gl_Position = vec4(1.0, 2.0, 3.0, 0.0);\n"
282                          "}\n";
283 
284     return result;
285 }
286 
287 /** Initializes ES objects required to execute the test.
288  *
289  *  Throws TestError exception if an error occurs.
290  *
291  **/
initTest()292 void TessellationShaderInvarianceBaseTest::initTest()
293 {
294     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
295     glw::GLuint shared_fs_id = 0;
296     glw::GLuint shared_tc_id = 0;
297     glw::GLuint shared_te_id = 0;
298     glw::GLuint shared_vs_id = 0;
299 
300     gl.genVertexArrays(1, &m_vao_id);
301     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
302 
303     gl.bindVertexArray(m_vao_id);
304     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
305 
306     /* Initialize GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object */
307     gl.genQueries(1, &m_qo_tfpw_id);
308     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries() call failed");
309 
310     /* Initialize tessellation shader utils */
311     m_utils_ptr = new TessellationShaderUtils(gl, this);
312 
313     /* Initialize a buffer object we will use to store XFB data.
314      * Note: we intentionally skip a glBufferData() call here,
315      *       the actual buffer storage size is iteration-specific.
316      **/
317     gl.genBuffers(1, &m_bo_id);
318     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
319 
320     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
321     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
322 
323     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
324                       m_bo_id);
325     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
326 
327     /* Iterate through all iterations */
328     const unsigned int n_iterations = getAmountOfIterations();
329     m_programs.reserve(n_iterations);
330 
331     const glw::GLenum SHADER_TYPE_FRAGMENT                = GL_FRAGMENT_SHADER;
332     const glw::GLenum SHADER_TYPE_TESSELLATION_CONTROL    = m_glExtTokens.TESS_CONTROL_SHADER;
333     const glw::GLenum SHADER_TYPE_TESSELLATION_EVALUATION = m_glExtTokens.TESS_EVALUATION_SHADER;
334     const glw::GLenum SHADER_TYPE_VERTEX                  = GL_VERTEX_SHADER;
335 
336     for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
337     {
338         _test_program program;
339 
340         /* Create an iteration-specific program object */
341         program.po_id = gl.createProgram();
342 
343         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
344 
345         /* Query the implementation on which shader types should be compiled on
346          * a per-iteration basis, and which can be initialized only once */
347         static const glw::GLenum shader_types[]  = {SHADER_TYPE_FRAGMENT, SHADER_TYPE_TESSELLATION_CONTROL,
348                                                     SHADER_TYPE_TESSELLATION_EVALUATION, SHADER_TYPE_VERTEX};
349         static const unsigned int n_shader_types = sizeof(shader_types) / sizeof(shader_types[0]);
350 
351         for (unsigned int n_shader_type = 0; n_shader_type < n_shader_types; ++n_shader_type)
352         {
353             std::string shader_body;
354             const char *shader_body_ptr = DE_NULL;
355             glw::GLuint shader_id       = 0;
356             glw::GLenum shader_type     = shader_types[n_shader_type];
357             glw::GLenum shader_type_es  = (glw::GLenum)shader_type;
358 
359             // Check whether the test should use a separate program objects for each iteration.
360             bool is_shader_iteration_specific = false;
361             if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
362             {
363                 is_shader_iteration_specific = true;
364             }
365             else if ((shader_type != SHADER_TYPE_FRAGMENT) && (shader_type != SHADER_TYPE_TESSELLATION_CONTROL) &&
366                      (shader_type != SHADER_TYPE_VERTEX))
367             {
368                 TCU_FAIL("Unrecognized shader type");
369             }
370 
371             /* We need to initialize the shader object if:
372              *
373              * - its body differs between iterations;
374              * - its body is shared by all iterations AND this is the first iteration
375              */
376             bool has_shader_been_generated = false;
377 
378             if ((!is_shader_iteration_specific && n_iteration == 0) || is_shader_iteration_specific)
379             {
380                 /* Create the shader object */
381                 has_shader_been_generated = true;
382                 shader_id                 = gl.createShader(shader_type_es);
383                 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
384 
385                 /* Assign shader body to the object */
386                 if (shader_type == SHADER_TYPE_FRAGMENT)
387                 {
388                     shader_body = getFSCode(n_iteration);
389                 }
390                 else if (shader_type == SHADER_TYPE_TESSELLATION_CONTROL)
391                 {
392                     shader_body = getTCCode(n_iteration);
393                 }
394                 else if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
395                 {
396                     shader_body = getTECode(n_iteration);
397                 }
398                 else if (shader_type == SHADER_TYPE_VERTEX)
399                 {
400                     shader_body = getVSCode(n_iteration);
401                 }
402                 else
403                 {
404                     TCU_FAIL("Unrecognized shader type");
405                 }
406 
407                 shader_body_ptr = shader_body.c_str();
408 
409                 shaderSourceSpecialized(shader_id, 1, &shader_body_ptr);
410                 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
411 
412                 /* Compile the shader object */
413                 m_utils_ptr->compileShaders(1,                 /* n_shaders */
414                                             &shader_id, true); /* should_succeed */
415 
416                 /* If this is a shader object that will be shared by all iterations, cache it
417                  * in a dedicated variable */
418                 if (!is_shader_iteration_specific)
419                 {
420                     if (shader_type == SHADER_TYPE_FRAGMENT)
421                     {
422                         shared_fs_id = shader_id;
423                     }
424                     else if (shader_type == SHADER_TYPE_TESSELLATION_CONTROL)
425                     {
426                         shared_tc_id = shader_id;
427                     }
428                     else if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
429                     {
430                         shared_te_id = shader_id;
431                     }
432                     else if (shader_type == SHADER_TYPE_VERTEX)
433                     {
434                         shared_vs_id = shader_id;
435                     }
436                     else
437                     {
438                         TCU_FAIL("Unrecognized shader type");
439                     }
440                 } /* if (!is_shader_iteration_specific) */
441             }     /* if (shader object needs to be initialized) */
442             else
443             {
444                 shader_id = (shader_type == SHADER_TYPE_FRAGMENT)                ? shared_fs_id :
445                             (shader_type == SHADER_TYPE_TESSELLATION_CONTROL)    ? shared_tc_id :
446                             (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION) ? shared_te_id :
447                                                                                    shared_vs_id;
448             }
449 
450             /* Attach the shader object to iteration-specific program object */
451             gl.attachShader(program.po_id, shader_id);
452 
453             GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
454 
455             /* Now that the object has been attached, we can flag it for deletion */
456             if (has_shader_been_generated)
457             {
458                 gl.deleteShader(shader_id);
459                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed");
460             }
461         } /* for (all shader types) */
462 
463         /* Set up transform feed-back */
464         unsigned int n_xfb_names = 0;
465         const char **xfb_names   = NULL;
466 
467         getXFBProperties(n_iteration, &n_xfb_names, &xfb_names);
468 
469         gl.transformFeedbackVaryings(program.po_id, n_xfb_names, xfb_names, GL_INTERLEAVED_ATTRIBS);
470         GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
471 
472         /* Try to link the program object */
473         glw::GLint link_status = GL_FALSE;
474 
475         gl.linkProgram(program.po_id);
476         GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
477 
478         gl.getProgramiv(program.po_id, GL_LINK_STATUS, &link_status);
479         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
480 
481         if (link_status != GL_TRUE)
482         {
483             TCU_FAIL("Program linking failed");
484         }
485 
486         /* Retrieve inner/outer tess level uniform locations */
487         program.inner_tess_level_uniform_location =
488             gl.getUniformLocation(program.po_id, getInnerTessLevelUniformName());
489         program.outer_tess_level_uniform_location =
490             gl.getUniformLocation(program.po_id, getOuterTessLevelUniformName());
491 
492         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed");
493 
494         /* Store the program object */
495         m_programs.push_back(program);
496     } /* for (all iterations) */
497 }
498 
499 /** Executes the test.
500  *
501  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
502  *
503  *  Note the function throws exception should an error occur!
504  *
505  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
506  **/
iterate(void)507 tcu::TestNode::IterateResult TessellationShaderInvarianceBaseTest::iterate(void)
508 {
509     /* Do not execute if required extensions are not supported. */
510     if (!m_is_tessellation_shader_supported)
511     {
512         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
513     }
514 
515     /* Initialize all objects needed to run the test */
516     initTest();
517 
518     /* Do a general set-up */
519     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
520 
521     gl.enable(GL_RASTERIZER_DISCARD);
522     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
523 
524     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
525     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
526 
527     /* There are two types of verification supported by this base test implementation:
528      *
529      * - iteration-specific (verifyResultDataForIteration() )
530      * - global             (verifyResultData() )
531      *
532      * It is up to test implementation to decide which of the two (or perhaps both)
533      * entry-points it should overload and use for validating the result data.
534      */
535     const unsigned int n_iterations = getAmountOfIterations();
536     char **iteration_data           = new char *[n_iterations];
537 
538     /* Execute the test */
539     for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
540     {
541         _test_program &program = m_programs[n_iteration];
542 
543         /* Retrieve iteration properties for current iteration */
544         unsigned int bo_size                                 = 0;
545         float inner_tess_levels[2]                           = {0};
546         bool is_point_mode                                   = false;
547         float outer_tess_levels[4]                           = {0};
548         _tessellation_primitive_mode primitive_mode          = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
549         _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
550 
551         getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &is_point_mode, &primitive_mode,
552                                &vertex_ordering, &bo_size);
553 
554         DE_ASSERT(bo_size != 0);
555 
556         /* Activate iteration-specific program */
557         gl.useProgram(program.po_id);
558         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed.");
559 
560         /* Set up buffer object storage */
561         {
562             char *zero_bo_data = new char[bo_size];
563 
564             memset(zero_bo_data, 0, bo_size);
565 
566             gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, zero_bo_data, GL_STATIC_DRAW);
567             GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
568 
569             delete[] zero_bo_data;
570             zero_bo_data = NULL;
571         }
572 
573         /* Allocate space for iteration-specific data */
574         iteration_data[n_iteration] = new char[bo_size];
575 
576         /* Configure inner/outer tessellation levels as requested for the iteration */
577         gl.uniform2fv(program.inner_tess_level_uniform_location, 1, /* count */
578                       inner_tess_levels);
579         GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
580 
581         gl.uniform4fv(program.outer_tess_level_uniform_location, 1, /* count */
582                       outer_tess_levels);
583         GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
584 
585         /* Launch the TFPW query */
586         gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tfpw_id);
587         GLU_EXPECT_NO_ERROR(gl.getError(),
588                             "glBeginQuery() for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN target failed.");
589 
590         /* Prepare for TF */
591         glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(primitive_mode, is_point_mode);
592 
593         gl.beginTransformFeedback(tf_mode);
594         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
595         {
596             /* Execute the draw call */
597             executeDrawCall(n_iteration);
598 
599             GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed");
600         }
601         gl.endTransformFeedback();
602         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
603 
604         gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
605         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) call failed");
606 
607         /* Make sure that we had sufficient amount of space in a buffer object we used to
608          * capture XFB data.
609          **/
610         glw::GLuint n_tf_primitives_written = 0;
611         glw::GLuint used_tf_bo_size         = 0;
612 
613         gl.getQueryObjectuiv(m_qo_tfpw_id, GL_QUERY_RESULT, &n_tf_primitives_written);
614         GLU_EXPECT_NO_ERROR(gl.getError(),
615                             "Could not retrieve GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object result");
616 
617         if (is_point_mode)
618         {
619             used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* components */);
620         }
621         else if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
622         {
623             used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 2 /* vertices */ *
624                                                        3 /* components */);
625         }
626         else
627         {
628             used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* vertices */ *
629                                                        3 /* components */);
630         }
631 
632         if (used_tf_bo_size != bo_size)
633         {
634             m_testCtx.getLog() << tcu::TestLog::Message << "Expected " << bo_size
635                                << " to be filled with tessellation data, "
636                                   "only "
637                                << used_tf_bo_size << "was used." << tcu::TestLog::EndMessage;
638 
639             TCU_FAIL("Amount of primitives generated during TF does not match amount of primitives that were expected"
640                      " to be generated by the tessellator");
641         }
642 
643         /* Map the buffer object we earlier bound to GL_TRANSFORM_FEEDBACK_BUFFER
644          * target into process space. */
645         const void *xfb_data = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
646                                                  bo_size, GL_MAP_READ_BIT);
647 
648         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
649 
650         memcpy(iteration_data[n_iteration], xfb_data, bo_size);
651 
652         /* Unmap the buffer object */
653         gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
654         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
655 
656         /* Ask the test implementation to verify the results */
657         verifyResultDataForIteration(n_iteration, iteration_data[n_iteration]);
658     } /* for (all iterations) */
659 
660     /* Now that we've executed all iterations, we can call a global verification
661      * entry-point */
662     verifyResultData((const void **)iteration_data);
663 
664     /* At this point we're safe to release space allocated for data coming from
665      * all the iterations */
666     for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
667     {
668         char *iter_data = (char *)iteration_data[n_iteration];
669         delete[] iter_data;
670 
671         iteration_data[n_iteration] = DE_NULL;
672     } /* for (all iterations) */
673 
674     delete[] iteration_data;
675     iteration_data = DE_NULL;
676 
677     /* All done */
678     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
679     return STOP;
680 }
681 
682 /* Does nothing (stub implementation)
683  *
684  * @param n_iteration Not used.
685  * @param data        Not used.
686  *
687  **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)688 void TessellationShaderInvarianceBaseTest::verifyResultDataForIteration(unsigned int n_iteration, const void *data)
689 {
690     DE_UNREF(n_iteration && data);
691 
692     /* Do nothing - this is just a stub. */
693 }
694 
695 /* Does nothing (stub implementation)
696  *
697  * @param all_iterations_data Not used.
698  *
699  **/
verifyResultData(const void ** all_iterations_data)700 void TessellationShaderInvarianceBaseTest::verifyResultData(const void **all_iterations_data)
701 {
702     DE_UNREF(all_iterations_data);
703 
704     /* Do nothing - this is just a stub. */
705 }
706 
707 /** Constructor.
708  *
709  *  @param context Rendering context.
710  *
711  **/
TessellationShaderInvarianceRule1Test(Context & context,const ExtParameters & extParams)712 TessellationShaderInvarianceRule1Test::TessellationShaderInvarianceRule1Test(Context &context,
713                                                                              const ExtParameters &extParams)
714     : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule1",
715                                            "Verifies conformance with first invariance rule")
716 {
717     /* Left blank intentionally */
718 }
719 
720 /** Destructor. */
~TessellationShaderInvarianceRule1Test()721 TessellationShaderInvarianceRule1Test::~TessellationShaderInvarianceRule1Test()
722 {
723     /* Left blank intentionally */
724 }
725 
726 /** Retrieves amount of iterations the base test implementation should run before
727  *  calling global verification routine.
728  *
729  *  @return Always 6.
730  **/
getAmountOfIterations()731 unsigned int TessellationShaderInvarianceRule1Test::getAmountOfIterations()
732 {
733     return 6;
734 }
735 
736 /** Returns a value that should be used for the draw call's "count" argument.
737  *
738  *  @param Always 3
739  **/
getDrawCallCountArgument()740 unsigned int TessellationShaderInvarianceRule1Test::getDrawCallCountArgument()
741 {
742     return 3;
743 }
744 
745 /** Retrieves iteration-specific tessellation properties.
746  *
747  *  @param n_iteration            Iteration index to retrieve the properties for.
748  *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
749  *                                tessellation level values. Must not be NULL.
750  *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
751  *                                tessellation level values. Must not be NULL.
752  *  @param out_point_mode         Deref will be used to store iteration-specific flag
753  *                                telling whether point mode should be enabled for given pass.
754  *                                Must not be NULL.
755  *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
756  *                                mode. Must not be NULL.
757  *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex ordering.
758  *                                Must not be NULL.
759  *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
760  *                                storage should offer for the draw call to succeed. Must not
761  *                                be NULL.
762  **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)763 void TessellationShaderInvarianceRule1Test::getIterationProperties(
764     unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
765     _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
766     unsigned int *out_result_buffer_size)
767 {
768     *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
769 
770     switch (n_iteration)
771     {
772     case 0:
773     case 5:
774     {
775         /* Triangles (point mode) */
776         out_inner_tess_levels[0] = 1.0f;
777         out_outer_tess_levels[0] = 1.0f;
778         out_outer_tess_levels[1] = 1.0f;
779         out_outer_tess_levels[2] = 1.0f;
780 
781         *out_point_mode     = true;
782         *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
783 
784         break;
785     }
786 
787     case 1:
788     case 3:
789     {
790         /* Lines */
791         out_outer_tess_levels[0] = 1.0f;
792         out_outer_tess_levels[1] = 1.0f;
793 
794         *out_point_mode     = false;
795         *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES;
796 
797         break;
798     }
799 
800     case 2:
801     case 4:
802     {
803         /* Triangles */
804         out_inner_tess_levels[0] = 1.0f;
805         out_outer_tess_levels[0] = 1.0f;
806         out_outer_tess_levels[1] = 1.0f;
807         out_outer_tess_levels[2] = 1.0f;
808 
809         *out_point_mode     = false;
810         *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
811 
812         break;
813     }
814 
815     default:
816     {
817         TCU_FAIL("Unrecognzied iteration index");
818     }
819     }
820 
821     *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
822         *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
823         *out_point_mode);
824 
825     *out_result_buffer_size = static_cast<unsigned int>(*out_result_buffer_size * getDrawCallCountArgument() *
826                                                         3 /* components */ * sizeof(float));
827 
828     DE_ASSERT(*out_result_buffer_size != 0);
829 }
830 
831 /** Retrieves iteration-specific tessellation evaluation shader code.
832  *
833  *  @param n_iteration Iteration index, for which the source code is being obtained.
834  *
835  *  @return Requested source code.
836  **/
getTECode(unsigned int n_iteration)837 std::string TessellationShaderInvarianceRule1Test::getTECode(unsigned int n_iteration)
838 {
839     unsigned int bo_size                                 = 0;
840     float inner_tess_levels[2]                           = {0};
841     float outer_tess_levels[4]                           = {0};
842     bool point_mode                                      = false;
843     _tessellation_primitive_mode primitive_mode          = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
844     _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
845 
846     getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode,
847                            &vertex_ordering, &bo_size);
848 
849     return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode,
850                                                      vertex_ordering, point_mode);
851 }
852 
853 /** Verifies result data. Accesses data generated by all iterations.
854  *
855  *  Throws TestError exception if an error occurs.
856  *
857  *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
858  *                             data generated by subsequent iterations.
859  **/
verifyResultData(const void ** all_iterations_data)860 void TessellationShaderInvarianceRule1Test::verifyResultData(const void **all_iterations_data)
861 {
862     const float *lines_vertex_data_1 = (const float *)all_iterations_data[1];
863     const float *lines_vertex_data_2 = (const float *)all_iterations_data[3];
864     const float *point_vertex_data_1 = (const float *)all_iterations_data[0];
865     const float *point_vertex_data_2 = (const float *)all_iterations_data[5];
866     const float *tris_vertex_data_1  = (const float *)all_iterations_data[2];
867     const float *tris_vertex_data_2  = (const float *)all_iterations_data[4];
868 
869     const unsigned int n_line_vertices  = 2 /* vertices per line segment */ * getDrawCallCountArgument(); /* lines */
870     const unsigned int n_point_vertices = 1 /* vertices per point */ * getDrawCallCountArgument();        /* points */
871     const unsigned int n_tri_vertices   = 3 /* vertices per triangle */ * getDrawCallCountArgument(); /* triangles */
872     const unsigned int vertex_size      = sizeof(float) * 3;                                          /* components */
873 
874     /* Make sure the data sets match, given different draw call ordering */
875     for (int n_type = 0; n_type < 3 /* lines, points, tris */; ++n_type)
876     {
877         const float *data1_ptr = DE_NULL;
878         const float *data2_ptr = DE_NULL;
879         std::string data_type_string;
880         unsigned int n_vertices = 0;
881 
882         switch (n_type)
883         {
884         case 0:
885         {
886             data1_ptr        = lines_vertex_data_1;
887             data2_ptr        = lines_vertex_data_2;
888             data_type_string = "Line";
889             n_vertices       = n_line_vertices;
890 
891             break;
892         }
893 
894         case 1:
895         {
896             data1_ptr        = point_vertex_data_1;
897             data2_ptr        = point_vertex_data_2;
898             data_type_string = "Point";
899             n_vertices       = n_point_vertices;
900 
901             break;
902         }
903 
904         case 2:
905         {
906             data1_ptr        = tris_vertex_data_1;
907             data2_ptr        = tris_vertex_data_2;
908             data_type_string = "Triangle";
909             n_vertices       = n_tri_vertices;
910 
911             break;
912         }
913 
914         default:
915         {
916             TCU_FAIL("Internal error: type index was not recognized");
917         }
918         } /* switch (n_type) */
919 
920         /* Make sure the buffer storage in both cases has been modified */
921         {
922             unsigned int zero_bo_size = vertex_size * n_vertices;
923             char *zero_bo_data        = new char[vertex_size * n_vertices];
924 
925             memset(zero_bo_data, 0, zero_bo_size);
926 
927             if (memcmp(data1_ptr, zero_bo_data, zero_bo_size) == 0 ||
928                 memcmp(data2_ptr, zero_bo_data, zero_bo_size) == 0)
929             {
930                 TCU_FAIL("One of the draw calls has not outputted any data to XFB buffer object storage");
931             }
932 
933             delete[] zero_bo_data;
934             zero_bo_data = NULL;
935         }
936 
937         /* Compare the data */
938         if (memcmp(data1_ptr, data2_ptr, vertex_size * n_vertices) != 0)
939         {
940             std::stringstream logMessage;
941 
942             logMessage << data_type_string << " data rendered in pass 1: (";
943 
944             for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
945             {
946                 logMessage << data1_ptr[n_vertex];
947 
948                 if (n_vertex != (n_vertices - 1))
949                 {
950                     logMessage << ", ";
951                 }
952                 else
953                 {
954                     logMessage << ") ";
955                 }
956             } /* for (all vertices) */
957 
958             logMessage << "and in pass 2: (";
959 
960             for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
961             {
962                 logMessage << data2_ptr[n_vertex];
963 
964                 if (n_vertex != (n_vertices - 1))
965                 {
966                     logMessage << ", ";
967                 }
968                 else
969                 {
970                     logMessage << ") ";
971                 }
972             } /* for (all vertices) */
973 
974             logMessage << "do not match";
975 
976             m_testCtx.getLog() << tcu::TestLog::Message << logMessage.str().c_str() << tcu::TestLog::EndMessage;
977 
978             TCU_FAIL("Data mismatch");
979         } /* if (data mismatch) */
980     }     /* for (all primitive types) */
981 }
982 
983 /** Constructor.
984  *
985  *  @param context Rendering context.
986  *
987  **/
TessellationShaderInvarianceRule2Test(Context & context,const ExtParameters & extParams)988 TessellationShaderInvarianceRule2Test::TessellationShaderInvarianceRule2Test(Context &context,
989                                                                              const ExtParameters &extParams)
990     : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule2",
991                                            "Verifies conformance with second invariance rule")
992 {
993     memset(m_n_tessellated_vertices, 0, sizeof(m_n_tessellated_vertices));
994 }
995 
996 /** Destructor. */
~TessellationShaderInvarianceRule2Test()997 TessellationShaderInvarianceRule2Test::~TessellationShaderInvarianceRule2Test()
998 {
999     /* Left blank intentionally */
1000 }
1001 
1002 /** Retrieves amount of iterations the base test implementation should run before
1003  *  calling global verification routine.
1004  *
1005  *  @return Always 4.
1006  **/
getAmountOfIterations()1007 unsigned int TessellationShaderInvarianceRule2Test::getAmountOfIterations()
1008 {
1009     return 4;
1010 }
1011 
1012 /** Retrieves iteration-specific tessellation properties.
1013  *
1014  *  @param n_iteration            Iteration index to retrieve the properties for.
1015  *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
1016  *                                tessellation level values. Must not be NULL.
1017  *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
1018  *                                tessellation level values. Must not be NULL.
1019  *  @param out_point_mode         Deref will be used to store iteration-specific flag
1020  *                                telling whether point mode should be enabled for given pass.
1021  *                                Must not be NULL.
1022  *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
1023  *                                mode. Must not be NULL.
1024  *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
1025  *                                ordering. Must not be NULL.
1026  *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1027  *                                storage should offer for the draw call to succeed. Can
1028  *                                be NULL.
1029  **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)1030 void TessellationShaderInvarianceRule2Test::getIterationProperties(
1031     unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
1032     _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
1033     unsigned int *out_result_buffer_size)
1034 {
1035     *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1036 
1037     switch (n_iteration)
1038     {
1039     case 0:
1040     case 1:
1041     {
1042         /* Triangles */
1043         out_outer_tess_levels[0] = 2.0f;
1044         out_outer_tess_levels[1] = 3.0f;
1045         out_outer_tess_levels[2] = 4.0f;
1046 
1047         if (n_iteration == 0)
1048         {
1049             out_inner_tess_levels[0] = 4.0f;
1050             out_inner_tess_levels[1] = 5.0f;
1051         }
1052         else
1053         {
1054             out_inner_tess_levels[0] = 3.0f;
1055             out_inner_tess_levels[1] = 4.0f;
1056         }
1057 
1058         *out_point_mode     = false;
1059         *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
1060 
1061         break;
1062     }
1063 
1064     case 2:
1065     case 3:
1066     {
1067         /* Quads */
1068         out_outer_tess_levels[0] = 2.0f;
1069         out_outer_tess_levels[1] = 3.0f;
1070         out_outer_tess_levels[2] = 4.0f;
1071         out_outer_tess_levels[3] = 5.0f;
1072 
1073         if (n_iteration == 2)
1074         {
1075             out_inner_tess_levels[0] = 2.0f;
1076             out_inner_tess_levels[1] = 3.0f;
1077         }
1078         else
1079         {
1080             out_inner_tess_levels[0] = 4.0f;
1081             out_inner_tess_levels[1] = 5.0f;
1082         }
1083 
1084         *out_point_mode     = false;
1085         *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
1086 
1087         break;
1088     }
1089 
1090     default:
1091     {
1092         TCU_FAIL("Unrecognized iteration index");
1093     }
1094     }
1095 
1096     if (out_result_buffer_size != DE_NULL)
1097     {
1098         *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1099             *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1100             *out_point_mode);
1101 
1102         m_n_tessellated_vertices[n_iteration] = *out_result_buffer_size;
1103         *out_result_buffer_size =
1104             static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1105 
1106         DE_ASSERT(*out_result_buffer_size != 0);
1107     }
1108 }
1109 
1110 /** Retrieves iteration-specific tessellation evaluation shader code.
1111  *
1112  *  @param n_iteration Iteration index, for which the source code is being obtained.
1113  *
1114  *  @return Requested source code.
1115  **/
getTECode(unsigned int n_iteration)1116 std::string TessellationShaderInvarianceRule2Test::getTECode(unsigned int n_iteration)
1117 {
1118     unsigned int bo_size                                 = 0;
1119     float inner_tess_levels[2]                           = {0};
1120     float outer_tess_levels[4]                           = {0};
1121     bool point_mode                                      = false;
1122     _tessellation_primitive_mode primitive_mode          = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
1123     _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
1124 
1125     getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode,
1126                            &vertex_ordering, &bo_size);
1127 
1128     return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode,
1129                                                      vertex_ordering, point_mode);
1130 }
1131 
1132 /** Verifies result data. Accesses data generated by all iterations.
1133  *
1134  *  Throws TestError exception if an error occurs.
1135  *
1136  *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
1137  *                             data generated by subsequent iterations.
1138  **/
verifyResultData(const void ** all_iterations_data)1139 void TessellationShaderInvarianceRule2Test::verifyResultData(const void **all_iterations_data)
1140 {
1141     /* Iterate through one tessellated set of vertices for a given primitive type
1142      * and identify outer vertices. Make sure exactly the same vertices can be
1143      * found in the other set of vertices, generated with different input tessellation
1144      * level.
1145      */
1146     for (int n_primitive_type = 0; n_primitive_type < 2; /* triangles / quads */
1147          ++n_primitive_type)
1148     {
1149         const float *data1_ptr                      = (const float *)all_iterations_data[n_primitive_type * 2 + 0];
1150         const float *data2_ptr                      = (const float *)all_iterations_data[n_primitive_type * 2 + 1];
1151         _tessellation_primitive_mode primitive_mode = (n_primitive_type == 0) ?
1152                                                           TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
1153                                                           TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
1154         std::vector<_vertex> outer_vertices;
1155 
1156         /* Iterate through all data1 vertices.. */
1157         for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2]; ++n_vertex)
1158         {
1159             /* Check if any of the components is equal to 0 or 1. If so, this could
1160              * be an edge vertex.
1161              */
1162             const float *vertex_ptr = data1_ptr + n_vertex * 3; /* components */
1163 
1164             if (TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, vertex_ptr))
1165             {
1166                 /* Only add the vertex if it has not been added already to the vector */
1167                 bool has_already_been_added = false;
1168 
1169                 for (std::vector<_vertex>::const_iterator vertex_iterator = outer_vertices.begin();
1170                      vertex_iterator != outer_vertices.end(); vertex_iterator++)
1171                 {
1172                     if (vertex_iterator->u == vertex_ptr[0] && vertex_iterator->v == vertex_ptr[1] &&
1173                         vertex_iterator->w == vertex_ptr[2])
1174                     {
1175                         has_already_been_added = true;
1176 
1177                         break;
1178                     }
1179                 } /* for (all outer vertices stored so far) */
1180 
1181                 if (!has_already_been_added)
1182                 {
1183                     _vertex vertex;
1184 
1185                     vertex.u = vertex_ptr[0];
1186                     vertex.v = vertex_ptr[1];
1187                     vertex.w = vertex_ptr[2];
1188 
1189                     outer_vertices.push_back(vertex);
1190                 }
1191             } /* if (input vertex is located on outer edge) */
1192         }     /* for (all input vertices) */
1193 
1194         DE_ASSERT(outer_vertices.size() != 0);
1195 
1196         /* Now that we know where outer vertices are, make sure they are present in the other data set */
1197         for (std::vector<_vertex>::const_iterator ref_vertex_iterator = outer_vertices.begin();
1198              ref_vertex_iterator != outer_vertices.end(); ref_vertex_iterator++)
1199         {
1200             bool has_been_found       = false;
1201             const _vertex &ref_vertex = *ref_vertex_iterator;
1202 
1203             for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2 + 1]; ++n_vertex)
1204             {
1205                 const float *vertex_ptr = data2_ptr + n_vertex * 3; /* components */
1206 
1207                 if (vertex_ptr[0] == ref_vertex.u && vertex_ptr[1] == ref_vertex.v && vertex_ptr[2] == ref_vertex.w)
1208                 {
1209                     has_been_found = true;
1210 
1211                     break;
1212                 }
1213             } /* for (all vertices in the other data set) */
1214 
1215             if (!has_been_found)
1216             {
1217                 float cmp_inner_tess_levels[2];
1218                 float cmp_outer_tess_levels[4];
1219                 bool cmp_point_mode;
1220                 _tessellation_primitive_mode cmp_primitive_mode;
1221                 _tessellation_shader_vertex_ordering cmp_vertex_ordering;
1222                 std::string primitive_type = (n_primitive_type == 0) ? "triangles" : "quads";
1223                 float ref_inner_tess_levels[2];
1224                 float ref_outer_tess_levels[4];
1225                 bool ref_point_mode;
1226                 _tessellation_primitive_mode ref_primitive_mode;
1227                 _tessellation_shader_vertex_ordering ref_vertex_ordering;
1228 
1229                 getIterationProperties(n_primitive_type * 2, ref_inner_tess_levels, ref_outer_tess_levels,
1230                                        &ref_point_mode, &ref_primitive_mode, &ref_vertex_ordering, NULL);
1231                 getIterationProperties(n_primitive_type * 2 + 1, cmp_inner_tess_levels, cmp_outer_tess_levels,
1232                                        &cmp_point_mode, &cmp_primitive_mode, &cmp_vertex_ordering, NULL);
1233 
1234                 m_testCtx.getLog() << tcu::TestLog::Message << "Outer vertex"
1235                                    << " (" << ref_vertex.u << ", " << ref_vertex.v << ", " << ref_vertex.w << ")"
1236                                    << " was not found in tessellated data coordinate set generated"
1237                                    << " for primitive type: " << primitive_type.c_str()
1238                                    << ". Reference inner tessellation level:"
1239                                    << " (" << ref_inner_tess_levels[0] << ", " << ref_inner_tess_levels[1]
1240                                    << "), reference outer tessellation level:"
1241                                    << " (" << ref_outer_tess_levels[0] << ", " << ref_outer_tess_levels[1] << ", "
1242                                    << ref_outer_tess_levels[2] << ", " << ref_outer_tess_levels[3]
1243                                    << "), test inner tessellation level:"
1244                                    << " (" << cmp_inner_tess_levels[0] << ", " << cmp_inner_tess_levels[1]
1245                                    << "), reference outer tessellation level:"
1246                                    << " (" << cmp_outer_tess_levels[0] << ", " << cmp_outer_tess_levels[1] << ", "
1247                                    << cmp_outer_tess_levels[2] << ", " << cmp_outer_tess_levels[3] << ")."
1248                                    << tcu::TestLog::EndMessage;
1249 
1250                 TCU_FAIL("Outer edge vertex was not found in tessellated coordinate set generated for "
1251                          "the same outer tessellation levels and vertex spacing, but different inner "
1252                          "tessellation levels");
1253             } /* if (outer edge vertex was not found in the other set) */
1254         }     /* for (all outer edge vertices) */
1255     }         /* for (both primitive types) */
1256 }
1257 
1258 /** Constructor.
1259  *
1260  *  @param context Rendering context.
1261  *
1262  **/
TessellationShaderInvarianceRule3Test(Context & context,const ExtParameters & extParams)1263 TessellationShaderInvarianceRule3Test::TessellationShaderInvarianceRule3Test(Context &context,
1264                                                                              const ExtParameters &extParams)
1265     : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule3",
1266                                            "Verifies conformance with third invariance rule")
1267 {
1268 }
1269 
1270 /** Destructor. */
~TessellationShaderInvarianceRule3Test()1271 TessellationShaderInvarianceRule3Test::~TessellationShaderInvarianceRule3Test()
1272 {
1273     /* Left blank intentionally */
1274 }
1275 
1276 /** Retrieves amount of iterations the base test implementation should run before
1277  *  calling global verification routine.
1278  *
1279  *  @return A value that depends on initTestIterations() behavior.
1280  **/
getAmountOfIterations()1281 unsigned int TessellationShaderInvarianceRule3Test::getAmountOfIterations()
1282 {
1283     if (m_test_iterations.size() == 0)
1284     {
1285         initTestIterations();
1286     }
1287 
1288     return (unsigned int)m_test_iterations.size();
1289 }
1290 
1291 /** Retrieves iteration-specific tessellation properties.
1292  *
1293  *  @param n_iteration            Iteration index to retrieve the properties for.
1294  *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
1295  *                                tessellation level values. Must not be NULL.
1296  *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
1297  *                                tessellation level values. Must not be NULL.
1298  *  @param out_point_mode         Deref will be used to store iteration-specific flag
1299  *                                telling whether point mode should be enabled for given pass.
1300  *                                Must not be NULL.
1301  *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
1302  *                                mode. Must not be NULL.
1303  *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
1304  *                                ordering. Must not be NULL.
1305  *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1306  *                                storage should offer for the draw call to succeed. Can
1307  *                                be NULL.
1308  **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)1309 void TessellationShaderInvarianceRule3Test::getIterationProperties(
1310     unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
1311     _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
1312     unsigned int *out_result_buffer_size)
1313 {
1314     DE_ASSERT(m_test_iterations.size() > n_iteration);
1315 
1316     _test_iteration &test_iteration = m_test_iterations[n_iteration];
1317 
1318     memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1319     memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1320 
1321     *out_point_mode      = false;
1322     *out_primitive_mode  = test_iteration.primitive_mode;
1323     *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1324 
1325     if (out_result_buffer_size != DE_NULL)
1326     {
1327         *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1328             *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing,
1329             *out_point_mode);
1330         test_iteration.n_vertices = *out_result_buffer_size;
1331         *out_result_buffer_size =
1332             static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1333 
1334         DE_ASSERT(*out_result_buffer_size != 0);
1335     }
1336 }
1337 
1338 /** Retrieves iteration-specific tessellation evaluation shader code.
1339  *
1340  *  @param n_iteration Iteration index, for which the source code is being obtained.
1341  *
1342  *  @return Requested source code.
1343  **/
getTECode(unsigned int n_iteration)1344 std::string TessellationShaderInvarianceRule3Test::getTECode(unsigned int n_iteration)
1345 {
1346     DE_ASSERT(m_test_iterations.size() > n_iteration);
1347 
1348     const _test_iteration &test_iteration = m_test_iterations[n_iteration];
1349 
1350     return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode,
1351                                                      TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */
1352 }
1353 
1354 /** Initializes test iterations for the test. The following modes and inner/outer tess level
1355  *  configurations are used to form the test set:
1356  *
1357  *  - Inner/outer tessellation level combinations as returned by
1358  *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
1359  *  - All primitive modes;
1360  *  - All vertex spacing modes;
1361  *
1362  *  All permutations are used to generate the test set.
1363  **/
initTestIterations()1364 void TessellationShaderInvarianceRule3Test::initTestIterations()
1365 {
1366     DE_ASSERT(m_test_iterations.size() == 0);
1367 
1368     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
1369     const glw::Functions &gl               = m_context.getRenderContext().getFunctions();
1370     glw::GLint gl_max_tess_gen_level_value = 0;
1371 
1372     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1373     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1374 
1375     /* Iterate through all primitive and vertex spacing modes */
1376     _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
1377                                                       TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1378                                                       TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
1379     _tessellation_shader_vertex_spacing vs_modes[] = {TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1380                                                       TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
1381                                                       TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD};
1382 
1383     const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1384     const unsigned int n_vs_modes        = sizeof(vs_modes) / sizeof(vs_modes[0]);
1385 
1386     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1387     {
1388         _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
1389 
1390         for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
1391         {
1392             _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
1393 
1394             /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
1395             _tessellation_levels_set levels_set;
1396 
1397             levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1398                 primitive_mode, gl_max_tess_gen_level_value,
1399                 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1400 
1401             /* Iterate through all configurations */
1402             for (_tessellation_levels_set_const_iterator levels_iterator = levels_set.begin();
1403                  levels_iterator != levels_set.end(); levels_iterator++)
1404             {
1405                 const _tessellation_levels &levels = *levels_iterator;
1406 
1407                 /* Create a test descriptor for all the parameters we now have */
1408                 _test_iteration test;
1409 
1410                 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
1411                 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
1412 
1413                 test.primitive_mode = primitive_mode;
1414                 test.vertex_spacing = vs_mode;
1415 
1416                 m_test_iterations.push_back(test);
1417             } /* for (all inner/outer tessellation levels) */
1418         }     /* for (all vertex spacing modes) */
1419     }         /* for (all primitive modes) */
1420 }
1421 
1422 /** Verifies result data on per-iteration basis.
1423  *
1424  *  Throws TestError exception if an error occurs.
1425  *
1426  *  @param n_iteration Index of iteration the check should be performed for.
1427  *  @param data        Points to array of vec3s storing the vertices as
1428  *                     generated by tessellation
1429  **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)1430 void TessellationShaderInvarianceRule3Test::verifyResultDataForIteration(unsigned int n_iteration, const void *data)
1431 {
1432     DE_ASSERT(m_test_iterations.size() > n_iteration);
1433 
1434     const glw::GLfloat *data_float        = (const glw::GLfloat *)data;
1435     const _test_iteration &test_iteration = m_test_iterations[n_iteration];
1436 
1437     /* Iterate through all generated vertices.. */
1438     for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex)
1439     {
1440         _vertex expected_vertex;
1441         const glw::GLfloat *vertex_data = data_float + 3 /* components */ * n_vertex;
1442 
1443         expected_vertex.u = -1.0f;
1444         expected_vertex.v = -1.0f;
1445         expected_vertex.w = -1.0f;
1446 
1447         /* Make sure that for each vertex, the following language from the extension
1448          * spec is followed:
1449          */
1450         switch (test_iteration.primitive_mode)
1451         {
1452         case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
1453         {
1454             /* For isoline tessellation, if it generates vertices at (0,x) and (1,x)
1455              * where <x> is not zero, it will also generate vertices at exactly (0,1-x)
1456              * and (1,1-x), respectively.
1457              */
1458             if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f)
1459             {
1460                 expected_vertex.u = vertex_data[0];
1461                 expected_vertex.v = 1.0f - vertex_data[1];
1462                 expected_vertex.w = -1.0f;
1463             }
1464             else if (vertex_data[0] == 1.0f && vertex_data[1] != 0.0f)
1465             {
1466                 expected_vertex.u = vertex_data[0];
1467                 expected_vertex.v = 1.0f - vertex_data[1];
1468                 expected_vertex.w = -1.0f;
1469             }
1470 
1471             break;
1472         } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES: */
1473 
1474         case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1475         {
1476             /* For quad tessellation, if the subdivision generates a vertex with
1477              * coordinates of (x,0) or (0,x), it will also generate a vertex with
1478              * coordinates of exactly (1-x,0) or (0,1-x), respectively.
1479              */
1480             if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f)
1481             {
1482                 expected_vertex.u = 1.0f - vertex_data[0];
1483                 expected_vertex.v = vertex_data[1];
1484                 expected_vertex.w = -1.0f;
1485             }
1486             else if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f)
1487             {
1488                 expected_vertex.u = vertex_data[0];
1489                 expected_vertex.v = 1.0f - vertex_data[1];
1490                 expected_vertex.w = -1.0f;
1491             }
1492 
1493             break;
1494         } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1495 
1496         case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1497         {
1498             /* For triangle tessellation, if the subdivision generates a vertex with
1499              * tessellation coordinates of the form (0,x,1-x), (x,0,1-x), or (x,1-x,0),
1500              * it will also generate a vertex with coordinates of exactly (0,1-x,x),
1501              * (1-x,0,x), or (1-x,x,0), respectively.
1502              */
1503             if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f && vertex_data[2] == (1.0f - vertex_data[1]))
1504             {
1505                 expected_vertex.u = vertex_data[0];
1506                 expected_vertex.v = vertex_data[2];
1507                 expected_vertex.w = vertex_data[1];
1508             }
1509             else if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f && vertex_data[2] == (1.0f - vertex_data[0]))
1510             {
1511                 expected_vertex.u = vertex_data[2];
1512                 expected_vertex.v = vertex_data[1];
1513                 expected_vertex.w = vertex_data[0];
1514             }
1515             else if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0.0f)
1516             {
1517                 expected_vertex.u = vertex_data[1];
1518                 expected_vertex.v = vertex_data[0];
1519                 expected_vertex.w = vertex_data[2];
1520             }
1521 
1522             break;
1523         } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1524 
1525         default:
1526         {
1527             TCU_FAIL("Primitive mode unrecognized");
1528         }
1529         } /* switch (test_iteration.primitive_mode) */
1530 
1531         /* If any of the "expected vertex"'s components is no longer negative,
1532          * make sure the vertex can be found in the result data */
1533         if (expected_vertex.u >= 0.0f || expected_vertex.v >= 0.0f || expected_vertex.w >= 0.0f)
1534         {
1535             bool has_been_found = false;
1536 
1537             for (unsigned int n_find_vertex = 0; n_find_vertex < test_iteration.n_vertices; ++n_find_vertex)
1538             {
1539                 const glw::GLfloat *current_vertex_data = data_float + 3 /* components */ * n_find_vertex;
1540 
1541                 const glw::GLfloat epsilon = 1e-4f;
1542                 glw::GLfloat absDelta[3]   = {de::abs(current_vertex_data[0] - expected_vertex.u),
1543                                               de::abs(current_vertex_data[1] - expected_vertex.v),
1544                                               de::abs(current_vertex_data[2] - expected_vertex.w)};
1545 
1546                 if (absDelta[0] < epsilon && absDelta[1] < epsilon &&
1547                     ((expected_vertex.w < 0.0f) || (expected_vertex.w >= 0.0f && absDelta[2] < epsilon)))
1548                 {
1549                     has_been_found = true;
1550 
1551                     break;
1552                 } /* if (the vertex data matches the expected vertex data) */
1553             }     /* for (all generated vertices)*/
1554 
1555             if (!has_been_found)
1556             {
1557                 TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator.");
1558             }
1559         } /* if (any of the components of expected_vertex is no longer negative) */
1560     }     /* for (all generated vertices) */
1561 }
1562 
1563 /** Constructor.
1564  *
1565  *  @param context Rendering context.
1566  *
1567  **/
TessellationShaderInvarianceRule4Test(Context & context,const ExtParameters & extParams)1568 TessellationShaderInvarianceRule4Test::TessellationShaderInvarianceRule4Test(Context &context,
1569                                                                              const ExtParameters &extParams)
1570     : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule4",
1571                                            "Verifies conformance with fourth invariance rule")
1572 {
1573 }
1574 
1575 /** Destructor. */
~TessellationShaderInvarianceRule4Test()1576 TessellationShaderInvarianceRule4Test::~TessellationShaderInvarianceRule4Test()
1577 {
1578     /* Left blank intentionally */
1579 }
1580 
1581 /** Retrieves amount of iterations the base test implementation should run before
1582  *  calling global verification routine.
1583  *
1584  *  @return A value that depends on initTestIterations() behavior.
1585  **/
getAmountOfIterations()1586 unsigned int TessellationShaderInvarianceRule4Test::getAmountOfIterations()
1587 {
1588     if (m_test_iterations.size() == 0)
1589     {
1590         initTestIterations();
1591     }
1592 
1593     return (unsigned int)m_test_iterations.size();
1594 }
1595 
1596 /** Retrieves iteration-specific tessellation properties.
1597  *
1598  *  @param n_iteration            Iteration index to retrieve the properties for.
1599  *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
1600  *                                tessellation level values. Must not be NULL.
1601  *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
1602  *                                tessellation level values. Must not be NULL.
1603  *  @param out_point_mode         Deref will be used to store iteration-specific flag
1604  *                                telling whether point mode should be enabled for given pass.
1605  *                                Must not be NULL.
1606  *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
1607  *                                mode. Must not be NULL.
1608  *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
1609  *                                ordering. Must not be NULL.
1610  *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1611  *                                storage should offer for the draw call to succeed. Can
1612  *                                be NULL.
1613  **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)1614 void TessellationShaderInvarianceRule4Test::getIterationProperties(
1615     unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
1616     _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
1617     unsigned int *out_result_buffer_size)
1618 {
1619     DE_ASSERT(m_test_iterations.size() > n_iteration);
1620 
1621     _test_iteration &test_iteration = m_test_iterations[n_iteration];
1622 
1623     memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1624     memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1625 
1626     *out_point_mode      = false;
1627     *out_primitive_mode  = test_iteration.primitive_mode;
1628     *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1629 
1630     if (out_result_buffer_size != DE_NULL)
1631     {
1632         *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1633             *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing,
1634             *out_point_mode);
1635         test_iteration.n_vertices = *out_result_buffer_size;
1636         *out_result_buffer_size =
1637             static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1638 
1639         DE_ASSERT(*out_result_buffer_size != 0);
1640     }
1641 }
1642 
1643 /** Retrieves iteration-specific tessellation evaluation shader code.
1644  *
1645  *  @param n_iteration Iteration index, for which the source code is being obtained.
1646  *
1647  *  @return Requested source code.
1648  **/
getTECode(unsigned int n_iteration)1649 std::string TessellationShaderInvarianceRule4Test::getTECode(unsigned int n_iteration)
1650 {
1651     DE_ASSERT(m_test_iterations.size() > n_iteration);
1652 
1653     const _test_iteration &test_iteration = m_test_iterations[n_iteration];
1654 
1655     return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode,
1656                                                      TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */
1657 }
1658 
1659 /** Initializes test iterations for the test. The following modes and inner/outer tess level
1660  *  configurations are used to form the test set:
1661  *
1662  *  - Inner/outer tessellation level combinations as returned by
1663  *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
1664  *  - 'Quads' and 'Triangles' primitive modes;
1665  *  - All vertex spacing modes;
1666  *
1667  *  All permutations are used to generate the test set.
1668  **/
initTestIterations()1669 void TessellationShaderInvarianceRule4Test::initTestIterations()
1670 {
1671     DE_ASSERT(m_test_iterations.size() == 0);
1672 
1673     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
1674     const glw::Functions &gl               = m_context.getRenderContext().getFunctions();
1675     glw::GLint gl_max_tess_gen_level_value = 0;
1676 
1677     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1678     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1679 
1680     /* Iterate through all primitive and vertex spacing modes relevant to the test */
1681     _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1682                                                       TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
1683     _tessellation_shader_vertex_spacing vs_modes[] = {TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1684                                                       TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
1685                                                       TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD};
1686 
1687     const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1688     const unsigned int n_vs_modes        = sizeof(vs_modes) / sizeof(vs_modes[0]);
1689 
1690     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1691     {
1692         _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
1693 
1694         for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
1695         {
1696             _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
1697 
1698             /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
1699             _tessellation_levels_set levels;
1700 
1701             levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1702                 primitive_mode, gl_max_tess_gen_level_value,
1703                 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1704 
1705             /* Iterate through all configurations */
1706             for (_tessellation_levels_set_const_iterator levels_iterator = levels.begin();
1707                  levels_iterator != levels.end(); levels_iterator++)
1708             {
1709                 const _tessellation_levels &current_levels = *levels_iterator;
1710 
1711                 /* Create a test descriptor for all the parameters we now have.
1712                  *
1713                  * The set we're operating on uses different outer tessellation level values, so we
1714                  * need to make sure the levels are set to the same FP values in order for the test
1715                  * to succeed. */
1716                 _test_iteration test;
1717 
1718                 memcpy(test.inner_tess_levels, current_levels.inner, sizeof(test.inner_tess_levels));
1719 
1720                 for (int n = 0; n < 4 /* outer tess levels */; ++n)
1721                 {
1722                     test.outer_tess_levels[n] = current_levels.outer[0];
1723                 }
1724 
1725                 test.primitive_mode = primitive_mode;
1726                 test.vertex_spacing = vs_mode;
1727 
1728                 m_test_iterations.push_back(test);
1729             } /* for (all inner/outer tessellation levels) */
1730         }     /* for (all vertex spacing modes) */
1731     }         /* for (all primitive modes) */
1732 }
1733 
1734 /** Verifies user-provided vertex data can be found in the provided vertex data array.
1735  *
1736  *  @param vertex_data                     Vertex data array the requested vertex data are to be found in.
1737  *  @param n_vertices                      Amount of vertices declared in @param vertex_data;
1738  *  @param vertex_data_seeked              Vertex data to be found in @param vertex_data;
1739  *  @param n_vertex_data_seeked_components Amount of components to take into account.
1740  *
1741  *  @return true if the vertex data was found, false otherwise.
1742  **/
isVertexDefined(const float * vertex_data,unsigned int n_vertices,const float * vertex_data_seeked,unsigned int n_vertex_data_seeked_components)1743 bool TessellationShaderInvarianceRule4Test::isVertexDefined(const float *vertex_data, unsigned int n_vertices,
1744                                                             const float *vertex_data_seeked,
1745                                                             unsigned int n_vertex_data_seeked_components)
1746 {
1747     bool result = false;
1748 
1749     DE_ASSERT(n_vertex_data_seeked_components >= 2);
1750 
1751     for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
1752     {
1753         const float *current_vertex_data = vertex_data + 3 /* components */ * n_vertex;
1754 
1755         if ((vertex_data_seeked[0] == current_vertex_data[0]) && (vertex_data_seeked[1] == current_vertex_data[1]) &&
1756             ((n_vertex_data_seeked_components < 3) ||
1757              (n_vertex_data_seeked_components >= 3 && (vertex_data_seeked[2] == current_vertex_data[2]))))
1758         {
1759             result = true;
1760 
1761             break;
1762         } /* if (components match) */
1763     }     /* for (all vertices) */
1764 
1765     return result;
1766 }
1767 
1768 /** Verifies result data on per-iteration basis.
1769  *
1770  *  Throws TestError exception if an error occurs.
1771  *
1772  *  @param n_iteration Index of iteration the check should be performed for.
1773  *  @param data        Points to array of vec3s storing the vertices as
1774  *                     generated by tessellation
1775  **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)1776 void TessellationShaderInvarianceRule4Test::verifyResultDataForIteration(unsigned int n_iteration, const void *data)
1777 {
1778     DE_ASSERT(m_test_iterations.size() > n_iteration);
1779 
1780     const glw::GLfloat *data_float        = (const glw::GLfloat *)data;
1781     const _test_iteration &test_iteration = m_test_iterations[n_iteration];
1782 
1783     /* Iterate through all generated vertices.. */
1784     for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex)
1785     {
1786         std::vector<_vertex> expected_vertices;
1787         const glw::GLfloat *vertex_data = data_float + 3 /* components */ * n_vertex;
1788 
1789         /* Make sure that for each vertex, the following language from the extension
1790          * spec is followed:
1791          */
1792         switch (test_iteration.primitive_mode)
1793         {
1794         case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1795         {
1796             /* For quad tessellation, if vertices at (x,0) and (1-x,0) are generated
1797              * when subdividing the v==0 edge, vertices must be generated at (0,x) and
1798              * (0,1-x) when subdividing an otherwise identical u==0 edge.
1799              */
1800             if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f)
1801             {
1802                 const float paired_vertex_data[] = {1.0f - vertex_data[0], vertex_data[1]};
1803 
1804                 if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 2)) /* components */
1805                 {
1806                     _vertex expected_vertex;
1807 
1808                     /* First expected vertex */
1809                     expected_vertex.u = vertex_data[1];
1810                     expected_vertex.v = vertex_data[0];
1811                     expected_vertex.w = -1.0f;
1812 
1813                     expected_vertices.push_back(expected_vertex);
1814 
1815                     /* The other expected vertex */
1816                     expected_vertex.u = vertex_data[1];
1817                     expected_vertex.v = 1.0f - vertex_data[0];
1818 
1819                     expected_vertices.push_back(expected_vertex);
1820                 } /* if (the other required vertex is defined) */
1821             }     /* if (the first required vertex is defined) */
1822 
1823             break;
1824         } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1825 
1826         case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1827         {
1828             /* For triangular tessellation, if vertices at (x,1-x,0) and (1-x,x,0) are
1829              * generated when subdividing the w==0 edge, vertices must be generated at
1830              * (x,0,1-x) and (1-x,0,x) when subdividing an otherwise identical v==0
1831              * edge.
1832              */
1833             if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0)
1834             {
1835                 const float paired_vertex_data[] = {vertex_data[1], vertex_data[0], vertex_data[2]};
1836 
1837                 if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 3)) /* components */
1838                 {
1839                     _vertex expected_vertex;
1840 
1841                     /* First expected vertex */
1842                     expected_vertex.u = vertex_data[0];
1843                     expected_vertex.v = vertex_data[2];
1844                     expected_vertex.w = vertex_data[1];
1845 
1846                     expected_vertices.push_back(expected_vertex);
1847 
1848                     /* The other expected vertex */
1849                     expected_vertex.u = vertex_data[1];
1850                     expected_vertex.v = vertex_data[2];
1851                     expected_vertex.w = vertex_data[0];
1852 
1853                     expected_vertices.push_back(expected_vertex);
1854                 } /* if (the other required vertex is defined) */
1855             }     /* if (the firsst required vertex is defined) */
1856 
1857             break;
1858         } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1859 
1860         default:
1861         {
1862             TCU_FAIL("Primitive mode unrecognized");
1863         }
1864         } /* switch (test_iteration.primitive_mode) */
1865 
1866         /* Iterate through all expected vertices */
1867         for (std::vector<_vertex>::const_iterator expected_vertex_iterator = expected_vertices.begin();
1868              expected_vertex_iterator != expected_vertices.end(); expected_vertex_iterator++)
1869         {
1870             const _vertex &expected_vertex    = *expected_vertex_iterator;
1871             const float expected_vertex_raw[] = {expected_vertex.u, expected_vertex.v, expected_vertex.w};
1872             bool has_been_found               = false;
1873 
1874             has_been_found = isVertexDefined(data_float, test_iteration.n_vertices, expected_vertex_raw,
1875                                              (expected_vertex.w < 0) ? 2 : 3);
1876 
1877             if (!has_been_found)
1878             {
1879                 std::stringstream expected_vertex_sstream;
1880 
1881                 expected_vertex_sstream << expected_vertex.u << ", " << expected_vertex.v;
1882 
1883                 if (expected_vertex.w >= 0.0f)
1884                 {
1885                     expected_vertex_sstream << ", " << expected_vertex.w;
1886                 }
1887 
1888                 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode:"
1889                                    << "["
1890                                    << TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration.primitive_mode)
1891                                    << "]"
1892                                    << "and vertex spacing mode:"
1893                                    << "["
1894                                    << TessellationShaderUtils::getESTokenForVertexSpacingMode(
1895                                           test_iteration.vertex_spacing)
1896                                    << "]"
1897                                    << " and inner tessellation levels:[" << test_iteration.inner_tess_levels[0] << ", "
1898                                    << test_iteration.inner_tess_levels[1] << ") "
1899                                    << " and outer tessellation levels:[" << test_iteration.outer_tess_levels[0] << ", "
1900                                    << test_iteration.outer_tess_levels[1] << ", " << test_iteration.outer_tess_levels[2]
1901                                    << ", " << test_iteration.outer_tess_levels[3] << ") "
1902                                    << " the following vertex was expected:[" << expected_vertex_sstream.str().c_str()
1903                                    << "] but was not found in the tessellated cooordinate data set"
1904                                    << tcu::TestLog::EndMessage;
1905 
1906                 TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator.");
1907             } /* if (the expected vertex data was not found) */
1908         }     /* for (all expected vertices) */
1909     }         /* for (all generated vertices) */
1910 }
1911 
1912 /** Constructor.
1913  *
1914  *  @param context Rendering context.
1915  *
1916  **/
TessellationShaderInvarianceRule5Test(Context & context,const ExtParameters & extParams)1917 TessellationShaderInvarianceRule5Test::TessellationShaderInvarianceRule5Test(Context &context,
1918                                                                              const ExtParameters &extParams)
1919     : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule5",
1920                                            "Verifies conformance with fifth invariance rule")
1921 {
1922 }
1923 
1924 /** Destructor. */
~TessellationShaderInvarianceRule5Test()1925 TessellationShaderInvarianceRule5Test::~TessellationShaderInvarianceRule5Test()
1926 {
1927     /* Left blank intentionally */
1928 }
1929 
1930 /** Retrieves amount of iterations the base test implementation should run before
1931  *  calling global verification routine.
1932  *
1933  *  @return A value that depends on initTestIterations() behavior.
1934  **/
getAmountOfIterations()1935 unsigned int TessellationShaderInvarianceRule5Test::getAmountOfIterations()
1936 {
1937     if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
1938     {
1939         initTestIterations();
1940     }
1941 
1942     return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
1943 }
1944 
1945 /** Retrieves _test_iteration instance specific for user-specified iteration index.
1946  *
1947  *  @param n_iteration Iteration index to retrieve _test_iteration instance for.
1948  *
1949  * @return Iteration-specific _test_iteration instance.
1950  *
1951  **/
getTestForIteration(unsigned int n_iteration)1952 TessellationShaderInvarianceRule5Test::_test_iteration &TessellationShaderInvarianceRule5Test::getTestForIteration(
1953     unsigned int n_iteration)
1954 {
1955     unsigned int n_triangles_tests  = (unsigned int)m_test_triangles_iterations.size();
1956     _test_iteration &test_iteration = (n_iteration < n_triangles_tests) ?
1957                                           m_test_triangles_iterations[n_iteration] :
1958                                           m_test_quads_iterations[n_iteration - n_triangles_tests];
1959 
1960     return test_iteration;
1961 }
1962 
1963 /** Retrieves iteration-specific tessellation properties.
1964  *
1965  *  @param n_iteration            Iteration index to retrieve the properties for.
1966  *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
1967  *                                tessellation level values. Must not be NULL.
1968  *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
1969  *                                tessellation level values. Must not be NULL.
1970  *  @param out_point_mode         Deref will be used to store iteration-specific flag
1971  *                                telling whether point mode should be enabled for given pass.
1972  *                                Must not be NULL.
1973  *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
1974  *                                mode. Must not be NULL.
1975  *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
1976  *                                ordering. Must not be NULL.
1977  *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1978  *                                storage should offer for the draw call to succeed. Can
1979  *                                be NULL.
1980  **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)1981 void TessellationShaderInvarianceRule5Test::getIterationProperties(
1982     unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
1983     _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
1984     unsigned int *out_result_buffer_size)
1985 {
1986     DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
1987 
1988     _test_iteration &test_iteration = getTestForIteration(n_iteration);
1989 
1990     memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1991     memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1992 
1993     *out_point_mode      = false;
1994     *out_primitive_mode  = test_iteration.primitive_mode;
1995     *out_vertex_ordering = test_iteration.vertex_ordering;
1996 
1997     if (out_result_buffer_size != DE_NULL)
1998     {
1999         *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2000             *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2001             *out_point_mode);
2002         test_iteration.n_vertices = *out_result_buffer_size;
2003         *out_result_buffer_size =
2004             static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2005 
2006         DE_ASSERT(*out_result_buffer_size != 0);
2007     }
2008 }
2009 
2010 /** Retrieves iteration-specific tessellation evaluation shader code.
2011  *
2012  *  @param n_iteration Iteration index, for which the source code is being obtained.
2013  *
2014  *  @return Requested source code.
2015  **/
getTECode(unsigned int n_iteration)2016 std::string TessellationShaderInvarianceRule5Test::getTECode(unsigned int n_iteration)
2017 {
2018     DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2019 
2020     const _test_iteration &test_iteration = getTestForIteration(n_iteration);
2021 
2022     return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2023                                                      test_iteration.primitive_mode, test_iteration.vertex_ordering,
2024                                                      false); /* point mode */
2025 }
2026 
2027 /** Initializes test iterations for the test. The following modes and inner/outer tess level
2028  *  configurations are used to form the test set:
2029  *
2030  *  - Last inner/outer tessellation level combination as returned by
2031  *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
2032  *  - All primitive modes;
2033  *  - All vertex spacing modes;
2034  *
2035  *  All permutations are used to generate the test set.
2036  **/
initTestIterations()2037 void TessellationShaderInvarianceRule5Test::initTestIterations()
2038 {
2039     DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2040 
2041     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2042     const glw::Functions &gl               = m_context.getRenderContext().getFunctions();
2043     glw::GLint gl_max_tess_gen_level_value = 0;
2044 
2045     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2046     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2047 
2048     /* Iterate through all primitive and vertex spacing modes relevant to the test */
2049     _tessellation_primitive_mode primitive_modes[]  = {TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2050                                                        TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
2051     _tessellation_shader_vertex_ordering vo_modes[] = {
2052         TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
2053         TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2054     };
2055 
2056     const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2057     const unsigned int n_vo_modes        = sizeof(vo_modes) / sizeof(vo_modes[0]);
2058 
2059     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2060     {
2061         _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2062 
2063         for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2064         {
2065             _tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode];
2066 
2067             /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
2068             _tessellation_levels_set levels_set;
2069 
2070             levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2071                 primitive_mode, gl_max_tess_gen_level_value,
2072                 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2073 
2074             /* Only use the last inner/outer level configuration, as reported by the utils function. */
2075             const _tessellation_levels &levels = levels_set[levels_set.size() - 1];
2076 
2077             /* Create a test descriptor for all the parameters we now have */
2078             _test_iteration test;
2079 
2080             memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2081             memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2082 
2083             test.primitive_mode  = primitive_mode;
2084             test.vertex_ordering = vertex_ordering;
2085 
2086             if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2087             {
2088                 m_test_triangles_iterations.push_back(test);
2089             }
2090             else
2091             {
2092                 m_test_quads_iterations.push_back(test);
2093             }
2094         } /* for (all vertex spacing modes) */
2095     }     /* for (all primitive modes) */
2096 }
2097 
2098 /** Verifies user-provided vertex data can be found in the provided vertex data array.
2099  *
2100  *  @param vertex_data                     Vertex data array the requested vertex data are to be found in.
2101  *  @param n_vertices                      Amount of vertices declared in @param vertex_data;
2102  *  @param vertex_data_seeked              Vertex data to be found in @param vertex_data;
2103  *  @param n_vertex_data_seeked_components Amount of components to take into account.
2104  *
2105  *  @return true if the vertex data was found, false otherwise.
2106  **/
isVertexDefined(const float * vertex_data,unsigned int n_vertices,const float * vertex_data_seeked,unsigned int n_vertex_data_seeked_components)2107 bool TessellationShaderInvarianceRule5Test::isVertexDefined(const float *vertex_data, unsigned int n_vertices,
2108                                                             const float *vertex_data_seeked,
2109                                                             unsigned int n_vertex_data_seeked_components)
2110 {
2111     const float epsilon = 1e-5f;
2112     bool result         = false;
2113 
2114     DE_ASSERT(n_vertex_data_seeked_components >= 2);
2115 
2116     for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
2117     {
2118         const float *current_vertex_data = vertex_data + 3 /* components */ * n_vertex;
2119 
2120         if (de::abs(vertex_data_seeked[0] - current_vertex_data[0]) < epsilon &&
2121             de::abs(vertex_data_seeked[1] - current_vertex_data[1]) < epsilon &&
2122             ((n_vertex_data_seeked_components < 3) ||
2123              (n_vertex_data_seeked_components >= 3 &&
2124               de::abs(vertex_data_seeked[2] - current_vertex_data[2]) < epsilon)))
2125         {
2126             result = true;
2127 
2128             break;
2129         } /* if (components match) */
2130     }     /* for (all vertices) */
2131 
2132     return result;
2133 }
2134 
2135 /** Verifies result data. Accesses data generated by all iterations.
2136  *
2137  *  Throws TestError exception if an error occurs.
2138  *
2139  *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2140  *                             data generated by subsequent iterations.
2141  **/
verifyResultData(const void ** all_iterations_data)2142 void TessellationShaderInvarianceRule5Test::verifyResultData(const void **all_iterations_data)
2143 {
2144     /* Run two separate iterations:
2145      *
2146      * a) triangles
2147      * b) quads
2148      */
2149     for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration)
2150     {
2151         const unsigned int n_base_iteration = (n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2152         const unsigned int set_size         = (n_iteration == 0) ? (unsigned int)m_test_triangles_iterations.size() :
2153                                                                    (unsigned int)m_test_quads_iterations.size();
2154         const _test_iterations &test_iterations =
2155             (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2156 
2157         DE_ASSERT(test_iterations.size() != 0);
2158 
2159         /* For each iteration, verify that all vertices generated for all three vertex spacing modes.
2160          * are exactly the same (but in different order) */
2161         const float *base_vertex_data = (const float *)all_iterations_data[n_base_iteration + 0];
2162 
2163         for (unsigned int n_set = 1; n_set < set_size; ++n_set)
2164         {
2165             const float *set_vertex_data = (const float *)all_iterations_data[n_base_iteration + n_set];
2166 
2167             /* Amount of vertices should not differ between sets */
2168             DE_ASSERT(test_iterations[0].n_vertices == test_iterations[n_set].n_vertices);
2169 
2170             /* Run through all vertices in base set and make sure they can be found in currently
2171              * processed set */
2172             for (unsigned int n_base_vertex = 0; n_base_vertex < test_iterations[0].n_vertices; ++n_base_vertex)
2173             {
2174                 const float *base_vertex = base_vertex_data + 3 /* components */ * n_base_vertex;
2175 
2176                 if (!isVertexDefined(set_vertex_data, test_iterations[n_set].n_vertices, base_vertex,
2177                                      3)) /* components */
2178                 {
2179                     const char *primitive_mode = (n_iteration == 0) ? "triangles" : "quads";
2180 
2181                     m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode [" << primitive_mode << "] "
2182                                        << "a vertex with tessellation coordinates:[" << base_vertex[0] << ", "
2183                                        << base_vertex[1] << ", " << base_vertex[2] << ") "
2184                                        << "could not have been found for both vertex orderings."
2185                                        << tcu::TestLog::EndMessage;
2186 
2187                     TCU_FAIL("Implementation does not follow Rule 5.");
2188                 }
2189             } /* for (all base set's vertices) */
2190         }     /* for (all sets) */
2191     }         /* for (both primitive types) */
2192 }
2193 
2194 /** Constructor.
2195  *
2196  *  @param context Rendering context.
2197  *
2198  **/
TessellationShaderInvarianceRule6Test(Context & context,const ExtParameters & extParams)2199 TessellationShaderInvarianceRule6Test::TessellationShaderInvarianceRule6Test(Context &context,
2200                                                                              const ExtParameters &extParams)
2201     : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule6",
2202                                            "Verifies conformance with sixth invariance rule")
2203 {
2204 }
2205 
2206 /** Destructor. */
~TessellationShaderInvarianceRule6Test()2207 TessellationShaderInvarianceRule6Test::~TessellationShaderInvarianceRule6Test()
2208 {
2209     /* Left blank intentionally */
2210 }
2211 
2212 /** Retrieves amount of iterations the base test implementation should run before
2213  *  calling global verification routine.
2214  *
2215  *  @return A value that depends on initTestIterations() behavior.
2216  **/
getAmountOfIterations()2217 unsigned int TessellationShaderInvarianceRule6Test::getAmountOfIterations()
2218 {
2219     if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
2220     {
2221         initTestIterations();
2222     }
2223 
2224     return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
2225 }
2226 
2227 /** Retrieves _test_iteration instance specific for user-specified iteration index.
2228  *
2229  *  @param n_iteration Iteration index to retrieve _test_iteration instance for.
2230  *
2231  * @return Iteration-specific _test_iteration instance.
2232  *
2233  **/
getTestForIteration(unsigned int n_iteration)2234 TessellationShaderInvarianceRule6Test::_test_iteration &TessellationShaderInvarianceRule6Test::getTestForIteration(
2235     unsigned int n_iteration)
2236 {
2237     unsigned int n_triangles_tests  = (unsigned int)m_test_triangles_iterations.size();
2238     _test_iteration &test_iteration = (n_iteration < n_triangles_tests) ?
2239                                           m_test_triangles_iterations[n_iteration] :
2240                                           m_test_quads_iterations[n_iteration - n_triangles_tests];
2241 
2242     return test_iteration;
2243 }
2244 
2245 /** Retrieves iteration-specific tessellation properties.
2246  *
2247  *  @param n_iteration            Iteration index to retrieve the properties for.
2248  *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
2249  *                                tessellation level values. Must not be NULL.
2250  *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
2251  *                                tessellation level values. Must not be NULL.
2252  *  @param out_point_mode         Deref will be used to store iteration-specific flag
2253  *                                telling whether point mode should be enabled for given pass.
2254  *                                Must not be NULL.
2255  *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
2256  *                                mode. Must not be NULL.
2257  *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
2258  *                                ordering. Must not be NULL.
2259  *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
2260  *                                storage should offer for the draw call to succeed. Can
2261  *                                be NULL.
2262  **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)2263 void TessellationShaderInvarianceRule6Test::getIterationProperties(
2264     unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
2265     _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
2266     unsigned int *out_result_buffer_size)
2267 {
2268     DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2269 
2270     _test_iteration &test_iteration = getTestForIteration(n_iteration);
2271 
2272     memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
2273     memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
2274 
2275     *out_point_mode      = false;
2276     *out_primitive_mode  = test_iteration.primitive_mode;
2277     *out_vertex_ordering = test_iteration.vertex_ordering;
2278 
2279     if (out_result_buffer_size != DE_NULL)
2280     {
2281         *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2282             *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2283             *out_point_mode);
2284         test_iteration.n_vertices = *out_result_buffer_size;
2285         *out_result_buffer_size =
2286             static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2287 
2288         DE_ASSERT(*out_result_buffer_size != 0);
2289     }
2290 }
2291 
2292 /** Retrieves iteration-specific tessellation evaluation shader code.
2293  *
2294  *  @param n_iteration Iteration index, for which the source code is being obtained.
2295  *
2296  *  @return Requested source code.
2297  **/
getTECode(unsigned int n_iteration)2298 std::string TessellationShaderInvarianceRule6Test::getTECode(unsigned int n_iteration)
2299 {
2300     DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2301 
2302     const _test_iteration &test_iteration = getTestForIteration(n_iteration);
2303 
2304     return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2305                                                      test_iteration.primitive_mode, test_iteration.vertex_ordering,
2306                                                      false); /* point mode */
2307 }
2308 
2309 /** Initializes test iterations for the test. The following modes and inner/outer tess level
2310  *  configurations are used to form the test set:
2311  *
2312  *  - Tessellation level combinations as returned by
2313  *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() (however, the inner
2314  *    tessellation level values are all set to values corresponding to last item returned for
2315  *    the set)
2316  *  - All primitive modes;
2317  *  - All vertex ordering modes;
2318  *
2319  *  All permutations are used to generate the test set.
2320  **/
initTestIterations()2321 void TessellationShaderInvarianceRule6Test::initTestIterations()
2322 {
2323     DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2324 
2325     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2326     const glw::Functions &gl               = m_context.getRenderContext().getFunctions();
2327     glw::GLint gl_max_tess_gen_level_value = 0;
2328 
2329     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2330     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2331 
2332     /* Iterate through all primitive and vertex spacing modes relevant to the test */
2333     _tessellation_primitive_mode primitive_modes[]               = {TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
2334                                                                     TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS};
2335     _tessellation_shader_vertex_ordering vertex_ordering_modes[] = {TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
2336                                                                     TESSELLATION_SHADER_VERTEX_ORDERING_CW};
2337 
2338     const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2339     const unsigned int n_vo_modes        = sizeof(vertex_ordering_modes) / sizeof(vertex_ordering_modes[0]);
2340 
2341     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2342     {
2343         _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2344 
2345         for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2346         {
2347             _tessellation_shader_vertex_ordering vertex_ordering = vertex_ordering_modes[n_vo_mode];
2348 
2349             /* Retrieve inner/outer tessellation level combinations we want the tests to be run for.
2350              * Since each level set we will be provided by getTessellationLevelSetForPrimitiveMode()
2351              * is unique and does not repeat, we'll just make sure the inner level values are set to
2352              * the same set of values, so that the conditions the test must meet are actually met.
2353              */
2354             float *inner_levels_to_use = DE_NULL;
2355             _tessellation_levels_set levels_set;
2356             unsigned int n_levels_sets = 0;
2357 
2358             levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2359                 primitive_mode, gl_max_tess_gen_level_value,
2360                 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2361 
2362             n_levels_sets       = (unsigned int)levels_set.size();
2363             inner_levels_to_use = levels_set[n_levels_sets - 1].inner;
2364 
2365             for (unsigned int n_levels_set = 0; n_levels_set < n_levels_sets - 1; n_levels_set++)
2366             {
2367                 /* Make sure the Utils function was not changed and that inner level values
2368                  * are actually unique across the whole set */
2369                 DE_ASSERT(levels_set[n_levels_set].inner[0] != levels_set[n_levels_sets - 1].inner[0] &&
2370                           levels_set[n_levels_set].inner[1] != levels_set[n_levels_sets - 1].inner[1]);
2371 
2372                 /* Force the last set's inner values to all level combinations we'll be using */
2373                 memcpy(levels_set[n_levels_set].inner, inner_levels_to_use, sizeof(levels_set[n_levels_set].inner));
2374             } /* for (all sets retrieved from Utils function */
2375 
2376             for (_tessellation_levels_set_const_iterator set_iterator = levels_set.begin();
2377                  set_iterator != levels_set.end(); set_iterator++)
2378             {
2379                 const _tessellation_levels &levels = *set_iterator;
2380 
2381                 /* Create a test descriptor for all the parameters we now have */
2382                 _test_iteration test;
2383 
2384                 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2385                 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2386 
2387                 test.primitive_mode  = primitive_mode;
2388                 test.vertex_ordering = vertex_ordering;
2389 
2390                 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2391                 {
2392                     m_test_triangles_iterations.push_back(test);
2393                 }
2394                 else
2395                 {
2396                     m_test_quads_iterations.push_back(test);
2397                 }
2398             } /* for (all level sets) */
2399         }     /* for (all vertex ordering modes) */
2400     }         /* for (all primitive modes) */
2401 }
2402 
2403 /** Verifies result data. Accesses data generated by all iterations.
2404  *
2405  *  Throws TestError exception if an error occurs.
2406  *
2407  *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2408  *                             data generated by subsequent iterations.
2409  **/
verifyResultData(const void ** all_iterations_data)2410 void TessellationShaderInvarianceRule6Test::verifyResultData(const void **all_iterations_data)
2411 {
2412     /* Run two separate iterations:
2413      *
2414      * a) triangles
2415      * b) quads
2416      */
2417 
2418     for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration)
2419     {
2420         const unsigned int n_base_iteration = (n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2421 
2422         const unsigned int n_sets = (n_iteration == 0) ? (unsigned int)m_test_triangles_iterations.size() :
2423                                                          (unsigned int)m_test_quads_iterations.size();
2424 
2425         _tessellation_primitive_mode primitive_mode = (n_iteration == 0) ?
2426                                                           TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
2427                                                           TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
2428 
2429         const _test_iterations &test_iterations =
2430             (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2431 
2432         const unsigned int n_triangles_in_base_set = test_iterations[0].n_vertices / 3 /* vertices per triangle */;
2433 
2434         DE_ASSERT(test_iterations.size() != 0);
2435 
2436         /* For each iteration, verify that all vertices generated for all three vertex spacing modes.
2437          * are exactly the same (but in different order) */
2438         const _test_iteration &base_test = test_iterations[0];
2439         const float *base_vertex_data    = (const float *)all_iterations_data[n_base_iteration + 0];
2440 
2441         for (unsigned int n_set = 1; n_set < n_sets; ++n_set)
2442         {
2443             const _test_iteration &set_test = test_iterations[n_set];
2444             const float *set_vertex_data    = (const float *)all_iterations_data[n_base_iteration + n_set];
2445 
2446             /* We're operating on triangles so make sure the amount of vertices we're dealing with is
2447              * divisible by 3 */
2448             DE_ASSERT((test_iterations[n_set].n_vertices % 3) == 0);
2449 
2450             const unsigned int n_triangles_in_curr_set = test_iterations[n_set].n_vertices / 3;
2451 
2452             /* Take base triangles and make sure they can be found in iteration-specific set.
2453              * Now, thing to keep in mind here is that we must not assume any specific vertex
2454              * and triangle order which is why the slow search. */
2455             for (unsigned int n_base_triangle = 0; n_base_triangle < n_triangles_in_base_set; ++n_base_triangle)
2456             {
2457                 /* Extract base triangle data first */
2458                 const float *base_triangle_vertex1 = base_vertex_data + n_base_triangle *
2459                                                                             3 * /* vertices per triangle */
2460                                                                             3;  /* components */
2461                 const float *base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */
2462                 const float *base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */
2463 
2464                 /* Only interior triangles should be left intact. Is this an interior triangle? */
2465                 if (!TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1) &&
2466                     !TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2) &&
2467                     !TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3))
2468                 {
2469                     /* Iterate through all triangles in considered set */
2470                     bool has_base_set_triangle_been_found = false;
2471 
2472                     for (unsigned int n_curr_set_triangle = 0; n_curr_set_triangle < n_triangles_in_curr_set;
2473                          ++n_curr_set_triangle)
2474                     {
2475                         const float *curr_triangle = set_vertex_data + n_curr_set_triangle *
2476                                                                            3 * /* vertices per triangle */
2477                                                                            3;  /* components */
2478 
2479                         if (TessellationShaderUtils::isTriangleDefined(base_triangle_vertex1, curr_triangle))
2480                         {
2481                             has_base_set_triangle_been_found = true;
2482 
2483                             break;
2484                         }
2485                     } /* for (all triangles in currently processed set) */
2486 
2487                     if (!has_base_set_triangle_been_found)
2488                     {
2489                         std::string primitive_mode_str =
2490                             TessellationShaderUtils::getESTokenForPrimitiveMode(base_test.primitive_mode);
2491 
2492                         m_testCtx.getLog()
2493                             << tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "]"
2494                             << ", base inner tessellation levels:"
2495                             << "[" << base_test.inner_tess_levels[0] << ", " << base_test.inner_tess_levels[1] << "]"
2496                             << ", base outer tessellation levels:"
2497                             << "[" << base_test.outer_tess_levels[0] << ", " << base_test.outer_tess_levels[1] << ", "
2498                             << base_test.outer_tess_levels[2] << ", " << base_test.outer_tess_levels[3] << "]"
2499                             << ", reference inner tessellation levels:"
2500                             << "[" << set_test.inner_tess_levels[0] << ", " << set_test.inner_tess_levels[1] << "]"
2501                             << ", reference outer tessellation levels:"
2502                             << "[" << set_test.outer_tess_levels[0] << ", " << set_test.outer_tess_levels[1] << ", "
2503                             << set_test.outer_tess_levels[2] << ", " << set_test.outer_tess_levels[3] << "]"
2504                             << ", the following triangle formed during base tessellation run was not found in "
2505                                "reference run:"
2506                             << "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", "
2507                             << base_triangle_vertex1[2] << "]x"
2508                             << "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", "
2509                             << base_triangle_vertex2[2] << "]x"
2510                             << "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", "
2511                             << base_triangle_vertex3[2]
2512 
2513                             << tcu::TestLog::EndMessage;
2514 
2515                         TCU_FAIL("Implementation does not appear to be rule 6-conformant");
2516                     } /* if (triangle created during base run was not found in reference run) */
2517                 }     /* if (base triangle is interior) */
2518             }         /* for (all base set's vertices) */
2519         }             /* for (all sets) */
2520     }                 /* for (both primitive types) */
2521 }
2522 
2523 /** Constructor.
2524  *
2525  *  @param context Rendering context.
2526  *
2527  **/
TessellationShaderInvarianceRule7Test(Context & context,const ExtParameters & extParams)2528 TessellationShaderInvarianceRule7Test::TessellationShaderInvarianceRule7Test(Context &context,
2529                                                                              const ExtParameters &extParams)
2530     : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule7",
2531                                            "Verifies conformance with seventh invariance rule")
2532 {
2533 }
2534 
2535 /** Destructor. */
~TessellationShaderInvarianceRule7Test()2536 TessellationShaderInvarianceRule7Test::~TessellationShaderInvarianceRule7Test()
2537 {
2538     /* Left blank intentionally */
2539 }
2540 
2541 /** Retrieves amount of iterations the base test implementation should run before
2542  *  calling global verification routine.
2543  *
2544  *  @return A value that depends on initTestIterations() behavior.
2545  **/
getAmountOfIterations()2546 unsigned int TessellationShaderInvarianceRule7Test::getAmountOfIterations()
2547 {
2548     if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
2549     {
2550         initTestIterations();
2551     }
2552 
2553     return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
2554 }
2555 
2556 /** Retrieves index of a test iteration that was initialized with user-provided
2557  *  properties.
2558  *
2559  *  @param is_triangles_iteration      true if the seeked test iteration should have
2560  *                                     been run for 'triangles' primitive mode', false
2561  *                                     if 'quads' primitive mode run is seeked.
2562  *  @param inner_tess_levels           Two FP values describing inner tessellation level
2563  *                                     values the seeked run should have used.
2564  *  @param outer_tess_levels           Four FP values describing outer tessellation level
2565  *                                     values the seeked run should have used.
2566  *  @param vertex_ordering             Vertex ordering mode the seeked run should have used.
2567  *  @param n_modified_outer_tess_level Tells which outer tessellation level should be
2568  *                                     excluded from checking.
2569  *
2570  *  @return 0xFFFFFFFF if no test iteration was run for user-provided properties,
2571  *          actual index otherwise.
2572  *
2573  **/
getTestIterationIndex(bool is_triangles_iteration,const float * inner_tess_levels,const float * outer_tess_levels,_tessellation_shader_vertex_ordering vertex_ordering,unsigned int n_modified_outer_tess_level)2574 unsigned int TessellationShaderInvarianceRule7Test::getTestIterationIndex(
2575     bool is_triangles_iteration, const float *inner_tess_levels, const float *outer_tess_levels,
2576     _tessellation_shader_vertex_ordering vertex_ordering, unsigned int n_modified_outer_tess_level)
2577 {
2578     const float epsilon = 1e-5f;
2579     unsigned int result = 0xFFFFFFFF;
2580     const _test_iterations &test_iterations =
2581         (is_triangles_iteration) ? m_test_triangles_iterations : m_test_quads_iterations;
2582     const unsigned int n_test_iterations = (unsigned int)test_iterations.size();
2583 
2584     for (unsigned int n_test_iteration = 0; n_test_iteration < n_test_iterations; ++n_test_iteration)
2585     {
2586         _test_iteration test_iteration = test_iterations[n_test_iteration];
2587 
2588         if (de::abs(test_iteration.inner_tess_levels[0] - inner_tess_levels[0]) < epsilon &&
2589             de::abs(test_iteration.inner_tess_levels[1] - inner_tess_levels[1]) < epsilon &&
2590             test_iteration.vertex_ordering == vertex_ordering &&
2591             test_iteration.n_modified_outer_tess_level == n_modified_outer_tess_level)
2592         {
2593             /* Only compare outer tessellation levels that have not been modified */
2594             if (((n_modified_outer_tess_level == 0) ||
2595                  (n_modified_outer_tess_level != 0 &&
2596                   de::abs(test_iteration.outer_tess_levels[0] - outer_tess_levels[0]) < epsilon)) &&
2597                 ((n_modified_outer_tess_level == 1) ||
2598                  (n_modified_outer_tess_level != 1 &&
2599                   de::abs(test_iteration.outer_tess_levels[1] - outer_tess_levels[1]) < epsilon)) &&
2600                 ((n_modified_outer_tess_level == 2) ||
2601                  (n_modified_outer_tess_level != 2 &&
2602                   de::abs(test_iteration.outer_tess_levels[2] - outer_tess_levels[2]) < epsilon)) &&
2603                 ((n_modified_outer_tess_level == 3) ||
2604                  (n_modified_outer_tess_level != 3 &&
2605                   de::abs(test_iteration.outer_tess_levels[3] - outer_tess_levels[3]) < epsilon)))
2606             {
2607                 result = n_test_iteration;
2608 
2609                 break;
2610             }
2611         }
2612     } /* for (all test iterations) */
2613 
2614     return result;
2615 }
2616 
2617 /** Retrieves _test_iteration instance specific for user-specified iteration index.
2618  *
2619  *  @param n_iteration Iteration index to retrieve _test_iteration instance for.
2620  *
2621  * @return Iteration-specific _test_iteration instance.
2622  *
2623  **/
getTestForIteration(unsigned int n_iteration)2624 TessellationShaderInvarianceRule7Test::_test_iteration &TessellationShaderInvarianceRule7Test::getTestForIteration(
2625     unsigned int n_iteration)
2626 {
2627     unsigned int n_triangles_tests  = (unsigned int)m_test_triangles_iterations.size();
2628     _test_iteration &test_iteration = (n_iteration < n_triangles_tests) ?
2629                                           m_test_triangles_iterations[n_iteration] :
2630                                           m_test_quads_iterations[n_iteration - n_triangles_tests];
2631 
2632     return test_iteration;
2633 }
2634 
2635 /** Retrieves iteration-specific tessellation properties.
2636  *
2637  *  @param n_iteration            Iteration index to retrieve the properties for.
2638  *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
2639  *                                tessellation level values. Must not be NULL.
2640  *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
2641  *                                tessellation level values. Must not be NULL.
2642  *  @param out_point_mode         Deref will be used to store iteration-specific flag
2643  *                                telling whether point mode should be enabled for given pass.
2644  *                                Must not be NULL.
2645  *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
2646  *                                mode. Must not be NULL.
2647  *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
2648  *                                ordering. Must not be NULL.
2649  *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
2650  *                                storage should offer for the draw call to succeed. Can
2651  *                                be NULL.
2652  **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)2653 void TessellationShaderInvarianceRule7Test::getIterationProperties(
2654     unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
2655     _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
2656     unsigned int *out_result_buffer_size)
2657 {
2658     DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2659 
2660     _test_iteration &test_iteration = getTestForIteration(n_iteration);
2661 
2662     memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
2663     memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
2664 
2665     *out_point_mode      = false;
2666     *out_primitive_mode  = test_iteration.primitive_mode;
2667     *out_vertex_ordering = test_iteration.vertex_ordering;
2668 
2669     if (out_result_buffer_size != DE_NULL)
2670     {
2671         *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2672             *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2673             *out_point_mode);
2674         test_iteration.n_vertices = *out_result_buffer_size;
2675         *out_result_buffer_size =
2676             static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2677 
2678         DE_ASSERT(*out_result_buffer_size != 0);
2679     }
2680 }
2681 
2682 /** Retrieves iteration-specific tessellation evaluation shader code.
2683  *
2684  *  @param n_iteration Iteration index, for which the source code is being obtained.
2685  *
2686  *  @return Requested source code.
2687  **/
getTECode(unsigned int n_iteration)2688 std::string TessellationShaderInvarianceRule7Test::getTECode(unsigned int n_iteration)
2689 {
2690     DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2691 
2692     const _test_iteration &test_iteration = getTestForIteration(n_iteration);
2693 
2694     return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2695                                                      test_iteration.primitive_mode, test_iteration.vertex_ordering,
2696                                                      false); /* point mode */
2697 }
2698 
2699 /** Initializes test iterations for the test. The following modes and inner/outer tess level
2700  *  configurations are used to form the test set:
2701  *
2702  *  - All inner/outer tessellation level combinations as returned by
2703  *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
2704  *    times 3 (for triangles) or 4 (for quads). For each combination,
2705  *    the test will capture tessellation coordinates multiple times, each
2706  *    time changing a different outer tessellation level value and leaving
2707  *    the rest intact.
2708  *  - All primitive modes;
2709  *  - All vertex spacing modes;
2710  *
2711  *  All permutations are used to generate the test set.
2712  **/
initTestIterations()2713 void TessellationShaderInvarianceRule7Test::initTestIterations()
2714 {
2715     DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2716 
2717     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2718     const glw::Functions &gl               = m_context.getRenderContext().getFunctions();
2719     glw::GLint gl_max_tess_gen_level_value = 0;
2720 
2721     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2722     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2723 
2724     /* Iterate through all primitive and vertex spacing modes relevant to the test */
2725     _tessellation_primitive_mode primitive_modes[]  = {TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2726                                                        TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
2727     _tessellation_shader_vertex_ordering vo_modes[] = {
2728         TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
2729         TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2730     };
2731 
2732     const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2733     const unsigned int n_vo_modes        = sizeof(vo_modes) / sizeof(vo_modes[0]);
2734 
2735     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2736     {
2737         _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2738         const unsigned int n_relevant_outer_tess_levels =
2739             (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 4 : 3;
2740 
2741         for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2742         {
2743             _tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode];
2744 
2745             /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
2746             _tessellation_levels_set levels_set;
2747 
2748             levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2749                 primitive_mode, gl_max_tess_gen_level_value,
2750                 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2751 
2752             /* Create test descriptor for all inner/outer level configurations we received from the utils function. */
2753             for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin();
2754                  levels_set_iterator != levels_set.end(); levels_set_iterator++)
2755             {
2756                 const _tessellation_levels &levels = *levels_set_iterator;
2757 
2758                 for (unsigned int n_outer_level_to_change = 0;
2759                      n_outer_level_to_change < n_relevant_outer_tess_levels + 1 /* base iteration */;
2760                      ++n_outer_level_to_change)
2761                 {
2762                     /* Create a test descriptor for all the parameters we now have */
2763                     _test_iteration test;
2764 
2765                     memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2766                     memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2767 
2768                     test.primitive_mode  = primitive_mode;
2769                     test.vertex_ordering = vertex_ordering;
2770 
2771                     /* Change iteration-specific outer tessellation level to a different value, but only
2772                      * if we're not preparing a base iteration*/
2773                     if (n_outer_level_to_change != n_relevant_outer_tess_levels)
2774                     {
2775                         test.n_modified_outer_tess_level                = n_outer_level_to_change;
2776                         test.outer_tess_levels[n_outer_level_to_change] = (float)(gl_max_tess_gen_level_value) / 3.0f;
2777                     }
2778                     else
2779                     {
2780                         test.is_base_iteration = true;
2781                     }
2782 
2783                     if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2784                     {
2785                         m_test_triangles_iterations.push_back(test);
2786                     }
2787                     else
2788                     {
2789                         m_test_quads_iterations.push_back(test);
2790                     }
2791                 }
2792             } /* for (all levels set entries) */
2793         }     /* for (all vertex spacing modes) */
2794     }         /* for (all primitive modes) */
2795 }
2796 
2797 /** Tells whether a triangle is included in user-provided set of triangles.
2798  *  The triangle is expected to use an undefined vertex ordering.
2799  *
2800  *  @param base_triangle_data     9 FP values defining 3 vertices of a triangle.
2801  *  @param vertex_data            Vertex stream. It is expected these vertices
2802  *                                form triangles. It is also assumed each vertex
2803  *                                is expressed with 3 components.
2804  *  @param vertex_data_n_vertices Amount of vertices that can be found in @param
2805  *                                vertex_data
2806  *
2807  *  @return true if the triangle was found in user-provided triangle set,
2808  *          false otherwise.
2809  *
2810  **/
isTriangleDefinedInVertexDataSet(const float * base_triangle_data,const float * vertex_data,unsigned int vertex_data_n_vertices)2811 bool TessellationShaderInvarianceRule7Test::isTriangleDefinedInVertexDataSet(const float *base_triangle_data,
2812                                                                              const float *vertex_data,
2813                                                                              unsigned int vertex_data_n_vertices)
2814 {
2815     bool result = false;
2816 
2817     for (unsigned int n_triangle = 0; n_triangle < vertex_data_n_vertices / 3 /* vertices per triangle */; n_triangle++)
2818     {
2819         const float *current_triangle_data = vertex_data + n_triangle * 3 * /* vertices per triangle */
2820                                                                3;           /* components */
2821 
2822         if (TessellationShaderUtils::isTriangleDefined(current_triangle_data, base_triangle_data))
2823         {
2824             result = true;
2825 
2826             break;
2827         }
2828     } /* for (all vertices) */
2829 
2830     return result;
2831 }
2832 
2833 /** Verifies result data. Accesses data generated by all iterations.
2834  *
2835  *  Throws TestError exception if an error occurs.
2836  *
2837  *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2838  *                             data generated by subsequent iterations.
2839  **/
verifyResultData(const void ** all_iterations_data)2840 void TessellationShaderInvarianceRule7Test::verifyResultData(const void **all_iterations_data)
2841 {
2842     const float epsilon = 1e-5f;
2843 
2844     /* Run two separate iterations:
2845      *
2846      * a) triangles
2847      * b) quads
2848      */
2849     for (unsigned int n_iteration = 0; n_iteration < 2 /* triangles, quads */; ++n_iteration)
2850     {
2851         bool is_triangles_iteration         = (n_iteration == 0);
2852         const unsigned int n_base_iteration = (n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2853         const unsigned int n_relevant_outer_tess_levels = (is_triangles_iteration) ? 3 : 4;
2854 
2855         _tessellation_primitive_mode primitive_mode = (n_iteration == 0) ?
2856                                                           TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
2857                                                           TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
2858 
2859         const _test_iterations &test_iterations =
2860             (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2861 
2862         DE_ASSERT(test_iterations.size() != 0);
2863 
2864         /* Find a base iteration first */
2865         for (unsigned int n_base_test_iteration = 0; n_base_test_iteration < test_iterations.size();
2866              n_base_test_iteration++)
2867         {
2868             const _test_iteration &base_iteration = test_iterations[n_base_test_iteration];
2869             std::vector<int> ref_iteration_indices;
2870 
2871             if (!base_iteration.is_base_iteration)
2872             {
2873                 continue;
2874             }
2875 
2876             /* Retrieve reference test iterations */
2877             for (unsigned int n_reference_iteration = 0; n_reference_iteration < n_relevant_outer_tess_levels;
2878                  ++n_reference_iteration)
2879             {
2880                 const unsigned int n_modified_outer_tess_level =
2881                     (base_iteration.n_modified_outer_tess_level + n_reference_iteration + 1) %
2882                     n_relevant_outer_tess_levels;
2883                 const unsigned int ref_iteration_index = getTestIterationIndex(
2884                     is_triangles_iteration, base_iteration.inner_tess_levels, base_iteration.outer_tess_levels,
2885                     base_iteration.vertex_ordering, n_modified_outer_tess_level);
2886 
2887                 DE_ASSERT(ref_iteration_index != 0xFFFFFFFF);
2888                 DE_ASSERT(ref_iteration_index != n_base_test_iteration);
2889 
2890                 ref_iteration_indices.push_back(ref_iteration_index);
2891             }
2892 
2893             /* We can now start comparing base data with the information generated for
2894              * reference iterations. */
2895             for (std::vector<int>::const_iterator ref_iteration_iterator = ref_iteration_indices.begin();
2896                  ref_iteration_iterator != ref_iteration_indices.end(); ref_iteration_iterator++)
2897             {
2898                 const int &n_ref_test_iteration      = *ref_iteration_iterator;
2899                 const _test_iteration &ref_iteration = test_iterations[n_ref_test_iteration];
2900 
2901                 /* Now move through all triangles generated for base test iteration. Focus on the ones
2902                  * that connect the outer edge with one of the inner ones */
2903                 const float *base_iteration_vertex_data =
2904                     (const float *)all_iterations_data[n_base_iteration + n_base_test_iteration];
2905                 const float *ref_iteration_vertex_data =
2906                     (const float *)all_iterations_data[n_base_iteration + n_ref_test_iteration];
2907 
2908                 for (unsigned int n_base_triangle = 0;
2909                      n_base_triangle < base_iteration.n_vertices / 3; /* vertices per triangle */
2910                      ++n_base_triangle)
2911                 {
2912                     const float *base_triangle_data =
2913                         base_iteration_vertex_data + n_base_triangle * 3 /* vertices */ * 3; /* components */
2914 
2915                     /* Is that the triangle type we're after? */
2916                     const float *base_triangle_vertex1 = base_triangle_data;
2917                     const float *base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */
2918                     const float *base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */
2919                     bool is_base_triangle_vertex1_outer =
2920                         TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1);
2921                     bool is_base_triangle_vertex2_outer =
2922                         TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2);
2923                     bool is_base_triangle_vertex3_outer =
2924                         TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3);
2925                     unsigned int n_outer_edge_vertices_found = 0;
2926 
2927                     n_outer_edge_vertices_found += (is_base_triangle_vertex1_outer == true);
2928                     n_outer_edge_vertices_found += (is_base_triangle_vertex2_outer == true);
2929                     n_outer_edge_vertices_found += (is_base_triangle_vertex3_outer == true);
2930 
2931                     if (n_outer_edge_vertices_found == 0)
2932                     {
2933                         /* This is an inner triangle, not really of our interest */
2934                         continue;
2935                     }
2936 
2937                     /* Which outer tessellation level describes the base data edge? */
2938                     unsigned int n_base_tess_level = 0;
2939 
2940                     if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2941                     {
2942                         if ((!is_base_triangle_vertex1_outer ||
2943                              (is_base_triangle_vertex1_outer && base_triangle_vertex1[0] == 0.0f)) &&
2944                             (!is_base_triangle_vertex2_outer ||
2945                              (is_base_triangle_vertex2_outer && base_triangle_vertex2[0] == 0.0f)) &&
2946                             (!is_base_triangle_vertex3_outer ||
2947                              (is_base_triangle_vertex3_outer && base_triangle_vertex3[0] == 0.0f)))
2948                         {
2949                             n_base_tess_level = 0;
2950                         }
2951                         else if ((!is_base_triangle_vertex1_outer ||
2952                                   (is_base_triangle_vertex1_outer && base_triangle_vertex1[1] == 0.0f)) &&
2953                                  (!is_base_triangle_vertex2_outer ||
2954                                   (is_base_triangle_vertex2_outer && base_triangle_vertex2[1] == 0.0f)) &&
2955                                  (!is_base_triangle_vertex3_outer ||
2956                                   (is_base_triangle_vertex3_outer && base_triangle_vertex3[1] == 0.0f)))
2957                         {
2958                             n_base_tess_level = 1;
2959                         }
2960                         else
2961                         {
2962                             DE_ASSERT((!is_base_triangle_vertex1_outer ||
2963                                        (is_base_triangle_vertex1_outer && base_triangle_vertex1[2] == 0.0f)) &&
2964                                       (!is_base_triangle_vertex2_outer ||
2965                                        (is_base_triangle_vertex2_outer && base_triangle_vertex2[2] == 0.0f)) &&
2966                                       (!is_base_triangle_vertex3_outer ||
2967                                        (is_base_triangle_vertex3_outer && base_triangle_vertex3[2] == 0.0f)));
2968 
2969                             n_base_tess_level = 2;
2970                         }
2971                     } /* if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) */
2972                     else
2973                     {
2974                         DE_ASSERT(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS);
2975 
2976                         std::size_t n_outer_edge_vertices = 0;
2977                         std::vector<const float *> outer_edge_vertices;
2978 
2979                         if (is_base_triangle_vertex1_outer)
2980                         {
2981                             outer_edge_vertices.push_back(base_triangle_vertex1);
2982                         }
2983 
2984                         if (is_base_triangle_vertex2_outer)
2985                         {
2986                             outer_edge_vertices.push_back(base_triangle_vertex2);
2987                         }
2988 
2989                         if (is_base_triangle_vertex3_outer)
2990                         {
2991                             outer_edge_vertices.push_back(base_triangle_vertex3);
2992                         }
2993 
2994                         n_outer_edge_vertices = outer_edge_vertices.size();
2995 
2996                         DE_ASSERT(n_outer_edge_vertices >= 1 && n_outer_edge_vertices <= 2);
2997 
2998                         bool is_top_outer_edge    = true;
2999                         bool is_right_outer_edge  = true;
3000                         bool is_bottom_outer_edge = true;
3001                         bool is_left_outer_edge   = true;
3002 
3003                         /* Find which outer edges the vertices don't belong to. If one is in a corner,
3004                          * the other will clarify to which edge both vertices belong. */
3005                         for (unsigned int n_vertex = 0; n_vertex < n_outer_edge_vertices; ++n_vertex)
3006                         {
3007                             /* Y < 1, not top outer edge */
3008                             if (de::abs(outer_edge_vertices[n_vertex][1] - 1.0f) > epsilon)
3009                             {
3010                                 is_top_outer_edge = false;
3011                             }
3012 
3013                             /* X < 1, not right outer edge */
3014                             if (de::abs(outer_edge_vertices[n_vertex][0] - 1.0f) > epsilon)
3015                             {
3016                                 is_right_outer_edge = false;
3017                             }
3018 
3019                             /* Y > 0, not bottom outer edge */
3020                             if (de::abs(outer_edge_vertices[n_vertex][1]) > epsilon)
3021                             {
3022                                 is_bottom_outer_edge = false;
3023                             }
3024 
3025                             /* X > 0, not left outer edge */
3026                             if (de::abs(outer_edge_vertices[n_vertex][0]) > epsilon)
3027                             {
3028                                 is_left_outer_edge = false;
3029                             }
3030                         }
3031 
3032                         if (n_outer_edge_vertices == 1)
3033                         {
3034                             /* A single vertex with corner-coordinates belongs to two edges. Choose one */
3035                             bool x_is_0 = de::abs(outer_edge_vertices[0][0]) < epsilon;
3036                             bool x_is_1 = de::abs(outer_edge_vertices[0][0] - 1.0f) < epsilon;
3037                             bool y_is_0 = de::abs(outer_edge_vertices[0][1]) < epsilon;
3038                             bool y_is_1 = de::abs(outer_edge_vertices[0][1] - 1.0f) < epsilon;
3039 
3040                             if (x_is_0 && y_is_0)
3041                             {
3042                                 /* bottom edge */
3043                                 DE_ASSERT(is_left_outer_edge && is_bottom_outer_edge);
3044                                 is_left_outer_edge = false;
3045                             }
3046                             else if (x_is_0 && y_is_1)
3047                             {
3048                                 /* left edge */
3049                                 DE_ASSERT(is_left_outer_edge && is_top_outer_edge);
3050                                 is_top_outer_edge = false;
3051                             }
3052                             else if (x_is_1 && y_is_0)
3053                             {
3054                                 /* right edge */
3055                                 DE_ASSERT(is_right_outer_edge && is_bottom_outer_edge);
3056                                 is_bottom_outer_edge = false;
3057                             }
3058                             else if (x_is_1 && y_is_1)
3059                             {
3060                                 /* top edge */
3061                                 DE_ASSERT(is_right_outer_edge && is_top_outer_edge);
3062                                 is_right_outer_edge = false;
3063                             }
3064                             else
3065                             {
3066                                 /* Not a corner vertex, only one of the edge-flags is set */
3067                             }
3068                         }
3069 
3070                         /* Quick checks */
3071                         DE_UNREF(is_top_outer_edge);
3072                         DE_ASSERT((is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge &&
3073                                    !is_right_outer_edge) ||
3074                                   (!is_left_outer_edge && is_top_outer_edge && !is_bottom_outer_edge &&
3075                                    !is_right_outer_edge) ||
3076                                   (!is_left_outer_edge && !is_top_outer_edge && is_bottom_outer_edge &&
3077                                    !is_right_outer_edge) ||
3078                                   (!is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge &&
3079                                    is_right_outer_edge));
3080 
3081                         /* We have all the data needed to determine which tessellation level describes
3082                          * subdivision of the edge that the triangle touches */
3083                         if (is_left_outer_edge)
3084                         {
3085                             n_base_tess_level = 0;
3086                         }
3087                         else if (is_bottom_outer_edge)
3088                         {
3089                             n_base_tess_level = 1;
3090                         }
3091                         else if (is_right_outer_edge)
3092                         {
3093                             n_base_tess_level = 2;
3094                         }
3095                         else
3096                         {
3097                             n_base_tess_level = 3;
3098                         }
3099                     }
3100 
3101                     /* We shouldn't perform the check if the edge we're processing was described
3102                      * by a different outer tessellation level in the reference data set */
3103                     if (n_base_tess_level == ref_iteration.n_modified_outer_tess_level)
3104                     {
3105                         continue;
3106                     }
3107 
3108                     /* This triangle should be present in both vertex data sets */
3109                     if (!isTriangleDefinedInVertexDataSet(base_triangle_data, ref_iteration_vertex_data,
3110                                                           ref_iteration.n_vertices))
3111                     {
3112                         const char *primitive_mode_str = (is_triangles_iteration) ? "triangles" : "quads";
3113 
3114                         m_testCtx.getLog()
3115                             << tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "] "
3116                             << ", inner tessellation levels:"
3117                             << "[" << base_iteration.inner_tess_levels[0] << ", " << base_iteration.inner_tess_levels[1]
3118                             << "], outer tessellation levels:"
3119                             << "[" << base_iteration.outer_tess_levels[0] << ", " << base_iteration.outer_tess_levels[1]
3120                             << ", " << base_iteration.outer_tess_levels[2] << ", "
3121                             << base_iteration.outer_tess_levels[3] << "], a triangle connecting inner & outer edges:"
3122                             << "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", "
3123                             << base_triangle_vertex1[2] << "]x"
3124                             << "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", "
3125                             << base_triangle_vertex2[2] << "]x"
3126                             << "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", "
3127                             << base_triangle_vertex3[2]
3128                             << "] was not found for runs using CW and CCW vertex ordering, "
3129                                "which is against the extension specification's rule 7."
3130                             << tcu::TestLog::EndMessage;
3131 
3132                         TCU_FAIL("Implementation is not conformant with Tessellation Rule 7");
3133                     }
3134                 } /* for (all triangles generated for base test iteration) */
3135             }     /* for (all reference iterations) */
3136         }         /* for (all base test iterations) */
3137     }             /* for (both primitive types) */
3138 }
3139 
3140 } /* namespace glcts */
3141