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 "esextcTessellationShaderTriangles.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_ci/** Constructor
35e5c31af7Sopenharmony_ci *
36e5c31af7Sopenharmony_ci * @param context Test context
37e5c31af7Sopenharmony_ci **/
38e5c31af7Sopenharmony_ciTessellationShaderTrianglesTests::TessellationShaderTrianglesTests(glcts::Context&		context,
39e5c31af7Sopenharmony_ci																   const ExtParameters& extParams)
40e5c31af7Sopenharmony_ci	: TestCaseGroupBase(context, extParams, "tessellation_shader_triangles_tessellation",
41e5c31af7Sopenharmony_ci						"Verifies triangle tessellation functionality")
42e5c31af7Sopenharmony_ci{
43e5c31af7Sopenharmony_ci	/* No implementation needed */
44e5c31af7Sopenharmony_ci}
45e5c31af7Sopenharmony_ci
46e5c31af7Sopenharmony_ci/**
47e5c31af7Sopenharmony_ci * Initializes test groups for geometry shader tests
48e5c31af7Sopenharmony_ci **/
49e5c31af7Sopenharmony_civoid TessellationShaderTrianglesTests::init(void)
50e5c31af7Sopenharmony_ci{
51e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderTrianglesDegenerateTriangle(m_context, m_extParams));
52e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderTrianglesIdenticalTriangles(m_context, m_extParams));
53e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderTrianglesInnerTessellationLevelRounding(m_context, m_extParams));
54e5c31af7Sopenharmony_ci}
55e5c31af7Sopenharmony_ci
56e5c31af7Sopenharmony_ci/** Constructor
57e5c31af7Sopenharmony_ci *
58e5c31af7Sopenharmony_ci * @param context Test context
59e5c31af7Sopenharmony_ci **/
60e5c31af7Sopenharmony_ciTessellationShaderTrianglesDegenerateTriangle::TessellationShaderTrianglesDegenerateTriangle(
61e5c31af7Sopenharmony_ci	Context& context, const ExtParameters& extParams)
62e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, "degenerate_triangle",
63e5c31af7Sopenharmony_ci				   "Verifies a degenerate triangle is generated by tessellator "
64e5c31af7Sopenharmony_ci				   "under a specific configuration of inner/outer tessellation "
65e5c31af7Sopenharmony_ci				   "levels & vertex spacing modes.")
66e5c31af7Sopenharmony_ci	, m_bo_id(0)
67e5c31af7Sopenharmony_ci	, m_fs_id(0)
68e5c31af7Sopenharmony_ci	, m_tc_id(0)
69e5c31af7Sopenharmony_ci	, m_vs_id(0)
70e5c31af7Sopenharmony_ci	, m_vao_id(0)
71e5c31af7Sopenharmony_ci{
72e5c31af7Sopenharmony_ci	/* Left blank on purpose */
73e5c31af7Sopenharmony_ci}
74e5c31af7Sopenharmony_ci
75e5c31af7Sopenharmony_ci/** Deinitializes ES objects created for the test. */
76e5c31af7Sopenharmony_civoid TessellationShaderTrianglesDegenerateTriangle::deinit()
77e5c31af7Sopenharmony_ci{
78e5c31af7Sopenharmony_ci	/* Call base class' deinit() */
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	/* Deinitialize TF buffer object bindings */
89e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
90e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
91e5c31af7Sopenharmony_ci
92e5c31af7Sopenharmony_ci	/* Reset GL_PATCH_VERTICES_EXT value */
93e5c31af7Sopenharmony_ci	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
94e5c31af7Sopenharmony_ci
95e5c31af7Sopenharmony_ci	/* Unbind vertex array object */
96e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
97e5c31af7Sopenharmony_ci
98e5c31af7Sopenharmony_ci	/* Free all ES objects we allocated for the test */
99e5c31af7Sopenharmony_ci	if (m_bo_id != 0)
100e5c31af7Sopenharmony_ci	{
101e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_bo_id);
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci		m_bo_id = 0;
104e5c31af7Sopenharmony_ci	}
105e5c31af7Sopenharmony_ci
106e5c31af7Sopenharmony_ci	if (m_fs_id != 0)
107e5c31af7Sopenharmony_ci	{
108e5c31af7Sopenharmony_ci		gl.deleteShader(m_fs_id);
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_ci		m_fs_id = 0;
111e5c31af7Sopenharmony_ci	}
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci	if (m_tc_id != 0)
114e5c31af7Sopenharmony_ci	{
115e5c31af7Sopenharmony_ci		gl.deleteShader(m_tc_id);
116e5c31af7Sopenharmony_ci
117e5c31af7Sopenharmony_ci		m_tc_id = 0;
118e5c31af7Sopenharmony_ci	}
119e5c31af7Sopenharmony_ci
120e5c31af7Sopenharmony_ci	if (m_vs_id != 0)
121e5c31af7Sopenharmony_ci	{
122e5c31af7Sopenharmony_ci		gl.deleteShader(m_vs_id);
123e5c31af7Sopenharmony_ci
124e5c31af7Sopenharmony_ci		m_vs_id = 0;
125e5c31af7Sopenharmony_ci	}
126e5c31af7Sopenharmony_ci
127e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
128e5c31af7Sopenharmony_ci	{
129e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci		m_vao_id = 0;
132e5c31af7Sopenharmony_ci	}
133e5c31af7Sopenharmony_ci
134e5c31af7Sopenharmony_ci	/* Deinitialize all test descriptors */
135e5c31af7Sopenharmony_ci	for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
136e5c31af7Sopenharmony_ci	{
137e5c31af7Sopenharmony_ci		deinitTestDescriptor(*it);
138e5c31af7Sopenharmony_ci	}
139e5c31af7Sopenharmony_ci	m_tests.clear();
140e5c31af7Sopenharmony_ci}
141e5c31af7Sopenharmony_ci
142e5c31af7Sopenharmony_ci/** Deinitialize all test pass-specific ES objects.
143e5c31af7Sopenharmony_ci *
144e5c31af7Sopenharmony_ci *  @param test Descriptor of a test pass to deinitialize.
145e5c31af7Sopenharmony_ci **/
146e5c31af7Sopenharmony_civoid TessellationShaderTrianglesDegenerateTriangle::deinitTestDescriptor(_test_descriptor& test)
147e5c31af7Sopenharmony_ci{
148e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
149e5c31af7Sopenharmony_ci
150e5c31af7Sopenharmony_ci	if (test.po_id != 0)
151e5c31af7Sopenharmony_ci	{
152e5c31af7Sopenharmony_ci		gl.deleteProgram(test.po_id);
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci		test.po_id = 0;
155e5c31af7Sopenharmony_ci	}
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_ci	if (test.te_id != 0)
158e5c31af7Sopenharmony_ci	{
159e5c31af7Sopenharmony_ci		gl.deleteShader(test.te_id);
160e5c31af7Sopenharmony_ci
161e5c31af7Sopenharmony_ci		test.te_id = 0;
162e5c31af7Sopenharmony_ci	}
163e5c31af7Sopenharmony_ci}
164e5c31af7Sopenharmony_ci
165e5c31af7Sopenharmony_ci/** Initializes ES objects necessary to run the test. */
166e5c31af7Sopenharmony_civoid TessellationShaderTrianglesDegenerateTriangle::initTest()
167e5c31af7Sopenharmony_ci{
168e5c31af7Sopenharmony_ci	/* Skip if required extensions are not supported. */
169e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
170e5c31af7Sopenharmony_ci	{
171e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
172e5c31af7Sopenharmony_ci	}
173e5c31af7Sopenharmony_ci
174e5c31af7Sopenharmony_ci	/* Generate all test-wide objects needed for test execution */
175e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
176e5c31af7Sopenharmony_ci
177e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
178e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
179e5c31af7Sopenharmony_ci
180e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
181e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
182e5c31af7Sopenharmony_ci
183e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_bo_id);
184e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
185e5c31af7Sopenharmony_ci
186e5c31af7Sopenharmony_ci	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
187e5c31af7Sopenharmony_ci	m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
188e5c31af7Sopenharmony_ci	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
189e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
190e5c31af7Sopenharmony_ci
191e5c31af7Sopenharmony_ci	/* Configure fragment shader body */
192e5c31af7Sopenharmony_ci	const char* fs_body = "${VERSION}\n"
193e5c31af7Sopenharmony_ci						  "\n"
194e5c31af7Sopenharmony_ci						  "void main()\n"
195e5c31af7Sopenharmony_ci						  "{\n"
196e5c31af7Sopenharmony_ci						  "}\n";
197e5c31af7Sopenharmony_ci
198e5c31af7Sopenharmony_ci	shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
199e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
200e5c31af7Sopenharmony_ci
201e5c31af7Sopenharmony_ci	/* Configure tessellation control shader body */
202e5c31af7Sopenharmony_ci	const char* tc_body = "${VERSION}\n"
203e5c31af7Sopenharmony_ci						  "\n"
204e5c31af7Sopenharmony_ci						  "${TESSELLATION_SHADER_REQUIRE}\n"
205e5c31af7Sopenharmony_ci						  "\n"
206e5c31af7Sopenharmony_ci						  "layout (vertices=3) out;\n"
207e5c31af7Sopenharmony_ci						  "\n"
208e5c31af7Sopenharmony_ci						  "void main()\n"
209e5c31af7Sopenharmony_ci						  "{\n"
210e5c31af7Sopenharmony_ci						  "    gl_out [gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
211e5c31af7Sopenharmony_ci						  "\n"
212e5c31af7Sopenharmony_ci						  "    gl_TessLevelInner[0] = 1.0;\n"
213e5c31af7Sopenharmony_ci						  "    gl_TessLevelOuter[0] = 1.0;\n"
214e5c31af7Sopenharmony_ci						  "    gl_TessLevelOuter[1] = 1.0;\n"
215e5c31af7Sopenharmony_ci						  "    gl_TessLevelOuter[2] = 1.0;\n"
216e5c31af7Sopenharmony_ci						  "}\n";
217e5c31af7Sopenharmony_ci
218e5c31af7Sopenharmony_ci	shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body);
219e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
220e5c31af7Sopenharmony_ci
221e5c31af7Sopenharmony_ci	/* Configure vertex shader body */
222e5c31af7Sopenharmony_ci	const char* vs_body = "${VERSION}\n"
223e5c31af7Sopenharmony_ci						  "\n"
224e5c31af7Sopenharmony_ci						  "void main()\n"
225e5c31af7Sopenharmony_ci						  "{\n"
226e5c31af7Sopenharmony_ci						  "    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
227e5c31af7Sopenharmony_ci						  "}\n";
228e5c31af7Sopenharmony_ci
229e5c31af7Sopenharmony_ci	shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
230e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
231e5c31af7Sopenharmony_ci
232e5c31af7Sopenharmony_ci	/* Compile all the shaders */
233e5c31af7Sopenharmony_ci	const glw::GLuint  shaders[] = { m_fs_id, m_tc_id, m_vs_id };
234e5c31af7Sopenharmony_ci	const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
235e5c31af7Sopenharmony_ci
236e5c31af7Sopenharmony_ci	for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
237e5c31af7Sopenharmony_ci	{
238e5c31af7Sopenharmony_ci		glw::GLuint shader = shaders[n_shader];
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci		if (shader != 0)
241e5c31af7Sopenharmony_ci		{
242e5c31af7Sopenharmony_ci			glw::GLint compile_status = GL_FALSE;
243e5c31af7Sopenharmony_ci
244e5c31af7Sopenharmony_ci			gl.compileShader(shader);
245e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
246e5c31af7Sopenharmony_ci
247e5c31af7Sopenharmony_ci			gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
248e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
249e5c31af7Sopenharmony_ci
250e5c31af7Sopenharmony_ci			if (compile_status != GL_TRUE)
251e5c31af7Sopenharmony_ci			{
252e5c31af7Sopenharmony_ci				TCU_FAIL("Shader compilation failed");
253e5c31af7Sopenharmony_ci			}
254e5c31af7Sopenharmony_ci		}
255e5c31af7Sopenharmony_ci	} /* for (all shaders) */
256e5c31af7Sopenharmony_ci
257e5c31af7Sopenharmony_ci	/* Initialize all test passes */
258e5c31af7Sopenharmony_ci	_test_descriptor test_equal_spacing;
259e5c31af7Sopenharmony_ci	_test_descriptor test_fractional_odd_spacing;
260e5c31af7Sopenharmony_ci
261e5c31af7Sopenharmony_ci	initTestDescriptor(test_equal_spacing, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
262e5c31af7Sopenharmony_ci	initTestDescriptor(test_fractional_odd_spacing, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci	m_tests.push_back(test_equal_spacing);
265e5c31af7Sopenharmony_ci	m_tests.push_back(test_fractional_odd_spacing);
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_ci	/* Set up buffer object storage */
268e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
269e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
270e5c31af7Sopenharmony_ci
271e5c31af7Sopenharmony_ci	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 3 /* components */ * 3 /* UVW sets */, NULL, /* data */
272e5c31af7Sopenharmony_ci				  GL_STATIC_DRAW);
273e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
274e5c31af7Sopenharmony_ci
275e5c31af7Sopenharmony_ci	/* Bind the buffer object to indiced TF binding point */
276e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
277e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
278e5c31af7Sopenharmony_ci}
279e5c31af7Sopenharmony_ci
280e5c31af7Sopenharmony_ci/** Initializes all ES objects necessary to run a specific test pass.
281e5c31af7Sopenharmony_ci *
282e5c31af7Sopenharmony_ci *  @param test           Test descriptor to fill with IDs of initialized objects.
283e5c31af7Sopenharmony_ci *  @param vertex_spacing Vertex spacing mode to use for the run.
284e5c31af7Sopenharmony_ci **/
285e5c31af7Sopenharmony_civoid TessellationShaderTrianglesDegenerateTriangle::initTestDescriptor(
286e5c31af7Sopenharmony_ci	_test_descriptor& test, _tessellation_shader_vertex_spacing vertex_spacing)
287e5c31af7Sopenharmony_ci{
288e5c31af7Sopenharmony_ci	test.vertex_spacing = vertex_spacing;
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci	/* Set up a program object for the descriptor */
291e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
292e5c31af7Sopenharmony_ci
293e5c31af7Sopenharmony_ci	test.po_id = gl.createProgram();
294e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
295e5c31af7Sopenharmony_ci
296e5c31af7Sopenharmony_ci	/* Set up a pass-specific tessellation evaluation shader object. */
297e5c31af7Sopenharmony_ci	test.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
298e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
299e5c31af7Sopenharmony_ci
300e5c31af7Sopenharmony_ci	/* Configure tessellation evaluation shader body */
301e5c31af7Sopenharmony_ci	const char* te_template = "${VERSION}\n"
302e5c31af7Sopenharmony_ci							  "\n"
303e5c31af7Sopenharmony_ci							  "${TESSELLATION_SHADER_REQUIRE}\n"
304e5c31af7Sopenharmony_ci							  "\n"
305e5c31af7Sopenharmony_ci							  "layout (triangles, VERTEX_SPACING_MODE) in;\n"
306e5c31af7Sopenharmony_ci							  "\n"
307e5c31af7Sopenharmony_ci							  "out vec3 result_uvw;\n"
308e5c31af7Sopenharmony_ci							  "\n"
309e5c31af7Sopenharmony_ci							  "void main()\n"
310e5c31af7Sopenharmony_ci							  "{\n"
311e5c31af7Sopenharmony_ci							  "    gl_Position = gl_in[0].gl_Position;\n"
312e5c31af7Sopenharmony_ci							  "    result_uvw  = gl_TessCoord;\n"
313e5c31af7Sopenharmony_ci							  "}\n";
314e5c31af7Sopenharmony_ci
315e5c31af7Sopenharmony_ci	const char* te_body_raw_ptr = DE_NULL;
316e5c31af7Sopenharmony_ci	std::string te_body_string  = te_template;
317e5c31af7Sopenharmony_ci	std::string vertex_spacing_mode_string;
318e5c31af7Sopenharmony_ci	const char* vertex_spacing_token	   = "VERTEX_SPACING_MODE";
319e5c31af7Sopenharmony_ci	std::size_t vertex_spacing_token_index = std::string::npos;
320e5c31af7Sopenharmony_ci
321e5c31af7Sopenharmony_ci	switch (vertex_spacing)
322e5c31af7Sopenharmony_ci	{
323e5c31af7Sopenharmony_ci	case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
324e5c31af7Sopenharmony_ci	{
325e5c31af7Sopenharmony_ci		vertex_spacing_mode_string = "equal_spacing";
326e5c31af7Sopenharmony_ci
327e5c31af7Sopenharmony_ci		break;
328e5c31af7Sopenharmony_ci	}
329e5c31af7Sopenharmony_ci
330e5c31af7Sopenharmony_ci	case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
331e5c31af7Sopenharmony_ci	{
332e5c31af7Sopenharmony_ci		vertex_spacing_mode_string = "fractional_odd_spacing";
333e5c31af7Sopenharmony_ci
334e5c31af7Sopenharmony_ci		break;
335e5c31af7Sopenharmony_ci	}
336e5c31af7Sopenharmony_ci
337e5c31af7Sopenharmony_ci	default:
338e5c31af7Sopenharmony_ci	{
339e5c31af7Sopenharmony_ci		TCU_FAIL("Invalid vertex spacing mode requested");
340e5c31af7Sopenharmony_ci	}
341e5c31af7Sopenharmony_ci	}
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_ci	while ((vertex_spacing_token_index = te_body_string.find(vertex_spacing_token)) != std::string::npos)
344e5c31af7Sopenharmony_ci	{
345e5c31af7Sopenharmony_ci		te_body_string = te_body_string.replace(vertex_spacing_token_index, strlen(vertex_spacing_token),
346e5c31af7Sopenharmony_ci												vertex_spacing_mode_string);
347e5c31af7Sopenharmony_ci
348e5c31af7Sopenharmony_ci		vertex_spacing_token_index = te_body_string.find(vertex_spacing_token);
349e5c31af7Sopenharmony_ci	}
350e5c31af7Sopenharmony_ci
351e5c31af7Sopenharmony_ci	te_body_raw_ptr = te_body_string.c_str();
352e5c31af7Sopenharmony_ci
353e5c31af7Sopenharmony_ci	shaderSourceSpecialized(test.te_id, 1 /* count */, &te_body_raw_ptr);
354e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
355e5c31af7Sopenharmony_ci
356e5c31af7Sopenharmony_ci	/* Compile the tessellation evaluation shader */
357e5c31af7Sopenharmony_ci	glw::GLint compile_status = GL_FALSE;
358e5c31af7Sopenharmony_ci
359e5c31af7Sopenharmony_ci	gl.compileShader(test.te_id);
360e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed for tessellation evaluation shader");
361e5c31af7Sopenharmony_ci
362e5c31af7Sopenharmony_ci	gl.getShaderiv(test.te_id, GL_COMPILE_STATUS, &compile_status);
363e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed for tessellation evaluation shader");
364e5c31af7Sopenharmony_ci
365e5c31af7Sopenharmony_ci	if (compile_status != GL_TRUE)
366e5c31af7Sopenharmony_ci	{
367e5c31af7Sopenharmony_ci		TCU_FAIL("Tessellation evaluation shader compilation failed");
368e5c31af7Sopenharmony_ci	}
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci	/* Attach all shader to the program object */
371e5c31af7Sopenharmony_ci	gl.attachShader(test.po_id, m_fs_id);
372e5c31af7Sopenharmony_ci	gl.attachShader(test.po_id, m_tc_id);
373e5c31af7Sopenharmony_ci	gl.attachShader(test.po_id, test.te_id);
374e5c31af7Sopenharmony_ci	gl.attachShader(test.po_id, m_vs_id);
375e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
376e5c31af7Sopenharmony_ci
377e5c31af7Sopenharmony_ci	/* Set up XFB */
378e5c31af7Sopenharmony_ci	const char*		   varyings[] = { "result_uvw" };
379e5c31af7Sopenharmony_ci	const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
380e5c31af7Sopenharmony_ci
381e5c31af7Sopenharmony_ci	gl.transformFeedbackVaryings(test.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
382e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
383e5c31af7Sopenharmony_ci
384e5c31af7Sopenharmony_ci	/* Link the program object */
385e5c31af7Sopenharmony_ci	glw::GLint link_status = GL_FALSE;
386e5c31af7Sopenharmony_ci
387e5c31af7Sopenharmony_ci	gl.linkProgram(test.po_id);
388e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
389e5c31af7Sopenharmony_ci
390e5c31af7Sopenharmony_ci	gl.getProgramiv(test.po_id, GL_LINK_STATUS, &link_status);
391e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
392e5c31af7Sopenharmony_ci
393e5c31af7Sopenharmony_ci	if (link_status != GL_TRUE)
394e5c31af7Sopenharmony_ci	{
395e5c31af7Sopenharmony_ci		TCU_FAIL("Program linking failed");
396e5c31af7Sopenharmony_ci	}
397e5c31af7Sopenharmony_ci}
398e5c31af7Sopenharmony_ci
399e5c31af7Sopenharmony_ci/** Executes the test.
400e5c31af7Sopenharmony_ci *
401e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
402e5c31af7Sopenharmony_ci *
403e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
404e5c31af7Sopenharmony_ci *
405e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
406e5c31af7Sopenharmony_ci **/
407e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderTrianglesDegenerateTriangle::iterate(void)
408e5c31af7Sopenharmony_ci{
409e5c31af7Sopenharmony_ci	/* Do not execute if required extensions are not supported. */
410e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
411e5c31af7Sopenharmony_ci	{
412e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
413e5c31af7Sopenharmony_ci	}
414e5c31af7Sopenharmony_ci
415e5c31af7Sopenharmony_ci	/* Initialize ES test objects */
416e5c31af7Sopenharmony_ci	initTest();
417e5c31af7Sopenharmony_ci
418e5c31af7Sopenharmony_ci	/* We only need to use one vertex per so go for it */
419e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
420e5c31af7Sopenharmony_ci
421e5c31af7Sopenharmony_ci	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
422e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
423e5c31af7Sopenharmony_ci
424e5c31af7Sopenharmony_ci	/* Iterate through all tests configured */
425e5c31af7Sopenharmony_ci	for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++)
426e5c31af7Sopenharmony_ci	{
427e5c31af7Sopenharmony_ci		const _test_descriptor& test = *test_iterator;
428e5c31af7Sopenharmony_ci
429e5c31af7Sopenharmony_ci		/* Run the iteration */
430e5c31af7Sopenharmony_ci		gl.useProgram(test.po_id);
431e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
432e5c31af7Sopenharmony_ci
433e5c31af7Sopenharmony_ci		/* Draw the test geometry */
434e5c31af7Sopenharmony_ci		gl.beginTransformFeedback(GL_TRIANGLES);
435e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_TRIANGLES) failed.");
436e5c31af7Sopenharmony_ci
437e5c31af7Sopenharmony_ci		gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
438e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
439e5c31af7Sopenharmony_ci
440e5c31af7Sopenharmony_ci		gl.endTransformFeedback();
441e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
442e5c31af7Sopenharmony_ci
443e5c31af7Sopenharmony_ci		/* Map the BO with result data into user space */
444e5c31af7Sopenharmony_ci		const float* triangle_vertex_data =
445e5c31af7Sopenharmony_ci			(const float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
446e5c31af7Sopenharmony_ci											sizeof(float) * 3 /* vec3 */ * 3 /* points */, GL_MAP_READ_BIT);
447e5c31af7Sopenharmony_ci
448e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
449e5c31af7Sopenharmony_ci
450e5c31af7Sopenharmony_ci		/* Make sure the triangle data is correct. Since we cannot rely on any specific order
451e5c31af7Sopenharmony_ci		 * of the result vertices, raise corresponding flag for each of the expected vertices.
452e5c31af7Sopenharmony_ci		 */
453e5c31af7Sopenharmony_ci		const float epsilon					 = 1e-5f;
454e5c31af7Sopenharmony_ci		bool		is_zero_zero_one_present = false;
455e5c31af7Sopenharmony_ci		bool		is_zero_one_zero_present = false;
456e5c31af7Sopenharmony_ci		bool		is_one_zero_zero_present = false;
457e5c31af7Sopenharmony_ci
458e5c31af7Sopenharmony_ci		for (unsigned int n_vertex = 0; n_vertex < 3 /* vertices */; ++n_vertex)
459e5c31af7Sopenharmony_ci		{
460e5c31af7Sopenharmony_ci			const float* triangle_ptr = triangle_vertex_data + 3 * n_vertex;
461e5c31af7Sopenharmony_ci
462e5c31af7Sopenharmony_ci			if (de::abs(triangle_ptr[0]) < epsilon && de::abs(triangle_ptr[1]) < epsilon &&
463e5c31af7Sopenharmony_ci				de::abs(triangle_ptr[2] - 1.0f) < epsilon)
464e5c31af7Sopenharmony_ci			{
465e5c31af7Sopenharmony_ci				if (!is_zero_zero_one_present)
466e5c31af7Sopenharmony_ci				{
467e5c31af7Sopenharmony_ci					is_zero_zero_one_present = true;
468e5c31af7Sopenharmony_ci				}
469e5c31af7Sopenharmony_ci				else
470e5c31af7Sopenharmony_ci				{
471e5c31af7Sopenharmony_ci					TCU_FAIL("(0, 0, 1) vertex outputted more than once");
472e5c31af7Sopenharmony_ci				}
473e5c31af7Sopenharmony_ci			}
474e5c31af7Sopenharmony_ci			else if (de::abs(triangle_ptr[0]) < epsilon && de::abs(triangle_ptr[1] - 1.0f) < epsilon &&
475e5c31af7Sopenharmony_ci					 de::abs(triangle_ptr[2]) < epsilon)
476e5c31af7Sopenharmony_ci			{
477e5c31af7Sopenharmony_ci				if (!is_zero_one_zero_present)
478e5c31af7Sopenharmony_ci				{
479e5c31af7Sopenharmony_ci					is_zero_one_zero_present = true;
480e5c31af7Sopenharmony_ci				}
481e5c31af7Sopenharmony_ci				else
482e5c31af7Sopenharmony_ci				{
483e5c31af7Sopenharmony_ci					TCU_FAIL("(0, 1, 0) vertex outputted more than once");
484e5c31af7Sopenharmony_ci				}
485e5c31af7Sopenharmony_ci			}
486e5c31af7Sopenharmony_ci			else if (de::abs(triangle_ptr[0] - 1.0f) < epsilon && de::abs(triangle_ptr[1]) < epsilon &&
487e5c31af7Sopenharmony_ci					 de::abs(triangle_ptr[2]) < epsilon)
488e5c31af7Sopenharmony_ci			{
489e5c31af7Sopenharmony_ci				if (!is_one_zero_zero_present)
490e5c31af7Sopenharmony_ci				{
491e5c31af7Sopenharmony_ci					is_one_zero_zero_present = true;
492e5c31af7Sopenharmony_ci				}
493e5c31af7Sopenharmony_ci				else
494e5c31af7Sopenharmony_ci				{
495e5c31af7Sopenharmony_ci					TCU_FAIL("(1, 0, 0) vertex outputted more than once");
496e5c31af7Sopenharmony_ci				}
497e5c31af7Sopenharmony_ci			}
498e5c31af7Sopenharmony_ci			else
499e5c31af7Sopenharmony_ci			{
500e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected vertex"
501e5c31af7Sopenharmony_ci								   << " (" << triangle_vertex_data[0] << ", " << triangle_vertex_data[1] << ", "
502e5c31af7Sopenharmony_ci								   << triangle_vertex_data[2] << ")"
503e5c31af7Sopenharmony_ci								   << " encountered for a degenerate triangle." << tcu::TestLog::EndMessage;
504e5c31af7Sopenharmony_ci
505e5c31af7Sopenharmony_ci				TCU_FAIL("Invalid vertex was generated by the tessellator");
506e5c31af7Sopenharmony_ci			}
507e5c31af7Sopenharmony_ci		} /* for (all vertices) */
508e5c31af7Sopenharmony_ci
509e5c31af7Sopenharmony_ci		/* Unmap the BO */
510e5c31af7Sopenharmony_ci		gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
511e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
512e5c31af7Sopenharmony_ci	}
513e5c31af7Sopenharmony_ci
514e5c31af7Sopenharmony_ci	/* All done */
515e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
516e5c31af7Sopenharmony_ci	return STOP;
517e5c31af7Sopenharmony_ci}
518e5c31af7Sopenharmony_ci
519e5c31af7Sopenharmony_ci/** Constructor
520e5c31af7Sopenharmony_ci *
521e5c31af7Sopenharmony_ci * @param context Test context
522e5c31af7Sopenharmony_ci **/
523e5c31af7Sopenharmony_ciTessellationShaderTrianglesIdenticalTriangles::TessellationShaderTrianglesIdenticalTriangles(
524e5c31af7Sopenharmony_ci	Context& context, const ExtParameters& extParams)
525e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, "identical_triangles",
526e5c31af7Sopenharmony_ci				   "Verifies that tessellation coordinates generated by the tessellator "
527e5c31af7Sopenharmony_ci				   "running in triangles mode do not change if second inner or fourth "
528e5c31af7Sopenharmony_ci				   "outer tessellation level is changed")
529e5c31af7Sopenharmony_ci	, m_vao_id(0)
530e5c31af7Sopenharmony_ci	, m_utils(DE_NULL)
531e5c31af7Sopenharmony_ci{
532e5c31af7Sopenharmony_ci	/* Left blank on purpose */
533e5c31af7Sopenharmony_ci}
534e5c31af7Sopenharmony_ci
535e5c31af7Sopenharmony_ci/** Deinitializes ES objects created for the test. */
536e5c31af7Sopenharmony_civoid TessellationShaderTrianglesIdenticalTriangles::deinit()
537e5c31af7Sopenharmony_ci{
538e5c31af7Sopenharmony_ci	/* Call base class' deinit() */
539e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
540e5c31af7Sopenharmony_ci
541e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
542e5c31af7Sopenharmony_ci	{
543e5c31af7Sopenharmony_ci		return;
544e5c31af7Sopenharmony_ci	}
545e5c31af7Sopenharmony_ci
546e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
547e5c31af7Sopenharmony_ci
548e5c31af7Sopenharmony_ci	/* Unbind vertex array object */
549e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
550e5c31af7Sopenharmony_ci
551e5c31af7Sopenharmony_ci	/* Deallocate test variables */
552e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
553e5c31af7Sopenharmony_ci	{
554e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
555e5c31af7Sopenharmony_ci
556e5c31af7Sopenharmony_ci		m_vao_id = 0;
557e5c31af7Sopenharmony_ci	}
558e5c31af7Sopenharmony_ci
559e5c31af7Sopenharmony_ci	/* Deinitialize utils instance */
560e5c31af7Sopenharmony_ci	if (m_utils != DE_NULL)
561e5c31af7Sopenharmony_ci	{
562e5c31af7Sopenharmony_ci		delete m_utils;
563e5c31af7Sopenharmony_ci
564e5c31af7Sopenharmony_ci		m_utils = DE_NULL;
565e5c31af7Sopenharmony_ci	}
566e5c31af7Sopenharmony_ci}
567e5c31af7Sopenharmony_ci
568e5c31af7Sopenharmony_ci/** Initializes ES objects necessary to run the test. */
569e5c31af7Sopenharmony_civoid TessellationShaderTrianglesIdenticalTriangles::initTest()
570e5c31af7Sopenharmony_ci{
571e5c31af7Sopenharmony_ci	/* Skip if required extensions are not supported. */
572e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
573e5c31af7Sopenharmony_ci	{
574e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
575e5c31af7Sopenharmony_ci	}
576e5c31af7Sopenharmony_ci
577e5c31af7Sopenharmony_ci	/* Initialize Utils instance */
578e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
579e5c31af7Sopenharmony_ci
580e5c31af7Sopenharmony_ci	m_utils = new TessellationShaderUtils(gl, this);
581e5c31af7Sopenharmony_ci
582e5c31af7Sopenharmony_ci	/* Initialize vertex array object */
583e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
584e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
585e5c31af7Sopenharmony_ci
586e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
587e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
588e5c31af7Sopenharmony_ci
589e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
590e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_gen_level_value = 0;
591e5c31af7Sopenharmony_ci
592e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
593e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
594e5c31af7Sopenharmony_ci
595e5c31af7Sopenharmony_ci	/* Initialize all test runs */
596e5c31af7Sopenharmony_ci	_tessellation_level_set_filter filter =
597e5c31af7Sopenharmony_ci		(_tessellation_level_set_filter)((int)TESSELLATION_LEVEL_SET_FILTER_ALL_COMBINATIONS |
598e5c31af7Sopenharmony_ci										 (int)TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE);
599e5c31af7Sopenharmony_ci
600e5c31af7Sopenharmony_ci	_tessellation_levels_set levels_sets = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
601e5c31af7Sopenharmony_ci		TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, gl_max_tess_gen_level_value, filter);
602e5c31af7Sopenharmony_ci
603e5c31af7Sopenharmony_ci	for (_tessellation_levels_set_const_iterator set_iterator = levels_sets.begin(); set_iterator != levels_sets.end();
604e5c31af7Sopenharmony_ci		 set_iterator++)
605e5c31af7Sopenharmony_ci	{
606e5c31af7Sopenharmony_ci		_run						run;
607e5c31af7Sopenharmony_ci		const _tessellation_levels& set = *set_iterator;
608e5c31af7Sopenharmony_ci
609e5c31af7Sopenharmony_ci		memcpy(run.base_inner, set.inner, sizeof(run.base_inner));
610e5c31af7Sopenharmony_ci		memcpy(run.base_outer, set.outer, sizeof(run.base_outer));
611e5c31af7Sopenharmony_ci
612e5c31af7Sopenharmony_ci		run.reference_inner[0] = run.base_inner[0];
613e5c31af7Sopenharmony_ci		run.reference_inner[1] = run.base_inner[1] * 0.25f;
614e5c31af7Sopenharmony_ci
615e5c31af7Sopenharmony_ci		run.reference_outer[0] = run.base_outer[0];
616e5c31af7Sopenharmony_ci		run.reference_outer[1] = run.base_outer[1];
617e5c31af7Sopenharmony_ci		run.reference_outer[2] = run.base_outer[2];
618e5c31af7Sopenharmony_ci		run.reference_outer[3] = run.base_outer[3] * 0.25f;
619e5c31af7Sopenharmony_ci
620e5c31af7Sopenharmony_ci		/* Retrieve vertex data for both passes */
621e5c31af7Sopenharmony_ci		glw::GLint n_base_vertices		= 0;
622e5c31af7Sopenharmony_ci		glw::GLint n_reference_vertices = 0;
623e5c31af7Sopenharmony_ci
624e5c31af7Sopenharmony_ci		n_base_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
625e5c31af7Sopenharmony_ci			TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.base_inner, run.base_outer,
626e5c31af7Sopenharmony_ci			TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, false);
627e5c31af7Sopenharmony_ci		n_reference_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
628e5c31af7Sopenharmony_ci			TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.reference_inner, run.reference_outer,
629e5c31af7Sopenharmony_ci			TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, false); /* is_point_mode_enabled */
630e5c31af7Sopenharmony_ci
631e5c31af7Sopenharmony_ci		if (n_base_vertices == 0)
632e5c31af7Sopenharmony_ci		{
633e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: "
634e5c31af7Sopenharmony_ci														   "inner tess levels:"
635e5c31af7Sopenharmony_ci														   "["
636e5c31af7Sopenharmony_ci							   << run.base_inner[0] << ", " << run.base_inner[1] << "]"
637e5c31af7Sopenharmony_ci																					", outer tess levels:"
638e5c31af7Sopenharmony_ci																					"["
639e5c31af7Sopenharmony_ci							   << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", "
640e5c31af7Sopenharmony_ci							   << run.base_outer[3] << "]"
641e5c31af7Sopenharmony_ci													   ", primitive mode: triangles, vertex spacing: equal."
642e5c31af7Sopenharmony_ci							   << tcu::TestLog::EndMessage;
643e5c31af7Sopenharmony_ci
644e5c31af7Sopenharmony_ci			TCU_FAIL("Zero vertices were generated by tessellator for base test pass");
645e5c31af7Sopenharmony_ci		}
646e5c31af7Sopenharmony_ci
647e5c31af7Sopenharmony_ci		if (n_reference_vertices == 0)
648e5c31af7Sopenharmony_ci		{
649e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: "
650e5c31af7Sopenharmony_ci														   "inner tess levels:"
651e5c31af7Sopenharmony_ci														   "["
652e5c31af7Sopenharmony_ci							   << run.reference_inner[0] << ", " << run.reference_inner[1] << "]"
653e5c31af7Sopenharmony_ci																							  ", outer tess levels:"
654e5c31af7Sopenharmony_ci																							  "["
655e5c31af7Sopenharmony_ci							   << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
656e5c31af7Sopenharmony_ci							   << run.reference_outer[2] << ", " << run.reference_outer[3]
657e5c31af7Sopenharmony_ci							   << "]"
658e5c31af7Sopenharmony_ci								  ", primitive mode: triangles, vertex spacing: equal."
659e5c31af7Sopenharmony_ci							   << tcu::TestLog::EndMessage;
660e5c31af7Sopenharmony_ci
661e5c31af7Sopenharmony_ci			TCU_FAIL("Zero vertices were generated by tessellator for reference test pass");
662e5c31af7Sopenharmony_ci		}
663e5c31af7Sopenharmony_ci
664e5c31af7Sopenharmony_ci		if (n_base_vertices != n_reference_vertices)
665e5c31af7Sopenharmony_ci		{
666e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "Amount of vertices generated by the tessellator differs"
667e5c31af7Sopenharmony_ci														   " for the following inner/outer configs: "
668e5c31af7Sopenharmony_ci														   "inner tess levels:"
669e5c31af7Sopenharmony_ci														   "["
670e5c31af7Sopenharmony_ci							   << run.base_inner[0] << ", " << run.base_inner[1] << "]"
671e5c31af7Sopenharmony_ci																					", outer tess levels:"
672e5c31af7Sopenharmony_ci																					"["
673e5c31af7Sopenharmony_ci							   << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", "
674e5c31af7Sopenharmony_ci							   << run.base_outer[3] << "]"
675e5c31af7Sopenharmony_ci													   " and inner tess levels:"
676e5c31af7Sopenharmony_ci													   "["
677e5c31af7Sopenharmony_ci							   << run.reference_inner[0] << ", " << run.reference_inner[1] << "]"
678e5c31af7Sopenharmony_ci																							  ", outer tess levels:"
679e5c31af7Sopenharmony_ci																							  "["
680e5c31af7Sopenharmony_ci							   << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
681e5c31af7Sopenharmony_ci							   << run.reference_outer[2] << ", " << run.reference_outer[3]
682e5c31af7Sopenharmony_ci							   << "]"
683e5c31af7Sopenharmony_ci								  ", primitive mode: triangles, vertex spacing: equal."
684e5c31af7Sopenharmony_ci							   << tcu::TestLog::EndMessage;
685e5c31af7Sopenharmony_ci
686e5c31af7Sopenharmony_ci			TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes");
687e5c31af7Sopenharmony_ci		}
688e5c31af7Sopenharmony_ci
689e5c31af7Sopenharmony_ci		run.n_vertices = n_base_vertices;
690e5c31af7Sopenharmony_ci
691e5c31af7Sopenharmony_ci		run.base_data = m_utils->getDataGeneratedByTessellator(
692e5c31af7Sopenharmony_ci			run.base_inner, false, /* is_point_mode_enabled */
693e5c31af7Sopenharmony_ci			TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
694e5c31af7Sopenharmony_ci			TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.base_outer);
695e5c31af7Sopenharmony_ci		run.reference_data = m_utils->getDataGeneratedByTessellator(
696e5c31af7Sopenharmony_ci			run.reference_inner, false, /* is_point_mode_enabled */
697e5c31af7Sopenharmony_ci			TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
698e5c31af7Sopenharmony_ci			TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.reference_outer);
699e5c31af7Sopenharmony_ci
700e5c31af7Sopenharmony_ci		/* Store the run data */
701e5c31af7Sopenharmony_ci		m_runs.push_back(run);
702e5c31af7Sopenharmony_ci	} /* for (all sets) */
703e5c31af7Sopenharmony_ci}
704e5c31af7Sopenharmony_ci
705e5c31af7Sopenharmony_ci/** Executes the test.
706e5c31af7Sopenharmony_ci *
707e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
708e5c31af7Sopenharmony_ci *
709e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
710e5c31af7Sopenharmony_ci *
711e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
712e5c31af7Sopenharmony_ci **/
713e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderTrianglesIdenticalTriangles::iterate(void)
714e5c31af7Sopenharmony_ci{
715e5c31af7Sopenharmony_ci	/* Do not execute if required extensions are not supported. */
716e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
717e5c31af7Sopenharmony_ci	{
718e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
719e5c31af7Sopenharmony_ci	}
720e5c31af7Sopenharmony_ci
721e5c31af7Sopenharmony_ci	/* Initialize the test */
722e5c31af7Sopenharmony_ci	initTest();
723e5c31af7Sopenharmony_ci
724e5c31af7Sopenharmony_ci	/* Iterate through all runs */
725e5c31af7Sopenharmony_ci
726e5c31af7Sopenharmony_ci	for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
727e5c31af7Sopenharmony_ci	{
728e5c31af7Sopenharmony_ci		const _run& run = *run_iterator;
729e5c31af7Sopenharmony_ci
730e5c31af7Sopenharmony_ci		/* Make sure the vertex data generated for two passes matches */
731e5c31af7Sopenharmony_ci		const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */;
732e5c31af7Sopenharmony_ci
733e5c31af7Sopenharmony_ci		for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle)
734e5c31af7Sopenharmony_ci		{
735e5c31af7Sopenharmony_ci			const float* triangle_a = (const float*)(&run.base_data[0]) +
736e5c31af7Sopenharmony_ci									  n_triangle * 3 /* vertices */
737e5c31af7Sopenharmony_ci										  * 3;		 /* components */
738e5c31af7Sopenharmony_ci			const float* triangle_b = (const float*)(&run.reference_data[0]) +
739e5c31af7Sopenharmony_ci									  n_triangle * 3 /* vertices */
740e5c31af7Sopenharmony_ci										  * 3;		 /* components */
741e5c31af7Sopenharmony_ci
742e5c31af7Sopenharmony_ci			if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b))
743e5c31af7Sopenharmony_ci			{
744e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message
745e5c31af7Sopenharmony_ci								   << "The following triangle, generated in the first pass, was not "
746e5c31af7Sopenharmony_ci									  "generated in the other. "
747e5c31af7Sopenharmony_ci									  "First pass' configuration: inner tess levels:"
748e5c31af7Sopenharmony_ci									  "["
749e5c31af7Sopenharmony_ci								   << run.base_inner[0] << ", " << run.base_inner[1] << "]"
750e5c31af7Sopenharmony_ci																						", outer tess levels:"
751e5c31af7Sopenharmony_ci																						"["
752e5c31af7Sopenharmony_ci								   << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2]
753e5c31af7Sopenharmony_ci								   << ", " << run.base_outer[3] << "]"
754e5c31af7Sopenharmony_ci																   "; second pass' configuration: inner tess levels:"
755e5c31af7Sopenharmony_ci																   "["
756e5c31af7Sopenharmony_ci								   << run.reference_inner[0] << ", " << run.reference_inner[1] << "]"
757e5c31af7Sopenharmony_ci																								  ", outer tess levels:"
758e5c31af7Sopenharmony_ci																								  "["
759e5c31af7Sopenharmony_ci								   << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
760e5c31af7Sopenharmony_ci								   << run.reference_outer[2] << ", " << run.reference_outer[3]
761e5c31af7Sopenharmony_ci								   << "]"
762e5c31af7Sopenharmony_ci									  ", primitive mode: triangles, vertex spacing: equal."
763e5c31af7Sopenharmony_ci								   << tcu::TestLog::EndMessage;
764e5c31af7Sopenharmony_ci
765e5c31af7Sopenharmony_ci				TCU_FAIL("A triangle from base vertex data set was not found in reference vertex data set.");
766e5c31af7Sopenharmony_ci			}
767e5c31af7Sopenharmony_ci		} /* for (all vertices) */
768e5c31af7Sopenharmony_ci	}	 /* for (all runs) */
769e5c31af7Sopenharmony_ci
770e5c31af7Sopenharmony_ci	/* All done */
771e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
772e5c31af7Sopenharmony_ci	return STOP;
773e5c31af7Sopenharmony_ci}
774e5c31af7Sopenharmony_ci
775e5c31af7Sopenharmony_ci/** Constructor
776e5c31af7Sopenharmony_ci *
777e5c31af7Sopenharmony_ci * @param context Test context
778e5c31af7Sopenharmony_ci **/
779e5c31af7Sopenharmony_ciTessellationShaderTrianglesInnerTessellationLevelRounding::TessellationShaderTrianglesInnerTessellationLevelRounding(
780e5c31af7Sopenharmony_ci	Context& context, const ExtParameters& extParams)
781e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, "inner_tessellation_level_rounding",
782e5c31af7Sopenharmony_ci				   "Verifies that inner tessellation level is rounded to 1 or 2,"
783e5c31af7Sopenharmony_ci				   " when the tessellator is run in triangles primitive mode and "
784e5c31af7Sopenharmony_ci				   "inner tessellation level is set to 1 and any of the outer "
785e5c31af7Sopenharmony_ci				   "tessellation levels is greater than one.")
786e5c31af7Sopenharmony_ci	, m_vao_id(0)
787e5c31af7Sopenharmony_ci	, m_utils(DE_NULL)
788e5c31af7Sopenharmony_ci{
789e5c31af7Sopenharmony_ci	/* Left blank on purpose */
790e5c31af7Sopenharmony_ci}
791e5c31af7Sopenharmony_ci
792e5c31af7Sopenharmony_ci/** Deinitializes ES objects created for the test. */
793e5c31af7Sopenharmony_civoid TessellationShaderTrianglesInnerTessellationLevelRounding::deinit()
794e5c31af7Sopenharmony_ci{
795e5c31af7Sopenharmony_ci	/* Call base class' deinit() */
796e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
797e5c31af7Sopenharmony_ci
798e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
799e5c31af7Sopenharmony_ci	{
800e5c31af7Sopenharmony_ci		return;
801e5c31af7Sopenharmony_ci	}
802e5c31af7Sopenharmony_ci
803e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
804e5c31af7Sopenharmony_ci
805e5c31af7Sopenharmony_ci	/* Unbind vertex array object */
806e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
807e5c31af7Sopenharmony_ci
808e5c31af7Sopenharmony_ci	/* Deallocate test variables */
809e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
810e5c31af7Sopenharmony_ci	{
811e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
812e5c31af7Sopenharmony_ci
813e5c31af7Sopenharmony_ci		m_vao_id = 0;
814e5c31af7Sopenharmony_ci	}
815e5c31af7Sopenharmony_ci
816e5c31af7Sopenharmony_ci	/* Deinitialize utils instance */
817e5c31af7Sopenharmony_ci	if (m_utils != DE_NULL)
818e5c31af7Sopenharmony_ci	{
819e5c31af7Sopenharmony_ci		delete m_utils;
820e5c31af7Sopenharmony_ci
821e5c31af7Sopenharmony_ci		m_utils = DE_NULL;
822e5c31af7Sopenharmony_ci	}
823e5c31af7Sopenharmony_ci}
824e5c31af7Sopenharmony_ci
825e5c31af7Sopenharmony_ci/** Executes the test.
826e5c31af7Sopenharmony_ci *
827e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
828e5c31af7Sopenharmony_ci *
829e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
830e5c31af7Sopenharmony_ci *
831e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
832e5c31af7Sopenharmony_ci **/
833e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderTrianglesInnerTessellationLevelRounding::iterate(void)
834e5c31af7Sopenharmony_ci{
835e5c31af7Sopenharmony_ci	/* Do not execute if required extensions are not supported. */
836e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
837e5c31af7Sopenharmony_ci	{
838e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
839e5c31af7Sopenharmony_ci	}
840e5c31af7Sopenharmony_ci
841e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
842e5c31af7Sopenharmony_ci
843e5c31af7Sopenharmony_ci	/* Initialize vertex array object */
844e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
845e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
846e5c31af7Sopenharmony_ci
847e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
848e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
849e5c31af7Sopenharmony_ci
850e5c31af7Sopenharmony_ci	/* Initialize and run test iterations. In later part, we will verify the generated data. */
851e5c31af7Sopenharmony_ci	runTestIterations();
852e5c31af7Sopenharmony_ci
853e5c31af7Sopenharmony_ci	/* Iterate through all runs */
854e5c31af7Sopenharmony_ci
855e5c31af7Sopenharmony_ci	for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
856e5c31af7Sopenharmony_ci	{
857e5c31af7Sopenharmony_ci		const _run& run = *run_iterator;
858e5c31af7Sopenharmony_ci
859e5c31af7Sopenharmony_ci		if (run.vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD &&
860e5c31af7Sopenharmony_ci			de::abs(run.set1_inner[0] - run.set2_inner[0]) > 1e-5f &&
861e5c31af7Sopenharmony_ci			de::min(run.set1_inner[0], run.set2_inner[0]) >= 1.0f)
862e5c31af7Sopenharmony_ci		{
863e5c31af7Sopenharmony_ci			/* In fractional_odd_spacing mode with inner level <f> >= 1.0f, the clamped
864e5c31af7Sopenharmony_ci			 and rounded integer level <n> is at least 3.
865e5c31af7Sopenharmony_ci
866e5c31af7Sopenharmony_ci			 These results in inner subdivision into at least <n>-2=1 segment and
867e5c31af7Sopenharmony_ci			 two additional, typically shorter segments.
868e5c31af7Sopenharmony_ci
869e5c31af7Sopenharmony_ci			 The length of these two additional segments relative to the others will
870e5c31af7Sopenharmony_ci			 decrease monotonically with the value of <n>-<f>, so if different <f> levels
871e5c31af7Sopenharmony_ci			 were used, we cannot proceed with matching the exact vertex data. */
872e5c31af7Sopenharmony_ci
873e5c31af7Sopenharmony_ci			continue;
874e5c31af7Sopenharmony_ci		}
875e5c31af7Sopenharmony_ci
876e5c31af7Sopenharmony_ci		/* Make sure the vertex data generated for two passes matches */
877e5c31af7Sopenharmony_ci		const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */;
878e5c31af7Sopenharmony_ci
879e5c31af7Sopenharmony_ci		for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle)
880e5c31af7Sopenharmony_ci		{
881e5c31af7Sopenharmony_ci			const float* triangle_a = (const float*)(&run.set1_data[0]) +
882e5c31af7Sopenharmony_ci									  n_triangle * 3 /* vertices */
883e5c31af7Sopenharmony_ci										  * 3;		 /* components */
884e5c31af7Sopenharmony_ci			const float* triangle_b = (const float*)(&run.set2_data[0]) +
885e5c31af7Sopenharmony_ci									  n_triangle * 3 /* vertices */
886e5c31af7Sopenharmony_ci										  * 3;		 /* components */
887e5c31af7Sopenharmony_ci
888e5c31af7Sopenharmony_ci			if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b))
889e5c31af7Sopenharmony_ci			{
890e5c31af7Sopenharmony_ci				std::string vs_mode_string =
891e5c31af7Sopenharmony_ci					TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
892e5c31af7Sopenharmony_ci
893e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message
894e5c31af7Sopenharmony_ci								   << "The following triangle, generated in the first pass, was not "
895e5c31af7Sopenharmony_ci									  "generated in the second one. "
896e5c31af7Sopenharmony_ci									  "First pass' configuration: inner tess levels:"
897e5c31af7Sopenharmony_ci									  "["
898e5c31af7Sopenharmony_ci								   << run.set1_inner[0] << ", " << run.set1_inner[1] << "]"
899e5c31af7Sopenharmony_ci																						", outer tess levels:"
900e5c31af7Sopenharmony_ci																						"["
901e5c31af7Sopenharmony_ci								   << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
902e5c31af7Sopenharmony_ci								   << ", " << run.set1_outer[3] << "]"
903e5c31af7Sopenharmony_ci																   "; second pass' configuration: inner tess levels:"
904e5c31af7Sopenharmony_ci																   "["
905e5c31af7Sopenharmony_ci								   << run.set2_inner[0] << ", " << run.set2_inner[1] << "]"
906e5c31af7Sopenharmony_ci																						", outer tess levels:"
907e5c31af7Sopenharmony_ci																						"["
908e5c31af7Sopenharmony_ci								   << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
909e5c31af7Sopenharmony_ci								   << ", " << run.set2_outer[3] << "]"
910e5c31af7Sopenharmony_ci																   ", primitive mode: triangles, vertex spacing: "
911e5c31af7Sopenharmony_ci								   << vs_mode_string << tcu::TestLog::EndMessage;
912e5c31af7Sopenharmony_ci
913e5c31af7Sopenharmony_ci				TCU_FAIL("A triangle from first pass' data set was not found in second pass' data set.");
914e5c31af7Sopenharmony_ci			}
915e5c31af7Sopenharmony_ci		} /* for (all vertices) */
916e5c31af7Sopenharmony_ci	}	 /* for (all runs) */
917e5c31af7Sopenharmony_ci
918e5c31af7Sopenharmony_ci	/* All done */
919e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
920e5c31af7Sopenharmony_ci	return STOP;
921e5c31af7Sopenharmony_ci}
922e5c31af7Sopenharmony_ci
923e5c31af7Sopenharmony_ci/** Runs all test iterations needed to generate data for later verification. */
924e5c31af7Sopenharmony_civoid TessellationShaderTrianglesInnerTessellationLevelRounding::runTestIterations()
925e5c31af7Sopenharmony_ci{
926e5c31af7Sopenharmony_ci	/* Skip if required extensions are not supported. */
927e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
928e5c31af7Sopenharmony_ci	{
929e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
930e5c31af7Sopenharmony_ci	}
931e5c31af7Sopenharmony_ci
932e5c31af7Sopenharmony_ci	/* Initialize Utils instance */
933e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
934e5c31af7Sopenharmony_ci
935e5c31af7Sopenharmony_ci	m_utils = new TessellationShaderUtils(gl, this);
936e5c31af7Sopenharmony_ci
937e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
938e5c31af7Sopenharmony_ci	glw::GLint gl_max_tess_gen_level_value = 0;
939e5c31af7Sopenharmony_ci
940e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
941e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
942e5c31af7Sopenharmony_ci
943e5c31af7Sopenharmony_ci	/* Initialize all test runs */
944e5c31af7Sopenharmony_ci	const glw::GLint   tess_levels[] = { 2, gl_max_tess_gen_level_value / 2, gl_max_tess_gen_level_value };
945e5c31af7Sopenharmony_ci	const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]);
946e5c31af7Sopenharmony_ci
947e5c31af7Sopenharmony_ci	const _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
948e5c31af7Sopenharmony_ci															 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
949e5c31af7Sopenharmony_ci															 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD };
950e5c31af7Sopenharmony_ci	const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
951e5c31af7Sopenharmony_ci
952e5c31af7Sopenharmony_ci	for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
953e5c31af7Sopenharmony_ci	{
954e5c31af7Sopenharmony_ci		_tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
955e5c31af7Sopenharmony_ci
956e5c31af7Sopenharmony_ci		for (unsigned int n_tess_level = 0; n_tess_level < n_tess_levels; ++n_tess_level)
957e5c31af7Sopenharmony_ci		{
958e5c31af7Sopenharmony_ci			/* Set up the run descriptor */
959e5c31af7Sopenharmony_ci			glw::GLint tess_level = tess_levels[n_tess_level];
960e5c31af7Sopenharmony_ci			_run	   run;
961e5c31af7Sopenharmony_ci
962e5c31af7Sopenharmony_ci			run.set1_inner[0] = 1.0f;
963e5c31af7Sopenharmony_ci			run.set1_inner[1] = 0.0f;
964e5c31af7Sopenharmony_ci			run.set2_inner[1] = 0.0f;
965e5c31af7Sopenharmony_ci
966e5c31af7Sopenharmony_ci			TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(vs_mode, 1.5f, gl_max_tess_gen_level_value,
967e5c31af7Sopenharmony_ci																			DE_NULL, /* out_clamped */
968e5c31af7Sopenharmony_ci																			run.set2_inner);
969e5c31af7Sopenharmony_ci			run.set1_outer[0] = (glw::GLfloat)tess_level;
970e5c31af7Sopenharmony_ci			run.set2_outer[0] = (glw::GLfloat)tess_level;
971e5c31af7Sopenharmony_ci			run.set1_outer[1] = (glw::GLfloat)tess_level;
972e5c31af7Sopenharmony_ci			run.set2_outer[1] = (glw::GLfloat)tess_level;
973e5c31af7Sopenharmony_ci			run.set1_outer[2] = (glw::GLfloat)tess_level;
974e5c31af7Sopenharmony_ci			run.set2_outer[2] = (glw::GLfloat)tess_level;
975e5c31af7Sopenharmony_ci			run.set1_outer[3] = (glw::GLfloat)tess_level;
976e5c31af7Sopenharmony_ci			run.set2_outer[3] = (glw::GLfloat)tess_level;
977e5c31af7Sopenharmony_ci
978e5c31af7Sopenharmony_ci			run.vertex_spacing = vs_mode;
979e5c31af7Sopenharmony_ci
980e5c31af7Sopenharmony_ci			/* Retrieve vertex data for both passes */
981e5c31af7Sopenharmony_ci			glw::GLint n_set1_vertices = 0;
982e5c31af7Sopenharmony_ci			glw::GLint n_set2_vertices = 0;
983e5c31af7Sopenharmony_ci
984e5c31af7Sopenharmony_ci			n_set1_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
985e5c31af7Sopenharmony_ci				TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set1_inner, run.set1_outer, run.vertex_spacing,
986e5c31af7Sopenharmony_ci				false); /* is_point_mode_enabled */
987e5c31af7Sopenharmony_ci			n_set2_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
988e5c31af7Sopenharmony_ci				TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set2_inner, run.set2_outer, run.vertex_spacing,
989e5c31af7Sopenharmony_ci				false); /* is_point_mode_enabled */
990e5c31af7Sopenharmony_ci
991e5c31af7Sopenharmony_ci			if (n_set1_vertices == 0)
992e5c31af7Sopenharmony_ci			{
993e5c31af7Sopenharmony_ci				std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
994e5c31af7Sopenharmony_ci
995e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: "
996e5c31af7Sopenharmony_ci															   "inner tess levels:"
997e5c31af7Sopenharmony_ci															   "["
998e5c31af7Sopenharmony_ci								   << run.set1_inner[0] << ", " << run.set1_inner[1] << "]"
999e5c31af7Sopenharmony_ci																						", outer tess levels:"
1000e5c31af7Sopenharmony_ci																						"["
1001e5c31af7Sopenharmony_ci								   << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
1002e5c31af7Sopenharmony_ci								   << ", " << run.set1_outer[3] << "]"
1003e5c31af7Sopenharmony_ci																   ", primitive mode: triangles, "
1004e5c31af7Sopenharmony_ci																   "vertex spacing: "
1005e5c31af7Sopenharmony_ci								   << vs_mode_string << tcu::TestLog::EndMessage;
1006e5c31af7Sopenharmony_ci
1007e5c31af7Sopenharmony_ci				TCU_FAIL("Zero vertices were generated by tessellator for first test pass");
1008e5c31af7Sopenharmony_ci			}
1009e5c31af7Sopenharmony_ci
1010e5c31af7Sopenharmony_ci			if (n_set2_vertices == 0)
1011e5c31af7Sopenharmony_ci			{
1012e5c31af7Sopenharmony_ci				std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1013e5c31af7Sopenharmony_ci
1014e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: "
1015e5c31af7Sopenharmony_ci															   "inner tess levels:"
1016e5c31af7Sopenharmony_ci															   "["
1017e5c31af7Sopenharmony_ci								   << run.set2_inner[0] << ", " << run.set2_inner[1] << "]"
1018e5c31af7Sopenharmony_ci																						", outer tess levels:"
1019e5c31af7Sopenharmony_ci																						"["
1020e5c31af7Sopenharmony_ci								   << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
1021e5c31af7Sopenharmony_ci								   << ", " << run.set2_outer[3] << "]"
1022e5c31af7Sopenharmony_ci																   ", primitive mode: triangles, "
1023e5c31af7Sopenharmony_ci																   "vertex spacing: "
1024e5c31af7Sopenharmony_ci								   << vs_mode_string << tcu::TestLog::EndMessage;
1025e5c31af7Sopenharmony_ci
1026e5c31af7Sopenharmony_ci				TCU_FAIL("Zero vertices were generated by tessellator for second test pass");
1027e5c31af7Sopenharmony_ci			}
1028e5c31af7Sopenharmony_ci
1029e5c31af7Sopenharmony_ci			if (n_set1_vertices != n_set2_vertices)
1030e5c31af7Sopenharmony_ci			{
1031e5c31af7Sopenharmony_ci				std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1032e5c31af7Sopenharmony_ci
1033e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Amount of vertices generated by the tessellator differs"
1034e5c31af7Sopenharmony_ci															   " for the following inner/outer configs: "
1035e5c31af7Sopenharmony_ci															   "inner tess levels:"
1036e5c31af7Sopenharmony_ci															   "["
1037e5c31af7Sopenharmony_ci								   << run.set1_inner[0] << ", " << run.set1_inner[1] << "]"
1038e5c31af7Sopenharmony_ci																						", outer tess levels:"
1039e5c31af7Sopenharmony_ci																						"["
1040e5c31af7Sopenharmony_ci								   << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
1041e5c31af7Sopenharmony_ci								   << ", " << run.set1_outer[3] << "]"
1042e5c31af7Sopenharmony_ci																   " and inner tess levels:"
1043e5c31af7Sopenharmony_ci																   "["
1044e5c31af7Sopenharmony_ci								   << run.set2_inner[0] << ", " << run.set2_inner[1] << "]"
1045e5c31af7Sopenharmony_ci																						", outer tess levels:"
1046e5c31af7Sopenharmony_ci																						"["
1047e5c31af7Sopenharmony_ci								   << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
1048e5c31af7Sopenharmony_ci								   << ", " << run.set2_outer[3] << "]"
1049e5c31af7Sopenharmony_ci																   ", primitive mode: triangles, vertex spacing: "
1050e5c31af7Sopenharmony_ci								   << vs_mode_string << tcu::TestLog::EndMessage;
1051e5c31af7Sopenharmony_ci
1052e5c31af7Sopenharmony_ci				TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes");
1053e5c31af7Sopenharmony_ci			}
1054e5c31af7Sopenharmony_ci
1055e5c31af7Sopenharmony_ci			run.n_vertices = n_set1_vertices;
1056e5c31af7Sopenharmony_ci
1057e5c31af7Sopenharmony_ci			run.set1_data = m_utils->getDataGeneratedByTessellator(run.set1_inner, false, /* is_point_mode_enabled */
1058e5c31af7Sopenharmony_ci																   TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
1059e5c31af7Sopenharmony_ci																   TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1060e5c31af7Sopenharmony_ci																   run.vertex_spacing, run.set1_outer);
1061e5c31af7Sopenharmony_ci			run.set2_data = m_utils->getDataGeneratedByTessellator(run.set2_inner, false, /* is_point_mode_enabled */
1062e5c31af7Sopenharmony_ci																   TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
1063e5c31af7Sopenharmony_ci																   TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1064e5c31af7Sopenharmony_ci																   run.vertex_spacing, run.set2_outer);
1065e5c31af7Sopenharmony_ci
1066e5c31af7Sopenharmony_ci			/* Store the run data */
1067e5c31af7Sopenharmony_ci			m_runs.push_back(run);
1068e5c31af7Sopenharmony_ci		} /* for (all sets) */
1069e5c31af7Sopenharmony_ci	}	 /* for (all vertex spacing modes) */
1070e5c31af7Sopenharmony_ci}
1071e5c31af7Sopenharmony_ci
1072e5c31af7Sopenharmony_ci} /* namespace glcts */
1073