• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /* Includes. */
25 #include "glcClipDistance.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "gluRenderContext.hpp"
29 #include "gluShaderUtil.hpp"
30 #include "gluStrUtil.hpp"
31 #include "tcuStringTemplate.hpp"
32 #include "tcuTestLog.hpp"
33 
34 #include <cmath>
35 #include <sstream>
36 
37 /* Stringify macro. */
38 #define _STR(s) STR(s)
39 #define STR(s) #s
40 
41 /* In OpenGL 3.0 specification GL_CLIP_DISTANCEi is named GL_CLIP_PLANEi */
42 #ifndef GL_CLIP_DISTANCE0
43 #define GL_CLIP_DISTANCE0 GL_CLIP_PLANE0
44 #endif
45 
46 /* In OpenGL 3.0 specification GL_MAX_CLIP_DISTANCES is named GL_MAX_CLIP_PLANES */
47 #ifndef GL_MAX_CLIP_DISTANCES
48 #define GL_MAX_CLIP_DISTANCES GL_MAX_CLIP_PLANES
49 #endif
50 
51 /******************************** Test Group Implementation       ********************************/
52 
53 /** @brief Clip distances tests group constructor.
54  *
55  *  @param [in] context     OpenGL context.
56  */
Tests(deqp::Context & context)57 glcts::ClipDistance::Tests::Tests(deqp::Context &context)
58     : TestCaseGroup(context, "clip_distance", "Clip Distance Test Suite")
59 {
60     /* Intentionally left blank */
61 }
62 
63 /** @brief Clip distances tests initializer. */
init()64 void glcts::ClipDistance::Tests::init()
65 {
66     addChild(new glcts::ClipDistance::CoverageTest(m_context));
67     addChild(new glcts::ClipDistance::FunctionalTest(m_context));
68     addChild(new glcts::ClipDistance::NegativeTest(m_context));
69 }
70 
71 /****************************** Coverage Tests Base Implementation   *****************************/
72 
73 /** @brief API base tests constructor.
74  *
75  *  @param context Rendering context
76  *  @param name Test name
77  *  @param description Test description
78  */
ClipDistanceTestBase(deqp::Context & context,const char * name,const char * description)79 glcts::ClipDistance::ClipDistanceTestBase::ClipDistanceTestBase(deqp::Context &context, const char *name,
80                                                                 const char *description)
81     : TestCase(context, name, description)
82     , m_extensionSupported(false)
83     , m_isContextES(false)
84 {
85     const glu::RenderContext &renderContext = m_context.getRenderContext();
86     glu::GLSLVersion glslVersion            = glu::getContextTypeGLSLVersion(renderContext.getType());
87     m_isContextES                           = glu::isContextTypeES(renderContext.getType());
88 
89     specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion);
90     if (m_isContextES)
91     {
92         specializationMap["EXTENSION"] = "#extension GL_EXT_clip_cull_distance : enable";
93         specializationMap["PRECISION"] = "precision highp float;";
94     }
95     else
96     {
97         specializationMap["EXTENSION"] = "";
98         specializationMap["PRECISION"] = "";
99     }
100 
101     auto contextType = m_context.getRenderContext().getType();
102     if (m_isContextES)
103     {
104         if (glu::contextSupports(contextType, glu::ApiType::es(3, 0)))
105         {
106             m_extensionSupported = context.getContextInfo().isExtensionSupported("GL_EXT_clip_cull_distance");
107         }
108     }
109     else
110     {
111         /* This test should only be executed if we're running a GL>=3.0 context */
112         if (glu::contextSupports(contextType, glu::ApiType::core(3, 0)))
113         {
114             m_extensionSupported = true;
115         }
116     }
117 }
118 
iterate()119 tcu::TestNode::IterateResult glcts::ClipDistance::ClipDistanceTestBase::iterate()
120 {
121     if (!m_extensionSupported)
122     {
123         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
124         if (!m_isContextES)
125         {
126             /* This test should only be executed if we're running a GL3.0 context */
127             throw tcu::NotSupportedError("GL_ARB_clip_distance is not supported");
128         }
129         else
130         {
131             throw tcu::NotSupportedError("GL_EXT_clip_cull_distance is not supported");
132         }
133         return STOP;
134     }
135 
136     test();
137 
138     return STOP;
139 }
140 
141 /******************************** Coverage Tests Implementation   ********************************/
142 
143 /** @brief API coverage tests constructor.
144  *
145  *  @param [in] context     OpenGL context.
146  */
CoverageTest(deqp::Context & context)147 glcts::ClipDistance::CoverageTest::CoverageTest(deqp::Context &context)
148     : ClipDistanceTestBase(context, "coverage", "Clip Distance API Coverage Test")
149     , m_gl_max_clip_distances_value(0)
150 {
151     /* Intentionally left blank. */
152 }
153 
154 /** @brief API coverage tests.
155  *
156  */
test()157 void glcts::ClipDistance::CoverageTest::test()
158 {
159     /* Shortcut for GL functionality */
160     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
161 
162     /* Running tests. */
163     bool is_ok = true;
164 
165     is_ok = is_ok && MaxClipDistancesValueTest(gl);
166     is_ok = is_ok && EnableDisableTest(gl);
167     is_ok = is_ok && MaxClipDistancesValueInVertexShaderTest(gl);
168     is_ok = is_ok && MaxClipDistancesValueInFragmentShaderTest(gl);
169     is_ok = is_ok && ClipDistancesValuePassing(gl);
170 
171     /* Result's setup. */
172     if (is_ok)
173     {
174         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
175     }
176     else
177     {
178         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
179     }
180 }
181 
182 /* @brief glGet GL_MAX_CLIP_DISTANCES limit coverage test.
183  *
184  *  @param [in] gl                  OpenGL functions' access.
185  *
186  *  @return True if passed, false otherwise.
187  */
MaxClipDistancesValueTest(const glw::Functions & gl)188 bool glcts::ClipDistance::CoverageTest::MaxClipDistancesValueTest(const glw::Functions &gl)
189 {
190     /*  Check that calling GetIntegerv with GL_MAX_CLIP_DISTANCES doesn't
191      generate any errors and returns a value at least 6 in OpenGL 3.0
192      or 8 in OpenGL 3.1 or OpenGL ES 3.2 and higher (see issues). */
193 
194     glw::GLint error_code = GL_NO_ERROR;
195 
196     gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &m_gl_max_clip_distances_value);
197 
198     error_code = gl.getError();
199 
200     if (error_code != GL_NO_ERROR)
201     {
202         m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv(" << STR(GL_MAX_CLIP_DISTANCES)
203                            << ") returned error code " << glu::getErrorStr(error_code) << " instead of GL_NO_ERROR."
204                            << tcu::TestLog::EndMessage;
205 
206         return false;
207     }
208     else
209     {
210         glw::GLint gl_max_clip_distances_minimum_value = 6; /* OpenGL 3.0 Specification minimum value */
211 
212         auto contextType = m_context.getRenderContext().getType();
213         /* OpenGL 3.1 specification minimum value, see bug #4803 */
214         /* or OpenGL 3.0 ES and extension GL_EXT_clip_cull_distance minimum value */
215         if (glu::contextSupports(contextType, glu::ApiType(3, 1, glu::PROFILE_CORE)) || m_isContextES)
216         {
217             gl_max_clip_distances_minimum_value = 8;
218         }
219 
220         if (m_gl_max_clip_distances_value < gl_max_clip_distances_minimum_value)
221         {
222             m_testCtx.getLog() << tcu::TestLog::Message << "Value of " << STR(GL_MAX_CLIP_DISTANCES) << "is equal to "
223                                << m_gl_max_clip_distances_value << " which is less than minimum required ("
224                                << gl_max_clip_distances_minimum_value << ")." << tcu::TestLog::EndMessage;
225 
226             return false;
227         }
228     }
229 
230     return true;
231 }
232 
233 /* @brief glEnable / glDisable of GL_CLIP_DISTANCEi coverage test.
234  *
235  *  @param [in] gl                  OpenGL functions' access.
236  *
237  *  @return True if passed, false otherwise.
238  */
EnableDisableTest(const glw::Functions & gl)239 bool glcts::ClipDistance::CoverageTest::EnableDisableTest(const glw::Functions &gl)
240 {
241     /*  Check that calling Enable and Disable with GL_CLIP_DISTANCEi for all
242      available clip distances does not generate errors.
243      glw::GLint error_code = GL_NO_ERROR; */
244 
245     glw::GLint error_code = GL_NO_ERROR;
246 
247     /* Test glEnable */
248     for (glw::GLint i = 0; i < m_gl_max_clip_distances_value; ++i)
249     {
250         gl.enable(GL_CLIP_DISTANCE0 + i);
251 
252         error_code = gl.getError();
253 
254         if (error_code != GL_NO_ERROR)
255         {
256             m_testCtx.getLog() << tcu::TestLog::Message << "glEnable(GL_CLIP_DISTANCE" << i << ") returned error code "
257                                << glu::getErrorStr(error_code) << " instead of GL_NO_ERROR."
258                                << tcu::TestLog::EndMessage;
259 
260             return false;
261         }
262     }
263 
264     /* Test glDisable */
265     for (glw::GLint i = 0; i < m_gl_max_clip_distances_value; ++i)
266     {
267         gl.disable(GL_CLIP_DISTANCE0 + i);
268 
269         error_code = gl.getError();
270 
271         if (error_code != GL_NO_ERROR)
272         {
273             m_testCtx.getLog() << tcu::TestLog::Message << "glDisable(GL_CLIP_DISTANCE" << i << ") returned error code "
274                                << glu::getErrorStr(error_code) << " instead of GL_NO_ERROR."
275                                << tcu::TestLog::EndMessage;
276 
277             return false;
278         }
279     }
280 
281     return true;
282 }
283 
284 /* @brief gl_MaxClipDistances value test in the vertex shader coverage test.
285  *
286  *  @param [in] gl                  OpenGL functions' access.
287  *
288  *  @return True if passed, false otherwise.
289  */
MaxClipDistancesValueInVertexShaderTest(const glw::Functions & gl)290 bool glcts::ClipDistance::CoverageTest::MaxClipDistancesValueInVertexShaderTest(const glw::Functions &gl)
291 {
292     /*  Make a program that consist of vertex and fragment shader stages. A
293      vertex shader shall assign the value of gl_MaxClipDistances to transform
294      feedback output variable. Setup gl_Position with passed in attribute.
295      Use blank fragment shader. Check that the shaders compiles and links
296      successfully. Draw a single GL_POINT with screen centered position
297      attribute, a configured transform feedback and GL_RASTERIZER_DISCARD.
298      Query transform feedback value and compare it against
299      GL_MAX_CLIP_DISTANCES. Expect that both values are equal. */
300 
301     /* Building program. */
302     std::string vertex_shader   = tcu::StringTemplate(m_vertex_shader_code_case_0).specialize(specializationMap);
303     std::string fragment_shader = tcu::StringTemplate(m_fragment_shader_code_case_0).specialize(specializationMap);
304 
305     std::string transform_feedback_varying_name = "max_value";
306 
307     std::vector<std::string> transform_feedback_varyings(1, transform_feedback_varying_name);
308 
309     glcts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader, transform_feedback_varyings);
310 
311     if (program.ProgramStatus().program_id == 0)
312     {
313         m_testCtx.getLog() << tcu::TestLog::Message << "Program failed to build.\n Vertex Shader:\n"
314                            << vertex_shader << "\nWith Vertex Shader compilation log:\n"
315                            << program.VertexShaderStatus().shader_log << "\nWith Fragment Shader:\n"
316                            << fragment_shader << "\nWith Fragment Shader compilation log:\n"
317                            << program.FragmentShaderStatus().shader_log << "\nWith Program linkage log:\n"
318                            << program.ProgramStatus().program_linkage_log << "\n"
319                            << tcu::TestLog::EndMessage;
320         return false;
321     }
322 
323     program.UseProgram();
324 
325     /* Creating and binding empty VAO. */
326     glcts::ClipDistance::Utility::VertexArrayObject vertex_array_object(gl, GL_POINTS);
327 
328     /* Creating and binding output VBO */
329     glcts::ClipDistance::Utility::VertexBufferObject<glw::GLint> vertex_buffer_object(gl, GL_TRANSFORM_FEEDBACK_BUFFER,
330                                                                                       std::vector<glw::GLint>(1, 0));
331 
332     /* Draw test. */
333     vertex_array_object.drawWithTransformFeedback(0, 1, true);
334 
335     /* Check results. */
336     std::vector<glw::GLint> results = vertex_buffer_object.readBuffer(m_isContextES);
337 
338     if (results.size() < 1)
339     {
340         m_testCtx.getLog() << tcu::TestLog::Message << "Results reading error." << tcu::TestLog::EndMessage;
341         return false;
342     }
343 
344     if (results[0] != m_gl_max_clip_distances_value)
345     {
346         m_testCtx.getLog() << tcu::TestLog::Message
347                            << "Vertex shader's gl_MaxClipDistances constant has improper value equal to " << results[0]
348                            << "but " << m_gl_max_clip_distances_value << "is expected. Test failed."
349                            << tcu::TestLog::EndMessage;
350         return false;
351     }
352 
353     /* Test passed. */
354     return true;
355 }
356 
357 /* @brief gl_MaxClipDistances value test in the fragment shader coverage test.
358  *
359  *  @param [in] gl                  OpenGL functions' access.
360  *
361  *  @return True if passed, false otherwise.
362  */
MaxClipDistancesValueInFragmentShaderTest(const glw::Functions & gl)363 bool glcts::ClipDistance::CoverageTest::MaxClipDistancesValueInFragmentShaderTest(const glw::Functions &gl)
364 {
365     /*  Make a program that consist of vertex and fragment shader stages. In
366      vertex shader setup gl_Position with passed in attribute. Check in
367      fragment shader using "if" statement that gl_MaxClipDistances is equal
368      to GL_MAX_CLIP_DISTANCES passed by uniform. If compared values are not
369      equal, discard the fragment. Output distinguishable color otherwise.
370      Check that the shader program compiles and links successfully. Draw a
371      single GL_POINT with screen centered position attribute and with a
372      configured 1 x 1 pixel size framebuffer. Using glReadPixels function,
373      check that point's fragments were not discarded. */
374 
375     /* Creating red-color-only frambuffer. */
376     glcts::ClipDistance::Utility::Framebuffer framebuffer(gl, 1, 1);
377 
378     if (!framebuffer.isValid())
379     {
380         m_testCtx.getLog() << tcu::TestLog::Message << "Unable to create framebuffer with size [1,1].\n"
381                            << tcu::TestLog::EndMessage;
382         return false;
383     }
384 
385     framebuffer.bind();
386     framebuffer.clear();
387 
388     /* Building program. */
389     std::string vertex_shader   = tcu::StringTemplate(m_vertex_shader_code_case_1).specialize(specializationMap);
390     std::string fragment_shader = tcu::StringTemplate(m_fragment_shader_code_case_1).specialize(specializationMap);
391 
392     glcts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader);
393 
394     if (program.ProgramStatus().program_id == 0)
395     {
396         m_testCtx.getLog() << tcu::TestLog::Message << "Program failed to build.\n Vertex Shader:\n"
397                            << vertex_shader << "\nWith Vertex Shader compilation log:\n"
398                            << program.VertexShaderStatus().shader_log << "\nWith Fragment Shader:\n"
399                            << fragment_shader << "\nWith Fragment Shader compilation log:\n"
400                            << program.FragmentShaderStatus().shader_log << "\nWith Program linkage log:\n"
401                            << program.ProgramStatus().program_linkage_log << "\n"
402                            << tcu::TestLog::EndMessage;
403 
404         return false;
405     }
406 
407     program.UseProgram();
408 
409     /* Creating empty VAO. */
410     glcts::ClipDistance::Utility::VertexArrayObject vertex_array_object(gl, GL_POINTS);
411 
412     /* Draw test. */
413     vertex_array_object.draw(0, 1);
414 
415     /* Fetch results. */
416     std::vector<glw::GLfloat> pixels = framebuffer.readPixels();
417 
418     if (pixels.size() < 1)
419     {
420         m_testCtx.getLog() << tcu::TestLog::Message << "ReadPixels error.\n" << tcu::TestLog::EndMessage;
421         return false;
422     }
423 
424     /* Check results. */
425     glw::GLuint gl_max_clip_distances_value_in_fragment_shader = glw::GLuint(pixels.front());
426 
427     if (gl_max_clip_distances_value_in_fragment_shader != glw::GLuint(m_gl_max_clip_distances_value))
428     {
429         m_testCtx.getLog() << tcu::TestLog::Message
430                            << "Fragment shader's gl_MaxClipDistances constant has improper value equal to "
431                            << gl_max_clip_distances_value_in_fragment_shader << "but " << m_gl_max_clip_distances_value
432                            << "is expected. Test failed." << tcu::TestLog::EndMessage;
433         return false;
434     }
435 
436     /* Test passed. */
437     return true;
438 }
439 
440 /* @brief Vertex shader to fragment shader passing coverage test.
441  *
442  *  @param [in] gl                  OpenGL functions' access.
443  *
444  *  @return True if passed, false otherwise.
445  */
ClipDistancesValuePassing(const glw::Functions & gl)446 bool glcts::ClipDistance::CoverageTest::ClipDistancesValuePassing(const glw::Functions &gl)
447 {
448     /*  Make a program that consist of vertex and fragment shader stages.
449      Redeclare gl_ClipDistance with size equal to GL_MAX_CLIP_DISTANCES in
450      vertex and fragment shader. In vertex shader, assign values to
451      gl_ClipDistance array using function of clip distance index i:
452 
453      f(i) = float(i + 1) / float(gl_MaxClipDistances).
454 
455      Setup gl_Position with passed in attribute. Read gl_ClipDistance in the
456      fragment shader and compare them with the same function. Take into
457      account low precision errors. If compared values are not equal, discard
458      the fragment. Output distinguishable color otherwise. Check that the
459      shaders compiles and the program links successfully. Enable all
460      GL_CLIP_DISTANCEs. Draw a single GL_POINT with screen centered position
461      attribute and with a configured 1 x 1 pixel size framebuffer. Using
462      glReadPixels function, check that point's fragments were not discarded. */
463 
464     /* Creating red-color-only frambuffer. */
465     glcts::ClipDistance::Utility::Framebuffer framebuffer(gl, 1, 1);
466 
467     if (!framebuffer.isValid())
468     {
469         m_testCtx.getLog() << tcu::TestLog::Message << "Unable to create framebuffer with size [1,1].\n"
470                            << tcu::TestLog::EndMessage;
471         return false;
472     }
473 
474     framebuffer.bind();
475     framebuffer.clear();
476 
477     /* Building program. */
478     std::string vertex_shader   = tcu::StringTemplate(m_vertex_shader_code_case_2).specialize(specializationMap);
479     std::string fragment_shader = tcu::StringTemplate(m_fragment_shader_code_case_2).specialize(specializationMap);
480 
481     glcts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader);
482 
483     if (program.ProgramStatus().program_id == 0)
484     {
485         m_testCtx.getLog() << tcu::TestLog::Message << "Program failed to build.\n Vertex Shader:\n"
486                            << vertex_shader << "\nWith Vertex Shader compilation log:\n"
487                            << program.VertexShaderStatus().shader_log << "\nWith Fragment Shader:\n"
488                            << fragment_shader << "\nWith Fragment Shader compilation log:\n"
489                            << program.FragmentShaderStatus().shader_log << "\nWith Program linkage log:\n"
490                            << program.ProgramStatus().program_linkage_log << "\n"
491                            << tcu::TestLog::EndMessage;
492         return false;
493     }
494 
495     program.UseProgram();
496 
497     /* Creating empty VAO. */
498     glcts::ClipDistance::Utility::VertexArrayObject vertex_array_object(gl, GL_POINTS);
499 
500     /* Draw test. */
501     vertex_array_object.draw(0, 1);
502 
503     /* Fetch results. */
504     std::vector<glw::GLfloat> pixels = framebuffer.readPixels();
505 
506     if (pixels.size() < 1)
507     {
508         m_testCtx.getLog() << tcu::TestLog::Message << "ReadPixels error.\n" << tcu::TestLog::EndMessage;
509         return false;
510     }
511 
512     /* Check results. */
513     glw::GLfloat results = pixels.front();
514 
515     if (fabs(results - 1.f) > 0.0125)
516     {
517         m_testCtx.getLog() << tcu::TestLog::Message
518                            << "Fragment shader values of gl_Clip_distance does not match vertex shader's output value."
519                            << tcu::TestLog::EndMessage;
520         return false;
521     }
522 
523     /* Test passed. */
524     return true;
525 }
526 
527 /** @brief Vertex shader source code to test gl_MaxClipDistances limit value in vertex shader (API Coverage Test). */
528 const glw::GLchar *glcts::ClipDistance::CoverageTest::m_vertex_shader_code_case_0 =
529     "${VERSION}\n"
530     "${EXTENSION}\n"
531     "flat out int max_value;\n"
532     "\n"
533     "void main()\n"
534     "{\n"
535     "    max_value   = gl_MaxClipDistances;\n"
536     "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
537     "}\n";
538 
539 /** @brief Fragment shader source code to test gl_MaxClipDistances limit value in vertex shader (API Coverage Test). */
540 const glw::GLchar *glcts::ClipDistance::CoverageTest::m_fragment_shader_code_case_0 =
541     "${VERSION}\n"
542     "${PRECISION}\n"
543     "out vec4 color;\n"
544     "\n"
545     "void main()\n"
546     "{\n"
547     "    color = vec4(0.0, 0.0, 0.0, 1.0);\n"
548     "}\n";
549 
550 /** @brief Vertex shader source code to test gl_MaxClipDistances limit value in fragment shader (API Coverage Test). */
551 const glw::GLchar *glcts::ClipDistance::CoverageTest::m_vertex_shader_code_case_1 =
552     "${VERSION}\n"
553     "\n"
554     "void main()\n"
555     "{\n"
556     "    gl_Position  = vec4(0.0, 0.0, 0.0, 1.0);\n"
557     "}\n";
558 
559 /** @brief Fragment shader source code to test gl_MaxClipDistances limit value in fragment shader (API Coverage Test). */
560 const glw::GLchar *glcts::ClipDistance::CoverageTest::m_fragment_shader_code_case_1 =
561     "${VERSION}\n"
562     "${EXTENSION}\n"
563     "${PRECISION}\n"
564     "\n"
565     "out highp vec4 color;\n"
566     "\n"
567     "void main()\n"
568     "{\n"
569     "    color = vec4(float(gl_MaxClipDistances), 0.0, 0.0, 1.0);\n"
570     "}\n";
571 
572 /** @brief Vertex shader source code to test if the gl_ClipDistance[] are passed properly to the fragment shader from vertex shader (API Coverage Test). */
573 const glw::GLchar *glcts::ClipDistance::CoverageTest::m_vertex_shader_code_case_2 =
574     "${VERSION}\n"
575     "${EXTENSION}\n"
576     "\n"
577     "out float gl_ClipDistance[gl_MaxClipDistances];\n"
578     "\n"
579     "void main()\n"
580     "{\n"
581     "    for(int i = 0; i < gl_MaxClipDistances; i++)\n"
582     "    {\n"
583     "        gl_ClipDistance[i] = float(i + 1) / float(gl_MaxClipDistances);\n"
584     "    }\n"
585     "\n"
586     "    gl_Position  = vec4(0.0, 0.0, 0.0, 1.0);\n"
587     "}\n";
588 
589 /** @brief Fragment shader source code to test if the gl_ClipDistance[] are passed properly to the fragment shader from vertex shader (API Coverage Test). */
590 const glw::GLchar *glcts::ClipDistance::CoverageTest::m_fragment_shader_code_case_2 =
591     "${VERSION}\n"
592     "${EXTENSION}\n"
593     "${PRECISION}\n"
594     "\n"
595     "in float gl_ClipDistance[gl_MaxClipDistances];\n"
596     "\n"
597     "out highp vec4 color;\n"
598     "\n"
599     "void main()\n"
600     "{\n"
601     "    for(int i = 0; i < gl_MaxClipDistances; i++)\n"
602     "    {\n"
603     "        if(abs(gl_ClipDistance[i] - float(i + 1) / float(gl_MaxClipDistances)) > 0.0125)\n"
604     "        {\n"
605     "            discard;\n"
606     "        }\n"
607     "    }\n"
608     "\n"
609     "    color = vec4(1.0, 0.0, 0.0, 1.0);\n"
610     "}\n";
611 
612 /******************************** Functional Tests Implementation ********************************/
613 
614 /** @brief Functional test constructor.
615  *
616  *  @param [in] context     OpenGL context.
617  */
FunctionalTest(deqp::Context & context)618 glcts::ClipDistance::FunctionalTest::FunctionalTest(deqp::Context &context)
619     : ClipDistanceTestBase(context, "functional", "Clip Distance Functional Test")
620     , m_gl_max_clip_distances_value(8) /* Specification minimum required */
621 {
622     /* Intentionally left blank */
623 }
624 
625 /** @brief functional test cases.
626  */
test()627 void glcts::ClipDistance::FunctionalTest::test()
628 {
629     /* Shortcut for GL functionality */
630     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
631 
632     gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &m_gl_max_clip_distances_value);
633 
634     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
635 
636     /* Functional test */
637 
638     /* For all primitive modes. */
639     for (glw::GLuint i_primitive_type = 0; i_primitive_type < m_primitive_types_count; ++i_primitive_type)
640     {
641         glw::GLenum primitive_type          = m_primitive_types[i_primitive_type];
642         glw::GLenum primitive_indices_count = m_primitive_indices[i_primitive_type];
643 
644         /* Framebuffer setup. */
645         glw::GLuint framebuffer_size = (primitive_type == GL_POINTS) ? 1 : 32;
646 
647         glcts::ClipDistance::Utility::Framebuffer framebuffer(gl, framebuffer_size,
648                                                               framebuffer_size); /* Framebuffer shall be square */
649 
650         framebuffer.bind();
651 
652         /* For all clip combinations. */
653         for (glw::GLuint i_clip_function = 0;
654              i_clip_function <
655              m_clip_function_count -
656                  int(i_primitive_type == GL_POINTS); /* Do not use last clip function with GL_POINTS. */
657              ++i_clip_function)
658         {
659             /* For both redeclaration types (implicit/explicit). */
660             for (glw::GLuint i_redeclaration = 0; i_redeclaration < 2; ++i_redeclaration)
661             {
662                 bool redeclaration = (i_redeclaration == 1);
663 
664                 /* For different clip array sizes. */
665                 for (glw::GLuint i_clip_count = 1; i_clip_count <= glw::GLuint(m_gl_max_clip_distances_value);
666                      ++i_clip_count)
667                 {
668                     /* Create and build program. */
669                     std::string vs_code, fs_code;
670                     glcts::ClipDistance::FunctionalTest::prepareShaderCode(
671                         redeclaration, redeclaration, i_clip_count, i_clip_function, primitive_type, vs_code, fs_code);
672 
673                     glcts::ClipDistance::Utility::Program program(gl, vs_code, fs_code);
674 
675                     if (program.ProgramStatus().program_id == GL_NONE)
676                     {
677                         /* Result's setup. */
678                         m_testCtx.getLog()
679                             << tcu::TestLog::Message
680                             << "Functional test have failed when building program.\nVertex shader code:\n"
681                             << vs_code << "\nWith Vertex Shader compilation log:\n"
682                             << program.VertexShaderStatus().shader_log << "\nWith Fragment Shader:\n"
683                             << fs_code << "\nWith Fragment Shader compilation log:\n"
684                             << program.FragmentShaderStatus().shader_log << "\nWith Program linkage log:\n"
685                             << program.FragmentShaderStatus().shader_log << "\n"
686                             << tcu::TestLog::EndMessage;
687 
688                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
689 
690                         return;
691                     }
692 
693                     program.UseProgram();
694 
695                     /* Framebuffer clear */
696                     framebuffer.clear();
697 
698                     /* Clip setup */
699                     gl.enable(GL_CLIP_DISTANCE0 + i_clip_count - 1);
700 
701                     /* Geometry Setup */
702                     glcts::ClipDistance::Utility::VertexArrayObject vertex_array_object(gl, primitive_type);
703 
704                     glcts::ClipDistance::Utility::VertexBufferObject<glw::GLfloat> *vertex_buffer_object =
705                         prepareGeometry(gl, primitive_type);
706 
707                     if (!vertex_buffer_object->useAsShaderInput(program, "position", 4))
708                     {
709                         /* Result's setup. */
710                         m_testCtx.getLog() << tcu::TestLog::Message
711                                            << "Functional test have failed when enabling vertex attribute array.\n"
712                                            << tcu::TestLog::EndMessage;
713 
714                         m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
715 
716                         delete vertex_buffer_object;
717                         return;
718                     }
719 
720                     /* Draw geometry to the framebuffer */
721                     vertex_array_object.draw(0, primitive_indices_count);
722 
723                     /* Check results */
724                     std::vector<glw::GLfloat> results = framebuffer.readPixels();
725 
726                     if (!checkResults(primitive_type, i_clip_function, results))
727                     {
728                         /* Result's setup. */
729                         m_testCtx.getLog()
730                             << tcu::TestLog::Message << "Functional test have failed when drawing "
731                             << glu::getPrimitiveTypeStr(primitive_type) << ((redeclaration) ? " with " : " without ")
732                             << "dynamic redeclaration, when " << i_clip_count
733                             << " GL_CLIP_DISTANCES where enabled and set up using function:\n"
734                             << m_clip_function[i_clip_function] << tcu::TestLog::EndMessage;
735 
736                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
737 
738                         delete vertex_buffer_object;
739                         return;
740                     }
741 
742                     delete vertex_buffer_object;
743                 }
744 
745                 /* Clip clean */
746                 for (glw::GLuint i_clip_count = 0; i_clip_count < glw::GLuint(m_gl_max_clip_distances_value);
747                      ++i_clip_count)
748                 {
749                     gl.disable(GL_CLIP_DISTANCE0 + i_clip_count);
750                 }
751             }
752         }
753     }
754 
755     /* Result's setup. */
756 
757     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
758 }
759 
760 /** @brief Prepare vertex shader code for functional test.
761  *
762  *  @param [in] explicit_redeclaration      Use explicit redeclaration with size.
763  *  @param [in] dynamic_setter              Use dynamic array setter.
764  *  @param [in] clip_count                  Set all first # of gl_ClipDistance-s.
765  *  @param [in] clip_function               Use #th clip function for gl_ClipDistance[] setup (see m_clip_function[]).
766  *  @param [in] primitive_type              Primitive mode.
767  *  @param [out] vertex_shader              Compilation ready vertex shader source code.
768  *  @param [out] fragment_shader            Compilation ready fragment shader source code.
769  */
prepareShaderCode(bool explicit_redeclaration,bool dynamic_setter,glw::GLuint clip_count,glw::GLuint clip_function,glw::GLenum primitive_type,std::string & vertex_shader,std::string & fragment_shader)770 void glcts::ClipDistance::FunctionalTest::prepareShaderCode(bool explicit_redeclaration, bool dynamic_setter,
771                                                             glw::GLuint clip_count, glw::GLuint clip_function,
772                                                             glw::GLenum primitive_type, std::string &vertex_shader,
773                                                             std::string &fragment_shader)
774 {
775     vertex_shader   = m_vertex_shader_code;
776     fragment_shader = m_fragment_shader_code;
777 
778     if (explicit_redeclaration)
779     {
780         vertex_shader = glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_DISTANCE_REDECLARATION",
781                                                                      m_explicit_redeclaration);
782     }
783     else
784     {
785         vertex_shader = glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_DISTANCE_REDECLARATION", "");
786     }
787 
788     if (dynamic_setter)
789     {
790         vertex_shader =
791             glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_DISTANCE_SETUP", m_dynamic_array_setter);
792     }
793     else
794     {
795         std::string static_setters = "";
796 
797         for (glw::GLuint i = 0; i < clip_count; ++i)
798         {
799             std::string i_setter = m_static_array_setter;
800             i_setter             = glcts::ClipDistance::Utility::preprocessCode(i_setter, "CLIP_INDEX",
801                                                                                 glcts::ClipDistance::Utility::itoa(i));
802             static_setters.append(i_setter);
803         }
804 
805         vertex_shader =
806             glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_DISTANCE_SETUP", static_setters);
807     }
808 
809     vertex_shader =
810         glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_FUNCTION", m_clip_function[clip_function]);
811     vertex_shader = glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_COUNT",
812                                                                  glcts::ClipDistance::Utility::itoa(clip_count));
813     switch (primitive_type)
814     {
815     case GL_POINTS:
816         vertex_shader = glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "VERTEX_COUNT", "1");
817         break;
818     case GL_LINES:
819         vertex_shader = glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "VERTEX_COUNT", "2");
820         break;
821     case GL_TRIANGLES:
822         vertex_shader = glcts::ClipDistance::Utility::preprocessCode(vertex_shader, "VERTEX_COUNT", "3");
823         break;
824     }
825 
826     vertex_shader   = tcu::StringTemplate(vertex_shader).specialize(specializationMap);
827     fragment_shader = tcu::StringTemplate(fragment_shader).specialize(specializationMap);
828 }
829 
830 /** @brief Prepare geometry for functional test.
831  *
832  *  @param [in] gl                  OpenGL functions' access.
833  *  @param [in] primitive_type      Primitive mode.
834  *
835  *  @return Vertex Buffer Object pointer.
836  */
prepareGeometry(const glw::Functions & gl,const glw::GLenum primitive_type)837 glcts::ClipDistance::Utility::VertexBufferObject<glw::GLfloat> *glcts::ClipDistance::FunctionalTest::prepareGeometry(
838     const glw::Functions &gl, const glw::GLenum primitive_type)
839 {
840     std::vector<glw::GLfloat> data;
841 
842     switch (primitive_type)
843     {
844     case GL_POINTS:
845         data.push_back(0.0);
846         data.push_back(0.0);
847         data.push_back(0.0);
848         data.push_back(1.0);
849         break;
850     case GL_LINES:
851         data.push_back(1.0);
852         data.push_back(1.0);
853         data.push_back(0.0);
854         data.push_back(1.0);
855         data.push_back(-1.0);
856         data.push_back(-1.0);
857         data.push_back(0.0);
858         data.push_back(1.0);
859         break;
860     case GL_TRIANGLES:
861         data.push_back(-1.0);
862         data.push_back(-1.0);
863         data.push_back(0.0);
864         data.push_back(1.0);
865         data.push_back(0.0);
866         data.push_back(1.0);
867         data.push_back(0.0);
868         data.push_back(1.0);
869         data.push_back(1.0);
870         data.push_back(-1.0);
871         data.push_back(0.0);
872         data.push_back(1.0);
873         break;
874     default:
875         return NULL;
876     }
877 
878     return new glcts::ClipDistance::Utility::VertexBufferObject<glw::GLfloat>(gl, GL_ARRAY_BUFFER, data);
879 }
880 
881 /** @brief Check results fetched from framebuffer of functional test.
882  *
883  *  @param [in] primitive_type      Primitive mode.
884  *  @param [in] clip_function       Use #th clip function for gl_ClipDistance[] setup (see m_clip_function[]).
885  *  @param [in] results             Array with framebuffer content.
886  *
887  *  @return True if proper result, false otherwise.
888  */
checkResults(glw::GLenum primitive_type,glw::GLuint clip_function,std::vector<glw::GLfloat> & results)889 bool glcts::ClipDistance::FunctionalTest::checkResults(glw::GLenum primitive_type, glw::GLuint clip_function,
890                                                        std::vector<glw::GLfloat> &results)
891 {
892     /* Check for errors */
893     if (results.size() == 0)
894     {
895         return false;
896     }
897 
898     /* Calculate surface/line integral */
899     glw::GLfloat integral = 0.f;
900 
901     glw::GLuint increment = (glw::GLuint)((primitive_type == GL_LINES) ?
902                                               glw::GLuint(sqrt(glw::GLfloat(results.size()))) + 1 /* line integral */ :
903                                               1 /* surface integral */);
904     glw::GLuint base      = (glw::GLuint)((primitive_type == GL_LINES) ?
905                                               glw::GLuint(sqrt(glw::GLfloat(results.size()))) /* line integral */ :
906                                               results.size() /* surface integral */);
907 
908     for (glw::GLuint i_pixels = 0; i_pixels < results.size(); i_pixels += increment)
909     {
910         integral += results[i_pixels];
911     }
912 
913     integral /= static_cast<glw::GLfloat>(base);
914 
915     /* Check with results' lookup table */
916     glw::GLuint i_primitive_type = (primitive_type == GL_POINTS) ? 0 : ((primitive_type == GL_LINES) ? 1 : 2);
917 
918     if (fabs(m_expected_integral[i_primitive_type * m_clip_function_count + clip_function] - integral) >
919         0.01 /* Precision */)
920     {
921         return false;
922     }
923 
924     return true;
925 }
926 
927 /* @brief Vertex Shader template for functional tests. */
928 const glw::GLchar *glcts::ClipDistance::FunctionalTest::m_vertex_shader_code = "${VERSION}\n"
929                                                                                "${EXTENSION}\n"
930                                                                                "\n"
931                                                                                "CLIP_DISTANCE_REDECLARATION"
932                                                                                "\n"
933                                                                                "CLIP_FUNCTION"
934                                                                                "\n"
935                                                                                "in vec4 position;\n"
936                                                                                "\n"
937                                                                                "void main()\n"
938                                                                                "{\n"
939                                                                                "CLIP_DISTANCE_SETUP"
940                                                                                "\n"
941                                                                                "    gl_Position  = position;\n"
942                                                                                "}\n";
943 
944 /* @brief Explicit redeclaration key value to preprocess the Vertex Shader template for functional tests. */
945 const glw::GLchar *glcts::ClipDistance::FunctionalTest::m_explicit_redeclaration =
946     "out float gl_ClipDistance[CLIP_COUNT];\n";
947 
948 /* @brief Dynamic array setter key value to preprocess the Vertex Shader template for functional tests. */
949 const glw::GLchar *glcts::ClipDistance::FunctionalTest::m_dynamic_array_setter =
950     "    for(int i = 0; i < CLIP_COUNT; i++)\n"
951     "    {\n"
952     "        gl_ClipDistance[i] = f(i);\n"
953     "    }\n";
954 
955 /* @brief Static array setter key value to preprocess the Vertex Shader template for functional tests. */
956 const glw::GLchar *glcts::ClipDistance::FunctionalTest::m_static_array_setter =
957     "    gl_ClipDistance[CLIP_INDEX] = f(CLIP_INDEX);\n";
958 
959 /* @brief Clip Distance functions to preprocess the Vertex Shader template for functional tests. */
960 const glw::GLchar *glcts::ClipDistance::FunctionalTest::m_clip_function[] = {
961     "float f(int i)\n"
962     "{\n"
963     "    return 0.0;\n"
964     "}\n",
965 
966     "float f(int i)\n"
967     "{\n"
968     "    return 0.25 + 0.75 * (float(i) + 1.0) * (float(gl_VertexID) + 1.0) / (float(CLIP_COUNT) * "
969     "float(VERTEX_COUNT));\n"
970     "}\n",
971 
972     "float f(int i)\n"
973     "{\n"
974     "    return - 0.25 - 0.75 * (float(i) + 1.0) * (float(gl_VertexID) + 1.0) / (float(CLIP_COUNT) * "
975     "float(VERTEX_COUNT));\n"
976     "}\n",
977 
978     /* This case must be last (it is not rendered for GL_POINTS). */
979     "#define PI 3.1415926535897932384626433832795\n"
980     "\n"
981     "float f(int i)\n"
982     "{\n"
983     "    if(i == 0)\n"
984     "    {\n"
985     /* This function case generates such series of gl_VertexID:
986      1.0, -1.0              -  for VERTEX_COUNT == 2 aka GL_LINES
987      1.0,  0.0, -1.0        -  for VERTEX_COUNT == 3 aka GL_TRIANGLES
988      and if needed in future:
989      1.0,  0.0, -1.0,  0.0  -  for VERTEX_COUNT == 4 aka GL_QUADS */
990     "        return cos( float(gl_VertexID) * PI / ceil( float(VERTEX_COUNT)/2.0 ) );\n"
991     "    }\n"
992     "\n"
993     "    return 0.25 + 0.75 * (float(i) + 1.0) * (float(gl_VertexID) + 1.0) / (float(CLIP_COUNT) * "
994     "float(VERTEX_COUNT));\n"
995     "}\n"};
996 
997 /* @brief Count of Clip Distance functions. */
998 const glw::GLuint glcts::ClipDistance::FunctionalTest::m_clip_function_count =
999     static_cast<glw::GLuint>(sizeof(m_clip_function) / sizeof(m_clip_function[0]));
1000 
1001 /* @brief Fragment shader source code for functional tests. */
1002 const glw::GLchar *glcts::ClipDistance::FunctionalTest::m_fragment_shader_code =
1003     "${VERSION}\n"
1004     "${PRECISION}\n"
1005     "\n"
1006     "out highp vec4 color;\n"
1007     "\n"
1008     "void main()\n"
1009     "{\n"
1010     "    color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1011     "}\n";
1012 
1013 /* @brief Primitive modes to be tested in functional test. */
1014 const glw::GLenum glcts::ClipDistance::FunctionalTest::m_primitive_types[] = {GL_POINTS, GL_LINES, GL_TRIANGLES};
1015 
1016 /* @brief Number of primitive indices for each primitive mode. */
1017 const glw::GLenum glcts::ClipDistance::FunctionalTest::m_primitive_indices[] = {1, 2, 3};
1018 
1019 /* @brief Primitive modes count. */
1020 const glw::GLuint glcts::ClipDistance::FunctionalTest::m_primitive_types_count =
1021     static_cast<glw::GLuint>(sizeof(m_primitive_types) / sizeof(m_primitive_types[0]));
1022 
1023 /* @brief Expected results of testing integral for functional test. */
1024 const glw::GLfloat
1025     glcts::ClipDistance::FunctionalTest::m_expected_integral[m_primitive_types_count * m_clip_function_count] = {
1026         1.0, 1.0, 0.0, 0.0, /* for GL_POINTS    */
1027         1.0, 1.0, 0.0, 0.5, /* for GL_LINES     */
1028         0.5, 0.5, 0.0, 0.25 /* for GL_TRIANGLES */
1029 };
1030 
1031 /******************************** Negative Tests Implementation   ********************************/
1032 
1033 /** @brief Negative tests constructor.
1034  *
1035  *  @param [in] context     OpenGL context.
1036  */
NegativeTest(deqp::Context & context)1037 glcts::ClipDistance::NegativeTest::NegativeTest(deqp::Context &context)
1038     : ClipDistanceTestBase(context, "negative", "Clip Distance Negative Tests")
1039 {
1040     /* Intentionally left blank */
1041 }
1042 
1043 /** @brief Iterate negative tests
1044  *
1045  *  @return Iteration result.
1046  */
test()1047 void glcts::ClipDistance::NegativeTest::test()
1048 {
1049     /* Shortcut for GL functionality */
1050     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1051 
1052     /* Iterate tests */
1053     bool is_ok     = true;
1054     bool may_be_ok = true;
1055 
1056     is_ok     = is_ok && testClipVertexBuildingErrors(gl);
1057     is_ok     = is_ok && testMaxClipDistancesBuildingErrors(gl);
1058     may_be_ok = may_be_ok && testClipDistancesRedeclarationBuildingErrors(gl);
1059 
1060     /* Result's setup. */
1061     if (is_ok)
1062     {
1063         if (may_be_ok)
1064         {
1065             m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1066         }
1067         else
1068         {
1069             m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Pass with warning");
1070         }
1071     }
1072     else
1073     {
1074         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1075     }
1076 }
1077 
1078 /** @brief Clip Distance / Clip Vertex negative test sub-case.
1079  *
1080  *  @param [in] gl  OpenGL functions' access.
1081  *
1082  *  @return True if passed, false otherwise.
1083  */
testClipVertexBuildingErrors(const glw::Functions & gl)1084 bool glcts::ClipDistance::NegativeTest::testClipVertexBuildingErrors(const glw::Functions &gl)
1085 {
1086     /* If OpenGL version < 3.1 is available, check that building shader program
1087      fails when vertex shader statically writes to both gl_ClipVertex and
1088      gl_ClipDistance[0]. Validate that the vertex shader which statically
1089      writes to only the gl_ClipVertex or to the gl_ClipDistance[0] builds
1090      without fail. */
1091 
1092     /* This test should only be executed if we're running a GL3.0 or less context,
1093        the output variable gl_ClipVertex was removed from OpenGL ES Shading Language. */
1094     if (m_isContextES ||
1095         !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType(3, 1, glu::PROFILE_CORE)))
1096     {
1097         return true;
1098     }
1099 
1100     std::string vertex_shader   = tcu::StringTemplate(m_vertex_shader_code_case_0).specialize(specializationMap);
1101     std::string fragment_shader = tcu::StringTemplate(m_fragment_shader_code).specialize(specializationMap);
1102 
1103     glcts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader);
1104 
1105     if (program.ProgramStatus().program_id)
1106     {
1107         m_testCtx.getLog() << tcu::TestLog::Message
1108                            << "Functional test have failed. "
1109                               "Building shader which statically writes to both gl_ClipVertex "
1110                               "and gl_ClipDistances[] has unexpectedly succeeded."
1111                            << tcu::TestLog::EndMessage;
1112 
1113         return false;
1114     }
1115 
1116     return true;
1117 }
1118 
1119 /** @brief Explicit redeclaration negative test sub-case.
1120  *
1121  *  @param [in] gl  OpenGL functions' access.
1122  *
1123  *  @return True if passed, false otherwise.
1124  */
testMaxClipDistancesBuildingErrors(const glw::Functions & gl)1125 bool glcts::ClipDistance::NegativeTest::testMaxClipDistancesBuildingErrors(const glw::Functions &gl)
1126 {
1127     /* Check that building shader program fails when gl_ClipDistance is
1128      redeclared in the shader with size higher than GL_MAX_CLIP_DISTANCES. */
1129 
1130     std::string vertex_shader   = tcu::StringTemplate(m_vertex_shader_code_case_1).specialize(specializationMap);
1131     std::string fragment_shader = tcu::StringTemplate(m_fragment_shader_code).specialize(specializationMap);
1132 
1133     glcts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader);
1134 
1135     if (program.ProgramStatus().program_id)
1136     {
1137         m_testCtx.getLog() << tcu::TestLog::Message
1138                            << "Functional test have failed. "
1139                               "Building shader with explicit redeclaration of gl_ClipDistance[] array with size "
1140                               "(gl_MaxClipDistances + 1) has unexpectedly succeeded."
1141                            << tcu::TestLog::EndMessage;
1142 
1143         return false;
1144     }
1145 
1146     return true;
1147 }
1148 
1149 /** @brief Implicit redeclaration negative test sub-case.
1150  *
1151  *  @param [in] gl  OpenGL functions' access.
1152  *
1153  *  @return True if passed, false when quality warning occured.
1154  */
testClipDistancesRedeclarationBuildingErrors(const glw::Functions & gl)1155 bool glcts::ClipDistance::NegativeTest::testClipDistancesRedeclarationBuildingErrors(const glw::Functions &gl)
1156 {
1157     /* Check that building shader program fails when gl_ClipDistance is not
1158      redeclared with explicit size and dynamic indexing is used.*/
1159 
1160     std::string vertex_shader   = tcu::StringTemplate(m_vertex_shader_code_case_2).specialize(specializationMap);
1161     std::string fragment_shader = tcu::StringTemplate(m_fragment_shader_code).specialize(specializationMap);
1162 
1163     glcts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader);
1164 
1165     if (program.ProgramStatus().program_id)
1166     {
1167         m_testCtx.getLog()
1168             << tcu::TestLog::Message
1169             << "Functional test have passed but with warning. "
1170                "Building shader without explicit redeclaration and with variable indexing has unexpectedly succeeded. "
1171                "This is within the bound of the specification (no error is being), but it may lead to errors."
1172             << tcu::TestLog::EndMessage;
1173 
1174         return false;
1175     }
1176 
1177     return true;
1178 }
1179 
1180 /** @brief Vertex shader source code for gl_ClipVertex negative test. */
1181 const glw::GLchar *glcts::ClipDistance::NegativeTest::m_vertex_shader_code_case_0 =
1182     "${VERSION}\n"
1183     "${EXTENSION}\n"
1184     "\n"
1185     "void main()\n"
1186     "{\n"
1187     "    gl_ClipDistance[0] = 0.0;\n"
1188     "    gl_ClipVertex       = vec4(0.0);\n"
1189     "    gl_Position         = vec4(1.0);\n"
1190     "}\n";
1191 
1192 /** @brief Vertex shader source code for explicit redeclaration negative test. */
1193 const glw::GLchar *glcts::ClipDistance::NegativeTest::m_vertex_shader_code_case_1 =
1194     "${VERSION}\n"
1195     "${EXTENSION}\n"
1196     "\n"
1197     "out float gl_ClipDistance[gl_MaxClipDistances + 1];\n"
1198     "\n"
1199     "void main()\n"
1200     "{\n"
1201     "    gl_ClipDistance[0] = 0.0;\n"
1202     "    gl_Position        = vec4(1.0);\n"
1203     "}\n";
1204 
1205 /** @brief Vertex shader source code for impilicit redeclaration negative test. */
1206 const glw::GLchar *glcts::ClipDistance::NegativeTest::m_vertex_shader_code_case_2 =
1207     "${VERSION}\n"
1208     "${EXTENSION}\n"
1209     "\n"
1210     "in int count;\n"
1211     "\n"
1212     "void main()\n"
1213     "{\n"
1214     "    for(int i = 0; i < count; i++)\n"
1215     "    {\n"
1216     "        gl_ClipDistance[i] = 0.0;\n"
1217     "    }\n"
1218     "\n"
1219     "    gl_Position = vec4(1.0);\n"
1220     "}\n";
1221 
1222 /** @brief Simple passthrough fragment shader source code for negative tests. */
1223 const glw::GLchar *glcts::ClipDistance::NegativeTest::m_fragment_shader_code = "${VERSION}\n"
1224                                                                                "${PRECISION}\n"
1225                                                                                "\n"
1226                                                                                "out vec4 color;\n"
1227                                                                                "\n"
1228                                                                                "void main()\n"
1229                                                                                "{\n"
1230                                                                                "    color = vec4(0.0, 0.0, 0.0, 1.0);\n"
1231                                                                                "}\n";
1232 
1233 /******************************** Utility Clases Implementations  ********************************/
1234 
1235 /** @brief Program constructor.
1236  *
1237  *  @param [in] gl                              OpenGL functions' access.
1238  *  @param [in] vertex_shader_code              Vertex shader source code.
1239  *  @param [in] fragment_shader_code            Fragment shader source code.
1240  *  @param [in] transform_feedback_varyings     Transform feedback varying names.
1241  */
Program(const glw::Functions & gl,const std::string & vertex_shader_code,const std::string & fragment_shader_code,std::vector<std::string> transform_feedback_varyings)1242 glcts::ClipDistance::Utility::Program::Program(const glw::Functions &gl, const std::string &vertex_shader_code,
1243                                                const std::string &fragment_shader_code,
1244                                                std::vector<std::string> transform_feedback_varyings)
1245     : m_gl(gl)
1246 {
1247     /* Compilation */
1248     const glw::GLchar *vertex_shader_code_c   = (const glw::GLchar *)vertex_shader_code.c_str();
1249     const glw::GLchar *fragment_shader_code_c = (const glw::GLchar *)fragment_shader_code.c_str();
1250 
1251     m_vertex_shader_status   = compileShader(GL_VERTEX_SHADER, &vertex_shader_code_c);
1252     m_fragment_shader_status = compileShader(GL_FRAGMENT_SHADER, &fragment_shader_code_c);
1253 
1254     /* Linking */
1255     m_program_status.program_id = 0;
1256     if (m_vertex_shader_status.shader_compilation_status && m_fragment_shader_status.shader_compilation_status)
1257     {
1258         m_program_status = linkShaders(m_vertex_shader_status, m_fragment_shader_status, transform_feedback_varyings);
1259     }
1260 
1261     /* Cleaning */
1262     if (m_vertex_shader_status.shader_id)
1263     {
1264         m_gl.deleteShader(m_vertex_shader_status.shader_id);
1265 
1266         m_vertex_shader_status.shader_id = 0;
1267     }
1268 
1269     if (m_fragment_shader_status.shader_id)
1270     {
1271         m_gl.deleteShader(m_fragment_shader_status.shader_id);
1272 
1273         m_fragment_shader_status.shader_id = 0;
1274     }
1275 }
1276 
1277 /** @brief Program destructor. */
~Program()1278 glcts::ClipDistance::Utility::Program::~Program()
1279 {
1280     if (m_vertex_shader_status.shader_id)
1281     {
1282         m_gl.deleteShader(m_vertex_shader_status.shader_id);
1283 
1284         m_vertex_shader_status.shader_id = 0;
1285     }
1286 
1287     if (m_fragment_shader_status.shader_id)
1288     {
1289         m_gl.deleteShader(m_fragment_shader_status.shader_id);
1290 
1291         m_fragment_shader_status.shader_id = 0;
1292     }
1293 
1294     if (m_program_status.program_id)
1295     {
1296         m_gl.deleteProgram(m_program_status.program_id);
1297 
1298         m_program_status.program_id = 0;
1299     }
1300 }
1301 
1302 /** @brief Vertex shader compilation status getter.
1303  *
1304  *  @return Vertex shader compilation status.
1305  */
1306 const glcts::ClipDistance::Utility::Program::CompilationStatus &glcts::ClipDistance::Utility::Program::
VertexShaderStatus() const1307     VertexShaderStatus() const
1308 {
1309     return m_vertex_shader_status;
1310 }
1311 
1312 /** @brief Fragment shader compilation status getter.
1313  *
1314  *  @return Fragment shader compilation status.
1315  */
1316 const glcts::ClipDistance::Utility::Program::CompilationStatus &glcts::ClipDistance::Utility::Program::
FragmentShaderStatus() const1317     FragmentShaderStatus() const
1318 {
1319     return m_fragment_shader_status;
1320 }
1321 
1322 /** @brief Program building status getter.
1323  *
1324  *  @return Program linkage status.
1325  */
ProgramStatus() const1326 const glcts::ClipDistance::Utility::Program::LinkageStatus &glcts::ClipDistance::Utility::Program::ProgramStatus() const
1327 {
1328     return m_program_status;
1329 }
1330 
1331 /** @brief Compile shader.
1332  *
1333  *  @param [in] shader_type     Shader type.
1334  *  @param [in] shader_code     Shader source code.
1335  *
1336  *  @return Compilation status.
1337  */
compileShader(const glw::GLenum shader_type,const glw::GLchar * const * shader_code)1338 glcts::ClipDistance::Utility::Program::CompilationStatus glcts::ClipDistance::Utility::Program::compileShader(
1339     const glw::GLenum shader_type, const glw::GLchar *const *shader_code)
1340 {
1341     CompilationStatus shader = {0, GL_NONE, ""};
1342 
1343     if (shader_code != nullptr)
1344     {
1345         try
1346         {
1347             /* Creation */
1348             shader.shader_id = m_gl.createShader(shader_type);
1349 
1350             GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader() call failed.");
1351 
1352             /* Compilation */
1353             m_gl.shaderSource(shader.shader_id, 1, shader_code, NULL);
1354 
1355             GLU_EXPECT_NO_ERROR(m_gl.getError(), "glShaderSource() call failed.");
1356 
1357             m_gl.compileShader(shader.shader_id);
1358 
1359             GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCompileShader() call failed.");
1360 
1361             /* Status */
1362             m_gl.getShaderiv(shader.shader_id, GL_COMPILE_STATUS, &shader.shader_compilation_status);
1363 
1364             GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv() call failed.");
1365 
1366             /* Logging */
1367             if (shader.shader_compilation_status == GL_FALSE)
1368             {
1369                 glw::GLint log_size = 0;
1370 
1371                 m_gl.getShaderiv(shader.shader_id, GL_INFO_LOG_LENGTH, &log_size);
1372 
1373                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv() call failed.");
1374 
1375                 if (log_size)
1376                 {
1377                     glw::GLchar *log = new glw::GLchar[log_size];
1378 
1379                     if (log)
1380                     {
1381                         memset(log, 0, log_size);
1382 
1383                         m_gl.getShaderInfoLog(shader.shader_id, log_size, nullptr, log);
1384 
1385                         shader.shader_log = log;
1386 
1387                         delete[] log;
1388 
1389                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderInfoLog() call failed.");
1390                     }
1391                 }
1392             }
1393         }
1394         catch (...)
1395         {
1396             if (shader.shader_id)
1397             {
1398                 m_gl.deleteShader(shader.shader_id);
1399 
1400                 shader.shader_id = 0;
1401             }
1402         }
1403     }
1404 
1405     return shader;
1406 }
1407 
1408 /** @brief Link compiled shaders.
1409  *
1410  *  @param [in] vertex_shader                   Vertex shader compilation status.
1411  *  @param [in] fragment_shader                 Fragment shader compilation status.
1412  *  @param [in] transform_feedback_varyings     Transform feedback varying names array.
1413  *
1414  *  @return Linkage status.
1415  */
linkShaders(const CompilationStatus & vertex_shader,const CompilationStatus & fragment_shader,std::vector<std::string> & transform_feedback_varyings)1416 glcts::ClipDistance::Utility::Program::LinkageStatus glcts::ClipDistance::Utility::Program::linkShaders(
1417     const CompilationStatus &vertex_shader, const CompilationStatus &fragment_shader,
1418     std::vector<std::string> &transform_feedback_varyings)
1419 {
1420     LinkageStatus program = {0, GL_NONE, ""};
1421 
1422     if (vertex_shader.shader_id && fragment_shader.shader_id)
1423     {
1424         try
1425         {
1426             /* Creation */
1427             program.program_id = m_gl.createProgram();
1428 
1429             GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader() call failed.");
1430 
1431             if (program.program_id)
1432             {
1433                 /* Transform Feedback setup */
1434                 for (std::vector<std::string>::iterator i = transform_feedback_varyings.begin();
1435                      i != transform_feedback_varyings.end(); ++i)
1436                 {
1437                     const glw::GLchar *varying = i->c_str();
1438 
1439                     m_gl.transformFeedbackVaryings(program.program_id, 1, &varying, GL_INTERLEAVED_ATTRIBS);
1440 
1441                     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTransformFeedbackVaryings() call failed.");
1442                 }
1443 
1444                 /* Linking */
1445                 m_gl.attachShader(program.program_id, vertex_shader.shader_id);
1446 
1447                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader() call failed.");
1448 
1449                 m_gl.attachShader(program.program_id, fragment_shader.shader_id);
1450 
1451                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader() call failed.");
1452 
1453                 m_gl.linkProgram(program.program_id);
1454 
1455                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glLinkProgram() call failed.");
1456 
1457                 /* Status query */
1458                 m_gl.getProgramiv(program.program_id, GL_LINK_STATUS, &program.program_linkage_status);
1459 
1460                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramiv() call failed.");
1461 
1462                 /* Logging */
1463                 if (program.program_linkage_status == GL_FALSE)
1464                 {
1465                     glw::GLint log_size = 0;
1466 
1467                     m_gl.getProgramiv(program.program_id, GL_INFO_LOG_LENGTH, &log_size);
1468 
1469                     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramiv() call failed.");
1470 
1471                     if (log_size)
1472                     {
1473                         glw::GLchar *log = new glw::GLchar[log_size];
1474 
1475                         if (log)
1476                         {
1477                             memset(log, 0, log_size);
1478 
1479                             m_gl.getProgramInfoLog(program.program_id, log_size, nullptr, log);
1480 
1481                             program.program_linkage_log = log;
1482 
1483                             delete[] log;
1484 
1485                             GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramInfoLog() call failed.");
1486                         }
1487                     }
1488                 }
1489 
1490                 /* Cleanup */
1491                 m_gl.detachShader(program.program_id, vertex_shader.shader_id);
1492 
1493                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader() call failed.");
1494 
1495                 m_gl.detachShader(program.program_id, fragment_shader.shader_id);
1496 
1497                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader() call failed.");
1498 
1499                 if (program.program_linkage_status == GL_FALSE)
1500                 {
1501                     m_gl.deleteProgram(program.program_id);
1502 
1503                     program.program_id = 0;
1504                 }
1505             }
1506         }
1507         catch (...)
1508         {
1509             if (program.program_id)
1510             {
1511                 m_gl.deleteProgram(program.program_id);
1512 
1513                 program.program_id = 0;
1514             }
1515         }
1516     }
1517 
1518     return program;
1519 }
1520 
1521 /** @brief Use program for drawing. */
UseProgram() const1522 void glcts::ClipDistance::Utility::Program::UseProgram() const
1523 {
1524     m_gl.useProgram(ProgramStatus().program_id);
1525     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram call failed.");
1526 }
1527 
1528 /** @brief Framebuffer (GL_32R only) constructor.
1529  *
1530  * @param [in] gl           OpenGL functions access.
1531  * @param [in] size_x       X size of framebuffer.
1532  * @param [in] size_y       Y size of framebuffer.
1533  */
Framebuffer(const glw::Functions & gl,const glw::GLsizei size_x,const glw::GLsizei size_y)1534 glcts::ClipDistance::Utility::Framebuffer::Framebuffer(const glw::Functions &gl, const glw::GLsizei size_x,
1535                                                        const glw::GLsizei size_y)
1536     : m_gl(gl)
1537     , m_size_x(size_x)
1538     , m_size_y(size_y)
1539     , m_framebuffer_id(0)
1540     , m_renderbuffer_id(0)
1541 {
1542     m_gl.genFramebuffers(1, &m_framebuffer_id);
1543     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers call failed.");
1544 
1545     m_gl.genRenderbuffers(1, &m_renderbuffer_id);
1546     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenRenderbuffers call failed.");
1547 
1548     m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_id);
1549     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer call failed.");
1550 
1551     m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer_id);
1552     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindRenderbuffer call failed.");
1553 
1554     m_gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32F, m_size_x, m_size_y);
1555     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glRenderbufferStorage call failed.");
1556 
1557     m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer_id);
1558     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferRenderbuffer call failed.");
1559 
1560     if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
1561     {
1562         m_gl.deleteFramebuffers(1, &m_framebuffer_id);
1563         m_framebuffer_id = 0;
1564 
1565         m_gl.deleteRenderbuffers(1, &m_renderbuffer_id);
1566         m_renderbuffer_id = 0;
1567         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteRenderbuffers call failed.");
1568         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteFramebuffers call failed.");
1569     }
1570 }
1571 
1572 /** @brief Framebuffer destructor */
~Framebuffer()1573 glcts::ClipDistance::Utility::Framebuffer::~Framebuffer()
1574 {
1575     if (m_framebuffer_id)
1576     {
1577         m_gl.deleteFramebuffers(1, &m_framebuffer_id);
1578         m_framebuffer_id = 0;
1579         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteFramebuffers call failed.");
1580     }
1581 
1582     if (m_renderbuffer_id)
1583     {
1584         m_gl.deleteRenderbuffers(1, &m_renderbuffer_id);
1585         m_renderbuffer_id = 0;
1586         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteRenderbuffers call failed.");
1587     }
1588 }
1589 
1590 /** @brief Check frambuffer completness.
1591  *
1592  *  @return True if valid, false otherwise.
1593  */
isValid()1594 bool glcts::ClipDistance::Utility::Framebuffer::isValid()
1595 {
1596     if (m_framebuffer_id)
1597     {
1598         return true;
1599     }
1600 
1601     return false;
1602 }
1603 
1604 /** @brief Bind framebuffer and setup viewport. */
bind()1605 void glcts::ClipDistance::Utility::Framebuffer::bind()
1606 {
1607     m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_id);
1608     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer call failed.");
1609 
1610     m_gl.viewport(0, 0, m_size_x, m_size_y);
1611     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glViewport call failed.");
1612 }
1613 
1614 /** @brief Read pixels from framebuffer.
1615  *
1616  *  @return Vector of read pixels.
1617  */
readPixels()1618 std::vector<glw::GLfloat> glcts::ClipDistance::Utility::Framebuffer::readPixels()
1619 {
1620     std::vector<glw::GLfloat> pixels(m_size_x * m_size_y);
1621 
1622     if ((m_size_x > 0) && (m_size_y > 0))
1623     {
1624         m_gl.readPixels(0, 0, m_size_x, m_size_y, GL_RED, GL_FLOAT, pixels.data());
1625         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels call failed.");
1626     }
1627 
1628     return pixels;
1629 }
1630 
1631 /** @brief Clear framebuffer. */
clear()1632 void glcts::ClipDistance::Utility::Framebuffer::clear()
1633 {
1634     if (isValid())
1635     {
1636         m_gl.clearColor(0.f, 0.f, 0.f, 1.f);
1637         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor call failed.");
1638 
1639         m_gl.clear(GL_COLOR_BUFFER_BIT);
1640         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear call failed.");
1641     }
1642 }
1643 
1644 /** @brief Vertex array object constructor.
1645  *
1646  *  @note It silently binds VAO to OpenGL.
1647  *
1648  *  @param [in] gl               OpenGL functions access.
1649  *  @param [in] primitive_type   Primitive mode.
1650  */
VertexArrayObject(const glw::Functions & gl,const glw::GLenum primitive_type)1651 glcts::ClipDistance::Utility::VertexArrayObject::VertexArrayObject(const glw::Functions &gl,
1652                                                                    const glw::GLenum primitive_type)
1653     : m_gl(gl)
1654     , m_vertex_array_object_id(0)
1655     , m_primitive_type(primitive_type)
1656 {
1657     m_gl.genVertexArrays(1, &m_vertex_array_object_id);
1658     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays call failed.");
1659 
1660     m_gl.bindVertexArray(m_vertex_array_object_id);
1661     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray call failed.");
1662 }
1663 
1664 /** @brief Vertex array object destructor. */
~VertexArrayObject()1665 glcts::ClipDistance::Utility::VertexArrayObject::~VertexArrayObject()
1666 {
1667     if (m_vertex_array_object_id)
1668     {
1669         m_gl.deleteVertexArrays(1, &m_vertex_array_object_id);
1670         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteVertexArrays call failed.");
1671     }
1672 }
1673 
1674 /** @brief Bind vertex array object. */
bind()1675 void glcts::ClipDistance::Utility::VertexArrayObject::bind()
1676 {
1677     if (m_vertex_array_object_id)
1678     {
1679         m_gl.bindVertexArray(m_vertex_array_object_id);
1680         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray call failed.");
1681     }
1682 }
1683 
1684 /** @brief Draw array.
1685  *
1686  *  @param [in] first       First index to be drawn.
1687  *  @param [in] count       Count of indices to be drawn.
1688  */
draw(glw::GLuint first,glw::GLuint count)1689 void glcts::ClipDistance::Utility::VertexArrayObject::draw(glw::GLuint first, glw::GLuint count)
1690 {
1691     m_gl.drawArrays(m_primitive_type, first, count);
1692     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
1693 }
1694 
1695 /** @brief Draw array and fetch transform feedback varyings.
1696  *
1697  *  @param [in] first                   First index to be drawn.
1698  *  @param [in] count                   Count of indices to be drawn.
1699  *  @param [in] discard_rasterizer      Shall we discard rasterizer?
1700  */
drawWithTransformFeedback(glw::GLuint first,glw::GLuint count,bool discard_rasterizer)1701 void glcts::ClipDistance::Utility::VertexArrayObject::drawWithTransformFeedback(glw::GLuint first, glw::GLuint count,
1702                                                                                 bool discard_rasterizer)
1703 {
1704     if (discard_rasterizer)
1705     {
1706         m_gl.enable(GL_RASTERIZER_DISCARD);
1707         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnable call failed.");
1708     }
1709 
1710     m_gl.beginTransformFeedback(GL_POINTS);
1711     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback call failed.");
1712 
1713     draw(first, count);
1714 
1715     m_gl.endTransformFeedback();
1716     GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback call failed.");
1717 
1718     if (discard_rasterizer)
1719     {
1720         m_gl.disable(GL_RASTERIZER_DISCARD);
1721         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisbale call failed.");
1722     }
1723 }
1724 
1725 /** @brief Substitute key with value within source code.
1726  *
1727  *  @param [in] source      Source code to be prerocessed.
1728  *  @param [in] key         Key to be substituted.
1729  *  @param [in] value       Value to be inserted.
1730  *
1731  *  @return Resulting string.
1732  */
preprocessCode(std::string source,std::string key,std::string value)1733 std::string glcts::ClipDistance::Utility::preprocessCode(std::string source, std::string key, std::string value)
1734 {
1735     std::string destination = source;
1736 
1737     while (true)
1738     {
1739         /* Find token in source code. */
1740         size_t position = destination.find(key, 0);
1741 
1742         /* No more occurences of this key. */
1743         if (position == std::string::npos)
1744         {
1745             break;
1746         }
1747 
1748         /* Replace token with sub_code. */
1749         destination.replace(position, key.size(), value);
1750     }
1751 
1752     return destination;
1753 }
1754 
1755 /** @brief Convert an integer to a string.
1756  *
1757  *  @param [in] i       Integer to be converted.
1758  *
1759  *  @return String representing integer.
1760  */
itoa(glw::GLint i)1761 std::string glcts::ClipDistance::Utility::itoa(glw::GLint i)
1762 {
1763     std::stringstream stream;
1764 
1765     stream << i;
1766 
1767     return stream.str();
1768 }
1769