Home | History | Annotate | Download | only in tessellation_shader
      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  **/
     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 */
     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  **/
     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  **/
    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  **/
    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  **/
    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  **/
    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  */
    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  */
    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  **/
    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  **/
    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  **/
    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  **/
    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  **/
    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  **/
    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  **/
    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  **/
    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  **/
    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  **/
   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  **/
   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  **/
   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_ASSERT("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  **/
   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