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 
46 namespace deqp
47 {
48 namespace egl
49 {
50 
51 using std::vector;
52 using eglu::ConfigInfo;
53 using tcu::TestLog;
54 using namespace eglw;
55 
getClientTypeFromAPIBit(EGLint apiBit)56 static 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 
getMinClientMajorVersion(EGLint apiBit)71 static 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 
86 class GetCurrentContextCase : public SingleContextRenderCase, private eglu::CallLogWrapper
87 {
88 public:
GetCurrentContextCase(EglTestContext & eglTestCtx,const char * name,const char * description,const eglu::FilterList & filters,EGLint surfaceTypeMask)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 
executeForContext(EGLDisplay display,EGLContext context,EGLSurface surface,const Config & config)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 
128 class GetCurrentSurfaceCase : public SingleContextRenderCase, private eglu::CallLogWrapper
129 {
130 public:
GetCurrentSurfaceCase(EglTestContext & eglTestCtx,const char * name,const char * description,const eglu::FilterList & filters,EGLint surfaceTypeMask)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 
executeForContext(EGLDisplay display,EGLContext context,EGLSurface surface,const Config & config)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 
170 class GetCurrentDisplayCase : public SingleContextRenderCase, private eglu::CallLogWrapper
171 {
172 public:
GetCurrentDisplayCase(EglTestContext & eglTestCtx,const char * name,const char * description,const eglu::FilterList & filters,EGLint surfaceTypeMask)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 
executeForContext(EGLDisplay display,EGLContext context,EGLSurface surface,const Config & config)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 
211 class QueryContextCase : public SingleContextRenderCase, private eglu::CallLogWrapper
212 {
213 public:
QueryContextCase(EglTestContext & eglTestCtx,const char * name,const char * description,const eglu::FilterList & filters,EGLint surfaceTypeMask)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 
getContextAttrib(EGLDisplay display,EGLContext context,EGLint attrib)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 
executeForContext(EGLDisplay display,EGLContext context,EGLSurface surface,const Config & config)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 
303 class QueryAPICase : public TestCase, private eglu::CallLogWrapper
304 {
305 public:
QueryAPICase(EglTestContext & eglTestCtx,const char * name,const char * description)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 
init(void)312 	void init (void)
313 	{
314 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
315 	}
316 
iterate(void)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 
QueryContextTests(EglTestContext & eglTestCtx)370 QueryContextTests::QueryContextTests (EglTestContext& eglTestCtx)
371 	: TestCaseGroup(eglTestCtx, "query_context", "Rendering context query tests")
372 {
373 }
374 
~QueryContextTests(void)375 QueryContextTests::~QueryContextTests (void)
376 {
377 }
378 
379 template<class QueryContextClass>
createQueryContextGroups(EglTestContext & eglTestCtx,tcu::TestCaseGroup * group)380 void 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 
init(void)390 void 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