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 "esextcTessellationShaderTCTE.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 #include <algorithm>
32 
33 namespace glcts
34 {
35 /** Constructor
36  *
37  * @param context Test context
38  **/
TessellationShaderTCTETests(glcts::Context & context,const ExtParameters & extParams)39 TessellationShaderTCTETests::TessellationShaderTCTETests(glcts::Context &context, const ExtParameters &extParams)
40     : TestCaseGroupBase(context, extParams, "tessellation_control_to_tessellation_evaluation",
41                         "Verifies various aspects of communication between tessellation "
42                         "control and tessellation evaluation stages")
43 {
44     /* No implementation needed */
45 }
46 
47 /**
48  * Initializes test groups for geometry shader tests
49  **/
init(void)50 void TessellationShaderTCTETests::init(void)
51 {
52     addChild(new glcts::TessellationShaderTCTEDataPassThrough(m_context, m_extParams));
53     addChild(new glcts::TessellationShaderTCTEgl_in(m_context, m_extParams));
54     addChild(new glcts::TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize(m_context, m_extParams));
55     addChild(new glcts::TessellationShaderTCTEgl_PatchVerticesIn(m_context, m_extParams));
56     addChild(new glcts::TessellationShaderTCTEgl_TessLevel(m_context, m_extParams));
57 }
58 
59 /** Constructor
60  *
61  * @param context Test context
62  **/
TessellationShaderTCTEDataPassThrough(Context & context,const ExtParameters & extParams)63 TessellationShaderTCTEDataPassThrough::TessellationShaderTCTEDataPassThrough(Context &context,
64                                                                              const ExtParameters &extParams)
65     : TestCaseBase(context, extParams, "data_pass_through",
66                    "Verifies data is correctly passed down the VS->TC->TS->(GS) pipeline.")
67     , m_bo_id(0)
68     , m_n_input_vertices_per_run(4)
69     , m_utils_ptr(DE_NULL)
70     , m_vao_id(0)
71 {
72     /* Left blank on purpose */
73 }
74 
75 /** Deinitializes all ES objects created for the test. */
deinit()76 void TessellationShaderTCTEDataPassThrough::deinit()
77 {
78     /** Call base class' deinit() function */
79     TestCaseBase::deinit();
80 
81     if (!m_is_tessellation_shader_supported)
82     {
83         return;
84     }
85 
86     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
87 
88     /* Revert GL_PATCH_VERTICES_EXT value to the default setting */
89     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
90 
91     /* Disable GL_RASTERIZER_DISCARD mode */
92     gl.disable(GL_RASTERIZER_DISCARD);
93 
94     /* Revert TF buffer object bindings */
95     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
96     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
97 
98     /* Unbind vertex array object */
99     gl.bindVertexArray(0);
100 
101     /* Release all objects we might've created */
102     if (m_bo_id != 0)
103     {
104         gl.deleteBuffers(1, &m_bo_id);
105 
106         m_bo_id = 0;
107     }
108 
109     if (m_vao_id != 0)
110     {
111         gl.deleteVertexArrays(1, &m_vao_id);
112 
113         m_vao_id = 0;
114     }
115 
116     for (_runs::iterator it = m_runs.begin(); it != m_runs.end(); ++it)
117     {
118         deinitTestRun(*it);
119     }
120     m_runs.clear();
121 
122     /* Release Utils instance */
123     if (m_utils_ptr != DE_NULL)
124     {
125         delete m_utils_ptr;
126 
127         m_utils_ptr = DE_NULL;
128     }
129 }
130 
131 /** Deinitializes all ES object created for a specific test run. **/
deinitTestRun(_run & run)132 void TessellationShaderTCTEDataPassThrough::deinitTestRun(_run &run)
133 {
134     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
135 
136     if (run.fs_id != 0)
137     {
138         gl.deleteShader(run.fs_id);
139 
140         run.fs_id = 0;
141     }
142 
143     if (run.gs_id != 0)
144     {
145         gl.deleteShader(run.gs_id);
146 
147         run.gs_id = 0;
148     }
149 
150     if (run.po_id != 0)
151     {
152         gl.deleteProgram(run.po_id);
153 
154         run.po_id = 0;
155     }
156 
157     if (run.tcs_id != 0)
158     {
159         gl.deleteShader(run.tcs_id);
160 
161         run.tcs_id = 0;
162     }
163 
164     if (run.tes_id != 0)
165     {
166         gl.deleteShader(run.tes_id);
167 
168         run.tes_id = 0;
169     }
170 
171     if (run.vs_id != 0)
172     {
173         gl.deleteShader(run.vs_id);
174 
175         run.vs_id = 0;
176     }
177 }
178 
179 /** Initializes all ES objects that will be used for the test. */
initTest()180 void TessellationShaderTCTEDataPassThrough::initTest()
181 {
182     /* The test requires EXT_tessellation_shader */
183     if (!m_is_tessellation_shader_supported)
184     {
185         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
186     }
187 
188     /* Create an Utils instance */
189     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
190 
191     m_utils_ptr = new TessellationShaderUtils(gl, this);
192 
193     /* Initialize vertex array object */
194     gl.genVertexArrays(1, &m_vao_id);
195     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
196 
197     gl.bindVertexArray(m_vao_id);
198     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
199 
200     /* Our program objects take a single vertex per patch */
201     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
202     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed");
203 
204     /* Disable rasterization */
205     gl.enable(GL_RASTERIZER_DISCARD);
206     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
207 
208     /* Create a buffer object we will use for XFB */
209     gl.genBuffers(1, &m_bo_id);
210     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
211 
212     /* Set up XFB buffer object bindings */
213     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
214     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
215 
216     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
217     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
218 
219     /* Prepare all the runs */
220     const _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
221                                                             TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
222                                                             TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
223     const unsigned int n_primitive_modes                 = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
224 
225     /* Iterate over all supported primitive modes */
226     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
227     {
228         _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
229 
230         /* If geometry shaders are supported, include a separate iteration to include them
231          * in the pipeline
232          */
233         for (int n_gs_stage_usage = 0; n_gs_stage_usage < ((m_is_geometry_shader_extension_supported) ? 2 : 1);
234              ++n_gs_stage_usage)
235         {
236             bool use_gs_stage = (n_gs_stage_usage == 1);
237 
238             /* If geometry shaders support gl_PointSize, include a separate iteration to pass
239              * point size data as well */
240             for (int n_gs_pointsize_usage = 0;
241                  n_gs_pointsize_usage < ((m_is_geometry_shader_point_size_supported) ? 2 : 1); ++n_gs_pointsize_usage)
242             {
243                 bool use_gs_pointsize_data = (n_gs_pointsize_usage == 1);
244 
245                 /* If tessellation shaders support gl_PointSize, include a separate iteration to pass
246                  * point size data as well */
247                 for (int n_ts_pointsize_usage = 0;
248                      n_ts_pointsize_usage < ((m_is_tessellation_shader_point_size_supported) ? 2 : 1);
249                      ++n_ts_pointsize_usage)
250                 {
251                     bool use_ts_pointsize_data = (n_ts_pointsize_usage == 1);
252 
253                     /* Note: it does not make sense to try to pass gl_PointSize data
254                      *       in geometry stage if tessellation stage did not provide it.
255                      */
256                     if (!use_ts_pointsize_data && use_gs_pointsize_data)
257                     {
258                         continue;
259                     }
260 
261                     /* Initialize test run data */
262                     _run run;
263 
264                     executeTestRun(run, primitive_mode, use_gs_stage, use_gs_pointsize_data, use_ts_pointsize_data);
265 
266                     /* Store the run for later usage */
267                     m_runs.push_back(run);
268                 } /* for (tessellation point size data usage off and on cases) */
269             }     /* for (geometry point size data usage off and on cases) */
270         }         /* for (GS stage usage) */
271     }             /* for (all primitive modes) */
272 }
273 
274 /** Initializes a test run, executes it and gathers all the rendered data for further
275  *  processing. Extracted data is stored in the run descriptor.
276  *
277  *  @param run                               Test run descriptor to fill with ES object data,
278  *                                           as well as generated data.
279  *  @param primitive_mode                    Primitive mode to use for the test run.
280  *  @param should_use_geometry_shader        true  if the test run should use Geometry Shader stage,
281  *                                           false otherwise.
282  *  @param should_pass_point_size_data_in_gs true if the test run should define two output variables
283  *                                           in Geometry Shader, later set to gl_PointSize values from
284  *                                           TC and TE stages. False to skip them.
285  *                                           Only set to true if GL_EXT_geometry_point_size extension
286  *                                           is supported.
287  *  @param should_pass_point_size_data_in_ts true if the test run should define two output variables
288  *                                           in both Tessellation Shader types, set to gl_PointSize values
289  *                                           as accessible during execution. False to skip the definitions.
290  *                                           Only set to true if GL_EXT_tessellation_point_size extension
291  *                                           is supported.
292  */
executeTestRun(_run & run,_tessellation_primitive_mode primitive_mode,bool should_use_geometry_shader,bool should_pass_point_size_data_in_gs,bool should_pass_point_size_data_in_ts)293 void TessellationShaderTCTEDataPassThrough::executeTestRun(_run &run, _tessellation_primitive_mode primitive_mode,
294                                                            bool should_use_geometry_shader,
295                                                            bool should_pass_point_size_data_in_gs,
296                                                            bool should_pass_point_size_data_in_ts)
297 {
298     run.primitive_mode = primitive_mode;
299 
300     /* Retrieve ES entry-points before we start */
301     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
302 
303     /* Create a program object first */
304     run.po_id = gl.createProgram();
305 
306     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
307 
308     /* Create all shader objects we wil be later attaching to the program object */
309     run.fs_id  = gl.createShader(GL_FRAGMENT_SHADER);
310     run.tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
311     run.tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
312     run.vs_id  = gl.createShader(GL_VERTEX_SHADER);
313 
314     if (should_use_geometry_shader)
315     {
316         run.gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
317     }
318 
319     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
320 
321     /* Attach the shader objects to the program object */
322     gl.attachShader(run.po_id, run.fs_id);
323     gl.attachShader(run.po_id, run.tcs_id);
324     gl.attachShader(run.po_id, run.tes_id);
325     gl.attachShader(run.po_id, run.vs_id);
326 
327     if (should_use_geometry_shader)
328     {
329         gl.attachShader(run.po_id, run.gs_id);
330     }
331 
332     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed");
333 
334     /* Set vertex shader's body */
335     const char *vs_body = "${VERSION}\n"
336                           "\n"
337                           "${SHADER_IO_BLOCKS_REQUIRE}\n"
338                           "\n"
339                           "out OUT_VS\n"
340                           "{\n"
341                           "    vec4  value1;\n"
342                           "    ivec4 value2;\n"
343                           "} out_data;\n"
344                           "\n"
345                           "void main()\n"
346                           "{\n"
347                           "    gl_Position     = vec4( float(gl_VertexID) );\n"
348                           "    gl_PointSize    = 1.0 / float(gl_VertexID + 1);\n"
349                           "    out_data.value1 =  vec4(float(gl_VertexID),        float(gl_VertexID) * 0.5,\n"
350                           "                            float(gl_VertexID) * 0.25, float(gl_VertexID) * 0.125);\n"
351                           "    out_data.value2 = ivec4(gl_VertexID,               gl_VertexID + 1,\n"
352                           "                            gl_VertexID + 2,           gl_VertexID + 3);\n"
353                           "}\n";
354 
355     shaderSourceSpecialized(run.vs_id, 1 /* count */, &vs_body);
356     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for vertex shader");
357 
358     /* Set minimal fragment shader's body */
359     const char *fs_body = "${VERSION}\n"
360                           "\n"
361                           "void main()\n"
362                           "{\n"
363                           "}\n";
364 
365     shaderSourceSpecialized(run.fs_id, 1 /* count */, &fs_body);
366     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for fragment shader");
367 
368     /* Set tessellation control shader's body */
369     {
370         std::stringstream body_sstream;
371         std::string body_string;
372         const char *body_raw_ptr = DE_NULL;
373 
374         body_sstream << "${VERSION}\n"
375                         "\n"
376                         "${TESSELLATION_SHADER_REQUIRE}\n";
377 
378         if (should_pass_point_size_data_in_ts)
379         {
380             body_sstream << "${TESSELLATION_POINT_SIZE_REQUIRE}\n";
381         }
382 
383         body_sstream << "\n"
384                         "layout(vertices = 2) out;\n"
385                         "\n"
386                         "in OUT_VS\n"
387                         "{\n"
388                         "    vec4  value1;\n"
389                         "    ivec4 value2;\n"
390                         "} in_vs_data[];\n"
391                         "\n"
392                         "out OUT_TC\n"
393                         "{\n";
394 
395         if (should_pass_point_size_data_in_ts)
396         {
397             body_sstream << "    float tc_pointSize;\n";
398         }
399 
400         body_sstream << "     vec4  tc_position;\n"
401                         "     vec4  tc_value1;\n"
402                         "    ivec4  tc_value2;\n"
403                         "} out_data[];\n"
404                         "\n"
405                         "patch out vec4 tc_patch_data;\n"
406                         "\n"
407                         "void main()\n"
408                         "{\n"
409                         "    int multiplier = 1;\n"
410                         "\n"
411                         "    if (gl_InvocationID == 0)\n"
412                         "    {\n"
413                         "        multiplier = 2;\n"
414                         "    }\n";
415 
416         if (should_pass_point_size_data_in_ts)
417         {
418             body_sstream << "    out_data         [gl_InvocationID].tc_pointSize = gl_in[0].gl_PointSize;\n"
419                             "    gl_out           [gl_InvocationID].gl_PointSize = gl_in[0].gl_PointSize * 2.0;\n";
420         }
421 
422         body_sstream << "    out_data         [gl_InvocationID].tc_position  = gl_in     [0].gl_Position;\n"
423                         "    out_data         [gl_InvocationID].tc_value1    = in_vs_data[0].value1      *  "
424                         "vec4(float(multiplier) );\n"
425                         "    out_data         [gl_InvocationID].tc_value2    = in_vs_data[0].value2      * ivec4(      "
426                         "multiplier);\n"
427                         "    gl_out           [gl_InvocationID].gl_Position  = gl_in     [0].gl_Position + vec4(3.0);\n"
428                         "    gl_TessLevelInner[0]                            = 4.0;\n"
429                         "    gl_TessLevelInner[1]                            = 4.0;\n"
430                         "    gl_TessLevelOuter[0]                            = 4.0;\n"
431                         "    gl_TessLevelOuter[1]                            = 4.0;\n"
432                         "    gl_TessLevelOuter[2]                            = 4.0;\n"
433                         "    gl_TessLevelOuter[3]                            = 4.0;\n"
434                         "\n"
435                         "    if (gl_InvocationID == 0)\n"
436                         "    {\n"
437                         "        tc_patch_data = in_vs_data[0].value1 *  vec4(float(multiplier) );\n"
438                         "    }\n"
439                         "}\n";
440 
441         body_string  = body_sstream.str();
442         body_raw_ptr = body_string.c_str();
443 
444         shaderSourceSpecialized(run.tcs_id, 1 /* count */, &body_raw_ptr);
445         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for tessellation control shader");
446     }
447 
448     /* Set tessellation evaluation shader's body */
449     {
450         std::stringstream body_sstream;
451         std::string body_string;
452         const char *body_raw_ptr = DE_NULL;
453 
454         /* Preamble */
455         body_sstream << "${VERSION}\n"
456                         "\n"
457                         "${TESSELLATION_SHADER_REQUIRE}\n";
458 
459         if (should_pass_point_size_data_in_ts)
460         {
461             body_sstream << "${TESSELLATION_POINT_SIZE_REQUIRE}\n";
462         }
463 
464         /* Layout qualifiers */
465         body_sstream << "\n"
466                         "layout(PRIMITIVE_MODE, point_mode) in;\n"
467                         "\n"
468 
469                         /* Input block definition starts here: */
470                         "in OUT_TC\n"
471                         "{\n";
472 
473         if (should_pass_point_size_data_in_ts)
474         {
475             body_sstream << "    float tc_pointSize;\n";
476         }
477 
478         body_sstream << "    vec4  tc_position;\n"
479                         "    vec4  tc_value1;\n"
480                         "   ivec4  tc_value2;\n"
481                         "} in_data[];\n"
482                         "\n"
483                         "patch in vec4 tc_patch_data;\n"
484                         "\n";
485         /* Input block definition ends here. */
486 
487         /* Output block definition (only defined if GS stage is present) starts here: */
488         if (should_use_geometry_shader)
489         {
490             body_sstream << "out OUT_TE\n"
491                             "{\n";
492 
493             /* Output block contents */
494             if (should_pass_point_size_data_in_ts)
495             {
496                 body_sstream << "    float tc_pointSize;\n"
497                                 "    float te_pointSize;\n";
498             }
499 
500             body_sstream << "    vec4  tc_position;\n"
501                             "    vec4  tc_value1;\n"
502                             "   ivec4  tc_value2;\n"
503                             "    vec4  te_position;\n"
504                             "} out_data;\n";
505         }
506         /* Output block definition ends here. */
507         else
508         {
509             if (should_pass_point_size_data_in_ts)
510             {
511                 body_sstream << "out float tc_pointSize;\n"
512                                 "out float te_pointSize;\n";
513             }
514 
515             body_sstream << "out  vec4  tc_position;\n"
516                             "out  vec4  tc_value1;\n"
517                             "flat out ivec4  tc_value2;\n"
518                             "out  vec4  te_position;\n"
519                             "out  vec4  te_patch_data;\n";
520         }
521 
522         body_sstream << "\n"
523                         "void main()\n"
524                         "{\n";
525 
526         if (should_use_geometry_shader)
527         {
528             body_sstream << "#define OUTPUT_VARIABLE(x) out_data.x\n";
529         }
530         else
531         {
532             body_sstream << "#define OUTPUT_VARIABLE(x) x\n";
533         }
534 
535         if (should_pass_point_size_data_in_ts)
536         {
537             body_sstream << "    OUTPUT_VARIABLE(tc_pointSize) = in_data[1].tc_pointSize;\n"
538                             "    OUTPUT_VARIABLE(te_pointSize) = gl_in[1].gl_PointSize;\n";
539         }
540 
541         body_sstream << "    OUTPUT_VARIABLE(tc_position)   = in_data[1].tc_position;\n"
542                         "    OUTPUT_VARIABLE(tc_value1)     = in_data[0].tc_value1;\n"
543                         "    OUTPUT_VARIABLE(tc_value2)     = in_data[1].tc_value2;\n"
544                         "    OUTPUT_VARIABLE(te_position)   = gl_in[0].gl_Position;\n";
545 
546         if (!should_use_geometry_shader)
547         {
548             body_sstream << "    OUTPUT_VARIABLE(te_patch_data) = tc_patch_data;\n";
549         }
550         body_sstream << "}\n";
551 
552         body_string = body_sstream.str();
553 
554         /* Replace PRIMITIVE_MODE token with user-requested primitive mode */
555         std::string primitive_mode_replacement    = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
556         std::string primitive_mode_token          = "PRIMITIVE_MODE";
557         std::size_t primitive_mode_token_position = std::string::npos;
558 
559         primitive_mode_token_position = body_string.find(primitive_mode_token);
560 
561         while (primitive_mode_token_position != std::string::npos)
562         {
563             body_string = body_string.replace(primitive_mode_token_position, primitive_mode_token.length(),
564                                               primitive_mode_replacement);
565 
566             primitive_mode_token_position = body_string.find(primitive_mode_token);
567         }
568 
569         body_raw_ptr = body_string.c_str();
570 
571         shaderSourceSpecialized(run.tes_id, 1 /* count */, &body_raw_ptr);
572         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for tessellation evaluation shader");
573     }
574 
575     /* Set geometry shader's body (if requested) */
576     if (should_use_geometry_shader)
577     {
578         std::stringstream body_sstream;
579         std::string body_string;
580         const char *body_raw_ptr = DE_NULL;
581 
582         body_sstream << "${VERSION}\n"
583                         "\n"
584                         "${GEOMETRY_SHADER_REQUIRE}\n";
585 
586         if (should_pass_point_size_data_in_gs)
587         {
588             body_sstream << "${GEOMETRY_POINT_SIZE_REQUIRE}\n";
589         }
590 
591         body_sstream << "${SHADER_IO_BLOCKS_REQUIRE}\n"
592                         "\n"
593                         "layout(points)                   in;\n"
594                         "layout(max_vertices = 2, points) out;\n"
595                         "\n"
596                         "in OUT_TE\n"
597                         "{\n";
598 
599         if (should_pass_point_size_data_in_ts)
600         {
601             body_sstream << "    float tc_pointSize;\n"
602                             "    float te_pointSize;\n";
603         }
604 
605         body_sstream << "    vec4  tc_position;\n"
606                         "    vec4  tc_value1;\n"
607                         "   ivec4  tc_value2;\n"
608                         "    vec4  te_position;\n"
609                         "} in_data[1];\n"
610                         "\n"
611                         "out float gs_tc_pointSize;\n"
612                         "out float gs_te_pointSize;\n"
613                         "out  vec4 gs_tc_position;\n"
614                         "out  vec4 gs_tc_value1;\n"
615                         "flat out ivec4 gs_tc_value2;\n"
616                         "out  vec4 gs_te_position;\n"
617                         "\n"
618                         "void main()\n"
619                         "{\n";
620 
621         if (should_pass_point_size_data_in_gs)
622         {
623             body_sstream << "    gs_tc_pointSize = in_data[0].tc_pointSize;\n"
624                             "    gs_te_pointSize = in_data[0].te_pointSize;\n";
625         }
626 
627         body_sstream << "    gs_tc_position = in_data[0].tc_position;\n"
628                         "    gs_tc_value1   = in_data[0].tc_value1;\n"
629                         "    gs_tc_value2   = in_data[0].tc_value2;\n"
630                         "    gs_te_position = in_data[0].te_position;\n"
631                         "    EmitVertex();\n";
632 
633         if (should_pass_point_size_data_in_gs)
634         {
635             body_sstream << "    gs_tc_pointSize = in_data[0].tc_pointSize + 1.0;\n"
636                             "    gs_te_pointSize = in_data[0].te_pointSize + 1.0;\n";
637         }
638 
639         body_sstream << "    gs_tc_position = in_data[0].tc_position +  vec4(1.0);\n"
640                         "    gs_tc_value1   = in_data[0].tc_value1   +  vec4(1.0);\n"
641                         "    gs_tc_value2   = in_data[0].tc_value2   + ivec4(1);\n"
642                         "    gs_te_position = in_data[0].te_position +  vec4(1.0);\n"
643                         "\n"
644                         "    EmitVertex();\n"
645                         "\n"
646                         "}\n";
647 
648         body_string  = body_sstream.str();
649         body_raw_ptr = body_string.c_str();
650 
651         shaderSourceSpecialized(run.gs_id, 1 /* count */, &body_raw_ptr);
652         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for geometry shader");
653     }
654 
655     /* Configure varyings */
656     unsigned int n_varyings                    = 0;
657     int varying_tc_pointSize_offset            = -1;
658     int varying_tc_position_offset             = -1;
659     int varying_tc_value1_offset               = -1;
660     int varying_tc_value2_offset               = -1;
661     int varying_te_patch_data_offset           = -1;
662     int varying_te_pointSize_offset            = -1;
663     int varying_te_position_offset             = -1;
664     const unsigned int varying_patch_data_size = sizeof(float) * 4; /*  vec4 */
665     const unsigned int varying_pointSize_size  = sizeof(float);
666     const unsigned int varying_position_size   = sizeof(float) * 4; /*  vec4 */
667     const unsigned int varying_value1_size     = sizeof(float) * 4; /*  vec4 */
668     const unsigned int varying_value2_size     = sizeof(int) * 4;   /* ivec4 */
669     const char **varyings                      = DE_NULL;
670     unsigned int varyings_size                 = 0;
671 
672     const char *gs_non_point_size_varyings[]     = {"gs_tc_position", "gs_tc_value1", "gs_tc_value2", "gs_te_position"};
673     const char *gs_point_size_varyings[]         = {"gs_tc_position", "gs_tc_value1",    "gs_tc_value2",
674                                                     "gs_te_position", "gs_tc_pointSize", "gs_te_pointSize"};
675     const char *non_gs_non_point_size_varyings[] = {"tc_position", "tc_value1", "tc_value2", "te_position",
676                                                     "te_patch_data"};
677     const char *non_gs_point_size_varyings[]     = {"tc_position",  "tc_value1",    "tc_value2",    "te_position",
678                                                     "tc_pointSize", "te_pointSize", "te_patch_data"};
679 
680     if (should_use_geometry_shader)
681     {
682         if (should_pass_point_size_data_in_gs)
683         {
684             n_varyings    = sizeof(gs_point_size_varyings) / sizeof(gs_point_size_varyings[0]);
685             varyings      = gs_point_size_varyings;
686             varyings_size = varying_position_size +  /* gs_tc_position  */
687                             varying_value1_size +    /* gs_tc_value1    */
688                             varying_value2_size +    /* gs_tc_value2    */
689                             varying_position_size +  /* gs_te_position  */
690                             varying_pointSize_size + /* gs_tc_pointSize */
691                             varying_pointSize_size;  /* gs_te_pointSize */
692 
693             varying_tc_position_offset  = 0;
694             varying_tc_value1_offset    = varying_tc_position_offset + varying_position_size;
695             varying_tc_value2_offset    = varying_tc_value1_offset + varying_value1_size;
696             varying_te_position_offset  = varying_tc_value2_offset + varying_value2_size;
697             varying_tc_pointSize_offset = varying_te_position_offset + varying_position_size;
698             varying_te_pointSize_offset = varying_tc_pointSize_offset + varying_pointSize_size;
699         }
700         else
701         {
702             n_varyings    = sizeof(gs_non_point_size_varyings) / sizeof(gs_non_point_size_varyings[0]);
703             varyings      = gs_non_point_size_varyings;
704             varyings_size = varying_position_size + /* gs_tc_position */
705                             varying_value1_size +   /* gs_tc_value1   */
706                             varying_value2_size +   /* gs_tc_value2   */
707                             varying_position_size;  /* gs_te_position */
708 
709             varying_tc_position_offset = 0;
710             varying_tc_value1_offset   = varying_tc_position_offset + varying_position_size;
711             varying_tc_value2_offset   = varying_tc_value1_offset + varying_value1_size;
712             varying_te_position_offset = varying_tc_value2_offset + varying_value2_size;
713         }
714     } /* if (should_use_geometry_shader) */
715     else
716     {
717         if (should_pass_point_size_data_in_ts)
718         {
719             n_varyings    = sizeof(non_gs_point_size_varyings) / sizeof(non_gs_point_size_varyings[0]);
720             varyings      = non_gs_point_size_varyings;
721             varyings_size = varying_position_size +  /* tc_position   */
722                             varying_value1_size +    /* tc_value1     */
723                             varying_value2_size +    /* tc_value2     */
724                             varying_position_size +  /* te_position   */
725                             varying_pointSize_size + /* tc_pointSize  */
726                             varying_pointSize_size + /* te_pointSize  */
727                             varying_patch_data_size; /* tc_patch_data */
728 
729             varying_tc_position_offset   = 0;
730             varying_tc_value1_offset     = varying_tc_position_offset + varying_position_size;
731             varying_tc_value2_offset     = varying_tc_value1_offset + varying_value1_size;
732             varying_te_position_offset   = varying_tc_value2_offset + varying_value2_size;
733             varying_tc_pointSize_offset  = varying_te_position_offset + varying_position_size;
734             varying_te_pointSize_offset  = varying_tc_pointSize_offset + varying_pointSize_size;
735             varying_te_patch_data_offset = varying_te_pointSize_offset + varying_pointSize_size;
736         }
737         else
738         {
739             n_varyings    = sizeof(non_gs_non_point_size_varyings) / sizeof(non_gs_non_point_size_varyings[0]);
740             varyings      = non_gs_non_point_size_varyings;
741             varyings_size = varying_position_size +  /* tc_position   */
742                             varying_value1_size +    /* tc_value1     */
743                             varying_value2_size +    /* tc_value2     */
744                             varying_position_size +  /* te_position   */
745                             varying_patch_data_size; /* tc_patch_data */
746 
747             varying_tc_position_offset   = 0;
748             varying_tc_value1_offset     = varying_tc_position_offset + varying_position_size;
749             varying_tc_value2_offset     = varying_tc_value1_offset + varying_value1_size;
750             varying_te_position_offset   = varying_tc_value2_offset + varying_value2_size;
751             varying_te_patch_data_offset = varying_te_position_offset + varying_position_size;
752         }
753     }
754 
755     gl.transformFeedbackVaryings(run.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
756     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
757 
758     /* Compile all the shader objects */
759     const glw::GLuint shaders[]  = {run.fs_id, run.gs_id, run.tcs_id, run.tes_id, run.vs_id};
760     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
761 
762     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
763     {
764         glw::GLuint shader = shaders[n_shader];
765 
766         if (shader != 0)
767         {
768             m_utils_ptr->compileShaders(1 /* n_shaders */, &shader, true);
769         }
770     }
771 
772     /* Link the program object */
773     gl.linkProgram(run.po_id);
774     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
775 
776     /* Make sure the linking has succeeded */
777     glw::GLint link_status = GL_FALSE;
778 
779     gl.getProgramiv(run.po_id, GL_LINK_STATUS, &link_status);
780     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
781 
782     if (link_status != GL_TRUE)
783     {
784         TCU_FAIL("Program linking failed");
785     }
786 
787     /* Now that we have a linked program object, it's time to determine how much space
788      * we will need to hold XFB data.
789      */
790     unsigned int bo_size              = 0;
791     unsigned int n_result_tess_coords = 0;
792     const float tess_levels[]         = /* as per shaders constructed by the test */
793         {4.0f, 4.0f, 4.0f, 4.0f};
794 
795     n_result_tess_coords = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
796         run.primitive_mode, tess_levels, tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
797         true); /* is_point_mode_enabled */
798 
799     if (should_use_geometry_shader)
800     {
801         /* Geometry shader will output twice as many vertices */
802         n_result_tess_coords *= 2;
803     }
804 
805     run.n_result_vertices_per_patch = n_result_tess_coords;
806     n_result_tess_coords *= m_n_input_vertices_per_run;
807     bo_size = n_result_tess_coords * varyings_size;
808 
809     /* Proceed with buffer object storage allocation */
810     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, /* data */
811                   GL_STATIC_DRAW);
812     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
813 
814     /* Great, time to actually render the data! */
815     glw::GLenum tf_mode =
816         TessellationShaderUtils::getTFModeForPrimitiveMode(run.primitive_mode, true); /* is_point_mode_enabled */
817 
818     gl.useProgram(run.po_id);
819     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
820 
821     gl.beginTransformFeedback(tf_mode);
822     GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
823     {
824         gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, m_n_input_vertices_per_run);
825         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
826     }
827     gl.endTransformFeedback();
828     GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
829 
830     /* The data should have landed in the buffer object storage by now. Map the BO into
831      * process space. */
832     const void *bo_ptr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
833                                            bo_size, GL_MAP_READ_BIT);
834 
835     GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
836 
837     /* Extract varyings' data */
838     for (unsigned int n_tess_coord = 0; n_tess_coord < n_result_tess_coords; ++n_tess_coord)
839     {
840         const char *data = (const char *)bo_ptr + n_tess_coord * varyings_size;
841 
842         if (varying_tc_position_offset != -1)
843         {
844             const float *position_data((const float *)(data + varying_tc_position_offset));
845             _vec4 new_entry(position_data[0], position_data[1], position_data[2], position_data[3]);
846 
847             run.result_tc_position_data.push_back(new_entry);
848         }
849 
850         if (varying_tc_value1_offset != -1)
851         {
852             const float *value1_data((const float *)(data + varying_tc_value1_offset));
853             _vec4 new_entry(value1_data[0], value1_data[1], value1_data[2], value1_data[3]);
854 
855             run.result_tc_value1_data.push_back(new_entry);
856         }
857 
858         if (varying_tc_value2_offset != -1)
859         {
860             const int *value2_data((const int *)(data + varying_tc_value2_offset));
861             _ivec4 new_entry(value2_data[0], value2_data[1], value2_data[2], value2_data[3]);
862 
863             run.result_tc_value2_data.push_back(new_entry);
864         }
865 
866         if (varying_te_position_offset != -1)
867         {
868             const float *position_data((const float *)(data + varying_te_position_offset));
869             _vec4 new_entry(position_data[0], position_data[1], position_data[2], position_data[3]);
870 
871             run.result_te_position_data.push_back(new_entry);
872         }
873 
874         if (varying_tc_pointSize_offset != -1)
875         {
876             const float *pointSize_ptr((const float *)(data + varying_tc_pointSize_offset));
877 
878             run.result_tc_pointSize_data.push_back(*pointSize_ptr);
879         }
880 
881         if (varying_te_pointSize_offset != -1)
882         {
883             const float *pointSize_ptr((const float *)(data + varying_te_pointSize_offset));
884 
885             run.result_te_pointSize_data.push_back(*pointSize_ptr);
886         }
887 
888         if (varying_te_patch_data_offset != -1)
889         {
890             const float *patch_data_ptr((const float *)(data + varying_te_patch_data_offset));
891             _vec4 new_entry(patch_data_ptr[0], patch_data_ptr[1], patch_data_ptr[2], patch_data_ptr[3]);
892 
893             run.result_te_patch_data.push_back(new_entry);
894         }
895     } /* for (all XFB data associated with tessellated coordinates) */
896 
897     /* Now that we're done extracting the data we need, we're fine to unmap the buffer object */
898     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
899     GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed");
900 }
901 
902 /** Executes the test.
903  *
904  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
905  *
906  *  Note the function throws exception should an error occur!
907  *
908  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
909  **/
iterate(void)910 tcu::TestNode::IterateResult TessellationShaderTCTEDataPassThrough::iterate(void)
911 {
912     const float epsilon = 1e-5f;
913 
914     /* Initialize ES test objects */
915     initTest();
916 
917     /* Iterate over all runs */
918     for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); ++run_iterator)
919     {
920         const _run &run = *run_iterator;
921 
922         /* Check result tc_pointSize data if available */
923         unsigned int n_vertex = 0;
924 
925         for (std::vector<glw::GLfloat>::const_iterator data_iterator = run.result_tc_pointSize_data.begin();
926              data_iterator != run.result_tc_pointSize_data.end(); data_iterator++, n_vertex++)
927         {
928             const glw::GLfloat data = *data_iterator;
929             unsigned int vertex_id  = n_vertex / run.n_result_vertices_per_patch;
930             float expected_value    = 1.0f / (float(vertex_id) + 1.0f);
931 
932             if (run.gs_id != 0 && (n_vertex % 2) != 0)
933             {
934                 /* Odd vertices emitted by geometry shader add 1 to all components */
935                 expected_value += 1.0f;
936             }
937 
938             if (de::abs(data - expected_value) > epsilon)
939             {
940                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_pointSize value found at index [" << n_vertex
941                                    << "];"
942                                       " expected:["
943                                    << expected_value
944                                    << "], "
945                                       " found:["
946                                    << data << "]." << tcu::TestLog::EndMessage;
947 
948                 TCU_FAIL("Invalid tc_pointSize value found");
949             }
950         }
951 
952         /* Check result tc_position data if available */
953         n_vertex -= n_vertex;
954 
955         for (std::vector<_vec4>::const_iterator data_iterator = run.result_tc_position_data.begin();
956              data_iterator != run.result_tc_position_data.end(); data_iterator++, n_vertex++)
957         {
958             const _vec4 &data    = *data_iterator;
959             float expected_value = (float)(n_vertex / run.n_result_vertices_per_patch);
960 
961             if (run.gs_id != 0 && (n_vertex % 2) != 0)
962             {
963                 /* Odd vertices emitted by geometry shader add 1 to all components */
964                 expected_value += 1.0f;
965             }
966 
967             if (de::abs(data.x - expected_value) > epsilon || de::abs(data.y - expected_value) > epsilon ||
968                 de::abs(data.z - expected_value) > epsilon || de::abs(data.w - expected_value) > epsilon)
969             {
970                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_position value found at index [" << n_vertex
971                                    << "];"
972                                       " expected:"
973                                       " ["
974                                    << expected_value << ", " << expected_value << ", " << expected_value << ", "
975                                    << expected_value
976                                    << "], found:"
977                                       " ["
978                                    << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
979                                    << tcu::TestLog::EndMessage;
980 
981                 TCU_FAIL("Invalid tc_position value found");
982             }
983         }
984 
985         /* Check result tc_value1 data if available */
986         n_vertex -= n_vertex;
987 
988         for (std::vector<_vec4>::const_iterator data_iterator = run.result_tc_value1_data.begin();
989              data_iterator != run.result_tc_value1_data.end(); data_iterator++, n_vertex++)
990         {
991             const _vec4 &data      = *data_iterator;
992             unsigned int vertex_id = n_vertex / run.n_result_vertices_per_patch;
993             _vec4 expected_value   = _vec4((float)vertex_id, ((float)vertex_id) * 0.5f, ((float)vertex_id) * 0.25f,
994                                            ((float)vertex_id) * 0.125f);
995 
996             /* TE uses an even vertex outputted by TC, so we need
997              * to multiply the expected value by 2.
998              */
999             expected_value.x *= 2.0f;
1000             expected_value.y *= 2.0f;
1001             expected_value.z *= 2.0f;
1002             expected_value.w *= 2.0f;
1003 
1004             if (run.gs_id != 0 && (n_vertex % 2) != 0)
1005             {
1006                 /* Odd vertices emitted by geometry shader add 1 to all components */
1007                 expected_value.x += 1.0f;
1008                 expected_value.y += 1.0f;
1009                 expected_value.z += 1.0f;
1010                 expected_value.w += 1.0f;
1011             }
1012 
1013             if (de::abs(data.x - expected_value.x) > epsilon || de::abs(data.y - expected_value.y) > epsilon ||
1014                 de::abs(data.z - expected_value.z) > epsilon || de::abs(data.w - expected_value.w) > epsilon)
1015             {
1016                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_value1 value found at index [" << n_vertex
1017                                    << "];"
1018                                       " expected:"
1019                                       " ["
1020                                    << expected_value.x << ", " << expected_value.y << ", " << expected_value.z << ", "
1021                                    << expected_value.w
1022                                    << "], found:"
1023                                       " ["
1024                                    << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
1025                                    << tcu::TestLog::EndMessage;
1026 
1027                 TCU_FAIL("Invalid tc_value1 value found");
1028             }
1029         }
1030 
1031         /* Check result tc_value2 data if available */
1032         n_vertex -= n_vertex;
1033 
1034         for (std::vector<_ivec4>::const_iterator data_iterator = run.result_tc_value2_data.begin();
1035              data_iterator != run.result_tc_value2_data.end(); data_iterator++, n_vertex++)
1036         {
1037             const _ivec4 &data     = *data_iterator;
1038             unsigned int vertex_id = n_vertex / run.n_result_vertices_per_patch;
1039             _ivec4 expected_value  = _ivec4(vertex_id, vertex_id + 1, vertex_id + 2, vertex_id + 3);
1040 
1041             if (run.gs_id != 0 && (n_vertex % 2) != 0)
1042             {
1043                 /* Odd vertices emitted by geometry shader add 1 to all components */
1044                 expected_value.x++;
1045                 expected_value.y++;
1046                 expected_value.z++;
1047                 expected_value.w++;
1048             }
1049 
1050             if (data.x != expected_value.x || data.y != expected_value.y || data.z != expected_value.z ||
1051                 data.w != expected_value.w)
1052             {
1053                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_value2 value found at index [" << n_vertex
1054                                    << "];"
1055                                       " expected:"
1056                                       " ["
1057                                    << expected_value.x << ", " << expected_value.y << ", " << expected_value.z << ", "
1058                                    << expected_value.w
1059                                    << "], found:"
1060                                       " ["
1061                                    << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
1062                                    << tcu::TestLog::EndMessage;
1063 
1064                 TCU_FAIL("Invalid tc_value2 value found");
1065             }
1066         }
1067 
1068         /* Check result te_pointSize data if available */
1069         n_vertex -= n_vertex;
1070 
1071         for (std::vector<glw::GLfloat>::const_iterator data_iterator = run.result_te_pointSize_data.begin();
1072              data_iterator != run.result_te_pointSize_data.end(); data_iterator++, n_vertex++)
1073         {
1074             const glw::GLfloat data = *data_iterator;
1075             unsigned int vertex_id  = n_vertex / run.n_result_vertices_per_patch;
1076             float expected_value    = 2.0f / (float(vertex_id) + 1.0f);
1077 
1078             if (run.gs_id != 0 && (n_vertex % 2) != 0)
1079             {
1080                 /* Odd vertices emitted by geometry shader add 1 to all components */
1081                 expected_value += 1.0f;
1082             }
1083 
1084             if (de::abs(data - expected_value) > epsilon)
1085             {
1086                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid te_pointSize value found at index [" << n_vertex
1087                                    << "];"
1088                                       " expected:["
1089                                    << expected_value
1090                                    << "], "
1091                                       " found:["
1092                                    << data << "]." << tcu::TestLog::EndMessage;
1093 
1094                 TCU_FAIL("Invalid te_pointSize value found");
1095             }
1096         }
1097 
1098         /* Check result te_position data if available */
1099         n_vertex -= n_vertex;
1100 
1101         for (std::vector<_vec4>::const_iterator data_iterator = run.result_te_position_data.begin();
1102              data_iterator != run.result_te_position_data.end(); data_iterator++, n_vertex++)
1103         {
1104             const _vec4 &data    = *data_iterator;
1105             float expected_value = (float)(n_vertex / run.n_result_vertices_per_patch);
1106 
1107             /* te_position should be equal to tc_position, with 3 added to all components */
1108             expected_value += 3.0f;
1109 
1110             if (run.gs_id != 0 && (n_vertex % 2) != 0)
1111             {
1112                 /* Odd vertices emitted by geometry shader add 1 to all components */
1113                 expected_value += 1.0f;
1114             }
1115 
1116             if (de::abs(data.x - expected_value) > epsilon || de::abs(data.y - expected_value) > epsilon ||
1117                 de::abs(data.z - expected_value) > epsilon || de::abs(data.w - expected_value) > epsilon)
1118             {
1119                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid te_position value found at index [" << n_vertex
1120                                    << "];"
1121                                       " expected:"
1122                                       " ["
1123                                    << expected_value << ", " << expected_value << ", " << expected_value << ", "
1124                                    << expected_value
1125                                    << "], found:"
1126                                       " ["
1127                                    << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
1128                                    << tcu::TestLog::EndMessage;
1129 
1130                 TCU_FAIL("Invalid te_position value found");
1131             }
1132         }
1133 
1134         /* Check result tc_patch_data data if available */
1135         n_vertex -= n_vertex;
1136 
1137         for (std::vector<_vec4>::const_iterator data_iterator = run.result_te_patch_data.begin();
1138              data_iterator != run.result_te_patch_data.end(); data_iterator++, n_vertex++)
1139         {
1140             const _vec4 &data      = *data_iterator;
1141             unsigned int vertex_id = n_vertex / run.n_result_vertices_per_patch;
1142             _vec4 expected_value   = _vec4((float)vertex_id, ((float)vertex_id) * 0.5f, ((float)vertex_id) * 0.25f,
1143                                            ((float)vertex_id) * 0.125f);
1144 
1145             /* TE uses an even vertex outputted by TC, so we need
1146              * to multiply the expected value by 2.
1147              */
1148             expected_value.x *= 2.0f;
1149             expected_value.y *= 2.0f;
1150             expected_value.z *= 2.0f;
1151             expected_value.w *= 2.0f;
1152 
1153             if (de::abs(data.x - expected_value.x) > epsilon || de::abs(data.y - expected_value.y) > epsilon ||
1154                 de::abs(data.z - expected_value.z) > epsilon || de::abs(data.w - expected_value.w) > epsilon)
1155             {
1156                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_patch_data value found at index ["
1157                                    << n_vertex
1158                                    << "];"
1159                                       " expected:"
1160                                       " ["
1161                                    << expected_value.x << ", " << expected_value.y << ", " << expected_value.z << ", "
1162                                    << expected_value.w
1163                                    << "], found:"
1164                                       " ["
1165                                    << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
1166                                    << tcu::TestLog::EndMessage;
1167 
1168                 TCU_FAIL("Invalid tc_patch_data value found");
1169             }
1170         }
1171     } /* for (all runs) */
1172 
1173     /* All done */
1174     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1175     return STOP;
1176 }
1177 
1178 /** Constructor
1179  *
1180  * @param context Test context
1181  **/
TessellationShaderTCTEgl_in(Context & context,const ExtParameters & extParams)1182 TessellationShaderTCTEgl_in::TessellationShaderTCTEgl_in(Context &context, const ExtParameters &extParams)
1183     : TestCaseBase(context, extParams, "gl_in",
1184                    "Verifies values of gl_in[] in a tessellation evaluation shader "
1185                    "are taken from output variables of a tessellation control shader"
1186                    "if one is present.")
1187     , m_bo_id(0)
1188     , m_fs_id(0)
1189     , m_po_id(0)
1190     , m_tcs_id(0)
1191     , m_tes_id(0)
1192     , m_vao_id(0)
1193     , m_vs_id(0)
1194 {
1195     /* Left blank on purpose */
1196 }
1197 
1198 /** Deinitializes all ES objects created for the test. */
deinit()1199 void TessellationShaderTCTEgl_in::deinit()
1200 {
1201     /** Call base class' deinit() function */
1202     TestCaseBase::deinit();
1203 
1204     if (!m_is_tessellation_shader_supported)
1205     {
1206         return;
1207     }
1208 
1209     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1210 
1211     /* Revert TF buffer object bindings */
1212     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
1213     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
1214 
1215     /* Reset GL_PATCH_VERTICES_EXT value to the default setting */
1216     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
1217 
1218     /* Disable GL_RASTERIZER_DISCARD mdoe */
1219     gl.disable(GL_RASTERIZER_DISCARD);
1220 
1221     /* Unbind vertex array object */
1222     gl.bindVertexArray(0);
1223 
1224     /* Release all objects we might've created */
1225     if (m_bo_id != 0)
1226     {
1227         gl.deleteBuffers(1, &m_bo_id);
1228 
1229         m_bo_id = 0;
1230     }
1231 
1232     if (m_fs_id != 0)
1233     {
1234         gl.deleteShader(m_fs_id);
1235 
1236         m_fs_id = 0;
1237     }
1238 
1239     if (m_po_id != 0)
1240     {
1241         gl.deleteProgram(m_po_id);
1242 
1243         m_po_id = 0;
1244     }
1245 
1246     if (m_tcs_id != 0)
1247     {
1248         gl.deleteShader(m_tcs_id);
1249 
1250         m_tcs_id = 0;
1251     }
1252 
1253     if (m_tes_id != 0)
1254     {
1255         gl.deleteShader(m_tes_id);
1256 
1257         m_tes_id = 0;
1258     }
1259 
1260     if (m_vs_id != 0)
1261     {
1262         gl.deleteShader(m_vs_id);
1263 
1264         m_vs_id = 0;
1265     }
1266 
1267     if (m_vao_id != 0)
1268     {
1269         gl.deleteVertexArrays(1, &m_vao_id);
1270 
1271         m_vao_id = 0;
1272     }
1273 }
1274 
1275 /** Initializes all ES objects that will be used for the test. */
initTest()1276 void TessellationShaderTCTEgl_in::initTest()
1277 {
1278     /* The test requires EXT_tessellation_shader */
1279     if (!m_is_tessellation_shader_supported)
1280     {
1281         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1282     }
1283 
1284     /* Generate a program object we will later configure */
1285     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1286 
1287     /* Initialize vertex array object */
1288     gl.genVertexArrays(1, &m_vao_id);
1289     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
1290 
1291     gl.bindVertexArray(m_vao_id);
1292     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
1293 
1294     /* Create program object */
1295     m_po_id = gl.createProgram();
1296 
1297     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
1298 
1299     /* Generate shader objects the test will use */
1300     m_fs_id  = gl.createShader(GL_FRAGMENT_SHADER);
1301     m_tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
1302     m_tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
1303     m_vs_id  = gl.createShader(GL_VERTEX_SHADER);
1304 
1305     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
1306 
1307     /* Configure fragment shader */
1308     const char *fs_body = "${VERSION}\n"
1309                           "\n"
1310                           "void main()\n"
1311                           "{\n"
1312                           "}\n";
1313 
1314     shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
1315     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader object");
1316 
1317     /* Configure tessellation control shader */
1318     const char *tc_body = "${VERSION}\n"
1319                           "\n"
1320                           /* Required EXT_tessellation_shader functionality */
1321                           "${TESSELLATION_SHADER_REQUIRE}\n"
1322                           "\n"
1323                           "layout (vertices = 1) out;\n"
1324                           "\n"
1325                           "out float out_float[];\n"
1326                           "out int   out_int[];\n"
1327                           "out ivec3 out_ivec3[];\n"
1328                           "out mat2  out_mat2[];\n"
1329                           "out uint  out_uint[];\n"
1330                           "out uvec2 out_uvec2[];\n"
1331                           "out vec4  out_vec4[];\n"
1332                           "\n"
1333                           "out struct\n"
1334                           "{\n"
1335                           "    int   test1;\n"
1336                           "    float test2;\n"
1337                           "} out_struct[];\n"
1338                           /* Body */
1339                           "void main()\n"
1340                           "{\n"
1341                           "    gl_out           [gl_InvocationID].gl_Position = vec4(5.0, 6.0, 7.0, 8.0);\n"
1342                           "    gl_TessLevelOuter[0]                           = 1.0;\n"
1343                           "    gl_TessLevelOuter[1]                           = 1.0;\n"
1344                           "\n"
1345                           "    out_float[gl_InvocationID] = 22.0;\n"
1346                           "    out_int  [gl_InvocationID] = 23;\n"
1347                           "    out_ivec3[gl_InvocationID] = ivec3(24, 25, 26);\n"
1348                           "    out_mat2 [gl_InvocationID] = mat2(vec2(27.0, 28.0), vec2(29.0, 30.0) );\n"
1349                           "    out_uint [gl_InvocationID] = 31u;\n"
1350                           "    out_uvec2[gl_InvocationID] = uvec2(32, 33);\n"
1351                           "    out_vec4 [gl_InvocationID] = vec4(34.0, 35.0, 36.0, 37.0);\n"
1352                           "\n"
1353                           "    out_struct[gl_InvocationID].test1 = 38;\n"
1354                           "    out_struct[gl_InvocationID].test2 = 39.0;\n"
1355                           "}\n";
1356 
1357     shaderSourceSpecialized(m_tcs_id, 1 /* count */, &tc_body);
1358     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader object");
1359 
1360     /* Configure tessellation evaluation shader */
1361     const char *te_body = "${VERSION}\n"
1362                           "\n"
1363                           "${TESSELLATION_SHADER_REQUIRE}\n"
1364                           "\n"
1365                           "layout (isolines, point_mode) in;\n"
1366                           "\n"
1367                           "in float out_float[];\n"
1368                           "in int   out_int[];\n"
1369                           "in ivec3 out_ivec3[];\n"
1370                           "in mat2  out_mat2[];\n"
1371                           "in uint  out_uint[];\n"
1372                           "in uvec2 out_uvec2[];\n"
1373                           "in vec4  out_vec4[];\n"
1374                           "in struct\n"
1375                           "{\n"
1376                           "    int   test1;\n"
1377                           "    float test2;\n"
1378                           "} out_struct[];\n"
1379                           "\n"
1380                           "out float result_float;\n"
1381                           "flat out int   result_int;\n"
1382                           "flat out ivec3 result_ivec3;\n"
1383                           "out mat2  result_mat2;\n"
1384                           "flat out int   result_struct_test1;\n"
1385                           "out float result_struct_test2;\n"
1386                           "flat out uint  result_uint;\n"
1387                           "flat out uvec2 result_uvec2;\n"
1388                           "out vec4  result_vec4;\n"
1389                           "\n"
1390                           "void main()\n"
1391                           "{\n"
1392                           "    gl_Position = gl_in[0].gl_Position;\n"
1393                           "\n"
1394                           "    result_float        = out_float [0];\n"
1395                           "    result_int          = out_int   [0];\n"
1396                           "    result_ivec3        = out_ivec3 [0];\n"
1397                           "    result_mat2         = out_mat2  [0];\n"
1398                           "    result_struct_test1 = out_struct[0].test1;\n"
1399                           "    result_struct_test2 = out_struct[0].test2;\n"
1400                           "    result_uint         = out_uint  [0];\n"
1401                           "    result_uvec2        = out_uvec2 [0];\n"
1402                           "    result_vec4         = out_vec4  [0];\n"
1403                           "}\n";
1404 
1405     shaderSourceSpecialized(m_tes_id, 1 /* count */, &te_body);
1406     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader object");
1407 
1408     /* Configure vertex shader */
1409     const char *vs_body = "${VERSION}\n"
1410                           "\n"
1411                           "${SHADER_IO_BLOCKS_ENABLE}\n"
1412                           "\n"
1413                           "out float out_float;\n"
1414                           "flat out int   out_int;\n"
1415                           "flat out ivec3 out_ivec3;\n"
1416                           "out mat2  out_mat2;\n"
1417                           "flat out uint  out_uint;\n"
1418                           "flat out uvec2 out_uvec2;\n"
1419                           "out vec4  out_vec4;\n"
1420                           "\n"
1421                           "flat out struct\n"
1422                           "{\n"
1423                           "    int   test1;\n"
1424                           "    float test2;\n"
1425                           "} out_struct;\n"
1426                           "\n"
1427                           "void main()\n"
1428                           "{\n"
1429                           "    gl_Position = vec4(1.0, 2.0, 3.0, 4.0);\n"
1430                           "\n"
1431                           "    out_float        = 1.0;\n"
1432                           "    out_int          = 2;\n"
1433                           "    out_ivec3        = ivec3(3, 4, 5);\n"
1434                           "    out_mat2         = mat2(vec2(6.0, 7.0), vec2(8.0, 9.0) );\n"
1435                           "    out_uint         = 10u;\n"
1436                           "    out_uvec2        = uvec2(11u, 12u);\n"
1437                           "    out_vec4         = vec4(12.0, 13.0, 14.0, 15.0);\n"
1438                           "    out_struct.test1 = 20;\n"
1439                           "    out_struct.test2 = 21.0;\n"
1440                           "}\n";
1441 
1442     shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
1443     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader object");
1444 
1445     /* Compile all shaders of our interest */
1446     const glw::GLuint shaders[]  = {m_fs_id, m_tcs_id, m_tes_id, m_vs_id};
1447     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
1448 
1449     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
1450     {
1451         glw::GLint compile_status = GL_FALSE;
1452         glw::GLuint shader        = shaders[n_shader];
1453 
1454         gl.compileShader(shader);
1455         GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
1456 
1457         gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
1458         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
1459 
1460         if (compile_status != GL_TRUE)
1461         {
1462             const char *src[] = {fs_body, tc_body, te_body, vs_body};
1463             m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
1464                                << " failed.\n"
1465                                << "Info log:\n"
1466                                << getCompilationInfoLog(shader) << "Shader:\n"
1467                                << src[n_shader] << tcu::TestLog::EndMessage;
1468 
1469             TCU_FAIL("Shader compilation failed");
1470         }
1471     } /* for (all shaders) */
1472 
1473     /* Attach the shaders to the test program object, set up XFB and then link the program */
1474     glw::GLint link_status           = GL_FALSE;
1475     glw::GLint n_xfb_varyings        = 0;
1476     const glw::GLchar **xfb_varyings = NULL;
1477     glw::GLint xfb_size              = 0;
1478 
1479     getXFBProperties(&xfb_varyings, &n_xfb_varyings, &xfb_size);
1480 
1481     gl.transformFeedbackVaryings(m_po_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
1482     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
1483 
1484     gl.attachShader(m_po_id, m_fs_id);
1485     gl.attachShader(m_po_id, m_tcs_id);
1486     gl.attachShader(m_po_id, m_tes_id);
1487     gl.attachShader(m_po_id, m_vs_id);
1488     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
1489 
1490     gl.linkProgram(m_po_id);
1491     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
1492 
1493     gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
1494     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
1495 
1496     if (link_status != GL_TRUE)
1497     {
1498         TCU_FAIL("Program linking failed");
1499     }
1500 
1501     /* Generate and set up a buffer object we will use to hold XFBed data. */
1502     gl.genBuffers(1, &m_bo_id);
1503     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
1504 
1505     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
1506     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
1507     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
1508     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
1509 
1510     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_size, NULL /* data */, GL_STATIC_DRAW);
1511     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
1512 
1513     /* We're good to execute the test! */
1514 }
1515 
1516 /** Retrieves XFB-specific properties that are used in various locations of
1517  *  this test implementation.
1518  *
1519  *  @param out_names    Deref will be used to store location of an array keeping
1520  *                      names of varyings that should be used for TF. Can be NULL,
1521  *                      in which case nothing will be stored under *out_names.
1522  *  @param out_n_names  Deref will be used to store number of strings the @param
1523  *                      out_names array holds. Can be NULL, in which case nothing
1524  *                      will be stored under *out_n_names.
1525  *  @param out_xfb_size Deref will be used to store amount of bytes needed to hold
1526  *                      all data generated by a draw call used by this test. Can be
1527  *                      NULL, in which case nothing will be stored under *out_xfb_size.
1528  **/
getXFBProperties(const glw::GLchar *** out_names,glw::GLint * out_n_names,glw::GLint * out_xfb_size)1529 void TessellationShaderTCTEgl_in::getXFBProperties(const glw::GLchar ***out_names, glw::GLint *out_n_names,
1530                                                    glw::GLint *out_xfb_size)
1531 {
1532     static const glw::GLchar *xfb_varyings[] = {
1533         "result_float",        "result_int",  "result_ivec3", "result_mat2", "result_struct_test1",
1534         "result_struct_test2", "result_uint", "result_uvec2", "result_vec4", "gl_Position"};
1535     static const unsigned int xfb_size = (sizeof(float) +      /* result_float */
1536                                           sizeof(int) +        /* result_int */
1537                                           sizeof(int) * 3 +    /* result_ivec3 */
1538                                           sizeof(float) * 4 +  /* result_mat2 */
1539                                           sizeof(int) +        /* result_struct_test1 */
1540                                           sizeof(float) +      /* result_struct_test2 */
1541                                           sizeof(int) +        /* result_uint */
1542                                           sizeof(int) * 2 +    /* result_uvec2 */
1543                                           sizeof(float) * 4 +  /* result_vec4 */
1544                                           sizeof(float) * 4) * /* gl_Position */
1545                                          2;                    /* two points will be generated by tessellation */
1546 
1547     static const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
1548 
1549     if (out_names != NULL)
1550     {
1551         *out_names = xfb_varyings;
1552     }
1553 
1554     if (out_n_names != NULL)
1555     {
1556         *out_n_names = n_xfb_varyings;
1557     }
1558 
1559     if (out_xfb_size != NULL)
1560     {
1561         /* NOTE: Tessellator is expected to generate two points for the purpose of
1562          *       this test, which is why we need to multiply the amount of bytes store
1563          *       in xfb_size by two.
1564          */
1565         *out_xfb_size = xfb_size * 2;
1566     }
1567 }
1568 
1569 /** Executes the test.
1570  *
1571  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1572  *
1573  *  Note the function throws exception should an error occur!
1574  *
1575  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
1576  **/
iterate(void)1577 tcu::TestNode::IterateResult TessellationShaderTCTEgl_in::iterate(void)
1578 {
1579     /* Initialize ES test objects */
1580     initTest();
1581 
1582     /* Our program object takes a single vertex per patch */
1583     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1584 
1585     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
1586     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed");
1587 
1588     /* Render the geometry. We're only interested in XFB data, not the visual outcome,
1589      * so disable rasterization before we fire a draw call.
1590      */
1591     gl.useProgram(m_po_id);
1592     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
1593 
1594     gl.enable(GL_RASTERIZER_DISCARD);
1595     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed");
1596 
1597     gl.beginTransformFeedback(GL_POINTS);
1598     GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) call failed");
1599     {
1600         gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
1601 
1602         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
1603     }
1604     gl.endTransformFeedback();
1605     GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
1606 
1607     /* Download the data we stored with TF */
1608     glw::GLint n_xfb_names        = 0;
1609     void *rendered_data           = NULL;
1610     const glw::GLchar **xfb_names = NULL;
1611     glw::GLint xfb_size           = 0;
1612 
1613     getXFBProperties(&xfb_names, &n_xfb_names, &xfb_size);
1614 
1615     rendered_data = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* offset */, xfb_size, GL_MAP_READ_BIT);
1616     GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
1617 
1618     /* Move through the result buffer and make sure the values we retrieved are valid.
1619      * Note that two points will be generated by the tessellator, so run the checks
1620      * twice.
1621      */
1622     typedef enum
1623     {
1624         XFB_VARYING_TYPE_FLOAT,
1625         XFB_VARYING_TYPE_INT,
1626 
1627         XFB_VARYING_TYPE_UNKNOWN
1628     } _xfb_varying_type;
1629 
1630     unsigned char *traveller_ptr = (unsigned char *)rendered_data;
1631 
1632     for (glw::GLint n_point = 0; n_point < 2 /* points */; ++n_point)
1633     {
1634         for (glw::GLint n_xfb_name = 0; n_xfb_name < n_xfb_names; ++n_xfb_name)
1635         {
1636             glw::GLfloat expected_value_float[4] = {0.0f};
1637             glw::GLint expected_value_int[4]     = {0};
1638             std::string name                     = xfb_names[n_xfb_name];
1639             unsigned int n_varying_components    = 0;
1640             _xfb_varying_type varying_type       = XFB_VARYING_TYPE_UNKNOWN;
1641 
1642             if (name.compare("result_float") == 0)
1643             {
1644                 expected_value_float[0] = 22.0f;
1645                 n_varying_components    = 1;
1646                 varying_type            = XFB_VARYING_TYPE_FLOAT;
1647             }
1648             else if (name.compare("result_int") == 0)
1649             {
1650                 expected_value_int[0] = 23;
1651                 n_varying_components  = 1;
1652                 varying_type          = XFB_VARYING_TYPE_INT;
1653             }
1654             else if (name.compare("result_ivec3") == 0)
1655             {
1656                 expected_value_int[0] = 24;
1657                 expected_value_int[1] = 25;
1658                 expected_value_int[2] = 26;
1659                 n_varying_components  = 3;
1660                 varying_type          = XFB_VARYING_TYPE_INT;
1661             }
1662             else if (name.compare("result_mat2") == 0)
1663             {
1664                 expected_value_float[0] = 27.0f;
1665                 expected_value_float[1] = 28.0f;
1666                 expected_value_float[2] = 29.0f;
1667                 expected_value_float[3] = 30.0f;
1668                 n_varying_components    = 4;
1669                 varying_type            = XFB_VARYING_TYPE_FLOAT;
1670             }
1671             else if (name.compare("result_struct_test1") == 0)
1672             {
1673                 expected_value_int[0] = 38;
1674                 n_varying_components  = 1;
1675                 varying_type          = XFB_VARYING_TYPE_INT;
1676             }
1677             else if (name.compare("result_struct_test2") == 0)
1678             {
1679                 expected_value_float[0] = 39.0f;
1680                 n_varying_components    = 1;
1681                 varying_type            = XFB_VARYING_TYPE_FLOAT;
1682             }
1683             else if (name.compare("result_uint") == 0)
1684             {
1685                 expected_value_int[0] = 31;
1686                 n_varying_components  = 1;
1687                 varying_type          = XFB_VARYING_TYPE_INT;
1688             }
1689             else if (name.compare("result_uvec2") == 0)
1690             {
1691                 expected_value_int[0] = 32;
1692                 expected_value_int[1] = 33;
1693                 n_varying_components  = 2;
1694                 varying_type          = XFB_VARYING_TYPE_INT;
1695             }
1696             else if (name.compare("result_vec4") == 0)
1697             {
1698                 expected_value_float[0] = 34.0f;
1699                 expected_value_float[1] = 35.0f;
1700                 expected_value_float[2] = 36.0f;
1701                 expected_value_float[3] = 37.0f;
1702                 n_varying_components    = 4;
1703                 varying_type            = XFB_VARYING_TYPE_FLOAT;
1704             }
1705             else if (name.compare("gl_Position") == 0)
1706             {
1707                 expected_value_float[0] = 5.0f;
1708                 expected_value_float[1] = 6.0f;
1709                 expected_value_float[2] = 7.0f;
1710                 expected_value_float[3] = 8.0f;
1711                 n_varying_components    = 4;
1712                 varying_type            = XFB_VARYING_TYPE_FLOAT;
1713             }
1714             else
1715             {
1716                 TCU_FAIL("Unrecognized XFB name");
1717             }
1718 
1719             /* Move through the requested amount of components and perform type-specific
1720              * comparison.
1721              */
1722             const float epsilon = (float)1e-5;
1723 
1724             for (unsigned int n_component = 0; n_component < n_varying_components; ++n_component)
1725             {
1726                 switch (varying_type)
1727                 {
1728                 case XFB_VARYING_TYPE_FLOAT:
1729                 {
1730                     glw::GLfloat *rendered_value = (glw::GLfloat *)traveller_ptr;
1731 
1732                     if (de::abs(*rendered_value - expected_value_float[n_component]) > epsilon)
1733                     {
1734                         m_testCtx.getLog()
1735                             << tcu::TestLog::Message << "Invalid component at index [" << n_component << "] "
1736                             << "(found:" << *rendered_value << " expected:" << expected_value_float[n_component]
1737                             << ") for varying [" << name.c_str() << "]" << tcu::TestLog::EndMessage;
1738                     }
1739 
1740                     traveller_ptr += sizeof(glw::GLfloat);
1741 
1742                     break;
1743                 }
1744 
1745                 case XFB_VARYING_TYPE_INT:
1746                 {
1747                     glw::GLint *rendered_value = (glw::GLint *)traveller_ptr;
1748 
1749                     if (*rendered_value != expected_value_int[n_component])
1750                     {
1751                         m_testCtx.getLog()
1752                             << tcu::TestLog::Message << "Invalid component at index [" << n_component << "] "
1753                             << "(found:" << *rendered_value << " expected:" << expected_value_int[n_component]
1754                             << ") for varying [" << name.c_str() << "]" << tcu::TestLog::EndMessage;
1755 
1756                         TCU_FAIL("Invalid rendered value");
1757                     }
1758 
1759                     traveller_ptr += sizeof(glw::GLint);
1760 
1761                     break;
1762                 }
1763 
1764                 default:
1765                 {
1766                     TCU_FAIL("Unrecognized varying type");
1767                 }
1768                 } /* switch(varying_type) */
1769 
1770             } /* for (all components) */
1771         }     /* for (all XFBed variables) */
1772     }         /* for (both points) */
1773 
1774     /* Unmap the BO */
1775     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1776     GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
1777 
1778     /* All done */
1779     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1780     return STOP;
1781 }
1782 
1783 /** Constructor
1784  *
1785  * @param context Test context
1786  **/
1787 TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::
TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize(Context & context,const ExtParameters & extParams)1788     TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize(Context &context, const ExtParameters &extParams)
1789     : TestCaseBase(context, extParams, "gl_MaxPatchVertices_Position_PointSize",
1790                    "Verifies gl_Position and gl_PointSize (if supported) "
1791                    "are set to correct values in TE stage. Checks if up to "
1792                    "gl_MaxPatchVertices input block values can be accessed "
1793                    "from TE stage. Also verifies if TC/TE stage properties "
1794                    "can be correctly queried for both regular and separate "
1795                    "program objects.")
1796     , m_bo_id(0)
1797     , m_gl_max_patch_vertices_value(0)
1798     , m_gl_max_tess_gen_level_value(0)
1799     , m_utils_ptr(DE_NULL)
1800     , m_vao_id(0)
1801 {
1802     /* Left blank on purpose */
1803 }
1804 
1805 /** Deinitializes all ES objects created for the test. */
deinit()1806 void TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::deinit()
1807 {
1808     /** Call base class' deinit() function */
1809     TestCaseBase::deinit();
1810 
1811     if (!m_is_tessellation_shader_supported)
1812     {
1813         return;
1814     }
1815 
1816     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1817 
1818     /* Revert TF buffer object bindings */
1819     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
1820     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
1821 
1822     /* Reset GL_PATCH_VERTICES_EXT value to the default setting */
1823     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
1824 
1825     /* Disable GL_RASTERIZER_DISCARD mode */
1826     gl.disable(GL_RASTERIZER_DISCARD);
1827 
1828     /* Unbind vertex array object */
1829     gl.bindVertexArray(0);
1830 
1831     /* Release all objects we might've created */
1832     if (m_bo_id != 0)
1833     {
1834         gl.deleteBuffers(1, &m_bo_id);
1835 
1836         m_bo_id = 0;
1837     }
1838     if (m_vao_id != 0)
1839     {
1840         gl.deleteVertexArrays(1, &m_vao_id);
1841 
1842         m_vao_id = 0;
1843     }
1844 
1845     if (m_utils_ptr != DE_NULL)
1846     {
1847         delete m_utils_ptr;
1848 
1849         m_utils_ptr = DE_NULL;
1850     }
1851 
1852     /* Release all test runs */
1853     for (_runs::iterator it = m_runs.begin(); it != m_runs.end(); ++it)
1854     {
1855         deinitTestRun(*it);
1856     }
1857     m_runs.clear();
1858 }
1859 
1860 /** Deinitializes all ES objects generated for a test run */
deinitTestRun(_run & run)1861 void TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::deinitTestRun(_run &run)
1862 {
1863     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1864 
1865     if (run.fs_id != 0)
1866     {
1867         gl.deleteShader(run.fs_id);
1868 
1869         run.fs_id = 0;
1870     }
1871 
1872     if (run.fs_program_id != 0)
1873     {
1874         gl.deleteProgram(run.fs_program_id);
1875 
1876         run.fs_program_id = 0;
1877     }
1878 
1879     if (run.pipeline_object_id != 0)
1880     {
1881         gl.deleteProgramPipelines(1, &run.pipeline_object_id);
1882 
1883         run.pipeline_object_id = 0;
1884     }
1885 
1886     if (run.po_id != 0)
1887     {
1888         gl.deleteProgram(run.po_id);
1889 
1890         run.po_id = 0;
1891     }
1892 
1893     if (run.tc_id != 0)
1894     {
1895         gl.deleteShader(run.tc_id);
1896 
1897         run.tc_id = 0;
1898     }
1899 
1900     if (run.tc_program_id != 0)
1901     {
1902         gl.deleteProgram(run.tc_program_id);
1903 
1904         run.tc_program_id = 0;
1905     }
1906 
1907     if (run.te_id != 0)
1908     {
1909         gl.deleteShader(run.te_id);
1910 
1911         run.te_id = 0;
1912     }
1913 
1914     if (run.te_program_id != 0)
1915     {
1916         gl.deleteProgram(run.te_program_id);
1917 
1918         run.te_program_id = 0;
1919     }
1920 
1921     if (run.vs_id != 0)
1922     {
1923         gl.deleteShader(run.vs_id);
1924 
1925         run.vs_id = 0;
1926     }
1927 
1928     if (run.vs_program_id != 0)
1929     {
1930         gl.deleteProgram(run.vs_program_id);
1931 
1932         run.vs_program_id = 0;
1933     }
1934 }
1935 
1936 /** Retrieves a minimal fragment shader code to be used for forming program objects
1937  *  used by the test.
1938  *
1939  *  @return As per description.
1940  **/
getFragmentShaderCode(bool should_accept_pointsize_data)1941 std::string TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::getFragmentShaderCode(
1942     bool should_accept_pointsize_data)
1943 {
1944     // Requires input to match previous stage's output
1945     std::stringstream result_code;
1946 
1947     result_code << "${VERSION}\n"
1948                    "\n"
1949                    "${SHADER_IO_BLOCKS_REQUIRE}\n"
1950                    "\n"
1951                    "precision highp float;\n"
1952                    "precision highp int;\n"
1953                    "out layout (location = 0) vec4 col;\n";
1954 
1955     if (should_accept_pointsize_data)
1956     {
1957         result_code << "in      float te_pointsize;\n";
1958     }
1959 
1960     result_code << "in       vec4 te_position;\n"
1961                    "in       vec2 te_value1;\n"
1962                    "in flat ivec4 te_value2;\n"
1963                    "\n"
1964                    "void main()\n"
1965                    "{\n"
1966                    "  col = vec4(1.0, 1.0, 1.0, 1.0);\n"
1967                    "}\n";
1968 
1969     return result_code.str();
1970 }
1971 
1972 /** Retrieves tessellation control shader source code, given user-provided arguments.
1973  *
1974  *  @param should_pass_pointsize_data true if Tessellation Control shader should configure
1975  *                                    gl_PointSize value. This should be only set to true
1976  *                                    if the tested ES implementation reports support of
1977  *                                    GL_EXT_tessellation_point_size extension.
1978  *  @param inner_tess_levels          Two FP values defining inner tessellation level values.
1979  *                                    Must not be NULL.
1980  *  @param outer_tess_levels          Four FP values defining outer tessellation level values.
1981  *                                    Must not be NULL.
1982  *
1983  *  @return As per description.
1984  **/
getTessellationControlShaderCode(bool should_pass_pointsize_data,const glw::GLfloat * inner_tess_levels,const glw::GLfloat * outer_tess_levels)1985 std::string TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::getTessellationControlShaderCode(
1986     bool should_pass_pointsize_data, const glw::GLfloat *inner_tess_levels, const glw::GLfloat *outer_tess_levels)
1987 {
1988     std::stringstream result_code;
1989 
1990     result_code << "${VERSION}\n"
1991                    "\n"
1992                    "${TESSELLATION_SHADER_REQUIRE}\n";
1993 
1994     if (should_pass_pointsize_data)
1995     {
1996         result_code << "${TESSELLATION_POINT_SIZE_REQUIRE}\n";
1997     }
1998 
1999     result_code << "\n"
2000                    "layout(vertices = "
2001                 << m_gl_max_patch_vertices_value
2002                 << ") out;\n"
2003                    "\n";
2004     if (should_pass_pointsize_data)
2005     {
2006         result_code << "${IN_PER_VERTEX_DECL_ARRAY_POINT_SIZE}";
2007         result_code << "${OUT_PER_VERTEX_DECL_ARRAY_POINT_SIZE}";
2008     }
2009     else
2010     {
2011         result_code << "${IN_PER_VERTEX_DECL_ARRAY}";
2012         result_code << "${OUT_PER_VERTEX_DECL_ARRAY}";
2013     }
2014     result_code << "out OUT_TC\n"
2015                    "{\n"
2016                    "     vec2 value1;\n"
2017                    "    ivec4 value2;\n"
2018                    "} result[];\n"
2019                    "\n"
2020                    "void main()\n"
2021                    "{\n";
2022 
2023     if (should_pass_pointsize_data)
2024     {
2025         result_code << "    gl_out[gl_InvocationID].gl_PointSize = 1.0 / float(gl_InvocationID + 1);\n";
2026     }
2027 
2028     result_code << "    gl_out[gl_InvocationID].gl_Position =  vec4(      float(gl_InvocationID * 4 + 0),   "
2029                    "float(gl_InvocationID * 4 + 1),\n"
2030                    "                                                      float(gl_InvocationID * 4 + 2),   "
2031                    "float(gl_InvocationID * 4 + 3));\n"
2032                    "    result[gl_InvocationID].value1      =  vec2(1.0 / float(gl_InvocationID + 1), 1.0 / "
2033                    "float(gl_InvocationID + 2) );\n"
2034                    "    result[gl_InvocationID].value2      = ivec4(            gl_InvocationID + 1,              "
2035                    "gl_InvocationID + 2,\n"
2036                    "                                                            gl_InvocationID + 3,              "
2037                    "gl_InvocationID + 4);\n"
2038                    "\n"
2039                    "    gl_TessLevelInner[0] = float("
2040                 << inner_tess_levels[0]
2041                 << ");\n"
2042                    "    gl_TessLevelInner[1] = float("
2043                 << inner_tess_levels[1]
2044                 << ");\n"
2045                    "    gl_TessLevelOuter[0] = float("
2046                 << outer_tess_levels[0]
2047                 << ");\n"
2048                    "    gl_TessLevelOuter[1] = float("
2049                 << outer_tess_levels[1]
2050                 << ");\n"
2051                    "    gl_TessLevelOuter[2] = float("
2052                 << outer_tess_levels[2]
2053                 << ");\n"
2054                    "    gl_TessLevelOuter[3] = float("
2055                 << outer_tess_levels[3]
2056                 << ");\n"
2057                    "}\n";
2058 
2059     return result_code.str();
2060 }
2061 
2062 /** Retrieves tessellation evaluation shader source code, given user-provided arguments.
2063  *
2064  *  @param should_pass_pointsize_data true if Tessellation Evaluation shader should set
2065  *                                    gl_PointSize to the value set by Tessellation Control
2066  *                                    stage. This should be only set to true if the tested
2067  *                                    ES implementation reports support of GL_EXT_tessellation_point_size
2068  *                                    extension, and TC stage assigns a value to gl_PointSize.
2069  *  @param primitive_mode             Primitive mode to use for the stage.
2070  *  @param vertex_ordering            Vertex ordering to use for the stage.
2071  *  @param vertex_spacing             Vertex spacing to use for the stage.
2072  *  @param is_point_mode_enabled      true to make the TE stage work in point mode, false otherwise.
2073  *
2074  *  @return As per description.
2075  **/
getTessellationEvaluationShaderCode(bool should_pass_pointsize_data,_tessellation_primitive_mode primitive_mode,_tessellation_shader_vertex_ordering vertex_ordering,_tessellation_shader_vertex_spacing vertex_spacing,bool is_point_mode_enabled)2076 std::string TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::getTessellationEvaluationShaderCode(
2077     bool should_pass_pointsize_data, _tessellation_primitive_mode primitive_mode,
2078     _tessellation_shader_vertex_ordering vertex_ordering, _tessellation_shader_vertex_spacing vertex_spacing,
2079     bool is_point_mode_enabled)
2080 {
2081     std::stringstream result_sstream;
2082     std::string result;
2083 
2084     result_sstream << "${VERSION}\n"
2085                       "\n"
2086                       "${TESSELLATION_SHADER_REQUIRE}\n";
2087 
2088     if (should_pass_pointsize_data)
2089     {
2090         result_sstream << "${TESSELLATION_POINT_SIZE_REQUIRE}\n";
2091     }
2092 
2093     result_sstream << "\n"
2094                       "layout (TESSELLATOR_PRIMITIVE_MODE VERTEX_SPACING_MODE VERTEX_ORDERING POINT_MODE) in;\n"
2095                       "\n";
2096     if (should_pass_pointsize_data)
2097     {
2098         result_sstream << "${IN_PER_VERTEX_DECL_ARRAY_POINT_SIZE}";
2099         result_sstream << "${OUT_PER_VERTEX_DECL_POINT_SIZE}";
2100     }
2101     else
2102     {
2103         result_sstream << "${IN_PER_VERTEX_DECL_ARRAY}";
2104         result_sstream << "${OUT_PER_VERTEX_DECL}";
2105     }
2106     result_sstream << "in OUT_TC\n"
2107                       "{\n"
2108                       "     vec2 value1;\n"
2109                       "    ivec4 value2;\n"
2110                       "} tc_data[];\n"
2111                       "\n";
2112 
2113     if (should_pass_pointsize_data)
2114     {
2115         result_sstream << "out      float te_pointsize;\n";
2116     }
2117 
2118     result_sstream << "out       vec4 te_position;\n"
2119                       "out       vec2 te_value1;\n"
2120                       "out flat ivec4 te_value2;\n"
2121                       "\n"
2122                       "void main()\n"
2123                       "{\n";
2124 
2125     if (should_pass_pointsize_data)
2126     {
2127         result_sstream << "    te_pointsize = 0.0;\n";
2128     }
2129 
2130     result_sstream << "    te_position  = vec4 (0.0);\n"
2131                       "    te_value1    = vec2 (0.0);\n"
2132                       "    te_value2    = ivec4(0);\n"
2133                       "\n"
2134                       "    for (int n = 0; n < "
2135                    << m_gl_max_patch_vertices_value
2136                    << "; ++n)\n"
2137                       "    {\n";
2138 
2139     if (should_pass_pointsize_data)
2140     {
2141         result_sstream << "        te_pointsize += gl_in[n].gl_PointSize;\n";
2142     }
2143 
2144     result_sstream << "        te_position += gl_in  [n].gl_Position;\n"
2145                       "        te_value1   += tc_data[n].value1;\n"
2146                       "        te_value2   += tc_data[n].value2;\n"
2147                       "    }\n"
2148                       "}\n";
2149 
2150     result = result_sstream.str();
2151 
2152     /* Replace the tokens */
2153     const char *point_mode_token           = "POINT_MODE";
2154     std::size_t point_mode_token_index     = std::string::npos;
2155     std::string primitive_mode_string      = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
2156     const char *primitive_mode_token       = "TESSELLATOR_PRIMITIVE_MODE";
2157     std::size_t primitive_mode_token_index = std::string::npos;
2158     std::string vertex_ordering_string;
2159     const char *vertex_ordering_token       = "VERTEX_ORDERING";
2160     std::size_t vertex_ordering_token_index = std::string::npos;
2161     std::string vertex_spacing_mode_string;
2162     const char *vertex_spacing_token       = "VERTEX_SPACING_MODE";
2163     std::size_t vertex_spacing_token_index = std::string::npos;
2164 
2165     /* Prepare the vertex ordering token. We need to do this manually, because the default vertex spacing
2166      * mode translates to empty string and the shader would fail to compile if we hadn't taken care of the
2167      * comma
2168      */
2169     if (vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT)
2170     {
2171         vertex_ordering_string = TessellationShaderUtils::getESTokenForVertexOrderingMode(vertex_ordering);
2172     }
2173     else
2174     {
2175         std::stringstream helper_sstream;
2176 
2177         helper_sstream << ", " << TessellationShaderUtils::getESTokenForVertexOrderingMode(vertex_ordering);
2178 
2179         vertex_ordering_string = helper_sstream.str();
2180     }
2181 
2182     /* Do the same for vertex spacing token */
2183     if (vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT)
2184     {
2185         vertex_spacing_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing);
2186     }
2187     else
2188     {
2189         std::stringstream helper_sstream;
2190 
2191         helper_sstream << ", " << TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing);
2192 
2193         vertex_spacing_mode_string = helper_sstream.str();
2194     }
2195 
2196     /* Primitive mode */
2197     while ((primitive_mode_token_index = result.find(primitive_mode_token)) != std::string::npos)
2198     {
2199         result = result.replace(primitive_mode_token_index, strlen(primitive_mode_token), primitive_mode_string);
2200 
2201         primitive_mode_token_index = result.find(primitive_mode_token);
2202     }
2203 
2204     /* Vertex ordering */
2205     while ((vertex_ordering_token_index = result.find(vertex_ordering_token)) != std::string::npos)
2206     {
2207         result = result.replace(vertex_ordering_token_index, strlen(vertex_ordering_token), vertex_ordering_string);
2208 
2209         vertex_ordering_token_index = result.find(vertex_ordering_token);
2210     }
2211 
2212     /* Vertex spacing */
2213     while ((vertex_spacing_token_index = result.find(vertex_spacing_token)) != std::string::npos)
2214     {
2215         result = result.replace(vertex_spacing_token_index, strlen(vertex_spacing_token), vertex_spacing_mode_string);
2216 
2217         vertex_spacing_token_index = result.find(vertex_spacing_token);
2218     }
2219 
2220     /* Point mode */
2221     while ((point_mode_token_index = result.find(point_mode_token)) != std::string::npos)
2222     {
2223         result = result.replace(point_mode_token_index, strlen(point_mode_token),
2224                                 (is_point_mode_enabled) ? ", point_mode" : "");
2225 
2226         point_mode_token_index = result.find(point_mode_token);
2227     }
2228 
2229     return result;
2230 }
2231 
2232 /** Retrieves a minimal vertex shader code to be used for forming program objects
2233  *  used by the test.
2234  *
2235  *  @return As per description.
2236  **/
getVertexShaderCode(bool should_pass_pointsize_data)2237 std::string TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::getVertexShaderCode(
2238     bool should_pass_pointsize_data)
2239 {
2240     std::stringstream result_sstream;
2241     result_sstream << "${VERSION}\n\n";
2242     if (should_pass_pointsize_data)
2243     {
2244         result_sstream << "${OUT_PER_VERTEX_DECL_POINT_SIZE}";
2245     }
2246     else
2247     {
2248         result_sstream << "${OUT_PER_VERTEX_DECL}";
2249     }
2250     result_sstream << "\n"
2251                       "void main()\n"
2252                       "{\n"
2253                       "}\n";
2254 
2255     return result_sstream.str();
2256 }
2257 
2258 /** Initializes all ES objects that will be used for the test. */
initTest()2259 void TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::initTest()
2260 {
2261     /* The test requires EXT_tessellation_shader */
2262     if (!m_is_tessellation_shader_supported)
2263     {
2264         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
2265     }
2266 
2267     /* Retrieve ES entry-points */
2268     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2269 
2270     /* Initialize vertex array object */
2271     gl.genVertexArrays(1, &m_vao_id);
2272     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
2273 
2274     gl.bindVertexArray(m_vao_id);
2275     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
2276 
2277     /* Generate a buffer object we will use to hold XFB data */
2278     gl.genBuffers(1, &m_bo_id);
2279     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
2280 
2281     /* Configure XFB buffer object bindings */
2282     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
2283     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
2284 
2285     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() / glBindBufferBase() call(s) failed");
2286 
2287     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2288     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &m_gl_max_tess_gen_level_value);
2289     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2290 
2291     /* Retrieve GL_MAX_PATCH_VERTICES_EXT value */
2292     gl.getIntegerv(m_glExtTokens.MAX_PATCH_VERTICES, &m_gl_max_patch_vertices_value);
2293     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_PATCH_VERTICES_EXT pname");
2294 
2295     /* We only need 1 vertex per input patch */
2296     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
2297     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
2298 
2299     /* Disable rasterization */
2300     gl.enable(GL_RASTERIZER_DISCARD);
2301     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
2302 
2303     /* Spawn utilities class instance */
2304     m_utils_ptr = new TessellationShaderUtils(gl, this);
2305 
2306     /* Initialize all test iterations */
2307     bool point_mode_enabled_flags[]                                    = {false, true};
2308     const _tessellation_primitive_mode primitive_modes[]               = {TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
2309                                                                           TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2310                                                                           TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
2311     const _tessellation_shader_vertex_ordering vertex_ordering_modes[] = {TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
2312                                                                           TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2313                                                                           TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT};
2314     const _tessellation_shader_vertex_spacing vertex_spacing_modes[]   = {
2315         TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
2316         TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD, TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT};
2317     const unsigned int n_point_mode_enabled_flags =
2318         sizeof(point_mode_enabled_flags) / sizeof(point_mode_enabled_flags[0]);
2319     const unsigned int n_primitive_modes       = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2320     const unsigned int n_vertex_ordering_modes = sizeof(vertex_ordering_modes) / sizeof(vertex_ordering_modes[0]);
2321     const unsigned int n_vertex_spacing_modes  = sizeof(vertex_spacing_modes) / sizeof(vertex_spacing_modes[0]);
2322 
2323     bool deleteResources = false;
2324 
2325     for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; n_primitive_mode++)
2326     {
2327         _tessellation_primitive_mode primitive_mode  = primitive_modes[n_primitive_mode];
2328         _tessellation_levels_set tessellation_levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2329             primitive_mode, m_gl_max_tess_gen_level_value, TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2330 
2331         for (_tessellation_levels_set_const_iterator tessellation_levels_iterator = tessellation_levels.begin();
2332              tessellation_levels_iterator != tessellation_levels.end(); tessellation_levels_iterator++)
2333         {
2334             const _tessellation_levels &tess_levels = *tessellation_levels_iterator;
2335 
2336             for (unsigned int n_vertex_ordering_mode = 0; n_vertex_ordering_mode < n_vertex_ordering_modes;
2337                  ++n_vertex_ordering_mode)
2338             {
2339                 _tessellation_shader_vertex_ordering vertex_ordering = vertex_ordering_modes[n_vertex_ordering_mode];
2340 
2341                 for (unsigned int n_vertex_spacing_mode = 0; n_vertex_spacing_mode < n_vertex_spacing_modes;
2342                      ++n_vertex_spacing_mode)
2343                 {
2344                     _tessellation_shader_vertex_spacing vertex_spacing = vertex_spacing_modes[n_vertex_spacing_mode];
2345 
2346                     for (unsigned int n_point_mode_enabled_flag = 0;
2347                          n_point_mode_enabled_flag < n_point_mode_enabled_flags; ++n_point_mode_enabled_flag)
2348                     {
2349                         bool is_point_mode_enabled = point_mode_enabled_flags[n_point_mode_enabled_flag];
2350 
2351                         /* Only create gl_PointSize-enabled runs if the implementation supports
2352                          * GL_EXT_tessellation_point_size extension
2353                          */
2354                         if (!m_is_tessellation_shader_point_size_supported && is_point_mode_enabled)
2355                         {
2356                             continue;
2357                         }
2358 
2359                         /* Execute the test run */
2360                         _run run;
2361 
2362                         memcpy(run.inner, tess_levels.inner, sizeof(run.inner));
2363                         memcpy(run.outer, tess_levels.outer, sizeof(run.outer));
2364 
2365                         run.point_mode      = is_point_mode_enabled;
2366                         run.primitive_mode  = primitive_mode;
2367                         run.vertex_ordering = vertex_ordering;
2368                         run.vertex_spacing  = vertex_spacing;
2369 
2370                         initTestRun(run);
2371 
2372                         if (deleteResources)
2373                         {
2374                             deinitTestRun(run);
2375                         }
2376 
2377                         deleteResources = true;
2378 
2379                         /* Store it for further processing */
2380                         m_runs.push_back(run);
2381                     } /* for (all 'point mode' enabled flags) */
2382                 }     /* for (all vertex spacing modes) */
2383             }         /* for (all vertex ordering modes) */
2384         }             /* for (all tessellation levels for active primitive mode) */
2385     }                 /* for (all primitive modes) */
2386 }
2387 
2388 /** Initializes all ES objects used by the test, captures the tessellation coordinates
2389  *  and stores them in the descriptor.
2390  *  Also performs a handful of other minor checks, as described by test specification.
2391  *
2392  *  @param run Run descriptor to operate on.
2393  **/
initTestRun(_run & run)2394 void TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::initTestRun(_run &run)
2395 {
2396     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2397 
2398     /* Build shader objects */
2399     run.fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2400     run.tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
2401     run.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
2402     run.vs_id = gl.createShader(GL_VERTEX_SHADER);
2403 
2404     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
2405 
2406     /* Generate fragment shader (or stand-alone program) */
2407     std::string fs_code_string  = getFragmentShaderCode(run.point_mode);
2408     const char *fs_code_raw_ptr = fs_code_string.c_str();
2409 
2410     shaderSourceSpecialized(run.fs_id, 1 /* count */, &fs_code_raw_ptr);
2411 
2412     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for fragment shader");
2413 
2414     /* Generate tessellation control shader (or stand-alone program) */
2415     std::string tc_code_string  = getTessellationControlShaderCode(run.point_mode, run.inner, run.outer);
2416     const char *tc_code_raw_ptr = tc_code_string.c_str();
2417 
2418     shaderSourceSpecialized(run.tc_id, 1 /* count */, &tc_code_raw_ptr);
2419 
2420     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for tessellation control shader");
2421 
2422     /* Generate tessellation evaluation shader (or stand-alone program) */
2423     std::string te_code_string = getTessellationEvaluationShaderCode(
2424         run.point_mode, run.primitive_mode, run.vertex_ordering, run.vertex_spacing, run.point_mode);
2425     const char *te_code_raw_ptr = te_code_string.c_str();
2426 
2427     shaderSourceSpecialized(run.te_id, 1 /* count */, &te_code_raw_ptr);
2428 
2429     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for tessellation evaluation shader");
2430 
2431     /* Generate vertex shader (or stand-alone program) */
2432     std::string vs_code_string  = getVertexShaderCode(run.point_mode);
2433     const char *vs_code_raw_ptr = vs_code_string.c_str();
2434 
2435     shaderSourceSpecialized(run.vs_id, 1 /* count */, &vs_code_raw_ptr);
2436 
2437     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for vertex shader");
2438 
2439     /* Compile all shaders first. Also make sure the shader objects we have
2440      * attached are correctly reported.
2441      */
2442     const glw::GLuint shaders[]  = {run.fs_id, run.tc_id, run.te_id, run.vs_id};
2443     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
2444 
2445     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
2446     {
2447         glw::GLint compile_status = GL_FALSE;
2448         glw::GLint shader         = shaders[n_shader];
2449 
2450         gl.compileShader(shader);
2451         GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
2452 
2453         gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
2454         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
2455 
2456         if (compile_status != GL_TRUE)
2457         {
2458             m_testCtx.getLog() << tcu::TestLog::Message << "Info log:\n"
2459                                << getCompilationInfoLog(shader) << "\nShader:\n"
2460                                << getShaderSource(shader) << tcu::TestLog::EndMessage;
2461             TCU_FAIL("Shader compilation failed");
2462         }
2463     }
2464 
2465     /* Run two iterations:
2466      *
2467      * 1) First, using a program object;
2468      * 2) The other one using pipeline objects;
2469      */
2470     for (unsigned int n_iteration = 0; n_iteration < 2 /* program / pipeline objects */; ++n_iteration)
2471     {
2472         bool should_use_program_object = (n_iteration == 0);
2473 
2474         /* Generate container object(s) first */
2475         if (!should_use_program_object)
2476         {
2477             gl.genProgramPipelines(1, &run.pipeline_object_id);
2478             GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() failed");
2479 
2480             /* As per test spec, make sure no tessellation stages are defined for
2481              * a pipeline object by default */
2482             glw::GLint program_tc_id = 1;
2483             glw::GLint program_te_id = 1;
2484 
2485             gl.getProgramPipelineiv(run.pipeline_object_id, m_glExtTokens.TESS_CONTROL_SHADER, &program_tc_id);
2486             gl.getProgramPipelineiv(run.pipeline_object_id, m_glExtTokens.TESS_EVALUATION_SHADER, &program_te_id);
2487             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() failed");
2488 
2489             if (program_tc_id != 0 || program_te_id != 0)
2490             {
2491                 GLU_EXPECT_NO_ERROR(gl.getError(), "A pipeline object returned a non-zero ID of "
2492                                                    "a separate program object when asked for TC/TE"
2493                                                    " program ID.");
2494             }
2495         }
2496         else
2497         {
2498             run.po_id = gl.createProgram();
2499             GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
2500         }
2501 
2502         if (!should_use_program_object)
2503         {
2504             run.fs_program_id = gl.createProgram();
2505             run.tc_program_id = gl.createProgram();
2506             run.te_program_id = gl.createProgram();
2507             run.vs_program_id = gl.createProgram();
2508 
2509             GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed");
2510         }
2511 
2512         /* Link program object(s) (and configure the pipeline object, if necessary) */
2513         const glw::GLuint programs_for_pipeline_iteration[] = {run.fs_program_id, run.tc_program_id, run.te_program_id,
2514                                                                run.vs_program_id};
2515         const glw::GLuint programs_for_program_iteration[]  = {run.po_id};
2516         const unsigned int n_programs_for_pipeline_iteration =
2517             sizeof(programs_for_pipeline_iteration) / sizeof(programs_for_pipeline_iteration[0]);
2518         const unsigned int n_programs_for_program_iteration =
2519             sizeof(programs_for_program_iteration) / sizeof(programs_for_program_iteration[0]);
2520 
2521         unsigned int n_programs       = 0;
2522         const glw::GLuint *programs   = DE_NULL;
2523         int xfb_pointsize_data_offset = -1;
2524         int xfb_position_data_offset  = -1;
2525         int xfb_value1_data_offset    = -1;
2526         int xfb_value2_data_offset    = -1;
2527         int xfb_varyings_size         = 0;
2528 
2529         if (should_use_program_object)
2530         {
2531             n_programs = n_programs_for_program_iteration;
2532             programs   = programs_for_program_iteration;
2533         }
2534         else
2535         {
2536             n_programs = n_programs_for_pipeline_iteration;
2537             programs   = programs_for_pipeline_iteration;
2538         }
2539 
2540         /* Attach and verify shader objects */
2541         for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
2542         {
2543             glw::GLuint parent_po_id = 0;
2544             glw::GLuint shader       = shaders[n_shader];
2545 
2546             if (should_use_program_object)
2547             {
2548                 gl.attachShader(run.po_id, shader);
2549                 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
2550 
2551                 parent_po_id = run.po_id;
2552             }
2553             else
2554             {
2555                 if (shader == run.fs_id)
2556                 {
2557                     gl.attachShader(run.fs_program_id, run.fs_id);
2558 
2559                     parent_po_id = run.fs_program_id;
2560                 }
2561                 else if (shader == run.tc_id)
2562                 {
2563                     gl.attachShader(run.tc_program_id, run.tc_id);
2564 
2565                     parent_po_id = run.tc_program_id;
2566                 }
2567                 else if (shader == run.te_id)
2568                 {
2569                     gl.attachShader(run.te_program_id, run.te_id);
2570 
2571                     parent_po_id = run.te_program_id;
2572                 }
2573                 else
2574                 {
2575                     DE_ASSERT(shader == run.vs_id);
2576 
2577                     gl.attachShader(run.vs_program_id, run.vs_id);
2578 
2579                     parent_po_id = run.vs_program_id;
2580                 }
2581 
2582                 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
2583             }
2584 
2585             /* Make sure the shader object we've attached is reported as a part
2586              * of the program object.
2587              */
2588             unsigned int attached_shaders[n_shaders] = {0};
2589             bool has_found_attached_shader           = false;
2590             glw::GLsizei n_attached_shaders          = 0;
2591 
2592             memset(attached_shaders, 0, sizeof(attached_shaders));
2593 
2594             gl.getAttachedShaders(parent_po_id, n_shaders, &n_attached_shaders, attached_shaders);
2595             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttachedShaders() failed");
2596 
2597             for (glw::GLsizei n_attached_shader = 0; n_attached_shader < n_attached_shaders; n_attached_shader++)
2598             {
2599                 if (attached_shaders[n_attached_shader] == shader)
2600                 {
2601                     has_found_attached_shader = true;
2602 
2603                     break;
2604                 }
2605             } /* for (all attached shader object IDs) */
2606 
2607             if (!has_found_attached_shader)
2608             {
2609                 TCU_FAIL("A shader object that was successfully attached to a program "
2610                          "object was not reported as one by subsequent glGetAttachedShaders() "
2611                          "call");
2612             }
2613         }
2614 
2615         /* Set up XFB */
2616         const char *xfb_varyings_w_pointsize[]  = {"te_position", "te_value1", "te_value2", "te_pointsize"};
2617         const char *xfb_varyings_wo_pointsize[] = {
2618             "te_position",
2619             "te_value1",
2620             "te_value2",
2621         };
2622         const char **xfb_varyings   = DE_NULL;
2623         unsigned int n_xfb_varyings = 0;
2624 
2625         if (run.point_mode)
2626         {
2627             xfb_varyings   = xfb_varyings_w_pointsize;
2628             n_xfb_varyings = sizeof(xfb_varyings_w_pointsize) / sizeof(xfb_varyings_w_pointsize[0]);
2629 
2630             xfb_position_data_offset = 0;
2631             xfb_value1_data_offset =
2632                 static_cast<unsigned int>(xfb_position_data_offset + sizeof(float) * 4); /* size of te_position */
2633             xfb_value2_data_offset =
2634                 static_cast<unsigned int>(xfb_value1_data_offset + sizeof(float) * 2); /* size of te_value1 */
2635             xfb_pointsize_data_offset =
2636                 static_cast<unsigned int>(xfb_value2_data_offset + sizeof(int) * 4); /* size of te_value2 */
2637 
2638             xfb_varyings_size = sizeof(float) * 4 + /* size of te_position */
2639                                 sizeof(float) * 2 + /* size of te_value1 */
2640                                 sizeof(int) * 4 +   /* size of te_value2 */
2641                                 sizeof(int);        /* size of te_pointsize */
2642         }
2643         else
2644         {
2645             xfb_varyings   = xfb_varyings_wo_pointsize;
2646             n_xfb_varyings = sizeof(xfb_varyings_wo_pointsize) / sizeof(xfb_varyings_wo_pointsize[0]);
2647 
2648             xfb_position_data_offset = 0;
2649             xfb_value1_data_offset =
2650                 static_cast<unsigned int>(xfb_position_data_offset + sizeof(float) * 4); /* size of te_position */
2651             xfb_value2_data_offset =
2652                 static_cast<unsigned int>(xfb_value1_data_offset + sizeof(float) * 2); /* size of te_value1 */
2653 
2654             xfb_varyings_size = sizeof(float) * 4 + /* size of te_position */
2655                                 sizeof(float) * 2 + /* size of te_value1 */
2656                                 sizeof(int) * 4;
2657         }
2658 
2659         if (!should_use_program_object)
2660         {
2661             gl.transformFeedbackVaryings(run.te_program_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
2662 
2663             GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
2664         }
2665         else
2666         {
2667             gl.transformFeedbackVaryings(run.po_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
2668 
2669             GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
2670         }
2671 
2672         /* Mark all program objects as separable for pipeline run */
2673         if (!should_use_program_object)
2674         {
2675             for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
2676             {
2677                 glw::GLuint program = programs[n_program];
2678 
2679                 gl.programParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
2680                 GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() failed.");
2681             }
2682         }
2683 
2684         /* Link the program object(s) */
2685         for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
2686         {
2687             glw::GLint link_status = GL_FALSE;
2688             glw::GLuint program    = programs[n_program];
2689 
2690             gl.linkProgram(program);
2691             GLU_EXPECT_NO_ERROR(gl.getError(), "Program linking failed");
2692 
2693             gl.getProgramiv(program, GL_LINK_STATUS, &link_status);
2694             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
2695 
2696             if (link_status != GL_TRUE)
2697             {
2698                 m_testCtx.getLog() << tcu::TestLog::Message << "Info log:\n"
2699                                    << getLinkingInfoLog(program) << tcu::TestLog::EndMessage;
2700                 TCU_FAIL("Program linking failed");
2701             }
2702 
2703             /* Make sure glGetProgramiv() reports correct tessellation properties for
2704              * the program object we've just linked successfully */
2705             if (program == run.po_id || program == run.tc_program_id || program == run.te_program_id)
2706             {
2707                 glw::GLenum expected_tess_gen_mode_value         = GL_NONE;
2708                 glw::GLenum expected_tess_gen_spacing_value      = GL_NONE;
2709                 glw::GLenum expected_tess_gen_vertex_order_value = GL_NONE;
2710                 glw::GLint tess_control_output_vertices_value    = GL_NONE;
2711                 glw::GLint tess_gen_mode_value                   = GL_NONE;
2712                 glw::GLint tess_gen_point_mode_value             = GL_NONE;
2713                 glw::GLint tess_gen_spacing_value                = GL_NONE;
2714                 glw::GLint tess_gen_vertex_order_value           = GL_NONE;
2715 
2716                 switch (run.primitive_mode)
2717                 {
2718                 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
2719                     expected_tess_gen_mode_value = m_glExtTokens.ISOLINES;
2720                     break;
2721                 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
2722                     expected_tess_gen_mode_value = m_glExtTokens.QUADS;
2723                     break;
2724                 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
2725                     expected_tess_gen_mode_value = GL_TRIANGLES;
2726                     break;
2727 
2728                 default:
2729                 {
2730                     /* Unrecognized primitive mode? */
2731                     DE_ASSERT(false);
2732                 }
2733                 } /* switch (run.primitive_mode) */
2734 
2735                 switch (run.vertex_spacing)
2736                 {
2737                 case TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT:
2738                 case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
2739                     expected_tess_gen_spacing_value = GL_EQUAL;
2740                     break;
2741                 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN:
2742                     expected_tess_gen_spacing_value = m_glExtTokens.FRACTIONAL_EVEN;
2743                     break;
2744                 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
2745                     expected_tess_gen_spacing_value = m_glExtTokens.FRACTIONAL_ODD;
2746                     break;
2747 
2748                 default:
2749                 {
2750                     /* Unrecognized vertex spacing mode? */
2751                     DE_ASSERT(false);
2752                 }
2753                 } /* switch (run.vertex_spacing) */
2754 
2755                 switch (run.vertex_ordering)
2756                 {
2757                 case TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT:
2758                 case TESSELLATION_SHADER_VERTEX_ORDERING_CCW:
2759                     expected_tess_gen_vertex_order_value = GL_CCW;
2760                     break;
2761                 case TESSELLATION_SHADER_VERTEX_ORDERING_CW:
2762                     expected_tess_gen_vertex_order_value = GL_CW;
2763                     break;
2764 
2765                 default:
2766                 {
2767                     /* Unrecognized vertex ordering mode? */
2768                     DE_ASSERT(false);
2769                 }
2770                 } /* switch (run.vertex_ordering) */
2771 
2772                 if (program == run.po_id || program == run.tc_program_id)
2773                 {
2774                     gl.getProgramiv(program, m_glExtTokens.TESS_CONTROL_OUTPUT_VERTICES,
2775                                     &tess_control_output_vertices_value);
2776                     GLU_EXPECT_NO_ERROR(gl.getError(),
2777                                         "glGetProgramiv() failed for GL_TESS_CONTROL_OUTPUT_VERTICES_EXT pname");
2778 
2779                     if (tess_control_output_vertices_value != m_gl_max_patch_vertices_value)
2780                     {
2781                         TCU_FAIL(
2782                             "Invalid value returned by glGetProgramiv() for GL_TESS_CONTROL_OUTPUT_VERTICES_EXT query");
2783                     }
2784                 }
2785 
2786                 if (program == run.po_id || program == run.te_program_id)
2787                 {
2788                     gl.getProgramiv(program, m_glExtTokens.TESS_GEN_MODE, &tess_gen_mode_value);
2789                     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed for GL_TESS_GEN_MODE_EXT pname");
2790 
2791                     if ((glw::GLuint)tess_gen_mode_value != expected_tess_gen_mode_value)
2792                     {
2793                         TCU_FAIL("Invalid value returned by glGetProgramiv() for GL_TESS_GEN_MODE_EXT query");
2794                     }
2795                 }
2796 
2797                 if (program == run.po_id || program == run.te_program_id)
2798                 {
2799                     gl.getProgramiv(program, m_glExtTokens.TESS_GEN_SPACING, &tess_gen_spacing_value);
2800                     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed for GL_TESS_GEN_SPACING_EXT pname");
2801 
2802                     if ((glw::GLuint)tess_gen_spacing_value != expected_tess_gen_spacing_value)
2803                     {
2804                         TCU_FAIL("Invalid value returned by glGetProgramiv() for GL_TESS_GEN_SPACING_EXT query");
2805                     }
2806                 }
2807 
2808                 if (program == run.po_id || program == run.te_program_id)
2809                 {
2810                     gl.getProgramiv(program, m_glExtTokens.TESS_GEN_VERTEX_ORDER, &tess_gen_vertex_order_value);
2811                     GLU_EXPECT_NO_ERROR(gl.getError(),
2812                                         "glGetProgramiv() failed for GL_TESS_GEN_VERTEX_ORDER_EXT pname");
2813 
2814                     if ((glw::GLuint)tess_gen_vertex_order_value != expected_tess_gen_vertex_order_value)
2815                     {
2816                         TCU_FAIL("Invalid value returned by glGetProgramiv() for GL_TESS_GEN_VERTEX_ORDER_EXT query");
2817                     }
2818                 }
2819 
2820                 if (program == run.po_id || program == run.te_program_id)
2821                 {
2822                     gl.getProgramiv(program, m_glExtTokens.TESS_GEN_POINT_MODE, &tess_gen_point_mode_value);
2823                     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed for GL_TESS_GEN_POINT_MODE_EXT pname");
2824 
2825                     if (tess_gen_point_mode_value != ((run.point_mode) ? GL_TRUE : GL_FALSE))
2826                     {
2827                         TCU_FAIL("Invalid value returned by glGetProgramiv() for GL_TESS_GEN_POINT_MODE_EXT query");
2828                     }
2829                 }
2830             } /* if (program == run.po_id || program == run.tc_program_id || program == run.te_program_id) */
2831         }     /* for (all considered program objects) */
2832 
2833         if (!should_use_program_object)
2834         {
2835             /* Attach all stages to the pipeline object */
2836             gl.useProgramStages(run.pipeline_object_id, GL_FRAGMENT_SHADER_BIT, run.fs_program_id);
2837             gl.useProgramStages(run.pipeline_object_id, m_glExtTokens.TESS_CONTROL_SHADER_BIT, run.tc_program_id);
2838             gl.useProgramStages(run.pipeline_object_id, m_glExtTokens.TESS_EVALUATION_SHADER_BIT, run.te_program_id);
2839             gl.useProgramStages(run.pipeline_object_id, GL_VERTEX_SHADER_BIT, run.vs_program_id);
2840             GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed");
2841 
2842             /* Make sure the pipeline object validates correctly */
2843             glw::GLint validate_status = GL_FALSE;
2844 
2845             gl.validateProgramPipeline(run.pipeline_object_id);
2846             GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed");
2847 
2848             gl.getProgramPipelineiv(run.pipeline_object_id, GL_VALIDATE_STATUS, &validate_status);
2849             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed");
2850 
2851             if (validate_status != GL_TRUE)
2852             {
2853                 m_testCtx.getLog() << tcu::TestLog::Message << "Info log:\n"
2854                                    << getPipelineInfoLog(run.pipeline_object_id) << "\n\nVertex Shader:\n"
2855                                    << vs_code_raw_ptr << "\n\nTessellation Control Shader:\n"
2856                                    << tc_code_raw_ptr << "\n\nTessellation Evaluation Shader:\n"
2857                                    << te_code_raw_ptr << "\n\nFragment Shader:\n"
2858                                    << fs_code_raw_ptr << tcu::TestLog::EndMessage;
2859                 TCU_FAIL("Pipeline object was found to be invalid");
2860             }
2861         }
2862 
2863         /* Determine how many vertices are going to be generated by the tessellator
2864          * for particular tessellation configuration.
2865          */
2866         unsigned int n_vertices_generated = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2867             run.primitive_mode, run.inner, run.outer, run.vertex_spacing, run.point_mode);
2868 
2869         /* Allocate enough space to hold the result XFB data */
2870         const unsigned int bo_size = xfb_varyings_size * n_vertices_generated;
2871 
2872         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
2873         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
2874 
2875         /* Use the pipeline or program object and render the data */
2876         glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(run.primitive_mode, run.point_mode);
2877 
2878         if (should_use_program_object)
2879         {
2880             gl.bindProgramPipeline(0);
2881             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed");
2882 
2883             gl.useProgram(run.po_id);
2884             GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
2885         }
2886         else
2887         {
2888             gl.bindProgramPipeline(run.pipeline_object_id);
2889             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed");
2890 
2891             gl.useProgram(0);
2892             GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
2893         }
2894 
2895         gl.beginTransformFeedback(tf_mode);
2896         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
2897         {
2898             gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
2899 
2900             GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
2901         }
2902         gl.endTransformFeedback();
2903         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
2904 
2905         /* Map the buffer object contents into process space */
2906         const char *xfb_data = (const char *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
2907                                                                bo_size, GL_MAP_READ_BIT);
2908 
2909         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
2910 
2911         /* Iterate through all vertices and extract all captured data. To reduce amount
2912          * of time necessary to verify the generated data, only store *unique* values.
2913          */
2914         for (unsigned int n_vertex = 0; n_vertex < n_vertices_generated; ++n_vertex)
2915         {
2916             if (xfb_pointsize_data_offset != -1)
2917             {
2918                 const float *data_ptr =
2919                     (const float *)(xfb_data + xfb_varyings_size * n_vertex + xfb_pointsize_data_offset);
2920 
2921                 if (std::find(run.result_pointsize_data.begin(), run.result_pointsize_data.end(), *data_ptr) ==
2922                     run.result_pointsize_data.end())
2923                 {
2924                     run.result_pointsize_data.push_back(*data_ptr);
2925                 }
2926             }
2927 
2928             if (xfb_position_data_offset != -1)
2929             {
2930                 const float *data_ptr =
2931                     (const float *)(xfb_data + xfb_varyings_size * n_vertex + xfb_position_data_offset);
2932                 _vec4 new_item = _vec4(data_ptr[0], data_ptr[1], data_ptr[2], data_ptr[3]);
2933 
2934                 if (std::find(run.result_position_data.begin(), run.result_position_data.end(), new_item) ==
2935                     run.result_position_data.end())
2936                 {
2937                     run.result_position_data.push_back(new_item);
2938                 }
2939             }
2940 
2941             if (xfb_value1_data_offset != -1)
2942             {
2943                 const float *data_ptr =
2944                     (const float *)(xfb_data + xfb_varyings_size * n_vertex + xfb_value1_data_offset);
2945                 _vec2 new_item = _vec2(data_ptr[0], data_ptr[1]);
2946 
2947                 if (std::find(run.result_value1_data.begin(), run.result_value1_data.end(), new_item) ==
2948                     run.result_value1_data.end())
2949                 {
2950                     run.result_value1_data.push_back(new_item);
2951                 }
2952             }
2953 
2954             if (xfb_value2_data_offset != -1)
2955             {
2956                 const int *data_ptr = (const int *)(xfb_data + xfb_varyings_size * n_vertex + xfb_value2_data_offset);
2957                 _ivec4 new_item     = _ivec4(data_ptr[0], data_ptr[1], data_ptr[2], data_ptr[3]);
2958 
2959                 if (std::find(run.result_value2_data.begin(), run.result_value2_data.end(), new_item) ==
2960                     run.result_value2_data.end())
2961                 {
2962                     run.result_value2_data.push_back(new_item);
2963                 }
2964             }
2965         } /* for (all result tessellation coordinates) */
2966 
2967         /* Good to unmap the buffer object at this point */
2968         gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2969         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
2970     } /* for (two iterations) */
2971 }
2972 
2973 /** Executes the test.
2974  *
2975  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2976  *
2977  *  Note the function throws exception should an error occur!
2978  *
2979  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
2980  **/
iterate(void)2981 tcu::TestNode::IterateResult TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::iterate(void)
2982 {
2983     /* Initialize ES test objects */
2984     initTest();
2985 
2986     /* Calculate reference values that should be generated for all runs */
2987     float reference_result_pointsize(0);
2988     _vec4 reference_result_position(0, 0, 0, 0);
2989     _vec2 reference_result_value1(0, 0);
2990     _ivec4 reference_result_value2(0, 0, 0, 0);
2991     const float epsilon = (float)1e-5;
2992 
2993     for (glw::GLint n_invocation = 0; n_invocation < m_gl_max_patch_vertices_value; ++n_invocation)
2994     {
2995         /* As per TC and TE shaders */
2996         reference_result_pointsize += 1.0f / static_cast<float>(n_invocation + 1);
2997 
2998         reference_result_position.x += static_cast<float>(n_invocation * 4 + 0);
2999         reference_result_position.y += static_cast<float>(n_invocation * 4 + 1);
3000         reference_result_position.z += static_cast<float>(n_invocation * 4 + 2);
3001         reference_result_position.w += static_cast<float>(n_invocation * 4 + 3);
3002 
3003         reference_result_value1.x += 1.0f / static_cast<float>(n_invocation + 1);
3004         reference_result_value1.y += 1.0f / static_cast<float>(n_invocation + 2);
3005 
3006         reference_result_value2.x += (n_invocation + 1);
3007         reference_result_value2.y += (n_invocation + 2);
3008         reference_result_value2.z += (n_invocation + 3);
3009         reference_result_value2.w += (n_invocation + 4);
3010     }
3011 
3012     /* Iterate through test runs and analyse the result data */
3013     for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
3014     {
3015         const _run &run = *run_iterator;
3016 
3017         /* For the very first run, make sure that the type of tessellation shader objects
3018          * is reported correctly for both program and pipeline object cases.
3019          */
3020         if (run_iterator == m_runs.begin())
3021         {
3022             const glw::Functions &gl  = m_context.getRenderContext().getFunctions();
3023             glw::GLint shader_type_tc = GL_NONE;
3024             glw::GLint shader_type_te = GL_NONE;
3025 
3026             /* Program objects first */
3027             gl.getShaderiv(run.tc_id, GL_SHADER_TYPE, &shader_type_tc);
3028             gl.getShaderiv(run.te_id, GL_SHADER_TYPE, &shader_type_te);
3029             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call(s) failed");
3030 
3031             if ((glw::GLenum)shader_type_tc != m_glExtTokens.TESS_CONTROL_SHADER)
3032             {
3033                 TCU_FAIL("Invalid shader type reported by glGetShaderiv() for a tessellation control shader");
3034             }
3035 
3036             if ((glw::GLenum)shader_type_te != m_glExtTokens.TESS_EVALUATION_SHADER)
3037             {
3038                 TCU_FAIL("Invalid shader type reported by glGetShaderiv() for a tessellation evaluation shader");
3039             }
3040 
3041             /* Let's query the pipeline object now */
3042             glw::GLint shader_id_tc = 0;
3043             glw::GLint shader_id_te = 0;
3044 
3045             gl.getProgramPipelineiv(run.pipeline_object_id, m_glExtTokens.TESS_CONTROL_SHADER, &shader_id_tc);
3046             gl.getProgramPipelineiv(run.pipeline_object_id, m_glExtTokens.TESS_EVALUATION_SHADER, &shader_id_te);
3047 
3048             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() failed for GL_TESS_CONTROL_SHADER_EXT / "
3049                                                "GL_TESS_EVALUATION_SHADER_EXT enum(s)");
3050 
3051             if ((glw::GLuint)shader_id_tc != run.tc_program_id)
3052             {
3053                 TCU_FAIL("Invalid separate program object ID reported for Tessellation Control stage");
3054             }
3055 
3056             if ((glw::GLuint)shader_id_te != run.te_program_id)
3057             {
3058                 TCU_FAIL("Invalid separate program object ID reported for Tessellation Evaluation stage");
3059             }
3060         }
3061 
3062         if ((run.point_mode && run.result_pointsize_data.size() != 1) ||
3063             (run.point_mode && de::abs(run.result_pointsize_data[0] - reference_result_pointsize) > epsilon))
3064         {
3065             /* It is a test bug if result_pointsize_data.size() == 0 */
3066             DE_ASSERT(run.result_pointsize_data.size() > 0);
3067 
3068             m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation Evaluation stage set gl_PointSize value to "
3069                                << run.result_pointsize_data[0] << " instead of expected value "
3070                                << reference_result_pointsize << tcu::TestLog::EndMessage;
3071 
3072             TCU_FAIL("Invalid gl_PointSize data exposed in TE stage");
3073         }
3074 
3075         if (run.result_position_data.size() != 1 || run.result_position_data[0] != reference_result_position)
3076         {
3077             /* It is a test bug if result_position_data.size() == 0 */
3078             DE_ASSERT(run.result_position_data.size() > 0);
3079 
3080             m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation Evaluation stage set gl_Position to "
3081                                << " (" << run.result_position_data[0].x << ", " << run.result_position_data[0].y << ", "
3082                                << run.result_position_data[0].z << ", " << run.result_position_data[0].w
3083                                << " ) instead of expected value"
3084                                   " ("
3085                                << reference_result_position.x << ", " << reference_result_position.y << ", "
3086                                << reference_result_position.z << ", " << reference_result_position.w << ")"
3087                                << tcu::TestLog::EndMessage;
3088 
3089             TCU_FAIL("Invalid gl_Position data exposed in TE stage");
3090         }
3091 
3092         if (run.result_value1_data.size() != 1 ||
3093             de::abs(run.result_value1_data[0].x - reference_result_value1.x) > epsilon ||
3094             de::abs(run.result_value1_data[0].y - reference_result_value1.y) > epsilon)
3095         {
3096             /* It is a test bug if result_value1_data.size() == 0 */
3097             DE_ASSERT(run.result_value1_data.size() > 0);
3098 
3099             m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation Evaluation stage set te_value1 to "
3100                                << " (" << run.result_value1_data[0].x << ", " << run.result_value1_data[0].y
3101                                << " ) instead of expected value"
3102                                   " ("
3103                                << reference_result_value1.x << ", " << reference_result_value1.y << ")"
3104                                << tcu::TestLog::EndMessage;
3105 
3106             TCU_FAIL("Invalid gl_Position data exposed in TE stage");
3107         }
3108 
3109         if (run.result_value2_data.size() != 1 || run.result_value2_data[0] != reference_result_value2)
3110         {
3111             /* It is a test bug if result_value2_data.size() == 0 */
3112             DE_ASSERT(run.result_value2_data.size() > 0);
3113 
3114             m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation Evaluation stage set te_value2 to "
3115                                << " (" << run.result_value2_data[0].x << ", " << run.result_value2_data[0].y << ", "
3116                                << run.result_value2_data[0].z << ", " << run.result_value2_data[0].w
3117                                << " ) instead of expected value"
3118                                   " ("
3119                                << reference_result_value2.x << ", " << reference_result_value2.y << ", "
3120                                << reference_result_value2.z << ", " << reference_result_value2.w << ")"
3121                                << tcu::TestLog::EndMessage;
3122 
3123             TCU_FAIL("Invalid value2 data saved in TE stage");
3124         }
3125     } /* for (all runs) */
3126 
3127     /* All done */
3128     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3129     return STOP;
3130 }
3131 
3132 /** Constructor
3133  *
3134  * @param context Test context
3135  **/
TessellationShaderTCTEgl_TessLevel(Context & context,const ExtParameters & extParams)3136 TessellationShaderTCTEgl_TessLevel::TessellationShaderTCTEgl_TessLevel(Context &context, const ExtParameters &extParams)
3137     : TestCaseBase(context, extParams, "gl_tessLevel",
3138                    "Verifies gl_TessLevelOuter and gl_TessLevelInner patch variable "
3139                    "values in a tessellation evaluation shader are valid and correspond"
3140                    "to values configured in a tessellation control shader (should one be "
3141                    "present) or to the default values, as set with glPatchParameterfv() calls")
3142     , m_gl_max_tess_gen_level_value(0)
3143     , m_bo_id(0)
3144     , m_vao_id(0)
3145 {
3146     /* Left blank on purpose */
3147 }
3148 
3149 /** Deinitializes all ES objects created for the test. */
deinit()3150 void TessellationShaderTCTEgl_TessLevel::deinit()
3151 {
3152     /** Call base class' deinit() function */
3153     TestCaseBase::deinit();
3154 
3155     if (!m_is_tessellation_shader_supported)
3156     {
3157         return;
3158     }
3159 
3160     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3161 
3162     /* Reset TF buffer object bindings */
3163     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
3164     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
3165 
3166     /* Reset GL_PATCH_VERTICES_EXT value to the default setting */
3167     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
3168 
3169     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3170     {
3171         /* Revert GL_PATCH_DEFAULT_INNER_LEVEL and GL_PATCH_DEFAULT_OUTER_LEVEL pname
3172          * values to the default settings */
3173         const float default_levels[] = {1.0f, 1.0f, 1.0f, 1.0f};
3174         gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, default_levels);
3175         gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, default_levels);
3176     }
3177 
3178     /* Disable GL_RASTERIZER_DISCARD mode */
3179     gl.disable(GL_RASTERIZER_DISCARD);
3180 
3181     /* Unbind vertex array object */
3182     gl.bindVertexArray(0);
3183 
3184     /* Release all objects we might've created */
3185     if (m_bo_id != 0)
3186     {
3187         gl.deleteBuffers(1, &m_bo_id);
3188 
3189         m_bo_id = 0;
3190     }
3191 
3192     if (m_vao_id != 0)
3193     {
3194         gl.deleteVertexArrays(1, &m_vao_id);
3195 
3196         m_vao_id = 0;
3197     }
3198 
3199     for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
3200     {
3201         deinitTestDescriptor(&*it);
3202     }
3203     m_tests.clear();
3204 }
3205 
3206 /** Deinitializes ES objects created for particular test pass.
3207  *
3208  *  @param test_ptr Test run descriptor. Must not be NULL.
3209  *
3210  **/
deinitTestDescriptor(_test_descriptor * test_ptr)3211 void TessellationShaderTCTEgl_TessLevel::deinitTestDescriptor(_test_descriptor *test_ptr)
3212 {
3213     /* Call base class' deinit() */
3214     TestCaseBase::deinit();
3215 
3216     /* Release all objects */
3217     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3218 
3219     if (test_ptr->fs_id != 0)
3220     {
3221         gl.deleteShader(test_ptr->fs_id);
3222 
3223         test_ptr->fs_id = 0;
3224     }
3225 
3226     if (test_ptr->po_id != 0)
3227     {
3228         gl.deleteProgram(test_ptr->po_id);
3229 
3230         test_ptr->po_id = 0;
3231     }
3232 
3233     if (test_ptr->tcs_id != 0)
3234     {
3235         gl.deleteShader(test_ptr->tcs_id);
3236 
3237         test_ptr->tcs_id = 0;
3238     }
3239 
3240     if (test_ptr->tes_id != 0)
3241     {
3242         gl.deleteShader(test_ptr->tes_id);
3243 
3244         test_ptr->tes_id = 0;
3245     }
3246 
3247     if (test_ptr->vs_id != 0)
3248     {
3249         gl.deleteShader(test_ptr->vs_id);
3250 
3251         test_ptr->vs_id = 0;
3252     }
3253 }
3254 
3255 /** Initializes all ES objects that will be used for the test. */
initTest()3256 void TessellationShaderTCTEgl_TessLevel::initTest()
3257 {
3258     /* The test requires EXT_tessellation_shader */
3259     if (!m_is_tessellation_shader_supported)
3260     {
3261         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
3262     }
3263 
3264     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value before we carry on */
3265     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3266 
3267     /* Initialize vertex array object */
3268     gl.genVertexArrays(1, &m_vao_id);
3269     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
3270 
3271     gl.bindVertexArray(m_vao_id);
3272     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
3273 
3274     /* Retrieve gen level */
3275     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &m_gl_max_tess_gen_level_value);
3276 
3277     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_MAX_TESS_GEN_LEVEL_EXT pname failed");
3278 
3279     /* Initialize test descriptors */
3280     _test_descriptor test_tcs_tes_equal;
3281     _test_descriptor test_tcs_tes_fe;
3282     _test_descriptor test_tcs_tes_fo;
3283     _test_descriptor test_tes_equal;
3284     _test_descriptor test_tes_fe;
3285     _test_descriptor test_tes_fo;
3286 
3287     initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_equal, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
3288     initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_fe,
3289                        TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN);
3290     initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_fo,
3291                        TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
3292     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3293     {
3294         initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_equal, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
3295         initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_fe,
3296                            TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN);
3297         initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_fo, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
3298     }
3299 
3300     m_tests.push_back(test_tcs_tes_equal);
3301     m_tests.push_back(test_tcs_tes_fe);
3302     m_tests.push_back(test_tcs_tes_fo);
3303     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3304     {
3305         m_tests.push_back(test_tes_equal);
3306         m_tests.push_back(test_tes_fe);
3307         m_tests.push_back(test_tes_fo);
3308     }
3309 
3310     /* Generate and set up a buffer object we will use to hold XFBed data.
3311      *
3312      * NOTE: We do not set the buffer object's storage here because its size
3313      *       is iteration-specific.
3314      **/
3315     gl.genBuffers(1, &m_bo_id);
3316     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
3317 
3318     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
3319     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
3320     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
3321     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
3322 
3323     /* We're good to execute the test! */
3324 }
3325 
3326 /** Initializes ES objects for a particular tess pass.
3327  *
3328  *  @param test_type           Determines test type to be used for initialization.
3329  *                             TEST_TYPE_TCS_TES will use both TC and TE stages,
3330  *                             TEST_TYPE_TES will assume only TE stage should be used.
3331  *  @param out_test_ptr        Deref will be used to store object data. Must not be NULL.
3332  *  @param vertex_spacing_mode Vertex spacing mode to use for the TE stage.
3333  *
3334  **/
initTestDescriptor(_tessellation_test_type test_type,_test_descriptor * out_test_ptr,_tessellation_shader_vertex_spacing vertex_spacing_mode)3335 void TessellationShaderTCTEgl_TessLevel::initTestDescriptor(_tessellation_test_type test_type,
3336                                                             _test_descriptor *out_test_ptr,
3337                                                             _tessellation_shader_vertex_spacing vertex_spacing_mode)
3338 {
3339     out_test_ptr->type           = test_type;
3340     out_test_ptr->vertex_spacing = vertex_spacing_mode;
3341 
3342     /* Generate a program object we will later configure */
3343     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3344 
3345     out_test_ptr->po_id = gl.createProgram();
3346 
3347     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
3348 
3349     /* Generate shader objects the test will use */
3350     out_test_ptr->fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3351     out_test_ptr->vs_id = gl.createShader(GL_VERTEX_SHADER);
3352 
3353     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES || test_type == TESSELLATION_TEST_TYPE_TES)
3354     {
3355         out_test_ptr->tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
3356     }
3357 
3358     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3359     {
3360         out_test_ptr->tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
3361     }
3362 
3363     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
3364 
3365     /* Configure fragment shader */
3366     const char *fs_body = "${VERSION}\n"
3367                           "\n"
3368                           "void main()\n"
3369                           "{\n"
3370                           "}\n";
3371 
3372     shaderSourceSpecialized(out_test_ptr->fs_id, 1 /* count */, &fs_body);
3373     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader object");
3374 
3375     /* Configure tessellation control shader */
3376     const char *tc_body = "${VERSION}\n"
3377                           "\n"
3378                           /* Required EXT_tessellation_shader functionality */
3379                           "${TESSELLATION_SHADER_REQUIRE}\n"
3380                           "\n"
3381                           "layout (vertices = 4) out;\n"
3382                           "\n"
3383                           "uniform vec2 inner_tess_levels;\n"
3384                           "uniform vec4 outer_tess_levels;\n"
3385                           "\n"
3386                           "void main()\n"
3387                           "{\n"
3388                           "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
3389                           "    if (gl_InvocationID == 0) {\n"
3390                           "        gl_TessLevelInner[0]                           = inner_tess_levels[0];\n"
3391                           "        gl_TessLevelInner[1]                           = inner_tess_levels[1];\n"
3392                           "        gl_TessLevelOuter[0]                           = outer_tess_levels[0];\n"
3393                           "        gl_TessLevelOuter[1]                           = outer_tess_levels[1];\n"
3394                           "        gl_TessLevelOuter[2]                           = outer_tess_levels[2];\n"
3395                           "        gl_TessLevelOuter[3]                           = outer_tess_levels[3];\n"
3396                           "   }\n"
3397                           "}\n";
3398 
3399     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3400     {
3401         shaderSourceSpecialized(out_test_ptr->tcs_id, 1 /* count */, &tc_body);
3402         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader object");
3403     }
3404 
3405     /* Configure tessellation evaluation shader */
3406     const char *te_body = "${VERSION}\n"
3407                           "\n"
3408                           "${TESSELLATION_SHADER_REQUIRE}\n"
3409                           "\n"
3410                           "layout (quads, point_mode, VERTEX_SPACING_MODE) in;\n"
3411                           "\n"
3412                           "out vec2 result_tess_level_inner;\n"
3413                           "out vec4 result_tess_level_outer;\n"
3414                           "\n"
3415                           "void main()\n"
3416                           "{\n"
3417                           "    vec4 p1 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
3418                           "    vec4 p2 = mix(gl_in[2].gl_Position,gl_in[3].gl_Position,gl_TessCoord.x);\n"
3419                           "    gl_Position = mix(p1, p2, gl_TessCoord.y);\n"
3420                           "\n"
3421                           "    result_tess_level_inner = vec2(gl_TessLevelInner[0],\n"
3422                           "                                   gl_TessLevelInner[1]);\n"
3423                           "    result_tess_level_outer = vec4(gl_TessLevelOuter[0],\n"
3424                           "                                   gl_TessLevelOuter[1],\n"
3425                           "                                   gl_TessLevelOuter[2],\n"
3426                           "                                   gl_TessLevelOuter[3]);\n"
3427                           "}\n";
3428 
3429     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES || test_type == TESSELLATION_TEST_TYPE_TES)
3430     {
3431         /* Replace VERTEX_SPACING_MODE with the mode provided by the caller */
3432         std::stringstream te_body_stringstream;
3433         std::string te_body_string;
3434         const std::string token = "VERTEX_SPACING_MODE";
3435         std::size_t token_index;
3436         std::string vertex_spacing_string =
3437             TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing_mode);
3438 
3439         te_body_stringstream << te_body;
3440         te_body_string = te_body_stringstream.str();
3441 
3442         token_index = te_body_string.find(token);
3443 
3444         while (token_index != std::string::npos)
3445         {
3446             te_body_string = te_body_string.replace(token_index, token.length(), vertex_spacing_string.c_str());
3447 
3448             token_index = te_body_string.find(token);
3449         }
3450 
3451         /* Set the shader source */
3452         const char *te_body_string_raw = te_body_string.c_str();
3453 
3454         shaderSourceSpecialized(out_test_ptr->tes_id, 1 /* count */, &te_body_string_raw);
3455         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader object");
3456     }
3457 
3458     /* Configure vertex shader */
3459     const char *vs_body = "${VERSION}\n"
3460                           "\n"
3461                           "void main()\n"
3462                           "{\n"
3463                           "    gl_Position = vec4(1.0, 2.0, 3.0, 4.0);\n"
3464                           "}\n";
3465 
3466     shaderSourceSpecialized(out_test_ptr->vs_id, 1 /* count */, &vs_body);
3467     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader object");
3468 
3469     /* Compile all shaders of our interest */
3470     const glw::GLuint shaders[]  = {out_test_ptr->fs_id, out_test_ptr->tcs_id, out_test_ptr->tes_id,
3471                                     out_test_ptr->vs_id};
3472     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
3473 
3474     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
3475     {
3476         glw::GLint compile_status = GL_FALSE;
3477         glw::GLuint shader        = shaders[n_shader];
3478 
3479         if (shader != 0)
3480         {
3481             gl.compileShader(shader);
3482             GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
3483 
3484             gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
3485             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
3486 
3487             if (compile_status != GL_TRUE)
3488             {
3489                 m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
3490                                    << " failed." << tcu::TestLog::EndMessage;
3491 
3492                 TCU_FAIL("Shader compilation failed");
3493             }
3494         } /* if (shader != 0) */
3495     }     /* for (all shaders) */
3496 
3497     /* Attach the shaders to the test program object, set up XFB and then link the program */
3498     glw::GLint link_status        = GL_FALSE;
3499     const char *varyings[]        = {"result_tess_level_inner", "result_tess_level_outer"};
3500     const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
3501 
3502     gl.transformFeedbackVaryings(out_test_ptr->po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
3503     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
3504 
3505     gl.attachShader(out_test_ptr->po_id, out_test_ptr->fs_id);
3506     gl.attachShader(out_test_ptr->po_id, out_test_ptr->vs_id);
3507 
3508     if (out_test_ptr->tcs_id != 0)
3509     {
3510         gl.attachShader(out_test_ptr->po_id, out_test_ptr->tcs_id);
3511     }
3512 
3513     if (out_test_ptr->tes_id != 0)
3514     {
3515         gl.attachShader(out_test_ptr->po_id, out_test_ptr->tes_id);
3516     }
3517 
3518     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
3519 
3520     gl.linkProgram(out_test_ptr->po_id);
3521     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
3522 
3523     gl.getProgramiv(out_test_ptr->po_id, GL_LINK_STATUS, &link_status);
3524     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
3525 
3526     if (link_status != GL_TRUE)
3527     {
3528         TCU_FAIL("Program linking failed");
3529     }
3530 
3531     /* Retrieve uniform locations */
3532     out_test_ptr->inner_tess_levels_uniform_location = gl.getUniformLocation(out_test_ptr->po_id, "inner_tess_levels");
3533     out_test_ptr->outer_tess_levels_uniform_location = gl.getUniformLocation(out_test_ptr->po_id, "outer_tess_levels");
3534 
3535     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed");
3536 
3537     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3538     {
3539         DE_ASSERT(out_test_ptr->inner_tess_levels_uniform_location != -1);
3540         DE_ASSERT(out_test_ptr->outer_tess_levels_uniform_location != -1);
3541     }
3542 }
3543 
3544 /** Executes the test.
3545  *
3546  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
3547  *
3548  *  Note the function throws exception should an error occur!
3549  *
3550  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
3551  **/
iterate(void)3552 tcu::TestNode::IterateResult TessellationShaderTCTEgl_TessLevel::iterate(void)
3553 {
3554     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3555 
3556     /* Initialize ES test objects */
3557     initTest();
3558 
3559     /* Our program object takes a single quad per patch */
3560     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 4);
3561     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed");
3562 
3563     /* Prepare for rendering */
3564     gl.enable(GL_RASTERIZER_DISCARD);
3565     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed.");
3566 
3567     /* We will iterate through all added tests. */
3568     for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); ++test_iterator)
3569     {
3570         /* Iterate through a few different inner/outer tessellation level combinations */
3571         glw::GLfloat tessellation_level_combinations[] = {
3572             /* inner[0] */ /* inner[1] */ /* outer[0] */ /* outer[1] */ /* outer[2] */ /* outer[3] */
3573             1.1f,
3574             1.4f,
3575             2.7f,
3576             3.1f,
3577             4.4f,
3578             5.7f,
3579             64.2f,
3580             32.5f,
3581             16.8f,
3582             8.2f,
3583             4.5f,
3584             2.8f,
3585             3.3f,
3586             6.6f,
3587             9.9f,
3588             12.3f,
3589             15.6f,
3590             18.9f};
3591         const unsigned int n_tessellation_level_combinations = sizeof(tessellation_level_combinations) /
3592                                                                sizeof(tessellation_level_combinations[0]) /
3593                                                                6; /* 2 inner + 4 outer levels */
3594 
3595         for (unsigned int n_combination = 0; n_combination < n_tessellation_level_combinations; ++n_combination)
3596         {
3597             glw::GLfloat inner_tess_level[] = {tessellation_level_combinations[n_combination * 6 + 0],
3598                                                tessellation_level_combinations[n_combination * 6 + 1]};
3599 
3600             glw::GLfloat outer_tess_level[] = {tessellation_level_combinations[n_combination * 6 + 2],
3601                                                tessellation_level_combinations[n_combination * 6 + 3],
3602                                                tessellation_level_combinations[n_combination * 6 + 4],
3603                                                tessellation_level_combinations[n_combination * 6 + 5]};
3604 
3605             TessellationShaderUtils tessUtils(gl, this);
3606             const unsigned int n_rendered_vertices = tessUtils.getAmountOfVerticesGeneratedByTessellator(
3607                 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, inner_tess_level, outer_tess_level,
3608                 test_iterator->vertex_spacing, true); /* is_point_mode_enabled */
3609 
3610             /* Test type determines how the tessellation levels should be set. */
3611             gl.useProgram(test_iterator->po_id);
3612             GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
3613 
3614             switch (test_iterator->type)
3615             {
3616             case TESSELLATION_TEST_TYPE_TCS_TES:
3617             {
3618                 gl.uniform2fv(test_iterator->inner_tess_levels_uniform_location, 1, /* count */
3619                               inner_tess_level);
3620                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
3621 
3622                 gl.uniform4fv(test_iterator->outer_tess_levels_uniform_location, 1, /* count */
3623                               outer_tess_level);
3624                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
3625 
3626                 break;
3627             }
3628 
3629             case TESSELLATION_TEST_TYPE_TES:
3630             {
3631                 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3632                 {
3633                     gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, inner_tess_level);
3634 
3635                     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameterfv() call failed for"
3636                                                        " GL_PATCH_DEFAULT_INNER_LEVEL pname");
3637 
3638                     gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, outer_tess_level);
3639 
3640                     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameterfv() call failed for"
3641                                                        " GL_PATCH_DEFAULT_OUTER_LEVEL pname");
3642                 }
3643                 break;
3644             }
3645 
3646             default:
3647             {
3648                 TCU_FAIL("Unrecognized test type");
3649             }
3650             } /* switch (test_iterator->type) */
3651 
3652             /* Set up storage properties for the buffer object, to which XFBed data will be
3653              * written.
3654              */
3655             const unsigned int n_bytes_needed =
3656                 static_cast<unsigned int>(n_rendered_vertices * (2 /* vec2 */ + 4 /* vec4 */) * sizeof(float));
3657 
3658             gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, n_bytes_needed, NULL /* data */, GL_STATIC_DRAW);
3659             GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
3660 
3661             /* Render the test geometry */
3662             gl.beginTransformFeedback(GL_POINTS);
3663             GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
3664             {
3665                 /* A single vertex will do, since we configured GL_PATCH_VERTICES_EXT to be 1 */
3666                 gl.drawArrays(GL_PATCHES_EXT, 0 /* first */, 4 /* count */);
3667 
3668                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
3669             }
3670             gl.endTransformFeedback();
3671             GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
3672 
3673             /* Now that the BO is filled with data, map it so we can check the storage's contents */
3674             const float *mapped_data_ptr =
3675                 (const float *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
3676                                                  n_bytes_needed, GL_MAP_READ_BIT);
3677 
3678             GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
3679 
3680             /* Verify the contents. For each result vertex, inner/outer tessellation levels should
3681              * be unchanged. */
3682             const float epsilon = (float)1e-5;
3683             const unsigned int n_result_points =
3684                 static_cast<unsigned int>(n_bytes_needed / sizeof(float) / (2 /* vec2 */ + 4 /* vec4 */));
3685 
3686             for (unsigned int n_point = 0; n_point < n_result_points; ++n_point)
3687             {
3688                 const float *point_data_ptr = mapped_data_ptr + (2 /* vec2 */ + 4 /* vec4 */) * n_point;
3689 
3690                 if (de::abs(point_data_ptr[2] - outer_tess_level[0]) > epsilon ||
3691                     de::abs(point_data_ptr[3] - outer_tess_level[1]) > epsilon)
3692                 {
3693                     std::string vertex_spacing_mode_string =
3694                         TessellationShaderUtils::getESTokenForVertexSpacingMode(test_iterator->vertex_spacing);
3695 
3696                     m_testCtx.getLog() << tcu::TestLog::Message
3697                                        << "Invalid inner/outer tessellation level used in TE stage;"
3698                                        << " expected outer:(" << outer_tess_level[0] << ", " << outer_tess_level[1]
3699                                        << ") "
3700                                        << " rendered outer:(" << point_data_ptr[2] << ", " << point_data_ptr[3] << ")"
3701                                        << " vertex spacing mode: " << vertex_spacing_mode_string.c_str()
3702                                        << tcu::TestLog::EndMessage;
3703 
3704                     TCU_FAIL("Invalid inner/outer tessellation level used in TE stage");
3705                 }
3706             } /* for (all points) */
3707 
3708             /* All done - unmap the storage */
3709             gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3710             GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
3711         } /* for (all tess level combinations) */
3712     }     /* for (all tests) */
3713 
3714     /* All done */
3715     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3716     return STOP;
3717 }
3718 
3719 /** Constructor
3720  *
3721  * @param context Test context
3722  **/
TessellationShaderTCTEgl_PatchVerticesIn(Context & context,const ExtParameters & extParams)3723 TessellationShaderTCTEgl_PatchVerticesIn::TessellationShaderTCTEgl_PatchVerticesIn(Context &context,
3724                                                                                    const ExtParameters &extParams)
3725     : TestCaseBase(context, extParams, "gl_PatchVerticesIn",
3726                    "Verifies gl_PatchVerticesIn size is valid in a tessellation"
3727                    " evaluation shader and corresponds to the value configured in"
3728                    " a tessellation control shader (should one be present) or to"
3729                    " the default value, as set with glPatchParameteriEXT() call")
3730     , m_gl_max_patch_vertices_value(0)
3731     , m_bo_id(0)
3732     , m_vao_id(0)
3733 {
3734     /* Left blank on purpose */
3735 }
3736 
3737 /** Deinitializes all ES objects created for the test. */
deinit()3738 void TessellationShaderTCTEgl_PatchVerticesIn::deinit()
3739 {
3740     /** Call base class' deinit() function */
3741     TestCaseBase::deinit();
3742 
3743     if (!m_is_tessellation_shader_supported)
3744     {
3745         return;
3746     }
3747 
3748     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3749 
3750     /* Reset TF buffer object bindings */
3751     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
3752     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
3753 
3754     /* Disable GL_RASTERIZER_DISCARD mode */
3755     gl.disable(GL_RASTERIZER_DISCARD);
3756 
3757     /* Reset GL_PATCH_VERTICES_EXT to the default setting */
3758     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
3759 
3760     /* Unbind vertex array object */
3761     gl.bindVertexArray(0);
3762 
3763     /* Release all objects we might've created */
3764     if (m_bo_id != 0)
3765     {
3766         gl.deleteBuffers(1, &m_bo_id);
3767 
3768         m_bo_id = 0;
3769     }
3770 
3771     if (m_vao_id != 0)
3772     {
3773         gl.deleteVertexArrays(1, &m_vao_id);
3774 
3775         m_vao_id = 0;
3776     }
3777 
3778     for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
3779     {
3780         deinitTestDescriptor(&*it);
3781     }
3782     m_tests.clear();
3783 }
3784 
3785 /** Deinitializes ES objects created for particular test pass.
3786  *
3787  *  @param test_ptr Test run descriptor. Must not be NULL.
3788  *
3789  **/
deinitTestDescriptor(_test_descriptor * test_ptr)3790 void TessellationShaderTCTEgl_PatchVerticesIn::deinitTestDescriptor(_test_descriptor *test_ptr)
3791 {
3792     /* Call base class' deinit() */
3793     TestCaseBase::deinit();
3794 
3795     /* Release all objects */
3796     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3797 
3798     if (test_ptr->fs_id != 0)
3799     {
3800         gl.deleteShader(test_ptr->fs_id);
3801 
3802         test_ptr->fs_id = 0;
3803     }
3804 
3805     if (test_ptr->po_id != 0)
3806     {
3807         gl.deleteProgram(test_ptr->po_id);
3808 
3809         test_ptr->po_id = 0;
3810     }
3811 
3812     if (test_ptr->tcs_id != 0)
3813     {
3814         gl.deleteShader(test_ptr->tcs_id);
3815 
3816         test_ptr->tcs_id = 0;
3817     }
3818 
3819     if (test_ptr->tes_id != 0)
3820     {
3821         gl.deleteShader(test_ptr->tes_id);
3822 
3823         test_ptr->tes_id = 0;
3824     }
3825 
3826     if (test_ptr->vs_id != 0)
3827     {
3828         gl.deleteShader(test_ptr->vs_id);
3829 
3830         test_ptr->vs_id = 0;
3831     }
3832 }
3833 
3834 /** Initializes all ES objects that will be used for the test. */
initTest()3835 void TessellationShaderTCTEgl_PatchVerticesIn::initTest()
3836 {
3837     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3838 
3839     /* The test requires EXT_tessellation_shader */
3840     if (!m_is_tessellation_shader_supported)
3841     {
3842         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
3843     }
3844 
3845     /* Initialize vertex array object */
3846     gl.genVertexArrays(1, &m_vao_id);
3847     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
3848 
3849     gl.bindVertexArray(m_vao_id);
3850     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
3851 
3852     /* Retrieve GL_MAX_PATCH_VERTICES_EXT value before we carry on */
3853     gl.getIntegerv(m_glExtTokens.MAX_PATCH_VERTICES, &m_gl_max_patch_vertices_value);
3854 
3855     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_MAX_PATCH_VERTICES_EXT pname failed");
3856 
3857     /* Initialize test descriptors.
3858      *
3859      * Make sure the values we use are multiples of 4 - this is because we're using isolines in the
3860      * tessellation stage, and in order to have the requested amount of line segments generated, we need
3861      * to use a multiply of 4 vertices per patch */
3862     glw::GLint n_half_max_patch_vertices_mul_4 = m_gl_max_patch_vertices_value / 2;
3863     glw::GLint n_max_patch_vertices_mul_4      = m_gl_max_patch_vertices_value;
3864 
3865     if ((n_half_max_patch_vertices_mul_4 % 4) != 0)
3866     {
3867         /* Round to nearest mul-of-4 integer */
3868         n_half_max_patch_vertices_mul_4 += (4 - (m_gl_max_patch_vertices_value / 2) % 4);
3869     }
3870 
3871     if ((n_max_patch_vertices_mul_4 % 4) != 0)
3872     {
3873         /* Round to previous nearest mul-of-4 integer */
3874         n_max_patch_vertices_mul_4 -= (m_gl_max_patch_vertices_value % 4);
3875     }
3876 
3877     _test_descriptor test_tcs_tes_4;
3878     _test_descriptor test_tcs_tes_half_max_patch_vertices_mul_4;
3879     _test_descriptor test_tcs_tes_max_patch_vertices_mul_4;
3880     _test_descriptor test_tes_4;
3881     _test_descriptor test_tes_half_max_patch_vertices_mul_4;
3882     _test_descriptor test_tes_max_patch_vertices_mul_4;
3883 
3884     initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_4, 4);
3885     initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_half_max_patch_vertices_mul_4,
3886                        n_half_max_patch_vertices_mul_4);
3887     initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_max_patch_vertices_mul_4,
3888                        n_max_patch_vertices_mul_4);
3889     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3890     {
3891         initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_4, 4);
3892         initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_half_max_patch_vertices_mul_4,
3893                            n_half_max_patch_vertices_mul_4);
3894         initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_max_patch_vertices_mul_4, n_max_patch_vertices_mul_4);
3895     }
3896 
3897     m_tests.push_back(test_tcs_tes_4);
3898     m_tests.push_back(test_tcs_tes_half_max_patch_vertices_mul_4);
3899     m_tests.push_back(test_tcs_tes_max_patch_vertices_mul_4);
3900     if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3901     {
3902         m_tests.push_back(test_tes_4);
3903         m_tests.push_back(test_tes_half_max_patch_vertices_mul_4);
3904         m_tests.push_back(test_tes_max_patch_vertices_mul_4);
3905     }
3906 
3907     /* Generate and set up a buffer object we will use to hold XFBed data.
3908      *
3909      * NOTE: We do not set the buffer object's storage here because its size
3910      *       is iteration-specific.
3911      **/
3912     gl.genBuffers(1, &m_bo_id);
3913     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
3914 
3915     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
3916     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
3917     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
3918     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
3919 
3920     /* We're good to execute the test! */
3921 }
3922 
3923 /** Initializes ES objects for a particular tess pass.
3924  *
3925  *  @param test_type        Determines test type to be used for initialization.
3926  *                          TEST_TYPE_TCS_TES will use both TC and TE stages,
3927  *                          TEST_TYPE_TES will assume only TE stage should be used.
3928  *  @param out_test_ptr     Deref will be used to store object data. Must not be NULL.
3929  *  @param input_patch_size Tells how many vertices should be used per patch for hte
3930  *                          result program object.
3931  **/
initTestDescriptor(_tessellation_test_type test_type,_test_descriptor * out_test_ptr,unsigned int input_patch_size)3932 void TessellationShaderTCTEgl_PatchVerticesIn::initTestDescriptor(_tessellation_test_type test_type,
3933                                                                   _test_descriptor *out_test_ptr,
3934                                                                   unsigned int input_patch_size)
3935 {
3936     out_test_ptr->input_patch_size = input_patch_size;
3937     out_test_ptr->type             = test_type;
3938 
3939     /* Generate a program object we will later configure */
3940     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3941 
3942     out_test_ptr->po_id = gl.createProgram();
3943 
3944     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
3945 
3946     /* Generate shader objects the test will use */
3947     out_test_ptr->fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3948     out_test_ptr->vs_id = gl.createShader(GL_VERTEX_SHADER);
3949 
3950     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES || test_type == TESSELLATION_TEST_TYPE_TES)
3951     {
3952         out_test_ptr->tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
3953     }
3954 
3955     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3956     {
3957         out_test_ptr->tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
3958     }
3959 
3960     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
3961 
3962     /* Configure fragment shader */
3963     const char *fs_body = "${VERSION}\n"
3964                           "\n"
3965                           "void main()\n"
3966                           "{\n"
3967                           "}\n";
3968 
3969     shaderSourceSpecialized(out_test_ptr->fs_id, 1 /* count */, &fs_body);
3970     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader object");
3971 
3972     /* Configure tessellation control shader */
3973     const char *tc_body = "${VERSION}\n"
3974                           "\n"
3975                           /* Required EXT_tessellation_shader functionality */
3976                           "${TESSELLATION_SHADER_REQUIRE}\n"
3977                           "\n"
3978                           "layout (vertices = VERTICES_TOKEN) out;\n"
3979                           "\n"
3980                           "void main()\n"
3981                           "{\n"
3982                           "    gl_out           [gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
3983                           "    gl_TessLevelOuter[0]                           = 1.0;\n"
3984                           "    gl_TessLevelOuter[1]                           = 1.0;\n"
3985                           "}\n";
3986 
3987     if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3988     {
3989         const char *result_body    = NULL;
3990         std::string tc_body_string = tc_body;
3991         std::size_t token_index    = -1;
3992         const char *token_string   = "VERTICES_TOKEN";
3993         std::stringstream vertices_stringstream;
3994         std::string vertices_string;
3995 
3996         vertices_stringstream << input_patch_size;
3997         vertices_string = vertices_stringstream.str();
3998 
3999         while ((token_index = tc_body_string.find(token_string)) != std::string::npos)
4000         {
4001             tc_body_string = tc_body_string.replace(token_index, strlen(token_string), vertices_string);
4002         }
4003 
4004         result_body = tc_body_string.c_str();
4005 
4006         shaderSourceSpecialized(out_test_ptr->tcs_id, 1 /* count */, &result_body);
4007         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader object");
4008     }
4009 
4010     /* Configure tessellation evaluation shader */
4011     const char *te_body = "${VERSION}\n"
4012                           "\n"
4013                           "${TESSELLATION_SHADER_REQUIRE}\n"
4014                           "\n"
4015                           "layout (isolines, point_mode) in;\n"
4016                           "\n"
4017                           "flat out int result_PatchVerticesIn;\n"
4018                           "\n"
4019                           "void main()\n"
4020                           "{\n"
4021                           "    gl_Position = gl_in[0].gl_Position;\n"
4022                           "\n"
4023                           "    result_PatchVerticesIn = gl_PatchVerticesIn;\n"
4024                           "}\n";
4025 
4026     shaderSourceSpecialized(out_test_ptr->tes_id, 1 /* count */, &te_body);
4027     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader object");
4028 
4029     /* Configure vertex shader */
4030     const char *vs_body = "${VERSION}\n"
4031                           "\n"
4032                           "void main()\n"
4033                           "{\n"
4034                           "    gl_Position = vec4(float(gl_VertexID), 2.0, 3.0, 4.0);\n"
4035                           "}\n";
4036 
4037     shaderSourceSpecialized(out_test_ptr->vs_id, 1 /* count */, &vs_body);
4038     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader object");
4039 
4040     /* Compile all shaders of our interest */
4041     const glw::GLuint shaders[]  = {out_test_ptr->fs_id, out_test_ptr->tcs_id, out_test_ptr->tes_id,
4042                                     out_test_ptr->vs_id};
4043     const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
4044 
4045     for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
4046     {
4047         glw::GLint compile_status = GL_FALSE;
4048         glw::GLuint shader        = shaders[n_shader];
4049 
4050         if (shader != 0)
4051         {
4052             gl.compileShader(shader);
4053             GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
4054 
4055             gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
4056             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
4057 
4058             if (compile_status != GL_TRUE)
4059             {
4060                 m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
4061                                    << " failed." << tcu::TestLog::EndMessage;
4062 
4063                 TCU_FAIL("Shader compilation failed");
4064             }
4065         } /* if (shader != 0) */
4066     }     /* for (all shaders) */
4067 
4068     /* Attach the shaders to the test program object, set up XFB and then link the program */
4069     glw::GLint link_status = GL_FALSE;
4070     const char *varyings[] = {
4071         "result_PatchVerticesIn",
4072     };
4073     const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
4074 
4075     gl.transformFeedbackVaryings(out_test_ptr->po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
4076     GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
4077 
4078     gl.attachShader(out_test_ptr->po_id, out_test_ptr->fs_id);
4079     gl.attachShader(out_test_ptr->po_id, out_test_ptr->vs_id);
4080 
4081     if (out_test_ptr->tcs_id != 0)
4082     {
4083         gl.attachShader(out_test_ptr->po_id, out_test_ptr->tcs_id);
4084     }
4085 
4086     if (out_test_ptr->tes_id != 0)
4087     {
4088         gl.attachShader(out_test_ptr->po_id, out_test_ptr->tes_id);
4089     }
4090 
4091     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
4092 
4093     gl.linkProgram(out_test_ptr->po_id);
4094     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
4095 
4096     gl.getProgramiv(out_test_ptr->po_id, GL_LINK_STATUS, &link_status);
4097     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
4098 
4099     if (link_status != GL_TRUE)
4100     {
4101         TCU_FAIL("Program linking failed");
4102     }
4103 }
4104 
4105 /** Executes the test.
4106  *
4107  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
4108  *
4109  *  Note the function throws exception should an error occur!
4110  *
4111  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
4112  **/
iterate(void)4113 tcu::TestNode::IterateResult TessellationShaderTCTEgl_PatchVerticesIn::iterate(void)
4114 {
4115     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
4116 
4117     /* Initialize ES test objects */
4118     initTest();
4119 
4120     /* Prepare for rendering */
4121     gl.enable(GL_RASTERIZER_DISCARD);
4122     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed.");
4123 
4124     /* We will iterate through all added tests. */
4125     for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); ++test_iterator)
4126     {
4127         /* Activate test-specific program object first. */
4128         gl.useProgram(test_iterator->po_id);
4129         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
4130 
4131         /* Test type tells determines how the tessellation levels should be set.
4132          * We don't need to do anything specific if TCS+TES are in, but if no
4133          * TCS is present, we need to configure default amount of input patch-vertices
4134          * to the test-specific value.
4135          */
4136         glw::GLint n_patch_vertices = 0;
4137 
4138         switch (test_iterator->type)
4139         {
4140         case TESSELLATION_TEST_TYPE_TCS_TES:
4141         {
4142             /* We're using isolines mode which requires at least 4 input vertices per patch */
4143             gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 4);
4144             GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() for GL_PATCH_VERTICES_EXT failed.");
4145 
4146             n_patch_vertices = 4;
4147 
4148             break;
4149         }
4150 
4151         case TESSELLATION_TEST_TYPE_TES:
4152         {
4153             gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, test_iterator->input_patch_size);
4154             GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed");
4155 
4156             n_patch_vertices = test_iterator->input_patch_size;
4157 
4158             break;
4159         }
4160 
4161         default:
4162         {
4163             TCU_FAIL("Unrecognized test type");
4164         }
4165         } /* switch (test_iterator->type) */
4166 
4167         /* Set up storage properties for the buffer object, to which XFBed data will be
4168          * written.
4169          **/
4170         const unsigned int n_bytes_needed = sizeof(int) * 2; /* the tessellator will output two vertices */
4171 
4172         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, n_bytes_needed, NULL /* data */, GL_STATIC_DRAW);
4173         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
4174 
4175         /* Render the test geometry */
4176         gl.beginTransformFeedback(GL_POINTS);
4177         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
4178         {
4179             /* Pass a single patch only */
4180             gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, n_patch_vertices);
4181 
4182             GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
4183         }
4184         gl.endTransformFeedback();
4185         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
4186 
4187         /* Now that the BO is filled with data, map it so we can check the storage's contents */
4188         const int *mapped_data_ptr = (const int *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
4189                                                                     n_bytes_needed, GL_MAP_READ_BIT);
4190 
4191         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
4192 
4193         /* Verify the contents. Make sure the value we retrieved is equal to the test-specific
4194          * amount of vertices per patch.
4195          */
4196         for (unsigned int n_vertex = 0; n_vertex < 2 /* output vertices */; ++n_vertex)
4197         {
4198             unsigned int te_PatchVerticesInSize = mapped_data_ptr[n_vertex];
4199 
4200             if (te_PatchVerticesInSize != test_iterator->input_patch_size)
4201             {
4202                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PatchVerticesIn defined for TE stage "
4203                                    << " and result vertex index:" << n_vertex
4204                                    << " expected:" << test_iterator->input_patch_size
4205                                    << " rendered:" << te_PatchVerticesInSize << tcu::TestLog::EndMessage;
4206 
4207                 TCU_FAIL("Invalid gl_PatchVerticesIn size used in TE stage");
4208             } /* if (comparison failed)  */
4209         }
4210 
4211         /* All done - unmap the storage */
4212         gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4213         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
4214     } /* for (all tests) */
4215 
4216     /* All done */
4217     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4218     return STOP;
4219 }
4220 
4221 } /* namespace glcts */
4222