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