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