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 */
55gl3cts::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. */
62void 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 */
75gl3cts::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 */
85tcu::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 */
124bool 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 */
174bool 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 */
225bool 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 */
297bool 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 */
379bool 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). */
461const 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). */
473const 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). */
484const 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). */
493const 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). */
504const 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). */
520const 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 */
546gl3cts::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. */
554void 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 */
568tcu::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 */
711std::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 */
780gl3cts::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 */
832bool 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. */
871const 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. */
887const 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. */
891const 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. */
898const 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. */
902const 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. */
941const 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. */
945const 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. */
956const 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. */
959const glw::GLenum gl3cts::ClipDistance::FunctionalTest::m_primitive_indices[] = { 1, 2, 3 };
960
961/* @brief Primitive modes count. */
962const 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. */
966const 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 */
979gl3cts::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 */
989tcu::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 */
1028bool 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 */
1063bool 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 */
1090bool 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. */
1113const 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. */
1124const 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. */
1136const 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. */
1152const 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 */
1171gl3cts::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. */
1207gl3cts::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 */
1235const gl3cts::ClipDistance::Utility::Program::CompilationStatus& gl3cts::ClipDistance::Utility::Program::
1236	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 */
1245const gl3cts::ClipDistance::Utility::Program::CompilationStatus& gl3cts::ClipDistance::Utility::Program::
1246	FragmentShaderStatus() const
1247{
1248	return m_fragment_shader_status;
1249}
1250
1251/** @brief Program building status getter.
1252 *
1253 *  @return Program linkage status.
1254 */
1255const 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 */
1268gl3cts::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 */
1346gl3cts::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. */
1452void 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 */
1464gl3cts::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 */
1499gl3cts::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 */
1520bool 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. */
1531void 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 */
1544std::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. */
1558void 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 */
1577gl3cts::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. */
1589gl3cts::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. */
1599void 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 */
1613void 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 */
1625void 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 */
1657std::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 */
1685std::string gl3cts::ClipDistance::Utility::itoa(glw::GLint i)
1686{
1687	std::stringstream stream;
1688
1689	stream << i;
1690
1691	return stream.str();
1692}
1693