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 
    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
   1531