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