1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * OpenGL Conformance Test Suite
3e5c31af7Sopenharmony_ci * -----------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright (c) 2014-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#include "esextcTessellationShaderPoints.hpp"
25e5c31af7Sopenharmony_ci#include "gluContextInfo.hpp"
26e5c31af7Sopenharmony_ci#include "gluDefs.hpp"
27e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
28e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
29e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_cinamespace glcts
32e5c31af7Sopenharmony_ci{
33e5c31af7Sopenharmony_ci
34e5c31af7Sopenharmony_ciconst unsigned int TessellationShaderPointsgl_PointSize::m_rt_height =
35e5c31af7Sopenharmony_ci	16; /* note: update shaders if you change this value */
36e5c31af7Sopenharmony_ciconst unsigned int TessellationShaderPointsgl_PointSize::m_rt_width =
37e5c31af7Sopenharmony_ci	16; /* note: update shaders if you change this value */
38e5c31af7Sopenharmony_ci
39e5c31af7Sopenharmony_ci/** Constructor
40e5c31af7Sopenharmony_ci *
41e5c31af7Sopenharmony_ci * @param context Test context
42e5c31af7Sopenharmony_ci **/
43e5c31af7Sopenharmony_ciTessellationShaderPointsTests::TessellationShaderPointsTests(glcts::Context& context, const ExtParameters& extParams)
44e5c31af7Sopenharmony_ci	: TestCaseGroupBase(context, extParams, "tessellation_shader_point_mode", "Verifies point mode functionality")
45e5c31af7Sopenharmony_ci{
46e5c31af7Sopenharmony_ci	/* No implementation needed */
47e5c31af7Sopenharmony_ci}
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_ci/**
50e5c31af7Sopenharmony_ci * Initializes test groups for geometry shader tests
51e5c31af7Sopenharmony_ci **/
52e5c31af7Sopenharmony_civoid TessellationShaderPointsTests::init(void)
53e5c31af7Sopenharmony_ci{
54e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderPointsgl_PointSize(m_context, m_extParams));
55e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderPointsVerification(m_context, m_extParams));
56e5c31af7Sopenharmony_ci}
57e5c31af7Sopenharmony_ci
58e5c31af7Sopenharmony_ci/** Constructor
59e5c31af7Sopenharmony_ci *
60e5c31af7Sopenharmony_ci * @param context       Test context
61e5c31af7Sopenharmony_ci * @param name          Test case's name
62e5c31af7Sopenharmony_ci * @param description   Test case's desricption
63e5c31af7Sopenharmony_ci **/
64e5c31af7Sopenharmony_ciTessellationShaderPointsgl_PointSize::TessellationShaderPointsgl_PointSize(Context&				context,
65e5c31af7Sopenharmony_ci																		   const ExtParameters& extParams)
66e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, "point_rendering", "Verifies point size used to render points is taken from"
67e5c31af7Sopenharmony_ci														  " the right stage")
68e5c31af7Sopenharmony_ci	, m_fbo_id(0)
69e5c31af7Sopenharmony_ci	, m_to_id(0)
70e5c31af7Sopenharmony_ci	, m_vao_id(0)
71e5c31af7Sopenharmony_ci{
72e5c31af7Sopenharmony_ci	/* Left blank on purpose */
73e5c31af7Sopenharmony_ci}
74e5c31af7Sopenharmony_ci
75e5c31af7Sopenharmony_ci/** Deinitializes all ES objects created for the test. */
76e5c31af7Sopenharmony_civoid TessellationShaderPointsgl_PointSize::deinit()
77e5c31af7Sopenharmony_ci{
78e5c31af7Sopenharmony_ci	/** Call base class' deinit() function */
79e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
80e5c31af7Sopenharmony_ci
81e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
82e5c31af7Sopenharmony_ci	{
83e5c31af7Sopenharmony_ci		return;
84e5c31af7Sopenharmony_ci	}
85e5c31af7Sopenharmony_ci
86e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
87e5c31af7Sopenharmony_ci
88e5c31af7Sopenharmony_ci	if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
89e5c31af7Sopenharmony_ci	{
90e5c31af7Sopenharmony_ci		/* Disable point size */
91e5c31af7Sopenharmony_ci		gl.disable(GL_PROGRAM_POINT_SIZE);
92e5c31af7Sopenharmony_ci	}
93e5c31af7Sopenharmony_ci
94e5c31af7Sopenharmony_ci	/* Reset the program object */
95e5c31af7Sopenharmony_ci	gl.useProgram(0);
96e5c31af7Sopenharmony_ci
97e5c31af7Sopenharmony_ci	/* Revert GL_PATCH_VERTICES_EXT to default value */
98e5c31af7Sopenharmony_ci	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
99e5c31af7Sopenharmony_ci
100e5c31af7Sopenharmony_ci	/* Unbind vertex array object */
101e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci	/* Deinitialize test-specific objects */
104e5c31af7Sopenharmony_ci	for (_tests_iterator it = m_tests.begin(); it != m_tests.end(); ++it)
105e5c31af7Sopenharmony_ci	{
106e5c31af7Sopenharmony_ci		const _test_descriptor& test = *it;
107e5c31af7Sopenharmony_ci
108e5c31af7Sopenharmony_ci		if (test.fs_id != 0)
109e5c31af7Sopenharmony_ci		{
110e5c31af7Sopenharmony_ci			gl.deleteShader(test.fs_id);
111e5c31af7Sopenharmony_ci		}
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci		if (test.gs_id != 0)
114e5c31af7Sopenharmony_ci		{
115e5c31af7Sopenharmony_ci			gl.deleteShader(test.gs_id);
116e5c31af7Sopenharmony_ci		}
117e5c31af7Sopenharmony_ci
118e5c31af7Sopenharmony_ci		if (test.po_id != 0)
119e5c31af7Sopenharmony_ci		{
120e5c31af7Sopenharmony_ci			gl.deleteProgram(test.po_id);
121e5c31af7Sopenharmony_ci		}
122e5c31af7Sopenharmony_ci
123e5c31af7Sopenharmony_ci		if (test.tes_id != 0)
124e5c31af7Sopenharmony_ci		{
125e5c31af7Sopenharmony_ci			gl.deleteShader(test.tes_id);
126e5c31af7Sopenharmony_ci		}
127e5c31af7Sopenharmony_ci
128e5c31af7Sopenharmony_ci		if (test.tcs_id != 0)
129e5c31af7Sopenharmony_ci		{
130e5c31af7Sopenharmony_ci			gl.deleteShader(test.tcs_id);
131e5c31af7Sopenharmony_ci		}
132e5c31af7Sopenharmony_ci
133e5c31af7Sopenharmony_ci		if (test.vs_id != 0)
134e5c31af7Sopenharmony_ci		{
135e5c31af7Sopenharmony_ci			gl.deleteShader(test.vs_id);
136e5c31af7Sopenharmony_ci		}
137e5c31af7Sopenharmony_ci	}
138e5c31af7Sopenharmony_ci	m_tests.clear();
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_ci	if (m_fbo_id != 0)
141e5c31af7Sopenharmony_ci	{
142e5c31af7Sopenharmony_ci		gl.deleteFramebuffers(1, &m_fbo_id);
143e5c31af7Sopenharmony_ci
144e5c31af7Sopenharmony_ci		m_fbo_id = 0;
145e5c31af7Sopenharmony_ci	}
146e5c31af7Sopenharmony_ci
147e5c31af7Sopenharmony_ci	if (m_to_id != 0)
148e5c31af7Sopenharmony_ci	{
149e5c31af7Sopenharmony_ci		gl.deleteTextures(1, &m_to_id);
150e5c31af7Sopenharmony_ci
151e5c31af7Sopenharmony_ci		m_to_id = 0;
152e5c31af7Sopenharmony_ci	}
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
155e5c31af7Sopenharmony_ci	{
156e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
157e5c31af7Sopenharmony_ci
158e5c31af7Sopenharmony_ci		m_vao_id = 0;
159e5c31af7Sopenharmony_ci	}
160e5c31af7Sopenharmony_ci}
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci/** Initializes all ES objects that will be used for the test. */
163e5c31af7Sopenharmony_civoid TessellationShaderPointsgl_PointSize::initTest()
164e5c31af7Sopenharmony_ci{
165e5c31af7Sopenharmony_ci	/* The test should only execute if maximum point size is at least 2 */
166e5c31af7Sopenharmony_ci	const glw::Functions& gl						 = m_context.getRenderContext().getFunctions();
167e5c31af7Sopenharmony_ci	glw::GLint			  gl_max_point_size_value[2] = { 0 };
168e5c31af7Sopenharmony_ci	const int			  min_max_point_size		 = 2;
169e5c31af7Sopenharmony_ci
170e5c31af7Sopenharmony_ci	if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
171e5c31af7Sopenharmony_ci	{
172e5c31af7Sopenharmony_ci		gl.getIntegerv(GL_POINT_SIZE_RANGE, gl_max_point_size_value);
173e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_POINT_SIZE_RANGE failed.");
174e5c31af7Sopenharmony_ci	}
175e5c31af7Sopenharmony_ci	else
176e5c31af7Sopenharmony_ci	{
177e5c31af7Sopenharmony_ci		gl.getIntegerv(GL_ALIASED_POINT_SIZE_RANGE, gl_max_point_size_value);
178e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_ALIASED_POINT_SIZE_RANGE failed.");
179e5c31af7Sopenharmony_ci	}
180e5c31af7Sopenharmony_ci
181e5c31af7Sopenharmony_ci	if (gl_max_point_size_value[1] < min_max_point_size)
182e5c31af7Sopenharmony_ci	{
183e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("Maximum point size is lower than 2.");
184e5c31af7Sopenharmony_ci	}
185e5c31af7Sopenharmony_ci
186e5c31af7Sopenharmony_ci	/* The test requires EXT_tessellation_shader, EXT_tessellation_shader_point_size */
187e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported || !m_is_tessellation_shader_point_size_supported)
188e5c31af7Sopenharmony_ci	{
189e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("At least one of the required extensions is not supported.");
190e5c31af7Sopenharmony_ci	}
191e5c31af7Sopenharmony_ci
192e5c31af7Sopenharmony_ci	/* Initialize vertex array object */
193e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
194e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
195e5c31af7Sopenharmony_ci
196e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
197e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ci	/* Initialize fs+gs+vs test descriptor */
200e5c31af7Sopenharmony_ci	if (m_is_geometry_shader_extension_supported)
201e5c31af7Sopenharmony_ci	{
202e5c31af7Sopenharmony_ci		_test_descriptor pass_fs_gs_tes_vs;
203e5c31af7Sopenharmony_ci
204e5c31af7Sopenharmony_ci		/* Configure shader bodies */
205e5c31af7Sopenharmony_ci		pass_fs_gs_tes_vs.fs_body = "${VERSION}\n"
206e5c31af7Sopenharmony_ci									"\n"
207e5c31af7Sopenharmony_ci									"precision highp float;\n"
208e5c31af7Sopenharmony_ci									"\n"
209e5c31af7Sopenharmony_ci									"in  vec4 color;\n"
210e5c31af7Sopenharmony_ci									"out vec4 result;\n"
211e5c31af7Sopenharmony_ci									"\n"
212e5c31af7Sopenharmony_ci									"void main()\n"
213e5c31af7Sopenharmony_ci									"{\n"
214e5c31af7Sopenharmony_ci									"    result = color;\n"
215e5c31af7Sopenharmony_ci									"}\n";
216e5c31af7Sopenharmony_ci
217e5c31af7Sopenharmony_ci		pass_fs_gs_tes_vs.gs_body = "${VERSION}\n"
218e5c31af7Sopenharmony_ci									"\n"
219e5c31af7Sopenharmony_ci									"${GEOMETRY_SHADER_REQUIRE}\n"
220e5c31af7Sopenharmony_ci									"${GEOMETRY_POINT_SIZE_REQUIRE}\n"
221e5c31af7Sopenharmony_ci									"\n"
222e5c31af7Sopenharmony_ci									"layout(points)                 in;\n"
223e5c31af7Sopenharmony_ci									"layout(points, max_vertices=5) out;\n"
224e5c31af7Sopenharmony_ci									"\n"
225e5c31af7Sopenharmony_ci									"out vec4 color;\n"
226e5c31af7Sopenharmony_ci									"\n"
227e5c31af7Sopenharmony_ci									"void main()\n"
228e5c31af7Sopenharmony_ci									"{\n"
229e5c31af7Sopenharmony_ci									"    const float point_dx = 2.0 / 16.0 /* rendertarget width */;\n"
230e5c31af7Sopenharmony_ci									"    const float point_dy = 2.0 / 16.0 /* rendertarget_height */;\n"
231e5c31af7Sopenharmony_ci									"\n"
232e5c31af7Sopenharmony_ci									/* Center */
233e5c31af7Sopenharmony_ci									"    color        = vec4(0.1, 0.2, 0.3, 0.4);\n"
234e5c31af7Sopenharmony_ci									"    gl_PointSize = 2.0;\n"
235e5c31af7Sopenharmony_ci									"    gl_Position  = vec4(point_dx + 0.0, point_dy + 0.0, 0.0, 1.0);\n"
236e5c31af7Sopenharmony_ci									"    EmitVertex();\n"
237e5c31af7Sopenharmony_ci									"\n"
238e5c31af7Sopenharmony_ci									/* Top-left corner */
239e5c31af7Sopenharmony_ci									"    color        = vec4(0.2, 0.3, 0.4, 0.5);\n"
240e5c31af7Sopenharmony_ci									"    gl_PointSize = 2.0;\n"
241e5c31af7Sopenharmony_ci									"    gl_Position  = vec4(point_dx - 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
242e5c31af7Sopenharmony_ci									"    EmitVertex();\n"
243e5c31af7Sopenharmony_ci									"\n"
244e5c31af7Sopenharmony_ci									/* Top-right corner */
245e5c31af7Sopenharmony_ci									"    color        = vec4(0.3, 0.4, 0.5, 0.6);\n"
246e5c31af7Sopenharmony_ci									"    gl_PointSize = 2.0;\n"
247e5c31af7Sopenharmony_ci									"    gl_Position  = vec4(-point_dx + 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
248e5c31af7Sopenharmony_ci									"    EmitVertex();\n"
249e5c31af7Sopenharmony_ci									"\n"
250e5c31af7Sopenharmony_ci									/* Bottom-left corner */
251e5c31af7Sopenharmony_ci									"    color        = vec4(0.4, 0.5, 0.6, 0.7);\n"
252e5c31af7Sopenharmony_ci									"    gl_PointSize = 2.0;\n"
253e5c31af7Sopenharmony_ci									"    gl_Position  = vec4(point_dx - 1.0, point_dy - 1.0, 0.0, 1.0);\n"
254e5c31af7Sopenharmony_ci									"    EmitVertex();\n"
255e5c31af7Sopenharmony_ci									"\n"
256e5c31af7Sopenharmony_ci									/* Bottom-right corner */
257e5c31af7Sopenharmony_ci									"    color        = vec4(0.5, 0.6, 0.7, 0.8);\n"
258e5c31af7Sopenharmony_ci									"    gl_PointSize = 2.0;\n"
259e5c31af7Sopenharmony_ci									"    gl_Position  = vec4(-point_dx + 1.0, point_dy - 1.0, 0.0, 1.0);\n"
260e5c31af7Sopenharmony_ci									"    EmitVertex();\n"
261e5c31af7Sopenharmony_ci									"\n"
262e5c31af7Sopenharmony_ci									"}\n";
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci		pass_fs_gs_tes_vs.tes_body = "${VERSION}\n"
265e5c31af7Sopenharmony_ci									 "\n"
266e5c31af7Sopenharmony_ci									 "${TESSELLATION_SHADER_REQUIRE}\n"
267e5c31af7Sopenharmony_ci									 "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
268e5c31af7Sopenharmony_ci									 "\n"
269e5c31af7Sopenharmony_ci									 "layout(isolines, point_mode) in;\n"
270e5c31af7Sopenharmony_ci									 "\n"
271e5c31af7Sopenharmony_ci									 "void main()\n"
272e5c31af7Sopenharmony_ci									 "{\n"
273e5c31af7Sopenharmony_ci									 "    gl_PointSize = 0.1;\n"
274e5c31af7Sopenharmony_ci									 "}\n";
275e5c31af7Sopenharmony_ci
276e5c31af7Sopenharmony_ci		pass_fs_gs_tes_vs.tcs_body = "${VERSION}\n"
277e5c31af7Sopenharmony_ci									 "\n"
278e5c31af7Sopenharmony_ci									 "${TESSELLATION_SHADER_REQUIRE}\n"
279e5c31af7Sopenharmony_ci									 "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
280e5c31af7Sopenharmony_ci									 "\n"
281e5c31af7Sopenharmony_ci									 "layout(vertices=1) out;\n"
282e5c31af7Sopenharmony_ci									 "\n"
283e5c31af7Sopenharmony_ci									 "void main()\n"
284e5c31af7Sopenharmony_ci									 "{\n"
285e5c31af7Sopenharmony_ci									 "    gl_out[gl_InvocationID].gl_Position =\n"
286e5c31af7Sopenharmony_ci									 "        gl_in[gl_InvocationID].gl_Position;\n"
287e5c31af7Sopenharmony_ci									 "    gl_out[gl_InvocationID].gl_PointSize =\n"
288e5c31af7Sopenharmony_ci									 "        gl_in[gl_InvocationID].gl_PointSize;\n"
289e5c31af7Sopenharmony_ci									 "\n"
290e5c31af7Sopenharmony_ci									 "    gl_TessLevelOuter[0] = 1.0;\n"
291e5c31af7Sopenharmony_ci									 "    gl_TessLevelOuter[1] = 1.0;\n"
292e5c31af7Sopenharmony_ci									 "    gl_TessLevelOuter[2] = 1.0;\n"
293e5c31af7Sopenharmony_ci									 "    gl_TessLevelOuter[3] = 1.0;\n"
294e5c31af7Sopenharmony_ci									 "    gl_TessLevelInner[0] = 1.0;\n"
295e5c31af7Sopenharmony_ci									 "    gl_TessLevelInner[1] = 1.0;\n"
296e5c31af7Sopenharmony_ci									 "}\n";
297e5c31af7Sopenharmony_ci
298e5c31af7Sopenharmony_ci		pass_fs_gs_tes_vs.vs_body = "${VERSION}\n"
299e5c31af7Sopenharmony_ci									"\n"
300e5c31af7Sopenharmony_ci									"void main()\n"
301e5c31af7Sopenharmony_ci									"{\n"
302e5c31af7Sopenharmony_ci									"    gl_PointSize = 0.01;\n"
303e5c31af7Sopenharmony_ci									"}\n";
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_ci		pass_fs_gs_tes_vs.draw_call_count = 1;
306e5c31af7Sopenharmony_ci
307e5c31af7Sopenharmony_ci		/* Store the descriptor in a vector that will be used by iterate() */
308e5c31af7Sopenharmony_ci		m_tests.push_back(pass_fs_gs_tes_vs);
309e5c31af7Sopenharmony_ci	} /* if (m_is_geometry_shader_extension_supported) */
310e5c31af7Sopenharmony_ci
311e5c31af7Sopenharmony_ci	/* Initialize fs+te+vs test descriptor */
312e5c31af7Sopenharmony_ci	if (m_is_tessellation_shader_supported)
313e5c31af7Sopenharmony_ci	{
314e5c31af7Sopenharmony_ci		_test_descriptor pass_fs_tes_vs;
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci		/* Configure shader bodies */
317e5c31af7Sopenharmony_ci		pass_fs_tes_vs.fs_body = "${VERSION}\n"
318e5c31af7Sopenharmony_ci								 "\n"
319e5c31af7Sopenharmony_ci								 "precision highp float;\n"
320e5c31af7Sopenharmony_ci								 "\n"
321e5c31af7Sopenharmony_ci								 "in  vec4 result_color;\n"
322e5c31af7Sopenharmony_ci								 "out vec4 result;\n"
323e5c31af7Sopenharmony_ci								 "\n"
324e5c31af7Sopenharmony_ci								 "void main()\n"
325e5c31af7Sopenharmony_ci								 "{\n"
326e5c31af7Sopenharmony_ci								 "    result = result_color;\n"
327e5c31af7Sopenharmony_ci								 "}\n";
328e5c31af7Sopenharmony_ci
329e5c31af7Sopenharmony_ci		pass_fs_tes_vs.tes_body = "${VERSION}\n"
330e5c31af7Sopenharmony_ci								  "\n"
331e5c31af7Sopenharmony_ci								  "${TESSELLATION_SHADER_REQUIRE}\n"
332e5c31af7Sopenharmony_ci								  "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
333e5c31af7Sopenharmony_ci								  "\n"
334e5c31af7Sopenharmony_ci								  "layout(isolines, point_mode) in;\n"
335e5c31af7Sopenharmony_ci								  "\n"
336e5c31af7Sopenharmony_ci								  "in  vec4 tcColor[];\n"
337e5c31af7Sopenharmony_ci								  "out vec4 result_color;\n"
338e5c31af7Sopenharmony_ci								  "\n"
339e5c31af7Sopenharmony_ci								  "void main()\n"
340e5c31af7Sopenharmony_ci								  "{\n"
341e5c31af7Sopenharmony_ci								  "    gl_PointSize = 2.0;\n"
342e5c31af7Sopenharmony_ci								  "    gl_Position  = gl_in[0].gl_Position;\n"
343e5c31af7Sopenharmony_ci								  "    result_color = tcColor[0];\n"
344e5c31af7Sopenharmony_ci								  "}\n";
345e5c31af7Sopenharmony_ci
346e5c31af7Sopenharmony_ci		pass_fs_tes_vs.tcs_body = "${VERSION}\n"
347e5c31af7Sopenharmony_ci								  "\n"
348e5c31af7Sopenharmony_ci								  "${TESSELLATION_SHADER_REQUIRE}\n"
349e5c31af7Sopenharmony_ci								  "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
350e5c31af7Sopenharmony_ci								  "\n"
351e5c31af7Sopenharmony_ci								  "layout(vertices=1) out;\n"
352e5c31af7Sopenharmony_ci								  "\n"
353e5c31af7Sopenharmony_ci								  "in  vec4 color[];\n"
354e5c31af7Sopenharmony_ci								  "out vec4 tcColor[];\n"
355e5c31af7Sopenharmony_ci								  "\n"
356e5c31af7Sopenharmony_ci								  "void main()\n"
357e5c31af7Sopenharmony_ci								  "{\n"
358e5c31af7Sopenharmony_ci								  "    tcColor[gl_InvocationID] = color[gl_InvocationID];\n"
359e5c31af7Sopenharmony_ci								  "    gl_out[gl_InvocationID].gl_Position =\n"
360e5c31af7Sopenharmony_ci								  "        gl_in[gl_InvocationID].gl_Position;\n"
361e5c31af7Sopenharmony_ci								  "    gl_out[gl_InvocationID].gl_PointSize =\n"
362e5c31af7Sopenharmony_ci								  "        gl_in[gl_InvocationID].gl_PointSize;\n"
363e5c31af7Sopenharmony_ci								  "\n"
364e5c31af7Sopenharmony_ci								  "    gl_TessLevelOuter[0] = 1.0;\n"
365e5c31af7Sopenharmony_ci								  "    gl_TessLevelOuter[1] = 1.0;\n"
366e5c31af7Sopenharmony_ci								  "    gl_TessLevelOuter[2] = 1.0;\n"
367e5c31af7Sopenharmony_ci								  "    gl_TessLevelOuter[3] = 1.0;\n"
368e5c31af7Sopenharmony_ci								  "    gl_TessLevelInner[0] = 1.0;\n"
369e5c31af7Sopenharmony_ci								  "    gl_TessLevelInner[1] = 1.0;\n"
370e5c31af7Sopenharmony_ci								  "}\n";
371e5c31af7Sopenharmony_ci
372e5c31af7Sopenharmony_ci		pass_fs_tes_vs.vs_body = "${VERSION}\n"
373e5c31af7Sopenharmony_ci								 "\n"
374e5c31af7Sopenharmony_ci								 "out vec4 color;\n"
375e5c31af7Sopenharmony_ci								 "\n"
376e5c31af7Sopenharmony_ci								 "void main()\n"
377e5c31af7Sopenharmony_ci								 "{\n"
378e5c31af7Sopenharmony_ci								 "    const float point_dx = 2.0 / 16.0 /* rendertarget width */;\n"
379e5c31af7Sopenharmony_ci								 "    const float point_dy = 2.0 / 16.0 /* rendertarget_height */;\n"
380e5c31af7Sopenharmony_ci								 "\n"
381e5c31af7Sopenharmony_ci								 "    gl_PointSize = 0.1;\n"
382e5c31af7Sopenharmony_ci								 "\n"
383e5c31af7Sopenharmony_ci								 "    switch (gl_VertexID)\n"
384e5c31af7Sopenharmony_ci								 "    {\n"
385e5c31af7Sopenharmony_ci								 "        case 0:\n"
386e5c31af7Sopenharmony_ci								 "        {\n"
387e5c31af7Sopenharmony_ci								 /* Center */
388e5c31af7Sopenharmony_ci								 "            color       = vec4(0.1, 0.2, 0.3, 0.4);\n"
389e5c31af7Sopenharmony_ci								 "            gl_Position = vec4(point_dx + 0.0, point_dy + 0.0, 0.0, 1.0);\n"
390e5c31af7Sopenharmony_ci								 "\n"
391e5c31af7Sopenharmony_ci								 "            break;\n"
392e5c31af7Sopenharmony_ci								 "        }\n"
393e5c31af7Sopenharmony_ci								 "\n"
394e5c31af7Sopenharmony_ci								 "        case 1:\n"
395e5c31af7Sopenharmony_ci								 "        {\n"
396e5c31af7Sopenharmony_ci								 /* Top-left corner */
397e5c31af7Sopenharmony_ci								 "            color       = vec4(0.2, 0.3, 0.4, 0.5);\n"
398e5c31af7Sopenharmony_ci								 "            gl_Position = vec4(point_dx - 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
399e5c31af7Sopenharmony_ci								 "\n"
400e5c31af7Sopenharmony_ci								 "            break;\n"
401e5c31af7Sopenharmony_ci								 "        }\n"
402e5c31af7Sopenharmony_ci								 "\n"
403e5c31af7Sopenharmony_ci								 "        case 2:\n"
404e5c31af7Sopenharmony_ci								 "        {\n"
405e5c31af7Sopenharmony_ci								 /* Top-right corner */
406e5c31af7Sopenharmony_ci								 "            color       = vec4(0.3, 0.4, 0.5, 0.6);\n"
407e5c31af7Sopenharmony_ci								 "            gl_Position = vec4(-point_dx + 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
408e5c31af7Sopenharmony_ci								 "\n"
409e5c31af7Sopenharmony_ci								 "            break;\n"
410e5c31af7Sopenharmony_ci								 "        }\n"
411e5c31af7Sopenharmony_ci								 "\n"
412e5c31af7Sopenharmony_ci								 "        case 3:\n"
413e5c31af7Sopenharmony_ci								 "        {\n"
414e5c31af7Sopenharmony_ci								 /* Bottom-left corner */
415e5c31af7Sopenharmony_ci								 "            color       = vec4(0.4, 0.5, 0.6, 0.7);\n"
416e5c31af7Sopenharmony_ci								 "            gl_Position = vec4(point_dx - 1.0, point_dy - 1.0, 0.0, 1.0);\n"
417e5c31af7Sopenharmony_ci								 "\n"
418e5c31af7Sopenharmony_ci								 "            break;\n"
419e5c31af7Sopenharmony_ci								 "        }\n"
420e5c31af7Sopenharmony_ci								 "\n"
421e5c31af7Sopenharmony_ci								 "        case 4:\n"
422e5c31af7Sopenharmony_ci								 "        {\n"
423e5c31af7Sopenharmony_ci								 /* Bottom-right corner */
424e5c31af7Sopenharmony_ci								 "            color       = vec4(0.5, 0.6, 0.7, 0.8);\n"
425e5c31af7Sopenharmony_ci								 "            gl_Position = vec4(-point_dx + 1.0, point_dy - 1.0, 0.0, 1.0);\n"
426e5c31af7Sopenharmony_ci								 "\n"
427e5c31af7Sopenharmony_ci								 "            break;\n"
428e5c31af7Sopenharmony_ci								 "        }\n"
429e5c31af7Sopenharmony_ci								 "    }\n"
430e5c31af7Sopenharmony_ci								 "}\n";
431e5c31af7Sopenharmony_ci
432e5c31af7Sopenharmony_ci		pass_fs_tes_vs.draw_call_count = 5; /* points in total */
433e5c31af7Sopenharmony_ci
434e5c31af7Sopenharmony_ci		/* Store the descriptor in a vector that will be used by iterate() */
435e5c31af7Sopenharmony_ci		m_tests.push_back(pass_fs_tes_vs);
436e5c31af7Sopenharmony_ci	} /* if (m_is_tessellation_shader_supported) */
437e5c31af7Sopenharmony_ci
438e5c31af7Sopenharmony_ci	/* Set up a color texture we will be rendering to */
439e5c31af7Sopenharmony_ci	gl.genTextures(1, &m_to_id);
440e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed");
441e5c31af7Sopenharmony_ci
442e5c31af7Sopenharmony_ci	gl.bindTexture(GL_TEXTURE_2D, m_to_id);
443e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
444e5c31af7Sopenharmony_ci
445e5c31af7Sopenharmony_ci	gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, m_rt_width, m_rt_height);
446e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() failed");
447e5c31af7Sopenharmony_ci
448e5c31af7Sopenharmony_ci	/* Set up a FBO we'll use for rendering */
449e5c31af7Sopenharmony_ci	gl.genFramebuffers(1, &m_fbo_id);
450e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() failed");
451e5c31af7Sopenharmony_ci
452e5c31af7Sopenharmony_ci	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
453e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() failed");
454e5c31af7Sopenharmony_ci
455e5c31af7Sopenharmony_ci	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
456e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() failed");
457e5c31af7Sopenharmony_ci
458e5c31af7Sopenharmony_ci	if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
459e5c31af7Sopenharmony_ci	{
460e5c31af7Sopenharmony_ci		/* Enable point size */
461e5c31af7Sopenharmony_ci		gl.enable(GL_PROGRAM_POINT_SIZE);
462e5c31af7Sopenharmony_ci	}
463e5c31af7Sopenharmony_ci
464e5c31af7Sopenharmony_ci	/* We're good to execute the test! */
465e5c31af7Sopenharmony_ci}
466e5c31af7Sopenharmony_ci
467e5c31af7Sopenharmony_ci/** Executes the test.
468e5c31af7Sopenharmony_ci *
469e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
470e5c31af7Sopenharmony_ci *
471e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
472e5c31af7Sopenharmony_ci *
473e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
474e5c31af7Sopenharmony_ci **/
475e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderPointsgl_PointSize::iterate(void)
476e5c31af7Sopenharmony_ci{
477e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
478e5c31af7Sopenharmony_ci
479e5c31af7Sopenharmony_ci	initTest();
480e5c31af7Sopenharmony_ci
481e5c31af7Sopenharmony_ci	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
482e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed");
483e5c31af7Sopenharmony_ci
484e5c31af7Sopenharmony_ci	/* Iterate through all test descriptors.. */
485e5c31af7Sopenharmony_ci	for (_tests_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++)
486e5c31af7Sopenharmony_ci	{
487e5c31af7Sopenharmony_ci		_test_descriptor& test = *test_iterator;
488e5c31af7Sopenharmony_ci
489e5c31af7Sopenharmony_ci		/* Generate all shader objects we'll need */
490e5c31af7Sopenharmony_ci		if (test.fs_body != NULL)
491e5c31af7Sopenharmony_ci		{
492e5c31af7Sopenharmony_ci			test.fs_id = gl.createShader(GL_FRAGMENT_SHADER);
493e5c31af7Sopenharmony_ci		}
494e5c31af7Sopenharmony_ci
495e5c31af7Sopenharmony_ci		if (test.gs_body != NULL)
496e5c31af7Sopenharmony_ci		{
497e5c31af7Sopenharmony_ci			test.gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
498e5c31af7Sopenharmony_ci		}
499e5c31af7Sopenharmony_ci
500e5c31af7Sopenharmony_ci		if (test.tes_body != NULL)
501e5c31af7Sopenharmony_ci		{
502e5c31af7Sopenharmony_ci			test.tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
503e5c31af7Sopenharmony_ci		}
504e5c31af7Sopenharmony_ci
505e5c31af7Sopenharmony_ci		if (test.tcs_body != NULL)
506e5c31af7Sopenharmony_ci		{
507e5c31af7Sopenharmony_ci			test.tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
508e5c31af7Sopenharmony_ci		}
509e5c31af7Sopenharmony_ci
510e5c31af7Sopenharmony_ci		if (test.vs_body != NULL)
511e5c31af7Sopenharmony_ci		{
512e5c31af7Sopenharmony_ci			test.vs_id = gl.createShader(GL_VERTEX_SHADER);
513e5c31af7Sopenharmony_ci		}
514e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
515e5c31af7Sopenharmony_ci
516e5c31af7Sopenharmony_ci		/* Generate a test program object before we continue */
517e5c31af7Sopenharmony_ci		test.po_id = gl.createProgram();
518e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed");
519e5c31af7Sopenharmony_ci
520e5c31af7Sopenharmony_ci		bool link_success =
521e5c31af7Sopenharmony_ci			buildProgram(test.po_id, test.fs_id, test.fs_id ? 1 : 0, &test.fs_body, test.gs_id, test.gs_id ? 1 : 0,
522e5c31af7Sopenharmony_ci						 &test.gs_body, test.tes_id, test.tes_id ? 1 : 0, &test.tes_body, test.tcs_id,
523e5c31af7Sopenharmony_ci						 test.tcs_id ? 1 : 0, &test.tcs_body, test.vs_id, test.vs_id ? 1 : 0, &test.vs_body);
524e5c31af7Sopenharmony_ci
525e5c31af7Sopenharmony_ci		if (!link_success)
526e5c31af7Sopenharmony_ci		{
527e5c31af7Sopenharmony_ci			TCU_FAIL("Program linking failed");
528e5c31af7Sopenharmony_ci		}
529e5c31af7Sopenharmony_ci
530e5c31af7Sopenharmony_ci		/* Prepare for rendering */
531e5c31af7Sopenharmony_ci		gl.clearColor(0.0f /* red */, 0.0f /* green */, 0.0f /* blue */, 0.0f /* alpha */);
532e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() failed");
533e5c31af7Sopenharmony_ci
534e5c31af7Sopenharmony_ci		gl.clear(GL_COLOR_BUFFER_BIT);
535e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glClear(GL_COLOR_BUFFER_BIT) failed");
536e5c31af7Sopenharmony_ci
537e5c31af7Sopenharmony_ci		gl.viewport(0 /* x */, 0 /* x */, m_rt_width, m_rt_height);
538e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() failed");
539e5c31af7Sopenharmony_ci
540e5c31af7Sopenharmony_ci		gl.useProgram(test.po_id);
541e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
542e5c31af7Sopenharmony_ci
543e5c31af7Sopenharmony_ci		/* Render */
544e5c31af7Sopenharmony_ci		gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, test.draw_call_count);
545e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
546e5c31af7Sopenharmony_ci
547e5c31af7Sopenharmony_ci		/* Read back the rendered data */
548e5c31af7Sopenharmony_ci		unsigned char buffer[m_rt_width * m_rt_height * 4 /* components */] = { 0 };
549e5c31af7Sopenharmony_ci
550e5c31af7Sopenharmony_ci		gl.readPixels(0, /* x */
551e5c31af7Sopenharmony_ci					  0, /* y */
552e5c31af7Sopenharmony_ci					  m_rt_width, m_rt_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
553e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() failed");
554e5c31af7Sopenharmony_ci
555e5c31af7Sopenharmony_ci		/* Verify all 5 points were rendered correctly */
556e5c31af7Sopenharmony_ci		const float		   epsilon		= (float)1.0f / 255.0f;
557e5c31af7Sopenharmony_ci		const unsigned int pixel_size   = 4; /* components, GL_UNSIGNED_BYTE */
558e5c31af7Sopenharmony_ci		const float		   point_data[] = {
559e5c31af7Sopenharmony_ci			/* x */ /* y */ /* r */ /* g */ /* b */ /* a */
560e5c31af7Sopenharmony_ci			0.5f, 0.5f, 0.1f, 0.2f, 0.3f, 0.4f,		/* center */
561e5c31af7Sopenharmony_ci			0.0f, 1.0f, 0.2f, 0.3f, 0.4f, 0.5f,		/* top-left */
562e5c31af7Sopenharmony_ci			1.0f, 1.0f, 0.3f, 0.4f, 0.5f, 0.6f,		/* top-right */
563e5c31af7Sopenharmony_ci			0.0f, 0.0f, 0.4f, 0.5f, 0.6f, 0.7f,		/* bottom-left */
564e5c31af7Sopenharmony_ci			1.0f, 0.0f, 0.5f, 0.6f, 0.7f, 0.8f		/* bottom-right */
565e5c31af7Sopenharmony_ci		};
566e5c31af7Sopenharmony_ci		const unsigned int row_size			  = pixel_size * m_rt_width;
567e5c31af7Sopenharmony_ci		const unsigned int n_fields_per_point = 6;
568e5c31af7Sopenharmony_ci		const unsigned int n_points			  = sizeof(point_data) / sizeof(point_data[0]) / n_fields_per_point;
569e5c31af7Sopenharmony_ci
570e5c31af7Sopenharmony_ci		for (unsigned int n_point = 0; n_point < n_points; ++n_point)
571e5c31af7Sopenharmony_ci		{
572e5c31af7Sopenharmony_ci			int   x = (int)(point_data[n_point * n_fields_per_point + 0] * float(m_rt_width - 1) + 0.5f);
573e5c31af7Sopenharmony_ci			int   y = (int)(point_data[n_point * n_fields_per_point + 1] * float(m_rt_height - 1) + 0.5f);
574e5c31af7Sopenharmony_ci			float expected_color_r = point_data[n_point * n_fields_per_point + 2];
575e5c31af7Sopenharmony_ci			float expected_color_g = point_data[n_point * n_fields_per_point + 3];
576e5c31af7Sopenharmony_ci			float expected_color_b = point_data[n_point * n_fields_per_point + 4];
577e5c31af7Sopenharmony_ci			float expected_color_a = point_data[n_point * n_fields_per_point + 5];
578e5c31af7Sopenharmony_ci
579e5c31af7Sopenharmony_ci			const unsigned char* rendered_color_ubyte_ptr = buffer + row_size * y + x * pixel_size;
580e5c31af7Sopenharmony_ci			const float			 rendered_color_r		  = float(rendered_color_ubyte_ptr[0]) / 255.0f;
581e5c31af7Sopenharmony_ci			const float			 rendered_color_g		  = float(rendered_color_ubyte_ptr[1]) / 255.0f;
582e5c31af7Sopenharmony_ci			const float			 rendered_color_b		  = float(rendered_color_ubyte_ptr[2]) / 255.0f;
583e5c31af7Sopenharmony_ci			const float			 rendered_color_a		  = float(rendered_color_ubyte_ptr[3]) / 255.0f;
584e5c31af7Sopenharmony_ci
585e5c31af7Sopenharmony_ci			/* Compare the pixels */
586e5c31af7Sopenharmony_ci			if (de::abs(expected_color_r - rendered_color_r) > epsilon ||
587e5c31af7Sopenharmony_ci				de::abs(expected_color_g - rendered_color_g) > epsilon ||
588e5c31af7Sopenharmony_ci				de::abs(expected_color_b - rendered_color_b) > epsilon ||
589e5c31af7Sopenharmony_ci				de::abs(expected_color_a - rendered_color_a) > epsilon)
590e5c31af7Sopenharmony_ci			{
591e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Pixel data comparison failed; expected: "
592e5c31af7Sopenharmony_ci								   << "(" << expected_color_r << ", " << expected_color_g << ", " << expected_color_b
593e5c31af7Sopenharmony_ci								   << ", " << expected_color_a << ") rendered: "
594e5c31af7Sopenharmony_ci								   << "(" << rendered_color_r << ", " << rendered_color_g << ", " << rendered_color_b
595e5c31af7Sopenharmony_ci								   << ", " << rendered_color_a << ") epsilon: " << epsilon << tcu::TestLog::EndMessage;
596e5c31af7Sopenharmony_ci
597e5c31af7Sopenharmony_ci				TCU_FAIL("Pixel data comparison failed");
598e5c31af7Sopenharmony_ci			}
599e5c31af7Sopenharmony_ci		} /* for (all points) */
600e5c31af7Sopenharmony_ci	}	 /* for (all tests) */
601e5c31af7Sopenharmony_ci
602e5c31af7Sopenharmony_ci	/* All done */
603e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
604e5c31af7Sopenharmony_ci	return STOP;
605e5c31af7Sopenharmony_ci}
606e5c31af7Sopenharmony_ci
607e5c31af7Sopenharmony_ci/** Constructor
608e5c31af7Sopenharmony_ci *
609e5c31af7Sopenharmony_ci * @param context Test context
610e5c31af7Sopenharmony_ci **/
611e5c31af7Sopenharmony_ciTessellationShaderPointsVerification::TessellationShaderPointsVerification(Context&				context,
612e5c31af7Sopenharmony_ci																		   const ExtParameters& extParams)
613e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, "points_verification",
614e5c31af7Sopenharmony_ci				   "Verifies points generated by the tessellator unit do not duplicate "
615e5c31af7Sopenharmony_ci				   "and that their amount is correct")
616e5c31af7Sopenharmony_ci	, m_utils(DE_NULL)
617e5c31af7Sopenharmony_ci	, m_vao_id(0)
618e5c31af7Sopenharmony_ci{
619e5c31af7Sopenharmony_ci	/* Left blank on purpose */
620e5c31af7Sopenharmony_ci}
621e5c31af7Sopenharmony_ci
622e5c31af7Sopenharmony_ci/* Deinitializes all ES Instances generated for the test */
623e5c31af7Sopenharmony_civoid TessellationShaderPointsVerification::deinit()
624e5c31af7Sopenharmony_ci{
625e5c31af7Sopenharmony_ci	/* Call base class' deinit() */
626e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
627e5c31af7Sopenharmony_ci
628e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
629e5c31af7Sopenharmony_ci	{
630e5c31af7Sopenharmony_ci		return;
631e5c31af7Sopenharmony_ci	}
632e5c31af7Sopenharmony_ci
633e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
634e5c31af7Sopenharmony_ci
635e5c31af7Sopenharmony_ci	/* Unbind vertex array object */
636e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
637e5c31af7Sopenharmony_ci
638e5c31af7Sopenharmony_ci	/* Delete utils instances */
639e5c31af7Sopenharmony_ci	if (m_utils != DE_NULL)
640e5c31af7Sopenharmony_ci	{
641e5c31af7Sopenharmony_ci		delete m_utils;
642e5c31af7Sopenharmony_ci
643e5c31af7Sopenharmony_ci		m_utils = DE_NULL;
644e5c31af7Sopenharmony_ci	}
645e5c31af7Sopenharmony_ci
646e5c31af7Sopenharmony_ci	/* Delete vertex array object */
647e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
648e5c31af7Sopenharmony_ci	{
649e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
650e5c31af7Sopenharmony_ci
651e5c31af7Sopenharmony_ci		m_vao_id = 0;
652e5c31af7Sopenharmony_ci	}
653e5c31af7Sopenharmony_ci}
654e5c31af7Sopenharmony_ci
655e5c31af7Sopenharmony_ci/** Initializes ES objects necessary to run the test. */
656e5c31af7Sopenharmony_civoid TessellationShaderPointsVerification::initTest()
657e5c31af7Sopenharmony_ci{
658e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
659e5c31af7Sopenharmony_ci
660e5c31af7Sopenharmony_ci	/* Skip if required extensions are not supported. */
661e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
662e5c31af7Sopenharmony_ci	{
663e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
664e5c31af7Sopenharmony_ci	}
665e5c31af7Sopenharmony_ci
666e5c31af7Sopenharmony_ci	/* Initialize and bind vertex array object */
667e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
668e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
669e5c31af7Sopenharmony_ci
670e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
671e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
672e5c31af7Sopenharmony_ci
673e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
674e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_gen_level_value = 0;
675e5c31af7Sopenharmony_ci
676e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
677e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
678e5c31af7Sopenharmony_ci
679e5c31af7Sopenharmony_ci	/* Initialize all test iterations */
680e5c31af7Sopenharmony_ci	const _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
681e5c31af7Sopenharmony_ci															 TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
682e5c31af7Sopenharmony_ci															 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
683e5c31af7Sopenharmony_ci	const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
684e5c31af7Sopenharmony_ci
685e5c31af7Sopenharmony_ci	const _tessellation_shader_vertex_spacing vertex_spacings[] = {
686e5c31af7Sopenharmony_ci		TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
687e5c31af7Sopenharmony_ci		TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
688e5c31af7Sopenharmony_ci	};
689e5c31af7Sopenharmony_ci	const unsigned int n_vertex_spacings = sizeof(vertex_spacings) / sizeof(vertex_spacings[0]);
690e5c31af7Sopenharmony_ci
691e5c31af7Sopenharmony_ci	for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
692e5c31af7Sopenharmony_ci	{
693e5c31af7Sopenharmony_ci		_tessellation_levels_set	 levels_set;
694e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
695e5c31af7Sopenharmony_ci
696e5c31af7Sopenharmony_ci		levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
697e5c31af7Sopenharmony_ci			primitive_mode, gl_max_tess_gen_level_value,
698e5c31af7Sopenharmony_ci			TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES);
699e5c31af7Sopenharmony_ci
700e5c31af7Sopenharmony_ci		for (unsigned int n_vertex_spacing = 0; n_vertex_spacing < n_vertex_spacings; ++n_vertex_spacing)
701e5c31af7Sopenharmony_ci		{
702e5c31af7Sopenharmony_ci			_tessellation_shader_vertex_spacing vertex_spacing = vertex_spacings[n_vertex_spacing];
703e5c31af7Sopenharmony_ci
704e5c31af7Sopenharmony_ci			for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin();
705e5c31af7Sopenharmony_ci				 levels_set_iterator != levels_set.end(); levels_set_iterator++)
706e5c31af7Sopenharmony_ci			{
707e5c31af7Sopenharmony_ci				const _tessellation_levels& levels = *levels_set_iterator;
708e5c31af7Sopenharmony_ci
709e5c31af7Sopenharmony_ci				/* Skip border cases that this test cannot handle */
710e5c31af7Sopenharmony_ci				if ((primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS ||
711e5c31af7Sopenharmony_ci					 primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) &&
712e5c31af7Sopenharmony_ci					vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD &&
713e5c31af7Sopenharmony_ci					(levels.inner[0] <= 1 || levels.inner[1] <= 1))
714e5c31af7Sopenharmony_ci				{
715e5c31af7Sopenharmony_ci					continue;
716e5c31af7Sopenharmony_ci				}
717e5c31af7Sopenharmony_ci
718e5c31af7Sopenharmony_ci				/* Initialize a test run descriptor for the iteration-specific properties */
719e5c31af7Sopenharmony_ci				_run run;
720e5c31af7Sopenharmony_ci
721e5c31af7Sopenharmony_ci				memcpy(run.inner, levels.inner, sizeof(run.inner));
722e5c31af7Sopenharmony_ci				memcpy(run.outer, levels.outer, sizeof(run.outer));
723e5c31af7Sopenharmony_ci
724e5c31af7Sopenharmony_ci				run.primitive_mode = primitive_mode;
725e5c31af7Sopenharmony_ci				run.vertex_spacing = vertex_spacing;
726e5c31af7Sopenharmony_ci
727e5c31af7Sopenharmony_ci				m_runs.push_back(run);
728e5c31af7Sopenharmony_ci			} /* for (all level sets) */
729e5c31af7Sopenharmony_ci		}	 /* for (all vertex spacing modes) */
730e5c31af7Sopenharmony_ci	}		  /* for (all primitive modes) */
731e5c31af7Sopenharmony_ci
732e5c31af7Sopenharmony_ci	/* Initialize utils instance.
733e5c31af7Sopenharmony_ci	 */
734e5c31af7Sopenharmony_ci	m_utils = new TessellationShaderUtils(gl, this);
735e5c31af7Sopenharmony_ci}
736e5c31af7Sopenharmony_ci
737e5c31af7Sopenharmony_ci/** Executes the test.
738e5c31af7Sopenharmony_ci *
739e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
740e5c31af7Sopenharmony_ci *
741e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
742e5c31af7Sopenharmony_ci *
743e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
744e5c31af7Sopenharmony_ci **/
745e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderPointsVerification::iterate(void)
746e5c31af7Sopenharmony_ci{
747e5c31af7Sopenharmony_ci	initTest();
748e5c31af7Sopenharmony_ci
749e5c31af7Sopenharmony_ci	/* Do not execute if required extensions are not supported. */
750e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
751e5c31af7Sopenharmony_ci	{
752e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
753e5c31af7Sopenharmony_ci	}
754e5c31af7Sopenharmony_ci
755e5c31af7Sopenharmony_ci	/* Iterate through all the test descriptors */
756e5c31af7Sopenharmony_ci	for (std::vector<_run>::const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
757e5c31af7Sopenharmony_ci	{
758e5c31af7Sopenharmony_ci		const _run&		  run = *run_iterator;
759e5c31af7Sopenharmony_ci		std::vector<char> run_data;
760e5c31af7Sopenharmony_ci		unsigned int	  run_n_vertices = 0;
761e5c31af7Sopenharmony_ci
762e5c31af7Sopenharmony_ci		run_data = m_utils->getDataGeneratedByTessellator(run.inner, true, /* point_mode */
763e5c31af7Sopenharmony_ci														  run.primitive_mode, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
764e5c31af7Sopenharmony_ci														  run.vertex_spacing, run.outer);
765e5c31af7Sopenharmony_ci
766e5c31af7Sopenharmony_ci		run_n_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(run.primitive_mode, run.inner, run.outer,
767e5c31af7Sopenharmony_ci																			run.vertex_spacing, true); /* point_mode */
768e5c31af7Sopenharmony_ci
769e5c31af7Sopenharmony_ci		/* First, make sure a valid amount of duplicate vertices was found for a single data set */
770e5c31af7Sopenharmony_ci		verifyCorrectAmountOfDuplicateVertices(run, &run_data[0], run_n_vertices);
771e5c31af7Sopenharmony_ci
772e5c31af7Sopenharmony_ci		/* Now, verify that amount of generated vertices is correct, given
773e5c31af7Sopenharmony_ci		 * tessellation shader stage configuration */
774e5c31af7Sopenharmony_ci		verifyCorrectAmountOfVertices(run, &run_data[0], run_n_vertices);
775e5c31af7Sopenharmony_ci	} /* for (all tests) */
776e5c31af7Sopenharmony_ci
777e5c31af7Sopenharmony_ci	/* All done */
778e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
779e5c31af7Sopenharmony_ci	return STOP;
780e5c31af7Sopenharmony_ci}
781e5c31af7Sopenharmony_ci
782e5c31af7Sopenharmony_ci/** Verifies that a correct amount of vertices was generated, given test iteration-specific properties.
783e5c31af7Sopenharmony_ci *  Throws a TestError exception in if an incorrect amount of vertices was generated by the tessellator.
784e5c31af7Sopenharmony_ci *
785e5c31af7Sopenharmony_ci *  @param run            Run descriptor.
786e5c31af7Sopenharmony_ci *  @param run_data       Data generated for the run.
787e5c31af7Sopenharmony_ci *  @param run_n_vertices Amount of vertices present at @param run_data.
788e5c31af7Sopenharmony_ci */
789e5c31af7Sopenharmony_civoid TessellationShaderPointsVerification::verifyCorrectAmountOfVertices(const _run& run, const void* run_data,
790e5c31af7Sopenharmony_ci																		 unsigned int run_n_vertices)
791e5c31af7Sopenharmony_ci{
792e5c31af7Sopenharmony_ci	(void)run_data;
793e5c31af7Sopenharmony_ci
794e5c31af7Sopenharmony_ci	const float			  epsilon					   = 1e-5f;
795e5c31af7Sopenharmony_ci	const glw::Functions& gl						   = m_context.getRenderContext().getFunctions();
796e5c31af7Sopenharmony_ci	unsigned int		  n_expected_vertices		   = 0;
797e5c31af7Sopenharmony_ci	float				  post_vs_inner_tess_levels[2] = { 0.0f };
798e5c31af7Sopenharmony_ci	float				  post_vs_outer_tess_levels[4] = { 0.0f };
799e5c31af7Sopenharmony_ci
800e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value*/
801e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_gen_level_value = 0;
802e5c31af7Sopenharmony_ci
803e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
804e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
805e5c31af7Sopenharmony_ci
806e5c31af7Sopenharmony_ci	/* Determine vertex spacing that the tessellator should have used for current primitive mode */
807e5c31af7Sopenharmony_ci	glw::GLfloat						actual_inner_levels[2]  = { 0.0f };
808e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_spacing actual_vs_mode			= run.vertex_spacing;
809e5c31af7Sopenharmony_ci	glw::GLfloat						clamped_inner_levels[2] = { 0.0f };
810e5c31af7Sopenharmony_ci
811e5c31af7Sopenharmony_ci	memcpy(actual_inner_levels, run.inner, sizeof(run.inner));
812e5c31af7Sopenharmony_ci
813e5c31af7Sopenharmony_ci	TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
814e5c31af7Sopenharmony_ci		run.vertex_spacing, actual_inner_levels[0], gl_max_tess_gen_level_value, clamped_inner_levels + 0,
815e5c31af7Sopenharmony_ci		DE_NULL); /* out_clamped_and_rounded */
816e5c31af7Sopenharmony_ci
817e5c31af7Sopenharmony_ci	TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
818e5c31af7Sopenharmony_ci		run.vertex_spacing, actual_inner_levels[1], gl_max_tess_gen_level_value, clamped_inner_levels + 1,
819e5c31af7Sopenharmony_ci		DE_NULL); /* out_clamped_and_rounded */
820e5c31af7Sopenharmony_ci
821e5c31af7Sopenharmony_ci	if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
822e5c31af7Sopenharmony_ci	{
823e5c31af7Sopenharmony_ci		/* For isolines tessellation, outer[1] is subdivided as per specified vertex spacing as specified.
824e5c31af7Sopenharmony_ci		 * outer[0] should be subdivided using equal vertex spacing.
825e5c31af7Sopenharmony_ci		 *
826e5c31af7Sopenharmony_ci		 * This is owing to the following language in the spec (* marks important subtleties):
827e5c31af7Sopenharmony_ci		 *
828e5c31af7Sopenharmony_ci		 * The *u==0* and *u==1* edges of the rectangle are subdivided according to the first outer
829e5c31af7Sopenharmony_ci		 * tessellation level. For the purposes of *this* subdivision, the tessellation spacing mode
830e5c31af7Sopenharmony_ci		 * is ignored and treated as "equal_spacing".
831e5c31af7Sopenharmony_ci		 */
832e5c31af7Sopenharmony_ci		TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
833e5c31af7Sopenharmony_ci																		run.outer[0], gl_max_tess_gen_level_value,
834e5c31af7Sopenharmony_ci																		DE_NULL, /* out_clamped */
835e5c31af7Sopenharmony_ci																		post_vs_outer_tess_levels);
836e5c31af7Sopenharmony_ci
837e5c31af7Sopenharmony_ci		TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
838e5c31af7Sopenharmony_ci			actual_vs_mode, run.outer[1], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
839e5c31af7Sopenharmony_ci			post_vs_outer_tess_levels + 1);
840e5c31af7Sopenharmony_ci	}
841e5c31af7Sopenharmony_ci
842e5c31af7Sopenharmony_ci	if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS)
843e5c31af7Sopenharmony_ci	{
844e5c31af7Sopenharmony_ci		/* As per extension spec:
845e5c31af7Sopenharmony_ci		 *
846e5c31af7Sopenharmony_ci		 * if either clamped inner tessellation level is one, that tessellation level
847e5c31af7Sopenharmony_ci		 * is treated as though it were originally specified as 1+epsilon, which would
848e5c31af7Sopenharmony_ci		 * rounded up to result in a two- or three-segment subdivision according to the
849e5c31af7Sopenharmony_ci		 * tessellation spacing.
850e5c31af7Sopenharmony_ci		 *
851e5c31af7Sopenharmony_ci		 **/
852e5c31af7Sopenharmony_ci		if (de::abs(clamped_inner_levels[0] - 1.0f) < epsilon)
853e5c31af7Sopenharmony_ci		{
854e5c31af7Sopenharmony_ci			TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
855e5c31af7Sopenharmony_ci				run.vertex_spacing, clamped_inner_levels[0] + 1.0f, /* epsilon */
856e5c31af7Sopenharmony_ci				gl_max_tess_gen_level_value, DE_NULL,				/* out_clamped */
857e5c31af7Sopenharmony_ci				actual_inner_levels + 0);
858e5c31af7Sopenharmony_ci		}
859e5c31af7Sopenharmony_ci
860e5c31af7Sopenharmony_ci		if (de::abs(clamped_inner_levels[1] - 1.0f) < epsilon)
861e5c31af7Sopenharmony_ci		{
862e5c31af7Sopenharmony_ci			TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
863e5c31af7Sopenharmony_ci				run.vertex_spacing, clamped_inner_levels[1] + 1.0f, /* epsilon */
864e5c31af7Sopenharmony_ci				gl_max_tess_gen_level_value, DE_NULL,				/* out_clamped */
865e5c31af7Sopenharmony_ci				actual_inner_levels + 1);
866e5c31af7Sopenharmony_ci		}
867e5c31af7Sopenharmony_ci	}
868e5c31af7Sopenharmony_ci
869e5c31af7Sopenharmony_ci	/* Retrieve tessellation level values, taking vertex spacing setting into account */
870e5c31af7Sopenharmony_ci	for (int n = 0; n < 2 /* inner tessellation level values */; ++n)
871e5c31af7Sopenharmony_ci	{
872e5c31af7Sopenharmony_ci		TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
873e5c31af7Sopenharmony_ci			actual_vs_mode, actual_inner_levels[n], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
874e5c31af7Sopenharmony_ci			post_vs_inner_tess_levels + n);
875e5c31af7Sopenharmony_ci	}
876e5c31af7Sopenharmony_ci
877e5c31af7Sopenharmony_ci	if (run.primitive_mode != TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
878e5c31af7Sopenharmony_ci	{
879e5c31af7Sopenharmony_ci		for (int n = 0; n < 4 /* outer tessellation level values */; ++n)
880e5c31af7Sopenharmony_ci		{
881e5c31af7Sopenharmony_ci			TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
882e5c31af7Sopenharmony_ci				actual_vs_mode, run.outer[n], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
883e5c31af7Sopenharmony_ci				post_vs_outer_tess_levels + n);
884e5c31af7Sopenharmony_ci		}
885e5c31af7Sopenharmony_ci	}
886e5c31af7Sopenharmony_ci
887e5c31af7Sopenharmony_ci	/* Calculate amount of vertices that should be generated in point mode */
888e5c31af7Sopenharmony_ci	switch (run.primitive_mode)
889e5c31af7Sopenharmony_ci	{
890e5c31af7Sopenharmony_ci	case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
891e5c31af7Sopenharmony_ci	{
892e5c31af7Sopenharmony_ci		n_expected_vertices = int(post_vs_outer_tess_levels[0]) * int(post_vs_outer_tess_levels[1] + 1);
893e5c31af7Sopenharmony_ci
894e5c31af7Sopenharmony_ci		break;
895e5c31af7Sopenharmony_ci	}
896e5c31af7Sopenharmony_ci
897e5c31af7Sopenharmony_ci	case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
898e5c31af7Sopenharmony_ci	{
899e5c31af7Sopenharmony_ci		n_expected_vertices = /* outer quad */
900e5c31af7Sopenharmony_ci			int(post_vs_outer_tess_levels[0]) + int(post_vs_outer_tess_levels[1]) + int(post_vs_outer_tess_levels[2]) +
901e5c31af7Sopenharmony_ci			int(post_vs_outer_tess_levels[3]) +
902e5c31af7Sopenharmony_ci			/* inner quad */
903e5c31af7Sopenharmony_ci			(int(post_vs_inner_tess_levels[0]) - 1) * (int(post_vs_inner_tess_levels[1]) - 1);
904e5c31af7Sopenharmony_ci
905e5c31af7Sopenharmony_ci		break;
906e5c31af7Sopenharmony_ci	}
907e5c31af7Sopenharmony_ci
908e5c31af7Sopenharmony_ci	case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
909e5c31af7Sopenharmony_ci	{
910e5c31af7Sopenharmony_ci		/* If the first inner tessellation level and all three outer tessellation
911e5c31af7Sopenharmony_ci		 * levels are exactly one after clamping and rounding, only a single triangle
912e5c31af7Sopenharmony_ci		 * with (u,v,w) coordinates of (0,0,1), (1,0,0), and (0,1,0) is generated.
913e5c31af7Sopenharmony_ci		 */
914e5c31af7Sopenharmony_ci		if (de::abs(run.inner[0] - 1.0f) < epsilon && de::abs(run.outer[0] - 1.0f) < epsilon &&
915e5c31af7Sopenharmony_ci			de::abs(run.outer[1] - 1.0f) < epsilon && de::abs(run.outer[2] - 1.0f) < epsilon)
916e5c31af7Sopenharmony_ci		{
917e5c31af7Sopenharmony_ci			n_expected_vertices = 3;
918e5c31af7Sopenharmony_ci		}
919e5c31af7Sopenharmony_ci		else
920e5c31af7Sopenharmony_ci		{
921e5c31af7Sopenharmony_ci			/* If the inner tessellation level is one and any of the outer tessellation
922e5c31af7Sopenharmony_ci			 * levels is greater than one, the inner tessellation level is treated as
923e5c31af7Sopenharmony_ci			 * though it were originally specified as 1+epsilon and will be rounded up to
924e5c31af7Sopenharmony_ci			 * result in a two- or three-segment subdivision according to the
925e5c31af7Sopenharmony_ci			 * tessellation spacing.
926e5c31af7Sopenharmony_ci			 */
927e5c31af7Sopenharmony_ci			if (de::abs(run.inner[0] - 1.0f) < epsilon &&
928e5c31af7Sopenharmony_ci				(run.outer[0] > 1.0f || run.outer[1] > 1.0f || run.outer[2] > 1.0f))
929e5c31af7Sopenharmony_ci			{
930e5c31af7Sopenharmony_ci				TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
931e5c31af7Sopenharmony_ci					run.vertex_spacing, 2.0f, gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
932e5c31af7Sopenharmony_ci					post_vs_inner_tess_levels);
933e5c31af7Sopenharmony_ci			}
934e5c31af7Sopenharmony_ci
935e5c31af7Sopenharmony_ci			/* Count vertices making up concentric inner triangles */
936e5c31af7Sopenharmony_ci			n_expected_vertices = (int)post_vs_outer_tess_levels[0] + (int)post_vs_outer_tess_levels[1] +
937e5c31af7Sopenharmony_ci								  (int)post_vs_outer_tess_levels[2];
938e5c31af7Sopenharmony_ci
939e5c31af7Sopenharmony_ci			for (int n = (int)post_vs_inner_tess_levels[0]; n >= 0; n -= 2)
940e5c31af7Sopenharmony_ci			{
941e5c31af7Sopenharmony_ci				/* For the outermost inner triangle, the inner triangle is degenerate -
942e5c31af7Sopenharmony_ci				 * a single point at the center of the triangle -- if <n> is two.
943e5c31af7Sopenharmony_ci				 */
944e5c31af7Sopenharmony_ci				if (n == 2)
945e5c31af7Sopenharmony_ci				{
946e5c31af7Sopenharmony_ci					n_expected_vertices++; /* degenerate vertex */
947e5c31af7Sopenharmony_ci
948e5c31af7Sopenharmony_ci					break;
949e5c31af7Sopenharmony_ci				}
950e5c31af7Sopenharmony_ci
951e5c31af7Sopenharmony_ci				/* If <n> is three, the edges of the inner triangle are not subdivided and is
952e5c31af7Sopenharmony_ci				 * the final triangle in the set of concentric triangles.
953e5c31af7Sopenharmony_ci				 */
954e5c31af7Sopenharmony_ci				if (n == 3)
955e5c31af7Sopenharmony_ci				{
956e5c31af7Sopenharmony_ci					n_expected_vertices += 3 /* vertices per triangle */;
957e5c31af7Sopenharmony_ci
958e5c31af7Sopenharmony_ci					break;
959e5c31af7Sopenharmony_ci				}
960e5c31af7Sopenharmony_ci
961e5c31af7Sopenharmony_ci				/* Otherwise, each edge of the inner triangle is divided into <n>-2 segments,
962e5c31af7Sopenharmony_ci				 * with the <n>-1 vertices of this subdivision produced by intersecting the
963e5c31af7Sopenharmony_ci				 * inner edge with lines perpendicular to the edge running through the <n>-1
964e5c31af7Sopenharmony_ci				 * innermost vertices of the subdivision of the outer edge.
965e5c31af7Sopenharmony_ci				 */
966e5c31af7Sopenharmony_ci				if (n >= 2)
967e5c31af7Sopenharmony_ci				{
968e5c31af7Sopenharmony_ci					n_expected_vertices += (n - 2) * 3 /* triangle edges */;
969e5c31af7Sopenharmony_ci				}
970e5c31af7Sopenharmony_ci				else
971e5c31af7Sopenharmony_ci				{
972e5c31af7Sopenharmony_ci					/* Count in the degenerate point instead */
973e5c31af7Sopenharmony_ci					n_expected_vertices++;
974e5c31af7Sopenharmony_ci				}
975e5c31af7Sopenharmony_ci			} /* for (all inner triangles) */
976e5c31af7Sopenharmony_ci		}
977e5c31af7Sopenharmony_ci
978e5c31af7Sopenharmony_ci		break;
979e5c31af7Sopenharmony_ci	}
980e5c31af7Sopenharmony_ci
981e5c31af7Sopenharmony_ci	default:
982e5c31af7Sopenharmony_ci	{
983e5c31af7Sopenharmony_ci		TCU_FAIL("Unrecognized primitive mode");
984e5c31af7Sopenharmony_ci	}
985e5c31af7Sopenharmony_ci	} /* switch (test.primitive_mode) */
986e5c31af7Sopenharmony_ci
987e5c31af7Sopenharmony_ci	/* Compare two values */
988e5c31af7Sopenharmony_ci	if (run_n_vertices != n_expected_vertices)
989e5c31af7Sopenharmony_ci	{
990e5c31af7Sopenharmony_ci		std::string primitive_mode = TessellationShaderUtils::getESTokenForPrimitiveMode(run.primitive_mode);
991e5c31af7Sopenharmony_ci		std::string vertex_spacing = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
992e5c31af7Sopenharmony_ci
993e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << run_n_vertices
994e5c31af7Sopenharmony_ci						   << " vertices were generated by the tessellator instead of expected " << n_expected_vertices
995e5c31af7Sopenharmony_ci						   << " for primitive mode [" << primitive_mode << "], vertex spacing mode [" << vertex_spacing
996e5c31af7Sopenharmony_ci						   << "], inner tessellation levels:[" << run.inner[0] << ", " << run.inner[1]
997e5c31af7Sopenharmony_ci						   << "], outer tessellation levels:[" << run.outer[0] << ", " << run.outer[1] << ", "
998e5c31af7Sopenharmony_ci						   << run.outer[2] << ", " << run.outer[3] << "], point mode enabled."
999e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
1000e5c31af7Sopenharmony_ci
1001e5c31af7Sopenharmony_ci		TCU_FAIL("Amount of vertices generated in point mode was incorrect");
1002e5c31af7Sopenharmony_ci	} /* if (test.n_vertices != n_expected_vertices) */
1003e5c31af7Sopenharmony_ci}
1004e5c31af7Sopenharmony_ci
1005e5c31af7Sopenharmony_ci/** Verifies a valid amount of duplicate vertices is present in the set of coordinates
1006e5c31af7Sopenharmony_ci *  generated by the tessellator, as described by user-provided test iteration descriptor.
1007e5c31af7Sopenharmony_ci *  Throws a TestError exception if the vertex set does not meet the requirements.
1008e5c31af7Sopenharmony_ci *
1009e5c31af7Sopenharmony_ci *  @param test           Test iteration descriptor.
1010e5c31af7Sopenharmony_ci *  @param run_data       Data generated for the run.
1011e5c31af7Sopenharmony_ci *  @param run_n_vertices Amount of vertices present at @param run_data.
1012e5c31af7Sopenharmony_ci **/
1013e5c31af7Sopenharmony_civoid TessellationShaderPointsVerification::verifyCorrectAmountOfDuplicateVertices(const _run& run, const void* run_data,
1014e5c31af7Sopenharmony_ci																				  unsigned int run_n_vertices)
1015e5c31af7Sopenharmony_ci{
1016e5c31af7Sopenharmony_ci	const float  epsilon			  = 1e-5f;
1017e5c31af7Sopenharmony_ci	unsigned int n_duplicate_vertices = 0;
1018e5c31af7Sopenharmony_ci
1019e5c31af7Sopenharmony_ci	for (unsigned int n_vertex_a = 0; n_vertex_a < run_n_vertices; ++n_vertex_a)
1020e5c31af7Sopenharmony_ci	{
1021e5c31af7Sopenharmony_ci		const float* vertex_a = (const float*)run_data + n_vertex_a * 3; /* components */
1022e5c31af7Sopenharmony_ci
1023e5c31af7Sopenharmony_ci		for (unsigned int n_vertex_b = n_vertex_a + 1; n_vertex_b < run_n_vertices; ++n_vertex_b)
1024e5c31af7Sopenharmony_ci		{
1025e5c31af7Sopenharmony_ci			const float* vertex_b = (const float*)run_data + n_vertex_b * 3; /* components */
1026e5c31af7Sopenharmony_ci
1027e5c31af7Sopenharmony_ci			if (de::abs(vertex_a[0] - vertex_b[0]) < epsilon && de::abs(vertex_a[1] - vertex_b[1]) < epsilon &&
1028e5c31af7Sopenharmony_ci				de::abs(vertex_a[2] - vertex_b[2]) < epsilon)
1029e5c31af7Sopenharmony_ci			{
1030e5c31af7Sopenharmony_ci				n_duplicate_vertices++;
1031e5c31af7Sopenharmony_ci			}
1032e5c31af7Sopenharmony_ci		} /* for (all vertices) */
1033e5c31af7Sopenharmony_ci	}	 /* for (all vertices) */
1034e5c31af7Sopenharmony_ci
1035e5c31af7Sopenharmony_ci	if (n_duplicate_vertices != 0)
1036e5c31af7Sopenharmony_ci	{
1037e5c31af7Sopenharmony_ci		std::string vertex_spacing = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
1038e5c31af7Sopenharmony_ci
1039e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Duplicate vertices found for the following tesselelation"
1040e5c31af7Sopenharmony_ci													   " configuration: tessellation level:"
1041e5c31af7Sopenharmony_ci													   "["
1042e5c31af7Sopenharmony_ci						   << run.inner[0] << ", " << run.inner[1] << "], "
1043e5c31af7Sopenharmony_ci																	  "outer tessellation level:"
1044e5c31af7Sopenharmony_ci																	  " ["
1045e5c31af7Sopenharmony_ci						   << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", " << run.outer[3]
1046e5c31af7Sopenharmony_ci						   << "], "
1047e5c31af7Sopenharmony_ci						   << "vertex spacing mode:[" << vertex_spacing.c_str() << "]" << tcu::TestLog::EndMessage;
1048e5c31af7Sopenharmony_ci
1049e5c31af7Sopenharmony_ci		TCU_FAIL("Duplicate vertex found");
1050e5c31af7Sopenharmony_ci	}
1051e5c31af7Sopenharmony_ci}
1052e5c31af7Sopenharmony_ci
1053e5c31af7Sopenharmony_ci} /* namespace glcts */
1054