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 "esextcTessellationShaderTessellation.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30 #include <cstdlib>
31 
32 namespace glcts
33 {
34 
35 /** Vertex shader source code for max_in_out_attributes test. */
36 const char *TessellationShaderTessellationMaxInOut::m_vs_code =
37     "${VERSION}\n"
38     "\n"
39     "${TESSELLATION_SHADER_REQUIRE}\n"
40     "${SHADER_IO_BLOCKS_ENABLE}\n"
41     "\n"
42     "precision highp float;\n"
43     "\n"
44     "layout(location = 0) in vec4 in_fv;\n"
45     "\n"
46     "out Vertex\n"
47     "{\n"
48     "    /* Note: we need to leave some space for gl_Position */\n"
49     "    vec4 value[(gl_MaxTessControlInputComponents) / 4 - 1];\n"
50     "} outVertex;\n"
51     "\n"
52     "void main()\n"
53     "{\n"
54     "    gl_Position = in_fv;\n"
55     "\n"
56     "    for (int i = 0 ; i < (gl_MaxTessControlInputComponents - "
57     "4) / 4 ; i++)\n" /* Max vec4 output attributes - gl_Position */
58     "    {\n"
59     "        outVertex.value[i] = vec4(float(4*i), float(4*i) + "
60     "1.0, float(4*i) + 2.0, float(4*i) + 3.0);\n"
61     "    }\n"
62     "}\n";
63 
64 /* Tessellation Control Shader code for max_in_out_attributes test */
65 const char *TessellationShaderTessellationMaxInOut::m_tcs_code_1 =
66     "${VERSION}\n"
67     "\n"
68     "${TESSELLATION_SHADER_REQUIRE}\n"
69     "\n"
70     "precision highp float;\n"
71     "\n"
72     "layout(vertices = 2) out;\n"
73     "\n"
74     "in Vertex\n"
75     "{\n"
76     "    /* Note: we need to leave some space for gl_Position */\n"
77     "    vec4 value[(gl_MaxTessControlInputComponents - 4) / 4];\n"
78     "} inVertex[];\n"
79     "\n"
80     "out Vertex\n"
81     "{\n"
82     "    /* Note: we need to leave some space for gl_Position */\n"
83     "    vec4 value[(gl_MaxTessControlOutputComponents - 4) / 4];\n"
84     "} outVariables[];\n"
85     "\n"
86     "void main()\n"
87     "{\n"
88     "    gl_TessLevelInner[0] = 1.0;\n"
89     "    gl_TessLevelInner[1] = 1.0;\n"
90     "    gl_TessLevelOuter[0] = 1.0;\n"
91     "    gl_TessLevelOuter[1] = 1.0;\n"
92     "    gl_TessLevelOuter[2] = 1.0;\n"
93     "    gl_TessLevelOuter[3] = 1.0;\n"
94     "\n"
95     "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
96     "\n"
97     "    for (int j = 0; j < (gl_MaxTessControlOutputComponents - 4) / 4; j++)\n"
98     "    {\n"
99     "        outVariables[gl_InvocationID].value[j] = vec4(float(4*j), float(4*j) + 1.0, float(4*j) + 2.0, float(4*j) "
100     "+ 3.0);\n"
101     "\n"
102     "        for (int i = 0; i < (gl_MaxTessControlInputComponents-4)/4; i++)\n"
103     "        {\n"
104     "            outVariables[gl_InvocationID].value[j] += inVertex[gl_InvocationID].value[i];\n"
105     "        }\n"
106     "    }\n"
107     "}\n";
108 
109 /* Tessellation Control Shader code for max_in_out_attributes test */
110 const char *TessellationShaderTessellationMaxInOut::m_tcs_code_2 =
111     "${VERSION}\n"
112     "\n"
113     "${TESSELLATION_SHADER_REQUIRE}\n"
114     "\n"
115     "precision highp float;\n"
116     "\n"
117     "layout(vertices = 2) out;\n"
118     "\n"
119     "patch out vec4 value[gl_MaxTessPatchComponents/4];\n"
120     "\n"
121     "void main()\n"
122     "{\n"
123     "    gl_TessLevelInner[0] = 1.0;\n"
124     "    gl_TessLevelInner[1] = 1.0;\n"
125     "    gl_TessLevelOuter[0] = 1.0;\n"
126     "    gl_TessLevelOuter[1] = 1.0;\n"
127     "    gl_TessLevelOuter[2] = 1.0;\n"
128     "    gl_TessLevelOuter[3] = 1.0;\n"
129     "\n"
130     "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
131     "\n"
132     "    for (int j = 0; j < gl_MaxTessPatchComponents / 4; j++)\n"
133     "    {\n"
134     "        value[j] = vec4(float(4*j), float(4*j) + 1.0, float(4*j) + 2.0, float(4*j) + 3.0);\n"
135     "    }\n"
136     "}\n";
137 
138 /* Tessellation Evaluation Shader code for max_in_out_attributes test */
139 const char *TessellationShaderTessellationMaxInOut::m_tes_code_1 =
140     "${VERSION}\n"
141     "\n"
142     "${TESSELLATION_SHADER_REQUIRE}\n"
143     "\n"
144     "precision highp float;\n"
145     "\n"
146     "layout (isolines, point_mode) in;\n"
147     "\n"
148     "in Vertex\n"
149     "{\n"
150     "    vec4 value[(gl_MaxTessEvaluationInputComponents - 4) / 4];\n"
151     "} inVariables[];\n"
152     "\n"
153     "out Vertex\n"
154     "{\n"
155     "    vec4 value[(gl_MaxTessEvaluationOutputComponents - 4) / 4];\n"
156     "} outVariables;\n"
157     "\n"
158     "void main()\n"
159     "{\n"
160     "    gl_Position = gl_in[0].gl_Position;\n"
161     "\n"
162     "    for (int j = 0; j < (gl_MaxTessEvaluationOutputComponents - 4) / 4; j++)\n"
163     "    {\n"
164     "        outVariables.value[j] = vec4(float(4*j), float(4*j) + 1.0, float(4*j) + 2.0, float(4*j) + 3.0);\n"
165     "\n"
166     "        for (int i = 0 ; i < (gl_MaxTessEvaluationInputComponents - 4) / 4; i++)\n"
167     "        {\n"
168     "            outVariables.value[j] += inVariables[0].value[i];\n"
169     "        }\n"
170     "    }\n"
171     "}\n";
172 
173 /* Tessellation Evaluation Shader code for max_in_out_attributes test */
174 const char *TessellationShaderTessellationMaxInOut::m_tes_code_2 =
175     "${VERSION}\n"
176     "\n"
177     "${TESSELLATION_SHADER_REQUIRE}\n"
178     "\n"
179     "precision highp float;\n"
180     "\n"
181     "layout (isolines, point_mode) in;\n"
182     "\n"
183     "patch in vec4 value[gl_MaxTessPatchComponents / 4];\n"
184     "\n"
185     "out vec4 out_value;\n"
186     "\n"
187     "void main()\n"
188     "{\n"
189     "    gl_Position    = gl_in[0].gl_Position;\n"
190     "    out_value = vec4(0.0);\n"
191     "\n"
192     "    for (int i = 0; i < gl_MaxTessPatchComponents / 4; i++)\n"
193     "    {\n"
194     "        out_value += value[i];\n"
195     "    }\n"
196     "}\n";
197 
198 /* Fragment Shader code for max_in_out_attributes test */
199 const char *TessellationShaderTessellationMaxInOut::m_fs_code = "${VERSION}\n"
200                                                                 "\n"
201                                                                 "void main()\n"
202                                                                 "{\n"
203                                                                 "}\n";
204 
205 /** Constructor
206  *
207  * @param context Test context
208  **/
TessellationShaderTessellationTests(glcts::Context & context,const ExtParameters & extParams)209 TessellationShaderTessellationTests::TessellationShaderTessellationTests(glcts::Context &context,
210                                                                          const ExtParameters &extParams)
211     : TestCaseGroupBase(context, extParams, "tessellation_shader_tessellation",
212                         "Verifies general tessellation functionality")
213 {
214     /* No implementation needed */
215 }
216 
217 /**
218  * Initializes test groups for geometry shader tests
219  **/
init(void)220 void TessellationShaderTessellationTests::init(void)
221 {
222     addChild(
223         new glcts::TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID(m_context, m_extParams));
224     addChild(
225         new glcts::TessellationShaderTessellationgl_TessCoord(m_context, m_extParams, TESSELLATION_TEST_TYPE_TCS_TES));
226     addChild(new glcts::TessellationShaderTessellationgl_TessCoord(m_context, m_extParams, TESSELLATION_TEST_TYPE_TES));
227     addChild(new glcts::TessellationShaderTessellationInputPatchDiscard(m_context, m_extParams));
228     addChild(new glcts::TessellationShaderTessellationMaxInOut(m_context, m_extParams));
229 }
230 
231 /** Constructor
232  *
233  * @param context Test context
234  **/
TessellationShaderTessellationInputPatchDiscard(Context & context,const ExtParameters & extParams)235 TessellationShaderTessellationInputPatchDiscard::TessellationShaderTessellationInputPatchDiscard(
236     Context &context, const ExtParameters &extParams)
237     : TestCaseBase(context, extParams, "input_patch_discard",
238                    "Verifies that patches, for which relevant outer tessellation levels have"
239                    " been defined to 0 or less, are discard by the tessellation primitive "
240                    " generator.")
241     , m_bo_id(0)
242     , m_fs_id(0)
243     , m_vs_id(0)
244     , m_vao_id(0)
245     , m_utils_ptr(0)
246 {
247     /* Left blank on purpose */
248 }
249 
250 /** Deinitializes ES objects created for the test. */
deinit()251 void TessellationShaderTessellationInputPatchDiscard::deinit()
252 {
253     /* Call base class' deinit() */
254     TestCaseBase::deinit();
255 
256     if (!m_is_tessellation_shader_supported)
257     {
258         return;
259     }
260 
261     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
262 
263     /* Remove TF buffer object bindings */
264     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
265     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
266 
267     /* Disable GL_RASTERIZER_DISCARD mode */
268     gl.disable(GL_RASTERIZER_DISCARD);
269 
270     /* Restore GL_PATCH_VERTICES_EXT value */
271     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
272 
273     /* Unbind vertex array object */
274     gl.bindVertexArray(0);
275 
276     /* Free all ES objects we allocated for the test */
277     if (m_bo_id != 0)
278     {
279         gl.deleteBuffers(1, &m_bo_id);
280 
281         m_bo_id = 0;
282     }
283 
284     if (m_fs_id != 0)
285     {
286         gl.deleteShader(m_fs_id);
287 
288         m_fs_id = 0;
289     }
290 
291     if (m_vs_id != 0)
292     {
293         gl.deleteShader(m_vs_id);
294 
295         m_vs_id = 0;
296     }
297 
298     if (m_vao_id != 0)
299     {
300         gl.deleteVertexArrays(1, &m_vao_id);
301 
302         m_vao_id = 0;
303     }
304 
305     /* Deinitialize all test descriptors */
306     for (_runs::iterator it = m_runs.begin(); it != m_runs.end(); ++it)
307     {
308         deinitRun(*it);
309     }
310     m_runs.clear();
311 
312     /* Release tessellation shader test utilities instance */
313     if (m_utils_ptr != NULL)
314     {
315         delete m_utils_ptr;
316 
317         m_utils_ptr = NULL;
318     }
319 }
320 
321 /** Deinitialize all test pass-specific ES objects.
322  *
323  *  @param test Descriptor of a test pass to deinitialize.
324  **/
deinitRun(_run & run)325 void TessellationShaderTessellationInputPatchDiscard::deinitRun(_run &run)
326 {
327     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
328 
329     if (run.po_id != 0)
330     {
331         gl.deleteProgram(run.po_id);
332 
333         run.po_id = 0;
334     }
335 
336     if (run.tc_id != 0)
337     {
338         gl.deleteShader(run.tc_id);
339 
340         run.tc_id = 0;
341     }
342 
343     if (run.te_id != 0)
344     {
345         gl.deleteShader(run.te_id);
346 
347         run.te_id = 0;
348     }
349 }
350 
351 /** Returns source code of a tessellation control shader for the test.
352  *
353  *  @return Requested string.
354  **/
getTCCode()355 std::string TessellationShaderTessellationInputPatchDiscard::getTCCode()
356 {
357     std::string result;
358 
359     result = "${VERSION}\n"
360              "\n"
361              "${TESSELLATION_SHADER_REQUIRE}\n"
362              "\n"
363              "layout(vertices = 2) out;\n"
364              "\n"
365              "out int tc_primitive_id[];\n"
366              "\n"
367              "void main()\n"
368              "{\n"
369              "    if ((gl_PrimitiveID % 4) == 0)\n"
370              "    {\n"
371              "        gl_TessLevelOuter[0] = 0.0;\n"
372              "        gl_TessLevelOuter[1] = 0.0;\n"
373              "        gl_TessLevelOuter[2] = 0.0;\n"
374              "        gl_TessLevelOuter[3] = 0.0;\n"
375              "    }\n"
376              "    else\n"
377              "    if ((gl_PrimitiveID % 4) == 2)\n"
378              "    {\n"
379              "        gl_TessLevelOuter[0] = -1.0;\n"
380              "        gl_TessLevelOuter[1] = -1.0;\n"
381              "        gl_TessLevelOuter[2] = -1.0;\n"
382              "        gl_TessLevelOuter[3] = -1.0;\n"
383              "    }\n"
384              "    else\n"
385              "    {\n"
386              "        gl_TessLevelOuter[0] = 1.0;\n"
387              "        gl_TessLevelOuter[1] = 1.0;\n"
388              "        gl_TessLevelOuter[2] = 1.0;\n"
389              "        gl_TessLevelOuter[3] = 1.0;\n"
390              "    }\n"
391              "\n"
392              "    gl_TessLevelInner[0]                           = 1.0;\n"
393              "    gl_TessLevelInner[1]                           = 1.0;\n"
394              "    gl_out           [gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
395              "    tc_primitive_id  [gl_InvocationID]             = gl_PrimitiveID;\n"
396              "}\n";
397 
398     return result;
399 }
400 
401 /** Returns source code of a tessellation evaluation shader for the test,
402  *  given user-specified vertex spacing and primitive modes.
403  *
404  *  Throws TestError exception if either of the arguments is invalid.
405  *
406  *  @param primitive_mode Primitive mode to use in the shader.
407  *
408  *  @return Requested string.
409  **/
getTECode(_tessellation_primitive_mode primitive_mode)410 std::string TessellationShaderTessellationInputPatchDiscard::getTECode(_tessellation_primitive_mode primitive_mode)
411 {
412     std::string result = "${VERSION}\n"
413                          "\n"
414                          "${TESSELLATION_SHADER_REQUIRE}\n"
415                          "\n"
416                          "layout(PRIMITIVE_MODE) in;\n"
417                          "\n"
418                          "in  int   tc_primitive_id   [];\n"
419                          "out ivec2 te_tc_primitive_id;\n"
420                          "out int   te_primitive_id;\n"
421                          "\n"
422                          "void main()\n"
423                          "{\n"
424                          "    te_tc_primitive_id[0] = tc_primitive_id[0];\n"
425                          "    te_tc_primitive_id[1] = tc_primitive_id[1];\n"
426                          "    te_primitive_id       = gl_PrimitiveID;\n"
427                          "}\n";
428 
429     /* Replace PRIMITIVE_MODE token with actual primitive_mode */
430     std::string primitive_mode_string      = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
431     const char *primitive_mode_token       = "PRIMITIVE_MODE";
432     std::size_t primitive_mode_token_index = std::string::npos;
433 
434     while ((primitive_mode_token_index = result.find(primitive_mode_token)) != std::string::npos)
435     {
436         result = result.replace(primitive_mode_token_index, strlen(primitive_mode_token), primitive_mode_string);
437 
438         primitive_mode_token_index = result.find(primitive_mode_token);
439     }
440 
441     /* Done */
442     return result;
443 }
444 
445 /** Initializes ES objects necessary to run the test. */
initTest()446 void TessellationShaderTessellationInputPatchDiscard::initTest()
447 {
448     /* Skip if required extensions are not supported. */
449     if (!m_is_tessellation_shader_supported)
450     {
451         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
452     }
453 
454     /* Generate all test-wide objects needed for test execution */
455     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
456     m_utils_ptr              = new TessellationShaderUtils(gl, this);
457 
458     gl.genVertexArrays(1, &m_vao_id);
459     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
460 
461     gl.bindVertexArray(m_vao_id);
462     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
463 
464     gl.genBuffers(1, &m_bo_id);
465     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
466 
467     m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
468     m_vs_id = gl.createShader(GL_VERTEX_SHADER);
469     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
470 
471     /* Configure fragment shader body */
472     const char *fs_body = "${VERSION}\n"
473                           "\n"
474                           "void main()\n"
475                           "{\n"
476                           "}\n";
477 
478     shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
479     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
480 
481     /* Configure vertex shader body */
482     const char *vs_body = "${VERSION}\n"
483                           "\n"
484                           "void main()\n"
485                           "{\n"
486                           "    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
487                           "}\n";
488 
489     shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
490     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
491 
492     /* Compile all the shaders */
493     const glw::GLuint shaders[]  = {m_fs_id, m_vs_id};
494     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
495 
496     m_utils_ptr->compileShaders(n_shaders, shaders, true);
497 
498     /* Initialize all the runs. */
499     const _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
500                                                             TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
501                                                             TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
502     const unsigned int n_primitive_modes                 = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
503 
504     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
505     {
506         /* Initialize the run */
507         _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
508         _run run;
509 
510         initRun(run, primitive_mode);
511 
512         /* Store the run */
513         m_runs.push_back(run);
514     } /* for (all primitive modes) */
515 
516     /* Set up buffer object bindings. Storage size will be determined on
517      * a per-iteration basis.
518      **/
519     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
520     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
521 
522     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
523     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
524 }
525 
526 /** Initializes all ES objects necessary to run a specific test pass.
527  *
528  *  Throws TestError exception if any of the arguments is found invalid.
529  *
530  *  @param run              Run descriptor to fill with IDs of initialized objects.
531  *  @param primitive_mode   Primitive mode to use for the pass.
532  **/
initRun(_run & run,_tessellation_primitive_mode primitive_mode)533 void TessellationShaderTessellationInputPatchDiscard::initRun(_run &run, _tessellation_primitive_mode primitive_mode)
534 {
535     run.primitive_mode = primitive_mode;
536 
537     /* Set up a program object for the descriptor */
538     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
539 
540     run.po_id = gl.createProgram();
541     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
542 
543     /* Set up tessellation shader objects. */
544     run.tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
545     run.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
546 
547     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
548 
549     /* Configure tessellation control shader body */
550     std::string tc_body         = getTCCode();
551     const char *tc_body_raw_ptr = tc_body.c_str();
552 
553     shaderSourceSpecialized(run.tc_id, 1 /* count */, &tc_body_raw_ptr);
554     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
555 
556     /* Configure tessellation evaluation shader body */
557     std::string te_body         = getTECode(primitive_mode);
558     const char *te_body_raw_ptr = te_body.c_str();
559 
560     shaderSourceSpecialized(run.te_id, 1 /* count */, &te_body_raw_ptr);
561     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
562 
563     /* Compile the tessellation evaluation shader */
564     glw::GLuint shaders[]        = {run.tc_id, run.te_id};
565     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
566 
567     m_utils_ptr->compileShaders(n_shaders, shaders, true);
568 
569     /* Attach all shader to the program object */
570     gl.attachShader(run.po_id, m_fs_id);
571     gl.attachShader(run.po_id, run.tc_id);
572     gl.attachShader(run.po_id, run.te_id);
573     gl.attachShader(run.po_id, m_vs_id);
574 
575     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
576 
577     /* Set up XFB */
578     const char *varyings[]        = {"te_tc_primitive_id", "te_primitive_id"};
579     const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
580 
581     gl.transformFeedbackVaryings(run.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
582     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
583 
584     /* Link the program object */
585     glw::GLint link_status = GL_FALSE;
586 
587     gl.linkProgram(run.po_id);
588     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
589 
590     gl.getProgramiv(run.po_id, GL_LINK_STATUS, &link_status);
591     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
592 
593     if (link_status != GL_TRUE)
594     {
595         TCU_FAIL("Program linking failed");
596     }
597 }
598 
599 /** Executes the test.
600  *
601  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
602  *
603  *  Note the function throws exception should an error occur!
604  *
605  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
606  **/
iterate(void)607 tcu::TestNode::IterateResult TessellationShaderTessellationInputPatchDiscard::iterate(void)
608 {
609     /* Do not execute if required extensions are not supported. */
610     if (!m_is_tessellation_shader_supported)
611     {
612         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
613     }
614 
615     /* Initialize ES test objects */
616     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
617 
618     initTest();
619 
620     /* We don't need rasterization for this test */
621     gl.enable(GL_RASTERIZER_DISCARD);
622     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
623 
624     /* Configure amount of vertices per input patch */
625     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
626     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
627 
628     /* Iterate through all tests configured */
629     for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
630     {
631         const _run &run = *run_iterator;
632 
633         /* Set up XFB target BO storage size. Each input patch will generate:
634          *
635          * a) 1 ivec2 and 1 int IF it is an odd patch;
636          * b) 0 bytes otherwise.
637          *
638          * This gives us a total of 2 * (sizeof(int)*2 + sizeof(int)) = 24 bytes per result coordinate,
639          * assuming it does not get discarded along the way.
640          *
641          * Amount of vertices that TE processes is mode-dependent. Note that for 'quads' we use 6 instead
642          * of 4 because the geometry will be broken down to triangles (1 quad = 2 triangles = 6 vertices)
643          * later in the pipeline.
644          */
645         const unsigned int n_total_primitives = 4;
646         const unsigned int n_vertices_per_patch =
647             ((run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) ? 2 :
648              (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS)    ? 6 :
649                                                                                    3);
650         const unsigned int n_bytes_per_result_vertex = sizeof(int) + 2 * sizeof(int);
651         const unsigned int n_bytes_needed = (n_total_primitives / 2) * n_vertices_per_patch * n_bytes_per_result_vertex;
652 
653         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, n_bytes_needed, NULL, /* data */
654                       GL_STATIC_DRAW);
655         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
656 
657         /* Activate the program object */
658         gl.useProgram(run.po_id);
659         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
660 
661         /* Draw the test geometry. */
662         glw::GLenum tf_mode =
663             TessellationShaderUtils::getTFModeForPrimitiveMode(run.primitive_mode, false); /* is_point_mode_enabled */
664 
665         gl.beginTransformFeedback(tf_mode);
666         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed.");
667 
668         gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* vertices per patch */ * n_total_primitives);
669         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
670 
671         gl.endTransformFeedback();
672         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
673 
674         /* Map the BO with result data into user space */
675         int *result_data = (int *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
676                                                     n_bytes_needed, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
677 
678         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
679 
680         /* Verification is based on the following reasoning:
681          *
682          * a) Both TC and TE stages should operate on the same primitive IDs (no re-ordering
683          *    of the IDs is allowed)
684          * b) Under test-specific configuration, tessellator will output 2 line segments (4 coordinates).
685          *    Two first two coordinates will be generated during tessellation of the second primitive,
686          *    and the other two coordinates will be generated during tessellation of the fourth primitive
687          *    (out of all four primitives that will enter the pipeline).
688          * c) In case of quads, 6 first coordinates will be generated during tessellation of the second primitive,
689          *    and the other six will be generated during tessellation of the fourth primitive.
690          * d) Finally, tessellator will output 2 triangles (6 coordinates). The first three coordinates will
691          *    be generated during tessellation of the second primitive, and the other two for the fourth
692          *    primitive.
693          * */
694         const int expected_primitive_ids[] = {
695             1, /* second primitive */
696             3  /* fourth primitive */
697         };
698         const unsigned int n_expected_primitive_ids =
699             sizeof(expected_primitive_ids) / sizeof(expected_primitive_ids[0]);
700         const unsigned int n_expected_repetitions =
701             (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) ? 2 :
702             (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS)    ? 6 :
703                                                                                   3;
704         const int *traveller_ptr = result_data;
705 
706         for (unsigned int n_primitive_id = 0; n_primitive_id < n_expected_primitive_ids; ++n_primitive_id)
707         {
708             int expected_primitive_id = expected_primitive_ids[n_primitive_id];
709 
710             for (unsigned int n_repetition = 0; n_repetition < n_expected_repetitions; ++n_repetition)
711             {
712                 for (unsigned int n_integer = 0; n_integer < 3 /* ivec2 + int */; ++n_integer)
713                 {
714                     if (*traveller_ptr != expected_primitive_id)
715                     {
716                         std::string primitive_mode_string =
717                             TessellationShaderUtils::getESTokenForPrimitiveMode(run.primitive_mode);
718 
719                         m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode: " << primitive_mode_string
720                                            << " invalid gl_PrimitiveID of value " << *traveller_ptr
721                                            << " was found instead of expected " << expected_primitive_id
722                                            << " at index:" << n_primitive_id * 3 /* ivec2 + int */ + n_integer
723                                            << tcu::TestLog::EndMessage;
724 
725                         TCU_FAIL("Discard mechanism failed");
726                     }
727 
728                     traveller_ptr++;
729                 } /* for (all captured integers) */
730             }     /* for (all repetitions) */
731         }         /* for (all non-discarded primitive ids) */
732 
733         /* Clear the buffer storage space before we unmap it */
734         memset(result_data, 0, n_bytes_needed);
735 
736         /* Unmap the BO */
737         gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
738         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
739     }
740 
741     /* All done */
742     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
743     return STOP;
744 }
745 
746 /** Constructor
747  *
748  * @param context Test context
749  **/
750 TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::
TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID(Context & context,const ExtParameters & extParams)751     TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID(Context &context,
752                                                                               const ExtParameters &extParams)
753     : TestCaseBase(context, extParams, "gl_InvocationID_PatchVerticesIn_PrimitiveID",
754                    "Verifies that gl_InvocationID, gl_PatchVerticesIn and gl_PrimitiveID "
755                    "are assigned correct values in TC and TE stages (where appropriate), "
756                    "when invoked with arrayed and indiced draw calls. Also verifies that "
757                    "restarting primitive topology does not restart primitive ID counter.")
758     , m_bo_id(0)
759     , m_fs_id(0)
760     , m_vs_id(0)
761     , m_vao_id(0)
762     , m_utils_ptr(0)
763 {
764     /* Left blank on purpose */
765 }
766 
767 /** Deinitializes ES objects created for the test. */
deinit()768 void TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::deinit()
769 {
770     /* Call base class' deinit() */
771     TestCaseBase::deinit();
772 
773     if (!m_is_tessellation_shader_supported)
774     {
775         return;
776     }
777 
778     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
779 
780     /* Disable modes this test has enabled */
781     gl.disable(GL_RASTERIZER_DISCARD);
782     GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed");
783 
784     gl.disable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
785     GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX) failed");
786 
787     /* Remove TF buffer object bindings */
788     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
789     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
790 
791     /* Restore GL_PATCH_VERTICES_EXT value */
792     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
793 
794     /* Unbind vertex array object */
795     gl.bindVertexArray(0);
796 
797     /* Free all ES objects we allocated for the test */
798     if (m_bo_id != 0)
799     {
800         gl.deleteBuffers(1, &m_bo_id);
801 
802         m_bo_id = 0;
803     }
804 
805     if (m_fs_id != 0)
806     {
807         gl.deleteShader(m_fs_id);
808 
809         m_fs_id = 0;
810     }
811 
812     if (m_vs_id != 0)
813     {
814         gl.deleteShader(m_vs_id);
815 
816         m_vs_id = 0;
817     }
818 
819     if (m_vao_id != 0)
820     {
821         gl.deleteVertexArrays(1, &m_vao_id);
822 
823         m_vao_id = 0;
824     }
825 
826     /* Deinitialize all run descriptors */
827     for (_runs::iterator it = m_runs.begin(); it != m_runs.end(); ++it)
828     {
829         deinitRun(*it);
830     }
831     m_runs.clear();
832 
833     /* Release tessellation shader test utilities instance */
834     if (m_utils_ptr != NULL)
835     {
836         delete m_utils_ptr;
837 
838         m_utils_ptr = NULL;
839     }
840 }
841 
842 /** Deinitialize all test pass-specific ES objects.
843  *
844  *  @param test Descriptor of a test pass to deinitialize.
845  **/
deinitRun(_run & run)846 void TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::deinitRun(_run &run)
847 {
848     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
849 
850     if (run.bo_indices_id != 0)
851     {
852         gl.deleteBuffers(1, &run.bo_indices_id);
853 
854         run.bo_indices_id = 0;
855     }
856 
857     if (run.po_id != 0)
858     {
859         gl.deleteProgram(run.po_id);
860 
861         run.po_id = 0;
862     }
863 
864     if (run.tc_id != 0)
865     {
866         gl.deleteShader(run.tc_id);
867 
868         run.tc_id = 0;
869     }
870 
871     if (run.te_id != 0)
872     {
873         gl.deleteShader(run.te_id);
874 
875         run.te_id = 0;
876     }
877 }
878 
879 /** Returns source code of a tessellation control shader.
880  *
881  *  @param n_patch_vertices Amount of vertices per patch to
882  *                          output in TC stage;
883  *
884  *  @return Requested string.
885  **/
getTCCode(glw::GLuint n_patch_vertices)886 std::string TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::getTCCode(
887     glw::GLuint n_patch_vertices)
888 {
889     static const char *tc_body =
890         "${VERSION}\n"
891         "\n"
892         "${TESSELLATION_SHADER_REQUIRE}\n"
893         "\n"
894         "layout(vertices = N_PATCH_VERTICES) out;\n"
895         "\n"
896         "out TC_OUT\n"
897         "{\n"
898         "    int tc_invocation_id;\n"
899         "    int tc_patch_vertices_in;\n"
900         "    int tc_primitive_id;\n"
901         "} out_te[];\n"
902         "\n"
903         "void main()\n"
904         "{\n"
905         "    gl_out[gl_InvocationID].gl_Position          = gl_in[gl_InvocationID].gl_Position;\n"
906         "    out_te[gl_InvocationID].tc_invocation_id     = gl_InvocationID;\n"
907         "    out_te[gl_InvocationID].tc_patch_vertices_in = gl_PatchVerticesIn;\n"
908         "    out_te[gl_InvocationID].tc_primitive_id      = gl_PrimitiveID;\n"
909         "\n"
910         "    gl_TessLevelInner[0] = 4.0;\n"
911         "    gl_TessLevelInner[1] = 4.0;\n"
912         "    gl_TessLevelOuter[0] = 4.0;\n"
913         "    gl_TessLevelOuter[1] = 4.0;\n"
914         "    gl_TessLevelOuter[2] = 4.0;\n"
915         "    gl_TessLevelOuter[3] = 4.0;\n"
916         "}\n";
917 
918     /* Construct a string out of user-provided integer value */
919     std::stringstream n_patch_vertices_sstream;
920     std::string n_patch_vertices_string;
921 
922     n_patch_vertices_sstream << n_patch_vertices;
923     n_patch_vertices_string = n_patch_vertices_sstream.str();
924 
925     /* Replace N_PATCH_VERTICES with user-provided value */
926     std::string result      = tc_body;
927     const std::string token = "N_PATCH_VERTICES";
928     std::size_t token_index = std::string::npos;
929 
930     while ((token_index = result.find(token)) != std::string::npos)
931     {
932         result = result.replace(token_index, token.length(), n_patch_vertices_string.c_str());
933 
934         token_index = result.find(token);
935     }
936 
937     return result;
938 }
939 
940 /** Returns source code of a tessellation evaluation shader for the test,
941  *  given user-specified primitive mode.
942  *
943  *  Throws TestError exception if either of the arguments is invalid.
944  *
945  *  @param primitive_mode Primitive mode to use in the shader.
946  *
947  *  @return Requested string.
948  **/
getTECode(_tessellation_primitive_mode primitive_mode)949 std::string TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::getTECode(
950     _tessellation_primitive_mode primitive_mode)
951 {
952     static const char *te_body = "${VERSION}\n"
953                                  "\n"
954                                  "${TESSELLATION_SHADER_REQUIRE}\n"
955                                  "\n"
956                                  "layout(PRIMITIVE_MODE) in;\n"
957                                  "\n"
958                                  "in TC_OUT\n"
959                                  "{\n"
960                                  "    int tc_invocation_id;\n"
961                                  "    int tc_patch_vertices_in;\n"
962                                  "    int tc_primitive_id;\n"
963                                  "} in_tc[];\n"
964                                  "\n"
965                                  "out int te_tc_invocation_id;\n"
966                                  "out int te_tc_patch_vertices_in;\n"
967                                  "out int te_tc_primitive_id;\n"
968                                  "out int te_patch_vertices_in;\n"
969                                  "out int te_primitive_id;\n"
970                                  "\n"
971                                  "void main()\n"
972                                  "{\n"
973                                  "    te_tc_invocation_id     = in_tc[gl_PatchVerticesIn-1].tc_invocation_id;\n"
974                                  "    te_tc_patch_vertices_in = in_tc[gl_PatchVerticesIn-1].tc_patch_vertices_in;\n"
975                                  "    te_tc_primitive_id      = in_tc[gl_PatchVerticesIn-1].tc_primitive_id;\n"
976                                  "    te_patch_vertices_in    = gl_PatchVerticesIn;\n"
977                                  "    te_primitive_id         = gl_PrimitiveID;\n"
978                                  "}";
979 
980     /* Replace PRIMITIVE_MODE with user-provided value */
981     std::string primitive_mode_string = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
982     std::string result                = te_body;
983     const std::string token           = "PRIMITIVE_MODE";
984     std::size_t token_index           = std::string::npos;
985 
986     while ((token_index = result.find(token)) != std::string::npos)
987     {
988         result = result.replace(token_index, token.length(), primitive_mode_string.c_str());
989 
990         token_index = result.find(token);
991     }
992 
993     return result;
994 }
995 
996 /** Initializes ES objects necessary to run the test. */
initTest()997 void TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::initTest()
998 {
999     /* Skip if required extensions are not supported. */
1000     if (!m_is_tessellation_shader_supported)
1001     {
1002         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1003     }
1004 
1005     /* Set up Utils instance */
1006     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1007 
1008     m_utils_ptr = new TessellationShaderUtils(gl, this);
1009 
1010     /* Initialize vertex array object */
1011     gl.genVertexArrays(1, &m_vao_id);
1012     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
1013 
1014     gl.bindVertexArray(m_vao_id);
1015     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
1016 
1017     /* Generate all test-wide objects needed for test execution */
1018     gl.genBuffers(1, &m_bo_id);
1019     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
1020 
1021     m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
1022     m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1023     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
1024 
1025     /* Configure fragment shader body */
1026     const char *fs_body = "${VERSION}\n"
1027                           "\n"
1028                           "void main()\n"
1029                           "{\n"
1030                           "}\n";
1031 
1032     shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
1033     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
1034 
1035     /* Configure vertex shader body */
1036     const char *vs_body = "${VERSION}\n"
1037                           "\n"
1038                           "in vec4 vertex_data;\n"
1039                           "\n"
1040                           "void main()\n"
1041                           "{\n"
1042                           "    gl_Position = vertex_data;\n"
1043                           "}\n";
1044 
1045     shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
1046     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
1047 
1048     /* Compile all the shaders */
1049     const glw::GLuint shaders[]  = {m_fs_id, m_vs_id};
1050     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
1051 
1052     m_utils_ptr->compileShaders(n_shaders, shaders, true /* should_succeed */);
1053 
1054     /* Retrieve GL_MAX_PATCH_VERTICES_EXT value before we continue */
1055     glw::GLint gl_max_patch_vertices_value = 0;
1056 
1057     gl.getIntegerv(m_glExtTokens.MAX_PATCH_VERTICES, &gl_max_patch_vertices_value);
1058     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_PATCH_VERTICES_EXT pname");
1059 
1060     /* Initialize all test passes */
1061     const unsigned int drawcall_count_multipliers[] = {3, 6};
1062     const bool is_indiced_draw_call_flags[]         = {false, true};
1063     const glw::GLint n_instances[]                  = {1, 4};
1064     const glw::GLint n_patch_vertices[]             = {4, gl_max_patch_vertices_value / 2, gl_max_patch_vertices_value};
1065     const _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
1066                                                             TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1067                                                             TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
1068     const unsigned int n_drawcall_count_multipliers =
1069         sizeof(drawcall_count_multipliers) / sizeof(drawcall_count_multipliers[0]);
1070     const unsigned int n_is_indiced_draw_call_flags =
1071         sizeof(is_indiced_draw_call_flags) / sizeof(is_indiced_draw_call_flags[0]);
1072     const unsigned int n_n_instances      = sizeof(n_instances) / sizeof(n_instances[0]);
1073     const unsigned int n_n_patch_vertices = sizeof(n_patch_vertices) / sizeof(n_patch_vertices[0]);
1074     const unsigned int n_primitive_modes  = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1075 
1076     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1077     {
1078         _tessellation_primitive_mode current_primitive_mode = primitive_modes[n_primitive_mode];
1079 
1080         for (unsigned int n_patch_vertices_item = 0; n_patch_vertices_item < n_n_patch_vertices;
1081              ++n_patch_vertices_item)
1082         {
1083             glw::GLint current_n_patch_vertices = n_patch_vertices[n_patch_vertices_item];
1084 
1085             for (unsigned int n_is_indiced_draw_call_flag = 0;
1086                  n_is_indiced_draw_call_flag < n_is_indiced_draw_call_flags; ++n_is_indiced_draw_call_flag)
1087             {
1088                 bool current_is_indiced_draw_call = is_indiced_draw_call_flags[n_is_indiced_draw_call_flag];
1089 
1090                 for (unsigned int n_instances_item = 0; n_instances_item < n_n_instances; ++n_instances_item)
1091                 {
1092                     glw::GLint current_n_instances = n_instances[n_instances_item];
1093 
1094                     for (unsigned int n_drawcall_count_multiplier = 0;
1095                          n_drawcall_count_multiplier < n_drawcall_count_multipliers; ++n_drawcall_count_multiplier)
1096                     {
1097                         const unsigned int drawcall_count_multiplier =
1098                             drawcall_count_multipliers[n_drawcall_count_multiplier];
1099 
1100                         /* Form the run descriptor */
1101                         _run run;
1102 
1103                         initRun(run, current_primitive_mode, current_n_patch_vertices, current_is_indiced_draw_call,
1104                                 current_n_instances, drawcall_count_multiplier);
1105 
1106                         /* Store the descriptor for later execution */
1107                         m_runs.push_back(run);
1108                     }
1109                 } /* for (all 'number of instances' settings) */
1110             }     /* for (all 'is indiced draw call' flags) */
1111         }         /* for (all 'n patch vertices' settings) */
1112     }             /* for (all primitive modes) */
1113 
1114     /* Set up buffer object bindings. Storage size will be determined on
1115      * a per-iteration basis.
1116      **/
1117     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
1118     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
1119 
1120     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
1121     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
1122 }
1123 
1124 /** Initializes all ES objects necessary to run a specific test pass.
1125  *
1126  *  Throws TestError exception if any of the arguments is found invalid.
1127  *
1128  *  @param run                       Test run descriptor to fill with IDs of initialized objects.
1129  *  @param primitive_mode            Primitive mode to use for the pass.
1130  *  @param n_patch_vertices          Amount of output patch vertices to use for the pass.
1131  *  @param is_indiced                true  if the draw call to be used for the test run should be indiced;
1132  *                                   false to use the non-indiced one.
1133  *  @param n_instances               Amount of instances to use for the draw call. Set to 1 if the draw
1134  *                                   call should be non-instanced.
1135  *  @param drawcall_count_multiplier Will be used to multiply the "count" argument of the draw call API
1136  *                                   function, effectively multiplying amount of primitives that will be
1137  *                                   generated by the tessellator.
1138  **/
initRun(_run & run,_tessellation_primitive_mode primitive_mode,glw::GLint n_patch_vertices,bool is_indiced,glw::GLint n_instances,unsigned int drawcall_count_multiplier)1139 void TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::initRun(
1140     _run &run, _tessellation_primitive_mode primitive_mode, glw::GLint n_patch_vertices, bool is_indiced,
1141     glw::GLint n_instances, unsigned int drawcall_count_multiplier)
1142 {
1143     run.drawcall_count_multiplier = drawcall_count_multiplier;
1144     run.drawcall_is_indiced       = is_indiced;
1145     run.n_instances               = n_instances;
1146     run.n_patch_vertices          = n_patch_vertices;
1147     run.primitive_mode            = primitive_mode;
1148 
1149     /* Set up a program object for the descriptor */
1150     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1151 
1152     run.po_id = gl.createProgram();
1153     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
1154 
1155     /* Set up tessellation control shader object */
1156     std::string tc_body         = getTCCode(n_patch_vertices);
1157     const char *tc_body_raw_ptr = tc_body.c_str();
1158 
1159     run.tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
1160     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
1161 
1162     shaderSourceSpecialized(run.tc_id, 1 /* count */, &tc_body_raw_ptr);
1163     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
1164 
1165     /* Set up tessellation evaluation shader object. */
1166     std::string te_body         = getTECode(primitive_mode);
1167     const char *te_body_raw_ptr = te_body.c_str();
1168 
1169     run.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
1170     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
1171 
1172     shaderSourceSpecialized(run.te_id, 1 /* count */, &te_body_raw_ptr);
1173     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
1174 
1175     /* Compile the shaders */
1176     const glw::GLuint shader_ids[]  = {run.tc_id, run.te_id};
1177     const unsigned int n_shader_ids = sizeof(shader_ids) / sizeof(shader_ids[0]);
1178 
1179     m_utils_ptr->compileShaders(n_shader_ids, shader_ids, true /* should_succeed */);
1180 
1181     /* Attach all shader to the program object */
1182     gl.attachShader(run.po_id, m_fs_id);
1183     gl.attachShader(run.po_id, run.te_id);
1184     gl.attachShader(run.po_id, m_vs_id);
1185     gl.attachShader(run.po_id, run.tc_id);
1186 
1187     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
1188 
1189     /* Set up XFB */
1190     const char *varyings[]        = {"te_tc_invocation_id", "te_tc_patch_vertices_in", "te_tc_primitive_id",
1191                                      "te_patch_vertices_in", "te_primitive_id"};
1192     const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
1193 
1194     gl.transformFeedbackVaryings(run.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
1195     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
1196 
1197     /* Link the program object */
1198     glw::GLint link_status = GL_FALSE;
1199 
1200     gl.linkProgram(run.po_id);
1201     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
1202 
1203     gl.getProgramiv(run.po_id, GL_LINK_STATUS, &link_status);
1204     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
1205 
1206     if (link_status != GL_TRUE)
1207     {
1208         TCU_FAIL("Program linking failed");
1209     }
1210 
1211     /* If this is going to be an indiced draw call, we need to initialize a buffer
1212      * object that will hold index data. GL_UNSIGNED_BYTE index type will be always
1213      * used for the purpose of this test.
1214      */
1215     if (is_indiced)
1216     {
1217         gl.genBuffers(1, &run.bo_indices_id);
1218         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
1219 
1220         /* Implementations are allowed NOT to support primitive restarting for patches.
1221          * Take this into account and do not insert restart indices, if ES reports no
1222          * support.
1223          */
1224         glw::GLboolean is_primitive_restart_supported = GL_TRUE;
1225 
1226         gl.getBooleanv(GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, &is_primitive_restart_supported);
1227         GLU_EXPECT_NO_ERROR(gl.getError(),
1228                             "glGetIntegerv() failed for GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED pname");
1229 
1230         /* Set up index buffer storage. Note that we're not using any attributes
1231          * in any stage - our goal is just to make sure the primitive counter does
1232          * not restart whenever restart index is encountered during a draw call */
1233         DE_ASSERT(run.n_patch_vertices > 3);
1234         DE_ASSERT(run.drawcall_count_multiplier > 1);
1235 
1236         const unsigned int interleave_rate = run.n_patch_vertices * 2;
1237         unsigned char *bo_contents         = DE_NULL;
1238         unsigned int bo_size =
1239             static_cast<unsigned int>(sizeof(unsigned char) * run.n_patch_vertices * run.drawcall_count_multiplier);
1240 
1241         /* Count in restart indices if necessary */
1242         if (is_primitive_restart_supported)
1243         {
1244             run.n_restart_indices = (bo_size / interleave_rate);
1245             bo_size += 1 /* restart index */ * run.n_restart_indices;
1246         }
1247 
1248         /* Allocate space for the index buffer */
1249         bo_contents = new unsigned char[bo_size];
1250 
1251         /* Interleave the restart index every two complete sets of vertices, each set
1252          * making up a full set of vertices. Fill all other indices with zeros. The
1253          * indices don't really matter since test shaders do not use any attributes -
1254          * what we want to verify is that the restart index does not break the primitive
1255          * id counter.
1256          *
1257          * NOTE: Our interleave rate is just an arbitrary value that makes
1258          *       sense, given the multipliers we use for the test */
1259         const unsigned char restart_index = 0xFF;
1260 
1261         memset(bo_contents, 0, bo_size);
1262 
1263         if (is_primitive_restart_supported)
1264         {
1265             for (unsigned int n_index = interleave_rate; n_index < bo_size; n_index += interleave_rate)
1266             {
1267                 bo_contents[n_index] = restart_index;
1268 
1269                 /* Move one index ahead */
1270                 n_index++;
1271             }
1272         }
1273 
1274         /* Set up the buffer object storage */
1275         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, run.bo_indices_id);
1276         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
1277 
1278         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, bo_size, bo_contents, GL_STATIC_DRAW);
1279         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
1280 
1281         /* Release the buffer */
1282         delete[] bo_contents;
1283 
1284         bo_contents = NULL;
1285     }
1286 
1287     /* Retrieve amount of tessellation coordinates.
1288      *
1289      * Note: this test assumes a constant tessellation level value of 4 for all
1290      *       inner/outer tessellation levels */
1291     const glw::GLfloat tess_levels[] = {4.0f, 4.0f, 4.0f, 4.0f};
1292 
1293     run.n_result_vertices = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1294         run.primitive_mode, tess_levels, tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1295         false); /* is_point_mode_enabled */
1296 
1297     /* The value we have at this point is for single patch only. To end up
1298      * with actual amount of coordinates that will be generated by the tessellator,
1299      * we need to multiply it by drawcall_count_multiplier * n_instances */
1300     run.n_result_vertices *= run.drawcall_count_multiplier * run.n_instances;
1301 
1302     /* We're done! */
1303 }
1304 
1305 /** Executes the test.
1306  *
1307  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1308  *
1309  *  Note the function throws exception should an error occur!
1310  *
1311  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
1312  **/
iterate(void)1313 tcu::TestNode::IterateResult TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::iterate(void)
1314 {
1315     /* Do not execute if required extensions are not supported. */
1316     if (!m_is_tessellation_shader_supported)
1317     {
1318         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1319     }
1320 
1321     /* Initialize ES test objects */
1322     initTest();
1323 
1324     /* Initialize tessellation shader utilities */
1325     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1326 
1327     /* We don't need rasterization for this test */
1328     gl.enable(GL_RASTERIZER_DISCARD);
1329     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
1330 
1331     /* Enable GL_PRIMITIVE_RESTART_FIXED_INDEX mode for indiced draw calls. */
1332     gl.enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
1333     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX) failed.");
1334 
1335     /* Iterate through all test runs configured */
1336     for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
1337     {
1338         const _run &run = *run_iterator;
1339 
1340         /* Configure run-specific amount of vertices per patch */
1341         gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, run.n_patch_vertices);
1342         GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
1343 
1344         /* Activate run-specific program object */
1345         gl.useProgram(run.po_id);
1346         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
1347 
1348         /* Update GL_ELEMENT_ARRAY_BUFFER binding, depending on run properties */
1349         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, (run.drawcall_is_indiced) ? run.bo_indices_id : 0);
1350         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not update GL_ELEMENT_ARRAY_BUFFER binding");
1351 
1352         /* Update transform feedback buffer bindings */
1353         gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
1354         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
1355 
1356         gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
1357         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
1358 
1359         /* Update the transform feedback buffer object storage. For each generated
1360          * tessellated coordinate, TE stage will output 5 integers. */
1361         glw::GLint bo_size = static_cast<glw::GLint>(run.n_result_vertices * 5 /* ints */ * sizeof(int));
1362 
1363         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, GL_STATIC_DRAW);
1364         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
1365 
1366         /* Render the geometry */
1367         glw::GLint drawcall_count = run.n_patch_vertices * run.drawcall_count_multiplier + run.n_restart_indices;
1368         glw::GLenum tf_mode =
1369             TessellationShaderUtils::getTFModeForPrimitiveMode(run.primitive_mode, false); /* is_point_mode_enabled */
1370 
1371         gl.beginTransformFeedback(tf_mode);
1372         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
1373         {
1374             if (run.drawcall_is_indiced)
1375             {
1376                 if (run.n_instances != 1)
1377                 {
1378                     gl.drawElementsInstanced(m_glExtTokens.PATCHES, drawcall_count, GL_UNSIGNED_BYTE,
1379                                              DE_NULL, /* indices */
1380                                              run.n_instances);
1381                     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElementsInstanced() failed");
1382                 } /* if (run.n_instances != 0) */
1383                 else
1384                 {
1385                     gl.drawElements(m_glExtTokens.PATCHES, drawcall_count, GL_UNSIGNED_BYTE, DE_NULL); /* indices */
1386                     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElements() failed");
1387                 }
1388             } /* if (run.drawcall_is_indiced) */
1389             else
1390             {
1391                 if (run.n_instances != 1)
1392                 {
1393                     gl.drawArraysInstanced(m_glExtTokens.PATCHES, 0, /* first */
1394                                            drawcall_count, run.n_instances);
1395                     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArraysInstanced() failed");
1396                 }
1397                 else
1398                 {
1399                     gl.drawArrays(m_glExtTokens.PATCHES, 0, /* first */
1400                                   drawcall_count);
1401                     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
1402                 }
1403             }
1404         }
1405         gl.endTransformFeedback();
1406         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
1407 
1408         /* Map the result buffer object */
1409         const int *result_data = (const int *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
1410                                                                 bo_size, GL_MAP_READ_BIT);
1411 
1412         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
1413 
1414         /* Verify gl_InvocationID values used in both stages were correct. In TE:
1415          *
1416          * te_tc_invocation_id = in_tc[gl_PatchVerticesIn-1].tc_invocation_id;
1417          *
1418          * In the list of varyings passed to glTransformFeedbackVaryings(),
1419          * te_tc_invocation_id is the very first item, so no need to offset
1420          * result_data when initializing result_traveller_ptr below.
1421          */
1422         const unsigned int n_int_varyings_per_tess_coordinate = 5;
1423         const int *result_traveller_ptr                       = result_data;
1424 
1425         for (unsigned int n_coordinate = 0; n_coordinate < run.n_result_vertices;
1426              ++n_coordinate, result_traveller_ptr += n_int_varyings_per_tess_coordinate)
1427         {
1428             const int expected_invocation_id = run.n_patch_vertices - 1;
1429             const int invocation_id_value    = *result_traveller_ptr;
1430 
1431             if (invocation_id_value != expected_invocation_id)
1432             {
1433                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_InvocationID value (" << invocation_id_value
1434                                    << ") "
1435                                       "was found for result coordinate at index "
1436                                    << n_coordinate
1437                                    << " "
1438                                       "instead of expected value ("
1439                                    << expected_invocation_id << ")." << tcu::TestLog::EndMessage;
1440 
1441                 TCU_FAIL("Invalid gl_InvocationID value used in TC stage");
1442             }
1443         } /* for (all result coordinates) */
1444 
1445         /* Verify gl_PrimitiveID values used in both stages were correct. In TE:
1446          *
1447          * te_tc_primitive_id = in_tc[gl_PatchVerticesIn-1].tc_primitive_id;
1448          * te_primitive_id    = gl_PrimitiveID;
1449          *
1450          * In the list of varyings passed to glTransformFeedbackVaryings(),
1451          * te_tc_primitive_id is passed as 3rd string and te_primitive_id is located on
1452          * 5th location.
1453          */
1454         const unsigned int n_result_vertices_per_patch_vertex_batch =
1455             run.n_result_vertices / run.drawcall_count_multiplier / run.n_instances;
1456         const unsigned int n_result_vertices_per_instance = run.n_result_vertices / run.n_instances;
1457 
1458         for (unsigned int n_coordinate = 0; n_coordinate < run.n_result_vertices; ++n_coordinate)
1459         {
1460             unsigned int actual_n_coordinate = n_coordinate;
1461 
1462             /* Subsequent instances reset gl_PrimitiveID counter */
1463             while (actual_n_coordinate >= n_result_vertices_per_instance)
1464             {
1465                 actual_n_coordinate -= n_result_vertices_per_instance;
1466             }
1467 
1468             /* Calculate expected gl_PrimitiveID value */
1469             const int expected_primitive_id = actual_n_coordinate / n_result_vertices_per_patch_vertex_batch;
1470 
1471             /* te_tc_primitive_id */
1472             result_traveller_ptr =
1473                 result_data + n_coordinate * n_int_varyings_per_tess_coordinate + 2; /* as per comment */
1474 
1475             if (*result_traveller_ptr != expected_primitive_id)
1476             {
1477                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PrimitiveID value (" << *result_traveller_ptr
1478                                    << ") "
1479                                       "was used in TC stage instead of expected value ("
1480                                    << expected_primitive_id
1481                                    << ") "
1482                                       " as stored for result coordinate at index "
1483                                    << n_coordinate << "." << tcu::TestLog::EndMessage;
1484 
1485                 TCU_FAIL("Invalid gl_PrimitiveID value used in TC stage");
1486             }
1487 
1488             /* te_primitive_id */
1489             result_traveller_ptr =
1490                 result_data + n_coordinate * n_int_varyings_per_tess_coordinate + 4; /* as per comment */
1491 
1492             if (*result_traveller_ptr != expected_primitive_id)
1493             {
1494                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PrimitiveID value (" << *result_traveller_ptr
1495                                    << ") "
1496                                       "was used in TE stage instead of expected value ("
1497                                    << expected_primitive_id
1498                                    << ") "
1499                                       " as stored for result coordinate at index "
1500                                    << n_coordinate << "." << tcu::TestLog::EndMessage;
1501 
1502                 TCU_FAIL("Invalid gl_PrimitiveID value used in TE stage");
1503             }
1504         } /* for (all result coordinates) */
1505 
1506         /* Verify gl_PatchVerticesIn values used in both stages were correct. In TE:
1507          *
1508          * te_tc_patch_vertices_in = in_tc[gl_PatchVerticesIn-1].tc_patch_vertices_in;
1509          * te_patch_vertices_in    = gl_PatchVerticesIn;
1510          *
1511          * In the list of varyings passed to glTransformFeedbackVaryings(),
1512          * te_tc_patch_vertices_in takes 2nd location and te_patch_vertices_in is
1513          * located at 4th position.
1514          *
1515          **/
1516         for (unsigned int n_coordinate = 0; n_coordinate < run.n_result_vertices; ++n_coordinate)
1517         {
1518             const int expected_patch_vertices_in_value = run.n_patch_vertices;
1519 
1520             /* te_tc_patch_vertices_in */
1521             result_traveller_ptr =
1522                 result_data + n_coordinate * n_int_varyings_per_tess_coordinate + 1; /* as per comment */
1523 
1524             if (*result_traveller_ptr != expected_patch_vertices_in_value)
1525             {
1526                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PatchVerticesIn value ("
1527                                    << *result_traveller_ptr
1528                                    << ") "
1529                                       "was used in TC stage instead of expected value ("
1530                                    << expected_patch_vertices_in_value
1531                                    << ") "
1532                                       " as stored for result coordinate at index "
1533                                    << n_coordinate << "." << tcu::TestLog::EndMessage;
1534 
1535                 TCU_FAIL("Invalid gl_PatchVerticesIn value used in TC stage");
1536             }
1537 
1538             /* te_patch_vertices_in */
1539             result_traveller_ptr =
1540                 result_data + n_coordinate * n_int_varyings_per_tess_coordinate + 3; /* as per comment */
1541 
1542             if (*result_traveller_ptr != expected_patch_vertices_in_value)
1543             {
1544                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PatchVerticesIn value ("
1545                                    << *result_traveller_ptr
1546                                    << ") "
1547                                       "was used in TE stage instead of expected value ("
1548                                    << expected_patch_vertices_in_value
1549                                    << ") "
1550                                       " as stored for result coordinate at index "
1551                                    << n_coordinate << "." << tcu::TestLog::EndMessage;
1552             }
1553         } /* for (all result coordinates) */
1554 
1555         /* Unmap the buffer object - we're done with this iteration */
1556         gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1557         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed");
1558     } /* for (all runs) */
1559 
1560     /* All done */
1561     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1562     return STOP;
1563 }
1564 
getTypeName(_tessellation_test_type test_type)1565 std::string TessellationShaderTessellationgl_TessCoord::getTypeName(_tessellation_test_type test_type)
1566 {
1567     static const char *names[2] = {"TCS_TES", "TES"};
1568     DE_ASSERT(0 <= test_type && test_type <= DE_LENGTH_OF_ARRAY(names));
1569     DE_STATIC_ASSERT(0 == TESSELLATION_TEST_TYPE_TCS_TES && 1 == TESSELLATION_TEST_TYPE_TES);
1570     return names[test_type];
1571 }
1572 
1573 /** Constructor
1574  *
1575  * @param context Test context
1576  **/
TessellationShaderTessellationgl_TessCoord(Context & context,const ExtParameters & extParams,_tessellation_test_type test_type)1577 TessellationShaderTessellationgl_TessCoord::TessellationShaderTessellationgl_TessCoord(
1578     Context &context, const ExtParameters &extParams, _tessellation_test_type test_type)
1579     : TestCaseBase(context, extParams, getTypeName(test_type).c_str(),
1580                    "Verifies that u, v, w components of gl_TessCoord are within "
1581                    "range for a variety of input/outer tessellation level combinations "
1582                    "for all primitive modes. Verifies each component is within valid "
1583                    " range. Also checks that w is always equal to 0 for isolines mode.")
1584     , m_test_type(test_type)
1585     , m_bo_id(0)
1586     , m_broken_ts_id(0)
1587     , m_fs_id(0)
1588     , m_vs_id(0)
1589     , m_vao_id(0)
1590     , m_utils_ptr(0)
1591 {
1592     /* Left blank on purpose */
1593 }
1594 
1595 /** Deinitializes ES objects created for the test. */
deinit()1596 void TessellationShaderTessellationgl_TessCoord::deinit()
1597 {
1598     /* Call base class' deinit() */
1599     TestCaseBase::deinit();
1600 
1601     if (!m_is_tessellation_shader_supported)
1602     {
1603         return;
1604     }
1605 
1606     if (glu::isContextTypeES(m_context.getRenderContext().getType()) && m_test_type == TESSELLATION_TEST_TYPE_TES)
1607     {
1608         return;
1609     }
1610 
1611     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1612 
1613     /* Revert buffer object bindings */
1614     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
1615     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
1616 
1617     /* Disable GL_RASTERIZER_DISCARD mode */
1618     gl.disable(GL_RASTERIZER_DISCARD);
1619 
1620     /* Restore GL_PATCH_VERTICES_EXT, GL_PATCH_DEFAULT_INNER_LEVEL and
1621      * GL_PATCH_DEFAULT_OUTER_LEVEL values */
1622     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
1623     {
1624         const float default_tess_levels[] = {1.0f, 1.0f, 1.0f, 1.0f};
1625         gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, default_tess_levels);
1626         gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, default_tess_levels);
1627     }
1628     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
1629 
1630     /* Unbind vertex array object */
1631     gl.bindVertexArray(0);
1632 
1633     /* Free all ES objects we allocated for the test */
1634     if (m_bo_id != 0)
1635     {
1636         gl.deleteBuffers(1, &m_bo_id);
1637 
1638         m_bo_id = 0;
1639     }
1640 
1641     if (m_broken_ts_id != 0)
1642     {
1643         gl.deleteShader(m_broken_ts_id);
1644 
1645         m_broken_ts_id = 0;
1646     }
1647 
1648     if (m_fs_id != 0)
1649     {
1650         gl.deleteShader(m_fs_id);
1651 
1652         m_fs_id = 0;
1653     }
1654 
1655     if (m_vs_id != 0)
1656     {
1657         gl.deleteShader(m_vs_id);
1658 
1659         m_vs_id = 0;
1660     }
1661 
1662     if (m_vao_id != 0)
1663     {
1664         gl.deleteVertexArrays(1, &m_vao_id);
1665 
1666         m_vao_id = 0;
1667     }
1668 
1669     /* Deinitialize all test descriptors */
1670     for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
1671     {
1672         deinitTestDescriptor(*it);
1673     }
1674     m_tests.clear();
1675 
1676     /* Release tessellation shader test utilities instance */
1677     if (m_utils_ptr != NULL)
1678     {
1679         delete m_utils_ptr;
1680 
1681         m_utils_ptr = NULL;
1682     }
1683 }
1684 
1685 /** Deinitialize all test pass-specific ES objects.
1686  *
1687  *  @param test Descriptor of a test pass to deinitialize.
1688  **/
deinitTestDescriptor(_test_descriptor & test)1689 void TessellationShaderTessellationgl_TessCoord::deinitTestDescriptor(_test_descriptor &test)
1690 {
1691     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1692 
1693     if (test.po_id != 0)
1694     {
1695         gl.deleteProgram(test.po_id);
1696 
1697         test.po_id = 0;
1698     }
1699 
1700     if (test.tc_id != 0)
1701     {
1702         gl.deleteShader(test.tc_id);
1703 
1704         test.tc_id = 0;
1705     }
1706 
1707     if (test.te_id != 0)
1708     {
1709         gl.deleteShader(test.te_id);
1710 
1711         test.te_id = 0;
1712     }
1713 }
1714 
1715 /** Returns source code of a tessellation control shader for the test,
1716  *  given user-specified amount of output patch vertices.
1717  *
1718  *  @param n_patch_vertices Amount of output patch vertices for TC stage.
1719  *
1720  *  @return Requested string.
1721  **/
getTCCode(glw::GLint n_patch_vertices)1722 std::string TessellationShaderTessellationgl_TessCoord::getTCCode(glw::GLint n_patch_vertices)
1723 {
1724     return TessellationShaderUtils::getGenericTCCode(n_patch_vertices, true);
1725 }
1726 
1727 /** Returns source code of a tessellation evaluation shader for the test,
1728  *  given user-specified vertex spacing and primitive modes.
1729  *
1730  *  Throws TestError exception if either of the arguments is invalid.
1731  *
1732  *  @param vertex_spacing Vertex spacing mode to use in the shader.
1733  *  @param primitive_mode Primitive mode to use in the shader.
1734  *
1735  *  @return Requested string.
1736  **/
getTECode(_tessellation_shader_vertex_spacing vertex_spacing,_tessellation_primitive_mode primitive_mode)1737 std::string TessellationShaderTessellationgl_TessCoord::getTECode(_tessellation_shader_vertex_spacing vertex_spacing,
1738                                                                   _tessellation_primitive_mode primitive_mode)
1739 {
1740     return TessellationShaderUtils::getGenericTECode(vertex_spacing, primitive_mode,
1741                                                      TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false);
1742 }
1743 
1744 /** Initializes ES objects necessary to run the test. */
initTest()1745 void TessellationShaderTessellationgl_TessCoord::initTest()
1746 {
1747     /* Skip if required extensions are not supported. */
1748     if (!m_is_tessellation_shader_supported)
1749     {
1750         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1751     }
1752 
1753     if (glu::isContextTypeES(m_context.getRenderContext().getType()) && m_test_type == TESSELLATION_TEST_TYPE_TES)
1754     {
1755         throw tcu::NotSupportedError("Test can't be run in ES context");
1756     }
1757 
1758     /* Generate all test-wide objects needed for test execution */
1759     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1760 
1761     gl.genVertexArrays(1, &m_vao_id);
1762     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
1763 
1764     gl.bindVertexArray(m_vao_id);
1765     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
1766 
1767     gl.genBuffers(1, &m_bo_id);
1768     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
1769 
1770     m_broken_ts_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
1771     m_fs_id        = gl.createShader(GL_FRAGMENT_SHADER);
1772     m_vs_id        = gl.createShader(GL_VERTEX_SHADER);
1773     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
1774 
1775     /* Configure fragment shader body */
1776     const char *fs_body = "${VERSION}\n"
1777                           "\n"
1778                           "void main()\n"
1779                           "{\n"
1780                           "}\n";
1781 
1782     shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
1783     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
1784 
1785     /* Configure vertex shader body */
1786     const char *vs_body = "${VERSION}\n"
1787                           "\n"
1788                           "void main()\n"
1789                           "{\n"
1790                           "    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
1791                           "}\n";
1792 
1793     shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
1794     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
1795 
1796     /* Compile all the shaders */
1797     const glw::GLuint shaders[]  = {m_fs_id, m_vs_id};
1798     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
1799 
1800     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
1801     {
1802         glw::GLuint shader = shaders[n_shader];
1803 
1804         if (shader != 0)
1805         {
1806             glw::GLint compile_status = GL_FALSE;
1807 
1808             gl.compileShader(shader);
1809             GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
1810 
1811             gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
1812             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
1813 
1814             if (compile_status != GL_TRUE)
1815             {
1816                 TCU_FAIL("Shader compilation failed");
1817             }
1818         }
1819     } /* for (all shaders) */
1820 
1821     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value before we start looping */
1822     glw::GLint gl_max_tess_gen_level_value = 0;
1823 
1824     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1825     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1826 
1827     /* Initialize all test passes - iterate over all primitive modes supported.. */
1828     for (int primitive_mode = static_cast<int>(TESSELLATION_SHADER_PRIMITIVE_MODE_FIRST);
1829          primitive_mode != static_cast<int>(TESSELLATION_SHADER_PRIMITIVE_MODE_COUNT); primitive_mode++)
1830     {
1831         /* Iterate over all tessellation level combinations defined for current primitive mode */
1832         _tessellation_levels_set tessellation_levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1833             static_cast<_tessellation_primitive_mode>(primitive_mode), gl_max_tess_gen_level_value,
1834             TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1835 
1836         for (_tessellation_levels_set_const_iterator levels_iterator = tessellation_levels.begin();
1837              levels_iterator != tessellation_levels.end(); levels_iterator++)
1838         {
1839             const _tessellation_levels &levels = *levels_iterator;
1840             _test_descriptor test;
1841 
1842             initTestDescriptor(test, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1843                                static_cast<_tessellation_primitive_mode>(primitive_mode), 1, /* n_patch_vertices */
1844                                levels.inner, levels.outer, m_test_type);
1845 
1846             /* Store the test descriptor */
1847             m_tests.push_back(test);
1848         } /* for (all tessellation level combinations for current primitive mode) */
1849     }     /* for (all primitive modes) */
1850 
1851     /* Set up buffer object bindings. Storage size will be determined on
1852      * a per-iteration basis.
1853      **/
1854     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
1855     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
1856 
1857     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
1858     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
1859 }
1860 
1861 /** Initializes all ES objects necessary to run a specific test pass.
1862  *
1863  *  Throws TestError exception if any of the arguments is found invalid.
1864  *
1865  *  @param test             Test descriptor to fill with IDs of initialized objects.
1866  *  @param vertex_spacing   Vertex spacing mode to use for the pass.
1867  *  @param primitive_mode   Primitive mode to use for the pass.
1868  *  @param n_patch_vertices Amount of output patch vertices to use for the pass.
1869  *  @param inner_tess_level Inner tessellation level values to be used for the pass.
1870  *                          Must not be NULL.
1871  *  @param outer_tess_level Outer tessellation level values to be used for the pass.
1872  *                          Must not be NULL.
1873  *  @param test_type        Defines which tessellation stages should be defined for the pass.
1874  **/
initTestDescriptor(_test_descriptor & test,_tessellation_shader_vertex_spacing vertex_spacing,_tessellation_primitive_mode primitive_mode,glw::GLint n_patch_vertices,const float * inner_tess_level,const float * outer_tess_level,_tessellation_test_type test_type)1875 void TessellationShaderTessellationgl_TessCoord::initTestDescriptor(
1876     _test_descriptor &test, _tessellation_shader_vertex_spacing vertex_spacing,
1877     _tessellation_primitive_mode primitive_mode, glw::GLint n_patch_vertices, const float *inner_tess_level,
1878     const float *outer_tess_level, _tessellation_test_type test_type)
1879 {
1880     test.n_patch_vertices = n_patch_vertices;
1881     test.primitive_mode   = primitive_mode;
1882     test.type             = test_type;
1883     test.vertex_spacing   = vertex_spacing;
1884 
1885     memcpy(test.tess_level_inner, inner_tess_level, sizeof(float) * 2 /* components */);
1886     memcpy(test.tess_level_outer, outer_tess_level, sizeof(float) * 4 /* components */);
1887 
1888     /* Set up a program object for the descriptor */
1889     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1890 
1891     test.po_id = gl.createProgram();
1892     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
1893 
1894     /* Set up a pass-specific tessellation shader objects. */
1895     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
1896     {
1897         test.tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
1898     }
1899 
1900     test.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
1901 
1902     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
1903 
1904     /* Configure tessellation control shader body */
1905     if (test.tc_id != 0)
1906     {
1907         std::string tc_body         = getTCCode(n_patch_vertices);
1908         const char *tc_body_raw_ptr = tc_body.c_str();
1909 
1910         shaderSourceSpecialized(test.tc_id, 1 /* count */, &tc_body_raw_ptr);
1911         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
1912     }
1913 
1914     /* Configure tessellation evaluation shader body */
1915     std::string te_body         = getTECode(vertex_spacing, primitive_mode);
1916     const char *te_body_raw_ptr = te_body.c_str();
1917 
1918     shaderSourceSpecialized(test.te_id, 1 /* count */, &te_body_raw_ptr);
1919     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
1920 
1921     /* Compile the tessellation evaluation shader */
1922     glw::GLint compile_status    = GL_FALSE;
1923     glw::GLuint shaders[]        = {test.tc_id, test.te_id};
1924     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
1925 
1926     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
1927     {
1928         glw::GLuint shader = shaders[n_shader];
1929 
1930         if (shader != 0)
1931         {
1932             gl.compileShader(shader);
1933             GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed for tessellation shader");
1934 
1935             gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
1936             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed for tessellation shader");
1937 
1938             if (compile_status != GL_TRUE)
1939             {
1940                 TCU_FAIL("Tessellation shader compilation failed");
1941             }
1942         }
1943     } /* for (all shaders) */
1944 
1945     /* Attach all shader to the program object */
1946     gl.attachShader(test.po_id, m_fs_id);
1947     gl.attachShader(test.po_id, test.te_id);
1948     gl.attachShader(test.po_id, m_vs_id);
1949 
1950     if (test.tc_id != 0)
1951     {
1952         gl.attachShader(test.po_id, test.tc_id);
1953     }
1954 
1955     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
1956 
1957     /* Set up XFB */
1958     const char *varyings[]        = {"result_uvw"};
1959     const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
1960 
1961     gl.transformFeedbackVaryings(test.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
1962     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
1963 
1964     /* Link the program object */
1965     glw::GLint link_status = GL_FALSE;
1966 
1967     gl.linkProgram(test.po_id);
1968     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
1969 
1970     gl.getProgramiv(test.po_id, GL_LINK_STATUS, &link_status);
1971     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
1972 
1973     if (link_status != GL_TRUE)
1974     {
1975         TCU_FAIL("Program linking failed");
1976     }
1977 
1978     /* If TCS stage is present, set up the corresponding uniforms as needed */
1979     if (test.type == TESSELLATION_TEST_TYPE_TCS_TES)
1980     {
1981         test.inner_tess_level_uniform_location = gl.getUniformLocation(test.po_id, "inner_tess_level");
1982         test.outer_tess_level_uniform_location = gl.getUniformLocation(test.po_id, "outer_tess_level");
1983 
1984         DE_ASSERT(test.inner_tess_level_uniform_location != -1);
1985         DE_ASSERT(test.outer_tess_level_uniform_location != -1);
1986 
1987         /* Now that we have the locations, let's configure the uniforms */
1988         gl.useProgram(test.po_id);
1989         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
1990 
1991         gl.uniform2fv(test.inner_tess_level_uniform_location, 1, /* count */
1992                       test.tess_level_inner);
1993         GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
1994 
1995         gl.uniform4fv(test.outer_tess_level_uniform_location, 1, /* count */
1996                       test.tess_level_outer);
1997         GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
1998     }
1999 }
2000 
2001 /** Executes the test.
2002  *
2003  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2004  *
2005  *  Note the function throws exception should an error occur!
2006  *
2007  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
2008  **/
iterate(void)2009 tcu::TestNode::IterateResult TessellationShaderTessellationgl_TessCoord::iterate(void)
2010 {
2011     /* Do not execute if required extensions are not supported. */
2012     if (!m_is_geometry_shader_extension_supported || !m_is_tessellation_shader_supported)
2013     {
2014         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
2015     }
2016 
2017     /* On ES skip test configurations that don't have TCS. */
2018     if (isContextTypeES(m_context.getRenderContext().getType()) && (m_test_type == TESSELLATION_TEST_TYPE_TES))
2019     {
2020         throw tcu::NotSupportedError("Implementation requires TCS and TES be used together; skipping.");
2021     }
2022 
2023     /* Initialize ES test objects */
2024     initTest();
2025 
2026     /* Initialize tessellation shader utilities */
2027     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2028 
2029     m_utils_ptr = new TessellationShaderUtils(gl, this);
2030 
2031     /* We don't need rasterization for this test */
2032     gl.enable(GL_RASTERIZER_DISCARD);
2033     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
2034 
2035     /* Iterate through all tests configured */
2036     for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++)
2037     {
2038         const _test_descriptor &test = *test_iterator;
2039 
2040         if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
2041         {
2042             /* If there is no TCS defined, define inner/outer tessellation levels */
2043             if (test.type == TESSELLATION_TEST_TYPE_TES)
2044             {
2045                 gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, test.tess_level_inner);
2046                 GLU_EXPECT_NO_ERROR(gl.getError(),
2047                                     "glPatchParameterfv() failed for GL_PATCH_DEFAULT_INNER_LEVEL pname");
2048 
2049                 gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, test.tess_level_outer);
2050                 GLU_EXPECT_NO_ERROR(gl.getError(),
2051                                     "glPatchParameterfv() failed for GL_PATCH_DEFAULT_OUTER_LEVEL pname");
2052             }
2053         }
2054 
2055         /* Configure amount of vertices per patch */
2056         gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, test.n_patch_vertices);
2057         GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
2058 
2059         /* Set up XFB target BO storage size. We will be capturing a total of 12 FP components per
2060          * result vertex.
2061          */
2062         unsigned int n_bytes_needed    = 0;
2063         unsigned int n_result_vertices = 0;
2064 
2065         n_result_vertices = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2066             test.primitive_mode, test.tess_level_inner, test.tess_level_outer, test.vertex_spacing, false);
2067         n_bytes_needed = static_cast<unsigned int>(n_result_vertices * sizeof(float) * 12 /* components */);
2068 
2069         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, n_bytes_needed, NULL, /* data */
2070                       GL_STATIC_DRAW);
2071         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
2072 
2073         /* Activate the program object */
2074         gl.useProgram(test.po_id);
2075         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
2076 
2077         /* Draw the test geometry. */
2078         glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(test.primitive_mode, false);
2079 
2080         gl.beginTransformFeedback(tf_mode);
2081         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_PATCHES_EXT) failed.");
2082 
2083         gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, test.n_patch_vertices);
2084         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
2085 
2086         gl.endTransformFeedback();
2087         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
2088 
2089         /* Map the BO with result data into user space */
2090         const float *vertex_data = (const float *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
2091                                                                     n_bytes_needed, GL_MAP_READ_BIT);
2092 
2093         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
2094 
2095         /* (test 1): Make sure that u+v+w == 1 (applicable for triangles only) */
2096         const float epsilon = 1e-5f;
2097 
2098         if (test.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2099         {
2100             for (unsigned int n_vertex = 0; n_vertex < n_result_vertices; ++n_vertex)
2101             {
2102                 const float *vertex_uvw = vertex_data + 3 /* components */ * n_vertex;
2103                 float sum_uvw           = vertex_uvw[0] + vertex_uvw[1] + vertex_uvw[2];
2104 
2105                 if (de::abs(sum_uvw - 1.0f) > epsilon)
2106                 {
2107                     m_testCtx.getLog() << tcu::TestLog::Message
2108                                        << "For triangles, U+V+W coordinates outputted "
2109                                           "by tessellator should sum up to 1.0. Instead, the "
2110                                           "following coordinates:"
2111                                        << " (" << vertex_uvw[0] << ", " << vertex_uvw[1] << ", " << vertex_uvw[2]
2112                                        << ") "
2113                                           "sum up to "
2114                                        << sum_uvw << "." << tcu::TestLog::EndMessage;
2115 
2116                     TCU_FAIL("U+V+W coordinates do not add up to 1, even though triangle/tessellation"
2117                              " was requested");
2118                 }
2119             } /* for (all vertices) */
2120         }     /* if (we're dealing with triangles or quads) */
2121 
2122         /* (test 2): Make sure that u, v, w e <0, 1> (always applicable) */
2123         for (unsigned int n_vertex = 0; n_vertex < n_result_vertices; ++n_vertex)
2124         {
2125             const float *vertex_uvw = vertex_data + 3 /* components */ * n_vertex;
2126 
2127             if (!(vertex_uvw[0] >= 0.0f && vertex_uvw[0] <= 1.0f && vertex_uvw[1] >= 0.0f && vertex_uvw[1] <= 1.0f &&
2128                   vertex_uvw[2] >= 0.0f && vertex_uvw[2] <= 1.0f))
2129             {
2130                 m_testCtx.getLog() << tcu::TestLog::Message
2131                                    << "U, V and W coordinates outputted by the tessellator should "
2132                                       "be within <0, 1> range. However, "
2133                                    << "vertex at index: " << n_vertex << "is defined by the following triple:"
2134                                    << " (" << vertex_uvw[0] << ", " << vertex_uvw[1] << ", " << vertex_uvw[2] << ")."
2135                                    << tcu::TestLog::EndMessage;
2136 
2137                 TCU_FAIL("U/V/W coordinate outputted by the tessellator is outside allowed range.");
2138             }
2139         } /* for (all vertices) */
2140 
2141         /* (test 3): Make sure w is always zero (applicable to quads and isolines) */
2142         if (test.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS ||
2143             test.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
2144         {
2145             for (unsigned int n_vertex = 0; n_vertex < n_result_vertices; ++n_vertex)
2146             {
2147                 const float *vertex_uvw = vertex_data + 3 /* components */ * n_vertex;
2148 
2149                 if (de::abs(vertex_uvw[2]) > epsilon)
2150                 {
2151                     m_testCtx.getLog() << tcu::TestLog::Message
2152                                        << "W coordinate should be zero for all vertices outputted "
2153                                           "for isolines and quads; for at least one vertex, W was "
2154                                           "found to be equal to: "
2155                                        << vertex_uvw[2] << tcu::TestLog::EndMessage;
2156 
2157                     TCU_FAIL("W coordinate was found to be non-zero for at least one tessellation coordinate"
2158                              " generated in either quads or isolines primitive mode");
2159                 }
2160             } /* for (all vertices) */
2161         }     /* if (we're dealing with quads or isolines) */
2162 
2163         /* Unmap the BO */
2164         gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2165         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
2166     }
2167 
2168     /* All done */
2169     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2170     return STOP;
2171 }
2172 
2173 /** Constructor
2174  *
2175  * @param context     Test context
2176  * @param name        Test case's name
2177  * @param description Test case's desricption
2178  **/
TessellationShaderTessellationMaxInOut(Context & context,const ExtParameters & extParams)2179 TessellationShaderTessellationMaxInOut::TessellationShaderTessellationMaxInOut(Context &context,
2180                                                                                const ExtParameters &extParams)
2181     : TestCaseBase(context, extParams, "max_in_out_attributes",
2182                    "Make sure it is possible to use up GL_MAX_TESS_*_COMPONENTS_EXT.")
2183     , m_po_id_1(0)
2184     , m_po_id_2(0)
2185     , m_fs_id(0)
2186     , m_tcs_id_1(0)
2187     , m_tcs_id_2(0)
2188     , m_tes_id_1(0)
2189     , m_tes_id_2(0)
2190     , m_vs_id_1(0)
2191     , m_vs_id_2(0)
2192     , m_tf_bo_id_1(0)
2193     , m_tf_bo_id_2(0)
2194     , m_patch_data_bo_id(0)
2195     , m_vao_id(0)
2196     , m_gl_max_tess_control_input_components_value(0)
2197     , m_gl_max_tess_control_output_components_value(0)
2198     , m_gl_max_tess_evaluation_input_components_value(0)
2199     , m_gl_max_tess_evaluation_output_components_value(0)
2200     , m_gl_max_transform_feedback_interleaved_components_value(0)
2201     , m_gl_max_tess_patch_components_value(0)
2202     , m_gl_max_vertex_output_components_value(0)
2203     , m_ref_vertex_attributes(DE_NULL)
2204     , m_tf_varyings_names(DE_NULL)
2205 {
2206     m_ref_patch_attributes[0] = 0.0f;
2207     m_ref_patch_attributes[1] = 0.0f;
2208     m_ref_patch_attributes[2] = 0.0f;
2209     m_ref_patch_attributes[3] = 0.0f;
2210 }
2211 
2212 /** Deinitializes all ES objects created for the test. */
deinit(void)2213 void TessellationShaderTessellationMaxInOut::deinit(void)
2214 {
2215     /* Call base class deinitialization routine */
2216     TestCaseBase::deinit();
2217 
2218     if (!m_is_tessellation_shader_supported)
2219     {
2220         return;
2221     }
2222 
2223     /* Deallocate dynamic arrays */
2224     if (m_ref_vertex_attributes != DE_NULL)
2225     {
2226         free(m_ref_vertex_attributes);
2227 
2228         m_ref_vertex_attributes = DE_NULL;
2229     }
2230 
2231     /* Deallocate the varyings array */
2232     if (m_tf_varyings_names != DE_NULL)
2233     {
2234         for (int i = 0; i < (m_gl_max_tess_evaluation_output_components_value) / 4 - 1 /* gl_Position */; i++)
2235         {
2236             if (m_tf_varyings_names[i] != DE_NULL)
2237             {
2238                 free(m_tf_varyings_names[i]);
2239 
2240                 m_tf_varyings_names[i] = DE_NULL;
2241             }
2242         }
2243 
2244         free(m_tf_varyings_names);
2245 
2246         m_tf_varyings_names = DE_NULL;
2247     }
2248 
2249     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2250 
2251     /* Reset GL_PATCH_VERTICES_EXT pname value */
2252     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
2253     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed!");
2254 
2255     /* Unbind vertex array object */
2256     gl.bindVertexArray(0);
2257 
2258     /* Release ES objects */
2259     if (m_fs_id != 0)
2260     {
2261         gl.deleteShader(m_fs_id);
2262 
2263         m_fs_id = 0;
2264     }
2265 
2266     if (m_po_id_1 != 0)
2267     {
2268         gl.deleteProgram(m_po_id_1);
2269 
2270         m_po_id_1 = 0;
2271     }
2272 
2273     if (m_po_id_2 != 0)
2274     {
2275         gl.deleteProgram(m_po_id_2);
2276 
2277         m_po_id_2 = 0;
2278     }
2279 
2280     if (m_tcs_id_1 != 0)
2281     {
2282         gl.deleteShader(m_tcs_id_1);
2283 
2284         m_tcs_id_1 = 0;
2285     }
2286 
2287     if (m_tcs_id_2 != 0)
2288     {
2289         gl.deleteShader(m_tcs_id_2);
2290 
2291         m_tcs_id_2 = 0;
2292     }
2293 
2294     if (m_tes_id_1 != 0)
2295     {
2296         gl.deleteShader(m_tes_id_1);
2297 
2298         m_tes_id_1 = 0;
2299     }
2300 
2301     if (m_tes_id_2 != 0)
2302     {
2303         gl.deleteShader(m_tes_id_2);
2304 
2305         m_tes_id_2 = 0;
2306     }
2307 
2308     if (m_vs_id_1 != 0)
2309     {
2310         gl.deleteShader(m_vs_id_1);
2311 
2312         m_vs_id_1 = 0;
2313     }
2314 
2315     if (m_vs_id_2 != 0)
2316     {
2317         gl.deleteShader(m_vs_id_2);
2318 
2319         m_vs_id_2 = 0;
2320     }
2321 
2322     if (m_tf_bo_id_1 != 0)
2323     {
2324         gl.deleteBuffers(1, &m_tf_bo_id_1);
2325 
2326         m_tf_bo_id_1 = 0;
2327     }
2328 
2329     if (m_tf_bo_id_2 != 0)
2330     {
2331         gl.deleteBuffers(1, &m_tf_bo_id_2);
2332 
2333         m_tf_bo_id_2 = 0;
2334     }
2335 
2336     if (m_patch_data_bo_id != 0)
2337     {
2338         gl.deleteBuffers(1, &m_patch_data_bo_id);
2339 
2340         m_patch_data_bo_id = 0;
2341     }
2342 
2343     if (m_vao_id != 0)
2344     {
2345         gl.deleteVertexArrays(1, &m_vao_id);
2346 
2347         m_vao_id = 0;
2348     }
2349 }
2350 
2351 /** Executes the test.
2352  *
2353  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2354  *
2355  *  Note the function throws exception should an error occur!
2356  *
2357  *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
2358  **/
iterate(void)2359 tcu::TestNode::IterateResult TessellationShaderTessellationMaxInOut::iterate(void)
2360 {
2361     /* Retrieve ES entry-points. */
2362     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2363 
2364     /* Initialize test-specific ES objects. */
2365     initTest();
2366 
2367     /* Execute test case 1 */
2368     gl.useProgram(m_po_id_1);
2369     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!");
2370 
2371     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
2372                       m_tf_bo_id_1);
2373     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed!");
2374 
2375     gl.beginTransformFeedback(GL_POINTS);
2376     GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
2377 
2378     gl.drawArrays(m_glExtTokens.PATCHES, 0, /* first */
2379                   2);                       /* count */
2380     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
2381 
2382     gl.endTransformFeedback();
2383     GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
2384 
2385     /* Verify the rendered data. */
2386     bool test_passed = true;
2387 
2388     test_passed &= compareValues("Per-vertex components test ", m_ref_vertex_attributes,
2389                                  m_gl_max_tess_evaluation_output_components_value / 4);
2390 
2391     /* Execute test case 2 */
2392     gl.useProgram(m_po_id_2);
2393     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!");
2394 
2395     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
2396                       m_tf_bo_id_2);
2397     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed!");
2398 
2399     gl.beginTransformFeedback(GL_POINTS);
2400     GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
2401 
2402     gl.drawArrays(m_glExtTokens.PATCHES, 0, /* first */
2403                   2);                       /* count */
2404     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
2405 
2406     gl.endTransformFeedback();
2407     GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
2408 
2409     /* Verify the rendered data */
2410     test_passed &=
2411         compareValues("Per-patch components test ", m_ref_patch_attributes, 1 /* amount of output vectors */);
2412 
2413     /* Test passed. */
2414     if (test_passed)
2415     {
2416         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2417     }
2418     else
2419     {
2420         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2421     }
2422 
2423     return STOP;
2424 }
2425 
2426 /** Sets up buffer objects.
2427  *
2428  *   Note the function throws exception should an error occur!
2429  **/
initBufferObjects(void)2430 void TessellationShaderTessellationMaxInOut::initBufferObjects(void)
2431 {
2432     /* Retrieve ES entry-points. */
2433     glw::GLint bo_size       = 0;
2434     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2435 
2436     /* Transform feedback buffer object for case 1 */
2437     gl.genBuffers(1, &m_tf_bo_id_1);
2438     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed!");
2439 
2440     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo_id_1);
2441     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!");
2442 
2443     bo_size = static_cast<glw::GLint>(2                                                      /* vertices       */
2444                                       * 4                                                    /* components     */
2445                                       * m_gl_max_tess_evaluation_output_components_value / 4 /* attributes     */
2446                                       * sizeof(glw::GLfloat));                               /* attribute size */
2447 
2448     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, NULL, GL_STATIC_DRAW);
2449     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
2450 
2451     /* Transform feedback buffer object for case 2 */
2452     bo_size = 2 *                       /* vertices */
2453               sizeof(glw::GLfloat) * 4; /* components */
2454 
2455     gl.genBuffers(1, &m_tf_bo_id_2);
2456     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed!");
2457 
2458     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo_id_2);
2459     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!");
2460 
2461     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, NULL, GL_STATIC_DRAW);
2462     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
2463 
2464     /* Set up vertex data buffer storage */
2465     glw::GLfloat vertices[2 /* vertices */ * 4 /* components */];
2466 
2467     bo_size     = sizeof(vertices);
2468     vertices[0] = 0.f;
2469     vertices[1] = 0.f;
2470     vertices[2] = 0.f;
2471     vertices[3] = 1.f;
2472     vertices[4] = 1.f;
2473     vertices[5] = 1.f;
2474     vertices[6] = 1.f;
2475     vertices[7] = 1.f;
2476 
2477     gl.genBuffers(1, &m_patch_data_bo_id);
2478     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed!");
2479 
2480     gl.bindBuffer(GL_ARRAY_BUFFER, m_patch_data_bo_id);
2481     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!");
2482 
2483     gl.bufferData(GL_ARRAY_BUFFER, bo_size, vertices, GL_STATIC_DRAW);
2484     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed!");
2485 
2486     gl.enableVertexAttribArray(0);
2487     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() failed!");
2488 
2489     gl.vertexAttribPointer(0,                  /* index */
2490                            4,                  /* size */
2491                            GL_FLOAT, GL_FALSE, /* normalized */
2492                            0,                  /* stride */
2493                            0);                 /* pointer */
2494     GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() failed!");
2495 }
2496 
2497 /** Initializes the test.
2498  *
2499  *  Note the function throws exception should an error occur!
2500  **/
initProgramObjects(void)2501 void TessellationShaderTessellationMaxInOut::initProgramObjects(void)
2502 {
2503     /* Retrieve ES entry-points */
2504     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2505 
2506     /* Create program objects. */
2507     m_po_id_1 = gl.createProgram();
2508     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!");
2509 
2510     m_po_id_2 = gl.createProgram();
2511     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!");
2512 
2513     /* Set up all the shader objects that will be used for the test */
2514     m_vs_id_1 = gl.createShader(GL_VERTEX_SHADER);
2515     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_VERTEX_SHADER) failed!");
2516 
2517     m_vs_id_2 = gl.createShader(GL_VERTEX_SHADER);
2518     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_VERTEX_SHADER) failed!");
2519 
2520     m_tcs_id_1 = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
2521     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_CONTROL_SHADER_EXT) failed!");
2522 
2523     m_tcs_id_2 = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
2524     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_CONTROL_SHADER_EXT) failed!");
2525 
2526     m_tes_id_1 = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
2527     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_EVALUATION_SHADER_EXT) failed!");
2528 
2529     m_tes_id_2 = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
2530     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_EVALUATION_SHADER_EXT) failed!");
2531 
2532     m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2533     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_FRAGMENT_SHADER) failed!");
2534 
2535     /* Transform Feedback setup for case 1
2536      *
2537      * Varyings array: m_tf_varyings_names[i <  m_gl_max_tess_evaluation_output_components_value / 4-1] == "Vertex.value[i]"
2538      *                 m_tf_varyings_names[i == m_gl_max_tess_evaluation_output_components_value / 4-1] == "gl_Position"
2539      */
2540     const char position_varying[] = "gl_Position";
2541 
2542     m_tf_varyings_names = (char **)malloc((m_gl_max_tess_evaluation_output_components_value / 4) * sizeof(char *));
2543 
2544     if (m_tf_varyings_names == DE_NULL)
2545     {
2546         throw tcu::ResourceError("Unable to allocate memory!");
2547     }
2548 
2549     for (int i = 0; i < (m_gl_max_tess_evaluation_output_components_value) / 4 /* attributes */ - 1 /* gl_Position */;
2550          i++)
2551     {
2552         std::stringstream tf_varying_stream;
2553         const char *tf_varying_raw_ptr = DE_NULL;
2554         std::string tf_varying_string;
2555 
2556         tf_varying_stream << "Vertex.value[" << i << "]";
2557         tf_varying_string  = tf_varying_stream.str();
2558         tf_varying_raw_ptr = tf_varying_string.c_str();
2559 
2560         m_tf_varyings_names[i] = (char *)malloc(strlen(tf_varying_raw_ptr) + 1 /* '\0' */);
2561         if (m_tf_varyings_names[i] == DE_NULL)
2562         {
2563             throw tcu::ResourceError("Unable to allocate memory!");
2564         }
2565 
2566         memcpy(m_tf_varyings_names[i], tf_varying_raw_ptr, strlen(tf_varying_raw_ptr) + 1);
2567     }
2568 
2569     m_tf_varyings_names[m_gl_max_tess_evaluation_output_components_value / 4 - 1 /* gl_Position */] =
2570         (char *)malloc(sizeof(position_varying));
2571     if (m_tf_varyings_names[m_gl_max_tess_evaluation_output_components_value / 4 - 1 /* gl_Position */] == DE_NULL)
2572     {
2573         throw tcu::ResourceError("Unable to allocate memory!");
2574     }
2575 
2576     memcpy(m_tf_varyings_names[m_gl_max_tess_evaluation_output_components_value / 4 - 1 /* gl_Position */],
2577            position_varying, sizeof(position_varying));
2578 
2579     /* Set up XFB */
2580     gl.transformFeedbackVaryings(m_po_id_1, m_gl_max_tess_evaluation_output_components_value / 4, m_tf_varyings_names,
2581                                  GL_INTERLEAVED_ATTRIBS);
2582     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed!");
2583 
2584     /* Set up program objects */
2585     const char *vs_code_raw_ptr    = m_vs_code;
2586     const char *tcs_code_1_raw_ptr = m_tcs_code_1;
2587     const char *tes_code_1_raw_ptr = m_tes_code_1;
2588     const char *tcs_code_2_raw_ptr = m_tcs_code_2;
2589     const char *tes_code_2_raw_ptr = m_tes_code_2;
2590 
2591     /* Build a program object to test case 1. */
2592     if (!TessellationShaderTessellationMaxInOut::buildProgram(m_po_id_1, m_vs_id_1, 1, &vs_code_raw_ptr, m_tcs_id_1, 1,
2593                                                               &tcs_code_1_raw_ptr, m_tes_id_1, 1, &tes_code_1_raw_ptr,
2594                                                               m_fs_id, 1, &m_fs_code))
2595     {
2596         TCU_FAIL("Could not build first test program object");
2597     }
2598 
2599     /* Tranform Feedback setup for case 2 */
2600     const char *const tf_varying_2 = "out_value";
2601 
2602     gl.transformFeedbackVaryings(m_po_id_2, 1 /* count */, &tf_varying_2, GL_INTERLEAVED_ATTRIBS);
2603     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed!");
2604 
2605     /* Build a program object for case 2 */
2606     if (!(TessellationShaderTessellationMaxInOut::buildProgram(m_po_id_2, m_vs_id_2, 1, &vs_code_raw_ptr, m_tcs_id_2, 1,
2607                                                                &tcs_code_2_raw_ptr, m_tes_id_2, 1, &tes_code_2_raw_ptr,
2608                                                                m_fs_id, 1, &m_fs_code)))
2609     {
2610         TCU_FAIL("Could not link second test program object");
2611     }
2612 }
2613 
2614 /** Initializes the test.
2615  *
2616  *  Note the function throws exception should an error occur!
2617  **/
initTest(void)2618 void TessellationShaderTessellationMaxInOut::initTest(void)
2619 {
2620     /* Render state setup */
2621     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2622 
2623     /* Skip if required extensions are not supported. */
2624     if (!m_is_tessellation_shader_supported)
2625     {
2626         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
2627     }
2628 
2629     /* Initialize vertex array object */
2630     gl.genVertexArrays(1, &m_vao_id);
2631     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
2632 
2633     gl.bindVertexArray(m_vao_id);
2634     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
2635 
2636     /* All tessellation control shaders used by this test assume two
2637      * vertices are going to be provided per input patch. */
2638     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 2);
2639 
2640     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed!");
2641 
2642     /* Carry on with initialization */
2643     retrieveGLConstantValues();
2644     initProgramObjects();
2645     initBufferObjects();
2646     initReferenceValues();
2647 
2648     gl.enable(GL_RASTERIZER_DISCARD);
2649     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(RASTERIZER_DISCARD) failed!");
2650 }
2651 
2652 /** Initializes reference values that will be compared against
2653  *  values generated by the program object.
2654  *  Fills m_ref_vertex_attributes and m_ref_patch_attributes arrays.
2655  *  These arrays are later used by compareValues() function.
2656  **/
initReferenceValues(void)2657 void TessellationShaderTessellationMaxInOut::initReferenceValues(void)
2658 {
2659     /* Allocate vertex attribute array data needed for reference values preparation. */
2660     int max_array_size = de::max(m_gl_max_tess_control_input_components_value,
2661                                  de::max(m_gl_max_tess_control_output_components_value,
2662                                          de::max(m_gl_max_tess_evaluation_input_components_value,
2663                                                  m_gl_max_tess_evaluation_output_components_value)));
2664 
2665     m_ref_vertex_attributes = (glw::GLfloat *)malloc(sizeof(glw::GLfloat) * (max_array_size));
2666     if (m_ref_vertex_attributes == DE_NULL)
2667     {
2668         throw tcu::ResourceError("Unable to allocate memory!");
2669     }
2670 
2671     /* We need to create an array consisting of gl_max_tess_evaluation_output_components items.
2672      * The array will be filled with the following values:
2673      *
2674      * reference_value[0],
2675      * (...)
2676      * reference_value[gl_max_tess_evaluation_output_components / 4 - 2],
2677      * reference_gl_Position
2678      *
2679      * which corresponds to output block defined for Tessellation Evaluation Stage:
2680      *
2681      * out Vertex
2682      * {
2683      *     vec4 value[(gl_MaxTessControlInputComponents) / 4 - 1];
2684      * } outVertex;
2685      *
2686      * + gl_Position.
2687      */
2688     glw::GLfloat sumInTCS[] = {0.0f, 0.0f, 0.0f, 0.0f};
2689     glw::GLfloat sumInTES[] = {0.0f, 0.0f, 0.0f, 0.0f};
2690 
2691     for (int i = 0; i < m_gl_max_tess_control_input_components_value - 4; /* gl_Position */
2692          i++)
2693     {
2694         m_ref_vertex_attributes[i] = (glw::GLfloat)i;
2695     }
2696 
2697     for (int i = 0; i < m_gl_max_tess_control_input_components_value - 4; /* gl_Position */
2698          i++)
2699     {
2700         sumInTCS[i % 4 /* component selector */] += m_ref_vertex_attributes[i];
2701     }
2702 
2703     for (int i = 0; i < m_gl_max_tess_control_output_components_value - 4; /* gl_Position */
2704          i++)
2705     {
2706         m_ref_vertex_attributes[i] = sumInTCS[i % 4] + (glw::GLfloat)i;
2707     }
2708 
2709     for (int i = m_gl_max_tess_control_input_components_value - 4; /* gl_Position */
2710          i < m_gl_max_tess_control_output_components_value - 4;    /* gl_Position */
2711          i++)
2712     {
2713         m_ref_vertex_attributes[i] = (glw::GLfloat)i;
2714     }
2715 
2716     for (int i = 0; i < m_gl_max_tess_evaluation_input_components_value - 4; /* gl_Position */
2717          i++)
2718     {
2719         sumInTES[i % 4 /* component selector */] += m_ref_vertex_attributes[i];
2720     }
2721 
2722     for (int i = 0; i < m_gl_max_tess_evaluation_output_components_value - 4; /* gl_Position */
2723          i++)
2724     {
2725         m_ref_vertex_attributes[i] = sumInTES[i % 4 /* component selector */] + (glw::GLfloat)i;
2726     }
2727 
2728     for (int i = m_gl_max_tess_evaluation_input_components_value - 4; /* gl_Position */
2729          i < m_gl_max_tess_evaluation_output_components_value - 4;    /* gl_Position */
2730          i++)
2731     {
2732         m_ref_vertex_attributes[i] = (glw::GLfloat)i;
2733     }
2734 
2735     /* Store gl_Position reference values (only first vertex will be compared) */
2736     m_ref_vertex_attributes[m_gl_max_tess_evaluation_output_components_value - 4] = 0.0f;
2737     m_ref_vertex_attributes[m_gl_max_tess_evaluation_output_components_value - 3] = 0.0f;
2738     m_ref_vertex_attributes[m_gl_max_tess_evaluation_output_components_value - 2] = 0.0f;
2739     m_ref_vertex_attributes[m_gl_max_tess_evaluation_output_components_value - 1] = 1.0f;
2740 
2741     /* Set up reference data for case 2
2742      *
2743      * Only one output vector will be needed for comparison.
2744      */
2745     m_ref_patch_attributes[0] = 0.0f;
2746     m_ref_patch_attributes[1] = 0.0f;
2747     m_ref_patch_attributes[2] = 0.0f;
2748     m_ref_patch_attributes[3] = 0.0f;
2749 
2750     for (int i = 0; i < m_gl_max_tess_patch_components_value; i++)
2751     {
2752         m_ref_patch_attributes[i % 4] += (glw::GLfloat)i;
2753     }
2754 }
2755 
2756 /** Retrieve OpenGL state and implementation values.
2757  *
2758  *  Note the function throws exception should an error occur!
2759  **/
retrieveGLConstantValues(void)2760 void TessellationShaderTessellationMaxInOut::retrieveGLConstantValues(void)
2761 {
2762     /* Retrieve ES entry-points. */
2763     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2764 
2765     /* Query implementation constants */
2766     gl.getIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &m_gl_max_vertex_output_components_value);
2767     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_VERTEX_OUTPUT_COMPONENTS pname!");
2768 
2769     gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_INPUT_COMPONENTS, &m_gl_max_tess_control_input_components_value);
2770     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT pname!");
2771 
2772     gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_OUTPUT_COMPONENTS, &m_gl_max_tess_control_output_components_value);
2773     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT pname!");
2774 
2775     gl.getIntegerv(m_glExtTokens.MAX_TESS_PATCH_COMPONENTS, &m_gl_max_tess_patch_components_value);
2776     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_PATCH_COMPONENTS_EXT pname!");
2777 
2778     gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_INPUT_COMPONENTS,
2779                    &m_gl_max_tess_evaluation_input_components_value);
2780     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT pname!");
2781 
2782     gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,
2783                    &m_gl_max_tess_evaluation_output_components_value);
2784     GLU_EXPECT_NO_ERROR(gl.getError(),
2785                         "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT pname!");
2786 
2787     gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
2788                    &m_gl_max_transform_feedback_interleaved_components_value);
2789     GLU_EXPECT_NO_ERROR(gl.getError(),
2790                         "glGetIntegerv() failed for GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS pname!");
2791 
2792     /* Quick checks */
2793     DE_ASSERT(m_gl_max_vertex_output_components_value != 0);
2794     DE_ASSERT(m_gl_max_tess_control_input_components_value != 0);
2795     DE_ASSERT(m_gl_max_tess_control_output_components_value != 0);
2796     DE_ASSERT(m_gl_max_tess_patch_components_value != 0);
2797     DE_ASSERT(m_gl_max_tess_evaluation_input_components_value != 0);
2798     DE_ASSERT(m_gl_max_tess_evaluation_output_components_value != 0);
2799     DE_ASSERT(m_gl_max_transform_feedback_interleaved_components_value != 0);
2800 
2801     /* Make sure it is possible to transfer all components through all the stages.
2802      * If not, the test may fail, so we throw not supported. */
2803     if (m_gl_max_vertex_output_components_value < m_gl_max_tess_control_input_components_value)
2804     {
2805         m_testCtx.getLog() << tcu::TestLog::Message << "Warning: GL_MAX_VERTEX_OUTPUT_COMPONENTS value:"
2806                            << m_gl_max_vertex_output_components_value
2807                            << " is less than GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT: "
2808                            << m_gl_max_tess_control_input_components_value
2809                            << ". It may not be possible to pass all GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT "
2810                               "per-vertex components from Vertex Shader to Tessellation Control Shader."
2811                            << tcu::TestLog::EndMessage;
2812         throw tcu::NotSupportedError("GL_MAX_VERTEX_OUTPUT_COMPONENTS < GL_MAX_TESS_CONTROL_INPUT_COMPONENTS");
2813     }
2814 
2815     if (m_gl_max_tess_control_output_components_value != m_gl_max_tess_evaluation_input_components_value)
2816     {
2817         m_testCtx.getLog() << tcu::TestLog::Message << "Warning: GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT:"
2818                            << m_gl_max_tess_control_output_components_value
2819                            << " is not equal to GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT:"
2820                            << m_gl_max_tess_evaluation_input_components_value
2821                            << ". It may not be possible to pass all GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT "
2822                               "per-vertex components from Tessellation Control Shader to Tessellation "
2823                               "Evaluation Shader."
2824                            << tcu::TestLog::EndMessage;
2825         throw tcu::NotSupportedError("GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS != "
2826                                      "GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS");
2827     }
2828 
2829     if (m_gl_max_tess_evaluation_output_components_value > m_gl_max_transform_feedback_interleaved_components_value)
2830     {
2831         m_testCtx.getLog() << tcu::TestLog::Message << "Warning: GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT:"
2832                            << m_gl_max_tess_evaluation_output_components_value
2833                            << " is greater than GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:"
2834                            << m_gl_max_transform_feedback_interleaved_components_value
2835                            << ". It may not be possible to check all GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT "
2836                               "per-vertex components from Tessellation Evaluation Shader."
2837                            << tcu::TestLog::EndMessage;
2838         throw tcu::NotSupportedError("GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS > "
2839                                      "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS");
2840     }
2841 }
2842 
2843 /** Maps buffer object storage bound to GL_TRANSFORM_FEEDBACK_BUFFER binding point into process space
2844  *  and verifies the downloaded data matches the user-provided reference data.
2845  *
2846  *  Note the function throws exception should an error occur!
2847  *
2848  *  @param description        Case description;
2849  *  @param reference_values   Array storing reference data;
2850  *  @param n_reference_values Number of vec4s available for reading under @param reference_values;
2851  *
2852  *  @return false if the comparison failed, or true otherwise.
2853  **/
compareValues(char const * description,glw::GLfloat * reference_values,int n_reference_values)2854 bool TessellationShaderTessellationMaxInOut::compareValues(char const *description, glw::GLfloat *reference_values,
2855                                                            int n_reference_values)
2856 {
2857     /* Retrieve ES entry-points */
2858     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2859 
2860     /* Map the buffer storage into process space. */
2861     glw::GLint bo_size = static_cast<glw::GLint>(2 /* number of vertices */ * sizeof(glw::GLfloat) *
2862                                                  n_reference_values * 4); /* number of components */
2863     glw::GLfloat *resultFloats =
2864         (glw::GLfloat *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bo_size, GL_MAP_READ_BIT);
2865     GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
2866 
2867     /* Verify the data */
2868     const glw::GLfloat epsilon = (glw::GLfloat)1e-5f;
2869     bool test_passed           = true;
2870 
2871     for (int i = 0; i < n_reference_values * 4 /* number of components */; i += 4 /* number of components */)
2872     {
2873         if ((de::abs(resultFloats[i] - reference_values[i]) > epsilon) ||
2874             (de::abs(resultFloats[i + 1] - reference_values[i + 1]) > epsilon) ||
2875             (de::abs(resultFloats[i + 2] - reference_values[i + 2]) > epsilon) ||
2876             (de::abs(resultFloats[i + 3] - reference_values[i + 3]) > epsilon))
2877         {
2878             m_testCtx.getLog() << tcu::TestLog::Message << description << ": captured results "
2879                                << "vec4(" << resultFloats[i + 0] << ", " << resultFloats[i + 1] << ", "
2880                                << resultFloats[i + 2] << ", " << resultFloats[i + 3] << ") "
2881                                << "are different from the expected values "
2882                                << "vec4(" << reference_values[i + 0] << ", " << reference_values[i + 1] << ", "
2883                                << reference_values[i + 2] << ", " << reference_values[i + 3] << ")."
2884                                << tcu::TestLog::EndMessage;
2885 
2886             test_passed = false;
2887             break;
2888         }
2889     }
2890 
2891     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2892     GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed!");
2893 
2894     return test_passed;
2895 }
2896 
2897 } /* namespace glcts */
2898