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