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, ¤t_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, ¤t_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