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 "esextcTessellationShaderXFB.hpp"
25 #include "esextcTessellationShaderUtils.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "glwFunctions.hpp"
30 #include "tcuTestLog.hpp"
31 
32 namespace glcts
33 {
34 
35 /** Constructor
36  *
37  * @param context Test context
38  **/
TessellationShaderXFB(Context & context,const ExtParameters & extParams)39 TessellationShaderXFB::TessellationShaderXFB(Context &context, const ExtParameters &extParams)
40     : TestCaseBase(context, extParams, "xfb_captures_data_from_correct_stage",
41                    "Verifies transform-feedback captures data from appropriate shader stage.")
42     , m_bo_id(0)
43     , m_fs_id(0)
44     , m_gs_id(0)
45     , m_po_id(0)
46     , m_tc_id(0)
47     , m_te_id(0)
48     , m_vs_id(0)
49     , m_pipeline_id(0)
50     , m_fs_program_id(0)
51     , m_gs_program_id(0)
52     , m_tc_program_id(0)
53     , m_te_program_id(0)
54     , m_vs_program_id(0)
55     , m_vao_id(0)
56 {
57     /* Left blank on purpose */
58 }
59 
60 /** Deinitializes ES objects created for the test. */
deinit()61 void TessellationShaderXFB::deinit()
62 {
63     /* Call base class' deinit() */
64     TestCaseBase::deinit();
65 
66     if (!m_is_tessellation_shader_supported)
67     {
68         return;
69     }
70 
71     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
72 
73     /* Reset GL_PATCH_VERTICES_EXT value */
74     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
75 
76     /* Disable any pipeline object that may still be active */
77     gl.bindProgramPipeline(0);
78 
79     /* Reset TF buffer object bindings */
80     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
81     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
82 
83     /* Unbind vertex array object */
84     gl.bindVertexArray(0);
85 
86     /* Free all ES objects we allocated for the test */
87     if (m_bo_id != 0)
88     {
89         gl.deleteBuffers(1, &m_bo_id);
90 
91         m_bo_id = 0;
92     }
93 
94     if (m_fs_id != 0)
95     {
96         gl.deleteShader(m_fs_id);
97 
98         m_fs_id = 0;
99     }
100 
101     if (m_fs_program_id != 0)
102     {
103         gl.deleteProgram(m_fs_program_id);
104 
105         m_fs_program_id = 0;
106     }
107 
108     if (m_gs_id != 0)
109     {
110         gl.deleteShader(m_gs_id);
111 
112         m_gs_id = 0;
113     }
114 
115     if (m_gs_program_id != 0)
116     {
117         gl.deleteProgram(m_gs_program_id);
118 
119         m_gs_program_id = 0;
120     }
121 
122     if (m_pipeline_id != 0)
123     {
124         gl.deleteProgramPipelines(1, &m_pipeline_id);
125 
126         m_pipeline_id = 0;
127     }
128 
129     if (m_po_id != 0)
130     {
131         gl.deleteProgram(m_po_id);
132 
133         m_po_id = 0;
134     }
135 
136     if (m_tc_id != 0)
137     {
138         gl.deleteShader(m_tc_id);
139 
140         m_tc_id = 0;
141     }
142 
143     if (m_tc_program_id != 0)
144     {
145         gl.deleteProgram(m_tc_program_id);
146 
147         m_tc_program_id = 0;
148     }
149 
150     if (m_te_id != 0)
151     {
152         gl.deleteShader(m_te_id);
153 
154         m_te_id = 0;
155     }
156 
157     if (m_te_program_id != 0)
158     {
159         gl.deleteProgram(m_te_program_id);
160 
161         m_te_program_id = 0;
162     }
163 
164     if (m_vs_id != 0)
165     {
166         gl.deleteShader(m_vs_id);
167 
168         m_vs_id = 0;
169     }
170 
171     if (m_vs_program_id != 0)
172     {
173         gl.deleteProgram(m_vs_program_id);
174 
175         m_vs_program_id = 0;
176     }
177 
178     if (m_vao_id != 0)
179     {
180         gl.deleteVertexArrays(1, &m_vao_id);
181 
182         m_vao_id = 0;
183     }
184 }
185 
186 /** Create separable programs **/
createSeparableProgram(glw::GLenum shader_type,unsigned int n_strings,const char * const * strings,unsigned int n_varyings,const char * const * varyings,bool should_succeed)187 glw::GLuint TessellationShaderXFB::createSeparableProgram(glw::GLenum shader_type, unsigned int n_strings,
188                                                           const char *const *strings, unsigned int n_varyings,
189                                                           const char *const *varyings, bool should_succeed)
190 {
191     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
192     glw::GLuint po_id        = 0;
193     glw::GLuint so_id        = 0;
194 
195     /* Create a shader object */
196     so_id = gl.createShader(shader_type);
197     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
198 
199     /* Create a program object */
200     po_id = gl.createProgram();
201     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
202 
203     /* Mark the program object as separable */
204     gl.programParameteri(po_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
205     GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() call failed");
206 
207     /* Configure XFB for the program object */
208     if (n_varyings != 0)
209     {
210         gl.transformFeedbackVaryings(po_id, n_varyings, varyings, GL_SEPARATE_ATTRIBS);
211         GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
212     }
213 
214     bool build_success = buildProgram(po_id, so_id, n_strings, strings);
215 
216     /* Safe to delete the shader object at this point */
217     gl.deleteShader(so_id);
218     GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed");
219 
220     if (!build_success)
221     {
222         gl.deleteProgram(po_id);
223         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram() call failed");
224         po_id = 0;
225 
226         if (should_succeed)
227         {
228             TCU_FAIL("Separable program should have succeeded");
229         }
230     }
231     else if (!should_succeed)
232     {
233         std::string shader_source = getShaderSource(so_id);
234         m_testCtx.getLog() << tcu::TestLog::Message << "Shader source:\n\n"
235                            << shader_source << "\n\n"
236                            << tcu::TestLog::EndMessage;
237         TCU_FAIL("Separable program should have failed");
238     }
239 
240     return po_id;
241 }
242 
243 /** Initializes ES objects necessary to run the test. */
initTest()244 void TessellationShaderXFB::initTest()
245 {
246     /* Skip if required extensions are not supported. */
247     if (!m_is_tessellation_shader_supported)
248     {
249         return;
250     }
251 
252     /* Generate all objects needed for the test */
253     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
254 
255     gl.genVertexArrays(1, &m_vao_id);
256     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
257 
258     gl.bindVertexArray(m_vao_id);
259     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
260 
261     gl.genBuffers(1, &m_bo_id);
262     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
263 
264     m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
265     m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
266     m_te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
267     m_vs_id = gl.createShader(GL_VERTEX_SHADER);
268     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
269 
270     m_po_id = gl.createProgram();
271     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
272 
273     if (m_is_geometry_shader_extension_supported)
274     {
275         m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
276         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed for GL_GEOMETRY_SHADER_EXT");
277     }
278 
279     gl.genProgramPipelines(1, &m_pipeline_id);
280     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() failed");
281 
282     /* Configure fragment shader body */
283     const char *fs_body = "${VERSION}\n"
284                           "\n"
285                           "${SHADER_IO_BLOCKS_REQUIRE}\n"
286                           "\n"
287                           "precision highp float;\n"
288                           "in BLOCK_INOUT { vec4 value; } user_in;\n"
289                           "\n"
290                           "void main()\n"
291                           "{\n"
292                           "}\n";
293 
294     shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
295     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
296 
297     /* Create a fragment shader program */
298     glw::GLint link_status          = GL_FALSE;
299     const glw::GLchar *varying_name = "BLOCK_INOUT.value";
300 
301     m_fs_program_id = createSeparableProgram(GL_FRAGMENT_SHADER, 1, /* n_strings */
302                                              &fs_body, 0,           /* n_varyings */
303                                              DE_NULL,               /* varyings */
304                                              true);                 /* should_succeed */
305 
306     gl.getProgramiv(m_fs_program_id, GL_LINK_STATUS, &link_status);
307     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
308 
309     if (link_status != GL_TRUE)
310     {
311         TCU_FAIL("Fragment shader program failed to link.");
312     }
313 
314     /* Configure geometry shader body */
315     const char *gs_body = "${VERSION}\n"
316                           "\n"
317                           "${GEOMETRY_SHADER_REQUIRE}\n"
318                           "\n"
319                           "layout(points)                   in;\n"
320                           "layout(points, max_vertices = 1) out;\n"
321                           "\n"
322                           "precision highp float;\n"
323                           "${IN_PER_VERTEX_DECL_ARRAY}"
324                           "${OUT_PER_VERTEX_DECL}"
325                           "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
326                           "out BLOCK_INOUT { vec4 value; } user_out;\n"
327                           "\n"
328                           "void main()\n"
329                           "{\n"
330                           "    user_out.value = vec4(1.0, 2.0, 3.0, 4.0);\n"
331                           "    gl_Position    = vec4(0.0, 0.0, 0.0, 1.0);\n"
332                           "\n"
333                           "    EmitVertex();\n"
334                           "}\n";
335 
336     if (m_is_geometry_shader_extension_supported)
337     {
338         shaderSourceSpecialized(m_gs_id, 1 /* count */, &gs_body);
339         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for geometry shader");
340 
341         /* Create a geometry shader program */
342         m_gs_program_id = createSeparableProgram(m_glExtTokens.GEOMETRY_SHADER, 1, /* n_strings */
343                                                  &gs_body, 1,                      /* n_varyings */
344                                                  &varying_name, true);             /* should_succeed */
345 
346         if (m_gs_program_id == 0)
347         {
348             TCU_FAIL("Could not create a separate geometry program object");
349         }
350 
351         gl.getProgramiv(m_gs_program_id, GL_LINK_STATUS, &link_status);
352         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
353 
354         if (link_status != GL_TRUE)
355         {
356             TCU_FAIL("Geometry shader program failed to link.");
357         }
358     }
359 
360     /* Configure tessellation control shader body */
361     const char *tc_body = "${VERSION}\n"
362                           "\n"
363                           "${TESSELLATION_SHADER_REQUIRE}\n"
364                           "\n"
365                           "layout (vertices=4) out;\n"
366                           "\n"
367                           "precision highp float;\n"
368                           "${IN_PER_VERTEX_DECL_ARRAY}"
369                           "${OUT_PER_VERTEX_DECL_ARRAY}"
370                           "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
371                           "out BLOCK_INOUT { vec4 value; } user_out[];\n"
372                           "\n"
373                           "void main()\n"
374                           "{\n"
375                           "    gl_out   [gl_InvocationID].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
376                           "    user_out [gl_InvocationID].value       = vec4(2.0, 3.0, 4.0, 5.0);\n"
377                           "\n"
378                           "    gl_TessLevelOuter[0] = 1.0;\n"
379                           "    gl_TessLevelOuter[1] = 1.0;\n"
380                           "}\n";
381 
382     shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body);
383     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
384 
385     /* Test creating a tessellation control shader program with feedback.
386      * For ES, this will fail, and so we will create a different
387      * program without the feedback varyings that we can use for our testing.
388      * (We can safely ignore the return value for the expected failure case.
389      * In the event that the failure case incorrectly succeeds,
390      * createSeparableProgram will generate a test failure exception.)
391      */
392 
393     bool tc_feedback_valid;
394     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
395     {
396         tc_feedback_valid = true;
397     }
398     else
399     {
400         tc_feedback_valid = false;
401     }
402 
403     /* Create a tessellation control shader program */
404     m_tc_program_id = createSeparableProgram(m_glExtTokens.TESS_CONTROL_SHADER, 1, /* n_strings */
405                                              &tc_body, 1,                          /* n_varyings */
406                                              &varying_name,                        /* varyings */
407                                              tc_feedback_valid);                   /* should_succeed */
408 
409     if (!tc_feedback_valid)
410     {
411         /* Create a valid tessellation control shader program for ES */
412         m_tc_program_id = createSeparableProgram(m_glExtTokens.TESS_CONTROL_SHADER, 1, /* n_strings */
413                                                  &tc_body, 0,                          /* n_varyings */
414                                                  DE_NULL,                              /* varyings */
415                                                  true);                                /* should_succeed */
416     }
417 
418     if (m_tc_program_id == 0)
419     {
420         TCU_FAIL("Could not create a separate tessellation control program object");
421     }
422 
423     gl.getProgramiv(m_tc_program_id, GL_LINK_STATUS, &link_status);
424     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
425 
426     if (link_status != GL_TRUE)
427     {
428         TCU_FAIL("Tessellation control shader program failed to link.");
429     }
430 
431     /* Configure tessellation evaluation shader body */
432     const char *te_body = "${VERSION}\n"
433                           "\n"
434                           "${TESSELLATION_SHADER_REQUIRE}\n"
435                           "\n"
436                           "layout (isolines, point_mode) in;\n"
437                           "\n"
438                           "precision highp float;\n"
439                           "${IN_PER_VERTEX_DECL_ARRAY}"
440                           "${OUT_PER_VERTEX_DECL}"
441                           "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
442                           "out BLOCK_INOUT { vec4 value; } user_out;\n"
443                           "\n"
444                           "void main()\n"
445                           "{\n"
446                           "    gl_Position     = gl_in[0].gl_Position;\n"
447                           "    user_out.value = vec4(3.0, 4.0, 5.0, 6.0);\n"
448                           "}\n";
449 
450     shaderSourceSpecialized(m_te_id, 1 /* count */, &te_body);
451     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
452 
453     /* Create a tessellation evaluation shader program */
454     m_te_program_id = createSeparableProgram(m_glExtTokens.TESS_EVALUATION_SHADER, 1, /* n_strings */
455                                              &te_body, 1,                             /* n_varyings */
456                                              &varying_name, true);                    /* should_succeed */
457 
458     if (m_te_program_id == 0)
459     {
460         TCU_FAIL("Could not create a separate tessellation evaluation program object");
461     }
462 
463     gl.getProgramiv(m_te_program_id, GL_LINK_STATUS, &link_status);
464     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
465 
466     if (link_status != GL_TRUE)
467     {
468         TCU_FAIL("Tessellation evaluation shader program failed to link.");
469     }
470 
471     /* Configure vertex shader body */
472     const char *vs_body = "${VERSION}\n"
473                           "\n"
474                           "${SHADER_IO_BLOCKS_REQUIRE}\n"
475                           "\n"
476                           "precision highp float;\n"
477                           "${OUT_PER_VERTEX_DECL}"
478                           "out BLOCK_INOUT { vec4 value; } user_out;\n"
479                           "\n"
480                           "void main()\n"
481                           "{\n"
482                           "    gl_Position    = vec4(1.0, 0.0, 0.0, 1.0);\n"
483                           "    user_out.value = vec4(4.0, 5.0, 6.0, 7.0);\n"
484                           "}\n";
485 
486     shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
487     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
488 
489     /* Configure vertex shader program */
490     m_vs_program_id = createSeparableProgram(GL_VERTEX_SHADER, 1,  /* n_strings */
491                                              &vs_body, 1,          /* n_varyings */
492                                              &varying_name, true); /* should_succeed */
493 
494     /* Compile all the shaders */
495     const glw::GLuint shaders[]  = {m_fs_id, (m_is_geometry_shader_extension_supported) ? m_gs_id : 0, m_tc_id, m_te_id,
496                                     m_vs_id};
497     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
498 
499     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
500     {
501         glw::GLuint shader = shaders[n_shader];
502 
503         if (shader != 0)
504         {
505             glw::GLint compile_status = GL_FALSE;
506 
507             gl.compileShader(shader);
508             GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
509 
510             gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
511             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
512 
513             if (compile_status != GL_TRUE)
514             {
515                 const char *src[] = {fs_body, gs_body, tc_body, te_body, vs_body};
516 
517                 m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
518                                    << " failed.\n"
519                                    << "Info log:\n"
520                                    << getCompilationInfoLog(shader) << "Shader:\n"
521                                    << src[n_shader] << tcu::TestLog::EndMessage;
522 
523                 TCU_FAIL("Shader compilation failed");
524             }
525         }
526     } /* for (all shaders) */
527 
528     /* Attach fragment & vertex shaders to the program object */
529     gl.attachShader(m_po_id, m_fs_id);
530     gl.attachShader(m_po_id, m_vs_id);
531     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
532 
533     /* Configure pipeline object's fragment & vertex stages */
534     gl.useProgramStages(m_pipeline_id, GL_FRAGMENT_SHADER_BIT, m_fs_program_id);
535     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed for fragment stage");
536 
537     gl.useProgramStages(m_pipeline_id, GL_VERTEX_SHADER_BIT, m_vs_program_id);
538     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed for vertex stage");
539 
540     /* Set up XFB for conventional program object */
541     gl.transformFeedbackVaryings(m_po_id, 1 /* count */, &varying_name, GL_SEPARATE_ATTRIBS);
542     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
543 
544     /* Set up buffer object storage.
545      * We allocate enough space for a 4 vertex patch, which is the size
546      * needed by desktop GL for the tessellation control shader feedback
547      * whenever GL_NV_gpu_shader5 is present. */
548     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
549     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
550 
551     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4 /* components */ * 4 /* vertices per patch */,
552                   NULL, /* data */
553                   GL_STATIC_DRAW);
554     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
555 
556     /* Bind the buffer object to indiced TF binding point */
557     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
558     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
559 }
560 
561 /** Executes the test.
562  *
563  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
564  *
565  *  Note the function throws exception should an error occur!
566  *
567  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
568  **/
iterate(void)569 tcu::TestNode::IterateResult TessellationShaderXFB::iterate(void)
570 {
571     /* Do not execute if required extensions are not supported. */
572     if (!m_is_tessellation_shader_supported)
573     {
574         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
575     }
576 
577     typedef std::vector<_test_descriptor> _tests;
578     typedef _tests::const_iterator _tests_const_iterator;
579 
580     /* Initialize ES test objects */
581     initTest();
582 
583     /* Describe test iterations */
584     _test_descriptor test_1; /* vs+tc+te+gs */
585     _test_descriptor test_2; /* vs+tc+te */
586     _test_descriptor test_3; /* vs+tc */
587     _tests tests;
588 
589     if (m_is_geometry_shader_extension_supported)
590     {
591         test_1.expected_data_source  = m_glExtTokens.GEOMETRY_SHADER;
592         test_1.expected_n_values     = 2;
593         test_1.should_draw_call_fail = false;
594         test_1.requires_pipeline     = false;
595         test_1.tf_mode               = GL_POINTS;
596         test_1.use_gs                = true;
597         test_1.use_tc                = true;
598         test_1.use_te                = true;
599 
600         tests.push_back(test_1);
601     }
602 
603     test_2.expected_data_source  = m_glExtTokens.TESS_EVALUATION_SHADER;
604     test_2.expected_n_values     = 2;
605     test_2.should_draw_call_fail = false;
606     test_2.requires_pipeline     = false;
607     test_2.tf_mode               = GL_POINTS;
608     test_2.use_gs                = false;
609     test_2.use_tc                = true;
610     test_2.use_te                = true;
611 
612     tests.push_back(test_2);
613 
614     /* Note: This is a special negative case */
615     test_3.expected_data_source = m_glExtTokens.TESS_CONTROL_SHADER;
616     test_3.expected_n_values    = 4;
617     if (!glu::isContextTypeES(m_context.getRenderContext().getType()) && isExtensionSupported("GL_NV_gpu_shader5"))
618     {
619         test_3.should_draw_call_fail = false;
620         test_3.tf_mode               = m_glExtTokens.PATCHES;
621     }
622     else
623     {
624         test_3.should_draw_call_fail = true;
625         test_3.tf_mode               = GL_POINTS;
626     }
627     test_3.requires_pipeline = true;
628     test_3.use_gs            = false;
629     test_3.use_tc            = true;
630     test_3.use_te            = false;
631 
632     tests.push_back(test_3);
633 
634     /* Use only one vertex per patch */
635     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
636 
637     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
638 
639     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed.");
640 
641     /* This test runs in two iterations:
642      *
643      * 1) Shaders are attached to a program object at the beginning of
644      *    each test. The test then executes. Once it's completed, the
645      *    shaders are detached from the program object;
646      * 2) A pipeline object is used instead of a program object.
647      */
648     for (int n_iteration = 0; n_iteration < 2; ++n_iteration)
649     {
650         bool use_pipeline_object = (n_iteration == 1);
651 
652         if (use_pipeline_object)
653         {
654             gl.bindProgramPipeline(m_pipeline_id);
655             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() failed.");
656 
657             gl.useProgram(0);
658             GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
659         }
660         else
661         {
662             gl.bindProgramPipeline(0);
663             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() failed.");
664 
665             /* The program object will be shortly re-linked so defer the glUseProgram() call */
666         }
667 
668         /* Iterate through all tests */
669         for (_tests_const_iterator test_iterator = tests.begin(); test_iterator != tests.end(); test_iterator++)
670         {
671             const _test_descriptor &test = *test_iterator;
672 
673             if (use_pipeline_object)
674             {
675                 /* Configure the pipeline object */
676                 if (m_is_geometry_shader_extension_supported)
677                 {
678                     gl.useProgramStages(m_pipeline_id, m_glExtTokens.GEOMETRY_SHADER_BIT,
679                                         test.use_gs ? m_gs_program_id : 0);
680                     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_GEOMETRY_SHADER_BIT_EXT");
681                 }
682 
683                 gl.useProgramStages(m_pipeline_id, m_glExtTokens.TESS_CONTROL_SHADER_BIT,
684                                     test.use_tc ? m_tc_program_id : 0);
685                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_TESS_CONTROL_SHADER_BIT_EXT");
686 
687                 gl.useProgramStages(m_pipeline_id, m_glExtTokens.TESS_EVALUATION_SHADER_BIT,
688                                     test.use_te ? m_te_program_id : 0);
689                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_TESS_EVALUATION_SHADER_BIT_EXT");
690 
691                 /* Validate the pipeline object */
692                 gl.validateProgramPipeline(m_pipeline_id);
693                 GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() failed");
694 
695                 /* Retrieve the validation result */
696                 glw::GLint validate_status = GL_FALSE;
697 
698                 gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status);
699                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() failed");
700 
701                 if (validate_status == GL_FALSE && !test.should_draw_call_fail)
702                 {
703                     m_testCtx.getLog() << tcu::TestLog::Message << "A pipeline object consisting of: "
704                                        << "[fragment stage] " << ((test.use_gs) ? "[geometry stage] " : "")
705                                        << ((test.use_tc) ? "[tessellation control stage] " : "")
706                                        << ((test.use_te) ? "[tessellation evaluation stage] " : "") << "[vertex stage] "
707                                        << "was not validated successfully, even though it should."
708                                        << tcu::TestLog::EndMessage;
709 
710                     TCU_FAIL("Pipeline object is considered invalid, even though the stage combination is valid");
711                 }
712             }
713             else
714             {
715                 if (test.requires_pipeline)
716                 {
717                     continue;
718                 }
719 
720                 /* Attach the shaders to the program object as described in
721                  * the test descriptor */
722                 if (test.use_gs)
723                 {
724                     gl.attachShader(m_po_id, m_gs_id);
725                     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach geometry shader");
726                 }
727 
728                 if (test.use_tc)
729                 {
730                     gl.attachShader(m_po_id, m_tc_id);
731                     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach tessellation control shader");
732                 }
733 
734                 if (test.use_te)
735                 {
736                     gl.attachShader(m_po_id, m_te_id);
737                     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach tessellation evaluation shader");
738                 }
739 
740                 /* Link the program object */
741                 gl.linkProgram(m_po_id);
742                 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not link program object");
743 
744                 /* Has the linking succeeded? */
745                 glw::GLint link_status = GL_FALSE;
746 
747                 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
748                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
749 
750                 if (link_status != GL_TRUE)
751                 {
752                     m_testCtx.getLog() << tcu::TestLog::Message << "A program object consisting of: "
753                                        << "[fragment shader] " << ((test.use_gs) ? "[geometry shader] " : "")
754                                        << ((test.use_tc) ? "[tessellation control shader] " : "")
755                                        << ((test.use_te) ? "[tessellation evaluation shader] " : "")
756                                        << "[vertex shader] "
757                                        << "failed to link, even though it should link successfully."
758                                        << tcu::TestLog::EndMessage;
759 
760                     TCU_FAIL("Program linking failed, even though the shader combination was valid");
761                 }
762 
763                 gl.useProgram(m_po_id);
764                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed.");
765             }
766 
767             /* Render a single point */
768             gl.enable(GL_RASTERIZER_DISCARD);
769             GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
770 
771             gl.beginTransformFeedback(test.tf_mode);
772 
773             bool didBeginXFBFail = false;
774             if (!test.should_draw_call_fail)
775             {
776                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) failed");
777             }
778             else
779             {
780                 /* For the negative case, i.e. beginTransformFeedback with an invalid pipeline of {VS, TCS, FS},
781                  * ES spec is not clear if beginTransformFeedback should error, so relax the requirment here so
782                  * that test passes as long as either beginTransformFeedback or the next draw call raises
783                  * INVALID_OPERATION */
784                 glw::GLint err = gl.getError();
785                 if (err == GL_INVALID_OPERATION)
786                 {
787                     didBeginXFBFail = true;
788                 }
789                 else if (err != GL_NO_ERROR)
790                 {
791                     TCU_FAIL("Unexpected GL error in a beginTransformFeedback made on the program pipeline whose"
792                              "program closest to TFB has no output varying specified");
793                 }
794             }
795 
796             {
797                 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
798 
799                 if (!test.should_draw_call_fail)
800                 {
801                     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
802                 }
803                 else
804                 {
805                     if (gl.getError() != GL_INVALID_OPERATION && !didBeginXFBFail)
806                     {
807                         TCU_FAIL("A draw call made using a program object lacking TES stage has"
808                                  " not generated a GL_INVALID_OPERATION as specified");
809                     }
810                 }
811             }
812             gl.endTransformFeedback();
813 
814             if (!didBeginXFBFail)
815             {
816                 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
817             }
818             else
819             {
820                 if (gl.getError() != GL_INVALID_OPERATION)
821                 {
822                     TCU_FAIL("An endTransformFeedback made on inactive xfb has not generated a "
823                              "GL_INVALID_OPERATION as specified");
824                 }
825             }
826 
827             gl.disable(GL_RASTERIZER_DISCARD);
828             GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed");
829 
830             if (!test.should_draw_call_fail)
831             {
832                 /* Retrieve the captured result values */
833                 glw::GLfloat *result_ptr = (glw::GLfloat *)gl.mapBufferRange(
834                     GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
835                     sizeof(float) * 4 /* components */ * test.expected_n_values, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
836 
837                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
838 
839                 /* Verify the data */
840                 const glw::GLfloat epsilon            = (glw::GLfloat)1e-5;
841                 const glw::GLfloat expected_gs_data[] = {1.0f, 2.0f, 3.0f, 4.0f};
842                 const glw::GLfloat expected_tc_data[] = {2.0f, 3.0f, 4.0f, 5.0f};
843                 const glw::GLfloat expected_te_data[] = {3.0f, 4.0f, 5.0f, 6.0f};
844                 const glw::GLfloat expected_vs_data[] = {4.0f, 5.0f, 6.0f, 7.0f};
845 
846                 for (int n_value = 0; n_value < test.expected_n_values; ++n_value)
847                 {
848                     const glw::GLfloat *expected_data_ptr = NULL;
849                     const glw::GLfloat *captured_data_ptr = result_ptr + n_value * 4 /* components */;
850 
851                     if (test.expected_data_source == m_glExtTokens.GEOMETRY_SHADER)
852                     {
853                         expected_data_ptr = expected_gs_data;
854                     }
855                     else if (test.expected_data_source == m_glExtTokens.TESS_CONTROL_SHADER)
856                     {
857                         expected_data_ptr = expected_tc_data;
858                     }
859                     else if (test.expected_data_source == m_glExtTokens.TESS_EVALUATION_SHADER)
860                     {
861                         expected_data_ptr = expected_te_data;
862                     }
863                     else if (test.expected_data_source == GL_VERTEX_SHADER)
864                     {
865                         expected_data_ptr = expected_vs_data;
866                     }
867                     else
868                     {
869                         TCU_FAIL("Unrecognized expected data source");
870                     }
871 
872                     if (de::abs(captured_data_ptr[0] - expected_data_ptr[0]) > epsilon ||
873                         de::abs(captured_data_ptr[1] - expected_data_ptr[1]) > epsilon ||
874                         de::abs(captured_data_ptr[2] - expected_data_ptr[2]) > epsilon ||
875                         de::abs(captured_data_ptr[3] - expected_data_ptr[3]) > epsilon)
876                     {
877                         m_testCtx.getLog()
878                             << tcu::TestLog::Message << "Captured data "
879                             << "(" << captured_data_ptr[0] << ", " << captured_data_ptr[1] << ", "
880                             << captured_data_ptr[2] << ", " << captured_data_ptr[3] << ")"
881                             << "is different from the expected value "
882                             << "(" << expected_data_ptr[0] << ", " << expected_data_ptr[1] << ", "
883                             << expected_data_ptr[2] << ", " << expected_data_ptr[3] << ")" << tcu::TestLog::EndMessage;
884 
885                         TCU_FAIL("Invalid data captured");
886                     }
887                 }
888 
889                 /* Unmap the buffer object, since we're done */
890                 memset(result_ptr, 0, sizeof(float) * 4 /* components */ * test.expected_n_values);
891 
892                 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
893                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed");
894             } /* if (!test.should_draw_call_fail) */
895 
896             if (!use_pipeline_object)
897             {
898                 /* Detach all shaders we attached to the program object at the beginning
899                  * of the iteration */
900                 if (test.use_gs)
901                 {
902                     gl.detachShader(m_po_id, m_gs_id);
903                     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach geometry shader");
904                 }
905 
906                 if (test.use_tc)
907                 {
908                     gl.detachShader(m_po_id, m_tc_id);
909                     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach tessellation control shader");
910                 }
911 
912                 if (test.use_te)
913                 {
914                     gl.detachShader(m_po_id, m_te_id);
915                     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach tessellation evaluation shader");
916                 }
917 
918             } /* if (!use_pipeline_object) */
919             else
920             {
921                 /* We don't need to do anything with the pipeline object - stages will be
922                  * re-defined in next iteration */
923             }
924         } /* for (all tests) */
925     }     /* for (all iterations) */
926 
927     /* All done */
928     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
929     return STOP;
930 }
931 
932 } /* namespace glcts */
933