1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program EGL 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 Multi threaded EGL tests 22 *//*--------------------------------------------------------------------*/ 23 #include "teglMultiThreadTests.hpp" 24 25 #include "egluNativeWindow.hpp" 26 #include "egluNativePixmap.hpp" 27 #include "egluUtil.hpp" 28 29 #include "tcuTestLog.hpp" 30 #include "tcuCommandLine.hpp" 31 32 #include "deRandom.hpp" 33 34 #include "deThread.hpp" 35 #include "deMutex.hpp" 36 #include "deSemaphore.hpp" 37 38 #include "deAtomic.h" 39 #include "deClock.h" 40 41 #include <vector> 42 #include <string> 43 #include <sstream> 44 45 using std::vector; 46 using std::string; 47 using std::pair; 48 using std::ostringstream; 49 50 namespace deqp 51 { 52 namespace egl 53 { 54 55 class ThreadLog 56 { 57 public: 58 class BeginMessageToken {}; 59 class EndMessageToken {}; 60 61 struct Message 62 { 63 Message (deUint64 timeUs_, const char* msg_) : timeUs(timeUs_), msg(msg_) {} 64 65 deUint64 timeUs; 66 string msg; 67 }; 68 69 ThreadLog (void) { m_messages.reserve(100); } 70 71 ThreadLog& operator<< (const BeginMessageToken&) { return *this; } 72 ThreadLog& operator<< (const EndMessageToken&); 73 74 template<class T> 75 ThreadLog& operator<< (const T& t) { m_message << t; return *this; } 76 const vector<Message>& getMessages (void) const { return m_messages; } 77 78 static BeginMessageToken BeginMessage; 79 static EndMessageToken EndMessage; 80 81 private: 82 ostringstream m_message; 83 vector<Message> m_messages; 84 }; 85 86 ThreadLog& ThreadLog::operator<< (const EndMessageToken&) 87 { 88 m_messages.push_back(Message(deGetMicroseconds(), m_message.str().c_str())); 89 m_message.str(""); 90 return *this; 91 } 92 93 ThreadLog::BeginMessageToken ThreadLog::BeginMessage; 94 ThreadLog::EndMessageToken ThreadLog::EndMessage; 95 96 class MultiThreadedTest; 97 98 class TestThread : public de::Thread 99 { 100 public: 101 enum ThreadStatus 102 { 103 THREADSTATUS_NOT_STARTED = 0, 104 THREADSTATUS_RUNNING, 105 THREADSTATUS_READY, 106 107 THREADSTATUS_NOT_SUPPORTED, 108 THREADSTATUS_ERROR 109 }; 110 111 TestThread (MultiThreadedTest& test, int id); 112 void run (void); 113 114 ThreadStatus getStatus (void) const { return m_status; } 115 ThreadLog& getLog (void) { return m_log; } 116 117 int getId (void) const { return m_id; } 118 119 void setStatus (ThreadStatus status) { m_status = status; } 120 121 122 // Test has stopped 123 class TestStop {}; 124 125 126 private: 127 MultiThreadedTest& m_test; 128 const int m_id; 129 ThreadStatus m_status; 130 ThreadLog m_log; 131 }; 132 133 class MultiThreadedTest : public TestCase 134 { 135 public: 136 MultiThreadedTest (EglTestContext& eglTestCtx, const char* name, const char* description, int threadCount, deUint64 timeoutUs); 137 virtual ~MultiThreadedTest (void); 138 virtual void deinit (void) {} 139 140 virtual bool runThread (TestThread& thread) = 0; 141 virtual IterateResult iterate (void); 142 bool execTest (TestThread& thread); 143 144 protected: 145 void barrier (TestThread& thread); 146 147 private: 148 int m_threadCount; 149 bool m_initialized; 150 deUint64 m_startTimeUs; 151 const deUint64 m_timeoutUs; 152 vector<TestThread*> m_threads; 153 154 volatile deInt32 m_barrierWaiters; 155 de::Semaphore m_barrierSemaphore1; 156 de::Semaphore m_barrierSemaphore2; 157 }; 158 159 TestThread::TestThread (MultiThreadedTest& test, int id) 160 : m_test (test) 161 , m_id (id) 162 , m_status (THREADSTATUS_NOT_STARTED) 163 { 164 } 165 166 void TestThread::run (void) 167 { 168 m_status = THREADSTATUS_RUNNING; 169 170 try 171 { 172 if (m_test.execTest(*this)) 173 m_status = THREADSTATUS_READY; 174 else 175 m_status = THREADSTATUS_ERROR; 176 } 177 catch (const TestThread::TestStop&) 178 { 179 getLog() << ThreadLog::BeginMessage << "Thread stopped" << ThreadLog::EndMessage; 180 } 181 catch (const tcu::NotSupportedError& e) 182 { 183 getLog() << ThreadLog::BeginMessage << "Not supported: '" << e.what() << "'" << ThreadLog::EndMessage; 184 } 185 catch (const std::exception& e) 186 { 187 getLog() << ThreadLog::BeginMessage << "Got exception: '" << e.what() << "'" << ThreadLog::EndMessage; 188 } 189 catch (...) 190 { 191 getLog() << ThreadLog::BeginMessage << "Unknown exception" << ThreadLog::EndMessage; 192 } 193 } 194 195 bool MultiThreadedTest::execTest (TestThread& thread) 196 { 197 bool isOk = false; 198 199 try 200 { 201 isOk = runThread(thread); 202 } 203 catch (const TestThread::TestStop&) 204 { 205 // Thread exited due to error in other thread 206 throw; 207 } 208 catch (const tcu::NotSupportedError&) 209 { 210 // Set status of each thread 211 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 212 m_threads[threadNdx]->setStatus(TestThread::THREADSTATUS_NOT_SUPPORTED); 213 214 // Release barriers 215 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 216 { 217 m_barrierSemaphore1.increment(); 218 m_barrierSemaphore2.increment(); 219 } 220 221 throw; 222 } 223 catch(...) 224 { 225 // Set status of each thread 226 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 227 m_threads[threadNdx]->setStatus(TestThread::THREADSTATUS_ERROR); 228 229 // Release barriers 230 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 231 { 232 m_barrierSemaphore1.increment(); 233 m_barrierSemaphore2.increment(); 234 } 235 236 throw; 237 } 238 239 return isOk; 240 } 241 242 MultiThreadedTest::MultiThreadedTest (EglTestContext& eglTestCtx, const char* name, const char* description, int threadCount, deUint64 timeoutUs) 243 : TestCase (eglTestCtx, name, description) 244 , m_threadCount (threadCount) 245 , m_initialized (false) 246 , m_startTimeUs (0) 247 , m_timeoutUs (timeoutUs) 248 249 , m_barrierWaiters (0) 250 , m_barrierSemaphore1 (0, 0) 251 , m_barrierSemaphore2 (1, 0) 252 { 253 } 254 255 MultiThreadedTest::~MultiThreadedTest (void) 256 { 257 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 258 delete m_threads[threadNdx]; 259 m_threads.clear(); 260 } 261 262 void MultiThreadedTest::barrier (TestThread& thread) 263 { 264 { 265 const deInt32 waiters = deAtomicIncrement32(&m_barrierWaiters); 266 267 if (waiters == m_threadCount) 268 { 269 m_barrierSemaphore2.decrement(); 270 m_barrierSemaphore1.increment(); 271 } 272 else 273 { 274 m_barrierSemaphore1.decrement(); 275 m_barrierSemaphore1.increment(); 276 } 277 } 278 279 { 280 const deInt32 waiters = deAtomicDecrement32(&m_barrierWaiters); 281 282 if (waiters == 0) 283 { 284 m_barrierSemaphore1.decrement(); 285 m_barrierSemaphore2.increment(); 286 } 287 else 288 { 289 m_barrierSemaphore2.decrement(); 290 m_barrierSemaphore2.increment(); 291 } 292 } 293 294 // Barrier was released due an error in other thread 295 if (thread.getStatus() != TestThread::THREADSTATUS_RUNNING) 296 throw TestThread::TestStop(); 297 } 298 299 TestCase::IterateResult MultiThreadedTest::iterate (void) 300 { 301 if (!m_initialized) 302 { 303 m_testCtx.getLog() << tcu::TestLog::Message << "Thread timeout limit: " << m_timeoutUs << "us" << tcu::TestLog::EndMessage; 304 305 // Create threads 306 m_threads.reserve(m_threadCount); 307 308 for (int threadNdx = 0; threadNdx < m_threadCount; threadNdx++) 309 m_threads.push_back(new TestThread(*this, threadNdx)); 310 311 m_startTimeUs = deGetMicroseconds(); 312 313 // Run threads 314 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 315 m_threads[threadNdx]->start(); 316 317 m_initialized = true; 318 } 319 320 int readyCount = 0; 321 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 322 { 323 if (m_threads[threadNdx]->getStatus() != TestThread::THREADSTATUS_RUNNING) 324 readyCount++; 325 } 326 327 if (readyCount == m_threadCount) 328 { 329 // Join threads 330 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 331 m_threads[threadNdx]->join(); 332 333 bool isOk = true; 334 bool notSupported = false; 335 336 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 337 { 338 if (m_threads[threadNdx]->getStatus() == TestThread::THREADSTATUS_ERROR) 339 isOk = false; 340 341 if (m_threads[threadNdx]->getStatus() == TestThread::THREADSTATUS_NOT_SUPPORTED) 342 notSupported = true; 343 } 344 345 // Get logs 346 { 347 vector<int> messageNdx; 348 349 messageNdx.resize(m_threads.size(), 0); 350 351 while (true) 352 { 353 int nextThreadNdx = -1; 354 deUint64 nextThreadTimeUs = 0; 355 356 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 357 { 358 if (messageNdx[threadNdx] >= (int)m_threads[threadNdx]->getLog().getMessages().size()) 359 continue; 360 361 if (nextThreadNdx == -1 || nextThreadTimeUs > m_threads[threadNdx]->getLog().getMessages()[messageNdx[threadNdx]].timeUs) 362 { 363 nextThreadNdx = threadNdx; 364 nextThreadTimeUs = m_threads[threadNdx]->getLog().getMessages()[messageNdx[threadNdx]].timeUs; 365 } 366 } 367 368 if (nextThreadNdx == -1) 369 break; 370 371 m_testCtx.getLog() << tcu::TestLog::Message << "[" << (nextThreadTimeUs - m_startTimeUs) << "] (" << nextThreadNdx << ") " << m_threads[nextThreadNdx]->getLog().getMessages()[messageNdx[nextThreadNdx]].msg << tcu::TestLog::EndMessage; 372 373 messageNdx[nextThreadNdx]++; 374 } 375 } 376 377 // Destroy threads 378 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 379 delete m_threads[threadNdx]; 380 381 m_threads.clear(); 382 383 // Set result 384 if (isOk) 385 { 386 if (notSupported) 387 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); 388 else 389 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 390 } 391 else 392 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 393 394 return STOP; 395 } 396 else 397 { 398 // Check for timeout 399 const deUint64 currentTimeUs = deGetMicroseconds(); 400 401 if (currentTimeUs - m_startTimeUs > m_timeoutUs) 402 { 403 // Get logs 404 { 405 vector<int> messageNdx; 406 407 messageNdx.resize(m_threads.size(), 0); 408 409 while (true) 410 { 411 int nextThreadNdx = -1; 412 deUint64 nextThreadTimeUs = 0; 413 414 for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++) 415 { 416 if (messageNdx[threadNdx] >= (int)m_threads[threadNdx]->getLog().getMessages().size()) 417 continue; 418 419 if (nextThreadNdx == -1 || nextThreadTimeUs > m_threads[threadNdx]->getLog().getMessages()[messageNdx[threadNdx]].timeUs) 420 { 421 nextThreadNdx = threadNdx; 422 nextThreadTimeUs = m_threads[threadNdx]->getLog().getMessages()[messageNdx[threadNdx]].timeUs; 423 } 424 } 425 426 if (nextThreadNdx == -1) 427 break; 428 429 m_testCtx.getLog() << tcu::TestLog::Message << "[" << (nextThreadTimeUs - m_startTimeUs) << "] (" << nextThreadNdx << ") " << m_threads[nextThreadNdx]->getLog().getMessages()[messageNdx[nextThreadNdx]].msg << tcu::TestLog::EndMessage; 430 431 messageNdx[nextThreadNdx]++; 432 } 433 } 434 435 m_testCtx.getLog() << tcu::TestLog::Message << "[" << (currentTimeUs - m_startTimeUs) << "] (-) Timeout, Limit: " << m_timeoutUs << "us" << tcu::TestLog::EndMessage; 436 m_testCtx.getLog() << tcu::TestLog::Message << "[" << (currentTimeUs - m_startTimeUs) << "] (-) Trying to perform resource cleanup..." << tcu::TestLog::EndMessage; 437 438 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 439 return STOP; 440 } 441 442 // Sleep 443 deSleep(10); 444 } 445 446 return CONTINUE; 447 } 448 449 namespace 450 { 451 452 const char* configAttributeToString (EGLint e) 453 { 454 switch (e) 455 { 456 case EGL_BUFFER_SIZE: return "EGL_BUFFER_SIZE"; 457 case EGL_RED_SIZE: return "EGL_RED_SIZE"; 458 case EGL_GREEN_SIZE: return "EGL_GREEN_SIZE"; 459 case EGL_BLUE_SIZE: return "EGL_BLUE_SIZE"; 460 case EGL_LUMINANCE_SIZE: return "EGL_LUMINANCE_SIZE"; 461 case EGL_ALPHA_SIZE: return "EGL_ALPHA_SIZE"; 462 case EGL_ALPHA_MASK_SIZE: return "EGL_ALPHA_MASK_SIZE"; 463 case EGL_BIND_TO_TEXTURE_RGB: return "EGL_BIND_TO_TEXTURE_RGB"; 464 case EGL_BIND_TO_TEXTURE_RGBA: return "EGL_BIND_TO_TEXTURE_RGBA"; 465 case EGL_COLOR_BUFFER_TYPE: return "EGL_COLOR_BUFFER_TYPE"; 466 case EGL_CONFIG_CAVEAT: return "EGL_CONFIG_CAVEAT"; 467 case EGL_CONFIG_ID: return "EGL_CONFIG_ID"; 468 case EGL_CONFORMANT: return "EGL_CONFORMANT"; 469 case EGL_DEPTH_SIZE: return "EGL_DEPTH_SIZE"; 470 case EGL_LEVEL: return "EGL_LEVEL"; 471 case EGL_MAX_PBUFFER_WIDTH: return "EGL_MAX_PBUFFER_WIDTH"; 472 case EGL_MAX_PBUFFER_HEIGHT: return "EGL_MAX_PBUFFER_HEIGHT"; 473 case EGL_MAX_PBUFFER_PIXELS: return "EGL_MAX_PBUFFER_PIXELS"; 474 case EGL_MAX_SWAP_INTERVAL: return "EGL_MAX_SWAP_INTERVAL"; 475 case EGL_MIN_SWAP_INTERVAL: return "EGL_MIN_SWAP_INTERVAL"; 476 case EGL_NATIVE_RENDERABLE: return "EGL_NATIVE_RENDERABLE"; 477 case EGL_NATIVE_VISUAL_ID: return "EGL_NATIVE_VISUAL_ID"; 478 case EGL_NATIVE_VISUAL_TYPE: return "EGL_NATIVE_VISUAL_TYPE"; 479 case EGL_RENDERABLE_TYPE: return "EGL_RENDERABLE_TYPE"; 480 case EGL_SAMPLE_BUFFERS: return "EGL_SAMPLE_BUFFERS"; 481 case EGL_SAMPLES: return "EGL_SAMPLES"; 482 case EGL_STENCIL_SIZE: return "EGL_STENCIL_SIZE"; 483 case EGL_SURFACE_TYPE: return "EGL_SURFACE_TYPE"; 484 case EGL_TRANSPARENT_TYPE: return "EGL_TRANSPARENT_TYPE"; 485 case EGL_TRANSPARENT_RED_VALUE: return "EGL_TRANSPARENT_RED_VALUE"; 486 case EGL_TRANSPARENT_GREEN_VALUE: return "EGL_TRANSPARENT_GREEN_VALUE"; 487 case EGL_TRANSPARENT_BLUE_VALUE: return "EGL_TRANSPARENT_BLUE_VALUE"; 488 default: return "<Unknown>"; 489 } 490 } 491 492 } // anonymous 493 494 class MultiThreadedConfigTest : public MultiThreadedTest 495 { 496 public: 497 MultiThreadedConfigTest (EglTestContext& context, const char* name, const char* description, int getConfigs, int chooseConfigs, int query); 498 bool runThread (TestThread& thread); 499 500 private: 501 EGLDisplay m_display; 502 const int m_getConfigs; 503 const int m_chooseConfigs; 504 const int m_query; 505 }; 506 507 MultiThreadedConfigTest::MultiThreadedConfigTest (EglTestContext& context, const char* name, const char* description, int getConfigs, int chooseConfigs, int query) 508 : MultiThreadedTest (context, name, description, 2, 20000000/*us = 20s*/) // \todo [mika] Set timeout to something relevant to frameworks timeout? 509 , m_display (EGL_NO_DISPLAY) 510 , m_getConfigs (getConfigs) 511 , m_chooseConfigs (chooseConfigs) 512 , m_query (query) 513 { 514 } 515 516 bool MultiThreadedConfigTest::runThread (TestThread& thread) 517 { 518 de::Random rnd(deInt32Hash(thread.getId() + 10435)); 519 vector<EGLConfig> configs; 520 521 if (thread.getId() == 0) 522 m_display = m_eglTestCtx.getDisplay().getEGLDisplay(); 523 524 barrier(thread); 525 526 for (int getConfigsNdx = 0; getConfigsNdx < m_getConfigs; getConfigsNdx++) 527 { 528 EGLint configCount; 529 530 // Get number of configs 531 { 532 EGLBoolean result; 533 534 result = eglGetConfigs(m_display, NULL, 0, &configCount); 535 thread.getLog() << ThreadLog::BeginMessage << result << " = eglGetConfigs(" << m_display << ", NULL, 0, " << configCount << ")" << ThreadLog::EndMessage; 536 TCU_CHECK_EGL_MSG("eglGetConfigs()"); 537 538 if (!result) 539 return false; 540 } 541 542 configs.resize(configs.size() + configCount); 543 544 // Get configs 545 if (configCount != 0) 546 { 547 EGLBoolean result; 548 549 result = eglGetConfigs(m_display, &(configs[configs.size() - configCount]), configCount, &configCount); 550 thread.getLog() << ThreadLog::BeginMessage << result << " = eglGetConfigs(" << m_display << ", &configs' " << configCount << ", " << configCount << ")" << ThreadLog::EndMessage; 551 TCU_CHECK_EGL_MSG("eglGetConfigs()"); 552 553 if (!result) 554 return false; 555 } 556 557 // Pop configs to stop config list growing 558 if (configs.size() > 40) 559 { 560 configs.erase(configs.begin() + 40, configs.end()); 561 } 562 else 563 { 564 const int popCount = rnd.getInt(0, (int)(configs.size()-2)); 565 566 configs.erase(configs.begin() + (configs.size() - popCount), configs.end()); 567 } 568 } 569 570 for (int chooseConfigsNdx = 0; chooseConfigsNdx < m_chooseConfigs; chooseConfigsNdx++) 571 { 572 EGLint configCount; 573 574 static const EGLint attribList[] = { 575 EGL_NONE 576 }; 577 578 // Get number of configs 579 { 580 EGLBoolean result; 581 582 result = eglChooseConfig(m_display, attribList, NULL, 0, &configCount); 583 thread.getLog() << ThreadLog::BeginMessage << result << " = eglChooseConfig(" << m_display << ", { EGL_NONE }, NULL, 0, " << configCount << ")" << ThreadLog::EndMessage; 584 TCU_CHECK_EGL_MSG("eglChooseConfig()"); 585 586 if (!result) 587 return false; 588 } 589 590 configs.resize(configs.size() + configCount); 591 592 // Get configs 593 if (configCount != 0) 594 { 595 EGLBoolean result; 596 597 result = eglChooseConfig(m_display, attribList, &(configs[configs.size() - configCount]), configCount, &configCount); 598 thread.getLog() << ThreadLog::BeginMessage << result << " = eglChooseConfig(" << m_display << ", { EGL_NONE }, &configs, " << configCount << ", " << configCount << ")" << ThreadLog::EndMessage; 599 TCU_CHECK_EGL_MSG("eglChooseConfig()"); 600 601 if (!result) 602 return false; 603 } 604 605 // Pop configs to stop config list growing 606 if (configs.size() > 40) 607 { 608 configs.erase(configs.begin() + 40, configs.end()); 609 } 610 else 611 { 612 const int popCount = rnd.getInt(0, (int)(configs.size()-2)); 613 614 configs.erase(configs.begin() + (configs.size() - popCount), configs.end()); 615 } 616 } 617 618 { 619 // Perform queries on configs 620 static const EGLint attributes[] = 621 { 622 EGL_BUFFER_SIZE, 623 EGL_RED_SIZE, 624 EGL_GREEN_SIZE, 625 EGL_BLUE_SIZE, 626 EGL_LUMINANCE_SIZE, 627 EGL_ALPHA_SIZE, 628 EGL_ALPHA_MASK_SIZE, 629 EGL_BIND_TO_TEXTURE_RGB, 630 EGL_BIND_TO_TEXTURE_RGBA, 631 EGL_COLOR_BUFFER_TYPE, 632 EGL_CONFIG_CAVEAT, 633 EGL_CONFIG_ID, 634 EGL_CONFORMANT, 635 EGL_DEPTH_SIZE, 636 EGL_LEVEL, 637 EGL_MAX_PBUFFER_WIDTH, 638 EGL_MAX_PBUFFER_HEIGHT, 639 EGL_MAX_PBUFFER_PIXELS, 640 EGL_MAX_SWAP_INTERVAL, 641 EGL_MIN_SWAP_INTERVAL, 642 EGL_NATIVE_RENDERABLE, 643 EGL_NATIVE_VISUAL_ID, 644 EGL_NATIVE_VISUAL_TYPE, 645 EGL_RENDERABLE_TYPE, 646 EGL_SAMPLE_BUFFERS, 647 EGL_SAMPLES, 648 EGL_STENCIL_SIZE, 649 EGL_SURFACE_TYPE, 650 EGL_TRANSPARENT_TYPE, 651 EGL_TRANSPARENT_RED_VALUE, 652 EGL_TRANSPARENT_GREEN_VALUE, 653 EGL_TRANSPARENT_BLUE_VALUE 654 }; 655 656 for (int queryNdx = 0; queryNdx < m_query; queryNdx++) 657 { 658 const EGLint attribute = attributes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(attributes)-1)]; 659 EGLConfig config = configs[rnd.getInt(0, (int)(configs.size()-1))]; 660 EGLint value; 661 EGLBoolean result; 662 663 result = eglGetConfigAttrib(m_display, config, attribute, &value); 664 thread.getLog() << ThreadLog::BeginMessage << result << " = eglGetConfigAttrib(" << m_display << ", " << config << ", " << configAttributeToString(attribute) << ", " << value << ")" << ThreadLog::EndMessage; 665 TCU_CHECK_EGL_MSG("eglGetConfigAttrib()"); 666 667 if (!result) 668 return false; 669 } 670 } 671 672 return true; 673 } 674 675 class MultiThreadedObjectTest : public MultiThreadedTest 676 { 677 public: 678 enum Type 679 { 680 TYPE_PBUFFER = (1<<0), 681 TYPE_PIXMAP = (1<<1), 682 TYPE_WINDOW = (1<<2), 683 TYPE_SINGLE_WINDOW = (1<<3), 684 TYPE_CONTEXT = (1<<4) 685 }; 686 687 MultiThreadedObjectTest (EglTestContext& context, const char* name, const char* description, deUint32 types); 688 ~MultiThreadedObjectTest (void); 689 690 virtual void deinit (void); 691 692 bool runThread (TestThread& thread); 693 694 void createDestroyObjects (TestThread& thread, int count); 695 void pushObjectsToShared (TestThread& thread); 696 void pullObjectsFromShared (TestThread& thread, int pbufferCount, int pixmapCount, int windowCount, int contextCount); 697 void querySetSharedObjects (TestThread& thread, int count); 698 void destroyObjects (TestThread& thread); 699 700 private: 701 EGLDisplay m_display; 702 EGLConfig m_config; 703 de::Random m_rnd0; 704 de::Random m_rnd1; 705 Type m_types; 706 707 volatile deUint32 m_hasWindow; 708 709 vector<pair<eglu::NativePixmap*, EGLSurface> > m_sharedNativePixmaps; 710 vector<pair<eglu::NativePixmap*, EGLSurface> > m_nativePixmaps0; 711 vector<pair<eglu::NativePixmap*, EGLSurface> > m_nativePixmaps1; 712 713 vector<pair<eglu::NativeWindow*, EGLSurface> > m_sharedNativeWindows; 714 vector<pair<eglu::NativeWindow*, EGLSurface> > m_nativeWindows0; 715 vector<pair<eglu::NativeWindow*, EGLSurface> > m_nativeWindows1; 716 717 vector<EGLSurface> m_sharedPbuffers; 718 vector<EGLSurface> m_pbuffers0; 719 vector<EGLSurface> m_pbuffers1; 720 721 vector<EGLContext> m_sharedContexts; 722 vector<EGLContext> m_contexts0; 723 vector<EGLContext> m_contexts1; 724 }; 725 726 MultiThreadedObjectTest::MultiThreadedObjectTest (EglTestContext& context, const char* name, const char* description, deUint32 type) 727 : MultiThreadedTest (context, name, description, 2, 20000000/*us = 20s*/) // \todo [mika] Set timeout to something relevant to frameworks timeout? 728 , m_display (EGL_NO_DISPLAY) 729 , m_config (DE_NULL) 730 , m_rnd0 (58204327) 731 , m_rnd1 (230983) 732 , m_types ((Type)type) 733 , m_hasWindow (0) 734 { 735 } 736 737 MultiThreadedObjectTest::~MultiThreadedObjectTest (void) 738 { 739 deinit(); 740 } 741 742 void MultiThreadedObjectTest::deinit (void) 743 { 744 // Clear pbuffers 745 for (int pbufferNdx = 0; pbufferNdx < (int)m_pbuffers0.size(); pbufferNdx++) 746 { 747 if (m_pbuffers0[pbufferNdx] != EGL_NO_SURFACE) 748 { 749 eglDestroySurface(m_display, m_pbuffers0[pbufferNdx]); 750 TCU_CHECK_EGL_MSG("eglDestroySurface()"); 751 m_pbuffers0[pbufferNdx] = EGL_NO_SURFACE; 752 } 753 } 754 m_pbuffers0.clear(); 755 756 for (int pbufferNdx = 0; pbufferNdx < (int)m_pbuffers1.size(); pbufferNdx++) 757 { 758 if (m_pbuffers1[pbufferNdx] != EGL_NO_SURFACE) 759 { 760 eglDestroySurface(m_display, m_pbuffers1[pbufferNdx]); 761 TCU_CHECK_EGL_MSG("eglDestroySurface()"); 762 m_pbuffers1[pbufferNdx] = EGL_NO_SURFACE; 763 } 764 } 765 m_pbuffers1.clear(); 766 767 for (int pbufferNdx = 0; pbufferNdx < (int)m_sharedPbuffers.size(); pbufferNdx++) 768 { 769 if (m_sharedPbuffers[pbufferNdx] != EGL_NO_SURFACE) 770 { 771 eglDestroySurface(m_display, m_sharedPbuffers[pbufferNdx]); 772 TCU_CHECK_EGL_MSG("eglDestroySurface()"); 773 m_sharedPbuffers[pbufferNdx] = EGL_NO_SURFACE; 774 } 775 } 776 m_sharedPbuffers.clear(); 777 778 for (int contextNdx = 0; contextNdx < (int)m_sharedContexts.size(); contextNdx++) 779 { 780 if (m_sharedContexts[contextNdx] != EGL_NO_CONTEXT) 781 { 782 eglDestroyContext(m_display, m_sharedContexts[contextNdx]); 783 TCU_CHECK_EGL_MSG("eglDestroyContext()"); 784 m_sharedContexts[contextNdx] = EGL_NO_CONTEXT; 785 } 786 } 787 m_sharedContexts.clear(); 788 789 for (int contextNdx = 0; contextNdx < (int)m_contexts0.size(); contextNdx++) 790 { 791 if (m_contexts0[contextNdx] != EGL_NO_CONTEXT) 792 { 793 eglDestroyContext(m_display, m_contexts0[contextNdx]); 794 TCU_CHECK_EGL_MSG("eglDestroyContext()"); 795 m_contexts0[contextNdx] = EGL_NO_CONTEXT; 796 } 797 } 798 m_contexts0.clear(); 799 800 for (int contextNdx = 0; contextNdx < (int)m_contexts1.size(); contextNdx++) 801 { 802 if (m_contexts1[contextNdx] != EGL_NO_CONTEXT) 803 { 804 eglDestroyContext(m_display, m_contexts1[contextNdx]); 805 TCU_CHECK_EGL_MSG("eglDestroyContext()"); 806 m_contexts1[contextNdx] = EGL_NO_CONTEXT; 807 } 808 } 809 m_contexts1.clear(); 810 811 // Clear pixmaps 812 for (int pixmapNdx = 0; pixmapNdx < (int)m_nativePixmaps0.size(); pixmapNdx++) 813 { 814 if (m_nativePixmaps0[pixmapNdx].second != EGL_NO_SURFACE) 815 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, m_nativePixmaps0[pixmapNdx].second)); 816 817 m_nativePixmaps0[pixmapNdx].second = EGL_NO_SURFACE; 818 delete m_nativePixmaps0[pixmapNdx].first; 819 m_nativePixmaps0[pixmapNdx].first = NULL; 820 } 821 m_nativePixmaps0.clear(); 822 823 for (int pixmapNdx = 0; pixmapNdx < (int)m_nativePixmaps1.size(); pixmapNdx++) 824 { 825 if (m_nativePixmaps1[pixmapNdx].second != EGL_NO_SURFACE) 826 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, m_nativePixmaps1[pixmapNdx].second)); 827 828 m_nativePixmaps1[pixmapNdx].second = EGL_NO_SURFACE; 829 delete m_nativePixmaps1[pixmapNdx].first; 830 m_nativePixmaps1[pixmapNdx].first = NULL; 831 } 832 m_nativePixmaps1.clear(); 833 834 for (int pixmapNdx = 0; pixmapNdx < (int)m_sharedNativePixmaps.size(); pixmapNdx++) 835 { 836 if (m_sharedNativePixmaps[pixmapNdx].second != EGL_NO_SURFACE) 837 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, m_sharedNativePixmaps[pixmapNdx].second)); 838 839 m_sharedNativePixmaps[pixmapNdx].second = EGL_NO_SURFACE; 840 delete m_sharedNativePixmaps[pixmapNdx].first; 841 m_sharedNativePixmaps[pixmapNdx].first = NULL; 842 } 843 m_sharedNativePixmaps.clear(); 844 845 // Clear windows 846 for (int windowNdx = 0; windowNdx < (int)m_nativeWindows1.size(); windowNdx++) 847 { 848 if (m_nativeWindows1[windowNdx].second != EGL_NO_SURFACE) 849 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, m_nativeWindows1[windowNdx].second)); 850 851 m_nativeWindows1[windowNdx].second = EGL_NO_SURFACE; 852 delete m_nativeWindows1[windowNdx].first; 853 m_nativeWindows1[windowNdx].first = NULL; 854 } 855 m_nativeWindows1.clear(); 856 857 for (int windowNdx = 0; windowNdx < (int)m_nativeWindows0.size(); windowNdx++) 858 { 859 if (m_nativeWindows0[windowNdx].second != EGL_NO_SURFACE) 860 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, m_nativeWindows0[windowNdx].second)); 861 862 m_nativeWindows0[windowNdx].second = EGL_NO_SURFACE; 863 delete m_nativeWindows0[windowNdx].first; 864 m_nativeWindows0[windowNdx].first = NULL; 865 } 866 m_nativeWindows0.clear(); 867 868 for (int windowNdx = 0; windowNdx < (int)m_sharedNativeWindows.size(); windowNdx++) 869 { 870 if (m_sharedNativeWindows[windowNdx].second != EGL_NO_SURFACE) 871 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, m_sharedNativeWindows[windowNdx].second)); 872 873 m_sharedNativeWindows[windowNdx].second = EGL_NO_SURFACE; 874 delete m_sharedNativeWindows[windowNdx].first; 875 m_sharedNativeWindows[windowNdx].first = NULL; 876 } 877 m_sharedNativeWindows.clear(); 878 } 879 880 bool MultiThreadedObjectTest::runThread (TestThread& thread) 881 { 882 if (thread.getId() == 0) 883 { 884 m_display = m_eglTestCtx.getDisplay().getEGLDisplay(); 885 886 EGLint surfaceTypes = 0; 887 888 if ((m_types & TYPE_WINDOW) != 0) 889 surfaceTypes |= EGL_WINDOW_BIT; 890 891 if ((m_types & TYPE_PBUFFER) != 0) 892 surfaceTypes |= EGL_PBUFFER_BIT; 893 894 if ((m_types & TYPE_PIXMAP) != 0) 895 surfaceTypes |= EGL_PIXMAP_BIT; 896 897 EGLint configCount; 898 EGLint attribList[] = 899 { 900 EGL_SURFACE_TYPE, surfaceTypes, 901 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 902 EGL_NONE 903 }; 904 905 TCU_CHECK_EGL_CALL(eglChooseConfig(m_display, attribList, &m_config, 1, &configCount)); 906 907 if (configCount == 0) 908 throw tcu::NotSupportedError("No usable config found", "", __FILE__, __LINE__); 909 } 910 911 barrier(thread); 912 913 // Create / Destroy Objects 914 if ((m_types & TYPE_SINGLE_WINDOW) != 0 && (m_types & TYPE_PBUFFER) == 0 && (m_types & TYPE_PIXMAP) == 0 && (m_types & TYPE_CONTEXT) == 0) 915 { 916 if (thread.getId() == 0) 917 createDestroyObjects(thread, 1); 918 } 919 else 920 createDestroyObjects(thread, 100); 921 922 // Push first threads objects to shared 923 if (thread.getId() == 0) 924 pushObjectsToShared(thread); 925 926 barrier(thread); 927 928 // Push second threads objects to shared 929 if (thread.getId() == 1) 930 pushObjectsToShared(thread); 931 932 barrier(thread); 933 934 // Make queries from shared surfaces 935 querySetSharedObjects(thread, 100); 936 937 barrier(thread); 938 939 // Pull surfaces for first thread from shared surfaces 940 if (thread.getId() == 0) 941 pullObjectsFromShared(thread, (int)(m_sharedPbuffers.size()/2), (int)(m_sharedNativePixmaps.size()/2), (int)(m_sharedNativeWindows.size()/2), (int)(m_sharedContexts.size()/2)); 942 943 barrier(thread); 944 945 // Pull surfaces for second thread from shared surfaces 946 if (thread.getId() == 1) 947 pullObjectsFromShared(thread, (int)m_sharedPbuffers.size(), (int)m_sharedNativePixmaps.size(), (int)m_sharedNativeWindows.size(), (int)m_sharedContexts.size()); 948 949 barrier(thread); 950 951 // Create / Destroy Objects 952 if ((m_types & TYPE_SINGLE_WINDOW) == 0) 953 createDestroyObjects(thread, 100); 954 955 // Destroy surfaces 956 destroyObjects(thread); 957 958 return true; 959 } 960 961 void MultiThreadedObjectTest::createDestroyObjects (TestThread& thread, int count) 962 { 963 de::Random& rnd = (thread.getId() == 0 ? m_rnd0 : m_rnd1); 964 vector<EGLSurface>& pbuffers = (thread.getId() == 0 ? m_pbuffers0 : m_pbuffers1); 965 vector<pair<eglu::NativeWindow*, EGLSurface> >& windows = (thread.getId() == 0 ? m_nativeWindows0 : m_nativeWindows1); 966 vector<pair<eglu::NativePixmap*, EGLSurface> >& pixmaps = (thread.getId() == 0 ? m_nativePixmaps0 : m_nativePixmaps1); 967 vector<EGLContext>& contexts = (thread.getId() == 0 ? m_contexts0 : m_contexts1); 968 969 vector<Type> objectTypes; 970 971 if ((m_types & TYPE_PBUFFER) != 0) 972 objectTypes.push_back(TYPE_PBUFFER); 973 974 if ((m_types & TYPE_PIXMAP) != 0) 975 objectTypes.push_back(TYPE_PIXMAP); 976 977 if ((m_types & TYPE_WINDOW) != 0) 978 objectTypes.push_back(TYPE_WINDOW); 979 980 if ((m_types & TYPE_CONTEXT) != 0) 981 objectTypes.push_back(TYPE_CONTEXT); 982 983 for (int createDestroyNdx = 0; createDestroyNdx < count; createDestroyNdx++) 984 { 985 bool create; 986 Type type; 987 988 if (pbuffers.size() > 5 && ((m_types & TYPE_PBUFFER) != 0)) 989 { 990 create = false; 991 type = TYPE_PBUFFER; 992 } 993 else if (windows.size() > 5 && ((m_types & TYPE_WINDOW) != 0)) 994 { 995 create = false; 996 type = TYPE_WINDOW; 997 } 998 else if (pixmaps.size() > 5 && ((m_types & TYPE_PIXMAP) != 0)) 999 { 1000 create = false; 1001 type = TYPE_PIXMAP; 1002 } 1003 else if (contexts.size() > 5 && ((m_types & TYPE_CONTEXT) != 0)) 1004 { 1005 create = false; 1006 type = TYPE_CONTEXT; 1007 } 1008 else if (pbuffers.size() < 3 && ((m_types & TYPE_PBUFFER) != 0)) 1009 { 1010 create = true; 1011 type = TYPE_PBUFFER; 1012 } 1013 else if (pixmaps.size() < 3 && ((m_types & TYPE_PIXMAP) != 0)) 1014 { 1015 create = true; 1016 type = TYPE_PIXMAP; 1017 } 1018 else if (contexts.size() < 3 && ((m_types & TYPE_CONTEXT) != 0)) 1019 { 1020 create = true; 1021 type = TYPE_CONTEXT; 1022 } 1023 else if (windows.size() < 3 && ((m_types & TYPE_WINDOW) != 0) && ((m_types & TYPE_SINGLE_WINDOW) == 0)) 1024 { 1025 create = true; 1026 type = TYPE_WINDOW; 1027 } 1028 else if (windows.empty() && ((m_types & TYPE_WINDOW) != 0) && ((m_types & TYPE_SINGLE_WINDOW) != 0)) 1029 { 1030 create = true; 1031 type = TYPE_WINDOW; 1032 } 1033 else 1034 { 1035 create = rnd.getBool(); 1036 type = rnd.choose<Type>(objectTypes.begin(), objectTypes.end()); 1037 } 1038 1039 if (create) 1040 { 1041 switch (type) 1042 { 1043 case TYPE_PBUFFER: 1044 { 1045 EGLSurface surface; 1046 1047 const EGLint attributes[] = 1048 { 1049 EGL_WIDTH, 64, 1050 EGL_HEIGHT, 64, 1051 1052 EGL_NONE 1053 }; 1054 1055 surface = eglCreatePbufferSurface(m_display, m_config, attributes); 1056 thread.getLog() << ThreadLog::BeginMessage << surface << " = eglCreatePbufferSurface(" << m_display << ", " << m_config << ", { EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE })" << ThreadLog::EndMessage; 1057 TCU_CHECK_EGL_MSG("eglCreatePbufferSurface()"); 1058 1059 pbuffers.push_back(surface); 1060 1061 break; 1062 } 1063 1064 case TYPE_WINDOW: 1065 { 1066 if ((m_types & TYPE_SINGLE_WINDOW) != 0) 1067 { 1068 if (deAtomicCompareExchange32(&m_hasWindow, 0, 1) == 0) 1069 { 1070 eglu::NativeWindow* window = DE_NULL; 1071 EGLSurface surface = EGL_NO_SURFACE; 1072 1073 try 1074 { 1075 window = m_eglTestCtx.createNativeWindow(m_eglTestCtx.getDisplay().getEGLDisplay(), m_config, DE_NULL, 64, 64, eglu::parseWindowVisibility(m_testCtx.getCommandLine())); 1076 surface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, m_eglTestCtx.getDisplay().getEGLDisplay(), m_config, DE_NULL); 1077 1078 thread.getLog() << ThreadLog::BeginMessage << surface << " = eglCreateWindowSurface()" << ThreadLog::EndMessage; 1079 windows.push_back(std::make_pair(window, surface)); 1080 } 1081 catch (const std::exception&) 1082 { 1083 if (surface != EGL_NO_SURFACE) 1084 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, surface)); 1085 delete window; 1086 throw; 1087 } 1088 } 1089 else 1090 { 1091 createDestroyNdx--; 1092 } 1093 } 1094 else 1095 { 1096 eglu::NativeWindow* window = DE_NULL; 1097 EGLSurface surface = EGL_NO_SURFACE; 1098 1099 try 1100 { 1101 window = m_eglTestCtx.createNativeWindow(m_eglTestCtx.getDisplay().getEGLDisplay(), m_config, DE_NULL, 64, 64, eglu::parseWindowVisibility(m_testCtx.getCommandLine())); 1102 surface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, m_eglTestCtx.getDisplay().getEGLDisplay(), m_config, DE_NULL); 1103 1104 thread.getLog() << ThreadLog::BeginMessage << surface << " = eglCreateWindowSurface()" << ThreadLog::EndMessage; 1105 windows.push_back(std::make_pair(window, surface)); 1106 } 1107 catch (const std::exception&) 1108 { 1109 if (surface != EGL_NO_SURFACE) 1110 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, surface)); 1111 delete window; 1112 throw; 1113 } 1114 } 1115 break; 1116 } 1117 1118 case TYPE_PIXMAP: 1119 { 1120 eglu::NativePixmap* pixmap = DE_NULL; 1121 EGLSurface surface = EGL_NO_SURFACE; 1122 1123 try 1124 { 1125 pixmap = m_eglTestCtx.createNativePixmap(m_eglTestCtx.getDisplay().getEGLDisplay(), m_config, DE_NULL, 64, 64); 1126 surface = eglu::createPixmapSurface(m_eglTestCtx.getNativeDisplay(), *pixmap, m_eglTestCtx.getDisplay().getEGLDisplay(), m_config, DE_NULL); 1127 1128 thread.getLog() << ThreadLog::BeginMessage << surface << " = eglCreatePixmapSurface()" << ThreadLog::EndMessage; 1129 pixmaps.push_back(std::make_pair(pixmap, surface)); 1130 } 1131 catch (const std::exception&) 1132 { 1133 if (surface != EGL_NO_SURFACE) 1134 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, surface)); 1135 delete pixmap; 1136 throw; 1137 } 1138 break; 1139 } 1140 1141 case TYPE_CONTEXT: 1142 { 1143 EGLContext context; 1144 1145 TCU_CHECK_EGL_CALL(eglBindAPI(EGL_OPENGL_ES_API)); 1146 thread.getLog() << ThreadLog::BeginMessage << "eglBindAPI(EGL_OPENGL_ES_API)" << ThreadLog::EndMessage; 1147 1148 const EGLint attributes[] = 1149 { 1150 EGL_CONTEXT_CLIENT_VERSION, 2, 1151 EGL_NONE 1152 }; 1153 1154 context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, attributes); 1155 thread.getLog() << ThreadLog::BeginMessage << context << " = eglCreateContext(" << m_display << ", " << m_config << ", EGL_NO_CONTEXT, { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE })" << ThreadLog::EndMessage; 1156 TCU_CHECK_EGL_MSG("eglCreateContext()"); 1157 contexts.push_back(context); 1158 break; 1159 } 1160 1161 default: 1162 DE_ASSERT(false); 1163 }; 1164 } 1165 else 1166 { 1167 switch (type) 1168 { 1169 case TYPE_PBUFFER: 1170 { 1171 const int pbufferNdx = rnd.getInt(0, (int)(pbuffers.size()-1)); 1172 EGLBoolean result; 1173 1174 result = eglDestroySurface(m_display, pbuffers[pbufferNdx]); 1175 thread.getLog() << ThreadLog::BeginMessage << result << " = eglDestroySurface(" << m_display << ", " << pbuffers[pbufferNdx] << ")" << ThreadLog::EndMessage; 1176 TCU_CHECK_EGL_MSG("eglDestroySurface()"); 1177 1178 pbuffers.erase(pbuffers.begin() + pbufferNdx); 1179 1180 break; 1181 } 1182 1183 case TYPE_WINDOW: 1184 { 1185 const int windowNdx = rnd.getInt(0, (int)(windows.size()-1)); 1186 1187 thread.getLog() << ThreadLog::BeginMessage << "eglDestroySurface(" << m_display << ", " << windows[windowNdx].second << ")" << ThreadLog::EndMessage; 1188 1189 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, windows[windowNdx].second)); 1190 windows[windowNdx].second = EGL_NO_SURFACE; 1191 delete windows[windowNdx].first; 1192 windows[windowNdx].first = DE_NULL; 1193 windows.erase(windows.begin() + windowNdx); 1194 1195 if ((m_types & TYPE_SINGLE_WINDOW) != 0) 1196 m_hasWindow = 0; 1197 1198 break; 1199 } 1200 1201 case TYPE_PIXMAP: 1202 { 1203 const int pixmapNdx = rnd.getInt(0, (int)(pixmaps.size()-1)); 1204 1205 thread.getLog() << ThreadLog::BeginMessage << "eglDestroySurface(" << m_display << ", " << pixmaps[pixmapNdx].second << ")" << ThreadLog::EndMessage; 1206 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, pixmaps[pixmapNdx].second)); 1207 pixmaps[pixmapNdx].second = EGL_NO_SURFACE; 1208 delete pixmaps[pixmapNdx].first; 1209 pixmaps[pixmapNdx].first = DE_NULL; 1210 pixmaps.erase(pixmaps.begin() + pixmapNdx); 1211 1212 break; 1213 } 1214 1215 case TYPE_CONTEXT: 1216 { 1217 const int contextNdx = rnd.getInt(0, (int)(contexts.size()-1)); 1218 1219 TCU_CHECK_EGL_CALL(eglDestroyContext(m_display, contexts[contextNdx])); 1220 thread.getLog() << ThreadLog::BeginMessage << "eglDestroyContext(" << m_display << ", " << contexts[contextNdx] << ")" << ThreadLog::EndMessage; 1221 contexts.erase(contexts.begin() + contextNdx); 1222 1223 break; 1224 } 1225 1226 default: 1227 DE_ASSERT(false); 1228 } 1229 1230 } 1231 } 1232 } 1233 1234 void MultiThreadedObjectTest::pushObjectsToShared (TestThread& thread) 1235 { 1236 vector<EGLSurface>& pbuffers = (thread.getId() == 0 ? m_pbuffers0 : m_pbuffers1); 1237 vector<pair<eglu::NativeWindow*, EGLSurface> >& windows = (thread.getId() == 0 ? m_nativeWindows0 : m_nativeWindows1); 1238 vector<pair<eglu::NativePixmap*, EGLSurface> >& pixmaps = (thread.getId() == 0 ? m_nativePixmaps0 : m_nativePixmaps1); 1239 vector<EGLContext>& contexts = (thread.getId() == 0 ? m_contexts0 : m_contexts1); 1240 1241 for (int pbufferNdx = 0; pbufferNdx < (int)pbuffers.size(); pbufferNdx++) 1242 m_sharedPbuffers.push_back(pbuffers[pbufferNdx]); 1243 1244 pbuffers.clear(); 1245 1246 for (int windowNdx = 0; windowNdx < (int)windows.size(); windowNdx++) 1247 m_sharedNativeWindows.push_back(windows[windowNdx]); 1248 1249 windows.clear(); 1250 1251 for (int pixmapNdx = 0; pixmapNdx < (int)pixmaps.size(); pixmapNdx++) 1252 m_sharedNativePixmaps.push_back(pixmaps[pixmapNdx]); 1253 1254 pixmaps.clear(); 1255 1256 for (int contextNdx = 0; contextNdx < (int)contexts.size(); contextNdx++) 1257 m_sharedContexts.push_back(contexts[contextNdx]); 1258 1259 contexts.clear(); 1260 } 1261 1262 void MultiThreadedObjectTest::pullObjectsFromShared (TestThread& thread, int pbufferCount, int pixmapCount, int windowCount, int contextCount) 1263 { 1264 de::Random& rnd = (thread.getId() == 0 ? m_rnd0 : m_rnd1); 1265 vector<EGLSurface>& pbuffers = (thread.getId() == 0 ? m_pbuffers0 : m_pbuffers1); 1266 vector<pair<eglu::NativeWindow*, EGLSurface> >& windows = (thread.getId() == 0 ? m_nativeWindows0 : m_nativeWindows1); 1267 vector<pair<eglu::NativePixmap*, EGLSurface> >& pixmaps = (thread.getId() == 0 ? m_nativePixmaps0 : m_nativePixmaps1); 1268 vector<EGLContext>& contexts = (thread.getId() == 0 ? m_contexts0 : m_contexts1); 1269 1270 for (int pbufferNdx = 0; pbufferNdx < pbufferCount; pbufferNdx++) 1271 { 1272 const int ndx = rnd.getInt(0, (int)(m_sharedPbuffers.size()-1)); 1273 1274 pbuffers.push_back(m_sharedPbuffers[ndx]); 1275 m_sharedPbuffers.erase(m_sharedPbuffers.begin() + ndx); 1276 } 1277 1278 for (int pixmapNdx = 0; pixmapNdx < pixmapCount; pixmapNdx++) 1279 { 1280 const int ndx = rnd.getInt(0, (int)(m_sharedNativePixmaps.size()-1)); 1281 1282 pixmaps.push_back(m_sharedNativePixmaps[ndx]); 1283 m_sharedNativePixmaps.erase(m_sharedNativePixmaps.begin() + ndx); 1284 } 1285 1286 for (int windowNdx = 0; windowNdx < windowCount; windowNdx++) 1287 { 1288 const int ndx = rnd.getInt(0, (int)(m_sharedNativeWindows.size()-1)); 1289 1290 windows.push_back(m_sharedNativeWindows[ndx]); 1291 m_sharedNativeWindows.erase(m_sharedNativeWindows.begin() + ndx); 1292 } 1293 1294 for (int contextNdx = 0; contextNdx < contextCount; contextNdx++) 1295 { 1296 const int ndx = rnd.getInt(0, (int)(m_sharedContexts.size()-1)); 1297 1298 contexts.push_back(m_sharedContexts[ndx]); 1299 m_sharedContexts.erase(m_sharedContexts.begin() + ndx); 1300 } 1301 } 1302 1303 void MultiThreadedObjectTest::querySetSharedObjects (TestThread& thread, int count) 1304 { 1305 de::Random& rnd = (thread.getId() == 0 ? m_rnd0 : m_rnd1); 1306 vector<Type> objectTypes; 1307 1308 if ((m_types & TYPE_PBUFFER) != 0) 1309 objectTypes.push_back(TYPE_PBUFFER); 1310 1311 if ((m_types & TYPE_PIXMAP) != 0) 1312 objectTypes.push_back(TYPE_PIXMAP); 1313 1314 if ((m_types & TYPE_WINDOW) != 0) 1315 objectTypes.push_back(TYPE_WINDOW); 1316 1317 if ((m_types & TYPE_CONTEXT) != 0) 1318 objectTypes.push_back(TYPE_CONTEXT); 1319 1320 for (int queryNdx = 0; queryNdx < count; queryNdx++) 1321 { 1322 const Type type = rnd.choose<Type>(objectTypes.begin(), objectTypes.end()); 1323 EGLSurface surface = EGL_NO_SURFACE; 1324 EGLContext context = EGL_NO_CONTEXT; 1325 1326 switch (type) 1327 { 1328 case TYPE_PBUFFER: 1329 surface = m_sharedPbuffers[rnd.getInt(0, (int)(m_sharedPbuffers.size()-1))]; 1330 break; 1331 1332 case TYPE_PIXMAP: 1333 surface = m_sharedNativePixmaps[rnd.getInt(0, (int)(m_sharedNativePixmaps.size()-1))].second; 1334 break; 1335 1336 case TYPE_WINDOW: 1337 surface = m_sharedNativeWindows[rnd.getInt(0, (int)(m_sharedNativeWindows.size()-1))].second; 1338 break; 1339 1340 case TYPE_CONTEXT: 1341 context = m_sharedContexts[rnd.getInt(0, (int)(m_sharedContexts.size()-1))]; 1342 break; 1343 1344 default: 1345 DE_ASSERT(false); 1346 } 1347 1348 if (surface != EGL_NO_SURFACE) 1349 { 1350 static const EGLint queryAttributes[] = 1351 { 1352 EGL_LARGEST_PBUFFER, 1353 EGL_HEIGHT, 1354 EGL_WIDTH 1355 }; 1356 1357 const EGLint attribute = queryAttributes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(queryAttributes) - 1)]; 1358 EGLBoolean result; 1359 EGLint value; 1360 1361 result = eglQuerySurface(m_display, surface, attribute, &value); 1362 thread.getLog() << ThreadLog::BeginMessage << result << " = eglQuerySurface(" << m_display << ", " << surface << ", " << attribute << ", " << value << ")" << ThreadLog::EndMessage; 1363 TCU_CHECK_EGL_MSG("eglQuerySurface()"); 1364 1365 } 1366 else if (context != EGL_NO_CONTEXT) 1367 { 1368 static const EGLint attributes[] = 1369 { 1370 EGL_CONFIG_ID, 1371 EGL_CONTEXT_CLIENT_TYPE, 1372 EGL_CONTEXT_CLIENT_VERSION, 1373 EGL_RENDER_BUFFER 1374 }; 1375 1376 const EGLint attribute = attributes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(attributes)-1)]; 1377 EGLint value; 1378 EGLBoolean result; 1379 1380 result = eglQueryContext(m_display, context, attribute, &value); 1381 thread.getLog() << ThreadLog::BeginMessage << result << " = eglQueryContext(" << m_display << ", " << context << ", " << attribute << ", " << value << ")" << ThreadLog::EndMessage; 1382 TCU_CHECK_EGL_MSG("eglQueryContext()"); 1383 1384 } 1385 else 1386 DE_ASSERT(false); 1387 } 1388 } 1389 1390 void MultiThreadedObjectTest::destroyObjects (TestThread& thread) 1391 { 1392 vector<EGLSurface>& pbuffers = (thread.getId() == 0 ? m_pbuffers0 : m_pbuffers1); 1393 vector<pair<eglu::NativeWindow*, EGLSurface> >& windows = (thread.getId() == 0 ? m_nativeWindows0 : m_nativeWindows1); 1394 vector<pair<eglu::NativePixmap*, EGLSurface> >& pixmaps = (thread.getId() == 0 ? m_nativePixmaps0 : m_nativePixmaps1); 1395 vector<EGLContext>& contexts = (thread.getId() == 0 ? m_contexts0 : m_contexts1); 1396 1397 for (int pbufferNdx = 0; pbufferNdx < (int)pbuffers.size(); pbufferNdx++) 1398 { 1399 if (pbuffers[pbufferNdx] != EGL_NO_SURFACE) 1400 { 1401 // Destroy EGLSurface 1402 EGLBoolean result; 1403 1404 result = eglDestroySurface(m_display, pbuffers[pbufferNdx]); 1405 thread.getLog() << ThreadLog::BeginMessage << result << " = eglDestroySurface(" << m_display << ", " << pbuffers[pbufferNdx] << ")" << ThreadLog::EndMessage; 1406 TCU_CHECK_EGL_MSG("eglDestroySurface()"); 1407 pbuffers[pbufferNdx] = EGL_NO_SURFACE; 1408 } 1409 } 1410 pbuffers.clear(); 1411 1412 for (int windowNdx = 0; windowNdx < (int)windows.size(); windowNdx++) 1413 { 1414 if (windows[windowNdx].second != EGL_NO_SURFACE) 1415 { 1416 thread.getLog() << ThreadLog::BeginMessage << "eglDestroySurface(" << m_display << ", " << windows[windowNdx].second << ")" << ThreadLog::EndMessage; 1417 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, windows[windowNdx].second)); 1418 windows[windowNdx].second = EGL_NO_SURFACE; 1419 } 1420 1421 if (windows[windowNdx].first) 1422 { 1423 delete windows[windowNdx].first; 1424 windows[windowNdx].first = NULL; 1425 } 1426 } 1427 windows.clear(); 1428 1429 for (int pixmapNdx = 0; pixmapNdx < (int)pixmaps.size(); pixmapNdx++) 1430 { 1431 if (pixmaps[pixmapNdx].first != EGL_NO_SURFACE) 1432 { 1433 thread.getLog() << ThreadLog::BeginMessage << "eglDestroySurface(" << m_display << ", " << pixmaps[pixmapNdx].second << ")" << ThreadLog::EndMessage; 1434 TCU_CHECK_EGL_CALL(eglDestroySurface(m_display, pixmaps[pixmapNdx].second)); 1435 pixmaps[pixmapNdx].second = EGL_NO_SURFACE; 1436 } 1437 1438 if (pixmaps[pixmapNdx].first) 1439 { 1440 delete pixmaps[pixmapNdx].first; 1441 pixmaps[pixmapNdx].first = NULL; 1442 } 1443 } 1444 pixmaps.clear(); 1445 1446 for (int contextNdx = 0; contextNdx < (int)contexts.size(); contextNdx++) 1447 { 1448 if (contexts[contextNdx] != EGL_NO_CONTEXT) 1449 { 1450 TCU_CHECK_EGL_CALL(eglDestroyContext(m_display, contexts[contextNdx])); 1451 thread.getLog() << ThreadLog::BeginMessage << "eglDestroyContext(" << m_display << ", " << contexts[contextNdx] << ")" << ThreadLog::EndMessage; 1452 contexts[contextNdx] = EGL_NO_CONTEXT; 1453 } 1454 } 1455 contexts.clear(); 1456 } 1457 1458 MultiThreadedTests::MultiThreadedTests (EglTestContext& context) 1459 : TestCaseGroup(context, "multithread", "Multithreaded EGL tests") 1460 { 1461 } 1462 1463 void MultiThreadedTests::init (void) 1464 { 1465 // Config tests 1466 addChild(new MultiThreadedConfigTest(m_eglTestCtx, "config", "", 30, 30, 30)); 1467 1468 // Object tests 1469 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer", "", MultiThreadedObjectTest::TYPE_PBUFFER)); 1470 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap", "", MultiThreadedObjectTest::TYPE_PIXMAP)); 1471 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "window", "", MultiThreadedObjectTest::TYPE_WINDOW)); 1472 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "single_window", "", MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_SINGLE_WINDOW)); 1473 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "context", "", MultiThreadedObjectTest::TYPE_CONTEXT)); 1474 1475 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_PIXMAP)); 1476 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_window", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_WINDOW)); 1477 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_single_window", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_SINGLE_WINDOW)); 1478 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_context", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_CONTEXT)); 1479 1480 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_window", "", MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_WINDOW)); 1481 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_single_window", "", MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_SINGLE_WINDOW)); 1482 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_context", "", MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_CONTEXT)); 1483 1484 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "window_context", "", MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_CONTEXT)); 1485 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "single_window_context", "", MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_SINGLE_WINDOW|MultiThreadedObjectTest::TYPE_CONTEXT)); 1486 1487 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_window", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_WINDOW)); 1488 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_single_window", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_SINGLE_WINDOW)); 1489 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_context", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_CONTEXT)); 1490 1491 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_window_context", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_CONTEXT)); 1492 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_single_window_context", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_SINGLE_WINDOW|MultiThreadedObjectTest::TYPE_CONTEXT)); 1493 1494 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_window_context", "", MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_CONTEXT)); 1495 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_single_window_context", "", MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_SINGLE_WINDOW|MultiThreadedObjectTest::TYPE_CONTEXT)); 1496 1497 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_window_context", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_CONTEXT)); 1498 addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_single_window_context", "", MultiThreadedObjectTest::TYPE_PBUFFER|MultiThreadedObjectTest::TYPE_PIXMAP|MultiThreadedObjectTest::TYPE_WINDOW|MultiThreadedObjectTest::TYPE_SINGLE_WINDOW|MultiThreadedObjectTest::TYPE_CONTEXT)); 1499 } 1500 1501 } // egl 1502 } // deqp 1503