• 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 "esextcTessellationShaderUtils.hpp"
25 #include "deMath.h"
26 #include "glwEnums.hpp"
27 #include "glwFunctions.hpp"
28 #include "tcuTestLog.hpp"
29 #include <sstream>
30 
31 namespace glcts
32 {
33 
34 /** Constructor
35  *
36  *  @param gl         DEQP container for ES entry-points
37  *  @param parentTest Pointer to owning test instance.
38  **/
TessellationShaderUtils(const glw::Functions & gl,glcts::TestCaseBase * parentTest)39 TessellationShaderUtils::TessellationShaderUtils(const glw::Functions& gl, glcts::TestCaseBase* parentTest)
40 	: m_gl(gl), m_bo_id(0), m_fs_id(0), m_qo_pg_id(0), m_vs_id(0), m_parent_test(parentTest)
41 {
42 	init();
43 }
44 
45 /** Destructor */
~TessellationShaderUtils()46 TessellationShaderUtils::~TessellationShaderUtils()
47 {
48 	deinit();
49 }
50 
51 /** Captures data generated by the tessellator when a geometry is drawn
52  *  for user-provided vertex counter program.
53  *
54  *  @param program Vertex counter program to use.
55  **/
captureTessellationData(_tessellation_vertex_counter_program & program)56 void TessellationShaderUtils::captureTessellationData(_tessellation_vertex_counter_program& program)
57 {
58 	/* Cache current program object ID before we continue */
59 	glw::GLint current_po_id = 0;
60 
61 	m_gl.getIntegerv(GL_CURRENT_PROGRAM, &current_po_id);
62 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() failed for GL_CURRENT_PROGRAM pname");
63 
64 	/* Cache current GL_PATCH_VERTICES_EXT setting before continuing */
65 	glw::GLint current_patch_vertices = 0;
66 
67 	m_gl.getIntegerv(GL_PATCH_VERTICES, &current_patch_vertices);
68 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() failed for GL_PATCH_VERTICES_EXT pname");
69 
70 	/* Activate the program object and the query object */
71 	m_gl.useProgram(program.po_id);
72 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
73 
74 	m_gl.beginQuery(m_parent_test->m_glExtTokens.PRIMITIVES_GENERATED, m_qo_pg_id);
75 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginQuery() called for target GL_PRIMITIVES_GENERATED_EXT failed");
76 
77 	/* Disable rasterization, if it's enabled */
78 	glw::GLboolean is_rasterization_disabled = m_gl.isEnabled(GL_RASTERIZER_DISCARD);
79 
80 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glIsEnabled(GL_RASTERIZER_DISCARD) failed");
81 
82 	if (is_rasterization_disabled)
83 	{
84 		m_gl.enable(GL_RASTERIZER_DISCARD);
85 
86 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
87 	}
88 
89 	/* Update GL_PATCH_VERTICES_EXT */
90 	m_gl.patchParameteri(m_parent_test->m_glExtTokens.PATCH_VERTICES, program.n_patch_vertices);
91 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glPatchParameteriEXT() failed");
92 
93 	/* Draw the test geometry */
94 	m_gl.drawArrays(m_parent_test->m_glExtTokens.PATCHES, 0, /* first */
95 					program.n_patch_vertices);				 /* count */
96 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() failed");
97 
98 	/* End the query and retrieve the result */
99 	glw::GLuint queryValue = 0;
100 
101 	m_gl.endQuery(m_parent_test->m_glExtTokens.PRIMITIVES_GENERATED);
102 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndQuery(GL_PRIMITIVES_GENERATED_EXT) failed");
103 
104 	m_gl.getQueryObjectuiv(m_qo_pg_id, GL_QUERY_RESULT, &queryValue);
105 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryiv() failed");
106 
107 	/* Store amount of primitives under result */
108 	program.n_data_vertices = ((unsigned int)queryValue);
109 
110 	if (!program.is_point_mode_enabled)
111 	{
112 		/* Quads get tessellated into triangles, meaning our primitives counter tells how
113 		 * many triangles were generated for both triangles and quads; isolines get
114 		 * tessellated into line segments.
115 		 */
116 		if (program.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS ||
117 			program.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
118 		{
119 			program.n_data_vertices *= 3; /* each triangle gets 3 vertices */
120 		}
121 		else
122 		{
123 			program.n_data_vertices *= 2; /* each isoline gets 2 vertices */
124 		}
125 	} /* if (!is_point_mode_enabled) */
126 
127 	if (program.n_data_vertices != 0)
128 	{
129 		/* Now that we now, how many vertices we need to allocate space for, set up TF */
130 		glw::GLint bo_size = static_cast<glw::GLint>(sizeof(float) * 3 /* components */ * program.n_data_vertices);
131 
132 		m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
133 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() failed");
134 
135 		m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
136 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() failed");
137 
138 		m_gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, /* data */
139 						GL_STATIC_DRAW);
140 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() failed");
141 
142 		/* Set up TF */
143 		glw::GLenum tf_mode =
144 			TessellationShaderUtils::getTFModeForPrimitiveMode(program.primitive_mode, program.is_point_mode_enabled);
145 
146 		m_gl.beginTransformFeedback(tf_mode);
147 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() failed");
148 
149 		m_gl.drawArrays(m_parent_test->m_glExtTokens.PATCHES, 0, /* first */
150 						program.n_patch_vertices);				 /* count */
151 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() failed");
152 
153 		m_gl.endTransformFeedback();
154 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() failed");
155 
156 		/* Map the BO and copy the contents */
157 		const void* xfb_data = m_gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
158 												   bo_size, GL_MAP_READ_BIT);
159 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() failed");
160 
161 		program.m_data.resize(bo_size);
162 
163 		memcpy(&program.m_data[0], xfb_data, bo_size);
164 
165 		m_gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
166 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() failed");
167 	} /* if (program.n_data_vertices != 0) */
168 
169 	/* Bring the rasterization back up, if it was enabled prior to this call */
170 	if (!is_rasterization_disabled)
171 	{
172 		m_gl.disable(GL_RASTERIZER_DISCARD);
173 
174 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed");
175 	}
176 
177 	/* Activate the pre-call program object*/
178 	m_gl.useProgram(current_po_id);
179 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
180 
181 	/* Bring back pre-call GL_PATCH_VERTICES_EXT setting */
182 	m_gl.patchParameteri(m_parent_test->m_glExtTokens.PATCH_VERTICES, current_patch_vertices);
183 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glPatchParameteriEXT() failed");
184 }
185 
186 /** Compiles all requested shaders. Should any of the shaders not compile,
187  *  TestError exception can be thrown if @param should_succeed is set to true.
188  *
189  *  @param n_shaders      Amount of shader IDs passed in @param shaders argument.
190  *  @param shaders        IDs of shader objects to compile.
191  *  @param should_succeed True if the shaders are expected to compile, false if
192  *                        it's fine for them to not to compile successfully.
193  **/
compileShaders(glw::GLint n_shaders,const glw::GLuint * shaders,bool should_succeed)194 void TessellationShaderUtils::compileShaders(glw::GLint n_shaders, const glw::GLuint* shaders, bool should_succeed)
195 {
196 	for (glw::GLint n_shader = 0; n_shader < n_shaders; ++n_shader)
197 	{
198 		glw::GLuint shader = shaders[n_shader];
199 
200 		if (shader != 0)
201 		{
202 			glw::GLint compile_status = GL_FALSE;
203 
204 			m_gl.compileShader(shader);
205 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCompileShader() failed");
206 
207 			m_gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
208 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv() failed");
209 
210 			if (should_succeed && compile_status != GL_TRUE)
211 			{
212 				std::string info_log	  = m_parent_test->getCompilationInfoLog(shader);
213 				std::string shader_source = m_parent_test->getShaderSource(shader);
214 
215 				m_parent_test->m_context.getTestContext().getLog() << tcu::TestLog::Message
216 																   << "Compilation failure:\n\n"
217 																   << info_log << "\n\n"
218 																   << "Source:\n\n"
219 																   << shader_source << "\n\n"
220 																   << tcu::TestLog::EndMessage;
221 				TCU_FAIL("Shader compilation failed");
222 			}
223 			else if (!should_succeed && compile_status == GL_TRUE)
224 			{
225 				std::string shader_source = m_parent_test->getShaderSource(shader);
226 				m_parent_test->m_context.getTestContext().getLog() << tcu::TestLog::Message
227 																   << "Compilation failure expected.\nSource:\n\n"
228 																   << shader_source << "\n\n"
229 																   << tcu::TestLog::EndMessage;
230 				TCU_FAIL("Shader compiled successfully, even though it was "
231 						 "expected to fail.");
232 			}
233 		}
234 	} /* for (all shaders) */
235 }
236 
237 /** Converts input barycentric coordinates to Cartesian coordinate system. The function assumes
238  *  a triangle basis built of the following verticeS: (0.5, 0), (1, 1), (0, 1).
239  *
240  *  @param barycentric_coordinates   Three FP values storing barycentric coordinates of a point. Must
241  *                                   NOT be NULL.
242  *  @param out_cartesian_coordinates Deref will be used to store two result FP values. Must not be NULL.
243  **/
convertBarycentricCoordinatesToCartesian(const float * barycentric_coordinates,float * out_cartesian_coordinates)244 void TessellationShaderUtils::convertBarycentricCoordinatesToCartesian(const float* barycentric_coordinates,
245 																	   float*		out_cartesian_coordinates)
246 {
247 	/* Assume output triangle uses the following base:
248 	 *
249 	 * (0.5, 0)
250 	 * (1,   1)
251 	 * (0,   1)
252 	 */
253 	const float triangle_vertex1_cartesian[2] = { 0.5f, 0.0f };
254 	const float triangle_vertex2_cartesian[2] = { 1.0f, 1.0f };
255 	const float triangle_vertex3_cartesian[2] = { 0.0f, 1.0f };
256 
257 	out_cartesian_coordinates[0] = (float)((double)barycentric_coordinates[0] * (double)triangle_vertex1_cartesian[0] +
258 										   (double)barycentric_coordinates[1] * (double)triangle_vertex2_cartesian[0] +
259 										   (double)barycentric_coordinates[2] * (double)triangle_vertex3_cartesian[0]);
260 	out_cartesian_coordinates[1] = barycentric_coordinates[0] * triangle_vertex1_cartesian[1] +
261 								   barycentric_coordinates[1] * triangle_vertex2_cartesian[1] +
262 								   barycentric_coordinates[2] * triangle_vertex3_cartesian[1];
263 }
264 
265 /** Converts input Cartesian coordinates to barycentric coordinate system. The function assumes
266  *  a triangle basis built of the following verticeS: (0.5, 0), (1, 1), (0, 1).
267  *
268  *  @param cartesian_coordinates       Two FP values storing Cartesian coordinates of a point. Must NOT
269  *                                     be NULL.
270  *  @param out_barycentric_coordinates Deref will be used to store three result FP values. Must NOT be NULL.
271  **/
convertCartesianCoordinatesToBarycentric(const float * cartesian_coordinates,float * out_barycentric_coordinates)272 void TessellationShaderUtils::convertCartesianCoordinatesToBarycentric(const float* cartesian_coordinates,
273 																	   float*		out_barycentric_coordinates)
274 {
275 	/* Assume input triangle uses the following base:
276 	 *
277 	 * (0.5, 0)
278 	 * (1,   1)
279 	 * (0,   1)
280 	 */
281 	const float x1 = 0.5f;
282 	const float x2 = 1.0f;
283 	const float x3 = 0.0f;
284 	const float y1 = 0.0f;
285 	const float y2 = 1.0f;
286 	const float y3 = 1.0f;
287 
288 	out_barycentric_coordinates[0] =
289 		((y2 - y3) * (cartesian_coordinates[0] - x3) + (x3 - x2) * (cartesian_coordinates[1] - y3)) /
290 		((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3));
291 	out_barycentric_coordinates[1] =
292 		((y3 - y1) * (cartesian_coordinates[0] - x3) + (x1 - x3) * (cartesian_coordinates[1] - y3)) /
293 		((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3));
294 	out_barycentric_coordinates[2] = 1.0f - out_barycentric_coordinates[0] - out_barycentric_coordinates[1];
295 }
296 
297 /** Deinitializes ES objects created for TessellationShaderUtils
298  *  instance.
299  **/
deinit()300 void TessellationShaderUtils::deinit()
301 {
302 	if (!m_parent_test->m_is_tessellation_shader_supported)
303 	{
304 		return;
305 	}
306 
307 	if (m_bo_id != 0)
308 	{
309 		m_gl.deleteBuffers(1, &m_bo_id);
310 
311 		m_bo_id = 0;
312 	}
313 
314 	if (m_fs_id != 0)
315 	{
316 		m_gl.deleteShader(m_fs_id);
317 
318 		m_fs_id = 0;
319 	}
320 
321 	if (m_qo_pg_id != 0)
322 	{
323 		m_gl.deleteQueries(1, &m_qo_pg_id);
324 
325 		m_qo_pg_id = 0;
326 	}
327 
328 	if (m_vs_id != 0)
329 	{
330 		m_gl.deleteShader(m_vs_id);
331 
332 		m_vs_id = 0;
333 	}
334 
335 	/* Revert TF buffer object bindings */
336 	m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
337 	m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
338 
339 	/* Disable GL_RASTERIZER_DISCARD mode */
340 	m_gl.disable(GL_RASTERIZER_DISCARD);
341 
342 	/* Restore GL_PATCH_VERTICES_EXT value */
343 	m_gl.patchParameteri(m_parent_test->m_glExtTokens.PATCH_VERTICES, 3);
344 }
345 
346 /** Retrieves generic tessellation control shader source code.
347  *  The shader users user-specified amount of output patch vertices and:
348  *
349  *  - sets gl_Position to gl_in[0].gl_Position if second argument is set to false.
350  *  - sets gl_Position to gl_in[gl_InvocationID].gl_Position otherwise.
351  *
352  *  @param n_patch_vertices                        Amount of output patch vertices
353  *                                                 to use in the shader.
354  *  @param should_use_glInvocationID_indexed_input See above.
355  *
356  *  @return Requested string.
357  */
getGenericTCCode(unsigned int n_patch_vertices,bool should_use_glInvocationID_indexed_input)358 std::string TessellationShaderUtils::getGenericTCCode(unsigned int n_patch_vertices,
359 													  bool		   should_use_glInvocationID_indexed_input)
360 {
361 	std::string result;
362 	const char* tc_body_false = "${VERSION}\n"
363 								"\n"
364 								"${TESSELLATION_SHADER_REQUIRE}\n"
365 								"\n"
366 								"layout (vertices = MAX_VERTICES) out;\n"
367 								"\n"
368 								"uniform vec2 inner_tess_level;\n"
369 								"uniform vec4 outer_tess_level;\n"
370 								"\n"
371 								"void main()\n"
372 								"{\n"
373 								"    gl_out[gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
374 								"\n"
375 								"    gl_TessLevelInner[0] = inner_tess_level.x;\n"
376 								"    gl_TessLevelInner[1] = inner_tess_level.y;\n"
377 								"    gl_TessLevelOuter[0] = outer_tess_level.x;\n"
378 								"    gl_TessLevelOuter[1] = outer_tess_level.y;\n"
379 								"    gl_TessLevelOuter[2] = outer_tess_level.z;\n"
380 								"    gl_TessLevelOuter[3] = outer_tess_level.w;\n"
381 								"}\n";
382 
383 	const char* tc_body_true = "${VERSION}\n"
384 							   "\n"
385 							   "${TESSELLATION_SHADER_REQUIRE}\n"
386 							   "\n"
387 							   "layout (vertices = MAX_VERTICES) out;\n"
388 							   "\n"
389 							   "uniform vec2 inner_tess_level;\n"
390 							   "uniform vec4 outer_tess_level;\n"
391 							   "\n"
392 							   "void main()\n"
393 							   "{\n"
394 							   "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
395 							   "\n"
396 							   "    gl_TessLevelInner[0] = inner_tess_level.x;\n"
397 							   "    gl_TessLevelInner[1] = inner_tess_level.y;\n"
398 							   "    gl_TessLevelOuter[0] = outer_tess_level.x;\n"
399 							   "    gl_TessLevelOuter[1] = outer_tess_level.y;\n"
400 							   "    gl_TessLevelOuter[2] = outer_tess_level.z;\n"
401 							   "    gl_TessLevelOuter[3] = outer_tess_level.w;\n"
402 							   "}\n";
403 
404 	const char*		  n_patch_vertices_raw_ptr = NULL;
405 	std::stringstream n_patch_vertices_sstream;
406 	std::string		  n_patch_vertices_string;
407 	std::string		  token		  = "MAX_VERTICES";
408 	std::size_t		  token_index = std::string::npos;
409 
410 	n_patch_vertices_sstream << n_patch_vertices;
411 	n_patch_vertices_string  = n_patch_vertices_sstream.str();
412 	n_patch_vertices_raw_ptr = n_patch_vertices_string.c_str();
413 
414 	result = (should_use_glInvocationID_indexed_input) ? tc_body_true : tc_body_false;
415 
416 	while ((token_index = result.find(token)) != std::string::npos)
417 	{
418 		result = result.replace(token_index, token.length(), n_patch_vertices_raw_ptr);
419 
420 		token_index = result.find(token);
421 	}
422 
423 	return result;
424 }
425 
426 /** Retrieves generic tessellation evaluation shader source code.
427  *  The shader users user-specified tessellation properties.
428  *
429  *  @param vertex_spacing Vertex spacing mode to use in the shader.
430  *  @param primitive_mode Primitive mode to use in the shader.
431  *  @param point_mode     true to use point_mode in the shader, false
432  *                        to omit it.
433  *
434  *  @return Requested string.
435  */
getGenericTECode(_tessellation_shader_vertex_spacing vertex_spacing,_tessellation_primitive_mode primitive_mode,_tessellation_shader_vertex_ordering vertex_ordering,bool point_mode)436 std::string TessellationShaderUtils::getGenericTECode(_tessellation_shader_vertex_spacing  vertex_spacing,
437 													  _tessellation_primitive_mode		   primitive_mode,
438 													  _tessellation_shader_vertex_ordering vertex_ordering,
439 													  bool								   point_mode)
440 {
441 	std::string result;
442 	const char* te_body = "${VERSION}\n"
443 						  "\n"
444 						  "${TESSELLATION_SHADER_REQUIRE}\n"
445 						  "\n"
446 						  "layout (TESSELLATOR_PRIMITIVE_MODE VERTEX_SPACING_MODE VERTEX_ORDERING POINT_MODE) in;\n"
447 						  "\n"
448 						  "out vec3 result_uvw;\n"
449 						  "\n"
450 						  "void main()\n"
451 						  "{\n"
452 						  "    gl_Position = gl_in[0].gl_Position;\n"
453 						  "    result_uvw  = gl_TessCoord;\n"
454 						  "}\n";
455 
456 	const char* point_mode_token		   = "POINT_MODE";
457 	std::size_t point_mode_token_index	 = std::string::npos;
458 	std::string primitive_mode_string	  = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
459 	const char* primitive_mode_token	   = "TESSELLATOR_PRIMITIVE_MODE";
460 	std::size_t primitive_mode_token_index = std::string::npos;
461 	std::string vertex_ordering_string;
462 	const char* vertex_ordering_token		= "VERTEX_ORDERING";
463 	std::size_t vertex_ordering_token_index = std::string::npos;
464 	std::string vertex_spacing_mode_string;
465 	const char* vertex_spacing_token	   = "VERTEX_SPACING_MODE";
466 	std::size_t vertex_spacing_token_index = std::string::npos;
467 
468 	result = te_body;
469 
470 	/* Prepare the vertex ordering token. We need to do this manually, because the default vertex spacing
471 	 * mode translates to empty string and the shader would fail to compile if we hadn't taken care of the
472 	 * comma
473 	 */
474 	if (vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT)
475 	{
476 		vertex_ordering_string = TessellationShaderUtils::getESTokenForVertexOrderingMode(vertex_ordering);
477 	}
478 	else
479 	{
480 		std::stringstream helper_sstream;
481 
482 		helper_sstream << ", " << TessellationShaderUtils::getESTokenForVertexOrderingMode(vertex_ordering);
483 
484 		vertex_ordering_string = helper_sstream.str();
485 	}
486 
487 	/* Do the same for vertex spacing token */
488 	if (vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT)
489 	{
490 		vertex_spacing_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing);
491 	}
492 	else
493 	{
494 		std::stringstream helper_sstream;
495 
496 		helper_sstream << ", " << TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing);
497 
498 		vertex_spacing_mode_string = helper_sstream.str();
499 	}
500 
501 	/* Primitive mode */
502 	while ((primitive_mode_token_index = result.find(primitive_mode_token)) != std::string::npos)
503 	{
504 		result = result.replace(primitive_mode_token_index, strlen(primitive_mode_token), primitive_mode_string);
505 
506 		primitive_mode_token_index = result.find(primitive_mode_token);
507 	}
508 
509 	/* Vertex ordering */
510 	while ((vertex_ordering_token_index = result.find(vertex_ordering_token)) != std::string::npos)
511 	{
512 		result = result.replace(vertex_ordering_token_index, strlen(vertex_ordering_token), vertex_ordering_string);
513 
514 		vertex_ordering_token_index = result.find(vertex_ordering_token);
515 	}
516 
517 	/* Vertex spacing */
518 	while ((vertex_spacing_token_index = result.find(vertex_spacing_token)) != std::string::npos)
519 	{
520 		result = result.replace(vertex_spacing_token_index, strlen(vertex_spacing_token), vertex_spacing_mode_string);
521 
522 		vertex_spacing_token_index = result.find(vertex_spacing_token);
523 	}
524 
525 	/* Point mode */
526 	while ((point_mode_token_index = result.find(point_mode_token)) != std::string::npos)
527 	{
528 		result = result.replace(point_mode_token_index, strlen(point_mode_token), (point_mode) ? ", point_mode" : "");
529 
530 		point_mode_token_index = result.find(point_mode_token);
531 	}
532 
533 	return result;
534 }
535 
536 /** Initializes ES objects that will be needed for non-static calls
537  *
538  *  This function throws TestError exception if an error occurs.
539  *
540  **/
init()541 void TessellationShaderUtils::init()
542 {
543 	if (!m_parent_test->m_is_tessellation_shader_supported)
544 	{
545 		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
546 	}
547 
548 	/* Create buffer object used to hold XFB data */
549 	m_gl.genBuffers(1, &m_bo_id);
550 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() failed");
551 
552 	/* Create query object */
553 	m_gl.genQueries(1, &m_qo_pg_id);
554 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenQueries() failed");
555 
556 	/* Initialize shader objects */
557 	m_fs_id = m_gl.createShader(GL_FRAGMENT_SHADER);
558 	m_vs_id = m_gl.createShader(GL_VERTEX_SHADER);
559 
560 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader() failed");
561 
562 	/* Initialize bodies of the shaders and try to compile them */
563 	const glw::GLuint  shaders[] = { m_fs_id, m_vs_id };
564 	const unsigned int n_shaders = DE_LENGTH_OF_ARRAY(shaders);
565 
566 	const char* fs_body = "${VERSION}\n"
567 						  "\n"
568 						  "void main()\n"
569 						  "{\n"
570 						  "}\n";
571 	const char* vs_body = "${VERSION}\n"
572 						  "\n"
573 						  "void main()\n"
574 						  "{\n"
575 						  "    gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
576 						  "}\n";
577 
578 	m_parent_test->shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
579 	m_parent_test->shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
580 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glShaderSource() failed");
581 
582 	compileShaders(n_shaders, shaders, true);
583 }
584 
585 /** Retrieves amount of vertices that will be generated for a draw call
586  *  that uses a program object, which is built of (at least) one tessellation
587  *  stage.
588  *
589  *  NOTE: This function can temporarily unbind active program object.
590  *        This function throws TestError exception if an error occurs.
591  *
592  *  @param primitive_mode           Primitive mode used for the tessellation.
593  *  @param inner_tessellation_level Two FP values that define inner tessellation levels.
594  *                                  Must NOT be NULL.
595  *  @param outer_tessellation_level Four FP values that define outer tessellation levels.
596  *                                  Must NOT be NULL.
597  *  @param vertex_spacing           Vertex spacing mode used for the tessellation.
598  *  @param is_point_mode_enabled    true if point_mode should be enabled for the query,
599  *                                  false otherwise.
600  *
601  *  This function REQUIRES GL_EXT_geometry_shader support.
602  *  This function throws TestError exception, should an error occur.
603  *
604  *  @return Amount of vertices that would be generated by the tessellator unit for
605  *          a particular draw call.
606  **/
getAmountOfVerticesGeneratedByTessellator(_tessellation_primitive_mode primitive_mode,const float * inner_tessellation_level,const float * outer_tessellation_level,_tessellation_shader_vertex_spacing vertex_spacing,bool is_point_mode_enabled)607 unsigned int TessellationShaderUtils::getAmountOfVerticesGeneratedByTessellator(
608 	_tessellation_primitive_mode primitive_mode, const float* inner_tessellation_level,
609 	const float* outer_tessellation_level, _tessellation_shader_vertex_spacing vertex_spacing,
610 	bool is_point_mode_enabled)
611 {
612 	unsigned int result = 0;
613 
614 	switch (primitive_mode)
615 	{
616 	case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
617 	case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
618 	case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
619 	{
620 		/* We refer to a counter program, TC and TE stages are configured as specified
621 		 * by the caller. Before we issue the draw call, we begin a query introduced in
622 		 * GL_EXT_geometry_shader that allows us to count how many primitives would have been generated. Doing so
623 		 * allows us to determine how many vertices were generated during the processed.
624 		 */
625 		const glw::GLint					 test_n_patch_vertices = 1;
626 		_tessellation_vertex_counter_program test_program(m_gl);
627 
628 		initTessellationVertexCounterProgram(inner_tessellation_level, outer_tessellation_level, test_n_patch_vertices,
629 											 vertex_spacing, primitive_mode, is_point_mode_enabled, test_program);
630 
631 		result = test_program.n_data_vertices;
632 		break;
633 	}
634 
635 	default:
636 	{
637 		TCU_FAIL("Unrecognized primitive mode");
638 	}
639 	} /* switch (primitive_mode) */
640 
641 	return result;
642 }
643 
644 /** Retrieves data generated by a tessellator for a particular tessellation configuration.
645  *
646  *  @param inner           Two FP values defining inner tessellation values to be used for tessellation.
647  *                         Must not be NULL.
648  *  @param point_mode      true if point mode is to be used for tessellation, false otherwise.
649  *  @param primitive_mode  Primitive mode to be used for tessellation.
650  *  @param vertex_ordering Vertex ordering to be used for tessellation.
651  *  @param vertex_spacing  Vertex spacing to be used for tessellation.
652  *  @param outer           Four FP values defining outer tessellation values to be used for tessellation.
653  *                         Must not be NULL.
654  *
655  *  @return Pointer to buffer containing tessellated coordinates.
656  **/
getDataGeneratedByTessellator(const float * inner,bool point_mode,_tessellation_primitive_mode primitive_mode,_tessellation_shader_vertex_ordering vertex_ordering,_tessellation_shader_vertex_spacing vertex_spacing,const float * outer)657 std::vector<char> TessellationShaderUtils::getDataGeneratedByTessellator(
658 	const float* inner, bool point_mode, _tessellation_primitive_mode primitive_mode,
659 	_tessellation_shader_vertex_ordering vertex_ordering, _tessellation_shader_vertex_spacing vertex_spacing,
660 	const float* outer)
661 {
662 	(void)vertex_ordering;
663 
664 	glw::GLint							 test_n_patch_vertices = getPatchVerticesForPrimitiveMode(primitive_mode);
665 	_tessellation_vertex_counter_program test_program(m_gl);
666 
667 	initTessellationVertexCounterProgram(inner, outer, test_n_patch_vertices, vertex_spacing, primitive_mode,
668 										 point_mode, test_program);
669 	return test_program.m_data;
670 }
671 
672 /** Retrieves ESSL token corresponding to particular primitive mode.
673  *  Will throw TestError exception if @param primitive_mode is not
674  *  valid.
675  *
676  *  @param primitive_mode Primitive mode to consider.
677  *
678  *  @return String telling how the primitive mode would be expressed in
679  *          ES SL.
680  **/
getESTokenForPrimitiveMode(_tessellation_primitive_mode primitive_mode)681 std::string TessellationShaderUtils::getESTokenForPrimitiveMode(_tessellation_primitive_mode primitive_mode)
682 {
683 	std::string result = "?";
684 
685 	switch (primitive_mode)
686 	{
687 	case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
688 	{
689 		result = "isolines";
690 
691 		break;
692 	}
693 
694 	case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
695 	{
696 		result = "quads";
697 
698 		break;
699 	}
700 
701 	case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
702 	{
703 		result = "triangles";
704 
705 		break;
706 	}
707 
708 	default:
709 	{
710 		TCU_FAIL("Unrecognized tessellation primitive mode");
711 	}
712 	}
713 
714 	return result;
715 }
716 
717 /** Retrieves ESSL token corresponding to particular vertex ordering.
718  *  Will throw TestError exception if @param vertex_ordering is not
719  *  valid.
720  *
721  *  @param vertex_ordering Vertex ordering to consider.
722  *
723  *  @return String telling how the vertex mode would be expressed in
724  *          ES SL.
725  **/
getESTokenForVertexOrderingMode(_tessellation_shader_vertex_ordering vertex_ordering)726 std::string TessellationShaderUtils::getESTokenForVertexOrderingMode(
727 	_tessellation_shader_vertex_ordering vertex_ordering)
728 {
729 	std::string result;
730 
731 	switch (vertex_ordering)
732 	{
733 	case TESSELLATION_SHADER_VERTEX_ORDERING_CCW:
734 	{
735 		result = "ccw";
736 
737 		break;
738 	}
739 
740 	case TESSELLATION_SHADER_VERTEX_ORDERING_CW:
741 	{
742 		result = "cw";
743 
744 		break;
745 	}
746 
747 	case TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT:
748 	{
749 		/* Simply return an empty token */
750 		result = "";
751 
752 		break;
753 	}
754 
755 	default:
756 	{
757 		TCU_FAIL("Unrecognized tessellation shader vertex ordering");
758 	}
759 	} /* switch (vertex_ordering) */
760 
761 	return result;
762 }
763 
764 /** Retrieves ESSL token corresponding to particular vertex spacing mode.
765  *  Will throw TestError exception if @param vertex_spacing is not
766  *  valid.
767  *
768  *  @param vertex_spacing Vertex spacing mode to consider.
769  *
770  *  @return String telling how the vertex spacing mode would be expressed in
771  *          ES SL.
772  **/
getESTokenForVertexSpacingMode(_tessellation_shader_vertex_spacing vertex_spacing)773 std::string TessellationShaderUtils::getESTokenForVertexSpacingMode(_tessellation_shader_vertex_spacing vertex_spacing)
774 {
775 	std::string result;
776 
777 	switch (vertex_spacing)
778 	{
779 	case TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT:
780 	{
781 		result = "";
782 
783 		break;
784 	}
785 
786 	case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
787 	{
788 		result = "equal_spacing";
789 
790 		break;
791 	}
792 
793 	case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN:
794 	{
795 		result = "fractional_even_spacing";
796 
797 		break;
798 	}
799 
800 	case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
801 	{
802 		result = "fractional_odd_spacing";
803 
804 		break;
805 	}
806 
807 	default:
808 	{
809 		TCU_FAIL("Invalid vertex spacing mode requested");
810 	}
811 	}
812 
813 	return result;
814 }
815 
816 /** Tells how many vertices should be passed in a single patch for
817  *  particular primitive mode to work for tessellation stage.
818  *
819  *  Throws TestError exception if @param primitive_mode is invalid.
820  *
821  *  @param primitive_mode Primitive mode to consider.
822  *
823  *  @return Requested value.
824  **/
getPatchVerticesForPrimitiveMode(_tessellation_primitive_mode primitive_mode)825 glw::GLint TessellationShaderUtils::getPatchVerticesForPrimitiveMode(_tessellation_primitive_mode primitive_mode)
826 {
827 	glw::GLint result = 0;
828 
829 	switch (primitive_mode)
830 	{
831 	case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
832 		result = 4;
833 		break;
834 	case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
835 		result = 4;
836 		break;
837 	case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
838 		result = 3;
839 		break;
840 
841 	default:
842 	{
843 		TCU_FAIL("Unrecognized primitive mode");
844 	}
845 	} /* switch (primitive_mode) */
846 
847 	return result;
848 }
849 
850 /** Retrieves tessellation level used by the tessellator, given
851  *  vertex spacing setting.
852  *
853  *  @param vertex_spacing              Vertex spacing used for tessellation
854  *                                     evaluation stage;
855  *  @param level                       Tessellation level as defined in TC
856  *                                     stage OR as configured with
857  *                                     GL_PATCH_DEFAULT_*_LEVEL pnames.
858  *  @param gl_max_tess_gen_level_value GL_MAX_TESS_GEN_LEVEL_EXT pname value,
859  *                                     as reported by the implementation.
860  *  @param out_clamped                 Deref will be used to store clamped (but
861  *                                     not rounded) representation. Can be NULL.
862  *  @param out_clamped_and_rounded     Deref will be used to store clamped and
863  *                                     rounded representation. Can be NULL.
864  **/
getTessellationLevelAfterVertexSpacing(_tessellation_shader_vertex_spacing vertex_spacing,float level,glw::GLint gl_max_tess_gen_level_value,float * out_clamped,float * out_clamped_and_rounded)865 void TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(_tessellation_shader_vertex_spacing vertex_spacing,
866 																	 float								 level,
867 																	 glw::GLint gl_max_tess_gen_level_value,
868 																	 float* out_clamped, float* out_clamped_and_rounded)
869 {
870 	/* Behavior is as per EXT_tessellation_shader spec */
871 	switch (vertex_spacing)
872 	{
873 	case TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT:
874 	case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
875 	{
876 		if (level < 1.0f)
877 		{
878 			level = 1.0f;
879 		}
880 		else if (level > (float)gl_max_tess_gen_level_value)
881 		{
882 			level = (float)gl_max_tess_gen_level_value;
883 		}
884 
885 		if (out_clamped != DE_NULL)
886 		{
887 			*out_clamped = level;
888 		}
889 
890 		/* Round *up* to nearest integer */
891 		level = (float)((int)(deFloatCeil(level) + 0.5f));
892 
893 		if (out_clamped_and_rounded != DE_NULL)
894 		{
895 			*out_clamped_and_rounded = level;
896 		}
897 
898 		break;
899 	}
900 
901 	case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN:
902 	{
903 		if (level < 2.0f)
904 		{
905 			level = 2.0f;
906 		}
907 		else if (level > (float)gl_max_tess_gen_level_value)
908 		{
909 			level = (float)gl_max_tess_gen_level_value;
910 		}
911 
912 		if (out_clamped != DE_NULL)
913 		{
914 			*out_clamped = level;
915 		}
916 
917 		/* Round *up* to nearest *even* integer */
918 		int level_temp = (int)(deFloatCeil(level) + 0.5f);
919 
920 		if ((level_temp % 2) != 0)
921 		{
922 			level_temp++;
923 		}
924 
925 		if (out_clamped_and_rounded != DE_NULL)
926 		{
927 			*out_clamped_and_rounded = (float)level_temp;
928 		}
929 
930 		break;
931 	}
932 
933 	case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
934 	{
935 		if (level < 1.0f)
936 		{
937 			level = 1.0f;
938 		}
939 		else if (level > (float)(gl_max_tess_gen_level_value - 1))
940 		{
941 			level = (float)(gl_max_tess_gen_level_value - 1);
942 		}
943 
944 		if (out_clamped != DE_NULL)
945 		{
946 			*out_clamped = level;
947 		}
948 
949 		/* Round to *up* nearest *odd* integer */
950 		int level_temp = (int)(deFloatCeil(level) + 0.5f);
951 
952 		if ((level_temp % 2) != 1)
953 		{
954 			level_temp++;
955 		}
956 
957 		if (out_clamped_and_rounded != DE_NULL)
958 		{
959 			*out_clamped_and_rounded = (float)level_temp;
960 		}
961 
962 		break;
963 	}
964 
965 	default:
966 	{
967 		TCU_FAIL("Unrecognized vertex spacing mode");
968 	}
969 	} /* switch(vertex_spacing) */
970 }
971 
972 /** Returns a vector of _tessellation_levels instances with different level values.
973  *
974  *  @param primitive_mode              Primitive mode to consider.
975  *  @param gl_max_tess_gen_level_value Implementation-specific GL_MAX_TESS_GEN_LEVEL_EXT value.
976  *  @param filter                      Condition which all generated tuples should meet in
977  *                                     order to land in the result vector.
978  *
979  *  @return _tessellation_levels_set instance storing described values.
980  **/
getTessellationLevelSetForPrimitiveMode(_tessellation_primitive_mode primitive_mode,glw::GLint gl_max_tess_gen_level_value,_tessellation_level_set_filter filter)981 _tessellation_levels_set TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
982 	_tessellation_primitive_mode primitive_mode, glw::GLint gl_max_tess_gen_level_value,
983 	_tessellation_level_set_filter filter)
984 {
985 	/* As a starter value, use a tessellation level that is different for each
986 	 * primitive modes, just to make sure the implementation can correctly
987 	 * handle various tessellation level values */
988 	glw::GLint n_min_patch_vertices = getPatchVerticesForPrimitiveMode(primitive_mode);
989 
990 	glw::GLint n_half_max_patch_vertices_mul_min = gl_max_tess_gen_level_value / 2;
991 	glw::GLint n_max_patch_vertices_mul_min		 = gl_max_tess_gen_level_value;
992 
993 	if ((n_half_max_patch_vertices_mul_min % n_min_patch_vertices) != 0)
994 	{
995 		/* Round to nearest mul-of-min integer */
996 		n_half_max_patch_vertices_mul_min +=
997 			(n_min_patch_vertices - (gl_max_tess_gen_level_value / 2) % n_min_patch_vertices);
998 	}
999 
1000 	if ((n_max_patch_vertices_mul_min % n_min_patch_vertices) != 0)
1001 	{
1002 		/* Round to previous nearest mul-of-min integer */
1003 		n_max_patch_vertices_mul_min -= (gl_max_tess_gen_level_value % n_min_patch_vertices);
1004 	}
1005 
1006 	/* Prepare the result vector items */
1007 	_tessellation_levels_set result;
1008 
1009 	if ((filter & TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE) != 0)
1010 	{
1011 		/* Prepare the result vector items */
1012 		_tessellation_levels item_1;
1013 		_tessellation_levels item_2;
1014 		_tessellation_levels item_3;
1015 
1016 		item_1.inner[0] = float(n_min_patch_vertices);
1017 		item_1.inner[1] = float(n_min_patch_vertices + 1);
1018 		item_1.outer[0] = float(n_min_patch_vertices + 3);
1019 		item_1.outer[1] = float(n_min_patch_vertices + 2);
1020 		item_1.outer[2] = float(n_min_patch_vertices + 1);
1021 		item_1.outer[3] = float(n_min_patch_vertices);
1022 
1023 		item_2.inner[0] = float(n_half_max_patch_vertices_mul_min);
1024 		item_2.inner[1] = float(n_half_max_patch_vertices_mul_min - 1);
1025 		item_2.outer[0] = float(n_half_max_patch_vertices_mul_min - 3);
1026 		item_2.outer[1] = float(n_half_max_patch_vertices_mul_min - 2);
1027 		item_2.outer[2] = float(n_half_max_patch_vertices_mul_min - 1);
1028 		item_2.outer[3] = float(n_half_max_patch_vertices_mul_min);
1029 
1030 		item_3.inner[0] = float(n_max_patch_vertices_mul_min - 1);
1031 		item_3.inner[1] = float(n_max_patch_vertices_mul_min - 2);
1032 		item_3.outer[0] = float(n_max_patch_vertices_mul_min - 3);
1033 		item_3.outer[1] = float(n_max_patch_vertices_mul_min - 4);
1034 		item_3.outer[2] = float(n_max_patch_vertices_mul_min - 5);
1035 		item_3.outer[3] = float(n_max_patch_vertices_mul_min - 6);
1036 
1037 		/* Push the items onto result vector. */
1038 		result.push_back(item_1);
1039 		result.push_back(item_2);
1040 		result.push_back(item_3);
1041 	}
1042 	else
1043 	{
1044 		DE_ASSERT((filter & TESSELLATION_LEVEL_SET_FILTER_ALL_COMBINATIONS) != 0 ||
1045 				  (filter & TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES) != 0);
1046 
1047 		const glw::GLint   base_values[] = { -1, 1, n_half_max_patch_vertices_mul_min, n_max_patch_vertices_mul_min };
1048 		const unsigned int n_base_values = DE_LENGTH_OF_ARRAY(base_values);
1049 
1050 		const unsigned int n_relevant_inner_tess_levels =
1051 			(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) ?
1052 				0 :
1053 				(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 2 : 1;
1054 
1055 		const unsigned int n_relevant_outer_tess_levels =
1056 			(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) ?
1057 				2 :
1058 				(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 4 : 3;
1059 
1060 		for (unsigned int n_inner0_base_value = 0;
1061 			 n_inner0_base_value < ((n_relevant_inner_tess_levels > 0) ? n_base_values : 1); ++n_inner0_base_value)
1062 		{
1063 			const glw::GLint inner0_value = base_values[n_inner0_base_value];
1064 
1065 			for (unsigned int n_inner1_base_value = 0;
1066 				 n_inner1_base_value < ((n_relevant_inner_tess_levels > 1) ? n_base_values : 1); ++n_inner1_base_value)
1067 			{
1068 				const glw::GLint inner1_value = base_values[n_inner1_base_value];
1069 
1070 				for (unsigned int n_outer0_base_value = 0;
1071 					 n_outer0_base_value < ((n_relevant_outer_tess_levels > 0) ? n_base_values : 1);
1072 					 ++n_outer0_base_value)
1073 				{
1074 					const glw::GLint outer0_value = base_values[n_outer0_base_value];
1075 
1076 					for (unsigned int n_outer1_base_value = 0;
1077 						 n_outer1_base_value < ((n_relevant_outer_tess_levels > 1) ? n_base_values : 1);
1078 						 ++n_outer1_base_value)
1079 					{
1080 						const glw::GLint outer1_value = base_values[n_outer1_base_value];
1081 
1082 						for (unsigned int n_outer2_base_value = 0;
1083 							 n_outer2_base_value < ((n_relevant_outer_tess_levels > 2) ? n_base_values : 1);
1084 							 ++n_outer2_base_value)
1085 						{
1086 							const glw::GLint outer2_value = base_values[n_outer2_base_value];
1087 
1088 							for (unsigned int n_outer3_base_value = 0;
1089 								 n_outer3_base_value < ((n_relevant_outer_tess_levels > 3) ? n_base_values : 1);
1090 								 ++n_outer3_base_value)
1091 							{
1092 								const glw::GLint outer3_value = base_values[n_outer3_base_value];
1093 
1094 								/* Skip combinations where any of the relevant outer tessellation level values
1095 								 * is negative. These would cause no tessellation coordinates to be generated
1096 								 * by the tessellator.
1097 								 */
1098 								if ((n_relevant_outer_tess_levels > 0 && outer0_value < 0) ||
1099 									(n_relevant_outer_tess_levels > 1 && outer1_value < 0) ||
1100 									(n_relevant_outer_tess_levels > 2 && outer2_value < 0) ||
1101 									(n_relevant_outer_tess_levels > 3 && outer3_value < 0))
1102 								{
1103 									continue;
1104 								}
1105 
1106 								/* If TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES
1107 								 * filter was requested, make sure the values used separately for inner and outer
1108 								 * tess levels are actually different. */
1109 								if ((filter &
1110 									 TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES) != 0)
1111 								{
1112 									DE_ASSERT(n_base_values >= 4 /* outer tess levels supported */);
1113 
1114 									if ((n_relevant_inner_tess_levels > 1 && inner0_value == inner1_value) ||
1115 										(n_relevant_outer_tess_levels > 1 && outer0_value == outer1_value) ||
1116 										(n_relevant_outer_tess_levels > 2 && outer1_value == outer2_value) ||
1117 										(n_relevant_outer_tess_levels > 3 && outer2_value == outer3_value))
1118 									{
1119 										continue;
1120 									}
1121 								} /* if ((filter & TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES) != 0) */
1122 
1123 								/* If TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE, make sure
1124 								 * no inner/outer tessellation level we're about to use is negative. */
1125 								if ((filter & TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE) != 0)
1126 								{
1127 									if ((n_relevant_inner_tess_levels > 0 && inner0_value < 0) ||
1128 										(n_relevant_inner_tess_levels > 1 && inner1_value < 0) ||
1129 										(n_relevant_outer_tess_levels > 0 && outer0_value < 0) ||
1130 										(n_relevant_outer_tess_levels > 1 && outer1_value < 0) ||
1131 										(n_relevant_outer_tess_levels > 2 && outer2_value < 0) ||
1132 										(n_relevant_outer_tess_levels > 3 && outer3_value < 0))
1133 									{
1134 										continue;
1135 									}
1136 								}
1137 
1138 								/* Construct the tess level combination */
1139 								_tessellation_levels item;
1140 
1141 								item.inner[0] = (glw::GLfloat)inner0_value;
1142 								item.inner[1] = (glw::GLfloat)inner1_value;
1143 								item.outer[0] = (glw::GLfloat)outer0_value;
1144 								item.outer[1] = (glw::GLfloat)outer1_value;
1145 								item.outer[2] = (glw::GLfloat)outer2_value;
1146 								item.outer[3] = (glw::GLfloat)outer3_value;
1147 
1148 								/* Store it */
1149 								result.push_back(item);
1150 							} /* for (all outer[3] base values) */
1151 						}	 /* for (all outer[2] base values) */
1152 					}		  /* for (all outer[1] base values) */
1153 				}			  /* for (all outer[0] base values) */
1154 			}				  /* for (all inner[1] base values) */
1155 		}					  /* for (all inner[0] base values) */
1156 	}
1157 
1158 	return result;
1159 }
1160 
1161 /** Retrieves transform feedback mode that should be used for glBeginTransformFeedback()
1162  *  call, if TF is to be active while a tessellated draw call is made.
1163  *
1164  *  This function throws TestError exception if @param primitive_mode is invalid.
1165  *
1166  *  @param primitive_mode Primitive mode to consider
1167  *  @param is_point_mode  true if tessellation is run in point_mode mode, false otherwise.
1168  *
1169  *  @return Corresponding ES enum.
1170  **/
getTFModeForPrimitiveMode(_tessellation_primitive_mode primitive_mode,bool is_point_mode)1171 glw::GLenum TessellationShaderUtils::getTFModeForPrimitiveMode(_tessellation_primitive_mode primitive_mode,
1172 															   bool							is_point_mode)
1173 {
1174 	glw::GLenum result = GL_NONE;
1175 
1176 	if (is_point_mode)
1177 	{
1178 		result = GL_POINTS;
1179 	}
1180 	else
1181 	{
1182 		switch (primitive_mode)
1183 		{
1184 		case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
1185 		{
1186 			result = GL_LINES;
1187 
1188 			break;
1189 		}
1190 
1191 		case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1192 		{
1193 			result = GL_TRIANGLES;
1194 
1195 			break;
1196 		}
1197 
1198 		case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1199 		{
1200 			result = GL_TRIANGLES;
1201 
1202 			break;
1203 		}
1204 
1205 		default:
1206 		{
1207 			TCU_FAIL("Unrecognized primitive mode");
1208 		}
1209 		} /* switch (primitive_mode) */
1210 	}
1211 
1212 	return result;
1213 }
1214 
1215 /** Initializes a counter program.
1216  *
1217  *  This function throws a TestError exception, should an error occur.
1218  *
1219  *  @param inner_tess_level      Two FP values to be used for inner tessellation levels. Must not be NULL.
1220  *  @param outer_tess_level      Four FP values to be used for outer tessellation levels. Must not be NULL.
1221  *  @param n_patch_vertices      Amount of TC stage output patch vertices.
1222  *  @param vertex_spacing        Vertex spacing mode to be used for tessellation.
1223  *  @param primitive_mode        Primitive mode to be used for tessellation.
1224  *  @param is_point_mode_enabled true if the point mode should be enabled for the program, false otherwise.
1225  *  @param result_descriptor     Objects created during initialization will be stored in the referenced descriptor.
1226  *
1227  **/
initTessellationVertexCounterProgram(const float * inner_tess_level,const float * outer_tess_level,glw::GLint n_patch_vertices,_tessellation_shader_vertex_spacing vertex_spacing,_tessellation_primitive_mode primitive_mode,bool is_point_mode_enabled,_tessellation_vertex_counter_program & result_descriptor)1228 void TessellationShaderUtils::initTessellationVertexCounterProgram(
1229 	const float* inner_tess_level, const float* outer_tess_level, glw::GLint n_patch_vertices,
1230 	_tessellation_shader_vertex_spacing vertex_spacing, _tessellation_primitive_mode primitive_mode,
1231 	bool is_point_mode_enabled, _tessellation_vertex_counter_program& result_descriptor)
1232 {
1233 	glw::GLint po_id = 0;
1234 	glw::GLint tc_id = 0;
1235 	glw::GLint te_id = 0;
1236 
1237 	/* Generate the shader objects */
1238 	tc_id = m_gl.createShader(m_parent_test->m_glExtTokens.TESS_CONTROL_SHADER);
1239 	te_id = m_gl.createShader(m_parent_test->m_glExtTokens.TESS_EVALUATION_SHADER);
1240 
1241 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "Could not create TC/TE shader objects");
1242 
1243 	/* Generate the program object */
1244 	po_id = m_gl.createProgram();
1245 
1246 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "Could not create a program object");
1247 
1248 	/* Initialize the shaders.
1249 	 *
1250 	 * Note: it's fine to use CCW ordering here, since it does not affect the amount
1251 	 *       of primitives generated by the tessellator.
1252 	 **/
1253 	std::string tc_code		= getGenericTCCode(n_patch_vertices, false);
1254 	const char* tc_code_ptr = tc_code.c_str();
1255 	std::string te_code		= getGenericTECode(vertex_spacing, primitive_mode, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1256 										   is_point_mode_enabled);
1257 	const char* te_code_ptr = te_code.c_str();
1258 
1259 	/* Set up XFB */
1260 	const char* varyings[] = { "result_uvw" };
1261 
1262 	m_gl.transformFeedbackVaryings(po_id, 1, /* count */
1263 								   varyings, GL_INTERLEAVED_ATTRIBS);
1264 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTransformFeedbackVaryings() call failed");
1265 
1266 	/* Link the program and check that the linking has succeeded */
1267 	bool build_success = m_parent_test->buildProgram(po_id, m_fs_id, 0 /* precompiled */, NULL, tc_id, 1, &tc_code_ptr,
1268 													 te_id, 1, &te_code_ptr, m_vs_id, 0 /* precompiled */, NULL);
1269 
1270 	if (!build_success)
1271 	{
1272 		TCU_FAIL("Compilation and/or linking failed");
1273 	}
1274 
1275 	/* Set up the inner/outer tess level uniforms */
1276 	glw::GLint inner_tess_level_uniform_location = -1;
1277 	glw::GLint outer_tess_level_uniform_location = -1;
1278 
1279 	inner_tess_level_uniform_location = m_gl.getUniformLocation(po_id, "inner_tess_level");
1280 	outer_tess_level_uniform_location = m_gl.getUniformLocation(po_id, "outer_tess_level");
1281 
1282 	DE_ASSERT(inner_tess_level_uniform_location != -1);
1283 	DE_ASSERT(outer_tess_level_uniform_location != -1);
1284 
1285 	m_gl.useProgram(po_id);
1286 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed");
1287 
1288 	m_gl.uniform2fv(inner_tess_level_uniform_location, 1, /* count */
1289 					inner_tess_level);
1290 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUniform2fv() call failed");
1291 
1292 	m_gl.uniform4fv(outer_tess_level_uniform_location, 1, /* count */
1293 					outer_tess_level);
1294 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUniform4fv() call failed");
1295 
1296 	/* Initialize the test descriptor */
1297 	memcpy(result_descriptor.inner_tess_level, inner_tess_level, sizeof(result_descriptor.inner_tess_level));
1298 	memcpy(result_descriptor.outer_tess_level, outer_tess_level, sizeof(result_descriptor.outer_tess_level));
1299 
1300 	result_descriptor.is_point_mode_enabled				= is_point_mode_enabled;
1301 	result_descriptor.n_patch_vertices					= n_patch_vertices;
1302 	result_descriptor.po_id								= po_id;
1303 	result_descriptor.primitive_mode					= primitive_mode;
1304 	result_descriptor.tc_id								= tc_id;
1305 	result_descriptor.te_id								= te_id;
1306 	result_descriptor.tess_level_inner_uniform_location = inner_tess_level_uniform_location;
1307 	result_descriptor.tess_level_outer_uniform_location = outer_tess_level_uniform_location;
1308 	result_descriptor.vertex_spacing					= vertex_spacing;
1309 
1310 	captureTessellationData(result_descriptor);
1311 }
1312 
1313 /** Tells whether user-provided vertex (expressed in tessellation space) generated
1314  *  during triangle tessellation is an outer edge vertex.
1315  *
1316  *  @param primitive_mode          Primitive mode, for which the tessellated vertex
1317  *                                 data was generated.
1318  *  @param tessellated_vertex_data Vertex data to check. Must define 3 floats.
1319  *
1320  *  @return true if the vertex is a part of an outer edge, false otherwise.
1321  **/
isOuterEdgeVertex(_tessellation_primitive_mode primitive_mode,const float * tessellated_vertex_data)1322 bool TessellationShaderUtils::isOuterEdgeVertex(_tessellation_primitive_mode primitive_mode,
1323 												const float*				 tessellated_vertex_data)
1324 {
1325 	const float epsilon = 1e-5f;
1326 	bool		result  = false;
1327 
1328 	switch (primitive_mode)
1329 	{
1330 	case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1331 	{
1332 		if (de::abs(tessellated_vertex_data[0]) < epsilon || de::abs(tessellated_vertex_data[0] - 1.0f) < epsilon ||
1333 			de::abs(tessellated_vertex_data[1]) < epsilon || de::abs(tessellated_vertex_data[1] - 1.0f) < epsilon ||
1334 			de::abs(tessellated_vertex_data[2]) < epsilon || de::abs(tessellated_vertex_data[2] - 1.0f) < epsilon)
1335 		{
1336 			/* Make sure vertex is inside the triangle */
1337 			if (0.0f <= tessellated_vertex_data[0] && tessellated_vertex_data[0] <= 1.0f &&
1338 				0.0f <= tessellated_vertex_data[1] && tessellated_vertex_data[1] <= 1.0f &&
1339 				0.0f <= tessellated_vertex_data[2] && tessellated_vertex_data[2] <= 1.0f)
1340 			{
1341 				result = true;
1342 			}
1343 		}
1344 
1345 		break;
1346 	} /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1347 
1348 	case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1349 	{
1350 		if (de::abs(tessellated_vertex_data[0]) < epsilon || de::abs(tessellated_vertex_data[0] - 1.0f) < epsilon ||
1351 			de::abs(tessellated_vertex_data[1]) < epsilon || de::abs(tessellated_vertex_data[1] - 1.0f) < epsilon)
1352 		{
1353 			result = true;
1354 		}
1355 
1356 		break;
1357 	} /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1358 
1359 	default:
1360 	{
1361 		DE_FATAL("Unrecognized primitive mode");
1362 	}
1363 	}
1364 
1365 	return result;
1366 }
1367 
1368 /** Returns true if two triangles are the same. Takes potentially different
1369  *  vertex ordering into consideration.
1370  *
1371  *  @param triangle_vertex_data Reference 9 FP values defining a triangle
1372  *                              that the triangle defined by @param vertex_data
1373  *                              will be compared against.
1374  *  @param vertex_data          9 FP values defining a triangle, perhaps in
1375  *                              a different order, that @param triangle_vertex_data
1376  *                              will be checked against.
1377  *
1378  *  @return true if the triangles are the same; false otherwise.
1379  *
1380  **/
isTriangleDefined(const float * triangle_vertex_data,const float * vertex_data)1381 bool TessellationShaderUtils::isTriangleDefined(const float* triangle_vertex_data, const float* vertex_data)
1382 {
1383 	const float epsilon							= 1e-5f;
1384 	bool		has_triangle_vertex1_been_found = false;
1385 	bool		has_triangle_vertex2_been_found = false;
1386 	bool		has_triangle_vertex3_been_found = false;
1387 	bool		result							= false;
1388 
1389 	if ((de::abs(triangle_vertex_data[0] - vertex_data[0]) < epsilon &&
1390 		 de::abs(triangle_vertex_data[1] - vertex_data[1]) < epsilon &&
1391 		 de::abs(triangle_vertex_data[2] - vertex_data[2]) < epsilon) ||
1392 		(de::abs(triangle_vertex_data[3] - vertex_data[0]) < epsilon &&
1393 		 de::abs(triangle_vertex_data[4] - vertex_data[1]) < epsilon &&
1394 		 de::abs(triangle_vertex_data[5] - vertex_data[2]) < epsilon) ||
1395 		(de::abs(triangle_vertex_data[6] - vertex_data[0]) < epsilon &&
1396 		 de::abs(triangle_vertex_data[7] - vertex_data[1]) < epsilon &&
1397 		 de::abs(triangle_vertex_data[8] - vertex_data[2]) < epsilon))
1398 	{
1399 		has_triangle_vertex1_been_found = true;
1400 	}
1401 
1402 	if ((de::abs(triangle_vertex_data[0] - vertex_data[3]) < epsilon &&
1403 		 de::abs(triangle_vertex_data[1] - vertex_data[4]) < epsilon &&
1404 		 de::abs(triangle_vertex_data[2] - vertex_data[5]) < epsilon) ||
1405 		(de::abs(triangle_vertex_data[3] - vertex_data[3]) < epsilon &&
1406 		 de::abs(triangle_vertex_data[4] - vertex_data[4]) < epsilon &&
1407 		 de::abs(triangle_vertex_data[5] - vertex_data[5]) < epsilon) ||
1408 		(de::abs(triangle_vertex_data[6] - vertex_data[3]) < epsilon &&
1409 		 de::abs(triangle_vertex_data[7] - vertex_data[4]) < epsilon &&
1410 		 de::abs(triangle_vertex_data[8] - vertex_data[5]) < epsilon))
1411 	{
1412 		has_triangle_vertex2_been_found = true;
1413 	}
1414 
1415 	if ((de::abs(triangle_vertex_data[0] - vertex_data[6]) < epsilon &&
1416 		 de::abs(triangle_vertex_data[1] - vertex_data[7]) < epsilon &&
1417 		 de::abs(triangle_vertex_data[2] - vertex_data[8]) < epsilon) ||
1418 		(de::abs(triangle_vertex_data[3] - vertex_data[6]) < epsilon &&
1419 		 de::abs(triangle_vertex_data[4] - vertex_data[7]) < epsilon &&
1420 		 de::abs(triangle_vertex_data[5] - vertex_data[8]) < epsilon) ||
1421 		(de::abs(triangle_vertex_data[6] - vertex_data[6]) < epsilon &&
1422 		 de::abs(triangle_vertex_data[7] - vertex_data[7]) < epsilon &&
1423 		 de::abs(triangle_vertex_data[8] - vertex_data[8]) < epsilon))
1424 	{
1425 		has_triangle_vertex3_been_found = true;
1426 	}
1427 
1428 	if (has_triangle_vertex1_been_found && has_triangle_vertex2_been_found && has_triangle_vertex3_been_found)
1429 	{
1430 		result = true;
1431 	}
1432 
1433 	return result;
1434 }
1435 
1436 } // namespace glcts
1437