Home | History | Annotate | Download | only in gl
      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  */
     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. */
     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  */
     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  */
     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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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. */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
   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  */
   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  */
   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  */
   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. */
   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::
   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  */
   1245 const 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  */
   1255 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  */
   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  */
   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. */
   1452 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  */
   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 */
   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  */
   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. */
   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  */
   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. */
   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  */
   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. */
   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. */
   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  */
   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  */
   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  */
   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  */
   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