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