blob: 38770f124dc514f27ce663e09d8f917b3c33ed32 [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.com56bfc5a2011-09-01 13:28:16 +000016#if GR_GL_PER_GL_FUNC_CALLBACK
17namespace {
18void GrGLDefaultInterfaceCallback(const GrGLInterface*) {}
19}
20#endif
21
bsalomon@google.com0b77d682011-08-19 13:28:54 +000022static SkAutoTUnref<const GrGLInterface> gDefaultGLInterface;
twiz@google.com59a190b2011-03-14 21:23:01 +000023
24void gl_version_from_string(int* major, int* minor,
25 const char* versionString) {
26 if (NULL == versionString) {
27 GrAssert(0);
28 *major = 0;
29 *minor = 0;
30 return;
31 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000032
twiz@google.com59a190b2011-03-14 21:23:01 +000033 int n = sscanf(versionString, "%d.%d", major, minor);
twiz@google.com0f31ca72011-03-18 17:38:11 +000034 if (2 == n) {
bsalomon@google.com56bfc5a2011-09-01 13:28:16 +000035 return;
twiz@google.com59a190b2011-03-14 21:23:01 +000036 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000037
twiz@google.com59a190b2011-03-14 21:23:01 +000038 char profile[2];
twiz@google.com0f31ca72011-03-18 17:38:11 +000039 n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
40 major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000041 bool ok = 4 == n;
42 if (!ok) {
twiz@google.com0f31ca72011-03-18 17:38:11 +000043 n = sscanf(versionString, "OpenGL ES %d.%d", major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000044 ok = 2 == n;
45 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000046
twiz@google.com59a190b2011-03-14 21:23:01 +000047 if (!ok) {
48 GrAssert(0);
49 *major = 0;
50 *minor = 0;
51 return;
52 }
twiz@google.com59a190b2011-03-14 21:23:01 +000053}
54
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +000055float gl_version_as_float_from_string(const char* versionString) {
56 int major, minor;
57 gl_version_from_string(&major, &minor, versionString);
58 GrAssert(minor >= 0);
59 // AFAIK there are only single digit minor numbers
60 if (minor < 10) {
61 return major + minor / 10.f;
62 } else if (minor < 100) {
63 return major + minor / 100.f;
64 } else if (minor < 1000) {
65 return major + minor / 1000.f;
66 } else {
67 GrAssert(!"Why so many digits in minor revision number?");
68 char temp[32];
69 sprintf(temp, "%d.%d", major, minor);
70 return (float) atof(temp);
71 }
72}
73
twiz@google.com59a190b2011-03-14 21:23:01 +000074bool has_gl_extension_from_string(const char* ext,
75 const char* extensionString) {
76 int extLength = strlen(ext);
77
78 while (true) {
79 int n = strcspn(extensionString, " ");
80 if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
81 return true;
82 }
83 if (0 == extensionString[n]) {
84 return false;
85 }
86 extensionString += n+1;
87 }
88
89 return false;
90}
91
bsalomon@google.com0b77d682011-08-19 13:28:54 +000092GR_API const GrGLInterface* GrGLSetDefaultGLInterface(const GrGLInterface* gl_interface) {
93 gl_interface->ref();
94 gDefaultGLInterface.reset(gl_interface);
95 return gl_interface;
twiz@google.com59a190b2011-03-14 21:23:01 +000096}
97
bsalomon@google.com0b77d682011-08-19 13:28:54 +000098GR_API const GrGLInterface* GrGLGetDefaultGLInterface() {
99 if (NULL == gDefaultGLInterface.get()) {
100 GrGLInitializeDefaultGLInterface();
101 }
102 return gDefaultGLInterface.get();
twiz@google.com59a190b2011-03-14 21:23:01 +0000103}
104
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000105bool has_gl_extension(const GrGLInterface* gl, const char* ext) {
bsalomon@google.comdca4aab2011-09-06 19:05:24 +0000106 const GrGLubyte* glstr;
107 GR_GL_CALL_RET(gl, glstr, GetString(GR_GL_EXTENSIONS));
108 return has_gl_extension_from_string(ext, (const char*) glstr);
twiz@google.com59a190b2011-03-14 21:23:01 +0000109}
110
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000111void gl_version(const GrGLInterface* gl, int* major, int* minor) {
bsalomon@google.comdca4aab2011-09-06 19:05:24 +0000112 const GrGLubyte* v;
113 GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION));
114 gl_version_from_string(major, minor, (const char*) v);
twiz@google.com59a190b2011-03-14 21:23:01 +0000115}
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000116
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000117float gl_version_as_float(const GrGLInterface* gl) {
bsalomon@google.comdca4aab2011-09-06 19:05:24 +0000118 const GrGLubyte* v;
119 GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION));
120 return gl_version_as_float_from_string((const char*)v);
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000121}
122
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000123GrGLInterface::GrGLInterface() {
124 fBindingsExported = (GrGLBinding)0;
125 fNPOTRenderTargetSupport = kProbe_GrGLCapability;
126 fMinRenderTargetHeight = kProbe_GrGLCapability;
127 fMinRenderTargetWidth = kProbe_GrGLCapability;
128
129 fActiveTexture = NULL;
130 fAttachShader = NULL;
131 fBindAttribLocation = NULL;
132 fBindBuffer = NULL;
133 fBindTexture = NULL;
134 fBlendColor = NULL;
135 fBlendFunc = NULL;
136 fBufferData = NULL;
137 fBufferSubData = NULL;
138 fClear = NULL;
139 fClearColor = NULL;
140 fClearStencil = NULL;
141 fClientActiveTexture = NULL;
142 fColor4ub = NULL;
143 fColorMask = NULL;
144 fColorPointer = NULL;
145 fCompileShader = NULL;
146 fCompressedTexImage2D = NULL;
147 fCreateProgram = NULL;
148 fCreateShader = NULL;
149 fCullFace = NULL;
150 fDeleteBuffers = NULL;
151 fDeleteProgram = NULL;
152 fDeleteShader = NULL;
153 fDeleteTextures = NULL;
154 fDepthMask = NULL;
155 fDisable = NULL;
156 fDisableClientState = NULL;
157 fDisableVertexAttribArray = NULL;
158 fDrawArrays = NULL;
159 fDrawBuffer = NULL;
160 fDrawBuffers = NULL;
161 fDrawElements = NULL;
162 fEnable = NULL;
163 fEnableClientState = NULL;
164 fEnableVertexAttribArray = NULL;
165 fFrontFace = NULL;
166 fGenBuffers = NULL;
167 fGenTextures = NULL;
168 fGetBufferParameteriv = NULL;
169 fGetError = NULL;
170 fGetIntegerv = NULL;
171 fGetProgramInfoLog = NULL;
172 fGetProgramiv = NULL;
173 fGetShaderInfoLog = NULL;
174 fGetShaderiv = NULL;
175 fGetString = NULL;
176 fGetTexLevelParameteriv = NULL;
177 fGetUniformLocation = NULL;
178 fLineWidth = NULL;
179 fLinkProgram = NULL;
180 fLoadMatrixf = NULL;
181 fMatrixMode = NULL;
182 fPixelStorei = NULL;
183 fPointSize = NULL;
184 fReadBuffer = NULL;
185 fReadPixels = NULL;
186 fScissor = NULL;
187 fShadeModel = NULL;
188 fShaderSource = NULL;
189 fStencilFunc = NULL;
190 fStencilFuncSeparate = NULL;
191 fStencilMask = NULL;
192 fStencilMaskSeparate = NULL;
193 fStencilOp = NULL;
194 fStencilOpSeparate = NULL;
195 fTexCoordPointer = NULL;
196 fTexEnvi = NULL;
197 fTexImage2D = NULL;
198 fTexParameteri = NULL;
199 fTexSubImage2D = NULL;
200 fUniform1f = NULL;
201 fUniform1i = NULL;
202 fUniform1fv = NULL;
203 fUniform1iv = NULL;
204 fUniform2f = NULL;
205 fUniform2i = NULL;
206 fUniform2fv = NULL;
207 fUniform2iv = NULL;
208 fUniform3f = NULL;
209 fUniform3i = NULL;
210 fUniform3fv = NULL;
211 fUniform3iv = NULL;
212 fUniform4f = NULL;
213 fUniform4i = NULL;
214 fUniform4fv = NULL;
215 fUniform4iv = NULL;
216 fUniformMatrix2fv = NULL;
217 fUniformMatrix3fv = NULL;
218 fUniformMatrix4fv = NULL;
219 fUseProgram = NULL;
220 fVertexAttrib4fv = NULL;
221 fVertexAttribPointer = NULL;
222 fVertexPointer = NULL;
223 fViewport = NULL;
224 fBindFramebuffer = NULL;
225 fBindRenderbuffer = NULL;
226 fCheckFramebufferStatus = NULL;
227 fDeleteFramebuffers = NULL;
228 fDeleteRenderbuffers = NULL;
229 fFramebufferRenderbuffer = NULL;
230 fFramebufferTexture2D = NULL;
231 fGenFramebuffers = NULL;
232 fGenRenderbuffers = NULL;
233 fGetFramebufferAttachmentParameteriv = NULL;
234 fGetRenderbufferParameteriv = NULL;
235 fRenderbufferStorage = NULL;
236 fRenderbufferStorageMultisample = NULL;
237 fBlitFramebuffer = NULL;
238 fResolveMultisampleFramebuffer = NULL;
239 fMapBuffer = NULL;
240 fUnmapBuffer = NULL;
241 fBindFragDataLocationIndexed = NULL;
bsalomon@google.com56bfc5a2011-09-01 13:28:16 +0000242
243#if GR_GL_PER_GL_FUNC_CALLBACK
244 fCallback = GrGLDefaultInterfaceCallback;
245 fCallbackData = 0;
246#endif
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000247}
248
249
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000250bool GrGLInterface::validateShaderFunctions() const {
251 // required for GrGpuGLShaders
252 if (NULL == fAttachShader ||
253 NULL == fBindAttribLocation ||
254 NULL == fCompileShader ||
255 NULL == fCreateProgram ||
256 NULL == fCreateShader ||
257 NULL == fDeleteProgram ||
258 NULL == fDeleteShader ||
259 NULL == fDisableVertexAttribArray ||
260 NULL == fEnableVertexAttribArray ||
261 NULL == fGetProgramInfoLog ||
262 NULL == fGetProgramiv ||
263 NULL == fGetShaderInfoLog ||
264 NULL == fGetShaderiv ||
265 NULL == fGetUniformLocation ||
266 NULL == fLinkProgram ||
267 NULL == fShaderSource ||
268 NULL == fUniform1f ||
269 NULL == fUniform1i ||
270 NULL == fUniform1fv ||
271 NULL == fUniform1iv ||
272 NULL == fUniform2f ||
273 NULL == fUniform2i ||
274 NULL == fUniform2fv ||
275 NULL == fUniform2iv ||
276 NULL == fUniform3f ||
277 NULL == fUniform3i ||
278 NULL == fUniform3fv ||
279 NULL == fUniform3iv ||
280 NULL == fUniform4f ||
281 NULL == fUniform4i ||
282 NULL == fUniform4fv ||
283 NULL == fUniform4iv ||
284 NULL == fUniformMatrix2fv ||
285 NULL == fUniformMatrix3fv ||
286 NULL == fUniformMatrix4fv ||
287 NULL == fUseProgram ||
288 NULL == fVertexAttrib4fv ||
289 NULL == fVertexAttribPointer) {
290 return false;
291 }
292 return true;
293}
294
295bool GrGLInterface::validateFixedFunctions() const {
296 if (NULL == fClientActiveTexture ||
297 NULL == fColor4ub ||
298 NULL == fColorPointer ||
299 NULL == fDisableClientState ||
300 NULL == fEnableClientState ||
301 NULL == fLoadMatrixf ||
302 NULL == fMatrixMode ||
303 NULL == fPointSize ||
304 NULL == fShadeModel ||
305 NULL == fTexCoordPointer ||
bsalomon@google.com4b9b6a22011-05-04 15:01:16 +0000306 NULL == fTexEnvi ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000307 NULL == fVertexPointer) {
308 return false;
309 }
310 return true;
311}
312
313bool GrGLInterface::validate(GrEngine engine) const {
314
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000315 bool isDesktop = this->supportsDesktop();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000316
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000317 bool isES = this->supportsES();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000318
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000319 if (isDesktop == isES) {
320 // must have one, don't support both in same interface
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000321 return false;
322 }
323
324 // functions that are always required
325 if (NULL == fActiveTexture ||
326 NULL == fBindBuffer ||
327 NULL == fBindTexture ||
328 NULL == fBlendFunc ||
329 NULL == fBufferData ||
330 NULL == fBufferSubData ||
331 NULL == fClear ||
332 NULL == fClearColor ||
333 NULL == fClearStencil ||
334 NULL == fColorMask ||
335 NULL == fCullFace ||
336 NULL == fDeleteBuffers ||
337 NULL == fDeleteTextures ||
338 NULL == fDepthMask ||
339 NULL == fDisable ||
340 NULL == fDrawArrays ||
341 NULL == fDrawElements ||
342 NULL == fEnable ||
343 NULL == fFrontFace ||
344 NULL == fGenBuffers ||
345 NULL == fGenTextures ||
346 NULL == fGetBufferParameteriv ||
347 NULL == fGetError ||
348 NULL == fGetIntegerv ||
349 NULL == fGetString ||
350 NULL == fPixelStorei ||
351 NULL == fReadPixels ||
352 NULL == fScissor ||
353 NULL == fStencilFunc ||
354 NULL == fStencilMask ||
355 NULL == fStencilOp ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000356 NULL == fTexImage2D ||
357 NULL == fTexParameteri ||
358 NULL == fTexSubImage2D ||
359 NULL == fViewport ||
360 NULL == fBindFramebuffer ||
361 NULL == fBindRenderbuffer ||
362 NULL == fCheckFramebufferStatus ||
363 NULL == fDeleteFramebuffers ||
364 NULL == fDeleteRenderbuffers ||
365 NULL == fFramebufferRenderbuffer ||
366 NULL == fFramebufferTexture2D ||
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000367 NULL == fGetFramebufferAttachmentParameteriv ||
368 NULL == fGetRenderbufferParameteriv ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000369 NULL == fGenFramebuffers ||
370 NULL == fGenRenderbuffers ||
371 NULL == fRenderbufferStorage) {
372 return false;
373 }
374
375 switch (engine) {
376 case kOpenGL_Shaders_GrEngine:
377 if (kES1_GrGLBinding == fBindingsExported) {
378 return false;
379 }
380 if (!this->validateShaderFunctions()) {
381 return false;
382 }
383 break;
384 case kOpenGL_Fixed_GrEngine:
385 if (kES1_GrGLBinding == fBindingsExported) {
386 return false;
387 }
388 if (!this->validateFixedFunctions()) {
389 return false;
390 }
391 break;
392 default:
393 return false;
394 }
395
396 int major, minor;
397 const char* ext;
398
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000399 gl_version(this, &major, &minor);
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000400 ext = (const char*)fGetString(GR_GL_EXTENSIONS);
401
402 // Now check that baseline ES/Desktop fns not covered above are present
403 // and that we have fn pointers for any advertised extensions that we will
404 // try to use.
405
406 // these functions are part of ES2, we assume they are available
407 // On the desktop we assume they are available if the extension
408 // is present or GL version is high enough.
409 if ((kES2_GrGLBinding & fBindingsExported)) {
410 if (NULL == fBlendColor ||
411 NULL == fStencilFuncSeparate ||
412 NULL == fStencilMaskSeparate ||
413 NULL == fStencilOpSeparate) {
414 return false;
415 }
416 } else if (kDesktop_GrGLBinding == fBindingsExported) {
417 if (major >= 2) {
418 if (NULL == fStencilFuncSeparate ||
419 NULL == fStencilMaskSeparate ||
420 NULL == fStencilOpSeparate) {
421 return false;
422 }
423 }
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000424 if (major >= 2 ||
425 has_gl_extension_from_string("GL_ARB_draw_buffers", ext)) {
426 if (NULL == fDrawBuffers) {
427 return false;
428 }
429 }
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000430 if (1 < major || (1 == major && 4 <= minor) ||
431 has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
432 if (NULL == fBlendColor) {
433 return false;
434 }
435 }
436 }
437
438 // optional function on desktop before 1.3
439 if (kDesktop_GrGLBinding != fBindingsExported ||
440 (1 < major || (1 == major && 3 <= minor)) ||
441 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
442 if (NULL == fCompressedTexImage2D) {
443 return false;
444 }
445 }
446
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000447 // part of desktop GL, but not ES
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000448 if (kDesktop_GrGLBinding == fBindingsExported &&
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000449 (NULL == fLineWidth ||
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000450 NULL == fGetTexLevelParameteriv ||
bsalomon@google.comc49d66b2011-08-03 14:22:30 +0000451 NULL == fDrawBuffer ||
452 NULL == fReadBuffer)) {
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000453 return false;
454 }
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000455
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000456 // FBO MSAA
457 if (kDesktop_GrGLBinding == fBindingsExported) {
458 // GL 3.0 and the ARB extension have multisample + blit
459 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
460 if (NULL == fRenderbufferStorageMultisample ||
461 NULL == fBlitFramebuffer) {
462 return false;
463 }
464 } else {
465 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
466 NULL == fBlitFramebuffer) {
467 return false;
468 }
469 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
470 NULL == fRenderbufferStorageMultisample) {
471 return false;
472 }
473 }
474 } else {
475 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
476 if (NULL == fRenderbufferStorageMultisample ||
477 NULL == fBlitFramebuffer) {
478 return false;
479 }
480 }
481 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
482 if (NULL == fRenderbufferStorageMultisample ||
483 NULL == fResolveMultisampleFramebuffer) {
484 return false;
485 }
486 }
487 }
488
489 // On ES buffer mapping is an extension. On Desktop
490 // buffer mapping was part of original VBO extension
491 // which we require.
492 if (kDesktop_GrGLBinding == fBindingsExported ||
493 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
494 if (NULL == fMapBuffer ||
495 NULL == fUnmapBuffer) {
496 return false;
497 }
498 }
499
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000500 // Dual source blending
501 if (kDesktop_GrGLBinding == fBindingsExported &&
502 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
503 (3 < major) || (3 == major && 3 <= minor))) {
504 if (NULL == fBindFragDataLocationIndexed) {
505 return false;
506 }
507 }
508
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000509 return true;
510}
511