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