1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
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 Context Info Class.
22 *//*--------------------------------------------------------------------*/
23
24#include "gluContextInfo.hpp"
25#include "gluRenderContext.hpp"
26#include "gluShaderProgram.hpp"
27#include "glwFunctions.hpp"
28#include "glwEnums.hpp"
29
30#include <iterator>
31#include <algorithm>
32
33using std::vector;
34using std::string;
35using std::set;
36
37namespace glu
38{
39
40class TryCompileProgram
41{
42public:
43	// \note Assumes that shader pointer can be stored as is (eg. it is static data)
44	TryCompileProgram (const char* vertexSource, const char* fragmentSource)
45		: m_vertexSource	(vertexSource)
46		, m_fragmentSource	(fragmentSource)
47	{
48	}
49
50	bool operator() (const RenderContext& context) const
51	{
52		ShaderProgram program(context,
53			ProgramSources() << VertexSource(m_vertexSource)
54							 << FragmentSource(m_fragmentSource));
55		return program.isOk();
56	}
57
58private:
59	const char*	m_vertexSource;
60	const char*	m_fragmentSource;
61};
62
63typedef CachedValue<bool, TryCompileProgram> IsProgramSupported;
64
65// ES2-specific context info
66class ES2ContextInfo : public ContextInfo
67{
68public:
69										ES2ContextInfo						(const RenderContext& context);
70										~ES2ContextInfo						(void) {}
71
72	bool								isVertexUniformLoopSupported		(void) const	{ return m_vertexUniformLoopsSupported.getValue(m_context);		}
73	bool								isVertexDynamicLoopSupported		(void) const	{ return m_vertexDynamicLoopsSupported.getValue(m_context);		}
74	bool								isFragmentHighPrecisionSupported	(void) const	{ return m_fragmentHighPrecisionSupported.getValue(m_context);	}
75	bool								isFragmentUniformLoopSupported		(void) const	{ return m_fragmentUniformLoopsSupported.getValue(m_context);	}
76	bool								isFragmentDynamicLoopSupported		(void) const	{ return m_fragmentDynamicLoopsSupported.getValue(m_context);	}
77
78private:
79	IsProgramSupported					m_vertexUniformLoopsSupported;
80	IsProgramSupported					m_vertexDynamicLoopsSupported;
81
82	IsProgramSupported					m_fragmentHighPrecisionSupported;
83	IsProgramSupported					m_fragmentUniformLoopsSupported;
84	IsProgramSupported					m_fragmentDynamicLoopsSupported;
85};
86
87static const char* s_defaultVertexShader =
88	"attribute highp vec4 a_position;\n"
89	"void main (void) {\n"
90	"	gl_Position = a_position;\n"
91	"}\n";
92static const char* s_defaultFragmentShader =
93	"void main (void) {\n"
94	"	gl_FragColor = vec4(1.0);\n"
95	"}\n";
96
97static const char* s_vertexUniformLoopsSupported =
98	"attribute highp vec4	a_position;\n"
99	"uniform int			u_numIters;\n"
100	"void main (void) {\n"
101	"	gl_Position = a_position;\n"
102	"	for (int i = 0; i < u_numIters; i++)\n"
103	"		gl_Position += vec4(0.1);\n"
104	"}\n";
105static const char* s_vertexDynamicLoopsSupported =
106	"attribute highp vec4	a_position;\n"
107	"uniform mediump float	a, b;\n"
108	"void main (void) {\n"
109	"	gl_Position = a_position;\n"
110	"	int numIters = a < b ? int(3.0*b) : int(a_position.x);\n"
111	"	for (int i = 0; i < numIters; i++)\n"
112	"		gl_Position += vec4(0.1);\n"
113	"}\n";
114
115static const char* s_fragmentHighPrecisionSupported =
116	"varying highp vec4		v_color;\n"
117	"void main (void) {\n"
118	"	highp float tmp = v_color.r;\n"
119	"	gl_FragColor = v_color;\n"
120	"}\n";
121static const char* s_fragmentUniformLoopsSupported =
122	"varying mediump vec4	v_color;\n"
123	"uniform int			u_numIters;\n"
124	"void main (void) {\n"
125	"	gl_FragColor = v_color;\n"
126	"	for (int i = 0; i < u_numIters; i++)\n"
127	"		gl_FragColor += vec4(0.1);\n"
128	"}\n";
129static const char* s_fragmentDynamicLoopsSupported =
130	"varying mediump vec4	v_color;\n"
131	"uniform mediump float	a, b;\n"
132	"void main (void) {\n"
133	"	gl_FragColor = v_color;\n"
134	"	int numIters = a < b ? int(3.0*b) : int(v_color.x);\n"
135	"	for (int i = 0; i < numIters; i++)\n"
136	"		gl_FragColor += vec4(0.1);\n"
137	"}\n";
138
139ES2ContextInfo::ES2ContextInfo (const RenderContext& context)
140	: glu::ContextInfo					(context)
141	, m_vertexUniformLoopsSupported		(TryCompileProgram(s_vertexUniformLoopsSupported, s_defaultFragmentShader))
142	, m_vertexDynamicLoopsSupported		(TryCompileProgram(s_vertexDynamicLoopsSupported, s_defaultFragmentShader))
143	, m_fragmentHighPrecisionSupported	(TryCompileProgram(s_defaultVertexShader, s_fragmentHighPrecisionSupported))
144	, m_fragmentUniformLoopsSupported	(TryCompileProgram(s_defaultVertexShader, s_fragmentUniformLoopsSupported))
145	, m_fragmentDynamicLoopsSupported	(TryCompileProgram(s_defaultVertexShader, s_fragmentDynamicLoopsSupported))
146{
147}
148
149static void split (vector<string>& dst, const string& src)
150{
151	size_t start = 0;
152	size_t end	 = string::npos;
153
154	while ((end = src.find(' ', start)) != string::npos)
155	{
156		dst.push_back(src.substr(start, end-start));
157		start = end+1;
158	}
159
160	if (start < end)
161		dst.push_back(src.substr(start, end-start));
162}
163
164vector<string> GetExtensions::operator() (const RenderContext& context) const
165{
166	const glw::Functions& gl = context.getFunctions();
167
168	if (context.getType().getAPI() == ApiType::es(2,0))
169	{
170		const char* result = (const char*)gl.getString(GL_EXTENSIONS);
171		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetString(GL_EXTENSIONS) failed");
172
173		vector<string> extensions;
174		split(extensions, string(result));
175
176		return extensions;
177	}
178	else
179	{
180		int				numExtensions	= 0;
181		vector<string>	extensions;
182
183		gl.getIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
184		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_NUM_EXTENSIONS) failed");
185
186		extensions.resize(numExtensions);
187		for (int ndx = 0; ndx < numExtensions; ndx++)
188			extensions[ndx] = (const char*)gl.getStringi(GL_EXTENSIONS, ndx);
189		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetStringi(GL_EXTENSIONS, ndx) failed");
190
191		return extensions;
192	}
193}
194
195set<int> GetCompressedTextureFormats::operator() (const RenderContext& context) const
196{
197	const glw::Functions& gl = context.getFunctions();
198
199	int numFormats = 0;
200	gl.getIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
201
202	vector<int> formats(numFormats);
203	if (numFormats > 0)
204		gl.getIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, &formats[0]);
205
206	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS) failed");
207
208	set<int> formatSet;
209	std::copy(formats.begin(), formats.end(), std::inserter(formatSet, formatSet.begin()));
210
211	return formatSet;
212}
213
214// ContextInfo
215
216ContextInfo::ContextInfo (const RenderContext& context)
217	: m_context(context)
218{
219}
220
221ContextInfo::~ContextInfo (void)
222{
223}
224
225int ContextInfo::getInt (int param) const
226{
227	int val = -1;
228	m_context.getFunctions().getIntegerv(param, &val);
229	GLU_EXPECT_NO_ERROR(m_context.getFunctions().getError(), "glGetIntegerv() failed");
230	return val;
231}
232
233bool ContextInfo::getBool (int param) const
234{
235	glw::GLboolean val = GL_FALSE;
236	m_context.getFunctions().getBooleanv(param, &val);
237	GLU_EXPECT_NO_ERROR(m_context.getFunctions().getError(), "glGetBooleanv() failed");
238	return val != GL_FALSE;
239}
240
241const char* ContextInfo::getString (int param) const
242{
243	const char* str = (const char*)m_context.getFunctions().getString(param);
244	GLU_EXPECT_NO_ERROR(m_context.getFunctions().getError(), "glGetString() failed");
245	return str;
246}
247
248bool ContextInfo::isCompressedTextureFormatSupported (int format) const
249{
250	const set<int>& formats = m_compressedTextureFormats.getValue(m_context);
251	return formats.find(format) != formats.end();
252}
253
254bool ContextInfo::isExtensionSupported (const char* name) const
255{
256	const std::vector<std::string>& extensions = getExtensions();
257	return std::find(extensions.begin(), extensions.end(), name) != extensions.end();
258}
259
260ContextInfo* ContextInfo::create (const RenderContext& context)
261{
262	// ES2 uses special variant that checks support for various shader features
263	// by trying to compile shader programs.
264	if (context.getType().getAPI() == ApiType::es(2,0))
265		return new ES2ContextInfo(context);
266
267	return new ContextInfo(context);
268}
269
270} // glu
271