1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 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 Basic Compute Shader Tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fAtomicCounterTests.hpp" 25 26 #include "gluShaderProgram.hpp" 27 #include "gluObjectWrapper.hpp" 28 #include "gluRenderContext.hpp" 29 30 #include "glwFunctions.hpp" 31 #include "glwEnums.hpp" 32 33 #include "tcuTestLog.hpp" 34 35 #include "deStringUtil.hpp" 36 #include "deRandom.hpp" 37 #include "deMemory.h" 38 39 #include <vector> 40 #include <string> 41 42 using namespace glw; 43 using tcu::TestLog; 44 45 using std::vector; 46 using std::string; 47 48 namespace deqp 49 { 50 namespace gles31 51 { 52 namespace Functional 53 { 54 namespace 55 { 56 57 class AtomicCounterTest : public TestCase 58 { 59 public: 60 enum Operation 61 { 62 OPERATION_INC = (1<<0), 63 OPERATION_DEC = (1<<1), 64 OPERATION_GET = (1<<2) 65 }; 66 67 enum OffsetType 68 { 69 OFFSETTYPE_NONE = 0, 70 OFFSETTYPE_BASIC, 71 OFFSETTYPE_REVERSE, 72 OFFSETTYPE_FIRST_AUTO, 73 OFFSETTYPE_DEFAULT_AUTO, 74 OFFSETTYPE_RESET_DEFAULT, 75 OFFSETTYPE_INVALID, 76 OFFSETTYPE_INVALID_OVERLAPPING, 77 OFFSETTYPE_INVALID_DEFAULT 78 }; 79 80 enum BindingType 81 { 82 BINDINGTYPE_BASIC = 0, 83 BINDINGTYPE_INVALID, 84 BINDINGTYPE_INVALID_DEFAULT 85 }; 86 87 struct TestSpec 88 { 89 TestSpec (void) 90 : atomicCounterCount (0) 91 , operations ((Operation)0) 92 , callCount (0) 93 , useBranches (false) 94 , threadCount (0) 95 , offsetType (OFFSETTYPE_NONE) 96 , bindingType (BINDINGTYPE_BASIC) 97 { 98 } 99 100 int atomicCounterCount; 101 Operation operations; 102 int callCount; 103 bool useBranches; 104 int threadCount; 105 OffsetType offsetType; 106 BindingType bindingType; 107 }; 108 109 AtomicCounterTest (Context& context, const char* name, const char* description, const TestSpec& spec); 110 ~AtomicCounterTest (void); 111 112 void init (void); 113 void deinit (void); 114 IterateResult iterate (void); 115 116 private: 117 const TestSpec m_spec; 118 119 bool checkAndLogCounterValues (TestLog& log, const vector<deUint32>& counters) const; 120 bool checkAndLogCallValues (TestLog& log, const vector<deUint32>& increments, const vector<deUint32>& decrements, const vector<deUint32>& preGets, const vector<deUint32>& postGets, const vector<deUint32>& gets) const; 121 void splitBuffer (const vector<deUint32>& buffer, vector<deUint32>& increments, vector<deUint32>& decrements, vector<deUint32>& preGets, vector<deUint32>& postGets, vector<deUint32>& gets) const; 122 deUint32 getInitialValue (void) const { return m_spec.callCount * m_spec.threadCount + 1; } 123 124 static string generateShaderSource (const TestSpec& spec); 125 static void getCountersValues (vector<deUint32>& counterValues, const vector<deUint32>& values, int ndx, int counterCount); 126 static bool checkRange (TestLog& log, const vector<deUint32>& values, const vector<deUint32>& min, const vector<deUint32>& max); 127 static bool checkUniquenessAndLinearity (TestLog& log, const vector<deUint32>& values); 128 static bool checkPath (const vector<deUint32>& increments, const vector<deUint32>& decrements, int initialValue, const TestSpec& spec); 129 130 int getOperationCount (void) const; 131 132 AtomicCounterTest& operator= (const AtomicCounterTest&); 133 AtomicCounterTest (const AtomicCounterTest&); 134 }; 135 136 int AtomicCounterTest::getOperationCount (void) const 137 { 138 int count = 0; 139 140 if (m_spec.operations & OPERATION_INC) 141 count++; 142 143 if (m_spec.operations & OPERATION_DEC) 144 count++; 145 146 if (m_spec.operations == OPERATION_GET) 147 count++; 148 else if (m_spec.operations & OPERATION_GET) 149 count += 2; 150 151 return count; 152 } 153 154 AtomicCounterTest::AtomicCounterTest (Context& context, const char* name, const char* description, const TestSpec& spec) 155 : TestCase (context, name, description) 156 , m_spec (spec) 157 { 158 } 159 160 AtomicCounterTest::~AtomicCounterTest (void) 161 { 162 } 163 164 void AtomicCounterTest::init (void) 165 { 166 } 167 168 void AtomicCounterTest::deinit (void) 169 { 170 } 171 172 string AtomicCounterTest::generateShaderSource (const TestSpec& spec) 173 { 174 std::ostringstream src; 175 176 src 177 << "#version 310 es\n" 178 << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"; 179 180 { 181 bool wroteLayout = false; 182 183 switch (spec.bindingType) 184 { 185 case BINDINGTYPE_INVALID_DEFAULT: 186 src << "layout(binding=10000"; 187 wroteLayout = true; 188 break; 189 190 default: 191 // Do nothing 192 break; 193 } 194 195 switch (spec.offsetType) 196 { 197 case OFFSETTYPE_DEFAULT_AUTO: 198 if (!wroteLayout) 199 src << "layout(binding=1, "; 200 else 201 src << ", "; 202 203 src << "offset=4"; 204 wroteLayout = true; 205 break; 206 207 case OFFSETTYPE_RESET_DEFAULT: 208 DE_ASSERT(spec.atomicCounterCount > 2); 209 210 if (!wroteLayout) 211 src << "layout(binding=1, "; 212 else 213 src << ", "; 214 215 src << "offset=" << (4 * spec.atomicCounterCount/2); 216 wroteLayout = true; 217 break; 218 219 case OFFSETTYPE_INVALID_DEFAULT: 220 if (!wroteLayout) 221 src << "layout(binding=1, "; 222 else 223 src << ", "; 224 225 src << "offset=1"; 226 wroteLayout = true; 227 break; 228 229 default: 230 // Do nothing 231 break; 232 } 233 234 if (wroteLayout) 235 src << ") uniform atomic_uint;\n"; 236 } 237 238 src 239 << "layout(binding = 1, std430) buffer Output {\n"; 240 241 if ((spec.operations & OPERATION_GET) != 0 && spec.operations != OPERATION_GET) 242 src << " uint preGet[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n"; 243 244 if ((spec.operations & OPERATION_INC) != 0) 245 src << " uint increment[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n"; 246 247 if ((spec.operations & OPERATION_DEC) != 0) 248 src << " uint decrement[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n"; 249 250 if ((spec.operations & OPERATION_GET) != 0 && spec.operations != OPERATION_GET) 251 src << " uint postGet[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n"; 252 253 if (spec.operations == OPERATION_GET) 254 src << " uint get[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n"; 255 256 src << "} sb_in;\n\n"; 257 258 for (int counterNdx = 0; counterNdx < spec.atomicCounterCount; counterNdx++) 259 { 260 bool layoutStarted = false; 261 262 if (spec.offsetType == OFFSETTYPE_RESET_DEFAULT && counterNdx == spec.atomicCounterCount/2) 263 src << "layout(binding=1, offset=0) uniform atomic_uint;\n"; 264 265 switch (spec.bindingType) 266 { 267 case BINDINGTYPE_BASIC: 268 layoutStarted = true; 269 src << "layout(binding=1"; 270 break; 271 272 case BINDINGTYPE_INVALID: 273 layoutStarted = true; 274 src << "layout(binding=10000"; 275 break; 276 277 case BINDINGTYPE_INVALID_DEFAULT: 278 // Nothing 279 break; 280 281 default: 282 DE_ASSERT(false); 283 } 284 285 switch (spec.offsetType) 286 { 287 case OFFSETTYPE_NONE: 288 if (layoutStarted) 289 src << ") "; 290 291 src << "uniform atomic_uint counter" << counterNdx << ";\n"; 292 293 break; 294 295 case OFFSETTYPE_BASIC: 296 if (!layoutStarted) 297 src << "layout("; 298 else 299 src << ", "; 300 301 src << "offset=" << (counterNdx * 4) << ") uniform atomic_uint counter" << counterNdx << ";\n"; 302 303 break; 304 305 case OFFSETTYPE_INVALID_DEFAULT: 306 if (layoutStarted) 307 src << ") "; 308 309 src << "uniform atomic_uint counter" << counterNdx << ";\n"; 310 311 break; 312 313 case OFFSETTYPE_INVALID: 314 if (!layoutStarted) 315 src << "layout("; 316 else 317 src << ", "; 318 319 src << "offset=" << (1 + counterNdx * 2) << ") uniform atomic_uint counter" << counterNdx << ";\n"; 320 321 break; 322 323 case OFFSETTYPE_INVALID_OVERLAPPING: 324 if (!layoutStarted) 325 src << "layout("; 326 else 327 src << ", "; 328 329 src << "offset=0) uniform atomic_uint counter" << counterNdx << ";\n"; 330 331 break; 332 333 case OFFSETTYPE_REVERSE: 334 if (!layoutStarted) 335 src << "layout("; 336 else 337 src << ", "; 338 339 src << "offset=" << (spec.atomicCounterCount - counterNdx - 1) * 4 << ") uniform atomic_uint counter" << (spec.atomicCounterCount - counterNdx - 1) << ";\n"; 340 341 break; 342 343 case OFFSETTYPE_FIRST_AUTO: 344 DE_ASSERT(spec.atomicCounterCount > 2); 345 346 if (counterNdx + 1 == spec.atomicCounterCount) 347 { 348 if (!layoutStarted) 349 src << "layout("; 350 else 351 src << ", "; 352 353 src << "offset=0) uniform atomic_uint counter0;\n"; 354 } 355 else if (counterNdx == 0) 356 { 357 if (!layoutStarted) 358 src << "layout("; 359 else 360 src << ", "; 361 362 src << "offset=4) uniform atomic_uint counter1;\n"; 363 } 364 else 365 { 366 if (layoutStarted) 367 src << ") "; 368 369 src << "uniform atomic_uint counter" << (counterNdx + 1) << ";\n"; 370 } 371 372 break; 373 374 case OFFSETTYPE_DEFAULT_AUTO: 375 if (counterNdx + 1 == spec.atomicCounterCount) 376 { 377 if (!layoutStarted) 378 src << "layout("; 379 else 380 src << ", "; 381 382 src << "offset=0) uniform atomic_uint counter0;\n"; 383 } 384 else 385 { 386 if (layoutStarted) 387 src << ") "; 388 389 src << "uniform atomic_uint counter" << (counterNdx + 1) << ";\n"; 390 } 391 392 break; 393 394 case OFFSETTYPE_RESET_DEFAULT: 395 if (layoutStarted) 396 src << ") "; 397 398 if (counterNdx < spec.atomicCounterCount/2) 399 src << "uniform atomic_uint counter" << (counterNdx + spec.atomicCounterCount/2) << ";\n"; 400 else 401 src << "uniform atomic_uint counter" << (counterNdx - spec.atomicCounterCount/2) << ";\n"; 402 403 break; 404 405 default: 406 DE_ASSERT(false); 407 } 408 } 409 410 src 411 << "\n" 412 << "void main (void)\n" 413 << "{\n"; 414 415 if (spec.callCount > 1) 416 src << "\tfor (uint i = 0u; i < " << spec.callCount << "u; i++)\n"; 417 418 src 419 << "\t{\n" 420 << "\t\tuint id = (gl_GlobalInvocationID.x"; 421 422 if (spec.callCount > 1) 423 src << " * "<< spec.callCount << "u"; 424 425 if (spec.callCount > 1) 426 src << " + i)"; 427 else 428 src << ")"; 429 430 if (spec.atomicCounterCount > 1) 431 src << " * " << spec.atomicCounterCount << "u"; 432 433 src << ";\n"; 434 435 for (int counterNdx = 0; counterNdx < spec.atomicCounterCount; counterNdx++) 436 { 437 if ((spec.operations & OPERATION_GET) != 0 && spec.operations != OPERATION_GET) 438 src << "\t\tsb_in.preGet[id + " << counterNdx << "u] = atomicCounter(counter" << counterNdx << ");\n"; 439 440 if (spec.useBranches && ((spec.operations & (OPERATION_INC|OPERATION_DEC)) == (OPERATION_INC|OPERATION_DEC))) 441 { 442 src 443 << "\t\tif (((gl_GlobalInvocationID.x" << (spec.callCount > 1 ? " + i" : "") << ") % 2u) == 0u)\n" 444 << "\t\t{\n" 445 << "\t\t\tsb_in.increment[id + " << counterNdx << "u] = atomicCounterIncrement(counter" << counterNdx << ");\n" 446 << "\t\t\tsb_in.decrement[id + " << counterNdx << "u] = uint(-1);\n" 447 << "\t\t}\n" 448 << "\t\telse\n" 449 << "\t\t{\n" 450 << "\t\t\tsb_in.decrement[id + " << counterNdx << "u] = atomicCounterDecrement(counter" << counterNdx << ") + 1u;\n" 451 << "\t\t\tsb_in.increment[id + " << counterNdx << "u] = uint(-1);\n" 452 << "\t\t}\n"; 453 } 454 else 455 { 456 if ((spec.operations & OPERATION_INC) != 0) 457 { 458 if (spec.useBranches) 459 { 460 src 461 << "\t\tif (((gl_GlobalInvocationID.x" << (spec.callCount > 1 ? " + i" : "") << ") % 2u) == 0u)\n" 462 << "\t\t{\n" 463 << "\t\t\tsb_in.increment[id + " << counterNdx << "u] = atomicCounterIncrement(counter" << counterNdx << ");\n" 464 << "\t\t}\n" 465 << "\t\telse\n" 466 << "\t\t{\n" 467 << "\t\t\tsb_in.increment[id + " << counterNdx << "u] = uint(-1);\n" 468 << "\t\t}\n"; 469 470 } 471 else 472 src << "\t\tsb_in.increment[id + " << counterNdx << "u] = atomicCounterIncrement(counter" << counterNdx << ");\n"; 473 } 474 475 if ((spec.operations & OPERATION_DEC) != 0) 476 { 477 if (spec.useBranches) 478 { 479 src 480 << "\t\tif (((gl_GlobalInvocationID.x" << (spec.callCount > 1 ? " + i" : "") << ") % 2u) == 0u)\n" 481 << "\t\t{\n" 482 << "\t\t\tsb_in.decrement[id + " << counterNdx << "u] = atomicCounterDecrement(counter" << counterNdx << ") + 1u;\n" 483 << "\t\t}\n" 484 << "\t\telse\n" 485 << "\t\t{\n" 486 << "\t\t\tsb_in.decrement[id + " << counterNdx << "u] = uint(-1);\n" 487 << "\t\t}\n"; 488 489 } 490 else 491 src << "\t\tsb_in.decrement[id + " << counterNdx << "u] = atomicCounterDecrement(counter" << counterNdx << ") + 1u;\n"; 492 } 493 } 494 495 if ((spec.operations & OPERATION_GET) != 0 && spec.operations != OPERATION_GET) 496 src << "\t\tsb_in.postGet[id + " << counterNdx << "u] = atomicCounter(counter" << counterNdx << ");\n"; 497 498 if ((spec.operations == OPERATION_GET) != 0) 499 { 500 if (spec.useBranches) 501 { 502 src 503 << "\t\tif (((gl_GlobalInvocationID.x" << (spec.callCount > 1 ? " + i" : "") << ") % 2u) == 0u)\n" 504 << "\t\t{\n" 505 << "\t\t\tsb_in.get[id + " << counterNdx << "u] = atomicCounter(counter" << counterNdx << ");\n" 506 << "\t\t}\n" 507 << "\t\telse\n" 508 << "\t\t{\n" 509 << "\t\t\tsb_in.get[id + " << counterNdx << "u] = uint(-1);\n" 510 << "\t\t}\n"; 511 } 512 else 513 src << "\t\tsb_in.get[id + " << counterNdx << "u] = atomicCounter(counter" << counterNdx << ");\n"; 514 } 515 } 516 517 src 518 << "\t}\n" 519 << "}\n"; 520 521 return src.str(); 522 } 523 524 bool AtomicCounterTest::checkAndLogCounterValues (TestLog& log, const vector<deUint32>& counters) const 525 { 526 tcu::ScopedLogSection counterSection (log, "Counter info", "Show initial value, current value and expected value of each counter."); 527 bool isOk = true; 528 529 // Check that atomic counters have sensible results 530 for (int counterNdx = 0; counterNdx < (int)counters.size(); counterNdx++) 531 { 532 const deUint32 value = counters[counterNdx]; 533 const deUint32 initialValue = getInitialValue(); 534 deUint32 expectedValue = (deUint32)-1; 535 536 if ((m_spec.operations & OPERATION_INC) != 0 && (m_spec.operations & OPERATION_DEC) == 0) 537 expectedValue = initialValue + (m_spec.useBranches ? m_spec.threadCount*m_spec.callCount - m_spec.threadCount*m_spec.callCount/2 : m_spec.threadCount*m_spec.callCount); 538 539 if ((m_spec.operations & OPERATION_INC) == 0 && (m_spec.operations & OPERATION_DEC) != 0) 540 expectedValue = initialValue - (m_spec.useBranches ? m_spec.threadCount*m_spec.callCount - m_spec.threadCount*m_spec.callCount/2 : m_spec.threadCount*m_spec.callCount); 541 542 if ((m_spec.operations & OPERATION_INC) != 0 && (m_spec.operations & OPERATION_DEC) != 0) 543 expectedValue = initialValue + (m_spec.useBranches ? m_spec.threadCount*m_spec.callCount - m_spec.threadCount*m_spec.callCount/2 : 0) - (m_spec.useBranches ? m_spec.threadCount*m_spec.callCount/2 : 0); 544 545 if ((m_spec.operations & OPERATION_INC) == 0 && (m_spec.operations & OPERATION_DEC) == 0) 546 expectedValue = initialValue; 547 548 log << TestLog::Message << "atomic_uint counter" << counterNdx << " initial value: " << initialValue << ", value: " << value << ", expected: " << expectedValue << (value == expectedValue ? "" : ", failed!") << TestLog::EndMessage; 549 550 if (value != expectedValue) 551 isOk = false; 552 } 553 554 return isOk; 555 } 556 557 void AtomicCounterTest::splitBuffer (const vector<deUint32>& buffer, vector<deUint32>& increments, vector<deUint32>& decrements, vector<deUint32>& preGets, vector<deUint32>& postGets, vector<deUint32>& gets) const 558 { 559 const int bufferValueCount = m_spec.callCount * m_spec.threadCount * m_spec.atomicCounterCount; 560 561 int firstPreGet = -1; 562 int firstPostGet = -1; 563 int firstGet = -1; 564 int firstInc = -1; 565 int firstDec = -1; 566 567 increments.clear(); 568 decrements.clear(); 569 preGets.clear(); 570 postGets.clear(); 571 gets.clear(); 572 573 if (m_spec.operations == OPERATION_GET) 574 firstGet = 0; 575 else if (m_spec.operations == OPERATION_INC) 576 firstInc = 0; 577 else if (m_spec.operations == OPERATION_DEC) 578 firstDec = 0; 579 else if (m_spec.operations == (OPERATION_GET|OPERATION_INC)) 580 { 581 firstPreGet = 0; 582 firstInc = bufferValueCount; 583 firstPostGet = bufferValueCount * 2; 584 } 585 else if (m_spec.operations == (OPERATION_GET|OPERATION_DEC)) 586 { 587 firstPreGet = 0; 588 firstDec = bufferValueCount; 589 firstPostGet = bufferValueCount * 2; 590 } 591 else if (m_spec.operations == (OPERATION_GET|OPERATION_DEC|OPERATION_INC)) 592 { 593 firstPreGet = 0; 594 firstInc = bufferValueCount; 595 firstDec = bufferValueCount * 2; 596 firstPostGet = bufferValueCount * 3; 597 } 598 else if (m_spec.operations == (OPERATION_DEC|OPERATION_INC)) 599 { 600 firstInc = 0; 601 firstDec = bufferValueCount; 602 } 603 else 604 DE_ASSERT(false); 605 606 for (int threadNdx = 0; threadNdx < m_spec.threadCount; threadNdx++) 607 { 608 for (int callNdx = 0; callNdx < m_spec.callCount; callNdx++) 609 { 610 for (int counterNdx = 0; counterNdx < m_spec.atomicCounterCount; counterNdx++) 611 { 612 const int id = ((threadNdx * m_spec.callCount) + callNdx) * m_spec.atomicCounterCount + counterNdx; 613 614 if (firstInc != -1) 615 increments.push_back(buffer[firstInc + id]); 616 617 if (firstDec != -1) 618 decrements.push_back(buffer[firstDec + id]); 619 620 if (firstPreGet != -1) 621 preGets.push_back(buffer[firstPreGet + id]); 622 623 if (firstPostGet != -1) 624 postGets.push_back(buffer[firstPostGet + id]); 625 626 if (firstGet != -1) 627 gets.push_back(buffer[firstGet + id]); 628 } 629 } 630 } 631 } 632 633 void AtomicCounterTest::getCountersValues (vector<deUint32>& counterValues, const vector<deUint32>& values, int ndx, int counterCount) 634 { 635 counterValues.resize(values.size()/counterCount, 0); 636 637 DE_ASSERT(values.size() % counterCount == 0); 638 639 for (int valueNdx = 0; valueNdx < (int)counterValues.size(); valueNdx++) 640 counterValues[valueNdx] = values[valueNdx * counterCount + ndx]; 641 } 642 643 bool AtomicCounterTest::checkRange (TestLog& log, const vector<deUint32>& values, const vector<deUint32>& min, const vector<deUint32>& max) 644 { 645 int failedCount = 0; 646 647 DE_ASSERT(values.size() == min.size()); 648 DE_ASSERT(values.size() == max.size()); 649 650 for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++) 651 { 652 if (values[valueNdx] != (deUint32)-1) 653 { 654 if (!deInRange32(values[valueNdx], min[valueNdx], max[valueNdx])) 655 { 656 if (failedCount < 20) 657 log << TestLog::Message << "Value " << values[valueNdx] << " not in range [" << min[valueNdx] << ", " << max[valueNdx] << "]." << TestLog::EndMessage; 658 failedCount++; 659 } 660 } 661 } 662 663 if (failedCount > 20) 664 log << TestLog::Message << "Number of values not in range: " << failedCount << ", displaying first 20 values." << TestLog::EndMessage; 665 666 return failedCount == 0; 667 } 668 669 bool AtomicCounterTest::checkUniquenessAndLinearity (TestLog& log, const vector<deUint32>& values) 670 { 671 vector<deUint32> counts; 672 int failedCount = 0; 673 deUint32 minValue = (deUint32)-1; 674 deUint32 maxValue = 0; 675 676 DE_ASSERT(!values.empty()); 677 678 for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++) 679 { 680 if (values[valueNdx] != (deUint32)-1) 681 { 682 minValue = std::min(minValue, values[valueNdx]); 683 maxValue = std::max(maxValue, values[valueNdx]); 684 } 685 } 686 687 counts.resize(maxValue - minValue + 1, 0); 688 689 for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++) 690 { 691 if (values[valueNdx] != (deUint32)-1) 692 counts[values[valueNdx] - minValue]++; 693 } 694 695 for (int countNdx = 0; countNdx < (int)counts.size(); countNdx++) 696 { 697 if (counts[countNdx] != 1) 698 { 699 if (failedCount < 20) 700 log << TestLog::Message << "Value " << (minValue + countNdx) << " is not unique. Returned " << counts[countNdx] << " times." << TestLog::EndMessage; 701 702 failedCount++; 703 } 704 } 705 706 if (failedCount > 20) 707 log << TestLog::Message << "Number of values not unique: " << failedCount << ", displaying first 20 values." << TestLog::EndMessage; 708 709 return failedCount == 0; 710 } 711 712 bool AtomicCounterTest::checkPath (const vector<deUint32>& increments, const vector<deUint32>& decrements, int initialValue, const TestSpec& spec) 713 { 714 const deUint32 lastValue = initialValue + (spec.useBranches ? spec.threadCount*spec.callCount - spec.threadCount*spec.callCount/2 : 0) - (spec.useBranches ? spec.threadCount*spec.callCount/2 : 0); 715 bool isOk = true; 716 717 vector<deUint32> incrementCounts; 718 vector<deUint32> decrementCounts; 719 720 deUint32 minValue = 0xFFFFFFFFu; 721 deUint32 maxValue = 0; 722 723 for (int valueNdx = 0; valueNdx < (int)increments.size(); valueNdx++) 724 { 725 if (increments[valueNdx] != (deUint32)-1) 726 { 727 minValue = std::min(minValue, increments[valueNdx]); 728 maxValue = std::max(maxValue, increments[valueNdx]); 729 } 730 } 731 732 for (int valueNdx = 0; valueNdx < (int)decrements.size(); valueNdx++) 733 { 734 if (decrements[valueNdx] != (deUint32)-1) 735 { 736 minValue = std::min(minValue, decrements[valueNdx]); 737 maxValue = std::max(maxValue, decrements[valueNdx]); 738 } 739 } 740 741 minValue = std::min(minValue, (deUint32)initialValue); 742 maxValue = std::max(maxValue, (deUint32)initialValue); 743 744 incrementCounts.resize(maxValue - minValue + 1, 0); 745 decrementCounts.resize(maxValue - minValue + 1, 0); 746 747 for (int valueNdx = 0; valueNdx < (int)increments.size(); valueNdx++) 748 { 749 if (increments[valueNdx] != (deUint32)-1) 750 incrementCounts[increments[valueNdx] - minValue]++; 751 } 752 753 for (int valueNdx = 0; valueNdx < (int)decrements.size(); valueNdx++) 754 { 755 if (decrements[valueNdx] != (deUint32)-1) 756 decrementCounts[decrements[valueNdx] - minValue]++; 757 } 758 759 int pos = initialValue - minValue; 760 761 while (incrementCounts[pos] + decrementCounts[pos] != 0) 762 { 763 if (incrementCounts[pos] > 0 && pos >= (int)(lastValue - minValue)) 764 { 765 // If can increment and incrementation would move us away from result value, increment 766 incrementCounts[pos]--; 767 pos++; 768 } 769 else if (decrementCounts[pos] > 0) 770 { 771 // If can, decrement 772 decrementCounts[pos]--; 773 pos--; 774 } 775 else if (incrementCounts[pos] > 0) 776 { 777 // If increment moves closer to result value and can't decrement, increment 778 incrementCounts[pos]--; 779 pos++; 780 } 781 else 782 DE_ASSERT(false); 783 784 if (pos < 0 || pos >= (int)incrementCounts.size()) 785 break; 786 } 787 788 if (minValue + pos != lastValue) 789 isOk = false; 790 791 for (int valueNdx = 0; valueNdx < (int)incrementCounts.size(); valueNdx++) 792 { 793 if (incrementCounts[valueNdx] != 0) 794 isOk = false; 795 } 796 797 for (int valueNdx = 0; valueNdx < (int)decrementCounts.size(); valueNdx++) 798 { 799 if (decrementCounts[valueNdx] != 0) 800 isOk = false; 801 } 802 803 return isOk; 804 } 805 806 bool AtomicCounterTest::checkAndLogCallValues (TestLog& log, const vector<deUint32>& increments, const vector<deUint32>& decrements, const vector<deUint32>& preGets, const vector<deUint32>& postGets, const vector<deUint32>& gets) const 807 { 808 bool isOk = true; 809 810 for (int counterNdx = 0; counterNdx < m_spec.atomicCounterCount; counterNdx++) 811 { 812 vector<deUint32> counterIncrements; 813 vector<deUint32> counterDecrements; 814 vector<deUint32> counterPreGets; 815 vector<deUint32> counterPostGets; 816 vector<deUint32> counterGets; 817 818 getCountersValues(counterIncrements, increments, counterNdx, m_spec.atomicCounterCount); 819 getCountersValues(counterDecrements, decrements, counterNdx, m_spec.atomicCounterCount); 820 getCountersValues(counterPreGets, preGets, counterNdx, m_spec.atomicCounterCount); 821 getCountersValues(counterPostGets, postGets, counterNdx, m_spec.atomicCounterCount); 822 getCountersValues(counterGets, gets, counterNdx, m_spec.atomicCounterCount); 823 824 if (m_spec.operations == OPERATION_GET) 825 { 826 tcu::ScopedLogSection valueCheck(log, ("counter" + de::toString(counterNdx) + " value check").c_str(), ("Check that counter" + de::toString(counterNdx) + " values haven't changed.").c_str()); 827 int changedValues = 0; 828 829 for (int valueNdx = 0; valueNdx < (int)gets.size(); valueNdx++) 830 { 831 if ((!m_spec.useBranches || gets[valueNdx] != (deUint32)-1) && gets[valueNdx] != getInitialValue()) 832 { 833 if (changedValues < 20) 834 log << TestLog::Message << "atomicCounter(counter" << counterNdx << ") returned " << gets[valueNdx] << " expected " << getInitialValue() << TestLog::EndMessage; 835 isOk = false; 836 changedValues++; 837 } 838 } 839 840 if (changedValues == 0) 841 log << TestLog::Message << "All values returned by atomicCounter(counter" << counterNdx << ") match initial value " << getInitialValue() << "." << TestLog::EndMessage; 842 else if (changedValues > 20) 843 log << TestLog::Message << "Total number of invalid values returned by atomicCounter(counter" << counterNdx << ") " << changedValues << " displaying first 20 values." << TestLog::EndMessage; 844 } 845 else if ((m_spec.operations & (OPERATION_INC|OPERATION_DEC)) == (OPERATION_INC|OPERATION_DEC)) 846 { 847 tcu::ScopedLogSection valueCheck(log, ("counter" + de::toString(counterNdx) + " path check").c_str(), ("Check that there is order in which counter" + de::toString(counterNdx) + " increments and decrements could have happened.").c_str()); 848 if (!checkPath(counterIncrements, counterDecrements, getInitialValue(), m_spec)) 849 { 850 isOk = false; 851 log << TestLog::Message << "No possible order of calls to atomicCounterIncrement(counter" << counterNdx << ") and atomicCounterDecrement(counter" << counterNdx << ") found." << TestLog::EndMessage; 852 } 853 else 854 log << TestLog::Message << "Found possible order of calls to atomicCounterIncrement(counter" << counterNdx << ") and atomicCounterDecrement(counter" << counterNdx << ")." << TestLog::EndMessage; 855 } 856 else if ((m_spec.operations & OPERATION_INC) != 0) 857 { 858 { 859 tcu::ScopedLogSection uniquenesCheck(log, ("counter" + de::toString(counterNdx) + " check uniqueness and linearity").c_str(), ("Check that counter" + de::toString(counterNdx) + " returned only unique and linear values.").c_str()); 860 861 if (!checkUniquenessAndLinearity(log, counterIncrements)) 862 { 863 isOk = false; 864 log << TestLog::Message << "atomicCounterIncrement(counter" << counterNdx << ") returned non unique values." << TestLog::EndMessage; 865 } 866 else 867 log << TestLog::Message << "atomicCounterIncrement(counter" << counterNdx << ") returned only unique values." << TestLog::EndMessage; 868 } 869 870 if (isOk && ((m_spec.operations & OPERATION_GET) != 0)) 871 { 872 tcu::ScopedLogSection uniquenesCheck(log, ("counter" + de::toString(counterNdx) + " check range").c_str(), ("Check that counter" + de::toString(counterNdx) + " returned only values values between previous and next atomicCounter(counter" + de::toString(counterNdx) + ").").c_str()); 873 874 if (!checkRange(log, counterIncrements, counterPreGets, counterPostGets)) 875 { 876 isOk = false; 877 log << TestLog::Message << "atomicCounterIncrement(counter" << counterNdx << ") returned value that is not between previous and next call to atomicCounter(counter" << counterNdx << ")." << TestLog::EndMessage; 878 } 879 else 880 log << TestLog::Message << "atomicCounterIncrement(counter" << counterNdx << ") returned only values between previous and next call to atomicCounter(counter" << counterNdx << ")." << TestLog::EndMessage; 881 } 882 } 883 else if ((m_spec.operations & OPERATION_DEC) != 0) 884 { 885 { 886 tcu::ScopedLogSection uniquenesCheck(log, ("counter" + de::toString(counterNdx) + " check uniqueness and linearity").c_str(), ("Check that counter" + de::toString(counterNdx) + " returned only unique and linear values.").c_str()); 887 888 if (!checkUniquenessAndLinearity(log, counterDecrements)) 889 { 890 isOk = false; 891 log << TestLog::Message << "atomicCounterDecrement(counter" << counterNdx << ") returned non unique values." << TestLog::EndMessage; 892 } 893 else 894 log << TestLog::Message << "atomicCounterDecrement(counter" << counterNdx << ") returned only unique values." << TestLog::EndMessage; 895 } 896 897 if (isOk && ((m_spec.operations & OPERATION_GET) != 0)) 898 { 899 tcu::ScopedLogSection uniquenesCheck(log, ("counter" + de::toString(counterNdx) + " check range").c_str(), ("Check that counter" + de::toString(counterNdx) + " returned only values values between previous and next atomicCounter(counter" + de::toString(counterNdx) + ".").c_str()); 900 901 if (!checkRange(log, counterDecrements, counterPostGets, counterPreGets)) 902 { 903 isOk = false; 904 log << TestLog::Message << "atomicCounterDecrement(counter" << counterNdx << ") returned value that is not between previous and next call to atomicCounter(counter" << counterNdx << ")." << TestLog::EndMessage; 905 } 906 else 907 log << TestLog::Message << "atomicCounterDecrement(counter" << counterNdx << ") returned only values between previous and next call to atomicCounter(counter" << counterNdx << ")." << TestLog::EndMessage; 908 } 909 } 910 } 911 912 return isOk; 913 } 914 915 TestCase::IterateResult AtomicCounterTest::iterate (void) 916 { 917 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 918 TestLog& log = m_testCtx.getLog(); 919 const glu::Buffer counterBuffer (m_context.getRenderContext()); 920 const glu::Buffer outputBuffer (m_context.getRenderContext()); 921 const glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() << glu::ShaderSource(glu::SHADERTYPE_COMPUTE, generateShaderSource(m_spec))); 922 923 const deInt32 counterBufferSize = m_spec.atomicCounterCount * 4; 924 const deInt32 ssoSize = m_spec.atomicCounterCount * m_spec.callCount * m_spec.threadCount * 4 * getOperationCount(); 925 926 log << program; 927 928 if (m_spec.offsetType == OFFSETTYPE_INVALID || m_spec.offsetType == OFFSETTYPE_INVALID_DEFAULT || m_spec.bindingType == BINDINGTYPE_INVALID || m_spec.bindingType == BINDINGTYPE_INVALID_DEFAULT || m_spec.offsetType == OFFSETTYPE_INVALID_OVERLAPPING) 929 { 930 if (program.isOk()) 931 { 932 log << TestLog::Message << "Expected program to fail, but compilation passed." << TestLog::EndMessage; 933 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile succeeded"); 934 return STOP; 935 } 936 else 937 { 938 log << TestLog::Message << "Compilation failed as expected." << TestLog::EndMessage; 939 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Compile failed"); 940 return STOP; 941 } 942 } 943 else if (!program.isOk()) 944 { 945 log << TestLog::Message << "Compile failed." << TestLog::EndMessage; 946 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed"); 947 return STOP; 948 } 949 950 gl.useProgram(program.getProgram()); 951 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()"); 952 953 // Create output buffer 954 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); 955 gl.bufferData(GL_SHADER_STORAGE_BUFFER, ssoSize, NULL, GL_STATIC_DRAW); 956 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create output buffer"); 957 958 // Create atomic counter buffer 959 { 960 vector<deUint32> data(m_spec.atomicCounterCount, getInitialValue()); 961 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *counterBuffer); 962 gl.bufferData(GL_SHADER_STORAGE_BUFFER, counterBufferSize, &(data[0]), GL_STATIC_DRAW); 963 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create buffer for atomic counters"); 964 } 965 966 // Bind output buffer 967 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, *outputBuffer); 968 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup output buffer"); 969 970 // Bind atomic counter buffer 971 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, *counterBuffer); 972 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup atomic counter buffer"); 973 974 // Dispath compute 975 gl.dispatchCompute(m_spec.threadCount, 1, 1); 976 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); 977 978 gl.finish(); 979 GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()"); 980 981 vector<deUint32> output(ssoSize/4, 0); 982 vector<deUint32> counters(m_spec.atomicCounterCount, 0); 983 984 // Read back output buffer 985 { 986 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); 987 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()"); 988 989 void* ptr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(output.size() * sizeof(deUint32)), GL_MAP_READ_BIT); 990 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()"); 991 992 deMemcpy(&(output[0]), ptr, (int)output.size() * sizeof(deUint32)); 993 994 if (!gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER)) 995 { 996 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()"); 997 TCU_CHECK_MSG(false, "Mapped buffer corrupted"); 998 } 999 1000 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 1001 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()"); 1002 } 1003 1004 // Read back counter buffer 1005 { 1006 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *counterBuffer); 1007 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()"); 1008 1009 void* ptr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(counters.size() * sizeof(deUint32)), GL_MAP_READ_BIT); 1010 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()"); 1011 1012 deMemcpy(&(counters[0]), ptr, (int)counters.size() * sizeof(deUint32)); 1013 1014 if (!gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER)) 1015 { 1016 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()"); 1017 TCU_CHECK_MSG(false, "Mapped buffer corrupted"); 1018 } 1019 1020 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 1021 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()"); 1022 } 1023 1024 bool isOk = true; 1025 1026 if (!checkAndLogCounterValues(log, counters)) 1027 isOk = false; 1028 1029 { 1030 vector<deUint32> increments; 1031 vector<deUint32> decrements; 1032 vector<deUint32> preGets; 1033 vector<deUint32> postGets; 1034 vector<deUint32> gets; 1035 1036 splitBuffer(output, increments, decrements, preGets, postGets, gets); 1037 1038 if (!checkAndLogCallValues(log, increments, decrements, preGets, postGets, gets)) 1039 isOk = false; 1040 } 1041 1042 if (isOk) 1043 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1044 else 1045 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 1046 1047 return STOP; 1048 } 1049 1050 string specToTestName (const AtomicCounterTest::TestSpec& spec) 1051 { 1052 std::ostringstream stream; 1053 1054 stream << spec.atomicCounterCount << (spec.atomicCounterCount == 1 ? "_counter" : "_counters"); 1055 stream << "_" << spec.callCount << (spec.callCount == 1 ? "_call" : "_calls"); 1056 stream << "_" << spec.threadCount << (spec.threadCount == 1 ? "_thread" : "_threads"); 1057 1058 return stream.str(); 1059 } 1060 1061 string specToTestDescription (const AtomicCounterTest::TestSpec& spec) 1062 { 1063 std::ostringstream stream; 1064 bool firstOperation = 0; 1065 1066 stream 1067 << "Test "; 1068 1069 if ((spec.operations & AtomicCounterTest::OPERATION_GET) != 0) 1070 { 1071 stream << "atomicCounter()"; 1072 firstOperation = false; 1073 } 1074 1075 if ((spec.operations & AtomicCounterTest::OPERATION_INC) != 0) 1076 { 1077 if (!firstOperation) 1078 stream << ", "; 1079 1080 stream << " atomicCounterIncrement()"; 1081 firstOperation = false; 1082 } 1083 1084 if ((spec.operations & AtomicCounterTest::OPERATION_DEC) != 0) 1085 { 1086 if (!firstOperation) 1087 stream << ", "; 1088 1089 stream << " atomicCounterDecrement()"; 1090 firstOperation = false; 1091 } 1092 1093 stream << " calls with "; 1094 1095 if (spec.useBranches) 1096 stream << " branches, "; 1097 1098 stream << spec.atomicCounterCount << " atomic counters, " << spec.callCount << " calls and " << spec.threadCount << " threads."; 1099 1100 return stream.str(); 1101 } 1102 1103 string operationToName (const AtomicCounterTest::Operation& operations, bool useBranch) 1104 { 1105 std::ostringstream stream; 1106 bool first = true; 1107 1108 if ((operations & AtomicCounterTest::OPERATION_GET) != 0) 1109 { 1110 stream << "get"; 1111 first = false; 1112 } 1113 1114 if ((operations & AtomicCounterTest::OPERATION_INC) != 0) 1115 { 1116 if (!first) 1117 stream << "_"; 1118 1119 stream << "inc"; 1120 first = false; 1121 } 1122 1123 if ((operations & AtomicCounterTest::OPERATION_DEC) != 0) 1124 { 1125 if (!first) 1126 stream << "_"; 1127 1128 stream << "dec"; 1129 first = false; 1130 } 1131 1132 if (useBranch) 1133 stream << "_branch"; 1134 1135 return stream.str(); 1136 } 1137 1138 string operationToDescription (const AtomicCounterTest::Operation& operations, bool useBranch) 1139 { 1140 std::ostringstream stream; 1141 bool firstOperation = 0; 1142 1143 stream 1144 << "Test "; 1145 1146 if ((operations & AtomicCounterTest::OPERATION_GET) != 0) 1147 { 1148 stream << "atomicCounter()"; 1149 firstOperation = false; 1150 } 1151 1152 if ((operations & AtomicCounterTest::OPERATION_INC) != 0) 1153 { 1154 if (!firstOperation) 1155 stream << ", "; 1156 1157 stream << " atomicCounterIncrement()"; 1158 firstOperation = false; 1159 } 1160 1161 if ((operations & AtomicCounterTest::OPERATION_DEC) != 0) 1162 { 1163 if (!firstOperation) 1164 stream << ", "; 1165 1166 stream << " atomicCounterDecrement()"; 1167 firstOperation = false; 1168 } 1169 1170 1171 if (useBranch) 1172 stream << " calls with branches."; 1173 else 1174 stream << "."; 1175 1176 return stream.str(); 1177 } 1178 1179 string layoutTypesToName (const AtomicCounterTest::BindingType& bindingType, const AtomicCounterTest::OffsetType& offsetType) 1180 { 1181 std::ostringstream stream; 1182 1183 switch (bindingType) 1184 { 1185 case AtomicCounterTest::BINDINGTYPE_BASIC: 1186 // Nothing 1187 break; 1188 1189 case AtomicCounterTest::BINDINGTYPE_INVALID: 1190 stream << "invalid_binding"; 1191 break; 1192 1193 default: 1194 DE_ASSERT(false); 1195 } 1196 1197 if (bindingType != AtomicCounterTest::BINDINGTYPE_BASIC && offsetType != AtomicCounterTest::OFFSETTYPE_NONE) 1198 stream << "_"; 1199 1200 switch (offsetType) 1201 { 1202 case AtomicCounterTest::OFFSETTYPE_BASIC: 1203 stream << "basic_offset"; 1204 break; 1205 1206 case AtomicCounterTest::OFFSETTYPE_REVERSE: 1207 stream << "reverse_offset"; 1208 break; 1209 1210 case AtomicCounterTest::OFFSETTYPE_INVALID: 1211 stream << "invalid_offset"; 1212 break; 1213 1214 case AtomicCounterTest::OFFSETTYPE_FIRST_AUTO: 1215 stream << "first_offset_set"; 1216 break; 1217 1218 case AtomicCounterTest::OFFSETTYPE_DEFAULT_AUTO: 1219 stream << "default_offset_set"; 1220 break; 1221 1222 case AtomicCounterTest::OFFSETTYPE_RESET_DEFAULT: 1223 stream << "reset_default_offset"; 1224 break; 1225 1226 case AtomicCounterTest::OFFSETTYPE_NONE: 1227 // Do nothing 1228 break; 1229 1230 default: 1231 DE_ASSERT(false); 1232 } 1233 1234 return stream.str(); 1235 } 1236 1237 string layoutTypesToDesc (const AtomicCounterTest::BindingType& bindingType, const AtomicCounterTest::OffsetType& offsetType) 1238 { 1239 std::ostringstream stream; 1240 1241 switch (bindingType) 1242 { 1243 case AtomicCounterTest::BINDINGTYPE_BASIC: 1244 stream << "Test using atomic counters with explicit layout bindings and"; 1245 break; 1246 1247 case AtomicCounterTest::BINDINGTYPE_INVALID: 1248 stream << "Test using atomic counters with invalid explicit layout bindings and"; 1249 break; 1250 1251 case AtomicCounterTest::BINDINGTYPE_INVALID_DEFAULT: 1252 stream << "Test using atomic counters with invalid default layout binding and"; 1253 break; 1254 1255 default: 1256 DE_ASSERT(false); 1257 } 1258 1259 switch (offsetType) 1260 { 1261 case AtomicCounterTest::OFFSETTYPE_NONE: 1262 stream << " no explicit offsets."; 1263 break; 1264 1265 case AtomicCounterTest::OFFSETTYPE_BASIC: 1266 stream << "explicit continuos offsets."; 1267 break; 1268 1269 case AtomicCounterTest::OFFSETTYPE_REVERSE: 1270 stream << "reversed explicit offsets."; 1271 break; 1272 1273 case AtomicCounterTest::OFFSETTYPE_INVALID: 1274 stream << "invalid explicit offsets."; 1275 break; 1276 1277 case AtomicCounterTest::OFFSETTYPE_FIRST_AUTO: 1278 stream << "only first counter with explicit offset."; 1279 break; 1280 1281 case AtomicCounterTest::OFFSETTYPE_DEFAULT_AUTO: 1282 stream << "default offset."; 1283 break; 1284 1285 case AtomicCounterTest::OFFSETTYPE_RESET_DEFAULT: 1286 stream << "default offset specified twice."; 1287 break; 1288 1289 default: 1290 DE_ASSERT(false); 1291 } 1292 1293 return stream.str(); 1294 } 1295 1296 } // Anonymous 1297 1298 AtomicCounterTests::AtomicCounterTests (Context& context) 1299 : TestCaseGroup(context, "atomic_counter", "Atomic counter tests") 1300 { 1301 // Runtime use tests 1302 { 1303 const int counterCounts[] = 1304 { 1305 1, 4, 8 1306 }; 1307 1308 const int callCounts[] = 1309 { 1310 1, 5, 100 1311 }; 1312 1313 const int threadCounts[] = 1314 { 1315 1, 10, 5000 1316 }; 1317 1318 const AtomicCounterTest::Operation operations[] = 1319 { 1320 AtomicCounterTest::OPERATION_GET, 1321 AtomicCounterTest::OPERATION_INC, 1322 AtomicCounterTest::OPERATION_DEC, 1323 1324 (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_GET), 1325 (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_DEC|AtomicCounterTest::OPERATION_GET), 1326 1327 (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_DEC), 1328 (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_DEC|AtomicCounterTest::OPERATION_GET) 1329 }; 1330 1331 for (int operationNdx = 0; operationNdx < DE_LENGTH_OF_ARRAY(operations); operationNdx++) 1332 { 1333 const AtomicCounterTest::Operation operation = operations[operationNdx]; 1334 1335 for (int branch = 0; branch < 2; branch++) 1336 { 1337 const bool useBranch = (branch == 1); 1338 1339 TestCaseGroup* operationGroup = new TestCaseGroup(m_context, operationToName(operation, useBranch).c_str(), operationToDescription(operation, useBranch).c_str()); 1340 1341 for (int counterCountNdx = 0; counterCountNdx < DE_LENGTH_OF_ARRAY(counterCounts); counterCountNdx++) 1342 { 1343 const int counterCount = counterCounts[counterCountNdx]; 1344 1345 for (int callCountNdx = 0; callCountNdx < DE_LENGTH_OF_ARRAY(callCounts); callCountNdx++) 1346 { 1347 const int callCount = callCounts[callCountNdx]; 1348 1349 for (int threadCountNdx = 0; threadCountNdx < DE_LENGTH_OF_ARRAY(threadCounts); threadCountNdx++) 1350 { 1351 const int threadCount = threadCounts[threadCountNdx]; 1352 1353 if (threadCount * callCount * counterCount > 10000) 1354 continue; 1355 1356 if (useBranch && threadCount * callCount == 1) 1357 continue; 1358 1359 AtomicCounterTest::TestSpec spec; 1360 1361 spec.atomicCounterCount = counterCount; 1362 spec.operations = operation; 1363 spec.callCount = callCount; 1364 spec.useBranches = useBranch; 1365 spec.threadCount = threadCount; 1366 spec.bindingType = AtomicCounterTest::BINDINGTYPE_BASIC; 1367 spec.offsetType = AtomicCounterTest::OFFSETTYPE_NONE; 1368 1369 operationGroup->addChild(new AtomicCounterTest(m_context, specToTestName(spec).c_str(), specToTestDescription(spec).c_str(), spec)); 1370 } 1371 } 1372 } 1373 1374 addChild(operationGroup); 1375 } 1376 } 1377 } 1378 1379 { 1380 TestCaseGroup* layoutGroup = new TestCaseGroup(m_context, "layout", "Layout qualifier tests."); 1381 1382 const int counterCounts[] = { 1, 8 }; 1383 const int callCounts[] = { 1, 5 }; 1384 const int threadCounts[] = { 1, 1000 }; 1385 1386 const AtomicCounterTest::Operation operations[] = 1387 { 1388 (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_GET), 1389 (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_DEC|AtomicCounterTest::OPERATION_GET), 1390 (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_DEC) 1391 }; 1392 1393 const AtomicCounterTest::OffsetType offsetTypes[] = 1394 { 1395 AtomicCounterTest::OFFSETTYPE_REVERSE, 1396 AtomicCounterTest::OFFSETTYPE_FIRST_AUTO, 1397 AtomicCounterTest::OFFSETTYPE_DEFAULT_AUTO, 1398 AtomicCounterTest::OFFSETTYPE_RESET_DEFAULT 1399 }; 1400 1401 for (int offsetTypeNdx = 0; offsetTypeNdx < DE_LENGTH_OF_ARRAY(offsetTypes); offsetTypeNdx++) 1402 { 1403 const AtomicCounterTest::OffsetType offsetType = offsetTypes[offsetTypeNdx]; 1404 1405 TestCaseGroup* layoutQualifierGroup = new TestCaseGroup(m_context, layoutTypesToName(AtomicCounterTest::BINDINGTYPE_BASIC, offsetType).c_str(), layoutTypesToDesc(AtomicCounterTest::BINDINGTYPE_BASIC, offsetType).c_str()); 1406 1407 for (int operationNdx = 0; operationNdx < DE_LENGTH_OF_ARRAY(operations); operationNdx++) 1408 { 1409 const AtomicCounterTest::Operation operation = operations[operationNdx]; 1410 1411 TestCaseGroup* operationGroup = new TestCaseGroup(m_context, operationToName(operation, false).c_str(), operationToDescription(operation, false).c_str()); 1412 1413 for (int counterCountNdx = 0; counterCountNdx < DE_LENGTH_OF_ARRAY(counterCounts); counterCountNdx++) 1414 { 1415 const int counterCount = counterCounts[counterCountNdx]; 1416 1417 if (offsetType == AtomicCounterTest::OFFSETTYPE_FIRST_AUTO && counterCount < 3) 1418 continue; 1419 1420 if (offsetType == AtomicCounterTest::OFFSETTYPE_DEFAULT_AUTO && counterCount < 2) 1421 continue; 1422 1423 if (offsetType == AtomicCounterTest::OFFSETTYPE_RESET_DEFAULT && counterCount < 2) 1424 continue; 1425 1426 if (offsetType == AtomicCounterTest::OFFSETTYPE_REVERSE && counterCount < 2) 1427 continue; 1428 1429 for (int callCountNdx = 0; callCountNdx < DE_LENGTH_OF_ARRAY(callCounts); callCountNdx++) 1430 { 1431 const int callCount = callCounts[callCountNdx]; 1432 1433 for (int threadCountNdx = 0; threadCountNdx < DE_LENGTH_OF_ARRAY(threadCounts); threadCountNdx++) 1434 { 1435 const int threadCount = threadCounts[threadCountNdx]; 1436 1437 AtomicCounterTest::TestSpec spec; 1438 1439 spec.atomicCounterCount = counterCount; 1440 spec.operations = operation; 1441 spec.callCount = callCount; 1442 spec.useBranches = false; 1443 spec.threadCount = threadCount; 1444 spec.bindingType = AtomicCounterTest::BINDINGTYPE_BASIC; 1445 spec.offsetType = offsetType; 1446 1447 operationGroup->addChild(new AtomicCounterTest(m_context, specToTestName(spec).c_str(), specToTestDescription(spec).c_str(), spec)); 1448 } 1449 } 1450 } 1451 layoutQualifierGroup->addChild(operationGroup); 1452 } 1453 layoutGroup->addChild(layoutQualifierGroup); 1454 } 1455 1456 { 1457 TestCaseGroup* invalidGroup = new TestCaseGroup(m_context, "invalid", "Test invalid layouts"); 1458 1459 { 1460 AtomicCounterTest::TestSpec spec; 1461 1462 spec.atomicCounterCount = 1; 1463 spec.operations = AtomicCounterTest::OPERATION_INC; 1464 spec.callCount = 1; 1465 spec.useBranches = false; 1466 spec.threadCount = 1; 1467 spec.bindingType = AtomicCounterTest::BINDINGTYPE_INVALID; 1468 spec.offsetType = AtomicCounterTest::OFFSETTYPE_NONE; 1469 1470 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_binding", "Test layout qualifiers with invalid binding.", spec)); 1471 } 1472 1473 { 1474 AtomicCounterTest::TestSpec spec; 1475 1476 spec.atomicCounterCount = 1; 1477 spec.operations = AtomicCounterTest::OPERATION_INC; 1478 spec.callCount = 1; 1479 spec.useBranches = false; 1480 spec.threadCount = 1; 1481 spec.bindingType = AtomicCounterTest::BINDINGTYPE_INVALID_DEFAULT; 1482 spec.offsetType = AtomicCounterTest::OFFSETTYPE_NONE; 1483 1484 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_default_binding", "Test layout qualifiers with invalid default binding.", spec)); 1485 } 1486 1487 { 1488 AtomicCounterTest::TestSpec spec; 1489 1490 spec.atomicCounterCount = 1; 1491 spec.operations = AtomicCounterTest::OPERATION_INC; 1492 spec.callCount = 1; 1493 spec.useBranches = false; 1494 spec.threadCount = 1; 1495 spec.bindingType = AtomicCounterTest::BINDINGTYPE_BASIC; 1496 spec.offsetType = AtomicCounterTest::OFFSETTYPE_INVALID; 1497 1498 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_offset_align", "Test layout qualifiers with invalid alignment offset.", spec)); 1499 } 1500 1501 { 1502 AtomicCounterTest::TestSpec spec; 1503 1504 spec.atomicCounterCount = 2; 1505 spec.operations = AtomicCounterTest::OPERATION_INC; 1506 spec.callCount = 1; 1507 spec.useBranches = false; 1508 spec.threadCount = 1; 1509 spec.bindingType = AtomicCounterTest::BINDINGTYPE_BASIC; 1510 spec.offsetType = AtomicCounterTest::OFFSETTYPE_INVALID_OVERLAPPING; 1511 1512 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_offset_overlap", "Test layout qualifiers with invalid overlapping offset.", spec)); 1513 } 1514 1515 { 1516 AtomicCounterTest::TestSpec spec; 1517 1518 spec.atomicCounterCount = 1; 1519 spec.operations = AtomicCounterTest::OPERATION_INC; 1520 spec.callCount = 1; 1521 spec.useBranches = false; 1522 spec.threadCount = 1; 1523 spec.bindingType = AtomicCounterTest::BINDINGTYPE_BASIC; 1524 spec.offsetType = AtomicCounterTest::OFFSETTYPE_INVALID_DEFAULT; 1525 1526 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_default_offset", "Test layout qualifiers with invalid default offset.", spec)); 1527 } 1528 1529 layoutGroup->addChild(invalidGroup); 1530 } 1531 1532 addChild(layoutGroup); 1533 } 1534 } 1535 1536 AtomicCounterTests::~AtomicCounterTests (void) 1537 { 1538 } 1539 1540 void AtomicCounterTests::init (void) 1541 { 1542 } 1543 1544 } // Functional 1545 } // gles31 1546 } // deqp 1547