blob: ec00f16dc45ef20f3411cb152d125ae4a6230f8b [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
twiz@google.com59a190b2011-03-14 21:23:01 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
twiz@google.com59a190b2011-03-14 21:23:01 +00007 */
8
9
twiz@google.com59a190b2011-03-14 21:23:01 +000010#include "GrTypes.h"
bsalomon@google.comf987d1b2011-04-04 17:13:52 +000011#include "GrGLInterface.h"
12#include "GrGLDefines.h"
twiz@google.com59a190b2011-03-14 21:23:01 +000013
14#include <stdio.h>
15
bsalomon@google.com0b77d682011-08-19 13:28:54 +000016static SkAutoTUnref<const GrGLInterface> gDefaultGLInterface;
twiz@google.com59a190b2011-03-14 21:23:01 +000017
18void gl_version_from_string(int* major, int* minor,
19 const char* versionString) {
20 if (NULL == versionString) {
21 GrAssert(0);
22 *major = 0;
23 *minor = 0;
24 return;
25 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000026
twiz@google.com59a190b2011-03-14 21:23:01 +000027 int n = sscanf(versionString, "%d.%d", major, minor);
twiz@google.com0f31ca72011-03-18 17:38:11 +000028 if (2 == n) {
29 return;
twiz@google.com59a190b2011-03-14 21:23:01 +000030 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000031
twiz@google.com59a190b2011-03-14 21:23:01 +000032 char profile[2];
twiz@google.com0f31ca72011-03-18 17:38:11 +000033 n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
34 major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000035 bool ok = 4 == n;
36 if (!ok) {
twiz@google.com0f31ca72011-03-18 17:38:11 +000037 n = sscanf(versionString, "OpenGL ES %d.%d", major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000038 ok = 2 == n;
39 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000040
twiz@google.com59a190b2011-03-14 21:23:01 +000041 if (!ok) {
42 GrAssert(0);
43 *major = 0;
44 *minor = 0;
45 return;
46 }
twiz@google.com59a190b2011-03-14 21:23:01 +000047}
48
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +000049float gl_version_as_float_from_string(const char* versionString) {
50 int major, minor;
51 gl_version_from_string(&major, &minor, versionString);
52 GrAssert(minor >= 0);
53 // AFAIK there are only single digit minor numbers
54 if (minor < 10) {
55 return major + minor / 10.f;
56 } else if (minor < 100) {
57 return major + minor / 100.f;
58 } else if (minor < 1000) {
59 return major + minor / 1000.f;
60 } else {
61 GrAssert(!"Why so many digits in minor revision number?");
62 char temp[32];
63 sprintf(temp, "%d.%d", major, minor);
64 return (float) atof(temp);
65 }
66}
67
twiz@google.com59a190b2011-03-14 21:23:01 +000068bool has_gl_extension_from_string(const char* ext,
69 const char* extensionString) {
70 int extLength = strlen(ext);
71
72 while (true) {
73 int n = strcspn(extensionString, " ");
74 if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
75 return true;
76 }
77 if (0 == extensionString[n]) {
78 return false;
79 }
80 extensionString += n+1;
81 }
82
83 return false;
84}
85
bsalomon@google.com0b77d682011-08-19 13:28:54 +000086GR_API const GrGLInterface* GrGLSetDefaultGLInterface(const GrGLInterface* gl_interface) {
87 gl_interface->ref();
88 gDefaultGLInterface.reset(gl_interface);
89 return gl_interface;
twiz@google.com59a190b2011-03-14 21:23:01 +000090}
91
bsalomon@google.com0b77d682011-08-19 13:28:54 +000092GR_API const GrGLInterface* GrGLGetDefaultGLInterface() {
93 if (NULL == gDefaultGLInterface.get()) {
94 GrGLInitializeDefaultGLInterface();
95 }
96 return gDefaultGLInterface.get();
twiz@google.com59a190b2011-03-14 21:23:01 +000097}
98
bsalomon@google.com0b77d682011-08-19 13:28:54 +000099bool has_gl_extension(const GrGLInterface* gl, const char* ext) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000100 const char* glstr = reinterpret_cast<const char*>(
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000101 gl->fGetString(GR_GL_EXTENSIONS));
twiz@google.com59a190b2011-03-14 21:23:01 +0000102
103 return has_gl_extension_from_string(ext, glstr);
104}
105
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000106void gl_version(const GrGLInterface* gl, int* major, int* minor) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000107 const char* v = reinterpret_cast<const char*>(
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000108 gl->fGetString(GR_GL_VERSION));
twiz@google.com59a190b2011-03-14 21:23:01 +0000109 gl_version_from_string(major, minor, v);
110}
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000111
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000112float gl_version_as_float(const GrGLInterface* gl) {
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000113 const char* v = reinterpret_cast<const char*>(
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000114 gl->fGetString(GR_GL_VERSION));
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000115 return gl_version_as_float_from_string(v);
116}
117
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000118GrGLInterface::GrGLInterface() {
119 fBindingsExported = (GrGLBinding)0;
120 fNPOTRenderTargetSupport = kProbe_GrGLCapability;
121 fMinRenderTargetHeight = kProbe_GrGLCapability;
122 fMinRenderTargetWidth = kProbe_GrGLCapability;
123
124 fActiveTexture = NULL;
125 fAttachShader = NULL;
126 fBindAttribLocation = NULL;
127 fBindBuffer = NULL;
128 fBindTexture = NULL;
129 fBlendColor = NULL;
130 fBlendFunc = NULL;
131 fBufferData = NULL;
132 fBufferSubData = NULL;
133 fClear = NULL;
134 fClearColor = NULL;
135 fClearStencil = NULL;
136 fClientActiveTexture = NULL;
137 fColor4ub = NULL;
138 fColorMask = NULL;
139 fColorPointer = NULL;
140 fCompileShader = NULL;
141 fCompressedTexImage2D = NULL;
142 fCreateProgram = NULL;
143 fCreateShader = NULL;
144 fCullFace = NULL;
145 fDeleteBuffers = NULL;
146 fDeleteProgram = NULL;
147 fDeleteShader = NULL;
148 fDeleteTextures = NULL;
149 fDepthMask = NULL;
150 fDisable = NULL;
151 fDisableClientState = NULL;
152 fDisableVertexAttribArray = NULL;
153 fDrawArrays = NULL;
154 fDrawBuffer = NULL;
155 fDrawBuffers = NULL;
156 fDrawElements = NULL;
157 fEnable = NULL;
158 fEnableClientState = NULL;
159 fEnableVertexAttribArray = NULL;
160 fFrontFace = NULL;
161 fGenBuffers = NULL;
162 fGenTextures = NULL;
163 fGetBufferParameteriv = NULL;
164 fGetError = NULL;
165 fGetIntegerv = NULL;
166 fGetProgramInfoLog = NULL;
167 fGetProgramiv = NULL;
168 fGetShaderInfoLog = NULL;
169 fGetShaderiv = NULL;
170 fGetString = NULL;
171 fGetTexLevelParameteriv = NULL;
172 fGetUniformLocation = NULL;
173 fLineWidth = NULL;
174 fLinkProgram = NULL;
175 fLoadMatrixf = NULL;
176 fMatrixMode = NULL;
177 fPixelStorei = NULL;
178 fPointSize = NULL;
179 fReadBuffer = NULL;
180 fReadPixels = NULL;
181 fScissor = NULL;
182 fShadeModel = NULL;
183 fShaderSource = NULL;
184 fStencilFunc = NULL;
185 fStencilFuncSeparate = NULL;
186 fStencilMask = NULL;
187 fStencilMaskSeparate = NULL;
188 fStencilOp = NULL;
189 fStencilOpSeparate = NULL;
190 fTexCoordPointer = NULL;
191 fTexEnvi = NULL;
192 fTexImage2D = NULL;
193 fTexParameteri = NULL;
194 fTexSubImage2D = NULL;
195 fUniform1f = NULL;
196 fUniform1i = NULL;
197 fUniform1fv = NULL;
198 fUniform1iv = NULL;
199 fUniform2f = NULL;
200 fUniform2i = NULL;
201 fUniform2fv = NULL;
202 fUniform2iv = NULL;
203 fUniform3f = NULL;
204 fUniform3i = NULL;
205 fUniform3fv = NULL;
206 fUniform3iv = NULL;
207 fUniform4f = NULL;
208 fUniform4i = NULL;
209 fUniform4fv = NULL;
210 fUniform4iv = NULL;
211 fUniformMatrix2fv = NULL;
212 fUniformMatrix3fv = NULL;
213 fUniformMatrix4fv = NULL;
214 fUseProgram = NULL;
215 fVertexAttrib4fv = NULL;
216 fVertexAttribPointer = NULL;
217 fVertexPointer = NULL;
218 fViewport = NULL;
219 fBindFramebuffer = NULL;
220 fBindRenderbuffer = NULL;
221 fCheckFramebufferStatus = NULL;
222 fDeleteFramebuffers = NULL;
223 fDeleteRenderbuffers = NULL;
224 fFramebufferRenderbuffer = NULL;
225 fFramebufferTexture2D = NULL;
226 fGenFramebuffers = NULL;
227 fGenRenderbuffers = NULL;
228 fGetFramebufferAttachmentParameteriv = NULL;
229 fGetRenderbufferParameteriv = NULL;
230 fRenderbufferStorage = NULL;
231 fRenderbufferStorageMultisample = NULL;
232 fBlitFramebuffer = NULL;
233 fResolveMultisampleFramebuffer = NULL;
234 fMapBuffer = NULL;
235 fUnmapBuffer = NULL;
236 fBindFragDataLocationIndexed = NULL;
237}
238
239
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000240bool GrGLInterface::validateShaderFunctions() const {
241 // required for GrGpuGLShaders
242 if (NULL == fAttachShader ||
243 NULL == fBindAttribLocation ||
244 NULL == fCompileShader ||
245 NULL == fCreateProgram ||
246 NULL == fCreateShader ||
247 NULL == fDeleteProgram ||
248 NULL == fDeleteShader ||
249 NULL == fDisableVertexAttribArray ||
250 NULL == fEnableVertexAttribArray ||
251 NULL == fGetProgramInfoLog ||
252 NULL == fGetProgramiv ||
253 NULL == fGetShaderInfoLog ||
254 NULL == fGetShaderiv ||
255 NULL == fGetUniformLocation ||
256 NULL == fLinkProgram ||
257 NULL == fShaderSource ||
258 NULL == fUniform1f ||
259 NULL == fUniform1i ||
260 NULL == fUniform1fv ||
261 NULL == fUniform1iv ||
262 NULL == fUniform2f ||
263 NULL == fUniform2i ||
264 NULL == fUniform2fv ||
265 NULL == fUniform2iv ||
266 NULL == fUniform3f ||
267 NULL == fUniform3i ||
268 NULL == fUniform3fv ||
269 NULL == fUniform3iv ||
270 NULL == fUniform4f ||
271 NULL == fUniform4i ||
272 NULL == fUniform4fv ||
273 NULL == fUniform4iv ||
274 NULL == fUniformMatrix2fv ||
275 NULL == fUniformMatrix3fv ||
276 NULL == fUniformMatrix4fv ||
277 NULL == fUseProgram ||
278 NULL == fVertexAttrib4fv ||
279 NULL == fVertexAttribPointer) {
280 return false;
281 }
282 return true;
283}
284
285bool GrGLInterface::validateFixedFunctions() const {
286 if (NULL == fClientActiveTexture ||
287 NULL == fColor4ub ||
288 NULL == fColorPointer ||
289 NULL == fDisableClientState ||
290 NULL == fEnableClientState ||
291 NULL == fLoadMatrixf ||
292 NULL == fMatrixMode ||
293 NULL == fPointSize ||
294 NULL == fShadeModel ||
295 NULL == fTexCoordPointer ||
bsalomon@google.com4b9b6a22011-05-04 15:01:16 +0000296 NULL == fTexEnvi ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000297 NULL == fVertexPointer) {
298 return false;
299 }
300 return true;
301}
302
303bool GrGLInterface::validate(GrEngine engine) const {
304
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000305 bool isDesktop = this->supportsDesktop();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000306
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000307 bool isES = this->supportsES();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000308
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000309 if (isDesktop == isES) {
310 // must have one, don't support both in same interface
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000311 return false;
312 }
313
314 // functions that are always required
315 if (NULL == fActiveTexture ||
316 NULL == fBindBuffer ||
317 NULL == fBindTexture ||
318 NULL == fBlendFunc ||
319 NULL == fBufferData ||
320 NULL == fBufferSubData ||
321 NULL == fClear ||
322 NULL == fClearColor ||
323 NULL == fClearStencil ||
324 NULL == fColorMask ||
325 NULL == fCullFace ||
326 NULL == fDeleteBuffers ||
327 NULL == fDeleteTextures ||
328 NULL == fDepthMask ||
329 NULL == fDisable ||
330 NULL == fDrawArrays ||
331 NULL == fDrawElements ||
332 NULL == fEnable ||
333 NULL == fFrontFace ||
334 NULL == fGenBuffers ||
335 NULL == fGenTextures ||
336 NULL == fGetBufferParameteriv ||
337 NULL == fGetError ||
338 NULL == fGetIntegerv ||
339 NULL == fGetString ||
340 NULL == fPixelStorei ||
341 NULL == fReadPixels ||
342 NULL == fScissor ||
343 NULL == fStencilFunc ||
344 NULL == fStencilMask ||
345 NULL == fStencilOp ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000346 NULL == fTexImage2D ||
347 NULL == fTexParameteri ||
348 NULL == fTexSubImage2D ||
349 NULL == fViewport ||
350 NULL == fBindFramebuffer ||
351 NULL == fBindRenderbuffer ||
352 NULL == fCheckFramebufferStatus ||
353 NULL == fDeleteFramebuffers ||
354 NULL == fDeleteRenderbuffers ||
355 NULL == fFramebufferRenderbuffer ||
356 NULL == fFramebufferTexture2D ||
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000357 NULL == fGetFramebufferAttachmentParameteriv ||
358 NULL == fGetRenderbufferParameteriv ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000359 NULL == fGenFramebuffers ||
360 NULL == fGenRenderbuffers ||
361 NULL == fRenderbufferStorage) {
362 return false;
363 }
364
365 switch (engine) {
366 case kOpenGL_Shaders_GrEngine:
367 if (kES1_GrGLBinding == fBindingsExported) {
368 return false;
369 }
370 if (!this->validateShaderFunctions()) {
371 return false;
372 }
373 break;
374 case kOpenGL_Fixed_GrEngine:
375 if (kES1_GrGLBinding == fBindingsExported) {
376 return false;
377 }
378 if (!this->validateFixedFunctions()) {
379 return false;
380 }
381 break;
382 default:
383 return false;
384 }
385
386 int major, minor;
387 const char* ext;
388
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000389 gl_version(this, &major, &minor);
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000390 ext = (const char*)fGetString(GR_GL_EXTENSIONS);
391
392 // Now check that baseline ES/Desktop fns not covered above are present
393 // and that we have fn pointers for any advertised extensions that we will
394 // try to use.
395
396 // these functions are part of ES2, we assume they are available
397 // On the desktop we assume they are available if the extension
398 // is present or GL version is high enough.
399 if ((kES2_GrGLBinding & fBindingsExported)) {
400 if (NULL == fBlendColor ||
401 NULL == fStencilFuncSeparate ||
402 NULL == fStencilMaskSeparate ||
403 NULL == fStencilOpSeparate) {
404 return false;
405 }
406 } else if (kDesktop_GrGLBinding == fBindingsExported) {
407 if (major >= 2) {
408 if (NULL == fStencilFuncSeparate ||
409 NULL == fStencilMaskSeparate ||
410 NULL == fStencilOpSeparate) {
411 return false;
412 }
413 }
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000414 if (major >= 2 ||
415 has_gl_extension_from_string("GL_ARB_draw_buffers", ext)) {
416 if (NULL == fDrawBuffers) {
417 return false;
418 }
419 }
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000420 if (1 < major || (1 == major && 4 <= minor) ||
421 has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
422 if (NULL == fBlendColor) {
423 return false;
424 }
425 }
426 }
427
428 // optional function on desktop before 1.3
429 if (kDesktop_GrGLBinding != fBindingsExported ||
430 (1 < major || (1 == major && 3 <= minor)) ||
431 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
432 if (NULL == fCompressedTexImage2D) {
433 return false;
434 }
435 }
436
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000437 // part of desktop GL, but not ES
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000438 if (kDesktop_GrGLBinding == fBindingsExported &&
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000439 (NULL == fLineWidth ||
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000440 NULL == fGetTexLevelParameteriv ||
bsalomon@google.comc49d66b2011-08-03 14:22:30 +0000441 NULL == fDrawBuffer ||
442 NULL == fReadBuffer)) {
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000443 return false;
444 }
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000445
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000446 // FBO MSAA
447 if (kDesktop_GrGLBinding == fBindingsExported) {
448 // GL 3.0 and the ARB extension have multisample + blit
449 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
450 if (NULL == fRenderbufferStorageMultisample ||
451 NULL == fBlitFramebuffer) {
452 return false;
453 }
454 } else {
455 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
456 NULL == fBlitFramebuffer) {
457 return false;
458 }
459 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
460 NULL == fRenderbufferStorageMultisample) {
461 return false;
462 }
463 }
464 } else {
465 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
466 if (NULL == fRenderbufferStorageMultisample ||
467 NULL == fBlitFramebuffer) {
468 return false;
469 }
470 }
471 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
472 if (NULL == fRenderbufferStorageMultisample ||
473 NULL == fResolveMultisampleFramebuffer) {
474 return false;
475 }
476 }
477 }
478
479 // On ES buffer mapping is an extension. On Desktop
480 // buffer mapping was part of original VBO extension
481 // which we require.
482 if (kDesktop_GrGLBinding == fBindingsExported ||
483 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
484 if (NULL == fMapBuffer ||
485 NULL == fUnmapBuffer) {
486 return false;
487 }
488 }
489
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000490 // Dual source blending
491 if (kDesktop_GrGLBinding == fBindingsExported &&
492 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
493 (3 < major) || (3 == major && 3 <= minor))) {
494 if (NULL == fBindFragDataLocationIndexed) {
495 return false;
496 }
497 }
498
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000499 return true;
500}
501