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 	{
Messagedeqp::egl::ThreadLog::Message70 					Message	(deUint64 timeUs_, const char* msg_) : timeUs(timeUs_), msg(msg_) {}
71 
72 		deUint64	timeUs;
73 		string		msg;
74 	};
75 
ThreadLog(void)76 								ThreadLog	(void)						{ m_messages.reserve(100); }
77 
operator <<(const BeginMessageToken &)78 	ThreadLog&					operator<<	(const BeginMessageToken&)	{ return *this; }
79 	ThreadLog&					operator<<	(const EndMessageToken&);
80 
81 	template<class T>
operator <<(const T & t)82 	ThreadLog&					operator<< 	(const T& t)				{ m_message << t; return *this; }
getMessages(void) const83 	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 
operator <<(const EndMessageToken &)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 
getStatus(void) const121 	ThreadStatus	getStatus	(void) const	{ return m_status; }
getLog(void)122 	ThreadLog&		getLog		(void)			{ return m_log; }
123 
getId(void) const124 	int				getId		(void) const	{ return m_id; }
125 
setStatus(ThreadStatus status)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 
getLibrary(void) const154 	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 
getLibrary(void) const174 inline const Library& TestThread::getLibrary (void) const
175 {
176 	return m_test.getLibrary();
177 }
178 
TestThread(MultiThreadedTest & test,int id)179 TestThread::TestThread (MultiThreadedTest& test, int id)
180 	: m_test	(test)
181 	, m_id		(id)
182 	, m_status	(THREADSTATUS_NOT_STARTED)
183 {
184 }
185 
run(void)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 
execTest(TestThread & thread)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 
MultiThreadedTest(EglTestContext & eglTestCtx,const char * name,const char * description,int threadCount,deUint64 timeoutUs)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 
~MultiThreadedTest(void)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 
init(void)284 void MultiThreadedTest::init (void)
285 {
286 	m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
287 }
288 
deinit(void)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 
barrier(TestThread & thread)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 
iterate(void)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 
configAttributeToString(EGLint e)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 
MultiThreadedConfigTest(EglTestContext & context,const char * name,const char * description,int getConfigs,int chooseConfigs,int query)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 
runThread(TestThread & thread)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 
MultiThreadedObjectTest(EglTestContext & context,const char * name,const char * description,deUint32 type)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 
~MultiThreadedObjectTest(void)767 MultiThreadedObjectTest::~MultiThreadedObjectTest (void)
768 {
769 	deinit();
770 }
771 
deinit(void)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 
runThread(TestThread & thread)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 
createDestroyObjects(TestThread & thread,int count)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 
pushObjectsToShared(TestThread & thread)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 
pullObjectsFromShared(TestThread & thread,int pbufferCount,int pixmapCount,int windowCount,int contextCount)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 
querySetSharedObjects(TestThread & thread,int count)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 
destroyObjects(TestThread & thread)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 
MultiThreadedTests(EglTestContext & context)1502 MultiThreadedTests::MultiThreadedTests (EglTestContext& context)
1503 	: TestCaseGroup(context, "multithread", "Multithreaded EGL tests")
1504 {
1505 }
1506 
init(void)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