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