blob: 2237474f9781fdf0cb4b554d1d20abd604e184f2 [file] [log] [blame]
twiz@google.com59a190b2011-03-14 21:23:01 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
twiz@google.com59a190b2011-03-14 21:23:01 +000018#include "GrTypes.h"
bsalomon@google.comf987d1b2011-04-04 17:13:52 +000019#include "GrGLInterface.h"
20#include "GrGLDefines.h"
twiz@google.com59a190b2011-03-14 21:23:01 +000021
22#include <stdio.h>
23
bsalomon@google.comf987d1b2011-04-04 17:13:52 +000024GrGLInterface* gGLInterface = NULL;
twiz@google.com59a190b2011-03-14 21:23:01 +000025
26void gl_version_from_string(int* major, int* minor,
27 const char* versionString) {
28 if (NULL == versionString) {
29 GrAssert(0);
30 *major = 0;
31 *minor = 0;
32 return;
33 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000034
twiz@google.com59a190b2011-03-14 21:23:01 +000035 int n = sscanf(versionString, "%d.%d", major, minor);
twiz@google.com0f31ca72011-03-18 17:38:11 +000036 if (2 == n) {
37 return;
twiz@google.com59a190b2011-03-14 21:23:01 +000038 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000039
twiz@google.com59a190b2011-03-14 21:23:01 +000040 char profile[2];
twiz@google.com0f31ca72011-03-18 17:38:11 +000041 n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
42 major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000043 bool ok = 4 == n;
44 if (!ok) {
twiz@google.com0f31ca72011-03-18 17:38:11 +000045 n = sscanf(versionString, "OpenGL ES %d.%d", major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000046 ok = 2 == n;
47 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000048
twiz@google.com59a190b2011-03-14 21:23:01 +000049 if (!ok) {
50 GrAssert(0);
51 *major = 0;
52 *minor = 0;
53 return;
54 }
twiz@google.com59a190b2011-03-14 21:23:01 +000055}
56
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +000057float gl_version_as_float_from_string(const char* versionString) {
58 int major, minor;
59 gl_version_from_string(&major, &minor, versionString);
60 GrAssert(minor >= 0);
61 // AFAIK there are only single digit minor numbers
62 if (minor < 10) {
63 return major + minor / 10.f;
64 } else if (minor < 100) {
65 return major + minor / 100.f;
66 } else if (minor < 1000) {
67 return major + minor / 1000.f;
68 } else {
69 GrAssert(!"Why so many digits in minor revision number?");
70 char temp[32];
71 sprintf(temp, "%d.%d", major, minor);
72 return (float) atof(temp);
73 }
74}
75
twiz@google.com59a190b2011-03-14 21:23:01 +000076bool has_gl_extension_from_string(const char* ext,
77 const char* extensionString) {
78 int extLength = strlen(ext);
79
80 while (true) {
81 int n = strcspn(extensionString, " ");
82 if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
83 return true;
84 }
85 if (0 == extensionString[n]) {
86 return false;
87 }
88 extensionString += n+1;
89 }
90
91 return false;
92}
93
bsalomon@google.com91826102011-03-21 19:51:57 +000094GR_API void GrGLSetGLInterface(GrGLInterface* gl_interface) {
twiz@google.com59a190b2011-03-14 21:23:01 +000095 gGLInterface = gl_interface;
96}
97
bsalomon@google.com91826102011-03-21 19:51:57 +000098GR_API GrGLInterface* GrGLGetGLInterface() {
twiz@google.com59a190b2011-03-14 21:23:01 +000099 return gGLInterface;
100}
101
twiz@google.com59a190b2011-03-14 21:23:01 +0000102bool has_gl_extension(const char* ext) {
103 const char* glstr = reinterpret_cast<const char*>(
bsalomon@google.comf987d1b2011-04-04 17:13:52 +0000104 GrGLGetGLInterface()->fGetString(GR_GL_EXTENSIONS));
twiz@google.com59a190b2011-03-14 21:23:01 +0000105
106 return has_gl_extension_from_string(ext, glstr);
107}
108
109void gl_version(int* major, int* minor) {
110 const char* v = reinterpret_cast<const char*>(
bsalomon@google.comf987d1b2011-04-04 17:13:52 +0000111 GrGLGetGLInterface()->fGetString(GR_GL_VERSION));
twiz@google.com59a190b2011-03-14 21:23:01 +0000112 gl_version_from_string(major, minor, v);
113}
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000114
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000115float gl_version_as_float() {
116 const char* v = reinterpret_cast<const char*>(
117 GrGLGetGLInterface()->fGetString(GR_GL_VERSION));
118 return gl_version_as_float_from_string(v);
119}
120
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000121bool GrGLInterface::validateShaderFunctions() const {
122 // required for GrGpuGLShaders
123 if (NULL == fAttachShader ||
124 NULL == fBindAttribLocation ||
125 NULL == fCompileShader ||
126 NULL == fCreateProgram ||
127 NULL == fCreateShader ||
128 NULL == fDeleteProgram ||
129 NULL == fDeleteShader ||
130 NULL == fDisableVertexAttribArray ||
131 NULL == fEnableVertexAttribArray ||
132 NULL == fGetProgramInfoLog ||
133 NULL == fGetProgramiv ||
134 NULL == fGetShaderInfoLog ||
135 NULL == fGetShaderiv ||
136 NULL == fGetUniformLocation ||
137 NULL == fLinkProgram ||
138 NULL == fShaderSource ||
139 NULL == fUniform1f ||
140 NULL == fUniform1i ||
141 NULL == fUniform1fv ||
142 NULL == fUniform1iv ||
143 NULL == fUniform2f ||
144 NULL == fUniform2i ||
145 NULL == fUniform2fv ||
146 NULL == fUniform2iv ||
147 NULL == fUniform3f ||
148 NULL == fUniform3i ||
149 NULL == fUniform3fv ||
150 NULL == fUniform3iv ||
151 NULL == fUniform4f ||
152 NULL == fUniform4i ||
153 NULL == fUniform4fv ||
154 NULL == fUniform4iv ||
155 NULL == fUniformMatrix2fv ||
156 NULL == fUniformMatrix3fv ||
157 NULL == fUniformMatrix4fv ||
158 NULL == fUseProgram ||
159 NULL == fVertexAttrib4fv ||
160 NULL == fVertexAttribPointer) {
161 return false;
162 }
163 return true;
164}
165
166bool GrGLInterface::validateFixedFunctions() const {
167 if (NULL == fClientActiveTexture ||
168 NULL == fColor4ub ||
169 NULL == fColorPointer ||
170 NULL == fDisableClientState ||
171 NULL == fEnableClientState ||
172 NULL == fLoadMatrixf ||
173 NULL == fMatrixMode ||
174 NULL == fPointSize ||
175 NULL == fShadeModel ||
176 NULL == fTexCoordPointer ||
bsalomon@google.com4b9b6a22011-05-04 15:01:16 +0000177 NULL == fTexEnvi ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000178 NULL == fVertexPointer) {
179 return false;
180 }
181 return true;
182}
183
184bool GrGLInterface::validate(GrEngine engine) const {
185
186 bool isDesktop = kDesktop_GrGLBinding == fBindingsExported;
187
188 // ES1 and 2 can be supported in the same interface
189 bool isES = ((kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported &&
190 !(~(kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported));
191
192 if (!isDesktop && !isES) {
193 return false;
194 }
195
196 // functions that are always required
197 if (NULL == fActiveTexture ||
198 NULL == fBindBuffer ||
199 NULL == fBindTexture ||
200 NULL == fBlendFunc ||
201 NULL == fBufferData ||
202 NULL == fBufferSubData ||
203 NULL == fClear ||
204 NULL == fClearColor ||
205 NULL == fClearStencil ||
206 NULL == fColorMask ||
207 NULL == fCullFace ||
208 NULL == fDeleteBuffers ||
209 NULL == fDeleteTextures ||
210 NULL == fDepthMask ||
211 NULL == fDisable ||
212 NULL == fDrawArrays ||
213 NULL == fDrawElements ||
214 NULL == fEnable ||
215 NULL == fFrontFace ||
216 NULL == fGenBuffers ||
217 NULL == fGenTextures ||
218 NULL == fGetBufferParameteriv ||
219 NULL == fGetError ||
220 NULL == fGetIntegerv ||
221 NULL == fGetString ||
222 NULL == fPixelStorei ||
223 NULL == fReadPixels ||
224 NULL == fScissor ||
225 NULL == fStencilFunc ||
226 NULL == fStencilMask ||
227 NULL == fStencilOp ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000228 NULL == fTexImage2D ||
229 NULL == fTexParameteri ||
230 NULL == fTexSubImage2D ||
231 NULL == fViewport ||
232 NULL == fBindFramebuffer ||
233 NULL == fBindRenderbuffer ||
234 NULL == fCheckFramebufferStatus ||
235 NULL == fDeleteFramebuffers ||
236 NULL == fDeleteRenderbuffers ||
237 NULL == fFramebufferRenderbuffer ||
238 NULL == fFramebufferTexture2D ||
239 NULL == fGenFramebuffers ||
240 NULL == fGenRenderbuffers ||
241 NULL == fRenderbufferStorage) {
242 return false;
243 }
244
245 switch (engine) {
246 case kOpenGL_Shaders_GrEngine:
247 if (kES1_GrGLBinding == fBindingsExported) {
248 return false;
249 }
250 if (!this->validateShaderFunctions()) {
251 return false;
252 }
253 break;
254 case kOpenGL_Fixed_GrEngine:
255 if (kES1_GrGLBinding == fBindingsExported) {
256 return false;
257 }
258 if (!this->validateFixedFunctions()) {
259 return false;
260 }
261 break;
262 default:
263 return false;
264 }
265
266 int major, minor;
267 const char* ext;
268
269 gl_version(&major, &minor);
270 ext = (const char*)fGetString(GR_GL_EXTENSIONS);
271
272 // Now check that baseline ES/Desktop fns not covered above are present
273 // and that we have fn pointers for any advertised extensions that we will
274 // try to use.
275
276 // these functions are part of ES2, we assume they are available
277 // On the desktop we assume they are available if the extension
278 // is present or GL version is high enough.
279 if ((kES2_GrGLBinding & fBindingsExported)) {
280 if (NULL == fBlendColor ||
281 NULL == fStencilFuncSeparate ||
282 NULL == fStencilMaskSeparate ||
283 NULL == fStencilOpSeparate) {
284 return false;
285 }
286 } else if (kDesktop_GrGLBinding == fBindingsExported) {
287 if (major >= 2) {
288 if (NULL == fStencilFuncSeparate ||
289 NULL == fStencilMaskSeparate ||
290 NULL == fStencilOpSeparate) {
291 return false;
292 }
293 }
294 if (1 < major || (1 == major && 4 <= minor) ||
295 has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
296 if (NULL == fBlendColor) {
297 return false;
298 }
299 }
300 }
301
302 // optional function on desktop before 1.3
303 if (kDesktop_GrGLBinding != fBindingsExported ||
304 (1 < major || (1 == major && 3 <= minor)) ||
305 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
306 if (NULL == fCompressedTexImage2D) {
307 return false;
308 }
309 }
310
311 // part of desktop GL
312 if (kDesktop_GrGLBinding == fBindingsExported &&
vandebo@chromium.orgec364712011-07-26 03:44:05 +0000313 NULL == fLineWidth) {
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000314 return false;
315 }
316 // FBO MSAA
317 if (kDesktop_GrGLBinding == fBindingsExported) {
318 // GL 3.0 and the ARB extension have multisample + blit
319 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
320 if (NULL == fRenderbufferStorageMultisample ||
321 NULL == fBlitFramebuffer) {
322 return false;
323 }
324 } else {
325 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
326 NULL == fBlitFramebuffer) {
327 return false;
328 }
329 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
330 NULL == fRenderbufferStorageMultisample) {
331 return false;
332 }
333 }
334 } else {
335 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
336 if (NULL == fRenderbufferStorageMultisample ||
337 NULL == fBlitFramebuffer) {
338 return false;
339 }
340 }
341 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
342 if (NULL == fRenderbufferStorageMultisample ||
343 NULL == fResolveMultisampleFramebuffer) {
344 return false;
345 }
346 }
347 }
348
349 // On ES buffer mapping is an extension. On Desktop
350 // buffer mapping was part of original VBO extension
351 // which we require.
352 if (kDesktop_GrGLBinding == fBindingsExported ||
353 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
354 if (NULL == fMapBuffer ||
355 NULL == fUnmapBuffer) {
356 return false;
357 }
358 }
359
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000360 // Dual source blending
361 if (kDesktop_GrGLBinding == fBindingsExported &&
362 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
363 (3 < major) || (3 == major && 3 <= minor))) {
364 if (NULL == fBindFragDataLocationIndexed) {
365 return false;
366 }
367 }
368
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000369 return true;
370}
371