blob: 68d058d80b6f630e49a0ad6942257aed77ff042c [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 ||
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000239 NULL == fGetFramebufferAttachmentParameteriv ||
240 NULL == fGetRenderbufferParameteriv ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000241 NULL == fGenFramebuffers ||
242 NULL == fGenRenderbuffers ||
243 NULL == fRenderbufferStorage) {
244 return false;
245 }
246
247 switch (engine) {
248 case kOpenGL_Shaders_GrEngine:
249 if (kES1_GrGLBinding == fBindingsExported) {
250 return false;
251 }
252 if (!this->validateShaderFunctions()) {
253 return false;
254 }
255 break;
256 case kOpenGL_Fixed_GrEngine:
257 if (kES1_GrGLBinding == fBindingsExported) {
258 return false;
259 }
260 if (!this->validateFixedFunctions()) {
261 return false;
262 }
263 break;
264 default:
265 return false;
266 }
267
268 int major, minor;
269 const char* ext;
270
271 gl_version(&major, &minor);
272 ext = (const char*)fGetString(GR_GL_EXTENSIONS);
273
274 // Now check that baseline ES/Desktop fns not covered above are present
275 // and that we have fn pointers for any advertised extensions that we will
276 // try to use.
277
278 // these functions are part of ES2, we assume they are available
279 // On the desktop we assume they are available if the extension
280 // is present or GL version is high enough.
281 if ((kES2_GrGLBinding & fBindingsExported)) {
282 if (NULL == fBlendColor ||
283 NULL == fStencilFuncSeparate ||
284 NULL == fStencilMaskSeparate ||
285 NULL == fStencilOpSeparate) {
286 return false;
287 }
288 } else if (kDesktop_GrGLBinding == fBindingsExported) {
289 if (major >= 2) {
290 if (NULL == fStencilFuncSeparate ||
291 NULL == fStencilMaskSeparate ||
292 NULL == fStencilOpSeparate) {
293 return false;
294 }
295 }
296 if (1 < major || (1 == major && 4 <= minor) ||
297 has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
298 if (NULL == fBlendColor) {
299 return false;
300 }
301 }
302 }
303
304 // optional function on desktop before 1.3
305 if (kDesktop_GrGLBinding != fBindingsExported ||
306 (1 < major || (1 == major && 3 <= minor)) ||
307 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
308 if (NULL == fCompressedTexImage2D) {
309 return false;
310 }
311 }
312
313 // part of desktop GL
314 if (kDesktop_GrGLBinding == fBindingsExported &&
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000315 (NULL == fLineWidth ||
316 NULL == fGetTexLevelParameteriv)) {
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000317 return false;
318 }
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000319
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000320 // FBO MSAA
321 if (kDesktop_GrGLBinding == fBindingsExported) {
322 // GL 3.0 and the ARB extension have multisample + blit
323 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
324 if (NULL == fRenderbufferStorageMultisample ||
325 NULL == fBlitFramebuffer) {
326 return false;
327 }
328 } else {
329 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
330 NULL == fBlitFramebuffer) {
331 return false;
332 }
333 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
334 NULL == fRenderbufferStorageMultisample) {
335 return false;
336 }
337 }
338 } else {
339 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
340 if (NULL == fRenderbufferStorageMultisample ||
341 NULL == fBlitFramebuffer) {
342 return false;
343 }
344 }
345 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
346 if (NULL == fRenderbufferStorageMultisample ||
347 NULL == fResolveMultisampleFramebuffer) {
348 return false;
349 }
350 }
351 }
352
353 // On ES buffer mapping is an extension. On Desktop
354 // buffer mapping was part of original VBO extension
355 // which we require.
356 if (kDesktop_GrGLBinding == fBindingsExported ||
357 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
358 if (NULL == fMapBuffer ||
359 NULL == fUnmapBuffer) {
360 return false;
361 }
362 }
363
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000364 // Dual source blending
365 if (kDesktop_GrGLBinding == fBindingsExported &&
366 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
367 (3 < major) || (3 == major && 3 <= minor))) {
368 if (NULL == fBindFragDataLocationIndexed) {
369 return false;
370 }
371 }
372
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000373 return true;
374}
375