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 Extension function pointer query tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "teglGetProcAddressTests.hpp"
25#include "teglTestCase.hpp"
26#include "egluCallLogWrapper.hpp"
27#include "egluStrUtil.hpp"
28#include "tcuTestLog.hpp"
29
30#include <vector>
31#include <string>
32#include <algorithm>
33#include <cctype>
34
35#if !defined(EGL_OPENGL_ES3_BIT_KHR)
36#	define EGL_OPENGL_ES3_BIT_KHR	0x0040
37#endif
38
39using tcu::TestLog;
40
41namespace deqp
42{
43namespace egl
44{
45
46namespace
47{
48
49// Function name strings generated from API headers
50
51#include "teglGetProcAddressTests.inl"
52
53std::vector<std::string> makeStringVector (const char** cStrArray)
54{
55	std::vector<std::string>	out;
56
57	for (int ndx = 0; cStrArray[ndx] != DE_NULL; ndx++)
58	{
59		out.push_back(std::string(cStrArray[ndx]));
60	}
61
62	return out;
63}
64
65std::vector<std::string> getExtensionNames (void)
66{
67	return makeStringVector(getExtensionStrs());
68}
69
70std::vector<std::string> getExtFunctionNames (const std::string& extName)
71{
72	const char** names_raw = getExtensionFuncStrs(extName);
73
74	return (names_raw != 0) ? makeStringVector(names_raw) : std::vector<std::string>();
75}
76
77std::vector<std::string> getCoreFunctionNames (EGLint apiBit)
78{
79	switch (apiBit)
80	{
81		case 0:							return makeStringVector(getCoreFunctionStrs());
82		case EGL_OPENGL_ES_BIT:			return makeStringVector(getGlesFunctionStrs());
83		case EGL_OPENGL_ES2_BIT:		return makeStringVector(getGles2FunctionStrs());
84		case EGL_OPENGL_ES3_BIT_KHR:	return makeStringVector(getGles3FunctionStrs());
85		default:
86			DE_ASSERT(DE_FALSE);
87	}
88
89	return std::vector<std::string>();
90}
91
92} // anonymous
93
94// Base class for eglGetProcAddress() test cases
95
96class GetProcAddressCase : public TestCase, protected eglu::CallLogWrapper
97{
98public:
99								GetProcAddressCase		(EglTestContext& eglTestCtx, const char* name, const char* description);
100	virtual						~GetProcAddressCase		(void);
101
102	void						init					(void);
103	IterateResult				iterate					(void);
104
105	bool						isSupported				(const std::string& extName);
106
107	virtual void				executeTest				(void) = 0;
108
109private:
110	std::vector<std::string>	m_supported;
111};
112
113GetProcAddressCase::GetProcAddressCase (EglTestContext& eglTestCtx, const char* name, const char* description)
114	: TestCase			(eglTestCtx, name, description)
115	, CallLogWrapper	(eglTestCtx.getTestContext().getLog())
116{
117}
118
119GetProcAddressCase::~GetProcAddressCase (void)
120{
121}
122
123void GetProcAddressCase::init (void)
124{
125	const tcu::egl::Display&	display		= m_eglTestCtx.getDisplay();
126	display.getExtensions(m_supported);
127
128	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
129}
130
131tcu::TestNode::IterateResult GetProcAddressCase::iterate (void)
132{
133	enableLogging(true);
134
135	executeTest();
136
137	enableLogging(false);
138
139	return STOP;
140}
141
142bool GetProcAddressCase::isSupported (const std::string& extName)
143{
144	return std::find(m_supported.begin(), m_supported.end(), extName) != m_supported.end();
145}
146
147// Test by extension
148
149class GetProcAddressExtensionCase : public GetProcAddressCase
150{
151public:
152	GetProcAddressExtensionCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::string& extName)
153		: GetProcAddressCase	(eglTestCtx, name, description)
154		, m_extName				(extName)
155	{
156	}
157
158	virtual ~GetProcAddressExtensionCase (void)
159	{
160	}
161
162	void executeTest (void)
163	{
164		TestLog&						log			= m_testCtx.getLog();
165		bool							supported	= isSupported(m_extName);
166		const std::vector<std::string>	funcNames	= getExtFunctionNames(m_extName);
167
168		DE_ASSERT(!funcNames.empty());
169
170		log << TestLog::Message << m_extName << ": " << (supported ? "supported" : "not supported") << TestLog::EndMessage;
171		log << TestLog::Message << TestLog::EndMessage;
172
173		for (std::vector<std::string>::const_iterator funcIter = funcNames.begin(); funcIter != funcNames.end(); funcIter++)
174		{
175			const std::string&	funcName			= *funcIter;
176			void				(*funcPtr)(void);
177
178			funcPtr = eglGetProcAddress(funcName.c_str());
179			TCU_CHECK_EGL();
180
181			if (supported && funcPtr == 0)
182			{
183				log << TestLog::Message << "Fail, received null pointer for supported extension function: " << funcName << TestLog::EndMessage;
184				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected null pointer");
185			}
186		}
187	}
188
189private:
190	std::string	m_extName;
191};
192
193// Test core functions
194
195class GetProcAddressCoreFunctionsCase : public GetProcAddressCase
196{
197public:
198	GetProcAddressCoreFunctionsCase (EglTestContext& eglTestCtx, const char* name, const char* description, const EGLint apiBit = 0)
199		: GetProcAddressCase	(eglTestCtx, name, description)
200		, m_funcNames			(getCoreFunctionNames(apiBit))
201		, m_apiBit				(apiBit)
202	{
203	}
204
205	virtual ~GetProcAddressCoreFunctionsCase (void)
206	{
207	}
208
209	bool isApiSupported (void)
210	{
211		const std::vector<eglu::ConfigInfo>	configs	= m_eglTestCtx.getConfigs();
212
213		if (m_apiBit == 0)
214			return true;
215
216		for (std::vector<eglu::ConfigInfo>::const_iterator configIter = configs.begin(); configIter != configs.end(); configIter++)
217		{
218			const eglu::ConfigInfo&	config	= *configIter;
219
220			if ((config.renderableType & m_apiBit) != 0)
221				return true;
222		}
223
224		return false;
225	}
226
227	void executeTest (void)
228	{
229		TestLog&	log					= m_testCtx.getLog();
230		const bool	funcPtrSupported	= isSupported("EGL_KHR_get_all_proc_addresses");
231		const bool	apiSupported		= isApiSupported();
232
233		log << TestLog::Message << "EGL_KHR_get_all_proc_addresses: " << (funcPtrSupported ? "supported" : "not supported") << TestLog::EndMessage;
234		log << TestLog::Message << TestLog::EndMessage;
235
236		if (!apiSupported)
237		{
238			log << TestLog::Message << eglu::getConfigAttribValueStr(EGL_RENDERABLE_TYPE, m_apiBit) << " not supported by any available configuration." << TestLog::EndMessage;
239			log << TestLog::Message << TestLog::EndMessage;
240		}
241
242		for (std::vector<std::string>::const_iterator funcIter = m_funcNames.begin(); funcIter != m_funcNames.end(); funcIter++)
243		{
244			const std::string&	funcName			= *funcIter;
245			void				(*funcPtr)(void);
246
247			funcPtr = eglGetProcAddress(funcName.c_str());
248			TCU_CHECK_EGL();
249
250			if (apiSupported && funcPtrSupported && (funcPtr == 0))
251			{
252				log << TestLog::Message << "Fail, received null pointer for supported function: " << funcName << TestLog::EndMessage;
253				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected null pointer");
254			}
255			else if (!apiSupported && (funcPtr != 0))
256			{
257				log << TestLog::Message << "Warning, received non-null value for unsupported function: " << funcName << TestLog::EndMessage;
258				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Non-null value for unsupported function");
259			}
260		}
261	}
262
263private:
264	const std::vector<std::string>	m_funcNames;
265	const EGLint					m_apiBit;
266};
267
268GetProcAddressTests::GetProcAddressTests (EglTestContext& eglTestCtx)
269	: TestCaseGroup(eglTestCtx, "get_proc_address", "eglGetProcAddress() tests")
270{
271}
272
273GetProcAddressTests::~GetProcAddressTests (void)
274{
275}
276
277void GetProcAddressTests::init (void)
278{
279	// extensions
280	{
281		tcu::TestCaseGroup* extensionsGroup = new tcu::TestCaseGroup(m_testCtx, "extension", "Test EGL extensions");
282		addChild(extensionsGroup);
283
284		const std::vector<std::string>	extNames	= getExtensionNames();
285
286		for (std::vector<std::string>::const_iterator extIter = extNames.begin(); extIter != extNames.end(); extIter++)
287		{
288			const std::string&				extName		= *extIter;
289			const std::vector<std::string>	funcNames	= getExtFunctionNames(extName);
290
291			std::string						testName	(extName);
292
293			if (funcNames.empty())
294				continue;
295
296			for (size_t ndx = 0; ndx < extName.length(); ndx++)
297				testName[ndx] = std::tolower(extName[ndx]);
298
299			extensionsGroup->addChild(new GetProcAddressExtensionCase(m_eglTestCtx, testName.c_str(), ("Test " + extName).c_str(), extName));
300		}
301	}
302
303	// core functions
304	{
305		tcu::TestCaseGroup* coreFuncGroup = new tcu::TestCaseGroup(m_testCtx, "core", "Test core functions");
306		addChild(coreFuncGroup);
307
308		coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase	(m_eglTestCtx,	"egl",		"Test EGL core functions"));
309		coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase	(m_eglTestCtx,	"gles",		"Test OpenGL ES core functions",	EGL_OPENGL_ES_BIT));
310		coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase	(m_eglTestCtx,	"gles2",	"Test OpenGL ES 2 core functions",	EGL_OPENGL_ES2_BIT));
311		coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase	(m_eglTestCtx,	"gles3",	"Test OpenGL ES 3 core functions",	EGL_OPENGL_ES3_BIT_KHR));
312	}
313}
314
315} // egl
316} // deqp
317