1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */ /*!
20  * \file
21  * \brief
22  */ /*-------------------------------------------------------------------*/
23 
24 #include "esextcTessellationShaderVertexOrdering.hpp"
25 #include "esextcTessellationShaderUtils.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "glwFunctions.hpp"
30 #include "tcuTestLog.hpp"
31 
32 namespace glcts
33 {
34 /** Constructor
35  *
36  * @param context Test context
37  **/
TessellationShaderVertexOrdering(Context & context,const ExtParameters & extParams)38 TessellationShaderVertexOrdering::TessellationShaderVertexOrdering(Context& context, const ExtParameters& extParams)
39 	: TestCaseBase(context, extParams, "vertex_ordering", "Verifies vertex ordering property affects the tessellation"
40 														  " process as per extension specification")
41 	, m_bo_id(0)
42 	, m_fs_id(0)
43 	, m_tc_id(0)
44 	, m_vs_id(0)
45 	, m_vao_id(0)
46 	, m_utils(DE_NULL)
47 {
48 	/* Left blank on purpose */
49 }
50 
51 /** Deinitializes ES objects created for the test. */
deinit()52 void TessellationShaderVertexOrdering::deinit()
53 {
54 	/* Call base class' deinit() */
55 	TestCaseBase::deinit();
56 
57 	if (!m_is_tessellation_shader_supported)
58 	{
59 		return;
60 	}
61 
62 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
63 
64 	/* Reset TF buffer object bindings */
65 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
66 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
67 
68 	/* Restore GL_PATCH_VERTICES_EXT value */
69 	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
70 
71 	/* Disable GL_RASTERIZER_DISCARD rendering mode */
72 	gl.disable(GL_RASTERIZER_DISCARD);
73 
74 	/* Reset active program object */
75 	gl.useProgram(0);
76 
77 	/* Unbind vertex array object */
78 	gl.bindVertexArray(0);
79 
80 	/* Free all ES objects we allocated for the test */
81 	if (m_bo_id != 0)
82 	{
83 		gl.deleteBuffers(1, &m_bo_id);
84 
85 		m_bo_id = 0;
86 	}
87 
88 	if (m_fs_id != 0)
89 	{
90 		gl.deleteShader(m_fs_id);
91 
92 		m_fs_id = 0;
93 	}
94 
95 	if (m_tc_id != 0)
96 	{
97 		gl.deleteShader(m_tc_id);
98 
99 		m_tc_id = 0;
100 	}
101 
102 	if (m_vs_id != 0)
103 	{
104 		gl.deleteShader(m_vs_id);
105 
106 		m_vs_id = 0;
107 	}
108 
109 	if (m_vao_id != 0)
110 	{
111 		gl.deleteVertexArrays(1, &m_vao_id);
112 
113 		m_vao_id = 0;
114 	}
115 
116 	/* Denitialize utils instance */
117 	if (m_utils != DE_NULL)
118 	{
119 		delete m_utils;
120 
121 		m_utils = DE_NULL;
122 	}
123 
124 	/* Deinitialize all test descriptors */
125 	_test_iterations::iterator it;
126 	for (it = m_tests.begin(); it != m_tests.end(); ++it)
127 	{
128 		deinitTestIteration(*it);
129 	}
130 	m_tests.clear();
131 
132 	for (it = m_tests_points.begin(); it != m_tests_points.end(); ++it)
133 	{
134 		deinitTestIteration(*it);
135 	}
136 	m_tests_points.clear();
137 }
138 
139 /** Deinitialize all test pass-specific ES objects.
140  *
141  *  @param test Descriptor of a test pass to deinitialize.
142  **/
deinitTestIteration(_test_iteration & test_iteration)143 void TessellationShaderVertexOrdering::deinitTestIteration(_test_iteration& test_iteration)
144 {
145 	if (test_iteration.data != DE_NULL)
146 	{
147 		delete[] test_iteration.data;
148 
149 		test_iteration.data = DE_NULL;
150 	}
151 }
152 
153 /** Initializes ES objects necessary to run the test. */
initTest()154 void TessellationShaderVertexOrdering::initTest()
155 {
156 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
157 
158 	/* Skip if required extensions are not supported. */
159 	if (!m_is_tessellation_shader_supported)
160 	{
161 		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
162 	}
163 
164 	/* Initialize vertex array object */
165 	gl.genVertexArrays(1, &m_vao_id);
166 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
167 
168 	gl.bindVertexArray(m_vao_id);
169 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
170 
171 	/* Set up patch size */
172 	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
173 	GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed for GL_PATCH_VERTICES_EXT pname");
174 
175 	/* Disable rasterization */
176 	gl.enable(GL_RASTERIZER_DISCARD);
177 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed");
178 
179 	/* Initialize utils instance */
180 	m_utils = new TessellationShaderUtils(gl, this);
181 
182 	/* Generate all test-wide objects needed for test execution */
183 	gl.genBuffers(1, &m_bo_id);
184 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
185 
186 	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
187 	m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
188 	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
189 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
190 
191 	/* Configure buffer object bindings */
192 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
193 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
194 
195 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
196 					  m_bo_id);
197 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
198 
199 	/* Configure fragment shader body */
200 	const char* fs_body = "${VERSION}\n"
201 						  "\n"
202 						  "void main()\n"
203 						  "{\n"
204 						  "}\n";
205 
206 	shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
207 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
208 
209 	/* Configure tessellation control shader body */
210 	std::string tc_body =
211 		TessellationShaderUtils::getGenericTCCode(4,	  /* n_patch_vertices */
212 												  false); /* should_use_glInvocationID_indexed_input */
213 	const char* tc_body_ptr = tc_body.c_str();
214 
215 	shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body_ptr);
216 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
217 
218 	/* Configure vertex shader body */
219 	const char* vs_body = "${VERSION}\n"
220 						  "\n"
221 						  "void main()\n"
222 						  "{\n"
223 						  "    gl_Position = vec4(1.0, 0.0, 0.0, 0.0);\n"
224 						  "}\n";
225 
226 	shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
227 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
228 
229 	/* Compile all the shaders */
230 	const glw::GLuint  shaders[] = { m_fs_id, m_tc_id, m_vs_id };
231 	const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
232 
233 	for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
234 	{
235 		glw::GLuint shader = shaders[n_shader];
236 
237 		if (shader != 0)
238 		{
239 			glw::GLint compile_status = GL_FALSE;
240 
241 			gl.compileShader(shader);
242 			GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
243 
244 			gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
245 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
246 
247 			if (compile_status != GL_TRUE)
248 			{
249 				TCU_FAIL("Shader compilation failed");
250 			}
251 		}
252 	} /* for (all shaders) */
253 
254 	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
255 	glw::GLint gl_max_tess_gen_level_value = 0;
256 
257 	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
258 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
259 
260 	/* Initialize all test iterations */
261 	bool			   point_mode_statuses[] = { false, true };
262 	const unsigned int n_point_mode_statuses = sizeof(point_mode_statuses) / sizeof(point_mode_statuses[0]);
263 
264 	const _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
265 															 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
266 															 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
267 	const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
268 
269 	const _tessellation_shader_vertex_ordering vertex_orderings[] = { TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
270 																	  TESSELLATION_SHADER_VERTEX_ORDERING_CW,
271 																	  TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT };
272 	const unsigned int n_vertex_orderings = sizeof(vertex_orderings) / sizeof(vertex_orderings[0]);
273 
274 	for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
275 	{
276 		_tessellation_levels_set	 levels_set;
277 		_tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
278 
279 		levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
280 			primitive_mode, gl_max_tess_gen_level_value,
281 			TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES);
282 
283 		for (unsigned int n_vertex_ordering = 0; n_vertex_ordering < n_vertex_orderings; ++n_vertex_ordering)
284 		{
285 			_tessellation_shader_vertex_ordering vertex_ordering = vertex_orderings[n_vertex_ordering];
286 
287 			for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin();
288 				 levels_set_iterator != levels_set.end(); levels_set_iterator++)
289 			{
290 				const _tessellation_levels& levels = *levels_set_iterator;
291 
292 				for (unsigned int n_point_mode_status = 0; n_point_mode_status < n_point_mode_statuses;
293 					 ++n_point_mode_status)
294 				{
295 					bool point_mode_status = point_mode_statuses[n_point_mode_status];
296 
297 					/* Initialize a test run descriptor for the iteration-specific properties */
298 					_test_iteration test_iteration = initTestIteration(levels.inner, levels.outer, primitive_mode,
299 																	   vertex_ordering, point_mode_status, m_utils);
300 
301 					/* Store the test iteration descriptor */
302 					if (!point_mode_status)
303 					{
304 						m_tests.push_back(test_iteration);
305 					}
306 					else
307 					{
308 						m_tests_points.push_back(test_iteration);
309 					}
310 				} /* for (all point mode statuses) */
311 			}	 /* for (all level sets) */
312 		}		  /* for (all vertex orderings) */
313 	}			  /* for (all primitive modes) */
314 
315 	/* Set up buffer object bindings */
316 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
317 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
318 
319 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
320 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
321 }
322 
323 /** Initializes all ES objects, runs the test, captures all vertices
324  *  generated by the tessellator and stores them in the result
325  *  descriptor.
326  *
327  *  NOTE: This function throws a TestError exception, should an error occur.
328  *
329  *  @param inner_tess_levels     Two FP values describing inner tessellation level values to be used
330  *                               for the test run. Must not be NULL.
331  *  @param outer_tess_levels     Four FP values describing outer tessellation level values to be used
332  *                               for the test run. Must not be NULL.
333  *  @param primitive_mode        Primitive mode to be used for the test run.
334  *  @param vertex_ordering       Vertex ordering to be used for the test run.
335  *  @param is_point_mode_enabled true if points mode should be used for the test run, false otherwise.
336  *
337  *  @return _test_iteration instance containing all described data.
338  *
339  **/
initTestIteration(const float * inner_tess_levels,const float * outer_tess_levels,_tessellation_primitive_mode primitive_mode,_tessellation_shader_vertex_ordering vertex_ordering,bool is_point_mode_enabled,TessellationShaderUtils * utils)340 TessellationShaderVertexOrdering::_test_iteration TessellationShaderVertexOrdering::initTestIteration(
341 	const float* inner_tess_levels, const float* outer_tess_levels, _tessellation_primitive_mode primitive_mode,
342 	_tessellation_shader_vertex_ordering vertex_ordering, bool is_point_mode_enabled, TessellationShaderUtils* utils)
343 {
344 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
345 	_test_iteration		  test_iteration;
346 
347 	/* Create & configure a tessellation evaluation shader for the iteration */
348 	const std::string te_code = TessellationShaderUtils::getGenericTECode(
349 		TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode, vertex_ordering, is_point_mode_enabled);
350 	const char* te_code_ptr = te_code.c_str();
351 
352 	glw::GLuint te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
353 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for GL_TESS_EVALUATION_SHADER_EXT pname");
354 
355 	shaderSourceSpecialized(te_id, 1, /* count */
356 							&te_code_ptr);
357 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
358 
359 	utils->compileShaders(1,			 /* n_shaders */
360 						  &te_id, true); /* should_succeed */
361 
362 	/* Create & form iteration-specific program object */
363 	glw::GLuint po_id = gl.createProgram();
364 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed");
365 
366 	gl.attachShader(po_id, m_fs_id);
367 	gl.attachShader(po_id, m_tc_id);
368 	gl.attachShader(po_id, te_id);
369 	gl.attachShader(po_id, m_vs_id);
370 	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed");
371 
372 	/* Set up XFB */
373 	const char* varyings[] = { "result_uvw" };
374 
375 	gl.transformFeedbackVaryings(po_id, 1, /* count */
376 								 varyings, GL_INTERLEAVED_ATTRIBS);
377 	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
378 
379 	/* Link the program object */
380 	glw::GLint link_status = GL_FALSE;
381 
382 	gl.linkProgram(po_id);
383 	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
384 
385 	gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
386 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
387 
388 	if (link_status != GL_TRUE)
389 	{
390 		TCU_FAIL("Program linking failed");
391 	}
392 
393 	gl.deleteShader(te_id);
394 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed");
395 
396 	/* Fill the remaining test iteration descriptor fields */
397 	memcpy(test_iteration.inner_tess_levels, inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
398 	memcpy(test_iteration.outer_tess_levels, outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
399 
400 	test_iteration.is_point_mode_enabled = is_point_mode_enabled;
401 	test_iteration.primitive_mode		 = primitive_mode;
402 	test_iteration.vertex_ordering		 = vertex_ordering;
403 	test_iteration.n_vertices			 = m_utils->getAmountOfVerticesGeneratedByTessellator(
404 		primitive_mode, inner_tess_levels, outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
405 		is_point_mode_enabled);
406 
407 	/* Configure the buffer object storage to hold required amount of data */
408 	glw::GLuint bo_size = static_cast<glw::GLuint>(test_iteration.n_vertices * 3 /* components */ * sizeof(float));
409 
410 	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, /* data */
411 				  GL_STATIC_DRAW);
412 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
413 
414 	/* Also configure the storage in the descriptor */
415 	test_iteration.data = new char[bo_size];
416 
417 	/* Render the data set */
418 	glw::GLint  inner_tess_level_uniform_location = gl.getUniformLocation(po_id, "inner_tess_level");
419 	glw::GLint  outer_tess_level_uniform_location = gl.getUniformLocation(po_id, "outer_tess_level");
420 	glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(primitive_mode, is_point_mode_enabled);
421 
422 	DE_ASSERT(inner_tess_level_uniform_location != -1);
423 	DE_ASSERT(outer_tess_level_uniform_location != -1);
424 
425 	gl.useProgram(po_id);
426 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
427 
428 	gl.uniform2fv(inner_tess_level_uniform_location, 1 /* count */, test_iteration.inner_tess_levels);
429 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
430 
431 	gl.uniform4fv(outer_tess_level_uniform_location, 1 /* count */, test_iteration.outer_tess_levels);
432 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
433 
434 	gl.beginTransformFeedback(tf_mode);
435 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
436 
437 	gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
438 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
439 
440 	gl.endTransformFeedback();
441 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
442 
443 	/* Map the XFB buffer object and copy the rendered data */
444 	const float* xfb_data = (const float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
445 															bo_size, GL_MAP_READ_BIT);
446 
447 	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
448 
449 	memcpy(test_iteration.data, xfb_data, bo_size);
450 
451 	/* Unmap the buffer object, now that we're done retrieving the captured data */
452 	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
453 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
454 
455 	gl.deleteProgram(po_id);
456 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram() call failed");
457 
458 	return test_iteration;
459 }
460 
461 /** Executes the test.
462  *
463  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
464  *
465  *  Note the function throws exception should an error occur!
466  *
467  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
468  **/
iterate(void)469 tcu::TestNode::IterateResult TessellationShaderVertexOrdering::iterate(void)
470 {
471 	initTest();
472 
473 	/* Do not execute if required extensions are not supported. */
474 	if (!m_is_tessellation_shader_supported)
475 	{
476 		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
477 	}
478 
479 	/* There are two main separate cases to consider here:
480 	 *
481 	 * a) for runs executed in "points" mode, we need to verify that vertex
482 	 *    ordering does not modify the order in which the points are generated.
483 	 * b) for both run types, for all primitives but isolines we need to verify
484 	 *    that the vertex ordering is actually taken into account.
485 	 */
486 	const float epsilon = 1e-5f;
487 
488 	for (_test_iterations_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end();
489 		 test_iterator++)
490 	{
491 		if (test_iterator->primitive_mode != TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
492 		{
493 			verifyVertexOrderingCorrectness(*test_iterator);
494 		}
495 	} /* for (all non-points runs) */
496 
497 	for (_test_iterations_const_iterator test_iterator = m_tests_points.begin(); test_iterator != m_tests_points.end();
498 		 test_iterator++)
499 	{
500 		const _test_iteration& test = *test_iterator;
501 
502 		/* For points_mode checks, we need to find a corresponding cw+ccw test pairs */
503 		if (test.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CCW ||
504 			test.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT)
505 		{
506 /* Find a corresponding CW test descriptor */
507 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
508 			bool has_paired_test_been_found = false;
509 #endif
510 			_test_iteration paired_test;
511 
512 			for (_test_iterations_const_iterator paired_test_iterator = m_tests_points.begin();
513 				 paired_test_iterator != m_tests_points.end(); ++paired_test_iterator)
514 			{
515 				if (de::abs(paired_test_iterator->inner_tess_levels[0] - test_iterator->inner_tess_levels[0]) <
516 						epsilon &&
517 					de::abs(paired_test_iterator->inner_tess_levels[1] - test_iterator->inner_tess_levels[1]) <
518 						epsilon &&
519 					de::abs(paired_test_iterator->outer_tess_levels[0] - test_iterator->outer_tess_levels[0]) <
520 						epsilon &&
521 					de::abs(paired_test_iterator->outer_tess_levels[1] - test_iterator->outer_tess_levels[1]) <
522 						epsilon &&
523 					de::abs(paired_test_iterator->outer_tess_levels[2] - test_iterator->outer_tess_levels[2]) <
524 						epsilon &&
525 					de::abs(paired_test_iterator->outer_tess_levels[3] - test_iterator->outer_tess_levels[3]) <
526 						epsilon &&
527 					paired_test_iterator->n_vertices == test_iterator->n_vertices &&
528 					paired_test_iterator->primitive_mode == test_iterator->primitive_mode &&
529 					paired_test_iterator->vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CW)
530 				{
531 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD)
532 					has_paired_test_been_found = true;
533 #endif
534 					paired_test = *paired_test_iterator;
535 
536 					break;
537 				}
538 			}
539 
540 			DE_ASSERT(has_paired_test_been_found);
541 
542 			/* Good to call the verification routine */
543 			verifyVertexOrderingDoesNotChangeGeneratedPoints(test, paired_test);
544 		} /* if (base test 's vertex ordering is CCW) */
545 	}	 /* for (all other runs) */
546 
547 	/* All done */
548 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
549 	return STOP;
550 }
551 
552 /** Verifies that vertex ordering in the data set stored in user-provided
553  *  test iteration descriptor matches the setting that was used in the
554  *  tessellation evaluation stage.
555  *
556  *  @param test_iteration Test iteration descriptor
557  *
558  **/
verifyVertexOrderingCorrectness(const _test_iteration & test_iteration)559 void TessellationShaderVertexOrdering::verifyVertexOrderingCorrectness(const _test_iteration& test_iteration)
560 {
561 	/* Sanity check */
562 	DE_ASSERT(test_iteration.primitive_mode != TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES);
563 
564 	/* Iterate through all vertices */
565 	const float		   epsilon					= 1e-5f;
566 	const unsigned int n_vertices_per_primitive = 3;
567 
568 	for (unsigned int n_primitive = 0; n_primitive < test_iteration.n_vertices / n_vertices_per_primitive;
569 		 ++n_primitive)
570 	{
571 		const float* primitive_data =
572 			(const float*)test_iteration.data + 3 /* components */ * n_primitive * n_vertices_per_primitive;
573 		const float* primitive_vertex1_data = primitive_data;
574 		const float* primitive_vertex2_data = primitive_vertex1_data + 3; /* components */
575 		const float* primitive_vertex3_data = primitive_vertex2_data + 3; /* components */
576 
577 		float cartesian_vertex_data[6] = { primitive_vertex1_data[0], primitive_vertex1_data[1],
578 										   primitive_vertex2_data[0], primitive_vertex2_data[1],
579 										   primitive_vertex3_data[0], primitive_vertex3_data[1] };
580 
581 		if (test_iteration.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
582 		{
583 			/* Triangles are described in barycentric coordinate. Convert to
584 			 * cartesian coordinates before we continue with actual test.
585 			 */
586 			const float barycentric_vertex_data[] = {
587 				primitive_vertex1_data[0], primitive_vertex1_data[1], primitive_vertex1_data[2],
588 				primitive_vertex2_data[0], primitive_vertex2_data[1], primitive_vertex2_data[2],
589 				primitive_vertex3_data[0], primitive_vertex3_data[1], primitive_vertex3_data[2],
590 			};
591 
592 			/* Sanity checks .. */
593 			DE_UNREF(epsilon);
594 			DE_ASSERT(de::abs(barycentric_vertex_data[0] + barycentric_vertex_data[1] + barycentric_vertex_data[2] -
595 							  1.0f) < epsilon);
596 			DE_ASSERT(de::abs(barycentric_vertex_data[3] + barycentric_vertex_data[4] + barycentric_vertex_data[5] -
597 							  1.0f) < epsilon);
598 			DE_ASSERT(de::abs(barycentric_vertex_data[6] + barycentric_vertex_data[7] + barycentric_vertex_data[8] -
599 							  1.0f) < epsilon);
600 
601 			for (unsigned int n_vertex = 0; n_vertex < 3; ++n_vertex)
602 			{
603 				TessellationShaderUtils::convertBarycentricCoordinatesToCartesian(
604 					barycentric_vertex_data + n_vertex * 3, cartesian_vertex_data + n_vertex * 2);
605 			}
606 		} /* if (test_iteration.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) */
607 
608 		/* Compute result of eq 3.6.1 */
609 		float determinant = 0.0f;
610 
611 		for (unsigned int n_vertex = 0; n_vertex < n_vertices_per_primitive; ++n_vertex)
612 		{
613 			int i_op_1 = (n_vertex + 1) % n_vertices_per_primitive;
614 
615 			determinant += (cartesian_vertex_data[n_vertex * 2 /* components */ + 0] *
616 								cartesian_vertex_data[i_op_1 * 2 /* components */ + 1] -
617 							cartesian_vertex_data[i_op_1 * 2 /* components */ + 0] *
618 								cartesian_vertex_data[n_vertex * 2 /* components */ + 1]);
619 		} /* for (all vertices) */
620 
621 		determinant *= 0.5f;
622 
623 		/* Positive determinant implies counterclockwise ordering */
624 		if (((test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CCW ||
625 			  test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT) &&
626 			 determinant < 0.0f) ||
627 			(test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CW && determinant >= 0.0f))
628 		{
629 			std::string primitive_mode =
630 				TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration.primitive_mode);
631 			std::string vertex_ordering =
632 				TessellationShaderUtils::getESTokenForVertexOrderingMode(test_iteration.vertex_ordering);
633 
634 			m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode: [" << primitive_mode.c_str()
635 							   << "] "
636 								  "and inner tessellation levels:"
637 								  " ["
638 							   << test_iteration.inner_tess_levels[0] << ", " << test_iteration.inner_tess_levels[1]
639 							   << "] "
640 								  "and outer tessellation levels:"
641 								  " ["
642 							   << test_iteration.outer_tess_levels[0] << ", " << test_iteration.outer_tess_levels[1]
643 							   << ", " << test_iteration.outer_tess_levels[2] << ", "
644 							   << test_iteration.outer_tess_levels[3] << "] "
645 							   << "and vertex ordering: [" << vertex_ordering.c_str()
646 							   << "] "
647 								  ", vertex orientation has been found to be incompatible with the ordering requested."
648 							   << tcu::TestLog::EndMessage;
649 
650 			if (test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CCW ||
651 				test_iteration.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT)
652 			{
653 				TCU_FAIL("Counter-clockwise ordering was expected but retrieved tessellation coordinates are laid out "
654 						 "in clockwise order");
655 			}
656 			else
657 			{
658 				TCU_FAIL("Clockwise ordering was expected but retrieved tessellation coordinates are laid out in "
659 						 "counter-clockwise order");
660 			}
661 		}
662 	} /* for (all triangles) */
663 }
664 
665 /** Verifies that vertices generated by the tessellator do not differ when run for exactly
666  *  the same tessellation evaluation shaders configure to run in point mode, with an exception
667  *  that one invokation used CW ordering and the other one used CCW ordering.
668  *
669  *  Note: this function throws a TestError exception, should an error occur.
670  *
671  *  @param test_iteration_a Test iteration which was run in point mode and uses CCW vertex
672  *                          ordering.
673  *  @param test_iteration_b Test iteration which was run in point mode and uses CW vertex
674  *                          ordering.
675  *
676  **/
verifyVertexOrderingDoesNotChangeGeneratedPoints(const _test_iteration & test_iteration_a,const _test_iteration & test_iteration_b)677 void TessellationShaderVertexOrdering::verifyVertexOrderingDoesNotChangeGeneratedPoints(
678 	const _test_iteration& test_iteration_a, const _test_iteration& test_iteration_b)
679 {
680 	const float epsilon = 1e-5f;
681 
682 	/* Sanity checks */
683 	DE_ASSERT(test_iteration_a.is_point_mode_enabled);
684 	DE_ASSERT(test_iteration_b.is_point_mode_enabled);
685 	DE_ASSERT(test_iteration_a.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CCW ||
686 			  test_iteration_a.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT);
687 	DE_ASSERT(test_iteration_b.vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_CW);
688 
689 	/* Iterate through all points in test set A and make sure they can be found in test set B */
690 	for (unsigned int n_vertex_a = 0; n_vertex_a < test_iteration_a.n_vertices; ++n_vertex_a)
691 	{
692 		bool		 has_been_found = false;
693 		const float* vertex_a_data  = (const float*)test_iteration_a.data + n_vertex_a * 3 /* components */;
694 
695 		for (unsigned int n_vertex_b = 0; n_vertex_b < test_iteration_b.n_vertices; ++n_vertex_b)
696 		{
697 			const float* vertex_b_data = (const float*)test_iteration_b.data + n_vertex_b * 3 /* components */;
698 
699 			if (de::abs(vertex_a_data[0] - vertex_b_data[0]) < epsilon &&
700 				de::abs(vertex_a_data[1] - vertex_b_data[1]) < epsilon &&
701 				de::abs(vertex_a_data[2] - vertex_b_data[2]) < epsilon)
702 			{
703 				has_been_found = true;
704 
705 				break;
706 			}
707 		} /* for (all B set vertices) */
708 
709 		if (!has_been_found)
710 		{
711 			std::string primitive_mode =
712 				TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration_a.primitive_mode);
713 			std::string vertex_ordering =
714 				TessellationShaderUtils::getESTokenForVertexOrderingMode(test_iteration_a.vertex_ordering);
715 
716 			m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode: [" << primitive_mode.c_str()
717 							   << "] "
718 								  "and inner tessellation levels:"
719 								  " ["
720 							   << test_iteration_a.inner_tess_levels[0] << ", " << test_iteration_a.inner_tess_levels[1]
721 							   << "] "
722 								  "and outer tessellation levels:"
723 								  " ["
724 							   << test_iteration_a.outer_tess_levels[0] << ", " << test_iteration_a.outer_tess_levels[1]
725 							   << ", " << test_iteration_a.outer_tess_levels[2] << ", "
726 							   << test_iteration_a.outer_tess_levels[3] << "] "
727 							   << ", vertices generated for CW and CCW orientations do not match."
728 							   << tcu::TestLog::EndMessage;
729 
730 			TCU_FAIL("For runs in which only vertex ordering setting differs, vertex from one run was not found in the "
731 					 "other run.");
732 		}
733 	} /* for (all A set vertices) */
734 }
735 
736 } /* namespace glcts */
737