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