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