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::vector;
34 using std::string;
35 using std::set;
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,
53 ProgramSources() << VertexSource(m_vertexSource)
54 << FragmentSource(m_fragmentSource));
55 return program.isOk();
56 }
57
58 private:
59 const char* m_vertexSource;
60 const char* m_fragmentSource;
61 };
62
63 typedef CachedValue<bool, TryCompileProgram> IsProgramSupported;
64
65 // ES2-specific context info
66 class ES2ContextInfo : public ContextInfo
67 {
68 public:
69 ES2ContextInfo (const RenderContext& context);
~ES2ContextInfo(void)70 ~ES2ContextInfo (void) {}
71
isVertexUniformLoopSupported(void) const72 bool isVertexUniformLoopSupported (void) const { return m_vertexUniformLoopsSupported.getValue(m_context); }
isVertexDynamicLoopSupported(void) const73 bool isVertexDynamicLoopSupported (void) const { return m_vertexDynamicLoopsSupported.getValue(m_context); }
isFragmentHighPrecisionSupported(void) const74 bool isFragmentHighPrecisionSupported (void) const { return m_fragmentHighPrecisionSupported.getValue(m_context); }
isFragmentUniformLoopSupported(void) const75 bool isFragmentUniformLoopSupported (void) const { return m_fragmentUniformLoopsSupported.getValue(m_context); }
isFragmentDynamicLoopSupported(void) const76 bool isFragmentDynamicLoopSupported (void) const { return m_fragmentDynamicLoopsSupported.getValue(m_context); }
77
78 private:
79 IsProgramSupported m_vertexUniformLoopsSupported;
80 IsProgramSupported m_vertexDynamicLoopsSupported;
81
82 IsProgramSupported m_fragmentHighPrecisionSupported;
83 IsProgramSupported m_fragmentUniformLoopsSupported;
84 IsProgramSupported m_fragmentDynamicLoopsSupported;
85 };
86
87 static const char* s_defaultVertexShader =
88 "attribute highp vec4 a_position;\n"
89 "void main (void) {\n"
90 " gl_Position = a_position;\n"
91 "}\n";
92 static const char* s_defaultFragmentShader =
93 "void main (void) {\n"
94 " gl_FragColor = vec4(1.0);\n"
95 "}\n";
96
97 static 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";
105 static 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
115 static 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";
121 static 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";
129 static 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
ES2ContextInfo(const RenderContext & context)139 ES2ContextInfo::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
split(vector<string> & dst,const string & src)149 static 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
operator ()(const RenderContext & context) const164 vector<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
operator ()(const RenderContext & context) const195 set<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
ContextInfo(const RenderContext & context)216 ContextInfo::ContextInfo (const RenderContext& context)
217 : m_context(context)
218 {
219 }
220
~ContextInfo(void)221 ContextInfo::~ContextInfo (void)
222 {
223 }
224
getInt(int param) const225 int 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
getBool(int param) const233 bool 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
getString(int param) const241 const 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
isCompressedTextureFormatSupported(int format) const248 bool 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
isExtensionSupported(const char * name) const254 bool 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
create(const RenderContext & context)260 ContextInfo* 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