d138daf265d70cf52f3d4a233aacbd3d665f3e0a
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / glesext / tessellation_shader / esextcTessellationShaderXFB.cpp
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  **/
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. */
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 **/
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. */
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 Desktop, if GL_NV_gpu_shader5 is available this will succeed, and
387          * so we'll use it for our testing.
388          * For ES, and for Desktop implementations that don't have
389          * GL_NV_gpu_shader5, this will fail, and so we will create a different
390          * program without the feedback varyings that we can use for our testing.
391          * (We can safely ignore the return value for the expected failure case.
392          * In the event that the failure case incorrectly succeeds,
393          * createSeparableProgram will generate a test failure exception.)
394          */
395
396         bool tc_feedback_valid;
397         if (!glu::isContextTypeES(m_context.getRenderContext().getType()) && isExtensionSupported("GL_NV_gpu_shader5"))
398         {
399                 tc_feedback_valid = true;
400         }
401         else
402         {
403                 tc_feedback_valid = false;
404         }
405
406         /* Create a tessellation control shader program */
407         m_tc_program_id = createSeparableProgram(m_glExtTokens.TESS_CONTROL_SHADER, 1, /* n_strings */
408                                                                                          &tc_body, 1,                                              /* n_varyings */
409                                                                                          &varying_name,                                            /* varyings */
410                                                                                          tc_feedback_valid);                               /* should_succeed */
411
412         if (!tc_feedback_valid)
413         {
414                 /* Create a valid tessellation control shader program for ES */
415                 m_tc_program_id = createSeparableProgram(m_glExtTokens.TESS_CONTROL_SHADER, 1, /* n_strings */
416                                                                                                  &tc_body, 0,                                              /* n_varyings */
417                                                                                                  DE_NULL,                                                          /* varyings */
418                                                                                                  true);                                                            /* should_succeed */
419         }
420
421         if (m_tc_program_id == 0)
422         {
423                 TCU_FAIL("Could not create a separate tessellation control program object");
424         }
425
426         gl.getProgramiv(m_tc_program_id, GL_LINK_STATUS, &link_status);
427         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
428
429         if (link_status != GL_TRUE)
430         {
431                 TCU_FAIL("Tessellation control shader program failed to link.");
432         }
433
434         /* Configure tessellation evaluation shader body */
435         const char* te_body = "${VERSION}\n"
436                                                   "\n"
437                                                   "${TESSELLATION_SHADER_REQUIRE}\n"
438                                                   "\n"
439                                                   "layout (isolines, point_mode) in;\n"
440                                                   "\n"
441                                                   "precision highp float;\n"
442                                                   "${IN_PER_VERTEX_DECL_ARRAY}"
443                                                   "${OUT_PER_VERTEX_DECL}"
444                                                   "in  BLOCK_INOUT { vec4 value; } user_in[];\n"
445                                                   "out BLOCK_INOUT { vec4 value; } user_out;\n"
446                                                   "\n"
447                                                   "void main()\n"
448                                                   "{\n"
449                                                   "    gl_Position     = gl_in[0].gl_Position;\n"
450                                                   "    user_out.value = vec4(3.0, 4.0, 5.0, 6.0);\n"
451                                                   "}\n";
452
453         shaderSourceSpecialized(m_te_id, 1 /* count */, &te_body);
454         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
455
456         /* Create a tessellation evaluation shader program */
457         m_te_program_id = createSeparableProgram(m_glExtTokens.TESS_EVALUATION_SHADER, 1, /* n_strings */
458                                                                                          &te_body, 1,                                                     /* n_varyings */
459                                                                                          &varying_name, true);                                    /* should_succeed */
460
461         if (m_te_program_id == 0)
462         {
463                 TCU_FAIL("Could not create a separate tessellation evaluation program object");
464         }
465
466         gl.getProgramiv(m_te_program_id, GL_LINK_STATUS, &link_status);
467         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
468
469         if (link_status != GL_TRUE)
470         {
471                 TCU_FAIL("Tessellation evaluation shader program failed to link.");
472         }
473
474         /* Configure vertex shader body */
475         const char* vs_body = "${VERSION}\n"
476                                                   "\n"
477                                                   "${SHADER_IO_BLOCKS_REQUIRE}\n"
478                                                   "\n"
479                                                   "precision highp float;\n"
480                                                   "${OUT_PER_VERTEX_DECL}"
481                                                   "out BLOCK_INOUT { vec4 value; } user_out;\n"
482                                                   "\n"
483                                                   "void main()\n"
484                                                   "{\n"
485                                                   "    gl_Position    = vec4(1.0, 0.0, 0.0, 1.0);\n"
486                                                   "    user_out.value = vec4(4.0, 5.0, 6.0, 7.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         /* Configure vertex shader program */
493         m_vs_program_id = createSeparableProgram(GL_VERTEX_SHADER, 1,  /* n_strings */
494                                                                                          &vs_body, 1,              /* n_varyings */
495                                                                                          &varying_name, true); /* should_succeed */
496
497         /* Compile all the shaders */
498         const glw::GLuint shaders[] = { m_fs_id, (m_is_geometry_shader_extension_supported) ? m_gs_id : 0, m_tc_id, m_te_id,
499                                                                         m_vs_id };
500         const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
501
502         for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
503         {
504                 glw::GLuint shader = shaders[n_shader];
505
506                 if (shader != 0)
507                 {
508                         glw::GLint compile_status = GL_FALSE;
509
510                         gl.compileShader(shader);
511                         GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
512
513                         gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
514                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
515
516                         if (compile_status != GL_TRUE)
517                         {
518                                 const char* src[] = { fs_body, gs_body, tc_body, te_body, vs_body };
519
520                                 m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
521                                                                    << " failed.\n"
522                                                                    << "Info log:\n"
523                                                                    << getCompilationInfoLog(shader) << "Shader:\n"
524                                                                    << src[n_shader] << tcu::TestLog::EndMessage;
525
526                                 TCU_FAIL("Shader compilation failed");
527                         }
528                 }
529         } /* for (all shaders) */
530
531         /* Attach fragment & vertex shaders to the program object */
532         gl.attachShader(m_po_id, m_fs_id);
533         gl.attachShader(m_po_id, m_vs_id);
534         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
535
536         /* Configure pipeline object's fragment & vertex stages */
537         gl.useProgramStages(m_pipeline_id, GL_FRAGMENT_SHADER_BIT, m_fs_program_id);
538         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed for fragment stage");
539
540         gl.useProgramStages(m_pipeline_id, GL_VERTEX_SHADER_BIT, m_vs_program_id);
541         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed for vertex stage");
542
543         /* Set up XFB for conventional program object */
544         gl.transformFeedbackVaryings(m_po_id, 1 /* count */, &varying_name, GL_SEPARATE_ATTRIBS);
545         GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
546
547         /* Set up buffer object storage.
548          * We allocate enough space for a 4 vertex patch, which is the size
549          * needed by desktop GL for the tessellation control shader feedback
550          * whenever GL_NV_gpu_shader5 is present. */
551         gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
552         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
553
554         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4 /* components */ * 4 /* vertices per patch */,
555                                   NULL, /* data */
556                                   GL_STATIC_DRAW);
557         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
558
559         /* Bind the buffer object to indiced TF binding point */
560         gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
561         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
562 }
563
564 /** Executes the test.
565  *
566  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
567  *
568  *  Note the function throws exception should an error occur!
569  *
570  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
571  **/
572 tcu::TestNode::IterateResult TessellationShaderXFB::iterate(void)
573 {
574         /* Do not execute if required extensions are not supported. */
575         if (!m_is_tessellation_shader_supported)
576         {
577                 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
578         }
579
580         typedef std::vector<_test_descriptor> _tests;
581         typedef _tests::const_iterator            _tests_const_iterator;
582
583         /* Initialize ES test objects */
584         initTest();
585
586         /* Describe test iterations */
587         _test_descriptor test_1; /* vs+tc+te+gs */
588         _test_descriptor test_2; /* vs+tc+te */
589         _test_descriptor test_3; /* vs+tc */
590         _tests                   tests;
591
592         if (m_is_geometry_shader_extension_supported)
593         {
594                 test_1.expected_data_source  = m_glExtTokens.GEOMETRY_SHADER;
595                 test_1.expected_n_values         = 2;
596                 test_1.should_draw_call_fail = false;
597                 test_1.requires_pipeline         = false;
598                 test_1.tf_mode                           = GL_POINTS;
599                 test_1.use_gs                            = true;
600                 test_1.use_tc                            = true;
601                 test_1.use_te                            = true;
602
603                 tests.push_back(test_1);
604         }
605
606         test_2.expected_data_source  = m_glExtTokens.TESS_EVALUATION_SHADER;
607         test_2.expected_n_values         = 2;
608         test_2.should_draw_call_fail = false;
609         test_2.requires_pipeline         = false;
610         test_2.tf_mode                           = GL_POINTS;
611         test_2.use_gs                            = false;
612         test_2.use_tc                            = true;
613         test_2.use_te                            = true;
614
615         tests.push_back(test_2);
616
617         /* Note: This is a special negative case */
618         test_3.expected_data_source = m_glExtTokens.TESS_CONTROL_SHADER;
619         test_3.expected_n_values        = 4;
620         if (!glu::isContextTypeES(m_context.getRenderContext().getType()) && isExtensionSupported("GL_NV_gpu_shader5"))
621         {
622                 test_3.should_draw_call_fail = false;
623                 test_3.tf_mode                           = m_glExtTokens.PATCHES;
624         }
625         else
626         {
627                 test_3.should_draw_call_fail = true;
628                 test_3.tf_mode                           = GL_POINTS;
629         }
630         test_3.requires_pipeline = true;
631         test_3.use_gs                    = false;
632         test_3.use_tc                    = true;
633         test_3.use_te                    = false;
634
635         tests.push_back(test_3);
636
637         /* Use only one vertex per patch */
638         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
639
640         gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
641
642         GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed.");
643
644         /* This test runs in two iterations:
645          *
646          * 1) Shaders are attached to a program object at the beginning of
647          *    each test. The test then executes. Once it's completed, the
648          *    shaders are detached from the program object;
649          * 2) A pipeline object is used instead of a program object.
650          */
651         for (int n_iteration = 0; n_iteration < 2; ++n_iteration)
652         {
653                 bool use_pipeline_object = (n_iteration == 1);
654
655                 if (use_pipeline_object)
656                 {
657                         gl.bindProgramPipeline(m_pipeline_id);
658                         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() failed.");
659
660                         gl.useProgram(0);
661                         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
662                 }
663                 else
664                 {
665                         gl.bindProgramPipeline(0);
666                         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() failed.");
667
668                         /* The program object will be shortly re-linked so defer the glUseProgram() call */
669                 }
670
671                 /* Iterate through all tests */
672                 for (_tests_const_iterator test_iterator = tests.begin(); test_iterator != tests.end(); test_iterator++)
673                 {
674                         const _test_descriptor& test = *test_iterator;
675
676                         if (use_pipeline_object)
677                         {
678                                 /* Configure the pipeline object */
679                                 if (m_is_geometry_shader_extension_supported)
680                                 {
681                                         gl.useProgramStages(m_pipeline_id, m_glExtTokens.GEOMETRY_SHADER_BIT,
682                                                                                 test.use_gs ? m_gs_program_id : 0);
683                                         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_GEOMETRY_SHADER_BIT_EXT");
684                                 }
685
686                                 gl.useProgramStages(m_pipeline_id, m_glExtTokens.TESS_CONTROL_SHADER_BIT,
687                                                                         test.use_tc ? m_tc_program_id : 0);
688                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_TESS_CONTROL_SHADER_BIT_EXT");
689
690                                 gl.useProgramStages(m_pipeline_id, m_glExtTokens.TESS_EVALUATION_SHADER_BIT,
691                                                                         test.use_te ? m_te_program_id : 0);
692                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() failed for GL_TESS_EVALUATION_SHADER_BIT_EXT");
693
694                                 /* Validate the pipeline object */
695                                 gl.validateProgramPipeline(m_pipeline_id);
696                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() failed");
697
698                                 /* Retrieve the validation result */
699                                 glw::GLint validate_status = GL_FALSE;
700
701                                 gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status);
702                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() failed");
703
704                                 if (validate_status == GL_FALSE && !test.should_draw_call_fail)
705                                 {
706                                         m_testCtx.getLog() << tcu::TestLog::Message << "A pipeline object consisting of: "
707                                                                            << "[fragment stage] " << ((test.use_gs) ? "[geometry stage] " : "")
708                                                                            << ((test.use_tc) ? "[tessellation control stage] " : "")
709                                                                            << ((test.use_te) ? "[tessellation evaluation stage] " : "") << "[vertex stage] "
710                                                                            << "was not validated successfully, even though it should."
711                                                                            << tcu::TestLog::EndMessage;
712
713                                         TCU_FAIL("Pipeline object is considered invalid, even though the stage combination is valid");
714                                 }
715                         }
716                         else
717                         {
718                                 if (test.requires_pipeline)
719                                 {
720                                         continue;
721                                 }
722
723                                 /* Attach the shaders to the program object as described in
724                                  * the test descriptor */
725                                 if (test.use_gs)
726                                 {
727                                         gl.attachShader(m_po_id, m_gs_id);
728                                         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach geometry shader");
729                                 }
730
731                                 if (test.use_tc)
732                                 {
733                                         gl.attachShader(m_po_id, m_tc_id);
734                                         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach tessellation control shader");
735                                 }
736
737                                 if (test.use_te)
738                                 {
739                                         gl.attachShader(m_po_id, m_te_id);
740                                         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach tessellation evaluation shader");
741                                 }
742
743                                 /* Link the program object */
744                                 gl.linkProgram(m_po_id);
745                                 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not link program object");
746
747                                 /* Has the linking succeeded? */
748                                 glw::GLint link_status = GL_FALSE;
749
750                                 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
751                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
752
753                                 if (link_status != GL_TRUE)
754                                 {
755                                         m_testCtx.getLog() << tcu::TestLog::Message << "A program object consisting of: "
756                                                                            << "[fragment shader] " << ((test.use_gs) ? "[geometry shader] " : "")
757                                                                            << ((test.use_tc) ? "[tessellation control shader] " : "")
758                                                                            << ((test.use_te) ? "[tessellation evaluation shader] " : "")
759                                                                            << "[vertex shader] "
760                                                                            << "failed to link, even though it should link successfully."
761                                                                            << tcu::TestLog::EndMessage;
762
763                                         TCU_FAIL("Program linking failed, even though the shader combination was valid");
764                                 }
765
766                                 gl.useProgram(m_po_id);
767                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed.");
768                         }
769
770                         /* Render a single point */
771                         gl.enable(GL_RASTERIZER_DISCARD);
772                         GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
773
774                         gl.beginTransformFeedback(test.tf_mode);
775
776                         bool didBeginXFBFail = false;
777                         if (!test.should_draw_call_fail)
778                         {
779                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) failed");
780                         }
781                         else
782                         {
783                                 /* For the negative case, i.e. beginTransformFeedback with an invalid pipeline of {VS, TCS, FS},
784                                  * ES spec is not clear if beginTransformFeedback should error, so relax the requirment here so
785                                  * that test passes as long as either beginTransformFeedback or the next draw call raises
786                                  * INVALID_OPERATION */
787                                 glw::GLint err = gl.getError();
788                                 if (err == GL_INVALID_OPERATION)
789                                 {
790                                         didBeginXFBFail = true;
791                                 }
792                                 else if (err != GL_NO_ERROR)
793                                 {
794                                         TCU_FAIL("Unexpected GL error in a beginTransformFeedback made on the program pipeline whose"
795                                                          "program closest to TFB has no output varying specified");
796                                 }
797                         }
798
799                         {
800                                 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
801
802                                 if (!test.should_draw_call_fail)
803                                 {
804                                         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
805                                 }
806                                 else
807                                 {
808                                         if (gl.getError() != GL_INVALID_OPERATION)
809                                         {
810                                                 TCU_FAIL("A draw call made using a program object lacking TES stage has"
811                                                                  " not generated a GL_INVALID_OPERATION as specified");
812                                         }
813                                 }
814                         }
815                         gl.endTransformFeedback();
816
817                         if (!didBeginXFBFail)
818                         {
819                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
820                         }
821                         else
822                         {
823                                 if (gl.getError() != GL_INVALID_OPERATION)
824                                 {
825                                         TCU_FAIL("An endTransformFeedback made on inactive xfb has not generated a "
826                                                          "GL_INVALID_OPERATION as specified");
827                                 }
828                         }
829
830                         gl.disable(GL_RASTERIZER_DISCARD);
831                         GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed");
832
833                         if (!test.should_draw_call_fail)
834                         {
835                                 /* Retrieve the captured result values */
836                                 glw::GLfloat* result_ptr = (glw::GLfloat*)gl.mapBufferRange(
837                                         GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
838                                         sizeof(float) * 4 /* components */ * test.expected_n_values, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
839
840                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
841
842                                 /* Verify the data */
843                                 const glw::GLfloat epsilon                        = (glw::GLfloat)1e-5;
844                                 const glw::GLfloat expected_gs_data[] = { 1.0f, 2.0f, 3.0f, 4.0f };
845                                 const glw::GLfloat expected_tc_data[] = { 2.0f, 3.0f, 4.0f, 5.0f };
846                                 const glw::GLfloat expected_te_data[] = { 3.0f, 4.0f, 5.0f, 6.0f };
847                                 const glw::GLfloat expected_vs_data[] = { 4.0f, 5.0f, 6.0f, 7.0f };
848
849                                 for (int n_value = 0; n_value < test.expected_n_values; ++n_value)
850                                 {
851                                         const glw::GLfloat* expected_data_ptr = NULL;
852                                         const glw::GLfloat* captured_data_ptr = result_ptr + n_value * 4 /* components */;
853
854                                         if (test.expected_data_source == m_glExtTokens.GEOMETRY_SHADER)
855                                         {
856                                                 expected_data_ptr = expected_gs_data;
857                                         }
858                                         else if (test.expected_data_source == m_glExtTokens.TESS_CONTROL_SHADER)
859                                         {
860                                                 expected_data_ptr = expected_tc_data;
861                                         }
862                                         else if (test.expected_data_source == m_glExtTokens.TESS_EVALUATION_SHADER)
863                                         {
864                                                 expected_data_ptr = expected_te_data;
865                                         }
866                                         else if (test.expected_data_source == GL_VERTEX_SHADER)
867                                         {
868                                                 expected_data_ptr = expected_vs_data;
869                                         }
870                                         else
871                                         {
872                                                 TCU_FAIL("Unrecognized expected data source");
873                                         }
874
875                                         if (de::abs(captured_data_ptr[0] - expected_data_ptr[0]) > epsilon ||
876                                                 de::abs(captured_data_ptr[1] - expected_data_ptr[1]) > epsilon ||
877                                                 de::abs(captured_data_ptr[2] - expected_data_ptr[2]) > epsilon ||
878                                                 de::abs(captured_data_ptr[3] - expected_data_ptr[3]) > epsilon)
879                                         {
880                                                 m_testCtx.getLog() << tcu::TestLog::Message << "Captured data "
881                                                                                    << "(" << captured_data_ptr[0] << ", " << captured_data_ptr[1] << ", "
882                                                                                    << captured_data_ptr[2] << ", " << captured_data_ptr[3] << ")"
883                                                                                    << "is different from the expected value "
884                                                                                    << "(" << expected_data_ptr[0] << ", " << expected_data_ptr[1] << ", "
885                                                                                    << expected_data_ptr[2] << ", " << expected_data_ptr[3] << ")"
886                                                                                    << tcu::TestLog::EndMessage;
887
888                                                 TCU_FAIL("Invalid data captured");
889                                         }
890                                 }
891
892                                 /* Unmap the buffer object, since we're done */
893                                 memset(result_ptr, 0, sizeof(float) * 4 /* components */ * test.expected_n_values);
894
895                                 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
896                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed");
897                         } /* if (!test.should_draw_call_fail) */
898
899                         if (!use_pipeline_object)
900                         {
901                                 /* Detach all shaders we attached to the program object at the beginning
902                                  * of the iteration */
903                                 if (test.use_gs)
904                                 {
905                                         gl.detachShader(m_po_id, m_gs_id);
906                                         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach geometry shader");
907                                 }
908
909                                 if (test.use_tc)
910                                 {
911                                         gl.detachShader(m_po_id, m_tc_id);
912                                         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach tessellation control shader");
913                                 }
914
915                                 if (test.use_te)
916                                 {
917                                         gl.detachShader(m_po_id, m_te_id);
918                                         GLU_EXPECT_NO_ERROR(gl.getError(), "Could not detach tessellation evaluation shader");
919                                 }
920
921                         } /* if (!use_pipeline_object) */
922                         else
923                         {
924                                 /* We don't need to do anything with the pipeline object - stages will be
925                                  * re-defined in next iteration */
926                         }
927                 } /* for (all tests) */
928         }        /* for (all iterations) */
929
930         /* All done */
931         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
932         return STOP;
933 }
934
935 } /* namespace glcts */