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 eglMakeCurrent performance tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "teglMakeCurrentPerfTests.hpp"
25 
26 #include "egluNativeWindow.hpp"
27 #include "egluNativePixmap.hpp"
28 #include "egluUtil.hpp"
29 
30 #include "eglwLibrary.hpp"
31 #include "eglwEnums.hpp"
32 
33 #include "tcuTestLog.hpp"
34 
35 #include "deRandom.hpp"
36 #include "deStringUtil.hpp"
37 
38 #include "deClock.h"
39 #include "deString.h"
40 
41 #include <algorithm>
42 #include <cmath>
43 #include <limits>
44 #include <sstream>
45 #include <string>
46 #include <vector>
47 
48 using std::ostringstream;
49 using std::string;
50 using std::vector;
51 
52 using tcu::TestLog;
53 
54 using namespace eglw;
55 
56 namespace deqp
57 {
58 namespace egl
59 {
60 
61 class MakeCurrentPerfCase : public TestCase
62 {
63 public:
64 	enum SurfaceType
65 	{
66 		SURFACETYPE_PBUFFER	= (1<<0),
67 		SURFACETYPE_WINDOW	= (1<<1),
68 		SURFACETYPE_PIXMAP	= (1<<2)
69 	};
70 
71 	struct Spec
72 	{
73 		SurfaceType	surfaceTypes;
74 		int			contextCount;
75 		int			surfaceCount;
76 
77 		bool		release;
78 
79 		int			iterationCount;
80 		int			sampleCount;
81 
82 		string		toName			(void) const;
83 		string		toDescription	(void) const;
84 	};
85 					MakeCurrentPerfCase		(EglTestContext& eglTestCtx, const Spec& spec, const char* name, const char* description);
86 					~MakeCurrentPerfCase	(void);
87 
88 	void			init					(void);
89 	void			deinit					(void);
90 	IterateResult	iterate					(void);
91 
92 private:
93 	Spec						m_spec;
94 	de::Random					m_rnd;
95 
96 	EGLDisplay					m_display;
97 	EGLConfig					m_config;
98 	vector<EGLContext>			m_contexts;
99 	vector<EGLSurface>			m_surfaces;
100 
101 	vector<eglu::NativeWindow*>	m_windows;
102 	vector<eglu::NativePixmap*>	m_pixmaps;
103 
104 	vector<deUint64>			m_samples;
105 
106 	void					chooseConfig	(void);
107 	void					createSurfaces	(void);
108 	void					createContexts	(void);
109 
110 	void					destroySurfaces	(void);
111 	void					destroyContexts	(void);
112 
113 	void					createPBuffer	(void);
114 	void					createWindow	(void);
115 	void					createPixmap	(void);
116 
117 	void					logTestInfo		(void);
118 	void					logResults		(void);
119 	// Disabled
120 							MakeCurrentPerfCase	(const MakeCurrentPerfCase&);
121 	MakeCurrentPerfCase&	operator=			(const MakeCurrentPerfCase&);
122 };
123 
toName(void) const124 string MakeCurrentPerfCase::Spec::toName (void) const
125 {
126 	ostringstream name;
127 
128 	name << "context";
129 
130 	if (contextCount > 1)
131 		name << "s_" << contextCount;
132 
133 	if ((surfaceTypes & SURFACETYPE_WINDOW) != 0)
134 		name << "_window" << (surfaceCount > 1 ? "s" : "");
135 
136 	if ((surfaceTypes & SURFACETYPE_PIXMAP) != 0)
137 		name << "_pixmap" << (surfaceCount > 1 ? "s" : "");
138 
139 	if ((surfaceTypes & SURFACETYPE_PBUFFER) != 0)
140 		name << "_pbuffer" << (surfaceCount > 1 ? "s" : "");
141 
142 	if (surfaceCount > 1)
143 		name << "_" << surfaceCount;
144 
145 	if (release)
146 		name << "_release";
147 
148 	return name.str();
149 }
150 
toDescription(void) const151 string MakeCurrentPerfCase::Spec::toDescription (void) const
152 {
153 	// \todo [mika] Generate descrpition
154 	return toName();
155 }
156 
MakeCurrentPerfCase(EglTestContext & eglTestCtx,const Spec & spec,const char * name,const char * description)157 MakeCurrentPerfCase::MakeCurrentPerfCase (EglTestContext& eglTestCtx, const Spec& spec, const char* name, const char* description)
158 	: TestCase		(eglTestCtx, tcu::NODETYPE_PERFORMANCE, name, description)
159 	, m_spec		(spec)
160 	, m_rnd			(deStringHash(name))
161 	, m_display		(EGL_NO_DISPLAY)
162 	, m_config		(DE_NULL)
163 {
164 }
165 
~MakeCurrentPerfCase(void)166 MakeCurrentPerfCase::~MakeCurrentPerfCase (void)
167 {
168 	deinit();
169 }
170 
init(void)171 void MakeCurrentPerfCase::init (void)
172 {
173 	m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
174 
175 	chooseConfig();
176 	createContexts();
177 	createSurfaces();
178 }
179 
deinit(void)180 void MakeCurrentPerfCase::deinit (void)
181 {
182 	destroyContexts();
183 	destroySurfaces();
184 
185 	if (m_display != EGL_NO_DISPLAY)
186 	{
187 		m_eglTestCtx.getLibrary().terminate(m_display);
188 		m_display = EGL_NO_DISPLAY;
189 	}
190 }
191 
chooseConfig(void)192 void MakeCurrentPerfCase::chooseConfig (void)
193 {
194 	const EGLint	surfaceBits	= ((m_spec.surfaceTypes & SURFACETYPE_WINDOW) != 0 ? EGL_WINDOW_BIT : 0)
195 									| ((m_spec.surfaceTypes & SURFACETYPE_PIXMAP) != 0 ? EGL_PIXMAP_BIT : 0)
196 									| ((m_spec.surfaceTypes & SURFACETYPE_PBUFFER) != 0 ? EGL_PBUFFER_BIT : 0);
197 
198 	const EGLint	attribList[] = {
199 		EGL_SURFACE_TYPE,		surfaceBits,
200 		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
201 		EGL_NONE
202 	};
203 
204 	const Library&	egl			= m_eglTestCtx.getLibrary();
205 	EGLint			configCount = 0;
206 
207 	EGLU_CHECK_CALL(egl, chooseConfig(m_display, attribList, &m_config, 1, &configCount));
208 
209 	if (configCount <= 0)
210 		throw tcu::NotSupportedError("No compatible configs found");
211 }
212 
createSurfaces(void)213 void MakeCurrentPerfCase::createSurfaces (void)
214 {
215 	vector<SurfaceType> types;
216 
217 	if ((m_spec.surfaceTypes & SURFACETYPE_WINDOW) != 0)
218 		types.push_back(SURFACETYPE_WINDOW);
219 
220 	if ((m_spec.surfaceTypes & SURFACETYPE_PIXMAP) != 0)
221 		types.push_back(SURFACETYPE_PIXMAP);
222 
223 	if ((m_spec.surfaceTypes & SURFACETYPE_PBUFFER) != 0)
224 		types.push_back(SURFACETYPE_PBUFFER);
225 
226 	DE_ASSERT((int)types.size() <= m_spec.surfaceCount);
227 
228 	// Create surfaces
229 	for (int surfaceNdx = 0; surfaceNdx < m_spec.surfaceCount; surfaceNdx++)
230 	{
231 		SurfaceType type = types[surfaceNdx % types.size()];
232 
233 		switch (type)
234 		{
235 			case SURFACETYPE_PBUFFER:
236 				createPBuffer();
237 				break;
238 
239 			case SURFACETYPE_WINDOW:
240 				createWindow();
241 				break;
242 
243 			case SURFACETYPE_PIXMAP:
244 				createPixmap();
245 				break;
246 
247 			default:
248 				DE_ASSERT(false);
249 		};
250 	}
251 }
252 
createPBuffer(void)253 void MakeCurrentPerfCase::createPBuffer (void)
254 {
255 	const Library&	egl		= m_eglTestCtx.getLibrary();
256 	const EGLint	width	= 256;
257 	const EGLint	height	= 256;
258 
259 	const EGLint attribList[] = {
260 		EGL_WIDTH,	width,
261 		EGL_HEIGHT, height,
262 		EGL_NONE
263 	};
264 
265 	EGLSurface	surface = egl.createPbufferSurface(m_display, m_config, attribList);
266 
267 	EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface()");
268 
269 	m_surfaces.push_back(surface);
270 }
271 
createWindow(void)272 void MakeCurrentPerfCase::createWindow (void)
273 {
274 	const Library&						egl				= m_eglTestCtx.getLibrary();
275 	const EGLint						width			= 256;
276 	const EGLint						height			= 256;
277 
278 	const eglu::NativeWindowFactory&	windowFactory	= eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
279 
280 	eglu::NativeWindow* 				window			= DE_NULL;
281 	EGLSurface							surface			= EGL_NO_SURFACE;
282 
283 	try
284 	{
285 		window	= windowFactory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_display, m_config, DE_NULL, eglu::WindowParams(width, height, eglu::parseWindowVisibility(m_eglTestCtx.getTestContext().getCommandLine())));
286 		surface	= eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, m_display, m_config, DE_NULL);
287 	}
288 	catch (...)
289 	{
290 		if (surface != EGL_NO_SURFACE)
291 			egl.destroySurface(m_display, surface);
292 
293 		delete window;
294 		throw;
295 	}
296 
297 	m_windows.push_back(window);
298 	m_surfaces.push_back(surface);
299 }
300 
createPixmap(void)301 void MakeCurrentPerfCase::createPixmap (void)
302 {
303 	const Library&						egl				= m_eglTestCtx.getLibrary();
304 	const EGLint						width			= 256;
305 	const EGLint						height			= 256;
306 
307 	const eglu::NativePixmapFactory&	pixmapFactory	= eglu::selectNativePixmapFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
308 
309 	eglu::NativePixmap* 				pixmap			= DE_NULL;
310 	EGLSurface							surface			= EGL_NO_SURFACE;
311 
312 	try
313 	{
314 		pixmap	= pixmapFactory.createPixmap(&m_eglTestCtx.getNativeDisplay(), m_display, m_config, DE_NULL, width, height);
315 		surface	= eglu::createPixmapSurface(m_eglTestCtx.getNativeDisplay(), *pixmap, m_display, m_config, DE_NULL);
316 	}
317 	catch (...)
318 	{
319 		if (surface != EGL_NO_SURFACE)
320 			egl.destroySurface(m_display, surface);
321 
322 		delete pixmap;
323 		throw;
324 	}
325 
326 	m_pixmaps.push_back(pixmap);
327 	m_surfaces.push_back(surface);
328 }
329 
destroySurfaces(void)330 void MakeCurrentPerfCase::destroySurfaces (void)
331 {
332 	const Library&	egl	= m_eglTestCtx.getLibrary();
333 
334 	if (m_surfaces.size() > 0)
335 	{
336 		EGLDisplay display = m_display;
337 
338 		// Destroy surfaces
339 		for (vector<EGLSurface>::iterator iter = m_surfaces.begin(); iter != m_surfaces.end(); ++iter)
340 		{
341 			if (*iter != EGL_NO_SURFACE)
342 				EGLU_CHECK_CALL(egl, destroySurface(display, *iter));
343 			*iter = EGL_NO_SURFACE;
344 		}
345 
346 		m_surfaces.clear();
347 
348 		// Destroy pixmaps
349 		for (vector<eglu::NativePixmap*>::iterator iter = m_pixmaps.begin(); iter != m_pixmaps.end(); ++iter)
350 		{
351 			delete *iter;
352 			*iter = NULL;
353 		}
354 
355 		m_pixmaps.clear();
356 
357 		// Destroy windows
358 		for (vector<eglu::NativeWindow*>::iterator iter = m_windows.begin(); iter != m_windows.end(); ++iter)
359 		{
360 			delete *iter;
361 			*iter = NULL;
362 		}
363 
364 		m_windows.clear();
365 
366 		// Clear all surface handles
367 		m_surfaces.clear();
368 	}
369 }
370 
createContexts(void)371 void MakeCurrentPerfCase::createContexts (void)
372 {
373 	const Library&	egl	= m_eglTestCtx.getLibrary();
374 
375 	for (int contextNdx = 0; contextNdx < m_spec.contextCount; contextNdx++)
376 	{
377 		const EGLint attribList[] = {
378 			EGL_CONTEXT_CLIENT_VERSION, 2,
379 			EGL_NONE
380 		};
381 
382 		EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API));
383 		EGLContext context = egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList);
384 		EGLU_CHECK_MSG(egl, "eglCreateContext()");
385 
386 		m_contexts.push_back(context);
387 	}
388 }
389 
destroyContexts(void)390 void MakeCurrentPerfCase::destroyContexts (void)
391 {
392 	const Library&	egl	= m_eglTestCtx.getLibrary();
393 	if (m_contexts.size() > 0)
394 	{
395 		EGLDisplay display = m_display;
396 
397 		for (vector<EGLContext>::iterator iter = m_contexts.begin(); iter != m_contexts.end(); ++iter)
398 		{
399 			if (*iter != EGL_NO_CONTEXT)
400 				EGLU_CHECK_CALL(egl, destroyContext(display, *iter));
401 			*iter = EGL_NO_CONTEXT;
402 		}
403 
404 		m_contexts.clear();
405 	}
406 }
407 
logTestInfo(void)408 void MakeCurrentPerfCase::logTestInfo (void)
409 {
410 	TestLog& log = m_testCtx.getLog();
411 
412 	{
413 		tcu::ScopedLogSection	section(log, "Test Info", "Test case information.");
414 
415 		log << TestLog::Message << "Context count: "	<< m_contexts.size()											<< TestLog::EndMessage;
416 		log << TestLog::Message << "Surfaces count: "	<< m_surfaces.size()											<< TestLog::EndMessage;
417 		log << TestLog::Message << "Sample count: "	<< m_spec.sampleCount												<< TestLog::EndMessage;
418 		log << TestLog::Message << "Iteration count: "	<< m_spec.iterationCount										<< TestLog::EndMessage;
419 		log << TestLog::Message << "Window count: "	<< m_windows.size()													<< TestLog::EndMessage;
420 		log << TestLog::Message << "Pixmap count: "	<< m_pixmaps.size()													<< TestLog::EndMessage;
421 		log << TestLog::Message << "PBuffer count: "	<< (m_surfaces.size() - m_windows.size() - m_pixmaps.size())	<< TestLog::EndMessage;
422 
423 		if (m_spec.release)
424 			log << TestLog::Message << "Context is released after each use. Both binding and releasing context are included in result time." << TestLog::EndMessage;
425 	}
426 }
427 
logResults(void)428 void MakeCurrentPerfCase::logResults (void)
429 {
430 	TestLog& log = m_testCtx.getLog();
431 
432 	log << TestLog::SampleList("Result", "Result")
433 		<< TestLog::SampleInfo << TestLog::ValueInfo("Time", "Time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
434 		<< TestLog::EndSampleInfo;
435 
436 	for (int sampleNdx = 0; sampleNdx < (int)m_samples.size(); sampleNdx++)
437 		log << TestLog::Sample << deInt64(m_samples[sampleNdx]) << TestLog::EndSample;
438 
439 	log << TestLog::EndSampleList;
440 
441 	// Log stats
442 	{
443 		deUint64	totalTimeUs				= 0;
444 		deUint64	totalIterationCount		= 0;
445 
446 		float		iterationTimeMeanUs		= 0.0f;
447 		float		iterationTimeMedianUs	= 0.0f;
448 		float		iterationTimeVarianceUs	= 0.0f;
449 		float		iterationTimeSkewnessUs	= 0.0f;
450 		float		iterationTimeMinUs		= std::numeric_limits<float>::max();
451 		float		iterationTimeMaxUs		= 0.0f;
452 
453 		std::sort(m_samples.begin(), m_samples.end());
454 
455 		// Calculate totals
456 		for (int sampleNdx = 0; sampleNdx < (int)m_samples.size(); sampleNdx++)
457 		{
458 			totalTimeUs			+= m_samples[sampleNdx];
459 			totalIterationCount	+= m_spec.iterationCount;
460 		}
461 
462 		// Calculate mean and median
463 		iterationTimeMeanUs		= ((float)(((double)totalTimeUs) / (double)totalIterationCount));
464 		iterationTimeMedianUs	= ((float)(((double)m_samples[m_samples.size() / 2]) / (double)m_spec.iterationCount));
465 
466 		// Calculate variance
467 		for (int sampleNdx = 0; sampleNdx < (int)m_samples.size(); sampleNdx++)
468 		{
469 			float iterationTimeUs	= (float)(((double)m_samples[sampleNdx]) / m_spec.iterationCount);
470 			iterationTimeVarianceUs	+= std::pow(iterationTimeUs - iterationTimeMedianUs, 2.0f);
471 		}
472 
473 		// Calculate min and max
474 		for (int sampleNdx = 0; sampleNdx < (int)m_samples.size(); sampleNdx++)
475 		{
476 			float iterationTimeUs	= (float)(((double)m_samples[sampleNdx]) / m_spec.iterationCount);
477 			iterationTimeMinUs		= std::min<float>(iterationTimeMinUs, iterationTimeUs);
478 			iterationTimeMaxUs		= std::max<float>(iterationTimeMaxUs, iterationTimeUs);
479 		}
480 
481 		iterationTimeVarianceUs /= (float)m_samples.size();
482 
483 		// Calculate skewness
484 		for (int sampleNdx = 0; sampleNdx < (int)m_samples.size(); sampleNdx++)
485 		{
486 			float iterationTimeUs	= (float)(((double)m_samples[sampleNdx]) / m_spec.iterationCount);
487 			iterationTimeSkewnessUs	= std::pow((iterationTimeUs - iterationTimeMedianUs) / iterationTimeVarianceUs, 2.0f);
488 		}
489 
490 		iterationTimeSkewnessUs /= (float)m_samples.size();
491 
492 		{
493 			tcu::ScopedLogSection	section(log, "Result", "Statistics from results.");
494 
495 			log << TestLog::Message << "Total time: "	<< totalTimeUs				<< "us" << TestLog::EndMessage;
496 			log << TestLog::Message << "Mean: "			<< iterationTimeMeanUs		<< "us" << TestLog::EndMessage;
497 			log << TestLog::Message << "Median: "		<< iterationTimeMedianUs	<< "us" << TestLog::EndMessage;
498 			log << TestLog::Message << "Variance: "		<< iterationTimeVarianceUs	<< "us" << TestLog::EndMessage;
499 			log << TestLog::Message << "Skewness: "		<< iterationTimeSkewnessUs	<< "us" << TestLog::EndMessage;
500 			log << TestLog::Message << "Min: "			<< iterationTimeMinUs		<< "us" << TestLog::EndMessage;
501 			log << TestLog::Message << "Max: "			<< iterationTimeMaxUs		<< "us" << TestLog::EndMessage;
502 		}
503 
504 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)(((double)totalTimeUs)/(double)totalIterationCount), 2).c_str());
505 	}
506 }
507 
iterate(void)508 TestCase::IterateResult MakeCurrentPerfCase::iterate (void)
509 {
510 	const Library&	egl	= m_eglTestCtx.getLibrary();
511 	if (m_samples.size() == 0)
512 		logTestInfo();
513 
514 	{
515 		EGLDisplay	display		= m_display;
516 		deUint64	beginTimeUs	= deGetMicroseconds();
517 
518 		for (int iteration = 0; iteration < m_spec.iterationCount; iteration++)
519 		{
520 			EGLContext	context = m_contexts[m_rnd.getUint32() % m_contexts.size()];
521 			EGLSurface	surface	= m_surfaces[m_rnd.getUint32() % m_surfaces.size()];
522 
523 			egl.makeCurrent(display, surface, surface, context);
524 
525 			if (m_spec.release)
526 				egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
527 		}
528 
529 		m_samples.push_back(deGetMicroseconds() - beginTimeUs);
530 
531 		egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
532 		EGLU_CHECK_MSG(egl, "eglMakeCurrent()");
533 	}
534 
535 	if ((int)m_samples.size() == m_spec.sampleCount)
536 	{
537 		logResults();
538 		return STOP;
539 	}
540 	else
541 		return CONTINUE;
542 }
543 
MakeCurrentPerfTests(EglTestContext & eglTestCtx)544 MakeCurrentPerfTests::MakeCurrentPerfTests (EglTestContext& eglTestCtx)
545 	: TestCaseGroup(eglTestCtx, "make_current", "eglMakeCurrent performance tests")
546 {
547 }
548 
init(void)549 void MakeCurrentPerfTests::init (void)
550 {
551 	const int iterationCount	= 100;
552 	const int sampleCount		= 100;
553 
554 	// Add simple test group
555 	{
556 		TestCaseGroup* simple = new TestCaseGroup(m_eglTestCtx, "simple", "Simple eglMakeCurrent performance tests using single context and surface");
557 
558 		const MakeCurrentPerfCase::SurfaceType types[] = {
559 			MakeCurrentPerfCase::SURFACETYPE_PBUFFER,
560 			MakeCurrentPerfCase::SURFACETYPE_PIXMAP,
561 			MakeCurrentPerfCase::SURFACETYPE_WINDOW
562 		};
563 
564 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); typeNdx++)
565 		{
566 			for (int releaseNdx = 0; releaseNdx < 2; releaseNdx++)
567 			{
568 				MakeCurrentPerfCase::Spec spec;
569 
570 				spec.surfaceTypes	= types[typeNdx];
571 				spec.contextCount	= 1;
572 				spec.surfaceCount	= 1;
573 				spec.release		= (releaseNdx == 1);
574 				spec.iterationCount	= iterationCount;
575 				spec.sampleCount	= sampleCount;
576 
577 				simple->addChild(new MakeCurrentPerfCase(m_eglTestCtx, spec, spec.toName().c_str(), spec.toDescription().c_str()));
578 			}
579 		}
580 
581 		addChild(simple);
582 	}
583 
584 	// Add multi context test group
585 	{
586 		TestCaseGroup* multiContext = new TestCaseGroup(m_eglTestCtx, "multi_context", "eglMakeCurrent performance tests using multiple contexts and single surface");
587 
588 		const MakeCurrentPerfCase::SurfaceType types[] = {
589 			MakeCurrentPerfCase::SURFACETYPE_PBUFFER,
590 			MakeCurrentPerfCase::SURFACETYPE_PIXMAP,
591 			MakeCurrentPerfCase::SURFACETYPE_WINDOW
592 		};
593 
594 		const int contextCounts[] = {
595 			10, 100
596 		};
597 
598 		for (int contextCountNdx = 0; contextCountNdx < DE_LENGTH_OF_ARRAY(contextCounts); contextCountNdx++)
599 		{
600 			for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); typeNdx++)
601 			{
602 				for (int releaseNdx = 0; releaseNdx < 2; releaseNdx++)
603 				{
604 					MakeCurrentPerfCase::Spec spec;
605 
606 					spec.surfaceTypes	= types[typeNdx];
607 					spec.contextCount	= contextCounts[contextCountNdx];
608 					spec.surfaceCount	= 1;
609 					spec.release		= (releaseNdx == 1);
610 					spec.iterationCount	= iterationCount;
611 					spec.sampleCount	= sampleCount;
612 
613 					multiContext->addChild(new MakeCurrentPerfCase(m_eglTestCtx, spec, spec.toName().c_str(), spec.toDescription().c_str()));
614 				}
615 			}
616 		}
617 
618 		addChild(multiContext);
619 	}
620 
621 	// Add multi surface test group
622 	{
623 		TestCaseGroup* multiSurface = new TestCaseGroup(m_eglTestCtx, "multi_surface", "eglMakeCurrent performance tests using single context and multiple surfaces");
624 
625 		const MakeCurrentPerfCase::SurfaceType types[] = {
626 			MakeCurrentPerfCase::SURFACETYPE_PBUFFER,
627 			MakeCurrentPerfCase::SURFACETYPE_PIXMAP,
628 			MakeCurrentPerfCase::SURFACETYPE_WINDOW,
629 
630 			(MakeCurrentPerfCase::SurfaceType)(MakeCurrentPerfCase::SURFACETYPE_PBUFFER	|MakeCurrentPerfCase::SURFACETYPE_PIXMAP),
631 			(MakeCurrentPerfCase::SurfaceType)(MakeCurrentPerfCase::SURFACETYPE_PBUFFER	|MakeCurrentPerfCase::SURFACETYPE_WINDOW),
632 			(MakeCurrentPerfCase::SurfaceType)(MakeCurrentPerfCase::SURFACETYPE_PIXMAP	|MakeCurrentPerfCase::SURFACETYPE_WINDOW),
633 
634 			(MakeCurrentPerfCase::SurfaceType)(MakeCurrentPerfCase::SURFACETYPE_PBUFFER|MakeCurrentPerfCase::SURFACETYPE_PIXMAP|MakeCurrentPerfCase::SURFACETYPE_WINDOW)
635 		};
636 
637 		const int surfaceCounts[] = {
638 			10, 100
639 		};
640 
641 		for (int surfaceCountNdx = 0; surfaceCountNdx < DE_LENGTH_OF_ARRAY(surfaceCounts); surfaceCountNdx++)
642 		{
643 			for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); typeNdx++)
644 			{
645 				for (int releaseNdx = 0; releaseNdx < 2; releaseNdx++)
646 				{
647 					MakeCurrentPerfCase::Spec spec;
648 
649 					spec.surfaceTypes	= types[typeNdx];
650 					spec.surfaceCount	= surfaceCounts[surfaceCountNdx];
651 					spec.contextCount	= 1;
652 					spec.release		= (releaseNdx == 1);
653 					spec.iterationCount	= iterationCount;
654 					spec.sampleCount	= sampleCount;
655 
656 					multiSurface->addChild(new MakeCurrentPerfCase(m_eglTestCtx, spec, spec.toName().c_str(), spec.toDescription().c_str()));
657 				}
658 			}
659 		}
660 
661 		addChild(multiSurface);
662 	}
663 
664 	// Add Complex? test group
665 	{
666 		TestCaseGroup* multi = new TestCaseGroup(m_eglTestCtx, "complex", "eglMakeCurrent performance tests using multiple contexts and multiple surfaces");
667 
668 		const MakeCurrentPerfCase::SurfaceType types[] = {
669 			MakeCurrentPerfCase::SURFACETYPE_PBUFFER,
670 			MakeCurrentPerfCase::SURFACETYPE_PIXMAP,
671 			MakeCurrentPerfCase::SURFACETYPE_WINDOW,
672 
673 			(MakeCurrentPerfCase::SurfaceType)(MakeCurrentPerfCase::SURFACETYPE_PBUFFER	|MakeCurrentPerfCase::SURFACETYPE_PIXMAP),
674 			(MakeCurrentPerfCase::SurfaceType)(MakeCurrentPerfCase::SURFACETYPE_PBUFFER	|MakeCurrentPerfCase::SURFACETYPE_WINDOW),
675 			(MakeCurrentPerfCase::SurfaceType)(MakeCurrentPerfCase::SURFACETYPE_PIXMAP	|MakeCurrentPerfCase::SURFACETYPE_WINDOW),
676 
677 			(MakeCurrentPerfCase::SurfaceType)(MakeCurrentPerfCase::SURFACETYPE_PBUFFER|MakeCurrentPerfCase::SURFACETYPE_PIXMAP|MakeCurrentPerfCase::SURFACETYPE_WINDOW)
678 		};
679 
680 		const int surfaceCounts[] = {
681 			10, 100
682 		};
683 
684 
685 		const int contextCounts[] = {
686 			10, 100
687 		};
688 
689 		for (int surfaceCountNdx = 0; surfaceCountNdx < DE_LENGTH_OF_ARRAY(surfaceCounts); surfaceCountNdx++)
690 		{
691 			for (int contextCountNdx = 0; contextCountNdx < DE_LENGTH_OF_ARRAY(contextCounts); contextCountNdx++)
692 			{
693 				for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); typeNdx++)
694 				{
695 					for (int releaseNdx = 0; releaseNdx < 2; releaseNdx++)
696 					{
697 						MakeCurrentPerfCase::Spec spec;
698 
699 						spec.surfaceTypes	= types[typeNdx];
700 						spec.contextCount	= contextCounts[contextCountNdx];
701 						spec.surfaceCount	= surfaceCounts[surfaceCountNdx];
702 						spec.release		= (releaseNdx == 1);
703 						spec.iterationCount	= iterationCount;
704 						spec.sampleCount	= sampleCount;
705 
706 						multi->addChild(new MakeCurrentPerfCase(m_eglTestCtx, spec, spec.toName().c_str(), spec.toDescription().c_str()));
707 					}
708 				}
709 			}
710 		}
711 
712 		addChild(multi);
713 	}
714 }
715 
716 } // egl
717 } // deqp
718