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 "esextcTessellationShaderInvariance.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/* Defines a single vertex in tessellation space */
35e5c31af7Sopenharmony_citypedef struct _vertex
36e5c31af7Sopenharmony_ci{
37e5c31af7Sopenharmony_ci	float u;
38e5c31af7Sopenharmony_ci	float v;
39e5c31af7Sopenharmony_ci	float w;
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_ci	_vertex()
42e5c31af7Sopenharmony_ci	{
43e5c31af7Sopenharmony_ci		u = 0.0f;
44e5c31af7Sopenharmony_ci		v = 0.0f;
45e5c31af7Sopenharmony_ci		w = 0.0f;
46e5c31af7Sopenharmony_ci	}
47e5c31af7Sopenharmony_ci} _vertex;
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_ci/** Constructor
50e5c31af7Sopenharmony_ci *
51e5c31af7Sopenharmony_ci * @param context Test context
52e5c31af7Sopenharmony_ci **/
53e5c31af7Sopenharmony_ciTessellationShaderInvarianceTests::TessellationShaderInvarianceTests(glcts::Context&	  context,
54e5c31af7Sopenharmony_ci																	 const ExtParameters& extParams)
55e5c31af7Sopenharmony_ci	: TestCaseGroupBase(context, extParams, "tessellation_invariance",
56e5c31af7Sopenharmony_ci						"Verifies the implementation conforms to invariance rules.")
57e5c31af7Sopenharmony_ci{
58e5c31af7Sopenharmony_ci	/* No implementation needed */
59e5c31af7Sopenharmony_ci}
60e5c31af7Sopenharmony_ci
61e5c31af7Sopenharmony_ci/**
62e5c31af7Sopenharmony_ci * Initializes test groups for geometry shader tests
63e5c31af7Sopenharmony_ci **/
64e5c31af7Sopenharmony_civoid TessellationShaderInvarianceTests::init(void)
65e5c31af7Sopenharmony_ci{
66e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderInvarianceRule1Test(m_context, m_extParams));
67e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderInvarianceRule2Test(m_context, m_extParams));
68e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderInvarianceRule3Test(m_context, m_extParams));
69e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderInvarianceRule4Test(m_context, m_extParams));
70e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderInvarianceRule5Test(m_context, m_extParams));
71e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderInvarianceRule6Test(m_context, m_extParams));
72e5c31af7Sopenharmony_ci	addChild(new glcts::TessellationShaderInvarianceRule7Test(m_context, m_extParams));
73e5c31af7Sopenharmony_ci}
74e5c31af7Sopenharmony_ci
75e5c31af7Sopenharmony_ci/** Constructor
76e5c31af7Sopenharmony_ci *
77e5c31af7Sopenharmony_ci * @param context     Test context
78e5c31af7Sopenharmony_ci * @param name        Test name
79e5c31af7Sopenharmony_ci * @param description Test description
80e5c31af7Sopenharmony_ci **/
81e5c31af7Sopenharmony_ciTessellationShaderInvarianceBaseTest::TessellationShaderInvarianceBaseTest(Context&				context,
82e5c31af7Sopenharmony_ci																		   const ExtParameters& extParams,
83e5c31af7Sopenharmony_ci																		   const char* name, const char* description)
84e5c31af7Sopenharmony_ci	: TestCaseBase(context, extParams, name, description)
85e5c31af7Sopenharmony_ci	, m_utils_ptr(DE_NULL)
86e5c31af7Sopenharmony_ci	, m_bo_id(0)
87e5c31af7Sopenharmony_ci	, m_qo_tfpw_id(0)
88e5c31af7Sopenharmony_ci	, m_vao_id(0)
89e5c31af7Sopenharmony_ci{
90e5c31af7Sopenharmony_ci	/* Left blank on purpose */
91e5c31af7Sopenharmony_ci}
92e5c31af7Sopenharmony_ci
93e5c31af7Sopenharmony_ci/** Deinitializes ES objects created for the test. */
94e5c31af7Sopenharmony_civoid TessellationShaderInvarianceBaseTest::deinit()
95e5c31af7Sopenharmony_ci{
96e5c31af7Sopenharmony_ci	/* Call base class' deinit() */
97e5c31af7Sopenharmony_ci	TestCaseBase::deinit();
98e5c31af7Sopenharmony_ci
99e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
100e5c31af7Sopenharmony_ci	{
101e5c31af7Sopenharmony_ci		return;
102e5c31af7Sopenharmony_ci	}
103e5c31af7Sopenharmony_ci
104e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
105e5c31af7Sopenharmony_ci
106e5c31af7Sopenharmony_ci	/* Revert buffer object bindings */
107e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
108e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_ci	/* Disable GL_RASTERIZER_DISCARD mode */
111e5c31af7Sopenharmony_ci	gl.disable(GL_RASTERIZER_DISCARD);
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci	/* Reset GL_PATCH_VERTICES_EXT to default value */
114e5c31af7Sopenharmony_ci	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
115e5c31af7Sopenharmony_ci
116e5c31af7Sopenharmony_ci	/* Unbind vertex array object */
117e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci	/* Deinitialize all ES objects that were created for test purposes */
120e5c31af7Sopenharmony_ci	if (m_bo_id != 0)
121e5c31af7Sopenharmony_ci	{
122e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_bo_id);
123e5c31af7Sopenharmony_ci
124e5c31af7Sopenharmony_ci		m_bo_id = 0;
125e5c31af7Sopenharmony_ci	}
126e5c31af7Sopenharmony_ci
127e5c31af7Sopenharmony_ci	for (_programs_iterator it = m_programs.begin(); it != m_programs.end(); ++it)
128e5c31af7Sopenharmony_ci	{
129e5c31af7Sopenharmony_ci		_test_program& program = *it;
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci		if (program.po_id != 0)
132e5c31af7Sopenharmony_ci		{
133e5c31af7Sopenharmony_ci			gl.deleteProgram(program.po_id);
134e5c31af7Sopenharmony_ci		}
135e5c31af7Sopenharmony_ci	}
136e5c31af7Sopenharmony_ci	m_programs.clear();
137e5c31af7Sopenharmony_ci
138e5c31af7Sopenharmony_ci	if (m_qo_tfpw_id != 0)
139e5c31af7Sopenharmony_ci	{
140e5c31af7Sopenharmony_ci		gl.deleteQueries(1, &m_qo_tfpw_id);
141e5c31af7Sopenharmony_ci
142e5c31af7Sopenharmony_ci		m_qo_tfpw_id = 0;
143e5c31af7Sopenharmony_ci	}
144e5c31af7Sopenharmony_ci
145e5c31af7Sopenharmony_ci	if (m_vao_id != 0)
146e5c31af7Sopenharmony_ci	{
147e5c31af7Sopenharmony_ci		gl.deleteVertexArrays(1, &m_vao_id);
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci		m_vao_id = 0;
150e5c31af7Sopenharmony_ci	}
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci	/* Deinitialize TS utils instance */
153e5c31af7Sopenharmony_ci	if (m_utils_ptr != NULL)
154e5c31af7Sopenharmony_ci	{
155e5c31af7Sopenharmony_ci		delete m_utils_ptr;
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_ci		m_utils_ptr = NULL;
158e5c31af7Sopenharmony_ci	}
159e5c31af7Sopenharmony_ci}
160e5c31af7Sopenharmony_ci
161e5c31af7Sopenharmony_ci/** Executes a single-counted GL_PATCHES_EXT draw call.
162e5c31af7Sopenharmony_ci *
163e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
164e5c31af7Sopenharmony_ci *
165e5c31af7Sopenharmony_ci *  @param n_iteration Not used.
166e5c31af7Sopenharmony_ci *
167e5c31af7Sopenharmony_ci **/
168e5c31af7Sopenharmony_civoid TessellationShaderInvarianceBaseTest::executeDrawCall(unsigned int n_iteration)
169e5c31af7Sopenharmony_ci{
170e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
171e5c31af7Sopenharmony_ci
172e5c31af7Sopenharmony_ci	DE_UNREF(n_iteration);
173e5c31af7Sopenharmony_ci
174e5c31af7Sopenharmony_ci	gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, getDrawCallCountArgument());
175e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
176e5c31af7Sopenharmony_ci}
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_ci/** Returns a value that should be used for the draw call's "count" argument.
179e5c31af7Sopenharmony_ci *
180e5c31af7Sopenharmony_ci *  @param Always 1
181e5c31af7Sopenharmony_ci **/
182e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceBaseTest::getDrawCallCountArgument()
183e5c31af7Sopenharmony_ci{
184e5c31af7Sopenharmony_ci	return 1;
185e5c31af7Sopenharmony_ci}
186e5c31af7Sopenharmony_ci
187e5c31af7Sopenharmony_ci/** Returns source code for fragment shader stage which does
188e5c31af7Sopenharmony_ci *  not do anything.
189e5c31af7Sopenharmony_ci *
190e5c31af7Sopenharmony_ci *  @param n_iteration Not used.
191e5c31af7Sopenharmony_ci *
192e5c31af7Sopenharmony_ci *  @return Requested string.
193e5c31af7Sopenharmony_ci **/
194e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceBaseTest::getFSCode(unsigned int n_iteration)
195e5c31af7Sopenharmony_ci{
196e5c31af7Sopenharmony_ci	DE_UNREF(n_iteration);
197e5c31af7Sopenharmony_ci
198e5c31af7Sopenharmony_ci	std::string result = "${VERSION}\n"
199e5c31af7Sopenharmony_ci						 "\n"
200e5c31af7Sopenharmony_ci						 "void main()\n"
201e5c31af7Sopenharmony_ci						 "{\n"
202e5c31af7Sopenharmony_ci						 "}\n";
203e5c31af7Sopenharmony_ci
204e5c31af7Sopenharmony_ci	return result;
205e5c31af7Sopenharmony_ci}
206e5c31af7Sopenharmony_ci
207e5c31af7Sopenharmony_ci/** Retrieves name of a vec2 uniform that stores inner tesselaton level information,
208e5c31af7Sopenharmony_ci *  later assigned to gl_TessLevelInner in tessellation evaluation shader.
209e5c31af7Sopenharmony_ci *
210e5c31af7Sopenharmony_ci *  @return Requested name.
211e5c31af7Sopenharmony_ci **/
212e5c31af7Sopenharmony_ciconst char* TessellationShaderInvarianceBaseTest::getInnerTessLevelUniformName()
213e5c31af7Sopenharmony_ci{
214e5c31af7Sopenharmony_ci	static const char* result = "inner_tess_level";
215e5c31af7Sopenharmony_ci
216e5c31af7Sopenharmony_ci	return result;
217e5c31af7Sopenharmony_ci}
218e5c31af7Sopenharmony_ci
219e5c31af7Sopenharmony_ci/** Retrieves name of a vec4 uniform that stores outer tesselation level information,
220e5c31af7Sopenharmony_ci *  later assigned to gl_TessLevelOuter in tessellation evaluation shader.
221e5c31af7Sopenharmony_ci *
222e5c31af7Sopenharmony_ci *  @return Requested name.
223e5c31af7Sopenharmony_ci **/
224e5c31af7Sopenharmony_ciconst char* TessellationShaderInvarianceBaseTest::getOuterTessLevelUniformName()
225e5c31af7Sopenharmony_ci{
226e5c31af7Sopenharmony_ci	static const char* result = "outer_tess_level";
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_ci	return result;
229e5c31af7Sopenharmony_ci}
230e5c31af7Sopenharmony_ci
231e5c31af7Sopenharmony_ci/** Returns generic tessellation control shader code, which sends 4 output patch
232e5c31af7Sopenharmony_ci *  to tessellation evaluation shader stage and uses the very first input patch
233e5c31af7Sopenharmony_ci *  vertex only.
234e5c31af7Sopenharmony_ci *
235e5c31af7Sopenharmony_ci *  @return Tessellation control source code.
236e5c31af7Sopenharmony_ci */
237e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceBaseTest::getTCCode(unsigned int n_iteration)
238e5c31af7Sopenharmony_ci{
239e5c31af7Sopenharmony_ci	DE_UNREF(n_iteration);
240e5c31af7Sopenharmony_ci
241e5c31af7Sopenharmony_ci	/* In order to support all three primitive types, our generic tessellation
242e5c31af7Sopenharmony_ci	 * control shader will pass 4 vertices to TE stage */
243e5c31af7Sopenharmony_ci	return TessellationShaderUtils::getGenericTCCode(4, /* n_patch_vertices */
244e5c31af7Sopenharmony_ci													 false);
245e5c31af7Sopenharmony_ci}
246e5c31af7Sopenharmony_ci
247e5c31af7Sopenharmony_ci/** Retrieves XFB properties for the test pass.
248e5c31af7Sopenharmony_ci *
249e5c31af7Sopenharmony_ci *  @param n_iteration Not used.
250e5c31af7Sopenharmony_ci *  @param out_n_names Deref will be used to store amount of strings @param *out_n_names
251e5c31af7Sopenharmony_ci *                     offers.
252e5c31af7Sopenharmony_ci *  @param out_names   Deref will be used to store pointer to an array of strings holding
253e5c31af7Sopenharmony_ci *                     names of varyings that should be captured via transform feedback.
254e5c31af7Sopenharmony_ci *                     Must not be NULL.
255e5c31af7Sopenharmony_ci *
256e5c31af7Sopenharmony_ci **/
257e5c31af7Sopenharmony_civoid TessellationShaderInvarianceBaseTest::getXFBProperties(unsigned int n_iteration, unsigned int* out_n_names,
258e5c31af7Sopenharmony_ci															const char*** out_names)
259e5c31af7Sopenharmony_ci{
260e5c31af7Sopenharmony_ci	static const char* names[] = { "result_uvw" };
261e5c31af7Sopenharmony_ci
262e5c31af7Sopenharmony_ci	DE_UNREF(n_iteration);
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci	*out_n_names = 1;
265e5c31af7Sopenharmony_ci	*out_names   = names;
266e5c31af7Sopenharmony_ci}
267e5c31af7Sopenharmony_ci
268e5c31af7Sopenharmony_ci/** Returns vertex shader source code. The shader sets gl_Position to
269e5c31af7Sopenharmony_ci *  vec4(1, 2, 3, 0).
270e5c31af7Sopenharmony_ci *
271e5c31af7Sopenharmony_ci *  @return Vertex shader source code.
272e5c31af7Sopenharmony_ci **/
273e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceBaseTest::getVSCode(unsigned int n_iteration)
274e5c31af7Sopenharmony_ci{
275e5c31af7Sopenharmony_ci	DE_UNREF(n_iteration);
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_ci	std::string result = "${VERSION}\n"
278e5c31af7Sopenharmony_ci						 "\n"
279e5c31af7Sopenharmony_ci						 "void main()\n"
280e5c31af7Sopenharmony_ci						 "{\n"
281e5c31af7Sopenharmony_ci						 "    gl_Position = vec4(1.0, 2.0, 3.0, 0.0);\n"
282e5c31af7Sopenharmony_ci						 "}\n";
283e5c31af7Sopenharmony_ci
284e5c31af7Sopenharmony_ci	return result;
285e5c31af7Sopenharmony_ci}
286e5c31af7Sopenharmony_ci
287e5c31af7Sopenharmony_ci/** Initializes ES objects required to execute the test.
288e5c31af7Sopenharmony_ci *
289e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
290e5c31af7Sopenharmony_ci *
291e5c31af7Sopenharmony_ci **/
292e5c31af7Sopenharmony_civoid TessellationShaderInvarianceBaseTest::initTest()
293e5c31af7Sopenharmony_ci{
294e5c31af7Sopenharmony_ci	const glw::Functions& gl		   = m_context.getRenderContext().getFunctions();
295e5c31af7Sopenharmony_ci	glw::GLuint			  shared_fs_id = 0;
296e5c31af7Sopenharmony_ci	glw::GLuint			  shared_tc_id = 0;
297e5c31af7Sopenharmony_ci	glw::GLuint			  shared_te_id = 0;
298e5c31af7Sopenharmony_ci	glw::GLuint			  shared_vs_id = 0;
299e5c31af7Sopenharmony_ci
300e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &m_vao_id);
301e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
302e5c31af7Sopenharmony_ci
303e5c31af7Sopenharmony_ci	gl.bindVertexArray(m_vao_id);
304e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
305e5c31af7Sopenharmony_ci
306e5c31af7Sopenharmony_ci	/* Initialize GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object */
307e5c31af7Sopenharmony_ci	gl.genQueries(1, &m_qo_tfpw_id);
308e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries() call failed");
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci	/* Initialize tessellation shader utils */
311e5c31af7Sopenharmony_ci	m_utils_ptr = new TessellationShaderUtils(gl, this);
312e5c31af7Sopenharmony_ci
313e5c31af7Sopenharmony_ci	/* Initialize a buffer object we will use to store XFB data.
314e5c31af7Sopenharmony_ci	 * Note: we intentionally skip a glBufferData() call here,
315e5c31af7Sopenharmony_ci	 *       the actual buffer storage size is iteration-specific.
316e5c31af7Sopenharmony_ci	 **/
317e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_bo_id);
318e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
321e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
322e5c31af7Sopenharmony_ci
323e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
324e5c31af7Sopenharmony_ci					  m_bo_id);
325e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
326e5c31af7Sopenharmony_ci
327e5c31af7Sopenharmony_ci	/* Iterate through all iterations */
328e5c31af7Sopenharmony_ci	const unsigned int n_iterations = getAmountOfIterations();
329e5c31af7Sopenharmony_ci	m_programs.reserve(n_iterations);
330e5c31af7Sopenharmony_ci
331e5c31af7Sopenharmony_ci	const glw::GLenum SHADER_TYPE_FRAGMENT				  = GL_FRAGMENT_SHADER;
332e5c31af7Sopenharmony_ci	const glw::GLenum SHADER_TYPE_TESSELLATION_CONTROL	= m_glExtTokens.TESS_CONTROL_SHADER;
333e5c31af7Sopenharmony_ci	const glw::GLenum SHADER_TYPE_TESSELLATION_EVALUATION = m_glExtTokens.TESS_EVALUATION_SHADER;
334e5c31af7Sopenharmony_ci	const glw::GLenum SHADER_TYPE_VERTEX				  = GL_VERTEX_SHADER;
335e5c31af7Sopenharmony_ci
336e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
337e5c31af7Sopenharmony_ci	{
338e5c31af7Sopenharmony_ci		_test_program program;
339e5c31af7Sopenharmony_ci
340e5c31af7Sopenharmony_ci		/* Create an iteration-specific program object */
341e5c31af7Sopenharmony_ci		program.po_id = gl.createProgram();
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
344e5c31af7Sopenharmony_ci
345e5c31af7Sopenharmony_ci		/* Query the implementation on which shader types should be compiled on
346e5c31af7Sopenharmony_ci		 * a per-iteration basis, and which can be initialized only once */
347e5c31af7Sopenharmony_ci		static const glw::GLenum shader_types[] = { SHADER_TYPE_FRAGMENT, SHADER_TYPE_TESSELLATION_CONTROL,
348e5c31af7Sopenharmony_ci													SHADER_TYPE_TESSELLATION_EVALUATION, SHADER_TYPE_VERTEX };
349e5c31af7Sopenharmony_ci		static const unsigned int n_shader_types = sizeof(shader_types) / sizeof(shader_types[0]);
350e5c31af7Sopenharmony_ci
351e5c31af7Sopenharmony_ci		for (unsigned int n_shader_type = 0; n_shader_type < n_shader_types; ++n_shader_type)
352e5c31af7Sopenharmony_ci		{
353e5c31af7Sopenharmony_ci			std::string shader_body;
354e5c31af7Sopenharmony_ci			const char* shader_body_ptr = DE_NULL;
355e5c31af7Sopenharmony_ci			glw::GLuint shader_id		= 0;
356e5c31af7Sopenharmony_ci			glw::GLenum shader_type		= shader_types[n_shader_type];
357e5c31af7Sopenharmony_ci			glw::GLenum shader_type_es  = (glw::GLenum)shader_type;
358e5c31af7Sopenharmony_ci
359e5c31af7Sopenharmony_ci			// Check whether the test should use a separate program objects for each iteration.
360e5c31af7Sopenharmony_ci			bool is_shader_iteration_specific = false;
361e5c31af7Sopenharmony_ci			if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
362e5c31af7Sopenharmony_ci			{
363e5c31af7Sopenharmony_ci				is_shader_iteration_specific = true;
364e5c31af7Sopenharmony_ci			}
365e5c31af7Sopenharmony_ci			else if ((shader_type != SHADER_TYPE_FRAGMENT) && (shader_type != SHADER_TYPE_TESSELLATION_CONTROL) &&
366e5c31af7Sopenharmony_ci					 (shader_type != SHADER_TYPE_VERTEX))
367e5c31af7Sopenharmony_ci			{
368e5c31af7Sopenharmony_ci				TCU_FAIL("Unrecognized shader type");
369e5c31af7Sopenharmony_ci			}
370e5c31af7Sopenharmony_ci
371e5c31af7Sopenharmony_ci			/* We need to initialize the shader object if:
372e5c31af7Sopenharmony_ci			 *
373e5c31af7Sopenharmony_ci			 * - its body differs between iterations;
374e5c31af7Sopenharmony_ci			 * - its body is shared by all iterations AND this is the first iteration
375e5c31af7Sopenharmony_ci			 */
376e5c31af7Sopenharmony_ci			bool has_shader_been_generated = false;
377e5c31af7Sopenharmony_ci
378e5c31af7Sopenharmony_ci			if ((!is_shader_iteration_specific && n_iteration == 0) || is_shader_iteration_specific)
379e5c31af7Sopenharmony_ci			{
380e5c31af7Sopenharmony_ci				/* Create the shader object */
381e5c31af7Sopenharmony_ci				has_shader_been_generated = true;
382e5c31af7Sopenharmony_ci				shader_id				  = gl.createShader(shader_type_es);
383e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci				/* Assign shader body to the object */
386e5c31af7Sopenharmony_ci				if (shader_type == SHADER_TYPE_FRAGMENT)
387e5c31af7Sopenharmony_ci				{
388e5c31af7Sopenharmony_ci					shader_body = getFSCode(n_iteration);
389e5c31af7Sopenharmony_ci				}
390e5c31af7Sopenharmony_ci				else if (shader_type == SHADER_TYPE_TESSELLATION_CONTROL)
391e5c31af7Sopenharmony_ci				{
392e5c31af7Sopenharmony_ci					shader_body = getTCCode(n_iteration);
393e5c31af7Sopenharmony_ci				}
394e5c31af7Sopenharmony_ci				else if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
395e5c31af7Sopenharmony_ci				{
396e5c31af7Sopenharmony_ci					shader_body = getTECode(n_iteration);
397e5c31af7Sopenharmony_ci				}
398e5c31af7Sopenharmony_ci				else if (shader_type == SHADER_TYPE_VERTEX)
399e5c31af7Sopenharmony_ci				{
400e5c31af7Sopenharmony_ci					shader_body = getVSCode(n_iteration);
401e5c31af7Sopenharmony_ci				}
402e5c31af7Sopenharmony_ci				else
403e5c31af7Sopenharmony_ci				{
404e5c31af7Sopenharmony_ci					TCU_FAIL("Unrecognized shader type");
405e5c31af7Sopenharmony_ci				}
406e5c31af7Sopenharmony_ci
407e5c31af7Sopenharmony_ci				shader_body_ptr = shader_body.c_str();
408e5c31af7Sopenharmony_ci
409e5c31af7Sopenharmony_ci				shaderSourceSpecialized(shader_id, 1, &shader_body_ptr);
410e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
411e5c31af7Sopenharmony_ci
412e5c31af7Sopenharmony_ci				/* Compile the shader object */
413e5c31af7Sopenharmony_ci				m_utils_ptr->compileShaders(1,				   /* n_shaders */
414e5c31af7Sopenharmony_ci											&shader_id, true); /* should_succeed */
415e5c31af7Sopenharmony_ci
416e5c31af7Sopenharmony_ci				/* If this is a shader object that will be shared by all iterations, cache it
417e5c31af7Sopenharmony_ci				 * in a dedicated variable */
418e5c31af7Sopenharmony_ci				if (!is_shader_iteration_specific)
419e5c31af7Sopenharmony_ci				{
420e5c31af7Sopenharmony_ci					if (shader_type == SHADER_TYPE_FRAGMENT)
421e5c31af7Sopenharmony_ci					{
422e5c31af7Sopenharmony_ci						shared_fs_id = shader_id;
423e5c31af7Sopenharmony_ci					}
424e5c31af7Sopenharmony_ci					else if (shader_type == SHADER_TYPE_TESSELLATION_CONTROL)
425e5c31af7Sopenharmony_ci					{
426e5c31af7Sopenharmony_ci						shared_tc_id = shader_id;
427e5c31af7Sopenharmony_ci					}
428e5c31af7Sopenharmony_ci					else if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
429e5c31af7Sopenharmony_ci					{
430e5c31af7Sopenharmony_ci						shared_te_id = shader_id;
431e5c31af7Sopenharmony_ci					}
432e5c31af7Sopenharmony_ci					else if (shader_type == SHADER_TYPE_VERTEX)
433e5c31af7Sopenharmony_ci					{
434e5c31af7Sopenharmony_ci						shared_vs_id = shader_id;
435e5c31af7Sopenharmony_ci					}
436e5c31af7Sopenharmony_ci					else
437e5c31af7Sopenharmony_ci					{
438e5c31af7Sopenharmony_ci						TCU_FAIL("Unrecognized shader type");
439e5c31af7Sopenharmony_ci					}
440e5c31af7Sopenharmony_ci				} /* if (!is_shader_iteration_specific) */
441e5c31af7Sopenharmony_ci			}	 /* if (shader object needs to be initialized) */
442e5c31af7Sopenharmony_ci			else
443e5c31af7Sopenharmony_ci			{
444e5c31af7Sopenharmony_ci				shader_id = (shader_type == SHADER_TYPE_FRAGMENT) ?
445e5c31af7Sopenharmony_ci								shared_fs_id :
446e5c31af7Sopenharmony_ci								(shader_type == SHADER_TYPE_TESSELLATION_CONTROL) ?
447e5c31af7Sopenharmony_ci								shared_tc_id :
448e5c31af7Sopenharmony_ci								(shader_type == SHADER_TYPE_TESSELLATION_EVALUATION) ? shared_te_id : shared_vs_id;
449e5c31af7Sopenharmony_ci			}
450e5c31af7Sopenharmony_ci
451e5c31af7Sopenharmony_ci			/* Attach the shader object to iteration-specific program object */
452e5c31af7Sopenharmony_ci			gl.attachShader(program.po_id, shader_id);
453e5c31af7Sopenharmony_ci
454e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
455e5c31af7Sopenharmony_ci
456e5c31af7Sopenharmony_ci			/* Now that the object has been attached, we can flag it for deletion */
457e5c31af7Sopenharmony_ci			if (has_shader_been_generated)
458e5c31af7Sopenharmony_ci			{
459e5c31af7Sopenharmony_ci				gl.deleteShader(shader_id);
460e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed");
461e5c31af7Sopenharmony_ci			}
462e5c31af7Sopenharmony_ci		} /* for (all shader types) */
463e5c31af7Sopenharmony_ci
464e5c31af7Sopenharmony_ci		/* Set up transform feed-back */
465e5c31af7Sopenharmony_ci		unsigned int n_xfb_names = 0;
466e5c31af7Sopenharmony_ci		const char** xfb_names   = NULL;
467e5c31af7Sopenharmony_ci
468e5c31af7Sopenharmony_ci		getXFBProperties(n_iteration, &n_xfb_names, &xfb_names);
469e5c31af7Sopenharmony_ci
470e5c31af7Sopenharmony_ci		gl.transformFeedbackVaryings(program.po_id, n_xfb_names, xfb_names, GL_INTERLEAVED_ATTRIBS);
471e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
472e5c31af7Sopenharmony_ci
473e5c31af7Sopenharmony_ci		/* Try to link the program object */
474e5c31af7Sopenharmony_ci		glw::GLint link_status = GL_FALSE;
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci		gl.linkProgram(program.po_id);
477e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
478e5c31af7Sopenharmony_ci
479e5c31af7Sopenharmony_ci		gl.getProgramiv(program.po_id, GL_LINK_STATUS, &link_status);
480e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
481e5c31af7Sopenharmony_ci
482e5c31af7Sopenharmony_ci		if (link_status != GL_TRUE)
483e5c31af7Sopenharmony_ci		{
484e5c31af7Sopenharmony_ci			TCU_FAIL("Program linking failed");
485e5c31af7Sopenharmony_ci		}
486e5c31af7Sopenharmony_ci
487e5c31af7Sopenharmony_ci		/* Retrieve inner/outer tess level uniform locations */
488e5c31af7Sopenharmony_ci		program.inner_tess_level_uniform_location =
489e5c31af7Sopenharmony_ci			gl.getUniformLocation(program.po_id, getInnerTessLevelUniformName());
490e5c31af7Sopenharmony_ci		program.outer_tess_level_uniform_location =
491e5c31af7Sopenharmony_ci			gl.getUniformLocation(program.po_id, getOuterTessLevelUniformName());
492e5c31af7Sopenharmony_ci
493e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed");
494e5c31af7Sopenharmony_ci
495e5c31af7Sopenharmony_ci		/* Store the program object */
496e5c31af7Sopenharmony_ci		m_programs.push_back(program);
497e5c31af7Sopenharmony_ci	} /* for (all iterations) */
498e5c31af7Sopenharmony_ci}
499e5c31af7Sopenharmony_ci
500e5c31af7Sopenharmony_ci/** Executes the test.
501e5c31af7Sopenharmony_ci *
502e5c31af7Sopenharmony_ci *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
503e5c31af7Sopenharmony_ci *
504e5c31af7Sopenharmony_ci *  Note the function throws exception should an error occur!
505e5c31af7Sopenharmony_ci *
506e5c31af7Sopenharmony_ci *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
507e5c31af7Sopenharmony_ci **/
508e5c31af7Sopenharmony_citcu::TestNode::IterateResult TessellationShaderInvarianceBaseTest::iterate(void)
509e5c31af7Sopenharmony_ci{
510e5c31af7Sopenharmony_ci	/* Do not execute if required extensions are not supported. */
511e5c31af7Sopenharmony_ci	if (!m_is_tessellation_shader_supported)
512e5c31af7Sopenharmony_ci	{
513e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
514e5c31af7Sopenharmony_ci	}
515e5c31af7Sopenharmony_ci
516e5c31af7Sopenharmony_ci	/* Initialize all objects needed to run the test */
517e5c31af7Sopenharmony_ci	initTest();
518e5c31af7Sopenharmony_ci
519e5c31af7Sopenharmony_ci	/* Do a general set-up */
520e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
521e5c31af7Sopenharmony_ci
522e5c31af7Sopenharmony_ci	gl.enable(GL_RASTERIZER_DISCARD);
523e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
524e5c31af7Sopenharmony_ci
525e5c31af7Sopenharmony_ci	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
526e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
527e5c31af7Sopenharmony_ci
528e5c31af7Sopenharmony_ci	/* There are two types of verification supported by this base test implementation:
529e5c31af7Sopenharmony_ci	 *
530e5c31af7Sopenharmony_ci	 * - iteration-specific (verifyResultDataForIteration() )
531e5c31af7Sopenharmony_ci	 * - global             (verifyResultData() )
532e5c31af7Sopenharmony_ci	 *
533e5c31af7Sopenharmony_ci	 * It is up to test implementation to decide which of the two (or perhaps both)
534e5c31af7Sopenharmony_ci	 * entry-points it should overload and use for validating the result data.
535e5c31af7Sopenharmony_ci	 */
536e5c31af7Sopenharmony_ci	const unsigned int n_iterations   = getAmountOfIterations();
537e5c31af7Sopenharmony_ci	char**			   iteration_data = new char*[n_iterations];
538e5c31af7Sopenharmony_ci
539e5c31af7Sopenharmony_ci	/* Execute the test */
540e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
541e5c31af7Sopenharmony_ci	{
542e5c31af7Sopenharmony_ci		_test_program& program = m_programs[n_iteration];
543e5c31af7Sopenharmony_ci
544e5c31af7Sopenharmony_ci		/* Retrieve iteration properties for current iteration */
545e5c31af7Sopenharmony_ci		unsigned int						 bo_size			  = 0;
546e5c31af7Sopenharmony_ci		float								 inner_tess_levels[2] = { 0 };
547e5c31af7Sopenharmony_ci		bool								 is_point_mode		  = false;
548e5c31af7Sopenharmony_ci		float								 outer_tess_levels[4] = { 0 };
549e5c31af7Sopenharmony_ci		_tessellation_primitive_mode		 primitive_mode		  = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
550e5c31af7Sopenharmony_ci		_tessellation_shader_vertex_ordering vertex_ordering	  = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
551e5c31af7Sopenharmony_ci
552e5c31af7Sopenharmony_ci		getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &is_point_mode, &primitive_mode,
553e5c31af7Sopenharmony_ci							   &vertex_ordering, &bo_size);
554e5c31af7Sopenharmony_ci
555e5c31af7Sopenharmony_ci		DE_ASSERT(bo_size != 0);
556e5c31af7Sopenharmony_ci
557e5c31af7Sopenharmony_ci		/* Activate iteration-specific program */
558e5c31af7Sopenharmony_ci		gl.useProgram(program.po_id);
559e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed.");
560e5c31af7Sopenharmony_ci
561e5c31af7Sopenharmony_ci		/* Set up buffer object storage */
562e5c31af7Sopenharmony_ci		{
563e5c31af7Sopenharmony_ci			char* zero_bo_data = new char[bo_size];
564e5c31af7Sopenharmony_ci
565e5c31af7Sopenharmony_ci			memset(zero_bo_data, 0, bo_size);
566e5c31af7Sopenharmony_ci
567e5c31af7Sopenharmony_ci			gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, zero_bo_data, GL_STATIC_DRAW);
568e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
569e5c31af7Sopenharmony_ci
570e5c31af7Sopenharmony_ci			delete[] zero_bo_data;
571e5c31af7Sopenharmony_ci			zero_bo_data = NULL;
572e5c31af7Sopenharmony_ci		}
573e5c31af7Sopenharmony_ci
574e5c31af7Sopenharmony_ci		/* Allocate space for iteration-specific data */
575e5c31af7Sopenharmony_ci		iteration_data[n_iteration] = new char[bo_size];
576e5c31af7Sopenharmony_ci
577e5c31af7Sopenharmony_ci		/* Configure inner/outer tessellation levels as requested for the iteration */
578e5c31af7Sopenharmony_ci		gl.uniform2fv(program.inner_tess_level_uniform_location, 1, /* count */
579e5c31af7Sopenharmony_ci					  inner_tess_levels);
580e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
581e5c31af7Sopenharmony_ci
582e5c31af7Sopenharmony_ci		gl.uniform4fv(program.outer_tess_level_uniform_location, 1, /* count */
583e5c31af7Sopenharmony_ci					  outer_tess_levels);
584e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
585e5c31af7Sopenharmony_ci
586e5c31af7Sopenharmony_ci		/* Launch the TFPW query */
587e5c31af7Sopenharmony_ci		gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tfpw_id);
588e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(),
589e5c31af7Sopenharmony_ci							"glBeginQuery() for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN target failed.");
590e5c31af7Sopenharmony_ci
591e5c31af7Sopenharmony_ci		/* Prepare for TF */
592e5c31af7Sopenharmony_ci		glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(primitive_mode, is_point_mode);
593e5c31af7Sopenharmony_ci
594e5c31af7Sopenharmony_ci		gl.beginTransformFeedback(tf_mode);
595e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
596e5c31af7Sopenharmony_ci		{
597e5c31af7Sopenharmony_ci			/* Execute the draw call */
598e5c31af7Sopenharmony_ci			executeDrawCall(n_iteration);
599e5c31af7Sopenharmony_ci
600e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed");
601e5c31af7Sopenharmony_ci		}
602e5c31af7Sopenharmony_ci		gl.endTransformFeedback();
603e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
604e5c31af7Sopenharmony_ci
605e5c31af7Sopenharmony_ci		gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
606e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) call failed");
607e5c31af7Sopenharmony_ci
608e5c31af7Sopenharmony_ci		/* Make sure that we had sufficient amount of space in a buffer object we used to
609e5c31af7Sopenharmony_ci		 * capture XFB data.
610e5c31af7Sopenharmony_ci		 **/
611e5c31af7Sopenharmony_ci		glw::GLuint n_tf_primitives_written = 0;
612e5c31af7Sopenharmony_ci		glw::GLuint used_tf_bo_size			= 0;
613e5c31af7Sopenharmony_ci
614e5c31af7Sopenharmony_ci		gl.getQueryObjectuiv(m_qo_tfpw_id, GL_QUERY_RESULT, &n_tf_primitives_written);
615e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(),
616e5c31af7Sopenharmony_ci							"Could not retrieve GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object result");
617e5c31af7Sopenharmony_ci
618e5c31af7Sopenharmony_ci		if (is_point_mode)
619e5c31af7Sopenharmony_ci		{
620e5c31af7Sopenharmony_ci			used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* components */);
621e5c31af7Sopenharmony_ci		}
622e5c31af7Sopenharmony_ci		else if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
623e5c31af7Sopenharmony_ci		{
624e5c31af7Sopenharmony_ci			used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 2 /* vertices */ *
625e5c31af7Sopenharmony_ci													   3 /* components */);
626e5c31af7Sopenharmony_ci		}
627e5c31af7Sopenharmony_ci		else
628e5c31af7Sopenharmony_ci		{
629e5c31af7Sopenharmony_ci			used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* vertices */ *
630e5c31af7Sopenharmony_ci													   3 /* components */);
631e5c31af7Sopenharmony_ci		}
632e5c31af7Sopenharmony_ci
633e5c31af7Sopenharmony_ci		if (used_tf_bo_size != bo_size)
634e5c31af7Sopenharmony_ci		{
635e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << "Expected " << bo_size
636e5c31af7Sopenharmony_ci							   << " to be filled with tessellation data, "
637e5c31af7Sopenharmony_ci								  "only "
638e5c31af7Sopenharmony_ci							   << used_tf_bo_size << "was used." << tcu::TestLog::EndMessage;
639e5c31af7Sopenharmony_ci
640e5c31af7Sopenharmony_ci			TCU_FAIL("Amount of primitives generated during TF does not match amount of primitives that were expected"
641e5c31af7Sopenharmony_ci					 " to be generated by the tessellator");
642e5c31af7Sopenharmony_ci		}
643e5c31af7Sopenharmony_ci
644e5c31af7Sopenharmony_ci		/* Map the buffer object we earlier bound to GL_TRANSFORM_FEEDBACK_BUFFER
645e5c31af7Sopenharmony_ci		 * target into process space. */
646e5c31af7Sopenharmony_ci		const void* xfb_data = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
647e5c31af7Sopenharmony_ci												 bo_size, GL_MAP_READ_BIT);
648e5c31af7Sopenharmony_ci
649e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
650e5c31af7Sopenharmony_ci
651e5c31af7Sopenharmony_ci		memcpy(iteration_data[n_iteration], xfb_data, bo_size);
652e5c31af7Sopenharmony_ci
653e5c31af7Sopenharmony_ci		/* Unmap the buffer object */
654e5c31af7Sopenharmony_ci		gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
655e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
656e5c31af7Sopenharmony_ci
657e5c31af7Sopenharmony_ci		/* Ask the test implementation to verify the results */
658e5c31af7Sopenharmony_ci		verifyResultDataForIteration(n_iteration, iteration_data[n_iteration]);
659e5c31af7Sopenharmony_ci	} /* for (all iterations) */
660e5c31af7Sopenharmony_ci
661e5c31af7Sopenharmony_ci	/* Now that we've executed all iterations, we can call a global verification
662e5c31af7Sopenharmony_ci	 * entry-point */
663e5c31af7Sopenharmony_ci	verifyResultData((const void**)iteration_data);
664e5c31af7Sopenharmony_ci
665e5c31af7Sopenharmony_ci	/* At this point we're safe to release space allocated for data coming from
666e5c31af7Sopenharmony_ci	 * all the iterations */
667e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
668e5c31af7Sopenharmony_ci	{
669e5c31af7Sopenharmony_ci		char* iter_data = (char*)iteration_data[n_iteration];
670e5c31af7Sopenharmony_ci		delete[] iter_data;
671e5c31af7Sopenharmony_ci
672e5c31af7Sopenharmony_ci		iteration_data[n_iteration] = DE_NULL;
673e5c31af7Sopenharmony_ci	} /* for (all iterations) */
674e5c31af7Sopenharmony_ci
675e5c31af7Sopenharmony_ci	delete[] iteration_data;
676e5c31af7Sopenharmony_ci	iteration_data = DE_NULL;
677e5c31af7Sopenharmony_ci
678e5c31af7Sopenharmony_ci	/* All done */
679e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
680e5c31af7Sopenharmony_ci	return STOP;
681e5c31af7Sopenharmony_ci}
682e5c31af7Sopenharmony_ci
683e5c31af7Sopenharmony_ci/* Does nothing (stub implementation)
684e5c31af7Sopenharmony_ci *
685e5c31af7Sopenharmony_ci * @param n_iteration Not used.
686e5c31af7Sopenharmony_ci * @param data        Not used.
687e5c31af7Sopenharmony_ci *
688e5c31af7Sopenharmony_ci **/
689e5c31af7Sopenharmony_civoid TessellationShaderInvarianceBaseTest::verifyResultDataForIteration(unsigned int n_iteration, const void* data)
690e5c31af7Sopenharmony_ci{
691e5c31af7Sopenharmony_ci	DE_UNREF(n_iteration && data);
692e5c31af7Sopenharmony_ci
693e5c31af7Sopenharmony_ci	/* Do nothing - this is just a stub. */
694e5c31af7Sopenharmony_ci}
695e5c31af7Sopenharmony_ci
696e5c31af7Sopenharmony_ci/* Does nothing (stub implementation)
697e5c31af7Sopenharmony_ci *
698e5c31af7Sopenharmony_ci * @param all_iterations_data Not used.
699e5c31af7Sopenharmony_ci *
700e5c31af7Sopenharmony_ci **/
701e5c31af7Sopenharmony_civoid TessellationShaderInvarianceBaseTest::verifyResultData(const void** all_iterations_data)
702e5c31af7Sopenharmony_ci{
703e5c31af7Sopenharmony_ci	DE_UNREF(all_iterations_data);
704e5c31af7Sopenharmony_ci
705e5c31af7Sopenharmony_ci	/* Do nothing - this is just a stub. */
706e5c31af7Sopenharmony_ci}
707e5c31af7Sopenharmony_ci
708e5c31af7Sopenharmony_ci/** Constructor.
709e5c31af7Sopenharmony_ci *
710e5c31af7Sopenharmony_ci *  @param context Rendering context.
711e5c31af7Sopenharmony_ci *
712e5c31af7Sopenharmony_ci **/
713e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule1Test::TessellationShaderInvarianceRule1Test(Context&			  context,
714e5c31af7Sopenharmony_ci																			 const ExtParameters& extParams)
715e5c31af7Sopenharmony_ci	: TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule1",
716e5c31af7Sopenharmony_ci										   "Verifies conformance with first invariance rule")
717e5c31af7Sopenharmony_ci{
718e5c31af7Sopenharmony_ci	/* Left blank intentionally */
719e5c31af7Sopenharmony_ci}
720e5c31af7Sopenharmony_ci
721e5c31af7Sopenharmony_ci/** Destructor. */
722e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule1Test::~TessellationShaderInvarianceRule1Test()
723e5c31af7Sopenharmony_ci{
724e5c31af7Sopenharmony_ci	/* Left blank intentionally */
725e5c31af7Sopenharmony_ci}
726e5c31af7Sopenharmony_ci
727e5c31af7Sopenharmony_ci/** Retrieves amount of iterations the base test implementation should run before
728e5c31af7Sopenharmony_ci *  calling global verification routine.
729e5c31af7Sopenharmony_ci *
730e5c31af7Sopenharmony_ci *  @return Always 6.
731e5c31af7Sopenharmony_ci **/
732e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule1Test::getAmountOfIterations()
733e5c31af7Sopenharmony_ci{
734e5c31af7Sopenharmony_ci	return 6;
735e5c31af7Sopenharmony_ci}
736e5c31af7Sopenharmony_ci
737e5c31af7Sopenharmony_ci/** Returns a value that should be used for the draw call's "count" argument.
738e5c31af7Sopenharmony_ci *
739e5c31af7Sopenharmony_ci *  @param Always 3
740e5c31af7Sopenharmony_ci **/
741e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule1Test::getDrawCallCountArgument()
742e5c31af7Sopenharmony_ci{
743e5c31af7Sopenharmony_ci	return 3;
744e5c31af7Sopenharmony_ci}
745e5c31af7Sopenharmony_ci
746e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation properties.
747e5c31af7Sopenharmony_ci *
748e5c31af7Sopenharmony_ci *  @param n_iteration            Iteration index to retrieve the properties for.
749e5c31af7Sopenharmony_ci *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
750e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
751e5c31af7Sopenharmony_ci *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
752e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
753e5c31af7Sopenharmony_ci *  @param out_point_mode         Deref will be used to store iteration-specific flag
754e5c31af7Sopenharmony_ci *                                telling whether point mode should be enabled for given pass.
755e5c31af7Sopenharmony_ci *                                Must not be NULL.
756e5c31af7Sopenharmony_ci *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
757e5c31af7Sopenharmony_ci *                                mode. Must not be NULL.
758e5c31af7Sopenharmony_ci *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex ordering.
759e5c31af7Sopenharmony_ci *                                Must not be NULL.
760e5c31af7Sopenharmony_ci *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
761e5c31af7Sopenharmony_ci *                                storage should offer for the draw call to succeed. Must not
762e5c31af7Sopenharmony_ci *                                be NULL.
763e5c31af7Sopenharmony_ci **/
764e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule1Test::getIterationProperties(
765e5c31af7Sopenharmony_ci	unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
766e5c31af7Sopenharmony_ci	_tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
767e5c31af7Sopenharmony_ci	unsigned int* out_result_buffer_size)
768e5c31af7Sopenharmony_ci{
769e5c31af7Sopenharmony_ci	*out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
770e5c31af7Sopenharmony_ci
771e5c31af7Sopenharmony_ci	switch (n_iteration)
772e5c31af7Sopenharmony_ci	{
773e5c31af7Sopenharmony_ci	case 0:
774e5c31af7Sopenharmony_ci	case 5:
775e5c31af7Sopenharmony_ci	{
776e5c31af7Sopenharmony_ci		/* Triangles (point mode) */
777e5c31af7Sopenharmony_ci		out_inner_tess_levels[0] = 1.0f;
778e5c31af7Sopenharmony_ci		out_outer_tess_levels[0] = 1.0f;
779e5c31af7Sopenharmony_ci		out_outer_tess_levels[1] = 1.0f;
780e5c31af7Sopenharmony_ci		out_outer_tess_levels[2] = 1.0f;
781e5c31af7Sopenharmony_ci
782e5c31af7Sopenharmony_ci		*out_point_mode		= true;
783e5c31af7Sopenharmony_ci		*out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
784e5c31af7Sopenharmony_ci
785e5c31af7Sopenharmony_ci		break;
786e5c31af7Sopenharmony_ci	}
787e5c31af7Sopenharmony_ci
788e5c31af7Sopenharmony_ci	case 1:
789e5c31af7Sopenharmony_ci	case 3:
790e5c31af7Sopenharmony_ci	{
791e5c31af7Sopenharmony_ci		/* Lines */
792e5c31af7Sopenharmony_ci		out_outer_tess_levels[0] = 1.0f;
793e5c31af7Sopenharmony_ci		out_outer_tess_levels[1] = 1.0f;
794e5c31af7Sopenharmony_ci
795e5c31af7Sopenharmony_ci		*out_point_mode		= false;
796e5c31af7Sopenharmony_ci		*out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES;
797e5c31af7Sopenharmony_ci
798e5c31af7Sopenharmony_ci		break;
799e5c31af7Sopenharmony_ci	}
800e5c31af7Sopenharmony_ci
801e5c31af7Sopenharmony_ci	case 2:
802e5c31af7Sopenharmony_ci	case 4:
803e5c31af7Sopenharmony_ci	{
804e5c31af7Sopenharmony_ci		/* Triangles */
805e5c31af7Sopenharmony_ci		out_inner_tess_levels[0] = 1.0f;
806e5c31af7Sopenharmony_ci		out_outer_tess_levels[0] = 1.0f;
807e5c31af7Sopenharmony_ci		out_outer_tess_levels[1] = 1.0f;
808e5c31af7Sopenharmony_ci		out_outer_tess_levels[2] = 1.0f;
809e5c31af7Sopenharmony_ci
810e5c31af7Sopenharmony_ci		*out_point_mode		= false;
811e5c31af7Sopenharmony_ci		*out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
812e5c31af7Sopenharmony_ci
813e5c31af7Sopenharmony_ci		break;
814e5c31af7Sopenharmony_ci	}
815e5c31af7Sopenharmony_ci
816e5c31af7Sopenharmony_ci	default:
817e5c31af7Sopenharmony_ci	{
818e5c31af7Sopenharmony_ci		TCU_FAIL("Unrecognzied iteration index");
819e5c31af7Sopenharmony_ci	}
820e5c31af7Sopenharmony_ci	}
821e5c31af7Sopenharmony_ci
822e5c31af7Sopenharmony_ci	*out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
823e5c31af7Sopenharmony_ci		*out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
824e5c31af7Sopenharmony_ci		*out_point_mode);
825e5c31af7Sopenharmony_ci
826e5c31af7Sopenharmony_ci	*out_result_buffer_size = static_cast<unsigned int>(*out_result_buffer_size * getDrawCallCountArgument() *
827e5c31af7Sopenharmony_ci														3 /* components */ * sizeof(float));
828e5c31af7Sopenharmony_ci
829e5c31af7Sopenharmony_ci	DE_ASSERT(*out_result_buffer_size != 0);
830e5c31af7Sopenharmony_ci}
831e5c31af7Sopenharmony_ci
832e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation evaluation shader code.
833e5c31af7Sopenharmony_ci *
834e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index, for which the source code is being obtained.
835e5c31af7Sopenharmony_ci *
836e5c31af7Sopenharmony_ci *  @return Requested source code.
837e5c31af7Sopenharmony_ci **/
838e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceRule1Test::getTECode(unsigned int n_iteration)
839e5c31af7Sopenharmony_ci{
840e5c31af7Sopenharmony_ci	unsigned int						 bo_size			  = 0;
841e5c31af7Sopenharmony_ci	float								 inner_tess_levels[2] = { 0 };
842e5c31af7Sopenharmony_ci	float								 outer_tess_levels[4] = { 0 };
843e5c31af7Sopenharmony_ci	bool								 point_mode			  = false;
844e5c31af7Sopenharmony_ci	_tessellation_primitive_mode		 primitive_mode		  = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
845e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_ordering vertex_ordering	  = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
846e5c31af7Sopenharmony_ci
847e5c31af7Sopenharmony_ci	getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode,
848e5c31af7Sopenharmony_ci						   &vertex_ordering, &bo_size);
849e5c31af7Sopenharmony_ci
850e5c31af7Sopenharmony_ci	return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode,
851e5c31af7Sopenharmony_ci													 vertex_ordering, point_mode);
852e5c31af7Sopenharmony_ci}
853e5c31af7Sopenharmony_ci
854e5c31af7Sopenharmony_ci/** Verifies result data. Accesses data generated by all iterations.
855e5c31af7Sopenharmony_ci *
856e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
857e5c31af7Sopenharmony_ci *
858e5c31af7Sopenharmony_ci *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
859e5c31af7Sopenharmony_ci *                             data generated by subsequent iterations.
860e5c31af7Sopenharmony_ci **/
861e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule1Test::verifyResultData(const void** all_iterations_data)
862e5c31af7Sopenharmony_ci{
863e5c31af7Sopenharmony_ci	const float* lines_vertex_data_1 = (const float*)all_iterations_data[1];
864e5c31af7Sopenharmony_ci	const float* lines_vertex_data_2 = (const float*)all_iterations_data[3];
865e5c31af7Sopenharmony_ci	const float* point_vertex_data_1 = (const float*)all_iterations_data[0];
866e5c31af7Sopenharmony_ci	const float* point_vertex_data_2 = (const float*)all_iterations_data[5];
867e5c31af7Sopenharmony_ci	const float* tris_vertex_data_1  = (const float*)all_iterations_data[2];
868e5c31af7Sopenharmony_ci	const float* tris_vertex_data_2  = (const float*)all_iterations_data[4];
869e5c31af7Sopenharmony_ci
870e5c31af7Sopenharmony_ci	const unsigned int n_line_vertices  = 2 /* vertices per line segment */ * getDrawCallCountArgument(); /* lines */
871e5c31af7Sopenharmony_ci	const unsigned int n_point_vertices = 1 /* vertices per point */ * getDrawCallCountArgument();		  /* points */
872e5c31af7Sopenharmony_ci	const unsigned int n_tri_vertices   = 3 /* vertices per triangle */ * getDrawCallCountArgument(); /* triangles */
873e5c31af7Sopenharmony_ci	const unsigned int vertex_size		= sizeof(float) * 3;										  /* components */
874e5c31af7Sopenharmony_ci
875e5c31af7Sopenharmony_ci	/* Make sure the data sets match, given different draw call ordering */
876e5c31af7Sopenharmony_ci	for (int n_type = 0; n_type < 3 /* lines, points, tris */; ++n_type)
877e5c31af7Sopenharmony_ci	{
878e5c31af7Sopenharmony_ci		const float* data1_ptr = DE_NULL;
879e5c31af7Sopenharmony_ci		const float* data2_ptr = DE_NULL;
880e5c31af7Sopenharmony_ci		std::string  data_type_string;
881e5c31af7Sopenharmony_ci		unsigned int n_vertices = 0;
882e5c31af7Sopenharmony_ci
883e5c31af7Sopenharmony_ci		switch (n_type)
884e5c31af7Sopenharmony_ci		{
885e5c31af7Sopenharmony_ci		case 0:
886e5c31af7Sopenharmony_ci		{
887e5c31af7Sopenharmony_ci			data1_ptr		 = lines_vertex_data_1;
888e5c31af7Sopenharmony_ci			data2_ptr		 = lines_vertex_data_2;
889e5c31af7Sopenharmony_ci			data_type_string = "Line";
890e5c31af7Sopenharmony_ci			n_vertices		 = n_line_vertices;
891e5c31af7Sopenharmony_ci
892e5c31af7Sopenharmony_ci			break;
893e5c31af7Sopenharmony_ci		}
894e5c31af7Sopenharmony_ci
895e5c31af7Sopenharmony_ci		case 1:
896e5c31af7Sopenharmony_ci		{
897e5c31af7Sopenharmony_ci			data1_ptr		 = point_vertex_data_1;
898e5c31af7Sopenharmony_ci			data2_ptr		 = point_vertex_data_2;
899e5c31af7Sopenharmony_ci			data_type_string = "Point";
900e5c31af7Sopenharmony_ci			n_vertices		 = n_point_vertices;
901e5c31af7Sopenharmony_ci
902e5c31af7Sopenharmony_ci			break;
903e5c31af7Sopenharmony_ci		}
904e5c31af7Sopenharmony_ci
905e5c31af7Sopenharmony_ci		case 2:
906e5c31af7Sopenharmony_ci		{
907e5c31af7Sopenharmony_ci			data1_ptr		 = tris_vertex_data_1;
908e5c31af7Sopenharmony_ci			data2_ptr		 = tris_vertex_data_2;
909e5c31af7Sopenharmony_ci			data_type_string = "Triangle";
910e5c31af7Sopenharmony_ci			n_vertices		 = n_tri_vertices;
911e5c31af7Sopenharmony_ci
912e5c31af7Sopenharmony_ci			break;
913e5c31af7Sopenharmony_ci		}
914e5c31af7Sopenharmony_ci
915e5c31af7Sopenharmony_ci		default:
916e5c31af7Sopenharmony_ci		{
917e5c31af7Sopenharmony_ci			TCU_FAIL("Internal error: type index was not recognized");
918e5c31af7Sopenharmony_ci		}
919e5c31af7Sopenharmony_ci		} /* switch (n_type) */
920e5c31af7Sopenharmony_ci
921e5c31af7Sopenharmony_ci		/* Make sure the buffer storage in both cases has been modified */
922e5c31af7Sopenharmony_ci		{
923e5c31af7Sopenharmony_ci			unsigned int zero_bo_size = vertex_size * n_vertices;
924e5c31af7Sopenharmony_ci			char*		 zero_bo_data = new char[vertex_size * n_vertices];
925e5c31af7Sopenharmony_ci
926e5c31af7Sopenharmony_ci			memset(zero_bo_data, 0, zero_bo_size);
927e5c31af7Sopenharmony_ci
928e5c31af7Sopenharmony_ci			if (memcmp(data1_ptr, zero_bo_data, zero_bo_size) == 0 ||
929e5c31af7Sopenharmony_ci				memcmp(data2_ptr, zero_bo_data, zero_bo_size) == 0)
930e5c31af7Sopenharmony_ci			{
931e5c31af7Sopenharmony_ci				TCU_FAIL("One of the draw calls has not outputted any data to XFB buffer object storage");
932e5c31af7Sopenharmony_ci			}
933e5c31af7Sopenharmony_ci
934e5c31af7Sopenharmony_ci			delete[] zero_bo_data;
935e5c31af7Sopenharmony_ci			zero_bo_data = NULL;
936e5c31af7Sopenharmony_ci		}
937e5c31af7Sopenharmony_ci
938e5c31af7Sopenharmony_ci		/* Compare the data */
939e5c31af7Sopenharmony_ci		if (memcmp(data1_ptr, data2_ptr, vertex_size * n_vertices) != 0)
940e5c31af7Sopenharmony_ci		{
941e5c31af7Sopenharmony_ci			std::stringstream logMessage;
942e5c31af7Sopenharmony_ci
943e5c31af7Sopenharmony_ci			logMessage << data_type_string << " data rendered in pass 1: (";
944e5c31af7Sopenharmony_ci
945e5c31af7Sopenharmony_ci			for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
946e5c31af7Sopenharmony_ci			{
947e5c31af7Sopenharmony_ci				logMessage << data1_ptr[n_vertex];
948e5c31af7Sopenharmony_ci
949e5c31af7Sopenharmony_ci				if (n_vertex != (n_vertices - 1))
950e5c31af7Sopenharmony_ci				{
951e5c31af7Sopenharmony_ci					logMessage << ", ";
952e5c31af7Sopenharmony_ci				}
953e5c31af7Sopenharmony_ci				else
954e5c31af7Sopenharmony_ci				{
955e5c31af7Sopenharmony_ci					logMessage << ") ";
956e5c31af7Sopenharmony_ci				}
957e5c31af7Sopenharmony_ci			} /* for (all vertices) */
958e5c31af7Sopenharmony_ci
959e5c31af7Sopenharmony_ci			logMessage << "and in pass 2: (";
960e5c31af7Sopenharmony_ci
961e5c31af7Sopenharmony_ci			for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
962e5c31af7Sopenharmony_ci			{
963e5c31af7Sopenharmony_ci				logMessage << data2_ptr[n_vertex];
964e5c31af7Sopenharmony_ci
965e5c31af7Sopenharmony_ci				if (n_vertex != (n_vertices - 1))
966e5c31af7Sopenharmony_ci				{
967e5c31af7Sopenharmony_ci					logMessage << ", ";
968e5c31af7Sopenharmony_ci				}
969e5c31af7Sopenharmony_ci				else
970e5c31af7Sopenharmony_ci				{
971e5c31af7Sopenharmony_ci					logMessage << ") ";
972e5c31af7Sopenharmony_ci				}
973e5c31af7Sopenharmony_ci			} /* for (all vertices) */
974e5c31af7Sopenharmony_ci
975e5c31af7Sopenharmony_ci			logMessage << "do not match";
976e5c31af7Sopenharmony_ci
977e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message << logMessage.str().c_str() << tcu::TestLog::EndMessage;
978e5c31af7Sopenharmony_ci
979e5c31af7Sopenharmony_ci			TCU_FAIL("Data mismatch");
980e5c31af7Sopenharmony_ci		} /* if (data mismatch) */
981e5c31af7Sopenharmony_ci	}	 /* for (all primitive types) */
982e5c31af7Sopenharmony_ci}
983e5c31af7Sopenharmony_ci
984e5c31af7Sopenharmony_ci/** Constructor.
985e5c31af7Sopenharmony_ci *
986e5c31af7Sopenharmony_ci *  @param context Rendering context.
987e5c31af7Sopenharmony_ci *
988e5c31af7Sopenharmony_ci **/
989e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule2Test::TessellationShaderInvarianceRule2Test(Context&			  context,
990e5c31af7Sopenharmony_ci																			 const ExtParameters& extParams)
991e5c31af7Sopenharmony_ci	: TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule2",
992e5c31af7Sopenharmony_ci										   "Verifies conformance with second invariance rule")
993e5c31af7Sopenharmony_ci{
994e5c31af7Sopenharmony_ci	memset(m_n_tessellated_vertices, 0, sizeof(m_n_tessellated_vertices));
995e5c31af7Sopenharmony_ci}
996e5c31af7Sopenharmony_ci
997e5c31af7Sopenharmony_ci/** Destructor. */
998e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule2Test::~TessellationShaderInvarianceRule2Test()
999e5c31af7Sopenharmony_ci{
1000e5c31af7Sopenharmony_ci	/* Left blank intentionally */
1001e5c31af7Sopenharmony_ci}
1002e5c31af7Sopenharmony_ci
1003e5c31af7Sopenharmony_ci/** Retrieves amount of iterations the base test implementation should run before
1004e5c31af7Sopenharmony_ci *  calling global verification routine.
1005e5c31af7Sopenharmony_ci *
1006e5c31af7Sopenharmony_ci *  @return Always 4.
1007e5c31af7Sopenharmony_ci **/
1008e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule2Test::getAmountOfIterations()
1009e5c31af7Sopenharmony_ci{
1010e5c31af7Sopenharmony_ci	return 4;
1011e5c31af7Sopenharmony_ci}
1012e5c31af7Sopenharmony_ci
1013e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation properties.
1014e5c31af7Sopenharmony_ci *
1015e5c31af7Sopenharmony_ci *  @param n_iteration            Iteration index to retrieve the properties for.
1016e5c31af7Sopenharmony_ci *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
1017e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
1018e5c31af7Sopenharmony_ci *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
1019e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
1020e5c31af7Sopenharmony_ci *  @param out_point_mode         Deref will be used to store iteration-specific flag
1021e5c31af7Sopenharmony_ci *                                telling whether point mode should be enabled for given pass.
1022e5c31af7Sopenharmony_ci *                                Must not be NULL.
1023e5c31af7Sopenharmony_ci *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
1024e5c31af7Sopenharmony_ci *                                mode. Must not be NULL.
1025e5c31af7Sopenharmony_ci *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
1026e5c31af7Sopenharmony_ci *                                ordering. Must not be NULL.
1027e5c31af7Sopenharmony_ci *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1028e5c31af7Sopenharmony_ci *                                storage should offer for the draw call to succeed. Can
1029e5c31af7Sopenharmony_ci *                                be NULL.
1030e5c31af7Sopenharmony_ci **/
1031e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule2Test::getIterationProperties(
1032e5c31af7Sopenharmony_ci	unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
1033e5c31af7Sopenharmony_ci	_tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
1034e5c31af7Sopenharmony_ci	unsigned int* out_result_buffer_size)
1035e5c31af7Sopenharmony_ci{
1036e5c31af7Sopenharmony_ci	*out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1037e5c31af7Sopenharmony_ci
1038e5c31af7Sopenharmony_ci	switch (n_iteration)
1039e5c31af7Sopenharmony_ci	{
1040e5c31af7Sopenharmony_ci	case 0:
1041e5c31af7Sopenharmony_ci	case 1:
1042e5c31af7Sopenharmony_ci	{
1043e5c31af7Sopenharmony_ci		/* Triangles */
1044e5c31af7Sopenharmony_ci		out_outer_tess_levels[0] = 2.0f;
1045e5c31af7Sopenharmony_ci		out_outer_tess_levels[1] = 3.0f;
1046e5c31af7Sopenharmony_ci		out_outer_tess_levels[2] = 4.0f;
1047e5c31af7Sopenharmony_ci
1048e5c31af7Sopenharmony_ci		if (n_iteration == 0)
1049e5c31af7Sopenharmony_ci		{
1050e5c31af7Sopenharmony_ci			out_inner_tess_levels[0] = 4.0f;
1051e5c31af7Sopenharmony_ci			out_inner_tess_levels[1] = 5.0f;
1052e5c31af7Sopenharmony_ci		}
1053e5c31af7Sopenharmony_ci		else
1054e5c31af7Sopenharmony_ci		{
1055e5c31af7Sopenharmony_ci			out_inner_tess_levels[0] = 3.0f;
1056e5c31af7Sopenharmony_ci			out_inner_tess_levels[1] = 4.0f;
1057e5c31af7Sopenharmony_ci		}
1058e5c31af7Sopenharmony_ci
1059e5c31af7Sopenharmony_ci		*out_point_mode		= false;
1060e5c31af7Sopenharmony_ci		*out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
1061e5c31af7Sopenharmony_ci
1062e5c31af7Sopenharmony_ci		break;
1063e5c31af7Sopenharmony_ci	}
1064e5c31af7Sopenharmony_ci
1065e5c31af7Sopenharmony_ci	case 2:
1066e5c31af7Sopenharmony_ci	case 3:
1067e5c31af7Sopenharmony_ci	{
1068e5c31af7Sopenharmony_ci		/* Quads */
1069e5c31af7Sopenharmony_ci		out_outer_tess_levels[0] = 2.0f;
1070e5c31af7Sopenharmony_ci		out_outer_tess_levels[1] = 3.0f;
1071e5c31af7Sopenharmony_ci		out_outer_tess_levels[2] = 4.0f;
1072e5c31af7Sopenharmony_ci		out_outer_tess_levels[3] = 5.0f;
1073e5c31af7Sopenharmony_ci
1074e5c31af7Sopenharmony_ci		if (n_iteration == 2)
1075e5c31af7Sopenharmony_ci		{
1076e5c31af7Sopenharmony_ci			out_inner_tess_levels[0] = 2.0f;
1077e5c31af7Sopenharmony_ci			out_inner_tess_levels[1] = 3.0f;
1078e5c31af7Sopenharmony_ci		}
1079e5c31af7Sopenharmony_ci		else
1080e5c31af7Sopenharmony_ci		{
1081e5c31af7Sopenharmony_ci			out_inner_tess_levels[0] = 4.0f;
1082e5c31af7Sopenharmony_ci			out_inner_tess_levels[1] = 5.0f;
1083e5c31af7Sopenharmony_ci		}
1084e5c31af7Sopenharmony_ci
1085e5c31af7Sopenharmony_ci		*out_point_mode		= false;
1086e5c31af7Sopenharmony_ci		*out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
1087e5c31af7Sopenharmony_ci
1088e5c31af7Sopenharmony_ci		break;
1089e5c31af7Sopenharmony_ci	}
1090e5c31af7Sopenharmony_ci
1091e5c31af7Sopenharmony_ci	default:
1092e5c31af7Sopenharmony_ci	{
1093e5c31af7Sopenharmony_ci		TCU_FAIL("Unrecognized iteration index");
1094e5c31af7Sopenharmony_ci	}
1095e5c31af7Sopenharmony_ci	}
1096e5c31af7Sopenharmony_ci
1097e5c31af7Sopenharmony_ci	if (out_result_buffer_size != DE_NULL)
1098e5c31af7Sopenharmony_ci	{
1099e5c31af7Sopenharmony_ci		*out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1100e5c31af7Sopenharmony_ci			*out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1101e5c31af7Sopenharmony_ci			*out_point_mode);
1102e5c31af7Sopenharmony_ci
1103e5c31af7Sopenharmony_ci		m_n_tessellated_vertices[n_iteration] = *out_result_buffer_size;
1104e5c31af7Sopenharmony_ci		*out_result_buffer_size =
1105e5c31af7Sopenharmony_ci			static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1106e5c31af7Sopenharmony_ci
1107e5c31af7Sopenharmony_ci		DE_ASSERT(*out_result_buffer_size != 0);
1108e5c31af7Sopenharmony_ci	}
1109e5c31af7Sopenharmony_ci}
1110e5c31af7Sopenharmony_ci
1111e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation evaluation shader code.
1112e5c31af7Sopenharmony_ci *
1113e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index, for which the source code is being obtained.
1114e5c31af7Sopenharmony_ci *
1115e5c31af7Sopenharmony_ci *  @return Requested source code.
1116e5c31af7Sopenharmony_ci **/
1117e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceRule2Test::getTECode(unsigned int n_iteration)
1118e5c31af7Sopenharmony_ci{
1119e5c31af7Sopenharmony_ci	unsigned int						 bo_size			  = 0;
1120e5c31af7Sopenharmony_ci	float								 inner_tess_levels[2] = { 0 };
1121e5c31af7Sopenharmony_ci	float								 outer_tess_levels[4] = { 0 };
1122e5c31af7Sopenharmony_ci	bool								 point_mode			  = false;
1123e5c31af7Sopenharmony_ci	_tessellation_primitive_mode		 primitive_mode		  = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
1124e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_ordering vertex_ordering	  = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
1125e5c31af7Sopenharmony_ci
1126e5c31af7Sopenharmony_ci	getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode,
1127e5c31af7Sopenharmony_ci						   &vertex_ordering, &bo_size);
1128e5c31af7Sopenharmony_ci
1129e5c31af7Sopenharmony_ci	return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode,
1130e5c31af7Sopenharmony_ci													 vertex_ordering, point_mode);
1131e5c31af7Sopenharmony_ci}
1132e5c31af7Sopenharmony_ci
1133e5c31af7Sopenharmony_ci/** Verifies result data. Accesses data generated by all iterations.
1134e5c31af7Sopenharmony_ci *
1135e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
1136e5c31af7Sopenharmony_ci *
1137e5c31af7Sopenharmony_ci *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
1138e5c31af7Sopenharmony_ci *                             data generated by subsequent iterations.
1139e5c31af7Sopenharmony_ci **/
1140e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule2Test::verifyResultData(const void** all_iterations_data)
1141e5c31af7Sopenharmony_ci{
1142e5c31af7Sopenharmony_ci	/* Iterate through one tessellated set of vertices for a given primitive type
1143e5c31af7Sopenharmony_ci	 * and identify outer vertices. Make sure exactly the same vertices can be
1144e5c31af7Sopenharmony_ci	 * found in the other set of vertices, generated with different input tessellation
1145e5c31af7Sopenharmony_ci	 * level.
1146e5c31af7Sopenharmony_ci	 */
1147e5c31af7Sopenharmony_ci	for (int n_primitive_type = 0; n_primitive_type < 2; /* triangles / quads */
1148e5c31af7Sopenharmony_ci		 ++n_primitive_type)
1149e5c31af7Sopenharmony_ci	{
1150e5c31af7Sopenharmony_ci		const float*				 data1_ptr		= (const float*)all_iterations_data[n_primitive_type * 2 + 0];
1151e5c31af7Sopenharmony_ci		const float*				 data2_ptr		= (const float*)all_iterations_data[n_primitive_type * 2 + 1];
1152e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = (n_primitive_type == 0) ?
1153e5c31af7Sopenharmony_ci														  TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
1154e5c31af7Sopenharmony_ci														  TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
1155e5c31af7Sopenharmony_ci		std::vector<_vertex> outer_vertices;
1156e5c31af7Sopenharmony_ci
1157e5c31af7Sopenharmony_ci		/* Iterate through all data1 vertices.. */
1158e5c31af7Sopenharmony_ci		for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2]; ++n_vertex)
1159e5c31af7Sopenharmony_ci		{
1160e5c31af7Sopenharmony_ci			/* Check if any of the components is equal to 0 or 1. If so, this could
1161e5c31af7Sopenharmony_ci			 * be an edge vertex.
1162e5c31af7Sopenharmony_ci			 */
1163e5c31af7Sopenharmony_ci			const float* vertex_ptr = data1_ptr + n_vertex * 3; /* components */
1164e5c31af7Sopenharmony_ci
1165e5c31af7Sopenharmony_ci			if (TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, vertex_ptr))
1166e5c31af7Sopenharmony_ci			{
1167e5c31af7Sopenharmony_ci				/* Only add the vertex if it has not been added already to the vector */
1168e5c31af7Sopenharmony_ci				bool has_already_been_added = false;
1169e5c31af7Sopenharmony_ci
1170e5c31af7Sopenharmony_ci				for (std::vector<_vertex>::const_iterator vertex_iterator = outer_vertices.begin();
1171e5c31af7Sopenharmony_ci					 vertex_iterator != outer_vertices.end(); vertex_iterator++)
1172e5c31af7Sopenharmony_ci				{
1173e5c31af7Sopenharmony_ci					if (vertex_iterator->u == vertex_ptr[0] && vertex_iterator->v == vertex_ptr[1] &&
1174e5c31af7Sopenharmony_ci						vertex_iterator->w == vertex_ptr[2])
1175e5c31af7Sopenharmony_ci					{
1176e5c31af7Sopenharmony_ci						has_already_been_added = true;
1177e5c31af7Sopenharmony_ci
1178e5c31af7Sopenharmony_ci						break;
1179e5c31af7Sopenharmony_ci					}
1180e5c31af7Sopenharmony_ci				} /* for (all outer vertices stored so far) */
1181e5c31af7Sopenharmony_ci
1182e5c31af7Sopenharmony_ci				if (!has_already_been_added)
1183e5c31af7Sopenharmony_ci				{
1184e5c31af7Sopenharmony_ci					_vertex vertex;
1185e5c31af7Sopenharmony_ci
1186e5c31af7Sopenharmony_ci					vertex.u = vertex_ptr[0];
1187e5c31af7Sopenharmony_ci					vertex.v = vertex_ptr[1];
1188e5c31af7Sopenharmony_ci					vertex.w = vertex_ptr[2];
1189e5c31af7Sopenharmony_ci
1190e5c31af7Sopenharmony_ci					outer_vertices.push_back(vertex);
1191e5c31af7Sopenharmony_ci				}
1192e5c31af7Sopenharmony_ci			} /* if (input vertex is located on outer edge) */
1193e5c31af7Sopenharmony_ci		}	 /* for (all input vertices) */
1194e5c31af7Sopenharmony_ci
1195e5c31af7Sopenharmony_ci		DE_ASSERT(outer_vertices.size() != 0);
1196e5c31af7Sopenharmony_ci
1197e5c31af7Sopenharmony_ci		/* Now that we know where outer vertices are, make sure they are present in the other data set */
1198e5c31af7Sopenharmony_ci		for (std::vector<_vertex>::const_iterator ref_vertex_iterator = outer_vertices.begin();
1199e5c31af7Sopenharmony_ci			 ref_vertex_iterator != outer_vertices.end(); ref_vertex_iterator++)
1200e5c31af7Sopenharmony_ci		{
1201e5c31af7Sopenharmony_ci			bool		   has_been_found = false;
1202e5c31af7Sopenharmony_ci			const _vertex& ref_vertex	 = *ref_vertex_iterator;
1203e5c31af7Sopenharmony_ci
1204e5c31af7Sopenharmony_ci			for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2 + 1]; ++n_vertex)
1205e5c31af7Sopenharmony_ci			{
1206e5c31af7Sopenharmony_ci				const float* vertex_ptr = data2_ptr + n_vertex * 3; /* components */
1207e5c31af7Sopenharmony_ci
1208e5c31af7Sopenharmony_ci				if (vertex_ptr[0] == ref_vertex.u && vertex_ptr[1] == ref_vertex.v && vertex_ptr[2] == ref_vertex.w)
1209e5c31af7Sopenharmony_ci				{
1210e5c31af7Sopenharmony_ci					has_been_found = true;
1211e5c31af7Sopenharmony_ci
1212e5c31af7Sopenharmony_ci					break;
1213e5c31af7Sopenharmony_ci				}
1214e5c31af7Sopenharmony_ci			} /* for (all vertices in the other data set) */
1215e5c31af7Sopenharmony_ci
1216e5c31af7Sopenharmony_ci			if (!has_been_found)
1217e5c31af7Sopenharmony_ci			{
1218e5c31af7Sopenharmony_ci				float								 cmp_inner_tess_levels[2];
1219e5c31af7Sopenharmony_ci				float								 cmp_outer_tess_levels[4];
1220e5c31af7Sopenharmony_ci				bool								 cmp_point_mode;
1221e5c31af7Sopenharmony_ci				_tessellation_primitive_mode		 cmp_primitive_mode;
1222e5c31af7Sopenharmony_ci				_tessellation_shader_vertex_ordering cmp_vertex_ordering;
1223e5c31af7Sopenharmony_ci				std::string							 primitive_type = (n_primitive_type == 0) ? "triangles" : "quads";
1224e5c31af7Sopenharmony_ci				float								 ref_inner_tess_levels[2];
1225e5c31af7Sopenharmony_ci				float								 ref_outer_tess_levels[4];
1226e5c31af7Sopenharmony_ci				bool								 ref_point_mode;
1227e5c31af7Sopenharmony_ci				_tessellation_primitive_mode		 ref_primitive_mode;
1228e5c31af7Sopenharmony_ci				_tessellation_shader_vertex_ordering ref_vertex_ordering;
1229e5c31af7Sopenharmony_ci
1230e5c31af7Sopenharmony_ci				getIterationProperties(n_primitive_type * 2, ref_inner_tess_levels, ref_outer_tess_levels,
1231e5c31af7Sopenharmony_ci									   &ref_point_mode, &ref_primitive_mode, &ref_vertex_ordering, NULL);
1232e5c31af7Sopenharmony_ci				getIterationProperties(n_primitive_type * 2 + 1, cmp_inner_tess_levels, cmp_outer_tess_levels,
1233e5c31af7Sopenharmony_ci									   &cmp_point_mode, &cmp_primitive_mode, &cmp_vertex_ordering, NULL);
1234e5c31af7Sopenharmony_ci
1235e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Outer vertex"
1236e5c31af7Sopenharmony_ci								   << " (" << ref_vertex.u << ", " << ref_vertex.v << ", " << ref_vertex.w << ")"
1237e5c31af7Sopenharmony_ci								   << " was not found in tessellated data coordinate set generated"
1238e5c31af7Sopenharmony_ci								   << " for primitive type: " << primitive_type.c_str()
1239e5c31af7Sopenharmony_ci								   << ". Reference inner tessellation level:"
1240e5c31af7Sopenharmony_ci								   << " (" << ref_inner_tess_levels[0] << ", " << ref_inner_tess_levels[1]
1241e5c31af7Sopenharmony_ci								   << "), reference outer tessellation level:"
1242e5c31af7Sopenharmony_ci								   << " (" << ref_outer_tess_levels[0] << ", " << ref_outer_tess_levels[1] << ", "
1243e5c31af7Sopenharmony_ci								   << ref_outer_tess_levels[2] << ", " << ref_outer_tess_levels[3]
1244e5c31af7Sopenharmony_ci								   << "), test inner tessellation level:"
1245e5c31af7Sopenharmony_ci								   << " (" << cmp_inner_tess_levels[0] << ", " << cmp_inner_tess_levels[1]
1246e5c31af7Sopenharmony_ci								   << "), reference outer tessellation level:"
1247e5c31af7Sopenharmony_ci								   << " (" << cmp_outer_tess_levels[0] << ", " << cmp_outer_tess_levels[1] << ", "
1248e5c31af7Sopenharmony_ci								   << cmp_outer_tess_levels[2] << ", " << cmp_outer_tess_levels[3] << ")."
1249e5c31af7Sopenharmony_ci								   << tcu::TestLog::EndMessage;
1250e5c31af7Sopenharmony_ci
1251e5c31af7Sopenharmony_ci				TCU_FAIL("Outer edge vertex was not found in tessellated coordinate set generated for "
1252e5c31af7Sopenharmony_ci						 "the same outer tessellation levels and vertex spacing, but different inner "
1253e5c31af7Sopenharmony_ci						 "tessellation levels");
1254e5c31af7Sopenharmony_ci			} /* if (outer edge vertex was not found in the other set) */
1255e5c31af7Sopenharmony_ci		}	 /* for (all outer edge vertices) */
1256e5c31af7Sopenharmony_ci	}		  /* for (both primitive types) */
1257e5c31af7Sopenharmony_ci}
1258e5c31af7Sopenharmony_ci
1259e5c31af7Sopenharmony_ci/** Constructor.
1260e5c31af7Sopenharmony_ci *
1261e5c31af7Sopenharmony_ci *  @param context Rendering context.
1262e5c31af7Sopenharmony_ci *
1263e5c31af7Sopenharmony_ci **/
1264e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule3Test::TessellationShaderInvarianceRule3Test(Context&			  context,
1265e5c31af7Sopenharmony_ci																			 const ExtParameters& extParams)
1266e5c31af7Sopenharmony_ci	: TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule3",
1267e5c31af7Sopenharmony_ci										   "Verifies conformance with third invariance rule")
1268e5c31af7Sopenharmony_ci{
1269e5c31af7Sopenharmony_ci}
1270e5c31af7Sopenharmony_ci
1271e5c31af7Sopenharmony_ci/** Destructor. */
1272e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule3Test::~TessellationShaderInvarianceRule3Test()
1273e5c31af7Sopenharmony_ci{
1274e5c31af7Sopenharmony_ci	/* Left blank intentionally */
1275e5c31af7Sopenharmony_ci}
1276e5c31af7Sopenharmony_ci
1277e5c31af7Sopenharmony_ci/** Retrieves amount of iterations the base test implementation should run before
1278e5c31af7Sopenharmony_ci *  calling global verification routine.
1279e5c31af7Sopenharmony_ci *
1280e5c31af7Sopenharmony_ci *  @return A value that depends on initTestIterations() behavior.
1281e5c31af7Sopenharmony_ci **/
1282e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule3Test::getAmountOfIterations()
1283e5c31af7Sopenharmony_ci{
1284e5c31af7Sopenharmony_ci	if (m_test_iterations.size() == 0)
1285e5c31af7Sopenharmony_ci	{
1286e5c31af7Sopenharmony_ci		initTestIterations();
1287e5c31af7Sopenharmony_ci	}
1288e5c31af7Sopenharmony_ci
1289e5c31af7Sopenharmony_ci	return (unsigned int)m_test_iterations.size();
1290e5c31af7Sopenharmony_ci}
1291e5c31af7Sopenharmony_ci
1292e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation properties.
1293e5c31af7Sopenharmony_ci *
1294e5c31af7Sopenharmony_ci *  @param n_iteration            Iteration index to retrieve the properties for.
1295e5c31af7Sopenharmony_ci *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
1296e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
1297e5c31af7Sopenharmony_ci *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
1298e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
1299e5c31af7Sopenharmony_ci *  @param out_point_mode         Deref will be used to store iteration-specific flag
1300e5c31af7Sopenharmony_ci *                                telling whether point mode should be enabled for given pass.
1301e5c31af7Sopenharmony_ci *                                Must not be NULL.
1302e5c31af7Sopenharmony_ci *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
1303e5c31af7Sopenharmony_ci *                                mode. Must not be NULL.
1304e5c31af7Sopenharmony_ci *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
1305e5c31af7Sopenharmony_ci *                                ordering. Must not be NULL.
1306e5c31af7Sopenharmony_ci *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1307e5c31af7Sopenharmony_ci *                                storage should offer for the draw call to succeed. Can
1308e5c31af7Sopenharmony_ci *                                be NULL.
1309e5c31af7Sopenharmony_ci **/
1310e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule3Test::getIterationProperties(
1311e5c31af7Sopenharmony_ci	unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
1312e5c31af7Sopenharmony_ci	_tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
1313e5c31af7Sopenharmony_ci	unsigned int* out_result_buffer_size)
1314e5c31af7Sopenharmony_ci{
1315e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_iterations.size() > n_iteration);
1316e5c31af7Sopenharmony_ci
1317e5c31af7Sopenharmony_ci	_test_iteration& test_iteration = m_test_iterations[n_iteration];
1318e5c31af7Sopenharmony_ci
1319e5c31af7Sopenharmony_ci	memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1320e5c31af7Sopenharmony_ci	memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1321e5c31af7Sopenharmony_ci
1322e5c31af7Sopenharmony_ci	*out_point_mode		 = false;
1323e5c31af7Sopenharmony_ci	*out_primitive_mode  = test_iteration.primitive_mode;
1324e5c31af7Sopenharmony_ci	*out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1325e5c31af7Sopenharmony_ci
1326e5c31af7Sopenharmony_ci	if (out_result_buffer_size != DE_NULL)
1327e5c31af7Sopenharmony_ci	{
1328e5c31af7Sopenharmony_ci		*out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1329e5c31af7Sopenharmony_ci			*out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing,
1330e5c31af7Sopenharmony_ci			*out_point_mode);
1331e5c31af7Sopenharmony_ci		test_iteration.n_vertices = *out_result_buffer_size;
1332e5c31af7Sopenharmony_ci		*out_result_buffer_size =
1333e5c31af7Sopenharmony_ci			static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1334e5c31af7Sopenharmony_ci
1335e5c31af7Sopenharmony_ci		DE_ASSERT(*out_result_buffer_size != 0);
1336e5c31af7Sopenharmony_ci	}
1337e5c31af7Sopenharmony_ci}
1338e5c31af7Sopenharmony_ci
1339e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation evaluation shader code.
1340e5c31af7Sopenharmony_ci *
1341e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index, for which the source code is being obtained.
1342e5c31af7Sopenharmony_ci *
1343e5c31af7Sopenharmony_ci *  @return Requested source code.
1344e5c31af7Sopenharmony_ci **/
1345e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceRule3Test::getTECode(unsigned int n_iteration)
1346e5c31af7Sopenharmony_ci{
1347e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_iterations.size() > n_iteration);
1348e5c31af7Sopenharmony_ci
1349e5c31af7Sopenharmony_ci	const _test_iteration& test_iteration = m_test_iterations[n_iteration];
1350e5c31af7Sopenharmony_ci
1351e5c31af7Sopenharmony_ci	return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode,
1352e5c31af7Sopenharmony_ci													 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */
1353e5c31af7Sopenharmony_ci}
1354e5c31af7Sopenharmony_ci
1355e5c31af7Sopenharmony_ci/** Initializes test iterations for the test. The following modes and inner/outer tess level
1356e5c31af7Sopenharmony_ci *  configurations are used to form the test set:
1357e5c31af7Sopenharmony_ci *
1358e5c31af7Sopenharmony_ci *  - Inner/outer tessellation level combinations as returned by
1359e5c31af7Sopenharmony_ci *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
1360e5c31af7Sopenharmony_ci *  - All primitive modes;
1361e5c31af7Sopenharmony_ci *  - All vertex spacing modes;
1362e5c31af7Sopenharmony_ci *
1363e5c31af7Sopenharmony_ci *  All permutations are used to generate the test set.
1364e5c31af7Sopenharmony_ci **/
1365e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule3Test::initTestIterations()
1366e5c31af7Sopenharmony_ci{
1367e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_iterations.size() == 0);
1368e5c31af7Sopenharmony_ci
1369e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
1370e5c31af7Sopenharmony_ci	const glw::Functions& gl						  = m_context.getRenderContext().getFunctions();
1371e5c31af7Sopenharmony_ci	glw::GLint			  gl_max_tess_gen_level_value = 0;
1372e5c31af7Sopenharmony_ci
1373e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1374e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1375e5c31af7Sopenharmony_ci
1376e5c31af7Sopenharmony_ci	/* Iterate through all primitive and vertex spacing modes */
1377e5c31af7Sopenharmony_ci	_tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
1378e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1379e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
1380e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1381e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
1382e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD };
1383e5c31af7Sopenharmony_ci
1384e5c31af7Sopenharmony_ci	const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1385e5c31af7Sopenharmony_ci	const unsigned int n_vs_modes		 = sizeof(vs_modes) / sizeof(vs_modes[0]);
1386e5c31af7Sopenharmony_ci
1387e5c31af7Sopenharmony_ci	for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1388e5c31af7Sopenharmony_ci	{
1389e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
1390e5c31af7Sopenharmony_ci
1391e5c31af7Sopenharmony_ci		for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
1392e5c31af7Sopenharmony_ci		{
1393e5c31af7Sopenharmony_ci			_tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
1394e5c31af7Sopenharmony_ci
1395e5c31af7Sopenharmony_ci			/* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
1396e5c31af7Sopenharmony_ci			_tessellation_levels_set levels_set;
1397e5c31af7Sopenharmony_ci
1398e5c31af7Sopenharmony_ci			levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1399e5c31af7Sopenharmony_ci				primitive_mode, gl_max_tess_gen_level_value,
1400e5c31af7Sopenharmony_ci				TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1401e5c31af7Sopenharmony_ci
1402e5c31af7Sopenharmony_ci			/* Iterate through all configurations */
1403e5c31af7Sopenharmony_ci			for (_tessellation_levels_set_const_iterator levels_iterator = levels_set.begin();
1404e5c31af7Sopenharmony_ci				 levels_iterator != levels_set.end(); levels_iterator++)
1405e5c31af7Sopenharmony_ci			{
1406e5c31af7Sopenharmony_ci				const _tessellation_levels& levels = *levels_iterator;
1407e5c31af7Sopenharmony_ci
1408e5c31af7Sopenharmony_ci				/* Create a test descriptor for all the parameters we now have */
1409e5c31af7Sopenharmony_ci				_test_iteration test;
1410e5c31af7Sopenharmony_ci
1411e5c31af7Sopenharmony_ci				memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
1412e5c31af7Sopenharmony_ci				memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
1413e5c31af7Sopenharmony_ci
1414e5c31af7Sopenharmony_ci				test.primitive_mode = primitive_mode;
1415e5c31af7Sopenharmony_ci				test.vertex_spacing = vs_mode;
1416e5c31af7Sopenharmony_ci
1417e5c31af7Sopenharmony_ci				m_test_iterations.push_back(test);
1418e5c31af7Sopenharmony_ci			} /* for (all inner/outer tessellation levels) */
1419e5c31af7Sopenharmony_ci		}	 /* for (all vertex spacing modes) */
1420e5c31af7Sopenharmony_ci	}		  /* for (all primitive modes) */
1421e5c31af7Sopenharmony_ci}
1422e5c31af7Sopenharmony_ci
1423e5c31af7Sopenharmony_ci/** Verifies result data on per-iteration basis.
1424e5c31af7Sopenharmony_ci *
1425e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
1426e5c31af7Sopenharmony_ci *
1427e5c31af7Sopenharmony_ci *  @param n_iteration Index of iteration the check should be performed for.
1428e5c31af7Sopenharmony_ci *  @param data        Points to array of vec3s storing the vertices as
1429e5c31af7Sopenharmony_ci *                     generated by tessellation
1430e5c31af7Sopenharmony_ci **/
1431e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule3Test::verifyResultDataForIteration(unsigned int n_iteration, const void* data)
1432e5c31af7Sopenharmony_ci{
1433e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_iterations.size() > n_iteration);
1434e5c31af7Sopenharmony_ci
1435e5c31af7Sopenharmony_ci	const glw::GLfloat*	data_float	 = (const glw::GLfloat*)data;
1436e5c31af7Sopenharmony_ci	const _test_iteration& test_iteration = m_test_iterations[n_iteration];
1437e5c31af7Sopenharmony_ci
1438e5c31af7Sopenharmony_ci	/* Iterate through all generated vertices.. */
1439e5c31af7Sopenharmony_ci	for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex)
1440e5c31af7Sopenharmony_ci	{
1441e5c31af7Sopenharmony_ci		_vertex				expected_vertex;
1442e5c31af7Sopenharmony_ci		const glw::GLfloat* vertex_data = data_float + 3 /* components */ * n_vertex;
1443e5c31af7Sopenharmony_ci
1444e5c31af7Sopenharmony_ci		expected_vertex.u = -1.0f;
1445e5c31af7Sopenharmony_ci		expected_vertex.v = -1.0f;
1446e5c31af7Sopenharmony_ci		expected_vertex.w = -1.0f;
1447e5c31af7Sopenharmony_ci
1448e5c31af7Sopenharmony_ci		/* Make sure that for each vertex, the following language from the extension
1449e5c31af7Sopenharmony_ci		 * spec is followed:
1450e5c31af7Sopenharmony_ci		 */
1451e5c31af7Sopenharmony_ci		switch (test_iteration.primitive_mode)
1452e5c31af7Sopenharmony_ci		{
1453e5c31af7Sopenharmony_ci		case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
1454e5c31af7Sopenharmony_ci		{
1455e5c31af7Sopenharmony_ci			/* For isoline tessellation, if it generates vertices at (0,x) and (1,x)
1456e5c31af7Sopenharmony_ci			 * where <x> is not zero, it will also generate vertices at exactly (0,1-x)
1457e5c31af7Sopenharmony_ci			 * and (1,1-x), respectively.
1458e5c31af7Sopenharmony_ci			 */
1459e5c31af7Sopenharmony_ci			if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f)
1460e5c31af7Sopenharmony_ci			{
1461e5c31af7Sopenharmony_ci				expected_vertex.u = vertex_data[0];
1462e5c31af7Sopenharmony_ci				expected_vertex.v = 1.0f - vertex_data[1];
1463e5c31af7Sopenharmony_ci				expected_vertex.w = -1.0f;
1464e5c31af7Sopenharmony_ci			}
1465e5c31af7Sopenharmony_ci			else if (vertex_data[0] == 1.0f && vertex_data[1] != 0.0f)
1466e5c31af7Sopenharmony_ci			{
1467e5c31af7Sopenharmony_ci				expected_vertex.u = vertex_data[0];
1468e5c31af7Sopenharmony_ci				expected_vertex.v = 1.0f - vertex_data[1];
1469e5c31af7Sopenharmony_ci				expected_vertex.w = -1.0f;
1470e5c31af7Sopenharmony_ci			}
1471e5c31af7Sopenharmony_ci
1472e5c31af7Sopenharmony_ci			break;
1473e5c31af7Sopenharmony_ci		} /* case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES: */
1474e5c31af7Sopenharmony_ci
1475e5c31af7Sopenharmony_ci		case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1476e5c31af7Sopenharmony_ci		{
1477e5c31af7Sopenharmony_ci			/* For quad tessellation, if the subdivision generates a vertex with
1478e5c31af7Sopenharmony_ci			 * coordinates of (x,0) or (0,x), it will also generate a vertex with
1479e5c31af7Sopenharmony_ci			 * coordinates of exactly (1-x,0) or (0,1-x), respectively.
1480e5c31af7Sopenharmony_ci			 */
1481e5c31af7Sopenharmony_ci			if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f)
1482e5c31af7Sopenharmony_ci			{
1483e5c31af7Sopenharmony_ci				expected_vertex.u = 1.0f - vertex_data[0];
1484e5c31af7Sopenharmony_ci				expected_vertex.v = vertex_data[1];
1485e5c31af7Sopenharmony_ci				expected_vertex.w = -1.0f;
1486e5c31af7Sopenharmony_ci			}
1487e5c31af7Sopenharmony_ci			else if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f)
1488e5c31af7Sopenharmony_ci			{
1489e5c31af7Sopenharmony_ci				expected_vertex.u = vertex_data[0];
1490e5c31af7Sopenharmony_ci				expected_vertex.v = 1.0f - vertex_data[1];
1491e5c31af7Sopenharmony_ci				expected_vertex.w = -1.0f;
1492e5c31af7Sopenharmony_ci			}
1493e5c31af7Sopenharmony_ci
1494e5c31af7Sopenharmony_ci			break;
1495e5c31af7Sopenharmony_ci		} /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1496e5c31af7Sopenharmony_ci
1497e5c31af7Sopenharmony_ci		case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1498e5c31af7Sopenharmony_ci		{
1499e5c31af7Sopenharmony_ci			/* For triangle tessellation, if the subdivision generates a vertex with
1500e5c31af7Sopenharmony_ci			 * tessellation coordinates of the form (0,x,1-x), (x,0,1-x), or (x,1-x,0),
1501e5c31af7Sopenharmony_ci			 * it will also generate a vertex with coordinates of exactly (0,1-x,x),
1502e5c31af7Sopenharmony_ci			 * (1-x,0,x), or (1-x,x,0), respectively.
1503e5c31af7Sopenharmony_ci			 */
1504e5c31af7Sopenharmony_ci			if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f && vertex_data[2] == (1.0f - vertex_data[1]))
1505e5c31af7Sopenharmony_ci			{
1506e5c31af7Sopenharmony_ci				expected_vertex.u = vertex_data[0];
1507e5c31af7Sopenharmony_ci				expected_vertex.v = vertex_data[2];
1508e5c31af7Sopenharmony_ci				expected_vertex.w = vertex_data[1];
1509e5c31af7Sopenharmony_ci			}
1510e5c31af7Sopenharmony_ci			else if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f && vertex_data[2] == (1.0f - vertex_data[0]))
1511e5c31af7Sopenharmony_ci			{
1512e5c31af7Sopenharmony_ci				expected_vertex.u = vertex_data[2];
1513e5c31af7Sopenharmony_ci				expected_vertex.v = vertex_data[1];
1514e5c31af7Sopenharmony_ci				expected_vertex.w = vertex_data[0];
1515e5c31af7Sopenharmony_ci			}
1516e5c31af7Sopenharmony_ci			else if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0.0f)
1517e5c31af7Sopenharmony_ci			{
1518e5c31af7Sopenharmony_ci				expected_vertex.u = vertex_data[1];
1519e5c31af7Sopenharmony_ci				expected_vertex.v = vertex_data[0];
1520e5c31af7Sopenharmony_ci				expected_vertex.w = vertex_data[2];
1521e5c31af7Sopenharmony_ci			}
1522e5c31af7Sopenharmony_ci
1523e5c31af7Sopenharmony_ci			break;
1524e5c31af7Sopenharmony_ci		} /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1525e5c31af7Sopenharmony_ci
1526e5c31af7Sopenharmony_ci		default:
1527e5c31af7Sopenharmony_ci		{
1528e5c31af7Sopenharmony_ci			TCU_FAIL("Primitive mode unrecognized");
1529e5c31af7Sopenharmony_ci		}
1530e5c31af7Sopenharmony_ci		} /* switch (test_iteration.primitive_mode) */
1531e5c31af7Sopenharmony_ci
1532e5c31af7Sopenharmony_ci		/* If any of the "expected vertex"'s components is no longer negative,
1533e5c31af7Sopenharmony_ci		 * make sure the vertex can be found in the result data */
1534e5c31af7Sopenharmony_ci		if (expected_vertex.u >= 0.0f || expected_vertex.v >= 0.0f || expected_vertex.w >= 0.0f)
1535e5c31af7Sopenharmony_ci		{
1536e5c31af7Sopenharmony_ci			bool has_been_found = false;
1537e5c31af7Sopenharmony_ci
1538e5c31af7Sopenharmony_ci			for (unsigned int n_find_vertex = 0; n_find_vertex < test_iteration.n_vertices; ++n_find_vertex)
1539e5c31af7Sopenharmony_ci			{
1540e5c31af7Sopenharmony_ci				const glw::GLfloat* current_vertex_data = data_float + 3 /* components */ * n_find_vertex;
1541e5c31af7Sopenharmony_ci
1542e5c31af7Sopenharmony_ci				const glw::GLfloat epsilon	 = 1e-4f;
1543e5c31af7Sopenharmony_ci				glw::GLfloat	   absDelta[3] = { de::abs(current_vertex_data[0] - expected_vertex.u),
1544e5c31af7Sopenharmony_ci											 de::abs(current_vertex_data[1] - expected_vertex.v),
1545e5c31af7Sopenharmony_ci											 de::abs(current_vertex_data[2] - expected_vertex.w) };
1546e5c31af7Sopenharmony_ci
1547e5c31af7Sopenharmony_ci				if (absDelta[0] < epsilon && absDelta[1] < epsilon &&
1548e5c31af7Sopenharmony_ci					((expected_vertex.w < 0.0f) || (expected_vertex.w >= 0.0f && absDelta[2] < epsilon)))
1549e5c31af7Sopenharmony_ci				{
1550e5c31af7Sopenharmony_ci					has_been_found = true;
1551e5c31af7Sopenharmony_ci
1552e5c31af7Sopenharmony_ci					break;
1553e5c31af7Sopenharmony_ci				} /* if (the vertex data matches the expected vertex data) */
1554e5c31af7Sopenharmony_ci			}	 /* for (all generated vertices)*/
1555e5c31af7Sopenharmony_ci
1556e5c31af7Sopenharmony_ci			if (!has_been_found)
1557e5c31af7Sopenharmony_ci			{
1558e5c31af7Sopenharmony_ci				TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator.");
1559e5c31af7Sopenharmony_ci			}
1560e5c31af7Sopenharmony_ci		} /* if (any of the components of expected_vertex is no longer negative) */
1561e5c31af7Sopenharmony_ci	}	 /* for (all generated vertices) */
1562e5c31af7Sopenharmony_ci}
1563e5c31af7Sopenharmony_ci
1564e5c31af7Sopenharmony_ci/** Constructor.
1565e5c31af7Sopenharmony_ci *
1566e5c31af7Sopenharmony_ci *  @param context Rendering context.
1567e5c31af7Sopenharmony_ci *
1568e5c31af7Sopenharmony_ci **/
1569e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule4Test::TessellationShaderInvarianceRule4Test(Context&			  context,
1570e5c31af7Sopenharmony_ci																			 const ExtParameters& extParams)
1571e5c31af7Sopenharmony_ci	: TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule4",
1572e5c31af7Sopenharmony_ci										   "Verifies conformance with fourth invariance rule")
1573e5c31af7Sopenharmony_ci{
1574e5c31af7Sopenharmony_ci}
1575e5c31af7Sopenharmony_ci
1576e5c31af7Sopenharmony_ci/** Destructor. */
1577e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule4Test::~TessellationShaderInvarianceRule4Test()
1578e5c31af7Sopenharmony_ci{
1579e5c31af7Sopenharmony_ci	/* Left blank intentionally */
1580e5c31af7Sopenharmony_ci}
1581e5c31af7Sopenharmony_ci
1582e5c31af7Sopenharmony_ci/** Retrieves amount of iterations the base test implementation should run before
1583e5c31af7Sopenharmony_ci *  calling global verification routine.
1584e5c31af7Sopenharmony_ci *
1585e5c31af7Sopenharmony_ci *  @return A value that depends on initTestIterations() behavior.
1586e5c31af7Sopenharmony_ci **/
1587e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule4Test::getAmountOfIterations()
1588e5c31af7Sopenharmony_ci{
1589e5c31af7Sopenharmony_ci	if (m_test_iterations.size() == 0)
1590e5c31af7Sopenharmony_ci	{
1591e5c31af7Sopenharmony_ci		initTestIterations();
1592e5c31af7Sopenharmony_ci	}
1593e5c31af7Sopenharmony_ci
1594e5c31af7Sopenharmony_ci	return (unsigned int)m_test_iterations.size();
1595e5c31af7Sopenharmony_ci}
1596e5c31af7Sopenharmony_ci
1597e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation properties.
1598e5c31af7Sopenharmony_ci *
1599e5c31af7Sopenharmony_ci *  @param n_iteration            Iteration index to retrieve the properties for.
1600e5c31af7Sopenharmony_ci *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
1601e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
1602e5c31af7Sopenharmony_ci *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
1603e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
1604e5c31af7Sopenharmony_ci *  @param out_point_mode         Deref will be used to store iteration-specific flag
1605e5c31af7Sopenharmony_ci *                                telling whether point mode should be enabled for given pass.
1606e5c31af7Sopenharmony_ci *                                Must not be NULL.
1607e5c31af7Sopenharmony_ci *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
1608e5c31af7Sopenharmony_ci *                                mode. Must not be NULL.
1609e5c31af7Sopenharmony_ci *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
1610e5c31af7Sopenharmony_ci *                                ordering. Must not be NULL.
1611e5c31af7Sopenharmony_ci *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1612e5c31af7Sopenharmony_ci *                                storage should offer for the draw call to succeed. Can
1613e5c31af7Sopenharmony_ci *                                be NULL.
1614e5c31af7Sopenharmony_ci **/
1615e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule4Test::getIterationProperties(
1616e5c31af7Sopenharmony_ci	unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
1617e5c31af7Sopenharmony_ci	_tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
1618e5c31af7Sopenharmony_ci	unsigned int* out_result_buffer_size)
1619e5c31af7Sopenharmony_ci{
1620e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_iterations.size() > n_iteration);
1621e5c31af7Sopenharmony_ci
1622e5c31af7Sopenharmony_ci	_test_iteration& test_iteration = m_test_iterations[n_iteration];
1623e5c31af7Sopenharmony_ci
1624e5c31af7Sopenharmony_ci	memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1625e5c31af7Sopenharmony_ci	memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1626e5c31af7Sopenharmony_ci
1627e5c31af7Sopenharmony_ci	*out_point_mode		 = false;
1628e5c31af7Sopenharmony_ci	*out_primitive_mode  = test_iteration.primitive_mode;
1629e5c31af7Sopenharmony_ci	*out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1630e5c31af7Sopenharmony_ci
1631e5c31af7Sopenharmony_ci	if (out_result_buffer_size != DE_NULL)
1632e5c31af7Sopenharmony_ci	{
1633e5c31af7Sopenharmony_ci		*out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1634e5c31af7Sopenharmony_ci			*out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing,
1635e5c31af7Sopenharmony_ci			*out_point_mode);
1636e5c31af7Sopenharmony_ci		test_iteration.n_vertices = *out_result_buffer_size;
1637e5c31af7Sopenharmony_ci		*out_result_buffer_size =
1638e5c31af7Sopenharmony_ci			static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1639e5c31af7Sopenharmony_ci
1640e5c31af7Sopenharmony_ci		DE_ASSERT(*out_result_buffer_size != 0);
1641e5c31af7Sopenharmony_ci	}
1642e5c31af7Sopenharmony_ci}
1643e5c31af7Sopenharmony_ci
1644e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation evaluation shader code.
1645e5c31af7Sopenharmony_ci *
1646e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index, for which the source code is being obtained.
1647e5c31af7Sopenharmony_ci *
1648e5c31af7Sopenharmony_ci *  @return Requested source code.
1649e5c31af7Sopenharmony_ci **/
1650e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceRule4Test::getTECode(unsigned int n_iteration)
1651e5c31af7Sopenharmony_ci{
1652e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_iterations.size() > n_iteration);
1653e5c31af7Sopenharmony_ci
1654e5c31af7Sopenharmony_ci	const _test_iteration& test_iteration = m_test_iterations[n_iteration];
1655e5c31af7Sopenharmony_ci
1656e5c31af7Sopenharmony_ci	return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode,
1657e5c31af7Sopenharmony_ci													 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */
1658e5c31af7Sopenharmony_ci}
1659e5c31af7Sopenharmony_ci
1660e5c31af7Sopenharmony_ci/** Initializes test iterations for the test. The following modes and inner/outer tess level
1661e5c31af7Sopenharmony_ci *  configurations are used to form the test set:
1662e5c31af7Sopenharmony_ci *
1663e5c31af7Sopenharmony_ci *  - Inner/outer tessellation level combinations as returned by
1664e5c31af7Sopenharmony_ci *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
1665e5c31af7Sopenharmony_ci *  - 'Quads' and 'Triangles' primitive modes;
1666e5c31af7Sopenharmony_ci *  - All vertex spacing modes;
1667e5c31af7Sopenharmony_ci *
1668e5c31af7Sopenharmony_ci *  All permutations are used to generate the test set.
1669e5c31af7Sopenharmony_ci **/
1670e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule4Test::initTestIterations()
1671e5c31af7Sopenharmony_ci{
1672e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_iterations.size() == 0);
1673e5c31af7Sopenharmony_ci
1674e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
1675e5c31af7Sopenharmony_ci	const glw::Functions& gl						  = m_context.getRenderContext().getFunctions();
1676e5c31af7Sopenharmony_ci	glw::GLint			  gl_max_tess_gen_level_value = 0;
1677e5c31af7Sopenharmony_ci
1678e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1679e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1680e5c31af7Sopenharmony_ci
1681e5c31af7Sopenharmony_ci	/* Iterate through all primitive and vertex spacing modes relevant to the test */
1682e5c31af7Sopenharmony_ci	_tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1683e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
1684e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1685e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
1686e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD };
1687e5c31af7Sopenharmony_ci
1688e5c31af7Sopenharmony_ci	const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1689e5c31af7Sopenharmony_ci	const unsigned int n_vs_modes		 = sizeof(vs_modes) / sizeof(vs_modes[0]);
1690e5c31af7Sopenharmony_ci
1691e5c31af7Sopenharmony_ci	for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1692e5c31af7Sopenharmony_ci	{
1693e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
1694e5c31af7Sopenharmony_ci
1695e5c31af7Sopenharmony_ci		for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
1696e5c31af7Sopenharmony_ci		{
1697e5c31af7Sopenharmony_ci			_tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
1698e5c31af7Sopenharmony_ci
1699e5c31af7Sopenharmony_ci			/* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
1700e5c31af7Sopenharmony_ci			_tessellation_levels_set levels;
1701e5c31af7Sopenharmony_ci
1702e5c31af7Sopenharmony_ci			levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1703e5c31af7Sopenharmony_ci				primitive_mode, gl_max_tess_gen_level_value,
1704e5c31af7Sopenharmony_ci				TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1705e5c31af7Sopenharmony_ci
1706e5c31af7Sopenharmony_ci			/* Iterate through all configurations */
1707e5c31af7Sopenharmony_ci			for (_tessellation_levels_set_const_iterator levels_iterator = levels.begin();
1708e5c31af7Sopenharmony_ci				 levels_iterator != levels.end(); levels_iterator++)
1709e5c31af7Sopenharmony_ci			{
1710e5c31af7Sopenharmony_ci				const _tessellation_levels& current_levels = *levels_iterator;
1711e5c31af7Sopenharmony_ci
1712e5c31af7Sopenharmony_ci				/* Create a test descriptor for all the parameters we now have.
1713e5c31af7Sopenharmony_ci				 *
1714e5c31af7Sopenharmony_ci				 * The set we're operating on uses different outer tessellation level values, so we
1715e5c31af7Sopenharmony_ci				 * need to make sure the levels are set to the same FP values in order for the test
1716e5c31af7Sopenharmony_ci				 * to succeed. */
1717e5c31af7Sopenharmony_ci				_test_iteration test;
1718e5c31af7Sopenharmony_ci
1719e5c31af7Sopenharmony_ci				memcpy(test.inner_tess_levels, current_levels.inner, sizeof(test.inner_tess_levels));
1720e5c31af7Sopenharmony_ci
1721e5c31af7Sopenharmony_ci				for (int n = 0; n < 4 /* outer tess levels */; ++n)
1722e5c31af7Sopenharmony_ci				{
1723e5c31af7Sopenharmony_ci					test.outer_tess_levels[n] = current_levels.outer[0];
1724e5c31af7Sopenharmony_ci				}
1725e5c31af7Sopenharmony_ci
1726e5c31af7Sopenharmony_ci				test.primitive_mode = primitive_mode;
1727e5c31af7Sopenharmony_ci				test.vertex_spacing = vs_mode;
1728e5c31af7Sopenharmony_ci
1729e5c31af7Sopenharmony_ci				m_test_iterations.push_back(test);
1730e5c31af7Sopenharmony_ci			} /* for (all inner/outer tessellation levels) */
1731e5c31af7Sopenharmony_ci		}	 /* for (all vertex spacing modes) */
1732e5c31af7Sopenharmony_ci	}		  /* for (all primitive modes) */
1733e5c31af7Sopenharmony_ci}
1734e5c31af7Sopenharmony_ci
1735e5c31af7Sopenharmony_ci/** Verifies user-provided vertex data can be found in the provided vertex data array.
1736e5c31af7Sopenharmony_ci *
1737e5c31af7Sopenharmony_ci *  @param vertex_data                     Vertex data array the requested vertex data are to be found in.
1738e5c31af7Sopenharmony_ci *  @param n_vertices                      Amount of vertices declared in @param vertex_data;
1739e5c31af7Sopenharmony_ci *  @param vertex_data_seeked              Vertex data to be found in @param vertex_data;
1740e5c31af7Sopenharmony_ci *  @param n_vertex_data_seeked_components Amount of components to take into account.
1741e5c31af7Sopenharmony_ci *
1742e5c31af7Sopenharmony_ci *  @return true if the vertex data was found, false otherwise.
1743e5c31af7Sopenharmony_ci **/
1744e5c31af7Sopenharmony_cibool TessellationShaderInvarianceRule4Test::isVertexDefined(const float* vertex_data, unsigned int n_vertices,
1745e5c31af7Sopenharmony_ci															const float* vertex_data_seeked,
1746e5c31af7Sopenharmony_ci															unsigned int n_vertex_data_seeked_components)
1747e5c31af7Sopenharmony_ci{
1748e5c31af7Sopenharmony_ci	bool result = false;
1749e5c31af7Sopenharmony_ci
1750e5c31af7Sopenharmony_ci	DE_ASSERT(n_vertex_data_seeked_components >= 2);
1751e5c31af7Sopenharmony_ci
1752e5c31af7Sopenharmony_ci	for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
1753e5c31af7Sopenharmony_ci	{
1754e5c31af7Sopenharmony_ci		const float* current_vertex_data = vertex_data + 3 /* components */ * n_vertex;
1755e5c31af7Sopenharmony_ci
1756e5c31af7Sopenharmony_ci		if ((vertex_data_seeked[0] == current_vertex_data[0]) && (vertex_data_seeked[1] == current_vertex_data[1]) &&
1757e5c31af7Sopenharmony_ci			((n_vertex_data_seeked_components < 3) ||
1758e5c31af7Sopenharmony_ci			 (n_vertex_data_seeked_components >= 3 && (vertex_data_seeked[2] == current_vertex_data[2]))))
1759e5c31af7Sopenharmony_ci		{
1760e5c31af7Sopenharmony_ci			result = true;
1761e5c31af7Sopenharmony_ci
1762e5c31af7Sopenharmony_ci			break;
1763e5c31af7Sopenharmony_ci		} /* if (components match) */
1764e5c31af7Sopenharmony_ci	}	 /* for (all vertices) */
1765e5c31af7Sopenharmony_ci
1766e5c31af7Sopenharmony_ci	return result;
1767e5c31af7Sopenharmony_ci}
1768e5c31af7Sopenharmony_ci
1769e5c31af7Sopenharmony_ci/** Verifies result data on per-iteration basis.
1770e5c31af7Sopenharmony_ci *
1771e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
1772e5c31af7Sopenharmony_ci *
1773e5c31af7Sopenharmony_ci *  @param n_iteration Index of iteration the check should be performed for.
1774e5c31af7Sopenharmony_ci *  @param data        Points to array of vec3s storing the vertices as
1775e5c31af7Sopenharmony_ci *                     generated by tessellation
1776e5c31af7Sopenharmony_ci **/
1777e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule4Test::verifyResultDataForIteration(unsigned int n_iteration, const void* data)
1778e5c31af7Sopenharmony_ci{
1779e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_iterations.size() > n_iteration);
1780e5c31af7Sopenharmony_ci
1781e5c31af7Sopenharmony_ci	const glw::GLfloat*	data_float	 = (const glw::GLfloat*)data;
1782e5c31af7Sopenharmony_ci	const _test_iteration& test_iteration = m_test_iterations[n_iteration];
1783e5c31af7Sopenharmony_ci
1784e5c31af7Sopenharmony_ci	/* Iterate through all generated vertices.. */
1785e5c31af7Sopenharmony_ci	for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex)
1786e5c31af7Sopenharmony_ci	{
1787e5c31af7Sopenharmony_ci		std::vector<_vertex> expected_vertices;
1788e5c31af7Sopenharmony_ci		const glw::GLfloat*  vertex_data = data_float + 3 /* components */ * n_vertex;
1789e5c31af7Sopenharmony_ci
1790e5c31af7Sopenharmony_ci		/* Make sure that for each vertex, the following language from the extension
1791e5c31af7Sopenharmony_ci		 * spec is followed:
1792e5c31af7Sopenharmony_ci		 */
1793e5c31af7Sopenharmony_ci		switch (test_iteration.primitive_mode)
1794e5c31af7Sopenharmony_ci		{
1795e5c31af7Sopenharmony_ci		case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1796e5c31af7Sopenharmony_ci		{
1797e5c31af7Sopenharmony_ci			/* For quad tessellation, if vertices at (x,0) and (1-x,0) are generated
1798e5c31af7Sopenharmony_ci			 * when subdividing the v==0 edge, vertices must be generated at (0,x) and
1799e5c31af7Sopenharmony_ci			 * (0,1-x) when subdividing an otherwise identical u==0 edge.
1800e5c31af7Sopenharmony_ci			 */
1801e5c31af7Sopenharmony_ci			if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f)
1802e5c31af7Sopenharmony_ci			{
1803e5c31af7Sopenharmony_ci				const float paired_vertex_data[] = { 1.0f - vertex_data[0], vertex_data[1] };
1804e5c31af7Sopenharmony_ci
1805e5c31af7Sopenharmony_ci				if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 2)) /* components */
1806e5c31af7Sopenharmony_ci				{
1807e5c31af7Sopenharmony_ci					_vertex expected_vertex;
1808e5c31af7Sopenharmony_ci
1809e5c31af7Sopenharmony_ci					/* First expected vertex */
1810e5c31af7Sopenharmony_ci					expected_vertex.u = vertex_data[1];
1811e5c31af7Sopenharmony_ci					expected_vertex.v = vertex_data[0];
1812e5c31af7Sopenharmony_ci					expected_vertex.w = -1.0f;
1813e5c31af7Sopenharmony_ci
1814e5c31af7Sopenharmony_ci					expected_vertices.push_back(expected_vertex);
1815e5c31af7Sopenharmony_ci
1816e5c31af7Sopenharmony_ci					/* The other expected vertex */
1817e5c31af7Sopenharmony_ci					expected_vertex.u = vertex_data[1];
1818e5c31af7Sopenharmony_ci					expected_vertex.v = 1.0f - vertex_data[0];
1819e5c31af7Sopenharmony_ci
1820e5c31af7Sopenharmony_ci					expected_vertices.push_back(expected_vertex);
1821e5c31af7Sopenharmony_ci				} /* if (the other required vertex is defined) */
1822e5c31af7Sopenharmony_ci			}	 /* if (the first required vertex is defined) */
1823e5c31af7Sopenharmony_ci
1824e5c31af7Sopenharmony_ci			break;
1825e5c31af7Sopenharmony_ci		} /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1826e5c31af7Sopenharmony_ci
1827e5c31af7Sopenharmony_ci		case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1828e5c31af7Sopenharmony_ci		{
1829e5c31af7Sopenharmony_ci			/* For triangular tessellation, if vertices at (x,1-x,0) and (1-x,x,0) are
1830e5c31af7Sopenharmony_ci			 * generated when subdividing the w==0 edge, vertices must be generated at
1831e5c31af7Sopenharmony_ci			 * (x,0,1-x) and (1-x,0,x) when subdividing an otherwise identical v==0
1832e5c31af7Sopenharmony_ci			 * edge.
1833e5c31af7Sopenharmony_ci			 */
1834e5c31af7Sopenharmony_ci			if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0)
1835e5c31af7Sopenharmony_ci			{
1836e5c31af7Sopenharmony_ci				const float paired_vertex_data[] = { vertex_data[1], vertex_data[0], vertex_data[2] };
1837e5c31af7Sopenharmony_ci
1838e5c31af7Sopenharmony_ci				if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 3)) /* components */
1839e5c31af7Sopenharmony_ci				{
1840e5c31af7Sopenharmony_ci					_vertex expected_vertex;
1841e5c31af7Sopenharmony_ci
1842e5c31af7Sopenharmony_ci					/* First expected vertex */
1843e5c31af7Sopenharmony_ci					expected_vertex.u = vertex_data[0];
1844e5c31af7Sopenharmony_ci					expected_vertex.v = vertex_data[2];
1845e5c31af7Sopenharmony_ci					expected_vertex.w = vertex_data[1];
1846e5c31af7Sopenharmony_ci
1847e5c31af7Sopenharmony_ci					expected_vertices.push_back(expected_vertex);
1848e5c31af7Sopenharmony_ci
1849e5c31af7Sopenharmony_ci					/* The other expected vertex */
1850e5c31af7Sopenharmony_ci					expected_vertex.u = vertex_data[1];
1851e5c31af7Sopenharmony_ci					expected_vertex.v = vertex_data[2];
1852e5c31af7Sopenharmony_ci					expected_vertex.w = vertex_data[0];
1853e5c31af7Sopenharmony_ci
1854e5c31af7Sopenharmony_ci					expected_vertices.push_back(expected_vertex);
1855e5c31af7Sopenharmony_ci				} /* if (the other required vertex is defined) */
1856e5c31af7Sopenharmony_ci			}	 /* if (the firsst required vertex is defined) */
1857e5c31af7Sopenharmony_ci
1858e5c31af7Sopenharmony_ci			break;
1859e5c31af7Sopenharmony_ci		} /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1860e5c31af7Sopenharmony_ci
1861e5c31af7Sopenharmony_ci		default:
1862e5c31af7Sopenharmony_ci		{
1863e5c31af7Sopenharmony_ci			TCU_FAIL("Primitive mode unrecognized");
1864e5c31af7Sopenharmony_ci		}
1865e5c31af7Sopenharmony_ci		} /* switch (test_iteration.primitive_mode) */
1866e5c31af7Sopenharmony_ci
1867e5c31af7Sopenharmony_ci		/* Iterate through all expected vertices */
1868e5c31af7Sopenharmony_ci		for (std::vector<_vertex>::const_iterator expected_vertex_iterator = expected_vertices.begin();
1869e5c31af7Sopenharmony_ci			 expected_vertex_iterator != expected_vertices.end(); expected_vertex_iterator++)
1870e5c31af7Sopenharmony_ci		{
1871e5c31af7Sopenharmony_ci			const _vertex& expected_vertex		 = *expected_vertex_iterator;
1872e5c31af7Sopenharmony_ci			const float	expected_vertex_raw[] = { expected_vertex.u, expected_vertex.v, expected_vertex.w };
1873e5c31af7Sopenharmony_ci			bool		   has_been_found		 = false;
1874e5c31af7Sopenharmony_ci
1875e5c31af7Sopenharmony_ci			has_been_found = isVertexDefined(data_float, test_iteration.n_vertices, expected_vertex_raw,
1876e5c31af7Sopenharmony_ci											 (expected_vertex.w < 0) ? 2 : 3);
1877e5c31af7Sopenharmony_ci
1878e5c31af7Sopenharmony_ci			if (!has_been_found)
1879e5c31af7Sopenharmony_ci			{
1880e5c31af7Sopenharmony_ci				std::stringstream expected_vertex_sstream;
1881e5c31af7Sopenharmony_ci
1882e5c31af7Sopenharmony_ci				expected_vertex_sstream << expected_vertex.u << ", " << expected_vertex.v;
1883e5c31af7Sopenharmony_ci
1884e5c31af7Sopenharmony_ci				if (expected_vertex.w >= 0.0f)
1885e5c31af7Sopenharmony_ci				{
1886e5c31af7Sopenharmony_ci					expected_vertex_sstream << ", " << expected_vertex.w;
1887e5c31af7Sopenharmony_ci				}
1888e5c31af7Sopenharmony_ci
1889e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode:"
1890e5c31af7Sopenharmony_ci								   << "["
1891e5c31af7Sopenharmony_ci								   << TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration.primitive_mode)
1892e5c31af7Sopenharmony_ci								   << "]"
1893e5c31af7Sopenharmony_ci								   << "and vertex spacing mode:"
1894e5c31af7Sopenharmony_ci								   << "[" << TessellationShaderUtils::getESTokenForVertexSpacingMode(
1895e5c31af7Sopenharmony_ci												 test_iteration.vertex_spacing)
1896e5c31af7Sopenharmony_ci								   << "]"
1897e5c31af7Sopenharmony_ci								   << " and inner tessellation levels:[" << test_iteration.inner_tess_levels[0] << ", "
1898e5c31af7Sopenharmony_ci								   << test_iteration.inner_tess_levels[1] << ") "
1899e5c31af7Sopenharmony_ci								   << " and outer tessellation levels:[" << test_iteration.outer_tess_levels[0] << ", "
1900e5c31af7Sopenharmony_ci								   << test_iteration.outer_tess_levels[1] << ", " << test_iteration.outer_tess_levels[2]
1901e5c31af7Sopenharmony_ci								   << ", " << test_iteration.outer_tess_levels[3] << ") "
1902e5c31af7Sopenharmony_ci								   << " the following vertex was expected:[" << expected_vertex_sstream.str().c_str()
1903e5c31af7Sopenharmony_ci								   << "] but was not found in the tessellated cooordinate data set"
1904e5c31af7Sopenharmony_ci								   << tcu::TestLog::EndMessage;
1905e5c31af7Sopenharmony_ci
1906e5c31af7Sopenharmony_ci				TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator.");
1907e5c31af7Sopenharmony_ci			} /* if (the expected vertex data was not found) */
1908e5c31af7Sopenharmony_ci		}	 /* for (all expected vertices) */
1909e5c31af7Sopenharmony_ci	}		  /* for (all generated vertices) */
1910e5c31af7Sopenharmony_ci}
1911e5c31af7Sopenharmony_ci
1912e5c31af7Sopenharmony_ci/** Constructor.
1913e5c31af7Sopenharmony_ci *
1914e5c31af7Sopenharmony_ci *  @param context Rendering context.
1915e5c31af7Sopenharmony_ci *
1916e5c31af7Sopenharmony_ci **/
1917e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule5Test::TessellationShaderInvarianceRule5Test(Context&			  context,
1918e5c31af7Sopenharmony_ci																			 const ExtParameters& extParams)
1919e5c31af7Sopenharmony_ci	: TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule5",
1920e5c31af7Sopenharmony_ci										   "Verifies conformance with fifth invariance rule")
1921e5c31af7Sopenharmony_ci{
1922e5c31af7Sopenharmony_ci}
1923e5c31af7Sopenharmony_ci
1924e5c31af7Sopenharmony_ci/** Destructor. */
1925e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule5Test::~TessellationShaderInvarianceRule5Test()
1926e5c31af7Sopenharmony_ci{
1927e5c31af7Sopenharmony_ci	/* Left blank intentionally */
1928e5c31af7Sopenharmony_ci}
1929e5c31af7Sopenharmony_ci
1930e5c31af7Sopenharmony_ci/** Retrieves amount of iterations the base test implementation should run before
1931e5c31af7Sopenharmony_ci *  calling global verification routine.
1932e5c31af7Sopenharmony_ci *
1933e5c31af7Sopenharmony_ci *  @return A value that depends on initTestIterations() behavior.
1934e5c31af7Sopenharmony_ci **/
1935e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule5Test::getAmountOfIterations()
1936e5c31af7Sopenharmony_ci{
1937e5c31af7Sopenharmony_ci	if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
1938e5c31af7Sopenharmony_ci	{
1939e5c31af7Sopenharmony_ci		initTestIterations();
1940e5c31af7Sopenharmony_ci	}
1941e5c31af7Sopenharmony_ci
1942e5c31af7Sopenharmony_ci	return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
1943e5c31af7Sopenharmony_ci}
1944e5c31af7Sopenharmony_ci
1945e5c31af7Sopenharmony_ci/** Retrieves _test_iteration instance specific for user-specified iteration index.
1946e5c31af7Sopenharmony_ci *
1947e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index to retrieve _test_iteration instance for.
1948e5c31af7Sopenharmony_ci *
1949e5c31af7Sopenharmony_ci * @return Iteration-specific _test_iteration instance.
1950e5c31af7Sopenharmony_ci *
1951e5c31af7Sopenharmony_ci **/
1952e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule5Test::_test_iteration& TessellationShaderInvarianceRule5Test::getTestForIteration(
1953e5c31af7Sopenharmony_ci	unsigned int n_iteration)
1954e5c31af7Sopenharmony_ci{
1955e5c31af7Sopenharmony_ci	unsigned int	 n_triangles_tests = (unsigned int)m_test_triangles_iterations.size();
1956e5c31af7Sopenharmony_ci	_test_iteration& test_iteration	= (n_iteration < n_triangles_tests) ?
1957e5c31af7Sopenharmony_ci										  m_test_triangles_iterations[n_iteration] :
1958e5c31af7Sopenharmony_ci										  m_test_quads_iterations[n_iteration - n_triangles_tests];
1959e5c31af7Sopenharmony_ci
1960e5c31af7Sopenharmony_ci	return test_iteration;
1961e5c31af7Sopenharmony_ci}
1962e5c31af7Sopenharmony_ci
1963e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation properties.
1964e5c31af7Sopenharmony_ci *
1965e5c31af7Sopenharmony_ci *  @param n_iteration            Iteration index to retrieve the properties for.
1966e5c31af7Sopenharmony_ci *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
1967e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
1968e5c31af7Sopenharmony_ci *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
1969e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
1970e5c31af7Sopenharmony_ci *  @param out_point_mode         Deref will be used to store iteration-specific flag
1971e5c31af7Sopenharmony_ci *                                telling whether point mode should be enabled for given pass.
1972e5c31af7Sopenharmony_ci *                                Must not be NULL.
1973e5c31af7Sopenharmony_ci *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
1974e5c31af7Sopenharmony_ci *                                mode. Must not be NULL.
1975e5c31af7Sopenharmony_ci *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
1976e5c31af7Sopenharmony_ci *                                ordering. Must not be NULL.
1977e5c31af7Sopenharmony_ci *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1978e5c31af7Sopenharmony_ci *                                storage should offer for the draw call to succeed. Can
1979e5c31af7Sopenharmony_ci *                                be NULL.
1980e5c31af7Sopenharmony_ci **/
1981e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule5Test::getIterationProperties(
1982e5c31af7Sopenharmony_ci	unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
1983e5c31af7Sopenharmony_ci	_tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
1984e5c31af7Sopenharmony_ci	unsigned int* out_result_buffer_size)
1985e5c31af7Sopenharmony_ci{
1986e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
1987e5c31af7Sopenharmony_ci
1988e5c31af7Sopenharmony_ci	_test_iteration& test_iteration = getTestForIteration(n_iteration);
1989e5c31af7Sopenharmony_ci
1990e5c31af7Sopenharmony_ci	memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1991e5c31af7Sopenharmony_ci	memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1992e5c31af7Sopenharmony_ci
1993e5c31af7Sopenharmony_ci	*out_point_mode		 = false;
1994e5c31af7Sopenharmony_ci	*out_primitive_mode  = test_iteration.primitive_mode;
1995e5c31af7Sopenharmony_ci	*out_vertex_ordering = test_iteration.vertex_ordering;
1996e5c31af7Sopenharmony_ci
1997e5c31af7Sopenharmony_ci	if (out_result_buffer_size != DE_NULL)
1998e5c31af7Sopenharmony_ci	{
1999e5c31af7Sopenharmony_ci		*out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2000e5c31af7Sopenharmony_ci			*out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2001e5c31af7Sopenharmony_ci			*out_point_mode);
2002e5c31af7Sopenharmony_ci		test_iteration.n_vertices = *out_result_buffer_size;
2003e5c31af7Sopenharmony_ci		*out_result_buffer_size =
2004e5c31af7Sopenharmony_ci			static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2005e5c31af7Sopenharmony_ci
2006e5c31af7Sopenharmony_ci		DE_ASSERT(*out_result_buffer_size != 0);
2007e5c31af7Sopenharmony_ci	}
2008e5c31af7Sopenharmony_ci}
2009e5c31af7Sopenharmony_ci
2010e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation evaluation shader code.
2011e5c31af7Sopenharmony_ci *
2012e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index, for which the source code is being obtained.
2013e5c31af7Sopenharmony_ci *
2014e5c31af7Sopenharmony_ci *  @return Requested source code.
2015e5c31af7Sopenharmony_ci **/
2016e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceRule5Test::getTECode(unsigned int n_iteration)
2017e5c31af7Sopenharmony_ci{
2018e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2019e5c31af7Sopenharmony_ci
2020e5c31af7Sopenharmony_ci	const _test_iteration& test_iteration = getTestForIteration(n_iteration);
2021e5c31af7Sopenharmony_ci
2022e5c31af7Sopenharmony_ci	return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2023e5c31af7Sopenharmony_ci													 test_iteration.primitive_mode, test_iteration.vertex_ordering,
2024e5c31af7Sopenharmony_ci													 false); /* point mode */
2025e5c31af7Sopenharmony_ci}
2026e5c31af7Sopenharmony_ci
2027e5c31af7Sopenharmony_ci/** Initializes test iterations for the test. The following modes and inner/outer tess level
2028e5c31af7Sopenharmony_ci *  configurations are used to form the test set:
2029e5c31af7Sopenharmony_ci *
2030e5c31af7Sopenharmony_ci *  - Last inner/outer tessellation level combination as returned by
2031e5c31af7Sopenharmony_ci *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
2032e5c31af7Sopenharmony_ci *  - All primitive modes;
2033e5c31af7Sopenharmony_ci *  - All vertex spacing modes;
2034e5c31af7Sopenharmony_ci *
2035e5c31af7Sopenharmony_ci *  All permutations are used to generate the test set.
2036e5c31af7Sopenharmony_ci **/
2037e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule5Test::initTestIterations()
2038e5c31af7Sopenharmony_ci{
2039e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2040e5c31af7Sopenharmony_ci
2041e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2042e5c31af7Sopenharmony_ci	const glw::Functions& gl						  = m_context.getRenderContext().getFunctions();
2043e5c31af7Sopenharmony_ci	glw::GLint			  gl_max_tess_gen_level_value = 0;
2044e5c31af7Sopenharmony_ci
2045e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2046e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2047e5c31af7Sopenharmony_ci
2048e5c31af7Sopenharmony_ci	/* Iterate through all primitive and vertex spacing modes relevant to the test */
2049e5c31af7Sopenharmony_ci	_tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2050e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
2051e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_ordering vo_modes[] = {
2052e5c31af7Sopenharmony_ci		TESSELLATION_SHADER_VERTEX_ORDERING_CCW, TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2053e5c31af7Sopenharmony_ci	};
2054e5c31af7Sopenharmony_ci
2055e5c31af7Sopenharmony_ci	const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2056e5c31af7Sopenharmony_ci	const unsigned int n_vo_modes		 = sizeof(vo_modes) / sizeof(vo_modes[0]);
2057e5c31af7Sopenharmony_ci
2058e5c31af7Sopenharmony_ci	for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2059e5c31af7Sopenharmony_ci	{
2060e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2061e5c31af7Sopenharmony_ci
2062e5c31af7Sopenharmony_ci		for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2063e5c31af7Sopenharmony_ci		{
2064e5c31af7Sopenharmony_ci			_tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode];
2065e5c31af7Sopenharmony_ci
2066e5c31af7Sopenharmony_ci			/* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
2067e5c31af7Sopenharmony_ci			_tessellation_levels_set levels_set;
2068e5c31af7Sopenharmony_ci
2069e5c31af7Sopenharmony_ci			levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2070e5c31af7Sopenharmony_ci				primitive_mode, gl_max_tess_gen_level_value,
2071e5c31af7Sopenharmony_ci				TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2072e5c31af7Sopenharmony_ci
2073e5c31af7Sopenharmony_ci			/* Only use the last inner/outer level configuration, as reported by the utils function. */
2074e5c31af7Sopenharmony_ci			const _tessellation_levels& levels = levels_set[levels_set.size() - 1];
2075e5c31af7Sopenharmony_ci
2076e5c31af7Sopenharmony_ci			/* Create a test descriptor for all the parameters we now have */
2077e5c31af7Sopenharmony_ci			_test_iteration test;
2078e5c31af7Sopenharmony_ci
2079e5c31af7Sopenharmony_ci			memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2080e5c31af7Sopenharmony_ci			memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2081e5c31af7Sopenharmony_ci
2082e5c31af7Sopenharmony_ci			test.primitive_mode  = primitive_mode;
2083e5c31af7Sopenharmony_ci			test.vertex_ordering = vertex_ordering;
2084e5c31af7Sopenharmony_ci
2085e5c31af7Sopenharmony_ci			if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2086e5c31af7Sopenharmony_ci			{
2087e5c31af7Sopenharmony_ci				m_test_triangles_iterations.push_back(test);
2088e5c31af7Sopenharmony_ci			}
2089e5c31af7Sopenharmony_ci			else
2090e5c31af7Sopenharmony_ci			{
2091e5c31af7Sopenharmony_ci				m_test_quads_iterations.push_back(test);
2092e5c31af7Sopenharmony_ci			}
2093e5c31af7Sopenharmony_ci		} /* for (all vertex spacing modes) */
2094e5c31af7Sopenharmony_ci	}	 /* for (all primitive modes) */
2095e5c31af7Sopenharmony_ci}
2096e5c31af7Sopenharmony_ci
2097e5c31af7Sopenharmony_ci/** Verifies user-provided vertex data can be found in the provided vertex data array.
2098e5c31af7Sopenharmony_ci *
2099e5c31af7Sopenharmony_ci *  @param vertex_data                     Vertex data array the requested vertex data are to be found in.
2100e5c31af7Sopenharmony_ci *  @param n_vertices                      Amount of vertices declared in @param vertex_data;
2101e5c31af7Sopenharmony_ci *  @param vertex_data_seeked              Vertex data to be found in @param vertex_data;
2102e5c31af7Sopenharmony_ci *  @param n_vertex_data_seeked_components Amount of components to take into account.
2103e5c31af7Sopenharmony_ci *
2104e5c31af7Sopenharmony_ci *  @return true if the vertex data was found, false otherwise.
2105e5c31af7Sopenharmony_ci **/
2106e5c31af7Sopenharmony_cibool TessellationShaderInvarianceRule5Test::isVertexDefined(const float* vertex_data, unsigned int n_vertices,
2107e5c31af7Sopenharmony_ci															const float* vertex_data_seeked,
2108e5c31af7Sopenharmony_ci															unsigned int n_vertex_data_seeked_components)
2109e5c31af7Sopenharmony_ci{
2110e5c31af7Sopenharmony_ci	const float epsilon = 1e-5f;
2111e5c31af7Sopenharmony_ci	bool		result  = false;
2112e5c31af7Sopenharmony_ci
2113e5c31af7Sopenharmony_ci	DE_ASSERT(n_vertex_data_seeked_components >= 2);
2114e5c31af7Sopenharmony_ci
2115e5c31af7Sopenharmony_ci	for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
2116e5c31af7Sopenharmony_ci	{
2117e5c31af7Sopenharmony_ci		const float* current_vertex_data = vertex_data + 3 /* components */ * n_vertex;
2118e5c31af7Sopenharmony_ci
2119e5c31af7Sopenharmony_ci		if (de::abs(vertex_data_seeked[0] - current_vertex_data[0]) < epsilon &&
2120e5c31af7Sopenharmony_ci			de::abs(vertex_data_seeked[1] - current_vertex_data[1]) < epsilon &&
2121e5c31af7Sopenharmony_ci			((n_vertex_data_seeked_components < 3) ||
2122e5c31af7Sopenharmony_ci			 (n_vertex_data_seeked_components >= 3 &&
2123e5c31af7Sopenharmony_ci			  de::abs(vertex_data_seeked[2] - current_vertex_data[2]) < epsilon)))
2124e5c31af7Sopenharmony_ci		{
2125e5c31af7Sopenharmony_ci			result = true;
2126e5c31af7Sopenharmony_ci
2127e5c31af7Sopenharmony_ci			break;
2128e5c31af7Sopenharmony_ci		} /* if (components match) */
2129e5c31af7Sopenharmony_ci	}	 /* for (all vertices) */
2130e5c31af7Sopenharmony_ci
2131e5c31af7Sopenharmony_ci	return result;
2132e5c31af7Sopenharmony_ci}
2133e5c31af7Sopenharmony_ci
2134e5c31af7Sopenharmony_ci/** Verifies result data. Accesses data generated by all iterations.
2135e5c31af7Sopenharmony_ci *
2136e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
2137e5c31af7Sopenharmony_ci *
2138e5c31af7Sopenharmony_ci *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2139e5c31af7Sopenharmony_ci *                             data generated by subsequent iterations.
2140e5c31af7Sopenharmony_ci **/
2141e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule5Test::verifyResultData(const void** all_iterations_data)
2142e5c31af7Sopenharmony_ci{
2143e5c31af7Sopenharmony_ci	/* Run two separate iterations:
2144e5c31af7Sopenharmony_ci	 *
2145e5c31af7Sopenharmony_ci	 * a) triangles
2146e5c31af7Sopenharmony_ci	 * b) quads
2147e5c31af7Sopenharmony_ci	 */
2148e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration)
2149e5c31af7Sopenharmony_ci	{
2150e5c31af7Sopenharmony_ci		const unsigned int n_base_iteration =
2151e5c31af7Sopenharmony_ci			(n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2152e5c31af7Sopenharmony_ci		const unsigned int set_size = (n_iteration == 0) ? (unsigned int)m_test_triangles_iterations.size() :
2153e5c31af7Sopenharmony_ci														   (unsigned int)m_test_quads_iterations.size();
2154e5c31af7Sopenharmony_ci		const _test_iterations& test_iterations =
2155e5c31af7Sopenharmony_ci			(n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2156e5c31af7Sopenharmony_ci
2157e5c31af7Sopenharmony_ci		DE_ASSERT(test_iterations.size() != 0);
2158e5c31af7Sopenharmony_ci
2159e5c31af7Sopenharmony_ci		/* For each iteration, verify that all vertices generated for all three vertex spacing modes.
2160e5c31af7Sopenharmony_ci		 * are exactly the same (but in different order) */
2161e5c31af7Sopenharmony_ci		const float* base_vertex_data = (const float*)all_iterations_data[n_base_iteration + 0];
2162e5c31af7Sopenharmony_ci
2163e5c31af7Sopenharmony_ci		for (unsigned int n_set = 1; n_set < set_size; ++n_set)
2164e5c31af7Sopenharmony_ci		{
2165e5c31af7Sopenharmony_ci			const float* set_vertex_data = (const float*)all_iterations_data[n_base_iteration + n_set];
2166e5c31af7Sopenharmony_ci
2167e5c31af7Sopenharmony_ci			/* Amount of vertices should not differ between sets */
2168e5c31af7Sopenharmony_ci			DE_ASSERT(test_iterations[0].n_vertices == test_iterations[n_set].n_vertices);
2169e5c31af7Sopenharmony_ci
2170e5c31af7Sopenharmony_ci			/* Run through all vertices in base set and make sure they can be found in currently
2171e5c31af7Sopenharmony_ci			 * processed set */
2172e5c31af7Sopenharmony_ci			for (unsigned int n_base_vertex = 0; n_base_vertex < test_iterations[0].n_vertices; ++n_base_vertex)
2173e5c31af7Sopenharmony_ci			{
2174e5c31af7Sopenharmony_ci				const float* base_vertex = base_vertex_data + 3 /* components */ * n_base_vertex;
2175e5c31af7Sopenharmony_ci
2176e5c31af7Sopenharmony_ci				if (!isVertexDefined(set_vertex_data, test_iterations[n_set].n_vertices, base_vertex,
2177e5c31af7Sopenharmony_ci									 3)) /* components */
2178e5c31af7Sopenharmony_ci				{
2179e5c31af7Sopenharmony_ci					const char* primitive_mode = (n_iteration == 0) ? "triangles" : "quads";
2180e5c31af7Sopenharmony_ci
2181e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode [" << primitive_mode << "] "
2182e5c31af7Sopenharmony_ci									   << "a vertex with tessellation coordinates:[" << base_vertex[0] << ", "
2183e5c31af7Sopenharmony_ci									   << base_vertex[1] << ", " << base_vertex[2] << ") "
2184e5c31af7Sopenharmony_ci									   << "could not have been found for both vertex orderings."
2185e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
2186e5c31af7Sopenharmony_ci
2187e5c31af7Sopenharmony_ci					TCU_FAIL("Implementation does not follow Rule 5.");
2188e5c31af7Sopenharmony_ci				}
2189e5c31af7Sopenharmony_ci			} /* for (all base set's vertices) */
2190e5c31af7Sopenharmony_ci		}	 /* for (all sets) */
2191e5c31af7Sopenharmony_ci	}		  /* for (both primitive types) */
2192e5c31af7Sopenharmony_ci}
2193e5c31af7Sopenharmony_ci
2194e5c31af7Sopenharmony_ci/** Constructor.
2195e5c31af7Sopenharmony_ci *
2196e5c31af7Sopenharmony_ci *  @param context Rendering context.
2197e5c31af7Sopenharmony_ci *
2198e5c31af7Sopenharmony_ci **/
2199e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule6Test::TessellationShaderInvarianceRule6Test(Context&			  context,
2200e5c31af7Sopenharmony_ci																			 const ExtParameters& extParams)
2201e5c31af7Sopenharmony_ci	: TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule6",
2202e5c31af7Sopenharmony_ci										   "Verifies conformance with sixth invariance rule")
2203e5c31af7Sopenharmony_ci{
2204e5c31af7Sopenharmony_ci}
2205e5c31af7Sopenharmony_ci
2206e5c31af7Sopenharmony_ci/** Destructor. */
2207e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule6Test::~TessellationShaderInvarianceRule6Test()
2208e5c31af7Sopenharmony_ci{
2209e5c31af7Sopenharmony_ci	/* Left blank intentionally */
2210e5c31af7Sopenharmony_ci}
2211e5c31af7Sopenharmony_ci
2212e5c31af7Sopenharmony_ci/** Retrieves amount of iterations the base test implementation should run before
2213e5c31af7Sopenharmony_ci *  calling global verification routine.
2214e5c31af7Sopenharmony_ci *
2215e5c31af7Sopenharmony_ci *  @return A value that depends on initTestIterations() behavior.
2216e5c31af7Sopenharmony_ci **/
2217e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule6Test::getAmountOfIterations()
2218e5c31af7Sopenharmony_ci{
2219e5c31af7Sopenharmony_ci	if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
2220e5c31af7Sopenharmony_ci	{
2221e5c31af7Sopenharmony_ci		initTestIterations();
2222e5c31af7Sopenharmony_ci	}
2223e5c31af7Sopenharmony_ci
2224e5c31af7Sopenharmony_ci	return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
2225e5c31af7Sopenharmony_ci}
2226e5c31af7Sopenharmony_ci
2227e5c31af7Sopenharmony_ci/** Retrieves _test_iteration instance specific for user-specified iteration index.
2228e5c31af7Sopenharmony_ci *
2229e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index to retrieve _test_iteration instance for.
2230e5c31af7Sopenharmony_ci *
2231e5c31af7Sopenharmony_ci * @return Iteration-specific _test_iteration instance.
2232e5c31af7Sopenharmony_ci *
2233e5c31af7Sopenharmony_ci **/
2234e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule6Test::_test_iteration& TessellationShaderInvarianceRule6Test::getTestForIteration(
2235e5c31af7Sopenharmony_ci	unsigned int n_iteration)
2236e5c31af7Sopenharmony_ci{
2237e5c31af7Sopenharmony_ci	unsigned int	 n_triangles_tests = (unsigned int)m_test_triangles_iterations.size();
2238e5c31af7Sopenharmony_ci	_test_iteration& test_iteration	= (n_iteration < n_triangles_tests) ?
2239e5c31af7Sopenharmony_ci										  m_test_triangles_iterations[n_iteration] :
2240e5c31af7Sopenharmony_ci										  m_test_quads_iterations[n_iteration - n_triangles_tests];
2241e5c31af7Sopenharmony_ci
2242e5c31af7Sopenharmony_ci	return test_iteration;
2243e5c31af7Sopenharmony_ci}
2244e5c31af7Sopenharmony_ci
2245e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation properties.
2246e5c31af7Sopenharmony_ci *
2247e5c31af7Sopenharmony_ci *  @param n_iteration            Iteration index to retrieve the properties for.
2248e5c31af7Sopenharmony_ci *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
2249e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
2250e5c31af7Sopenharmony_ci *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
2251e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
2252e5c31af7Sopenharmony_ci *  @param out_point_mode         Deref will be used to store iteration-specific flag
2253e5c31af7Sopenharmony_ci *                                telling whether point mode should be enabled for given pass.
2254e5c31af7Sopenharmony_ci *                                Must not be NULL.
2255e5c31af7Sopenharmony_ci *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
2256e5c31af7Sopenharmony_ci *                                mode. Must not be NULL.
2257e5c31af7Sopenharmony_ci *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
2258e5c31af7Sopenharmony_ci *                                ordering. Must not be NULL.
2259e5c31af7Sopenharmony_ci *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
2260e5c31af7Sopenharmony_ci *                                storage should offer for the draw call to succeed. Can
2261e5c31af7Sopenharmony_ci *                                be NULL.
2262e5c31af7Sopenharmony_ci **/
2263e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule6Test::getIterationProperties(
2264e5c31af7Sopenharmony_ci	unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
2265e5c31af7Sopenharmony_ci	_tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
2266e5c31af7Sopenharmony_ci	unsigned int* out_result_buffer_size)
2267e5c31af7Sopenharmony_ci{
2268e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2269e5c31af7Sopenharmony_ci
2270e5c31af7Sopenharmony_ci	_test_iteration& test_iteration = getTestForIteration(n_iteration);
2271e5c31af7Sopenharmony_ci
2272e5c31af7Sopenharmony_ci	memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
2273e5c31af7Sopenharmony_ci	memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
2274e5c31af7Sopenharmony_ci
2275e5c31af7Sopenharmony_ci	*out_point_mode		 = false;
2276e5c31af7Sopenharmony_ci	*out_primitive_mode  = test_iteration.primitive_mode;
2277e5c31af7Sopenharmony_ci	*out_vertex_ordering = test_iteration.vertex_ordering;
2278e5c31af7Sopenharmony_ci
2279e5c31af7Sopenharmony_ci	if (out_result_buffer_size != DE_NULL)
2280e5c31af7Sopenharmony_ci	{
2281e5c31af7Sopenharmony_ci		*out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2282e5c31af7Sopenharmony_ci			*out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2283e5c31af7Sopenharmony_ci			*out_point_mode);
2284e5c31af7Sopenharmony_ci		test_iteration.n_vertices = *out_result_buffer_size;
2285e5c31af7Sopenharmony_ci		*out_result_buffer_size =
2286e5c31af7Sopenharmony_ci			static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2287e5c31af7Sopenharmony_ci
2288e5c31af7Sopenharmony_ci		DE_ASSERT(*out_result_buffer_size != 0);
2289e5c31af7Sopenharmony_ci	}
2290e5c31af7Sopenharmony_ci}
2291e5c31af7Sopenharmony_ci
2292e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation evaluation shader code.
2293e5c31af7Sopenharmony_ci *
2294e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index, for which the source code is being obtained.
2295e5c31af7Sopenharmony_ci *
2296e5c31af7Sopenharmony_ci *  @return Requested source code.
2297e5c31af7Sopenharmony_ci **/
2298e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceRule6Test::getTECode(unsigned int n_iteration)
2299e5c31af7Sopenharmony_ci{
2300e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2301e5c31af7Sopenharmony_ci
2302e5c31af7Sopenharmony_ci	const _test_iteration& test_iteration = getTestForIteration(n_iteration);
2303e5c31af7Sopenharmony_ci
2304e5c31af7Sopenharmony_ci	return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2305e5c31af7Sopenharmony_ci													 test_iteration.primitive_mode, test_iteration.vertex_ordering,
2306e5c31af7Sopenharmony_ci													 false); /* point mode */
2307e5c31af7Sopenharmony_ci}
2308e5c31af7Sopenharmony_ci
2309e5c31af7Sopenharmony_ci/** Initializes test iterations for the test. The following modes and inner/outer tess level
2310e5c31af7Sopenharmony_ci *  configurations are used to form the test set:
2311e5c31af7Sopenharmony_ci *
2312e5c31af7Sopenharmony_ci *  - Tessellation level combinations as returned by
2313e5c31af7Sopenharmony_ci *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() (however, the inner
2314e5c31af7Sopenharmony_ci *    tessellation level values are all set to values corresponding to last item returned for
2315e5c31af7Sopenharmony_ci *    the set)
2316e5c31af7Sopenharmony_ci *  - All primitive modes;
2317e5c31af7Sopenharmony_ci *  - All vertex ordering modes;
2318e5c31af7Sopenharmony_ci *
2319e5c31af7Sopenharmony_ci *  All permutations are used to generate the test set.
2320e5c31af7Sopenharmony_ci **/
2321e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule6Test::initTestIterations()
2322e5c31af7Sopenharmony_ci{
2323e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2324e5c31af7Sopenharmony_ci
2325e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2326e5c31af7Sopenharmony_ci	const glw::Functions& gl						  = m_context.getRenderContext().getFunctions();
2327e5c31af7Sopenharmony_ci	glw::GLint			  gl_max_tess_gen_level_value = 0;
2328e5c31af7Sopenharmony_ci
2329e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2330e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2331e5c31af7Sopenharmony_ci
2332e5c31af7Sopenharmony_ci	/* Iterate through all primitive and vertex spacing modes relevant to the test */
2333e5c31af7Sopenharmony_ci	_tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
2334e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS };
2335e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_ordering vertex_ordering_modes[] = { TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
2336e5c31af7Sopenharmony_ci																	 TESSELLATION_SHADER_VERTEX_ORDERING_CW };
2337e5c31af7Sopenharmony_ci
2338e5c31af7Sopenharmony_ci	const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2339e5c31af7Sopenharmony_ci	const unsigned int n_vo_modes		 = sizeof(vertex_ordering_modes) / sizeof(vertex_ordering_modes[0]);
2340e5c31af7Sopenharmony_ci
2341e5c31af7Sopenharmony_ci	for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2342e5c31af7Sopenharmony_ci	{
2343e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2344e5c31af7Sopenharmony_ci
2345e5c31af7Sopenharmony_ci		for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2346e5c31af7Sopenharmony_ci		{
2347e5c31af7Sopenharmony_ci			_tessellation_shader_vertex_ordering vertex_ordering = vertex_ordering_modes[n_vo_mode];
2348e5c31af7Sopenharmony_ci
2349e5c31af7Sopenharmony_ci			/* Retrieve inner/outer tessellation level combinations we want the tests to be run for.
2350e5c31af7Sopenharmony_ci			 * Since each level set we will be provided by getTessellationLevelSetForPrimitiveMode()
2351e5c31af7Sopenharmony_ci			 * is unique and does not repeat, we'll just make sure the inner level values are set to
2352e5c31af7Sopenharmony_ci			 * the same set of values, so that the conditions the test must meet are actually met.
2353e5c31af7Sopenharmony_ci			 */
2354e5c31af7Sopenharmony_ci			float*					 inner_levels_to_use = DE_NULL;
2355e5c31af7Sopenharmony_ci			_tessellation_levels_set levels_set;
2356e5c31af7Sopenharmony_ci			unsigned int			 n_levels_sets = 0;
2357e5c31af7Sopenharmony_ci
2358e5c31af7Sopenharmony_ci			levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2359e5c31af7Sopenharmony_ci				primitive_mode, gl_max_tess_gen_level_value,
2360e5c31af7Sopenharmony_ci				TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2361e5c31af7Sopenharmony_ci
2362e5c31af7Sopenharmony_ci			n_levels_sets		= (unsigned int)levels_set.size();
2363e5c31af7Sopenharmony_ci			inner_levels_to_use = levels_set[n_levels_sets - 1].inner;
2364e5c31af7Sopenharmony_ci
2365e5c31af7Sopenharmony_ci			for (unsigned int n_levels_set = 0; n_levels_set < n_levels_sets - 1; n_levels_set++)
2366e5c31af7Sopenharmony_ci			{
2367e5c31af7Sopenharmony_ci				/* Make sure the Utils function was not changed and that inner level values
2368e5c31af7Sopenharmony_ci				 * are actually unique across the whole set */
2369e5c31af7Sopenharmony_ci				DE_ASSERT(levels_set[n_levels_set].inner[0] != levels_set[n_levels_sets - 1].inner[0] &&
2370e5c31af7Sopenharmony_ci						  levels_set[n_levels_set].inner[1] != levels_set[n_levels_sets - 1].inner[1]);
2371e5c31af7Sopenharmony_ci
2372e5c31af7Sopenharmony_ci				/* Force the last set's inner values to all level combinations we'll be using */
2373e5c31af7Sopenharmony_ci				memcpy(levels_set[n_levels_set].inner, inner_levels_to_use, sizeof(levels_set[n_levels_set].inner));
2374e5c31af7Sopenharmony_ci			} /* for (all sets retrieved from Utils function */
2375e5c31af7Sopenharmony_ci
2376e5c31af7Sopenharmony_ci			for (_tessellation_levels_set_const_iterator set_iterator = levels_set.begin();
2377e5c31af7Sopenharmony_ci				 set_iterator != levels_set.end(); set_iterator++)
2378e5c31af7Sopenharmony_ci			{
2379e5c31af7Sopenharmony_ci				const _tessellation_levels& levels = *set_iterator;
2380e5c31af7Sopenharmony_ci
2381e5c31af7Sopenharmony_ci				/* Create a test descriptor for all the parameters we now have */
2382e5c31af7Sopenharmony_ci				_test_iteration test;
2383e5c31af7Sopenharmony_ci
2384e5c31af7Sopenharmony_ci				memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2385e5c31af7Sopenharmony_ci				memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2386e5c31af7Sopenharmony_ci
2387e5c31af7Sopenharmony_ci				test.primitive_mode  = primitive_mode;
2388e5c31af7Sopenharmony_ci				test.vertex_ordering = vertex_ordering;
2389e5c31af7Sopenharmony_ci
2390e5c31af7Sopenharmony_ci				if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2391e5c31af7Sopenharmony_ci				{
2392e5c31af7Sopenharmony_ci					m_test_triangles_iterations.push_back(test);
2393e5c31af7Sopenharmony_ci				}
2394e5c31af7Sopenharmony_ci				else
2395e5c31af7Sopenharmony_ci				{
2396e5c31af7Sopenharmony_ci					m_test_quads_iterations.push_back(test);
2397e5c31af7Sopenharmony_ci				}
2398e5c31af7Sopenharmony_ci			} /* for (all level sets) */
2399e5c31af7Sopenharmony_ci		}	 /* for (all vertex ordering modes) */
2400e5c31af7Sopenharmony_ci	}		  /* for (all primitive modes) */
2401e5c31af7Sopenharmony_ci}
2402e5c31af7Sopenharmony_ci
2403e5c31af7Sopenharmony_ci/** Verifies result data. Accesses data generated by all iterations.
2404e5c31af7Sopenharmony_ci *
2405e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
2406e5c31af7Sopenharmony_ci *
2407e5c31af7Sopenharmony_ci *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2408e5c31af7Sopenharmony_ci *                             data generated by subsequent iterations.
2409e5c31af7Sopenharmony_ci **/
2410e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule6Test::verifyResultData(const void** all_iterations_data)
2411e5c31af7Sopenharmony_ci{
2412e5c31af7Sopenharmony_ci	/* Run two separate iterations:
2413e5c31af7Sopenharmony_ci	 *
2414e5c31af7Sopenharmony_ci	 * a) triangles
2415e5c31af7Sopenharmony_ci	 * b) quads
2416e5c31af7Sopenharmony_ci	 */
2417e5c31af7Sopenharmony_ci
2418e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration)
2419e5c31af7Sopenharmony_ci	{
2420e5c31af7Sopenharmony_ci		const unsigned int n_base_iteration =
2421e5c31af7Sopenharmony_ci			(n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2422e5c31af7Sopenharmony_ci
2423e5c31af7Sopenharmony_ci		const unsigned int n_sets = (n_iteration == 0) ? (unsigned int)m_test_triangles_iterations.size() :
2424e5c31af7Sopenharmony_ci														 (unsigned int)m_test_quads_iterations.size();
2425e5c31af7Sopenharmony_ci
2426e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = (n_iteration == 0) ?
2427e5c31af7Sopenharmony_ci														  TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
2428e5c31af7Sopenharmony_ci														  TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
2429e5c31af7Sopenharmony_ci
2430e5c31af7Sopenharmony_ci		const _test_iterations& test_iterations =
2431e5c31af7Sopenharmony_ci			(n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2432e5c31af7Sopenharmony_ci
2433e5c31af7Sopenharmony_ci		const unsigned int n_triangles_in_base_set = test_iterations[0].n_vertices / 3 /* vertices per triangle */;
2434e5c31af7Sopenharmony_ci
2435e5c31af7Sopenharmony_ci		DE_ASSERT(test_iterations.size() != 0);
2436e5c31af7Sopenharmony_ci
2437e5c31af7Sopenharmony_ci		/* For each iteration, verify that all vertices generated for all three vertex spacing modes.
2438e5c31af7Sopenharmony_ci		 * are exactly the same (but in different order) */
2439e5c31af7Sopenharmony_ci		const _test_iteration& base_test		= test_iterations[0];
2440e5c31af7Sopenharmony_ci		const float*		   base_vertex_data = (const float*)all_iterations_data[n_base_iteration + 0];
2441e5c31af7Sopenharmony_ci
2442e5c31af7Sopenharmony_ci		for (unsigned int n_set = 1; n_set < n_sets; ++n_set)
2443e5c31af7Sopenharmony_ci		{
2444e5c31af7Sopenharmony_ci			const _test_iteration& set_test		   = test_iterations[n_set];
2445e5c31af7Sopenharmony_ci			const float*		   set_vertex_data = (const float*)all_iterations_data[n_base_iteration + n_set];
2446e5c31af7Sopenharmony_ci
2447e5c31af7Sopenharmony_ci			/* We're operating on triangles so make sure the amount of vertices we're dealing with is
2448e5c31af7Sopenharmony_ci			 * divisible by 3 */
2449e5c31af7Sopenharmony_ci			DE_ASSERT((test_iterations[n_set].n_vertices % 3) == 0);
2450e5c31af7Sopenharmony_ci
2451e5c31af7Sopenharmony_ci			const unsigned int n_triangles_in_curr_set = test_iterations[n_set].n_vertices / 3;
2452e5c31af7Sopenharmony_ci
2453e5c31af7Sopenharmony_ci			/* Take base triangles and make sure they can be found in iteration-specific set.
2454e5c31af7Sopenharmony_ci			 * Now, thing to keep in mind here is that we must not assume any specific vertex
2455e5c31af7Sopenharmony_ci			 * and triangle order which is why the slow search. */
2456e5c31af7Sopenharmony_ci			for (unsigned int n_base_triangle = 0; n_base_triangle < n_triangles_in_base_set; ++n_base_triangle)
2457e5c31af7Sopenharmony_ci			{
2458e5c31af7Sopenharmony_ci				/* Extract base triangle data first */
2459e5c31af7Sopenharmony_ci				const float* base_triangle_vertex1 = base_vertex_data +
2460e5c31af7Sopenharmony_ci													 n_base_triangle * 3 *		/* vertices per triangle */
2461e5c31af7Sopenharmony_ci														 3;						/* components */
2462e5c31af7Sopenharmony_ci				const float* base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */
2463e5c31af7Sopenharmony_ci				const float* base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */
2464e5c31af7Sopenharmony_ci
2465e5c31af7Sopenharmony_ci				/* Only interior triangles should be left intact. Is this an interior triangle? */
2466e5c31af7Sopenharmony_ci				if (!TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1) &&
2467e5c31af7Sopenharmony_ci					!TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2) &&
2468e5c31af7Sopenharmony_ci					!TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3))
2469e5c31af7Sopenharmony_ci				{
2470e5c31af7Sopenharmony_ci					/* Iterate through all triangles in considered set */
2471e5c31af7Sopenharmony_ci					bool has_base_set_triangle_been_found = false;
2472e5c31af7Sopenharmony_ci
2473e5c31af7Sopenharmony_ci					for (unsigned int n_curr_set_triangle = 0; n_curr_set_triangle < n_triangles_in_curr_set;
2474e5c31af7Sopenharmony_ci						 ++n_curr_set_triangle)
2475e5c31af7Sopenharmony_ci					{
2476e5c31af7Sopenharmony_ci						const float* curr_triangle = set_vertex_data +
2477e5c31af7Sopenharmony_ci													 n_curr_set_triangle * 3 * /* vertices per triangle */
2478e5c31af7Sopenharmony_ci														 3;					   /* components */
2479e5c31af7Sopenharmony_ci
2480e5c31af7Sopenharmony_ci						if (TessellationShaderUtils::isTriangleDefined(base_triangle_vertex1, curr_triangle))
2481e5c31af7Sopenharmony_ci						{
2482e5c31af7Sopenharmony_ci							has_base_set_triangle_been_found = true;
2483e5c31af7Sopenharmony_ci
2484e5c31af7Sopenharmony_ci							break;
2485e5c31af7Sopenharmony_ci						}
2486e5c31af7Sopenharmony_ci					} /* for (all triangles in currently processed set) */
2487e5c31af7Sopenharmony_ci
2488e5c31af7Sopenharmony_ci					if (!has_base_set_triangle_been_found)
2489e5c31af7Sopenharmony_ci					{
2490e5c31af7Sopenharmony_ci						std::string primitive_mode_str =
2491e5c31af7Sopenharmony_ci							TessellationShaderUtils::getESTokenForPrimitiveMode(base_test.primitive_mode);
2492e5c31af7Sopenharmony_ci
2493e5c31af7Sopenharmony_ci						m_testCtx.getLog()
2494e5c31af7Sopenharmony_ci							<< tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "]"
2495e5c31af7Sopenharmony_ci							<< ", base inner tessellation levels:"
2496e5c31af7Sopenharmony_ci							<< "[" << base_test.inner_tess_levels[0] << ", " << base_test.inner_tess_levels[1] << "]"
2497e5c31af7Sopenharmony_ci							<< ", base outer tessellation levels:"
2498e5c31af7Sopenharmony_ci							<< "[" << base_test.outer_tess_levels[0] << ", " << base_test.outer_tess_levels[1] << ", "
2499e5c31af7Sopenharmony_ci							<< base_test.outer_tess_levels[2] << ", " << base_test.outer_tess_levels[3] << "]"
2500e5c31af7Sopenharmony_ci							<< ", reference inner tessellation levels:"
2501e5c31af7Sopenharmony_ci							<< "[" << set_test.inner_tess_levels[0] << ", " << set_test.inner_tess_levels[1] << "]"
2502e5c31af7Sopenharmony_ci							<< ", reference outer tessellation levels:"
2503e5c31af7Sopenharmony_ci							<< "[" << set_test.outer_tess_levels[0] << ", " << set_test.outer_tess_levels[1] << ", "
2504e5c31af7Sopenharmony_ci							<< set_test.outer_tess_levels[2] << ", " << set_test.outer_tess_levels[3] << "]"
2505e5c31af7Sopenharmony_ci							<< ", the following triangle formed during base tessellation run was not found in "
2506e5c31af7Sopenharmony_ci							   "reference run:"
2507e5c31af7Sopenharmony_ci							<< "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", "
2508e5c31af7Sopenharmony_ci							<< base_triangle_vertex1[2] << "]x"
2509e5c31af7Sopenharmony_ci							<< "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", "
2510e5c31af7Sopenharmony_ci							<< base_triangle_vertex2[2] << "]x"
2511e5c31af7Sopenharmony_ci							<< "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", "
2512e5c31af7Sopenharmony_ci							<< base_triangle_vertex3[2]
2513e5c31af7Sopenharmony_ci
2514e5c31af7Sopenharmony_ci							<< tcu::TestLog::EndMessage;
2515e5c31af7Sopenharmony_ci
2516e5c31af7Sopenharmony_ci						TCU_FAIL("Implementation does not appear to be rule 6-conformant");
2517e5c31af7Sopenharmony_ci					} /* if (triangle created during base run was not found in reference run) */
2518e5c31af7Sopenharmony_ci				}	 /* if (base triangle is interior) */
2519e5c31af7Sopenharmony_ci			}		  /* for (all base set's vertices) */
2520e5c31af7Sopenharmony_ci		}			  /* for (all sets) */
2521e5c31af7Sopenharmony_ci	}				  /* for (both primitive types) */
2522e5c31af7Sopenharmony_ci}
2523e5c31af7Sopenharmony_ci
2524e5c31af7Sopenharmony_ci/** Constructor.
2525e5c31af7Sopenharmony_ci *
2526e5c31af7Sopenharmony_ci *  @param context Rendering context.
2527e5c31af7Sopenharmony_ci *
2528e5c31af7Sopenharmony_ci **/
2529e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule7Test::TessellationShaderInvarianceRule7Test(Context&			  context,
2530e5c31af7Sopenharmony_ci																			 const ExtParameters& extParams)
2531e5c31af7Sopenharmony_ci	: TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule7",
2532e5c31af7Sopenharmony_ci										   "Verifies conformance with seventh invariance rule")
2533e5c31af7Sopenharmony_ci{
2534e5c31af7Sopenharmony_ci}
2535e5c31af7Sopenharmony_ci
2536e5c31af7Sopenharmony_ci/** Destructor. */
2537e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule7Test::~TessellationShaderInvarianceRule7Test()
2538e5c31af7Sopenharmony_ci{
2539e5c31af7Sopenharmony_ci	/* Left blank intentionally */
2540e5c31af7Sopenharmony_ci}
2541e5c31af7Sopenharmony_ci
2542e5c31af7Sopenharmony_ci/** Retrieves amount of iterations the base test implementation should run before
2543e5c31af7Sopenharmony_ci *  calling global verification routine.
2544e5c31af7Sopenharmony_ci *
2545e5c31af7Sopenharmony_ci *  @return A value that depends on initTestIterations() behavior.
2546e5c31af7Sopenharmony_ci **/
2547e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule7Test::getAmountOfIterations()
2548e5c31af7Sopenharmony_ci{
2549e5c31af7Sopenharmony_ci	if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
2550e5c31af7Sopenharmony_ci	{
2551e5c31af7Sopenharmony_ci		initTestIterations();
2552e5c31af7Sopenharmony_ci	}
2553e5c31af7Sopenharmony_ci
2554e5c31af7Sopenharmony_ci	return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
2555e5c31af7Sopenharmony_ci}
2556e5c31af7Sopenharmony_ci
2557e5c31af7Sopenharmony_ci/** Retrieves index of a test iteration that was initialized with user-provided
2558e5c31af7Sopenharmony_ci *  properties.
2559e5c31af7Sopenharmony_ci *
2560e5c31af7Sopenharmony_ci *  @param is_triangles_iteration      true if the seeked test iteration should have
2561e5c31af7Sopenharmony_ci *                                     been run for 'triangles' primitive mode', false
2562e5c31af7Sopenharmony_ci *                                     if 'quads' primitive mode run is seeked.
2563e5c31af7Sopenharmony_ci *  @param inner_tess_levels           Two FP values describing inner tessellation level
2564e5c31af7Sopenharmony_ci *                                     values the seeked run should have used.
2565e5c31af7Sopenharmony_ci *  @param outer_tess_levels           Four FP values describing outer tessellation level
2566e5c31af7Sopenharmony_ci *                                     values the seeked run should have used.
2567e5c31af7Sopenharmony_ci *  @param vertex_ordering             Vertex ordering mode the seeked run should have used.
2568e5c31af7Sopenharmony_ci *  @param n_modified_outer_tess_level Tells which outer tessellation level should be
2569e5c31af7Sopenharmony_ci *                                     excluded from checking.
2570e5c31af7Sopenharmony_ci *
2571e5c31af7Sopenharmony_ci *  @return 0xFFFFFFFF if no test iteration was run for user-provided properties,
2572e5c31af7Sopenharmony_ci *          actual index otherwise.
2573e5c31af7Sopenharmony_ci *
2574e5c31af7Sopenharmony_ci **/
2575e5c31af7Sopenharmony_ciunsigned int TessellationShaderInvarianceRule7Test::getTestIterationIndex(
2576e5c31af7Sopenharmony_ci	bool is_triangles_iteration, const float* inner_tess_levels, const float* outer_tess_levels,
2577e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_ordering vertex_ordering, unsigned int n_modified_outer_tess_level)
2578e5c31af7Sopenharmony_ci{
2579e5c31af7Sopenharmony_ci	const float				epsilon = 1e-5f;
2580e5c31af7Sopenharmony_ci	unsigned int			result  = 0xFFFFFFFF;
2581e5c31af7Sopenharmony_ci	const _test_iterations& test_iterations =
2582e5c31af7Sopenharmony_ci		(is_triangles_iteration) ? m_test_triangles_iterations : m_test_quads_iterations;
2583e5c31af7Sopenharmony_ci	const unsigned int n_test_iterations = (unsigned int)test_iterations.size();
2584e5c31af7Sopenharmony_ci
2585e5c31af7Sopenharmony_ci	for (unsigned int n_test_iteration = 0; n_test_iteration < n_test_iterations; ++n_test_iteration)
2586e5c31af7Sopenharmony_ci	{
2587e5c31af7Sopenharmony_ci		_test_iteration test_iteration = test_iterations[n_test_iteration];
2588e5c31af7Sopenharmony_ci
2589e5c31af7Sopenharmony_ci		if (de::abs(test_iteration.inner_tess_levels[0] - inner_tess_levels[0]) < epsilon &&
2590e5c31af7Sopenharmony_ci			de::abs(test_iteration.inner_tess_levels[1] - inner_tess_levels[1]) < epsilon &&
2591e5c31af7Sopenharmony_ci			test_iteration.vertex_ordering == vertex_ordering &&
2592e5c31af7Sopenharmony_ci			test_iteration.n_modified_outer_tess_level == n_modified_outer_tess_level)
2593e5c31af7Sopenharmony_ci		{
2594e5c31af7Sopenharmony_ci			/* Only compare outer tessellation levels that have not been modified */
2595e5c31af7Sopenharmony_ci			if (((n_modified_outer_tess_level == 0) ||
2596e5c31af7Sopenharmony_ci				 (n_modified_outer_tess_level != 0 &&
2597e5c31af7Sopenharmony_ci				  de::abs(test_iteration.outer_tess_levels[0] - outer_tess_levels[0]) < epsilon)) &&
2598e5c31af7Sopenharmony_ci				((n_modified_outer_tess_level == 1) ||
2599e5c31af7Sopenharmony_ci				 (n_modified_outer_tess_level != 1 &&
2600e5c31af7Sopenharmony_ci				  de::abs(test_iteration.outer_tess_levels[1] - outer_tess_levels[1]) < epsilon)) &&
2601e5c31af7Sopenharmony_ci				((n_modified_outer_tess_level == 2) ||
2602e5c31af7Sopenharmony_ci				 (n_modified_outer_tess_level != 2 &&
2603e5c31af7Sopenharmony_ci				  de::abs(test_iteration.outer_tess_levels[2] - outer_tess_levels[2]) < epsilon)) &&
2604e5c31af7Sopenharmony_ci				((n_modified_outer_tess_level == 3) ||
2605e5c31af7Sopenharmony_ci				 (n_modified_outer_tess_level != 3 &&
2606e5c31af7Sopenharmony_ci				  de::abs(test_iteration.outer_tess_levels[3] - outer_tess_levels[3]) < epsilon)))
2607e5c31af7Sopenharmony_ci			{
2608e5c31af7Sopenharmony_ci				result = n_test_iteration;
2609e5c31af7Sopenharmony_ci
2610e5c31af7Sopenharmony_ci				break;
2611e5c31af7Sopenharmony_ci			}
2612e5c31af7Sopenharmony_ci		}
2613e5c31af7Sopenharmony_ci	} /* for (all test iterations) */
2614e5c31af7Sopenharmony_ci
2615e5c31af7Sopenharmony_ci	return result;
2616e5c31af7Sopenharmony_ci}
2617e5c31af7Sopenharmony_ci
2618e5c31af7Sopenharmony_ci/** Retrieves _test_iteration instance specific for user-specified iteration index.
2619e5c31af7Sopenharmony_ci *
2620e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index to retrieve _test_iteration instance for.
2621e5c31af7Sopenharmony_ci *
2622e5c31af7Sopenharmony_ci * @return Iteration-specific _test_iteration instance.
2623e5c31af7Sopenharmony_ci *
2624e5c31af7Sopenharmony_ci **/
2625e5c31af7Sopenharmony_ciTessellationShaderInvarianceRule7Test::_test_iteration& TessellationShaderInvarianceRule7Test::getTestForIteration(
2626e5c31af7Sopenharmony_ci	unsigned int n_iteration)
2627e5c31af7Sopenharmony_ci{
2628e5c31af7Sopenharmony_ci	unsigned int	 n_triangles_tests = (unsigned int)m_test_triangles_iterations.size();
2629e5c31af7Sopenharmony_ci	_test_iteration& test_iteration	= (n_iteration < n_triangles_tests) ?
2630e5c31af7Sopenharmony_ci										  m_test_triangles_iterations[n_iteration] :
2631e5c31af7Sopenharmony_ci										  m_test_quads_iterations[n_iteration - n_triangles_tests];
2632e5c31af7Sopenharmony_ci
2633e5c31af7Sopenharmony_ci	return test_iteration;
2634e5c31af7Sopenharmony_ci}
2635e5c31af7Sopenharmony_ci
2636e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation properties.
2637e5c31af7Sopenharmony_ci *
2638e5c31af7Sopenharmony_ci *  @param n_iteration            Iteration index to retrieve the properties for.
2639e5c31af7Sopenharmony_ci *  @param out_inner_tess_levels  Deref will be used to store iteration-specific inner
2640e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
2641e5c31af7Sopenharmony_ci *  @param out_outer_tess_levels  Deref will be used to store iteration-specific outer
2642e5c31af7Sopenharmony_ci *                                tessellation level values. Must not be NULL.
2643e5c31af7Sopenharmony_ci *  @param out_point_mode         Deref will be used to store iteration-specific flag
2644e5c31af7Sopenharmony_ci *                                telling whether point mode should be enabled for given pass.
2645e5c31af7Sopenharmony_ci *                                Must not be NULL.
2646e5c31af7Sopenharmony_ci *  @param out_primitive_mode     Deref will be used to store iteration-specific primitive
2647e5c31af7Sopenharmony_ci *                                mode. Must not be NULL.
2648e5c31af7Sopenharmony_ci *  @param out_vertex_ordering    Deref will be used to store iteration-specific vertex
2649e5c31af7Sopenharmony_ci *                                ordering. Must not be NULL.
2650e5c31af7Sopenharmony_ci *  @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
2651e5c31af7Sopenharmony_ci *                                storage should offer for the draw call to succeed. Can
2652e5c31af7Sopenharmony_ci *                                be NULL.
2653e5c31af7Sopenharmony_ci **/
2654e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule7Test::getIterationProperties(
2655e5c31af7Sopenharmony_ci	unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
2656e5c31af7Sopenharmony_ci	_tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
2657e5c31af7Sopenharmony_ci	unsigned int* out_result_buffer_size)
2658e5c31af7Sopenharmony_ci{
2659e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2660e5c31af7Sopenharmony_ci
2661e5c31af7Sopenharmony_ci	_test_iteration& test_iteration = getTestForIteration(n_iteration);
2662e5c31af7Sopenharmony_ci
2663e5c31af7Sopenharmony_ci	memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
2664e5c31af7Sopenharmony_ci	memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
2665e5c31af7Sopenharmony_ci
2666e5c31af7Sopenharmony_ci	*out_point_mode		 = false;
2667e5c31af7Sopenharmony_ci	*out_primitive_mode  = test_iteration.primitive_mode;
2668e5c31af7Sopenharmony_ci	*out_vertex_ordering = test_iteration.vertex_ordering;
2669e5c31af7Sopenharmony_ci
2670e5c31af7Sopenharmony_ci	if (out_result_buffer_size != DE_NULL)
2671e5c31af7Sopenharmony_ci	{
2672e5c31af7Sopenharmony_ci		*out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2673e5c31af7Sopenharmony_ci			*out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2674e5c31af7Sopenharmony_ci			*out_point_mode);
2675e5c31af7Sopenharmony_ci		test_iteration.n_vertices = *out_result_buffer_size;
2676e5c31af7Sopenharmony_ci		*out_result_buffer_size =
2677e5c31af7Sopenharmony_ci			static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2678e5c31af7Sopenharmony_ci
2679e5c31af7Sopenharmony_ci		DE_ASSERT(*out_result_buffer_size != 0);
2680e5c31af7Sopenharmony_ci	}
2681e5c31af7Sopenharmony_ci}
2682e5c31af7Sopenharmony_ci
2683e5c31af7Sopenharmony_ci/** Retrieves iteration-specific tessellation evaluation shader code.
2684e5c31af7Sopenharmony_ci *
2685e5c31af7Sopenharmony_ci *  @param n_iteration Iteration index, for which the source code is being obtained.
2686e5c31af7Sopenharmony_ci *
2687e5c31af7Sopenharmony_ci *  @return Requested source code.
2688e5c31af7Sopenharmony_ci **/
2689e5c31af7Sopenharmony_cistd::string TessellationShaderInvarianceRule7Test::getTECode(unsigned int n_iteration)
2690e5c31af7Sopenharmony_ci{
2691e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2692e5c31af7Sopenharmony_ci
2693e5c31af7Sopenharmony_ci	const _test_iteration& test_iteration = getTestForIteration(n_iteration);
2694e5c31af7Sopenharmony_ci
2695e5c31af7Sopenharmony_ci	return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2696e5c31af7Sopenharmony_ci													 test_iteration.primitive_mode, test_iteration.vertex_ordering,
2697e5c31af7Sopenharmony_ci													 false); /* point mode */
2698e5c31af7Sopenharmony_ci}
2699e5c31af7Sopenharmony_ci
2700e5c31af7Sopenharmony_ci/** Initializes test iterations for the test. The following modes and inner/outer tess level
2701e5c31af7Sopenharmony_ci *  configurations are used to form the test set:
2702e5c31af7Sopenharmony_ci *
2703e5c31af7Sopenharmony_ci *  - All inner/outer tessellation level combinations as returned by
2704e5c31af7Sopenharmony_ci *    TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
2705e5c31af7Sopenharmony_ci *    times 3 (for triangles) or 4 (for quads). For each combination,
2706e5c31af7Sopenharmony_ci *    the test will capture tessellation coordinates multiple times, each
2707e5c31af7Sopenharmony_ci *    time changing a different outer tessellation level value and leaving
2708e5c31af7Sopenharmony_ci *    the rest intact.
2709e5c31af7Sopenharmony_ci *  - All primitive modes;
2710e5c31af7Sopenharmony_ci *  - All vertex spacing modes;
2711e5c31af7Sopenharmony_ci *
2712e5c31af7Sopenharmony_ci *  All permutations are used to generate the test set.
2713e5c31af7Sopenharmony_ci **/
2714e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule7Test::initTestIterations()
2715e5c31af7Sopenharmony_ci{
2716e5c31af7Sopenharmony_ci	DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2717e5c31af7Sopenharmony_ci
2718e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2719e5c31af7Sopenharmony_ci	const glw::Functions& gl						  = m_context.getRenderContext().getFunctions();
2720e5c31af7Sopenharmony_ci	glw::GLint			  gl_max_tess_gen_level_value = 0;
2721e5c31af7Sopenharmony_ci
2722e5c31af7Sopenharmony_ci	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2723e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2724e5c31af7Sopenharmony_ci
2725e5c31af7Sopenharmony_ci	/* Iterate through all primitive and vertex spacing modes relevant to the test */
2726e5c31af7Sopenharmony_ci	_tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2727e5c31af7Sopenharmony_ci													   TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
2728e5c31af7Sopenharmony_ci	_tessellation_shader_vertex_ordering vo_modes[] = {
2729e5c31af7Sopenharmony_ci		TESSELLATION_SHADER_VERTEX_ORDERING_CCW, TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2730e5c31af7Sopenharmony_ci	};
2731e5c31af7Sopenharmony_ci
2732e5c31af7Sopenharmony_ci	const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2733e5c31af7Sopenharmony_ci	const unsigned int n_vo_modes		 = sizeof(vo_modes) / sizeof(vo_modes[0]);
2734e5c31af7Sopenharmony_ci
2735e5c31af7Sopenharmony_ci	for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2736e5c31af7Sopenharmony_ci	{
2737e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2738e5c31af7Sopenharmony_ci		const unsigned int			 n_relevant_outer_tess_levels =
2739e5c31af7Sopenharmony_ci			(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 4 : 3;
2740e5c31af7Sopenharmony_ci
2741e5c31af7Sopenharmony_ci		for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2742e5c31af7Sopenharmony_ci		{
2743e5c31af7Sopenharmony_ci			_tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode];
2744e5c31af7Sopenharmony_ci
2745e5c31af7Sopenharmony_ci			/* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
2746e5c31af7Sopenharmony_ci			_tessellation_levels_set levels_set;
2747e5c31af7Sopenharmony_ci
2748e5c31af7Sopenharmony_ci			levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2749e5c31af7Sopenharmony_ci				primitive_mode, gl_max_tess_gen_level_value,
2750e5c31af7Sopenharmony_ci				TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2751e5c31af7Sopenharmony_ci
2752e5c31af7Sopenharmony_ci			/* Create test descriptor for all inner/outer level configurations we received from the utils function. */
2753e5c31af7Sopenharmony_ci			for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin();
2754e5c31af7Sopenharmony_ci				 levels_set_iterator != levels_set.end(); levels_set_iterator++)
2755e5c31af7Sopenharmony_ci			{
2756e5c31af7Sopenharmony_ci				const _tessellation_levels& levels = *levels_set_iterator;
2757e5c31af7Sopenharmony_ci
2758e5c31af7Sopenharmony_ci				for (unsigned int n_outer_level_to_change = 0;
2759e5c31af7Sopenharmony_ci					 n_outer_level_to_change < n_relevant_outer_tess_levels + 1 /* base iteration */;
2760e5c31af7Sopenharmony_ci					 ++n_outer_level_to_change)
2761e5c31af7Sopenharmony_ci				{
2762e5c31af7Sopenharmony_ci					/* Create a test descriptor for all the parameters we now have */
2763e5c31af7Sopenharmony_ci					_test_iteration test;
2764e5c31af7Sopenharmony_ci
2765e5c31af7Sopenharmony_ci					memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2766e5c31af7Sopenharmony_ci					memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2767e5c31af7Sopenharmony_ci
2768e5c31af7Sopenharmony_ci					test.primitive_mode  = primitive_mode;
2769e5c31af7Sopenharmony_ci					test.vertex_ordering = vertex_ordering;
2770e5c31af7Sopenharmony_ci
2771e5c31af7Sopenharmony_ci					/* Change iteration-specific outer tessellation level to a different value, but only
2772e5c31af7Sopenharmony_ci					 * if we're not preparing a base iteration*/
2773e5c31af7Sopenharmony_ci					if (n_outer_level_to_change != n_relevant_outer_tess_levels)
2774e5c31af7Sopenharmony_ci					{
2775e5c31af7Sopenharmony_ci						test.n_modified_outer_tess_level				= n_outer_level_to_change;
2776e5c31af7Sopenharmony_ci						test.outer_tess_levels[n_outer_level_to_change] = (float)(gl_max_tess_gen_level_value) / 3.0f;
2777e5c31af7Sopenharmony_ci					}
2778e5c31af7Sopenharmony_ci					else
2779e5c31af7Sopenharmony_ci					{
2780e5c31af7Sopenharmony_ci						test.is_base_iteration = true;
2781e5c31af7Sopenharmony_ci					}
2782e5c31af7Sopenharmony_ci
2783e5c31af7Sopenharmony_ci					if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2784e5c31af7Sopenharmony_ci					{
2785e5c31af7Sopenharmony_ci						m_test_triangles_iterations.push_back(test);
2786e5c31af7Sopenharmony_ci					}
2787e5c31af7Sopenharmony_ci					else
2788e5c31af7Sopenharmony_ci					{
2789e5c31af7Sopenharmony_ci						m_test_quads_iterations.push_back(test);
2790e5c31af7Sopenharmony_ci					}
2791e5c31af7Sopenharmony_ci				}
2792e5c31af7Sopenharmony_ci			} /* for (all levels set entries) */
2793e5c31af7Sopenharmony_ci		}	 /* for (all vertex spacing modes) */
2794e5c31af7Sopenharmony_ci	}		  /* for (all primitive modes) */
2795e5c31af7Sopenharmony_ci}
2796e5c31af7Sopenharmony_ci
2797e5c31af7Sopenharmony_ci/** Tells whether a triangle is included in user-provided set of triangles.
2798e5c31af7Sopenharmony_ci *  The triangle is expected to use an undefined vertex ordering.
2799e5c31af7Sopenharmony_ci *
2800e5c31af7Sopenharmony_ci *  @param base_triangle_data     9 FP values defining 3 vertices of a triangle.
2801e5c31af7Sopenharmony_ci *  @param vertex_data            Vertex stream. It is expected these vertices
2802e5c31af7Sopenharmony_ci *                                form triangles. It is also assumed each vertex
2803e5c31af7Sopenharmony_ci *                                is expressed with 3 components.
2804e5c31af7Sopenharmony_ci *  @param vertex_data_n_vertices Amount of vertices that can be found in @param
2805e5c31af7Sopenharmony_ci *                                vertex_data
2806e5c31af7Sopenharmony_ci *
2807e5c31af7Sopenharmony_ci *  @return true if the triangle was found in user-provided triangle set,
2808e5c31af7Sopenharmony_ci *          false otherwise.
2809e5c31af7Sopenharmony_ci *
2810e5c31af7Sopenharmony_ci **/
2811e5c31af7Sopenharmony_cibool TessellationShaderInvarianceRule7Test::isTriangleDefinedInVertexDataSet(const float* base_triangle_data,
2812e5c31af7Sopenharmony_ci																			 const float* vertex_data,
2813e5c31af7Sopenharmony_ci																			 unsigned int vertex_data_n_vertices)
2814e5c31af7Sopenharmony_ci{
2815e5c31af7Sopenharmony_ci	bool result = false;
2816e5c31af7Sopenharmony_ci
2817e5c31af7Sopenharmony_ci	for (unsigned int n_triangle = 0; n_triangle < vertex_data_n_vertices / 3 /* vertices per triangle */; n_triangle++)
2818e5c31af7Sopenharmony_ci	{
2819e5c31af7Sopenharmony_ci		const float* current_triangle_data = vertex_data +
2820e5c31af7Sopenharmony_ci											 n_triangle * 3 * /* vertices per triangle */
2821e5c31af7Sopenharmony_ci												 3;			  /* components */
2822e5c31af7Sopenharmony_ci
2823e5c31af7Sopenharmony_ci		if (TessellationShaderUtils::isTriangleDefined(current_triangle_data, base_triangle_data))
2824e5c31af7Sopenharmony_ci		{
2825e5c31af7Sopenharmony_ci			result = true;
2826e5c31af7Sopenharmony_ci
2827e5c31af7Sopenharmony_ci			break;
2828e5c31af7Sopenharmony_ci		}
2829e5c31af7Sopenharmony_ci	} /* for (all vertices) */
2830e5c31af7Sopenharmony_ci
2831e5c31af7Sopenharmony_ci	return result;
2832e5c31af7Sopenharmony_ci}
2833e5c31af7Sopenharmony_ci
2834e5c31af7Sopenharmony_ci/** Verifies result data. Accesses data generated by all iterations.
2835e5c31af7Sopenharmony_ci *
2836e5c31af7Sopenharmony_ci *  Throws TestError exception if an error occurs.
2837e5c31af7Sopenharmony_ci *
2838e5c31af7Sopenharmony_ci *  @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2839e5c31af7Sopenharmony_ci *                             data generated by subsequent iterations.
2840e5c31af7Sopenharmony_ci **/
2841e5c31af7Sopenharmony_civoid TessellationShaderInvarianceRule7Test::verifyResultData(const void** all_iterations_data)
2842e5c31af7Sopenharmony_ci{
2843e5c31af7Sopenharmony_ci	const float epsilon = 1e-5f;
2844e5c31af7Sopenharmony_ci
2845e5c31af7Sopenharmony_ci	/* Run two separate iterations:
2846e5c31af7Sopenharmony_ci	 *
2847e5c31af7Sopenharmony_ci	 * a) triangles
2848e5c31af7Sopenharmony_ci	 * b) quads
2849e5c31af7Sopenharmony_ci	 */
2850e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 2 /* triangles, quads */; ++n_iteration)
2851e5c31af7Sopenharmony_ci	{
2852e5c31af7Sopenharmony_ci		bool			   is_triangles_iteration = (n_iteration == 0);
2853e5c31af7Sopenharmony_ci		const unsigned int n_base_iteration =
2854e5c31af7Sopenharmony_ci			(n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2855e5c31af7Sopenharmony_ci		const unsigned int n_relevant_outer_tess_levels = (is_triangles_iteration) ? 3 : 4;
2856e5c31af7Sopenharmony_ci
2857e5c31af7Sopenharmony_ci		_tessellation_primitive_mode primitive_mode = (n_iteration == 0) ?
2858e5c31af7Sopenharmony_ci														  TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
2859e5c31af7Sopenharmony_ci														  TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
2860e5c31af7Sopenharmony_ci
2861e5c31af7Sopenharmony_ci		const _test_iterations& test_iterations =
2862e5c31af7Sopenharmony_ci			(n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2863e5c31af7Sopenharmony_ci
2864e5c31af7Sopenharmony_ci		DE_ASSERT(test_iterations.size() != 0);
2865e5c31af7Sopenharmony_ci
2866e5c31af7Sopenharmony_ci		/* Find a base iteration first */
2867e5c31af7Sopenharmony_ci		for (unsigned int n_base_test_iteration = 0; n_base_test_iteration < test_iterations.size();
2868e5c31af7Sopenharmony_ci			 n_base_test_iteration++)
2869e5c31af7Sopenharmony_ci		{
2870e5c31af7Sopenharmony_ci			const _test_iteration& base_iteration = test_iterations[n_base_test_iteration];
2871e5c31af7Sopenharmony_ci			std::vector<int>	   ref_iteration_indices;
2872e5c31af7Sopenharmony_ci
2873e5c31af7Sopenharmony_ci			if (!base_iteration.is_base_iteration)
2874e5c31af7Sopenharmony_ci			{
2875e5c31af7Sopenharmony_ci				continue;
2876e5c31af7Sopenharmony_ci			}
2877e5c31af7Sopenharmony_ci
2878e5c31af7Sopenharmony_ci			/* Retrieve reference test iterations */
2879e5c31af7Sopenharmony_ci			for (unsigned int n_reference_iteration = 0; n_reference_iteration < n_relevant_outer_tess_levels;
2880e5c31af7Sopenharmony_ci				 ++n_reference_iteration)
2881e5c31af7Sopenharmony_ci			{
2882e5c31af7Sopenharmony_ci				const unsigned int n_modified_outer_tess_level =
2883e5c31af7Sopenharmony_ci					(base_iteration.n_modified_outer_tess_level + n_reference_iteration + 1) %
2884e5c31af7Sopenharmony_ci					n_relevant_outer_tess_levels;
2885e5c31af7Sopenharmony_ci				const unsigned int ref_iteration_index = getTestIterationIndex(
2886e5c31af7Sopenharmony_ci					is_triangles_iteration, base_iteration.inner_tess_levels, base_iteration.outer_tess_levels,
2887e5c31af7Sopenharmony_ci					base_iteration.vertex_ordering, n_modified_outer_tess_level);
2888e5c31af7Sopenharmony_ci
2889e5c31af7Sopenharmony_ci				DE_ASSERT(ref_iteration_index != 0xFFFFFFFF);
2890e5c31af7Sopenharmony_ci				DE_ASSERT(ref_iteration_index != n_base_test_iteration);
2891e5c31af7Sopenharmony_ci
2892e5c31af7Sopenharmony_ci				ref_iteration_indices.push_back(ref_iteration_index);
2893e5c31af7Sopenharmony_ci			}
2894e5c31af7Sopenharmony_ci
2895e5c31af7Sopenharmony_ci			/* We can now start comparing base data with the information generated for
2896e5c31af7Sopenharmony_ci			 * reference iterations. */
2897e5c31af7Sopenharmony_ci			for (std::vector<int>::const_iterator ref_iteration_iterator = ref_iteration_indices.begin();
2898e5c31af7Sopenharmony_ci				 ref_iteration_iterator != ref_iteration_indices.end(); ref_iteration_iterator++)
2899e5c31af7Sopenharmony_ci			{
2900e5c31af7Sopenharmony_ci				const int&			   n_ref_test_iteration = *ref_iteration_iterator;
2901e5c31af7Sopenharmony_ci				const _test_iteration& ref_iteration		= test_iterations[n_ref_test_iteration];
2902e5c31af7Sopenharmony_ci
2903e5c31af7Sopenharmony_ci				/* Now move through all triangles generated for base test iteration. Focus on the ones
2904e5c31af7Sopenharmony_ci				 * that connect the outer edge with one of the inner ones */
2905e5c31af7Sopenharmony_ci				const float* base_iteration_vertex_data =
2906e5c31af7Sopenharmony_ci					(const float*)all_iterations_data[n_base_iteration + n_base_test_iteration];
2907e5c31af7Sopenharmony_ci				const float* ref_iteration_vertex_data =
2908e5c31af7Sopenharmony_ci					(const float*)all_iterations_data[n_base_iteration + n_ref_test_iteration];
2909e5c31af7Sopenharmony_ci
2910e5c31af7Sopenharmony_ci				for (unsigned int n_base_triangle = 0;
2911e5c31af7Sopenharmony_ci					 n_base_triangle < base_iteration.n_vertices / 3; /* vertices per triangle */
2912e5c31af7Sopenharmony_ci					 ++n_base_triangle)
2913e5c31af7Sopenharmony_ci				{
2914e5c31af7Sopenharmony_ci					const float* base_triangle_data =
2915e5c31af7Sopenharmony_ci						base_iteration_vertex_data + n_base_triangle * 3 /* vertices */ * 3; /* components */
2916e5c31af7Sopenharmony_ci
2917e5c31af7Sopenharmony_ci					/* Is that the triangle type we're after? */
2918e5c31af7Sopenharmony_ci					const float* base_triangle_vertex1 = base_triangle_data;
2919e5c31af7Sopenharmony_ci					const float* base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */
2920e5c31af7Sopenharmony_ci					const float* base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */
2921e5c31af7Sopenharmony_ci					bool		 is_base_triangle_vertex1_outer =
2922e5c31af7Sopenharmony_ci						TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1);
2923e5c31af7Sopenharmony_ci					bool is_base_triangle_vertex2_outer =
2924e5c31af7Sopenharmony_ci						TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2);
2925e5c31af7Sopenharmony_ci					bool is_base_triangle_vertex3_outer =
2926e5c31af7Sopenharmony_ci						TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3);
2927e5c31af7Sopenharmony_ci					unsigned int n_outer_edge_vertices_found = 0;
2928e5c31af7Sopenharmony_ci
2929e5c31af7Sopenharmony_ci					n_outer_edge_vertices_found += (is_base_triangle_vertex1_outer == true);
2930e5c31af7Sopenharmony_ci					n_outer_edge_vertices_found += (is_base_triangle_vertex2_outer == true);
2931e5c31af7Sopenharmony_ci					n_outer_edge_vertices_found += (is_base_triangle_vertex3_outer == true);
2932e5c31af7Sopenharmony_ci
2933e5c31af7Sopenharmony_ci					if (n_outer_edge_vertices_found == 0)
2934e5c31af7Sopenharmony_ci					{
2935e5c31af7Sopenharmony_ci						/* This is an inner triangle, not really of our interest */
2936e5c31af7Sopenharmony_ci						continue;
2937e5c31af7Sopenharmony_ci					}
2938e5c31af7Sopenharmony_ci
2939e5c31af7Sopenharmony_ci					/* Which outer tessellation level describes the base data edge? */
2940e5c31af7Sopenharmony_ci					unsigned int n_base_tess_level = 0;
2941e5c31af7Sopenharmony_ci
2942e5c31af7Sopenharmony_ci					if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2943e5c31af7Sopenharmony_ci					{
2944e5c31af7Sopenharmony_ci						if ((!is_base_triangle_vertex1_outer ||
2945e5c31af7Sopenharmony_ci							 (is_base_triangle_vertex1_outer && base_triangle_vertex1[0] == 0.0f)) &&
2946e5c31af7Sopenharmony_ci							(!is_base_triangle_vertex2_outer ||
2947e5c31af7Sopenharmony_ci							 (is_base_triangle_vertex2_outer && base_triangle_vertex2[0] == 0.0f)) &&
2948e5c31af7Sopenharmony_ci							(!is_base_triangle_vertex3_outer ||
2949e5c31af7Sopenharmony_ci							 (is_base_triangle_vertex3_outer && base_triangle_vertex3[0] == 0.0f)))
2950e5c31af7Sopenharmony_ci						{
2951e5c31af7Sopenharmony_ci							n_base_tess_level = 0;
2952e5c31af7Sopenharmony_ci						}
2953e5c31af7Sopenharmony_ci						else if ((!is_base_triangle_vertex1_outer ||
2954e5c31af7Sopenharmony_ci								  (is_base_triangle_vertex1_outer && base_triangle_vertex1[1] == 0.0f)) &&
2955e5c31af7Sopenharmony_ci								 (!is_base_triangle_vertex2_outer ||
2956e5c31af7Sopenharmony_ci								  (is_base_triangle_vertex2_outer && base_triangle_vertex2[1] == 0.0f)) &&
2957e5c31af7Sopenharmony_ci								 (!is_base_triangle_vertex3_outer ||
2958e5c31af7Sopenharmony_ci								  (is_base_triangle_vertex3_outer && base_triangle_vertex3[1] == 0.0f)))
2959e5c31af7Sopenharmony_ci						{
2960e5c31af7Sopenharmony_ci							n_base_tess_level = 1;
2961e5c31af7Sopenharmony_ci						}
2962e5c31af7Sopenharmony_ci						else
2963e5c31af7Sopenharmony_ci						{
2964e5c31af7Sopenharmony_ci							DE_ASSERT((!is_base_triangle_vertex1_outer ||
2965e5c31af7Sopenharmony_ci									   (is_base_triangle_vertex1_outer && base_triangle_vertex1[2] == 0.0f)) &&
2966e5c31af7Sopenharmony_ci									  (!is_base_triangle_vertex2_outer ||
2967e5c31af7Sopenharmony_ci									   (is_base_triangle_vertex2_outer && base_triangle_vertex2[2] == 0.0f)) &&
2968e5c31af7Sopenharmony_ci									  (!is_base_triangle_vertex3_outer ||
2969e5c31af7Sopenharmony_ci									   (is_base_triangle_vertex3_outer && base_triangle_vertex3[2] == 0.0f)));
2970e5c31af7Sopenharmony_ci
2971e5c31af7Sopenharmony_ci							n_base_tess_level = 2;
2972e5c31af7Sopenharmony_ci						}
2973e5c31af7Sopenharmony_ci					} /* if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) */
2974e5c31af7Sopenharmony_ci					else
2975e5c31af7Sopenharmony_ci					{
2976e5c31af7Sopenharmony_ci						DE_ASSERT(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS);
2977e5c31af7Sopenharmony_ci
2978e5c31af7Sopenharmony_ci						std::size_t				  n_outer_edge_vertices = 0;
2979e5c31af7Sopenharmony_ci						std::vector<const float*> outer_edge_vertices;
2980e5c31af7Sopenharmony_ci
2981e5c31af7Sopenharmony_ci						if (is_base_triangle_vertex1_outer)
2982e5c31af7Sopenharmony_ci						{
2983e5c31af7Sopenharmony_ci							outer_edge_vertices.push_back(base_triangle_vertex1);
2984e5c31af7Sopenharmony_ci						}
2985e5c31af7Sopenharmony_ci
2986e5c31af7Sopenharmony_ci						if (is_base_triangle_vertex2_outer)
2987e5c31af7Sopenharmony_ci						{
2988e5c31af7Sopenharmony_ci							outer_edge_vertices.push_back(base_triangle_vertex2);
2989e5c31af7Sopenharmony_ci						}
2990e5c31af7Sopenharmony_ci
2991e5c31af7Sopenharmony_ci						if (is_base_triangle_vertex3_outer)
2992e5c31af7Sopenharmony_ci						{
2993e5c31af7Sopenharmony_ci							outer_edge_vertices.push_back(base_triangle_vertex3);
2994e5c31af7Sopenharmony_ci						}
2995e5c31af7Sopenharmony_ci
2996e5c31af7Sopenharmony_ci						n_outer_edge_vertices = outer_edge_vertices.size();
2997e5c31af7Sopenharmony_ci
2998e5c31af7Sopenharmony_ci						DE_ASSERT(n_outer_edge_vertices >= 1 && n_outer_edge_vertices <= 2);
2999e5c31af7Sopenharmony_ci
3000e5c31af7Sopenharmony_ci						bool is_top_outer_edge	= true;
3001e5c31af7Sopenharmony_ci						bool is_right_outer_edge  = true;
3002e5c31af7Sopenharmony_ci						bool is_bottom_outer_edge = true;
3003e5c31af7Sopenharmony_ci						bool is_left_outer_edge   = true;
3004e5c31af7Sopenharmony_ci
3005e5c31af7Sopenharmony_ci						/* Find which outer edges the vertices don't belong to. If one is in a corner,
3006e5c31af7Sopenharmony_ci						 * the other will clarify to which edge both vertices belong. */
3007e5c31af7Sopenharmony_ci						for (unsigned int n_vertex = 0; n_vertex < n_outer_edge_vertices; ++n_vertex)
3008e5c31af7Sopenharmony_ci						{
3009e5c31af7Sopenharmony_ci							/* Y < 1, not top outer edge */
3010e5c31af7Sopenharmony_ci							if (de::abs(outer_edge_vertices[n_vertex][1] - 1.0f) > epsilon)
3011e5c31af7Sopenharmony_ci							{
3012e5c31af7Sopenharmony_ci								is_top_outer_edge = false;
3013e5c31af7Sopenharmony_ci							}
3014e5c31af7Sopenharmony_ci
3015e5c31af7Sopenharmony_ci							/* X < 1, not right outer edge */
3016e5c31af7Sopenharmony_ci							if (de::abs(outer_edge_vertices[n_vertex][0] - 1.0f) > epsilon)
3017e5c31af7Sopenharmony_ci							{
3018e5c31af7Sopenharmony_ci								is_right_outer_edge = false;
3019e5c31af7Sopenharmony_ci							}
3020e5c31af7Sopenharmony_ci
3021e5c31af7Sopenharmony_ci							/* Y > 0, not bottom outer edge */
3022e5c31af7Sopenharmony_ci							if (de::abs(outer_edge_vertices[n_vertex][1]) > epsilon)
3023e5c31af7Sopenharmony_ci							{
3024e5c31af7Sopenharmony_ci								is_bottom_outer_edge = false;
3025e5c31af7Sopenharmony_ci							}
3026e5c31af7Sopenharmony_ci
3027e5c31af7Sopenharmony_ci							/* X > 0, not left outer edge */
3028e5c31af7Sopenharmony_ci							if (de::abs(outer_edge_vertices[n_vertex][0]) > epsilon)
3029e5c31af7Sopenharmony_ci							{
3030e5c31af7Sopenharmony_ci								is_left_outer_edge = false;
3031e5c31af7Sopenharmony_ci							}
3032e5c31af7Sopenharmony_ci						}
3033e5c31af7Sopenharmony_ci
3034e5c31af7Sopenharmony_ci						if (n_outer_edge_vertices == 1)
3035e5c31af7Sopenharmony_ci						{
3036e5c31af7Sopenharmony_ci							/* A single vertex with corner-coordinates belongs to two edges. Choose one */
3037e5c31af7Sopenharmony_ci							bool x_is_0 = de::abs(outer_edge_vertices[0][0]) < epsilon;
3038e5c31af7Sopenharmony_ci							bool x_is_1 = de::abs(outer_edge_vertices[0][0] - 1.0f) < epsilon;
3039e5c31af7Sopenharmony_ci							bool y_is_0 = de::abs(outer_edge_vertices[0][1]) < epsilon;
3040e5c31af7Sopenharmony_ci							bool y_is_1 = de::abs(outer_edge_vertices[0][1] - 1.0f) < epsilon;
3041e5c31af7Sopenharmony_ci
3042e5c31af7Sopenharmony_ci							if (x_is_0 && y_is_0)
3043e5c31af7Sopenharmony_ci							{
3044e5c31af7Sopenharmony_ci								/* bottom edge */
3045e5c31af7Sopenharmony_ci								DE_ASSERT(is_left_outer_edge && is_bottom_outer_edge);
3046e5c31af7Sopenharmony_ci								is_left_outer_edge = false;
3047e5c31af7Sopenharmony_ci							}
3048e5c31af7Sopenharmony_ci							else if (x_is_0 && y_is_1)
3049e5c31af7Sopenharmony_ci							{
3050e5c31af7Sopenharmony_ci								/* left edge */
3051e5c31af7Sopenharmony_ci								DE_ASSERT(is_left_outer_edge && is_top_outer_edge);
3052e5c31af7Sopenharmony_ci								is_top_outer_edge = false;
3053e5c31af7Sopenharmony_ci							}
3054e5c31af7Sopenharmony_ci							else if (x_is_1 && y_is_0)
3055e5c31af7Sopenharmony_ci							{
3056e5c31af7Sopenharmony_ci								/* right edge */
3057e5c31af7Sopenharmony_ci								DE_ASSERT(is_right_outer_edge && is_bottom_outer_edge);
3058e5c31af7Sopenharmony_ci								is_bottom_outer_edge = false;
3059e5c31af7Sopenharmony_ci							}
3060e5c31af7Sopenharmony_ci							else if (x_is_1 && y_is_1)
3061e5c31af7Sopenharmony_ci							{
3062e5c31af7Sopenharmony_ci								/* top edge */
3063e5c31af7Sopenharmony_ci								DE_ASSERT(is_right_outer_edge && is_top_outer_edge);
3064e5c31af7Sopenharmony_ci								is_right_outer_edge = false;
3065e5c31af7Sopenharmony_ci							}
3066e5c31af7Sopenharmony_ci							else
3067e5c31af7Sopenharmony_ci							{
3068e5c31af7Sopenharmony_ci								/* Not a corner vertex, only one of the edge-flags is set */
3069e5c31af7Sopenharmony_ci							}
3070e5c31af7Sopenharmony_ci						}
3071e5c31af7Sopenharmony_ci
3072e5c31af7Sopenharmony_ci						/* Quick checks */
3073e5c31af7Sopenharmony_ci						DE_UNREF(is_top_outer_edge);
3074e5c31af7Sopenharmony_ci						DE_ASSERT((is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge &&
3075e5c31af7Sopenharmony_ci								   !is_right_outer_edge) ||
3076e5c31af7Sopenharmony_ci								  (!is_left_outer_edge && is_top_outer_edge && !is_bottom_outer_edge &&
3077e5c31af7Sopenharmony_ci								   !is_right_outer_edge) ||
3078e5c31af7Sopenharmony_ci								  (!is_left_outer_edge && !is_top_outer_edge && is_bottom_outer_edge &&
3079e5c31af7Sopenharmony_ci								   !is_right_outer_edge) ||
3080e5c31af7Sopenharmony_ci								  (!is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge &&
3081e5c31af7Sopenharmony_ci								   is_right_outer_edge));
3082e5c31af7Sopenharmony_ci
3083e5c31af7Sopenharmony_ci						/* We have all the data needed to determine which tessellation level describes
3084e5c31af7Sopenharmony_ci						 * subdivision of the edge that the triangle touches */
3085e5c31af7Sopenharmony_ci						if (is_left_outer_edge)
3086e5c31af7Sopenharmony_ci						{
3087e5c31af7Sopenharmony_ci							n_base_tess_level = 0;
3088e5c31af7Sopenharmony_ci						}
3089e5c31af7Sopenharmony_ci						else if (is_bottom_outer_edge)
3090e5c31af7Sopenharmony_ci						{
3091e5c31af7Sopenharmony_ci							n_base_tess_level = 1;
3092e5c31af7Sopenharmony_ci						}
3093e5c31af7Sopenharmony_ci						else if (is_right_outer_edge)
3094e5c31af7Sopenharmony_ci						{
3095e5c31af7Sopenharmony_ci							n_base_tess_level = 2;
3096e5c31af7Sopenharmony_ci						}
3097e5c31af7Sopenharmony_ci						else
3098e5c31af7Sopenharmony_ci						{
3099e5c31af7Sopenharmony_ci							n_base_tess_level = 3;
3100e5c31af7Sopenharmony_ci						}
3101e5c31af7Sopenharmony_ci					}
3102e5c31af7Sopenharmony_ci
3103e5c31af7Sopenharmony_ci					/* We shouldn't perform the check if the edge we're processing was described
3104e5c31af7Sopenharmony_ci					 * by a different outer tessellation level in the reference data set */
3105e5c31af7Sopenharmony_ci					if (n_base_tess_level == ref_iteration.n_modified_outer_tess_level)
3106e5c31af7Sopenharmony_ci					{
3107e5c31af7Sopenharmony_ci						continue;
3108e5c31af7Sopenharmony_ci					}
3109e5c31af7Sopenharmony_ci
3110e5c31af7Sopenharmony_ci					/* This triangle should be present in both vertex data sets */
3111e5c31af7Sopenharmony_ci					if (!isTriangleDefinedInVertexDataSet(base_triangle_data, ref_iteration_vertex_data,
3112e5c31af7Sopenharmony_ci														  ref_iteration.n_vertices))
3113e5c31af7Sopenharmony_ci					{
3114e5c31af7Sopenharmony_ci						const char* primitive_mode_str = (is_triangles_iteration) ? "triangles" : "quads";
3115e5c31af7Sopenharmony_ci
3116e5c31af7Sopenharmony_ci						m_testCtx.getLog()
3117e5c31af7Sopenharmony_ci							<< tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "] "
3118e5c31af7Sopenharmony_ci							<< ", inner tessellation levels:"
3119e5c31af7Sopenharmony_ci							<< "[" << base_iteration.inner_tess_levels[0] << ", " << base_iteration.inner_tess_levels[1]
3120e5c31af7Sopenharmony_ci							<< "], outer tessellation levels:"
3121e5c31af7Sopenharmony_ci							<< "[" << base_iteration.outer_tess_levels[0] << ", " << base_iteration.outer_tess_levels[1]
3122e5c31af7Sopenharmony_ci							<< ", " << base_iteration.outer_tess_levels[2] << ", "
3123e5c31af7Sopenharmony_ci							<< base_iteration.outer_tess_levels[3] << "], a triangle connecting inner & outer edges:"
3124e5c31af7Sopenharmony_ci							<< "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", "
3125e5c31af7Sopenharmony_ci							<< base_triangle_vertex1[2] << "]x"
3126e5c31af7Sopenharmony_ci							<< "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", "
3127e5c31af7Sopenharmony_ci							<< base_triangle_vertex2[2] << "]x"
3128e5c31af7Sopenharmony_ci							<< "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", "
3129e5c31af7Sopenharmony_ci							<< base_triangle_vertex3[2] << "] was not found for runs using CW and CCW vertex ordering, "
3130e5c31af7Sopenharmony_ci														   "which is against the extension specification's rule 7."
3131e5c31af7Sopenharmony_ci							<< tcu::TestLog::EndMessage;
3132e5c31af7Sopenharmony_ci
3133e5c31af7Sopenharmony_ci						TCU_FAIL("Implementation is not conformant with Tessellation Rule 7");
3134e5c31af7Sopenharmony_ci					}
3135e5c31af7Sopenharmony_ci				} /* for (all triangles generated for base test iteration) */
3136e5c31af7Sopenharmony_ci			}	 /* for (all reference iterations) */
3137e5c31af7Sopenharmony_ci		}		  /* for (all base test iterations) */
3138e5c31af7Sopenharmony_ci	}			  /* for (both primitive types) */
3139e5c31af7Sopenharmony_ci}
3140e5c31af7Sopenharmony_ci
3141e5c31af7Sopenharmony_ci} /* namespace glcts */
3142