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 {
Messagedeqp::egl::ThreadLog::Message70 Message (deUint64 timeUs_, const char* msg_) : timeUs(timeUs_), msg(msg_) {}
71
72 deUint64 timeUs;
73 string msg;
74 };
75
ThreadLog(void)76 ThreadLog (void) { m_messages.reserve(100); }
77
operator <<(const BeginMessageToken &)78 ThreadLog& operator<< (const BeginMessageToken&) { return *this; }
79 ThreadLog& operator<< (const EndMessageToken&);
80
81 template<class T>
operator <<(const T & t)82 ThreadLog& operator<< (const T& t) { m_message << t; return *this; }
getMessages(void) const83 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
operator <<(const EndMessageToken &)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
getStatus(void) const121 ThreadStatus getStatus (void) const { return m_status; }
getLog(void)122 ThreadLog& getLog (void) { return m_log; }
123
getId(void) const124 int getId (void) const { return m_id; }
125
setStatus(ThreadStatus status)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
getLibrary(void) const154 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
getLibrary(void) const174 inline const Library& TestThread::getLibrary (void) const
175 {
176 return m_test.getLibrary();
177 }
178
TestThread(MultiThreadedTest & test,int id)179 TestThread::TestThread (MultiThreadedTest& test, int id)
180 : m_test (test)
181 , m_id (id)
182 , m_status (THREADSTATUS_NOT_STARTED)
183 {
184 }
185
run(void)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
execTest(TestThread & thread)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
MultiThreadedTest(EglTestContext & eglTestCtx,const char * name,const char * description,int threadCount,deUint64 timeoutUs)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
~MultiThreadedTest(void)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
init(void)284 void MultiThreadedTest::init (void)
285 {
286 m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
287 }
288
deinit(void)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
barrier(TestThread & thread)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
iterate(void)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
configAttributeToString(EGLint e)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
MultiThreadedConfigTest(EglTestContext & context,const char * name,const char * description,int getConfigs,int chooseConfigs,int query)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
runThread(TestThread & thread)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
MultiThreadedObjectTest(EglTestContext & context,const char * name,const char * description,deUint32 type)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
~MultiThreadedObjectTest(void)767 MultiThreadedObjectTest::~MultiThreadedObjectTest (void)
768 {
769 deinit();
770 }
771
deinit(void)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
runThread(TestThread & thread)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
createDestroyObjects(TestThread & thread,int count)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
pushObjectsToShared(TestThread & thread)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
pullObjectsFromShared(TestThread & thread,int pbufferCount,int pixmapCount,int windowCount,int contextCount)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
querySetSharedObjects(TestThread & thread,int count)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
destroyObjects(TestThread & thread)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
MultiThreadedTests(EglTestContext & context)1502 MultiThreadedTests::MultiThreadedTests (EglTestContext& context)
1503 : TestCaseGroup(context, "multithread", "Multithreaded EGL tests")
1504 {
1505 }
1506
init(void)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