Adjust cull_distance position on pixel center
[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, 1.0);\n"
727                                 "    out_gs      = result_value;\n"
728                                 "    EmitVertex();\n"
729                                 "\n"
730                                 "    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
731                                 "    out_gs      = result_value;\n"
732                                 "    EmitVertex();\n"
733                                 "\n"
734                                 "    gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
735                                 "    out_gs      = result_value;\n"
736                                 "    EmitVertex();\n"
737                                 "\n"
738                                 "    gl_Position = vec4(1.0, -1.0, 0.0, 1.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                                 "    gl_Position = vec4(0.0, 0.0, 0.0, 1.);\n"
787                                 "}\n";
788                         std::string te_body = te_body_template;
789
790                         static const glw::GLchar* vs_body_template = "#version 150\n"
791                                                                                                                  "\n"
792                                                                                                                  "#extension GL_ARB_cull_distance : require\n"
793                                                                                                                  "\n"
794                                                                                                                  "flat out int out_vs;\n"
795                                                                                                                  "\n"
796                                                                                                                  "void main()\n"
797                                                                                                                  "{\n"
798                                                                                                                  "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
799                                                                                                                  "    out_vs      = TOKEN;\n"
800                                                                                                                  "}\n";
801                         std::string vs_body = vs_body_template;
802
803                         const _stage& current_stage = stages[n_stage];
804
805                         /* Build shader bodies */
806                         struct _shader_body
807                         {
808                                 std::string* body_ptr;
809                                 glw::GLenum  gl_type;
810                         } shader_bodies[] = { { &cs_body, GL_COMPUTE_SHADER },             { &fs_body, GL_FRAGMENT_SHADER },
811                                                                   { &gs_body, GL_GEOMETRY_SHADER },                { &tc_body, GL_TESS_CONTROL_SHADER },
812                                                                   { &te_body, GL_TESS_EVALUATION_SHADER }, { &vs_body, GL_VERTEX_SHADER } };
813                         static const glw::GLchar* input_fs_token_string = "INPUT_FS_NAME";
814                         static const glw::GLchar* input_gs_token_string = "INPUT_GS_NAME";
815                         static const glw::GLchar* input_te_token_string = "INPUT_TE_NAME";
816                         static const glw::GLchar* input_tc_token_string = "INPUT_TC_NAME";
817                         static const glw::GLuint  n_shader_bodies               = sizeof(shader_bodies) / sizeof(shader_bodies[0]);
818
819                         std::size_t                               token_position = std::string::npos;
820                         static const glw::GLchar* token_string   = "TOKEN";
821
822                         for (glw::GLuint n_shader_body = 0; n_shader_body < n_shader_bodies; ++n_shader_body)
823                         {
824                                 _shader_body& current_body = shader_bodies[n_shader_body];
825
826                                 /* Is this stage actually used? */
827                                 if (((current_body.gl_type == GL_COMPUTE_SHADER) && (!current_stage.use_cs)) ||
828                                         ((current_body.gl_type == GL_FRAGMENT_SHADER) && (!current_stage.use_fs)) ||
829                                         ((current_body.gl_type == GL_TESS_CONTROL_SHADER) && (!current_stage.use_tc)) ||
830                                         ((current_body.gl_type == GL_TESS_EVALUATION_SHADER) && (!current_stage.use_te)) ||
831                                         ((current_body.gl_type == GL_VERTEX_SHADER) && (!current_stage.use_vs)))
832                                 {
833                                         /* Skip the iteration. */
834                                         continue;
835                                 }
836
837                                 /* Iterate over all token and replace them with stage-specific values */
838                                 struct _token_value_pair
839                                 {
840                                         const glw::GLchar* token;
841                                         const glw::GLchar* value;
842                                 } token_value_pairs[] = {
843                                         /* NOTE: The last entry is filled by the switch() block below */
844                                         { token_string, current_run.essl_token_value },
845                                         { NULL, NULL },
846                                 };
847
848                                 const size_t n_token_value_pairs = sizeof(token_value_pairs) / sizeof(token_value_pairs[0]);
849
850                                 switch (current_body.gl_type)
851                                 {
852                                 case GL_COMPUTE_SHADER:
853                                 case GL_VERTEX_SHADER:
854                                         break;
855
856                                 case GL_FRAGMENT_SHADER:
857                                 {
858                                         token_value_pairs[1].token = input_fs_token_string;
859                                         token_value_pairs[1].value = current_stage.fs_input;
860
861                                         break;
862                                 }
863
864                                 case GL_GEOMETRY_SHADER:
865                                 {
866                                         token_value_pairs[1].token = input_gs_token_string;
867                                         token_value_pairs[1].value = current_stage.gs_input;
868
869                                         break;
870                                 }
871
872                                 case GL_TESS_CONTROL_SHADER:
873                                 {
874                                         token_value_pairs[1].token = input_tc_token_string;
875                                         token_value_pairs[1].value = current_stage.tc_input;
876
877                                         break;
878                                 }
879
880                                 case GL_TESS_EVALUATION_SHADER:
881                                 {
882                                         token_value_pairs[1].token = input_te_token_string;
883                                         token_value_pairs[1].value = current_stage.te_input;
884
885                                         break;
886                                 }
887
888                                 default:
889                                         TCU_FAIL("Unrecognized shader body type");
890                                 }
891
892                                 for (glw::GLuint n_pair = 0; n_pair < n_token_value_pairs; ++n_pair)
893                                 {
894                                         const _token_value_pair& current_pair = token_value_pairs[n_pair];
895
896                                         if (current_pair.token == NULL || current_pair.value == NULL)
897                                         {
898                                                 continue;
899                                         }
900
901                                         while ((token_position = current_body.body_ptr->find(current_pair.token)) != std::string::npos)
902                                         {
903                                                 current_body.body_ptr->replace(token_position, strlen(current_pair.token), current_pair.value);
904                                         }
905                                 } /* for (all token+value pairs) */
906                         }        /* for (all sader bodies) */
907
908                         /* Build the test program */
909                         CullDistance::Utilities::buildProgram(
910                                 gl, m_testCtx, current_stage.use_cs ? cs_body.c_str() : DE_NULL,
911                                 current_stage.use_fs ? fs_body.c_str() : DE_NULL, current_stage.use_gs ? gs_body.c_str() : DE_NULL,
912                                 current_stage.use_tc ? tc_body.c_str() : DE_NULL, current_stage.use_te ? te_body.c_str() : DE_NULL,
913                                 current_stage.use_vs ? vs_body.c_str() : DE_NULL, (current_stage.tf_output_name != NULL) ? 1 : 0,
914                                 (const glw::GLchar**)&current_stage.tf_output_name, &m_po_id);
915
916                         /* Bind the test program */
917                         DE_ASSERT(m_po_id != 0);
918
919                         gl.useProgram(m_po_id);
920                         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
921
922                         /* Execute the draw call. Transform Feed-back should be enabled for all iterations
923                          * par the CS one, since we use a different tool to capture the result data in the
924                          * latter case.
925                          */
926                         if (!current_stage.use_cs)
927                         {
928                                 gl.beginTransformFeedback(current_stage.tf_mode);
929                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
930
931                                 gl.drawArrays(current_stage.draw_call_mode, 0,   /* first */
932                                                           current_stage.n_draw_call_vertices); /* count */
933                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
934
935                                 gl.endTransformFeedback();
936                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
937                         } /* if (uses_tf) */
938                         else
939                         {
940                                 gl.dispatchCompute(1,  /* num_groups_x */
941                                                                    1,  /* num_groups_y */
942                                                                    1); /* num_groups_z */
943                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() call failed.");
944                         }
945
946                         /* Verify the result values */
947                         if (!current_stage.use_cs)
948                         {
949                                 glw::GLint* result_data_ptr = DE_NULL;
950
951                                 /* Retrieve the data captured by Transform Feedback */
952                                 result_data_ptr = (glw::GLint*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
953                                                                                                                                  sizeof(unsigned int) * 1, GL_MAP_READ_BIT);
954                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
955
956                                 if (*result_data_ptr != current_run.gl_value)
957                                 {
958                                         m_testCtx.getLog() << tcu::TestLog::Message << current_run.name << " value "
959                                                                                                                                                                            "["
960                                                                            << *result_data_ptr << "]"
961                                                                                                                           " does not match the one reported by glGetIntegerv() "
962                                                                                                                           "["
963                                                                            << current_run.gl_value << "]" << tcu::TestLog::EndMessage;
964
965                                         TCU_FAIL("GL constant value does not match the ES SL equivalent");
966                                 }
967
968                                 if (*result_data_ptr < current_run.min_value)
969                                 {
970                                         m_testCtx.getLog() << tcu::TestLog::Message << current_run.name << " value "
971                                                                                                                                                                            "["
972                                                                            << *result_data_ptr << "]"
973                                                                                                                           " does not meet the minimum specification requirements "
974                                                                                                                           "["
975                                                                            << current_run.min_value << "]" << tcu::TestLog::EndMessage;
976
977                                         TCU_FAIL("GL constant value does not meet minimum specification requirements");
978                                 }
979
980                                 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
981                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
982                         }
983
984                         for (glw::GLuint n_stage_internal = 0; n_stage_internal < 2; /* CS, FS write to separate textures */
985                                  ++n_stage_internal)
986                         {
987                                 glw::GLuint to_id = (n_stage_internal == 0) ? m_cs_to_id : m_fbo_draw_to_id;
988
989                                 if (((n_stage_internal == 0) && (!current_stage.use_cs)) ||
990                                         ((n_stage_internal == 1) && (!current_stage.use_fs)))
991                                 {
992                                         /* Skip the iteration */
993                                         continue;
994                                 }
995
996                                 /* Check the image data the test CS / FS should have written */
997                                 glw::GLint result_value = 0;
998
999                                 gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, to_id, 0); /* level */
1000                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
1001
1002                                 /* NOTE: We're using our custom read framebuffer here, so we'll be reading
1003                                  *       from the texture, that the writes have been issued to earlier. */
1004                                 gl.finish();
1005                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() call failed.");
1006
1007                                 gl.readPixels(0, /* x */
1008                                                           0, /* y */
1009                                                           1, /* width */
1010                                                           1, /* height */
1011                                                           GL_RED_INTEGER, GL_INT, &result_value);
1012                                 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
1013
1014                                 if (result_value != current_run.gl_value)
1015                                 {
1016                                         m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
1017                                                                            << " value accessible to the compute / fragment shader "
1018                                                                                   "["
1019                                                                            << result_value << "]"
1020                                                                                                                   " does not match the one reported by glGetIntegerv() "
1021                                                                                                                   "["
1022                                                                            << current_run.gl_value << "]" << tcu::TestLog::EndMessage;
1023
1024                                         TCU_FAIL("GL constant value does not match the ES SL equivalent");
1025                                 }
1026
1027                                 if (result_value < current_run.min_value)
1028                                 {
1029                                         m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
1030                                                                            << " value accessible to the compute / fragment shader "
1031                                                                                   "["
1032                                                                            << result_value << "]"
1033                                                                                                                   " does not meet the minimum specification requirements "
1034                                                                                                                   "["
1035                                                                            << current_run.min_value << "]" << tcu::TestLog::EndMessage;
1036
1037                                         TCU_FAIL("GL constant value does not meet minimum specification requirements");
1038                                 }
1039                         }
1040
1041                         /* Clear the data buffer before we continue */
1042                         static const glw::GLubyte bo_clear_data[bo_size] = { 0 };
1043
1044                         gl.bufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
1045                                                          bo_size, bo_clear_data);
1046                         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
1047
1048                         /* Clear the texture mip-map before we continue */
1049                         glw::GLint clear_values[4] = { 0, 0, 0, 0 };
1050
1051                         gl.clearBufferiv(GL_COLOR, 0, /* drawbuffer */
1052                                                          clear_values);
1053                         GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferiv() call failed.");
1054
1055                         /* Release program before we move on to the next iteration */
1056                         if (m_po_id != 0)
1057                         {
1058                                 gl.deleteProgram(m_po_id);
1059
1060                                 m_po_id = 0;
1061                         }
1062                 } /* for (all stages) */
1063         }        /* for (both runs) */
1064
1065         /* All done */
1066         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1067
1068         return STOP;
1069 }
1070
1071 /** Constructor.
1072  *
1073  *  @param context Rendering context handle.
1074  **/
1075 CullDistance::FunctionalTest::FunctionalTest(deqp::Context& context)
1076         : TestCase(context, "functional", "Cull Distance Functional Test")
1077         , m_bo_data()
1078         , m_bo_id(0)
1079         , m_fbo_id(0)
1080         , m_po_id(0)
1081         , m_render_primitives(0)
1082         , m_render_vertices(0)
1083         , m_sub_grid_cell_size(0)
1084         , m_to_id(0)
1085         , m_vao_id(0)
1086         , m_to_height(512)
1087         , m_to_width(512)
1088         , m_to_pixel_data_cache()
1089 {
1090         /* Left blank on purpose */
1091 }
1092
1093 /** @brief Build OpenGL program for functional tests
1094  *
1095  *  @param [in]  clipdistances_array_size   use size of gl_ClipDistance array
1096  *  @param [in]  culldistances_array_size   use size of gl_CullDistance array
1097  *  @param [in]  dynamic_index_writes       use dunamic indexing for setting  the gl_ClipDistance and gl_CullDistance arrays
1098  *  @param [in]  primitive_mode             primitive_mode will be used for rendering
1099  *  @param [in]  redeclare_clipdistances    redeclare gl_ClipDistance
1100  *  @param [in]  redeclare_culldistances    redeclare gl_CullDistance
1101  *  @param [in]  use_core_functionality     use core OpenGL functionality
1102  *  @param [in]  use_gs                     use geometry shader
1103  *  @param [in]  use_ts                     use tessellation shader
1104  *  @param [in]  fetch_culldistance_from_fs fetch check sum of gl_ClipDistance and gl_CullDistance from fragment shader
1105  */
1106 void CullDistance::FunctionalTest::buildPO(glw::GLuint clipdistances_array_size, glw::GLuint culldistances_array_size,
1107                                                                                    bool dynamic_index_writes, _primitive_mode primitive_mode,
1108                                                                                    bool redeclare_clipdistances, bool redeclare_culldistances,
1109                                                                                    bool use_core_functionality, bool use_gs, bool use_ts,
1110                                                                                    bool fetch_culldistance_from_fs)
1111 {
1112         deinitPO();
1113
1114         /* Form the vertex shader */
1115         glw::GLuint clipdistances_input_size =
1116                 clipdistances_array_size > 0 ? clipdistances_array_size : 1; /* Avoid zero-sized array compilation error */
1117         glw::GLuint culldistances_input_size =
1118                 culldistances_array_size > 0 ? culldistances_array_size : 1; /* Avoid zero-sized array compilation error */
1119         static const glw::GLchar* dynamic_array_setters =
1120                 "\n"
1121                 "#if TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES\n"
1122                 "        for (int n_clipdistance_entry = 0;\n"
1123                 "                 n_clipdistance_entry < TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES;\n"
1124                 "               ++n_clipdistance_entry)\n"
1125                 "        {\n"
1126                 "            ASSIGN_CLIP_DISTANCE(n_clipdistance_entry);\n"
1127                 "        }\n"
1128                 "#endif"
1129                 "\n"
1130                 "#if TEMPLATE_N_GL_CULLDISTANCE_ENTRIES \n"
1131                 "        for (int n_culldistance_entry = 0;\n"
1132                 "                 n_culldistance_entry < TEMPLATE_N_GL_CULLDISTANCE_ENTRIES;\n"
1133                 "               ++n_culldistance_entry)\n"
1134                 "        {\n"
1135                 "            ASSIGN_CULL_DISTANCE(n_culldistance_entry);\n"
1136                 "        }\n"
1137                 "#endif\n";
1138
1139         static const glw::GLchar* core_functionality = "#version 450\n";
1140
1141         static const glw::GLchar* extention_functionality = "#version 440\n"
1142                                                                                                                 "\n"
1143                                                                                                                 "#extension GL_ARB_cull_distance : require\n"
1144                                                                                                                 "\n"
1145                                                                                                                 "#ifndef GL_ARB_cull_distance\n"
1146                                                                                                                 "    #error GL_ARB_cull_distance is undefined\n"
1147                                                                                                                 "#endif\n";
1148
1149         static const glw::GLchar* fetch_function = "highp float fetch()\n"
1150                                                                                            "{\n"
1151                                                                                            "    highp float sum = 0.0;\n"
1152                                                                                            "\n"
1153                                                                                            "TEMPLATE_SUM_SETTER"
1154                                                                                            "\n"
1155                                                                                            "    return sum / TEMPLATE_SUM_DIVIDER;\n"
1156                                                                                            "}\n"
1157                                                                                            "\n"
1158                                                                                            "#define ASSIGN_RETURN_VALUE fetch()";
1159
1160         static const glw::GLchar* fs_template = "TEMPLATE_HEADER_DECLARATION\n"
1161                                                                                         "\n"
1162                                                                                         "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1163                                                                                         "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1164                                                                                         "\n"
1165                                                                                         "TEMPLATE_ASSIGN_RETURN_VALUE\n"
1166                                                                                         "\n"
1167                                                                                         "out vec4 out_fs;\n"
1168                                                                                         "\n"
1169                                                                                         "/* Fragment shader main function */\n"
1170                                                                                         "void main()\n"
1171                                                                                         "{\n"
1172                                                                                         "    out_fs = vec4(ASSIGN_RETURN_VALUE, 1.0, 1.0, 1.0);\n"
1173                                                                                         "}\n";
1174
1175         static const glw::GLchar* gs_template = "TEMPLATE_HEADER_DECLARATION\n"
1176                                                                                         "\n"
1177                                                                                         "TEMPLATE_LAYOUT_IN\n"
1178                                                                                         "TEMPLATE_LAYOUT_OUT\n"
1179                                                                                         "\n"
1180                                                                                         "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1181                                                                                         "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1182                                                                                         "\n"
1183                                                                                         "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1184                                                                                         "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1185                                                                                         "\n"
1186                                                                                         "/* Geometry shader (passthrough) main function */\n"
1187                                                                                         "void main()\n"
1188                                                                                         "{\n"
1189                                                                                         "    for (int n_vertex_index = 0;\n"
1190                                                                                         "             n_vertex_index < gl_in.length();\n"
1191                                                                                         "             n_vertex_index ++)\n"
1192                                                                                         "    {\n"
1193                                                                                         "        gl_Position = gl_in[n_vertex_index].gl_Position;\n"
1194                                                                                         "\n"
1195                                                                                         "        TEMPLATE_ARRAY_SETTERS\n"
1196                                                                                         "\n"
1197                                                                                         "        EmitVertex();\n"
1198                                                                                         "    }\n"
1199                                                                                         "\n"
1200                                                                                         "    EndPrimitive();\n"
1201                                                                                         "}\n";
1202
1203         static const glw::GLchar* tc_template =
1204                 "TEMPLATE_HEADER_DECLARATION\n"
1205                 "\n"
1206                 "TEMPLATE_LAYOUT_OUT\n"
1207                 "\n"
1208                 "out gl_PerVertex {\n"
1209                 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1210                 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1211                 "vec4 gl_Position;\n"
1212                 "} gl_out[];\n"
1213                 "\n"
1214                 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1215                 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1216                 "\n"
1217                 "/* Tesselation control shader main function */\n"
1218                 "void main()\n"
1219                 "{\n"
1220                 "    gl_TessLevelInner[0] = 1.0;\n"
1221                 "    gl_TessLevelInner[1] = 1.0;\n"
1222                 "    gl_TessLevelOuter[0] = 1.0;\n"
1223                 "    gl_TessLevelOuter[1] = 1.0;\n"
1224                 "    gl_TessLevelOuter[2] = 1.0;\n"
1225                 "    gl_TessLevelOuter[3] = 1.0;\n"
1226                 "    /* Clipdistance and culldistance array setters */\n"
1227                 "    {\n"
1228                 "        TEMPLATE_ARRAY_SETTERS\n"
1229                 "    }\n"
1230                 "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1231                 "}\n";
1232
1233         static const glw::GLchar* te_template = "TEMPLATE_HEADER_DECLARATION\n"
1234                                                                                         "\n"
1235                                                                                         "TEMPLATE_LAYOUT_IN\n"
1236                                                                                         "\n"
1237                                                                                         "in gl_PerVertex {\n"
1238                                                                                         "TEMPLATE_REDECLARE_IN_CLIPDISTANCE\n"
1239                                                                                         "TEMPLATE_REDECLARE_IN_CULLDISTANCE\n"
1240                                                                                         "vec4 gl_Position;\n"
1241                                                                                         "} gl_in[];\n"
1242                                                                                         "\n"
1243                                                                                         "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1244                                                                                         "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1245                                                                                         "\n"
1246                                                                                         "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1247                                                                                         "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1248                                                                                         "\n"
1249                                                                                         "/* Tesselation evaluation shader main function */\n"
1250                                                                                         "void main()\n"
1251                                                                                         "{\n"
1252                                                                                         "    /* Clipdistance and culldistance array setters */\n"
1253                                                                                         "    {\n"
1254                                                                                         "        TEMPLATE_ARRAY_SETTERS\n"
1255                                                                                         "    }\n"
1256                                                                                         "    gl_Position = TEMPLATE_OUT_FORMULA;\n"
1257                                                                                         "}\n";
1258
1259         static const glw::GLchar* vs_template =
1260                 "TEMPLATE_HEADER_DECLARATION\n"
1261                 "\n"
1262                 "in float clipdistance_data[TEMPLATE_CLIPDISTANCE_INPUT_SIZE];\n"
1263                 "in float culldistance_data[TEMPLATE_CULLDISTANCE_INPUT_SIZE];\n"
1264                 "in vec2  position;\n"
1265                 "\n"
1266                 "TEMPLATE_REDECLARE_CLIPDISTANCE\n"
1267                 "TEMPLATE_REDECLARE_CULLDISTANCE\n"
1268                 "\n"
1269                 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
1270                 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
1271                 "\n"
1272                 "/* Vertex shader main function */\n"
1273                 "void main()\n"
1274                 "{\n"
1275                 "    /* Clipdistance and culldistance array setters */\n"
1276                 "    {\n"
1277                 "        TEMPLATE_ARRAY_SETTERS\n"
1278                 "    }\n"
1279                 "    gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, 0.0, 1.0);\n"
1280                 "}\n";
1281
1282         std::string* shader_body_string_fs       = DE_NULL;
1283         std::string* shader_body_string_gs       = DE_NULL;
1284         std::string* shader_body_string_tc       = DE_NULL;
1285         std::string* shader_body_string_te       = DE_NULL;
1286         std::string* shader_body_string_vs       = DE_NULL;
1287         std::string  shader_header_declaration = use_core_functionality ? core_functionality : extention_functionality;
1288
1289         struct _shaders_configuration
1290         {
1291                 glw::GLenum                type;
1292                 const glw::GLchar* shader_template;
1293                 std::string                body;
1294                 const bool                 use;
1295         } shaders_configuration[] = { {
1296                                                                           GL_FRAGMENT_SHADER, fs_template, std::string(), true,
1297                                                                   },
1298                                                                   {
1299                                                                           GL_GEOMETRY_SHADER, gs_template, std::string(), use_gs,
1300                                                                   },
1301                                                                   {
1302                                                                           GL_TESS_CONTROL_SHADER, tc_template, std::string(), use_ts,
1303                                                                   },
1304                                                                   {
1305                                                                           GL_TESS_EVALUATION_SHADER, te_template, std::string(), use_ts,
1306                                                                   },
1307                                                                   {
1308                                                                           GL_VERTEX_SHADER, vs_template, std::string(), true,
1309                                                                   } };
1310
1311         const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]);
1312
1313         /* Construct shader bodies out of templates */
1314         for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
1315         {
1316                 if (shaders_configuration[n_shader_index].use)
1317                 {
1318                         std::string  array_setters;
1319                         std::string  clipdistance_array_declaration;
1320                         std::string  culldistance_array_declaration;
1321                         std::string  clipdistance_in_array_declaration;
1322                         std::string  culldistance_in_array_declaration;
1323                         std::string& shader_source = shaders_configuration[n_shader_index].body;
1324
1325                         /* Copy template into shader body source */
1326                         shader_source = shaders_configuration[n_shader_index].shader_template;
1327
1328                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_HEADER_DECLARATION"),
1329                                                                                                 shader_header_declaration);
1330
1331                         /* Shader-specific actions */
1332                         switch (shaders_configuration[n_shader_index].type)
1333                         {
1334                         case GL_FRAGMENT_SHADER:
1335                         {
1336                                 shader_body_string_fs = &shaders_configuration[n_shader_index].body;
1337
1338                                 if (fetch_culldistance_from_fs)
1339                                 {
1340                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"),
1341                                                                                                                 std::string(fetch_function));
1342
1343                                         std::string fetch_sum_setters = "";
1344                                         for (glw::GLuint i = 0; i < clipdistances_array_size; ++i)
1345                                         {
1346                                                 fetch_sum_setters.append("    sum += abs(gl_ClipDistance[");
1347                                                 fetch_sum_setters.append(CullDistance::Utilities::intToString(i));
1348                                                 fetch_sum_setters.append("]) * ");
1349                                                 fetch_sum_setters.append(CullDistance::Utilities::intToString(i + 1));
1350                                                 fetch_sum_setters.append(".0;\n");
1351                                         }
1352
1353                                         fetch_sum_setters.append("\n");
1354
1355                                         for (glw::GLuint i = 0; i < culldistances_array_size; ++i)
1356                                         {
1357                                                 fetch_sum_setters.append("    sum += abs(gl_CullDistance[");
1358                                                 fetch_sum_setters.append(CullDistance::Utilities::intToString(i));
1359                                                 fetch_sum_setters.append("]) * ");
1360                                                 fetch_sum_setters.append(
1361                                                         CullDistance::Utilities::intToString(i + 1 + clipdistances_array_size));
1362                                                 fetch_sum_setters.append(".0;\n");
1363                                         }
1364
1365                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_SUM_SETTER"),
1366                                                                                                                 std::string(fetch_sum_setters));
1367                                         CullDistance::Utilities::replaceAll(
1368                                                 shader_source, std::string("TEMPLATE_SUM_DIVIDER"),
1369                                                 std::string(CullDistance::Utilities::intToString(
1370                                                                                 (clipdistances_array_size + culldistances_array_size) *
1371                                                                                 ((clipdistances_array_size + culldistances_array_size + 1))))
1372                                                         .append(".0"));
1373                                 }
1374                                 else
1375                                 {
1376                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"),
1377                                                                                                                 std::string("#define ASSIGN_RETURN_VALUE 1.0"));
1378                                 }
1379
1380                                 break;
1381                         }
1382
1383                         case GL_GEOMETRY_SHADER:
1384                         {
1385                                 shader_body_string_gs = &shaders_configuration[n_shader_index].body;
1386
1387                                 CullDistance::Utilities::replaceAll(
1388                                         shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1389                                         std::string("gl_ClipDistance[IDX] = gl_in[n_vertex_index].gl_ClipDistance[IDX]"));
1390                                 CullDistance::Utilities::replaceAll(
1391                                         shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1392                                         std::string("gl_CullDistance[IDX] = gl_in[n_vertex_index].gl_CullDistance[IDX]"));
1393
1394                                 switch (primitive_mode)
1395                                 {
1396                                 case PRIMITIVE_MODE_LINES:
1397                                 {
1398                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1399                                                                                                                 std::string("layout(lines)                        in;"));
1400                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1401                                                                                                                 std::string("layout(line_strip, max_vertices = 2) out;"));
1402
1403                                         break;
1404                                 }
1405                                 case PRIMITIVE_MODE_POINTS:
1406                                 {
1407                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1408                                                                                                                 std::string("layout(points)                   in;"));
1409                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1410                                                                                                                 std::string("layout(points, max_vertices = 1) out;"));
1411
1412                                         break;
1413                                 }
1414                                 case PRIMITIVE_MODE_TRIANGLES:
1415                                 {
1416                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1417                                                                                                                 std::string("layout(triangles)                        in;"));
1418                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1419                                                                                                                 std::string("layout(triangle_strip, max_vertices = 3) out;"));
1420
1421                                         break;
1422                                 }
1423                                 default:
1424                                         TCU_FAIL("Unknown primitive mode");
1425                                 }
1426
1427                                 break;
1428                         }
1429
1430                         case GL_TESS_CONTROL_SHADER:
1431                         {
1432                                 shader_body_string_tc = &shaders_configuration[n_shader_index].body;
1433
1434                                 CullDistance::Utilities::replaceAll(
1435                                         shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1436                                         std::string(
1437                                                 "gl_out[gl_InvocationID].gl_ClipDistance[IDX] = gl_in[gl_InvocationID].gl_ClipDistance[IDX]"));
1438                                 CullDistance::Utilities::replaceAll(
1439                                         shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1440                                         std::string(
1441                                                 "gl_out[gl_InvocationID].gl_CullDistance[IDX] = gl_in[gl_InvocationID].gl_CullDistance[IDX]"));
1442
1443                                 switch (primitive_mode)
1444                                 {
1445                                 case PRIMITIVE_MODE_LINES:
1446                                 {
1447                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1448                                                                                                                 std::string("layout(vertices = 2) out;"));
1449
1450                                         break;
1451                                 }
1452                                 case PRIMITIVE_MODE_POINTS:
1453                                 {
1454                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1455                                                                                                                 std::string("layout(vertices = 1) out;"));
1456
1457                                         break;
1458                                 }
1459                                 case PRIMITIVE_MODE_TRIANGLES:
1460                                 {
1461                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
1462                                                                                                                 std::string("layout(vertices = 3) out;"));
1463
1464                                         break;
1465                                 }
1466                                 default:
1467                                         TCU_FAIL("Unknown primitive mode");
1468                                 }
1469
1470                                 break;
1471                         }
1472
1473                         case GL_TESS_EVALUATION_SHADER:
1474                         {
1475                                 shader_body_string_te = &shaders_configuration[n_shader_index].body;
1476
1477                                 switch (primitive_mode)
1478                                 {
1479                                 case PRIMITIVE_MODE_LINES:
1480                                 {
1481                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1482                                                                                                                 std::string("layout(isolines) in;"));
1483                                         CullDistance::Utilities::replaceAll(
1484                                                 shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1485                                                 std::string("mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x)"));
1486                                         CullDistance::Utilities::replaceAll(
1487                                                 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1488                                                 std::string("gl_ClipDistance[IDX] = mix(gl_in[0].gl_ClipDistance[IDX], "
1489                                                                         "gl_in[1].gl_ClipDistance[IDX], gl_TessCoord.x)"));
1490                                         CullDistance::Utilities::replaceAll(
1491                                                 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1492                                                 std::string("gl_CullDistance[IDX] = mix(gl_in[0].gl_CullDistance[IDX], "
1493                                                                         "gl_in[1].gl_CullDistance[IDX], gl_TessCoord.x)"));
1494
1495                                         break;
1496                                 }
1497                                 case PRIMITIVE_MODE_POINTS:
1498                                 {
1499                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1500                                                                                                                 std::string("layout(isolines, point_mode) in;"));
1501                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1502                                                                                                                 std::string("gl_in[0].gl_Position"));
1503                                         CullDistance::Utilities::replaceAll(
1504                                                 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1505                                                 std::string("gl_ClipDistance[IDX] = gl_in[0].gl_ClipDistance[IDX]"));
1506                                         CullDistance::Utilities::replaceAll(
1507                                                 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1508                                                 std::string("gl_CullDistance[IDX] = gl_in[0].gl_CullDistance[IDX]"));
1509
1510                                         break;
1511                                 }
1512                                 case PRIMITIVE_MODE_TRIANGLES:
1513                                 {
1514                                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
1515                                                                                                                 std::string("layout(triangles) in;"));
1516                                         CullDistance::Utilities::replaceAll(
1517                                                 shader_source, std::string("TEMPLATE_OUT_FORMULA"),
1518                                                 std::string("vec4(mat3(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, "
1519                                                                         "gl_in[2].gl_Position.xyz) * gl_TessCoord, 1.0)"));
1520                                         CullDistance::Utilities::replaceAll(
1521                                                 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1522                                                 std::string("gl_ClipDistance[IDX] = dot(vec3(gl_in[0].gl_ClipDistance[IDX], "
1523                                                                         "gl_in[1].gl_ClipDistance[IDX], gl_in[2].gl_ClipDistance[IDX]), gl_TessCoord)"));
1524                                         CullDistance::Utilities::replaceAll(
1525                                                 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1526                                                 std::string("gl_CullDistance[IDX] = dot(vec3(gl_in[0].gl_CullDistance[IDX], "
1527                                                                         "gl_in[1].gl_CullDistance[IDX], gl_in[2].gl_CullDistance[IDX]), gl_TessCoord)"));
1528
1529                                         break;
1530                                 }
1531                                 default:
1532                                         TCU_FAIL("Unknown primitive mode");
1533                                 }
1534
1535                                 break;
1536                         }
1537
1538                         case GL_VERTEX_SHADER:
1539                         {
1540                                 shader_body_string_vs = &shaders_configuration[n_shader_index].body;
1541
1542                                 /* Specify input data size for clipdistances data */
1543                                 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CLIPDISTANCE_INPUT_SIZE"),
1544                                                                                                         CullDistance::Utilities::intToString(clipdistances_input_size));
1545
1546                                 /* Specify input data size for culldistances data */
1547                                 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CULLDISTANCE_INPUT_SIZE"),
1548                                                                                                         CullDistance::Utilities::intToString(culldistances_input_size));
1549
1550                                 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
1551                                                                                                         std::string("gl_ClipDistance[IDX] = clipdistance_data[IDX]"));
1552                                 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
1553                                                                                                         std::string("gl_CullDistance[IDX] = culldistance_data[IDX]"));
1554
1555                                 break;
1556                         }
1557
1558                         default:
1559                                 TCU_FAIL("Unknown shader type");
1560                         }
1561
1562                         /* Adjust clipdistances declaration */
1563                         if (redeclare_clipdistances && clipdistances_array_size > 0)
1564                         {
1565                                 if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER)
1566                                 {
1567                                         if (fetch_culldistance_from_fs)
1568                                         {
1569                                                 clipdistance_array_declaration =
1570                                                         std::string("in float gl_ClipDistance[") +
1571                                                         CullDistance::Utilities::intToString(clipdistances_array_size) + std::string("];");
1572                                         }
1573                                 }
1574                                 else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER)
1575                                 {
1576                                         clipdistance_array_declaration = std::string("float gl_ClipDistance[") +
1577                                                                                                          CullDistance::Utilities::intToString(clipdistances_array_size) +
1578                                                                                                          std::string("];");
1579                                 }
1580                                 else
1581                                 {
1582                                         clipdistance_array_declaration = std::string("out float gl_ClipDistance[") +
1583                                                                                                          CullDistance::Utilities::intToString(clipdistances_array_size) +
1584                                                                                                          std::string("];");
1585                                         clipdistance_in_array_declaration = std::string("in float gl_ClipDistance[") +
1586                                                                                                                 CullDistance::Utilities::intToString(clipdistances_array_size) +
1587                                                                                                                 std::string("];");
1588                                 }
1589                         }
1590                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CLIPDISTANCE"),
1591                                                                                                 clipdistance_array_declaration);
1592                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CLIPDISTANCE"),
1593                                                                                                 clipdistance_in_array_declaration);
1594
1595                         /* Adjust culldistances declaration */
1596                         if (redeclare_culldistances && culldistances_array_size > 0)
1597                         {
1598                                 if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER)
1599                                 {
1600                                         if (fetch_culldistance_from_fs)
1601                                         {
1602                                                 culldistance_array_declaration =
1603                                                         std::string("in float gl_CullDistance[") +
1604                                                         CullDistance::Utilities::intToString(culldistances_array_size) + std::string("];");
1605                                         }
1606                                 }
1607                                 else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER)
1608                                 {
1609                                         culldistance_array_declaration = std::string("float gl_CullDistance[") +
1610                                                                                                          CullDistance::Utilities::intToString(culldistances_array_size) +
1611                                                                                                          std::string("];");
1612                                 }
1613                                 else
1614                                 {
1615                                         culldistance_array_declaration = std::string("out float gl_CullDistance[") +
1616                                                                                                          CullDistance::Utilities::intToString(culldistances_array_size) +
1617                                                                                                          std::string("];");
1618                                         culldistance_in_array_declaration = std::string("in float gl_CullDistance[") +
1619                                                                                                                 CullDistance::Utilities::intToString(culldistances_array_size) +
1620                                                                                                                 std::string("];");
1621                                 }
1622                         }
1623                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CULLDISTANCE"),
1624                                                                                                 culldistance_array_declaration);
1625                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CULLDISTANCE"),
1626                                                                                                 culldistance_in_array_declaration);
1627
1628                         /* Adjust clip/cull distances setters */
1629                         if (dynamic_index_writes)
1630                         {
1631                                 array_setters = dynamic_array_setters;
1632
1633                                 CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES"),
1634                                                                                                         CullDistance::Utilities::intToString(clipdistances_array_size));
1635                                 CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CULLDISTANCE_ENTRIES"),
1636                                                                                                         CullDistance::Utilities::intToString(culldistances_array_size));
1637                         }
1638                         else
1639                         {
1640                                 std::stringstream static_array_setters_sstream;
1641
1642                                 static_array_setters_sstream << "\n";
1643
1644                                 for (glw::GLuint clipdistances_array_entry = 0; clipdistances_array_entry < clipdistances_array_size;
1645                                          ++clipdistances_array_entry)
1646                                 {
1647                                         static_array_setters_sstream << "        ASSIGN_CLIP_DISTANCE(" << clipdistances_array_entry
1648                                                                                                  << ");\n";
1649                                 }
1650
1651                                 static_array_setters_sstream << "\n";
1652
1653                                 for (glw::GLuint culldistances_array_entry = 0; culldistances_array_entry < culldistances_array_size;
1654                                          ++culldistances_array_entry)
1655                                 {
1656                                         static_array_setters_sstream << "        ASSIGN_CULL_DISTANCE(" << culldistances_array_entry
1657                                                                                                  << ");\n";
1658                                 }
1659
1660                                 array_setters = static_array_setters_sstream.str();
1661                         }
1662
1663                         CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ARRAY_SETTERS"), array_setters);
1664                 }
1665         }
1666
1667         /* Build the geometry shader */
1668         CullDistance::Utilities::buildProgram(
1669                 m_context.getRenderContext().getFunctions(), m_testCtx, DE_NULL, /* Compute shader                    */
1670                 shader_body_string_fs != DE_NULL ? shader_body_string_fs->c_str() :
1671                                                                                    DE_NULL, /* Fragment shader                   */
1672                 shader_body_string_gs != DE_NULL ? shader_body_string_gs->c_str() :
1673                                                                                    DE_NULL, /* Geometry shader                   */
1674                 shader_body_string_tc != DE_NULL ? shader_body_string_tc->c_str() :
1675                                                                                    DE_NULL, /* Tesselation control shader        */
1676                 shader_body_string_te != DE_NULL ? shader_body_string_te->c_str() :
1677                                                                                    DE_NULL, /* Tesselation evaluation shader     */
1678                 shader_body_string_vs != DE_NULL ? shader_body_string_vs->c_str() :
1679                                                                                    DE_NULL, /* Vertex shader                     */
1680                 0,                                                                                      /* Transform feedback varyings count */
1681                 DE_NULL,                                                                        /* Transform feedback varyings       */
1682                 &m_po_id                                                                        /* Program object id                 */
1683                 );
1684 }
1685
1686 /** Generates primitive data required to test a case with specified
1687  *  gl_ClipDistance and glCullDistance array sizes for specified
1688  *  primitive mode. Generated primitive data is stored in m_bo_data
1689  *  as well uploaded into buffer specified in m_bo_id buffer.
1690  *  Also the procedure binds vertex attribute locations to
1691  *  program object m_po_id.
1692  *
1693  *  @param clipdistances_array_size gl_ClipDistance array size. Can be 0.
1694  *  @param culldistances_array_size gl_CullDistance array size. Can be 0.
1695  *  @param _primitive_mode          Primitives to be generated. Can be:
1696  *                                  PRIMITIVE_MODE_POINTS,
1697  *                                  PRIMITIVE_MODE_LINES,
1698  *                                  PRIMITIVE_MODE_TRIANGLES.
1699  */
1700 void CullDistance::FunctionalTest::configureVAO(glw::GLuint clipdistances_array_size,
1701                                                                                                 glw::GLuint culldistances_array_size, _primitive_mode primitive_mode)
1702 {
1703         /* Detailed test description.
1704          *
1705          * configureVAO() generates primitives layouted in grid. Primitve
1706          * consists of up to 3 vertices and each vertex is accompanied by:
1707          * - array of clipdistances (clipdistances_array_size floats);
1708          * - array of culldistances (culldistances_array_size floats);
1709          * - rendering position coordinates (x and y);
1710          * - check position coordinates (x and y).
1711          *
1712          * The grid has following layout:
1713          *
1714          *     Grid                       |         gl_CullDistance[x]         |
1715          *                                |  0 .. culldistances_array_size - 1 |
1716          *                                |  0th  |  1st  |  2nd  | .......... |
1717          *     ---------------------------+-------+-------+-------+------------+
1718          *     0th  gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
1719          *     1st  gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
1720          *     ...                        |  ...  |  ...  |  ...  | .......... |
1721          *     y-th gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
1722          *     ...                        |  ...  |  ...  |  ...  | .......... |
1723          *     clipdistances_array_size-1 |Subgrid|Subgrid|Subgrid| .......... |
1724          *
1725          * Each grid cell contains subgrid of 3*3 items in size with following
1726          * structure:
1727          *
1728          *     Subgrid        |        x-th gl_CullDistance test           |
1729          *                    |                                            |
1730          *     y-th           | all vertices | 0th vertex   | all vertices |
1731          *     gl_ClipDistance| in primitive | in primitive | in primitive |
1732          *     tests          | dist[x] > 0  | dist[x] < 0  | dist[x] < 0  |
1733          *     ---------------+--------------+--------------+--------------+
1734          *        all vertices| primitive #0 | primitive #1 | primitive #2 |
1735          *        in primitive|              |              |              |
1736          *        dist[y] > 0 |   visible    |   visible    |    culled    |
1737          *     ---------------+--------------+--------------+--------------+
1738          *        0th vertex  | primitive #3 | primitive #4 | primitive #5 |
1739          *        in primitive|  0th vertex  |  0th vertex  |              |
1740          *        dist[y] < 0 |   clipped    |   clipped    |    culled    |
1741          *     ---------------+--------------+--------------+--------------+
1742          *        all vertices| primitive #6 | primitive #7 | primitive #8 |
1743          *        in primitive|              |              |              |
1744          *        dist[y] < 0 |   clipped    |   clipped    |    culled    |
1745          *     ---------------+--------------+--------------+--------------+
1746          *
1747          * Expected rendering result is specified in cell bottom.
1748          * It can be one of the following:
1749          * - "visible" means the primitive is not affected neither by gl_CullDistance
1750          *             nor by gl_ClipDistance and rendered as a whole;
1751          * - "clipped" for the vertex means the vertex is not rendered, while other
1752          *             primitive vertices and some filling fragments are rendered;
1753          * - "clipped" for primitive means none of primitive vertices and fragments
1754          *             are rendered and thus primitive is not rendered and is invisible;
1755          * - "culled"  means, that neither primitive vertices, nor primitive filling
1756          *             fragments are rendered (primitive is invisible).
1757          *
1758          * All subgrid items contain same primitive rendered. Depending on
1759          * test case running it would be either triangle, or line, or point:
1760          *
1761          *     triangle    line        point
1762          *     8x8 box     8x8 box     3x3 box
1763          *     ........    ........    ...
1764          *     .0----2.    .0......    .0.
1765          *     ..\@@@|.    ..\.....    ...
1766          *     ...\@@|.    ...\....
1767          *     ....\@|.    ....\...
1768          *     .....\|.    .....\..
1769          *     ......1.    ......1.
1770          *     ........    ........
1771          *
1772          *     where 0 - is a 0th vertex primitive
1773          *           1 - is a 1st vertex primitive
1774          *           2 - is a 2nd vertex primitive
1775          *
1776          * The culldistances_array_size can be 0. In that case, grid height
1777          * is assumed equal to 1, but 0 glCullDistances is specified.
1778          * Similar handled clipdistances_array_size.
1779          *
1780          * The data generated is used and checked in executeRenderTest().
1781          * After rendering each primitive vertex is tested:
1782          * - if it is rendered, if it have to be rendered (according distance);
1783          * - if it is not rendered, if it have to be not rendered (according distance).
1784          * Due to "top-left" rasterization rule check position is
1785          * different from rendering vertex position.
1786          *
1787          * Also one pixel width guarding box is checked to be clear.
1788          */
1789
1790         const glw::Functions& gl                           = m_context.getRenderContext().getFunctions();
1791         const glw::GLuint        n_sub_grid_cells = 3; /* Tested distance is positive for all vertices in the primitive;
1792          * Tested distance is negative for 0th vertex in the primitive;
1793          * Tested distance is negative for all vertices in the primitive;
1794          */
1795         const glw::GLuint        sub_grid_cell_size =
1796                 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 8 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 3 : 8);
1797
1798         const glw::GLuint grid_cell_size = n_sub_grid_cells * sub_grid_cell_size;
1799         const glw::GLuint n_primitive_vertices =
1800                 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 : 3);
1801
1802         const glw::GLuint n_grid_cells_x                           = culldistances_array_size != 0 ? culldistances_array_size : 1;
1803         const glw::GLuint n_grid_cells_y                           = clipdistances_array_size != 0 ? clipdistances_array_size : 1;
1804         const glw::GLuint n_pervertex_float_attributes = clipdistances_array_size + culldistances_array_size +
1805                                                                                                          2 /* vertex' draw x, y */ + 2 /* vertex' checkpoint x, y */;
1806         const glw::GLuint n_primitives_total     = n_grid_cells_x * n_sub_grid_cells * n_grid_cells_y * n_sub_grid_cells;
1807         const glw::GLuint n_vertices_total               = n_primitives_total * n_primitive_vertices;
1808         const glw::GLuint offsets_line_draw_x[2] = {
1809                 1, sub_grid_cell_size - 1
1810         }; /* vertex x offsets to subgrid cell origin for line primitive     */
1811         const glw::GLuint offsets_line_draw_y[2] = {
1812                 1, sub_grid_cell_size - 1
1813         }; /* vertex y offsets to subgrid cell origin for line primitive     */
1814         const glw::GLuint offsets_line_checkpoint_x[2] = {
1815                 1, sub_grid_cell_size - 2
1816         }; /* pixel x offsets to subgrid cell origin for line primitive      */
1817         const glw::GLuint offsets_line_checkpoint_y[2] = {
1818                 1, sub_grid_cell_size - 2
1819         }; /* pixel y offsets to subgrid cell origin for line primitive      */
1820         const glw::GLuint offsets_point_draw_x[1] = {
1821                 1
1822         }; /* vertex x offsets to subgrid cell origin for point primitive    */
1823         const glw::GLuint offsets_point_draw_y[1] = {
1824                 1
1825         }; /* vertex y offsets to subgrid cell origin for point primitive    */
1826         const glw::GLuint offsets_point_checkpoint_x[1] = {
1827                 1
1828         }; /* pixel x offsets to subgrid cell origin for point primitive     */
1829         const glw::GLuint offsets_point_checkpoint_y[1] = {
1830                 1
1831         }; /* pixel y offsets to subgrid cell origin for point primitive     */
1832         const glw::GLuint offsets_triangle_draw_x[3] = {
1833                 1, sub_grid_cell_size - 1, sub_grid_cell_size - 1
1834         }; /* vertex x offsets to subgrid cell origin for triangle primitive */
1835         const glw::GLuint offsets_triangle_draw_y[3] = {
1836                 1, sub_grid_cell_size - 1, 1
1837         }; /* vertex y offsets to subgrid cell origin for triangle primitive */
1838         const glw::GLuint offsets_triangle_checkpoint_x[3] = {
1839                 1, sub_grid_cell_size - 2, sub_grid_cell_size - 2
1840         }; /* pixel x offsets to subgrid cell origin for triangle primitive  */
1841         const glw::GLuint offsets_triangle_checkpoint_y[3] = {
1842                 1, sub_grid_cell_size - 2, 1
1843         }; /* pixel y offsets to subgrid cell origin for triangle primitive  */
1844         const glw::GLfloat offsets_pixel_center_x = (primitive_mode == PRIMITIVE_MODE_POINTS) ? 0.5f : 0;
1845         const glw::GLfloat offsets_pixel_center_y = (primitive_mode == PRIMITIVE_MODE_POINTS) ? 0.5f : 0;
1846         /* Clear data left from previous tests. */
1847         m_bo_data.clear();
1848
1849         /* No data to render */
1850         m_render_primitives = 0;
1851         m_render_vertices   = 0;
1852
1853         /* Preallocate space for bo_points_count */
1854         m_bo_data.reserve(n_vertices_total * n_pervertex_float_attributes);
1855
1856         /* Generate test data for cell_y-th clip distance */
1857         for (glw::GLuint cell_y = 0; cell_y < n_grid_cells_y; cell_y++)
1858         {
1859                 /* Generate test data for cell_x-th cull distance */
1860                 for (glw::GLuint cell_x = 0; cell_x < n_grid_cells_x; cell_x++)
1861                 {
1862                         /* Check clip distance sub cases:
1863                          * 0. Tested distance is positive for all vertices in the primitive;
1864                          * 1. Tested distance is negative for 0th vertex in the primitive;
1865                          * 2. Tested distance is negative for all vertices in the primitive;
1866                          */
1867                         for (glw::GLuint n_sub_cell_y = 0; n_sub_cell_y < n_sub_grid_cells; n_sub_cell_y++)
1868                         {
1869                                 /* Check cull distance sub cases:
1870                                  * 0. Tested distance is positive for all vertices in the primitive;
1871                                  * 1. Tested distance is negative for 0th vertex in the primitive;
1872                                  * 2. Tested distance is negative for all vertices in the primitive;
1873                                  */
1874                                 for (glw::GLuint n_sub_cell_x = 0; n_sub_cell_x < n_sub_grid_cells; n_sub_cell_x++)
1875                                 {
1876                                         /* Generate vertices in primitive */
1877                                         for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < n_primitive_vertices;
1878                                                  n_primitive_vertex++)
1879                                         {
1880                                                 /* Fill in clipdistance array for the n_primitive_vertex vertex in primitive */
1881                                                 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
1882                                                          n_clipdistance_entry++)
1883                                                 {
1884                                                         glw::GLfloat distance_value = 0.0f;
1885                                                         bool             negative               = true;
1886
1887                                                         /* Special approach to tested clipdistance entry. */
1888                                                         if (n_clipdistance_entry == cell_y)
1889                                                         {
1890                                                                 /* The primitive vertex should be affected by the clip distance */
1891                                                                 switch (n_sub_cell_y)
1892                                                                 {
1893                                                                 case 0:
1894                                                                 {
1895                                                                         /* subgrid row 0: all primitive vertices have tested distance value positive */
1896                                                                         negative = false;
1897
1898                                                                         break;
1899                                                                 }
1900                                                                 case 1:
1901                                                                 {
1902                                                                         /* subgrid row 1: tested distance value for 0th primitive vertex is negative,
1903                                                                          all other primitive vertices have tested distance value positive */
1904                                                                         negative = (n_primitive_vertex == 0) ? true : false;
1905
1906                                                                         break;
1907                                                                 }
1908                                                                 case 2:
1909                                                                 {
1910                                                                         /* subgrid row 2: tested distance value is negative for all primitive vertices */
1911                                                                         negative = true;
1912
1913                                                                         break;
1914                                                                 }
1915                                                                 default:
1916                                                                         TCU_FAIL("Invalid subgrid cell index");
1917                                                                 }
1918
1919                                                                 distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_clipdistance_entry + 1);
1920                                                         }
1921                                                         else
1922                                                         {
1923                                                                 /* For clip distances other than tested: assign positive value to avoid its influence. */
1924                                                                 distance_value = glw::GLfloat(clipdistances_array_size + n_clipdistance_entry + 1);
1925                                                         }
1926
1927                                                         m_bo_data.push_back(distance_value / glw::GLfloat(clipdistances_array_size));
1928                                                 } /* for (all gl_ClipDistance[] array values) */
1929
1930                                                 /* Fill in culldistance array for the n_primitive_vertex vertex in primitive */
1931                                                 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
1932                                                          n_culldistance_entry++)
1933                                                 {
1934                                                         glw::GLfloat distance_value = 0.0f;
1935                                                         bool             negative               = true;
1936
1937                                                         /* Special approach to tested culldistance entry. */
1938                                                         if (n_culldistance_entry == cell_x)
1939                                                         {
1940                                                                 /* The primitive vertex should be affected by the cull distance */
1941                                                                 switch (n_sub_cell_x)
1942                                                                 {
1943                                                                 case 0:
1944                                                                 {
1945                                                                         /* subgrid column 0: all primitive vertices have tested distance value positive */
1946                                                                         negative = false;
1947
1948                                                                         break;
1949                                                                 }
1950                                                                 case 1:
1951                                                                 {
1952                                                                         /* subgrid column 1: tested distance value for 0th primitive vertex is negative,
1953                                                                          all other primitive vertices have tested distance value positive */
1954                                                                         negative = (n_primitive_vertex == 0) ? true : false;
1955
1956                                                                         break;
1957                                                                 }
1958                                                                 case 2:
1959                                                                 {
1960                                                                         /* subgrid column 2: tested distance value is negative for all primitive vertices */
1961                                                                         negative = true;
1962
1963                                                                         break;
1964                                                                 }
1965                                                                 default:
1966                                                                         TCU_FAIL("Invalid subgrid cell index");
1967                                                                 }
1968
1969                                                                 distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_culldistance_entry + 1);
1970                                                         }
1971                                                         else
1972                                                         {
1973                                                                 /* For cull distances other than tested: assign 0th vertex negative value,
1974                                                                  to check absence of between-distances influence. */
1975                                                                 if (n_primitive_vertices > 1 && n_primitive_vertex == 0)
1976                                                                 {
1977                                                                         distance_value = -glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1);
1978                                                                 }
1979                                                                 else
1980                                                                 {
1981                                                                         /* This culldistance is out of interest: assign positive value. */
1982                                                                         distance_value = glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1);
1983                                                                 }
1984                                                         }
1985
1986                                                         m_bo_data.push_back(distance_value / glw::GLfloat(culldistances_array_size));
1987                                                 } /* for (all gl_CullDistance[] array values) */
1988
1989                                                 /* Generate primitve vertex draw and checkpoint coordinates */
1990                                                 glw::GLint vertex_draw_pixel_offset_x           = 0;
1991                                                 glw::GLint vertex_draw_pixel_offset_y           = 0;
1992                                                 glw::GLint vertex_checkpoint_pixel_offset_x = 0;
1993                                                 glw::GLint vertex_checkpoint_pixel_offset_y = 0;
1994
1995                                                 switch (primitive_mode)
1996                                                 {
1997                                                 case PRIMITIVE_MODE_LINES:
1998                                                 {
1999                                                         vertex_draw_pixel_offset_x               = offsets_line_draw_x[n_primitive_vertex];
2000                                                         vertex_draw_pixel_offset_y               = offsets_line_draw_y[n_primitive_vertex];
2001                                                         vertex_checkpoint_pixel_offset_x = offsets_line_checkpoint_x[n_primitive_vertex];
2002                                                         vertex_checkpoint_pixel_offset_y = offsets_line_checkpoint_y[n_primitive_vertex];
2003
2004                                                         break;
2005                                                 }
2006
2007                                                 case PRIMITIVE_MODE_POINTS:
2008                                                 {
2009                                                         vertex_draw_pixel_offset_x               = offsets_point_draw_x[n_primitive_vertex];
2010                                                         vertex_draw_pixel_offset_y               = offsets_point_draw_y[n_primitive_vertex];
2011                                                         vertex_checkpoint_pixel_offset_x = offsets_point_checkpoint_x[n_primitive_vertex];
2012                                                         vertex_checkpoint_pixel_offset_y = offsets_point_checkpoint_y[n_primitive_vertex];
2013
2014                                                         break;
2015                                                 }
2016
2017                                                 case PRIMITIVE_MODE_TRIANGLES:
2018                                                 {
2019                                                         vertex_draw_pixel_offset_x               = offsets_triangle_draw_x[n_primitive_vertex];
2020                                                         vertex_draw_pixel_offset_y               = offsets_triangle_draw_y[n_primitive_vertex];
2021                                                         vertex_checkpoint_pixel_offset_x = offsets_triangle_checkpoint_x[n_primitive_vertex];
2022                                                         vertex_checkpoint_pixel_offset_y = offsets_triangle_checkpoint_y[n_primitive_vertex];
2023
2024                                                         break;
2025                                                 }
2026
2027                                                 default:
2028                                                         TCU_FAIL("Unknown primitive mode");
2029                                                 }
2030
2031                                                 /* Origin of sub_cell */
2032                                                 glw::GLint sub_cell_origin_x = cell_x * grid_cell_size + n_sub_cell_x * sub_grid_cell_size;
2033                                                 glw::GLint sub_cell_origin_y = cell_y * grid_cell_size + n_sub_cell_y * sub_grid_cell_size;
2034                                                 /* Normalized texture coordinates of vertex draw position. */
2035                                                 glw::GLfloat x =
2036                                                         (glw::GLfloat(sub_cell_origin_x + vertex_draw_pixel_offset_x) + offsets_pixel_center_x) /
2037                                                         glw::GLfloat(m_to_width);
2038                                                 glw::GLfloat y =
2039                                                         (glw::GLfloat(sub_cell_origin_y + vertex_draw_pixel_offset_y) + offsets_pixel_center_y) /
2040                                                         glw::GLfloat(m_to_height);
2041                                                 /* Normalized texture coordinates of vertex checkpoint position. */
2042                                                 glw::GLfloat checkpoint_x = glw::GLfloat(sub_cell_origin_x + vertex_checkpoint_pixel_offset_x) /
2043                                                                                                         glw::GLfloat(m_to_width);
2044                                                 glw::GLfloat checkpoint_y = glw::GLfloat(sub_cell_origin_y + vertex_checkpoint_pixel_offset_y) /
2045                                                                                                         glw::GLfloat(m_to_height);
2046
2047                                                 /* Add vertex draw coordinates into buffer. */
2048                                                 m_bo_data.push_back(x);
2049                                                 m_bo_data.push_back(y);
2050
2051                                                 /* Add vertex checkpoint coordinates into buffer. */
2052                                                 m_bo_data.push_back(checkpoint_x);
2053                                                 m_bo_data.push_back(checkpoint_y);
2054                                         } /* for (all vertices in primitive) */
2055                                 }        /* for (all horizontal sub cells) */
2056                         }                 /* for (all vertical sub cells) */
2057                 }                         /* for (all horizontal cells) */
2058         }                                 /* for (all vertical cells) */
2059
2060         /* Sanity check: make sure we pushed required amount of data */
2061         DE_ASSERT(m_bo_data.size() == n_vertices_total * n_pervertex_float_attributes);
2062
2063         /* Save number of primitives to render */
2064         m_render_primitives  = n_primitives_total;
2065         m_render_vertices       = n_vertices_total;
2066         m_sub_grid_cell_size = sub_grid_cell_size;
2067
2068         /* Copy the data to the buffer object */
2069         gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id);
2070         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2071
2072         gl.bufferData(GL_ARRAY_BUFFER, m_bo_data.size() * sizeof(glw::GLfloat), &m_bo_data[0], GL_STATIC_DRAW);
2073         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2074
2075         DE_ASSERT(m_po_id != 0);
2076
2077         /* Bind VAO data to program */
2078         glw::GLint po_clipdistance_array_location = -1;
2079         glw::GLint po_culldistance_array_location = -1;
2080         glw::GLint po_position_location                   = -1;
2081
2082         /* Retrieve clipdistance and culldistance attribute locations */
2083         gl.bindVertexArray(m_vao_id);
2084         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2085
2086         po_clipdistance_array_location = gl.getAttribLocation(m_po_id, "clipdistance_data[0]");
2087         po_culldistance_array_location = gl.getAttribLocation(m_po_id, "culldistance_data[0]");
2088         po_position_location               = gl.getAttribLocation(m_po_id, "position");
2089
2090         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() call(s) failed.");
2091
2092         if (clipdistances_array_size > 0)
2093         {
2094                 DE_ASSERT(po_clipdistance_array_location != -1);
2095         }
2096
2097         if (culldistances_array_size > 0)
2098         {
2099                 DE_ASSERT(po_culldistance_array_location != -1);
2100         }
2101
2102         DE_ASSERT(po_position_location != -1);
2103
2104         glw::GLintptr   current_offset = 0;
2105         const glw::GLint stride                 = static_cast<glw::GLint>(n_pervertex_float_attributes * sizeof(glw::GLfloat));
2106
2107         gl.bindVertexArray(m_vao_id);
2108         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2109
2110         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; ++n_clipdistance_entry)
2111         {
2112                 gl.vertexAttribPointer(po_clipdistance_array_location + n_clipdistance_entry, 1, /* size */
2113                                                            GL_FLOAT, GL_FALSE,                                                                           /* normalized */
2114                                                            stride, (const glw::GLvoid*)current_offset);
2115                 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
2116
2117                 gl.enableVertexAttribArray(po_clipdistance_array_location + n_clipdistance_entry);
2118                 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
2119
2120                 current_offset += sizeof(glw::GLfloat);
2121         } /* for (all clip distance array value attributes) */
2122
2123         for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size; ++n_culldistance_entry)
2124         {
2125                 gl.vertexAttribPointer(po_culldistance_array_location + n_culldistance_entry, 1, /* size */
2126                                                            GL_FLOAT, GL_FALSE,                                                                           /* normalized */
2127                                                            stride, (const glw::GLvoid*)current_offset);
2128                 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
2129
2130                 gl.enableVertexAttribArray(po_culldistance_array_location + n_culldistance_entry);
2131                 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
2132
2133                 current_offset += sizeof(glw::GLfloat);
2134         } /* for (all cull distance array value attributes) */
2135
2136         gl.vertexAttribPointer(po_position_location, 2, /* size */
2137                                                    GL_FLOAT, GL_FALSE,          /* normalized */
2138                                                    stride, (const glw::GLvoid*)current_offset);
2139         GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed");
2140
2141         gl.enableVertexAttribArray(po_position_location);
2142         GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed");
2143 }
2144
2145 /** @brief Cull Distance Functional Test deinitialization */
2146 void CullDistance::FunctionalTest::deinit()
2147 {
2148         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2149
2150         if (m_fbo_id != 0)
2151         {
2152                 gl.deleteFramebuffers(1, &m_fbo_id);
2153
2154                 m_fbo_id = 0;
2155         }
2156
2157         if (m_to_id != 0)
2158         {
2159                 gl.deleteTextures(1, &m_to_id);
2160
2161                 m_to_id = 0;
2162         }
2163
2164         if (m_vao_id != 0)
2165         {
2166                 gl.deleteVertexArrays(1, &m_vao_id);
2167
2168                 m_vao_id = 0;
2169         }
2170
2171         deinitPO();
2172 }
2173
2174 /** @brief Cull Distance Functional Test deinitialization of OpenGL programs */
2175 void CullDistance::FunctionalTest::deinitPO()
2176 {
2177         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2178
2179         if (m_po_id != 0)
2180         {
2181                 gl.deleteProgram(m_po_id);
2182
2183                 m_po_id = 0;
2184         }
2185 }
2186
2187 /** @brief Executes single render test case
2188  *
2189  * @param [in]  clipdistances_array_size    Size of gl_ClipDistance[] array
2190  * @param [in]  culldistances_array_size    Size of gl_CullDistance[] array
2191  * @param [in]  primitive_mode              Type of primitives to be rendered (see enum _primitive_mode)
2192  * @param [in]  use_tesselation             Indicate whether to use tessellation shader
2193  * @param [in]  fetch_culldistance_from_fs  Indicate whether to fetch gl_CullDistance and gl_ClipDistance values from the fragment shader
2194  */
2195 void CullDistance::FunctionalTest::executeRenderTest(glw::GLuint         clipdistances_array_size,
2196                                                                                                          glw::GLuint     culldistances_array_size,
2197                                                                                                          _primitive_mode primitive_mode, bool use_tesselation,
2198                                                                                                          bool fetch_culldistance_from_fs)
2199 {
2200         const glw::Functions& gl                                                  = m_context.getRenderContext().getFunctions();
2201         glw::GLenum                       mode                                            = GL_NONE;
2202         glw::GLuint                       n_clipped_vertices_real        = 0;
2203         glw::GLuint                       n_culled_primitives_real      = 0;
2204         glw::GLuint                       n_not_clipped_vertices_real = 0;
2205         const glw::GLuint        primitive_vertices_count =
2206                 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 : 3);
2207         const glw::GLuint stride_in_floats =
2208                 clipdistances_array_size + culldistances_array_size + 2 /* position's x, y*/ + 2 /* checkpoint x,y */;
2209
2210         switch (primitive_mode)
2211         {
2212         case PRIMITIVE_MODE_LINES:
2213         {
2214                 mode = GL_LINES;
2215
2216                 break;
2217         }
2218         case PRIMITIVE_MODE_POINTS:
2219         {
2220                 mode = GL_POINTS;
2221
2222                 break;
2223         }
2224         case PRIMITIVE_MODE_TRIANGLES:
2225         {
2226                 mode = GL_TRIANGLES;
2227
2228                 break;
2229         }
2230         default:
2231                 TCU_FAIL("Unknown primitive mode");
2232         }
2233
2234         if (use_tesselation)
2235         {
2236                 mode = GL_PATCHES;
2237
2238                 gl.patchParameteri(GL_PATCH_VERTICES, primitive_vertices_count);
2239                 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
2240         }
2241
2242         gl.clear(GL_COLOR_BUFFER_BIT);
2243         GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
2244
2245         gl.useProgram(m_po_id);
2246         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2247
2248         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++)
2249         {
2250                 gl.enable(GL_CLIP_DISTANCE0 + n_clipdistance_entry);
2251                 GLU_EXPECT_NO_ERROR(gl.getError(), "gl.enable(GL_CLIP_DISTANCE)() call failed.");
2252         } /* for (all clip distance array value attributes) */
2253
2254         gl.drawArrays(mode, 0, m_render_vertices);
2255         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray() call(s) failed.");
2256
2257         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++)
2258         {
2259                 gl.disable(GL_CLIP_DISTANCE0 + n_clipdistance_entry);
2260                 GLU_EXPECT_NO_ERROR(gl.getError(), "gl.disable(GL_CLIP_DISTANCE)() call failed.");
2261         } /* for (all clip distance array value attributes) */
2262
2263         gl.useProgram(0);
2264         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2265
2266         /* Read generated texture into m_to_pixel_data_cache */
2267         readTexturePixels();
2268
2269         for (glw::GLint n_primitive_index = 0; n_primitive_index < m_render_primitives; n_primitive_index++)
2270         {
2271                 glw::GLuint base_index_of_primitive              = n_primitive_index * primitive_vertices_count * stride_in_floats;
2272                 bool            primitive_culled                         = false;
2273                 glw::GLint  primitive_culled_by_distance = -1;
2274
2275                 /* Check the bounding box is clear */
2276                 glw::GLuint base_index_of_vertex          = base_index_of_primitive;
2277                 glw::GLuint checkpoint_position_index = base_index_of_vertex + clipdistances_array_size +
2278                                                                                                 culldistances_array_size + 2 /* ignore vertex coordinates */;
2279                 glw::GLint checkpoint_x = glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index]);
2280                 glw::GLint checkpoint_y = glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index + 1]);
2281                 glw::GLint origin_x             = checkpoint_x - 1;
2282                 glw::GLint origin_y             = checkpoint_y - 1;
2283                 for (glw::GLint pixel_offset = 0; pixel_offset < m_sub_grid_cell_size; pixel_offset++)
2284                 {
2285                         if (readRedPixelValue(origin_x + pixel_offset, origin_y) != 0)
2286                         {
2287                                 TCU_FAIL("Top edge of bounding box is overwritten");
2288                         }
2289
2290                         if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1, origin_y + pixel_offset) != 0)
2291                         {
2292                                 TCU_FAIL("Right edge of bounding box is overwritten");
2293                         }
2294
2295                         if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1 - pixel_offset,
2296                                                                   origin_y + m_sub_grid_cell_size - 1) != 0)
2297                         {
2298                                 TCU_FAIL("Bottom edge of bounding box is overwritten");
2299                         }
2300
2301                         if (readRedPixelValue(origin_x, origin_y + m_sub_grid_cell_size - 1 - pixel_offset) != 0)
2302                         {
2303                                 TCU_FAIL("Left edge of bounding box is overwritten");
2304                         }
2305                 }
2306
2307                 /* Determine if primitive has been culled */
2308                 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
2309                          n_culldistance_entry++)
2310                 {
2311                         bool distance_negative_in_all_primitive_vertices = true;
2312
2313                         for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2314                                  n_primitive_vertex++)
2315                         {
2316                                 glw::GLint base_index_of_vertex_internal =
2317                                         base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2318                                 glw::GLint      culldistance_array_offset = base_index_of_vertex_internal + clipdistances_array_size;
2319                                 glw::GLfloat* vertex_culldistance_array = &m_bo_data[culldistance_array_offset];
2320
2321                                 if (vertex_culldistance_array[n_culldistance_entry] >= 0)
2322                                 {
2323                                         /* Primitive is not culled, due to one of its distances is not negative */
2324                                         distance_negative_in_all_primitive_vertices = false;
2325
2326                                         /* Skip left vertices for this distance */
2327                                         break;
2328                                 }
2329                         }
2330
2331                         /* The distance is negative in all primitive vertices, so this distance culls the primitive */
2332                         if (distance_negative_in_all_primitive_vertices)
2333                         {
2334                                 primitive_culled                         = true;
2335                                 primitive_culled_by_distance = n_culldistance_entry;
2336
2337                                 n_culled_primitives_real++;
2338
2339                                 /* Skip left distances from check */
2340                                 break;
2341                         }
2342                 }
2343
2344                 /* Validate culling */
2345                 if (primitive_culled)
2346                 {
2347                         /* Check whether primitive was culled and all its vertices are invisible */
2348                         for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2349                                  n_primitive_vertex++)
2350                         {
2351                                 glw::GLint base_index_of_vertex_internal =
2352                                         base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2353                                 glw::GLint checkpoint_position_index_internal = base_index_of_vertex_internal +
2354                                                                                                                                 clipdistances_array_size + culldistances_array_size +
2355                                                                                                                                 2 /* ignore vertex coordinates */;
2356                                 glw::GLint checkpoint_x_internal =
2357                                         glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2358                                 glw::GLint checkpoint_y_internal =
2359                                         glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2360                                 glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2361
2362                                 /* Make sure vertex is invisible */
2363                                 if (vertex_color_red_value != 0)
2364                                 {
2365                                         m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] "
2366                                                                            << "should be culled by distance [" << primitive_culled_by_distance << "]"
2367                                                                            << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y
2368                                                                            << ") is visible." << tcu::TestLog::EndMessage;
2369
2370                                         TCU_FAIL("Primitive is expected to be culled, but one of its vertices is visible.");
2371                                 }
2372                         }
2373
2374                         /* Primitive is culled, no reason to check clipping */
2375                         continue;
2376                 }
2377
2378                 bool all_vertices_are_clipped = true;
2379
2380                 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count; n_primitive_vertex++)
2381                 {
2382                         glw::GLuint base_index_of_vertex_internal = base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2383                         glw::GLuint clipdistance_array_index      = base_index_of_vertex_internal;
2384                         glw::GLuint checkpoint_position_index_internal = base_index_of_vertex_internal + clipdistances_array_size +
2385                                                                                                                          culldistances_array_size +
2386                                                                                                                          2 /* ignore vertex coordinates */;
2387                         glw::GLint checkpoint_x_internal =
2388                                 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2389                         glw::GLint checkpoint_y_internal =
2390                                 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2391                         glw::GLfloat* vertex_clipdistance_array  = &m_bo_data[clipdistance_array_index];
2392                         bool              vertex_clipped                         = false;
2393                         glw::GLint      vertex_clipped_by_distance = 0;
2394                         glw::GLint      vertex_color_red_value   = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2395
2396                         /* Check whether pixel should be clipped */
2397                         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
2398                                  n_clipdistance_entry++)
2399                         {
2400                                 if (vertex_clipdistance_array[n_clipdistance_entry] < 0)
2401                                 {
2402                                         vertex_clipped                     = true;
2403                                         vertex_clipped_by_distance = n_clipdistance_entry;
2404
2405                                         break;
2406                                 }
2407                         }
2408
2409                         all_vertices_are_clipped &= vertex_clipped;
2410
2411                         /* Validate whether real data same as expected */
2412                         if (vertex_clipped)
2413                         {
2414                                 if (vertex_color_red_value != 0)
2415                                 {
2416                                         m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] "
2417                                                                            << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") "
2418                                                                            << "should be clipped by distance [" << vertex_clipped_by_distance << "] "
2419                                                                            << "(distance value [" << vertex_clipdistance_array[vertex_clipped_by_distance]
2420                                                                            << "])" << tcu::TestLog::EndMessage;
2421
2422                                         TCU_FAIL("Vertex is expected to be clipped and invisible, while it is visible.");
2423                                 }
2424                                 else
2425                                 {
2426                                         n_clipped_vertices_real++;
2427                                 }
2428                         }
2429                         else
2430                         {
2431                                 if (vertex_color_red_value == 0)
2432                                 {
2433                                         m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] "
2434                                                                            << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") "
2435                                                                            << "should not be clipped." << tcu::TestLog::EndMessage;
2436
2437                                         TCU_FAIL("Vertex is unexpectedly clipped or invisible");
2438                                 }
2439                                 else
2440                                 {
2441                                         n_not_clipped_vertices_real++;
2442                                 }
2443                         }
2444                 }
2445
2446                 if (!all_vertices_are_clipped)
2447                 {
2448                         /* Check fetched values from the shader (Point 2 of Basic Outline : "Use program that...") */
2449                         if (fetch_culldistance_from_fs)
2450                         {
2451                                 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
2452                                          n_primitive_vertex++)
2453                                 {
2454                                         /* Get shader output value */
2455                                         glw::GLuint base_index_of_vertex_internal =
2456                                                 base_index_of_primitive + n_primitive_vertex * stride_in_floats;
2457                                         glw::GLuint checkpoint_position_index_internal =
2458                                                 base_index_of_vertex_internal + clipdistances_array_size + culldistances_array_size +
2459                                                 2 /* ignore vertex coordinates */;
2460                                         glw::GLuint culldistances_index = base_index_of_vertex_internal + clipdistances_array_size;
2461                                         glw::GLint  checkpoint_x_internal =
2462                                                 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
2463                                         glw::GLint checkpoint_y_internal =
2464                                                 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
2465                                         glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
2466
2467                                         /* Calculate culldistances check sum hash */
2468                                         float sum = 0.f;
2469
2470                                         for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
2471                                                  ++n_clipdistance_entry)
2472                                         {
2473                                                 sum += de::abs(m_bo_data[base_index_of_vertex_internal + n_clipdistance_entry]) *
2474                                                            float(n_clipdistance_entry + 1);
2475                                         }
2476
2477                                         for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
2478                                                  ++n_culldistance_entry)
2479                                         {
2480                                                 sum += de::abs(m_bo_data[culldistances_index + n_culldistance_entry]) *
2481                                                            float(n_culldistance_entry + 1 + clipdistances_array_size);
2482                                         }
2483
2484                                         /* limit sum and return */
2485                                         glw::GLint sum_hash =
2486                                                 glw::GLint(sum / glw::GLfloat((clipdistances_array_size + culldistances_array_size) *
2487                                                                                                           (clipdistances_array_size + culldistances_array_size + 1)) *
2488                                                                    65535.f /* normalizing to short */);
2489                                         sum_hash = (sum_hash < 65536) ? sum_hash : 65535; /* clamping to short */
2490
2491                                         /* Compare against setup value */
2492                                         if (std::abs(vertex_color_red_value - sum_hash) > 4 /* precision 4/65536 */)
2493                                         {
2494                                                 m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] "
2495                                                                                    << "should have culldistance hash sum " << sum_hash
2496                                                                                    << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y
2497                                                                                    << ") has sum hash equal to " << vertex_color_red_value
2498                                                                                    << tcu::TestLog::EndMessage;
2499
2500                                                 TCU_FAIL("Culled distances returned from fragment shader dose not match expected values.");
2501                                         }
2502                                 }
2503                         }
2504                 }
2505         }
2506
2507         /* sub_grid cell size is 3*3 */
2508         DE_ASSERT(m_render_primitives % 9 == 0);
2509
2510         /* Sanity check */
2511         switch (primitive_mode)
2512         {
2513         case PRIMITIVE_MODE_LINES:
2514         case PRIMITIVE_MODE_TRIANGLES:
2515         {
2516                 /* Validate culled primitives */
2517                 if (culldistances_array_size == 0)
2518                 {
2519                         DE_ASSERT(n_culled_primitives_real == 0);
2520                 }
2521                 else
2522                 {
2523                         /* Each 3rd line or triangle should be culled by test design */
2524                         DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives / 3);
2525                 }
2526
2527                 /* Validate clipped vertices */
2528                 if (clipdistances_array_size == 0)
2529                 {
2530                         DE_ASSERT(n_clipped_vertices_real == 0);
2531                 }
2532                 else
2533                 {
2534 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
2535                         glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3;
2536                         glw::GLint n_clipped_vertices_expected          = /* One third of primitives has 0th vertex clipped */
2537                                 one_third_of_rendered_primitives +
2538                                 /* One third of primitives clipped completely     */
2539                                 one_third_of_rendered_primitives * primitive_vertices_count;
2540
2541                         DE_ASSERT(glw::GLint(n_clipped_vertices_real) == n_clipped_vertices_expected);
2542 #endif
2543                 }
2544                 break;
2545         }
2546
2547         case PRIMITIVE_MODE_POINTS:
2548         {
2549                 /* Validate culled primitives */
2550                 if (culldistances_array_size == 0)
2551                 {
2552                         DE_ASSERT(n_culled_primitives_real == 0);
2553                 }
2554                 else
2555                 {
2556                         /* 2/3 points should be culled by test design */
2557                         DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives * 2 / 3);
2558                 }
2559
2560                 /* Validate clipped vertices */
2561                 if (clipdistances_array_size == 0)
2562                 {
2563                         DE_ASSERT(n_clipped_vertices_real == 0);
2564                 }
2565                 else
2566                 {
2567 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
2568                         glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3;
2569
2570                         /* 2/3 of rendered points should be clipped by test design */
2571                         DE_ASSERT(glw::GLint(n_clipped_vertices_real) == 2 * one_third_of_rendered_primitives);
2572 #endif
2573                 }
2574
2575                 break;
2576         }
2577         default:
2578                 TCU_FAIL("Unknown primitive mode");
2579         }
2580 }
2581
2582 /** Executes test iteration.
2583  *
2584  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2585  */
2586 tcu::TestNode::IterateResult CullDistance::FunctionalTest::iterate()
2587 {
2588         /* This test should only be executed if ARB_cull_distance is supported, or if
2589          * we're running a GL4.5 context
2590          */
2591         if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
2592                 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
2593         {
2594                 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
2595         }
2596
2597         const glw::Functions& gl                        = m_context.getRenderContext().getFunctions();
2598         bool                              has_succeeded = true;
2599         bool is_core = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
2600
2601         /* Retrieve important GL constant values */
2602         glw::GLint gl_max_clip_distances_value                                   = 0;
2603         glw::GLint gl_max_combined_clip_and_cull_distances_value = 0;
2604         glw::GLint gl_max_cull_distances_value                                   = 0;
2605
2606         gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value);
2607         gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
2608         gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
2609         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call(s) failed.");
2610
2611         gl.genTextures(1, &m_to_id);
2612         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
2613
2614         gl.bindTexture(GL_TEXTURE_2D, m_to_id);
2615         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
2616
2617         gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
2618                                         GL_R32F, m_to_width, m_to_height);
2619         GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
2620
2621         /* Set up the draw/read FBO */
2622         gl.genFramebuffers(1, &m_fbo_id);
2623         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
2624
2625         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
2626         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
2627
2628         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); /* level */
2629         GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
2630
2631         /* Prepare a buffer object */
2632         gl.genBuffers(1, &m_bo_id);
2633         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2634
2635         /* Prepare a VAO. We will configure separately for each iteration. */
2636         gl.genVertexArrays(1, &m_vao_id);
2637         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2638
2639         /* Iterate over all functional tests */
2640         struct _test_item
2641         {
2642                 bool redeclare_clipdistances_array;
2643                 bool redeclare_culldistances_array;
2644                 bool dynamic_index_writes;
2645                 bool use_passthrough_gs;
2646                 bool use_passthrough_ts;
2647                 bool use_core_functionality;
2648                 bool fetch_culldistances;
2649         } test_items[] = { /* Use the basic outline to test the basic functionality of cull distances. */
2650                                            {
2651                                                    true,        /* redeclare_clipdistances_array */
2652                                                    true,        /* redeclare_culldistances_array */
2653                                                    false,   /* dynamic_index_writes          */
2654                                                    false,   /* use_passthrough_gs            */
2655                                                    false,   /* use_passthrough_ts            */
2656                                                    is_core, /* use_core_functionality        */
2657                                                    false        /* fetch_culldistances           */
2658                                            },
2659                                            /* Use the basic outline but don't redeclare gl_ClipDistance with a size. */
2660                                            {
2661                                                    false,   /* redeclare_clipdistances_array */
2662                                                    true,        /* redeclare_culldistances_array */
2663                                                    false,   /* dynamic_index_writes          */
2664                                                    false,   /* use_passthrough_gs            */
2665                                                    false,   /* use_passthrough_ts            */
2666                                                    is_core, /* use_core_functionality        */
2667                                                    false        /* fetch_culldistances           */
2668                                            },
2669                                            /* Use the basic outline but don't redeclare gl_CullDistance with a size. */
2670                                            {
2671                                                    true,        /* redeclare_clipdistances_array  */
2672                                                    false,   /* redeclare_culldistances_array  */
2673                                                    false,   /* dynamic_index_writes           */
2674                                                    false,   /* use_passthrough_gs             */
2675                                                    false,   /* use_passthrough_ts             */
2676                                                    is_core, /* use_core_functionality         */
2677                                                    false        /* fetch_culldistances            */
2678                                            },
2679                                            /* Use the basic outline but don't redeclare either gl_ClipDistance or
2680                  * gl_CullDistance with a size.
2681                  */
2682                                            {
2683                                                    false,   /* redeclare_clipdistances_array */
2684                                                    false,   /* redeclare_culldistances_array */
2685                                                    false,   /* dynamic_index_writes          */
2686                                                    false,   /* use_passthrough_gs            */
2687                                                    false,   /* use_passthrough_ts            */
2688                                                    is_core, /* use_core_functionality        */
2689                                                    false        /* fetch_culldistances           */
2690                                            },
2691                                            /* Use the basic outline but use dynamic indexing when writing the elements
2692                  * of the gl_ClipDistance and gl_CullDistance arrays.
2693                  */
2694                                            {
2695                                                    true,        /* redeclare_clipdistances_array */
2696                                                    true,        /* redeclare_culldistances_array */
2697                                                    true,        /* dynamic_index_writes          */
2698                                                    false,   /* use_passthrough_gs            */
2699                                                    false,   /* use_passthrough_ts            */
2700                                                    is_core, /* use_core_functionality        */
2701                                                    false        /* fetch_culldistances           */
2702                                            },
2703                                            /* Use the basic outline but add a geometry shader to the program that
2704                  * simply passes through all written clip and cull distances.
2705                  */
2706                                            {
2707                                                    true,        /* redeclare_clipdistances_array */
2708                                                    true,        /* redeclare_culldistances_array */
2709                                                    false,   /* dynamic_index_writes          */
2710                                                    true,        /* use_passthrough_gs            */
2711                                                    false,   /* use_passthrough_ts            */
2712                                                    is_core, /* use_core_functionality        */
2713                                                    false        /* fetch_culldistances           */
2714                                            },
2715                                            /* Use the basic outline but add a tessellation control and tessellation
2716                  * evaluation shader to the program which simply pass through all written
2717                  * clip and cull distances.
2718                  */
2719                                            {
2720                                                    true,        /* redeclare_clipdistances_array */
2721                                                    true,        /* redeclare_culldistances_array */
2722                                                    false,   /* dynamic_index_writes          */
2723                                                    false,   /* use_passthrough_gs            */
2724                                                    true,        /* use_passthrough_ts            */
2725                                                    is_core, /* use_core_functionality        */
2726                                                    false        /* fetch_culldistances           */
2727                                            },
2728                                            /* Test that using #extension with GL_ARB_cull_distance allows using the
2729                  * feature even with an earlier version of GLSL. Also test that the
2730                  * extension name is available as preprocessor #define.
2731                  */
2732                                            {
2733                                                    true,  /* redeclare_clipdistances_array */
2734                                                    true,  /* redeclare_culldistances_array */
2735                                                    false, /* dynamic_index_writes          */
2736                                                    false, /* use_passthrough_gs            */
2737                                                    false, /* use_passthrough_ts            */
2738                                                    false, /* use_core_functionality        */
2739                                                    false  /* fetch_culldistances           */
2740                                            },
2741                                            /* Use a program that has only a vertex shader and a fragment shader.
2742                  * The vertex shader should redeclare gl_ClipDistance with a size that
2743                  * fits all enabled cull distances. Also redeclare gl_CullDistance with a
2744                  * size. The sum of the two sizes should not be more than MAX_COMBINED_-
2745                  * CLIP_AND_CULL_DISTANCES. The fragment shader should output the cull
2746                  * distances written by the vertex shader by reading them from the built-in
2747                  * array gl_CullDistance.
2748                  */
2749                                            {
2750                                                    true,  /* redeclare_clipdistances_array */
2751                                                    true,  /* redeclare_culldistances_array */
2752                                                    false, /* dynamic_index_writes          */
2753                                                    false, /* use_passthrough_gs            */
2754                                                    false, /* use_passthrough_ts            */
2755                                                    false, /* use_core_functionality        */
2756                                                    true   /* fetch_culldistances           */
2757                                            }
2758         };
2759         const glw::GLuint n_test_items = sizeof(test_items) / sizeof(test_items[0]);
2760
2761         gl.viewport(0, 0, m_to_width, m_to_height);
2762         GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
2763
2764         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2765         GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed.");
2766
2767         for (glw::GLuint n_test_item = 0; n_test_item < n_test_items; ++n_test_item)
2768         {
2769                 /* Check for OpenGL feature support */
2770                 if (test_items[n_test_item].use_passthrough_ts)
2771                 {
2772                         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) &&
2773                                 !m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader"))
2774                         {
2775                                 continue; // no tessellation shader support
2776                         }
2777                 }
2778
2779                 const _test_item&        current_test_item                                              = test_items[n_test_item];
2780                 const _primitive_mode primitive_modes[PRIMITIVE_MODE_COUNT] = { PRIMITIVE_MODE_LINES, PRIMITIVE_MODE_POINTS,
2781                                                                                                                                                 PRIMITIVE_MODE_TRIANGLES };
2782
2783                 for (glw::GLuint primitive_mode_index = 0; primitive_mode_index < PRIMITIVE_MODE_COUNT; ++primitive_mode_index)
2784                 {
2785                         _primitive_mode primitive_mode = primitive_modes[primitive_mode_index];
2786
2787                         /* Iterate over a set of gl_ClipDistances[] and gl_CullDistances[] array sizes */
2788                         for (glw::GLint n_iteration = 0; n_iteration <= gl_max_combined_clip_and_cull_distances_value;
2789                                  ++n_iteration)
2790                         {
2791                                 glw::GLuint clipdistances_array_size = 0;
2792                                 glw::GLuint culldistances_array_size = 0;
2793
2794                                 if (n_iteration != 0 && n_iteration <= gl_max_clip_distances_value)
2795                                 {
2796                                         clipdistances_array_size = n_iteration;
2797                                 }
2798
2799                                 if ((gl_max_combined_clip_and_cull_distances_value - n_iteration) < gl_max_cull_distances_value)
2800                                 {
2801                                         culldistances_array_size = gl_max_combined_clip_and_cull_distances_value - n_iteration;
2802                                 }
2803                                 else
2804                                 {
2805                                         culldistances_array_size = gl_max_cull_distances_value;
2806                                 }
2807
2808                                 if (clipdistances_array_size == 0 && culldistances_array_size == 0)
2809                                 {
2810                                         /* Skip the dummy iteration */
2811                                         continue;
2812                                 }
2813
2814                                 if (current_test_item.fetch_culldistances && (primitive_mode != PRIMITIVE_MODE_POINTS))
2815                                 {
2816                                         continue;
2817                                 }
2818
2819                                 /* Create a program to run */
2820                                 buildPO(clipdistances_array_size, culldistances_array_size, current_test_item.dynamic_index_writes,
2821                                                 primitive_mode, current_test_item.redeclare_clipdistances_array,
2822                                                 current_test_item.redeclare_culldistances_array, current_test_item.use_core_functionality,
2823                                                 current_test_item.use_passthrough_gs, current_test_item.use_passthrough_ts,
2824                                                 current_test_item.fetch_culldistances);
2825
2826                                 /* Initialize VAO data */
2827                                 configureVAO(clipdistances_array_size, culldistances_array_size, primitive_mode);
2828
2829                                 /* Run GLSL program and check results */
2830                                 executeRenderTest(clipdistances_array_size, culldistances_array_size, primitive_mode,
2831                                                                   current_test_item.use_passthrough_ts, current_test_item.fetch_culldistances);
2832
2833                         } /* for (all iterations) */
2834                 }        /* for (all test modes) */
2835         }                 /* for (all test items) */
2836
2837         /* All done */
2838         if (has_succeeded)
2839         {
2840                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2841         }
2842         else
2843         {
2844                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2845         }
2846
2847         return STOP;
2848 }
2849
2850 /** Returns pixel red component read from texture at position x, y.
2851  *
2852  *  @param x x-coordinate to read pixel color component from
2853  *  @param y y-coordinate to read pixel color component from
2854  **/
2855 glw::GLint CullDistance::FunctionalTest::readRedPixelValue(glw::GLint x, glw::GLint y)
2856 {
2857         glw::GLint result = -1;
2858
2859         DE_ASSERT(x >= 0 && (glw::GLuint)x < m_to_width);
2860         DE_ASSERT(y >= 0 && (glw::GLuint)y < m_to_height);
2861
2862         result = m_to_pixel_data_cache[(m_to_width * y + x) * m_to_pixel_data_cache_color_components];
2863
2864         return result;
2865 }
2866
2867 /** Reads texture into m_to_pixel_data_cache.
2868  *  Texture size determined by fields m_to_width, m_to_height
2869  **/
2870 void CullDistance::FunctionalTest::readTexturePixels()
2871 {
2872         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2873
2874         m_to_pixel_data_cache.clear();
2875
2876         m_to_pixel_data_cache.resize(m_to_width * m_to_height * m_to_pixel_data_cache_color_components);
2877
2878         /* Read vertex from texture */
2879         gl.readPixels(0,                   /* x      */
2880                                   0,               /* y      */
2881                                   m_to_width,  /* width  */
2882                                   m_to_height, /* height */
2883                                   GL_RGBA, GL_UNSIGNED_SHORT, &m_to_pixel_data_cache[0]);
2884         GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
2885 }
2886
2887 /** Constructor.
2888  *
2889  *  @param context Rendering context handle.
2890  **/
2891 CullDistance::NegativeTest::NegativeTest(deqp::Context& context)
2892         : TestCase(context, "negative", "Cull Distance Negative Test")
2893         , m_fs_id(0)
2894         , m_po_id(0)
2895         , m_temp_buffer(DE_NULL)
2896         , m_vs_id(0)
2897 {
2898         /* Left blank on purpose */
2899 }
2900
2901 /** @brief Cull Distance Negative Test deinitialization */
2902 void CullDistance::NegativeTest::deinit()
2903 {
2904         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2905
2906         if (m_fs_id != 0)
2907         {
2908                 gl.deleteShader(m_fs_id);
2909
2910                 m_fs_id = 0;
2911         }
2912
2913         if (m_po_id != 0)
2914         {
2915                 gl.deleteProgram(m_po_id);
2916
2917                 m_po_id = 0;
2918         }
2919
2920         if (m_vs_id != 0)
2921         {
2922                 gl.deleteShader(m_vs_id);
2923
2924                 m_vs_id = 0;
2925         }
2926
2927         if (m_temp_buffer != DE_NULL)
2928         {
2929                 delete[] m_temp_buffer;
2930
2931                 m_temp_buffer = DE_NULL;
2932         }
2933 }
2934
2935 /** @brief Get string description of test with given parameters
2936  *
2937  *  @param [in] n_test_iteration                    Test iteration number
2938  *  @param [in] should_redeclare_output_variables   Indicate whether test redeclared gl_ClipDistance and gl_CullDistance
2939  *  @param [in] use_dynamic_index_based_writes      Indicate whether test used dynamic index-based setters
2940  *
2941  *  @return String containing description.
2942  */
2943 std::string CullDistance::NegativeTest::getTestDescription(int n_test_iteration, bool should_redeclare_output_variables,
2944                                                                                                                    bool use_dynamic_index_based_writes)
2945 {
2946         std::stringstream stream;
2947
2948         stream << "Test iteration [" << n_test_iteration << "] which uses a vertex shader that:\n\n"
2949                    << ((should_redeclare_output_variables) ?
2950                                    "* redeclares gl_ClipDistance and gl_CullDistance arrays\n" :
2951                                    "* does not redeclare gl_ClipDistance and gl_CullDistance arrays\n")
2952                    << ((use_dynamic_index_based_writes) ? "* uses dynamic index-based writes\n" : "* uses static writes\n");
2953
2954         return stream.str();
2955 }
2956
2957 /** Executes test iteration.
2958  *
2959  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2960  */
2961 tcu::TestNode::IterateResult CullDistance::NegativeTest::iterate()
2962 {
2963         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2964
2965         /* Build the test shaders. */
2966         const glw::GLchar* token_dynamic_index_based_writes = "DYNAMIC_INDEX_BASED_WRITES";
2967         const glw::GLchar* token_insert_static_writes           = "INSERT_STATIC_WRITES";
2968         const glw::GLchar* token_n_gl_clipdistance_entries  = "N_GL_CLIPDISTANCE_ENTRIES";
2969         const glw::GLchar* token_n_gl_culldistance_entries  = "N_GL_CULLDISTANCE_ENTRIES";
2970         const glw::GLchar* token_redeclare_output_variables = "REDECLARE_OUTPUT_VARIABLES";
2971
2972         const glw::GLchar* fs_body = "#version 130\n"
2973                                                                  "\n"
2974                                                                  "void main()\n"
2975                                                                  "{\n"
2976                                                                  "}\n";
2977
2978         const glw::GLchar* vs_body_preamble = "#version 130\n"
2979                                                                                   "\n"
2980                                                                                   "    #extension GL_ARB_cull_distance : require\n"
2981                                                                                   "\n";
2982
2983         const glw::GLchar* vs_body_main = "#ifdef REDECLARE_OUTPUT_VARIABLES\n"
2984                                                                           "    out float gl_ClipDistance[N_GL_CLIPDISTANCE_ENTRIES];\n"
2985                                                                           "    out float gl_CullDistance[N_GL_CULLDISTANCE_ENTRIES];\n"
2986                                                                           "#endif\n"
2987                                                                           "\n"
2988                                                                           "void main()\n"
2989                                                                           "{\n"
2990                                                                           "#ifdef DYNAMIC_INDEX_BASED_WRITES\n"
2991                                                                           "    for (int n_clipdistance_entry = 0;\n"
2992                                                                           "             n_clipdistance_entry < N_GL_CLIPDISTANCE_ENTRIES;\n"
2993                                                                           "           ++n_clipdistance_entry)\n"
2994                                                                           "    {\n"
2995                                                                           "        gl_ClipDistance[n_clipdistance_entry] = float(n_clipdistance_entry) / "
2996                                                                           "float(N_GL_CLIPDISTANCE_ENTRIES);\n"
2997                                                                           "    }\n"
2998                                                                           "\n"
2999                                                                           "    for (int n_culldistance_entry = 0;\n"
3000                                                                           "             n_culldistance_entry < N_GL_CULLDISTANCE_ENTRIES;\n"
3001                                                                           "           ++n_culldistance_entry)\n"
3002                                                                           "    {\n"
3003                                                                           "        gl_CullDistance[n_culldistance_entry] = float(n_culldistance_entry) / "
3004                                                                           "float(N_GL_CULLDISTANCE_ENTRIES);\n"
3005                                                                           "    }\n"
3006                                                                           "#else\n"
3007                                                                           "    INSERT_STATIC_WRITES\n"
3008                                                                           "#endif\n"
3009                                                                           "}\n";
3010
3011         /* This test should only be executed if ARB_cull_distance is supported, or if
3012          * we're running a GL4.5 context
3013          */
3014         if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
3015                 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
3016         {
3017                 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
3018         }
3019
3020         /* It only makes sense to run this test if GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES
3021          * is lower than a sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CLIP_CULL_DISTANCES.
3022          */
3023         glw::GLint  gl_max_clip_distances_value                                   = 0;
3024         glw::GLint  gl_max_combined_clip_and_cull_distances_value = 0;
3025         glw::GLint  gl_max_cull_distances_value                                   = 0;
3026         glw::GLuint n_gl_clipdistance_array_items                                 = 0;
3027         std::string n_gl_clipdistance_array_items_string;
3028         glw::GLuint n_gl_culldistance_array_items = 0;
3029         std::string n_gl_culldistance_array_items_string;
3030         std::string static_write_shader_body_part;
3031
3032         gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value);
3033         gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
3034         gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
3035
3036         if (gl_max_clip_distances_value + gl_max_cull_distances_value < gl_max_combined_clip_and_cull_distances_value)
3037         {
3038                 m_testCtx.getLog() << tcu::TestLog::Message
3039                                                    << "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES is larger than or equal to "
3040                                                           "the sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CULL_DISTANCES. Skipping."
3041                                                    << tcu::TestLog::EndMessage;
3042
3043                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3044
3045                 return STOP;
3046         }
3047
3048         n_gl_clipdistance_array_items = gl_max_clip_distances_value;
3049         n_gl_culldistance_array_items = gl_max_combined_clip_and_cull_distances_value - gl_max_clip_distances_value + 1;
3050
3051         /* Determine the number of items we will want the gl_ClipDistance and gl_CullDistance arrays
3052          * to hold for test iterations that will re-declare the built-in output variables.
3053          */
3054         {
3055                 std::stringstream temp_sstream;
3056
3057                 temp_sstream << n_gl_clipdistance_array_items;
3058
3059                 n_gl_clipdistance_array_items_string = temp_sstream.str();
3060         }
3061
3062         {
3063                 std::stringstream temp_sstream;
3064
3065                 temp_sstream << n_gl_culldistance_array_items;
3066
3067                 n_gl_culldistance_array_items_string = temp_sstream.str();
3068         }
3069
3070         /* Form the "static write" shader body part. */
3071         {
3072                 std::stringstream temp_sstream;
3073
3074                 temp_sstream << "gl_ClipDistance[" << n_gl_clipdistance_array_items_string.c_str() << "] = 0.0f;\n"
3075                                          << "gl_CullDistance[" << n_gl_culldistance_array_items_string.c_str() << "] = 0.0f;\n";
3076
3077                 static_write_shader_body_part = temp_sstream.str();
3078         }
3079
3080         /* Prepare GL objects before we continue */
3081         glw::GLint compile_status = GL_FALSE;
3082
3083         m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3084         m_po_id = gl.createProgram();
3085         m_vs_id = gl.createShader(GL_VERTEX_SHADER);
3086
3087         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() calls failed.");
3088
3089         gl.attachShader(m_po_id, m_fs_id);
3090         gl.attachShader(m_po_id, m_vs_id);
3091
3092         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
3093
3094         gl.shaderSource(m_fs_id, 1,                     /* count */
3095                                         &fs_body, DE_NULL); /* length */
3096         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
3097
3098         gl.compileShader(m_fs_id);
3099         GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
3100
3101         gl.getShaderiv(m_fs_id, GL_COMPILE_STATUS, &compile_status);
3102         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3103
3104         if (compile_status == GL_FALSE)
3105         {
3106                 TCU_FAIL("Fragment shader failed to compile.");
3107         }
3108
3109         /* Run three separate test iterations. */
3110         struct _test_item
3111         {
3112                 bool should_redeclare_output_variables;
3113                 bool use_dynamic_index_based_writes;
3114         } test_items[] = { /* Negative Test 1 */
3115                                            { true, false },
3116
3117                                            /* Negative Test 2 */
3118                                            { false, false },
3119
3120                                            /* Negative Test 3 */
3121                                            { false, true }
3122         };
3123         const unsigned int n_test_items = sizeof(test_items) / sizeof(test_items[0]);
3124
3125         for (unsigned int n_test_item = 0; n_test_item < n_test_items; ++n_test_item)
3126         {
3127                 const _test_item& current_test_item = test_items[n_test_item];
3128
3129                 /* Prepare vertex shader body */
3130                 std::size_t               token_position = std::string::npos;
3131                 std::stringstream vs_body_sstream;
3132                 std::string               vs_body_string;
3133
3134                 vs_body_sstream << vs_body_preamble << "\n";
3135
3136                 if (current_test_item.should_redeclare_output_variables)
3137                 {
3138                         vs_body_sstream << "#define " << token_redeclare_output_variables << "\n";
3139                 }
3140
3141                 if (current_test_item.use_dynamic_index_based_writes)
3142                 {
3143                         vs_body_sstream << "#define " << token_dynamic_index_based_writes << "\n";
3144                 }
3145
3146                 vs_body_sstream << vs_body_main;
3147
3148                 /* Replace tokens with meaningful values */
3149                 vs_body_string = vs_body_sstream.str();
3150
3151                 while ((token_position = vs_body_string.find(token_n_gl_clipdistance_entries)) != std::string::npos)
3152                 {
3153                         vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries),
3154                                                                                                         n_gl_clipdistance_array_items_string);
3155                 }
3156
3157                 while ((token_position = vs_body_string.find(token_n_gl_culldistance_entries)) != std::string::npos)
3158                 {
3159                         vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries),
3160                                                                                                         n_gl_culldistance_array_items_string);
3161                 }
3162
3163                 while ((token_position = vs_body_string.find(token_insert_static_writes)) != std::string::npos)
3164                 {
3165                         vs_body_string = vs_body_string.replace(token_position, strlen(token_insert_static_writes),
3166                                                                                                         static_write_shader_body_part);
3167                 }
3168
3169                 /* Try to compile the vertex shader */
3170                 glw::GLint  compile_status_internal = GL_FALSE;
3171                 const char* vs_body_raw_ptr                     = vs_body_string.c_str();
3172
3173                 gl.shaderSource(m_vs_id, 1,                                     /* count */
3174                                                 &vs_body_raw_ptr, DE_NULL); /* length */
3175                 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
3176
3177                 gl.compileShader(m_vs_id);
3178                 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
3179
3180                 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status_internal);
3181                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3182
3183                 if (compile_status_internal == GL_FALSE)
3184                 {
3185                         glw::GLint buffer_size = 0;
3186
3187                         /* Log the compilation error */
3188                         m_testCtx.getLog() << tcu::TestLog::Message
3189                                                            << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3190                                                                                                          current_test_item.use_dynamic_index_based_writes)
3191                                                            << "has failed (as expected) to compile with the following info log:\n\n"
3192                                                            << tcu::TestLog::EndMessage;
3193
3194                         gl.getShaderiv(m_vs_id, GL_INFO_LOG_LENGTH, &buffer_size);
3195                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
3196
3197                         m_temp_buffer = new glw::GLchar[buffer_size + 1];
3198
3199                         memset(m_temp_buffer, 0, buffer_size + 1);
3200
3201                         gl.getShaderInfoLog(m_vs_id, buffer_size, DE_NULL, /* length */
3202                                                                 m_temp_buffer);
3203                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed.");
3204
3205                         m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage;
3206
3207                         delete[] m_temp_buffer;
3208                         m_temp_buffer = DE_NULL;
3209
3210                         /* Move on to the next iteration */
3211                         continue;
3212                 }
3213
3214                 /* Try to link the program object */
3215                 glw::GLint link_status = GL_FALSE;
3216
3217                 gl.linkProgram(m_po_id);
3218                 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
3219
3220                 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
3221                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
3222
3223                 if (link_status == GL_TRUE)
3224                 {
3225                         m_testCtx.getLog() << tcu::TestLog::Message
3226                                                            << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3227                                                                                                          current_test_item.use_dynamic_index_based_writes)
3228                                                            << "has linked successfully which is invalid!" << tcu::TestLog::EndMessage;
3229
3230                         TCU_FAIL("Program object has linked successfully, even though the process should have failed.");
3231                 }
3232                 else
3233                 {
3234                         glw::GLint buffer_size = 0;
3235
3236                         m_testCtx.getLog() << tcu::TestLog::Message
3237                                                            << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
3238                                                                                                          current_test_item.use_dynamic_index_based_writes)
3239                                                            << "has failed (as expected) to link with the following info log:\n\n"
3240                                                            << tcu::TestLog::EndMessage;
3241
3242                         gl.getProgramiv(m_po_id, GL_INFO_LOG_LENGTH, &buffer_size);
3243                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
3244
3245                         m_temp_buffer = new glw::GLchar[buffer_size + 1];
3246
3247                         memset(m_temp_buffer, 0, buffer_size + 1);
3248
3249                         gl.getProgramInfoLog(m_po_id, buffer_size, DE_NULL, /* length */
3250                                                                  m_temp_buffer);
3251                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed.");
3252
3253                         m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage;
3254
3255                         delete[] m_temp_buffer;
3256                         m_temp_buffer = DE_NULL;
3257                 }
3258         } /* for (all test items) */
3259
3260         /* All done */
3261         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3262
3263         return STOP;
3264 }
3265
3266 /** Constructor.
3267  *
3268  *  @param context Rendering context.
3269  */
3270 CullDistance::Tests::Tests(deqp::Context& context) : TestCaseGroup(context, "cull_distance", "Cull Distance Test Suite")
3271 {
3272 }
3273
3274 /** Initializes the test group contents. */
3275 void CullDistance::Tests::init()
3276 {
3277         addChild(new CullDistance::APICoverageTest(m_context));
3278         addChild(new CullDistance::FunctionalTest(m_context));
3279         addChild(new CullDistance::NegativeTest(m_context));
3280 }
3281 } /* glcts namespace */