Home | History | Annotate | Download | only in egl
      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
   1547