Fix GL45-CTS.cull_distance.functional test
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / gl / gl3cCullDistanceTests.cpp
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2015-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 /**
25  */ /*!
26  * \file  gl3cCullDistanceTests.cpp
27  * \brief Cull Distance Test Suite Implementation
28  */ /*-------------------------------------------------------------------*/
29
30 #include "gl3cCullDistanceTests.hpp"
31 #include "gluContextInfo.hpp"
32 #include "gluDefs.hpp"
33 #include "gluStrUtil.hpp"
34 #include "glwEnums.hpp"
35 #include "glwFunctions.hpp"
36 #include "tcuRenderTarget.hpp"
37 #include "tcuTestLog.hpp"
38
39 #include <cmath>
40 #include <sstream>
41 #include <string>
42 #include <vector>
43
44 #ifndef GL_MAX_CULL_DISTANCES
45 #define GL_MAX_CULL_DISTANCES (0x82F9)
46 #endif
47 #ifndef GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES
48 #define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES (0x82FA)
49 #endif
50
51 namespace glcts
52 {
53 /** @brief Build OpenGL program
54  *
55  *  @param [in]  gl             OpenGL function bindings
56  *  @param [in]  testCtx        Context
57  *  @param [in]  cs_body        Compute shader source code
58  *  @param [in]  fs_body        Fragment shader source code
59  *  @param [in]  gs_body        Geometric shader source code
60  *  @param [in]  tc_body        Tessellation control shader source code
61  *  @param [in]  te_body        Tessellation evaluation shader source code
62  *  @param [in]  vs_body        Vertex shader source code
63  *  @param [in]  n_tf_varyings  Number of transform feedback varyings
64  *  @param [in]  tf_varyings    Transform feedback varyings names
65  *
66  *  @param [out] out_program    If succeeded output program GL handle, 0 otherwise.
67  */
68 void CullDistance::Utilities::buildProgram(const glw::Functions& gl, tcu::TestContext& testCtx,
69                                                                                    const glw::GLchar* cs_body, const glw::GLchar* fs_body,
70                                                                                    const glw::GLchar* gs_body, const glw::GLchar* tc_body,
71                                                                                    const glw::GLchar* te_body, const glw::GLchar* vs_body,
72                                                                                    const glw::GLuint& n_tf_varyings, const glw::GLchar** tf_varyings,
73                                                                                    glw::GLuint* out_program)
74 {
75         glw::GLuint po_id = 0;
76
77         struct _shaders_configuration
78         {
79                 glw::GLenum                type;
80                 const glw::GLchar* body;
81                 glw::GLuint                id;
82         } shaders_configuration[] = { { GL_COMPUTE_SHADER, cs_body, 0 },                 { GL_FRAGMENT_SHADER, fs_body, 0 },
83                                                                   { GL_GEOMETRY_SHADER, gs_body, 0 },            { GL_TESS_CONTROL_SHADER, tc_body, 0 },
84                                                                   { GL_TESS_EVALUATION_SHADER, te_body, 0 }, { GL_VERTEX_SHADER, vs_body, 0 } };
85
86         const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]);
87
88         /* Guard allocated OpenGL resources */
89         try
90         {
91                 /* Create needed programs */
92                 po_id = gl.createProgram();
93                 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
94
95                 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
96                 {
97                         if (shaders_configuration[n_shader_index].body != DE_NULL)
98                         {
99                                 /* Generate shader object */
100                                 shaders_configuration[n_shader_index].id = gl.createShader(shaders_configuration[n_shader_index].type);
101                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
102
103                                 glw::GLint                compile_status = GL_FALSE;
104                                 const glw::GLuint so_id                  = shaders_configuration[n_shader_index].id;
105
106                                 /* Assign shader source code */
107                                 gl.shaderSource(shaders_configuration[n_shader_index].id, 1,               /* count */
108                                                                 &shaders_configuration[n_shader_index].body, DE_NULL); /* length */
109                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
110
111                                 gl.compileShader(so_id);
112                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
113
114                                 gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
115                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
116
117                                 if (compile_status == GL_FALSE)
118                                 {
119                                         std::vector<glw::GLchar> log_array(1);
120                                         glw::GLint                               log_length = 0;
121                                         std::string                              log_string("Failed to retrieve log");
122
123                                         /* Retrive compilation log length */
124                                         gl.getShaderiv(so_id, GL_INFO_LOG_LENGTH, &log_length);
125                                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
126
127                                         log_array.resize(log_length + 1, 0);
128
129                                         gl.getShaderInfoLog(so_id, log_length, DE_NULL, &log_array[0]);
130                                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed.");
131
132                                         log_string = std::string(&log_array[0]);
133
134                                         testCtx.getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
135                                                                          << "Shader type: " << shaders_configuration[n_shader_index].type << "\n"
136                                                                          << "Shader compilation error log:\n"
137                                                                          << log_string << "\n"
138                                                                          << "Shader source code:\n"
139                                                                          << shaders_configuration[n_shader_index].body << "\n"
140                                                                          << tcu::TestLog::EndMessage;
141
142                                         TCU_FAIL("Shader compilation has failed.");
143                                 }
144
145                                 /* Also attach the shader to the corresponding program object */
146                                 gl.attachShader(po_id, so_id);
147
148                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed");
149                         } /* if (shaders_configuration[n_shader_index].body != DE_NULL) */
150                 }        /* for (all shader object IDs) */
151
152                 /* Set transform feedback if requested */
153                 if (n_tf_varyings > 0)
154                 {
155                         gl.transformFeedbackVaryings(po_id, n_tf_varyings, tf_varyings, GL_INTERLEAVED_ATTRIBS);
156                         GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
157                 }
158
159                 /* Try to link the program objects */
160                 if (po_id != 0)
161                 {
162                         glw::GLint link_status = GL_FALSE;
163
164                         gl.linkProgram(po_id);
165                         GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
166
167                         gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
168                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
169
170                         if (link_status == GL_FALSE)
171                         {
172                                 std::vector<glw::GLchar> log_array(1);
173                                 glw::GLsizei                     log_length = 0;
174                                 std::string                              log_string;
175
176                                 /* Retreive compilation log length */
177                                 gl.getProgramiv(po_id, GL_INFO_LOG_LENGTH, &log_length);
178                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
179
180                                 log_array.resize(log_length + 1, 0);
181
182                                 /* Retreive compilation log */
183                                 gl.getProgramInfoLog(po_id, log_length, DE_NULL, &log_array[0]);
184                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed.");
185
186                                 log_string = std::string(&log_array[0]);
187
188                                 /* Log linking error message */
189                                 testCtx.getLog() << tcu::TestLog::Message << "Program linking has failed.\n"
190                                                                  << "Linking error log:\n"
191                                                                  << log_string << "\n"
192                                                                  << tcu::TestLog::EndMessage;
193
194                                 /* Log shader source code of shaders involved */
195                                 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
196                                 {
197                                         if (shaders_configuration[n_shader_index].body != DE_NULL)
198                                         {
199                                                 testCtx.getLog() << tcu::TestLog::Message << "Shader source code of type "
200                                                                                  << shaders_configuration[n_shader_index].type << " follows:\n"
201                                                                                  << shaders_configuration[n_shader_index].body << "\n"
202                                                                                  << tcu::TestLog::EndMessage;
203                                         }
204                                 }
205
206                                 TCU_FAIL("Program linking failed");
207                         }
208                 } /* if (po_id != 0) */
209
210                 /* Delete all shaders we've created */
211                 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
212                 {
213                         const glw::GLuint so_id = shaders_configuration[n_shader_index].id;
214
215                         if (so_id != 0)
216                         {
217                                 gl.deleteShader(so_id);
218
219                                 shaders_configuration[n_shader_index].id = 0;
220
221                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
222                         }
223                 }
224
225                 /* Store the result progrtam IDs */
226                 *out_program = po_id;
227         }
228         catch (...)
229         {
230                 /* Delete all shaders we've created */
231                 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
232                 {
233                         const glw::GLuint so_id = shaders_configuration[n_shader_index].id;
234
235                         if (so_id != 0)
236                         {
237                                 gl.deleteShader(so_id);
238
239                                 shaders_configuration[n_shader_index].id = 0;
240                         }
241                 }
242
243                 /* Delete the program object */
244                 if (po_id != 0)
245                 {
246                         gl.deleteProgram(po_id);
247
248                         po_id = 0;
249                 }
250
251                 /* Rethrow */
252                 throw;
253         }
254 }
255
256 /** @brief Replace all occurences of a substring in a string by a substring
257  *
258  *  @param [in,out] str    string to be edited
259  *  @param [in]     from   substring to be replaced
260  *  @param [out]    to     new substring
261  */
262 void CullDistance::Utilities::replaceAll(std::string& str, const std::string& from, const std::string& to)
263 {
264         for (size_t start_pos = str.find(from, 0); start_pos != std::string::npos; start_pos = str.find(from, start_pos))
265         {
266                 str.replace(start_pos, from.length(), to);
267
268                 start_pos += to.length();
269         }
270
271         return;
272 }
273
274 /** @brief Convert integer to string representation
275  *
276  *  @param [in] integer     input integer to be converted
277  *
278  *  @return String representation of integer
279  */
280 std::string CullDistance::Utilities::intToString(glw::GLint integer)
281 {
282         std::stringstream temp_sstream;
283
284         temp_sstream << integer;
285
286         return temp_sstream.str();
287 }
288
289 /** Constructor.
290  *
291  *  @param context Rendering context handle.
292  **/
293 CullDistance::APICoverageTest::APICoverageTest(deqp::Context& context)
294         : TestCase(context, "coverage", "Cull Distance API Coverage Test")
295         , m_bo_id(0)
296         , m_cs_id(0)
297         , m_cs_to_id(0)
298         , m_fbo_draw_id(0)
299         , m_fbo_draw_to_id(0)
300         , m_fbo_read_id(0)
301         , m_fs_id(0)
302         , m_gs_id(0)
303         , m_po_id(0)
304         , m_tc_id(0)
305         , m_te_id(0)
306         , m_vao_id(0)
307         , m_vs_id(0)
308 {
309         /* Left blank on purpose */
310 }
311
312 /** @brief Cull Distance API Coverage Test deinitialization */
313 void CullDistance::APICoverageTest::deinit()
314 {
315         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
316
317         if (m_bo_id != 0)
318         {
319                 gl.deleteBuffers(1, &m_bo_id);
320
321                 m_bo_id = 0;
322         }
323
324         if (m_cs_id != 0)
325         {
326                 gl.deleteShader(m_cs_id);
327
328                 m_cs_id = 0;
329         }
330
331         if (m_cs_to_id != 0)
332         {
333                 gl.deleteTextures(1, &m_cs_to_id);
334
335                 m_cs_to_id = 0;
336         }
337
338         if (m_fbo_draw_id != 0)
339         {
340                 gl.deleteFramebuffers(1, &m_fbo_draw_id);
341
342                 m_fbo_draw_id = 0;
343         }
344
345         if (m_fbo_draw_to_id != 0)
346         {
347                 gl.deleteTextures(1, &m_fbo_draw_to_id);
348
349                 m_fbo_draw_to_id = 0;
350         }
351
352         if (m_fbo_read_id != 0)
353         {
354                 gl.deleteFramebuffers(1, &m_fbo_read_id);
355
356                 m_fbo_read_id = 0;
357         }
358
359         if (m_fs_id != 0)
360         {
361                 gl.deleteShader(m_fs_id);
362
363                 m_fs_id = 0;
364         }
365
366         if (m_gs_id != 0)
367         {
368                 gl.deleteShader(m_gs_id);
369
370                 m_gs_id = 0;
371         }
372
373         if (m_po_id != 0)
374         {
375                 gl.deleteProgram(m_po_id);
376
377                 m_po_id = 0;
378         }
379
380         if (m_tc_id != 0)
381         {
382                 gl.deleteShader(m_tc_id);
383
384                 m_tc_id = 0;
385         }
386
387         if (m_te_id != 0)
388         {
389                 gl.deleteShader(m_te_id);
390
391                 m_te_id = 0;
392         }
393
394         if (m_vao_id != 0)
395         {
396                 gl.deleteVertexArrays(1, &m_vao_id);
397
398                 m_vao_id = 0;
399         }
400
401         if (m_vs_id != 0)
402         {
403                 gl.deleteShader(m_vs_id);
404
405                 m_vs_id = 0;
406         }
407
408         /* Restore default pack alignment value */
409         gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
410 }
411
412 /** Executes test iteration.
413  *
414  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
415  */
416 tcu::TestNode::IterateResult CullDistance::APICoverageTest::iterate()
417 {
418         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
419
420         /* This test should only be executed if ARB_cull_distance is supported, or if
421          * we're running a GL4.5 context
422          */
423         if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
424                 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
425         {
426                 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
427         }
428
429         /* Check that calling GetIntegerv with MAX_CULL_DISTANCES doesn't generate
430          * any errors and returns a value at least 8.
431          *
432          * Check that calling GetIntegerv with MAX_COMBINED_CLIP_AND_CULL_DISTANCES
433          * doesn't generate any errors and returns a value at least 8.
434          *
435          */
436         glw::GLint error_code                                                                    = GL_NO_ERROR;
437         glw::GLint gl_max_cull_distances_value                                   = 0;
438         glw::GLint gl_max_combined_clip_and_cull_distances_value = 0;
439
440         gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
441
442         error_code = gl.getError();
443         if (error_code != GL_NO_ERROR)
444         {
445                 m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned error code "
446                                                    << "[" << glu::getErrorStr(error_code) << "] for GL_MAX_CULL_DISTANCES"
447                                                                                                                                          " query instead of GL_NO_ERROR"
448                                                    << tcu::TestLog::EndMessage;
449
450                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
451
452                 return STOP;
453         }
454
455         gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
456
457         error_code = gl.getError();
458         if (error_code != GL_NO_ERROR)
459         {
460                 m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned error code "
461                                                    << "[" << glu::getErrorStr(error_code) << "] for "
462                                                                                                                                          "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES query "
463                                                                                                                                          "instead of GL_NO_ERROR"
464                                                    << tcu::TestLog::EndMessage;
465
466                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
467
468                 return STOP;
469         }
470
471         /* Before we proceed with the two other tests, initialize a buffer & a texture
472          * object we will need to capture data from the programs */
473         static const glw::GLuint bo_size = sizeof(int) * 4 /* components */ * 4 /* result points */;
474
475         gl.genBuffers(1, &m_bo_id);
476         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
477
478         gl.genFramebuffers(1, &m_fbo_draw_id);
479         gl.genFramebuffers(1, &m_fbo_read_id);
480         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call(s) failed.");
481
482         gl.genTextures(1, &m_cs_to_id);
483         gl.genTextures(1, &m_fbo_draw_to_id);
484         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
485
486         gl.genVertexArrays(1, &m_vao_id);
487         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
488
489         gl.bindVertexArray(m_vao_id);
490         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
491
492         gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
493         gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
494                                           m_bo_id);
495         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() or glBindBufferBase() call(s) failed.");
496
497         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, GL_STATIC_DRAW);
498         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
499
500         for (glw::GLuint n_to_id = 0; n_to_id < 2; /* CS, FBO */ ++n_to_id)
501         {
502                 gl.bindTexture(GL_TEXTURE_2D, (n_to_id == 0) ? m_cs_to_id : m_fbo_draw_to_id);
503                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
504
505                 gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
506                                                 GL_R32I, 1,               /* width */
507                                                 1);                               /* height */
508                 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
509         }
510
511         gl.bindImageTexture(0,                     /* unit */
512                                                 m_cs_to_id, 0, /* level */
513                                                 GL_FALSE,         /* layered */
514                                                 0,                         /* layer */
515                                                 GL_WRITE_ONLY, GL_R32I);
516         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture() call failed.");
517
518         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_draw_id);
519         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
520
521         gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fbo_draw_to_id, 0); /* level */
522         GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
523
524         gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read_id);
525         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
526
527         gl.viewport(0,  /* x */
528                                 0,  /* y */
529                                 1,  /* width */
530                                 1); /* height */
531         GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
532
533         gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
534         GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
535
536         /* There are two new GL constants, where value we need to verify */
537         struct _run
538         {
539                 const glw::GLchar* essl_token_value;
540                 glw::GLenum                gl_enum;
541                 glw::GLint                 gl_value;
542                 glw::GLint                 min_value;
543                 const glw::GLchar* name;
544         } runs[] = { { "gl_MaxCullDistances", GL_MAX_CULL_DISTANCES, gl_max_cull_distances_value, 8 /*minimum required */,
545                                    "GL_MAX_CULL_DISTANCES" },
546                                  { "gl_MaxCombinedClipAndCullDistances", GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES,
547                                    gl_max_combined_clip_and_cull_distances_value, 8 /*minimum required */,
548                                    "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES" } };
549
550         static const glw::GLuint n_runs = sizeof(runs) / sizeof(runs[0]);
551
552         for (glw::GLuint n_run = 0; n_run < n_runs; ++n_run)
553         {
554                 _run& current_run = runs[n_run];
555
556                 static const struct _stage
557                 {
558                         bool use_cs;
559                         bool use_fs;
560                         bool use_gs;
561                         bool use_tc;
562                         bool use_te;
563                         bool use_vs;
564
565                         const glw::GLchar* fs_input;
566                         const glw::GLchar* gs_input;
567                         const glw::GLchar* tc_input;
568                         const glw::GLchar* te_input;
569
570                         const glw::GLchar* tf_output_name;
571                         const glw::GLenum  tf_mode;
572
573                         glw::GLenum draw_call_mode;
574                         glw::GLuint n_draw_call_vertices;
575                 } stages[] = { /* CS only test */
576                                            {
577                                                    /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
578                                                    true, false, false, false, false, false,
579
580                                                    NULL,        /* fs_input             */
581                                                    NULL,        /* gs_input             */
582                                                    NULL,        /* tc_input             */
583                                                    NULL,        /* te_input             */
584                                                    NULL,        /* tf_output_name       */
585                                                    GL_NONE, /* tf_mode              */
586                                                    GL_NONE, /* draw_call_mode       */
587                                                    0,           /* n_draw_call_vertices */
588                                            },
589                                            /* VS+GS+TC+TE+FS test */
590                                            {
591                                                    /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
592                                                    false, true, true, true, true, true,
593
594                                                    "out_gs",     /* fs_input             */
595                                                    "out_te",     /* gs_input             */
596                                                    "out_vs",     /* tc_input             */
597                                                    "out_tc",     /* te_input             */
598                                                    "out_gs",     /* tf_output_name       */
599                                                    GL_TRIANGLES, /* tf_mode              */
600                                                    GL_PATCHES,   /* draw_call_mode       */
601                                                    3,                    /* n_draw_call_vertices */
602                                            },
603                                            /* VS+GS+FS test */
604                                            {
605                                                    /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
606                                                    false, true, true, false, false, true,
607
608                                                    "out_gs",     /* fs_input             */
609                                                    "out_vs",     /* gs_input             */
610                                                    NULL,                 /* tc_input             */
611                                                    NULL,                 /* te_input             */
612                                                    "out_gs",     /* tf_output_name       */
613                                                    GL_TRIANGLES, /* tf_mode              */
614                                                    GL_POINTS,   /* draw_call_mode       */
615                                                    1,                    /* n_draw_call_vertices */
616                                            },
617                                            /* VS+TC+TE+FS test */
618                                            {
619                                                    /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
620                                                    false, true, false, true, true, true,
621
622                                                    "out_te",   /* fs_input             */
623                                                    NULL,           /* gs_input             */
624                                                    "out_vs",   /* tc_input             */
625                                                    "out_tc",   /* te_input             */
626                                                    "out_te",   /* tf_output_name       */
627                                                    GL_POINTS,  /* tf_mode              */
628                                                    GL_PATCHES, /* draw_call_mode       */
629                                                    3               /* n_draw_call_vertices */
630                                            },
631                                            /* VS test */
632                                            {
633                                                    /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
634                                                    false, false, false, false, false, true,
635
636                                                    "out_vs",  /* fs_input             */
637                                                    NULL,          /* gs_input             */
638                                                    NULL,          /* tc_input             */
639                                                    NULL,          /* te_input             */
640                                                    "out_vs",  /* tf_output_name       */
641                                                    GL_POINTS, /* tf_mode              */
642                                                    GL_POINTS, /* draw_call_mode       */
643                                                    1              /* n_draw_call_vertices */
644                                            }
645                 };
646                 const glw::GLuint n_stages = sizeof(stages) / sizeof(stages[0]);
647
648                 /* Run through all test stages */
649                 for (glw::GLuint n_stage = 0; n_stage < n_stages; ++n_stage)
650                 {
651                         /* Check for OpenGL feature support */
652                         if (stages[n_stage].use_cs)
653                         {
654                                 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)) &&
655                                         !m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader"))
656                                 {
657                                         continue; // no compute shader support
658                                 }
659                         }
660                         if (stages[n_stage].use_tc || stages[n_stage].use_te)
661                         {
662                                 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) &&
663                                         !m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader"))
664                                 {
665                                         continue; // no tessellation shader support
666                                 }
667                         }
668
669                         /* Check that use of the GLSL built-in constant gl_MaxCullDistance in any
670                          * shader stage (including compute shader) does not affect the shader
671                          * compilation & program linking process.
672                          */
673                         static const glw::GLchar* cs_body_template =
674                                 "#version 150\n"
675                                 "\n"
676                                 "#extension GL_ARB_compute_shader          : require\n"
677                                 "#extension GL_ARB_cull_distance           : require\n"
678                                 "#extension GL_ARB_shader_image_load_store : require\n"
679                                 "\n"
680                                 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
681                                 "\n"
682                                 "layout(r32i) uniform writeonly iimage2D result;\n"
683                                 "\n"
684                                 "void main()\n"
685                                 "{\n"
686                                 "    imageStore(result, ivec2(0),ivec4(TOKEN) );\n"
687                                 "}\n";
688                         std::string cs_body = cs_body_template;
689
690                         static const glw::GLchar* fs_body_template = "#version 150\n"
691                                                                                                                  "\n"
692                                                                                                                  "#extension GL_ARB_cull_distance : require\n"
693                                                                                                                  "\n"
694                                                                                                                  "flat in  int INPUT_FS_NAME;\n"
695                                                                                                                  "out int out_fs;\n"
696                                                                                                                  "\n"
697                                                                                                                  "void main()\n"
698                                                                                                                  "{\n"
699                                                                                                                  "    if (INPUT_FS_NAME == TOKEN)\n"
700                                                                                                                  "    {\n"
701                                                                                                                  "        out_fs = TOKEN;\n"
702                                                                                                                  "    }\n"
703                                                                                                                  "    else\n"
704                                                                                                                  "    {\n"
705                                                                                                                  "        out_fs = -1;\n"
706                                                                                                                  "    }\n"
707                                                                                                                  "}\n";
708                         std::string fs_body = fs_body_template;
709
710                         static const glw::GLchar* gs_body_template =
711                                 "#version 150\n"
712                                 "\n"
713                                 "#extension GL_ARB_cull_distance : require\n"
714                                 "\n"
715                                 "flat in  int INPUT_GS_NAME[];\n"
716                                 "flat out int out_gs;\n"
717                                 "\n"
718                                 "layout(points)                           in;\n"
719                                 "layout(triangle_strip, max_vertices = 4) out;\n"
720                                 "\n"
721                                 "void main()\n"
722                                 "{\n"
723                                 "    int result_value = (INPUT_GS_NAME[0] == TOKEN) ? TOKEN : -1;\n"
724                                 "\n"
725                                 /* Draw a full-screen quad */
726                                 "    gl_Position = vec4(-1.0, 1.0, 0.0, 0.0);\n"
727                                 "    out_gs      = result_value;\n"
728                                 "    EmitVertex();\n"
729                                 "\n"
730                                 "    gl_Position = vec4(-1.0, -1.0, 0.0, 0.0);\n"
731                                 "    out_gs      = result_value;\n"
732                                 "    EmitVertex();\n"
733                                 "\n"
734                                 "    gl_Position = vec4(1.0, 1.0, 0.0, 0.0);\n"
735                                 "    out_gs      = result_value;\n"
736                                 "    EmitVertex();\n"
737                                 "\n"
738                                 "    gl_Position = vec4(1.0, -1.0, 0.0, 0.0);\n"
739                                 "    out_gs      = result_value;\n"
740                                 "    EmitVertex();\n"
741                                 "    EndPrimitive();\n"
742                                 "}\n";
743                         std::string gs_body = gs_body_template;
744
745                         static const glw::GLchar* tc_body_template =
746                                 "#version 400\n"
747                                 "\n"
748                                 "#extension GL_ARB_cull_distance : require\n"
749                                 "\n"
750                                 "layout(vertices = 1) out;\n"
751                                 "\n"
752                                 "flat in  int INPUT_TC_NAME[];\n"
753                                 "flat out int out_tc       [];\n"
754                                 "\n"
755                                 "void main()\n"
756                                 "{\n"
757                                 "    int result_value = (INPUT_TC_NAME[0] == TOKEN) ? TOKEN : -1;\n"
758                                 "\n"
759                                 "    out_tc[gl_InvocationID]             = result_value;\n"
760                                 "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
761                                 "    gl_TessLevelInner[0]                = 1.0;\n"
762                                 "    gl_TessLevelInner[1]                = 1.0;\n"
763                                 "    gl_TessLevelOuter[0]                = 1.0;\n"
764                                 "    gl_TessLevelOuter[1]                = 1.0;\n"
765                                 "    gl_TessLevelOuter[2]                = 1.0;\n"
766                                 "    gl_TessLevelOuter[3]                = 1.0;\n"
767                                 "}\n";
768                         std::string tc_body = tc_body_template;
769
770                         static const glw::GLchar* te_body_template =
771                                 "#version 400\n"
772                                 "\n"
773                                 "#extension GL_ARB_cull_distance : require\n"
774                                 "\n"
775                                 "flat in  int INPUT_TE_NAME[];\n"
776                                 "flat out int out_te;\n"
777                                 "\n"
778                                 "layout(isolines, point_mode) in;\n"
779                                 "\n"
780                                 "void main()\n"
781                                 "{\n"
782                                 "    int result_value = (INPUT_TE_NAME[0] == TOKEN) ? TOKEN : 0;\n"
783                                 "\n"
784                                 "    out_te = result_value;\n"
785                                 "}\n";
786                         std::string te_body = te_body_template;
787
788                         static const glw::GLchar* vs_body_template = "#version 150\n"
789                                                                                                                  "\n"
790                                                                                                                  "#extension GL_ARB_cull_distance : require\n"
791                                                                                                                  "\n"
792                                                                                                                  "flat out int out_vs;\n"
793                                                                                                                  "\n"
794                                                                                                                  "void main()\n"
795                                                                                                                  "{\n"
796                                                                                                                  "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
797                                                                                                                  "    out_vs      = TOKEN;\n"
798                                                                                                                  "}\n";
799                         std::string vs_body = vs_body_template;
800
801                         const _stage& current_stage = stages[n_stage];
802
803                         /* Build shader bodies */
804                         struct _shader_body
805                         {
806                                 std::string* body_ptr;
807                                 glw::GLenum  gl_type;
808                         } shader_bodies[] = { { &cs_body, GL_COMPUTE_SHADER },             { &fs_body, GL_FRAGMENT_SHADER },
809                                                                   { &gs_body, GL_GEOMETRY_SHADER },                { &tc_body, GL_TESS_CONTROL_SHADER },
810                                                                   { &te_body, GL_TESS_EVALUATION_SHADER }, { &vs_body, GL_VERTEX_SHADER } };
811                         static const glw::GLchar* input_fs_token_string = "INPUT_FS_NAME";
812                         static const glw::GLchar* input_gs_token_string = "INPUT_GS_NAME";
813                         static const glw::GLchar* input_te_token_string = "INPUT_TE_NAME";
814                         static const glw::GLchar* input_tc_token_string = "INPUT_TC_NAME";
815                         static const glw::GLuint  n_shader_bodies               = sizeof(shader_bodies) / sizeof(shader_bodies[0]);
816
817                         std::size_t                               token_position = std::string::npos;
818                         static const glw::GLchar* token_string   = "TOKEN";
819
820                         for (glw::GLuint n_shader_body = 0; n_shader_body < n_shader_bodies; ++n_shader_body)
821                         {
822                                 _shader_body& current_body = shader_bodies[n_shader_body];
823
824                                 /* Is this stage actually used? */
825                                 if (((current_body.gl_type == GL_COMPUTE_SHADER) && (!current_stage.use_cs)) ||
826                                         ((current_body.gl_type == GL_FRAGMENT_SHADER) && (!current_stage.use_fs)) ||
827                                         ((current_body.gl_type == GL_TESS_CONTROL_SHADER) && (!current_stage.use_tc)) ||
828                                         ((current_body.gl_type == GL_TESS_EVALUATION_SHADER) && (!current_stage.use_te)) ||
829                                         ((current_body.gl_type == GL_VERTEX_SHADER) && (!current_stage.use_vs)))
830                                 {
831                                         /* Skip the iteration. */
832                                         continue;
833                                 }
834
835                                 /* Iterate over all token and replace them with stage-specific values */
836                                 struct _token_value_pair
837                                 {
838                                         const glw::GLchar* token;
839                                         const glw::GLchar* value;
840                                 } token_value_pairs[] = {
841                                         /* NOTE: The last entry is filled by the switch() block below */
842                                         { token_string, current_run.essl_token_value },
843                                         { NULL, NULL },
844                                 };
845
846                                 const size_t n_token_value_pairs = sizeof(token_value_pairs) / sizeof(token_value_pairs[0]);
847
848                                 switch (current_body.gl_type)
849                                 {
850                                 case GL_COMPUTE_SHADER:
851                                 case GL_VERTEX_SHADER:
852                                         break;
853
854                                 case GL_FRAGMENT_SHADER:
855                                 {
856                                         token_value_pairs[1].token = input_fs_token_string;
857                                         token_value_pairs[1].value = current_stage.fs_input;
858
859                                         break;
860                                 }
861
862                                 case GL_GEOMETRY_SHADER:
863                                 {
864                                         token_value_pairs[1].token = input_gs_token_string;
865                                         token_value_pairs[1].value = current_stage.gs_input;
866
867                                         break;
868                                 }
869
870                                 case GL_TESS_CONTROL_SHADER:
871                                 {
872                                         token_value_pairs[1].token = input_tc_token_string;
873                                         token_value_pairs[1].value = current_stage.tc_input;
874
875                                         break;
876                                 }
877
878                                 case GL_TESS_EVALUATION_SHADER:
879                                 {
880                                         token_value_pairs[1].token = input_te_token_string;
881                                         token_value_pairs[1].value = current_stage.te_input;
882
883                                         break;
884                                 }
885
886                                 default:
887                                         TCU_FAIL("Unrecognized shader body type");
888                                 }
889
890                                 for (glw::GLuint n_pair = 0; n_pair < n_token_value_pairs; ++n_pair)
891                                 {
892                                         const _token_value_pair& current_pair = token_value_pairs[n_pair];
893
894                                         if (current_pair.token == NULL || current_pair.value == NULL)
895                                         {
896                                                 continue;
897                                         }
898
899                                         while ((token_position = current_body.body_ptr->find(current_pair.token)) != std::string::npos)
900                                         {
901                                                 current_body.body_ptr->replace(token_position, strlen(current_pair.token), current_pair.value);
902                                         }
903                                 } /* for (all token+value pairs) */
904                         }        /* for (all sader bodies) */
905
906                         /* Build the test program */
907                         CullDistance::Utilities::buildProgram(
908                                 gl, m_testCtx, current_stage.use_cs ? cs_body.c_str() : DE_NULL,
909                                 current_stage.use_fs ? fs_body.c_str() : DE_NULL, current_stage.use_gs ? gs_body.c_str() : DE_NULL,
910                                 current_stage.use_tc ? tc_body.c_str() : DE_NULL, current_stage.use_te ? te_body.c_str() : DE_NULL,
911                                 current_stage.use_vs ? vs_body.c_str() : DE_NULL, (current_stage.tf_output_name != NULL) ? 1 : 0,
912                                 (const glw::GLchar**)&current_stage.tf_output_name, &m_po_id);
913
914                         /* Bind the test program */
915                         DE_ASSERT(m_po_id != 0);
916
917                         gl.useProgram(m_po_id);
918                         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
919
920                         /* Execute the draw call. Transform Feed-back should be enabled for all iterations
921                          * par the CS one, since we use a different tool to capture the result data in the
922                          * latter case.
923                          */
924                         if (!current_stage.use_cs)
925                         {
926                                 gl.beginTransformFeedback(current_stage.tf_mode);
927                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
928
929                                 gl.drawArrays(current_stage.draw_call_mode, 0,   /* first */
930                                                           current_stage.n_draw_call_vertices); /* count */
931                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
932
933                                 gl.endTransformFeedback();
934                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
935                         } /* if (uses_tf) */
936                         else
937                         {
938                                 gl.dispatchCompute(1,  /* num_groups_x */
939                                                                    1,  /* num_groups_y */
940                                                                    1); /* num_groups_z */
941                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() call failed.");
942                         }
943
944                         /* Verify the result values */
945                         if (!current_stage.use_cs)
946                         {
947                                 glw::GLint* result_data_ptr = DE_NULL;
948
949                                 /* Retrieve the data captured by Transform Feedback */
950                                 result_data_ptr = (glw::GLint*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
951                                                                                                                                  sizeof(unsigned int) * 1, GL_MAP_READ_BIT);
952                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
953
954                                 if (*result_data_ptr != current_run.gl_value)
955                                 {
956                                         m_testCtx.getLog() << tcu::TestLog::Message << current_run.name << " value "
957                                                                                                                                                                            "["
958                                                                            << *result_data_ptr << "]"
959                                                                                                                           " does not match the one reported by glGetIntegerv() "
960                                                                                                                           "["
961                                                                            << current_run.gl_value << "]" << tcu::TestLog::EndMessage;
962
963                                         TCU_FAIL("GL constant value does not match the ES SL equivalent");
964                                 }
965
966                                 if (*result_data_ptr < current_run.min_value)
967                                 {
968                                         m_testCtx.getLog() << tcu::TestLog::Message << current_run.name << " value "
969                                                                                                                                                                            "["
970                                                                            << *result_data_ptr << "]"
971                                                                                                                           " does not meet the minimum specification requirements "
972                                                                                                                           "["
973                                                                            << current_run.min_value << "]" << tcu::TestLog::EndMessage;
974
975                                         TCU_FAIL("GL constant value does not meet minimum specification requirements");
976                                 }
977
978                                 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
979                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
980                         }
981
982                         for (glw::GLuint n_stage_internal = 0; n_stage_internal < 2; /* CS, FS write to separate textures */
983                                  ++n_stage_internal)
984                         {
985                                 glw::GLuint to_id = (n_stage_internal == 0) ? m_cs_to_id : m_fbo_draw_to_id;
986
987                                 if (((n_stage_internal == 0) && (!current_stage.use_cs)) ||
988                                         ((n_stage_internal == 1) && (!current_stage.use_fs)))
989                                 {
990                                         /* Skip the iteration */
991                                         continue;
992                                 }
993
994                                 /* Check the image data the test CS / FS should have written */
995                                 glw::GLint result_value = 0;
996
997                                 gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, to_id, 0); /* level */
998                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
999
1000                                 /* NOTE: We're using our custom read framebuffer here, so we'll be reading
1001                                  *       from the texture, that the writes have been issued to earlier. */
1002                                 gl.finish();
1003                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() call failed.");
1004
1005                                 gl.readPixels(0, /* x */
1006                                                           0, /* y */
1007                                                           1, /* width */
1008                                                           1, /* height */
1009                                                           GL_RED_INTEGER, GL_INT, &result_value);
1010                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
1011
1012                                 if (result_value != current_run.gl_value)
1013                                 {
1014                                         m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
1015                                                                            << " value accessible to the compute / fragment shader "
1016                                                                                   "["
1017                                                                            << result_value << "]"
1018                                                                                                                   " does not match the one reported by glGetIntegerv() "
1019                                                                                                                   "["
1020                                                                            << current_run.gl_value << "]" << tcu::TestLog::EndMessage;
1021
1022                                         TCU_FAIL("GL constant value does not match the ES SL equivalent");
1023                                 }
1024
1025                                 if (result_value < current_run.min_value)
1026                                 {
1027                                         m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
1028                                                                            << " value accessible to the compute / fragment shader "
1029                                                                                   "["
1030                                                                            << result_value << "]"
1031                                                                                                                   " does not meet the minimum specification requirements "
1032                                                                                                                   "["
1033                                                                            << current_run.min_value << "]" << tcu::TestLog::EndMessage;
1034
1035                                         TCU_FAIL("GL constant value does not meet minimum specification requirements");
1036                                 }
1037                         }
1038
1039                         /* Clear the data buffer before we continue */
1040                         static const glw::GLubyte bo_clear_data[bo_size] = { 0 };
1041
1042                         gl.bufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
1043                                                          bo_size, bo_clear_data);
1044                         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
1045
1046                         /* Clear the texture mip-map before we continue */
1047                         glw::GLint clear_values[4] = { 0, 0, 0, 0 };
1048
1049                         gl.clearBufferiv(GL_COLOR, 0, /* drawbuffer */
1050                                                          clear_values);
1051                         GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferiv() call failed.");
1052
1053                         /* Release program before we move on to the next iteration */
1054                         if (m_po_id != 0)
1055                         {
1056                                 gl.deleteProgram(m_po_id);
1057
1058                                 m_po_id = 0;
1059                         }
1060                 } /* for (all stages) */
1061         }        /* for (both runs) */
1062
1063         /* All done */
1064         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1065
1066         return STOP;
1067 }
1068
1069 /** Constructor.
1070  *
1071  *  @param context Rendering context handle.
1072  **/
1073 CullDistance::FunctionalTest::FunctionalTest(deqp::Context& context)
1074         : TestCase(context, "functional", "Cull Distance Functional Test")
1075         , m_bo_data()
1076         , m_bo_id(0)
1077         , m_fbo_id(0)
1078         , m_po_id(0)
1079         , m_render_primitives(0)
1080         , m_render_vertices(0)
1081         , m_sub_grid_cell_size(0)
1082         , m_to_id(0)
1083         , m_vao_id(0)
1084         , m_to_height(512)
1085         , m_to_width(512)
1086         , m_to_pixel_data_cache()
1087 {
1088         /* Left blank on purpose */
1089 }
1090
1091 /** @brief Build OpenGL program for functional tests
1092  *
1093  *  @param [in]  clipdistances_array_size   use size of gl_ClipDistance array
1094  *  @param [in]  culldistances_array_size   use size of gl_CullDistance array
1095  *  @param [in]  dynamic_index_writes       use dunamic indexing for setting  the gl_ClipDistance and gl_CullDistance arrays
1096  *  @param [in]  primitive_mode             primitive_mode will be used for rendering
1097  *  @param [in]  redeclare_clipdistances    redeclare gl_ClipDistance
1098  *  @param [in]  redeclare_culldistances    redeclare gl_CullDistance
1099  *  @param [in]  use_core_functionality     use core OpenGL functionality
1100  *  @param [in]  use_gs                     use geometry shader
1101  *  @param [in]  use_ts                     use tessellation shader
1102  *  @param [in]  fetch_culldistance_from_fs fetch check sum of gl_ClipDistance and gl_CullDistance from fragment shader
1103  */
1104 void CullDistance::FunctionalTest::buildPO(glw::GLuint clipdistances_array_size, glw::GLuint culldistances_array_size,
1105                                                                                    bool dynamic_index_writes, _primitive_mode primitive_mode,
1106                                                                                    bool redeclare_clipdistances, bool redeclare_culldistances,
1107                                                                                    bool use_core_functionality, bool use_gs, bool use_ts,
1108                                                                                    bool fetch_culldistance_from_fs)
1109 {
1110         deinitPO();
1111
1112         /* Form the vertex shader */
1113         glw::GLuint clipdistances_input_size =
1114                 clipdistances_array_size > 0 ? clipdistances_array_size : 1; /* Avoid zero-sized array compilation error */
1115         glw::GLuint culldistances_input_size =
1116                 culldistances_array_size > 0 ? culldistances_array_size : 1; /* Avoid zero-sized array compilation error */
1117         static const glw::GLchar* dynamic_array_setters =
1118                 "\n"
1119                 "#if TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES\n"
1120                 "        for (int n_clipdistance_entry = 0;\n"
1121                 "                 n_clipdistance_entry < TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES;\n"
1122                 "               ++n_clipdistance_entry)\n"
1123                 "        {\n"
1124                 "            ASSIGN_CLIP_DISTANCE(n_clipdistance_entry);\n"
1125                 "        }\n"
1126                 "#endif"
1127                 "\n"
1128                 "#if TEMPLATE_N_GL_CULLDISTANCE_ENTRIES \n"
1129                 "        for (int n_culldistance_entry = 0;\n"
1130                 "                 n_culldistance_entry < TEMPLATE_N_GL_CULLDISTANCE_ENTRIES;\n"
1131                 "               ++n_culldistance_entry)\n"
1132                 "        {\n"
1133                 "            ASSIGN_CULL_DISTANCE(n_culldistance_entry);\n"
1134                 "        }\n"
1135                 "#endif\n";
1136
1137         static const glw::GLchar* core_functionality = "#version 450\n";
1138
1139         static const glw::GLchar* extention_functionality = "#version 440\n"
1140                                                                                                                 "\n"
1141                                                                                                                 "#extension GL_ARB_cull_distance : require\n"
1142                                                                                                                 "\n"
1143                                                                                                                 "#ifndef GL_ARB_cull_distance\n"
1144                                                                                                                 "    #error GL_ARB_cull_distance is undefined\n"
1145                                                                                                                 "#endif\n";
1146
1147         static const glw::GLchar* fetch_function = "highp float fetch()\n"
1148                                                                                            "{\n"
1149                                                                                            "    highp float sum = 0.0;\n"
1150                                                                                            "\n"
1151                                                                                            "TEMPLATE_SUM_SETTER"
1152                                                                                            "\n"
1153                                                                                            "    return sum / TEMPLATE_SUM_DIVIDER;\n"
1154                                                                                            "}\n"
1155                                                                                            "\n"
1156                                                                                            "#define ASSIGN_RETURN_VALUE fetch()";
1157
1158         static const glw::GLchar* fs_template = "TEMPLATE_HEADER_DECLARATION\n"
1159                                                                                         "\n"
1160                                                                                         "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1161                                                                                         "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1162                                                                                         "\n"
1163                                                                                         "TEMPLATE_ASSIGN_RETURN_VALUE\n"
1164                                                                                         "\n"
1165                                                                                         "out vec4 out_fs;\n"
1166                                                                                         "\n"
1167                                                                                         "/* Fragment shader main function */\n"
1168                                                                                         "void main()\n"
1169                                                                                         "{\n"
1170                                                                                         "    out_fs = vec4(ASSIGN_RETURN_VALUE, 1.0, 1.0, 1.0);\n"
1171                                                                                         "}\n";
1172
1173         static const glw::GLchar* gs_template = "TEMPLATE_HEADER_DECLARATION\n"
1174                                                                                         "\n"
1175                                                                                         "TEMPLATE_LAYOUT_IN\n"
1176                                                                                         "TEMPLATE_LAYOUT_OUT\n"
1177                                                                                         "\n"
1178                                                                                         "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1179                                                                                         "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1180                                                                                         "\n"
1181                                                                                         "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1182                                                                                         "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1183                                                                                         "\n"
1184                                                                                         "/* Geometry shader (passthrough) main function */\n"
1185                                                                                         "void main()\n"
1186                                                                                         "{\n"
1187                                                                                         "    for (int n_vertex_index = 0;\n"
1188                                                                                         "             n_vertex_index < gl_in.length();\n"
1189                                                                                         "             n_vertex_index ++)\n"
1190                                                                                         "    {\n"
1191                                                                                         "        gl_Position = gl_in[n_vertex_index].gl_Position;\n"
1192                                                                                         "\n"
1193                                                                                         "        TEMPLATE_ARRAY_SETTERS\n"
1194                                                                                         "\n"
1195                                                                                         "        EmitVertex();\n"
1196                                                                                         "    }\n"
1197                                                                                         "\n"
1198                                                                                         "    EndPrimitive();\n"
1199                                                                                         "}\n";
1200
1201         static const glw::GLchar* tc_template =
1202                 "TEMPLATE_HEADER_DECLARATION\n"
1203                 "\n"
1204                 "TEMPLATE_LAYOUT_OUT\n"
1205                 "\n"
1206                 "out gl_PerVertex {\n"
1207                 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1208                 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1209                 "vec4 gl_Position;\n"
1210                 "} gl_out[];\n"
1211                 "\n"
1212                 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1213                 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1214                 "\n"
1215                 "/* Tesselation control shader main function */\n"
1216                 "void main()\n"
1217                 "{\n"
1218                 "    gl_TessLevelInner[0] = 1.0;\n"
1219                 "    gl_TessLevelInner[1] = 1.0;\n"
1220                 "    gl_TessLevelOuter[0] = 1.0;\n"
1221                 "    gl_TessLevelOuter[1] = 1.0;\n"
1222                 "    gl_TessLevelOuter[2] = 1.0;\n"
1223                 "    gl_TessLevelOuter[3] = 1.0;\n"
1224                 "    /* Clipdistance and culldistance array setters */\n"
1225                 "    {\n"
1226                 "        TEMPLATE_ARRAY_SETTERS\n"
1227                 "    }\n"
1228                 "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1229                 "}\n";
1230
1231         static const glw::GLchar* te_template = "TEMPLATE_HEADER_DECLARATION\n"
1232                                                                                         "\n"
1233                                                                                         "TEMPLATE_LAYOUT_IN\n"
1234                                                                                         "\n"
1235                                                                                         "in gl_PerVertex {\n"
1236                                                                                         "TEMPLATE_REDECLARE_IN_CLIPDISTANCE\n"
1237                                                                                         "TEMPLATE_REDECLARE_IN_CULLDISTANCE\n"
1238                                                                                         "vec4 gl_Position;\n"
1239                                                                                         "} gl_in[];\n"
1240                                                                                         "\n"
1241                                                                                         "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1242                                                                                         "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1243                                                                                         "\n"
1244                                                                                         "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1245                                                                                         "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1246                                                                                         "\n"
1247                                                                                         "/* Tesselation evaluation shader main function */\n"
1248                                                                                         "void main()\n"
1249                                                                                         "{\n"
1250                                                                                         "    /* Clipdistance and culldistance array setters */\n"
1251                                                                                         "    {\n"
1252                                                                                         "        TEMPLATE_ARRAY_SETTERS\n"
1253                                                                                         "    }\n"
1254                                                                                         "    gl_Position = TEMPLATE_OUT_FORMULA;\n"
1255                                                                                         "}\n";
1256
1257         static const glw::GLchar* vs_template =
1258                 "TEMPLATE_HEADER_DECLARATION\n"
1259                 "\n"
1260                 "in float clipdistance_data[TEMPLATE_CLIPDISTANCE_INPUT_SIZE];\n"
1261                 "in float culldistance_data[TEMPLATE_CULLDISTANCE_INPUT_SIZE];\n"
1262                 "in vec2  position;\n"
1263                 "\n"
1264                 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1265                 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1266                 "\n"
1267                 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1268                 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1269                 "\n"
1270                 "/* Vertex shader main function */\n"
1271                 "void main()\n"
1272                 "{\n"
1273                 "    /* Clipdistance and culldistance array setters */\n"
1274                 "    {\n"
1275                 "        TEMPLATE_ARRAY_SETTERS\n"
1276                 "    }\n"
1277                 "    gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, 0.0, 1.0);\n"
1278                 "}\n";
1279
1280         std::string* shader_body_string_fs       = DE_NULL;
1281         std::string* shader_body_string_gs       = DE_NULL;
1282         std::string* shader_body_string_tc       = DE_NULL;
1283         std::string* shader_body_string_te       = DE_NULL;
1284         std::string* shader_body_string_vs       = DE_NULL;
1285         std::string  shader_header_declaration = use_core_functionality ? core_functionality : extention_functionality;
1286
1287         struct _shaders_configuration
1288         {
1289                 glw::GLenum                type;
1290                 const glw::GLchar* shader_template;
1291                 std::string                body;
1292                 const bool                 use;
1293         } shaders_configuration[] = { {
1294                                                                           GL_FRAGMENT_SHADER, fs_template, std::string(), true,
1295                                                                   },
1296                                                                   {
1297                                                                           GL_GEOMETRY_SHADER, gs_template, std::string(), use_gs,
1298                                                                   },
1299                                                                   {
1300                                                                           GL_TESS_CONTROL_SHADER, tc_template, std::string(), use_ts,
1301                                                                   },
1302                                                                   {
1303                                                                           GL_TESS_EVALUATION_SHADER, te_template, std::string(), use_ts,
1304                                                                   },
1305                                                                   {
1306                                                                           GL_VERTEX_SHADER, vs_template, std::string(), true,
1307                                                                   } };
1308
1309         const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]);
1310
1311         /* Construct shader bodies out of templates */
1312         for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
1313         {
1314                 if (shaders_configuration[n_shader_index].use)
1315                 {
1316                         std::string  array_setters;
1317                         std::string  clipdistance_array_declaration;
1318                         std::string  culldistance_array_declaration;
1319                         std::string  clipdistance_in_array_declaration;
1320                         std::string  culldistance_in_array_declaration;
1321                         std::string& shader_source = shaders_configuration[n_shader_index].body;
1322
1323                         /* Copy template into shader body source */
1324                         shader_source = shaders_configuration[n_shader_index].shader_template;
1325
1326                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_HEADER_DECLARATION"),
1327                                                                                                 shader_header_declaration);
1328
1329                         /* Shader-specific actions */
1330                         switch (shaders_configuration[n_shader_index].type)
1331                         {
1332                         case GL_FRAGMENT_SHADER:
1333                         {
1334                                 shader_body_string_fs = &shaders_configuration[n_shader_index].body;
1335
1336                                 if (fetch_culldistance_from_fs)
1337                                 {
1338                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"),
1339                                                                                                                 std::string(fetch_function));
1340
1341                                         std::string fetch_sum_setters = "";
1342                                         for (glw::GLuint i = 0; i < clipdistances_array_size; ++i)
1343                                         {
1344                                                 fetch_sum_setters.append("    sum += abs(gl_ClipDistance[");
1345                                                 fetch_sum_setters.append(CullDistance::Utilities::intToString(i));
1346                                                 fetch_sum_setters.append("]) * ");
1347                                                 fetch_sum_setters.append(CullDistance::Utilities::intToString(i + 1));
1348                                                 fetch_sum_setters.append(".0;\n");
1349                                         }
1350
1351                                         fetch_sum_setters.append("\n");
1352
1353                                         for (glw::GLuint i = 0; i < culldistances_array_size; ++i)
1354                                         {
1355                                                 fetch_sum_setters.append("    sum += abs(gl_CullDistance[");
1356                                                 fetch_sum_setters.append(CullDistance::Utilities::intToString(i));
1357                                                 fetch_sum_setters.append("]) * ");
1358                                                 fetch_sum_setters.append(
1359                                                         CullDistance::Utilities::intToString(i + 1 + clipdistances_array_size));
1360                                                 fetch_sum_setters.append(".0;\n");
1361                                         }
1362
1363                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_SUM_SETTER"),
1364                                                                                                                 std::string(fetch_sum_setters));
1365                                         CullDistance::Utilities::replaceAll(
1366                                                 shader_source, std::string("TEMPLATE_SUM_DIVIDER"),
1367                                                 std::string(CullDistance::Utilities::intToString(
1368                                                                                 (clipdistances_array_size + culldistances_array_size) *
1369                                                                                 ((clipdistances_array_size + culldistances_array_size + 1))))
1370                                                         .append(".0"));
1371                                 }
1372                                 else
1373                                 {
1374                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"),
1375                                                                                                                 std::string("#define ASSIGN_RETURN_VALUE 1.0"));
1376                                 }
1377
1378                                 break;
1379                         }
1380
1381                         case GL_GEOMETRY_SHADER:
1382                         {
1383                                 shader_body_string_gs = &shaders_configuration[n_shader_index].body;
1384
1385                                 CullDistance::Utilities::replaceAll(
1386                                         shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1387                                         std::string("gl_ClipDistance[IDX] = gl_in[n_vertex_index].gl_ClipDistance[IDX]"));
1388                                 CullDistance::Utilities::replaceAll(
1389                                         shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1390                                         std::string("gl_CullDistance[IDX] = gl_in[n_vertex_index].gl_CullDistance[IDX]"));
1391
1392                                 switch (primitive_mode)
1393                                 {
1394                                 case PRIMITIVE_MODE_LINES:
1395                                 {
1396                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1397                                                                                                                 std::string("layout(lines)                        in;"));
1398                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1399                                                                                                                 std::string("layout(line_strip, max_vertices = 2) out;"));
1400
1401                                         break;
1402                                 }
1403                                 case PRIMITIVE_MODE_POINTS:
1404                                 {
1405                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1406                                                                                                                 std::string("layout(points)                   in;"));
1407                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1408                                                                                                                 std::string("layout(points, max_vertices = 1) out;"));
1409
1410                                         break;
1411                                 }
1412                                 case PRIMITIVE_MODE_TRIANGLES:
1413                                 {
1414                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1415                                                                                                                 std::string("layout(triangles)                        in;"));
1416                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1417                                                                                                                 std::string("layout(triangle_strip, max_vertices = 3) out;"));
1418
1419                                         break;
1420                                 }
1421                                 default:
1422                                         TCU_FAIL("Unknown primitive mode");
1423                                 }
1424
1425                                 break;
1426                         }
1427
1428                         case GL_TESS_CONTROL_SHADER:
1429                         {
1430                                 shader_body_string_tc = &shaders_configuration[n_shader_index].body;
1431
1432                                 CullDistance::Utilities::replaceAll(
1433                                         shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1434                                         std::string(
1435                                                 "gl_out[gl_InvocationID].gl_ClipDistance[IDX] = gl_in[gl_InvocationID].gl_ClipDistance[IDX]"));
1436                                 CullDistance::Utilities::replaceAll(
1437                                         shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1438                                         std::string(
1439                                                 "gl_out[gl_InvocationID].gl_CullDistance[IDX] = gl_in[gl_InvocationID].gl_CullDistance[IDX]"));
1440
1441                                 switch (primitive_mode)
1442                                 {
1443                                 case PRIMITIVE_MODE_LINES:
1444                                 {
1445                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1446                                                                                                                 std::string("layout(vertices = 2) out;"));
1447
1448                                         break;
1449                                 }
1450                                 case PRIMITIVE_MODE_POINTS:
1451                                 {
1452                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1453                                                                                                                 std::string("layout(vertices = 1) out;"));
1454
1455                                         break;
1456                                 }
1457                                 case PRIMITIVE_MODE_TRIANGLES:
1458                                 {
1459                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1460                                                                                                                 std::string("layout(vertices = 3) out;"));
1461
1462                                         break;
1463                                 }
1464                                 default:
1465                                         TCU_FAIL("Unknown primitive mode");
1466                                 }
1467
1468                                 break;
1469                         }
1470
1471                         case GL_TESS_EVALUATION_SHADER:
1472                         {
1473                                 shader_body_string_te = &shaders_configuration[n_shader_index].body;
1474
1475                                 switch (primitive_mode)
1476                                 {
1477                                 case PRIMITIVE_MODE_LINES:
1478                                 {
1479                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1480                                                                                                                 std::string("layout(isolines) in;"));
1481                                         CullDistance::Utilities::replaceAll(
1482                                                 shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1483                                                 std::string("mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x)"));
1484                                         CullDistance::Utilities::replaceAll(
1485                                                 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1486                                                 std::string("gl_ClipDistance[IDX] = mix(gl_in[0].gl_ClipDistance[IDX], "
1487                                                                         "gl_in[1].gl_ClipDistance[IDX], gl_TessCoord.x)"));
1488                                         CullDistance::Utilities::replaceAll(
1489                                                 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1490                                                 std::string("gl_CullDistance[IDX] = mix(gl_in[0].gl_CullDistance[IDX], "
1491                                                                         "gl_in[1].gl_CullDistance[IDX], gl_TessCoord.x)"));
1492
1493                                         break;
1494                                 }
1495                                 case PRIMITIVE_MODE_POINTS:
1496                                 {
1497                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1498                                                                                                                 std::string("layout(isolines, point_mode) in;"));
1499                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1500                                                                                                                 std::string("gl_in[0].gl_Position"));
1501                                         CullDistance::Utilities::replaceAll(
1502                                                 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1503                                                 std::string("gl_ClipDistance[IDX] = gl_in[0].gl_ClipDistance[IDX]"));
1504                                         CullDistance::Utilities::replaceAll(
1505                                                 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1506                                                 std::string("gl_CullDistance[IDX] = gl_in[0].gl_CullDistance[IDX]"));
1507
1508                                         break;
1509                                 }
1510                                 case PRIMITIVE_MODE_TRIANGLES:
1511                                 {
1512                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1513                                                                                                                 std::string("layout(triangles) in;"));
1514                                         CullDistance::Utilities::replaceAll(
1515                                                 shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1516                                                 std::string("vec4(mat3(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, "
1517                                                                         "gl_in[2].gl_Position.xyz) * gl_TessCoord, 1.0)"));
1518                                         CullDistance::Utilities::replaceAll(
1519                                                 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1520                                                 std::string("gl_ClipDistance[IDX] = dot(vec3(gl_in[0].gl_ClipDistance[IDX], "
1521                                                                         "gl_in[1].gl_ClipDistance[IDX], gl_in[2].gl_ClipDistance[IDX]), gl_TessCoord)"));
1522                                         CullDistance::Utilities::replaceAll(
1523                                                 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1524                                                 std::string("gl_CullDistance[IDX] = dot(vec3(gl_in[0].gl_CullDistance[IDX], "
1525                                                                         "gl_in[1].gl_CullDistance[IDX], gl_in[2].gl_CullDistance[IDX]), gl_TessCoord)"));
1526
1527                                         break;
1528                                 }
1529                                 default:
1530                                         TCU_FAIL("Unknown primitive mode");
1531                                 }
1532
1533                                 break;
1534                         }
1535
1536                         case GL_VERTEX_SHADER:
1537                         {
1538                                 shader_body_string_vs = &shaders_configuration[n_shader_index].body;
1539
1540                                 /* Specify input data size for clipdistances data */
1541                                 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CLIPDISTANCE_INPUT_SIZE"),
1542                                                                                                         CullDistance::Utilities::intToString(clipdistances_input_size));
1543
1544                                 /* Specify input data size for culldistances data */
1545                                 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CULLDISTANCE_INPUT_SIZE"),
1546                                                                                                         CullDistance::Utilities::intToString(culldistances_input_size));
1547
1548                                 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1549                                                                                                         std::string("gl_ClipDistance[IDX] = clipdistance_data[IDX]"));
1550                                 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1551                                                                                                         std::string("gl_CullDistance[IDX] = culldistance_data[IDX]"));
1552
1553                                 break;
1554                         }
1555
1556                         default:
1557                                 TCU_FAIL("Unknown shader type");
1558                         }
1559
1560                         /* Adjust clipdistances declaration */
1561                         if (redeclare_clipdistances && clipdistances_array_size > 0)
1562                         {
1563                                 if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER)
1564                                 {
1565                                         if (fetch_culldistance_from_fs)
1566                                         {
1567                                                 clipdistance_array_declaration =
1568                                                         std::string("in float gl_ClipDistance[") +
1569                                                         CullDistance::Utilities::intToString(clipdistances_array_size) + std::string("];");
1570                                         }
1571                                 }
1572                                 else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER)
1573                                 {
1574                                         clipdistance_array_declaration = std::string("float gl_ClipDistance[") +
1575                                                                                                          CullDistance::Utilities::intToString(clipdistances_array_size) +
1576                                                                                                          std::string("];");
1577                                 }
1578                                 else
1579                                 {
1580                                         clipdistance_array_declaration = std::string("out float gl_ClipDistance[") +
1581                                                                                                          CullDistance::Utilities::intToString(clipdistances_array_size) +
1582                                                                                                          std::string("];");
1583                                         clipdistance_in_array_declaration = std::string("in float gl_ClipDistance[") +
1584                                                                                                                 CullDistance::Utilities::intToString(clipdistances_array_size) +
1585                                                                                                                 std::string("];");
1586                                 }
1587                         }
1588                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CLIPDISTANCE"),
1589                                                                                                 clipdistance_array_declaration);
1590                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CLIPDISTANCE"),
1591                                                                                                 clipdistance_in_array_declaration);
1592
1593                         /* Adjust culldistances declaration */
1594                         if (redeclare_culldistances && culldistances_array_size > 0)
1595                         {
1596                                 if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER)
1597                                 {
1598                                         if (fetch_culldistance_from_fs)
1599                                         {
1600                                                 culldistance_array_declaration =
1601                                                         std::string("in float gl_CullDistance[") +
1602                                                         CullDistance::Utilities::intToString(culldistances_array_size) + std::string("];");
1603                                         }
1604                                 }
1605                                 else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER)
1606                                 {
1607                                         culldistance_array_declaration = std::string("float gl_CullDistance[") +
1608                                                                                                          CullDistance::Utilities::intToString(culldistances_array_size) +
1609                                                                                                          std::string("];");
1610                                 }
1611                                 else
1612                                 {
1613                                         culldistance_array_declaration = std::string("out float gl_CullDistance[") +
1614                                                                                                          CullDistance::Utilities::intToString(culldistances_array_size) +
1615                                                                                                          std::string("];");
1616                                         culldistance_in_array_declaration = std::string("in float gl_CullDistance[") +
1617                                                                                                                 CullDistance::Utilities::intToString(culldistances_array_size) +
1618                                                                                                                 std::string("];");
1619                                 }
1620                         }
1621                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CULLDISTANCE"),
1622                                                                                                 culldistance_array_declaration);
1623                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CULLDISTANCE"),
1624                                                                                                 culldistance_in_array_declaration);
1625
1626                         /* Adjust clip/cull distances setters */
1627                         if (dynamic_index_writes)
1628                         {
1629                                 array_setters = dynamic_array_setters;
1630
1631                                 CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES"),
1632                                                                                                         CullDistance::Utilities::intToString(clipdistances_array_size));
1633                                 CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CULLDISTANCE_ENTRIES"),
1634                                                                                                         CullDistance::Utilities::intToString(culldistances_array_size));
1635                         }
1636                         else
1637                         {
1638                                 std::stringstream static_array_setters_sstream;
1639
1640                                 static_array_setters_sstream << "\n";
1641
1642                                 for (glw::GLuint clipdistances_array_entry = 0; clipdistances_array_entry < clipdistances_array_size;
1643                                          ++clipdistances_array_entry)
1644                                 {
1645                                         static_array_setters_sstream << "        ASSIGN_CLIP_DISTANCE(" << clipdistances_array_entry
1646                                                                                                  << ");\n";
1647                                 }
1648
1649                                 static_array_setters_sstream << "\n";
1650
1651                                 for (glw::GLuint culldistances_array_entry = 0; culldistances_array_entry < culldistances_array_size;
1652                                          ++culldistances_array_entry)
1653                                 {
1654                                         static_array_setters_sstream << "        ASSIGN_CULL_DISTANCE(" << culldistances_array_entry
1655                                                                                                  << ");\n";
1656                                 }
1657
1658                                 array_setters = static_array_setters_sstream.str();
1659                         }
1660
1661                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ARRAY_SETTERS"), array_setters);
1662                 }
1663         }
1664
1665         /* Build the geometry shader */
1666         CullDistance::Utilities::buildProgram(
1667                 m_context.getRenderContext().getFunctions(), m_testCtx, DE_NULL, /* Compute shader                    */
1668                 shader_body_string_fs != DE_NULL ? shader_body_string_fs->c_str() :
1669                                                                                    DE_NULL, /* Fragment shader                   */
1670                 shader_body_string_gs != DE_NULL ? shader_body_string_gs->c_str() :
1671                                                                                    DE_NULL, /* Geometry shader                   */
1672                 shader_body_string_tc != DE_NULL ? shader_body_string_tc->c_str() :
1673                                                                                    DE_NULL, /* Tesselation control shader        */
1674                 shader_body_string_te != DE_NULL ? shader_body_string_te->c_str() :
1675                                                                                    DE_NULL, /* Tesselation evaluation shader     */
1676                 shader_body_string_vs != DE_NULL ? shader_body_string_vs->c_str() :
1677                                                                                    DE_NULL, /* Vertex shader                     */
1678                 0,                                                                                      /* Transform feedback varyings count */
1679                 DE_NULL,                                                                        /* Transform feedback varyings       */
1680                 &m_po_id                                                                        /* Program object id                 */
1681                 );
1682 }
1683
1684 /** Generates primitive data required to test a case with specified
1685  *  gl_ClipDistance and glCullDistance array sizes for specified
1686  *  primitive mode. Generated primitive data is stored in m_bo_data
1687  *  as well uploaded into buffer specified in m_bo_id buffer.
1688  *  Also the procedure binds vertex attribute locations to
1689  *  program object m_po_id.
1690  *
1691  *  @param clipdistances_array_size gl_ClipDistance array size. Can be 0.
1692  *  @param culldistances_array_size gl_CullDistance array size. Can be 0.
1693  *  @param _primitive_mode          Primitives to be generated. Can be:
1694  *                                  PRIMITIVE_MODE_POINTS,
1695  *                                  PRIMITIVE_MODE_LINES,
1696  *                                  PRIMITIVE_MODE_TRIANGLES.
1697  */
1698 void CullDistance::FunctionalTest::configureVAO(glw::GLuint clipdistances_array_size,
1699                                                                                                 glw::GLuint culldistances_array_size, _primitive_mode primitive_mode)
1700 {
1701         /* Detailed test description.
1702          *
1703          * configureVAO() generates primitives layouted in grid. Primitve
1704          * consists of up to 3 vertices and each vertex is accompanied by:
1705          * - array of clipdistances (clipdistances_array_size floats);
1706          * - array of culldistances (culldistances_array_size floats);
1707          * - rendering position coordinates (x and y);
1708          * - check position coordinates (x and y).
1709          *
1710          * The grid has following layout:
1711          *
1712          *     Grid                       |         gl_CullDistance[x]         |
1713          *                                |  0 .. culldistances_array_size - 1 |
1714          *                                |  0th  |  1st  |  2nd  | .......... |
1715          *     ---------------------------+-------+-------+-------+------------+
1716          *     0th  gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
1717          *     1st  gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
1718          *     ...                        |  ...  |  ...  |  ...  | .......... |
1719          *     y-th gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
1720          *     ...                        |  ...  |  ...  |  ...  | .......... |
1721          *     clipdistances_array_size-1 |Subgrid|Subgrid|Subgrid| .......... |
1722          *
1723          * Each grid cell contains subgrid of 3*3 items in size with following
1724          * structure:
1725          *
1726          *     Subgrid        |        x-th gl_CullDistance test           |
1727          *                    |                                            |
1728          *     y-th           | all vertices | 0th vertex   | all vertices |
1729          *     gl_ClipDistance| in primitive | in primitive | in primitive |
1730          *     tests          | dist[x] > 0  | dist[x] < 0  | dist[x] < 0  |
1731          *     ---------------+--------------+--------------+--------------+
1732          *        all vertices| primitive #0 | primitive #1 | primitive #2 |
1733          *        in primitive|              |              |              |
1734          *        dist[y] > 0 |   visible    |   visible    |    culled    |
1735          *     ---------------+--------------+--------------+--------------+
1736          *        0th vertex  | primitive #3 | primitive #4 | primitive #5 |
1737          *        in primitive|  0th vertex  |  0th vertex  |              |
1738          *        dist[y] < 0 |   clipped    |   clipped    |    culled    |
1739          *     ---------------+--------------+--------------+--------------+
1740          *        all vertices| primitive #6 | primitive #7 | primitive #8 |
1741          *        in primitive|              |              |              |
1742          *        dist[y] < 0 |   clipped    |   clipped    |    culled    |
1743          *     ---------------+--------------+--------------+--------------+
1744          *
1745          * Expected rendering result is specified in cell bottom.
1746          * It can be one of the following:
1747          * - "visible" means the primitive is not affected neither by gl_CullDistance
1748          *             nor by gl_ClipDistance and rendered as a whole;
1749          * - "clipped" for the vertex means the vertex is not rendered, while other
1750          *             primitive vertices and some filling fragments are rendered;
1751          * - "clipped" for primitive means none of primitive vertices and fragments
1752          *             are rendered and thus primitive is not rendered and is invisible;
1753          * - "culled"  means, that neither primitive vertices, nor primitive filling
1754          *             fragments are rendered (primitive is invisible).
1755          *
1756          * All subgrid items contain same primitive rendered. Depending on
1757          * test case running it would be either triangle, or line, or point:
1758          *
1759          *     triangle    line        point
1760          *     8x8 box     8x8 box     3x3 box
1761          *     ........    ........    ...
1762          *     .0----2.    .0......    .0.
1763          *     ..\@@@|.    ..\.....    ...
1764          *     ...\@@|.    ...\....
1765          *     ....\@|.    ....\...
1766          *     .....\|.    .....\..
1767          *     ......1.    ......1.
1768          *     ........    ........
1769          *
1770          *     where 0 - is a 0th vertex primitive
1771          *           1 - is a 1st vertex primitive
1772          *           2 - is a 2nd vertex primitive
1773          *
1774          * The culldistances_array_size can be 0. In that case, grid height
1775          * is assumed equal to 1, but 0 glCullDistances is specified.
1776          * Similar handled clipdistances_array_size.
1777          *
1778          * The data generated is used and checked in executeRenderTest().
1779          * After rendering each primitive vertex is tested:
1780          * - if it is rendered, if it have to be rendered (according distance);
1781          * - if it is not rendered, if it have to be not rendered (according distance).
1782          * Due to "top-left" rasterization rule check position is
1783          * different from rendering vertex position.
1784          *
1785          * Also one pixel width guarding box is checked to be clear.
1786          */
1787
1788         const glw::Functions& gl                           = m_context.getRenderContext().getFunctions();
1789         const glw::GLuint        n_sub_grid_cells = 3; /* Tested distance is positive for all vertices in the primitive;
1790          * Tested distance is negative for 0th vertex in the primitive;
1791          * Tested distance is negative for all vertices in the primitive;
1792          */
1793         const glw::GLuint        sub_grid_cell_size =
1794                 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 8 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 3 : 8);
1795
1796         const glw::GLuint grid_cell_size = n_sub_grid_cells * sub_grid_cell_size;
1797         const glw::GLuint n_primitive_vertices =
1798                 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 : 3);
1799
1800         const glw::GLuint n_grid_cells_x                           = culldistances_array_size != 0 ? culldistances_array_size : 1;
1801         const glw::GLuint n_grid_cells_y                           = clipdistances_array_size != 0 ? clipdistances_array_size : 1;
1802         const glw::GLuint n_pervertex_float_attributes = clipdistances_array_size + culldistances_array_size +
1803                                                                                                          2 /* vertex' draw x, y */ + 2 /* vertex' checkpoint x, y */;
1804         const glw::GLuint n_primitives_total     = n_grid_cells_x * n_sub_grid_cells * n_grid_cells_y * n_sub_grid_cells;
1805         const glw::GLuint n_vertices_total               = n_primitives_total * n_primitive_vertices;
1806         const glw::GLuint offsets_line_draw_x[2] = {
1807                 1, sub_grid_cell_size - 1
1808         }; /* vertex x offsets to subgrid cell origin for line primitive     */
1809         const glw::GLuint offsets_line_draw_y[2] = {
1810                 1, sub_grid_cell_size - 1
1811         }; /* vertex y offsets to subgrid cell origin for line primitive     */
1812         const glw::GLuint offsets_line_checkpoint_x[2] = {
1813                 1, sub_grid_cell_size - 2
1814         }; /* pixel x offsets to subgrid cell origin for line primitive      */
1815         const glw::GLuint offsets_line_checkpoint_y[2] = {
1816                 1, sub_grid_cell_size - 2
1817         }; /* pixel y offsets to subgrid cell origin for line primitive      */
1818         const glw::GLuint offsets_point_draw_x[1] = {
1819                 1
1820         }; /* vertex x offsets to subgrid cell origin for point primitive    */
1821         const glw::GLuint offsets_point_draw_y[1] = {
1822                 2
1823         }; /* vertex y offsets to subgrid cell origin for point primitive    */
1824         const glw::GLuint offsets_point_checkpoint_x[1] = {
1825                 1
1826         }; /* pixel x offsets to subgrid cell origin for point primitive     */
1827         const glw::GLuint offsets_point_checkpoint_y[1] = {
1828                 1
1829         }; /* pixel y offsets to subgrid cell origin for point primitive     */
1830         const glw::GLuint offsets_triangle_draw_x[3] = {
1831                 1, sub_grid_cell_size - 1, sub_grid_cell_size - 1
1832         }; /* vertex x offsets to subgrid cell origin for triangle primitive */
1833         const glw::GLuint offsets_triangle_draw_y[3] = {
1834                 1, sub_grid_cell_size - 1, 1
1835         }; /* vertex y offsets to subgrid cell origin for triangle primitive */
1836         const glw::GLuint offsets_triangle_checkpoint_x[3] = {
1837                 1, sub_grid_cell_size - 2, sub_grid_cell_size - 2
1838         }; /* pixel x offsets to subgrid cell origin for triangle primitive  */
1839         const glw::GLuint offsets_triangle_checkpoint_y[3] = {
1840                 1, sub_grid_cell_size - 2, 1
1841         }; /* pixel y offsets to subgrid cell origin for triangle primitive  */
1842
1843         /* Clear data left from previous tests. */
1844         m_bo_data.clear();
1845
1846         /* No data to render */
1847         m_render_primitives = 0;
1848         m_render_vertices   = 0;
1849
1850         /* Preallocate space for bo_points_count */
1851         m_bo_data.reserve(n_vertices_total * n_pervertex_float_attributes);
1852
1853         /* Generate test data for cell_y-th clip distance */
1854         for (glw::GLuint cell_y = 0; cell_y < n_grid_cells_y; cell_y++)
1855         {
1856                 /* Generate test data for cell_x-th cull distance */
1857                 for (glw::GLuint cell_x = 0; cell_x < n_grid_cells_x; cell_x++)
1858                 {
1859                         /* Check clip distance sub cases:
1860                          * 0. Tested distance is positive for all vertices in the primitive;
1861                          * 1. Tested distance is negative for 0th vertex in the primitive;
1862                          * 2. Tested distance is negative for all vertices in the primitive;
1863                          */
1864                         for (glw::GLuint n_sub_cell_y = 0; n_sub_cell_y < n_sub_grid_cells; n_sub_cell_y++)
1865                         {
1866                                 /* Check cull distance sub cases:
1867                                  * 0. Tested distance is positive for all vertices in the primitive;
1868                                  * 1. Tested distance is negative for 0th vertex in the primitive;
1869                                  * 2. Tested distance is negative for all vertices in the primitive;
1870                                  */
1871                                 for (glw::GLuint n_sub_cell_x = 0; n_sub_cell_x < n_sub_grid_cells; n_sub_cell_x++)
1872                                 {
1873                                         /* Generate vertices in primitive */
1874                                         for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < n_primitive_vertices;
1875                                                  n_primitive_vertex++)
1876                                         {
1877                                                 /* Fill in clipdistance array for the n_primitive_vertex vertex in primitive */
1878                                                 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
1879                                                          n_clipdistance_entry++)
1880                                                 {
1881                                                         glw::GLfloat distance_value = 0.0f;
1882                                                         bool             negative               = true;
1883
1884                                                         /* Special approach to tested clipdistance entry. */
1885                                                         if (n_clipdistance_entry == cell_y)
1886                                                         {
1887                                                                 /* The primitive vertex should be affected by the clip distance */
1888                                                                 switch (n_sub_cell_y)
1889                                                                 {
1890                                                                 case 0:
1891                                                                 {
1892                                                                         /* subgrid row 0: all primitive vertices have tested distance value positive */
1893                                                                         negative = false;
1894
1895                                                                         break;
1896                                                                 }
1897                                                                 case 1:
1898                                                                 {
1899                                                                         /* subgrid row 1: tested distance value for 0th primitive vertex is negative,
1900                                                                          all other primitive vertices have tested distance value positive */
1901                                                                         negative = (n_primitive_vertex == 0) ? true : false;
1902
1903                                                                         break;
1904                                                                 }
1905                                                                 case 2:
1906                                                                 {
1907                                                                         /* subgrid row 2: tested distance value is negative for all primitive vertices */
1908                                                                         negative = true;
1909
1910                                                                         break;
1911                                                                 }
1912                                                                 default:
1913                                                                         TCU_FAIL("Invalid subgrid cell index");
1914                                                                 }
1915
1916                                                                 distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_clipdistance_entry + 1);
1917                                                         }
1918                                                         else
1919                                                         {
1920                                                                 /* For clip distances other than tested: assign positive value to avoid its influence. */
1921                                                                 distance_value = glw::GLfloat(clipdistances_array_size + n_clipdistance_entry + 1);
1922                                                         }
1923
1924                                                         m_bo_data.push_back(distance_value / glw::GLfloat(clipdistances_array_size));
1925                                                 } /* for (all gl_ClipDistance[] array values) */
1926
1927                                                 /* Fill in culldistance array for the n_primitive_vertex vertex in primitive */
1928                                                 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
1929                                                          n_culldistance_entry++)
1930                                                 {
1931                                                         glw::GLfloat distance_value = 0.0f;
1932                                                         bool             negative               = true;
1933
1934                                                         /* Special approach to tested culldistance entry. */
1935                                                         if (n_culldistance_entry == cell_x)
1936                                                         {
1937                                                                 /* The primitive vertex should be affected by the cull distance */
1938                                                                 switch (n_sub_cell_x)
1939                                                                 {
1940                                                                 case 0:
1941                                                                 {
1942                                                                         /* subgrid column 0: all primitive vertices have tested distance value positive */
1943                                                                         negative = false;
1944
1945                                                                         break;
1946                                                                 }
1947                                                                 case 1:
1948                                                                 {
1949                                                                         /* subgrid column 1: tested distance value for 0th primitive vertex is negative,
1950                                                                          all other primitive vertices have tested distance value positive */
1951                                                                         negative = (n_primitive_vertex == 0) ? true : false;
1952
1953                                                                         break;
1954                                                                 }
1955                                                                 case 2:
1956                                                                 {
1957                                                                         /* subgrid column 2: tested distance value is negative for all primitive vertices */
1958                                                                         negative = true;
1959
1960                                                                         break;
1961                                                                 }
1962                                                                 default:
1963                                                                         TCU_FAIL("Invalid subgrid cell index");
1964                                                                 }
1965
1966                                                                 distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_culldistance_entry + 1);
1967                                                         }
1968                                                         else
1969                                                         {
1970                                                                 /* For cull distances other than tested: assign 0th vertex negative value,
1971                                                                  to check absence of between-distances influence. */
1972                                                                 if (n_primitive_vertices > 1 && n_primitive_vertex == 0)
1973                                                                 {
1974                                                                         distance_value = -glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1);
1975                                                                 }
1976                                                                 else
1977                                                                 {
1978                                                                         /* This culldistance is out of interest: assign positive value. */
1979                                                                         distance_value = glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1);
1980                                                                 }
1981                                                         }
1982
1983                                                         m_bo_data.push_back(distance_value / glw::GLfloat(culldistances_array_size));
1984                                                 } /* for (all gl_CullDistance[] array values) */
1985
1986                                                 /* Generate primitve vertex draw and checkpoint coordinates */
1987                                                 glw::GLint vertex_draw_pixel_offset_x           = 0;
1988                                                 glw::GLint vertex_draw_pixel_offset_y           = 0;
1989                                                 glw::GLint vertex_checkpoint_pixel_offset_x = 0;
1990                                                 glw::GLint vertex_checkpoint_pixel_offset_y = 0;
1991
1992                                                 switch (primitive_mode)
1993                                                 {
1994                                                 case PRIMITIVE_MODE_LINES:
1995                                                 {
1996                                                         vertex_draw_pixel_offset_x               = offsets_line_draw_x[n_primitive_vertex];
1997                                                         vertex_draw_pixel_offset_y               = offsets_line_draw_y[n_primitive_vertex];
1998                                                         vertex_checkpoint_pixel_offset_x = offsets_line_checkpoint_x[n_primitive_vertex];
1999                                                         vertex_checkpoint_pixel_offset_y = offsets_line_checkpoint_y[n_primitive_vertex];
2000
2001                                                         break;
2002                                                 }
2003
2004                                                 case PRIMITIVE_MODE_POINTS:
2005                                                 {
2006                                                         vertex_draw_pixel_offset_x               = offsets_point_draw_x[n_primitive_vertex];
2007                                                         vertex_draw_pixel_offset_y               = offsets_point_draw_y[n_primitive_vertex];
2008                                                         vertex_checkpoint_pixel_offset_x = offsets_point_checkpoint_x[n_primitive_vertex];
2009                                                         vertex_checkpoint_pixel_offset_y = offsets_point_checkpoint_y[n_primitive_vertex];
2010
2011                                                         break;
2012                                                 }
2013
2014                                                 case PRIMITIVE_MODE_TRIANGLES:
2015                                                 {
2016                                                         vertex_draw_pixel_offset_x               = offsets_triangle_draw_x[n_primitive_vertex];
2017                                                         vertex_draw_pixel_offset_y               = offsets_triangle_draw_y[n_primitive_vertex];
2018                                                         vertex_checkpoint_pixel_offset_x = offsets_triangle_checkpoint_x[n_primitive_vertex];
2019                                                         vertex_checkpoint_pixel_offset_y = offsets_triangle_checkpoint_y[n_primitive_vertex];
2020
2021                                                         break;
2022                                                 }
2023
2024                                                 default:
2025                                                         TCU_FAIL("Unknown primitive mode");
2026                                                 }
2027
2028                                                 /* Origin of sub_cell */
2029                                                 glw::GLint sub_cell_origin_x = cell_x * grid_cell_size + n_sub_cell_x * sub_grid_cell_size;
2030                                                 glw::GLint sub_cell_origin_y = cell_y * grid_cell_size + n_sub_cell_y * sub_grid_cell_size;
2031                                                 /* Normalized texture coordinates of vertex draw position. */
2032                                                 glw::GLfloat x =
2033                                                         glw::GLfloat(sub_cell_origin_x + vertex_draw_pixel_offset_x) / glw::GLfloat(m_to_width);
2034                                                 glw::GLfloat y =
2035                                                         glw::GLfloat(sub_cell_origin_y + vertex_draw_pixel_offset_y) / glw::GLfloat(m_to_height);
2036                                                 /* Normalized texture coordinates of vertex checkpoint position. */
2037                                                 glw::GLfloat checkpoint_x = glw::GLfloat(sub_cell_origin_x + vertex_checkpoint_pixel_offset_x) /
2038                                                                                                         glw::GLfloat(m_to_width);
2039                                                 glw::GLfloat checkpoint_y = glw::GLfloat(sub_cell_origin_y + vertex_checkpoint_pixel_offset_y) /
2040                                                                                                         glw::GLfloat(m_to_height);
2041
2042                                                 /* Add vertex draw coordinates into buffer. */
2043                                                 m_bo_data.push_back(x);
2044                                                 m_bo_data.push_back(y);
2045
2046                                                 /* Add vertex checkpoint coordinates into buffer. */
2047                                                 m_bo_data.push_back(checkpoint_x);
2048                                                 m_bo_data.push_back(checkpoint_y);
2049                                         } /* for (all vertices in primitive) */
2050                                 }        /* for (all horizontal sub cells) */
2051                         }                 /* for (all vertical sub cells) */
2052                 }                         /* for (all horizontal cells) */
2053         }                                 /* for (all vertical cells) */
2054
2055         /* Sanity check: make sure we pushed required amount of data */
2056         DE_ASSERT(m_bo_data.size() == n_vertices_total * n_pervertex_float_attributes);
2057
2058         /* Save number of primitives to render */
2059         m_render_primitives  = n_primitives_total;
2060         m_render_vertices       = n_vertices_total;
2061         m_sub_grid_cell_size = sub_grid_cell_size;
2062
2063         /* Copy the data to the buffer object */
2064         gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id);
2065         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2066
2067         gl.bufferData(GL_ARRAY_BUFFER, m_bo_data.size() * sizeof(glw::GLfloat), &m_bo_data[0], GL_STATIC_DRAW);
2068         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2069
2070         DE_ASSERT(m_po_id != 0);
2071
2072         /* Bind VAO data to program */
2073         glw::GLint po_clipdistance_array_location = -1;
2074         glw::GLint po_culldistance_array_location = -1;
2075         glw::GLint po_position_location                   = -1;
2076
2077         /* Retrieve clipdistance and culldistance attribute locations */
2078         gl.bindVertexArray(m_vao_id);
2079         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2080
2081         po_clipdistance_array_location = gl.getAttribLocation(m_po_id, "clipdistance_data[0]");
2082         po_culldistance_array_location = gl.getAttribLocation(m_po_id, "culldistance_data[0]");
2083         po_position_location               = gl.getAttribLocation(m_po_id, "position");
2084
2085         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() call(s) failed.");
2086
2087         if (clipdistances_array_size > 0)
2088         {
2089                 DE_ASSERT(po_clipdistance_array_location != -1);
2090         }
2091
2092         if (culldistances_array_size > 0)
2093         {
2094                 DE_ASSERT(po_culldistance_array_location != -1);
2095         }
2096
2097         DE_ASSERT(po_position_location != -1);
2098
2099         glw::GLintptr   current_offset = 0;
2100         const glw::GLint stride                 = static_cast<glw::GLint>(n_pervertex_float_attributes * sizeof(glw::GLfloat));
2101
2102         gl.bindVertexArray(m_vao_id);
2103         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2104
2105         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; ++n_clipdistance_entry)
2106         {
2107                 gl.vertexAttribPointer(po_clipdistance_array_location + n_clipdistance_entry, 1, /* size */
2108                                                            GL_FLOAT, GL_FALSE,                                                                           /* normalized */
2109                                                            stride, (const glw::GLvoid*)current_offset);
2110                 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
2111
2112                 gl.enableVertexAttribArray(po_clipdistance_array_location + n_clipdistance_entry);
2113                 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
2114
2115                 current_offset += sizeof(glw::GLfloat);
2116         } /* for (all clip distance array value attributes) */
2117
2118         for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size; ++n_culldistance_entry)
2119         {
2120                 gl.vertexAttribPointer(po_culldistance_array_location + n_culldistance_entry, 1, /* size */
2121                                                            GL_FLOAT, GL_FALSE,                                                                           /* normalized */
2122                                                            stride, (const glw::GLvoid*)current_offset);
2123                 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
2124
2125                 gl.enableVertexAttribArray(po_culldistance_array_location + n_culldistance_entry);
2126                 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
2127
2128                 current_offset += sizeof(glw::GLfloat);
2129         } /* for (all cull distance array value attributes) */
2130
2131         gl.vertexAttribPointer(po_position_location, 2, /* size */
2132                                                    GL_FLOAT, GL_FALSE,          /* normalized */
2133                                                    stride, (const glw::GLvoid*)current_offset);
2134         GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed");
2135
2136         gl.enableVertexAttribArray(po_position_location);
2137         GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed");
2138 }
2139
2140 /** @brief Cull Distance Functional Test deinitialization */
2141 void CullDistance::FunctionalTest::deinit()
2142 {
2143         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2144
2145         if (m_fbo_id != 0)
2146         {
2147                 gl.deleteFramebuffers(1, &m_fbo_id);
2148
2149                 m_fbo_id = 0;
2150         }
2151
2152         if (m_to_id != 0)
2153         {
2154                 gl.deleteTextures(1, &m_to_id);
2155
2156                 m_to_id = 0;
2157         }
2158
2159         if (m_vao_id != 0)
2160         {
2161                 gl.deleteVertexArrays(1, &m_vao_id);
2162
2163                 m_vao_id = 0;
2164         }
2165
2166         deinitPO();
2167 }
2168
2169 /** @brief Cull Distance Functional Test deinitialization of OpenGL programs */
2170 void CullDistance::FunctionalTest::deinitPO()
2171 {
2172         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2173
2174         if (m_po_id != 0)
2175         {
2176                 gl.deleteProgram(m_po_id);
2177
2178                 m_po_id = 0;
2179         }
2180 }
2181
2182 /** @brief Executes single render test case
2183  *
2184  * @param [in]  clipdistances_array_size    Size of gl_ClipDistance[] array
2185  * @param [in]  culldistances_array_size    Size of gl_CullDistance[] array
2186  * @param [in]  primitive_mode              Type of primitives to be rendered (see enum _primitive_mode)
2187  * @param [in]  use_tesselation             Indicate whether to use tessellation shader
2188  * @param [in]  fetch_culldistance_from_fs  Indicate whether to fetch gl_CullDistance and gl_ClipDistance values from the fragment shader
2189  */
2190 void CullDistance::FunctionalTest::executeRenderTest(glw::GLuint         clipdistances_array_size,
2191                                                                                                          glw::GLuint     culldistances_array_size,
2192                                                                                                          _primitive_mode primitive_mode, bool use_tesselation,
2193                                                                                                          bool fetch_culldistance_from_fs)
2194 {
2195         const glw::Functions& gl                                                  = m_context.getRenderContext().getFunctions();
2196         glw::GLenum                       mode                                            = GL_NONE;
2197         glw::GLuint                       n_clipped_vertices_real        = 0;
2198         glw::GLuint                       n_culled_primitives_real      = 0;
2199         glw::GLuint                       n_not_clipped_vertices_real = 0;
2200         const glw::GLuint        primitive_vertices_count =
2201                 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 : 3);
2202         const glw::GLuint stride_in_floats =
2203                 clipdistances_array_size + culldistances_array_size + 2 /* position's x, y*/ + 2 /* checkpoint x,y */;
2204
2205         switch (primitive_mode)
2206         {
2207         case PRIMITIVE_MODE_LINES:
2208         {
2209                 mode = GL_LINES;
2210
2211                 break;
2212         }
2213         case PRIMITIVE_MODE_POINTS:
2214         {
2215                 mode = GL_POINTS;
2216
2217                 break;
2218         }
2219         case PRIMITIVE_MODE_TRIANGLES:
2220         {
2221                 mode = GL_TRIANGLES;
2222
2223                 break;
2224         }
2225         default:
2226                 TCU_FAIL("Unknown primitive mode");
2227         }
2228
2229         if (use_tesselation)
2230         {
2231                 mode = GL_PATCHES;
2232
2233                 gl.patchParameteri(GL_PATCH_VERTICES, primitive_vertices_count);
2234                 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
2235         }
2236
2237         gl.clear(GL_COLOR_BUFFER_BIT);
2238         GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
2239
2240         gl.useProgram(m_po_id);
2241         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2242
2243         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++)
2244         {
2245                 gl.enable(GL_CLIP_DISTANCE0 + n_clipdistance_entry);
2246                 GLU_EXPECT_NO_ERROR(gl.getError(), "gl.enable(GL_CLIP_DISTANCE)() call failed.");
2247         } /* for (all clip distance array value attributes) */
2248
2249         gl.drawArrays(mode, 0, m_render_vertices);
2250         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray() call(s) failed.");
2251
2252         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++)
2253         {
2254                 gl.disable(GL_CLIP_DISTANCE0 + n_clipdistance_entry);
2255                 GLU_EXPECT_NO_ERROR(gl.getError(), "gl.disable(GL_CLIP_DISTANCE)() call failed.");
2256         } /* for (all clip distance array value attributes) */
2257
2258         gl.useProgram(0);
2259         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2260
2261         /* Read generated texture into m_to_pixel_data_cache */
2262         readTexturePixels();
2263
2264         for (glw::GLint n_primitive_index = 0; n_primitive_index < m_render_primitives; n_primitive_index++)
2265         {
2266                 glw::GLuint base_index_of_primitive              = n_primitive_index * primitive_vertices_count * stride_in_floats;
2267                 bool            primitive_culled                         = false;
2268                 glw::GLint  primitive_culled_by_distance = -1;
2269
2270                 /* Check the bounding box is clear */
2271                 glw::GLuint base_index_of_vertex          = base_index_of_primitive;
2272                 glw::GLuint checkpoint_position_index = base_index_of_vertex + clipdistances_array_size +
2273                                                                                                 culldistances_array_size + 2 /* ignore vertex coordinates */;
2274                 glw::GLint checkpoint_x = glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index]);
2275                 glw::GLint checkpoint_y = glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index + 1]);
2276                 glw::GLint origin_x             = checkpoint_x - 1;
2277                 glw::GLint origin_y             = checkpoint_y - 1;
2278                 for (glw::GLint pixel_offset = 0; pixel_offset < m_sub_grid_cell_size; pixel_offset++)
2279                 {
2280                         if (readRedPixelValue(origin_x + pixel_offset, origin_y) != 0)
2281                         {
2282                                 TCU_FAIL("Top edge of bounding box is overwritten");
2283                         }
2284
2285                         if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1, origin_y + pixel_offset) != 0)
2286                         {
2287                                 TCU_FAIL("Right edge of bounding box is overwritten");
2288                         }
2289
2290                         if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1 - pixel_offset,
2291                                                                   origin_y + m_sub_grid_cell_size - 1) != 0)
2292                         {
2293                                 TCU_FAIL("Bottom edge of bounding box is overwritten");
2294                         }
2295
2296                         if (readRedPixelValue(origin_x, origin_y + m_sub_grid_cell_size - 1 - pixel_offset) != 0)
2297                         {
2298                                 TCU_FAIL("Left edge of bounding box is overwritten");
2299                         }
2300                 }
2301
2302                 /* Determine if primitive has been culled */
2303                 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
2304                          n_culldistance_entry++)
2305                 {
2306                         bool distance_negative_in_all_primitive_vertices = true;
2307
2308                         for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2309                                  n_primitive_vertex++)
2310                         {
2311                                 glw::GLint base_index_of_vertex_internal =
2312                                         base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2313                                 glw::GLint      culldistance_array_offset = base_index_of_vertex_internal + clipdistances_array_size;
2314                                 glw::GLfloat* vertex_culldistance_array = &m_bo_data[culldistance_array_offset];
2315
2316                                 if (vertex_culldistance_array[n_culldistance_entry] >= 0)
2317                                 {
2318                                         /* Primitive is not culled, due to one of its distances is not negative */
2319                                         distance_negative_in_all_primitive_vertices = false;
2320
2321                                         /* Skip left vertices for this distance */
2322                                         break;
2323                                 }
2324                         }
2325
2326                         /* The distance is negative in all primitive vertices, so this distance culls the primitive */
2327                         if (distance_negative_in_all_primitive_vertices)
2328                         {
2329                                 primitive_culled                         = true;
2330                                 primitive_culled_by_distance = n_culldistance_entry;
2331
2332                                 n_culled_primitives_real++;
2333
2334                                 /* Skip left distances from check */
2335                                 break;
2336                         }
2337                 }
2338
2339                 /* Validate culling */
2340                 if (primitive_culled)
2341                 {
2342                         /* Check whether primitive was culled and all its vertices are invisible */
2343                         for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2344                                  n_primitive_vertex++)
2345                         {
2346                                 glw::GLint base_index_of_vertex_internal =
2347                                         base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2348                                 glw::GLint checkpoint_position_index_internal = base_index_of_vertex_internal +
2349                                                                                                                                 clipdistances_array_size + culldistances_array_size +
2350                                                                                                                                 2 /* ignore vertex coordinates */;
2351                                 glw::GLint checkpoint_x_internal =
2352                                         glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2353                                 glw::GLint checkpoint_y_internal =
2354                                         glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2355                                 glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2356
2357                                 /* Make sure vertex is invisible */
2358                                 if (vertex_color_red_value != 0)
2359                                 {
2360                                         m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] "
2361                                                                            << "should be culled by distance [" << primitive_culled_by_distance << "]"
2362                                                                            << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y
2363                                                                            << ") is visible." << tcu::TestLog::EndMessage;
2364
2365                                         TCU_FAIL("Primitive is expected to be culled, but one of its vertices is visible.");
2366                                 }
2367                         }
2368
2369                         /* Primitive is culled, no reason to check clipping */
2370                         continue;
2371                 }
2372
2373                 bool all_vertices_are_clipped = true;
2374
2375                 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count; n_primitive_vertex++)
2376                 {
2377                         glw::GLuint base_index_of_vertex_internal = base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2378                         glw::GLuint clipdistance_array_index      = base_index_of_vertex_internal;
2379                         glw::GLuint checkpoint_position_index_internal = base_index_of_vertex_internal + clipdistances_array_size +
2380                                                                                                                          culldistances_array_size +
2381                                                                                                                          2 /* ignore vertex coordinates */;
2382                         glw::GLint checkpoint_x_internal =
2383                                 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2384                         glw::GLint checkpoint_y_internal =
2385                                 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2386                         glw::GLfloat* vertex_clipdistance_array  = &m_bo_data[clipdistance_array_index];
2387                         bool              vertex_clipped                         = false;
2388                         glw::GLint      vertex_clipped_by_distance = 0;
2389                         glw::GLint      vertex_color_red_value   = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2390
2391                         /* Check whether pixel should be clipped */
2392                         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
2393                                  n_clipdistance_entry++)
2394                         {
2395                                 if (vertex_clipdistance_array[n_clipdistance_entry] < 0)
2396                                 {
2397                                         vertex_clipped                     = true;
2398                                         vertex_clipped_by_distance = n_clipdistance_entry;
2399
2400                                         break;
2401                                 }
2402                         }
2403
2404                         all_vertices_are_clipped &= vertex_clipped;
2405
2406                         /* Validate whether real data same as expected */
2407                         if (vertex_clipped)
2408                         {
2409                                 if (vertex_color_red_value != 0)
2410                                 {
2411                                         m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] "
2412                                                                            << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") "
2413                                                                            << "should be clipped by distance [" << vertex_clipped_by_distance << "] "
2414                                                                            << "(distance value [" << vertex_clipdistance_array[vertex_clipped_by_distance]
2415                                                                            << "])" << tcu::TestLog::EndMessage;
2416
2417                                         TCU_FAIL("Vertex is expected to be clipped and invisible, while it is visible.");
2418                                 }
2419                                 else
2420                                 {
2421                                         n_clipped_vertices_real++;
2422                                 }
2423                         }
2424                         else
2425                         {
2426                                 if (vertex_color_red_value == 0)
2427                                 {
2428                                         m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] "
2429                                                                            << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") "
2430                                                                            << "should not be clipped." << tcu::TestLog::EndMessage;
2431
2432                                         TCU_FAIL("Vertex is unexpectedly clipped or invisible");
2433                                 }
2434                                 else
2435                                 {
2436                                         n_not_clipped_vertices_real++;
2437                                 }
2438                         }
2439                 }
2440
2441                 if (!all_vertices_are_clipped)
2442                 {
2443                         /* Check fetched values from the shader (Point 2 of Basic Outline : "Use program that...") */
2444                         if (fetch_culldistance_from_fs)
2445                         {
2446                                 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2447                                          n_primitive_vertex++)
2448                                 {
2449                                         /* Get shader output value */
2450                                         glw::GLuint base_index_of_vertex_internal =
2451                                                 base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2452                                         glw::GLuint checkpoint_position_index_internal =
2453                                                 base_index_of_vertex_internal + clipdistances_array_size + culldistances_array_size +
2454                                                 2 /* ignore vertex coordinates */;
2455                                         glw::GLuint culldistances_index = base_index_of_vertex_internal + clipdistances_array_size;
2456                                         glw::GLint  checkpoint_x_internal =
2457                                                 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2458                                         glw::GLint checkpoint_y_internal =
2459                                                 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2460                                         glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2461
2462                                         /* Calculate culldistances check sum hash */
2463                                         float sum = 0.f;
2464
2465                                         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
2466                                                  ++n_clipdistance_entry)
2467                                         {
2468                                                 sum += de::abs(m_bo_data[base_index_of_vertex_internal + n_clipdistance_entry]) *
2469                                                            float(n_clipdistance_entry + 1);
2470                                         }
2471
2472                                         for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
2473                                                  ++n_culldistance_entry)
2474                                         {
2475                                                 sum += de::abs(m_bo_data[culldistances_index + n_culldistance_entry]) *
2476                                                            float(n_culldistance_entry + 1 + clipdistances_array_size);
2477                                         }
2478
2479                                         /* limit sum and return */
2480                                         glw::GLint sum_hash =
2481                                                 glw::GLint(sum / glw::GLfloat((clipdistances_array_size + culldistances_array_size) *
2482                                                                                                           (clipdistances_array_size + culldistances_array_size + 1)) *
2483                                                                    65535.f /* normalizing to short */);
2484                                         sum_hash = (sum_hash < 65536) ? sum_hash : 65535; /* clamping to short */
2485
2486                                         /* Compare against setup value */
2487                                         if (std::abs(vertex_color_red_value - sum_hash) > 4 /* precision 4/65536 */)
2488                                         {
2489                                                 m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] "
2490                                                                                    << "should have culldistance hash sum " << sum_hash
2491                                                                                    << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y
2492                                                                                    << ") has sum hash equal to " << vertex_color_red_value
2493                                                                                    << tcu::TestLog::EndMessage;
2494
2495                                                 TCU_FAIL("Culled distances returned from fragment shader dose not match expected values.");
2496                                         }
2497                                 }
2498                         }
2499                 }
2500         }
2501
2502         /* sub_grid cell size is 3*3 */
2503         DE_ASSERT(m_render_primitives % 9 == 0);
2504
2505         /* Sanity check */
2506         switch (primitive_mode)
2507         {
2508         case PRIMITIVE_MODE_LINES:
2509         case PRIMITIVE_MODE_TRIANGLES:
2510         {
2511                 /* Validate culled primitives */
2512                 if (culldistances_array_size == 0)
2513                 {
2514                         DE_ASSERT(n_culled_primitives_real == 0);
2515                 }
2516                 else
2517                 {
2518                         /* Each 3rd line or triangle should be culled by test design */
2519                         DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives / 3);
2520                 }
2521
2522                 /* Validate clipped vertices */
2523                 if (clipdistances_array_size == 0)
2524                 {
2525                         DE_ASSERT(n_clipped_vertices_real == 0);
2526                 }
2527                 else
2528                 {
2529 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
2530                         glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3;
2531                         glw::GLint n_clipped_vertices_expected          = /* One third of primitives has 0th vertex clipped */
2532                                 one_third_of_rendered_primitives +
2533                                 /* One third of primitives clipped completely     */
2534                                 one_third_of_rendered_primitives * primitive_vertices_count;
2535
2536                         DE_ASSERT(glw::GLint(n_clipped_vertices_real) == n_clipped_vertices_expected);
2537 #endif
2538                 }
2539                 break;
2540         }
2541
2542         case PRIMITIVE_MODE_POINTS:
2543         {
2544                 /* Validate culled primitives */
2545                 if (culldistances_array_size == 0)
2546                 {
2547                         DE_ASSERT(n_culled_primitives_real == 0);
2548                 }
2549                 else
2550                 {
2551                         /* 2/3 points should be culled by test design */
2552                         DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives * 2 / 3);
2553                 }
2554
2555                 /* Validate clipped vertices */
2556                 if (clipdistances_array_size == 0)
2557                 {
2558                         DE_ASSERT(n_clipped_vertices_real == 0);
2559                 }
2560                 else
2561                 {
2562 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
2563                         glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3;
2564
2565                         /* 2/3 of rendered points should be clipped by test design */
2566                         DE_ASSERT(glw::GLint(n_clipped_vertices_real) == 2 * one_third_of_rendered_primitives);
2567 #endif
2568                 }
2569
2570                 break;
2571         }
2572         default:
2573                 TCU_FAIL("Unknown primitive mode");
2574         }
2575 }
2576
2577 /** Executes test iteration.
2578  *
2579  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2580  */
2581 tcu::TestNode::IterateResult CullDistance::FunctionalTest::iterate()
2582 {
2583         /* This test should only be executed if ARB_cull_distance is supported, or if
2584          * we're running a GL4.5 context
2585          */
2586         if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
2587                 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
2588         {
2589                 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
2590         }
2591
2592         const glw::Functions& gl                        = m_context.getRenderContext().getFunctions();
2593         bool                              has_succeeded = true;
2594         bool is_core = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
2595
2596         /* Retrieve important GL constant values */
2597         glw::GLint gl_max_clip_distances_value                                   = 0;
2598         glw::GLint gl_max_combined_clip_and_cull_distances_value = 0;
2599         glw::GLint gl_max_cull_distances_value                                   = 0;
2600
2601         gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value);
2602         gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
2603         gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
2604         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call(s) failed.");
2605
2606         gl.genTextures(1, &m_to_id);
2607         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
2608
2609         gl.bindTexture(GL_TEXTURE_2D, m_to_id);
2610         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
2611
2612         gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
2613                                         GL_R32F, m_to_width, m_to_height);
2614         GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
2615
2616         /* Set up the draw/read FBO */
2617         gl.genFramebuffers(1, &m_fbo_id);
2618         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
2619
2620         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
2621         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
2622
2623         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); /* level */
2624         GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
2625
2626         /* Prepare a buffer object */
2627         gl.genBuffers(1, &m_bo_id);
2628         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2629
2630         /* Prepare a VAO. We will configure separately for each iteration. */
2631         gl.genVertexArrays(1, &m_vao_id);
2632         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2633
2634         /* Iterate over all functional tests */
2635         struct _test_item
2636         {
2637                 bool redeclare_clipdistances_array;
2638                 bool redeclare_culldistances_array;
2639                 bool dynamic_index_writes;
2640                 bool use_passthrough_gs;
2641                 bool use_passthrough_ts;
2642                 bool use_core_functionality;
2643                 bool fetch_culldistances;
2644         } test_items[] = { /* Use the basic outline to test the basic functionality of cull distances. */
2645                                            {
2646                                                    true,        /* redeclare_clipdistances_array */
2647                                                    true,        /* redeclare_culldistances_array */
2648                                                    false,   /* dynamic_index_writes          */
2649                                                    false,   /* use_passthrough_gs            */
2650                                                    false,   /* use_passthrough_ts            */
2651                                                    is_core, /* use_core_functionality        */
2652                                                    false        /* fetch_culldistances           */
2653                                            },
2654                                            /* Use the basic outline but don't redeclare gl_ClipDistance with a size. */
2655                                            {
2656                                                    false,   /* redeclare_clipdistances_array */
2657                                                    true,        /* redeclare_culldistances_array */
2658                                                    false,   /* dynamic_index_writes          */
2659                                                    false,   /* use_passthrough_gs            */
2660                                                    false,   /* use_passthrough_ts            */
2661                                                    is_core, /* use_core_functionality        */
2662                                                    false        /* fetch_culldistances           */
2663                                            },
2664                                            /* Use the basic outline but don't redeclare gl_CullDistance with a size. */
2665                                            {
2666                                                    true,        /* redeclare_clipdistances_array  */
2667                                                    false,   /* redeclare_culldistances_array  */
2668                                                    false,   /* dynamic_index_writes           */
2669                                                    false,   /* use_passthrough_gs             */
2670                                                    false,   /* use_passthrough_ts             */
2671                                                    is_core, /* use_core_functionality         */
2672                                                    false        /* fetch_culldistances            */
2673                                            },
2674                                            /* Use the basic outline but don't redeclare either gl_ClipDistance or
2675                  * gl_CullDistance with a size.
2676                  */
2677                                            {
2678                                                    false,   /* redeclare_clipdistances_array */
2679                                                    false,   /* redeclare_culldistances_array */
2680                                                    false,   /* dynamic_index_writes          */
2681                                                    false,   /* use_passthrough_gs            */
2682                                                    false,   /* use_passthrough_ts            */
2683                                                    is_core, /* use_core_functionality        */
2684                                                    false        /* fetch_culldistances           */
2685                                            },
2686                                            /* Use the basic outline but use dynamic indexing when writing the elements
2687                  * of the gl_ClipDistance and gl_CullDistance arrays.
2688                  */
2689                                            {
2690                                                    true,        /* redeclare_clipdistances_array */
2691                                                    true,        /* redeclare_culldistances_array */
2692                                                    true,        /* dynamic_index_writes          */
2693                                                    false,   /* use_passthrough_gs            */
2694                                                    false,   /* use_passthrough_ts            */
2695                                                    is_core, /* use_core_functionality        */
2696                                                    false        /* fetch_culldistances           */
2697                                            },
2698                                            /* Use the basic outline but add a geometry shader to the program that
2699                  * simply passes through all written clip and cull distances.
2700                  */
2701                                            {
2702                                                    true,        /* redeclare_clipdistances_array */
2703                                                    true,        /* redeclare_culldistances_array */
2704                                                    false,   /* dynamic_index_writes          */
2705                                                    true,        /* use_passthrough_gs            */
2706                                                    false,   /* use_passthrough_ts            */
2707                                                    is_core, /* use_core_functionality        */
2708                                                    false        /* fetch_culldistances           */
2709                                            },
2710                                            /* Use the basic outline but add a tessellation control and tessellation
2711                  * evaluation shader to the program which simply pass through all written
2712                  * clip and cull distances.
2713                  */
2714                                            {
2715                                                    true,        /* redeclare_clipdistances_array */
2716                                                    true,        /* redeclare_culldistances_array */
2717                                                    false,   /* dynamic_index_writes          */
2718                                                    false,   /* use_passthrough_gs            */
2719                                                    true,        /* use_passthrough_ts            */
2720                                                    is_core, /* use_core_functionality        */
2721                                                    false        /* fetch_culldistances           */
2722                                            },
2723                                            /* Test that using #extension with GL_ARB_cull_distance allows using the
2724                  * feature even with an earlier version of GLSL. Also test that the
2725                  * extension name is available as preprocessor #define.
2726                  */
2727                                            {
2728                                                    true,  /* redeclare_clipdistances_array */
2729                                                    true,  /* redeclare_culldistances_array */
2730                                                    false, /* dynamic_index_writes          */
2731                                                    false, /* use_passthrough_gs            */
2732                                                    false, /* use_passthrough_ts            */
2733                                                    false, /* use_core_functionality        */
2734                                                    false  /* fetch_culldistances           */
2735                                            },
2736                                            /* Use a program that has only a vertex shader and a fragment shader.
2737                  * The vertex shader should redeclare gl_ClipDistance with a size that
2738                  * fits all enabled cull distances. Also redeclare gl_CullDistance with a
2739                  * size. The sum of the two sizes should not be more than MAX_COMBINED_-
2740                  * CLIP_AND_CULL_DISTANCES. The fragment shader should output the cull
2741                  * distances written by the vertex shader by reading them from the built-in
2742                  * array gl_CullDistance.
2743                  */
2744                                            {
2745                                                    true,  /* redeclare_clipdistances_array */
2746                                                    true,  /* redeclare_culldistances_array */
2747                                                    false, /* dynamic_index_writes          */
2748                                                    false, /* use_passthrough_gs            */
2749                                                    false, /* use_passthrough_ts            */
2750                                                    false, /* use_core_functionality        */
2751                                                    true   /* fetch_culldistances           */
2752                                            }
2753         };
2754         const glw::GLuint n_test_items = sizeof(test_items) / sizeof(test_items[0]);
2755
2756         gl.viewport(0, 0, m_to_width, m_to_height);
2757         GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
2758
2759         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2760         GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed.");
2761
2762         for (glw::GLuint n_test_item = 0; n_test_item < n_test_items; ++n_test_item)
2763         {
2764                 /* Check for OpenGL feature support */
2765                 if (test_items[n_test_item].use_passthrough_ts)
2766                 {
2767                         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) &&
2768                                 !m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader"))
2769                         {
2770                                 continue; // no tessellation shader support
2771                         }
2772                 }
2773
2774                 const _test_item&        current_test_item                                              = test_items[n_test_item];
2775                 const _primitive_mode primitive_modes[PRIMITIVE_MODE_COUNT] = { PRIMITIVE_MODE_LINES, PRIMITIVE_MODE_POINTS,
2776                                                                                                                                                 PRIMITIVE_MODE_TRIANGLES };
2777
2778                 for (glw::GLuint primitive_mode_index = 0; primitive_mode_index < PRIMITIVE_MODE_COUNT; ++primitive_mode_index)
2779                 {
2780                         _primitive_mode primitive_mode = primitive_modes[primitive_mode_index];
2781
2782                         /* Iterate over a set of gl_ClipDistances[] and gl_CullDistances[] array sizes */
2783                         for (glw::GLint n_iteration = 0; n_iteration <= gl_max_combined_clip_and_cull_distances_value;
2784                                  ++n_iteration)
2785                         {
2786                                 glw::GLuint clipdistances_array_size = 0;
2787                                 glw::GLuint culldistances_array_size = 0;
2788
2789                                 if (n_iteration != 0 && n_iteration <= gl_max_clip_distances_value)
2790                                 {
2791                                         clipdistances_array_size = n_iteration;
2792                                 }
2793
2794                                 if ((gl_max_combined_clip_and_cull_distances_value - n_iteration) < gl_max_cull_distances_value)
2795                                 {
2796                                         culldistances_array_size = gl_max_combined_clip_and_cull_distances_value - n_iteration;
2797                                 }
2798                                 else
2799                                 {
2800                                         culldistances_array_size = gl_max_cull_distances_value;
2801                                 }
2802
2803                                 if (clipdistances_array_size == 0 && culldistances_array_size == 0)
2804                                 {
2805                                         /* Skip the dummy iteration */
2806                                         continue;
2807                                 }
2808
2809                                 if (current_test_item.fetch_culldistances && (primitive_mode != PRIMITIVE_MODE_POINTS))
2810                                 {
2811                                         continue;
2812                                 }
2813
2814                                 /* Create a program to run */
2815                                 buildPO(clipdistances_array_size, culldistances_array_size, current_test_item.dynamic_index_writes,
2816                                                 primitive_mode, current_test_item.redeclare_clipdistances_array,
2817                                                 current_test_item.redeclare_culldistances_array, current_test_item.use_core_functionality,
2818                                                 current_test_item.use_passthrough_gs, current_test_item.use_passthrough_ts,
2819                                                 current_test_item.fetch_culldistances);
2820
2821                                 /* Initialize VAO data */
2822                                 configureVAO(clipdistances_array_size, culldistances_array_size, primitive_mode);
2823
2824                                 /* Run GLSL program and check results */
2825                                 executeRenderTest(clipdistances_array_size, culldistances_array_size, primitive_mode,
2826                                                                   current_test_item.use_passthrough_ts, current_test_item.fetch_culldistances);
2827
2828                         } /* for (all iterations) */
2829                 }        /* for (all test modes) */
2830         }                 /* for (all test items) */
2831
2832         /* All done */
2833         if (has_succeeded)
2834         {
2835                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2836         }
2837         else
2838         {
2839                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2840         }
2841
2842         return STOP;
2843 }
2844
2845 /** Returns pixel red component read from texture at position x, y.
2846  *
2847  *  @param x x-coordinate to read pixel color component from
2848  *  @param y y-coordinate to read pixel color component from
2849  **/
2850 glw::GLint CullDistance::FunctionalTest::readRedPixelValue(glw::GLint x, glw::GLint y)
2851 {
2852         glw::GLint result = -1;
2853
2854         DE_ASSERT(x >= 0 && (glw::GLuint)x < m_to_width);
2855         DE_ASSERT(y >= 0 && (glw::GLuint)y < m_to_height);
2856
2857         result = m_to_pixel_data_cache[(m_to_width * y + x) * m_to_pixel_data_cache_color_components];
2858
2859         return result;
2860 }
2861
2862 /** Reads texture into m_to_pixel_data_cache.
2863  *  Texture size determined by fields m_to_width, m_to_height
2864  **/
2865 void CullDistance::FunctionalTest::readTexturePixels()
2866 {
2867         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2868
2869         m_to_pixel_data_cache.clear();
2870
2871         m_to_pixel_data_cache.resize(m_to_width * m_to_height * m_to_pixel_data_cache_color_components);
2872
2873         /* Read vertex from texture */
2874         gl.readPixels(0,                   /* x      */
2875                                   0,               /* y      */
2876                                   m_to_width,  /* width  */
2877                                   m_to_height, /* height */
2878                                   GL_RGBA, GL_UNSIGNED_SHORT, &m_to_pixel_data_cache[0]);
2879         GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
2880 }
2881
2882 /** Constructor.
2883  *
2884  *  @param context Rendering context handle.
2885  **/
2886 CullDistance::NegativeTest::NegativeTest(deqp::Context& context)
2887         : TestCase(context, "negative", "Cull Distance Negative Test")
2888         , m_fs_id(0)
2889         , m_po_id(0)
2890         , m_temp_buffer(DE_NULL)
2891         , m_vs_id(0)
2892 {
2893         /* Left blank on purpose */
2894 }
2895
2896 /** @brief Cull Distance Negative Test deinitialization */
2897 void CullDistance::NegativeTest::deinit()
2898 {
2899         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2900
2901         if (m_fs_id != 0)
2902         {
2903                 gl.deleteShader(m_fs_id);
2904
2905                 m_fs_id = 0;
2906         }
2907
2908         if (m_po_id != 0)
2909         {
2910                 gl.deleteProgram(m_po_id);
2911
2912                 m_po_id = 0;
2913         }
2914
2915         if (m_vs_id != 0)
2916         {
2917                 gl.deleteShader(m_vs_id);
2918
2919                 m_vs_id = 0;
2920         }
2921
2922         if (m_temp_buffer != DE_NULL)
2923         {
2924                 delete[] m_temp_buffer;
2925
2926                 m_temp_buffer = DE_NULL;
2927         }
2928 }
2929
2930 /** @brief Get string description of test with given parameters
2931  *
2932  *  @param [in] n_test_iteration                    Test iteration number
2933  *  @param [in] should_redeclare_output_variables   Indicate whether test redeclared gl_ClipDistance and gl_CullDistance
2934  *  @param [in] use_dynamic_index_based_writes      Indicate whether test used dynamic index-based setters
2935  *
2936  *  @return String containing description.
2937  */
2938 std::string CullDistance::NegativeTest::getTestDescription(int n_test_iteration, bool should_redeclare_output_variables,
2939                                                                                                                    bool use_dynamic_index_based_writes)
2940 {
2941         std::stringstream stream;
2942
2943         stream << "Test iteration [" << n_test_iteration << "] which uses a vertex shader that:\n\n"
2944                    << ((should_redeclare_output_variables) ?
2945                                    "* redeclares gl_ClipDistance and gl_CullDistance arrays\n" :
2946                                    "* does not redeclare gl_ClipDistance and gl_CullDistance arrays\n")
2947                    << ((use_dynamic_index_based_writes) ? "* uses dynamic index-based writes\n" : "* uses static writes\n");
2948
2949         return stream.str();
2950 }
2951
2952 /** Executes test iteration.
2953  *
2954  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2955  */
2956 tcu::TestNode::IterateResult CullDistance::NegativeTest::iterate()
2957 {
2958         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2959
2960         /* Build the test shaders. */
2961         const glw::GLchar* token_dynamic_index_based_writes = "DYNAMIC_INDEX_BASED_WRITES";
2962         const glw::GLchar* token_insert_static_writes           = "INSERT_STATIC_WRITES";
2963         const glw::GLchar* token_n_gl_clipdistance_entries  = "N_GL_CLIPDISTANCE_ENTRIES";
2964         const glw::GLchar* token_n_gl_culldistance_entries  = "N_GL_CULLDISTANCE_ENTRIES";
2965         const glw::GLchar* token_redeclare_output_variables = "REDECLARE_OUTPUT_VARIABLES";
2966
2967         const glw::GLchar* fs_body = "#version 130\n"
2968                                                                  "\n"
2969                                                                  "void main()\n"
2970                                                                  "{\n"
2971                                                                  "}\n";
2972
2973         const glw::GLchar* vs_body_preamble = "#version 130\n"
2974                                                                                   "\n"
2975                                                                                   "    #extension GL_ARB_cull_distance : require\n"
2976                                                                                   "\n";
2977
2978         const glw::GLchar* vs_body_main = "#ifdef REDECLARE_OUTPUT_VARIABLES\n"
2979                                                                           "    out float gl_ClipDistance[N_GL_CLIPDISTANCE_ENTRIES];\n"
2980                                                                           "    out float gl_CullDistance[N_GL_CULLDISTANCE_ENTRIES];\n"
2981                                                                           "#endif\n"
2982                                                                           "\n"
2983                                                                           "void main()\n"
2984                                                                           "{\n"
2985                                                                           "#ifdef DYNAMIC_INDEX_BASED_WRITES\n"
2986                                                                           "    for (int n_clipdistance_entry = 0;\n"
2987                                                                           "             n_clipdistance_entry < N_GL_CLIPDISTANCE_ENTRIES;\n"
2988                                                                           "           ++n_clipdistance_entry)\n"
2989                                                                           "    {\n"
2990                                                                           "        gl_ClipDistance[n_clipdistance_entry] = float(n_clipdistance_entry) / "
2991                                                                           "float(N_GL_CLIPDISTANCE_ENTRIES);\n"
2992                                                                           "    }\n"
2993                                                                           "\n"
2994                                                                           "    for (int n_culldistance_entry = 0;\n"
2995                                                                           "             n_culldistance_entry < N_GL_CULLDISTANCE_ENTRIES;\n"
2996                                                                           "           ++n_culldistance_entry)\n"
2997                                                                           "    {\n"
2998                                                                           "        gl_CullDistance[n_culldistance_entry] = float(n_culldistance_entry) / "
2999                                                                           "float(N_GL_CULLDISTANCE_ENTRIES);\n"
3000                                                                           "    }\n"
3001                                                                           "#else\n"
3002                                                                           "    INSERT_STATIC_WRITES\n"
3003                                                                           "#endif\n"
3004                                                                           "}\n";
3005
3006         /* This test should only be executed if ARB_cull_distance is supported, or if
3007          * we're running a GL4.5 context
3008          */
3009         if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
3010                 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
3011         {
3012                 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
3013         }
3014
3015         /* It only makes sense to run this test if GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES
3016          * is lower than a sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CLIP_CULL_DISTANCES.
3017          */
3018         glw::GLint  gl_max_clip_distances_value                                   = 0;
3019         glw::GLint  gl_max_combined_clip_and_cull_distances_value = 0;
3020         glw::GLint  gl_max_cull_distances_value                                   = 0;
3021         glw::GLuint n_gl_clipdistance_array_items                                 = 0;
3022         std::string n_gl_clipdistance_array_items_string;
3023         glw::GLuint n_gl_culldistance_array_items = 0;
3024         std::string n_gl_culldistance_array_items_string;
3025         std::string static_write_shader_body_part;
3026
3027         gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value);
3028         gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
3029         gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
3030
3031         if (gl_max_clip_distances_value + gl_max_cull_distances_value < gl_max_combined_clip_and_cull_distances_value)
3032         {
3033                 m_testCtx.getLog() << tcu::TestLog::Message
3034                                                    << "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES is larger than or equal to "
3035                                                           "the sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CULL_DISTANCES. Skipping."
3036                                                    << tcu::TestLog::EndMessage;
3037
3038                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3039
3040                 return STOP;
3041         }
3042
3043         n_gl_clipdistance_array_items = gl_max_clip_distances_value;
3044         n_gl_culldistance_array_items = gl_max_combined_clip_and_cull_distances_value - gl_max_clip_distances_value + 1;
3045
3046         /* Determine the number of items we will want the gl_ClipDistance and gl_CullDistance arrays
3047          * to hold for test iterations that will re-declare the built-in output variables.
3048          */
3049         {
3050                 std::stringstream temp_sstream;
3051
3052                 temp_sstream << n_gl_clipdistance_array_items;
3053
3054                 n_gl_clipdistance_array_items_string = temp_sstream.str();
3055         }
3056
3057         {
3058                 std::stringstream temp_sstream;
3059
3060                 temp_sstream << n_gl_culldistance_array_items;
3061
3062                 n_gl_culldistance_array_items_string = temp_sstream.str();
3063         }
3064
3065         /* Form the "static write" shader body part. */
3066         {
3067                 std::stringstream temp_sstream;
3068
3069                 temp_sstream << "gl_ClipDistance[" << n_gl_clipdistance_array_items_string.c_str() << "] = 0.0f;\n"
3070                                          << "gl_CullDistance[" << n_gl_culldistance_array_items_string.c_str() << "] = 0.0f;\n";
3071
3072                 static_write_shader_body_part = temp_sstream.str();
3073         }
3074
3075         /* Prepare GL objects before we continue */
3076         glw::GLint compile_status = GL_FALSE;
3077
3078         m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3079         m_po_id = gl.createProgram();
3080         m_vs_id = gl.createShader(GL_VERTEX_SHADER);
3081
3082         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() calls failed.");
3083
3084         gl.attachShader(m_po_id, m_fs_id);
3085         gl.attachShader(m_po_id, m_vs_id);
3086
3087         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
3088
3089         gl.shaderSource(m_fs_id, 1,                     /* count */
3090                                         &fs_body, DE_NULL); /* length */
3091         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
3092
3093         gl.compileShader(m_fs_id);
3094         GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
3095
3096         gl.getShaderiv(m_fs_id, GL_COMPILE_STATUS, &compile_status);
3097         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3098
3099         if (compile_status == GL_FALSE)
3100         {
3101                 TCU_FAIL("Fragment shader failed to compile.");
3102         }
3103
3104         /* Run three separate test iterations. */
3105         struct _test_item
3106         {
3107                 bool should_redeclare_output_variables;
3108                 bool use_dynamic_index_based_writes;
3109         } test_items[] = { /* Negative Test 1 */
3110                                            { true, false },
3111
3112                                            /* Negative Test 2 */
3113                                            { false, false },
3114
3115                                            /* Negative Test 3 */
3116                                            { false, true }
3117         };
3118         const unsigned int n_test_items = sizeof(test_items) / sizeof(test_items[0]);
3119
3120         for (unsigned int n_test_item = 0; n_test_item < n_test_items; ++n_test_item)
3121         {
3122                 const _test_item& current_test_item = test_items[n_test_item];
3123
3124                 /* Prepare vertex shader body */
3125                 std::size_t               token_position = std::string::npos;
3126                 std::stringstream vs_body_sstream;
3127                 std::string               vs_body_string;
3128
3129                 vs_body_sstream << vs_body_preamble << "\n";
3130
3131                 if (current_test_item.should_redeclare_output_variables)
3132                 {
3133                         vs_body_sstream << "#define " << token_redeclare_output_variables << "\n";
3134                 }
3135
3136                 if (current_test_item.use_dynamic_index_based_writes)
3137                 {
3138                         vs_body_sstream << "#define " << token_dynamic_index_based_writes << "\n";
3139                 }
3140
3141                 vs_body_sstream << vs_body_main;
3142
3143                 /* Replace tokens with meaningful values */
3144                 vs_body_string = vs_body_sstream.str();
3145
3146                 while ((token_position = vs_body_string.find(token_n_gl_clipdistance_entries)) != std::string::npos)
3147                 {
3148                         vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries),
3149                                                                                                         n_gl_clipdistance_array_items_string);
3150                 }
3151
3152                 while ((token_position = vs_body_string.find(token_n_gl_culldistance_entries)) != std::string::npos)
3153                 {
3154                         vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries),
3155                                                                                                         n_gl_culldistance_array_items_string);
3156                 }
3157
3158                 while ((token_position = vs_body_string.find(token_insert_static_writes)) != std::string::npos)
3159                 {
3160                         vs_body_string = vs_body_string.replace(token_position, strlen(token_insert_static_writes),
3161                                                                                                         static_write_shader_body_part);
3162                 }
3163
3164                 /* Try to compile the vertex shader */
3165                 glw::GLint  compile_status_internal = GL_FALSE;
3166                 const char* vs_body_raw_ptr                     = vs_body_string.c_str();
3167
3168                 gl.shaderSource(m_vs_id, 1,                                     /* count */
3169                                                 &vs_body_raw_ptr, DE_NULL); /* length */
3170                 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
3171
3172                 gl.compileShader(m_vs_id);
3173                 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
3174
3175                 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status_internal);
3176                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3177
3178                 if (compile_status_internal == GL_FALSE)
3179                 {
3180                         glw::GLint buffer_size = 0;
3181
3182                         /* Log the compilation error */
3183                         m_testCtx.getLog() << tcu::TestLog::Message
3184                                                            << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3185                                                                                                          current_test_item.use_dynamic_index_based_writes)
3186                                                            << "has failed (as expected) to compile with the following info log:\n\n"
3187                                                            << tcu::TestLog::EndMessage;
3188
3189                         gl.getShaderiv(m_vs_id, GL_INFO_LOG_LENGTH, &buffer_size);
3190                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3191
3192                         m_temp_buffer = new glw::GLchar[buffer_size + 1];
3193
3194                         memset(m_temp_buffer, 0, buffer_size + 1);
3195
3196                         gl.getShaderInfoLog(m_vs_id, buffer_size, DE_NULL, /* length */
3197                                                                 m_temp_buffer);
3198                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed.");
3199
3200                         m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage;
3201
3202                         delete[] m_temp_buffer;
3203                         m_temp_buffer = DE_NULL;
3204
3205                         /* Move on to the next iteration */
3206                         continue;
3207                 }
3208
3209                 /* Try to link the program object */
3210                 glw::GLint link_status = GL_FALSE;
3211
3212                 gl.linkProgram(m_po_id);
3213                 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
3214
3215                 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
3216                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
3217
3218                 if (link_status == GL_TRUE)
3219                 {
3220                         m_testCtx.getLog() << tcu::TestLog::Message
3221                                                            << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3222                                                                                                          current_test_item.use_dynamic_index_based_writes)
3223                                                            << "has linked successfully which is invalid!" << tcu::TestLog::EndMessage;
3224
3225                         TCU_FAIL("Program object has linked successfully, even though the process should have failed.");
3226                 }
3227                 else
3228                 {
3229                         glw::GLint buffer_size = 0;
3230
3231                         m_testCtx.getLog() << tcu::TestLog::Message
3232                                                            << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3233                                                                                                          current_test_item.use_dynamic_index_based_writes)
3234                                                            << "has failed (as expected) to link with the following info log:\n\n"
3235                                                            << tcu::TestLog::EndMessage;
3236
3237                         gl.getProgramiv(m_po_id, GL_INFO_LOG_LENGTH, &buffer_size);
3238                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
3239
3240                         m_temp_buffer = new glw::GLchar[buffer_size + 1];
3241
3242                         memset(m_temp_buffer, 0, buffer_size + 1);
3243
3244                         gl.getProgramInfoLog(m_po_id, buffer_size, DE_NULL, /* length */
3245                                                                  m_temp_buffer);
3246                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed.");
3247
3248                         m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage;
3249
3250                         delete[] m_temp_buffer;
3251                         m_temp_buffer = DE_NULL;
3252                 }
3253         } /* for (all test items) */
3254
3255         /* All done */
3256         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3257
3258         return STOP;
3259 }
3260
3261 /** Constructor.
3262  *
3263  *  @param context Rendering context.
3264  */
3265 CullDistance::Tests::Tests(deqp::Context& context) : TestCaseGroup(context, "cull_distance", "Cull Distance Test Suite")
3266 {
3267 }
3268
3269 /** Initializes the test group contents. */
3270 void CullDistance::Tests::init()
3271 {
3272         addChild(new CullDistance::APICoverageTest(m_context));
3273         addChild(new CullDistance::FunctionalTest(m_context));
3274         addChild(new CullDistance::NegativeTest(m_context));
3275 }
3276 } /* glcts namespace */