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