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