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