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