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 "esextcTessellationShaderInvariance.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 /* Defines a single vertex in tessellation space */ 35 typedef struct _vertex 36 { 37 float u; 38 float v; 39 float w; 40 41 _vertex() 42 { 43 u = 0.0f; 44 v = 0.0f; 45 w = 0.0f; 46 } 47 } _vertex; 48 49 /** Constructor 50 * 51 * @param context Test context 52 **/ 53 TessellationShaderInvarianceTests::TessellationShaderInvarianceTests(glcts::Context& context, 54 const ExtParameters& extParams) 55 : TestCaseGroupBase(context, extParams, "tessellation_invariance", 56 "Verifies the implementation conforms to invariance rules.") 57 { 58 /* No implementation needed */ 59 } 60 61 /** 62 * Initializes test groups for geometry shader tests 63 **/ 64 void TessellationShaderInvarianceTests::init(void) 65 { 66 addChild(new glcts::TessellationShaderInvarianceRule1Test(m_context, m_extParams)); 67 addChild(new glcts::TessellationShaderInvarianceRule2Test(m_context, m_extParams)); 68 addChild(new glcts::TessellationShaderInvarianceRule3Test(m_context, m_extParams)); 69 addChild(new glcts::TessellationShaderInvarianceRule4Test(m_context, m_extParams)); 70 addChild(new glcts::TessellationShaderInvarianceRule5Test(m_context, m_extParams)); 71 addChild(new glcts::TessellationShaderInvarianceRule6Test(m_context, m_extParams)); 72 addChild(new glcts::TessellationShaderInvarianceRule7Test(m_context, m_extParams)); 73 } 74 75 /** Constructor 76 * 77 * @param context Test context 78 * @param name Test name 79 * @param description Test description 80 **/ 81 TessellationShaderInvarianceBaseTest::TessellationShaderInvarianceBaseTest(Context& context, 82 const ExtParameters& extParams, 83 const char* name, const char* description) 84 : TestCaseBase(context, extParams, name, description) 85 , m_utils_ptr(DE_NULL) 86 , m_bo_id(0) 87 , m_qo_tfpw_id(0) 88 , m_vao_id(0) 89 { 90 /* Left blank on purpose */ 91 } 92 93 /** Deinitializes ES objects created for the test. */ 94 void TessellationShaderInvarianceBaseTest::deinit() 95 { 96 /* Call base class' deinit() */ 97 TestCaseBase::deinit(); 98 99 if (!m_is_tessellation_shader_supported) 100 { 101 return; 102 } 103 104 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 105 106 /* Revert buffer object bindings */ 107 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */); 108 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */); 109 110 /* Disable GL_RASTERIZER_DISCARD mode */ 111 gl.disable(GL_RASTERIZER_DISCARD); 112 113 /* Reset GL_PATCH_VERTICES_EXT to default value */ 114 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3); 115 116 /* Unbind vertex array object */ 117 gl.bindVertexArray(0); 118 119 /* Deinitialize all ES objects that were created for test purposes */ 120 if (m_bo_id != 0) 121 { 122 gl.deleteBuffers(1, &m_bo_id); 123 124 m_bo_id = 0; 125 } 126 127 for (_programs_iterator it = m_programs.begin(); it != m_programs.end(); ++it) 128 { 129 _test_program& program = *it; 130 131 if (program.po_id != 0) 132 { 133 gl.deleteProgram(program.po_id); 134 } 135 } 136 m_programs.clear(); 137 138 if (m_qo_tfpw_id != 0) 139 { 140 gl.deleteQueries(1, &m_qo_tfpw_id); 141 142 m_qo_tfpw_id = 0; 143 } 144 145 if (m_vao_id != 0) 146 { 147 gl.deleteVertexArrays(1, &m_vao_id); 148 149 m_vao_id = 0; 150 } 151 152 /* Deinitialize TS utils instance */ 153 if (m_utils_ptr != NULL) 154 { 155 delete m_utils_ptr; 156 157 m_utils_ptr = NULL; 158 } 159 } 160 161 /** Executes a single-counted GL_PATCHES_EXT draw call. 162 * 163 * Throws TestError exception if an error occurs. 164 * 165 * @param n_iteration Not used. 166 * 167 **/ 168 void TessellationShaderInvarianceBaseTest::executeDrawCall(unsigned int n_iteration) 169 { 170 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 171 172 DE_UNREF(n_iteration); 173 174 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, getDrawCallCountArgument()); 175 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed"); 176 } 177 178 /** Returns a value that should be used for the draw call's "count" argument. 179 * 180 * @param Always 1 181 **/ 182 unsigned int TessellationShaderInvarianceBaseTest::getDrawCallCountArgument() 183 { 184 return 1; 185 } 186 187 /** Returns source code for fragment shader stage which does 188 * not do anything. 189 * 190 * @param n_iteration Not used. 191 * 192 * @return Requested string. 193 **/ 194 std::string TessellationShaderInvarianceBaseTest::getFSCode(unsigned int n_iteration) 195 { 196 DE_UNREF(n_iteration); 197 198 std::string result = "${VERSION}\n" 199 "\n" 200 "void main()\n" 201 "{\n" 202 "}\n"; 203 204 return result; 205 } 206 207 /** Retrieves name of a vec2 uniform that stores inner tesselaton level information, 208 * later assigned to gl_TessLevelInner in tessellation evaluation shader. 209 * 210 * @return Requested name. 211 **/ 212 const char* TessellationShaderInvarianceBaseTest::getInnerTessLevelUniformName() 213 { 214 static const char* result = "inner_tess_level"; 215 216 return result; 217 } 218 219 /** Retrieves name of a vec4 uniform that stores outer tesselation level information, 220 * later assigned to gl_TessLevelOuter in tessellation evaluation shader. 221 * 222 * @return Requested name. 223 **/ 224 const char* TessellationShaderInvarianceBaseTest::getOuterTessLevelUniformName() 225 { 226 static const char* result = "outer_tess_level"; 227 228 return result; 229 } 230 231 /** Returns generic tessellation control shader code, which sends 4 output patch 232 * to tessellation evaluation shader stage and uses the very first input patch 233 * vertex only. 234 * 235 * @return Tessellation control source code. 236 */ 237 std::string TessellationShaderInvarianceBaseTest::getTCCode(unsigned int n_iteration) 238 { 239 DE_UNREF(n_iteration); 240 241 /* In order to support all three primitive types, our generic tessellation 242 * control shader will pass 4 vertices to TE stage */ 243 return TessellationShaderUtils::getGenericTCCode(4, /* n_patch_vertices */ 244 false); 245 } 246 247 /** Retrieves XFB properties for the test pass. 248 * 249 * @param n_iteration Not used. 250 * @param out_n_names Deref will be used to store amount of strings @param *out_n_names 251 * offers. 252 * @param out_names Deref will be used to store pointer to an array of strings holding 253 * names of varyings that should be captured via transform feedback. 254 * Must not be NULL. 255 * 256 **/ 257 void TessellationShaderInvarianceBaseTest::getXFBProperties(unsigned int n_iteration, unsigned int* out_n_names, 258 const char*** out_names) 259 { 260 static const char* names[] = { "result_uvw" }; 261 262 DE_UNREF(n_iteration); 263 264 *out_n_names = 1; 265 *out_names = names; 266 } 267 268 /** Returns vertex shader source code. The shader sets gl_Position to 269 * vec4(1, 2, 3, 0). 270 * 271 * @return Vertex shader source code. 272 **/ 273 std::string TessellationShaderInvarianceBaseTest::getVSCode(unsigned int n_iteration) 274 { 275 DE_UNREF(n_iteration); 276 277 std::string result = "${VERSION}\n" 278 "\n" 279 "void main()\n" 280 "{\n" 281 " gl_Position = vec4(1.0, 2.0, 3.0, 0.0);\n" 282 "}\n"; 283 284 return result; 285 } 286 287 /** Initializes ES objects required to execute the test. 288 * 289 * Throws TestError exception if an error occurs. 290 * 291 **/ 292 void TessellationShaderInvarianceBaseTest::initTest() 293 { 294 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 295 glw::GLuint shared_fs_id = 0; 296 glw::GLuint shared_tc_id = 0; 297 glw::GLuint shared_te_id = 0; 298 glw::GLuint shared_vs_id = 0; 299 300 gl.genVertexArrays(1, &m_vao_id); 301 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); 302 303 gl.bindVertexArray(m_vao_id); 304 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); 305 306 /* Initialize GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object */ 307 gl.genQueries(1, &m_qo_tfpw_id); 308 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries() call failed"); 309 310 /* Initialize tessellation shader utils */ 311 m_utils_ptr = new TessellationShaderUtils(gl, this); 312 313 /* Initialize a buffer object we will use to store XFB data. 314 * Note: we intentionally skip a glBufferData() call here, 315 * the actual buffer storage size is iteration-specific. 316 **/ 317 gl.genBuffers(1, &m_bo_id); 318 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed"); 319 320 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id); 321 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed"); 322 323 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */ 324 m_bo_id); 325 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed"); 326 327 /* Iterate through all iterations */ 328 const unsigned int n_iterations = getAmountOfIterations(); 329 m_programs.reserve(n_iterations); 330 331 const glw::GLenum SHADER_TYPE_FRAGMENT = GL_FRAGMENT_SHADER; 332 const glw::GLenum SHADER_TYPE_TESSELLATION_CONTROL = m_glExtTokens.TESS_CONTROL_SHADER; 333 const glw::GLenum SHADER_TYPE_TESSELLATION_EVALUATION = m_glExtTokens.TESS_EVALUATION_SHADER; 334 const glw::GLenum SHADER_TYPE_VERTEX = GL_VERTEX_SHADER; 335 336 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration) 337 { 338 _test_program program; 339 340 /* Create an iteration-specific program object */ 341 program.po_id = gl.createProgram(); 342 343 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); 344 345 /* Query the implementation on which shader types should be compiled on 346 * a per-iteration basis, and which can be initialized only once */ 347 static const glw::GLenum shader_types[] = { SHADER_TYPE_FRAGMENT, SHADER_TYPE_TESSELLATION_CONTROL, 348 SHADER_TYPE_TESSELLATION_EVALUATION, SHADER_TYPE_VERTEX }; 349 static const unsigned int n_shader_types = sizeof(shader_types) / sizeof(shader_types[0]); 350 351 for (unsigned int n_shader_type = 0; n_shader_type < n_shader_types; ++n_shader_type) 352 { 353 std::string shader_body; 354 const char* shader_body_ptr = DE_NULL; 355 glw::GLuint shader_id = 0; 356 glw::GLenum shader_type = shader_types[n_shader_type]; 357 glw::GLenum shader_type_es = (glw::GLenum)shader_type; 358 359 // Check whether the test should use a separate program objects for each iteration. 360 bool is_shader_iteration_specific = false; 361 if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION) 362 { 363 is_shader_iteration_specific = true; 364 } 365 else if ((shader_type != SHADER_TYPE_FRAGMENT) && (shader_type != SHADER_TYPE_TESSELLATION_CONTROL) && 366 (shader_type != SHADER_TYPE_VERTEX)) 367 { 368 TCU_FAIL("Unrecognized shader type"); 369 } 370 371 /* We need to initialize the shader object if: 372 * 373 * - its body differs between iterations; 374 * - its body is shared by all iterations AND this is the first iteration 375 */ 376 bool has_shader_been_generated = false; 377 378 if ((!is_shader_iteration_specific && n_iteration == 0) || is_shader_iteration_specific) 379 { 380 /* Create the shader object */ 381 has_shader_been_generated = true; 382 shader_id = gl.createShader(shader_type_es); 383 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed"); 384 385 /* Assign shader body to the object */ 386 if (shader_type == SHADER_TYPE_FRAGMENT) 387 { 388 shader_body = getFSCode(n_iteration); 389 } 390 else if (shader_type == SHADER_TYPE_TESSELLATION_CONTROL) 391 { 392 shader_body = getTCCode(n_iteration); 393 } 394 else if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION) 395 { 396 shader_body = getTECode(n_iteration); 397 } 398 else if (shader_type == SHADER_TYPE_VERTEX) 399 { 400 shader_body = getVSCode(n_iteration); 401 } 402 else 403 { 404 TCU_FAIL("Unrecognized shader type"); 405 } 406 407 shader_body_ptr = shader_body.c_str(); 408 409 shaderSourceSpecialized(shader_id, 1, &shader_body_ptr); 410 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed"); 411 412 /* Compile the shader object */ 413 m_utils_ptr->compileShaders(1, /* n_shaders */ 414 &shader_id, true); /* should_succeed */ 415 416 /* If this is a shader object that will be shared by all iterations, cache it 417 * in a dedicated variable */ 418 if (!is_shader_iteration_specific) 419 { 420 if (shader_type == SHADER_TYPE_FRAGMENT) 421 { 422 shared_fs_id = shader_id; 423 } 424 else if (shader_type == SHADER_TYPE_TESSELLATION_CONTROL) 425 { 426 shared_tc_id = shader_id; 427 } 428 else if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION) 429 { 430 shared_te_id = shader_id; 431 } 432 else if (shader_type == SHADER_TYPE_VERTEX) 433 { 434 shared_vs_id = shader_id; 435 } 436 else 437 { 438 TCU_FAIL("Unrecognized shader type"); 439 } 440 } /* if (!is_shader_iteration_specific) */ 441 } /* if (shader object needs to be initialized) */ 442 else 443 { 444 shader_id = (shader_type == SHADER_TYPE_FRAGMENT) ? 445 shared_fs_id : 446 (shader_type == SHADER_TYPE_TESSELLATION_CONTROL) ? 447 shared_tc_id : 448 (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION) ? shared_te_id : shared_vs_id; 449 } 450 451 /* Attach the shader object to iteration-specific program object */ 452 gl.attachShader(program.po_id, shader_id); 453 454 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed."); 455 456 /* Now that the object has been attached, we can flag it for deletion */ 457 if (has_shader_been_generated) 458 { 459 gl.deleteShader(shader_id); 460 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed"); 461 } 462 } /* for (all shader types) */ 463 464 /* Set up transform feed-back */ 465 unsigned int n_xfb_names = 0; 466 const char** xfb_names = NULL; 467 468 getXFBProperties(n_iteration, &n_xfb_names, &xfb_names); 469 470 gl.transformFeedbackVaryings(program.po_id, n_xfb_names, xfb_names, GL_INTERLEAVED_ATTRIBS); 471 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed."); 472 473 /* Try to link the program object */ 474 glw::GLint link_status = GL_FALSE; 475 476 gl.linkProgram(program.po_id); 477 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed"); 478 479 gl.getProgramiv(program.po_id, GL_LINK_STATUS, &link_status); 480 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed"); 481 482 if (link_status != GL_TRUE) 483 { 484 TCU_FAIL("Program linking failed"); 485 } 486 487 /* Retrieve inner/outer tess level uniform locations */ 488 program.inner_tess_level_uniform_location = 489 gl.getUniformLocation(program.po_id, getInnerTessLevelUniformName()); 490 program.outer_tess_level_uniform_location = 491 gl.getUniformLocation(program.po_id, getOuterTessLevelUniformName()); 492 493 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed"); 494 495 /* Store the program object */ 496 m_programs.push_back(program); 497 } /* for (all iterations) */ 498 } 499 500 /** Executes the test. 501 * 502 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. 503 * 504 * Note the function throws exception should an error occur! 505 * 506 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again. 507 **/ 508 tcu::TestNode::IterateResult TessellationShaderInvarianceBaseTest::iterate(void) 509 { 510 /* Do not execute if required extensions are not supported. */ 511 if (!m_is_tessellation_shader_supported) 512 { 513 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); 514 } 515 516 /* Initialize all objects needed to run the test */ 517 initTest(); 518 519 /* Do a general set-up */ 520 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 521 522 gl.enable(GL_RASTERIZER_DISCARD); 523 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed."); 524 525 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1); 526 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname"); 527 528 /* There are two types of verification supported by this base test implementation: 529 * 530 * - iteration-specific (verifyResultDataForIteration() ) 531 * - global (verifyResultData() ) 532 * 533 * It is up to test implementation to decide which of the two (or perhaps both) 534 * entry-points it should overload and use for validating the result data. 535 */ 536 const unsigned int n_iterations = getAmountOfIterations(); 537 char** iteration_data = new char*[n_iterations]; 538 539 /* Execute the test */ 540 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration) 541 { 542 _test_program& program = m_programs[n_iteration]; 543 544 /* Retrieve iteration properties for current iteration */ 545 unsigned int bo_size = 0; 546 float inner_tess_levels[2] = { 0 }; 547 bool is_point_mode = false; 548 float outer_tess_levels[4] = { 0 }; 549 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN; 550 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN; 551 552 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &is_point_mode, &primitive_mode, 553 &vertex_ordering, &bo_size); 554 555 DE_ASSERT(bo_size != 0); 556 557 /* Activate iteration-specific program */ 558 gl.useProgram(program.po_id); 559 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed."); 560 561 /* Set up buffer object storage */ 562 { 563 char* zero_bo_data = new char[bo_size]; 564 565 memset(zero_bo_data, 0, bo_size); 566 567 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, zero_bo_data, GL_STATIC_DRAW); 568 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed"); 569 570 delete[] zero_bo_data; 571 zero_bo_data = NULL; 572 } 573 574 /* Allocate space for iteration-specific data */ 575 iteration_data[n_iteration] = new char[bo_size]; 576 577 /* Configure inner/outer tessellation levels as requested for the iteration */ 578 gl.uniform2fv(program.inner_tess_level_uniform_location, 1, /* count */ 579 inner_tess_levels); 580 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed"); 581 582 gl.uniform4fv(program.outer_tess_level_uniform_location, 1, /* count */ 583 outer_tess_levels); 584 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed"); 585 586 /* Launch the TFPW query */ 587 gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tfpw_id); 588 GLU_EXPECT_NO_ERROR(gl.getError(), 589 "glBeginQuery() for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN target failed."); 590 591 /* Prepare for TF */ 592 glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(primitive_mode, is_point_mode); 593 594 gl.beginTransformFeedback(tf_mode); 595 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed"); 596 { 597 /* Execute the draw call */ 598 executeDrawCall(n_iteration); 599 600 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed"); 601 } 602 gl.endTransformFeedback(); 603 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed"); 604 605 gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); 606 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) call failed"); 607 608 /* Make sure that we had sufficient amount of space in a buffer object we used to 609 * capture XFB data. 610 **/ 611 glw::GLuint n_tf_primitives_written = 0; 612 glw::GLuint used_tf_bo_size = 0; 613 614 gl.getQueryObjectuiv(m_qo_tfpw_id, GL_QUERY_RESULT, &n_tf_primitives_written); 615 GLU_EXPECT_NO_ERROR(gl.getError(), 616 "Could not retrieve GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object result"); 617 618 if (is_point_mode) 619 { 620 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* components */); 621 } 622 else if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) 623 { 624 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 2 /* vertices */ * 625 3 /* components */); 626 } 627 else 628 { 629 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* vertices */ * 630 3 /* components */); 631 } 632 633 if (used_tf_bo_size != bo_size) 634 { 635 m_testCtx.getLog() << tcu::TestLog::Message << "Expected " << bo_size 636 << " to be filled with tessellation data, " 637 "only " 638 << used_tf_bo_size << "was used." << tcu::TestLog::EndMessage; 639 640 TCU_FAIL("Amount of primitives generated during TF does not match amount of primitives that were expected" 641 " to be generated by the tessellator"); 642 } 643 644 /* Map the buffer object we earlier bound to GL_TRANSFORM_FEEDBACK_BUFFER 645 * target into process space. */ 646 const void* xfb_data = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */ 647 bo_size, GL_MAP_READ_BIT); 648 649 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed"); 650 651 memcpy(iteration_data[n_iteration], xfb_data, bo_size); 652 653 /* Unmap the buffer object */ 654 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); 655 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed"); 656 657 /* Ask the test implementation to verify the results */ 658 verifyResultDataForIteration(n_iteration, iteration_data[n_iteration]); 659 } /* for (all iterations) */ 660 661 /* Now that we've executed all iterations, we can call a global verification 662 * entry-point */ 663 verifyResultData((const void**)iteration_data); 664 665 /* At this point we're safe to release space allocated for data coming from 666 * all the iterations */ 667 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration) 668 { 669 char* iter_data = (char*)iteration_data[n_iteration]; 670 delete[] iter_data; 671 672 iteration_data[n_iteration] = DE_NULL; 673 } /* for (all iterations) */ 674 675 delete[] iteration_data; 676 iteration_data = DE_NULL; 677 678 /* All done */ 679 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 680 return STOP; 681 } 682 683 /* Does nothing (stub implementation) 684 * 685 * @param n_iteration Not used. 686 * @param data Not used. 687 * 688 **/ 689 void TessellationShaderInvarianceBaseTest::verifyResultDataForIteration(unsigned int n_iteration, const void* data) 690 { 691 DE_UNREF(n_iteration && data); 692 693 /* Do nothing - this is just a stub. */ 694 } 695 696 /* Does nothing (stub implementation) 697 * 698 * @param all_iterations_data Not used. 699 * 700 **/ 701 void TessellationShaderInvarianceBaseTest::verifyResultData(const void** all_iterations_data) 702 { 703 DE_UNREF(all_iterations_data); 704 705 /* Do nothing - this is just a stub. */ 706 } 707 708 /** Constructor. 709 * 710 * @param context Rendering context. 711 * 712 **/ 713 TessellationShaderInvarianceRule1Test::TessellationShaderInvarianceRule1Test(Context& context, 714 const ExtParameters& extParams) 715 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule1", 716 "Verifies conformance with first invariance rule") 717 { 718 /* Left blank intentionally */ 719 } 720 721 /** Destructor. */ 722 TessellationShaderInvarianceRule1Test::~TessellationShaderInvarianceRule1Test() 723 { 724 /* Left blank intentionally */ 725 } 726 727 /** Retrieves amount of iterations the base test implementation should run before 728 * calling global verification routine. 729 * 730 * @return Always 6. 731 **/ 732 unsigned int TessellationShaderInvarianceRule1Test::getAmountOfIterations() 733 { 734 return 6; 735 } 736 737 /** Returns a value that should be used for the draw call's "count" argument. 738 * 739 * @param Always 3 740 **/ 741 unsigned int TessellationShaderInvarianceRule1Test::getDrawCallCountArgument() 742 { 743 return 3; 744 } 745 746 /** Retrieves iteration-specific tessellation properties. 747 * 748 * @param n_iteration Iteration index to retrieve the properties for. 749 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner 750 * tessellation level values. Must not be NULL. 751 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer 752 * tessellation level values. Must not be NULL. 753 * @param out_point_mode Deref will be used to store iteration-specific flag 754 * telling whether point mode should be enabled for given pass. 755 * Must not be NULL. 756 * @param out_primitive_mode Deref will be used to store iteration-specific primitive 757 * mode. Must not be NULL. 758 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex ordering. 759 * Must not be NULL. 760 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object 761 * storage should offer for the draw call to succeed. Must not 762 * be NULL. 763 **/ 764 void TessellationShaderInvarianceRule1Test::getIterationProperties( 765 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode, 766 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering, 767 unsigned int* out_result_buffer_size) 768 { 769 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW; 770 771 switch (n_iteration) 772 { 773 case 0: 774 case 5: 775 { 776 /* Triangles (point mode) */ 777 out_inner_tess_levels[0] = 1.0f; 778 out_outer_tess_levels[0] = 1.0f; 779 out_outer_tess_levels[1] = 1.0f; 780 out_outer_tess_levels[2] = 1.0f; 781 782 *out_point_mode = true; 783 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES; 784 785 break; 786 } 787 788 case 1: 789 case 3: 790 { 791 /* Lines */ 792 out_outer_tess_levels[0] = 1.0f; 793 out_outer_tess_levels[1] = 1.0f; 794 795 *out_point_mode = false; 796 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES; 797 798 break; 799 } 800 801 case 2: 802 case 4: 803 { 804 /* Triangles */ 805 out_inner_tess_levels[0] = 1.0f; 806 out_outer_tess_levels[0] = 1.0f; 807 out_outer_tess_levels[1] = 1.0f; 808 out_outer_tess_levels[2] = 1.0f; 809 810 *out_point_mode = false; 811 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES; 812 813 break; 814 } 815 816 default: 817 { 818 TCU_FAIL("Unrecognzied iteration index"); 819 } 820 } 821 822 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator( 823 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 824 *out_point_mode); 825 826 *out_result_buffer_size = static_cast<unsigned int>(*out_result_buffer_size * getDrawCallCountArgument() * 827 3 /* components */ * sizeof(float)); 828 829 DE_ASSERT(*out_result_buffer_size != 0); 830 } 831 832 /** Retrieves iteration-specific tessellation evaluation shader code. 833 * 834 * @param n_iteration Iteration index, for which the source code is being obtained. 835 * 836 * @return Requested source code. 837 **/ 838 std::string TessellationShaderInvarianceRule1Test::getTECode(unsigned int n_iteration) 839 { 840 unsigned int bo_size = 0; 841 float inner_tess_levels[2] = { 0 }; 842 float outer_tess_levels[4] = { 0 }; 843 bool point_mode = false; 844 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN; 845 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN; 846 847 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode, 848 &vertex_ordering, &bo_size); 849 850 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode, 851 vertex_ordering, point_mode); 852 } 853 854 /** Verifies result data. Accesses data generated by all iterations. 855 * 856 * Throws TestError exception if an error occurs. 857 * 858 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord 859 * data generated by subsequent iterations. 860 **/ 861 void TessellationShaderInvarianceRule1Test::verifyResultData(const void** all_iterations_data) 862 { 863 const float* lines_vertex_data_1 = (const float*)all_iterations_data[1]; 864 const float* lines_vertex_data_2 = (const float*)all_iterations_data[3]; 865 const float* point_vertex_data_1 = (const float*)all_iterations_data[0]; 866 const float* point_vertex_data_2 = (const float*)all_iterations_data[5]; 867 const float* tris_vertex_data_1 = (const float*)all_iterations_data[2]; 868 const float* tris_vertex_data_2 = (const float*)all_iterations_data[4]; 869 870 const unsigned int n_line_vertices = 2 /* vertices per line segment */ * getDrawCallCountArgument(); /* lines */ 871 const unsigned int n_point_vertices = 1 /* vertices per point */ * getDrawCallCountArgument(); /* points */ 872 const unsigned int n_tri_vertices = 3 /* vertices per triangle */ * getDrawCallCountArgument(); /* triangles */ 873 const unsigned int vertex_size = sizeof(float) * 3; /* components */ 874 875 /* Make sure the data sets match, given different draw call ordering */ 876 for (int n_type = 0; n_type < 3 /* lines, points, tris */; ++n_type) 877 { 878 const float* data1_ptr = DE_NULL; 879 const float* data2_ptr = DE_NULL; 880 std::string data_type_string; 881 unsigned int n_vertices = 0; 882 883 switch (n_type) 884 { 885 case 0: 886 { 887 data1_ptr = lines_vertex_data_1; 888 data2_ptr = lines_vertex_data_2; 889 data_type_string = "Line"; 890 n_vertices = n_line_vertices; 891 892 break; 893 } 894 895 case 1: 896 { 897 data1_ptr = point_vertex_data_1; 898 data2_ptr = point_vertex_data_2; 899 data_type_string = "Point"; 900 n_vertices = n_point_vertices; 901 902 break; 903 } 904 905 case 2: 906 { 907 data1_ptr = tris_vertex_data_1; 908 data2_ptr = tris_vertex_data_2; 909 data_type_string = "Triangle"; 910 n_vertices = n_tri_vertices; 911 912 break; 913 } 914 915 default: 916 { 917 TCU_FAIL("Internal error: type index was not recognized"); 918 } 919 } /* switch (n_type) */ 920 921 /* Make sure the buffer storage in both cases has been modified */ 922 { 923 unsigned int zero_bo_size = vertex_size * n_vertices; 924 char* zero_bo_data = new char[vertex_size * n_vertices]; 925 926 memset(zero_bo_data, 0, zero_bo_size); 927 928 if (memcmp(data1_ptr, zero_bo_data, zero_bo_size) == 0 || 929 memcmp(data2_ptr, zero_bo_data, zero_bo_size) == 0) 930 { 931 TCU_FAIL("One of the draw calls has not outputted any data to XFB buffer object storage"); 932 } 933 934 delete[] zero_bo_data; 935 zero_bo_data = NULL; 936 } 937 938 /* Compare the data */ 939 if (memcmp(data1_ptr, data2_ptr, vertex_size * n_vertices) != 0) 940 { 941 std::stringstream logMessage; 942 943 logMessage << data_type_string << " data rendered in pass 1: ("; 944 945 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex) 946 { 947 logMessage << data1_ptr[n_vertex]; 948 949 if (n_vertex != (n_vertices - 1)) 950 { 951 logMessage << ", "; 952 } 953 else 954 { 955 logMessage << ") "; 956 } 957 } /* for (all vertices) */ 958 959 logMessage << "and in pass 2: ("; 960 961 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex) 962 { 963 logMessage << data2_ptr[n_vertex]; 964 965 if (n_vertex != (n_vertices - 1)) 966 { 967 logMessage << ", "; 968 } 969 else 970 { 971 logMessage << ") "; 972 } 973 } /* for (all vertices) */ 974 975 logMessage << "do not match"; 976 977 m_testCtx.getLog() << tcu::TestLog::Message << logMessage.str().c_str() << tcu::TestLog::EndMessage; 978 979 TCU_FAIL("Data mismatch"); 980 } /* if (data mismatch) */ 981 } /* for (all primitive types) */ 982 } 983 984 /** Constructor. 985 * 986 * @param context Rendering context. 987 * 988 **/ 989 TessellationShaderInvarianceRule2Test::TessellationShaderInvarianceRule2Test(Context& context, 990 const ExtParameters& extParams) 991 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule2", 992 "Verifies conformance with second invariance rule") 993 { 994 memset(m_n_tessellated_vertices, 0, sizeof(m_n_tessellated_vertices)); 995 } 996 997 /** Destructor. */ 998 TessellationShaderInvarianceRule2Test::~TessellationShaderInvarianceRule2Test() 999 { 1000 /* Left blank intentionally */ 1001 } 1002 1003 /** Retrieves amount of iterations the base test implementation should run before 1004 * calling global verification routine. 1005 * 1006 * @return Always 4. 1007 **/ 1008 unsigned int TessellationShaderInvarianceRule2Test::getAmountOfIterations() 1009 { 1010 return 4; 1011 } 1012 1013 /** Retrieves iteration-specific tessellation properties. 1014 * 1015 * @param n_iteration Iteration index to retrieve the properties for. 1016 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner 1017 * tessellation level values. Must not be NULL. 1018 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer 1019 * tessellation level values. Must not be NULL. 1020 * @param out_point_mode Deref will be used to store iteration-specific flag 1021 * telling whether point mode should be enabled for given pass. 1022 * Must not be NULL. 1023 * @param out_primitive_mode Deref will be used to store iteration-specific primitive 1024 * mode. Must not be NULL. 1025 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex 1026 * ordering. Must not be NULL. 1027 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object 1028 * storage should offer for the draw call to succeed. Can 1029 * be NULL. 1030 **/ 1031 void TessellationShaderInvarianceRule2Test::getIterationProperties( 1032 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode, 1033 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering, 1034 unsigned int* out_result_buffer_size) 1035 { 1036 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW; 1037 1038 switch (n_iteration) 1039 { 1040 case 0: 1041 case 1: 1042 { 1043 /* Triangles */ 1044 out_outer_tess_levels[0] = 2.0f; 1045 out_outer_tess_levels[1] = 3.0f; 1046 out_outer_tess_levels[2] = 4.0f; 1047 1048 if (n_iteration == 0) 1049 { 1050 out_inner_tess_levels[0] = 4.0f; 1051 out_inner_tess_levels[1] = 5.0f; 1052 } 1053 else 1054 { 1055 out_inner_tess_levels[0] = 3.0f; 1056 out_inner_tess_levels[1] = 4.0f; 1057 } 1058 1059 *out_point_mode = false; 1060 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES; 1061 1062 break; 1063 } 1064 1065 case 2: 1066 case 3: 1067 { 1068 /* Quads */ 1069 out_outer_tess_levels[0] = 2.0f; 1070 out_outer_tess_levels[1] = 3.0f; 1071 out_outer_tess_levels[2] = 4.0f; 1072 out_outer_tess_levels[3] = 5.0f; 1073 1074 if (n_iteration == 2) 1075 { 1076 out_inner_tess_levels[0] = 2.0f; 1077 out_inner_tess_levels[1] = 3.0f; 1078 } 1079 else 1080 { 1081 out_inner_tess_levels[0] = 4.0f; 1082 out_inner_tess_levels[1] = 5.0f; 1083 } 1084 1085 *out_point_mode = false; 1086 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS; 1087 1088 break; 1089 } 1090 1091 default: 1092 { 1093 TCU_FAIL("Unrecognized iteration index"); 1094 } 1095 } 1096 1097 if (out_result_buffer_size != DE_NULL) 1098 { 1099 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator( 1100 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 1101 *out_point_mode); 1102 1103 m_n_tessellated_vertices[n_iteration] = *out_result_buffer_size; 1104 *out_result_buffer_size = 1105 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float)); 1106 1107 DE_ASSERT(*out_result_buffer_size != 0); 1108 } 1109 } 1110 1111 /** Retrieves iteration-specific tessellation evaluation shader code. 1112 * 1113 * @param n_iteration Iteration index, for which the source code is being obtained. 1114 * 1115 * @return Requested source code. 1116 **/ 1117 std::string TessellationShaderInvarianceRule2Test::getTECode(unsigned int n_iteration) 1118 { 1119 unsigned int bo_size = 0; 1120 float inner_tess_levels[2] = { 0 }; 1121 float outer_tess_levels[4] = { 0 }; 1122 bool point_mode = false; 1123 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN; 1124 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN; 1125 1126 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode, 1127 &vertex_ordering, &bo_size); 1128 1129 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode, 1130 vertex_ordering, point_mode); 1131 } 1132 1133 /** Verifies result data. Accesses data generated by all iterations. 1134 * 1135 * Throws TestError exception if an error occurs. 1136 * 1137 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord 1138 * data generated by subsequent iterations. 1139 **/ 1140 void TessellationShaderInvarianceRule2Test::verifyResultData(const void** all_iterations_data) 1141 { 1142 /* Iterate through one tessellated set of vertices for a given primitive type 1143 * and identify outer vertices. Make sure exactly the same vertices can be 1144 * found in the other set of vertices, generated with different input tessellation 1145 * level. 1146 */ 1147 for (int n_primitive_type = 0; n_primitive_type < 2; /* triangles / quads */ 1148 ++n_primitive_type) 1149 { 1150 const float* data1_ptr = (const float*)all_iterations_data[n_primitive_type * 2 + 0]; 1151 const float* data2_ptr = (const float*)all_iterations_data[n_primitive_type * 2 + 1]; 1152 _tessellation_primitive_mode primitive_mode = (n_primitive_type == 0) ? 1153 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES : 1154 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS; 1155 std::vector<_vertex> outer_vertices; 1156 1157 /* Iterate through all data1 vertices.. */ 1158 for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2]; ++n_vertex) 1159 { 1160 /* Check if any of the components is equal to 0 or 1. If so, this could 1161 * be an edge vertex. 1162 */ 1163 const float* vertex_ptr = data1_ptr + n_vertex * 3; /* components */ 1164 1165 if (TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, vertex_ptr)) 1166 { 1167 /* Only add the vertex if it has not been added already to the vector */ 1168 bool has_already_been_added = false; 1169 1170 for (std::vector<_vertex>::const_iterator vertex_iterator = outer_vertices.begin(); 1171 vertex_iterator != outer_vertices.end(); vertex_iterator++) 1172 { 1173 if (vertex_iterator->u == vertex_ptr[0] && vertex_iterator->v == vertex_ptr[1] && 1174 vertex_iterator->w == vertex_ptr[2]) 1175 { 1176 has_already_been_added = true; 1177 1178 break; 1179 } 1180 } /* for (all outer vertices stored so far) */ 1181 1182 if (!has_already_been_added) 1183 { 1184 _vertex vertex; 1185 1186 vertex.u = vertex_ptr[0]; 1187 vertex.v = vertex_ptr[1]; 1188 vertex.w = vertex_ptr[2]; 1189 1190 outer_vertices.push_back(vertex); 1191 } 1192 } /* if (input vertex is located on outer edge) */ 1193 } /* for (all input vertices) */ 1194 1195 DE_ASSERT(outer_vertices.size() != 0); 1196 1197 /* Now that we know where outer vertices are, make sure they are present in the other data set */ 1198 for (std::vector<_vertex>::const_iterator ref_vertex_iterator = outer_vertices.begin(); 1199 ref_vertex_iterator != outer_vertices.end(); ref_vertex_iterator++) 1200 { 1201 bool has_been_found = false; 1202 const _vertex& ref_vertex = *ref_vertex_iterator; 1203 1204 for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2 + 1]; ++n_vertex) 1205 { 1206 const float* vertex_ptr = data2_ptr + n_vertex * 3; /* components */ 1207 1208 if (vertex_ptr[0] == ref_vertex.u && vertex_ptr[1] == ref_vertex.v && vertex_ptr[2] == ref_vertex.w) 1209 { 1210 has_been_found = true; 1211 1212 break; 1213 } 1214 } /* for (all vertices in the other data set) */ 1215 1216 if (!has_been_found) 1217 { 1218 float cmp_inner_tess_levels[2]; 1219 float cmp_outer_tess_levels[4]; 1220 bool cmp_point_mode; 1221 _tessellation_primitive_mode cmp_primitive_mode; 1222 _tessellation_shader_vertex_ordering cmp_vertex_ordering; 1223 std::string primitive_type = (n_primitive_type == 0) ? "triangles" : "quads"; 1224 float ref_inner_tess_levels[2]; 1225 float ref_outer_tess_levels[4]; 1226 bool ref_point_mode; 1227 _tessellation_primitive_mode ref_primitive_mode; 1228 _tessellation_shader_vertex_ordering ref_vertex_ordering; 1229 1230 getIterationProperties(n_primitive_type * 2, ref_inner_tess_levels, ref_outer_tess_levels, 1231 &ref_point_mode, &ref_primitive_mode, &ref_vertex_ordering, NULL); 1232 getIterationProperties(n_primitive_type * 2 + 1, cmp_inner_tess_levels, cmp_outer_tess_levels, 1233 &cmp_point_mode, &cmp_primitive_mode, &cmp_vertex_ordering, NULL); 1234 1235 m_testCtx.getLog() << tcu::TestLog::Message << "Outer vertex" 1236 << " (" << ref_vertex.u << ", " << ref_vertex.v << ", " << ref_vertex.w << ")" 1237 << " was not found in tessellated data coordinate set generated" 1238 << " for primitive type: " << primitive_type.c_str() 1239 << ". Reference inner tessellation level:" 1240 << " (" << ref_inner_tess_levels[0] << ", " << ref_inner_tess_levels[1] 1241 << "), reference outer tessellation level:" 1242 << " (" << ref_outer_tess_levels[0] << ", " << ref_outer_tess_levels[1] << ", " 1243 << ref_outer_tess_levels[2] << ", " << ref_outer_tess_levels[3] 1244 << "), test inner tessellation level:" 1245 << " (" << cmp_inner_tess_levels[0] << ", " << cmp_inner_tess_levels[1] 1246 << "), reference outer tessellation level:" 1247 << " (" << cmp_outer_tess_levels[0] << ", " << cmp_outer_tess_levels[1] << ", " 1248 << cmp_outer_tess_levels[2] << ", " << cmp_outer_tess_levels[3] << ")." 1249 << tcu::TestLog::EndMessage; 1250 1251 TCU_FAIL("Outer edge vertex was not found in tessellated coordinate set generated for " 1252 "the same outer tessellation levels and vertex spacing, but different inner " 1253 "tessellation levels"); 1254 } /* if (outer edge vertex was not found in the other set) */ 1255 } /* for (all outer edge vertices) */ 1256 } /* for (both primitive types) */ 1257 } 1258 1259 /** Constructor. 1260 * 1261 * @param context Rendering context. 1262 * 1263 **/ 1264 TessellationShaderInvarianceRule3Test::TessellationShaderInvarianceRule3Test(Context& context, 1265 const ExtParameters& extParams) 1266 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule3", 1267 "Verifies conformance with third invariance rule") 1268 { 1269 } 1270 1271 /** Destructor. */ 1272 TessellationShaderInvarianceRule3Test::~TessellationShaderInvarianceRule3Test() 1273 { 1274 /* Left blank intentionally */ 1275 } 1276 1277 /** Retrieves amount of iterations the base test implementation should run before 1278 * calling global verification routine. 1279 * 1280 * @return A value that depends on initTestIterations() behavior. 1281 **/ 1282 unsigned int TessellationShaderInvarianceRule3Test::getAmountOfIterations() 1283 { 1284 if (m_test_iterations.size() == 0) 1285 { 1286 initTestIterations(); 1287 } 1288 1289 return (unsigned int)m_test_iterations.size(); 1290 } 1291 1292 /** Retrieves iteration-specific tessellation properties. 1293 * 1294 * @param n_iteration Iteration index to retrieve the properties for. 1295 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner 1296 * tessellation level values. Must not be NULL. 1297 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer 1298 * tessellation level values. Must not be NULL. 1299 * @param out_point_mode Deref will be used to store iteration-specific flag 1300 * telling whether point mode should be enabled for given pass. 1301 * Must not be NULL. 1302 * @param out_primitive_mode Deref will be used to store iteration-specific primitive 1303 * mode. Must not be NULL. 1304 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex 1305 * ordering. Must not be NULL. 1306 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object 1307 * storage should offer for the draw call to succeed. Can 1308 * be NULL. 1309 **/ 1310 void TessellationShaderInvarianceRule3Test::getIterationProperties( 1311 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode, 1312 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering, 1313 unsigned int* out_result_buffer_size) 1314 { 1315 DE_ASSERT(m_test_iterations.size() > n_iteration); 1316 1317 _test_iteration& test_iteration = m_test_iterations[n_iteration]; 1318 1319 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels)); 1320 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels)); 1321 1322 *out_point_mode = false; 1323 *out_primitive_mode = test_iteration.primitive_mode; 1324 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW; 1325 1326 if (out_result_buffer_size != DE_NULL) 1327 { 1328 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator( 1329 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing, 1330 *out_point_mode); 1331 test_iteration.n_vertices = *out_result_buffer_size; 1332 *out_result_buffer_size = 1333 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float)); 1334 1335 DE_ASSERT(*out_result_buffer_size != 0); 1336 } 1337 } 1338 1339 /** Retrieves iteration-specific tessellation evaluation shader code. 1340 * 1341 * @param n_iteration Iteration index, for which the source code is being obtained. 1342 * 1343 * @return Requested source code. 1344 **/ 1345 std::string TessellationShaderInvarianceRule3Test::getTECode(unsigned int n_iteration) 1346 { 1347 DE_ASSERT(m_test_iterations.size() > n_iteration); 1348 1349 const _test_iteration& test_iteration = m_test_iterations[n_iteration]; 1350 1351 return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode, 1352 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */ 1353 } 1354 1355 /** Initializes test iterations for the test. The following modes and inner/outer tess level 1356 * configurations are used to form the test set: 1357 * 1358 * - Inner/outer tessellation level combinations as returned by 1359 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() 1360 * - All primitive modes; 1361 * - All vertex spacing modes; 1362 * 1363 * All permutations are used to generate the test set. 1364 **/ 1365 void TessellationShaderInvarianceRule3Test::initTestIterations() 1366 { 1367 DE_ASSERT(m_test_iterations.size() == 0); 1368 1369 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ 1370 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1371 glw::GLint gl_max_tess_gen_level_value = 0; 1372 1373 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); 1374 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); 1375 1376 /* Iterate through all primitive and vertex spacing modes */ 1377 _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES, 1378 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, 1379 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES }; 1380 _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 1381 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN, 1382 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD }; 1383 1384 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]); 1385 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]); 1386 1387 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode) 1388 { 1389 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode]; 1390 1391 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode) 1392 { 1393 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode]; 1394 1395 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */ 1396 _tessellation_levels_set levels_set; 1397 1398 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode( 1399 primitive_mode, gl_max_tess_gen_level_value, 1400 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE); 1401 1402 /* Iterate through all configurations */ 1403 for (_tessellation_levels_set_const_iterator levels_iterator = levels_set.begin(); 1404 levels_iterator != levels_set.end(); levels_iterator++) 1405 { 1406 const _tessellation_levels& levels = *levels_iterator; 1407 1408 /* Create a test descriptor for all the parameters we now have */ 1409 _test_iteration test; 1410 1411 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels)); 1412 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels)); 1413 1414 test.primitive_mode = primitive_mode; 1415 test.vertex_spacing = vs_mode; 1416 1417 m_test_iterations.push_back(test); 1418 } /* for (all inner/outer tessellation levels) */ 1419 } /* for (all vertex spacing modes) */ 1420 } /* for (all primitive modes) */ 1421 } 1422 1423 /** Verifies result data on per-iteration basis. 1424 * 1425 * Throws TestError exception if an error occurs. 1426 * 1427 * @param n_iteration Index of iteration the check should be performed for. 1428 * @param data Points to array of vec3s storing the vertices as 1429 * generated by tessellation 1430 **/ 1431 void TessellationShaderInvarianceRule3Test::verifyResultDataForIteration(unsigned int n_iteration, const void* data) 1432 { 1433 DE_ASSERT(m_test_iterations.size() > n_iteration); 1434 1435 const glw::GLfloat* data_float = (const glw::GLfloat*)data; 1436 const _test_iteration& test_iteration = m_test_iterations[n_iteration]; 1437 1438 /* Iterate through all generated vertices.. */ 1439 for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex) 1440 { 1441 _vertex expected_vertex; 1442 const glw::GLfloat* vertex_data = data_float + 3 /* components */ * n_vertex; 1443 1444 expected_vertex.u = -1.0f; 1445 expected_vertex.v = -1.0f; 1446 expected_vertex.w = -1.0f; 1447 1448 /* Make sure that for each vertex, the following language from the extension 1449 * spec is followed: 1450 */ 1451 switch (test_iteration.primitive_mode) 1452 { 1453 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES: 1454 { 1455 /* For isoline tessellation, if it generates vertices at (0,x) and (1,x) 1456 * where <x> is not zero, it will also generate vertices at exactly (0,1-x) 1457 * and (1,1-x), respectively. 1458 */ 1459 if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f) 1460 { 1461 expected_vertex.u = vertex_data[0]; 1462 expected_vertex.v = 1.0f - vertex_data[1]; 1463 expected_vertex.w = -1.0f; 1464 } 1465 else if (vertex_data[0] == 1.0f && vertex_data[1] != 0.0f) 1466 { 1467 expected_vertex.u = vertex_data[0]; 1468 expected_vertex.v = 1.0f - vertex_data[1]; 1469 expected_vertex.w = -1.0f; 1470 } 1471 1472 break; 1473 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES: */ 1474 1475 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: 1476 { 1477 /* For quad tessellation, if the subdivision generates a vertex with 1478 * coordinates of (x,0) or (0,x), it will also generate a vertex with 1479 * coordinates of exactly (1-x,0) or (0,1-x), respectively. 1480 */ 1481 if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f) 1482 { 1483 expected_vertex.u = 1.0f - vertex_data[0]; 1484 expected_vertex.v = vertex_data[1]; 1485 expected_vertex.w = -1.0f; 1486 } 1487 else if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f) 1488 { 1489 expected_vertex.u = vertex_data[0]; 1490 expected_vertex.v = 1.0f - vertex_data[1]; 1491 expected_vertex.w = -1.0f; 1492 } 1493 1494 break; 1495 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */ 1496 1497 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: 1498 { 1499 /* For triangle tessellation, if the subdivision generates a vertex with 1500 * tessellation coordinates of the form (0,x,1-x), (x,0,1-x), or (x,1-x,0), 1501 * it will also generate a vertex with coordinates of exactly (0,1-x,x), 1502 * (1-x,0,x), or (1-x,x,0), respectively. 1503 */ 1504 if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f && vertex_data[2] == (1.0f - vertex_data[1])) 1505 { 1506 expected_vertex.u = vertex_data[0]; 1507 expected_vertex.v = vertex_data[2]; 1508 expected_vertex.w = vertex_data[1]; 1509 } 1510 else if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f && vertex_data[2] == (1.0f - vertex_data[0])) 1511 { 1512 expected_vertex.u = vertex_data[2]; 1513 expected_vertex.v = vertex_data[1]; 1514 expected_vertex.w = vertex_data[0]; 1515 } 1516 else if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0.0f) 1517 { 1518 expected_vertex.u = vertex_data[1]; 1519 expected_vertex.v = vertex_data[0]; 1520 expected_vertex.w = vertex_data[2]; 1521 } 1522 1523 break; 1524 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */ 1525 1526 default: 1527 { 1528 TCU_FAIL("Primitive mode unrecognized"); 1529 } 1530 } /* switch (test_iteration.primitive_mode) */ 1531 1532 /* If any of the "expected vertex"'s components is no longer negative, 1533 * make sure the vertex can be found in the result data */ 1534 if (expected_vertex.u >= 0.0f || expected_vertex.v >= 0.0f || expected_vertex.w >= 0.0f) 1535 { 1536 bool has_been_found = false; 1537 1538 for (unsigned int n_find_vertex = 0; n_find_vertex < test_iteration.n_vertices; ++n_find_vertex) 1539 { 1540 const glw::GLfloat* current_vertex_data = data_float + 3 /* components */ * n_find_vertex; 1541 1542 const glw::GLfloat epsilon = 1e-4f; 1543 glw::GLfloat absDelta[3] = { de::abs(current_vertex_data[0] - expected_vertex.u), 1544 de::abs(current_vertex_data[1] - expected_vertex.v), 1545 de::abs(current_vertex_data[2] - expected_vertex.w) }; 1546 1547 if (absDelta[0] < epsilon && absDelta[1] < epsilon && 1548 ((expected_vertex.w < 0.0f) || (expected_vertex.w >= 0.0f && absDelta[2] < epsilon))) 1549 { 1550 has_been_found = true; 1551 1552 break; 1553 } /* if (the vertex data matches the expected vertex data) */ 1554 } /* for (all generated vertices)*/ 1555 1556 if (!has_been_found) 1557 { 1558 TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator."); 1559 } 1560 } /* if (any of the components of expected_vertex is no longer negative) */ 1561 } /* for (all generated vertices) */ 1562 } 1563 1564 /** Constructor. 1565 * 1566 * @param context Rendering context. 1567 * 1568 **/ 1569 TessellationShaderInvarianceRule4Test::TessellationShaderInvarianceRule4Test(Context& context, 1570 const ExtParameters& extParams) 1571 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule4", 1572 "Verifies conformance with fourth invariance rule") 1573 { 1574 } 1575 1576 /** Destructor. */ 1577 TessellationShaderInvarianceRule4Test::~TessellationShaderInvarianceRule4Test() 1578 { 1579 /* Left blank intentionally */ 1580 } 1581 1582 /** Retrieves amount of iterations the base test implementation should run before 1583 * calling global verification routine. 1584 * 1585 * @return A value that depends on initTestIterations() behavior. 1586 **/ 1587 unsigned int TessellationShaderInvarianceRule4Test::getAmountOfIterations() 1588 { 1589 if (m_test_iterations.size() == 0) 1590 { 1591 initTestIterations(); 1592 } 1593 1594 return (unsigned int)m_test_iterations.size(); 1595 } 1596 1597 /** Retrieves iteration-specific tessellation properties. 1598 * 1599 * @param n_iteration Iteration index to retrieve the properties for. 1600 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner 1601 * tessellation level values. Must not be NULL. 1602 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer 1603 * tessellation level values. Must not be NULL. 1604 * @param out_point_mode Deref will be used to store iteration-specific flag 1605 * telling whether point mode should be enabled for given pass. 1606 * Must not be NULL. 1607 * @param out_primitive_mode Deref will be used to store iteration-specific primitive 1608 * mode. Must not be NULL. 1609 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex 1610 * ordering. Must not be NULL. 1611 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object 1612 * storage should offer for the draw call to succeed. Can 1613 * be NULL. 1614 **/ 1615 void TessellationShaderInvarianceRule4Test::getIterationProperties( 1616 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode, 1617 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering, 1618 unsigned int* out_result_buffer_size) 1619 { 1620 DE_ASSERT(m_test_iterations.size() > n_iteration); 1621 1622 _test_iteration& test_iteration = m_test_iterations[n_iteration]; 1623 1624 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels)); 1625 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels)); 1626 1627 *out_point_mode = false; 1628 *out_primitive_mode = test_iteration.primitive_mode; 1629 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW; 1630 1631 if (out_result_buffer_size != DE_NULL) 1632 { 1633 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator( 1634 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing, 1635 *out_point_mode); 1636 test_iteration.n_vertices = *out_result_buffer_size; 1637 *out_result_buffer_size = 1638 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float)); 1639 1640 DE_ASSERT(*out_result_buffer_size != 0); 1641 } 1642 } 1643 1644 /** Retrieves iteration-specific tessellation evaluation shader code. 1645 * 1646 * @param n_iteration Iteration index, for which the source code is being obtained. 1647 * 1648 * @return Requested source code. 1649 **/ 1650 std::string TessellationShaderInvarianceRule4Test::getTECode(unsigned int n_iteration) 1651 { 1652 DE_ASSERT(m_test_iterations.size() > n_iteration); 1653 1654 const _test_iteration& test_iteration = m_test_iterations[n_iteration]; 1655 1656 return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode, 1657 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */ 1658 } 1659 1660 /** Initializes test iterations for the test. The following modes and inner/outer tess level 1661 * configurations are used to form the test set: 1662 * 1663 * - Inner/outer tessellation level combinations as returned by 1664 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() 1665 * - 'Quads' and 'Triangles' primitive modes; 1666 * - All vertex spacing modes; 1667 * 1668 * All permutations are used to generate the test set. 1669 **/ 1670 void TessellationShaderInvarianceRule4Test::initTestIterations() 1671 { 1672 DE_ASSERT(m_test_iterations.size() == 0); 1673 1674 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ 1675 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1676 glw::GLint gl_max_tess_gen_level_value = 0; 1677 1678 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); 1679 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); 1680 1681 /* Iterate through all primitive and vertex spacing modes relevant to the test */ 1682 _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, 1683 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES }; 1684 _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 1685 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN, 1686 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD }; 1687 1688 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]); 1689 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]); 1690 1691 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode) 1692 { 1693 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode]; 1694 1695 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode) 1696 { 1697 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode]; 1698 1699 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */ 1700 _tessellation_levels_set levels; 1701 1702 levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode( 1703 primitive_mode, gl_max_tess_gen_level_value, 1704 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE); 1705 1706 /* Iterate through all configurations */ 1707 for (_tessellation_levels_set_const_iterator levels_iterator = levels.begin(); 1708 levels_iterator != levels.end(); levels_iterator++) 1709 { 1710 const _tessellation_levels& current_levels = *levels_iterator; 1711 1712 /* Create a test descriptor for all the parameters we now have. 1713 * 1714 * The set we're operating on uses different outer tessellation level values, so we 1715 * need to make sure the levels are set to the same FP values in order for the test 1716 * to succeed. */ 1717 _test_iteration test; 1718 1719 memcpy(test.inner_tess_levels, current_levels.inner, sizeof(test.inner_tess_levels)); 1720 1721 for (int n = 0; n < 4 /* outer tess levels */; ++n) 1722 { 1723 test.outer_tess_levels[n] = current_levels.outer[0]; 1724 } 1725 1726 test.primitive_mode = primitive_mode; 1727 test.vertex_spacing = vs_mode; 1728 1729 m_test_iterations.push_back(test); 1730 } /* for (all inner/outer tessellation levels) */ 1731 } /* for (all vertex spacing modes) */ 1732 } /* for (all primitive modes) */ 1733 } 1734 1735 /** Verifies user-provided vertex data can be found in the provided vertex data array. 1736 * 1737 * @param vertex_data Vertex data array the requested vertex data are to be found in. 1738 * @param n_vertices Amount of vertices declared in @param vertex_data; 1739 * @param vertex_data_seeked Vertex data to be found in @param vertex_data; 1740 * @param n_vertex_data_seeked_components Amount of components to take into account. 1741 * 1742 * @return true if the vertex data was found, false otherwise. 1743 **/ 1744 bool TessellationShaderInvarianceRule4Test::isVertexDefined(const float* vertex_data, unsigned int n_vertices, 1745 const float* vertex_data_seeked, 1746 unsigned int n_vertex_data_seeked_components) 1747 { 1748 bool result = false; 1749 1750 DE_ASSERT(n_vertex_data_seeked_components >= 2); 1751 1752 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex) 1753 { 1754 const float* current_vertex_data = vertex_data + 3 /* components */ * n_vertex; 1755 1756 if ((vertex_data_seeked[0] == current_vertex_data[0]) && (vertex_data_seeked[1] == current_vertex_data[1]) && 1757 ((n_vertex_data_seeked_components < 3) || 1758 (n_vertex_data_seeked_components >= 3 && (vertex_data_seeked[2] == current_vertex_data[2])))) 1759 { 1760 result = true; 1761 1762 break; 1763 } /* if (components match) */ 1764 } /* for (all vertices) */ 1765 1766 return result; 1767 } 1768 1769 /** Verifies result data on per-iteration basis. 1770 * 1771 * Throws TestError exception if an error occurs. 1772 * 1773 * @param n_iteration Index of iteration the check should be performed for. 1774 * @param data Points to array of vec3s storing the vertices as 1775 * generated by tessellation 1776 **/ 1777 void TessellationShaderInvarianceRule4Test::verifyResultDataForIteration(unsigned int n_iteration, const void* data) 1778 { 1779 DE_ASSERT(m_test_iterations.size() > n_iteration); 1780 1781 const glw::GLfloat* data_float = (const glw::GLfloat*)data; 1782 const _test_iteration& test_iteration = m_test_iterations[n_iteration]; 1783 1784 /* Iterate through all generated vertices.. */ 1785 for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex) 1786 { 1787 std::vector<_vertex> expected_vertices; 1788 const glw::GLfloat* vertex_data = data_float + 3 /* components */ * n_vertex; 1789 1790 /* Make sure that for each vertex, the following language from the extension 1791 * spec is followed: 1792 */ 1793 switch (test_iteration.primitive_mode) 1794 { 1795 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: 1796 { 1797 /* For quad tessellation, if vertices at (x,0) and (1-x,0) are generated 1798 * when subdividing the v==0 edge, vertices must be generated at (0,x) and 1799 * (0,1-x) when subdividing an otherwise identical u==0 edge. 1800 */ 1801 if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f) 1802 { 1803 const float paired_vertex_data[] = { 1.0f - vertex_data[0], vertex_data[1] }; 1804 1805 if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 2)) /* components */ 1806 { 1807 _vertex expected_vertex; 1808 1809 /* First expected vertex */ 1810 expected_vertex.u = vertex_data[1]; 1811 expected_vertex.v = vertex_data[0]; 1812 expected_vertex.w = -1.0f; 1813 1814 expected_vertices.push_back(expected_vertex); 1815 1816 /* The other expected vertex */ 1817 expected_vertex.u = vertex_data[1]; 1818 expected_vertex.v = 1.0f - vertex_data[0]; 1819 1820 expected_vertices.push_back(expected_vertex); 1821 } /* if (the other required vertex is defined) */ 1822 } /* if (the first required vertex is defined) */ 1823 1824 break; 1825 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */ 1826 1827 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: 1828 { 1829 /* For triangular tessellation, if vertices at (x,1-x,0) and (1-x,x,0) are 1830 * generated when subdividing the w==0 edge, vertices must be generated at 1831 * (x,0,1-x) and (1-x,0,x) when subdividing an otherwise identical v==0 1832 * edge. 1833 */ 1834 if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0) 1835 { 1836 const float paired_vertex_data[] = { vertex_data[1], vertex_data[0], vertex_data[2] }; 1837 1838 if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 3)) /* components */ 1839 { 1840 _vertex expected_vertex; 1841 1842 /* First expected vertex */ 1843 expected_vertex.u = vertex_data[0]; 1844 expected_vertex.v = vertex_data[2]; 1845 expected_vertex.w = vertex_data[1]; 1846 1847 expected_vertices.push_back(expected_vertex); 1848 1849 /* The other expected vertex */ 1850 expected_vertex.u = vertex_data[1]; 1851 expected_vertex.v = vertex_data[2]; 1852 expected_vertex.w = vertex_data[0]; 1853 1854 expected_vertices.push_back(expected_vertex); 1855 } /* if (the other required vertex is defined) */ 1856 } /* if (the firsst required vertex is defined) */ 1857 1858 break; 1859 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */ 1860 1861 default: 1862 { 1863 TCU_FAIL("Primitive mode unrecognized"); 1864 } 1865 } /* switch (test_iteration.primitive_mode) */ 1866 1867 /* Iterate through all expected vertices */ 1868 for (std::vector<_vertex>::const_iterator expected_vertex_iterator = expected_vertices.begin(); 1869 expected_vertex_iterator != expected_vertices.end(); expected_vertex_iterator++) 1870 { 1871 const _vertex& expected_vertex = *expected_vertex_iterator; 1872 const float expected_vertex_raw[] = { expected_vertex.u, expected_vertex.v, expected_vertex.w }; 1873 bool has_been_found = false; 1874 1875 has_been_found = isVertexDefined(data_float, test_iteration.n_vertices, expected_vertex_raw, 1876 (expected_vertex.w < 0) ? 2 : 3); 1877 1878 if (!has_been_found) 1879 { 1880 std::stringstream expected_vertex_sstream; 1881 1882 expected_vertex_sstream << expected_vertex.u << ", " << expected_vertex.v; 1883 1884 if (expected_vertex.w >= 0.0f) 1885 { 1886 expected_vertex_sstream << ", " << expected_vertex.w; 1887 } 1888 1889 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode:" 1890 << "[" 1891 << TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration.primitive_mode) 1892 << "]" 1893 << "and vertex spacing mode:" 1894 << "[" << TessellationShaderUtils::getESTokenForVertexSpacingMode( 1895 test_iteration.vertex_spacing) 1896 << "]" 1897 << " and inner tessellation levels:[" << test_iteration.inner_tess_levels[0] << ", " 1898 << test_iteration.inner_tess_levels[1] << ") " 1899 << " and outer tessellation levels:[" << test_iteration.outer_tess_levels[0] << ", " 1900 << test_iteration.outer_tess_levels[1] << ", " << test_iteration.outer_tess_levels[2] 1901 << ", " << test_iteration.outer_tess_levels[3] << ") " 1902 << " the following vertex was expected:[" << expected_vertex_sstream.str().c_str() 1903 << "] but was not found in the tessellated cooordinate data set" 1904 << tcu::TestLog::EndMessage; 1905 1906 TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator."); 1907 } /* if (the expected vertex data was not found) */ 1908 } /* for (all expected vertices) */ 1909 } /* for (all generated vertices) */ 1910 } 1911 1912 /** Constructor. 1913 * 1914 * @param context Rendering context. 1915 * 1916 **/ 1917 TessellationShaderInvarianceRule5Test::TessellationShaderInvarianceRule5Test(Context& context, 1918 const ExtParameters& extParams) 1919 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule5", 1920 "Verifies conformance with fifth invariance rule") 1921 { 1922 } 1923 1924 /** Destructor. */ 1925 TessellationShaderInvarianceRule5Test::~TessellationShaderInvarianceRule5Test() 1926 { 1927 /* Left blank intentionally */ 1928 } 1929 1930 /** Retrieves amount of iterations the base test implementation should run before 1931 * calling global verification routine. 1932 * 1933 * @return A value that depends on initTestIterations() behavior. 1934 **/ 1935 unsigned int TessellationShaderInvarianceRule5Test::getAmountOfIterations() 1936 { 1937 if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0) 1938 { 1939 initTestIterations(); 1940 } 1941 1942 return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size()); 1943 } 1944 1945 /** Retrieves _test_iteration instance specific for user-specified iteration index. 1946 * 1947 * @param n_iteration Iteration index to retrieve _test_iteration instance for. 1948 * 1949 * @return Iteration-specific _test_iteration instance. 1950 * 1951 **/ 1952 TessellationShaderInvarianceRule5Test::_test_iteration& TessellationShaderInvarianceRule5Test::getTestForIteration( 1953 unsigned int n_iteration) 1954 { 1955 unsigned int n_triangles_tests = (unsigned int)m_test_triangles_iterations.size(); 1956 _test_iteration& test_iteration = (n_iteration < n_triangles_tests) ? 1957 m_test_triangles_iterations[n_iteration] : 1958 m_test_quads_iterations[n_iteration - n_triangles_tests]; 1959 1960 return test_iteration; 1961 } 1962 1963 /** Retrieves iteration-specific tessellation properties. 1964 * 1965 * @param n_iteration Iteration index to retrieve the properties for. 1966 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner 1967 * tessellation level values. Must not be NULL. 1968 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer 1969 * tessellation level values. Must not be NULL. 1970 * @param out_point_mode Deref will be used to store iteration-specific flag 1971 * telling whether point mode should be enabled for given pass. 1972 * Must not be NULL. 1973 * @param out_primitive_mode Deref will be used to store iteration-specific primitive 1974 * mode. Must not be NULL. 1975 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex 1976 * ordering. Must not be NULL. 1977 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object 1978 * storage should offer for the draw call to succeed. Can 1979 * be NULL. 1980 **/ 1981 void TessellationShaderInvarianceRule5Test::getIterationProperties( 1982 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode, 1983 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering, 1984 unsigned int* out_result_buffer_size) 1985 { 1986 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration); 1987 1988 _test_iteration& test_iteration = getTestForIteration(n_iteration); 1989 1990 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels)); 1991 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels)); 1992 1993 *out_point_mode = false; 1994 *out_primitive_mode = test_iteration.primitive_mode; 1995 *out_vertex_ordering = test_iteration.vertex_ordering; 1996 1997 if (out_result_buffer_size != DE_NULL) 1998 { 1999 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator( 2000 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 2001 *out_point_mode); 2002 test_iteration.n_vertices = *out_result_buffer_size; 2003 *out_result_buffer_size = 2004 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float)); 2005 2006 DE_ASSERT(*out_result_buffer_size != 0); 2007 } 2008 } 2009 2010 /** Retrieves iteration-specific tessellation evaluation shader code. 2011 * 2012 * @param n_iteration Iteration index, for which the source code is being obtained. 2013 * 2014 * @return Requested source code. 2015 **/ 2016 std::string TessellationShaderInvarianceRule5Test::getTECode(unsigned int n_iteration) 2017 { 2018 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration); 2019 2020 const _test_iteration& test_iteration = getTestForIteration(n_iteration); 2021 2022 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 2023 test_iteration.primitive_mode, test_iteration.vertex_ordering, 2024 false); /* point mode */ 2025 } 2026 2027 /** Initializes test iterations for the test. The following modes and inner/outer tess level 2028 * configurations are used to form the test set: 2029 * 2030 * - Last inner/outer tessellation level combination as returned by 2031 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() 2032 * - All primitive modes; 2033 * - All vertex spacing modes; 2034 * 2035 * All permutations are used to generate the test set. 2036 **/ 2037 void TessellationShaderInvarianceRule5Test::initTestIterations() 2038 { 2039 DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0); 2040 2041 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ 2042 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2043 glw::GLint gl_max_tess_gen_level_value = 0; 2044 2045 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); 2046 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); 2047 2048 /* Iterate through all primitive and vertex spacing modes relevant to the test */ 2049 _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, 2050 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES }; 2051 _tessellation_shader_vertex_ordering vo_modes[] = { 2052 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, TESSELLATION_SHADER_VERTEX_ORDERING_CW, 2053 }; 2054 2055 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]); 2056 const unsigned int n_vo_modes = sizeof(vo_modes) / sizeof(vo_modes[0]); 2057 2058 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode) 2059 { 2060 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode]; 2061 2062 for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode) 2063 { 2064 _tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode]; 2065 2066 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */ 2067 _tessellation_levels_set levels_set; 2068 2069 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode( 2070 primitive_mode, gl_max_tess_gen_level_value, 2071 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE); 2072 2073 /* Only use the last inner/outer level configuration, as reported by the utils function. */ 2074 const _tessellation_levels& levels = levels_set[levels_set.size() - 1]; 2075 2076 /* Create a test descriptor for all the parameters we now have */ 2077 _test_iteration test; 2078 2079 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels)); 2080 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels)); 2081 2082 test.primitive_mode = primitive_mode; 2083 test.vertex_ordering = vertex_ordering; 2084 2085 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) 2086 { 2087 m_test_triangles_iterations.push_back(test); 2088 } 2089 else 2090 { 2091 m_test_quads_iterations.push_back(test); 2092 } 2093 } /* for (all vertex spacing modes) */ 2094 } /* for (all primitive modes) */ 2095 } 2096 2097 /** Verifies user-provided vertex data can be found in the provided vertex data array. 2098 * 2099 * @param vertex_data Vertex data array the requested vertex data are to be found in. 2100 * @param n_vertices Amount of vertices declared in @param vertex_data; 2101 * @param vertex_data_seeked Vertex data to be found in @param vertex_data; 2102 * @param n_vertex_data_seeked_components Amount of components to take into account. 2103 * 2104 * @return true if the vertex data was found, false otherwise. 2105 **/ 2106 bool TessellationShaderInvarianceRule5Test::isVertexDefined(const float* vertex_data, unsigned int n_vertices, 2107 const float* vertex_data_seeked, 2108 unsigned int n_vertex_data_seeked_components) 2109 { 2110 const float epsilon = 1e-5f; 2111 bool result = false; 2112 2113 DE_ASSERT(n_vertex_data_seeked_components >= 2); 2114 2115 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex) 2116 { 2117 const float* current_vertex_data = vertex_data + 3 /* components */ * n_vertex; 2118 2119 if (de::abs(vertex_data_seeked[0] - current_vertex_data[0]) < epsilon && 2120 de::abs(vertex_data_seeked[1] - current_vertex_data[1]) < epsilon && 2121 ((n_vertex_data_seeked_components < 3) || 2122 (n_vertex_data_seeked_components >= 3 && 2123 de::abs(vertex_data_seeked[2] - current_vertex_data[2]) < epsilon))) 2124 { 2125 result = true; 2126 2127 break; 2128 } /* if (components match) */ 2129 } /* for (all vertices) */ 2130 2131 return result; 2132 } 2133 2134 /** Verifies result data. Accesses data generated by all iterations. 2135 * 2136 * Throws TestError exception if an error occurs. 2137 * 2138 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord 2139 * data generated by subsequent iterations. 2140 **/ 2141 void TessellationShaderInvarianceRule5Test::verifyResultData(const void** all_iterations_data) 2142 { 2143 /* Run two separate iterations: 2144 * 2145 * a) triangles 2146 * b) quads 2147 */ 2148 for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration) 2149 { 2150 const unsigned int n_base_iteration = 2151 (n_iteration == 0) ? 0 : (const unsigned int)m_test_triangles_iterations.size(); 2152 const unsigned int set_size = (n_iteration == 0) ? (const unsigned int)m_test_triangles_iterations.size() : 2153 (const unsigned int)m_test_quads_iterations.size(); 2154 const _test_iterations& test_iterations = 2155 (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations; 2156 2157 DE_ASSERT(test_iterations.size() != 0); 2158 2159 /* For each iteration, verify that all vertices generated for all three vertex spacing modes. 2160 * are exactly the same (but in different order) */ 2161 const float* base_vertex_data = (const float*)all_iterations_data[n_base_iteration + 0]; 2162 2163 for (unsigned int n_set = 1; n_set < set_size; ++n_set) 2164 { 2165 const float* set_vertex_data = (const float*)all_iterations_data[n_base_iteration + n_set]; 2166 2167 /* Amount of vertices should not differ between sets */ 2168 DE_ASSERT(test_iterations[0].n_vertices == test_iterations[n_set].n_vertices); 2169 2170 /* Run through all vertices in base set and make sure they can be found in currently 2171 * processed set */ 2172 for (unsigned int n_base_vertex = 0; n_base_vertex < test_iterations[0].n_vertices; ++n_base_vertex) 2173 { 2174 const float* base_vertex = base_vertex_data + 3 /* components */ * n_base_vertex; 2175 2176 if (!isVertexDefined(set_vertex_data, test_iterations[n_set].n_vertices, base_vertex, 2177 3)) /* components */ 2178 { 2179 const char* primitive_mode = (n_iteration == 0) ? "triangles" : "quads"; 2180 2181 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode [" << primitive_mode << "] " 2182 << "a vertex with tessellation coordinates:[" << base_vertex[0] << ", " 2183 << base_vertex[1] << ", " << base_vertex[2] << ") " 2184 << "could not have been found for both vertex orderings." 2185 << tcu::TestLog::EndMessage; 2186 2187 TCU_FAIL("Implementation does not follow Rule 5."); 2188 } 2189 } /* for (all base set's vertices) */ 2190 } /* for (all sets) */ 2191 } /* for (both primitive types) */ 2192 } 2193 2194 /** Constructor. 2195 * 2196 * @param context Rendering context. 2197 * 2198 **/ 2199 TessellationShaderInvarianceRule6Test::TessellationShaderInvarianceRule6Test(Context& context, 2200 const ExtParameters& extParams) 2201 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule6", 2202 "Verifies conformance with sixth invariance rule") 2203 { 2204 } 2205 2206 /** Destructor. */ 2207 TessellationShaderInvarianceRule6Test::~TessellationShaderInvarianceRule6Test() 2208 { 2209 /* Left blank intentionally */ 2210 } 2211 2212 /** Retrieves amount of iterations the base test implementation should run before 2213 * calling global verification routine. 2214 * 2215 * @return A value that depends on initTestIterations() behavior. 2216 **/ 2217 unsigned int TessellationShaderInvarianceRule6Test::getAmountOfIterations() 2218 { 2219 if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0) 2220 { 2221 initTestIterations(); 2222 } 2223 2224 return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size()); 2225 } 2226 2227 /** Retrieves _test_iteration instance specific for user-specified iteration index. 2228 * 2229 * @param n_iteration Iteration index to retrieve _test_iteration instance for. 2230 * 2231 * @return Iteration-specific _test_iteration instance. 2232 * 2233 **/ 2234 TessellationShaderInvarianceRule6Test::_test_iteration& TessellationShaderInvarianceRule6Test::getTestForIteration( 2235 unsigned int n_iteration) 2236 { 2237 unsigned int n_triangles_tests = (unsigned int)m_test_triangles_iterations.size(); 2238 _test_iteration& test_iteration = (n_iteration < n_triangles_tests) ? 2239 m_test_triangles_iterations[n_iteration] : 2240 m_test_quads_iterations[n_iteration - n_triangles_tests]; 2241 2242 return test_iteration; 2243 } 2244 2245 /** Retrieves iteration-specific tessellation properties. 2246 * 2247 * @param n_iteration Iteration index to retrieve the properties for. 2248 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner 2249 * tessellation level values. Must not be NULL. 2250 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer 2251 * tessellation level values. Must not be NULL. 2252 * @param out_point_mode Deref will be used to store iteration-specific flag 2253 * telling whether point mode should be enabled for given pass. 2254 * Must not be NULL. 2255 * @param out_primitive_mode Deref will be used to store iteration-specific primitive 2256 * mode. Must not be NULL. 2257 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex 2258 * ordering. Must not be NULL. 2259 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object 2260 * storage should offer for the draw call to succeed. Can 2261 * be NULL. 2262 **/ 2263 void TessellationShaderInvarianceRule6Test::getIterationProperties( 2264 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode, 2265 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering, 2266 unsigned int* out_result_buffer_size) 2267 { 2268 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration); 2269 2270 _test_iteration& test_iteration = getTestForIteration(n_iteration); 2271 2272 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels)); 2273 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels)); 2274 2275 *out_point_mode = false; 2276 *out_primitive_mode = test_iteration.primitive_mode; 2277 *out_vertex_ordering = test_iteration.vertex_ordering; 2278 2279 if (out_result_buffer_size != DE_NULL) 2280 { 2281 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator( 2282 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 2283 *out_point_mode); 2284 test_iteration.n_vertices = *out_result_buffer_size; 2285 *out_result_buffer_size = 2286 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float)); 2287 2288 DE_ASSERT(*out_result_buffer_size != 0); 2289 } 2290 } 2291 2292 /** Retrieves iteration-specific tessellation evaluation shader code. 2293 * 2294 * @param n_iteration Iteration index, for which the source code is being obtained. 2295 * 2296 * @return Requested source code. 2297 **/ 2298 std::string TessellationShaderInvarianceRule6Test::getTECode(unsigned int n_iteration) 2299 { 2300 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration); 2301 2302 const _test_iteration& test_iteration = getTestForIteration(n_iteration); 2303 2304 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 2305 test_iteration.primitive_mode, test_iteration.vertex_ordering, 2306 false); /* point mode */ 2307 } 2308 2309 /** Initializes test iterations for the test. The following modes and inner/outer tess level 2310 * configurations are used to form the test set: 2311 * 2312 * - Tessellation level combinations as returned by 2313 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() (however, the inner 2314 * tessellation level values are all set to values corresponding to last item returned for 2315 * the set) 2316 * - All primitive modes; 2317 * - All vertex ordering modes; 2318 * 2319 * All permutations are used to generate the test set. 2320 **/ 2321 void TessellationShaderInvarianceRule6Test::initTestIterations() 2322 { 2323 DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0); 2324 2325 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ 2326 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2327 glw::GLint gl_max_tess_gen_level_value = 0; 2328 2329 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); 2330 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); 2331 2332 /* Iterate through all primitive and vertex spacing modes relevant to the test */ 2333 _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, 2334 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS }; 2335 _tessellation_shader_vertex_ordering vertex_ordering_modes[] = { TESSELLATION_SHADER_VERTEX_ORDERING_CCW, 2336 TESSELLATION_SHADER_VERTEX_ORDERING_CW }; 2337 2338 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]); 2339 const unsigned int n_vo_modes = sizeof(vertex_ordering_modes) / sizeof(vertex_ordering_modes[0]); 2340 2341 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode) 2342 { 2343 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode]; 2344 2345 for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode) 2346 { 2347 _tessellation_shader_vertex_ordering vertex_ordering = vertex_ordering_modes[n_vo_mode]; 2348 2349 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for. 2350 * Since each level set we will be provided by getTessellationLevelSetForPrimitiveMode() 2351 * is unique and does not repeat, we'll just make sure the inner level values are set to 2352 * the same set of values, so that the conditions the test must meet are actually met. 2353 */ 2354 float* inner_levels_to_use = DE_NULL; 2355 _tessellation_levels_set levels_set; 2356 unsigned int n_levels_sets = 0; 2357 2358 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode( 2359 primitive_mode, gl_max_tess_gen_level_value, 2360 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE); 2361 2362 n_levels_sets = (unsigned int)levels_set.size(); 2363 inner_levels_to_use = levels_set[n_levels_sets - 1].inner; 2364 2365 for (unsigned int n_levels_set = 0; n_levels_set < n_levels_sets - 1; n_levels_set++) 2366 { 2367 /* Make sure the Utils function was not changed and that inner level values 2368 * are actually unique across the whole set */ 2369 DE_ASSERT(levels_set[n_levels_set].inner[0] != levels_set[n_levels_sets - 1].inner[0] && 2370 levels_set[n_levels_set].inner[1] != levels_set[n_levels_sets - 1].inner[1]); 2371 2372 /* Force the last set's inner values to all level combinations we'll be using */ 2373 memcpy(levels_set[n_levels_set].inner, inner_levels_to_use, sizeof(levels_set[n_levels_set].inner)); 2374 } /* for (all sets retrieved from Utils function */ 2375 2376 for (_tessellation_levels_set_const_iterator set_iterator = levels_set.begin(); 2377 set_iterator != levels_set.end(); set_iterator++) 2378 { 2379 const _tessellation_levels& levels = *set_iterator; 2380 2381 /* Create a test descriptor for all the parameters we now have */ 2382 _test_iteration test; 2383 2384 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels)); 2385 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels)); 2386 2387 test.primitive_mode = primitive_mode; 2388 test.vertex_ordering = vertex_ordering; 2389 2390 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) 2391 { 2392 m_test_triangles_iterations.push_back(test); 2393 } 2394 else 2395 { 2396 m_test_quads_iterations.push_back(test); 2397 } 2398 } /* for (all level sets) */ 2399 } /* for (all vertex ordering modes) */ 2400 } /* for (all primitive modes) */ 2401 } 2402 2403 /** Verifies result data. Accesses data generated by all iterations. 2404 * 2405 * Throws TestError exception if an error occurs. 2406 * 2407 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord 2408 * data generated by subsequent iterations. 2409 **/ 2410 void TessellationShaderInvarianceRule6Test::verifyResultData(const void** all_iterations_data) 2411 { 2412 /* Run two separate iterations: 2413 * 2414 * a) triangles 2415 * b) quads 2416 */ 2417 2418 for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration) 2419 { 2420 const unsigned int n_base_iteration = 2421 (n_iteration == 0) ? 0 : (const unsigned int)m_test_triangles_iterations.size(); 2422 2423 const unsigned int n_sets = (n_iteration == 0) ? (const unsigned int)m_test_triangles_iterations.size() : 2424 (const unsigned int)m_test_quads_iterations.size(); 2425 2426 _tessellation_primitive_mode primitive_mode = (n_iteration == 0) ? 2427 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES : 2428 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS; 2429 2430 const _test_iterations& test_iterations = 2431 (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations; 2432 2433 const unsigned int n_triangles_in_base_set = test_iterations[0].n_vertices / 3 /* vertices per triangle */; 2434 2435 DE_ASSERT(test_iterations.size() != 0); 2436 2437 /* For each iteration, verify that all vertices generated for all three vertex spacing modes. 2438 * are exactly the same (but in different order) */ 2439 const _test_iteration& base_test = test_iterations[0]; 2440 const float* base_vertex_data = (const float*)all_iterations_data[n_base_iteration + 0]; 2441 2442 for (unsigned int n_set = 1; n_set < n_sets; ++n_set) 2443 { 2444 const _test_iteration& set_test = test_iterations[n_set]; 2445 const float* set_vertex_data = (const float*)all_iterations_data[n_base_iteration + n_set]; 2446 2447 /* We're operating on triangles so make sure the amount of vertices we're dealing with is 2448 * divisible by 3 */ 2449 DE_ASSERT((test_iterations[n_set].n_vertices % 3) == 0); 2450 2451 const unsigned int n_triangles_in_curr_set = test_iterations[n_set].n_vertices / 3; 2452 2453 /* Take base triangles and make sure they can be found in iteration-specific set. 2454 * Now, thing to keep in mind here is that we must not assume any specific vertex 2455 * and triangle order which is why the slow search. */ 2456 for (unsigned int n_base_triangle = 0; n_base_triangle < n_triangles_in_base_set; ++n_base_triangle) 2457 { 2458 /* Extract base triangle data first */ 2459 const float* base_triangle_vertex1 = base_vertex_data + 2460 n_base_triangle * 3 * /* vertices per triangle */ 2461 3; /* components */ 2462 const float* base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */ 2463 const float* base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */ 2464 2465 /* Only interior triangles should be left intact. Is this an interior triangle? */ 2466 if (!TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1) && 2467 !TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2) && 2468 !TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3)) 2469 { 2470 /* Iterate through all triangles in considered set */ 2471 bool has_base_set_triangle_been_found = false; 2472 2473 for (unsigned int n_curr_set_triangle = 0; n_curr_set_triangle < n_triangles_in_curr_set; 2474 ++n_curr_set_triangle) 2475 { 2476 const float* curr_triangle = set_vertex_data + 2477 n_curr_set_triangle * 3 * /* vertices per triangle */ 2478 3; /* components */ 2479 2480 if (TessellationShaderUtils::isTriangleDefined(base_triangle_vertex1, curr_triangle)) 2481 { 2482 has_base_set_triangle_been_found = true; 2483 2484 break; 2485 } 2486 } /* for (all triangles in currently processed set) */ 2487 2488 if (!has_base_set_triangle_been_found) 2489 { 2490 std::string primitive_mode_str = 2491 TessellationShaderUtils::getESTokenForPrimitiveMode(base_test.primitive_mode); 2492 2493 m_testCtx.getLog() 2494 << tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "]" 2495 << ", base inner tessellation levels:" 2496 << "[" << base_test.inner_tess_levels[0] << ", " << base_test.inner_tess_levels[1] << "]" 2497 << ", base outer tessellation levels:" 2498 << "[" << base_test.outer_tess_levels[0] << ", " << base_test.outer_tess_levels[1] << ", " 2499 << base_test.outer_tess_levels[2] << ", " << base_test.outer_tess_levels[3] << "]" 2500 << ", reference inner tessellation levels:" 2501 << "[" << set_test.inner_tess_levels[0] << ", " << set_test.inner_tess_levels[1] << "]" 2502 << ", reference outer tessellation levels:" 2503 << "[" << set_test.outer_tess_levels[0] << ", " << set_test.outer_tess_levels[1] << ", " 2504 << set_test.outer_tess_levels[2] << ", " << set_test.outer_tess_levels[3] << "]" 2505 << ", the following triangle formed during base tessellation run was not found in " 2506 "reference run:" 2507 << "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", " 2508 << base_triangle_vertex1[2] << "]x" 2509 << "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", " 2510 << base_triangle_vertex2[2] << "]x" 2511 << "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", " 2512 << base_triangle_vertex3[2] 2513 2514 << tcu::TestLog::EndMessage; 2515 2516 TCU_FAIL("Implementation does not appear to be rule 6-conformant"); 2517 } /* if (triangle created during base run was not found in reference run) */ 2518 } /* if (base triangle is interior) */ 2519 } /* for (all base set's vertices) */ 2520 } /* for (all sets) */ 2521 } /* for (both primitive types) */ 2522 } 2523 2524 /** Constructor. 2525 * 2526 * @param context Rendering context. 2527 * 2528 **/ 2529 TessellationShaderInvarianceRule7Test::TessellationShaderInvarianceRule7Test(Context& context, 2530 const ExtParameters& extParams) 2531 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule7", 2532 "Verifies conformance with seventh invariance rule") 2533 { 2534 } 2535 2536 /** Destructor. */ 2537 TessellationShaderInvarianceRule7Test::~TessellationShaderInvarianceRule7Test() 2538 { 2539 /* Left blank intentionally */ 2540 } 2541 2542 /** Retrieves amount of iterations the base test implementation should run before 2543 * calling global verification routine. 2544 * 2545 * @return A value that depends on initTestIterations() behavior. 2546 **/ 2547 unsigned int TessellationShaderInvarianceRule7Test::getAmountOfIterations() 2548 { 2549 if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0) 2550 { 2551 initTestIterations(); 2552 } 2553 2554 return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size()); 2555 } 2556 2557 /** Retrieves index of a test iteration that was initialized with user-provided 2558 * properties. 2559 * 2560 * @param is_triangles_iteration true if the seeked test iteration should have 2561 * been run for 'triangles' primitive mode', false 2562 * if 'quads' primitive mode run is seeked. 2563 * @param inner_tess_levels Two FP values describing inner tessellation level 2564 * values the seeked run should have used. 2565 * @param outer_tess_levels Four FP values describing outer tessellation level 2566 * values the seeked run should have used. 2567 * @param vertex_ordering Vertex ordering mode the seeked run should have used. 2568 * @param n_modified_outer_tess_level Tells which outer tessellation level should be 2569 * excluded from checking. 2570 * 2571 * @return 0xFFFFFFFF if no test iteration was run for user-provided properties, 2572 * actual index otherwise. 2573 * 2574 **/ 2575 unsigned int TessellationShaderInvarianceRule7Test::getTestIterationIndex( 2576 bool is_triangles_iteration, const float* inner_tess_levels, const float* outer_tess_levels, 2577 _tessellation_shader_vertex_ordering vertex_ordering, unsigned int n_modified_outer_tess_level) 2578 { 2579 const float epsilon = 1e-5f; 2580 unsigned int result = 0xFFFFFFFF; 2581 const _test_iterations& test_iterations = 2582 (is_triangles_iteration) ? m_test_triangles_iterations : m_test_quads_iterations; 2583 const unsigned int n_test_iterations = (const unsigned int)test_iterations.size(); 2584 2585 for (unsigned int n_test_iteration = 0; n_test_iteration < n_test_iterations; ++n_test_iteration) 2586 { 2587 _test_iteration test_iteration = test_iterations[n_test_iteration]; 2588 2589 if (de::abs(test_iteration.inner_tess_levels[0] - inner_tess_levels[0]) < epsilon && 2590 de::abs(test_iteration.inner_tess_levels[1] - inner_tess_levels[1]) < epsilon && 2591 test_iteration.vertex_ordering == vertex_ordering && 2592 test_iteration.n_modified_outer_tess_level == n_modified_outer_tess_level) 2593 { 2594 /* Only compare outer tessellation levels that have not been modified */ 2595 if (((n_modified_outer_tess_level == 0) || 2596 (n_modified_outer_tess_level != 0 && 2597 de::abs(test_iteration.outer_tess_levels[0] - outer_tess_levels[0]) < epsilon)) && 2598 ((n_modified_outer_tess_level == 1) || 2599 (n_modified_outer_tess_level != 1 && 2600 de::abs(test_iteration.outer_tess_levels[1] - outer_tess_levels[1]) < epsilon)) && 2601 ((n_modified_outer_tess_level == 2) || 2602 (n_modified_outer_tess_level != 2 && 2603 de::abs(test_iteration.outer_tess_levels[2] - outer_tess_levels[2]) < epsilon)) && 2604 ((n_modified_outer_tess_level == 3) || 2605 (n_modified_outer_tess_level != 3 && 2606 de::abs(test_iteration.outer_tess_levels[3] - outer_tess_levels[3]) < epsilon))) 2607 { 2608 result = n_test_iteration; 2609 2610 break; 2611 } 2612 } 2613 } /* for (all test iterations) */ 2614 2615 return result; 2616 } 2617 2618 /** Retrieves _test_iteration instance specific for user-specified iteration index. 2619 * 2620 * @param n_iteration Iteration index to retrieve _test_iteration instance for. 2621 * 2622 * @return Iteration-specific _test_iteration instance. 2623 * 2624 **/ 2625 TessellationShaderInvarianceRule7Test::_test_iteration& TessellationShaderInvarianceRule7Test::getTestForIteration( 2626 unsigned int n_iteration) 2627 { 2628 unsigned int n_triangles_tests = (unsigned int)m_test_triangles_iterations.size(); 2629 _test_iteration& test_iteration = (n_iteration < n_triangles_tests) ? 2630 m_test_triangles_iterations[n_iteration] : 2631 m_test_quads_iterations[n_iteration - n_triangles_tests]; 2632 2633 return test_iteration; 2634 } 2635 2636 /** Retrieves iteration-specific tessellation properties. 2637 * 2638 * @param n_iteration Iteration index to retrieve the properties for. 2639 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner 2640 * tessellation level values. Must not be NULL. 2641 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer 2642 * tessellation level values. Must not be NULL. 2643 * @param out_point_mode Deref will be used to store iteration-specific flag 2644 * telling whether point mode should be enabled for given pass. 2645 * Must not be NULL. 2646 * @param out_primitive_mode Deref will be used to store iteration-specific primitive 2647 * mode. Must not be NULL. 2648 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex 2649 * ordering. Must not be NULL. 2650 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object 2651 * storage should offer for the draw call to succeed. Can 2652 * be NULL. 2653 **/ 2654 void TessellationShaderInvarianceRule7Test::getIterationProperties( 2655 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode, 2656 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering, 2657 unsigned int* out_result_buffer_size) 2658 { 2659 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration); 2660 2661 _test_iteration& test_iteration = getTestForIteration(n_iteration); 2662 2663 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels)); 2664 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels)); 2665 2666 *out_point_mode = false; 2667 *out_primitive_mode = test_iteration.primitive_mode; 2668 *out_vertex_ordering = test_iteration.vertex_ordering; 2669 2670 if (out_result_buffer_size != DE_NULL) 2671 { 2672 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator( 2673 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 2674 *out_point_mode); 2675 test_iteration.n_vertices = *out_result_buffer_size; 2676 *out_result_buffer_size = 2677 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float)); 2678 2679 DE_ASSERT(*out_result_buffer_size != 0); 2680 } 2681 } 2682 2683 /** Retrieves iteration-specific tessellation evaluation shader code. 2684 * 2685 * @param n_iteration Iteration index, for which the source code is being obtained. 2686 * 2687 * @return Requested source code. 2688 **/ 2689 std::string TessellationShaderInvarianceRule7Test::getTECode(unsigned int n_iteration) 2690 { 2691 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration); 2692 2693 const _test_iteration& test_iteration = getTestForIteration(n_iteration); 2694 2695 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, 2696 test_iteration.primitive_mode, test_iteration.vertex_ordering, 2697 false); /* point mode */ 2698 } 2699 2700 /** Initializes test iterations for the test. The following modes and inner/outer tess level 2701 * configurations are used to form the test set: 2702 * 2703 * - All inner/outer tessellation level combinations as returned by 2704 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() 2705 * times 3 (for triangles) or 4 (for quads). For each combination, 2706 * the test will capture tessellation coordinates multiple times, each 2707 * time changing a different outer tessellation level value and leaving 2708 * the rest intact. 2709 * - All primitive modes; 2710 * - All vertex spacing modes; 2711 * 2712 * All permutations are used to generate the test set. 2713 **/ 2714 void TessellationShaderInvarianceRule7Test::initTestIterations() 2715 { 2716 DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0); 2717 2718 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ 2719 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2720 glw::GLint gl_max_tess_gen_level_value = 0; 2721 2722 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); 2723 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); 2724 2725 /* Iterate through all primitive and vertex spacing modes relevant to the test */ 2726 _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, 2727 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES }; 2728 _tessellation_shader_vertex_ordering vo_modes[] = { 2729 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, TESSELLATION_SHADER_VERTEX_ORDERING_CW, 2730 }; 2731 2732 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]); 2733 const unsigned int n_vo_modes = sizeof(vo_modes) / sizeof(vo_modes[0]); 2734 2735 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode) 2736 { 2737 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode]; 2738 const unsigned int n_relevant_outer_tess_levels = 2739 (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 4 : 3; 2740 2741 for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode) 2742 { 2743 _tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode]; 2744 2745 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */ 2746 _tessellation_levels_set levels_set; 2747 2748 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode( 2749 primitive_mode, gl_max_tess_gen_level_value, 2750 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE); 2751 2752 /* Create test descriptor for all inner/outer level configurations we received from the utils function. */ 2753 for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin(); 2754 levels_set_iterator != levels_set.end(); levels_set_iterator++) 2755 { 2756 const _tessellation_levels& levels = *levels_set_iterator; 2757 2758 for (unsigned int n_outer_level_to_change = 0; 2759 n_outer_level_to_change < n_relevant_outer_tess_levels + 1 /* base iteration */; 2760 ++n_outer_level_to_change) 2761 { 2762 /* Create a test descriptor for all the parameters we now have */ 2763 _test_iteration test; 2764 2765 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels)); 2766 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels)); 2767 2768 test.primitive_mode = primitive_mode; 2769 test.vertex_ordering = vertex_ordering; 2770 2771 /* Change iteration-specific outer tessellation level to a different value, but only 2772 * if we're not preparing a base iteration*/ 2773 if (n_outer_level_to_change != n_relevant_outer_tess_levels) 2774 { 2775 test.n_modified_outer_tess_level = n_outer_level_to_change; 2776 test.outer_tess_levels[n_outer_level_to_change] = (float)(gl_max_tess_gen_level_value) / 3.0f; 2777 } 2778 else 2779 { 2780 test.is_base_iteration = true; 2781 } 2782 2783 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) 2784 { 2785 m_test_triangles_iterations.push_back(test); 2786 } 2787 else 2788 { 2789 m_test_quads_iterations.push_back(test); 2790 } 2791 } 2792 } /* for (all levels set entries) */ 2793 } /* for (all vertex spacing modes) */ 2794 } /* for (all primitive modes) */ 2795 } 2796 2797 /** Tells whether a triangle is included in user-provided set of triangles. 2798 * The triangle is expected to use an undefined vertex ordering. 2799 * 2800 * @param base_triangle_data 9 FP values defining 3 vertices of a triangle. 2801 * @param vertex_data Vertex stream. It is expected these vertices 2802 * form triangles. It is also assumed each vertex 2803 * is expressed with 3 components. 2804 * @param vertex_data_n_vertices Amount of vertices that can be found in @param 2805 * vertex_data 2806 * 2807 * @return true if the triangle was found in user-provided triangle set, 2808 * false otherwise. 2809 * 2810 **/ 2811 bool TessellationShaderInvarianceRule7Test::isTriangleDefinedInVertexDataSet(const float* base_triangle_data, 2812 const float* vertex_data, 2813 unsigned int vertex_data_n_vertices) 2814 { 2815 bool result = false; 2816 2817 for (unsigned int n_triangle = 0; n_triangle < vertex_data_n_vertices / 3 /* vertices per triangle */; n_triangle++) 2818 { 2819 const float* current_triangle_data = vertex_data + 2820 n_triangle * 3 * /* vertices per triangle */ 2821 3; /* components */ 2822 2823 if (TessellationShaderUtils::isTriangleDefined(current_triangle_data, base_triangle_data)) 2824 { 2825 result = true; 2826 2827 break; 2828 } 2829 } /* for (all vertices) */ 2830 2831 return result; 2832 } 2833 2834 /** Verifies result data. Accesses data generated by all iterations. 2835 * 2836 * Throws TestError exception if an error occurs. 2837 * 2838 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord 2839 * data generated by subsequent iterations. 2840 **/ 2841 void TessellationShaderInvarianceRule7Test::verifyResultData(const void** all_iterations_data) 2842 { 2843 const float epsilon = 1e-5f; 2844 2845 /* Run two separate iterations: 2846 * 2847 * a) triangles 2848 * b) quads 2849 */ 2850 for (unsigned int n_iteration = 0; n_iteration < 2 /* triangles, quads */; ++n_iteration) 2851 { 2852 bool is_triangles_iteration = (n_iteration == 0); 2853 const unsigned int n_base_iteration = 2854 (n_iteration == 0) ? 0 : (const unsigned int)m_test_triangles_iterations.size(); 2855 const unsigned int n_relevant_outer_tess_levels = (is_triangles_iteration) ? 3 : 4; 2856 2857 _tessellation_primitive_mode primitive_mode = (n_iteration == 0) ? 2858 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES : 2859 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS; 2860 2861 const _test_iterations& test_iterations = 2862 (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations; 2863 2864 DE_ASSERT(test_iterations.size() != 0); 2865 2866 /* Find a base iteration first */ 2867 for (unsigned int n_base_test_iteration = 0; n_base_test_iteration < test_iterations.size(); 2868 n_base_test_iteration++) 2869 { 2870 const _test_iteration& base_iteration = test_iterations[n_base_test_iteration]; 2871 std::vector<int> ref_iteration_indices; 2872 2873 if (!base_iteration.is_base_iteration) 2874 { 2875 continue; 2876 } 2877 2878 /* Retrieve reference test iterations */ 2879 for (unsigned int n_reference_iteration = 0; n_reference_iteration < n_relevant_outer_tess_levels; 2880 ++n_reference_iteration) 2881 { 2882 const unsigned int n_modified_outer_tess_level = 2883 (base_iteration.n_modified_outer_tess_level + n_reference_iteration + 1) % 2884 n_relevant_outer_tess_levels; 2885 const unsigned int ref_iteration_index = getTestIterationIndex( 2886 is_triangles_iteration, base_iteration.inner_tess_levels, base_iteration.outer_tess_levels, 2887 base_iteration.vertex_ordering, n_modified_outer_tess_level); 2888 2889 DE_ASSERT(ref_iteration_index != 0xFFFFFFFF); 2890 DE_ASSERT(ref_iteration_index != n_base_test_iteration); 2891 2892 ref_iteration_indices.push_back(ref_iteration_index); 2893 } 2894 2895 /* We can now start comparing base data with the information generated for 2896 * reference iterations. */ 2897 for (std::vector<int>::const_iterator ref_iteration_iterator = ref_iteration_indices.begin(); 2898 ref_iteration_iterator != ref_iteration_indices.end(); ref_iteration_iterator++) 2899 { 2900 const int& n_ref_test_iteration = *ref_iteration_iterator; 2901 const _test_iteration& ref_iteration = test_iterations[n_ref_test_iteration]; 2902 2903 /* Now move through all triangles generated for base test iteration. Focus on the ones 2904 * that connect the outer edge with one of the inner ones */ 2905 const float* base_iteration_vertex_data = 2906 (const float*)all_iterations_data[n_base_iteration + n_base_test_iteration]; 2907 const float* ref_iteration_vertex_data = 2908 (const float*)all_iterations_data[n_base_iteration + n_ref_test_iteration]; 2909 2910 for (unsigned int n_base_triangle = 0; 2911 n_base_triangle < base_iteration.n_vertices / 3; /* vertices per triangle */ 2912 ++n_base_triangle) 2913 { 2914 const float* base_triangle_data = 2915 base_iteration_vertex_data + n_base_triangle * 3 /* vertices */ * 3; /* components */ 2916 2917 /* Is that the triangle type we're after? */ 2918 const float* base_triangle_vertex1 = base_triangle_data; 2919 const float* base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */ 2920 const float* base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */ 2921 bool is_base_triangle_vertex1_outer = 2922 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1); 2923 bool is_base_triangle_vertex2_outer = 2924 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2); 2925 bool is_base_triangle_vertex3_outer = 2926 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3); 2927 unsigned int n_outer_edge_vertices_found = 0; 2928 2929 n_outer_edge_vertices_found += (is_base_triangle_vertex1_outer == true); 2930 n_outer_edge_vertices_found += (is_base_triangle_vertex2_outer == true); 2931 n_outer_edge_vertices_found += (is_base_triangle_vertex3_outer == true); 2932 2933 if (n_outer_edge_vertices_found == 0) 2934 { 2935 /* This is an inner triangle, not really of our interest */ 2936 continue; 2937 } 2938 2939 /* Which outer tessellation level describes the base data edge? */ 2940 unsigned int n_base_tess_level = 0; 2941 2942 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) 2943 { 2944 if ((!is_base_triangle_vertex1_outer || 2945 (is_base_triangle_vertex1_outer && base_triangle_vertex1[0] == 0.0f)) && 2946 (!is_base_triangle_vertex2_outer || 2947 (is_base_triangle_vertex2_outer && base_triangle_vertex2[0] == 0.0f)) && 2948 (!is_base_triangle_vertex3_outer || 2949 (is_base_triangle_vertex3_outer && base_triangle_vertex3[0] == 0.0f))) 2950 { 2951 n_base_tess_level = 0; 2952 } 2953 else if ((!is_base_triangle_vertex1_outer || 2954 (is_base_triangle_vertex1_outer && base_triangle_vertex1[1] == 0.0f)) && 2955 (!is_base_triangle_vertex2_outer || 2956 (is_base_triangle_vertex2_outer && base_triangle_vertex2[1] == 0.0f)) && 2957 (!is_base_triangle_vertex3_outer || 2958 (is_base_triangle_vertex3_outer && base_triangle_vertex3[1] == 0.0f))) 2959 { 2960 n_base_tess_level = 1; 2961 } 2962 else 2963 { 2964 DE_ASSERT((!is_base_triangle_vertex1_outer || 2965 (is_base_triangle_vertex1_outer && base_triangle_vertex1[2] == 0.0f)) && 2966 (!is_base_triangle_vertex2_outer || 2967 (is_base_triangle_vertex2_outer && base_triangle_vertex2[2] == 0.0f)) && 2968 (!is_base_triangle_vertex3_outer || 2969 (is_base_triangle_vertex3_outer && base_triangle_vertex3[2] == 0.0f))); 2970 2971 n_base_tess_level = 2; 2972 } 2973 } /* if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) */ 2974 else 2975 { 2976 DE_ASSERT(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS); 2977 2978 std::size_t n_outer_edge_vertices = 0; 2979 std::vector<const float*> outer_edge_vertices; 2980 2981 if (is_base_triangle_vertex1_outer) 2982 { 2983 outer_edge_vertices.push_back(base_triangle_vertex1); 2984 } 2985 2986 if (is_base_triangle_vertex2_outer) 2987 { 2988 outer_edge_vertices.push_back(base_triangle_vertex2); 2989 } 2990 2991 if (is_base_triangle_vertex3_outer) 2992 { 2993 outer_edge_vertices.push_back(base_triangle_vertex3); 2994 } 2995 2996 n_outer_edge_vertices = outer_edge_vertices.size(); 2997 2998 DE_ASSERT(n_outer_edge_vertices >= 1 && n_outer_edge_vertices <= 2); 2999 3000 bool is_top_outer_edge = true; 3001 bool is_right_outer_edge = true; 3002 bool is_bottom_outer_edge = true; 3003 bool is_left_outer_edge = true; 3004 3005 /* Find which outer edges the vertices don't belong to. If one is in a corner, 3006 * the other will clarify to which edge both vertices belong. */ 3007 for (unsigned int n_vertex = 0; n_vertex < n_outer_edge_vertices; ++n_vertex) 3008 { 3009 /* Y < 1, not top outer edge */ 3010 if (de::abs(outer_edge_vertices[n_vertex][1] - 1.0f) > epsilon) 3011 { 3012 is_top_outer_edge = false; 3013 } 3014 3015 /* X < 1, not right outer edge */ 3016 if (de::abs(outer_edge_vertices[n_vertex][0] - 1.0f) > epsilon) 3017 { 3018 is_right_outer_edge = false; 3019 } 3020 3021 /* Y > 0, not bottom outer edge */ 3022 if (de::abs(outer_edge_vertices[n_vertex][1]) > epsilon) 3023 { 3024 is_bottom_outer_edge = false; 3025 } 3026 3027 /* X > 0, not left outer edge */ 3028 if (de::abs(outer_edge_vertices[n_vertex][0]) > epsilon) 3029 { 3030 is_left_outer_edge = false; 3031 } 3032 } 3033 3034 if (n_outer_edge_vertices == 1) 3035 { 3036 /* A single vertex with corner-coordinates belongs to two edges. Choose one */ 3037 bool x_is_0 = de::abs(outer_edge_vertices[0][0]) < epsilon; 3038 bool x_is_1 = de::abs(outer_edge_vertices[0][0] - 1.0f) < epsilon; 3039 bool y_is_0 = de::abs(outer_edge_vertices[0][1]) < epsilon; 3040 bool y_is_1 = de::abs(outer_edge_vertices[0][1] - 1.0f) < epsilon; 3041 3042 if (x_is_0 && y_is_0) 3043 { 3044 /* bottom edge */ 3045 DE_ASSERT(is_left_outer_edge && is_bottom_outer_edge); 3046 is_left_outer_edge = false; 3047 } 3048 else if (x_is_0 && y_is_1) 3049 { 3050 /* left edge */ 3051 DE_ASSERT(is_left_outer_edge && is_top_outer_edge); 3052 is_top_outer_edge = false; 3053 } 3054 else if (x_is_1 && y_is_0) 3055 { 3056 /* right edge */ 3057 DE_ASSERT(is_right_outer_edge && is_bottom_outer_edge); 3058 is_bottom_outer_edge = false; 3059 } 3060 else if (x_is_1 && y_is_1) 3061 { 3062 /* top edge */ 3063 DE_ASSERT(is_right_outer_edge && is_top_outer_edge); 3064 is_right_outer_edge = false; 3065 } 3066 else 3067 { 3068 /* Not a corner vertex, only one of the edge-flags is set */ 3069 } 3070 } 3071 3072 /* Sanity checks */ 3073 DE_UNREF(is_top_outer_edge); 3074 DE_ASSERT((is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge && 3075 !is_right_outer_edge) || 3076 (!is_left_outer_edge && is_top_outer_edge && !is_bottom_outer_edge && 3077 !is_right_outer_edge) || 3078 (!is_left_outer_edge && !is_top_outer_edge && is_bottom_outer_edge && 3079 !is_right_outer_edge) || 3080 (!is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge && 3081 is_right_outer_edge)); 3082 3083 /* We have all the data needed to determine which tessellation level describes 3084 * subdivision of the edge that the triangle touches */ 3085 if (is_left_outer_edge) 3086 { 3087 n_base_tess_level = 0; 3088 } 3089 else if (is_bottom_outer_edge) 3090 { 3091 n_base_tess_level = 1; 3092 } 3093 else if (is_right_outer_edge) 3094 { 3095 n_base_tess_level = 2; 3096 } 3097 else 3098 { 3099 n_base_tess_level = 3; 3100 } 3101 } 3102 3103 /* We shouldn't perform the check if the edge we're processing was described 3104 * by a different outer tessellation level in the reference data set */ 3105 if (n_base_tess_level == ref_iteration.n_modified_outer_tess_level) 3106 { 3107 continue; 3108 } 3109 3110 /* This triangle should be present in both vertex data sets */ 3111 if (!isTriangleDefinedInVertexDataSet(base_triangle_data, ref_iteration_vertex_data, 3112 ref_iteration.n_vertices)) 3113 { 3114 const char* primitive_mode_str = (is_triangles_iteration) ? "triangles" : "quads"; 3115 3116 m_testCtx.getLog() 3117 << tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "] " 3118 << ", inner tessellation levels:" 3119 << "[" << base_iteration.inner_tess_levels[0] << ", " << base_iteration.inner_tess_levels[1] 3120 << "], outer tessellation levels:" 3121 << "[" << base_iteration.outer_tess_levels[0] << ", " << base_iteration.outer_tess_levels[1] 3122 << ", " << base_iteration.outer_tess_levels[2] << ", " 3123 << base_iteration.outer_tess_levels[3] << "], a triangle connecting inner & outer edges:" 3124 << "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", " 3125 << base_triangle_vertex1[2] << "]x" 3126 << "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", " 3127 << base_triangle_vertex2[2] << "]x" 3128 << "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", " 3129 << base_triangle_vertex3[2] << "] was not found for runs using CW and CCW vertex ordering, " 3130 "which is against the extension specification's rule 7." 3131 << tcu::TestLog::EndMessage; 3132 3133 TCU_FAIL("Implementation is not conformant with Tessellation Rule 7"); 3134 } 3135 } /* for (all triangles generated for base test iteration) */ 3136 } /* for (all reference iterations) */ 3137 } /* for (all base test iterations) */ 3138 } /* for (both primitive types) */ 3139 } 3140 3141 } /* namespace glcts */ 3142