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