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 "esextcTessellationShaderTriangles.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 /** Constructor
35  *
36  * @param context Test context
37  **/
TessellationShaderTrianglesTests(glcts::Context & context,const ExtParameters & extParams)38 TessellationShaderTrianglesTests::TessellationShaderTrianglesTests(glcts::Context &context,
39                                                                    const ExtParameters &extParams)
40     : TestCaseGroupBase(context, extParams, "tessellation_shader_triangles_tessellation",
41                         "Verifies triangle tessellation functionality")
42 {
43     /* No implementation needed */
44 }
45 
46 /**
47  * Initializes test groups for geometry shader tests
48  **/
init(void)49 void TessellationShaderTrianglesTests::init(void)
50 {
51     addChild(new glcts::TessellationShaderTrianglesDegenerateTriangle(m_context, m_extParams));
52     addChild(new glcts::TessellationShaderTrianglesIdenticalTriangles(m_context, m_extParams));
53     addChild(new glcts::TessellationShaderTrianglesInnerTessellationLevelRounding(m_context, m_extParams));
54 }
55 
56 /** Constructor
57  *
58  * @param context Test context
59  **/
TessellationShaderTrianglesDegenerateTriangle(Context & context,const ExtParameters & extParams)60 TessellationShaderTrianglesDegenerateTriangle::TessellationShaderTrianglesDegenerateTriangle(
61     Context &context, const ExtParameters &extParams)
62     : TestCaseBase(context, extParams, "degenerate_triangle",
63                    "Verifies a degenerate triangle is generated by tessellator "
64                    "under a specific configuration of inner/outer tessellation "
65                    "levels & vertex spacing modes.")
66     , m_bo_id(0)
67     , m_fs_id(0)
68     , m_tc_id(0)
69     , m_vs_id(0)
70     , m_vao_id(0)
71 {
72     /* Left blank on purpose */
73 }
74 
75 /** Deinitializes ES objects created for the test. */
deinit()76 void TessellationShaderTrianglesDegenerateTriangle::deinit()
77 {
78     /* Call base class' deinit() */
79     TestCaseBase::deinit();
80 
81     if (!m_is_tessellation_shader_supported)
82     {
83         return;
84     }
85 
86     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
87 
88     /* Deinitialize TF buffer object bindings */
89     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
90     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
91 
92     /* Reset GL_PATCH_VERTICES_EXT value */
93     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
94 
95     /* Unbind vertex array object */
96     gl.bindVertexArray(0);
97 
98     /* Free all ES objects we allocated for the test */
99     if (m_bo_id != 0)
100     {
101         gl.deleteBuffers(1, &m_bo_id);
102 
103         m_bo_id = 0;
104     }
105 
106     if (m_fs_id != 0)
107     {
108         gl.deleteShader(m_fs_id);
109 
110         m_fs_id = 0;
111     }
112 
113     if (m_tc_id != 0)
114     {
115         gl.deleteShader(m_tc_id);
116 
117         m_tc_id = 0;
118     }
119 
120     if (m_vs_id != 0)
121     {
122         gl.deleteShader(m_vs_id);
123 
124         m_vs_id = 0;
125     }
126 
127     if (m_vao_id != 0)
128     {
129         gl.deleteVertexArrays(1, &m_vao_id);
130 
131         m_vao_id = 0;
132     }
133 
134     /* Deinitialize all test descriptors */
135     for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
136     {
137         deinitTestDescriptor(*it);
138     }
139     m_tests.clear();
140 }
141 
142 /** Deinitialize all test pass-specific ES objects.
143  *
144  *  @param test Descriptor of a test pass to deinitialize.
145  **/
deinitTestDescriptor(_test_descriptor & test)146 void TessellationShaderTrianglesDegenerateTriangle::deinitTestDescriptor(_test_descriptor &test)
147 {
148     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
149 
150     if (test.po_id != 0)
151     {
152         gl.deleteProgram(test.po_id);
153 
154         test.po_id = 0;
155     }
156 
157     if (test.te_id != 0)
158     {
159         gl.deleteShader(test.te_id);
160 
161         test.te_id = 0;
162     }
163 }
164 
165 /** Initializes ES objects necessary to run the test. */
initTest()166 void TessellationShaderTrianglesDegenerateTriangle::initTest()
167 {
168     /* Skip if required extensions are not supported. */
169     if (!m_is_tessellation_shader_supported)
170     {
171         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
172     }
173 
174     /* Generate all test-wide objects needed for test execution */
175     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
176 
177     gl.genVertexArrays(1, &m_vao_id);
178     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
179 
180     gl.bindVertexArray(m_vao_id);
181     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
182 
183     gl.genBuffers(1, &m_bo_id);
184     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
185 
186     m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
187     m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
188     m_vs_id = gl.createShader(GL_VERTEX_SHADER);
189     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
190 
191     /* Configure fragment shader body */
192     const char *fs_body = "${VERSION}\n"
193                           "\n"
194                           "void main()\n"
195                           "{\n"
196                           "}\n";
197 
198     shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
199     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
200 
201     /* Configure tessellation control shader body */
202     const char *tc_body = "${VERSION}\n"
203                           "\n"
204                           "${TESSELLATION_SHADER_REQUIRE}\n"
205                           "\n"
206                           "layout (vertices=3) out;\n"
207                           "\n"
208                           "void main()\n"
209                           "{\n"
210                           "    gl_out [gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
211                           "\n"
212                           "    gl_TessLevelInner[0] = 1.0;\n"
213                           "    gl_TessLevelOuter[0] = 1.0;\n"
214                           "    gl_TessLevelOuter[1] = 1.0;\n"
215                           "    gl_TessLevelOuter[2] = 1.0;\n"
216                           "}\n";
217 
218     shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body);
219     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
220 
221     /* Configure vertex shader body */
222     const char *vs_body = "${VERSION}\n"
223                           "\n"
224                           "void main()\n"
225                           "{\n"
226                           "    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
227                           "}\n";
228 
229     shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
230     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
231 
232     /* Compile all the shaders */
233     const glw::GLuint shaders[]  = {m_fs_id, m_tc_id, m_vs_id};
234     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
235 
236     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
237     {
238         glw::GLuint shader = shaders[n_shader];
239 
240         if (shader != 0)
241         {
242             glw::GLint compile_status = GL_FALSE;
243 
244             gl.compileShader(shader);
245             GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
246 
247             gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
248             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
249 
250             if (compile_status != GL_TRUE)
251             {
252                 TCU_FAIL("Shader compilation failed");
253             }
254         }
255     } /* for (all shaders) */
256 
257     /* Initialize all test passes */
258     _test_descriptor test_equal_spacing;
259     _test_descriptor test_fractional_odd_spacing;
260 
261     initTestDescriptor(test_equal_spacing, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
262     initTestDescriptor(test_fractional_odd_spacing, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
263 
264     m_tests.push_back(test_equal_spacing);
265     m_tests.push_back(test_fractional_odd_spacing);
266 
267     /* Set up buffer object storage */
268     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
269     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
270 
271     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 3 /* components */ * 3 /* UVW sets */, NULL, /* data */
272                   GL_STATIC_DRAW);
273     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
274 
275     /* Bind the buffer object to indiced TF binding point */
276     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
277     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
278 }
279 
280 /** Initializes all ES objects necessary to run a specific test pass.
281  *
282  *  @param test           Test descriptor to fill with IDs of initialized objects.
283  *  @param vertex_spacing Vertex spacing mode to use for the run.
284  **/
initTestDescriptor(_test_descriptor & test,_tessellation_shader_vertex_spacing vertex_spacing)285 void TessellationShaderTrianglesDegenerateTriangle::initTestDescriptor(
286     _test_descriptor &test, _tessellation_shader_vertex_spacing vertex_spacing)
287 {
288     test.vertex_spacing = vertex_spacing;
289 
290     /* Set up a program object for the descriptor */
291     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
292 
293     test.po_id = gl.createProgram();
294     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
295 
296     /* Set up a pass-specific tessellation evaluation shader object. */
297     test.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
298     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
299 
300     /* Configure tessellation evaluation shader body */
301     const char *te_template = "${VERSION}\n"
302                               "\n"
303                               "${TESSELLATION_SHADER_REQUIRE}\n"
304                               "\n"
305                               "layout (triangles, VERTEX_SPACING_MODE) in;\n"
306                               "\n"
307                               "out vec3 result_uvw;\n"
308                               "\n"
309                               "void main()\n"
310                               "{\n"
311                               "    gl_Position = gl_in[0].gl_Position;\n"
312                               "    result_uvw  = gl_TessCoord;\n"
313                               "}\n";
314 
315     const char *te_body_raw_ptr = DE_NULL;
316     std::string te_body_string  = te_template;
317     std::string vertex_spacing_mode_string;
318     const char *vertex_spacing_token       = "VERTEX_SPACING_MODE";
319     std::size_t vertex_spacing_token_index = std::string::npos;
320 
321     switch (vertex_spacing)
322     {
323     case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
324     {
325         vertex_spacing_mode_string = "equal_spacing";
326 
327         break;
328     }
329 
330     case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
331     {
332         vertex_spacing_mode_string = "fractional_odd_spacing";
333 
334         break;
335     }
336 
337     default:
338     {
339         TCU_FAIL("Invalid vertex spacing mode requested");
340     }
341     }
342 
343     while ((vertex_spacing_token_index = te_body_string.find(vertex_spacing_token)) != std::string::npos)
344     {
345         te_body_string = te_body_string.replace(vertex_spacing_token_index, strlen(vertex_spacing_token),
346                                                 vertex_spacing_mode_string);
347 
348         vertex_spacing_token_index = te_body_string.find(vertex_spacing_token);
349     }
350 
351     te_body_raw_ptr = te_body_string.c_str();
352 
353     shaderSourceSpecialized(test.te_id, 1 /* count */, &te_body_raw_ptr);
354     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
355 
356     /* Compile the tessellation evaluation shader */
357     glw::GLint compile_status = GL_FALSE;
358 
359     gl.compileShader(test.te_id);
360     GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed for tessellation evaluation shader");
361 
362     gl.getShaderiv(test.te_id, GL_COMPILE_STATUS, &compile_status);
363     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed for tessellation evaluation shader");
364 
365     if (compile_status != GL_TRUE)
366     {
367         TCU_FAIL("Tessellation evaluation shader compilation failed");
368     }
369 
370     /* Attach all shader to the program object */
371     gl.attachShader(test.po_id, m_fs_id);
372     gl.attachShader(test.po_id, m_tc_id);
373     gl.attachShader(test.po_id, test.te_id);
374     gl.attachShader(test.po_id, m_vs_id);
375     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
376 
377     /* Set up XFB */
378     const char *varyings[]        = {"result_uvw"};
379     const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
380 
381     gl.transformFeedbackVaryings(test.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
382     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
383 
384     /* Link the program object */
385     glw::GLint link_status = GL_FALSE;
386 
387     gl.linkProgram(test.po_id);
388     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
389 
390     gl.getProgramiv(test.po_id, GL_LINK_STATUS, &link_status);
391     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
392 
393     if (link_status != GL_TRUE)
394     {
395         TCU_FAIL("Program linking failed");
396     }
397 }
398 
399 /** Executes the test.
400  *
401  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
402  *
403  *  Note the function throws exception should an error occur!
404  *
405  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
406  **/
iterate(void)407 tcu::TestNode::IterateResult TessellationShaderTrianglesDegenerateTriangle::iterate(void)
408 {
409     /* Do not execute if required extensions are not supported. */
410     if (!m_is_tessellation_shader_supported)
411     {
412         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
413     }
414 
415     /* Initialize ES test objects */
416     initTest();
417 
418     /* We only need to use one vertex per so go for it */
419     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
420 
421     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
422     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
423 
424     /* Iterate through all tests configured */
425     for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++)
426     {
427         const _test_descriptor &test = *test_iterator;
428 
429         /* Run the iteration */
430         gl.useProgram(test.po_id);
431         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
432 
433         /* Draw the test geometry */
434         gl.beginTransformFeedback(GL_TRIANGLES);
435         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_TRIANGLES) failed.");
436 
437         gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
438         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
439 
440         gl.endTransformFeedback();
441         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
442 
443         /* Map the BO with result data into user space */
444         const float *triangle_vertex_data =
445             (const float *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
446                                              sizeof(float) * 3 /* vec3 */ * 3 /* points */, GL_MAP_READ_BIT);
447 
448         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
449 
450         /* Make sure the triangle data is correct. Since we cannot rely on any specific order
451          * of the result vertices, raise corresponding flag for each of the expected vertices.
452          */
453         const float epsilon           = 1e-5f;
454         bool is_zero_zero_one_present = false;
455         bool is_zero_one_zero_present = false;
456         bool is_one_zero_zero_present = false;
457 
458         for (unsigned int n_vertex = 0; n_vertex < 3 /* vertices */; ++n_vertex)
459         {
460             const float *triangle_ptr = triangle_vertex_data + 3 * n_vertex;
461 
462             if (de::abs(triangle_ptr[0]) < epsilon && de::abs(triangle_ptr[1]) < epsilon &&
463                 de::abs(triangle_ptr[2] - 1.0f) < epsilon)
464             {
465                 if (!is_zero_zero_one_present)
466                 {
467                     is_zero_zero_one_present = true;
468                 }
469                 else
470                 {
471                     TCU_FAIL("(0, 0, 1) vertex outputted more than once");
472                 }
473             }
474             else if (de::abs(triangle_ptr[0]) < epsilon && de::abs(triangle_ptr[1] - 1.0f) < epsilon &&
475                      de::abs(triangle_ptr[2]) < epsilon)
476             {
477                 if (!is_zero_one_zero_present)
478                 {
479                     is_zero_one_zero_present = true;
480                 }
481                 else
482                 {
483                     TCU_FAIL("(0, 1, 0) vertex outputted more than once");
484                 }
485             }
486             else if (de::abs(triangle_ptr[0] - 1.0f) < epsilon && de::abs(triangle_ptr[1]) < epsilon &&
487                      de::abs(triangle_ptr[2]) < epsilon)
488             {
489                 if (!is_one_zero_zero_present)
490                 {
491                     is_one_zero_zero_present = true;
492                 }
493                 else
494                 {
495                     TCU_FAIL("(1, 0, 0) vertex outputted more than once");
496                 }
497             }
498             else
499             {
500                 m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected vertex"
501                                    << " (" << triangle_vertex_data[0] << ", " << triangle_vertex_data[1] << ", "
502                                    << triangle_vertex_data[2] << ")"
503                                    << " encountered for a degenerate triangle." << tcu::TestLog::EndMessage;
504 
505                 TCU_FAIL("Invalid vertex was generated by the tessellator");
506             }
507         } /* for (all vertices) */
508 
509         /* Unmap the BO */
510         gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
511         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
512     }
513 
514     /* All done */
515     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
516     return STOP;
517 }
518 
519 /** Constructor
520  *
521  * @param context Test context
522  **/
TessellationShaderTrianglesIdenticalTriangles(Context & context,const ExtParameters & extParams)523 TessellationShaderTrianglesIdenticalTriangles::TessellationShaderTrianglesIdenticalTriangles(
524     Context &context, const ExtParameters &extParams)
525     : TestCaseBase(context, extParams, "identical_triangles",
526                    "Verifies that tessellation coordinates generated by the tessellator "
527                    "running in triangles mode do not change if second inner or fourth "
528                    "outer tessellation level is changed")
529     , m_vao_id(0)
530     , m_utils(DE_NULL)
531 {
532     /* Left blank on purpose */
533 }
534 
535 /** Deinitializes ES objects created for the test. */
deinit()536 void TessellationShaderTrianglesIdenticalTriangles::deinit()
537 {
538     /* Call base class' deinit() */
539     TestCaseBase::deinit();
540 
541     if (!m_is_tessellation_shader_supported)
542     {
543         return;
544     }
545 
546     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
547 
548     /* Unbind vertex array object */
549     gl.bindVertexArray(0);
550 
551     /* Deallocate test variables */
552     if (m_vao_id != 0)
553     {
554         gl.deleteVertexArrays(1, &m_vao_id);
555 
556         m_vao_id = 0;
557     }
558 
559     /* Deinitialize utils instance */
560     if (m_utils != DE_NULL)
561     {
562         delete m_utils;
563 
564         m_utils = DE_NULL;
565     }
566 }
567 
568 /** Initializes ES objects necessary to run the test. */
initTest()569 void TessellationShaderTrianglesIdenticalTriangles::initTest()
570 {
571     /* Skip if required extensions are not supported. */
572     if (!m_is_tessellation_shader_supported)
573     {
574         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
575     }
576 
577     /* Initialize Utils instance */
578     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
579 
580     m_utils = new TessellationShaderUtils(gl, this);
581 
582     /* Initialize vertex array object */
583     gl.genVertexArrays(1, &m_vao_id);
584     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
585 
586     gl.bindVertexArray(m_vao_id);
587     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
588 
589     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
590     glw::GLint gl_max_tess_gen_level_value = 0;
591 
592     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
593     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
594 
595     /* Initialize all test runs */
596     _tessellation_level_set_filter filter =
597         (_tessellation_level_set_filter)((int)TESSELLATION_LEVEL_SET_FILTER_ALL_COMBINATIONS |
598                                          (int)TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE);
599 
600     _tessellation_levels_set levels_sets = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
601         TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, gl_max_tess_gen_level_value, filter);
602 
603     for (_tessellation_levels_set_const_iterator set_iterator = levels_sets.begin(); set_iterator != levels_sets.end();
604          set_iterator++)
605     {
606         _run run;
607         const _tessellation_levels &set = *set_iterator;
608 
609         memcpy(run.base_inner, set.inner, sizeof(run.base_inner));
610         memcpy(run.base_outer, set.outer, sizeof(run.base_outer));
611 
612         run.reference_inner[0] = run.base_inner[0];
613         run.reference_inner[1] = run.base_inner[1] * 0.25f;
614 
615         run.reference_outer[0] = run.base_outer[0];
616         run.reference_outer[1] = run.base_outer[1];
617         run.reference_outer[2] = run.base_outer[2];
618         run.reference_outer[3] = run.base_outer[3] * 0.25f;
619 
620         /* Retrieve vertex data for both passes */
621         glw::GLint n_base_vertices      = 0;
622         glw::GLint n_reference_vertices = 0;
623 
624         n_base_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
625             TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.base_inner, run.base_outer,
626             TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, false);
627         n_reference_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
628             TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.reference_inner, run.reference_outer,
629             TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, false); /* is_point_mode_enabled */
630 
631         if (n_base_vertices == 0)
632         {
633             m_testCtx.getLog() << tcu::TestLog::Message
634                                << "No vertices were generated by tessellator for: "
635                                   "inner tess levels:"
636                                   "["
637                                << run.base_inner[0] << ", " << run.base_inner[1]
638                                << "]"
639                                   ", outer tess levels:"
640                                   "["
641                                << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", "
642                                << run.base_outer[3]
643                                << "]"
644                                   ", primitive mode: triangles, vertex spacing: equal."
645                                << tcu::TestLog::EndMessage;
646 
647             TCU_FAIL("Zero vertices were generated by tessellator for base test pass");
648         }
649 
650         if (n_reference_vertices == 0)
651         {
652             m_testCtx.getLog() << tcu::TestLog::Message
653                                << "No vertices were generated by tessellator for: "
654                                   "inner tess levels:"
655                                   "["
656                                << run.reference_inner[0] << ", " << run.reference_inner[1]
657                                << "]"
658                                   ", outer tess levels:"
659                                   "["
660                                << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
661                                << run.reference_outer[2] << ", " << run.reference_outer[3]
662                                << "]"
663                                   ", primitive mode: triangles, vertex spacing: equal."
664                                << tcu::TestLog::EndMessage;
665 
666             TCU_FAIL("Zero vertices were generated by tessellator for reference test pass");
667         }
668 
669         if (n_base_vertices != n_reference_vertices)
670         {
671             m_testCtx.getLog() << tcu::TestLog::Message
672                                << "Amount of vertices generated by the tessellator differs"
673                                   " for the following inner/outer configs: "
674                                   "inner tess levels:"
675                                   "["
676                                << run.base_inner[0] << ", " << run.base_inner[1]
677                                << "]"
678                                   ", outer tess levels:"
679                                   "["
680                                << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", "
681                                << run.base_outer[3]
682                                << "]"
683                                   " and inner tess levels:"
684                                   "["
685                                << run.reference_inner[0] << ", " << run.reference_inner[1]
686                                << "]"
687                                   ", outer tess levels:"
688                                   "["
689                                << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
690                                << run.reference_outer[2] << ", " << run.reference_outer[3]
691                                << "]"
692                                   ", primitive mode: triangles, vertex spacing: equal."
693                                << tcu::TestLog::EndMessage;
694 
695             TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes");
696         }
697 
698         run.n_vertices = n_base_vertices;
699 
700         run.base_data = m_utils->getDataGeneratedByTessellator(
701             run.base_inner, false, /* is_point_mode_enabled */
702             TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
703             TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.base_outer);
704         run.reference_data = m_utils->getDataGeneratedByTessellator(
705             run.reference_inner, false, /* is_point_mode_enabled */
706             TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
707             TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.reference_outer);
708 
709         /* Store the run data */
710         m_runs.push_back(run);
711     } /* for (all sets) */
712 }
713 
714 /** Executes the test.
715  *
716  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
717  *
718  *  Note the function throws exception should an error occur!
719  *
720  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
721  **/
iterate(void)722 tcu::TestNode::IterateResult TessellationShaderTrianglesIdenticalTriangles::iterate(void)
723 {
724     /* Do not execute if required extensions are not supported. */
725     if (!m_is_tessellation_shader_supported)
726     {
727         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
728     }
729 
730     /* Initialize the test */
731     initTest();
732 
733     /* Iterate through all runs */
734 
735     for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
736     {
737         const _run &run = *run_iterator;
738 
739         /* Make sure the vertex data generated for two passes matches */
740         const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */;
741 
742         for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle)
743         {
744             const float *triangle_a = (const float *)(&run.base_data[0]) + n_triangle * 3      /* vertices */
745                                                                                * 3;            /* components */
746             const float *triangle_b = (const float *)(&run.reference_data[0]) + n_triangle * 3 /* vertices */
747                                                                                     * 3;       /* components */
748 
749             if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b))
750             {
751                 m_testCtx.getLog() << tcu::TestLog::Message
752                                    << "The following triangle, generated in the first pass, was not "
753                                       "generated in the other. "
754                                       "First pass' configuration: inner tess levels:"
755                                       "["
756                                    << run.base_inner[0] << ", " << run.base_inner[1]
757                                    << "]"
758                                       ", outer tess levels:"
759                                       "["
760                                    << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2]
761                                    << ", " << run.base_outer[3]
762                                    << "]"
763                                       "; second pass' configuration: inner tess levels:"
764                                       "["
765                                    << run.reference_inner[0] << ", " << run.reference_inner[1]
766                                    << "]"
767                                       ", outer tess levels:"
768                                       "["
769                                    << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
770                                    << run.reference_outer[2] << ", " << run.reference_outer[3]
771                                    << "]"
772                                       ", primitive mode: triangles, vertex spacing: equal."
773                                    << tcu::TestLog::EndMessage;
774 
775                 TCU_FAIL("A triangle from base vertex data set was not found in reference vertex data set.");
776             }
777         } /* for (all vertices) */
778     }     /* for (all runs) */
779 
780     /* All done */
781     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
782     return STOP;
783 }
784 
785 /** Constructor
786  *
787  * @param context Test context
788  **/
TessellationShaderTrianglesInnerTessellationLevelRounding(Context & context,const ExtParameters & extParams)789 TessellationShaderTrianglesInnerTessellationLevelRounding::TessellationShaderTrianglesInnerTessellationLevelRounding(
790     Context &context, const ExtParameters &extParams)
791     : TestCaseBase(context, extParams, "inner_tessellation_level_rounding",
792                    "Verifies that inner tessellation level is rounded to 1 or 2,"
793                    " when the tessellator is run in triangles primitive mode and "
794                    "inner tessellation level is set to 1 and any of the outer "
795                    "tessellation levels is greater than one.")
796     , m_vao_id(0)
797     , m_utils(DE_NULL)
798 {
799     /* Left blank on purpose */
800 }
801 
802 /** Deinitializes ES objects created for the test. */
deinit()803 void TessellationShaderTrianglesInnerTessellationLevelRounding::deinit()
804 {
805     /* Call base class' deinit() */
806     TestCaseBase::deinit();
807 
808     if (!m_is_tessellation_shader_supported)
809     {
810         return;
811     }
812 
813     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
814 
815     /* Unbind vertex array object */
816     gl.bindVertexArray(0);
817 
818     /* Deallocate test variables */
819     if (m_vao_id != 0)
820     {
821         gl.deleteVertexArrays(1, &m_vao_id);
822 
823         m_vao_id = 0;
824     }
825 
826     /* Deinitialize utils instance */
827     if (m_utils != DE_NULL)
828     {
829         delete m_utils;
830 
831         m_utils = DE_NULL;
832     }
833 }
834 
835 /** Executes the test.
836  *
837  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
838  *
839  *  Note the function throws exception should an error occur!
840  *
841  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
842  **/
iterate(void)843 tcu::TestNode::IterateResult TessellationShaderTrianglesInnerTessellationLevelRounding::iterate(void)
844 {
845     /* Do not execute if required extensions are not supported. */
846     if (!m_is_tessellation_shader_supported)
847     {
848         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
849     }
850 
851     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
852 
853     /* Initialize vertex array object */
854     gl.genVertexArrays(1, &m_vao_id);
855     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
856 
857     gl.bindVertexArray(m_vao_id);
858     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
859 
860     /* Initialize and run test iterations. In later part, we will verify the generated data. */
861     runTestIterations();
862 
863     /* Iterate through all runs */
864 
865     for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
866     {
867         const _run &run = *run_iterator;
868 
869         if (run.vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD &&
870             de::abs(run.set1_inner[0] - run.set2_inner[0]) > 1e-5f &&
871             de::min(run.set1_inner[0], run.set2_inner[0]) >= 1.0f)
872         {
873             /* In fractional_odd_spacing mode with inner level <f> >= 1.0f, the clamped
874              and rounded integer level <n> is at least 3.
875 
876              These results in inner subdivision into at least <n>-2=1 segment and
877              two additional, typically shorter segments.
878 
879              The length of these two additional segments relative to the others will
880              decrease monotonically with the value of <n>-<f>, so if different <f> levels
881              were used, we cannot proceed with matching the exact vertex data. */
882 
883             continue;
884         }
885 
886         /* Make sure the vertex data generated for two passes matches */
887         const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */;
888 
889         for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle)
890         {
891             const float *triangle_a = (const float *)(&run.set1_data[0]) + n_triangle * 3 /* vertices */
892                                                                                * 3;       /* components */
893             const float *triangle_b = (const float *)(&run.set2_data[0]) + n_triangle * 3 /* vertices */
894                                                                                * 3;       /* components */
895 
896             if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b))
897             {
898                 std::string vs_mode_string =
899                     TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
900 
901                 m_testCtx.getLog() << tcu::TestLog::Message
902                                    << "The following triangle, generated in the first pass, was not "
903                                       "generated in the second one. "
904                                       "First pass' configuration: inner tess levels:"
905                                       "["
906                                    << run.set1_inner[0] << ", " << run.set1_inner[1]
907                                    << "]"
908                                       ", outer tess levels:"
909                                       "["
910                                    << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
911                                    << ", " << run.set1_outer[3]
912                                    << "]"
913                                       "; second pass' configuration: inner tess levels:"
914                                       "["
915                                    << run.set2_inner[0] << ", " << run.set2_inner[1]
916                                    << "]"
917                                       ", outer tess levels:"
918                                       "["
919                                    << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
920                                    << ", " << run.set2_outer[3]
921                                    << "]"
922                                       ", primitive mode: triangles, vertex spacing: "
923                                    << vs_mode_string << tcu::TestLog::EndMessage;
924 
925                 TCU_FAIL("A triangle from first pass' data set was not found in second pass' data set.");
926             }
927         } /* for (all vertices) */
928     }     /* for (all runs) */
929 
930     /* All done */
931     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
932     return STOP;
933 }
934 
935 /** Runs all test iterations needed to generate data for later verification. */
runTestIterations()936 void TessellationShaderTrianglesInnerTessellationLevelRounding::runTestIterations()
937 {
938     /* Skip if required extensions are not supported. */
939     if (!m_is_tessellation_shader_supported)
940     {
941         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
942     }
943 
944     /* Initialize Utils instance */
945     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
946 
947     m_utils = new TessellationShaderUtils(gl, this);
948 
949     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
950     glw::GLint gl_max_tess_gen_level_value = 0;
951 
952     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
953     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
954 
955     /* Initialize all test runs */
956     const glw::GLint tess_levels[]   = {2, gl_max_tess_gen_level_value / 2, gl_max_tess_gen_level_value};
957     const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]);
958 
959     const _tessellation_shader_vertex_spacing vs_modes[] = {TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
960                                                             TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
961                                                             TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD};
962     const unsigned int n_vs_modes                        = sizeof(vs_modes) / sizeof(vs_modes[0]);
963 
964     for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
965     {
966         _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
967 
968         for (unsigned int n_tess_level = 0; n_tess_level < n_tess_levels; ++n_tess_level)
969         {
970             /* Set up the run descriptor */
971             glw::GLint tess_level = tess_levels[n_tess_level];
972             _run run;
973 
974             run.set1_inner[0] = 1.0f;
975             run.set1_inner[1] = 0.0f;
976             run.set2_inner[1] = 0.0f;
977 
978             TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(vs_mode, 1.5f, gl_max_tess_gen_level_value,
979                                                                             DE_NULL, /* out_clamped */
980                                                                             run.set2_inner);
981             run.set1_outer[0] = (glw::GLfloat)tess_level;
982             run.set2_outer[0] = (glw::GLfloat)tess_level;
983             run.set1_outer[1] = (glw::GLfloat)tess_level;
984             run.set2_outer[1] = (glw::GLfloat)tess_level;
985             run.set1_outer[2] = (glw::GLfloat)tess_level;
986             run.set2_outer[2] = (glw::GLfloat)tess_level;
987             run.set1_outer[3] = (glw::GLfloat)tess_level;
988             run.set2_outer[3] = (glw::GLfloat)tess_level;
989 
990             run.vertex_spacing = vs_mode;
991 
992             /* Retrieve vertex data for both passes */
993             glw::GLint n_set1_vertices = 0;
994             glw::GLint n_set2_vertices = 0;
995 
996             n_set1_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
997                 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set1_inner, run.set1_outer, run.vertex_spacing,
998                 false); /* is_point_mode_enabled */
999             n_set2_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
1000                 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set2_inner, run.set2_outer, run.vertex_spacing,
1001                 false); /* is_point_mode_enabled */
1002 
1003             if (n_set1_vertices == 0)
1004             {
1005                 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1006 
1007                 m_testCtx.getLog() << tcu::TestLog::Message
1008                                    << "No vertices were generated by tessellator for: "
1009                                       "inner tess levels:"
1010                                       "["
1011                                    << run.set1_inner[0] << ", " << run.set1_inner[1]
1012                                    << "]"
1013                                       ", outer tess levels:"
1014                                       "["
1015                                    << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
1016                                    << ", " << run.set1_outer[3]
1017                                    << "]"
1018                                       ", primitive mode: triangles, "
1019                                       "vertex spacing: "
1020                                    << vs_mode_string << tcu::TestLog::EndMessage;
1021 
1022                 TCU_FAIL("Zero vertices were generated by tessellator for first test pass");
1023             }
1024 
1025             if (n_set2_vertices == 0)
1026             {
1027                 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1028 
1029                 m_testCtx.getLog() << tcu::TestLog::Message
1030                                    << "No vertices were generated by tessellator for: "
1031                                       "inner tess levels:"
1032                                       "["
1033                                    << run.set2_inner[0] << ", " << run.set2_inner[1]
1034                                    << "]"
1035                                       ", outer tess levels:"
1036                                       "["
1037                                    << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
1038                                    << ", " << run.set2_outer[3]
1039                                    << "]"
1040                                       ", primitive mode: triangles, "
1041                                       "vertex spacing: "
1042                                    << vs_mode_string << tcu::TestLog::EndMessage;
1043 
1044                 TCU_FAIL("Zero vertices were generated by tessellator for second test pass");
1045             }
1046 
1047             if (n_set1_vertices != n_set2_vertices)
1048             {
1049                 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1050 
1051                 m_testCtx.getLog() << tcu::TestLog::Message
1052                                    << "Amount of vertices generated by the tessellator differs"
1053                                       " for the following inner/outer configs: "
1054                                       "inner tess levels:"
1055                                       "["
1056                                    << run.set1_inner[0] << ", " << run.set1_inner[1]
1057                                    << "]"
1058                                       ", outer tess levels:"
1059                                       "["
1060                                    << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
1061                                    << ", " << run.set1_outer[3]
1062                                    << "]"
1063                                       " and inner tess levels:"
1064                                       "["
1065                                    << run.set2_inner[0] << ", " << run.set2_inner[1]
1066                                    << "]"
1067                                       ", outer tess levels:"
1068                                       "["
1069                                    << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
1070                                    << ", " << run.set2_outer[3]
1071                                    << "]"
1072                                       ", primitive mode: triangles, vertex spacing: "
1073                                    << vs_mode_string << tcu::TestLog::EndMessage;
1074 
1075                 TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes");
1076             }
1077 
1078             run.n_vertices = n_set1_vertices;
1079 
1080             run.set1_data = m_utils->getDataGeneratedByTessellator(run.set1_inner, false, /* is_point_mode_enabled */
1081                                                                    TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
1082                                                                    TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1083                                                                    run.vertex_spacing, run.set1_outer);
1084             run.set2_data = m_utils->getDataGeneratedByTessellator(run.set2_inner, false, /* is_point_mode_enabled */
1085                                                                    TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
1086                                                                    TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1087                                                                    run.vertex_spacing, run.set2_outer);
1088 
1089             /* Store the run data */
1090             m_runs.push_back(run);
1091         } /* for (all sets) */
1092     }     /* for (all vertex spacing modes) */
1093 }
1094 
1095 } /* namespace glcts */
1096