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