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 /**
     25  */ /*!
     26  * \file  gl3cCullDistanceTests.cpp
     27  * \brief Cull Distance Test Suite Implementation
     28  */ /*-------------------------------------------------------------------*/
     29 
     30 #include "gl3cCullDistanceTests.hpp"
     31 #include "gluContextInfo.hpp"
     32 #include "gluDefs.hpp"
     33 #include "gluStrUtil.hpp"
     34 #include "glwEnums.hpp"
     35 #include "glwFunctions.hpp"
     36 #include "tcuRenderTarget.hpp"
     37 #include "tcuTestLog.hpp"
     38 
     39 #include <cmath>
     40 #include <sstream>
     41 #include <string>
     42 #include <vector>
     43 
     44 #ifndef GL_MAX_CULL_DISTANCES
     45 #define GL_MAX_CULL_DISTANCES (0x82F9)
     46 #endif
     47 #ifndef GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES
     48 #define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES (0x82FA)
     49 #endif
     50 
     51 namespace glcts
     52 {
     53 /** @brief Build OpenGL program
     54  *
     55  *  @param [in]  gl             OpenGL function bindings
     56  *  @param [in]  testCtx        Context
     57  *  @param [in]  cs_body        Compute shader source code
     58  *  @param [in]  fs_body        Fragment shader source code
     59  *  @param [in]  gs_body        Geometric shader source code
     60  *  @param [in]  tc_body        Tessellation control shader source code
     61  *  @param [in]  te_body        Tessellation evaluation shader source code
     62  *  @param [in]  vs_body        Vertex shader source code
     63  *  @param [in]  n_tf_varyings  Number of transform feedback varyings
     64  *  @param [in]  tf_varyings    Transform feedback varyings names
     65  *
     66  *  @param [out] out_program    If succeeded output program GL handle, 0 otherwise.
     67  */
     68 void CullDistance::Utilities::buildProgram(const glw::Functions& gl, tcu::TestContext& testCtx,
     69 										   const glw::GLchar* cs_body, const glw::GLchar* fs_body,
     70 										   const glw::GLchar* gs_body, const glw::GLchar* tc_body,
     71 										   const glw::GLchar* te_body, const glw::GLchar* vs_body,
     72 										   const glw::GLuint& n_tf_varyings, const glw::GLchar** tf_varyings,
     73 										   glw::GLuint* out_program)
     74 {
     75 	glw::GLuint po_id = 0;
     76 
     77 	struct _shaders_configuration
     78 	{
     79 		glw::GLenum		   type;
     80 		const glw::GLchar* body;
     81 		glw::GLuint		   id;
     82 	} shaders_configuration[] = { { GL_COMPUTE_SHADER, cs_body, 0 },		 { GL_FRAGMENT_SHADER, fs_body, 0 },
     83 								  { GL_GEOMETRY_SHADER, gs_body, 0 },		 { GL_TESS_CONTROL_SHADER, tc_body, 0 },
     84 								  { GL_TESS_EVALUATION_SHADER, te_body, 0 }, { GL_VERTEX_SHADER, vs_body, 0 } };
     85 
     86 	const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]);
     87 
     88 	/* Guard allocated OpenGL resources */
     89 	try
     90 	{
     91 		/* Create needed programs */
     92 		po_id = gl.createProgram();
     93 		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
     94 
     95 		for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
     96 		{
     97 			if (shaders_configuration[n_shader_index].body != DE_NULL)
     98 			{
     99 				/* Generate shader object */
    100 				shaders_configuration[n_shader_index].id = gl.createShader(shaders_configuration[n_shader_index].type);
    101 				GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
    102 
    103 				glw::GLint		  compile_status = GL_FALSE;
    104 				const glw::GLuint so_id			 = shaders_configuration[n_shader_index].id;
    105 
    106 				/* Assign shader source code */
    107 				gl.shaderSource(shaders_configuration[n_shader_index].id, 1,		   /* count */
    108 								&shaders_configuration[n_shader_index].body, DE_NULL); /* length */
    109 				GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
    110 
    111 				gl.compileShader(so_id);
    112 				GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
    113 
    114 				gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
    115 				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
    116 
    117 				if (compile_status == GL_FALSE)
    118 				{
    119 					std::vector<glw::GLchar> log_array(1);
    120 					glw::GLint				 log_length = 0;
    121 					std::string				 log_string("Failed to retrieve log");
    122 
    123 					/* Retrive compilation log length */
    124 					gl.getShaderiv(so_id, GL_INFO_LOG_LENGTH, &log_length);
    125 					GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
    126 
    127 					log_array.resize(log_length + 1, 0);
    128 
    129 					gl.getShaderInfoLog(so_id, log_length, DE_NULL, &log_array[0]);
    130 					GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed.");
    131 
    132 					log_string = std::string(&log_array[0]);
    133 
    134 					testCtx.getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
    135 									 << "Shader type: " << shaders_configuration[n_shader_index].type << "\n"
    136 									 << "Shader compilation error log:\n"
    137 									 << log_string << "\n"
    138 									 << "Shader source code:\n"
    139 									 << shaders_configuration[n_shader_index].body << "\n"
    140 									 << tcu::TestLog::EndMessage;
    141 
    142 					TCU_FAIL("Shader compilation has failed.");
    143 				}
    144 
    145 				/* Also attach the shader to the corresponding program object */
    146 				gl.attachShader(po_id, so_id);
    147 
    148 				GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed");
    149 			} /* if (shaders_configuration[n_shader_index].body != DE_NULL) */
    150 		}	 /* for (all shader object IDs) */
    151 
    152 		/* Set transform feedback if requested */
    153 		if (n_tf_varyings > 0)
    154 		{
    155 			gl.transformFeedbackVaryings(po_id, n_tf_varyings, tf_varyings, GL_INTERLEAVED_ATTRIBS);
    156 			GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
    157 		}
    158 
    159 		/* Try to link the program objects */
    160 		if (po_id != 0)
    161 		{
    162 			glw::GLint link_status = GL_FALSE;
    163 
    164 			gl.linkProgram(po_id);
    165 			GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
    166 
    167 			gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
    168 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
    169 
    170 			if (link_status == GL_FALSE)
    171 			{
    172 				std::vector<glw::GLchar> log_array(1);
    173 				glw::GLsizei			 log_length = 0;
    174 				std::string				 log_string;
    175 
    176 				/* Retreive compilation log length */
    177 				gl.getProgramiv(po_id, GL_INFO_LOG_LENGTH, &log_length);
    178 				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
    179 
    180 				log_array.resize(log_length + 1, 0);
    181 
    182 				/* Retreive compilation log */
    183 				gl.getProgramInfoLog(po_id, log_length, DE_NULL, &log_array[0]);
    184 				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed.");
    185 
    186 				log_string = std::string(&log_array[0]);
    187 
    188 				/* Log linking error message */
    189 				testCtx.getLog() << tcu::TestLog::Message << "Program linking has failed.\n"
    190 								 << "Linking error log:\n"
    191 								 << log_string << "\n"
    192 								 << tcu::TestLog::EndMessage;
    193 
    194 				/* Log shader source code of shaders involved */
    195 				for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
    196 				{
    197 					if (shaders_configuration[n_shader_index].body != DE_NULL)
    198 					{
    199 						testCtx.getLog() << tcu::TestLog::Message << "Shader source code of type "
    200 										 << shaders_configuration[n_shader_index].type << " follows:\n"
    201 										 << shaders_configuration[n_shader_index].body << "\n"
    202 										 << tcu::TestLog::EndMessage;
    203 					}
    204 				}
    205 
    206 				TCU_FAIL("Program linking failed");
    207 			}
    208 		} /* if (po_id != 0) */
    209 
    210 		/* Delete all shaders we've created */
    211 		for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
    212 		{
    213 			const glw::GLuint so_id = shaders_configuration[n_shader_index].id;
    214 
    215 			if (so_id != 0)
    216 			{
    217 				gl.deleteShader(so_id);
    218 
    219 				shaders_configuration[n_shader_index].id = 0;
    220 
    221 				GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
    222 			}
    223 		}
    224 
    225 		/* Store the result progrtam IDs */
    226 		*out_program = po_id;
    227 	}
    228 	catch (...)
    229 	{
    230 		/* Delete all shaders we've created */
    231 		for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
    232 		{
    233 			const glw::GLuint so_id = shaders_configuration[n_shader_index].id;
    234 
    235 			if (so_id != 0)
    236 			{
    237 				gl.deleteShader(so_id);
    238 
    239 				shaders_configuration[n_shader_index].id = 0;
    240 			}
    241 		}
    242 
    243 		/* Delete the program object */
    244 		if (po_id != 0)
    245 		{
    246 			gl.deleteProgram(po_id);
    247 
    248 			po_id = 0;
    249 		}
    250 
    251 		/* Rethrow */
    252 		throw;
    253 	}
    254 }
    255 
    256 /** @brief Replace all occurences of a substring in a string by a substring
    257  *
    258  *  @param [in,out] str    string to be edited
    259  *  @param [in]     from   substring to be replaced
    260  *  @param [out]    to     new substring
    261  */
    262 void CullDistance::Utilities::replaceAll(std::string& str, const std::string& from, const std::string& to)
    263 {
    264 	for (size_t start_pos = str.find(from, 0); start_pos != std::string::npos; start_pos = str.find(from, start_pos))
    265 	{
    266 		str.replace(start_pos, from.length(), to);
    267 
    268 		start_pos += to.length();
    269 	}
    270 
    271 	return;
    272 }
    273 
    274 /** @brief Convert integer to string representation
    275  *
    276  *  @param [in] integer     input integer to be converted
    277  *
    278  *  @return String representation of integer
    279  */
    280 std::string CullDistance::Utilities::intToString(glw::GLint integer)
    281 {
    282 	std::stringstream temp_sstream;
    283 
    284 	temp_sstream << integer;
    285 
    286 	return temp_sstream.str();
    287 }
    288 
    289 /** Constructor.
    290  *
    291  *  @param context Rendering context handle.
    292  **/
    293 CullDistance::APICoverageTest::APICoverageTest(deqp::Context& context)
    294 	: TestCase(context, "coverage", "Cull Distance API Coverage Test")
    295 	, m_bo_id(0)
    296 	, m_cs_id(0)
    297 	, m_cs_to_id(0)
    298 	, m_fbo_draw_id(0)
    299 	, m_fbo_draw_to_id(0)
    300 	, m_fbo_read_id(0)
    301 	, m_fs_id(0)
    302 	, m_gs_id(0)
    303 	, m_po_id(0)
    304 	, m_tc_id(0)
    305 	, m_te_id(0)
    306 	, m_vao_id(0)
    307 	, m_vs_id(0)
    308 {
    309 	/* Left blank on purpose */
    310 }
    311 
    312 /** @brief Cull Distance API Coverage Test deinitialization */
    313 void CullDistance::APICoverageTest::deinit()
    314 {
    315 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    316 
    317 	if (m_bo_id != 0)
    318 	{
    319 		gl.deleteBuffers(1, &m_bo_id);
    320 
    321 		m_bo_id = 0;
    322 	}
    323 
    324 	if (m_cs_id != 0)
    325 	{
    326 		gl.deleteShader(m_cs_id);
    327 
    328 		m_cs_id = 0;
    329 	}
    330 
    331 	if (m_cs_to_id != 0)
    332 	{
    333 		gl.deleteTextures(1, &m_cs_to_id);
    334 
    335 		m_cs_to_id = 0;
    336 	}
    337 
    338 	if (m_fbo_draw_id != 0)
    339 	{
    340 		gl.deleteFramebuffers(1, &m_fbo_draw_id);
    341 
    342 		m_fbo_draw_id = 0;
    343 	}
    344 
    345 	if (m_fbo_draw_to_id != 0)
    346 	{
    347 		gl.deleteTextures(1, &m_fbo_draw_to_id);
    348 
    349 		m_fbo_draw_to_id = 0;
    350 	}
    351 
    352 	if (m_fbo_read_id != 0)
    353 	{
    354 		gl.deleteFramebuffers(1, &m_fbo_read_id);
    355 
    356 		m_fbo_read_id = 0;
    357 	}
    358 
    359 	if (m_fs_id != 0)
    360 	{
    361 		gl.deleteShader(m_fs_id);
    362 
    363 		m_fs_id = 0;
    364 	}
    365 
    366 	if (m_gs_id != 0)
    367 	{
    368 		gl.deleteShader(m_gs_id);
    369 
    370 		m_gs_id = 0;
    371 	}
    372 
    373 	if (m_po_id != 0)
    374 	{
    375 		gl.deleteProgram(m_po_id);
    376 
    377 		m_po_id = 0;
    378 	}
    379 
    380 	if (m_tc_id != 0)
    381 	{
    382 		gl.deleteShader(m_tc_id);
    383 
    384 		m_tc_id = 0;
    385 	}
    386 
    387 	if (m_te_id != 0)
    388 	{
    389 		gl.deleteShader(m_te_id);
    390 
    391 		m_te_id = 0;
    392 	}
    393 
    394 	if (m_vao_id != 0)
    395 	{
    396 		gl.deleteVertexArrays(1, &m_vao_id);
    397 
    398 		m_vao_id = 0;
    399 	}
    400 
    401 	if (m_vs_id != 0)
    402 	{
    403 		gl.deleteShader(m_vs_id);
    404 
    405 		m_vs_id = 0;
    406 	}
    407 
    408 	/* Restore default pack alignment value */
    409 	gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
    410 }
    411 
    412 /** Executes test iteration.
    413  *
    414  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
    415  */
    416 tcu::TestNode::IterateResult CullDistance::APICoverageTest::iterate()
    417 {
    418 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    419 
    420 	/* This test should only be executed if ARB_cull_distance is supported, or if
    421 	 * we're running a GL4.5 context
    422 	 */
    423 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
    424 		!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
    425 	{
    426 		throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
    427 	}
    428 
    429 	/* Check that calling GetIntegerv with MAX_CULL_DISTANCES doesn't generate
    430 	 * any errors and returns a value at least 8.
    431 	 *
    432 	 * Check that calling GetIntegerv with MAX_COMBINED_CLIP_AND_CULL_DISTANCES
    433 	 * doesn't generate any errors and returns a value at least 8.
    434 	 *
    435 	 */
    436 	glw::GLint error_code									 = GL_NO_ERROR;
    437 	glw::GLint gl_max_cull_distances_value					 = 0;
    438 	glw::GLint gl_max_combined_clip_and_cull_distances_value = 0;
    439 
    440 	gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
    441 
    442 	error_code = gl.getError();
    443 	if (error_code != GL_NO_ERROR)
    444 	{
    445 		m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned error code "
    446 						   << "[" << glu::getErrorStr(error_code) << "] for GL_MAX_CULL_DISTANCES"
    447 																	 " query instead of GL_NO_ERROR"
    448 						   << tcu::TestLog::EndMessage;
    449 
    450 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    451 
    452 		return STOP;
    453 	}
    454 
    455 	gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
    456 
    457 	error_code = gl.getError();
    458 	if (error_code != GL_NO_ERROR)
    459 	{
    460 		m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned error code "
    461 						   << "[" << glu::getErrorStr(error_code) << "] for "
    462 																	 "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES query "
    463 																	 "instead of GL_NO_ERROR"
    464 						   << tcu::TestLog::EndMessage;
    465 
    466 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    467 
    468 		return STOP;
    469 	}
    470 
    471 	/* Before we proceed with the two other tests, initialize a buffer & a texture
    472 	 * object we will need to capture data from the programs */
    473 	static const glw::GLuint bo_size = sizeof(int) * 4 /* components */ * 4 /* result points */;
    474 
    475 	gl.genBuffers(1, &m_bo_id);
    476 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
    477 
    478 	gl.genFramebuffers(1, &m_fbo_draw_id);
    479 	gl.genFramebuffers(1, &m_fbo_read_id);
    480 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call(s) failed.");
    481 
    482 	gl.genTextures(1, &m_cs_to_id);
    483 	gl.genTextures(1, &m_fbo_draw_to_id);
    484 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
    485 
    486 	gl.genVertexArrays(1, &m_vao_id);
    487 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
    488 
    489 	gl.bindVertexArray(m_vao_id);
    490 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
    491 
    492 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
    493 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
    494 					  m_bo_id);
    495 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() or glBindBufferBase() call(s) failed.");
    496 
    497 	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, GL_STATIC_DRAW);
    498 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
    499 
    500 	for (glw::GLuint n_to_id = 0; n_to_id < 2; /* CS, FBO */ ++n_to_id)
    501 	{
    502 		gl.bindTexture(GL_TEXTURE_2D, (n_to_id == 0) ? m_cs_to_id : m_fbo_draw_to_id);
    503 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
    504 
    505 		gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
    506 						GL_R32I, 1,		  /* width */
    507 						1);				  /* height */
    508 		GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
    509 	}
    510 
    511 	gl.bindImageTexture(0,			   /* unit */
    512 						m_cs_to_id, 0, /* level */
    513 						GL_FALSE,	  /* layered */
    514 						0,			   /* layer */
    515 						GL_WRITE_ONLY, GL_R32I);
    516 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture() call failed.");
    517 
    518 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_draw_id);
    519 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
    520 
    521 	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fbo_draw_to_id, 0); /* level */
    522 	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
    523 
    524 	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read_id);
    525 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
    526 
    527 	gl.viewport(0,  /* x */
    528 				0,  /* y */
    529 				1,  /* width */
    530 				1); /* height */
    531 	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
    532 
    533 	gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
    534 	GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
    535 
    536 	/* There are two new GL constants, where value we need to verify */
    537 	struct _run
    538 	{
    539 		const glw::GLchar* essl_token_value;
    540 		glw::GLenum		   gl_enum;
    541 		glw::GLint		   gl_value;
    542 		glw::GLint		   min_value;
    543 		const glw::GLchar* name;
    544 	} runs[] = { { "gl_MaxCullDistances", GL_MAX_CULL_DISTANCES, gl_max_cull_distances_value, 8 /*minimum required */,
    545 				   "GL_MAX_CULL_DISTANCES" },
    546 				 { "gl_MaxCombinedClipAndCullDistances", GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES,
    547 				   gl_max_combined_clip_and_cull_distances_value, 8 /*minimum required */,
    548 				   "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES" } };
    549 
    550 	static const glw::GLuint n_runs = sizeof(runs) / sizeof(runs[0]);
    551 
    552 	for (glw::GLuint n_run = 0; n_run < n_runs; ++n_run)
    553 	{
    554 		_run& current_run = runs[n_run];
    555 
    556 		static const struct _stage
    557 		{
    558 			bool use_cs;
    559 			bool use_fs;
    560 			bool use_gs;
    561 			bool use_tc;
    562 			bool use_te;
    563 			bool use_vs;
    564 
    565 			const glw::GLchar* fs_input;
    566 			const glw::GLchar* gs_input;
    567 			const glw::GLchar* tc_input;
    568 			const glw::GLchar* te_input;
    569 
    570 			const glw::GLchar* tf_output_name;
    571 			const glw::GLenum  tf_mode;
    572 
    573 			glw::GLenum draw_call_mode;
    574 			glw::GLuint n_draw_call_vertices;
    575 		} stages[] = { /* CS only test */
    576 					   {
    577 						   /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
    578 						   true, false, false, false, false, false,
    579 
    580 						   NULL,	/* fs_input             */
    581 						   NULL,	/* gs_input             */
    582 						   NULL,	/* tc_input             */
    583 						   NULL,	/* te_input             */
    584 						   NULL,	/* tf_output_name       */
    585 						   GL_NONE, /* tf_mode              */
    586 						   GL_NONE, /* draw_call_mode       */
    587 						   0,		/* n_draw_call_vertices */
    588 					   },
    589 					   /* VS+GS+TC+TE+FS test */
    590 					   {
    591 						   /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
    592 						   false, true, true, true, true, true,
    593 
    594 						   "out_gs",	 /* fs_input             */
    595 						   "out_te",	 /* gs_input             */
    596 						   "out_vs",	 /* tc_input             */
    597 						   "out_tc",	 /* te_input             */
    598 						   "out_gs",	 /* tf_output_name       */
    599 						   GL_TRIANGLES, /* tf_mode              */
    600 						   GL_PATCHES,   /* draw_call_mode       */
    601 						   3,			 /* n_draw_call_vertices */
    602 					   },
    603 					   /* VS+GS+FS test */
    604 					   {
    605 						   /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
    606 						   false, true, true, false, false, true,
    607 
    608 						   "out_gs",	 /* fs_input             */
    609 						   "out_vs",	 /* gs_input             */
    610 						   NULL,		 /* tc_input             */
    611 						   NULL,		 /* te_input             */
    612 						   "out_gs",	 /* tf_output_name       */
    613 						   GL_TRIANGLES, /* tf_mode              */
    614 						   GL_POINTS,	/* draw_call_mode       */
    615 						   1,			 /* n_draw_call_vertices */
    616 					   },
    617 					   /* VS+TC+TE+FS test */
    618 					   {
    619 						   /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
    620 						   false, true, false, true, true, true,
    621 
    622 						   "out_te",   /* fs_input             */
    623 						   NULL,	   /* gs_input             */
    624 						   "out_vs",   /* tc_input             */
    625 						   "out_tc",   /* te_input             */
    626 						   "out_te",   /* tf_output_name       */
    627 						   GL_POINTS,  /* tf_mode              */
    628 						   GL_PATCHES, /* draw_call_mode       */
    629 						   3		   /* n_draw_call_vertices */
    630 					   },
    631 					   /* VS test */
    632 					   {
    633 						   /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */
    634 						   false, false, false, false, false, true,
    635 
    636 						   "out_vs",  /* fs_input             */
    637 						   NULL,	  /* gs_input             */
    638 						   NULL,	  /* tc_input             */
    639 						   NULL,	  /* te_input             */
    640 						   "out_vs",  /* tf_output_name       */
    641 						   GL_POINTS, /* tf_mode              */
    642 						   GL_POINTS, /* draw_call_mode       */
    643 						   1		  /* n_draw_call_vertices */
    644 					   }
    645 		};
    646 		const glw::GLuint n_stages = sizeof(stages) / sizeof(stages[0]);
    647 
    648 		/* Run through all test stages */
    649 		for (glw::GLuint n_stage = 0; n_stage < n_stages; ++n_stage)
    650 		{
    651 			/* Check for OpenGL feature support */
    652 			if (stages[n_stage].use_cs)
    653 			{
    654 				if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)) &&
    655 					!m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader"))
    656 				{
    657 					continue; // no compute shader support
    658 				}
    659 			}
    660 			if (stages[n_stage].use_tc || stages[n_stage].use_te)
    661 			{
    662 				if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) &&
    663 					!m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader"))
    664 				{
    665 					continue; // no tessellation shader support
    666 				}
    667 			}
    668 
    669 			/* Check that use of the GLSL built-in constant gl_MaxCullDistance in any
    670 			 * shader stage (including compute shader) does not affect the shader
    671 			 * compilation & program linking process.
    672 			 */
    673 			static const glw::GLchar* cs_body_template =
    674 				"#version 150\n"
    675 				"\n"
    676 				"#extension GL_ARB_compute_shader          : require\n"
    677 				"#extension GL_ARB_cull_distance           : require\n"
    678 				"#extension GL_ARB_shader_image_load_store : require\n"
    679 				"\n"
    680 				"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
    681 				"\n"
    682 				"layout(r32i) uniform writeonly iimage2D result;\n"
    683 				"\n"
    684 				"void main()\n"
    685 				"{\n"
    686 				"    imageStore(result, ivec2(0),ivec4(TOKEN) );\n"
    687 				"}\n";
    688 			std::string cs_body = cs_body_template;
    689 
    690 			static const glw::GLchar* fs_body_template = "#version 150\n"
    691 														 "\n"
    692 														 "#extension GL_ARB_cull_distance : require\n"
    693 														 "\n"
    694 														 "flat in  int INPUT_FS_NAME;\n"
    695 														 "out int out_fs;\n"
    696 														 "\n"
    697 														 "void main()\n"
    698 														 "{\n"
    699 														 "    if (INPUT_FS_NAME == TOKEN)\n"
    700 														 "    {\n"
    701 														 "        out_fs = TOKEN;\n"
    702 														 "    }\n"
    703 														 "    else\n"
    704 														 "    {\n"
    705 														 "        out_fs = -1;\n"
    706 														 "    }\n"
    707 														 "}\n";
    708 			std::string fs_body = fs_body_template;
    709 
    710 			static const glw::GLchar* gs_body_template =
    711 				"#version 150\n"
    712 				"\n"
    713 				"#extension GL_ARB_cull_distance : require\n"
    714 				"\n"
    715 				"flat in  int INPUT_GS_NAME[];\n"
    716 				"flat out int out_gs;\n"
    717 				"\n"
    718 				"layout(points)                           in;\n"
    719 				"layout(triangle_strip, max_vertices = 4) out;\n"
    720 				"\n"
    721 				"void main()\n"
    722 				"{\n"
    723 				"    int result_value = (INPUT_GS_NAME[0] == TOKEN) ? TOKEN : -1;\n"
    724 				"\n"
    725 				/* Draw a full-screen quad */
    726 				"    gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
    727 				"    out_gs      = result_value;\n"
    728 				"    EmitVertex();\n"
    729 				"\n"
    730 				"    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
    731 				"    out_gs      = result_value;\n"
    732 				"    EmitVertex();\n"
    733 				"\n"
    734 				"    gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
    735 				"    out_gs      = result_value;\n"
    736 				"    EmitVertex();\n"
    737 				"\n"
    738 				"    gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
    739 				"    out_gs      = result_value;\n"
    740 				"    EmitVertex();\n"
    741 				"    EndPrimitive();\n"
    742 				"}\n";
    743 			std::string gs_body = gs_body_template;
    744 
    745 			static const glw::GLchar* tc_body_template =
    746 				"#version 400\n"
    747 				"\n"
    748 				"#extension GL_ARB_cull_distance : require\n"
    749 				"\n"
    750 				"layout(vertices = 1) out;\n"
    751 				"\n"
    752 				"flat in  int INPUT_TC_NAME[];\n"
    753 				"flat out int out_tc       [];\n"
    754 				"\n"
    755 				"void main()\n"
    756 				"{\n"
    757 				"    int result_value = (INPUT_TC_NAME[0] == TOKEN) ? TOKEN : -1;\n"
    758 				"\n"
    759 				"    out_tc[gl_InvocationID]             = result_value;\n"
    760 				"    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
    761 				"    gl_TessLevelInner[0]                = 1.0;\n"
    762 				"    gl_TessLevelInner[1]                = 1.0;\n"
    763 				"    gl_TessLevelOuter[0]                = 1.0;\n"
    764 				"    gl_TessLevelOuter[1]                = 1.0;\n"
    765 				"    gl_TessLevelOuter[2]                = 1.0;\n"
    766 				"    gl_TessLevelOuter[3]                = 1.0;\n"
    767 				"}\n";
    768 			std::string tc_body = tc_body_template;
    769 
    770 			static const glw::GLchar* te_body_template =
    771 				"#version 400\n"
    772 				"\n"
    773 				"#extension GL_ARB_cull_distance : require\n"
    774 				"\n"
    775 				"flat in  int INPUT_TE_NAME[];\n"
    776 				"flat out int out_te;\n"
    777 				"\n"
    778 				"layout(isolines, point_mode) in;\n"
    779 				"\n"
    780 				"void main()\n"
    781 				"{\n"
    782 				"    int result_value = (INPUT_TE_NAME[0] == TOKEN) ? TOKEN : 0;\n"
    783 				"\n"
    784 				"    out_te = result_value;\n"
    785 				"\n"
    786 				"    gl_Position = vec4(0.0, 0.0, 0.0, 1.);\n"
    787 				"}\n";
    788 			std::string te_body = te_body_template;
    789 
    790 			static const glw::GLchar* vs_body_template = "#version 150\n"
    791 														 "\n"
    792 														 "#extension GL_ARB_cull_distance : require\n"
    793 														 "\n"
    794 														 "flat out int out_vs;\n"
    795 														 "\n"
    796 														 "void main()\n"
    797 														 "{\n"
    798 														 "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
    799 														 "    out_vs      = TOKEN;\n"
    800 														 "}\n";
    801 			std::string vs_body = vs_body_template;
    802 
    803 			const _stage& current_stage = stages[n_stage];
    804 
    805 			/* Build shader bodies */
    806 			struct _shader_body
    807 			{
    808 				std::string* body_ptr;
    809 				glw::GLenum  gl_type;
    810 			} shader_bodies[] = { { &cs_body, GL_COMPUTE_SHADER },		   { &fs_body, GL_FRAGMENT_SHADER },
    811 								  { &gs_body, GL_GEOMETRY_SHADER },		   { &tc_body, GL_TESS_CONTROL_SHADER },
    812 								  { &te_body, GL_TESS_EVALUATION_SHADER }, { &vs_body, GL_VERTEX_SHADER } };
    813 			static const glw::GLchar* input_fs_token_string = "INPUT_FS_NAME";
    814 			static const glw::GLchar* input_gs_token_string = "INPUT_GS_NAME";
    815 			static const glw::GLchar* input_te_token_string = "INPUT_TE_NAME";
    816 			static const glw::GLchar* input_tc_token_string = "INPUT_TC_NAME";
    817 			static const glw::GLuint  n_shader_bodies		= sizeof(shader_bodies) / sizeof(shader_bodies[0]);
    818 
    819 			std::size_t				  token_position = std::string::npos;
    820 			static const glw::GLchar* token_string   = "TOKEN";
    821 
    822 			for (glw::GLuint n_shader_body = 0; n_shader_body < n_shader_bodies; ++n_shader_body)
    823 			{
    824 				_shader_body& current_body = shader_bodies[n_shader_body];
    825 
    826 				/* Is this stage actually used? */
    827 				if (((current_body.gl_type == GL_COMPUTE_SHADER) && (!current_stage.use_cs)) ||
    828 					((current_body.gl_type == GL_FRAGMENT_SHADER) && (!current_stage.use_fs)) ||
    829 					((current_body.gl_type == GL_TESS_CONTROL_SHADER) && (!current_stage.use_tc)) ||
    830 					((current_body.gl_type == GL_TESS_EVALUATION_SHADER) && (!current_stage.use_te)) ||
    831 					((current_body.gl_type == GL_VERTEX_SHADER) && (!current_stage.use_vs)))
    832 				{
    833 					/* Skip the iteration. */
    834 					continue;
    835 				}
    836 
    837 				/* Iterate over all token and replace them with stage-specific values */
    838 				struct _token_value_pair
    839 				{
    840 					const glw::GLchar* token;
    841 					const glw::GLchar* value;
    842 				} token_value_pairs[] = {
    843 					/* NOTE: The last entry is filled by the switch() block below */
    844 					{ token_string, current_run.essl_token_value },
    845 					{ NULL, NULL },
    846 				};
    847 
    848 				const size_t n_token_value_pairs = sizeof(token_value_pairs) / sizeof(token_value_pairs[0]);
    849 
    850 				switch (current_body.gl_type)
    851 				{
    852 				case GL_COMPUTE_SHADER:
    853 				case GL_VERTEX_SHADER:
    854 					break;
    855 
    856 				case GL_FRAGMENT_SHADER:
    857 				{
    858 					token_value_pairs[1].token = input_fs_token_string;
    859 					token_value_pairs[1].value = current_stage.fs_input;
    860 
    861 					break;
    862 				}
    863 
    864 				case GL_GEOMETRY_SHADER:
    865 				{
    866 					token_value_pairs[1].token = input_gs_token_string;
    867 					token_value_pairs[1].value = current_stage.gs_input;
    868 
    869 					break;
    870 				}
    871 
    872 				case GL_TESS_CONTROL_SHADER:
    873 				{
    874 					token_value_pairs[1].token = input_tc_token_string;
    875 					token_value_pairs[1].value = current_stage.tc_input;
    876 
    877 					break;
    878 				}
    879 
    880 				case GL_TESS_EVALUATION_SHADER:
    881 				{
    882 					token_value_pairs[1].token = input_te_token_string;
    883 					token_value_pairs[1].value = current_stage.te_input;
    884 
    885 					break;
    886 				}
    887 
    888 				default:
    889 					TCU_FAIL("Unrecognized shader body type");
    890 				}
    891 
    892 				for (glw::GLuint n_pair = 0; n_pair < n_token_value_pairs; ++n_pair)
    893 				{
    894 					const _token_value_pair& current_pair = token_value_pairs[n_pair];
    895 
    896 					if (current_pair.token == NULL || current_pair.value == NULL)
    897 					{
    898 						continue;
    899 					}
    900 
    901 					while ((token_position = current_body.body_ptr->find(current_pair.token)) != std::string::npos)
    902 					{
    903 						current_body.body_ptr->replace(token_position, strlen(current_pair.token), current_pair.value);
    904 					}
    905 				} /* for (all token+value pairs) */
    906 			}	 /* for (all sader bodies) */
    907 
    908 			/* Build the test program */
    909 			CullDistance::Utilities::buildProgram(
    910 				gl, m_testCtx, current_stage.use_cs ? cs_body.c_str() : DE_NULL,
    911 				current_stage.use_fs ? fs_body.c_str() : DE_NULL, current_stage.use_gs ? gs_body.c_str() : DE_NULL,
    912 				current_stage.use_tc ? tc_body.c_str() : DE_NULL, current_stage.use_te ? te_body.c_str() : DE_NULL,
    913 				current_stage.use_vs ? vs_body.c_str() : DE_NULL, (current_stage.tf_output_name != NULL) ? 1 : 0,
    914 				(const glw::GLchar**)&current_stage.tf_output_name, &m_po_id);
    915 
    916 			/* Bind the test program */
    917 			DE_ASSERT(m_po_id != 0);
    918 
    919 			gl.useProgram(m_po_id);
    920 			GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
    921 
    922 			/* Execute the draw call. Transform Feed-back should be enabled for all iterations
    923 			 * par the CS one, since we use a different tool to capture the result data in the
    924 			 * latter case.
    925 			 */
    926 			if (!current_stage.use_cs)
    927 			{
    928 				gl.beginTransformFeedback(current_stage.tf_mode);
    929 				GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
    930 
    931 				gl.drawArrays(current_stage.draw_call_mode, 0,	 /* first */
    932 							  current_stage.n_draw_call_vertices); /* count */
    933 				GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
    934 
    935 				gl.endTransformFeedback();
    936 				GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
    937 			} /* if (uses_tf) */
    938 			else
    939 			{
    940 				gl.dispatchCompute(1,  /* num_groups_x */
    941 								   1,  /* num_groups_y */
    942 								   1); /* num_groups_z */
    943 				GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() call failed.");
    944 			}
    945 
    946 			/* Verify the result values */
    947 			if (!current_stage.use_cs)
    948 			{
    949 				glw::GLint* result_data_ptr = DE_NULL;
    950 
    951 				/* Retrieve the data captured by Transform Feedback */
    952 				result_data_ptr = (glw::GLint*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
    953 																 sizeof(unsigned int) * 1, GL_MAP_READ_BIT);
    954 				GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
    955 
    956 				if (*result_data_ptr != current_run.gl_value)
    957 				{
    958 					m_testCtx.getLog() << tcu::TestLog::Message << current_run.name << " value "
    959 																					   "["
    960 									   << *result_data_ptr << "]"
    961 															  " does not match the one reported by glGetIntegerv() "
    962 															  "["
    963 									   << current_run.gl_value << "]" << tcu::TestLog::EndMessage;
    964 
    965 					TCU_FAIL("GL constant value does not match the ES SL equivalent");
    966 				}
    967 
    968 				if (*result_data_ptr < current_run.min_value)
    969 				{
    970 					m_testCtx.getLog() << tcu::TestLog::Message << current_run.name << " value "
    971 																					   "["
    972 									   << *result_data_ptr << "]"
    973 															  " does not meet the minimum specification requirements "
    974 															  "["
    975 									   << current_run.min_value << "]" << tcu::TestLog::EndMessage;
    976 
    977 					TCU_FAIL("GL constant value does not meet minimum specification requirements");
    978 				}
    979 
    980 				gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
    981 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
    982 			}
    983 
    984 			for (glw::GLuint n_stage_internal = 0; n_stage_internal < 2; /* CS, FS write to separate textures */
    985 				 ++n_stage_internal)
    986 			{
    987 				glw::GLuint to_id = (n_stage_internal == 0) ? m_cs_to_id : m_fbo_draw_to_id;
    988 
    989 				if (((n_stage_internal == 0) && (!current_stage.use_cs)) ||
    990 					((n_stage_internal == 1) && (!current_stage.use_fs)))
    991 				{
    992 					/* Skip the iteration */
    993 					continue;
    994 				}
    995 
    996 				/* Check the image data the test CS / FS should have written */
    997 				glw::GLint result_value = 0;
    998 
    999 				gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, to_id, 0); /* level */
   1000 				GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
   1001 
   1002 				/* NOTE: We're using our custom read framebuffer here, so we'll be reading
   1003 				 *       from the texture, that the writes have been issued to earlier. */
   1004 				gl.finish();
   1005 				GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() call failed.");
   1006 
   1007 				gl.readPixels(0, /* x */
   1008 							  0, /* y */
   1009 							  1, /* width */
   1010 							  1, /* height */
   1011 							  GL_RED_INTEGER, GL_INT, &result_value);
   1012 				GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
   1013 
   1014 				if (result_value != current_run.gl_value)
   1015 				{
   1016 					m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
   1017 									   << " value accessible to the compute / fragment shader "
   1018 										  "["
   1019 									   << result_value << "]"
   1020 														  " does not match the one reported by glGetIntegerv() "
   1021 														  "["
   1022 									   << current_run.gl_value << "]" << tcu::TestLog::EndMessage;
   1023 
   1024 					TCU_FAIL("GL constant value does not match the ES SL equivalent");
   1025 				}
   1026 
   1027 				if (result_value < current_run.min_value)
   1028 				{
   1029 					m_testCtx.getLog() << tcu::TestLog::Message << current_run.name
   1030 									   << " value accessible to the compute / fragment shader "
   1031 										  "["
   1032 									   << result_value << "]"
   1033 														  " does not meet the minimum specification requirements "
   1034 														  "["
   1035 									   << current_run.min_value << "]" << tcu::TestLog::EndMessage;
   1036 
   1037 					TCU_FAIL("GL constant value does not meet minimum specification requirements");
   1038 				}
   1039 			}
   1040 
   1041 			/* Clear the data buffer before we continue */
   1042 			static const glw::GLubyte bo_clear_data[bo_size] = { 0 };
   1043 
   1044 			gl.bufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
   1045 							 bo_size, bo_clear_data);
   1046 			GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
   1047 
   1048 			/* Clear the texture mip-map before we continue */
   1049 			glw::GLint clear_values[4] = { 0, 0, 0, 0 };
   1050 
   1051 			gl.clearBufferiv(GL_COLOR, 0, /* drawbuffer */
   1052 							 clear_values);
   1053 			GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferiv() call failed.");
   1054 
   1055 			/* Release program before we move on to the next iteration */
   1056 			if (m_po_id != 0)
   1057 			{
   1058 				gl.deleteProgram(m_po_id);
   1059 
   1060 				m_po_id = 0;
   1061 			}
   1062 		} /* for (all stages) */
   1063 	}	 /* for (both runs) */
   1064 
   1065 	/* All done */
   1066 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1067 
   1068 	return STOP;
   1069 }
   1070 
   1071 /** Constructor.
   1072  *
   1073  *  @param context Rendering context handle.
   1074  **/
   1075 CullDistance::FunctionalTest::FunctionalTest(deqp::Context& context)
   1076 	: TestCase(context, "functional", "Cull Distance Functional Test")
   1077 	, m_bo_data()
   1078 	, m_bo_id(0)
   1079 	, m_fbo_id(0)
   1080 	, m_po_id(0)
   1081 	, m_render_primitives(0)
   1082 	, m_render_vertices(0)
   1083 	, m_sub_grid_cell_size(0)
   1084 	, m_to_id(0)
   1085 	, m_vao_id(0)
   1086 	, m_to_height(512)
   1087 	, m_to_width(512)
   1088 	, m_to_pixel_data_cache()
   1089 {
   1090 	/* Left blank on purpose */
   1091 }
   1092 
   1093 /** @brief Build OpenGL program for functional tests
   1094  *
   1095  *  @param [in]  clipdistances_array_size   use size of gl_ClipDistance array
   1096  *  @param [in]  culldistances_array_size   use size of gl_CullDistance array
   1097  *  @param [in]  dynamic_index_writes       use dunamic indexing for setting  the gl_ClipDistance and gl_CullDistance arrays
   1098  *  @param [in]  primitive_mode             primitive_mode will be used for rendering
   1099  *  @param [in]  redeclare_clipdistances    redeclare gl_ClipDistance
   1100  *  @param [in]  redeclare_culldistances    redeclare gl_CullDistance
   1101  *  @param [in]  use_core_functionality     use core OpenGL functionality
   1102  *  @param [in]  use_gs                     use geometry shader
   1103  *  @param [in]  use_ts                     use tessellation shader
   1104  *  @param [in]  fetch_culldistance_from_fs fetch check sum of gl_ClipDistance and gl_CullDistance from fragment shader
   1105  */
   1106 void CullDistance::FunctionalTest::buildPO(glw::GLuint clipdistances_array_size, glw::GLuint culldistances_array_size,
   1107 										   bool dynamic_index_writes, _primitive_mode primitive_mode,
   1108 										   bool redeclare_clipdistances, bool redeclare_culldistances,
   1109 										   bool use_core_functionality, bool use_gs, bool use_ts,
   1110 										   bool fetch_culldistance_from_fs)
   1111 {
   1112 	deinitPO();
   1113 
   1114 	/* Form the vertex shader */
   1115 	glw::GLuint clipdistances_input_size =
   1116 		clipdistances_array_size > 0 ? clipdistances_array_size : 1; /* Avoid zero-sized array compilation error */
   1117 	glw::GLuint culldistances_input_size =
   1118 		culldistances_array_size > 0 ? culldistances_array_size : 1; /* Avoid zero-sized array compilation error */
   1119 	static const glw::GLchar* dynamic_array_setters =
   1120 		"\n"
   1121 		"#if TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES\n"
   1122 		"	 for (int n_clipdistance_entry = 0;\n"
   1123 		"		  n_clipdistance_entry < TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES;\n"
   1124 		"		++n_clipdistance_entry)\n"
   1125 		"	 {\n"
   1126 		"	     ASSIGN_CLIP_DISTANCE(n_clipdistance_entry);\n"
   1127 		"	 }\n"
   1128 		"#endif"
   1129 		"\n"
   1130 		"#if TEMPLATE_N_GL_CULLDISTANCE_ENTRIES \n"
   1131 		"	 for (int n_culldistance_entry = 0;\n"
   1132 		"		  n_culldistance_entry < TEMPLATE_N_GL_CULLDISTANCE_ENTRIES;\n"
   1133 		"		++n_culldistance_entry)\n"
   1134 		"	 {\n"
   1135 		"	     ASSIGN_CULL_DISTANCE(n_culldistance_entry);\n"
   1136 		"	 }\n"
   1137 		"#endif\n";
   1138 
   1139 	static const glw::GLchar* core_functionality = "#version 450\n";
   1140 
   1141 	static const glw::GLchar* extention_functionality = "#version 440\n"
   1142 														"\n"
   1143 														"#extension GL_ARB_cull_distance : require\n"
   1144 														"\n"
   1145 														"#ifndef GL_ARB_cull_distance\n"
   1146 														"    #error GL_ARB_cull_distance is undefined\n"
   1147 														"#endif\n";
   1148 
   1149 	static const glw::GLchar* fetch_function = "highp float fetch()\n"
   1150 											   "{\n"
   1151 											   "    highp float sum = 0.0;\n"
   1152 											   "\n"
   1153 											   "TEMPLATE_SUM_SETTER"
   1154 											   "\n"
   1155 											   "    return sum / TEMPLATE_SUM_DIVIDER;\n"
   1156 											   "}\n"
   1157 											   "\n"
   1158 											   "#define ASSIGN_RETURN_VALUE fetch()";
   1159 
   1160 	static const glw::GLchar* fs_template = "TEMPLATE_HEADER_DECLARATION\n"
   1161 											"\n"
   1162 											"TEMPLATE_REDECLARE_CLIPDISTANCE\n"
   1163 											"TEMPLATE_REDECLARE_CULLDISTANCE\n"
   1164 											"\n"
   1165 											"TEMPLATE_ASSIGN_RETURN_VALUE\n"
   1166 											"\n"
   1167 											"out vec4 out_fs;\n"
   1168 											"\n"
   1169 											"/* Fragment shader main function */\n"
   1170 											"void main()\n"
   1171 											"{\n"
   1172 											"    out_fs = vec4(ASSIGN_RETURN_VALUE, 1.0, 1.0, 1.0);\n"
   1173 											"}\n";
   1174 
   1175 	static const glw::GLchar* gs_template = "TEMPLATE_HEADER_DECLARATION\n"
   1176 											"\n"
   1177 											"TEMPLATE_LAYOUT_IN\n"
   1178 											"TEMPLATE_LAYOUT_OUT\n"
   1179 											"\n"
   1180 											"TEMPLATE_REDECLARE_CLIPDISTANCE\n"
   1181 											"TEMPLATE_REDECLARE_CULLDISTANCE\n"
   1182 											"\n"
   1183 											"#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
   1184 											"#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
   1185 											"\n"
   1186 											"/* Geometry shader (passthrough) main function */\n"
   1187 											"void main()\n"
   1188 											"{\n"
   1189 											"    for (int n_vertex_index = 0;\n"
   1190 											"             n_vertex_index < gl_in.length();\n"
   1191 											"             n_vertex_index ++)\n"
   1192 											"    {\n"
   1193 											"        gl_Position = gl_in[n_vertex_index].gl_Position;\n"
   1194 											"\n"
   1195 											"        TEMPLATE_ARRAY_SETTERS\n"
   1196 											"\n"
   1197 											"        EmitVertex();\n"
   1198 											"    }\n"
   1199 											"\n"
   1200 											"    EndPrimitive();\n"
   1201 											"}\n";
   1202 
   1203 	static const glw::GLchar* tc_template =
   1204 		"TEMPLATE_HEADER_DECLARATION\n"
   1205 		"\n"
   1206 		"TEMPLATE_LAYOUT_OUT\n"
   1207 		"\n"
   1208 		"out gl_PerVertex {\n"
   1209 		"TEMPLATE_REDECLARE_CLIPDISTANCE\n"
   1210 		"TEMPLATE_REDECLARE_CULLDISTANCE\n"
   1211 		"vec4 gl_Position;\n"
   1212 		"} gl_out[];\n"
   1213 		"\n"
   1214 		"#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
   1215 		"#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
   1216 		"\n"
   1217 		"/* Tesselation control shader main function */\n"
   1218 		"void main()\n"
   1219 		"{\n"
   1220 		"    gl_TessLevelInner[0] = 1.0;\n"
   1221 		"    gl_TessLevelInner[1] = 1.0;\n"
   1222 		"    gl_TessLevelOuter[0] = 1.0;\n"
   1223 		"    gl_TessLevelOuter[1] = 1.0;\n"
   1224 		"    gl_TessLevelOuter[2] = 1.0;\n"
   1225 		"    gl_TessLevelOuter[3] = 1.0;\n"
   1226 		"    /* Clipdistance and culldistance array setters */\n"
   1227 		"    {\n"
   1228 		"        TEMPLATE_ARRAY_SETTERS\n"
   1229 		"    }\n"
   1230 		"    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
   1231 		"}\n";
   1232 
   1233 	static const glw::GLchar* te_template = "TEMPLATE_HEADER_DECLARATION\n"
   1234 											"\n"
   1235 											"TEMPLATE_LAYOUT_IN\n"
   1236 											"\n"
   1237 											"in gl_PerVertex {\n"
   1238 											"TEMPLATE_REDECLARE_IN_CLIPDISTANCE\n"
   1239 											"TEMPLATE_REDECLARE_IN_CULLDISTANCE\n"
   1240 											"vec4 gl_Position;\n"
   1241 											"} gl_in[];\n"
   1242 											"\n"
   1243 											"TEMPLATE_REDECLARE_CLIPDISTANCE\n"
   1244 											"TEMPLATE_REDECLARE_CULLDISTANCE\n"
   1245 											"\n"
   1246 											"#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
   1247 											"#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
   1248 											"\n"
   1249 											"/* Tesselation evaluation shader main function */\n"
   1250 											"void main()\n"
   1251 											"{\n"
   1252 											"    /* Clipdistance and culldistance array setters */\n"
   1253 											"    {\n"
   1254 											"        TEMPLATE_ARRAY_SETTERS\n"
   1255 											"    }\n"
   1256 											"    gl_Position = TEMPLATE_OUT_FORMULA;\n"
   1257 											"}\n";
   1258 
   1259 	static const glw::GLchar* vs_template =
   1260 		"TEMPLATE_HEADER_DECLARATION\n"
   1261 		"\n"
   1262 		"in float clipdistance_data[TEMPLATE_CLIPDISTANCE_INPUT_SIZE];\n"
   1263 		"in float culldistance_data[TEMPLATE_CULLDISTANCE_INPUT_SIZE];\n"
   1264 		"in vec2  position;\n"
   1265 		"\n"
   1266 		"TEMPLATE_REDECLARE_CLIPDISTANCE\n"
   1267 		"TEMPLATE_REDECLARE_CULLDISTANCE\n"
   1268 		"\n"
   1269 		"#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n"
   1270 		"#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n"
   1271 		"\n"
   1272 		"/* Vertex shader main function */\n"
   1273 		"void main()\n"
   1274 		"{\n"
   1275 		"    /* Clipdistance and culldistance array setters */\n"
   1276 		"    {\n"
   1277 		"        TEMPLATE_ARRAY_SETTERS\n"
   1278 		"    }\n"
   1279 		"    gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, 0.0, 1.0);\n"
   1280 		"}\n";
   1281 
   1282 	std::string* shader_body_string_fs	 = DE_NULL;
   1283 	std::string* shader_body_string_gs	 = DE_NULL;
   1284 	std::string* shader_body_string_tc	 = DE_NULL;
   1285 	std::string* shader_body_string_te	 = DE_NULL;
   1286 	std::string* shader_body_string_vs	 = DE_NULL;
   1287 	std::string  shader_header_declaration = use_core_functionality ? core_functionality : extention_functionality;
   1288 
   1289 	struct _shaders_configuration
   1290 	{
   1291 		glw::GLenum		   type;
   1292 		const glw::GLchar* shader_template;
   1293 		std::string		   body;
   1294 		const bool		   use;
   1295 	} shaders_configuration[] = { {
   1296 									  GL_FRAGMENT_SHADER, fs_template, std::string(), true,
   1297 								  },
   1298 								  {
   1299 									  GL_GEOMETRY_SHADER, gs_template, std::string(), use_gs,
   1300 								  },
   1301 								  {
   1302 									  GL_TESS_CONTROL_SHADER, tc_template, std::string(), use_ts,
   1303 								  },
   1304 								  {
   1305 									  GL_TESS_EVALUATION_SHADER, te_template, std::string(), use_ts,
   1306 								  },
   1307 								  {
   1308 									  GL_VERTEX_SHADER, vs_template, std::string(), true,
   1309 								  } };
   1310 
   1311 	const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]);
   1312 
   1313 	/* Construct shader bodies out of templates */
   1314 	for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++)
   1315 	{
   1316 		if (shaders_configuration[n_shader_index].use)
   1317 		{
   1318 			std::string  array_setters;
   1319 			std::string  clipdistance_array_declaration;
   1320 			std::string  culldistance_array_declaration;
   1321 			std::string  clipdistance_in_array_declaration;
   1322 			std::string  culldistance_in_array_declaration;
   1323 			std::string& shader_source = shaders_configuration[n_shader_index].body;
   1324 
   1325 			/* Copy template into shader body source */
   1326 			shader_source = shaders_configuration[n_shader_index].shader_template;
   1327 
   1328 			CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_HEADER_DECLARATION"),
   1329 												shader_header_declaration);
   1330 
   1331 			/* Shader-specific actions */
   1332 			switch (shaders_configuration[n_shader_index].type)
   1333 			{
   1334 			case GL_FRAGMENT_SHADER:
   1335 			{
   1336 				shader_body_string_fs = &shaders_configuration[n_shader_index].body;
   1337 
   1338 				if (fetch_culldistance_from_fs)
   1339 				{
   1340 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"),
   1341 														std::string(fetch_function));
   1342 
   1343 					std::string fetch_sum_setters = "";
   1344 					for (glw::GLuint i = 0; i < clipdistances_array_size; ++i)
   1345 					{
   1346 						fetch_sum_setters.append("    sum += abs(gl_ClipDistance[");
   1347 						fetch_sum_setters.append(CullDistance::Utilities::intToString(i));
   1348 						fetch_sum_setters.append("]) * ");
   1349 						fetch_sum_setters.append(CullDistance::Utilities::intToString(i + 1));
   1350 						fetch_sum_setters.append(".0;\n");
   1351 					}
   1352 
   1353 					fetch_sum_setters.append("\n");
   1354 
   1355 					for (glw::GLuint i = 0; i < culldistances_array_size; ++i)
   1356 					{
   1357 						fetch_sum_setters.append("    sum += abs(gl_CullDistance[");
   1358 						fetch_sum_setters.append(CullDistance::Utilities::intToString(i));
   1359 						fetch_sum_setters.append("]) * ");
   1360 						fetch_sum_setters.append(
   1361 							CullDistance::Utilities::intToString(i + 1 + clipdistances_array_size));
   1362 						fetch_sum_setters.append(".0;\n");
   1363 					}
   1364 
   1365 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_SUM_SETTER"),
   1366 														std::string(fetch_sum_setters));
   1367 					CullDistance::Utilities::replaceAll(
   1368 						shader_source, std::string("TEMPLATE_SUM_DIVIDER"),
   1369 						std::string(CullDistance::Utilities::intToString(
   1370 										(clipdistances_array_size + culldistances_array_size) *
   1371 										((clipdistances_array_size + culldistances_array_size + 1))))
   1372 							.append(".0"));
   1373 				}
   1374 				else
   1375 				{
   1376 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"),
   1377 														std::string("#define ASSIGN_RETURN_VALUE 1.0"));
   1378 				}
   1379 
   1380 				break;
   1381 			}
   1382 
   1383 			case GL_GEOMETRY_SHADER:
   1384 			{
   1385 				shader_body_string_gs = &shaders_configuration[n_shader_index].body;
   1386 
   1387 				CullDistance::Utilities::replaceAll(
   1388 					shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
   1389 					std::string("gl_ClipDistance[IDX] = gl_in[n_vertex_index].gl_ClipDistance[IDX]"));
   1390 				CullDistance::Utilities::replaceAll(
   1391 					shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
   1392 					std::string("gl_CullDistance[IDX] = gl_in[n_vertex_index].gl_CullDistance[IDX]"));
   1393 
   1394 				switch (primitive_mode)
   1395 				{
   1396 				case PRIMITIVE_MODE_LINES:
   1397 				{
   1398 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
   1399 														std::string("layout(lines)                        in;"));
   1400 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
   1401 														std::string("layout(line_strip, max_vertices = 2) out;"));
   1402 
   1403 					break;
   1404 				}
   1405 				case PRIMITIVE_MODE_POINTS:
   1406 				{
   1407 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
   1408 														std::string("layout(points)                   in;"));
   1409 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
   1410 														std::string("layout(points, max_vertices = 1) out;"));
   1411 
   1412 					break;
   1413 				}
   1414 				case PRIMITIVE_MODE_TRIANGLES:
   1415 				{
   1416 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
   1417 														std::string("layout(triangles)                        in;"));
   1418 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
   1419 														std::string("layout(triangle_strip, max_vertices = 3) out;"));
   1420 
   1421 					break;
   1422 				}
   1423 				default:
   1424 					TCU_FAIL("Unknown primitive mode");
   1425 				}
   1426 
   1427 				break;
   1428 			}
   1429 
   1430 			case GL_TESS_CONTROL_SHADER:
   1431 			{
   1432 				shader_body_string_tc = &shaders_configuration[n_shader_index].body;
   1433 
   1434 				CullDistance::Utilities::replaceAll(
   1435 					shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
   1436 					std::string(
   1437 						"gl_out[gl_InvocationID].gl_ClipDistance[IDX] = gl_in[gl_InvocationID].gl_ClipDistance[IDX]"));
   1438 				CullDistance::Utilities::replaceAll(
   1439 					shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
   1440 					std::string(
   1441 						"gl_out[gl_InvocationID].gl_CullDistance[IDX] = gl_in[gl_InvocationID].gl_CullDistance[IDX]"));
   1442 
   1443 				switch (primitive_mode)
   1444 				{
   1445 				case PRIMITIVE_MODE_LINES:
   1446 				{
   1447 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
   1448 														std::string("layout(vertices = 2) out;"));
   1449 
   1450 					break;
   1451 				}
   1452 				case PRIMITIVE_MODE_POINTS:
   1453 				{
   1454 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
   1455 														std::string("layout(vertices = 1) out;"));
   1456 
   1457 					break;
   1458 				}
   1459 				case PRIMITIVE_MODE_TRIANGLES:
   1460 				{
   1461 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"),
   1462 														std::string("layout(vertices = 3) out;"));
   1463 
   1464 					break;
   1465 				}
   1466 				default:
   1467 					TCU_FAIL("Unknown primitive mode");
   1468 				}
   1469 
   1470 				break;
   1471 			}
   1472 
   1473 			case GL_TESS_EVALUATION_SHADER:
   1474 			{
   1475 				shader_body_string_te = &shaders_configuration[n_shader_index].body;
   1476 
   1477 				switch (primitive_mode)
   1478 				{
   1479 				case PRIMITIVE_MODE_LINES:
   1480 				{
   1481 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
   1482 														std::string("layout(isolines) in;"));
   1483 					CullDistance::Utilities::replaceAll(
   1484 						shader_source, std::string("TEMPLATE_OUT_FORMULA"),
   1485 						std::string("mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x)"));
   1486 					CullDistance::Utilities::replaceAll(
   1487 						shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
   1488 						std::string("gl_ClipDistance[IDX] = mix(gl_in[0].gl_ClipDistance[IDX], "
   1489 									"gl_in[1].gl_ClipDistance[IDX], gl_TessCoord.x)"));
   1490 					CullDistance::Utilities::replaceAll(
   1491 						shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
   1492 						std::string("gl_CullDistance[IDX] = mix(gl_in[0].gl_CullDistance[IDX], "
   1493 									"gl_in[1].gl_CullDistance[IDX], gl_TessCoord.x)"));
   1494 
   1495 					break;
   1496 				}
   1497 				case PRIMITIVE_MODE_POINTS:
   1498 				{
   1499 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
   1500 														std::string("layout(isolines, point_mode) in;"));
   1501 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_OUT_FORMULA"),
   1502 														std::string("gl_in[0].gl_Position"));
   1503 					CullDistance::Utilities::replaceAll(
   1504 						shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
   1505 						std::string("gl_ClipDistance[IDX] = gl_in[0].gl_ClipDistance[IDX]"));
   1506 					CullDistance::Utilities::replaceAll(
   1507 						shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
   1508 						std::string("gl_CullDistance[IDX] = gl_in[0].gl_CullDistance[IDX]"));
   1509 
   1510 					break;
   1511 				}
   1512 				case PRIMITIVE_MODE_TRIANGLES:
   1513 				{
   1514 					CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"),
   1515 														std::string("layout(triangles) in;"));
   1516 					CullDistance::Utilities::replaceAll(
   1517 						shader_source, std::string("TEMPLATE_OUT_FORMULA"),
   1518 						std::string("vec4(mat3(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, "
   1519 									"gl_in[2].gl_Position.xyz) * gl_TessCoord, 1.0)"));
   1520 					CullDistance::Utilities::replaceAll(
   1521 						shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
   1522 						std::string("gl_ClipDistance[IDX] = dot(vec3(gl_in[0].gl_ClipDistance[IDX], "
   1523 									"gl_in[1].gl_ClipDistance[IDX], gl_in[2].gl_ClipDistance[IDX]), gl_TessCoord)"));
   1524 					CullDistance::Utilities::replaceAll(
   1525 						shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
   1526 						std::string("gl_CullDistance[IDX] = dot(vec3(gl_in[0].gl_CullDistance[IDX], "
   1527 									"gl_in[1].gl_CullDistance[IDX], gl_in[2].gl_CullDistance[IDX]), gl_TessCoord)"));
   1528 
   1529 					break;
   1530 				}
   1531 				default:
   1532 					TCU_FAIL("Unknown primitive mode");
   1533 				}
   1534 
   1535 				break;
   1536 			}
   1537 
   1538 			case GL_VERTEX_SHADER:
   1539 			{
   1540 				shader_body_string_vs = &shaders_configuration[n_shader_index].body;
   1541 
   1542 				/* Specify input data size for clipdistances data */
   1543 				CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CLIPDISTANCE_INPUT_SIZE"),
   1544 													CullDistance::Utilities::intToString(clipdistances_input_size));
   1545 
   1546 				/* Specify input data size for culldistances data */
   1547 				CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CULLDISTANCE_INPUT_SIZE"),
   1548 													CullDistance::Utilities::intToString(culldistances_input_size));
   1549 
   1550 				CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"),
   1551 													std::string("gl_ClipDistance[IDX] = clipdistance_data[IDX]"));
   1552 				CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"),
   1553 													std::string("gl_CullDistance[IDX] = culldistance_data[IDX]"));
   1554 
   1555 				break;
   1556 			}
   1557 
   1558 			default:
   1559 				TCU_FAIL("Unknown shader type");
   1560 			}
   1561 
   1562 			/* Adjust clipdistances declaration */
   1563 			if (redeclare_clipdistances && clipdistances_array_size > 0)
   1564 			{
   1565 				if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER)
   1566 				{
   1567 					if (fetch_culldistance_from_fs)
   1568 					{
   1569 						clipdistance_array_declaration =
   1570 							std::string("in float gl_ClipDistance[") +
   1571 							CullDistance::Utilities::intToString(clipdistances_array_size) + std::string("];");
   1572 					}
   1573 				}
   1574 				else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER)
   1575 				{
   1576 					clipdistance_array_declaration = std::string("float gl_ClipDistance[") +
   1577 													 CullDistance::Utilities::intToString(clipdistances_array_size) +
   1578 													 std::string("];");
   1579 				}
   1580 				else
   1581 				{
   1582 					clipdistance_array_declaration = std::string("out float gl_ClipDistance[") +
   1583 													 CullDistance::Utilities::intToString(clipdistances_array_size) +
   1584 													 std::string("];");
   1585 					clipdistance_in_array_declaration = std::string("in float gl_ClipDistance[") +
   1586 														CullDistance::Utilities::intToString(clipdistances_array_size) +
   1587 														std::string("];");
   1588 				}
   1589 			}
   1590 			CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CLIPDISTANCE"),
   1591 												clipdistance_array_declaration);
   1592 			CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CLIPDISTANCE"),
   1593 												clipdistance_in_array_declaration);
   1594 
   1595 			/* Adjust culldistances declaration */
   1596 			if (redeclare_culldistances && culldistances_array_size > 0)
   1597 			{
   1598 				if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER)
   1599 				{
   1600 					if (fetch_culldistance_from_fs)
   1601 					{
   1602 						culldistance_array_declaration =
   1603 							std::string("in float gl_CullDistance[") +
   1604 							CullDistance::Utilities::intToString(culldistances_array_size) + std::string("];");
   1605 					}
   1606 				}
   1607 				else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER)
   1608 				{
   1609 					culldistance_array_declaration = std::string("float gl_CullDistance[") +
   1610 													 CullDistance::Utilities::intToString(culldistances_array_size) +
   1611 													 std::string("];");
   1612 				}
   1613 				else
   1614 				{
   1615 					culldistance_array_declaration = std::string("out float gl_CullDistance[") +
   1616 													 CullDistance::Utilities::intToString(culldistances_array_size) +
   1617 													 std::string("];");
   1618 					culldistance_in_array_declaration = std::string("in float gl_CullDistance[") +
   1619 														CullDistance::Utilities::intToString(culldistances_array_size) +
   1620 														std::string("];");
   1621 				}
   1622 			}
   1623 			CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CULLDISTANCE"),
   1624 												culldistance_array_declaration);
   1625 			CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CULLDISTANCE"),
   1626 												culldistance_in_array_declaration);
   1627 
   1628 			/* Adjust clip/cull distances setters */
   1629 			if (dynamic_index_writes)
   1630 			{
   1631 				array_setters = dynamic_array_setters;
   1632 
   1633 				CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES"),
   1634 													CullDistance::Utilities::intToString(clipdistances_array_size));
   1635 				CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CULLDISTANCE_ENTRIES"),
   1636 													CullDistance::Utilities::intToString(culldistances_array_size));
   1637 			}
   1638 			else
   1639 			{
   1640 				std::stringstream static_array_setters_sstream;
   1641 
   1642 				static_array_setters_sstream << "\n";
   1643 
   1644 				for (glw::GLuint clipdistances_array_entry = 0; clipdistances_array_entry < clipdistances_array_size;
   1645 					 ++clipdistances_array_entry)
   1646 				{
   1647 					static_array_setters_sstream << "        ASSIGN_CLIP_DISTANCE(" << clipdistances_array_entry
   1648 												 << ");\n";
   1649 				}
   1650 
   1651 				static_array_setters_sstream << "\n";
   1652 
   1653 				for (glw::GLuint culldistances_array_entry = 0; culldistances_array_entry < culldistances_array_size;
   1654 					 ++culldistances_array_entry)
   1655 				{
   1656 					static_array_setters_sstream << "        ASSIGN_CULL_DISTANCE(" << culldistances_array_entry
   1657 												 << ");\n";
   1658 				}
   1659 
   1660 				array_setters = static_array_setters_sstream.str();
   1661 			}
   1662 
   1663 			CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ARRAY_SETTERS"), array_setters);
   1664 		}
   1665 	}
   1666 
   1667 	/* Build the geometry shader */
   1668 	CullDistance::Utilities::buildProgram(
   1669 		m_context.getRenderContext().getFunctions(), m_testCtx, DE_NULL, /* Compute shader                    */
   1670 		shader_body_string_fs != DE_NULL ? shader_body_string_fs->c_str() :
   1671 										   DE_NULL, /* Fragment shader                   */
   1672 		shader_body_string_gs != DE_NULL ? shader_body_string_gs->c_str() :
   1673 										   DE_NULL, /* Geometry shader                   */
   1674 		shader_body_string_tc != DE_NULL ? shader_body_string_tc->c_str() :
   1675 										   DE_NULL, /* Tesselation control shader        */
   1676 		shader_body_string_te != DE_NULL ? shader_body_string_te->c_str() :
   1677 										   DE_NULL, /* Tesselation evaluation shader     */
   1678 		shader_body_string_vs != DE_NULL ? shader_body_string_vs->c_str() :
   1679 										   DE_NULL, /* Vertex shader                     */
   1680 		0,											/* Transform feedback varyings count */
   1681 		DE_NULL,									/* Transform feedback varyings       */
   1682 		&m_po_id									/* Program object id                 */
   1683 		);
   1684 }
   1685 
   1686 /** Generates primitive data required to test a case with specified
   1687  *  gl_ClipDistance and glCullDistance array sizes for specified
   1688  *  primitive mode. Generated primitive data is stored in m_bo_data
   1689  *  as well uploaded into buffer specified in m_bo_id buffer.
   1690  *  Also the procedure binds vertex attribute locations to
   1691  *  program object m_po_id.
   1692  *
   1693  *  @param clipdistances_array_size gl_ClipDistance array size. Can be 0.
   1694  *  @param culldistances_array_size gl_CullDistance array size. Can be 0.
   1695  *  @param _primitive_mode          Primitives to be generated. Can be:
   1696  *                                  PRIMITIVE_MODE_POINTS,
   1697  *                                  PRIMITIVE_MODE_LINES,
   1698  *                                  PRIMITIVE_MODE_TRIANGLES.
   1699  */
   1700 void CullDistance::FunctionalTest::configureVAO(glw::GLuint clipdistances_array_size,
   1701 												glw::GLuint culldistances_array_size, _primitive_mode primitive_mode)
   1702 {
   1703 	/* Detailed test description.
   1704 	 *
   1705 	 * configureVAO() generates primitives layouted in grid. Primitve
   1706 	 * consists of up to 3 vertices and each vertex is accompanied by:
   1707 	 * - array of clipdistances (clipdistances_array_size floats);
   1708 	 * - array of culldistances (culldistances_array_size floats);
   1709 	 * - rendering position coordinates (x and y);
   1710 	 * - check position coordinates (x and y).
   1711 	 *
   1712 	 * The grid has following layout:
   1713 	 *
   1714 	 *     Grid                       |         gl_CullDistance[x]         |
   1715 	 *                                |  0 .. culldistances_array_size - 1 |
   1716 	 *                                |  0th  |  1st  |  2nd  | .......... |
   1717 	 *     ---------------------------+-------+-------+-------+------------+
   1718 	 *     0th  gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
   1719 	 *     1st  gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
   1720 	 *     ...                        |  ...  |  ...  |  ...  | .......... |
   1721 	 *     y-th gl_ClipDistance       |Subgrid|Subgrid|Subgrid| .......... |
   1722 	 *     ...                        |  ...  |  ...  |  ...  | .......... |
   1723 	 *     clipdistances_array_size-1 |Subgrid|Subgrid|Subgrid| .......... |
   1724 	 *
   1725 	 * Each grid cell contains subgrid of 3*3 items in size with following
   1726 	 * structure:
   1727 	 *
   1728 	 *     Subgrid        |        x-th gl_CullDistance test           |
   1729 	 *                    |                                            |
   1730 	 *     y-th           | all vertices | 0th vertex   | all vertices |
   1731 	 *     gl_ClipDistance| in primitive | in primitive | in primitive |
   1732 	 *     tests          | dist[x] > 0  | dist[x] < 0  | dist[x] < 0  |
   1733 	 *     ---------------+--------------+--------------+--------------+
   1734 	 *        all vertices| primitive #0 | primitive #1 | primitive #2 |
   1735 	 *        in primitive|              |              |              |
   1736 	 *        dist[y] > 0 |   visible    |   visible    |    culled    |
   1737 	 *     ---------------+--------------+--------------+--------------+
   1738 	 *        0th vertex  | primitive #3 | primitive #4 | primitive #5 |
   1739 	 *        in primitive|  0th vertex  |  0th vertex  |              |
   1740 	 *        dist[y] < 0 |   clipped    |   clipped    |    culled    |
   1741 	 *     ---------------+--------------+--------------+--------------+
   1742 	 *        all vertices| primitive #6 | primitive #7 | primitive #8 |
   1743 	 *        in primitive|              |              |              |
   1744 	 *        dist[y] < 0 |   clipped    |   clipped    |    culled    |
   1745 	 *     ---------------+--------------+--------------+--------------+
   1746 	 *
   1747 	 * Expected rendering result is specified in cell bottom.
   1748 	 * It can be one of the following:
   1749 	 * - "visible" means the primitive is not affected neither by gl_CullDistance
   1750 	 *             nor by gl_ClipDistance and rendered as a whole;
   1751 	 * - "clipped" for the vertex means the vertex is not rendered, while other
   1752 	 *             primitive vertices and some filling fragments are rendered;
   1753 	 * - "clipped" for primitive means none of primitive vertices and fragments
   1754 	 *             are rendered and thus primitive is not rendered and is invisible;
   1755 	 * - "culled"  means, that neither primitive vertices, nor primitive filling
   1756 	 *             fragments are rendered (primitive is invisible).
   1757 	 *
   1758 	 * All subgrid items contain same primitive rendered. Depending on
   1759 	 * test case running it would be either triangle, or line, or point:
   1760 	 *
   1761 	 *     triangle    line        point
   1762 	 *     8x8 box     8x8 box     3x3 box
   1763 	 *     ........    ........    ...
   1764 	 *     .0----2.    .0......    .0.
   1765 	 *     ..\@@@|.    ..\.....    ...
   1766 	 *     ...\@@|.    ...\....
   1767 	 *     ....\@|.    ....\...
   1768 	 *     .....\|.    .....\..
   1769 	 *     ......1.    ......1.
   1770 	 *     ........    ........
   1771 	 *
   1772 	 *     where 0 - is a 0th vertex primitive
   1773 	 *           1 - is a 1st vertex primitive
   1774 	 *           2 - is a 2nd vertex primitive
   1775 	 *
   1776 	 * The culldistances_array_size can be 0. In that case, grid height
   1777 	 * is assumed equal to 1, but 0 glCullDistances is specified.
   1778 	 * Similar handled clipdistances_array_size.
   1779 	 *
   1780 	 * The data generated is used and checked in executeRenderTest().
   1781 	 * After rendering each primitive vertex is tested:
   1782 	 * - if it is rendered, if it have to be rendered (according distance);
   1783 	 * - if it is not rendered, if it have to be not rendered (according distance).
   1784 	 * Due to "top-left" rasterization rule check position is
   1785 	 * different from rendering vertex position.
   1786 	 *
   1787 	 * Also one pixel width guarding box is checked to be clear.
   1788 	 */
   1789 
   1790 	const glw::Functions& gl			   = m_context.getRenderContext().getFunctions();
   1791 	const glw::GLuint	 n_sub_grid_cells = 3; /* Tested distance is positive for all vertices in the primitive;
   1792 	 * Tested distance is negative for 0th vertex in the primitive;
   1793 	 * Tested distance is negative for all vertices in the primitive;
   1794 	 */
   1795 	const glw::GLuint	 sub_grid_cell_size =
   1796 		((primitive_mode == PRIMITIVE_MODE_LINES) ? 8 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 3 : 8);
   1797 
   1798 	const glw::GLuint grid_cell_size = n_sub_grid_cells * sub_grid_cell_size;
   1799 	const glw::GLuint n_primitive_vertices =
   1800 		((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 : 3);
   1801 
   1802 	const glw::GLuint n_grid_cells_x			   = culldistances_array_size != 0 ? culldistances_array_size : 1;
   1803 	const glw::GLuint n_grid_cells_y			   = clipdistances_array_size != 0 ? clipdistances_array_size : 1;
   1804 	const glw::GLuint n_pervertex_float_attributes = clipdistances_array_size + culldistances_array_size +
   1805 													 2 /* vertex' draw x, y */ + 2 /* vertex' checkpoint x, y */;
   1806 	const glw::GLuint n_primitives_total	 = n_grid_cells_x * n_sub_grid_cells * n_grid_cells_y * n_sub_grid_cells;
   1807 	const glw::GLuint n_vertices_total		 = n_primitives_total * n_primitive_vertices;
   1808 	const glw::GLuint offsets_line_draw_x[2] = {
   1809 		1, sub_grid_cell_size - 1
   1810 	}; /* vertex x offsets to subgrid cell origin for line primitive     */
   1811 	const glw::GLuint offsets_line_draw_y[2] = {
   1812 		1, sub_grid_cell_size - 1
   1813 	}; /* vertex y offsets to subgrid cell origin for line primitive     */
   1814 	const glw::GLuint offsets_line_checkpoint_x[2] = {
   1815 		1, sub_grid_cell_size - 2
   1816 	}; /* pixel x offsets to subgrid cell origin for line primitive      */
   1817 	const glw::GLuint offsets_line_checkpoint_y[2] = {
   1818 		1, sub_grid_cell_size - 2
   1819 	}; /* pixel y offsets to subgrid cell origin for line primitive      */
   1820 	const glw::GLuint offsets_point_draw_x[1] = {
   1821 		1
   1822 	}; /* vertex x offsets to subgrid cell origin for point primitive    */
   1823 	const glw::GLuint offsets_point_draw_y[1] = {
   1824 		1
   1825 	}; /* vertex y offsets to subgrid cell origin for point primitive    */
   1826 	const glw::GLuint offsets_point_checkpoint_x[1] = {
   1827 		1
   1828 	}; /* pixel x offsets to subgrid cell origin for point primitive     */
   1829 	const glw::GLuint offsets_point_checkpoint_y[1] = {
   1830 		1
   1831 	}; /* pixel y offsets to subgrid cell origin for point primitive     */
   1832 	const glw::GLuint offsets_triangle_draw_x[3] = {
   1833 		1, sub_grid_cell_size - 1, sub_grid_cell_size - 1
   1834 	}; /* vertex x offsets to subgrid cell origin for triangle primitive */
   1835 	const glw::GLuint offsets_triangle_draw_y[3] = {
   1836 		1, sub_grid_cell_size - 1, 1
   1837 	}; /* vertex y offsets to subgrid cell origin for triangle primitive */
   1838 	const glw::GLuint offsets_triangle_checkpoint_x[3] = {
   1839 		1, sub_grid_cell_size - 2, sub_grid_cell_size - 2
   1840 	}; /* pixel x offsets to subgrid cell origin for triangle primitive  */
   1841 	const glw::GLuint offsets_triangle_checkpoint_y[3] = {
   1842 		1, sub_grid_cell_size - 2, 1
   1843 	}; /* pixel y offsets to subgrid cell origin for triangle primitive  */
   1844 	const glw::GLfloat offsets_pixel_center_x = (primitive_mode == PRIMITIVE_MODE_POINTS) ? 0.5f : 0;
   1845 	const glw::GLfloat offsets_pixel_center_y = (primitive_mode == PRIMITIVE_MODE_POINTS) ? 0.5f : 0;
   1846 	/* Clear data left from previous tests. */
   1847 	m_bo_data.clear();
   1848 
   1849 	/* No data to render */
   1850 	m_render_primitives = 0;
   1851 	m_render_vertices   = 0;
   1852 
   1853 	/* Preallocate space for bo_points_count */
   1854 	m_bo_data.reserve(n_vertices_total * n_pervertex_float_attributes);
   1855 
   1856 	/* Generate test data for cell_y-th clip distance */
   1857 	for (glw::GLuint cell_y = 0; cell_y < n_grid_cells_y; cell_y++)
   1858 	{
   1859 		/* Generate test data for cell_x-th cull distance */
   1860 		for (glw::GLuint cell_x = 0; cell_x < n_grid_cells_x; cell_x++)
   1861 		{
   1862 			/* Check clip distance sub cases:
   1863 			 * 0. Tested distance is positive for all vertices in the primitive;
   1864 			 * 1. Tested distance is negative for 0th vertex in the primitive;
   1865 			 * 2. Tested distance is negative for all vertices in the primitive;
   1866 			 */
   1867 			for (glw::GLuint n_sub_cell_y = 0; n_sub_cell_y < n_sub_grid_cells; n_sub_cell_y++)
   1868 			{
   1869 				/* Check cull distance sub cases:
   1870 				 * 0. Tested distance is positive for all vertices in the primitive;
   1871 				 * 1. Tested distance is negative for 0th vertex in the primitive;
   1872 				 * 2. Tested distance is negative for all vertices in the primitive;
   1873 				 */
   1874 				for (glw::GLuint n_sub_cell_x = 0; n_sub_cell_x < n_sub_grid_cells; n_sub_cell_x++)
   1875 				{
   1876 					/* Generate vertices in primitive */
   1877 					for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < n_primitive_vertices;
   1878 						 n_primitive_vertex++)
   1879 					{
   1880 						/* Fill in clipdistance array for the n_primitive_vertex vertex in primitive */
   1881 						for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
   1882 							 n_clipdistance_entry++)
   1883 						{
   1884 							glw::GLfloat distance_value = 0.0f;
   1885 							bool		 negative		= true;
   1886 
   1887 							/* Special approach to tested clipdistance entry. */
   1888 							if (n_clipdistance_entry == cell_y)
   1889 							{
   1890 								/* The primitive vertex should be affected by the clip distance */
   1891 								switch (n_sub_cell_y)
   1892 								{
   1893 								case 0:
   1894 								{
   1895 									/* subgrid row 0: all primitive vertices have tested distance value positive */
   1896 									negative = false;
   1897 
   1898 									break;
   1899 								}
   1900 								case 1:
   1901 								{
   1902 									/* subgrid row 1: tested distance value for 0th primitive vertex is negative,
   1903 									 all other primitive vertices have tested distance value positive */
   1904 									negative = (n_primitive_vertex == 0) ? true : false;
   1905 
   1906 									break;
   1907 								}
   1908 								case 2:
   1909 								{
   1910 									/* subgrid row 2: tested distance value is negative for all primitive vertices */
   1911 									negative = true;
   1912 
   1913 									break;
   1914 								}
   1915 								default:
   1916 									TCU_FAIL("Invalid subgrid cell index");
   1917 								}
   1918 
   1919 								distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_clipdistance_entry + 1);
   1920 							}
   1921 							else
   1922 							{
   1923 								/* For clip distances other than tested: assign positive value to avoid its influence. */
   1924 								distance_value = glw::GLfloat(clipdistances_array_size + n_clipdistance_entry + 1);
   1925 							}
   1926 
   1927 							m_bo_data.push_back(distance_value / glw::GLfloat(clipdistances_array_size));
   1928 						} /* for (all gl_ClipDistance[] array values) */
   1929 
   1930 						/* Fill in culldistance array for the n_primitive_vertex vertex in primitive */
   1931 						for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
   1932 							 n_culldistance_entry++)
   1933 						{
   1934 							glw::GLfloat distance_value = 0.0f;
   1935 							bool		 negative		= true;
   1936 
   1937 							/* Special approach to tested culldistance entry. */
   1938 							if (n_culldistance_entry == cell_x)
   1939 							{
   1940 								/* The primitive vertex should be affected by the cull distance */
   1941 								switch (n_sub_cell_x)
   1942 								{
   1943 								case 0:
   1944 								{
   1945 									/* subgrid column 0: all primitive vertices have tested distance value positive */
   1946 									negative = false;
   1947 
   1948 									break;
   1949 								}
   1950 								case 1:
   1951 								{
   1952 									/* subgrid column 1: tested distance value for 0th primitive vertex is negative,
   1953 									 all other primitive vertices have tested distance value positive */
   1954 									negative = (n_primitive_vertex == 0) ? true : false;
   1955 
   1956 									break;
   1957 								}
   1958 								case 2:
   1959 								{
   1960 									/* subgrid column 2: tested distance value is negative for all primitive vertices */
   1961 									negative = true;
   1962 
   1963 									break;
   1964 								}
   1965 								default:
   1966 									TCU_FAIL("Invalid subgrid cell index");
   1967 								}
   1968 
   1969 								distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_culldistance_entry + 1);
   1970 							}
   1971 							else
   1972 							{
   1973 								/* For cull distances other than tested: assign 0th vertex negative value,
   1974 								 to check absence of between-distances influence. */
   1975 								if (n_primitive_vertices > 1 && n_primitive_vertex == 0)
   1976 								{
   1977 									distance_value = -glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1);
   1978 								}
   1979 								else
   1980 								{
   1981 									/* This culldistance is out of interest: assign positive value. */
   1982 									distance_value = glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1);
   1983 								}
   1984 							}
   1985 
   1986 							m_bo_data.push_back(distance_value / glw::GLfloat(culldistances_array_size));
   1987 						} /* for (all gl_CullDistance[] array values) */
   1988 
   1989 						/* Generate primitve vertex draw and checkpoint coordinates */
   1990 						glw::GLint vertex_draw_pixel_offset_x		= 0;
   1991 						glw::GLint vertex_draw_pixel_offset_y		= 0;
   1992 						glw::GLint vertex_checkpoint_pixel_offset_x = 0;
   1993 						glw::GLint vertex_checkpoint_pixel_offset_y = 0;
   1994 
   1995 						switch (primitive_mode)
   1996 						{
   1997 						case PRIMITIVE_MODE_LINES:
   1998 						{
   1999 							vertex_draw_pixel_offset_x		 = offsets_line_draw_x[n_primitive_vertex];
   2000 							vertex_draw_pixel_offset_y		 = offsets_line_draw_y[n_primitive_vertex];
   2001 							vertex_checkpoint_pixel_offset_x = offsets_line_checkpoint_x[n_primitive_vertex];
   2002 							vertex_checkpoint_pixel_offset_y = offsets_line_checkpoint_y[n_primitive_vertex];
   2003 
   2004 							break;
   2005 						}
   2006 
   2007 						case PRIMITIVE_MODE_POINTS:
   2008 						{
   2009 							vertex_draw_pixel_offset_x		 = offsets_point_draw_x[n_primitive_vertex];
   2010 							vertex_draw_pixel_offset_y		 = offsets_point_draw_y[n_primitive_vertex];
   2011 							vertex_checkpoint_pixel_offset_x = offsets_point_checkpoint_x[n_primitive_vertex];
   2012 							vertex_checkpoint_pixel_offset_y = offsets_point_checkpoint_y[n_primitive_vertex];
   2013 
   2014 							break;
   2015 						}
   2016 
   2017 						case PRIMITIVE_MODE_TRIANGLES:
   2018 						{
   2019 							vertex_draw_pixel_offset_x		 = offsets_triangle_draw_x[n_primitive_vertex];
   2020 							vertex_draw_pixel_offset_y		 = offsets_triangle_draw_y[n_primitive_vertex];
   2021 							vertex_checkpoint_pixel_offset_x = offsets_triangle_checkpoint_x[n_primitive_vertex];
   2022 							vertex_checkpoint_pixel_offset_y = offsets_triangle_checkpoint_y[n_primitive_vertex];
   2023 
   2024 							break;
   2025 						}
   2026 
   2027 						default:
   2028 							TCU_FAIL("Unknown primitive mode");
   2029 						}
   2030 
   2031 						/* Origin of sub_cell */
   2032 						glw::GLint sub_cell_origin_x = cell_x * grid_cell_size + n_sub_cell_x * sub_grid_cell_size;
   2033 						glw::GLint sub_cell_origin_y = cell_y * grid_cell_size + n_sub_cell_y * sub_grid_cell_size;
   2034 						/* Normalized texture coordinates of vertex draw position. */
   2035 						glw::GLfloat x =
   2036 							(glw::GLfloat(sub_cell_origin_x + vertex_draw_pixel_offset_x) + offsets_pixel_center_x) /
   2037 							glw::GLfloat(m_to_width);
   2038 						glw::GLfloat y =
   2039 							(glw::GLfloat(sub_cell_origin_y + vertex_draw_pixel_offset_y) + offsets_pixel_center_y) /
   2040 							glw::GLfloat(m_to_height);
   2041 						/* Normalized texture coordinates of vertex checkpoint position. */
   2042 						glw::GLfloat checkpoint_x = glw::GLfloat(sub_cell_origin_x + vertex_checkpoint_pixel_offset_x) /
   2043 													glw::GLfloat(m_to_width);
   2044 						glw::GLfloat checkpoint_y = glw::GLfloat(sub_cell_origin_y + vertex_checkpoint_pixel_offset_y) /
   2045 													glw::GLfloat(m_to_height);
   2046 
   2047 						/* Add vertex draw coordinates into buffer. */
   2048 						m_bo_data.push_back(x);
   2049 						m_bo_data.push_back(y);
   2050 
   2051 						/* Add vertex checkpoint coordinates into buffer. */
   2052 						m_bo_data.push_back(checkpoint_x);
   2053 						m_bo_data.push_back(checkpoint_y);
   2054 					} /* for (all vertices in primitive) */
   2055 				}	 /* for (all horizontal sub cells) */
   2056 			}		  /* for (all vertical sub cells) */
   2057 		}			  /* for (all horizontal cells) */
   2058 	}				  /* for (all vertical cells) */
   2059 
   2060 	/* Sanity check: make sure we pushed required amount of data */
   2061 	DE_ASSERT(m_bo_data.size() == n_vertices_total * n_pervertex_float_attributes);
   2062 
   2063 	/* Save number of primitives to render */
   2064 	m_render_primitives  = n_primitives_total;
   2065 	m_render_vertices	= n_vertices_total;
   2066 	m_sub_grid_cell_size = sub_grid_cell_size;
   2067 
   2068 	/* Copy the data to the buffer object */
   2069 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id);
   2070 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
   2071 
   2072 	gl.bufferData(GL_ARRAY_BUFFER, m_bo_data.size() * sizeof(glw::GLfloat), &m_bo_data[0], GL_STATIC_DRAW);
   2073 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
   2074 
   2075 	DE_ASSERT(m_po_id != 0);
   2076 
   2077 	/* Bind VAO data to program */
   2078 	glw::GLint po_clipdistance_array_location = -1;
   2079 	glw::GLint po_culldistance_array_location = -1;
   2080 	glw::GLint po_position_location			  = -1;
   2081 
   2082 	/* Retrieve clipdistance and culldistance attribute locations */
   2083 	gl.bindVertexArray(m_vao_id);
   2084 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
   2085 
   2086 	po_clipdistance_array_location = gl.getAttribLocation(m_po_id, "clipdistance_data[0]");
   2087 	po_culldistance_array_location = gl.getAttribLocation(m_po_id, "culldistance_data[0]");
   2088 	po_position_location		   = gl.getAttribLocation(m_po_id, "position");
   2089 
   2090 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() call(s) failed.");
   2091 
   2092 	if (clipdistances_array_size > 0)
   2093 	{
   2094 		DE_ASSERT(po_clipdistance_array_location != -1);
   2095 	}
   2096 
   2097 	if (culldistances_array_size > 0)
   2098 	{
   2099 		DE_ASSERT(po_culldistance_array_location != -1);
   2100 	}
   2101 
   2102 	DE_ASSERT(po_position_location != -1);
   2103 
   2104 	glw::GLintptr	current_offset = 0;
   2105 	const glw::GLint stride			= static_cast<glw::GLint>(n_pervertex_float_attributes * sizeof(glw::GLfloat));
   2106 
   2107 	gl.bindVertexArray(m_vao_id);
   2108 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
   2109 
   2110 	for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; ++n_clipdistance_entry)
   2111 	{
   2112 		gl.vertexAttribPointer(po_clipdistance_array_location + n_clipdistance_entry, 1, /* size */
   2113 							   GL_FLOAT, GL_FALSE,										 /* normalized */
   2114 							   stride, (const glw::GLvoid*)current_offset);
   2115 		GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
   2116 
   2117 		gl.enableVertexAttribArray(po_clipdistance_array_location + n_clipdistance_entry);
   2118 		GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
   2119 
   2120 		current_offset += sizeof(glw::GLfloat);
   2121 	} /* for (all clip distance array value attributes) */
   2122 
   2123 	for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size; ++n_culldistance_entry)
   2124 	{
   2125 		gl.vertexAttribPointer(po_culldistance_array_location + n_culldistance_entry, 1, /* size */
   2126 							   GL_FLOAT, GL_FALSE,										 /* normalized */
   2127 							   stride, (const glw::GLvoid*)current_offset);
   2128 		GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
   2129 
   2130 		gl.enableVertexAttribArray(po_culldistance_array_location + n_culldistance_entry);
   2131 		GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
   2132 
   2133 		current_offset += sizeof(glw::GLfloat);
   2134 	} /* for (all cull distance array value attributes) */
   2135 
   2136 	gl.vertexAttribPointer(po_position_location, 2, /* size */
   2137 						   GL_FLOAT, GL_FALSE,		/* normalized */
   2138 						   stride, (const glw::GLvoid*)current_offset);
   2139 	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed");
   2140 
   2141 	gl.enableVertexAttribArray(po_position_location);
   2142 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed");
   2143 }
   2144 
   2145 /** @brief Cull Distance Functional Test deinitialization */
   2146 void CullDistance::FunctionalTest::deinit()
   2147 {
   2148 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2149 
   2150 	if (m_fbo_id != 0)
   2151 	{
   2152 		gl.deleteFramebuffers(1, &m_fbo_id);
   2153 
   2154 		m_fbo_id = 0;
   2155 	}
   2156 
   2157 	if (m_to_id != 0)
   2158 	{
   2159 		gl.deleteTextures(1, &m_to_id);
   2160 
   2161 		m_to_id = 0;
   2162 	}
   2163 
   2164 	if (m_vao_id != 0)
   2165 	{
   2166 		gl.deleteVertexArrays(1, &m_vao_id);
   2167 
   2168 		m_vao_id = 0;
   2169 	}
   2170 
   2171 	deinitPO();
   2172 }
   2173 
   2174 /** @brief Cull Distance Functional Test deinitialization of OpenGL programs */
   2175 void CullDistance::FunctionalTest::deinitPO()
   2176 {
   2177 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2178 
   2179 	if (m_po_id != 0)
   2180 	{
   2181 		gl.deleteProgram(m_po_id);
   2182 
   2183 		m_po_id = 0;
   2184 	}
   2185 }
   2186 
   2187 /** @brief Executes single render test case
   2188  *
   2189  * @param [in]  clipdistances_array_size    Size of gl_ClipDistance[] array
   2190  * @param [in]  culldistances_array_size    Size of gl_CullDistance[] array
   2191  * @param [in]  primitive_mode              Type of primitives to be rendered (see enum _primitive_mode)
   2192  * @param [in]  use_tesselation             Indicate whether to use tessellation shader
   2193  * @param [in]  fetch_culldistance_from_fs  Indicate whether to fetch gl_CullDistance and gl_ClipDistance values from the fragment shader
   2194  */
   2195 void CullDistance::FunctionalTest::executeRenderTest(glw::GLuint	 clipdistances_array_size,
   2196 													 glw::GLuint	 culldistances_array_size,
   2197 													 _primitive_mode primitive_mode, bool use_tesselation,
   2198 													 bool fetch_culldistance_from_fs)
   2199 {
   2200 	const glw::Functions& gl						  = m_context.getRenderContext().getFunctions();
   2201 	glw::GLenum			  mode						  = GL_NONE;
   2202 	glw::GLuint			  n_clipped_vertices_real	 = 0;
   2203 	glw::GLuint			  n_culled_primitives_real	= 0;
   2204 	glw::GLuint			  n_not_clipped_vertices_real = 0;
   2205 	const glw::GLuint	 primitive_vertices_count =
   2206 		((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 : 3);
   2207 	const glw::GLuint stride_in_floats =
   2208 		clipdistances_array_size + culldistances_array_size + 2 /* position's x, y*/ + 2 /* checkpoint x,y */;
   2209 
   2210 	switch (primitive_mode)
   2211 	{
   2212 	case PRIMITIVE_MODE_LINES:
   2213 	{
   2214 		mode = GL_LINES;
   2215 
   2216 		break;
   2217 	}
   2218 	case PRIMITIVE_MODE_POINTS:
   2219 	{
   2220 		mode = GL_POINTS;
   2221 
   2222 		break;
   2223 	}
   2224 	case PRIMITIVE_MODE_TRIANGLES:
   2225 	{
   2226 		mode = GL_TRIANGLES;
   2227 
   2228 		break;
   2229 	}
   2230 	default:
   2231 		TCU_FAIL("Unknown primitive mode");
   2232 	}
   2233 
   2234 	if (use_tesselation)
   2235 	{
   2236 		mode = GL_PATCHES;
   2237 
   2238 		gl.patchParameteri(GL_PATCH_VERTICES, primitive_vertices_count);
   2239 		GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
   2240 	}
   2241 
   2242 	gl.clear(GL_COLOR_BUFFER_BIT);
   2243 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
   2244 
   2245 	gl.useProgram(m_po_id);
   2246 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
   2247 
   2248 	for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++)
   2249 	{
   2250 		gl.enable(GL_CLIP_DISTANCE0 + n_clipdistance_entry);
   2251 		GLU_EXPECT_NO_ERROR(gl.getError(), "gl.enable(GL_CLIP_DISTANCE)() call failed.");
   2252 	} /* for (all clip distance array value attributes) */
   2253 
   2254 	gl.drawArrays(mode, 0, m_render_vertices);
   2255 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray() call(s) failed.");
   2256 
   2257 	for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++)
   2258 	{
   2259 		gl.disable(GL_CLIP_DISTANCE0 + n_clipdistance_entry);
   2260 		GLU_EXPECT_NO_ERROR(gl.getError(), "gl.disable(GL_CLIP_DISTANCE)() call failed.");
   2261 	} /* for (all clip distance array value attributes) */
   2262 
   2263 	gl.useProgram(0);
   2264 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
   2265 
   2266 	/* Read generated texture into m_to_pixel_data_cache */
   2267 	readTexturePixels();
   2268 
   2269 	for (glw::GLint n_primitive_index = 0; n_primitive_index < m_render_primitives; n_primitive_index++)
   2270 	{
   2271 		glw::GLuint base_index_of_primitive		 = n_primitive_index * primitive_vertices_count * stride_in_floats;
   2272 		bool		primitive_culled			 = false;
   2273 		glw::GLint  primitive_culled_by_distance = -1;
   2274 
   2275 		/* Check the bounding box is clear */
   2276 		glw::GLuint base_index_of_vertex	  = base_index_of_primitive;
   2277 		glw::GLuint checkpoint_position_index = base_index_of_vertex + clipdistances_array_size +
   2278 												culldistances_array_size + 2 /* ignore vertex coordinates */;
   2279 		glw::GLint checkpoint_x = glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index]);
   2280 		glw::GLint checkpoint_y = glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index + 1]);
   2281 		glw::GLint origin_x		= checkpoint_x - 1;
   2282 		glw::GLint origin_y		= checkpoint_y - 1;
   2283 		for (glw::GLint pixel_offset = 0; pixel_offset < m_sub_grid_cell_size; pixel_offset++)
   2284 		{
   2285 			if (readRedPixelValue(origin_x + pixel_offset, origin_y) != 0)
   2286 			{
   2287 				TCU_FAIL("Top edge of bounding box is overwritten");
   2288 			}
   2289 
   2290 			if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1, origin_y + pixel_offset) != 0)
   2291 			{
   2292 				TCU_FAIL("Right edge of bounding box is overwritten");
   2293 			}
   2294 
   2295 			if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1 - pixel_offset,
   2296 								  origin_y + m_sub_grid_cell_size - 1) != 0)
   2297 			{
   2298 				TCU_FAIL("Bottom edge of bounding box is overwritten");
   2299 			}
   2300 
   2301 			if (readRedPixelValue(origin_x, origin_y + m_sub_grid_cell_size - 1 - pixel_offset) != 0)
   2302 			{
   2303 				TCU_FAIL("Left edge of bounding box is overwritten");
   2304 			}
   2305 		}
   2306 
   2307 		/* Determine if primitive has been culled */
   2308 		for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
   2309 			 n_culldistance_entry++)
   2310 		{
   2311 			bool distance_negative_in_all_primitive_vertices = true;
   2312 
   2313 			for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
   2314 				 n_primitive_vertex++)
   2315 			{
   2316 				glw::GLint base_index_of_vertex_internal =
   2317 					base_index_of_primitive + n_primitive_vertex * stride_in_floats;
   2318 				glw::GLint	culldistance_array_offset = base_index_of_vertex_internal + clipdistances_array_size;
   2319 				glw::GLfloat* vertex_culldistance_array = &m_bo_data[culldistance_array_offset];
   2320 
   2321 				if (vertex_culldistance_array[n_culldistance_entry] >= 0)
   2322 				{
   2323 					/* Primitive is not culled, due to one of its distances is not negative */
   2324 					distance_negative_in_all_primitive_vertices = false;
   2325 
   2326 					/* Skip left vertices for this distance */
   2327 					break;
   2328 				}
   2329 			}
   2330 
   2331 			/* The distance is negative in all primitive vertices, so this distance culls the primitive */
   2332 			if (distance_negative_in_all_primitive_vertices)
   2333 			{
   2334 				primitive_culled			 = true;
   2335 				primitive_culled_by_distance = n_culldistance_entry;
   2336 
   2337 				n_culled_primitives_real++;
   2338 
   2339 				/* Skip left distances from check */
   2340 				break;
   2341 			}
   2342 		}
   2343 
   2344 		/* Validate culling */
   2345 		if (primitive_culled)
   2346 		{
   2347 			/* Check whether primitive was culled and all its vertices are invisible */
   2348 			for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
   2349 				 n_primitive_vertex++)
   2350 			{
   2351 				glw::GLint base_index_of_vertex_internal =
   2352 					base_index_of_primitive + n_primitive_vertex * stride_in_floats;
   2353 				glw::GLint checkpoint_position_index_internal = base_index_of_vertex_internal +
   2354 																clipdistances_array_size + culldistances_array_size +
   2355 																2 /* ignore vertex coordinates */;
   2356 				glw::GLint checkpoint_x_internal =
   2357 					glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
   2358 				glw::GLint checkpoint_y_internal =
   2359 					glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
   2360 				glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
   2361 
   2362 				/* Make sure vertex is invisible */
   2363 				if (vertex_color_red_value != 0)
   2364 				{
   2365 					m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] "
   2366 									   << "should be culled by distance [" << primitive_culled_by_distance << "]"
   2367 									   << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y
   2368 									   << ") is visible." << tcu::TestLog::EndMessage;
   2369 
   2370 					TCU_FAIL("Primitive is expected to be culled, but one of its vertices is visible.");
   2371 				}
   2372 			}
   2373 
   2374 			/* Primitive is culled, no reason to check clipping */
   2375 			continue;
   2376 		}
   2377 
   2378 		bool all_vertices_are_clipped = true;
   2379 
   2380 		for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count; n_primitive_vertex++)
   2381 		{
   2382 			glw::GLuint base_index_of_vertex_internal = base_index_of_primitive + n_primitive_vertex * stride_in_floats;
   2383 			glw::GLuint clipdistance_array_index	  = base_index_of_vertex_internal;
   2384 			glw::GLuint checkpoint_position_index_internal = base_index_of_vertex_internal + clipdistances_array_size +
   2385 															 culldistances_array_size +
   2386 															 2 /* ignore vertex coordinates */;
   2387 			glw::GLint checkpoint_x_internal =
   2388 				glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
   2389 			glw::GLint checkpoint_y_internal =
   2390 				glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
   2391 			glw::GLfloat* vertex_clipdistance_array  = &m_bo_data[clipdistance_array_index];
   2392 			bool		  vertex_clipped			 = false;
   2393 			glw::GLint	vertex_clipped_by_distance = 0;
   2394 			glw::GLint	vertex_color_red_value	 = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
   2395 
   2396 			/* Check whether pixel should be clipped */
   2397 			for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
   2398 				 n_clipdistance_entry++)
   2399 			{
   2400 				if (vertex_clipdistance_array[n_clipdistance_entry] < 0)
   2401 				{
   2402 					vertex_clipped			   = true;
   2403 					vertex_clipped_by_distance = n_clipdistance_entry;
   2404 
   2405 					break;
   2406 				}
   2407 			}
   2408 
   2409 			all_vertices_are_clipped &= vertex_clipped;
   2410 
   2411 			/* Validate whether real data same as expected */
   2412 			if (vertex_clipped)
   2413 			{
   2414 				if (vertex_color_red_value != 0)
   2415 				{
   2416 					m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] "
   2417 									   << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") "
   2418 									   << "should be clipped by distance [" << vertex_clipped_by_distance << "] "
   2419 									   << "(distance value [" << vertex_clipdistance_array[vertex_clipped_by_distance]
   2420 									   << "])" << tcu::TestLog::EndMessage;
   2421 
   2422 					TCU_FAIL("Vertex is expected to be clipped and invisible, while it is visible.");
   2423 				}
   2424 				else
   2425 				{
   2426 					n_clipped_vertices_real++;
   2427 				}
   2428 			}
   2429 			else
   2430 			{
   2431 				if (vertex_color_red_value == 0)
   2432 				{
   2433 					m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] "
   2434 									   << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") "
   2435 									   << "should not be clipped." << tcu::TestLog::EndMessage;
   2436 
   2437 					TCU_FAIL("Vertex is unexpectedly clipped or invisible");
   2438 				}
   2439 				else
   2440 				{
   2441 					n_not_clipped_vertices_real++;
   2442 				}
   2443 			}
   2444 		}
   2445 
   2446 		if (!all_vertices_are_clipped)
   2447 		{
   2448 			/* Check fetched values from the shader (Point 2 of Basic Outline : "Use program that...") */
   2449 			if (fetch_culldistance_from_fs)
   2450 			{
   2451 				for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count;
   2452 					 n_primitive_vertex++)
   2453 				{
   2454 					/* Get shader output value */
   2455 					glw::GLuint base_index_of_vertex_internal =
   2456 						base_index_of_primitive + n_primitive_vertex * stride_in_floats;
   2457 					glw::GLuint checkpoint_position_index_internal =
   2458 						base_index_of_vertex_internal + clipdistances_array_size + culldistances_array_size +
   2459 						2 /* ignore vertex coordinates */;
   2460 					glw::GLuint culldistances_index = base_index_of_vertex_internal + clipdistances_array_size;
   2461 					glw::GLint  checkpoint_x_internal =
   2462 						glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]);
   2463 					glw::GLint checkpoint_y_internal =
   2464 						glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]);
   2465 					glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal);
   2466 
   2467 					/* Calculate culldistances check sum hash */
   2468 					float sum = 0.f;
   2469 
   2470 					for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size;
   2471 						 ++n_clipdistance_entry)
   2472 					{
   2473 						sum += de::abs(m_bo_data[base_index_of_vertex_internal + n_clipdistance_entry]) *
   2474 							   float(n_clipdistance_entry + 1);
   2475 					}
   2476 
   2477 					for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size;
   2478 						 ++n_culldistance_entry)
   2479 					{
   2480 						sum += de::abs(m_bo_data[culldistances_index + n_culldistance_entry]) *
   2481 							   float(n_culldistance_entry + 1 + clipdistances_array_size);
   2482 					}
   2483 
   2484 					/* limit sum and return */
   2485 					glw::GLint sum_hash =
   2486 						glw::GLint(sum / glw::GLfloat((clipdistances_array_size + culldistances_array_size) *
   2487 													  (clipdistances_array_size + culldistances_array_size + 1)) *
   2488 								   65535.f /* normalizing to short */);
   2489 					sum_hash = (sum_hash < 65536) ? sum_hash : 65535; /* clamping to short */
   2490 
   2491 					/* Compare against setup value */
   2492 					if (std::abs(vertex_color_red_value - sum_hash) > 4 /* precision 4/65536 */)
   2493 					{
   2494 						m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] "
   2495 										   << "should have culldistance hash sum " << sum_hash
   2496 										   << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y
   2497 										   << ") has sum hash equal to " << vertex_color_red_value
   2498 										   << tcu::TestLog::EndMessage;
   2499 
   2500 						TCU_FAIL("Culled distances returned from fragment shader dose not match expected values.");
   2501 					}
   2502 				}
   2503 			}
   2504 		}
   2505 	}
   2506 
   2507 	/* sub_grid cell size is 3*3 */
   2508 	DE_ASSERT(m_render_primitives % 9 == 0);
   2509 
   2510 	/* Sanity check */
   2511 	switch (primitive_mode)
   2512 	{
   2513 	case PRIMITIVE_MODE_LINES:
   2514 	case PRIMITIVE_MODE_TRIANGLES:
   2515 	{
   2516 		/* Validate culled primitives */
   2517 		if (culldistances_array_size == 0)
   2518 		{
   2519 			DE_ASSERT(n_culled_primitives_real == 0);
   2520 		}
   2521 		else
   2522 		{
   2523 			/* Each 3rd line or triangle should be culled by test design */
   2524 			DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives / 3);
   2525 		}
   2526 
   2527 		/* Validate clipped vertices */
   2528 		if (clipdistances_array_size == 0)
   2529 		{
   2530 			DE_ASSERT(n_clipped_vertices_real == 0);
   2531 		}
   2532 		else
   2533 		{
   2534 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
   2535 			glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3;
   2536 			glw::GLint n_clipped_vertices_expected		= /* One third of primitives has 0th vertex clipped */
   2537 				one_third_of_rendered_primitives +
   2538 				/* One third of primitives clipped completely     */
   2539 				one_third_of_rendered_primitives * primitive_vertices_count;
   2540 
   2541 			DE_ASSERT(glw::GLint(n_clipped_vertices_real) == n_clipped_vertices_expected);
   2542 #endif
   2543 		}
   2544 		break;
   2545 	}
   2546 
   2547 	case PRIMITIVE_MODE_POINTS:
   2548 	{
   2549 		/* Validate culled primitives */
   2550 		if (culldistances_array_size == 0)
   2551 		{
   2552 			DE_ASSERT(n_culled_primitives_real == 0);
   2553 		}
   2554 		else
   2555 		{
   2556 			/* 2/3 points should be culled by test design */
   2557 			DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives * 2 / 3);
   2558 		}
   2559 
   2560 		/* Validate clipped vertices */
   2561 		if (clipdistances_array_size == 0)
   2562 		{
   2563 			DE_ASSERT(n_clipped_vertices_real == 0);
   2564 		}
   2565 		else
   2566 		{
   2567 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
   2568 			glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3;
   2569 
   2570 			/* 2/3 of rendered points should be clipped by test design */
   2571 			DE_ASSERT(glw::GLint(n_clipped_vertices_real) == 2 * one_third_of_rendered_primitives);
   2572 #endif
   2573 		}
   2574 
   2575 		break;
   2576 	}
   2577 	default:
   2578 		TCU_FAIL("Unknown primitive mode");
   2579 	}
   2580 }
   2581 
   2582 /** Executes test iteration.
   2583  *
   2584  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
   2585  */
   2586 tcu::TestNode::IterateResult CullDistance::FunctionalTest::iterate()
   2587 {
   2588 	/* This test should only be executed if ARB_cull_distance is supported, or if
   2589 	 * we're running a GL4.5 context
   2590 	 */
   2591 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
   2592 		!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
   2593 	{
   2594 		throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
   2595 	}
   2596 
   2597 	const glw::Functions& gl			= m_context.getRenderContext().getFunctions();
   2598 	bool				  has_succeeded = true;
   2599 	bool is_core = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
   2600 
   2601 	/* Retrieve important GL constant values */
   2602 	glw::GLint gl_max_clip_distances_value					 = 0;
   2603 	glw::GLint gl_max_combined_clip_and_cull_distances_value = 0;
   2604 	glw::GLint gl_max_cull_distances_value					 = 0;
   2605 
   2606 	gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value);
   2607 	gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
   2608 	gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
   2609 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call(s) failed.");
   2610 
   2611 	gl.genTextures(1, &m_to_id);
   2612 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
   2613 
   2614 	gl.bindTexture(GL_TEXTURE_2D, m_to_id);
   2615 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
   2616 
   2617 	gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
   2618 					GL_R32F, m_to_width, m_to_height);
   2619 	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
   2620 
   2621 	/* Set up the draw/read FBO */
   2622 	gl.genFramebuffers(1, &m_fbo_id);
   2623 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
   2624 
   2625 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
   2626 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
   2627 
   2628 	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); /* level */
   2629 	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
   2630 
   2631 	/* Prepare a buffer object */
   2632 	gl.genBuffers(1, &m_bo_id);
   2633 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
   2634 
   2635 	/* Prepare a VAO. We will configure separately for each iteration. */
   2636 	gl.genVertexArrays(1, &m_vao_id);
   2637 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
   2638 
   2639 	/* Iterate over all functional tests */
   2640 	struct _test_item
   2641 	{
   2642 		bool redeclare_clipdistances_array;
   2643 		bool redeclare_culldistances_array;
   2644 		bool dynamic_index_writes;
   2645 		bool use_passthrough_gs;
   2646 		bool use_passthrough_ts;
   2647 		bool use_core_functionality;
   2648 		bool fetch_culldistances;
   2649 	} test_items[] = { /* Use the basic outline to test the basic functionality of cull distances. */
   2650 					   {
   2651 						   true,	/* redeclare_clipdistances_array */
   2652 						   true,	/* redeclare_culldistances_array */
   2653 						   false,   /* dynamic_index_writes          */
   2654 						   false,   /* use_passthrough_gs            */
   2655 						   false,   /* use_passthrough_ts            */
   2656 						   is_core, /* use_core_functionality        */
   2657 						   false	/* fetch_culldistances           */
   2658 					   },
   2659 					   /* Use the basic outline but don't redeclare gl_ClipDistance with a size. */
   2660 					   {
   2661 						   false,   /* redeclare_clipdistances_array */
   2662 						   true,	/* redeclare_culldistances_array */
   2663 						   false,   /* dynamic_index_writes          */
   2664 						   false,   /* use_passthrough_gs            */
   2665 						   false,   /* use_passthrough_ts            */
   2666 						   is_core, /* use_core_functionality        */
   2667 						   false	/* fetch_culldistances           */
   2668 					   },
   2669 					   /* Use the basic outline but don't redeclare gl_CullDistance with a size. */
   2670 					   {
   2671 						   true,	/* redeclare_clipdistances_array  */
   2672 						   false,   /* redeclare_culldistances_array  */
   2673 						   false,   /* dynamic_index_writes           */
   2674 						   false,   /* use_passthrough_gs             */
   2675 						   false,   /* use_passthrough_ts             */
   2676 						   is_core, /* use_core_functionality         */
   2677 						   false	/* fetch_culldistances            */
   2678 					   },
   2679 					   /* Use the basic outline but don't redeclare either gl_ClipDistance or
   2680 		 * gl_CullDistance with a size.
   2681 		 */
   2682 					   {
   2683 						   false,   /* redeclare_clipdistances_array */
   2684 						   false,   /* redeclare_culldistances_array */
   2685 						   false,   /* dynamic_index_writes          */
   2686 						   false,   /* use_passthrough_gs            */
   2687 						   false,   /* use_passthrough_ts            */
   2688 						   is_core, /* use_core_functionality        */
   2689 						   false	/* fetch_culldistances           */
   2690 					   },
   2691 					   /* Use the basic outline but use dynamic indexing when writing the elements
   2692 		 * of the gl_ClipDistance and gl_CullDistance arrays.
   2693 		 */
   2694 					   {
   2695 						   true,	/* redeclare_clipdistances_array */
   2696 						   true,	/* redeclare_culldistances_array */
   2697 						   true,	/* dynamic_index_writes          */
   2698 						   false,   /* use_passthrough_gs            */
   2699 						   false,   /* use_passthrough_ts            */
   2700 						   is_core, /* use_core_functionality        */
   2701 						   false	/* fetch_culldistances           */
   2702 					   },
   2703 					   /* Use the basic outline but add a geometry shader to the program that
   2704 		 * simply passes through all written clip and cull distances.
   2705 		 */
   2706 					   {
   2707 						   true,	/* redeclare_clipdistances_array */
   2708 						   true,	/* redeclare_culldistances_array */
   2709 						   false,   /* dynamic_index_writes          */
   2710 						   true,	/* use_passthrough_gs            */
   2711 						   false,   /* use_passthrough_ts            */
   2712 						   is_core, /* use_core_functionality        */
   2713 						   false	/* fetch_culldistances           */
   2714 					   },
   2715 					   /* Use the basic outline but add a tessellation control and tessellation
   2716 		 * evaluation shader to the program which simply pass through all written
   2717 		 * clip and cull distances.
   2718 		 */
   2719 					   {
   2720 						   true,	/* redeclare_clipdistances_array */
   2721 						   true,	/* redeclare_culldistances_array */
   2722 						   false,   /* dynamic_index_writes          */
   2723 						   false,   /* use_passthrough_gs            */
   2724 						   true,	/* use_passthrough_ts            */
   2725 						   is_core, /* use_core_functionality        */
   2726 						   false	/* fetch_culldistances           */
   2727 					   },
   2728 					   /* Test that using #extension with GL_ARB_cull_distance allows using the
   2729 		 * feature even with an earlier version of GLSL. Also test that the
   2730 		 * extension name is available as preprocessor #define.
   2731 		 */
   2732 					   {
   2733 						   true,  /* redeclare_clipdistances_array */
   2734 						   true,  /* redeclare_culldistances_array */
   2735 						   false, /* dynamic_index_writes          */
   2736 						   false, /* use_passthrough_gs            */
   2737 						   false, /* use_passthrough_ts            */
   2738 						   false, /* use_core_functionality        */
   2739 						   false  /* fetch_culldistances           */
   2740 					   },
   2741 					   /* Use a program that has only a vertex shader and a fragment shader.
   2742 		 * The vertex shader should redeclare gl_ClipDistance with a size that
   2743 		 * fits all enabled cull distances. Also redeclare gl_CullDistance with a
   2744 		 * size. The sum of the two sizes should not be more than MAX_COMBINED_-
   2745 		 * CLIP_AND_CULL_DISTANCES. The fragment shader should output the cull
   2746 		 * distances written by the vertex shader by reading them from the built-in
   2747 		 * array gl_CullDistance.
   2748 		 */
   2749 					   {
   2750 						   true,  /* redeclare_clipdistances_array */
   2751 						   true,  /* redeclare_culldistances_array */
   2752 						   false, /* dynamic_index_writes          */
   2753 						   false, /* use_passthrough_gs            */
   2754 						   false, /* use_passthrough_ts            */
   2755 						   false, /* use_core_functionality        */
   2756 						   true   /* fetch_culldistances           */
   2757 					   }
   2758 	};
   2759 	const glw::GLuint n_test_items = sizeof(test_items) / sizeof(test_items[0]);
   2760 
   2761 	gl.viewport(0, 0, m_to_width, m_to_height);
   2762 	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
   2763 
   2764 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   2765 	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed.");
   2766 
   2767 	for (glw::GLuint n_test_item = 0; n_test_item < n_test_items; ++n_test_item)
   2768 	{
   2769 		/* Check for OpenGL feature support */
   2770 		if (test_items[n_test_item].use_passthrough_ts)
   2771 		{
   2772 			if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) &&
   2773 				!m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader"))
   2774 			{
   2775 				continue; // no tessellation shader support
   2776 			}
   2777 		}
   2778 
   2779 		const _test_item&	 current_test_item						= test_items[n_test_item];
   2780 		const _primitive_mode primitive_modes[PRIMITIVE_MODE_COUNT] = { PRIMITIVE_MODE_LINES, PRIMITIVE_MODE_POINTS,
   2781 																		PRIMITIVE_MODE_TRIANGLES };
   2782 
   2783 		for (glw::GLuint primitive_mode_index = 0; primitive_mode_index < PRIMITIVE_MODE_COUNT; ++primitive_mode_index)
   2784 		{
   2785 			_primitive_mode primitive_mode = primitive_modes[primitive_mode_index];
   2786 
   2787 			/* Iterate over a set of gl_ClipDistances[] and gl_CullDistances[] array sizes */
   2788 			for (glw::GLint n_iteration = 0; n_iteration <= gl_max_combined_clip_and_cull_distances_value;
   2789 				 ++n_iteration)
   2790 			{
   2791 				glw::GLuint clipdistances_array_size = 0;
   2792 				glw::GLuint culldistances_array_size = 0;
   2793 
   2794 				if (n_iteration != 0 && n_iteration <= gl_max_clip_distances_value)
   2795 				{
   2796 					clipdistances_array_size = n_iteration;
   2797 				}
   2798 
   2799 				if ((gl_max_combined_clip_and_cull_distances_value - n_iteration) < gl_max_cull_distances_value)
   2800 				{
   2801 					culldistances_array_size = gl_max_combined_clip_and_cull_distances_value - n_iteration;
   2802 				}
   2803 				else
   2804 				{
   2805 					culldistances_array_size = gl_max_cull_distances_value;
   2806 				}
   2807 
   2808 				if (clipdistances_array_size == 0 && culldistances_array_size == 0)
   2809 				{
   2810 					/* Skip the dummy iteration */
   2811 					continue;
   2812 				}
   2813 
   2814 				if (current_test_item.fetch_culldistances && (primitive_mode != PRIMITIVE_MODE_POINTS))
   2815 				{
   2816 					continue;
   2817 				}
   2818 
   2819 				/* Create a program to run */
   2820 				buildPO(clipdistances_array_size, culldistances_array_size, current_test_item.dynamic_index_writes,
   2821 						primitive_mode, current_test_item.redeclare_clipdistances_array,
   2822 						current_test_item.redeclare_culldistances_array, current_test_item.use_core_functionality,
   2823 						current_test_item.use_passthrough_gs, current_test_item.use_passthrough_ts,
   2824 						current_test_item.fetch_culldistances);
   2825 
   2826 				/* Initialize VAO data */
   2827 				configureVAO(clipdistances_array_size, culldistances_array_size, primitive_mode);
   2828 
   2829 				/* Run GLSL program and check results */
   2830 				executeRenderTest(clipdistances_array_size, culldistances_array_size, primitive_mode,
   2831 								  current_test_item.use_passthrough_ts, current_test_item.fetch_culldistances);
   2832 
   2833 			} /* for (all iterations) */
   2834 		}	 /* for (all test modes) */
   2835 	}		  /* for (all test items) */
   2836 
   2837 	/* All done */
   2838 	if (has_succeeded)
   2839 	{
   2840 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   2841 	}
   2842 	else
   2843 	{
   2844 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
   2845 	}
   2846 
   2847 	return STOP;
   2848 }
   2849 
   2850 /** Returns pixel red component read from texture at position x, y.
   2851  *
   2852  *  @param x x-coordinate to read pixel color component from
   2853  *  @param y y-coordinate to read pixel color component from
   2854  **/
   2855 glw::GLint CullDistance::FunctionalTest::readRedPixelValue(glw::GLint x, glw::GLint y)
   2856 {
   2857 	glw::GLint result = -1;
   2858 
   2859 	DE_ASSERT(x >= 0 && (glw::GLuint)x < m_to_width);
   2860 	DE_ASSERT(y >= 0 && (glw::GLuint)y < m_to_height);
   2861 
   2862 	result = m_to_pixel_data_cache[(m_to_width * y + x) * m_to_pixel_data_cache_color_components];
   2863 
   2864 	return result;
   2865 }
   2866 
   2867 /** Reads texture into m_to_pixel_data_cache.
   2868  *  Texture size determined by fields m_to_width, m_to_height
   2869  **/
   2870 void CullDistance::FunctionalTest::readTexturePixels()
   2871 {
   2872 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2873 
   2874 	m_to_pixel_data_cache.clear();
   2875 
   2876 	m_to_pixel_data_cache.resize(m_to_width * m_to_height * m_to_pixel_data_cache_color_components);
   2877 
   2878 	/* Read vertex from texture */
   2879 	gl.readPixels(0,		   /* x      */
   2880 				  0,		   /* y      */
   2881 				  m_to_width,  /* width  */
   2882 				  m_to_height, /* height */
   2883 				  GL_RGBA, GL_UNSIGNED_SHORT, &m_to_pixel_data_cache[0]);
   2884 	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
   2885 }
   2886 
   2887 /** Constructor.
   2888  *
   2889  *  @param context Rendering context handle.
   2890  **/
   2891 CullDistance::NegativeTest::NegativeTest(deqp::Context& context)
   2892 	: TestCase(context, "negative", "Cull Distance Negative Test")
   2893 	, m_fs_id(0)
   2894 	, m_po_id(0)
   2895 	, m_temp_buffer(DE_NULL)
   2896 	, m_vs_id(0)
   2897 {
   2898 	/* Left blank on purpose */
   2899 }
   2900 
   2901 /** @brief Cull Distance Negative Test deinitialization */
   2902 void CullDistance::NegativeTest::deinit()
   2903 {
   2904 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2905 
   2906 	if (m_fs_id != 0)
   2907 	{
   2908 		gl.deleteShader(m_fs_id);
   2909 
   2910 		m_fs_id = 0;
   2911 	}
   2912 
   2913 	if (m_po_id != 0)
   2914 	{
   2915 		gl.deleteProgram(m_po_id);
   2916 
   2917 		m_po_id = 0;
   2918 	}
   2919 
   2920 	if (m_vs_id != 0)
   2921 	{
   2922 		gl.deleteShader(m_vs_id);
   2923 
   2924 		m_vs_id = 0;
   2925 	}
   2926 
   2927 	if (m_temp_buffer != DE_NULL)
   2928 	{
   2929 		delete[] m_temp_buffer;
   2930 
   2931 		m_temp_buffer = DE_NULL;
   2932 	}
   2933 }
   2934 
   2935 /** @brief Get string description of test with given parameters
   2936  *
   2937  *  @param [in] n_test_iteration                    Test iteration number
   2938  *  @param [in] should_redeclare_output_variables   Indicate whether test redeclared gl_ClipDistance and gl_CullDistance
   2939  *  @param [in] use_dynamic_index_based_writes      Indicate whether test used dynamic index-based setters
   2940  *
   2941  *  @return String containing description.
   2942  */
   2943 std::string CullDistance::NegativeTest::getTestDescription(int n_test_iteration, bool should_redeclare_output_variables,
   2944 														   bool use_dynamic_index_based_writes)
   2945 {
   2946 	std::stringstream stream;
   2947 
   2948 	stream << "Test iteration [" << n_test_iteration << "] which uses a vertex shader that:\n\n"
   2949 		   << ((should_redeclare_output_variables) ?
   2950 				   "* redeclares gl_ClipDistance and gl_CullDistance arrays\n" :
   2951 				   "* does not redeclare gl_ClipDistance and gl_CullDistance arrays\n")
   2952 		   << ((use_dynamic_index_based_writes) ? "* uses dynamic index-based writes\n" : "* uses static writes\n");
   2953 
   2954 	return stream.str();
   2955 }
   2956 
   2957 /** Executes test iteration.
   2958  *
   2959  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
   2960  */
   2961 tcu::TestNode::IterateResult CullDistance::NegativeTest::iterate()
   2962 {
   2963 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2964 
   2965 	/* Build the test shaders. */
   2966 	const glw::GLchar* token_dynamic_index_based_writes = "DYNAMIC_INDEX_BASED_WRITES";
   2967 	const glw::GLchar* token_insert_static_writes		= "INSERT_STATIC_WRITES";
   2968 	const glw::GLchar* token_n_gl_clipdistance_entries  = "N_GL_CLIPDISTANCE_ENTRIES";
   2969 	const glw::GLchar* token_n_gl_culldistance_entries  = "N_GL_CULLDISTANCE_ENTRIES";
   2970 	const glw::GLchar* token_redeclare_output_variables = "REDECLARE_OUTPUT_VARIABLES";
   2971 
   2972 	const glw::GLchar* fs_body = "#version 130\n"
   2973 								 "\n"
   2974 								 "void main()\n"
   2975 								 "{\n"
   2976 								 "}\n";
   2977 
   2978 	const glw::GLchar* vs_body_preamble = "#version 130\n"
   2979 										  "\n"
   2980 										  "    #extension GL_ARB_cull_distance : require\n"
   2981 										  "\n";
   2982 
   2983 	const glw::GLchar* vs_body_main = "#ifdef REDECLARE_OUTPUT_VARIABLES\n"
   2984 									  "    out float gl_ClipDistance[N_GL_CLIPDISTANCE_ENTRIES];\n"
   2985 									  "    out float gl_CullDistance[N_GL_CULLDISTANCE_ENTRIES];\n"
   2986 									  "#endif\n"
   2987 									  "\n"
   2988 									  "void main()\n"
   2989 									  "{\n"
   2990 									  "#ifdef DYNAMIC_INDEX_BASED_WRITES\n"
   2991 									  "    for (int n_clipdistance_entry = 0;\n"
   2992 									  "             n_clipdistance_entry < N_GL_CLIPDISTANCE_ENTRIES;\n"
   2993 									  "           ++n_clipdistance_entry)\n"
   2994 									  "    {\n"
   2995 									  "        gl_ClipDistance[n_clipdistance_entry] = float(n_clipdistance_entry) / "
   2996 									  "float(N_GL_CLIPDISTANCE_ENTRIES);\n"
   2997 									  "    }\n"
   2998 									  "\n"
   2999 									  "    for (int n_culldistance_entry = 0;\n"
   3000 									  "             n_culldistance_entry < N_GL_CULLDISTANCE_ENTRIES;\n"
   3001 									  "           ++n_culldistance_entry)\n"
   3002 									  "    {\n"
   3003 									  "        gl_CullDistance[n_culldistance_entry] = float(n_culldistance_entry) / "
   3004 									  "float(N_GL_CULLDISTANCE_ENTRIES);\n"
   3005 									  "    }\n"
   3006 									  "#else\n"
   3007 									  "    INSERT_STATIC_WRITES\n"
   3008 									  "#endif\n"
   3009 									  "}\n";
   3010 
   3011 	/* This test should only be executed if ARB_cull_distance is supported, or if
   3012 	 * we're running a GL4.5 context
   3013 	 */
   3014 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") &&
   3015 		!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
   3016 	{
   3017 		throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported");
   3018 	}
   3019 
   3020 	/* It only makes sense to run this test if GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES
   3021 	 * is lower than a sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CLIP_CULL_DISTANCES.
   3022 	 */
   3023 	glw::GLint  gl_max_clip_distances_value					  = 0;
   3024 	glw::GLint  gl_max_combined_clip_and_cull_distances_value = 0;
   3025 	glw::GLint  gl_max_cull_distances_value					  = 0;
   3026 	glw::GLuint n_gl_clipdistance_array_items				  = 0;
   3027 	std::string n_gl_clipdistance_array_items_string;
   3028 	glw::GLuint n_gl_culldistance_array_items = 0;
   3029 	std::string n_gl_culldistance_array_items_string;
   3030 	std::string static_write_shader_body_part;
   3031 
   3032 	gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value);
   3033 	gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value);
   3034 	gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value);
   3035 
   3036 	if (gl_max_clip_distances_value + gl_max_cull_distances_value < gl_max_combined_clip_and_cull_distances_value)
   3037 	{
   3038 		m_testCtx.getLog() << tcu::TestLog::Message
   3039 						   << "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES is larger than or equal to "
   3040 							  "the sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CULL_DISTANCES. Skipping."
   3041 						   << tcu::TestLog::EndMessage;
   3042 
   3043 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   3044 
   3045 		return STOP;
   3046 	}
   3047 
   3048 	n_gl_clipdistance_array_items = gl_max_clip_distances_value;
   3049 	n_gl_culldistance_array_items = gl_max_combined_clip_and_cull_distances_value - gl_max_clip_distances_value + 1;
   3050 
   3051 	/* Determine the number of items we will want the gl_ClipDistance and gl_CullDistance arrays
   3052 	 * to hold for test iterations that will re-declare the built-in output variables.
   3053 	 */
   3054 	{
   3055 		std::stringstream temp_sstream;
   3056 
   3057 		temp_sstream << n_gl_clipdistance_array_items;
   3058 
   3059 		n_gl_clipdistance_array_items_string = temp_sstream.str();
   3060 	}
   3061 
   3062 	{
   3063 		std::stringstream temp_sstream;
   3064 
   3065 		temp_sstream << n_gl_culldistance_array_items;
   3066 
   3067 		n_gl_culldistance_array_items_string = temp_sstream.str();
   3068 	}
   3069 
   3070 	/* Form the "static write" shader body part. */
   3071 	{
   3072 		std::stringstream temp_sstream;
   3073 
   3074 		temp_sstream << "gl_ClipDistance[" << n_gl_clipdistance_array_items_string.c_str() << "] = 0.0f;\n"
   3075 					 << "gl_CullDistance[" << n_gl_culldistance_array_items_string.c_str() << "] = 0.0f;\n";
   3076 
   3077 		static_write_shader_body_part = temp_sstream.str();
   3078 	}
   3079 
   3080 	/* Prepare GL objects before we continue */
   3081 	glw::GLint compile_status = GL_FALSE;
   3082 
   3083 	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
   3084 	m_po_id = gl.createProgram();
   3085 	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
   3086 
   3087 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() calls failed.");
   3088 
   3089 	gl.attachShader(m_po_id, m_fs_id);
   3090 	gl.attachShader(m_po_id, m_vs_id);
   3091 
   3092 	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
   3093 
   3094 	gl.shaderSource(m_fs_id, 1,			/* count */
   3095 					&fs_body, DE_NULL); /* length */
   3096 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
   3097 
   3098 	gl.compileShader(m_fs_id);
   3099 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
   3100 
   3101 	gl.getShaderiv(m_fs_id, GL_COMPILE_STATUS, &compile_status);
   3102 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
   3103 
   3104 	if (compile_status == GL_FALSE)
   3105 	{
   3106 		TCU_FAIL("Fragment shader failed to compile.");
   3107 	}
   3108 
   3109 	/* Run three separate test iterations. */
   3110 	struct _test_item
   3111 	{
   3112 		bool should_redeclare_output_variables;
   3113 		bool use_dynamic_index_based_writes;
   3114 	} test_items[] = { /* Negative Test 1 */
   3115 					   { true, false },
   3116 
   3117 					   /* Negative Test 2 */
   3118 					   { false, false },
   3119 
   3120 					   /* Negative Test 3 */
   3121 					   { false, true }
   3122 	};
   3123 	const unsigned int n_test_items = sizeof(test_items) / sizeof(test_items[0]);
   3124 
   3125 	for (unsigned int n_test_item = 0; n_test_item < n_test_items; ++n_test_item)
   3126 	{
   3127 		const _test_item& current_test_item = test_items[n_test_item];
   3128 
   3129 		/* Prepare vertex shader body */
   3130 		std::size_t		  token_position = std::string::npos;
   3131 		std::stringstream vs_body_sstream;
   3132 		std::string		  vs_body_string;
   3133 
   3134 		vs_body_sstream << vs_body_preamble << "\n";
   3135 
   3136 		if (current_test_item.should_redeclare_output_variables)
   3137 		{
   3138 			vs_body_sstream << "#define " << token_redeclare_output_variables << "\n";
   3139 		}
   3140 
   3141 		if (current_test_item.use_dynamic_index_based_writes)
   3142 		{
   3143 			vs_body_sstream << "#define " << token_dynamic_index_based_writes << "\n";
   3144 		}
   3145 
   3146 		vs_body_sstream << vs_body_main;
   3147 
   3148 		/* Replace tokens with meaningful values */
   3149 		vs_body_string = vs_body_sstream.str();
   3150 
   3151 		while ((token_position = vs_body_string.find(token_n_gl_clipdistance_entries)) != std::string::npos)
   3152 		{
   3153 			vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries),
   3154 													n_gl_clipdistance_array_items_string);
   3155 		}
   3156 
   3157 		while ((token_position = vs_body_string.find(token_n_gl_culldistance_entries)) != std::string::npos)
   3158 		{
   3159 			vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries),
   3160 													n_gl_culldistance_array_items_string);
   3161 		}
   3162 
   3163 		while ((token_position = vs_body_string.find(token_insert_static_writes)) != std::string::npos)
   3164 		{
   3165 			vs_body_string = vs_body_string.replace(token_position, strlen(token_insert_static_writes),
   3166 													static_write_shader_body_part);
   3167 		}
   3168 
   3169 		/* Try to compile the vertex shader */
   3170 		glw::GLint  compile_status_internal = GL_FALSE;
   3171 		const char* vs_body_raw_ptr			= vs_body_string.c_str();
   3172 
   3173 		gl.shaderSource(m_vs_id, 1,					/* count */
   3174 						&vs_body_raw_ptr, DE_NULL); /* length */
   3175 		GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
   3176 
   3177 		gl.compileShader(m_vs_id);
   3178 		GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
   3179 
   3180 		gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status_internal);
   3181 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
   3182 
   3183 		if (compile_status_internal == GL_FALSE)
   3184 		{
   3185 			glw::GLint buffer_size = 0;
   3186 
   3187 			/* Log the compilation error */
   3188 			m_testCtx.getLog() << tcu::TestLog::Message
   3189 							   << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
   3190 													 current_test_item.use_dynamic_index_based_writes)
   3191 							   << "has failed (as expected) to compile with the following info log:\n\n"
   3192 							   << tcu::TestLog::EndMessage;
   3193 
   3194 			gl.getShaderiv(m_vs_id, GL_INFO_LOG_LENGTH, &buffer_size);
   3195 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
   3196 
   3197 			m_temp_buffer = new glw::GLchar[buffer_size + 1];
   3198 
   3199 			memset(m_temp_buffer, 0, buffer_size + 1);
   3200 
   3201 			gl.getShaderInfoLog(m_vs_id, buffer_size, DE_NULL, /* length */
   3202 								m_temp_buffer);
   3203 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed.");
   3204 
   3205 			m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage;
   3206 
   3207 			delete[] m_temp_buffer;
   3208 			m_temp_buffer = DE_NULL;
   3209 
   3210 			/* Move on to the next iteration */
   3211 			continue;
   3212 		}
   3213 
   3214 		/* Try to link the program object */
   3215 		glw::GLint link_status = GL_FALSE;
   3216 
   3217 		gl.linkProgram(m_po_id);
   3218 		GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
   3219 
   3220 		gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
   3221 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
   3222 
   3223 		if (link_status == GL_TRUE)
   3224 		{
   3225 			m_testCtx.getLog() << tcu::TestLog::Message
   3226 							   << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
   3227 													 current_test_item.use_dynamic_index_based_writes)
   3228 							   << "has linked successfully which is invalid!" << tcu::TestLog::EndMessage;
   3229 
   3230 			TCU_FAIL("Program object has linked successfully, even though the process should have failed.");
   3231 		}
   3232 		else
   3233 		{
   3234 			glw::GLint buffer_size = 0;
   3235 
   3236 			m_testCtx.getLog() << tcu::TestLog::Message
   3237 							   << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables,
   3238 													 current_test_item.use_dynamic_index_based_writes)
   3239 							   << "has failed (as expected) to link with the following info log:\n\n"
   3240 							   << tcu::TestLog::EndMessage;
   3241 
   3242 			gl.getProgramiv(m_po_id, GL_INFO_LOG_LENGTH, &buffer_size);
   3243 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
   3244 
   3245 			m_temp_buffer = new glw::GLchar[buffer_size + 1];
   3246 
   3247 			memset(m_temp_buffer, 0, buffer_size + 1);
   3248 
   3249 			gl.getProgramInfoLog(m_po_id, buffer_size, DE_NULL, /* length */
   3250 								 m_temp_buffer);
   3251 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed.");
   3252 
   3253 			m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage;
   3254 
   3255 			delete[] m_temp_buffer;
   3256 			m_temp_buffer = DE_NULL;
   3257 		}
   3258 	} /* for (all test items) */
   3259 
   3260 	/* All done */
   3261 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   3262 
   3263 	return STOP;
   3264 }
   3265 
   3266 /** Constructor.
   3267  *
   3268  *  @param context Rendering context.
   3269  */
   3270 CullDistance::Tests::Tests(deqp::Context& context) : TestCaseGroup(context, "cull_distance", "Cull Distance Test Suite")
   3271 {
   3272 }
   3273 
   3274 /** Initializes the test group contents. */
   3275 void CullDistance::Tests::init()
   3276 {
   3277 	addChild(new CullDistance::APICoverageTest(m_context));
   3278 	addChild(new CullDistance::FunctionalTest(m_context));
   3279 	addChild(new CullDistance::NegativeTest(m_context));
   3280 }
   3281 } /* glcts namespace */
   3282