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 Config query tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "teglQueryContextTests.hpp"
25#include "teglRenderCase.hpp"
26#include "teglRenderCase.hpp"
27#include "egluCallLogWrapper.hpp"
28#include "egluStrUtil.hpp"
29#include "tcuCommandLine.hpp"
30#include "tcuTestLog.hpp"
31#include "tcuTestContext.hpp"
32
33#include "egluUtil.hpp"
34#include "egluNativeDisplay.hpp"
35#include "egluNativeWindow.hpp"
36#include "egluNativePixmap.hpp"
37
38#include "eglwLibrary.hpp"
39#include "eglwEnums.hpp"
40
41#include "deUniquePtr.hpp"
42#include "deSTLUtil.hpp"
43
44#include <vector>
45
46namespace deqp
47{
48namespace egl
49{
50
51using std::vector;
52using eglu::ConfigInfo;
53using tcu::TestLog;
54using namespace eglw;
55
56static EGLint getClientTypeFromAPIBit (EGLint apiBit)
57{
58	switch (apiBit)
59	{
60		case EGL_OPENGL_BIT:		return EGL_OPENGL_API;
61		case EGL_OPENGL_ES_BIT:		return EGL_OPENGL_ES_API;
62		case EGL_OPENGL_ES2_BIT:	return EGL_OPENGL_ES_API;
63		case EGL_OPENGL_ES3_BIT:	return EGL_OPENGL_ES_API;
64		case EGL_OPENVG_BIT:		return EGL_OPENVG_API;
65		default:
66			DE_ASSERT(false);
67			return 0;
68	}
69}
70
71static EGLint getMinClientMajorVersion (EGLint apiBit)
72{
73	switch (apiBit)
74	{
75		case EGL_OPENGL_BIT:		return 1;
76		case EGL_OPENGL_ES_BIT:		return 1;
77		case EGL_OPENGL_ES2_BIT:	return 2;
78		case EGL_OPENGL_ES3_BIT:	return 3;
79		case EGL_OPENVG_BIT:		return 1;
80		default:
81			DE_ASSERT(false);
82			return 0;
83	}
84}
85
86class GetCurrentContextCase : public SingleContextRenderCase, private eglu::CallLogWrapper
87{
88public:
89	GetCurrentContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const eglu::FilterList& filters, EGLint surfaceTypeMask)
90		: SingleContextRenderCase	(eglTestCtx, name, description, getBuildClientAPIMask(), surfaceTypeMask, filters)
91		, eglu::CallLogWrapper		(eglTestCtx.getLibrary(), m_testCtx.getLog())
92	{
93	}
94
95	void executeForContext (EGLDisplay display, EGLContext context, EGLSurface surface, const Config& config)
96	{
97		const Library&	egl	= m_eglTestCtx.getLibrary();
98		TestLog&		log	= m_testCtx.getLog();
99
100		DE_UNREF(display);
101		DE_UNREF(surface);
102		DE_UNREF(config);
103
104		enableLogging(true);
105
106		const EGLContext	gotContext	= eglGetCurrentContext();
107		EGLU_CHECK_MSG(egl, "eglGetCurrentContext");
108
109		if (gotContext == context)
110		{
111			log << TestLog::Message << "  Pass" << TestLog::EndMessage;
112		}
113		else if (gotContext == EGL_NO_CONTEXT)
114		{
115			log << TestLog::Message << "  Fail, got EGL_NO_CONTEXT" << TestLog::EndMessage;
116			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected EGL_NO_CONTEXT");
117		}
118		else if (gotContext != context)
119		{
120			log << TestLog::Message << "  Fail, call returned the wrong context. Expected: " << tcu::toHex(context) << ", got: " << tcu::toHex(gotContext) << TestLog::EndMessage;
121			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid context");
122		}
123
124		enableLogging(false);
125	}
126};
127
128class GetCurrentSurfaceCase : public SingleContextRenderCase, private eglu::CallLogWrapper
129{
130public:
131	GetCurrentSurfaceCase (EglTestContext& eglTestCtx, const char* name, const char* description, const eglu::FilterList& filters, EGLint surfaceTypeMask)
132		: SingleContextRenderCase	(eglTestCtx, name, description, getBuildClientAPIMask(), surfaceTypeMask, filters)
133		, eglu::CallLogWrapper		(eglTestCtx.getLibrary(), m_testCtx.getLog())
134	{
135	}
136
137	void executeForContext (EGLDisplay display, EGLContext context, EGLSurface surface, const Config& config)
138	{
139		const Library&	egl	= m_eglTestCtx.getLibrary();
140		TestLog&		log	= m_testCtx.getLog();
141
142		DE_UNREF(display);
143		DE_UNREF(context);
144		DE_UNREF(config);
145
146		enableLogging(true);
147
148		const EGLContext	gotReadSurface	= eglGetCurrentSurface(EGL_READ);
149		EGLU_CHECK_MSG(egl, "eglGetCurrentSurface(EGL_READ)");
150
151		const EGLContext	gotDrawSurface	= eglGetCurrentSurface(EGL_DRAW);
152		EGLU_CHECK_MSG(egl, "eglGetCurrentSurface(EGL_DRAW)");
153
154		if (gotReadSurface == surface && gotDrawSurface == surface)
155		{
156			log << TestLog::Message << "  Pass" << TestLog::EndMessage;
157		}
158		else
159		{
160			log << TestLog::Message << "  Fail, read surface: " << tcu::toHex(gotReadSurface)
161									<< ", draw surface: " << tcu::toHex(gotDrawSurface)
162									<< ", expected: " << tcu::toHex(surface) << TestLog::EndMessage;
163			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid surface");
164		}
165
166		enableLogging(false);
167	}
168};
169
170class GetCurrentDisplayCase : public SingleContextRenderCase, private eglu::CallLogWrapper
171{
172public:
173	GetCurrentDisplayCase (EglTestContext& eglTestCtx, const char* name, const char* description, const eglu::FilterList& filters, EGLint surfaceTypeMask)
174		: SingleContextRenderCase	(eglTestCtx, name, description, getBuildClientAPIMask(), surfaceTypeMask, filters)
175		, eglu::CallLogWrapper		(eglTestCtx.getLibrary(), m_testCtx.getLog())
176	{
177	}
178
179	void executeForContext (EGLDisplay display, EGLContext context, EGLSurface surface, const Config& config)
180	{
181		const Library&	egl	= m_eglTestCtx.getLibrary();
182		TestLog&		log	= m_testCtx.getLog();
183
184		DE_UNREF(surface && context);
185		DE_UNREF(config);
186
187		enableLogging(true);
188
189		const EGLDisplay	gotDisplay	= eglGetCurrentDisplay();
190		EGLU_CHECK_MSG(egl, "eglGetCurrentDisplay");
191
192		if (gotDisplay == display)
193		{
194			log << TestLog::Message << "  Pass" << TestLog::EndMessage;
195		}
196		else if (gotDisplay == EGL_NO_DISPLAY)
197		{
198			log << TestLog::Message << "  Fail, got EGL_NO_DISPLAY" << TestLog::EndMessage;
199			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected EGL_NO_DISPLAY");
200		}
201		else if (gotDisplay != display)
202		{
203			log << TestLog::Message << "  Fail, call returned the wrong display. Expected: " << tcu::toHex(display) << ", got: " << tcu::toHex(gotDisplay) << TestLog::EndMessage;
204			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid display");
205		}
206
207		enableLogging(false);
208	}
209};
210
211class QueryContextCase : public SingleContextRenderCase, private eglu::CallLogWrapper
212{
213public:
214	QueryContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const eglu::FilterList& filters, EGLint surfaceTypeMask)
215		: SingleContextRenderCase	(eglTestCtx, name, description, getBuildClientAPIMask(), surfaceTypeMask, filters)
216		, eglu::CallLogWrapper		(eglTestCtx.getLibrary(), m_testCtx.getLog())
217	{
218	}
219
220	EGLint getContextAttrib (EGLDisplay display, EGLContext context, EGLint attrib)
221	{
222		const Library&	egl	= m_eglTestCtx.getLibrary();
223		EGLint			value;
224		EGLU_CHECK_CALL(egl, queryContext(display, context, attrib, &value));
225
226		return value;
227	}
228
229	void executeForContext (EGLDisplay display, EGLContext context, EGLSurface surface, const Config& config)
230	{
231		const Library&		egl		= m_eglTestCtx.getLibrary();
232		TestLog&			log		= m_testCtx.getLog();
233		const eglu::Version	version	= eglu::getVersion(egl, display);
234
235		DE_UNREF(surface);
236		enableLogging(true);
237
238		// Config ID
239		{
240			const EGLint	configID		= getContextAttrib(display, context, EGL_CONFIG_ID);
241			const EGLint	surfaceConfigID	= eglu::getConfigAttribInt(egl, display, config.config, EGL_CONFIG_ID);
242
243			if (configID != surfaceConfigID)
244			{
245				log << TestLog::Message << "  Fail, config ID doesn't match the one used to create the context." << TestLog::EndMessage;
246				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid config ID");
247			}
248		}
249
250		// Client API type
251		if (version >= eglu::Version(1, 2))
252		{
253			const EGLint	clientType		= getContextAttrib(display, context, EGL_CONTEXT_CLIENT_TYPE);
254
255			if (clientType != getClientTypeFromAPIBit(config.apiBits))
256			{
257				log << TestLog::Message << "  Fail, client API type doesn't match." << TestLog::EndMessage;
258				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid client API type");
259			}
260		}
261
262		// Client API version
263		if (version >= eglu::Version(1, 3))
264		{
265			const EGLint	clientVersion	= getContextAttrib(display, context, EGL_CONTEXT_CLIENT_VERSION);
266
267			// \todo [2014-10-21 mika] Query actual supported api version from client api to make this check stricter.
268			if (clientVersion < getMinClientMajorVersion(config.apiBits))
269			{
270				log << TestLog::Message << "  Fail, client API version doesn't match." << TestLog::EndMessage;
271				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid client API version");
272			}
273		}
274
275		// Render buffer
276		if (version >= eglu::Version(1, 2))
277		{
278			const EGLint	renderBuffer	= getContextAttrib(display, context, EGL_RENDER_BUFFER);
279
280			if (config.surfaceTypeBit == EGL_PIXMAP_BIT && renderBuffer != EGL_SINGLE_BUFFER)
281			{
282				log << TestLog::Message << "  Fail, render buffer should be EGL_SINGLE_BUFFER for a pixmap surface." << TestLog::EndMessage;
283				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer");
284			}
285			else if (config.surfaceTypeBit == EGL_PBUFFER_BIT && renderBuffer != EGL_BACK_BUFFER)
286			{
287				log << TestLog::Message << "  Fail, render buffer should be EGL_BACK_BUFFER for a pbuffer surface." << TestLog::EndMessage;
288				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer");
289			}
290			else if (config.surfaceTypeBit == EGL_WINDOW_BIT && renderBuffer != EGL_SINGLE_BUFFER && renderBuffer != EGL_BACK_BUFFER)
291			{
292				log << TestLog::Message << "  Fail, render buffer should be either EGL_SINGLE_BUFFER or EGL_BACK_BUFFER for a window surface." << TestLog::EndMessage;
293				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer");
294			}
295		}
296
297		enableLogging(false);
298
299		log << TestLog::Message << "  Pass" << TestLog::EndMessage;
300	}
301};
302
303class QueryAPICase : public TestCase, private eglu::CallLogWrapper
304{
305public:
306	QueryAPICase (EglTestContext& eglTestCtx, const char* name, const char* description)
307		: TestCase		(eglTestCtx, name, description)
308		, CallLogWrapper(eglTestCtx.getLibrary(), eglTestCtx.getTestContext().getLog())
309	{
310	}
311
312	void init (void)
313	{
314		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
315	}
316
317	IterateResult iterate (void)
318	{
319		const Library&			egl				= m_eglTestCtx.getLibrary();
320		EGLDisplay				display			= eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
321		tcu::TestLog&			log				= m_testCtx.getLog();
322		const EGLenum			apis[]			= { EGL_OPENGL_API, EGL_OPENGL_ES_API, EGL_OPENVG_API };
323		const vector<EGLenum>	supportedAPIs	= eglu::getClientAPIs(egl, display);
324
325		enableLogging(true);
326
327		{
328			const EGLenum	api	= eglQueryAPI();
329
330			if (api != EGL_OPENGL_ES_API && (de::contains(supportedAPIs.begin(), supportedAPIs.end(), EGL_OPENGL_ES_API)))
331			{
332				log << TestLog::Message << "  Fail, initial value should be EGL_OPENGL_ES_API if OpenGL ES is supported." << TestLog::EndMessage;
333				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid default value");
334			}
335			else if (api != EGL_NONE && !(de::contains(supportedAPIs.begin(), supportedAPIs.end(), EGL_OPENGL_ES_API)))
336			{
337				log << TestLog::Message << "  Fail, initial value should be EGL_NONE if OpenGL ES is not supported." << TestLog::EndMessage;
338				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid default value");
339			}
340		}
341
342		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(apis); ndx++)
343		{
344			const EGLenum	api	= apis[ndx];
345
346			log << TestLog::Message << TestLog::EndMessage;
347
348			if (de::contains(supportedAPIs.begin(), supportedAPIs.end(), api))
349			{
350				egl.bindAPI(api);
351
352				if (api != egl.queryAPI())
353				{
354					log << TestLog::Message << "  Fail, return value does not match previously bound API." << TestLog::EndMessage;
355					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid return value");
356				}
357			}
358			else
359			{
360				log << TestLog::Message << eglu::getAPIStr(api) << " not supported." << TestLog::EndMessage;
361			}
362		}
363
364		enableLogging(false);
365		eglTerminate(display);
366		return STOP;
367	}
368};
369
370QueryContextTests::QueryContextTests (EglTestContext& eglTestCtx)
371	: TestCaseGroup(eglTestCtx, "query_context", "Rendering context query tests")
372{
373}
374
375QueryContextTests::~QueryContextTests (void)
376{
377}
378
379template<class QueryContextClass>
380void createQueryContextGroups (EglTestContext& eglTestCtx, tcu::TestCaseGroup* group)
381{
382	std::vector<RenderFilterList> filterLists;
383
384	getDefaultRenderFilterLists(filterLists, eglu::FilterList());
385
386	for (std::vector<RenderFilterList>::const_iterator listIter = filterLists.begin(); listIter != filterLists.end(); listIter++)
387		group->addChild(new QueryContextClass(eglTestCtx, listIter->getName(), "", *listIter, listIter->getSurfaceTypeMask()));
388}
389
390void QueryContextTests::init (void)
391{
392	{
393		tcu::TestCaseGroup* simpleGroup = new tcu::TestCaseGroup(m_testCtx, "simple", "Simple API tests");
394		addChild(simpleGroup);
395
396		simpleGroup->addChild(new QueryAPICase(m_eglTestCtx, "query_api", "eglQueryAPI() test"));
397	}
398
399	// eglGetCurrentContext
400	{
401		tcu::TestCaseGroup* getCurrentContextGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_context", "eglGetCurrentContext() tests");
402		addChild(getCurrentContextGroup);
403
404		createQueryContextGroups<GetCurrentContextCase>(m_eglTestCtx, getCurrentContextGroup);
405	}
406
407	// eglGetCurrentSurface
408	{
409		tcu::TestCaseGroup* getCurrentSurfaceGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_surface", "eglGetCurrentSurface() tests");
410		addChild(getCurrentSurfaceGroup);
411
412		createQueryContextGroups<GetCurrentSurfaceCase>(m_eglTestCtx, getCurrentSurfaceGroup);
413	}
414
415	// eglGetCurrentDisplay
416	{
417		tcu::TestCaseGroup* getCurrentDisplayGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_display", "eglGetCurrentDisplay() tests");
418		addChild(getCurrentDisplayGroup);
419
420		createQueryContextGroups<GetCurrentDisplayCase>(m_eglTestCtx, getCurrentDisplayGroup);
421	}
422
423	// eglQueryContext
424	{
425		tcu::TestCaseGroup* queryContextGroup = new tcu::TestCaseGroup(m_testCtx, "query_context", "eglQueryContext() tests");
426		addChild(queryContextGroup);
427
428		createQueryContextGroups<QueryContextCase>(m_eglTestCtx, queryContextGroup);
429	}
430}
431
432} // egl
433} // deqp
434