• 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 "esextcTessellationShaderIsolines.hpp"
25 #include "esextcTessellationShaderUtils.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "glwFunctions.hpp"
30 #include "tcuTestLog.hpp"
31 
32 namespace glcts
33 {
34 
35 /** Constructor
36  *
37  * @param context Test context
38  **/
TessellationShadersIsolines(Context & context,const ExtParameters & extParams)39 TessellationShadersIsolines::TessellationShadersIsolines(Context& context, const ExtParameters& extParams)
40 	: TestCaseBase(context, extParams, "isolines_tessellation",
41 				   "Verifies that the number of isolines generated during tessellation is "
42 				   "derived from the first outer tessellation level.\n"
43 				   "Makes sure that the number of segments in each isoline is derived from "
44 				   "the second outer tessellation level.\n"
45 				   "Makes sure that both inner tessellation levels and the 3rd and the 4th "
46 				   "outer tessellation levels do not affect the tessellation process.\n"
47 				   "Makes sure that equal_spacing vertex spacing mode does not affect amount"
48 				   " of generated isolines.\n"
49 				   "Makes sure no line is drawn between (0, 1) and (1, 1) in (u, v) domain.")
50 	, m_irrelevant_tess_value_1(0.0f)
51 	, m_irrelevant_tess_value_2(0.0f)
52 	, m_utils_ptr(DE_NULL)
53 	, m_vao_id(0)
54 {
55 	/* Left blank on purpose */
56 }
57 
58 /** Checks that amount of isolines generated during tessellation corresponds to the
59  *  first outer tessellation level.
60  *
61  *  This check needs not to operate over all test results generated for a particular
62  *  vertex spacing mode.
63  *
64  *  @param test_result Value of MAX_TESS_GEN_LEVEL token. For ES3.1 it will be equal to
65  *                     GL_MAX_TESS_GEN_LEVEL_EXT and for ES3.2 to GL_MAX_TESS_GEN_LEVEL.
66  *
67  **/
checkFirstOuterTessellationLevelEffect(_test_result & test_result,const glw::GLenum glMaxTessGenLevelToken)68 void TessellationShadersIsolines::checkFirstOuterTessellationLevelEffect(_test_result&	 test_result,
69 																		 const glw::GLenum glMaxTessGenLevelToken)
70 {
71 	glcts::Context&		  context					  = test_result.parent->parent->getContext();
72 	const glw::Functions& gl						  = context.getRenderContext().getFunctions();
73 	glw::GLint			  gl_max_tess_gen_level_value = 0;
74 	unsigned int		  n_isolines_expected		  = 0;
75 
76 	if (test_result.n_vertices != 0)
77 	{
78 		/* Calculate how many isolines we're expecting */
79 		gl.getIntegerv(glMaxTessGenLevelToken, &gl_max_tess_gen_level_value);
80 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
81 
82 		/* NOTE: Amount of isolines should always be based on TESSELLATION_SHADER_VERTEX_SPACING_EQUAL
83 		 *       vertex spacing mode, even if a different one is defined in TE stage.
84 		 */
85 		float outer_zero_tess_level_clamped_rounded = 0.0f;
86 
87 		TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
88 			TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, test_result.parent->outer_tess_levels[0],
89 			gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
90 			&outer_zero_tess_level_clamped_rounded);
91 
92 		n_isolines_expected = (unsigned int)outer_zero_tess_level_clamped_rounded;
93 
94 		if (test_result.n_isolines != n_isolines_expected)
95 		{
96 			tcu::TestContext& test = test_result.parent->parent->getTestContext();
97 
98 			test.getLog() << tcu::TestLog::Message
99 						  << "Tessellator generated an invalid amount of isolines:" << test_result.n_isolines
100 						  << " instead of the expected amount:" << n_isolines_expected
101 						  << " for the following inner tessellation level configuration:"
102 						  << " (" << test_result.parent->inner_tess_levels[0] << ", "
103 						  << test_result.parent->inner_tess_levels[1] << ")"
104 						  << " and the following outer tesellation level configuration:"
105 						  << " (" << test_result.parent->outer_tess_levels[0] << ", "
106 						  << test_result.parent->outer_tess_levels[1] << ", "
107 						  << test_result.parent->outer_tess_levels[2] << ", "
108 						  << test_result.parent->outer_tess_levels[3] << ")" << tcu::TestLog::EndMessage;
109 
110 			TCU_FAIL("Invalid amount of isolines generated by tessellator");
111 		}
112 	} /* if (test_run.n_vertices != 0) */
113 }
114 
115 /** Makes sure that tessellation coordinates generated for inner+outer tessellation level
116  *  configurations, between which irrelevant levels have been defined, are exactly the same.
117  *
118  *  This check needs to operate over all test results generated for a particular
119  *  vertex spacing mode.
120  *
121  *  This function throws a TestError exception if the check fails.
122  **/
checkIrrelevantTessellationLevelsHaveNoEffect()123 void TessellationShadersIsolines::checkIrrelevantTessellationLevelsHaveNoEffect()
124 {
125 	/* Make sure that two example data sets, for which irrelevant tessellation levels have
126 	 * been changed, are exactly the same
127 	 */
128 	DE_ASSERT(m_test_results.find(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL) != m_test_results.end());
129 
130 	const float			   epsilon								  = 1e-5f;
131 	float				   irrelevant_tess_level1_rounded_clamped = 0.0f;
132 	int					   irrelevant_tess_level1				  = 0;
133 	float				   irrelevant_tess_level2_rounded_clamped = 0.0f;
134 	int					   irrelevant_tess_level2				  = 0;
135 	_test_results_iterator test_result_iterator_start =
136 		m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].begin();
137 	_test_results_iterator test_result_iterator_end = m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].end();
138 
139 	/* Calculate two tessellation level values that we've used in init() */
140 	const glw::Functions& gl						  = m_context.getRenderContext().getFunctions();
141 	glw::GLint			  gl_max_tess_gen_level_value = 0;
142 
143 	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
144 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
145 
146 	TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
147 		TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, m_irrelevant_tess_value_1, gl_max_tess_gen_level_value,
148 		DE_NULL, /* out_clamped */
149 		&irrelevant_tess_level1_rounded_clamped);
150 	TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
151 		TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, m_irrelevant_tess_value_2, gl_max_tess_gen_level_value,
152 		DE_NULL, /* out_clamped */
153 		&irrelevant_tess_level2_rounded_clamped);
154 
155 	irrelevant_tess_level1 = (int)irrelevant_tess_level1_rounded_clamped;
156 	irrelevant_tess_level2 = (int)irrelevant_tess_level2_rounded_clamped;
157 
158 	DE_ASSERT(de::abs(irrelevant_tess_level1 - irrelevant_tess_level2) > epsilon);
159 
160 	/* Iterate through all test runs for equal spacing */
161 	for (_test_results_iterator test_result_iterator = test_result_iterator_start;
162 		 test_result_iterator != test_result_iterator_end; test_result_iterator++)
163 	{
164 		_test_result test_result = *test_result_iterator;
165 
166 		if (test_result.irrelevant_tess_level == irrelevant_tess_level1)
167 		{
168 			_test_result test_result_reference =
169 				findTestResult(irrelevant_tess_level2, test_result.outer1_tess_level, test_result.outer2_tess_level,
170 							   TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
171 
172 			/* data for current test run and the reference one should match */
173 			DE_ASSERT(test_result.n_vertices == test_result_reference.n_vertices);
174 
175 			for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex)
176 			{
177 				const float* vertex_data_1 = (&test_result.rendered_data[0]) + n_vertex * 3;		   /* components */
178 				const float* vertex_data_2 = (&test_result_reference.rendered_data[0]) + n_vertex * 3; /* components */
179 
180 				if (de::abs(vertex_data_1[0] - vertex_data_2[0]) > epsilon ||
181 					de::abs(vertex_data_1[1] - vertex_data_2[1]) > epsilon ||
182 					de::abs(vertex_data_1[2] - vertex_data_2[2]) > epsilon)
183 				{
184 					tcu::TestContext& test = test_result_iterator->parent->parent->getTestContext();
185 
186 					test.getLog()
187 						<< tcu::TestLog::Message
188 						<< "Tessellator generated non-matching data for different tessellation level configurations, "
189 						   "where only irrelevant tessellation levels have been changed; "
190 						<< " data generated for {inner:"
191 						<< " (" << test_result.parent->inner_tess_levels[0] << ", "
192 						<< test_result.parent->inner_tess_levels[1] << ")"
193 						<< " outer:"
194 						<< " (" << test_result.parent->outer_tess_levels[0] << ", "
195 						<< test_result.parent->outer_tess_levels[1] << ", " << test_result.parent->outer_tess_levels[2]
196 						<< ", " << test_result.parent->outer_tess_levels[3] << ")"
197 						<< "}:"
198 						<< " (" << vertex_data_1[0] << ", " << vertex_data_1[1] << ", " << vertex_data_1[2] << ")"
199 						<< ", data generated for {inner:"
200 						<< " (" << test_result_reference.parent->inner_tess_levels[0] << ", "
201 						<< test_result_reference.parent->inner_tess_levels[1] << ")"
202 						<< " outer:"
203 						<< " (" << test_result_reference.parent->outer_tess_levels[0] << ", "
204 						<< test_result_reference.parent->outer_tess_levels[1] << ", "
205 						<< test_result_reference.parent->outer_tess_levels[2] << ", "
206 						<< test_result_reference.parent->outer_tess_levels[3] << ")"
207 						<< "}:"
208 						<< " (" << vertex_data_2[0] << ", " << vertex_data_2[1] << ", " << vertex_data_2[2] << ")"
209 						<< tcu::TestLog::EndMessage;
210 
211 					TCU_FAIL("Invalid amount of unique line segments generated by tessellator");
212 				} /* if (equal and fractional_even data mismatch) */
213 			}	 /* for (all vertices) */
214 		}		  /* if (current test result's irrelelvant tessellation levels match what we're after) */
215 	}			  /* for (all test runs) */
216 }
217 
218 /** Checks that the amount of line segments generated per isoline is as defined by
219  *  second outer tessellation level.
220  *
221  *  This check needs not to operate over all test results generated for a particular
222  *  vertex spacing mode.
223  *
224  *  This function throws a TestError exception if the check fails.
225  *
226  *  @param test_result Test result descriptor to perform the check on.
227  *
228  **/
checkSecondOuterTessellationLevelEffect(_test_result & test_result,const glw::GLenum glMaxTessGenLevelToken)229 void TessellationShadersIsolines::checkSecondOuterTessellationLevelEffect(_test_result&		test_result,
230 																		  const glw::GLenum glMaxTessGenLevelToken)
231 {
232 	typedef float _line_segment_x;
233 	typedef std::pair<_line_segment_x, _line_segment_x> _line_segment;
234 	typedef std::vector<_line_segment> _line_segments;
235 	typedef _line_segments::iterator   _line_segments_iterator;
236 
237 	glcts::Context&		  context = test_result.parent->parent->getContext();
238 	const float			  epsilon = 1e-5f;
239 	_line_segments		  found_line_segments;
240 	const glw::Functions& gl								   = context.getRenderContext().getFunctions();
241 	glw::GLint			  gl_max_tess_gen_level_value		   = 0;
242 	float				  outer_tess_levels1_clamped_rounded   = 0.0f;
243 	unsigned int		  n_line_segments_per_isoline_expected = 0;
244 	unsigned int		  n_unique_line_segments_found		   = 0;
245 
246 	if (test_result.n_vertices != 0)
247 	{
248 		/* Calculate how many isolines we're expecting */
249 		gl.getIntegerv(glMaxTessGenLevelToken, &gl_max_tess_gen_level_value);
250 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
251 
252 		TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
253 			test_result.parent->vertex_spacing_mode, test_result.parent->outer_tess_levels[1],
254 			gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
255 			&outer_tess_levels1_clamped_rounded);
256 
257 		n_line_segments_per_isoline_expected = (unsigned int)outer_tess_levels1_clamped_rounded;
258 
259 		/* Count unique line segments found in all the line segments making up the result data set.  */
260 		for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices;
261 			 n_vertex += 2 /* vertices per line segment */)
262 		{
263 			bool		 was_line_segment_found = false;
264 			const float* vertex1				= (&test_result.rendered_data[0]) + n_vertex * 3; /* components */
265 			float		 vertex1_x				= vertex1[0];
266 			const float* vertex2				= (&test_result.rendered_data[0]) + (n_vertex + 1) * 3; /* components */
267 			float		 vertex2_x				= vertex2[0];
268 
269 			for (_line_segments_iterator found_line_segments_iterator = found_line_segments.begin();
270 				 found_line_segments_iterator != found_line_segments.end(); found_line_segments_iterator++)
271 			{
272 				float& found_vertex1_x = found_line_segments_iterator->first;
273 				float& found_vertex2_x = found_line_segments_iterator->second;
274 
275 				if (de::abs(found_vertex1_x - vertex1_x) < epsilon && de::abs(found_vertex2_x - vertex2_x) < epsilon)
276 				{
277 					was_line_segment_found = true;
278 
279 					break;
280 				}
281 			} /* for (all found Ys) */
282 
283 			if (!was_line_segment_found)
284 			{
285 				found_line_segments.push_back(_line_segment(vertex1_x, vertex2_x));
286 			}
287 		} /* for (all vertices) */
288 
289 		/* Compare the values */
290 		n_unique_line_segments_found = (unsigned int)found_line_segments.size();
291 
292 		if (n_unique_line_segments_found != n_line_segments_per_isoline_expected)
293 		{
294 			tcu::TestContext& test = test_result.parent->parent->getTestContext();
295 
296 			test.getLog() << tcu::TestLog::Message << "Tessellator generated an invalid amount of unique line segments:"
297 						  << n_unique_line_segments_found
298 						  << " instead of the expected amount:" << n_line_segments_per_isoline_expected
299 						  << " for the following inner tessellation level configuration:"
300 						  << " (" << test_result.parent->inner_tess_levels[0] << ", "
301 						  << test_result.parent->inner_tess_levels[1] << ")"
302 						  << " and the following outer tesellation level configuration:"
303 						  << " (" << test_result.parent->outer_tess_levels[0] << ", "
304 						  << test_result.parent->outer_tess_levels[1] << ", "
305 						  << test_result.parent->outer_tess_levels[2] << ", "
306 						  << test_result.parent->outer_tess_levels[3] << ")"
307 						  << " and the following vertex spacing mode: " << test_result.parent->vertex_spacing_mode
308 						  << tcu::TestLog::EndMessage;
309 
310 			TCU_FAIL("Invalid amount of unique line segments generated by tessellator");
311 		}
312 	} /* if (test_run.n_vertices != 0) */
313 }
314 
315 /** Verifies that no vertex making up any of the line segments outputted by the
316  *  tessellator is located at height equal to -1.
317  *
318  *  This check needs not to operate over all test results generated for a particular
319  *  vertex spacing mode.
320  *
321  *  This function throws a TestError exception if the check fails.
322  *
323  *  @param test_result Test result descriptor to perform the check on.
324  *
325  **/
checkNoLineSegmentIsDefinedAtHeightOne(_test_result & test_result,glw::GLenum unused)326 void TessellationShadersIsolines::checkNoLineSegmentIsDefinedAtHeightOne(_test_result& test_result, glw::GLenum unused)
327 {
328 	(void)unused; // suppress warning
329 
330 	const float epsilon = 1e-5f;
331 
332 	for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex)
333 	{
334 		const float* vertex = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */
335 
336 		if (de::abs(vertex[1] - 1.0f) < epsilon)
337 		{
338 			tcu::TestContext& test = test_result.parent->parent->getTestContext();
339 
340 			test.getLog() << tcu::TestLog::Message << "Tessellator generated the following coordinate:"
341 						  << " (" << vertex[0] << ", " << vertex[1] << ", " << vertex[2] << ")"
342 						  << " for the following inner tessellation level configuration:"
343 						  << " (" << test_result.parent->inner_tess_levels[0] << ", "
344 						  << test_result.parent->inner_tess_levels[1] << ")"
345 						  << " and the following outer tesellation level configuration:"
346 						  << " (" << test_result.parent->outer_tess_levels[0] << ", "
347 						  << test_result.parent->outer_tess_levels[1] << ", "
348 						  << test_result.parent->outer_tess_levels[2] << ", "
349 						  << test_result.parent->outer_tess_levels[3] << ")"
350 						  << " which is invalid: Y must never be equal to 1." << tcu::TestLog::EndMessage;
351 
352 			TCU_FAIL("Invalid line segment generated by tessellator");
353 		} /* If the Y coordinate is set at 1 */
354 	}	 /* for (all vertices) */
355 }
356 
357 /** Verifies that amount of isolines generated for the same inner+outer level
358  *  configurations but for different vertex spacing modes is exactly the same.
359  *
360  *  This check needs to operate over all test results generated for a particular
361  *  vertex spacing mode.
362  *
363  *  This function throws a TestError exception if the check fails.
364  *
365  **/
checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines()366 void TessellationShadersIsolines::checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines()
367 {
368 	DE_ASSERT(m_tests.find(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL) != m_tests.end());
369 
370 	_test_results_iterator test_result_iterator_start =
371 		m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].begin();
372 	_test_results_iterator test_result_iterator_end = m_test_results[TESSELLATION_SHADER_VERTEX_SPACING_EQUAL].end();
373 
374 	for (_test_results_iterator test_result_iterator = test_result_iterator_start;
375 		 test_result_iterator != test_result_iterator_end; test_result_iterator++)
376 	{
377 		_test_result& test_result_equal = *test_result_iterator;
378 		_test_result  test_result_fe;
379 		_test_result  test_result_fo;
380 
381 		/* Find a corresponding fractional_even test run descriptor */
382 		test_result_fe =
383 			findTestResult(test_result_equal.irrelevant_tess_level, test_result_equal.outer1_tess_level,
384 						   test_result_equal.outer2_tess_level, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN);
385 		test_result_fo =
386 			findTestResult(test_result_equal.irrelevant_tess_level, test_result_equal.outer1_tess_level,
387 						   test_result_equal.outer2_tess_level, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
388 
389 		/* Make sure the amounts match */
390 		if (test_result_equal.n_isolines != test_result_fe.n_isolines ||
391 			test_result_fe.n_isolines != test_result_fo.n_isolines)
392 		{
393 			tcu::TestContext& test = test_result_iterator->parent->parent->getTestContext();
394 
395 			test.getLog() << tcu::TestLog::Message << "Tessellator generated different amount of isolines for EQUAL/"
396 													  "FRACTIONAL_EVEN/FRACTIONAL_ODD vertex spacing modes which is "
397 													  "invalid."
398 						  << tcu::TestLog::EndMessage;
399 
400 			TCU_FAIL("Invalid amount of unique isolines generated by tessellator");
401 		} /* if (amount of generated isolines does not match) */
402 	}	 /* for (all test runs) */
403 }
404 
405 /** Counts amount of unique isolines in the captured data set and updates
406  *  n_isolines field of user-provided @param test_result instance.
407  *
408  *  @param test_result Test result instance to update.
409  */
countIsolines(_test_result & test_result)410 void TessellationShadersIsolines::countIsolines(_test_result& test_result)
411 {
412 	const float		   epsilon = 1e-5f;
413 	std::vector<float> found_ys;
414 
415 	for (unsigned int n_vertex = 0; n_vertex < test_result.n_vertices; ++n_vertex)
416 	{
417 		bool		 was_y_found = false;
418 		const float* vertex		 = (&test_result.rendered_data[0]) + n_vertex * 3; /* components */
419 		float		 vertex_y	= vertex[1];
420 
421 		for (std::vector<float>::iterator found_ys_iterator = found_ys.begin(); found_ys_iterator != found_ys.end();
422 			 found_ys_iterator++)
423 		{
424 			float& found_y = *found_ys_iterator;
425 
426 			if (de::abs(vertex_y - found_y) < epsilon)
427 			{
428 				was_y_found = true;
429 
430 				break;
431 			}
432 		} /* for (all found Ys) */
433 
434 		if (!was_y_found)
435 		{
436 			found_ys.push_back(vertex_y);
437 		}
438 	} /* for (all vertices) */
439 
440 	/* Store the value */
441 	test_result.n_isolines = (unsigned int)found_ys.size();
442 }
443 
444 /** Deinitializes ES objects created for the test. */
deinit()445 void TessellationShadersIsolines::deinit()
446 {
447 	/* Call base class' deinit() */
448 	TestCaseBase::deinit();
449 
450 	if (!m_is_tessellation_shader_supported)
451 	{
452 		return;
453 	}
454 
455 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
456 
457 	/* Reset GL_PATCH_VERTICES_EXT to default value */
458 	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
459 
460 	/* Disable GL_RASTERIZER_DISCARD mode */
461 	gl.disable(GL_RASTERIZER_DISCARD);
462 
463 	/* Unbind vertex array object */
464 	gl.bindVertexArray(0);
465 
466 	/* Release Utilities instance */
467 	if (m_utils_ptr != NULL)
468 	{
469 		delete m_utils_ptr;
470 
471 		m_utils_ptr = DE_NULL;
472 	}
473 
474 	if (m_vao_id != 0)
475 	{
476 		gl.deleteVertexArrays(1, &m_vao_id);
477 
478 		m_vao_id = 0;
479 	}
480 
481 	/* Free the data structures we allocated for the test */
482 	m_tests.clear();
483 }
484 
485 /** Retrieves test result structure for a particular set of properties.
486  *
487  *  @param irrelevant_tess_level Irrelevant tessellation level the test result descriptor should be using.
488  *  @param outer1_tess_level     First outer tessellation level value  the test result descriptor should be using.
489  *  @param outer2_tess_level     Second outer tessellation level value the test result descriptor should be using.
490  *  @param vertex_spacing_mode   Vertex spacing mode the test result descriptor should be using.
491  *
492  *  This function throws a TestError exception if the test result descriptor the caller is after is not found.
493  *
494  *  @return Test result descriptor of interest.
495  **/
findTestResult(_irrelevant_tess_level irrelevant_tess_level,_outer1_tess_level outer1_tess_level,_outer2_tess_level outer2_tess_level,_tessellation_shader_vertex_spacing vertex_spacing_mode)496 TessellationShadersIsolines::_test_result TessellationShadersIsolines::findTestResult(
497 	_irrelevant_tess_level irrelevant_tess_level, _outer1_tess_level outer1_tess_level,
498 	_outer2_tess_level outer2_tess_level, _tessellation_shader_vertex_spacing vertex_spacing_mode)
499 {
500 	DE_ASSERT(m_tests.find(vertex_spacing_mode) != m_tests.end());
501 
502 	_test_results&							  test_results = m_test_results[vertex_spacing_mode];
503 	bool									  has_found	= false;
504 	TessellationShadersIsolines::_test_result result;
505 
506 	for (_test_results_iterator test_results_iterator = test_results.begin();
507 		 test_results_iterator != test_results.end(); test_results_iterator++)
508 	{
509 		if (test_results_iterator->irrelevant_tess_level == irrelevant_tess_level &&
510 			test_results_iterator->outer1_tess_level == outer1_tess_level &&
511 			test_results_iterator->outer2_tess_level == outer2_tess_level)
512 		{
513 			has_found = true;
514 			result	= *test_results_iterator;
515 
516 			break;
517 		}
518 	} /* for (all test runs) */
519 
520 	if (!has_found)
521 	{
522 		TCU_FAIL("Requested test run was not found.");
523 	}
524 
525 	return result;
526 }
527 
528 /** Retrieves rendering context associated with the test instance.
529  *
530  *  @return Rendering context.
531  *
532  **/
getContext()533 Context& TessellationShadersIsolines::getContext()
534 {
535 	return m_context;
536 }
537 
538 /** Initializes ES objects necessary to run the test. */
initTest()539 void TessellationShadersIsolines::initTest()
540 {
541 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
542 
543 	/* Skip if required extensions are not supported. */
544 	if (!m_is_tessellation_shader_supported)
545 	{
546 		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
547 	}
548 
549 	/* Generate Utilities instance */
550 	m_utils_ptr = new TessellationShaderUtils(gl, this);
551 
552 	/* Set up vertex array object */
553 	gl.genVertexArrays(1, &m_vao_id);
554 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
555 
556 	gl.bindVertexArray(m_vao_id);
557 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
558 
559 	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
560 	glw::GLint gl_max_tess_gen_level_value = 0;
561 
562 	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
563 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
564 
565 	/* Initialize reference tessellation values */
566 	const glw::GLfloat tess_levels[] = { -1.0f, 4.0f, float(gl_max_tess_gen_level_value) * 0.5f,
567 										 float(gl_max_tess_gen_level_value) };
568 	const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]);
569 
570 	m_irrelevant_tess_value_1 = tess_levels[0];
571 	m_irrelevant_tess_value_2 = tess_levels[1];
572 
573 	/* Initialize all test passes.
574 	 *
575 	 * Make sure each relevant outer tessellation level iterates through values
576 	 * of our interest
577 	 */
578 	for (unsigned int outer1_tess_level_index = 0; outer1_tess_level_index < n_tess_levels; ++outer1_tess_level_index)
579 	{
580 		for (unsigned int outer2_tess_level_index = 0; outer2_tess_level_index < n_tess_levels;
581 			 ++outer2_tess_level_index)
582 		{
583 			/* To make the test execute in a reasonable time frame, just use
584 			 * two different levels for the outer tessellation levels */
585 			DE_STATIC_ASSERT(n_tess_levels >= 2);
586 
587 			for (unsigned int other_tess_level_index = 0; other_tess_level_index < 2 /* see comment */;
588 				 ++other_tess_level_index)
589 			{
590 				float inner_tess_levels[2] = { tess_levels[other_tess_level_index],
591 											   tess_levels[other_tess_level_index] };
592 				float outer_tess_levels[4] = { tess_levels[outer1_tess_level_index],
593 											   tess_levels[outer2_tess_level_index],
594 											   tess_levels[other_tess_level_index],
595 											   tess_levels[other_tess_level_index] };
596 
597 				/* Finally, iterate over three vertex spacing modes */
598 				_tessellation_shader_vertex_spacing vertex_spacing_mode;
599 
600 				const _tessellation_shader_vertex_spacing vs_modes[] = {
601 					TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
602 					TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD
603 				};
604 				const int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
605 
606 				for (int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
607 				{
608 					vertex_spacing_mode = vs_modes[n_vs_mode];
609 
610 					_test_descriptor test;
611 
612 					initTestDescriptor(vertex_spacing_mode, inner_tess_levels, outer_tess_levels,
613 									   tess_levels[other_tess_level_index], test);
614 
615 					m_tests[vertex_spacing_mode].push_back(test);
616 				} /* for (all available vertex spacing modes) */
617 			}	 /* for (all irrelevant tessellation levels) */
618 		}		  /* for (all defined second outer tessellation levels) */
619 	}			  /* for (all defined first outer tessellation levels) */
620 }
621 
622 /** Initializes all ES objects necessary to run a specific test pass.
623  *
624  *  @param vertex_spacing        Vertex spacing mode to initialize the test descriptor with.
625  *  @param inner_tess_levels     Two FP values defining subsequent inner tessellation levels
626  *                               to be used for initializing the test descriptor. Must NOT be
627  *                               NULL.
628  *  @param outer_tess_levels     Four FP values defining subsequent outer tessellation levels
629  *                               to be used for initializing the test descriptor. Must NOT be
630  *                               NULL.
631  *  @param irrelevant_tess_level Value to be used to set irrelevant tessellation level values.
632  *  @param test                  Test descriptor to fill with IDs of initialized objects.
633  **/
initTestDescriptor(_tessellation_shader_vertex_spacing vertex_spacing,const float * inner_tess_levels,const float * outer_tess_levels,float irrelevant_tess_level,_test_descriptor & test)634 void TessellationShadersIsolines::initTestDescriptor(_tessellation_shader_vertex_spacing vertex_spacing,
635 													 const float* inner_tess_levels, const float* outer_tess_levels,
636 													 float irrelevant_tess_level, _test_descriptor& test)
637 {
638 	memcpy(test.inner_tess_levels, inner_tess_levels, sizeof(test.inner_tess_levels));
639 	memcpy(test.outer_tess_levels, outer_tess_levels, sizeof(test.outer_tess_levels));
640 
641 	test.parent				   = this;
642 	test.irrelevant_tess_level = irrelevant_tess_level;
643 	test.vertex_spacing_mode   = vertex_spacing;
644 }
645 
646 /** Executes the test.
647  *
648  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
649  *
650  *  Note the function throws exception should an error occur!
651  *
652  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
653  **/
iterate(void)654 tcu::TestNode::IterateResult TessellationShadersIsolines::iterate(void)
655 {
656 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
657 
658 	initTest();
659 
660 	/* We only need to use one vertex per so go for it */
661 	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
662 	GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
663 
664 	/* We don't need to rasterize anything in this test */
665 	gl.enable(GL_RASTERIZER_DISCARD);
666 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
667 
668 	/* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value before we continue */
669 	glw::GLint gl_max_tess_gen_level_value = 0;
670 
671 	gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
672 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname.");
673 
674 	/* To perform actual tests, we need to first retrieve the tessellated coordinates data.
675 	 * Run all tests configured and fill per-test buffer with the information.
676 	 **/
677 	for (_tests_per_vertex_spacing_map_iterator vs_key_iterator = m_tests.begin(); vs_key_iterator != m_tests.end();
678 		 vs_key_iterator++)
679 	{
680 		for (_tests_const_iterator test_iterator = vs_key_iterator->second.begin();
681 			 test_iterator != vs_key_iterator->second.end(); test_iterator++)
682 		{
683 			const _test_descriptor& test = *test_iterator;
684 
685 			/* Capture tessellation data for considered configuration */
686 			unsigned int n_rendered_vertices = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
687 				TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, test.inner_tess_levels, test.outer_tess_levels,
688 				test.vertex_spacing_mode, false); /* is_point_mode_enabled */
689 			std::vector<char> rendered_data = m_utils_ptr->getDataGeneratedByTessellator(
690 				test.inner_tess_levels, false, /* point mode */
691 				TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
692 				test.vertex_spacing_mode, test.outer_tess_levels);
693 
694 			/* Store the data in a test result descriptor */
695 			_test_result result;
696 
697 			result.n_vertices			 = n_rendered_vertices;
698 			result.parent				 = &test;
699 			result.irrelevant_tess_level = (int)test.irrelevant_tess_level;
700 			result.outer1_tess_level	 = (int)test.outer_tess_levels[0];
701 			result.outer2_tess_level	 = (int)test.outer_tess_levels[1];
702 			result.rendered_data.resize(rendered_data.size() / sizeof(float));
703 			if (0 != rendered_data.size())
704 			{
705 				memcpy(&result.rendered_data[0], &rendered_data[0], rendered_data.size());
706 			}
707 			countIsolines(result);
708 
709 			/* Store the test run descriptor. */
710 			m_test_results[test.vertex_spacing_mode].push_back(result);
711 		}
712 	}
713 
714 	/* Now we can proceed with actual tests */
715 	/* (test 1): Make sure amount of isolines is determined by first outer tessellation level */
716 	runForAllTestResults(checkFirstOuterTessellationLevelEffect);
717 
718 	/* (test 2): Make sure amount of line segments per height is determined by second outer
719 	 *           tessellation level.
720 	 */
721 	runForAllTestResults(checkSecondOuterTessellationLevelEffect);
722 
723 	/* (test 3): Make sure 3rd, 4th outer tessellation levels, as well as all inner tessellation
724 	 *           levels have no impact on the tessellated coordinates */
725 	checkIrrelevantTessellationLevelsHaveNoEffect();
726 
727 	/* (test 4): Make sure no matter what vertex spacing is requested in TC stage, it is always
728 	 *           equal_spacing that is applied.
729 	 */
730 	checkVertexSpacingDoesNotAffectAmountOfGeneratedIsolines();
731 
732 	/* (test 5): Make sure that no data set features a line segment at height of 1. */
733 	runForAllTestResults(checkNoLineSegmentIsDefinedAtHeightOne);
734 
735 	/* All done */
736 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
737 	return STOP;
738 }
739 
740 /** Calls the caller-provided function provided for each test result descriptor
741  *  created during pre-computation stage.
742  *
743  *  @param pProcessTestRun Function pointer to call. The function will be called
744  *                         exactly once for each cached test result descriptor.
745  *
746  **/
runForAllTestResults(PFNTESTRESULTPROCESSORPROC pProcessTestResult)747 void TessellationShadersIsolines::runForAllTestResults(PFNTESTRESULTPROCESSORPROC pProcessTestResult)
748 {
749 	for (_test_results_per_vertex_spacing_map_iterator vs_key_iterator = m_test_results.begin();
750 		 vs_key_iterator != m_test_results.end(); vs_key_iterator++)
751 	{
752 		for (_test_results_iterator test_results_iterator = vs_key_iterator->second.begin();
753 			 test_results_iterator != vs_key_iterator->second.end(); test_results_iterator++)
754 		{
755 			_test_result& test_result = *test_results_iterator;
756 
757 			pProcessTestResult(test_result, m_glExtTokens.MAX_TESS_GEN_LEVEL);
758 		} /* for (all level3 keys) */
759 	}	 /* for (all vertex spacing modes) */
760 }
761 
762 } /* namespace glcts */
763