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