1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 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 Primitive restart tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fPrimitiveRestartTests.hpp" 25 #include "gluShaderProgram.hpp" 26 #include "gluPixelTransfer.hpp" 27 #include "tcuTestLog.hpp" 28 #include "tcuSurface.hpp" 29 #include "tcuImageCompare.hpp" 30 #include "tcuRenderTarget.hpp" 31 #include "deRandom.hpp" 32 #include "deMath.h" 33 #include "deString.h" 34 35 #include "glw.h" 36 37 using tcu::Vec4; 38 39 namespace deqp 40 { 41 namespace gles3 42 { 43 namespace Functional 44 { 45 46 static const int MAX_RENDER_WIDTH = 256; 47 static const int MAX_RENDER_HEIGHT = 256; 48 49 static const deUint32 MAX_UNSIGNED_BYTE = (1<<8) - 1; 50 static const deUint32 MAX_UNSIGNED_SHORT = (1<<16) - 1; 51 static const deUint32 MAX_UNSIGNED_INT = (deUint32)((1ULL << 32) - 1); 52 53 static const deUint8 RESTART_INDEX_UNSIGNED_BYTE = (deUint8)MAX_UNSIGNED_BYTE; 54 static const deUint16 RESTART_INDEX_UNSIGNED_SHORT = (deUint16)MAX_UNSIGNED_SHORT; 55 static const deUint32 RESTART_INDEX_UNSIGNED_INT = MAX_UNSIGNED_INT; 56 57 class PrimitiveRestartCase : public TestCase 58 { 59 public: 60 enum PrimitiveType 61 { 62 PRIMITIVE_POINTS = 0, 63 PRIMITIVE_LINE_STRIP, 64 PRIMITIVE_LINE_LOOP, 65 PRIMITIVE_LINES, 66 PRIMITIVE_TRIANGLE_STRIP, 67 PRIMITIVE_TRIANGLE_FAN, 68 PRIMITIVE_TRIANGLES, 69 70 PRIMITIVE_LAST 71 }; 72 73 enum IndexType 74 { 75 INDEX_UNSIGNED_BYTE = 0, 76 INDEX_UNSIGNED_SHORT, 77 INDEX_UNSIGNED_INT, 78 79 INDEX_LAST 80 }; 81 82 enum Function 83 { 84 FUNCTION_DRAW_ELEMENTS = 0, 85 FUNCTION_DRAW_ELEMENTS_INSTANCED, 86 FUNCTION_DRAW_RANGE_ELEMENTS, 87 88 FUNCTION_LAST 89 }; 90 91 PrimitiveRestartCase (Context& context, const char* name, const char* description, PrimitiveType primType, IndexType indexType, Function function, bool beginWithRestart, bool endWithRestart, bool duplicateRestarts); 92 ~PrimitiveRestartCase (void); 93 94 void init (void); 95 void deinit (void); 96 IterateResult iterate (void); 97 98 private: 99 PrimitiveRestartCase (const PrimitiveRestartCase& other); 100 PrimitiveRestartCase& operator= (const PrimitiveRestartCase& other); 101 102 void draw (int startNdx, int count); 103 104 void renderWithRestart (void); 105 void renderWithoutRestart (void); 106 107 // Helper functions for handling the appropriate index vector (according to m_indexType). 108 void addIndex (deUint32 index); 109 deUint32 getIndex (int indexNdx); 110 int getNumIndices (void); 111 void* getIndexPtr (int indexNdx); 112 113 // \note Only one of the following index vectors is used (according to m_indexType). 114 std::vector<deUint8> m_indicesUB; 115 std::vector<deUint16> m_indicesUS; 116 std::vector<deUint32> m_indicesUI; 117 118 std::vector<float> m_positions; 119 120 PrimitiveType m_primType; 121 IndexType m_indexType; 122 Function m_function; 123 124 bool m_beginWithRestart; // Whether there will be restart indices at the beginning of the index array. 125 bool m_endWithRestart; // Whether there will be restart indices at the end of the index array. 126 bool m_duplicateRestarts; // Whether two consecutive restarts are used instead of one. 127 128 glu::ShaderProgram* m_program; 129 }; 130 131 PrimitiveRestartCase::PrimitiveRestartCase (Context& context, const char* name, const char* description, PrimitiveType primType, IndexType indexType, Function function, bool beginWithRestart, bool endWithRestart, bool duplicateRestarts) 132 : TestCase (context, name, description) 133 , m_primType (primType) 134 , m_indexType (indexType) 135 , m_function (function) 136 , m_beginWithRestart (beginWithRestart) 137 , m_endWithRestart (endWithRestart) 138 , m_duplicateRestarts (duplicateRestarts) 139 , m_program (DE_NULL) 140 { 141 } 142 143 PrimitiveRestartCase::~PrimitiveRestartCase (void) 144 { 145 PrimitiveRestartCase::deinit(); 146 } 147 148 void PrimitiveRestartCase::deinit (void) 149 { 150 delete m_program; 151 m_program = DE_NULL; 152 } 153 154 void PrimitiveRestartCase::addIndex (deUint32 index) 155 { 156 if (m_indexType == INDEX_UNSIGNED_BYTE) 157 { 158 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_BYTE)); 159 m_indicesUB.push_back((deUint8)index); 160 } 161 else if (m_indexType == INDEX_UNSIGNED_SHORT) 162 { 163 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_SHORT)); 164 m_indicesUS.push_back((deUint16)index); 165 } 166 else if (m_indexType == INDEX_UNSIGNED_INT) 167 { 168 DE_ASSERT(de::inRange(index, (deUint32)0, MAX_UNSIGNED_INT)); 169 m_indicesUI.push_back((deUint32)index); 170 } 171 else 172 DE_ASSERT(DE_FALSE); 173 } 174 175 deUint32 PrimitiveRestartCase::getIndex (int indexNdx) 176 { 177 switch (m_indexType) 178 { 179 case INDEX_UNSIGNED_BYTE: return (deUint32)m_indicesUB[indexNdx]; 180 case INDEX_UNSIGNED_SHORT: return (deUint32)m_indicesUS[indexNdx]; 181 case INDEX_UNSIGNED_INT: return m_indicesUI[indexNdx]; 182 default: 183 DE_ASSERT(DE_FALSE); 184 return 0; 185 } 186 } 187 188 int PrimitiveRestartCase::getNumIndices (void) 189 { 190 switch (m_indexType) 191 { 192 case INDEX_UNSIGNED_BYTE: return (int)m_indicesUB.size(); 193 case INDEX_UNSIGNED_SHORT: return (int)m_indicesUS.size(); 194 case INDEX_UNSIGNED_INT: return (int)m_indicesUI.size(); 195 default: 196 DE_ASSERT(DE_FALSE); 197 return 0; 198 } 199 } 200 201 // Pointer to the index value at index indexNdx. 202 void* PrimitiveRestartCase::getIndexPtr (int indexNdx) 203 { 204 switch (m_indexType) 205 { 206 case INDEX_UNSIGNED_BYTE: return (void*)&m_indicesUB[indexNdx]; 207 case INDEX_UNSIGNED_SHORT: return (void*)&m_indicesUS[indexNdx]; 208 case INDEX_UNSIGNED_INT: return (void*)&m_indicesUI[indexNdx]; 209 default: 210 DE_ASSERT(DE_FALSE); 211 return DE_NULL; 212 } 213 } 214 215 void PrimitiveRestartCase::init (void) 216 { 217 // Create shader program. 218 219 static const char* vertShaderSource = 220 "#version 300 es\n" 221 "in highp vec4 a_position;\n" 222 "\n" 223 "void main()\n" 224 "{\n" 225 " gl_Position = a_position;\n" 226 "}\n"; 227 228 static const char* fragShaderSource = 229 "#version 300 es\n" 230 "layout(location = 0) out mediump vec4 o_color;\n" 231 "\n" 232 "void main()\n" 233 "{\n" 234 " o_color = vec4(1.0f);\n" 235 "}\n"; 236 237 DE_ASSERT(!m_program); 238 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSource, fragShaderSource)); 239 240 if(!m_program->isOk()) 241 { 242 m_testCtx.getLog() << *m_program; 243 TCU_FAIL("Failed to compile shader"); 244 } 245 246 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE 247 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT 248 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT 249 : 0; 250 251 DE_ASSERT(restartIndex != 0); 252 253 DE_ASSERT(getNumIndices() == 0); 254 255 // If testing a case with restart at beginning, add it there. 256 if (m_beginWithRestart) 257 { 258 addIndex(restartIndex); 259 if (m_duplicateRestarts) 260 addIndex(restartIndex); 261 } 262 263 // Generate vertex positions and indices depending on primitive type. 264 // \note At this point, restarts shall not be added to the start or the end of the index vector. Those are special cases, and are done above and after the following if-else chain, respectively. 265 266 if (m_primType == PRIMITIVE_POINTS) 267 { 268 // Generate rows with different numbers of points. 269 270 deUint32 curIndex = 0; 271 const int numRows = 20; 272 273 for (int row = 0; row < numRows; row++) 274 { 275 for (int col = 0; col < row + 1; col++) 276 { 277 float fx = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numRows; 278 float fy = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows; 279 280 m_positions.push_back(fx); 281 m_positions.push_back(fy); 282 283 addIndex(curIndex++); 284 } 285 286 if (row < numRows - 1) // Add a restart after all but last row. 287 { 288 addIndex(restartIndex); 289 if (m_duplicateRestarts) 290 addIndex(restartIndex); 291 } 292 } 293 } 294 else if (m_primType == PRIMITIVE_LINE_STRIP || m_primType == PRIMITIVE_LINE_LOOP || m_primType == PRIMITIVE_LINES) 295 { 296 // Generate a numRows x numCols arrangement of line polygons of different vertex counts. 297 298 deUint32 curIndex = 0; 299 const int numRows = 4; 300 const int numCols = 4; 301 302 for (int row = 0; row < numRows; row++) 303 { 304 float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows; 305 306 for (int col = 0; col < numCols; col++) 307 { 308 float centerX = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols; 309 int numVertices = row*numCols + col + 1; 310 311 for (int i = 0; i < numVertices; i++) 312 { 313 float fx = centerX + 0.9f * deFloatCos((float)i*2.0f*DE_PI / (float)numVertices) / (float)numCols; 314 float fy = centerY + 0.9f * deFloatSin((float)i*2.0f*DE_PI / (float)numVertices) / (float)numRows; 315 316 m_positions.push_back(fx); 317 m_positions.push_back(fy); 318 319 addIndex(curIndex++); 320 } 321 322 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon. 323 { 324 addIndex(restartIndex); 325 if (m_duplicateRestarts) 326 addIndex(restartIndex); 327 } 328 } 329 } 330 } 331 else if (m_primType == PRIMITIVE_TRIANGLE_STRIP) 332 { 333 // Generate a number of horizontal triangle strips of different lengths. 334 335 deUint32 curIndex = 0; 336 const int numStrips = 20; 337 338 for (int stripNdx = 0; stripNdx < numStrips; stripNdx++) 339 { 340 int numVertices = stripNdx + 1; 341 342 for (int i = 0; i < numVertices; i++) 343 { 344 float fx = -0.9f + 1.8f * (float)(i/2*2) / numStrips; 345 float fy = -0.9f + 1.8f * ((float)stripNdx + (i%2 == 0 ? 0.0f : 0.8f)) / numStrips; 346 347 m_positions.push_back(fx); 348 m_positions.push_back(fy); 349 350 addIndex(curIndex++); 351 } 352 353 if (stripNdx < numStrips - 1) // Add a restart after all but last strip. 354 { 355 addIndex(restartIndex); 356 if (m_duplicateRestarts) 357 addIndex(restartIndex); 358 } 359 } 360 } 361 else if (m_primType == PRIMITIVE_TRIANGLE_FAN) 362 { 363 // Generate a numRows x numCols arrangement of triangle fan polygons of different vertex counts. 364 365 deUint32 curIndex = 0; 366 const int numRows = 4; 367 const int numCols = 4; 368 369 for (int row = 0; row < numRows; row++) 370 { 371 float centerY = -1.0f + 2.0f * ((float)row + 0.5f) / (float)numRows; 372 373 for (int col = 0; col < numCols; col++) 374 { 375 float centerX = -1.0f + 2.0f * ((float)col + 0.5f) / (float)numCols; 376 int numArcVertices = row*numCols + col; 377 378 m_positions.push_back(centerX); 379 m_positions.push_back(centerY); 380 381 addIndex(curIndex++); 382 383 for (int i = 0; i < numArcVertices; i++) 384 { 385 float fx = centerX + 0.9f * deFloatCos((float)i*2.0f*DE_PI / (float)numArcVertices) / (float)numCols; 386 float fy = centerY + 0.9f * deFloatSin((float)i*2.0f*DE_PI / (float)numArcVertices) / (float)numRows; 387 388 m_positions.push_back(fx); 389 m_positions.push_back(fy); 390 391 addIndex(curIndex++); 392 } 393 394 if (col < numCols - 1 || row < numRows - 1) // Add a restart after all but last polygon. 395 { 396 addIndex(restartIndex); 397 if (m_duplicateRestarts) 398 addIndex(restartIndex); 399 } 400 } 401 } 402 } 403 else if (m_primType == PRIMITIVE_TRIANGLES) 404 { 405 // Generate a number of rows with (potentially incomplete) triangles. 406 407 deUint32 curIndex = 0; 408 const int numRows = 3*7; 409 410 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 411 { 412 int numVertices = rowNdx + 1; 413 414 for (int i = 0; i < numVertices; i++) 415 { 416 float fx = -0.9f + 1.8f * ((float)(i/3) + (i%3 == 2 ? 0.8f : 0.0f)) * 3 / numRows; 417 float fy = -0.9f + 1.8f * ((float)rowNdx + (i%3 == 0 ? 0.0f : 0.8f)) / numRows; 418 419 m_positions.push_back(fx); 420 m_positions.push_back(fy); 421 422 addIndex(curIndex++); 423 } 424 425 if (rowNdx < numRows - 1) // Add a restart after all but last row. 426 { 427 addIndex(restartIndex); 428 if (m_duplicateRestarts) 429 addIndex(restartIndex); 430 } 431 } 432 } 433 else 434 DE_ASSERT(DE_FALSE); 435 436 // If testing a case with restart at end, add it there. 437 if (m_endWithRestart) 438 { 439 addIndex(restartIndex); 440 if (m_duplicateRestarts) 441 addIndex(restartIndex); 442 } 443 444 // Special case assertions. 445 446 int numIndices = getNumIndices(); 447 448 DE_ASSERT(numIndices > 0); 449 DE_ASSERT(m_beginWithRestart || getIndex(0) != restartIndex); // We don't want restarts at beginning unless the case is a special case. 450 DE_ASSERT(m_endWithRestart || getIndex(numIndices-1) != restartIndex); // We don't want restarts at end unless the case is a special case. 451 452 if (!m_duplicateRestarts) 453 for (int i = 1; i < numIndices; i++) 454 DE_ASSERT(getIndex(i) != restartIndex || getIndex(i-1) != restartIndex); // We don't want duplicate restarts unless the case is a special case. 455 } 456 457 PrimitiveRestartCase::IterateResult PrimitiveRestartCase::iterate (void) 458 { 459 int width = deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH); 460 int height = deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT); 461 462 int xOffsetMax = m_context.getRenderTarget().getWidth() - width; 463 int yOffsetMax = m_context.getRenderTarget().getHeight() - height; 464 465 de::Random rnd (deStringHash(getName())); 466 467 int xOffset = rnd.getInt(0, xOffsetMax); 468 int yOffset = rnd.getInt(0, yOffsetMax); 469 tcu::Surface referenceImg (width, height); 470 tcu::Surface resultImg (width, height); 471 472 glViewport(xOffset, yOffset, width, height); 473 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 474 475 deUint32 program = m_program->getProgram(); 476 glUseProgram(program); 477 478 // Setup position attribute. 479 480 int loc = glGetAttribLocation(program, "a_position"); 481 glEnableVertexAttribArray(loc); 482 glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, &m_positions[0]); 483 484 // Render result. 485 486 renderWithRestart(); 487 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, resultImg.getAccess()); 488 489 // Render reference (same scene as the real deal, but emulate primitive restart without actually using it). 490 491 renderWithoutRestart(); 492 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, referenceImg.getAccess()); 493 494 // Compare. 495 496 bool testOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", referenceImg, resultImg, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT); 497 498 m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 499 testOk ? "Pass" : "Fail"); 500 501 glUseProgram(0); 502 503 return STOP; 504 } 505 506 // Draw with the appropriate GLES3 draw function. 507 void PrimitiveRestartCase::draw (int startNdx, int count) 508 { 509 GLenum primTypeGL; 510 511 switch (m_primType) 512 { 513 case PRIMITIVE_POINTS: primTypeGL = GL_POINTS; break; 514 case PRIMITIVE_LINE_STRIP: primTypeGL = GL_LINE_STRIP; break; 515 case PRIMITIVE_LINE_LOOP: primTypeGL = GL_LINE_LOOP; break; 516 case PRIMITIVE_LINES: primTypeGL = GL_LINES; break; 517 case PRIMITIVE_TRIANGLE_STRIP: primTypeGL = GL_TRIANGLE_STRIP; break; 518 case PRIMITIVE_TRIANGLE_FAN: primTypeGL = GL_TRIANGLE_FAN; break; 519 case PRIMITIVE_TRIANGLES: primTypeGL = GL_TRIANGLES; break; 520 default: 521 DE_ASSERT(DE_FALSE); 522 primTypeGL = 0; 523 } 524 525 GLenum indexTypeGL; 526 527 switch (m_indexType) 528 { 529 case INDEX_UNSIGNED_BYTE: indexTypeGL = GL_UNSIGNED_BYTE; break; 530 case INDEX_UNSIGNED_SHORT: indexTypeGL = GL_UNSIGNED_SHORT; break; 531 case INDEX_UNSIGNED_INT: indexTypeGL = GL_UNSIGNED_INT; break; 532 default: 533 DE_ASSERT(DE_FALSE); 534 indexTypeGL = 0; 535 } 536 537 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE 538 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT 539 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT 540 : 0; 541 542 DE_ASSERT(restartIndex != 0); 543 544 if (m_function == FUNCTION_DRAW_ELEMENTS) 545 glDrawElements(primTypeGL, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx)); 546 else if (m_function == FUNCTION_DRAW_ELEMENTS_INSTANCED) 547 glDrawElementsInstanced(primTypeGL, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx), 1); 548 else 549 { 550 DE_ASSERT(m_function == FUNCTION_DRAW_RANGE_ELEMENTS); 551 552 // Find the largest non-restart index in the index array (for glDrawRangeElements() end parameter). 553 554 deUint32 max = 0; 555 556 int numIndices = getNumIndices(); 557 for (int i = 0; i < numIndices; i++) 558 { 559 deUint32 index = getIndex(i); 560 if (index != restartIndex && index > max) 561 max = index; 562 } 563 564 glDrawRangeElements(primTypeGL, 0, (GLuint)max, (GLsizei)count, indexTypeGL, (GLvoid*)getIndexPtr(startNdx)); 565 } 566 } 567 568 void PrimitiveRestartCase::renderWithRestart (void) 569 { 570 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() begin"); 571 572 glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); 573 GLU_CHECK_MSG("Enable primitive restart"); 574 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 575 GLU_CHECK_MSG("Clear in PrimitiveRestartCase::renderWithRestart()"); 576 577 draw(0, getNumIndices()); 578 579 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithRestart()"); 580 581 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithRestart() end"); 582 } 583 584 void PrimitiveRestartCase::renderWithoutRestart (void) 585 { 586 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() begin"); 587 588 deUint32 restartIndex = m_indexType == INDEX_UNSIGNED_BYTE ? RESTART_INDEX_UNSIGNED_BYTE 589 : m_indexType == INDEX_UNSIGNED_SHORT ? RESTART_INDEX_UNSIGNED_SHORT 590 : m_indexType == INDEX_UNSIGNED_INT ? RESTART_INDEX_UNSIGNED_INT 591 : 0; 592 593 DE_ASSERT(restartIndex != 0); 594 595 glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX); 596 GLU_CHECK_MSG("Disable primitive restart"); 597 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 598 GLU_CHECK_MSG("Clear in PrimitiveRestartCase::renderWithoutRestart()"); 599 600 // Draw, emulating primitive restart. 601 602 int numIndices = getNumIndices(); 603 604 DE_ASSERT(numIndices >= 0); 605 606 int indexArrayStartNdx = 0; // Keep track of the draw start index - first index after a primitive restart, or initially the first index altogether. 607 608 for (int indexArrayNdx = 0; indexArrayNdx <= numIndices; indexArrayNdx++) // \note Goes one "too far" in order to detect end of array as well. 609 { 610 if (indexArrayNdx >= numIndices || getIndex(indexArrayNdx) == restartIndex) // \note Handle end of array the same way as a restart index encounter. 611 { 612 if (indexArrayStartNdx < numIndices) 613 { 614 // Draw from index indexArrayStartNdx to index indexArrayNdx-1 . 615 616 draw(indexArrayStartNdx, indexArrayNdx - indexArrayStartNdx); 617 GLU_CHECK_MSG("Draw in PrimitiveRestartCase::renderWithoutRestart()"); 618 } 619 620 indexArrayStartNdx = indexArrayNdx + 1; // Next draw starts just after this restart index. 621 } 622 } 623 624 GLU_CHECK_MSG("PrimitiveRestartCase::renderWithoutRestart() end"); 625 } 626 627 PrimitiveRestartTests::PrimitiveRestartTests (Context& context) 628 : TestCaseGroup(context, "primitive_restart", "Primitive restart tests") 629 { 630 } 631 632 PrimitiveRestartTests::~PrimitiveRestartTests (void) 633 { 634 } 635 636 void PrimitiveRestartTests::init (void) 637 { 638 for (int isRestartBeginCaseI = 0; isRestartBeginCaseI <= 1; isRestartBeginCaseI++) 639 for (int isRestartEndCaseI = 0; isRestartEndCaseI <= 1; isRestartEndCaseI++) 640 for (int isDuplicateRestartCaseI = 0; isDuplicateRestartCaseI <= 1; isDuplicateRestartCaseI++) 641 { 642 bool isRestartBeginCase = isRestartBeginCaseI != 0; 643 bool isRestartEndCase = isRestartEndCaseI != 0; 644 bool isDuplicateRestartCase = isDuplicateRestartCaseI != 0; 645 646 std::string specialCaseGroupName; 647 648 if (isRestartBeginCase) specialCaseGroupName = "begin_restart"; 649 if (isRestartEndCase) specialCaseGroupName += std::string(specialCaseGroupName.empty() ? "" : "_") + "end_restart"; 650 if (isDuplicateRestartCase) specialCaseGroupName += std::string(specialCaseGroupName.empty() ? "" : "_") + "duplicate_restarts"; 651 652 if (specialCaseGroupName.empty()) 653 specialCaseGroupName = "basic"; 654 655 TestCaseGroup* specialCaseGroup = new TestCaseGroup(m_context, specialCaseGroupName.c_str(), ""); 656 addChild(specialCaseGroup); 657 658 for (int primType = 0; primType < (int)PrimitiveRestartCase::PRIMITIVE_LAST; primType++) 659 { 660 const char* primTypeName = primType == (int)PrimitiveRestartCase::PRIMITIVE_POINTS ? "points" 661 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINE_STRIP ? "line_strip" 662 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINE_LOOP ? "line_loop" 663 : primType == (int)PrimitiveRestartCase::PRIMITIVE_LINES ? "lines" 664 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLE_STRIP ? "triangle_strip" 665 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLE_FAN ? "triangle_fan" 666 : primType == (int)PrimitiveRestartCase::PRIMITIVE_TRIANGLES ? "triangles" 667 : DE_NULL; 668 669 DE_ASSERT(primTypeName != DE_NULL); 670 671 TestCaseGroup* primTypeGroup = new TestCaseGroup(m_context, primTypeName, ""); 672 specialCaseGroup->addChild(primTypeGroup); 673 674 for (int indexType = 0; indexType < (int)PrimitiveRestartCase::INDEX_LAST; indexType++) 675 { 676 const char *indexTypeName = indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_BYTE ? "unsigned_byte" 677 : indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_SHORT ? "unsigned_short" 678 : indexType == (int)PrimitiveRestartCase::INDEX_UNSIGNED_INT ? "unsigned_int" 679 : DE_NULL; 680 681 DE_ASSERT(indexTypeName != DE_NULL); 682 683 TestCaseGroup* indexTypeGroup = new TestCaseGroup(m_context, indexTypeName, ""); 684 primTypeGroup->addChild(indexTypeGroup); 685 686 for (int function = 0; function < (int)PrimitiveRestartCase::FUNCTION_LAST; function++) 687 { 688 const char* functionName = function == (int)PrimitiveRestartCase::FUNCTION_DRAW_ELEMENTS ? "draw_elements" 689 : function == (int)PrimitiveRestartCase::FUNCTION_DRAW_ELEMENTS_INSTANCED ? "draw_elements_instanced" 690 : function == (int)PrimitiveRestartCase::FUNCTION_DRAW_RANGE_ELEMENTS ? "draw_range_elements" 691 : DE_NULL; 692 693 DE_ASSERT(functionName != DE_NULL); 694 695 indexTypeGroup->addChild(new PrimitiveRestartCase(m_context, 696 functionName, 697 "", 698 (PrimitiveRestartCase::PrimitiveType)primType, 699 (PrimitiveRestartCase::IndexType)indexType, 700 (PrimitiveRestartCase::Function)function, 701 isRestartBeginCase, 702 isRestartEndCase, 703 isDuplicateRestartCase)); 704 } 705 } 706 } 707 } 708 } 709 710 } // Functional 711 } // gles3 712 } // deqp 713