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