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 "esextcTessellationShaderPoints.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 const unsigned int TessellationShaderPointsgl_PointSize::m_rt_height =
35     16; /* note: update shaders if you change this value */
36 const unsigned int TessellationShaderPointsgl_PointSize::m_rt_width =
37     16; /* note: update shaders if you change this value */
38 
39 /** Constructor
40  *
41  * @param context Test context
42  **/
TessellationShaderPointsTests(glcts::Context & context,const ExtParameters & extParams)43 TessellationShaderPointsTests::TessellationShaderPointsTests(glcts::Context &context, const ExtParameters &extParams)
44     : TestCaseGroupBase(context, extParams, "tessellation_shader_point_mode", "Verifies point mode functionality")
45 {
46     /* No implementation needed */
47 }
48 
49 /**
50  * Initializes test groups for geometry shader tests
51  **/
init(void)52 void TessellationShaderPointsTests::init(void)
53 {
54     addChild(new glcts::TessellationShaderPointsgl_PointSize(m_context, m_extParams));
55     addChild(new glcts::TessellationShaderPointsVerification(m_context, m_extParams));
56 }
57 
58 /** Constructor
59  *
60  * @param context       Test context
61  * @param name          Test case's name
62  * @param description   Test case's desricption
63  **/
TessellationShaderPointsgl_PointSize(Context & context,const ExtParameters & extParams)64 TessellationShaderPointsgl_PointSize::TessellationShaderPointsgl_PointSize(Context &context,
65                                                                            const ExtParameters &extParams)
66     : TestCaseBase(context, extParams, "point_rendering",
67                    "Verifies point size used to render points is taken from"
68                    " the right stage")
69     , m_fbo_id(0)
70     , m_to_id(0)
71     , m_vao_id(0)
72 {
73     /* Left blank on purpose */
74 }
75 
76 /** Deinitializes all ES objects created for the test. */
deinit()77 void TessellationShaderPointsgl_PointSize::deinit()
78 {
79     /** Call base class' deinit() function */
80     TestCaseBase::deinit();
81 
82     if (!m_is_tessellation_shader_supported)
83     {
84         return;
85     }
86 
87     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
88 
89     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
90     {
91         /* Disable point size */
92         gl.disable(GL_PROGRAM_POINT_SIZE);
93     }
94 
95     /* Reset the program object */
96     gl.useProgram(0);
97 
98     /* Revert GL_PATCH_VERTICES_EXT to default value */
99     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
100 
101     /* Unbind vertex array object */
102     gl.bindVertexArray(0);
103 
104     /* Deinitialize test-specific objects */
105     for (_tests_iterator it = m_tests.begin(); it != m_tests.end(); ++it)
106     {
107         const _test_descriptor &test = *it;
108 
109         if (test.fs_id != 0)
110         {
111             gl.deleteShader(test.fs_id);
112         }
113 
114         if (test.gs_id != 0)
115         {
116             gl.deleteShader(test.gs_id);
117         }
118 
119         if (test.po_id != 0)
120         {
121             gl.deleteProgram(test.po_id);
122         }
123 
124         if (test.tes_id != 0)
125         {
126             gl.deleteShader(test.tes_id);
127         }
128 
129         if (test.tcs_id != 0)
130         {
131             gl.deleteShader(test.tcs_id);
132         }
133 
134         if (test.vs_id != 0)
135         {
136             gl.deleteShader(test.vs_id);
137         }
138     }
139     m_tests.clear();
140 
141     if (m_fbo_id != 0)
142     {
143         gl.deleteFramebuffers(1, &m_fbo_id);
144 
145         m_fbo_id = 0;
146     }
147 
148     if (m_to_id != 0)
149     {
150         gl.deleteTextures(1, &m_to_id);
151 
152         m_to_id = 0;
153     }
154 
155     if (m_vao_id != 0)
156     {
157         gl.deleteVertexArrays(1, &m_vao_id);
158 
159         m_vao_id = 0;
160     }
161 }
162 
163 /** Initializes all ES objects that will be used for the test. */
initTest()164 void TessellationShaderPointsgl_PointSize::initTest()
165 {
166     /* The test should only execute if maximum point size is at least 2 */
167     const glw::Functions &gl              = m_context.getRenderContext().getFunctions();
168     glw::GLint gl_max_point_size_value[2] = {0};
169     const int min_max_point_size          = 2;
170 
171     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
172     {
173         gl.getIntegerv(GL_POINT_SIZE_RANGE, gl_max_point_size_value);
174         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_POINT_SIZE_RANGE failed.");
175     }
176     else
177     {
178         gl.getIntegerv(GL_ALIASED_POINT_SIZE_RANGE, gl_max_point_size_value);
179         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_ALIASED_POINT_SIZE_RANGE failed.");
180     }
181 
182     if (gl_max_point_size_value[1] < min_max_point_size)
183     {
184         throw tcu::NotSupportedError("Maximum point size is lower than 2.");
185     }
186 
187     /* The test requires EXT_tessellation_shader, EXT_tessellation_shader_point_size */
188     if (!m_is_tessellation_shader_supported || !m_is_tessellation_shader_point_size_supported)
189     {
190         throw tcu::NotSupportedError("At least one of the required extensions is not supported.");
191     }
192 
193     /* Initialize vertex array object */
194     gl.genVertexArrays(1, &m_vao_id);
195     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
196 
197     gl.bindVertexArray(m_vao_id);
198     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
199 
200     /* Initialize fs+gs+vs test descriptor */
201     if (m_is_geometry_shader_extension_supported)
202     {
203         _test_descriptor pass_fs_gs_tes_vs;
204 
205         /* Configure shader bodies */
206         pass_fs_gs_tes_vs.fs_body = "${VERSION}\n"
207                                     "\n"
208                                     "precision highp float;\n"
209                                     "\n"
210                                     "in  vec4 color;\n"
211                                     "out vec4 result;\n"
212                                     "\n"
213                                     "void main()\n"
214                                     "{\n"
215                                     "    result = color;\n"
216                                     "}\n";
217 
218         pass_fs_gs_tes_vs.gs_body = "${VERSION}\n"
219                                     "\n"
220                                     "${GEOMETRY_SHADER_REQUIRE}\n"
221                                     "${GEOMETRY_POINT_SIZE_REQUIRE}\n"
222                                     "\n"
223                                     "layout(points)                 in;\n"
224                                     "layout(points, max_vertices=5) out;\n"
225                                     "\n"
226                                     "out vec4 color;\n"
227                                     "\n"
228                                     "void main()\n"
229                                     "{\n"
230                                     "    const float point_dx = 2.0 / 16.0 /* rendertarget width */;\n"
231                                     "    const float point_dy = 2.0 / 16.0 /* rendertarget_height */;\n"
232                                     "\n"
233                                     /* Center */
234                                     "    color        = vec4(0.1, 0.2, 0.3, 0.4);\n"
235                                     "    gl_PointSize = 2.0;\n"
236                                     "    gl_Position  = vec4(point_dx + 0.0, point_dy + 0.0, 0.0, 1.0);\n"
237                                     "    EmitVertex();\n"
238                                     "\n"
239                                     /* Top-left corner */
240                                     "    color        = vec4(0.2, 0.3, 0.4, 0.5);\n"
241                                     "    gl_PointSize = 2.0;\n"
242                                     "    gl_Position  = vec4(point_dx - 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
243                                     "    EmitVertex();\n"
244                                     "\n"
245                                     /* Top-right corner */
246                                     "    color        = vec4(0.3, 0.4, 0.5, 0.6);\n"
247                                     "    gl_PointSize = 2.0;\n"
248                                     "    gl_Position  = vec4(-point_dx + 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
249                                     "    EmitVertex();\n"
250                                     "\n"
251                                     /* Bottom-left corner */
252                                     "    color        = vec4(0.4, 0.5, 0.6, 0.7);\n"
253                                     "    gl_PointSize = 2.0;\n"
254                                     "    gl_Position  = vec4(point_dx - 1.0, point_dy - 1.0, 0.0, 1.0);\n"
255                                     "    EmitVertex();\n"
256                                     "\n"
257                                     /* Bottom-right corner */
258                                     "    color        = vec4(0.5, 0.6, 0.7, 0.8);\n"
259                                     "    gl_PointSize = 2.0;\n"
260                                     "    gl_Position  = vec4(-point_dx + 1.0, point_dy - 1.0, 0.0, 1.0);\n"
261                                     "    EmitVertex();\n"
262                                     "\n"
263                                     "}\n";
264 
265         pass_fs_gs_tes_vs.tes_body = "${VERSION}\n"
266                                      "\n"
267                                      "${TESSELLATION_SHADER_REQUIRE}\n"
268                                      "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
269                                      "\n"
270                                      "layout(isolines, point_mode) in;\n"
271                                      "\n"
272                                      "void main()\n"
273                                      "{\n"
274                                      "    gl_PointSize = 0.1;\n"
275                                      "}\n";
276 
277         pass_fs_gs_tes_vs.tcs_body = "${VERSION}\n"
278                                      "\n"
279                                      "${TESSELLATION_SHADER_REQUIRE}\n"
280                                      "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
281                                      "\n"
282                                      "layout(vertices=1) out;\n"
283                                      "\n"
284                                      "void main()\n"
285                                      "{\n"
286                                      "    gl_out[gl_InvocationID].gl_Position =\n"
287                                      "        gl_in[gl_InvocationID].gl_Position;\n"
288                                      "    gl_out[gl_InvocationID].gl_PointSize =\n"
289                                      "        gl_in[gl_InvocationID].gl_PointSize;\n"
290                                      "\n"
291                                      "    gl_TessLevelOuter[0] = 1.0;\n"
292                                      "    gl_TessLevelOuter[1] = 1.0;\n"
293                                      "    gl_TessLevelOuter[2] = 1.0;\n"
294                                      "    gl_TessLevelOuter[3] = 1.0;\n"
295                                      "    gl_TessLevelInner[0] = 1.0;\n"
296                                      "    gl_TessLevelInner[1] = 1.0;\n"
297                                      "}\n";
298 
299         pass_fs_gs_tes_vs.vs_body = "${VERSION}\n"
300                                     "\n"
301                                     "void main()\n"
302                                     "{\n"
303                                     "    gl_PointSize = 0.01;\n"
304                                     "}\n";
305 
306         pass_fs_gs_tes_vs.draw_call_count = 1;
307 
308         /* Store the descriptor in a vector that will be used by iterate() */
309         m_tests.push_back(pass_fs_gs_tes_vs);
310     } /* if (m_is_geometry_shader_extension_supported) */
311 
312     /* Initialize fs+te+vs test descriptor */
313     if (m_is_tessellation_shader_supported)
314     {
315         _test_descriptor pass_fs_tes_vs;
316 
317         /* Configure shader bodies */
318         pass_fs_tes_vs.fs_body = "${VERSION}\n"
319                                  "\n"
320                                  "precision highp float;\n"
321                                  "\n"
322                                  "in  vec4 result_color;\n"
323                                  "out vec4 result;\n"
324                                  "\n"
325                                  "void main()\n"
326                                  "{\n"
327                                  "    result = result_color;\n"
328                                  "}\n";
329 
330         pass_fs_tes_vs.tes_body = "${VERSION}\n"
331                                   "\n"
332                                   "${TESSELLATION_SHADER_REQUIRE}\n"
333                                   "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
334                                   "\n"
335                                   "layout(isolines, point_mode) in;\n"
336                                   "\n"
337                                   "in  vec4 tcColor[];\n"
338                                   "out vec4 result_color;\n"
339                                   "\n"
340                                   "void main()\n"
341                                   "{\n"
342                                   "    gl_PointSize = 2.0;\n"
343                                   "    gl_Position  = gl_in[0].gl_Position;\n"
344                                   "    result_color = tcColor[0];\n"
345                                   "}\n";
346 
347         pass_fs_tes_vs.tcs_body = "${VERSION}\n"
348                                   "\n"
349                                   "${TESSELLATION_SHADER_REQUIRE}\n"
350                                   "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
351                                   "\n"
352                                   "layout(vertices=1) out;\n"
353                                   "\n"
354                                   "in  vec4 color[];\n"
355                                   "out vec4 tcColor[];\n"
356                                   "\n"
357                                   "void main()\n"
358                                   "{\n"
359                                   "    tcColor[gl_InvocationID] = color[gl_InvocationID];\n"
360                                   "    gl_out[gl_InvocationID].gl_Position =\n"
361                                   "        gl_in[gl_InvocationID].gl_Position;\n"
362                                   "    gl_out[gl_InvocationID].gl_PointSize =\n"
363                                   "        gl_in[gl_InvocationID].gl_PointSize;\n"
364                                   "\n"
365                                   "    gl_TessLevelOuter[0] = 1.0;\n"
366                                   "    gl_TessLevelOuter[1] = 1.0;\n"
367                                   "    gl_TessLevelOuter[2] = 1.0;\n"
368                                   "    gl_TessLevelOuter[3] = 1.0;\n"
369                                   "    gl_TessLevelInner[0] = 1.0;\n"
370                                   "    gl_TessLevelInner[1] = 1.0;\n"
371                                   "}\n";
372 
373         pass_fs_tes_vs.vs_body = "${VERSION}\n"
374                                  "\n"
375                                  "out vec4 color;\n"
376                                  "\n"
377                                  "void main()\n"
378                                  "{\n"
379                                  "    const float point_dx = 2.0 / 16.0 /* rendertarget width */;\n"
380                                  "    const float point_dy = 2.0 / 16.0 /* rendertarget_height */;\n"
381                                  "\n"
382                                  "    gl_PointSize = 0.1;\n"
383                                  "\n"
384                                  "    switch (gl_VertexID)\n"
385                                  "    {\n"
386                                  "        case 0:\n"
387                                  "        {\n"
388                                  /* Center */
389                                  "            color       = vec4(0.1, 0.2, 0.3, 0.4);\n"
390                                  "            gl_Position = vec4(point_dx + 0.0, point_dy + 0.0, 0.0, 1.0);\n"
391                                  "\n"
392                                  "            break;\n"
393                                  "        }\n"
394                                  "\n"
395                                  "        case 1:\n"
396                                  "        {\n"
397                                  /* Top-left corner */
398                                  "            color       = vec4(0.2, 0.3, 0.4, 0.5);\n"
399                                  "            gl_Position = vec4(point_dx - 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
400                                  "\n"
401                                  "            break;\n"
402                                  "        }\n"
403                                  "\n"
404                                  "        case 2:\n"
405                                  "        {\n"
406                                  /* Top-right corner */
407                                  "            color       = vec4(0.3, 0.4, 0.5, 0.6);\n"
408                                  "            gl_Position = vec4(-point_dx + 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
409                                  "\n"
410                                  "            break;\n"
411                                  "        }\n"
412                                  "\n"
413                                  "        case 3:\n"
414                                  "        {\n"
415                                  /* Bottom-left corner */
416                                  "            color       = vec4(0.4, 0.5, 0.6, 0.7);\n"
417                                  "            gl_Position = vec4(point_dx - 1.0, point_dy - 1.0, 0.0, 1.0);\n"
418                                  "\n"
419                                  "            break;\n"
420                                  "        }\n"
421                                  "\n"
422                                  "        case 4:\n"
423                                  "        {\n"
424                                  /* Bottom-right corner */
425                                  "            color       = vec4(0.5, 0.6, 0.7, 0.8);\n"
426                                  "            gl_Position = vec4(-point_dx + 1.0, point_dy - 1.0, 0.0, 1.0);\n"
427                                  "\n"
428                                  "            break;\n"
429                                  "        }\n"
430                                  "    }\n"
431                                  "}\n";
432 
433         pass_fs_tes_vs.draw_call_count = 5; /* points in total */
434 
435         /* Store the descriptor in a vector that will be used by iterate() */
436         m_tests.push_back(pass_fs_tes_vs);
437     } /* if (m_is_tessellation_shader_supported) */
438 
439     /* Set up a color texture we will be rendering to */
440     gl.genTextures(1, &m_to_id);
441     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed");
442 
443     gl.bindTexture(GL_TEXTURE_2D, m_to_id);
444     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
445 
446     gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, m_rt_width, m_rt_height);
447     GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() failed");
448 
449     /* Set up a FBO we'll use for rendering */
450     gl.genFramebuffers(1, &m_fbo_id);
451     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() failed");
452 
453     gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
454     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() failed");
455 
456     gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
457     GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() failed");
458 
459     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
460     {
461         /* Enable point size */
462         gl.enable(GL_PROGRAM_POINT_SIZE);
463     }
464 
465     /* We're good to execute the test! */
466 }
467 
468 /** Executes the test.
469  *
470  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
471  *
472  *  Note the function throws exception should an error occur!
473  *
474  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
475  **/
iterate(void)476 tcu::TestNode::IterateResult TessellationShaderPointsgl_PointSize::iterate(void)
477 {
478     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
479 
480     initTest();
481 
482     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
483     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed");
484 
485     /* Iterate through all test descriptors.. */
486     for (_tests_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++)
487     {
488         _test_descriptor &test = *test_iterator;
489 
490         /* Generate all shader objects we'll need */
491         if (test.fs_body != NULL)
492         {
493             test.fs_id = gl.createShader(GL_FRAGMENT_SHADER);
494         }
495 
496         if (test.gs_body != NULL)
497         {
498             test.gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
499         }
500 
501         if (test.tes_body != NULL)
502         {
503             test.tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
504         }
505 
506         if (test.tcs_body != NULL)
507         {
508             test.tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
509         }
510 
511         if (test.vs_body != NULL)
512         {
513             test.vs_id = gl.createShader(GL_VERTEX_SHADER);
514         }
515         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
516 
517         /* Generate a test program object before we continue */
518         test.po_id = gl.createProgram();
519         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed");
520 
521         bool link_success =
522             buildProgram(test.po_id, test.fs_id, test.fs_id ? 1 : 0, &test.fs_body, test.gs_id, test.gs_id ? 1 : 0,
523                          &test.gs_body, test.tes_id, test.tes_id ? 1 : 0, &test.tes_body, test.tcs_id,
524                          test.tcs_id ? 1 : 0, &test.tcs_body, test.vs_id, test.vs_id ? 1 : 0, &test.vs_body);
525 
526         if (!link_success)
527         {
528             TCU_FAIL("Program linking failed");
529         }
530 
531         /* Prepare for rendering */
532         gl.clearColor(0.0f /* red */, 0.0f /* green */, 0.0f /* blue */, 0.0f /* alpha */);
533         GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() failed");
534 
535         gl.clear(GL_COLOR_BUFFER_BIT);
536         GLU_EXPECT_NO_ERROR(gl.getError(), "glClear(GL_COLOR_BUFFER_BIT) failed");
537 
538         gl.viewport(0 /* x */, 0 /* x */, m_rt_width, m_rt_height);
539         GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() failed");
540 
541         gl.useProgram(test.po_id);
542         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
543 
544         /* Render */
545         gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, test.draw_call_count);
546         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
547 
548         /* Read back the rendered data */
549         unsigned char buffer[m_rt_width * m_rt_height * 4 /* components */] = {0};
550 
551         gl.readPixels(0, /* x */
552                       0, /* y */
553                       m_rt_width, m_rt_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
554         GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() failed");
555 
556         /* Verify all 5 points were rendered correctly */
557         const float epsilon           = (float)1.0f / 255.0f;
558         const unsigned int pixel_size = 4; /* components, GL_UNSIGNED_BYTE */
559         const float point_data[]      = {
560             /* x */ /* y */ /* r */ /* g */ /* b */ /* a */
561             0.5f,
562             0.5f,
563             0.1f,
564             0.2f,
565             0.3f,
566             0.4f, /* center */
567             0.0f,
568             1.0f,
569             0.2f,
570             0.3f,
571             0.4f,
572             0.5f, /* top-left */
573             1.0f,
574             1.0f,
575             0.3f,
576             0.4f,
577             0.5f,
578             0.6f, /* top-right */
579             0.0f,
580             0.0f,
581             0.4f,
582             0.5f,
583             0.6f,
584             0.7f, /* bottom-left */
585             1.0f,
586             0.0f,
587             0.5f,
588             0.6f,
589             0.7f,
590             0.8f /* bottom-right */
591         };
592         const unsigned int row_size           = pixel_size * m_rt_width;
593         const unsigned int n_fields_per_point = 6;
594         const unsigned int n_points           = sizeof(point_data) / sizeof(point_data[0]) / n_fields_per_point;
595 
596         for (unsigned int n_point = 0; n_point < n_points; ++n_point)
597         {
598             int x = (int)(point_data[n_point * n_fields_per_point + 0] * float(m_rt_width - 1) + 0.5f);
599             int y = (int)(point_data[n_point * n_fields_per_point + 1] * float(m_rt_height - 1) + 0.5f);
600             float expected_color_r = point_data[n_point * n_fields_per_point + 2];
601             float expected_color_g = point_data[n_point * n_fields_per_point + 3];
602             float expected_color_b = point_data[n_point * n_fields_per_point + 4];
603             float expected_color_a = point_data[n_point * n_fields_per_point + 5];
604 
605             const unsigned char *rendered_color_ubyte_ptr = buffer + row_size * y + x * pixel_size;
606             const float rendered_color_r                  = float(rendered_color_ubyte_ptr[0]) / 255.0f;
607             const float rendered_color_g                  = float(rendered_color_ubyte_ptr[1]) / 255.0f;
608             const float rendered_color_b                  = float(rendered_color_ubyte_ptr[2]) / 255.0f;
609             const float rendered_color_a                  = float(rendered_color_ubyte_ptr[3]) / 255.0f;
610 
611             /* Compare the pixels */
612             if (de::abs(expected_color_r - rendered_color_r) > epsilon ||
613                 de::abs(expected_color_g - rendered_color_g) > epsilon ||
614                 de::abs(expected_color_b - rendered_color_b) > epsilon ||
615                 de::abs(expected_color_a - rendered_color_a) > epsilon)
616             {
617                 m_testCtx.getLog() << tcu::TestLog::Message << "Pixel data comparison failed; expected: "
618                                    << "(" << expected_color_r << ", " << expected_color_g << ", " << expected_color_b
619                                    << ", " << expected_color_a << ") rendered: "
620                                    << "(" << rendered_color_r << ", " << rendered_color_g << ", " << rendered_color_b
621                                    << ", " << rendered_color_a << ") epsilon: " << epsilon << tcu::TestLog::EndMessage;
622 
623                 TCU_FAIL("Pixel data comparison failed");
624             }
625         } /* for (all points) */
626     }     /* for (all tests) */
627 
628     /* All done */
629     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
630     return STOP;
631 }
632 
633 /** Constructor
634  *
635  * @param context Test context
636  **/
TessellationShaderPointsVerification(Context & context,const ExtParameters & extParams)637 TessellationShaderPointsVerification::TessellationShaderPointsVerification(Context &context,
638                                                                            const ExtParameters &extParams)
639     : TestCaseBase(context, extParams, "points_verification",
640                    "Verifies points generated by the tessellator unit do not duplicate "
641                    "and that their amount is correct")
642     , m_utils(DE_NULL)
643     , m_vao_id(0)
644 {
645     /* Left blank on purpose */
646 }
647 
648 /* Deinitializes all ES Instances generated for the test */
deinit()649 void TessellationShaderPointsVerification::deinit()
650 {
651     /* Call base class' deinit() */
652     TestCaseBase::deinit();
653 
654     if (!m_is_tessellation_shader_supported)
655     {
656         return;
657     }
658 
659     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
660 
661     /* Unbind vertex array object */
662     gl.bindVertexArray(0);
663 
664     /* Delete utils instances */
665     if (m_utils != DE_NULL)
666     {
667         delete m_utils;
668 
669         m_utils = DE_NULL;
670     }
671 
672     /* Delete vertex array object */
673     if (m_vao_id != 0)
674     {
675         gl.deleteVertexArrays(1, &m_vao_id);
676 
677         m_vao_id = 0;
678     }
679 }
680 
681 /** Initializes ES objects necessary to run the test. */
initTest()682 void TessellationShaderPointsVerification::initTest()
683 {
684     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
685 
686     /* Skip if required extensions are not supported. */
687     if (!m_is_tessellation_shader_supported)
688     {
689         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
690     }
691 
692     /* Initialize and bind vertex array object */
693     gl.genVertexArrays(1, &m_vao_id);
694     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
695 
696     gl.bindVertexArray(m_vao_id);
697     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
698 
699     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
700     glw::GLint gl_max_tess_gen_level_value = 0;
701 
702     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
703     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
704 
705     /* Initialize all test iterations */
706     const _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
707                                                             TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
708                                                             TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
709     const unsigned int n_primitive_modes                 = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
710 
711     const _tessellation_shader_vertex_spacing vertex_spacings[] = {
712         TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD,
713         TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
714         TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
715     };
716     const unsigned int n_vertex_spacings = sizeof(vertex_spacings) / sizeof(vertex_spacings[0]);
717 
718     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
719     {
720         _tessellation_levels_set levels_set;
721         _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
722 
723         levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
724             primitive_mode, gl_max_tess_gen_level_value,
725             TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES);
726 
727         for (unsigned int n_vertex_spacing = 0; n_vertex_spacing < n_vertex_spacings; ++n_vertex_spacing)
728         {
729             _tessellation_shader_vertex_spacing vertex_spacing = vertex_spacings[n_vertex_spacing];
730 
731             for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin();
732                  levels_set_iterator != levels_set.end(); levels_set_iterator++)
733             {
734                 const _tessellation_levels &levels = *levels_set_iterator;
735 
736                 /* Skip border cases that this test cannot handle */
737                 if ((primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS ||
738                      primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) &&
739                     vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD &&
740                     (levels.inner[0] <= 1 || levels.inner[1] <= 1))
741                 {
742                     continue;
743                 }
744 
745                 /* Initialize a test run descriptor for the iteration-specific properties */
746                 _run run;
747 
748                 memcpy(run.inner, levels.inner, sizeof(run.inner));
749                 memcpy(run.outer, levels.outer, sizeof(run.outer));
750 
751                 run.primitive_mode = primitive_mode;
752                 run.vertex_spacing = vertex_spacing;
753 
754                 m_runs.push_back(run);
755             } /* for (all level sets) */
756         }     /* for (all vertex spacing modes) */
757     }         /* for (all primitive modes) */
758 
759     /* Initialize utils instance.
760      */
761     m_utils = new TessellationShaderUtils(gl, this);
762 }
763 
764 /** Executes the test.
765  *
766  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
767  *
768  *  Note the function throws exception should an error occur!
769  *
770  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
771  **/
iterate(void)772 tcu::TestNode::IterateResult TessellationShaderPointsVerification::iterate(void)
773 {
774     initTest();
775 
776     /* Do not execute if required extensions are not supported. */
777     if (!m_is_tessellation_shader_supported)
778     {
779         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
780     }
781 
782     /* Iterate through all the test descriptors */
783     for (std::vector<_run>::const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
784     {
785         const _run &run = *run_iterator;
786         std::vector<char> run_data;
787         unsigned int run_n_vertices = 0;
788 
789         run_data = m_utils->getDataGeneratedByTessellator(run.inner, true, /* point_mode */
790                                                           run.primitive_mode, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
791                                                           run.vertex_spacing, run.outer);
792 
793         run_n_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(run.primitive_mode, run.inner, run.outer,
794                                                                             run.vertex_spacing, true); /* point_mode */
795 
796         /* First, make sure a valid amount of duplicate vertices was found for a single data set */
797         verifyCorrectAmountOfDuplicateVertices(run, &run_data[0], run_n_vertices);
798 
799         /* Now, verify that amount of generated vertices is correct, given
800          * tessellation shader stage configuration */
801         verifyCorrectAmountOfVertices(run, &run_data[0], run_n_vertices);
802     } /* for (all tests) */
803 
804     /* All done */
805     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
806     return STOP;
807 }
808 
809 /** Verifies that a correct amount of vertices was generated, given test iteration-specific properties.
810  *  Throws a TestError exception in if an incorrect amount of vertices was generated by the tessellator.
811  *
812  *  @param run            Run descriptor.
813  *  @param run_data       Data generated for the run.
814  *  @param run_n_vertices Amount of vertices present at @param run_data.
815  */
verifyCorrectAmountOfVertices(const _run & run,const void * run_data,unsigned int run_n_vertices)816 void TessellationShaderPointsVerification::verifyCorrectAmountOfVertices(const _run &run, const void *run_data,
817                                                                          unsigned int run_n_vertices)
818 {
819     (void)run_data;
820 
821     const float epsilon                = 1e-5f;
822     const glw::Functions &gl           = m_context.getRenderContext().getFunctions();
823     unsigned int n_expected_vertices   = 0;
824     float post_vs_inner_tess_levels[2] = {0.0f};
825     float post_vs_outer_tess_levels[4] = {0.0f};
826 
827     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value*/
828     glw::GLint gl_max_tess_gen_level_value = 0;
829 
830     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
831     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
832 
833     /* Determine vertex spacing that the tessellator should have used for current primitive mode */
834     glw::GLfloat actual_inner_levels[2]                = {0.0f};
835     _tessellation_shader_vertex_spacing actual_vs_mode = run.vertex_spacing;
836     glw::GLfloat clamped_inner_levels[2]               = {0.0f};
837 
838     memcpy(actual_inner_levels, run.inner, sizeof(run.inner));
839 
840     TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
841         run.vertex_spacing, actual_inner_levels[0], gl_max_tess_gen_level_value, clamped_inner_levels + 0,
842         DE_NULL); /* out_clamped_and_rounded */
843 
844     TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
845         run.vertex_spacing, actual_inner_levels[1], gl_max_tess_gen_level_value, clamped_inner_levels + 1,
846         DE_NULL); /* out_clamped_and_rounded */
847 
848     if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
849     {
850         /* For isolines tessellation, outer[1] is subdivided as per specified vertex spacing as specified.
851          * outer[0] should be subdivided using equal vertex spacing.
852          *
853          * This is owing to the following language in the spec (* marks important subtleties):
854          *
855          * The *u==0* and *u==1* edges of the rectangle are subdivided according to the first outer
856          * tessellation level. For the purposes of *this* subdivision, the tessellation spacing mode
857          * is ignored and treated as "equal_spacing".
858          */
859         TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
860                                                                         run.outer[0], gl_max_tess_gen_level_value,
861                                                                         DE_NULL, /* out_clamped */
862                                                                         post_vs_outer_tess_levels);
863 
864         TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
865             actual_vs_mode, run.outer[1], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
866             post_vs_outer_tess_levels + 1);
867     }
868 
869     if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS)
870     {
871         /* As per extension spec:
872          *
873          * if either clamped inner tessellation level is one, that tessellation level
874          * is treated as though it were originally specified as 1+epsilon, which would
875          * rounded up to result in a two- or three-segment subdivision according to the
876          * tessellation spacing.
877          *
878          **/
879         if (de::abs(clamped_inner_levels[0] - 1.0f) < epsilon)
880         {
881             TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
882                 run.vertex_spacing, clamped_inner_levels[0] + 1.0f, /* epsilon */
883                 gl_max_tess_gen_level_value, DE_NULL,               /* out_clamped */
884                 actual_inner_levels + 0);
885         }
886 
887         if (de::abs(clamped_inner_levels[1] - 1.0f) < epsilon)
888         {
889             TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
890                 run.vertex_spacing, clamped_inner_levels[1] + 1.0f, /* epsilon */
891                 gl_max_tess_gen_level_value, DE_NULL,               /* out_clamped */
892                 actual_inner_levels + 1);
893         }
894     }
895 
896     /* Retrieve tessellation level values, taking vertex spacing setting into account */
897     for (int n = 0; n < 2 /* inner tessellation level values */; ++n)
898     {
899         TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
900             actual_vs_mode, actual_inner_levels[n], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
901             post_vs_inner_tess_levels + n);
902     }
903 
904     if (run.primitive_mode != TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
905     {
906         for (int n = 0; n < 4 /* outer tessellation level values */; ++n)
907         {
908             TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
909                 actual_vs_mode, run.outer[n], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
910                 post_vs_outer_tess_levels + n);
911         }
912     }
913 
914     /* Calculate amount of vertices that should be generated in point mode */
915     switch (run.primitive_mode)
916     {
917     case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
918     {
919         n_expected_vertices = int(post_vs_outer_tess_levels[0]) * int(post_vs_outer_tess_levels[1] + 1);
920 
921         break;
922     }
923 
924     case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
925     {
926         n_expected_vertices = /* outer quad */
927             int(post_vs_outer_tess_levels[0]) + int(post_vs_outer_tess_levels[1]) + int(post_vs_outer_tess_levels[2]) +
928             int(post_vs_outer_tess_levels[3]) +
929             /* inner quad */
930             (int(post_vs_inner_tess_levels[0]) - 1) * (int(post_vs_inner_tess_levels[1]) - 1);
931 
932         break;
933     }
934 
935     case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
936     {
937         /* If the first inner tessellation level and all three outer tessellation
938          * levels are exactly one after clamping and rounding, only a single triangle
939          * with (u,v,w) coordinates of (0,0,1), (1,0,0), and (0,1,0) is generated.
940          */
941         if (de::abs(run.inner[0] - 1.0f) < epsilon && de::abs(run.outer[0] - 1.0f) < epsilon &&
942             de::abs(run.outer[1] - 1.0f) < epsilon && de::abs(run.outer[2] - 1.0f) < epsilon)
943         {
944             n_expected_vertices = 3;
945         }
946         else
947         {
948             /* If the inner tessellation level is one and any of the outer tessellation
949              * levels is greater than one, the inner tessellation level is treated as
950              * though it were originally specified as 1+epsilon and will be rounded up to
951              * result in a two- or three-segment subdivision according to the
952              * tessellation spacing.
953              */
954             if (de::abs(run.inner[0] - 1.0f) < epsilon &&
955                 (run.outer[0] > 1.0f || run.outer[1] > 1.0f || run.outer[2] > 1.0f))
956             {
957                 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
958                     run.vertex_spacing, 2.0f, gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
959                     post_vs_inner_tess_levels);
960             }
961 
962             /* Count vertices making up concentric inner triangles */
963             n_expected_vertices = (int)post_vs_outer_tess_levels[0] + (int)post_vs_outer_tess_levels[1] +
964                                   (int)post_vs_outer_tess_levels[2];
965 
966             for (int n = (int)post_vs_inner_tess_levels[0]; n >= 0; n -= 2)
967             {
968                 /* For the outermost inner triangle, the inner triangle is degenerate -
969                  * a single point at the center of the triangle -- if <n> is two.
970                  */
971                 if (n == 2)
972                 {
973                     n_expected_vertices++; /* degenerate vertex */
974 
975                     break;
976                 }
977 
978                 /* If <n> is three, the edges of the inner triangle are not subdivided and is
979                  * the final triangle in the set of concentric triangles.
980                  */
981                 if (n == 3)
982                 {
983                     n_expected_vertices += 3 /* vertices per triangle */;
984 
985                     break;
986                 }
987 
988                 /* Otherwise, each edge of the inner triangle is divided into <n>-2 segments,
989                  * with the <n>-1 vertices of this subdivision produced by intersecting the
990                  * inner edge with lines perpendicular to the edge running through the <n>-1
991                  * innermost vertices of the subdivision of the outer edge.
992                  */
993                 if (n >= 2)
994                 {
995                     n_expected_vertices += (n - 2) * 3 /* triangle edges */;
996                 }
997                 else
998                 {
999                     /* Count in the degenerate point instead */
1000                     n_expected_vertices++;
1001                 }
1002             } /* for (all inner triangles) */
1003         }
1004 
1005         break;
1006     }
1007 
1008     default:
1009     {
1010         TCU_FAIL("Unrecognized primitive mode");
1011     }
1012     } /* switch (test.primitive_mode) */
1013 
1014     /* Compare two values */
1015     if (run_n_vertices != n_expected_vertices)
1016     {
1017         std::string primitive_mode = TessellationShaderUtils::getESTokenForPrimitiveMode(run.primitive_mode);
1018         std::string vertex_spacing = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
1019 
1020         m_testCtx.getLog() << tcu::TestLog::Message << run_n_vertices
1021                            << " vertices were generated by the tessellator instead of expected " << n_expected_vertices
1022                            << " for primitive mode [" << primitive_mode << "], vertex spacing mode [" << vertex_spacing
1023                            << "], inner tessellation levels:[" << run.inner[0] << ", " << run.inner[1]
1024                            << "], outer tessellation levels:[" << run.outer[0] << ", " << run.outer[1] << ", "
1025                            << run.outer[2] << ", " << run.outer[3] << "], point mode enabled."
1026                            << tcu::TestLog::EndMessage;
1027 
1028         TCU_FAIL("Amount of vertices generated in point mode was incorrect");
1029     } /* if (test.n_vertices != n_expected_vertices) */
1030 }
1031 
1032 /** Verifies a valid amount of duplicate vertices is present in the set of coordinates
1033  *  generated by the tessellator, as described by user-provided test iteration descriptor.
1034  *  Throws a TestError exception if the vertex set does not meet the requirements.
1035  *
1036  *  @param test           Test iteration descriptor.
1037  *  @param run_data       Data generated for the run.
1038  *  @param run_n_vertices Amount of vertices present at @param run_data.
1039  **/
verifyCorrectAmountOfDuplicateVertices(const _run & run,const void * run_data,unsigned int run_n_vertices)1040 void TessellationShaderPointsVerification::verifyCorrectAmountOfDuplicateVertices(const _run &run, const void *run_data,
1041                                                                                   unsigned int run_n_vertices)
1042 {
1043     const float epsilon               = 1e-5f;
1044     unsigned int n_duplicate_vertices = 0;
1045 
1046     for (unsigned int n_vertex_a = 0; n_vertex_a < run_n_vertices; ++n_vertex_a)
1047     {
1048         const float *vertex_a = (const float *)run_data + n_vertex_a * 3; /* components */
1049 
1050         for (unsigned int n_vertex_b = n_vertex_a + 1; n_vertex_b < run_n_vertices; ++n_vertex_b)
1051         {
1052             const float *vertex_b = (const float *)run_data + n_vertex_b * 3; /* components */
1053 
1054             if (de::abs(vertex_a[0] - vertex_b[0]) < epsilon && de::abs(vertex_a[1] - vertex_b[1]) < epsilon &&
1055                 de::abs(vertex_a[2] - vertex_b[2]) < epsilon)
1056             {
1057                 n_duplicate_vertices++;
1058             }
1059         } /* for (all vertices) */
1060     }     /* for (all vertices) */
1061 
1062     if (n_duplicate_vertices != 0)
1063     {
1064         std::string vertex_spacing = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
1065 
1066         m_testCtx.getLog() << tcu::TestLog::Message
1067                            << "Duplicate vertices found for the following tesselelation"
1068                               " configuration: tessellation level:"
1069                               "["
1070                            << run.inner[0] << ", " << run.inner[1]
1071                            << "], "
1072                               "outer tessellation level:"
1073                               " ["
1074                            << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", " << run.outer[3]
1075                            << "], "
1076                            << "vertex spacing mode:[" << vertex_spacing.c_str() << "]" << tcu::TestLog::EndMessage;
1077 
1078         TCU_FAIL("Duplicate vertex found");
1079     }
1080 }
1081 
1082 } /* namespace glcts */
1083