1/*-------------------------------------------------------------------------
2 * drawElements Quality Program Platform Utilites
3 * ----------------------------------------------
4 *
5 * Copyright 2015 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 Android platform capability query JNI component
22 *//*--------------------------------------------------------------------*/
23
24#include "tcuDefs.hpp"
25
26#include "tcuCommandLine.hpp"
27#include "gluRenderConfig.hpp"
28#include "gluRenderContext.hpp"
29#include "eglwLibrary.hpp"
30#include "eglwEnums.hpp"
31#include "egluUtil.hpp"
32#include "egluGLUtil.hpp"
33
34#include <jni.h>
35
36namespace
37{
38namespace opt
39{
40
41DE_DECLARE_COMMAND_LINE_OPT(GLMajorVersion, int);
42DE_DECLARE_COMMAND_LINE_OPT(GLMinorVersion, int);
43
44} // opt
45
46class GLConfigParser : public tcu::CommandLine
47{
48public:
49					GLConfigParser			(const std::string& argString);
50
51	bool			hasGLMajorVersion		(void) const;
52	bool			hasGLMinorVersion		(void) const;
53	int				getGLMajorVersion		(void) const;
54	int				getGLMinorVersion		(void) const;
55
56private:
57	virtual void	registerExtendedOptions	(de::cmdline::Parser& parser);
58};
59
60GLConfigParser::GLConfigParser (const std::string& argString)
61{
62	const std::string execString = "fakebinaryname " + argString; // convert argument list to full command line
63
64	if (!parse(execString))
65	{
66		tcu::print("failed to parse command line");
67		TCU_THROW(Exception, "failed to parse command line");
68	}
69}
70
71bool GLConfigParser::hasGLMajorVersion (void) const
72{
73	return getCommandLine().hasOption<opt::GLMajorVersion>();
74}
75
76bool GLConfigParser::hasGLMinorVersion (void) const
77{
78	return getCommandLine().hasOption<opt::GLMinorVersion>();
79}
80
81int GLConfigParser::getGLMajorVersion (void) const
82{
83	DE_ASSERT(hasGLMajorVersion());
84	return getCommandLine().getOption<opt::GLMajorVersion>();
85}
86
87int GLConfigParser::getGLMinorVersion (void) const
88{
89	DE_ASSERT(hasGLMinorVersion());
90	return getCommandLine().getOption<opt::GLMinorVersion>();
91}
92
93void GLConfigParser::registerExtendedOptions (de::cmdline::Parser& parser)
94{
95	using de::cmdline::Option;
96
97	parser
98		<< Option<opt::GLMajorVersion>	(DE_NULL, "deqp-gl-major-version", "OpenGL ES Major version")
99		<< Option<opt::GLMinorVersion>	(DE_NULL, "deqp-gl-minor-version", "OpenGL ES Minor version");
100}
101
102glu::RenderConfig parseRenderConfig (const std::string& argsStr)
103{
104	const GLConfigParser parsedCommandLine (argsStr);
105
106	if (!parsedCommandLine.hasGLMajorVersion() ||
107		!parsedCommandLine.hasGLMinorVersion())
108	{
109		tcu::print("minor and major version must be supplied");
110		TCU_THROW(Exception, "minor and major version must be supplied");
111	}
112	else
113	{
114		const glu::ContextType	testContextType	(glu::ApiType::es(parsedCommandLine.getGLMajorVersion(), parsedCommandLine.getGLMinorVersion()));
115		glu::RenderConfig		renderConfig	(testContextType);
116
117		glu::parseRenderConfig(&renderConfig, parsedCommandLine);
118
119		return renderConfig;
120	}
121}
122
123bool isRenderConfigSupported (const std::string& cmdLineStr)
124{
125	const glu::RenderConfig		renderConfig	= parseRenderConfig(cmdLineStr);
126	const eglw::DefaultLibrary	egl;
127	const eglw::EGLDisplay		display			= egl.getDisplay(EGL_DEFAULT_DISPLAY);
128	eglw::EGLint				eglMajor		= -1;
129	eglw::EGLint				eglMinor		= -1;
130
131	if (display == EGL_NO_DISPLAY)
132	{
133		tcu::print("could not get default display");
134		TCU_THROW(Exception, "could not get default display");
135	}
136
137	if (egl.initialize(display, &eglMajor, &eglMinor) != EGL_TRUE)
138	{
139		tcu::print("failed to initialize egl");
140		TCU_THROW(Exception, "failed to initialize egl");
141	}
142	tcu::print("EGL initialized, major=%d, minor=%d", eglMajor, eglMinor);
143
144	try
145	{
146		// ignoring return value
147		(void)eglu::chooseConfig(egl, display, renderConfig);
148	}
149	catch (const tcu::NotSupportedError&)
150	{
151		tcu::print("No matching config");
152		egl.terminate(display);
153		return false;
154	}
155	catch (...)
156	{
157		egl.terminate(display);
158		throw;
159	}
160	egl.terminate(display);
161
162	return true;
163}
164
165} // anonymous
166
167
168DE_BEGIN_EXTERN_C
169
170JNIEXPORT jint JNICALL Java_com_drawelements_deqp_platformutil_DeqpPlatformCapabilityQueryInstrumentation_nativeRenderConfigSupportedQuery (JNIEnv* env, jclass, jstring jCmdLine)
171{
172	enum
173	{
174		CONFIGQUERYRESULT_SUPPORTED = 0,
175		CONFIGQUERYRESULT_NOT_SUPPORTED = 1,
176		CONFIGQUERYRESULT_GENERIC_ERROR = -1,
177	};
178
179	std::string			cmdLine;
180	const char* const	cmdLineBytes = env->GetStringUTFChars(jCmdLine, DE_NULL);
181
182	if (cmdLineBytes == DE_NULL)
183	{
184		// no command line is not executable
185		tcu::print("no command line supplied");
186		return CONFIGQUERYRESULT_GENERIC_ERROR;
187	}
188
189	try
190	{
191		// try to copy to local buffer
192		cmdLine = std::string(cmdLineBytes);
193	}
194	catch (const std::bad_alloc&)
195	{
196		env->ReleaseStringUTFChars(jCmdLine, cmdLineBytes);
197		tcu::print("failed to copy cmdLine");
198		return CONFIGQUERYRESULT_GENERIC_ERROR;
199	}
200	env->ReleaseStringUTFChars(jCmdLine, cmdLineBytes);
201
202	try
203	{
204		const bool isSupported = isRenderConfigSupported(cmdLine);
205
206		return (isSupported) ? (CONFIGQUERYRESULT_SUPPORTED)
207		                     : (CONFIGQUERYRESULT_NOT_SUPPORTED);
208	}
209	catch (const std::exception& ex)
210	{
211		// don't bother forwarding the exception to the caller. They cannot do anything with the exception anyway.
212		tcu::print("Error: %s", ex.what());
213		return CONFIGQUERYRESULT_GENERIC_ERROR;
214	}
215}
216
217DE_END_EXTERN_C
218