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