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