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