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