blob: 9bee8062e8da4e9d16cd124b9785fcc995ae3638 [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) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000106 const char* glstr = reinterpret_cast<const char*>(
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000107 gl->fGetString(GR_GL_EXTENSIONS));
twiz@google.com59a190b2011-03-14 21:23:01 +0000108
109 return has_gl_extension_from_string(ext, glstr);
110}
111
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000112void gl_version(const GrGLInterface* gl, int* major, int* minor) {
twiz@google.com59a190b2011-03-14 21:23:01 +0000113 const char* v = reinterpret_cast<const char*>(
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000114 gl->fGetString(GR_GL_VERSION));
twiz@google.com59a190b2011-03-14 21:23:01 +0000115 gl_version_from_string(major, minor, v);
116}
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000117
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000118float gl_version_as_float(const GrGLInterface* gl) {
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000119 const char* v = reinterpret_cast<const char*>(
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000120 gl->fGetString(GR_GL_VERSION));
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000121 return gl_version_as_float_from_string(v);
122}
123
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000124GrGLInterface::GrGLInterface() {
125 fBindingsExported = (GrGLBinding)0;
126 fNPOTRenderTargetSupport = kProbe_GrGLCapability;
127 fMinRenderTargetHeight = kProbe_GrGLCapability;
128 fMinRenderTargetWidth = kProbe_GrGLCapability;
129
130 fActiveTexture = NULL;
131 fAttachShader = NULL;
132 fBindAttribLocation = NULL;
133 fBindBuffer = NULL;
134 fBindTexture = NULL;
135 fBlendColor = NULL;
136 fBlendFunc = NULL;
137 fBufferData = NULL;
138 fBufferSubData = NULL;
139 fClear = NULL;
140 fClearColor = NULL;
141 fClearStencil = NULL;
142 fClientActiveTexture = NULL;
143 fColor4ub = NULL;
144 fColorMask = NULL;
145 fColorPointer = NULL;
146 fCompileShader = NULL;
147 fCompressedTexImage2D = NULL;
148 fCreateProgram = NULL;
149 fCreateShader = NULL;
150 fCullFace = NULL;
151 fDeleteBuffers = NULL;
152 fDeleteProgram = NULL;
153 fDeleteShader = NULL;
154 fDeleteTextures = NULL;
155 fDepthMask = NULL;
156 fDisable = NULL;
157 fDisableClientState = NULL;
158 fDisableVertexAttribArray = NULL;
159 fDrawArrays = NULL;
160 fDrawBuffer = NULL;
161 fDrawBuffers = NULL;
162 fDrawElements = NULL;
163 fEnable = NULL;
164 fEnableClientState = NULL;
165 fEnableVertexAttribArray = NULL;
166 fFrontFace = NULL;
167 fGenBuffers = NULL;
168 fGenTextures = NULL;
169 fGetBufferParameteriv = NULL;
170 fGetError = NULL;
171 fGetIntegerv = NULL;
172 fGetProgramInfoLog = NULL;
173 fGetProgramiv = NULL;
174 fGetShaderInfoLog = NULL;
175 fGetShaderiv = NULL;
176 fGetString = NULL;
177 fGetTexLevelParameteriv = NULL;
178 fGetUniformLocation = NULL;
179 fLineWidth = NULL;
180 fLinkProgram = NULL;
181 fLoadMatrixf = NULL;
182 fMatrixMode = NULL;
183 fPixelStorei = NULL;
184 fPointSize = NULL;
185 fReadBuffer = NULL;
186 fReadPixels = NULL;
187 fScissor = NULL;
188 fShadeModel = NULL;
189 fShaderSource = NULL;
190 fStencilFunc = NULL;
191 fStencilFuncSeparate = NULL;
192 fStencilMask = NULL;
193 fStencilMaskSeparate = NULL;
194 fStencilOp = NULL;
195 fStencilOpSeparate = NULL;
196 fTexCoordPointer = NULL;
197 fTexEnvi = NULL;
198 fTexImage2D = NULL;
199 fTexParameteri = NULL;
200 fTexSubImage2D = NULL;
201 fUniform1f = NULL;
202 fUniform1i = NULL;
203 fUniform1fv = NULL;
204 fUniform1iv = NULL;
205 fUniform2f = NULL;
206 fUniform2i = NULL;
207 fUniform2fv = NULL;
208 fUniform2iv = NULL;
209 fUniform3f = NULL;
210 fUniform3i = NULL;
211 fUniform3fv = NULL;
212 fUniform3iv = NULL;
213 fUniform4f = NULL;
214 fUniform4i = NULL;
215 fUniform4fv = NULL;
216 fUniform4iv = NULL;
217 fUniformMatrix2fv = NULL;
218 fUniformMatrix3fv = NULL;
219 fUniformMatrix4fv = NULL;
220 fUseProgram = NULL;
221 fVertexAttrib4fv = NULL;
222 fVertexAttribPointer = NULL;
223 fVertexPointer = NULL;
224 fViewport = NULL;
225 fBindFramebuffer = NULL;
226 fBindRenderbuffer = NULL;
227 fCheckFramebufferStatus = NULL;
228 fDeleteFramebuffers = NULL;
229 fDeleteRenderbuffers = NULL;
230 fFramebufferRenderbuffer = NULL;
231 fFramebufferTexture2D = NULL;
232 fGenFramebuffers = NULL;
233 fGenRenderbuffers = NULL;
234 fGetFramebufferAttachmentParameteriv = NULL;
235 fGetRenderbufferParameteriv = NULL;
236 fRenderbufferStorage = NULL;
237 fRenderbufferStorageMultisample = NULL;
238 fBlitFramebuffer = NULL;
239 fResolveMultisampleFramebuffer = NULL;
240 fMapBuffer = NULL;
241 fUnmapBuffer = NULL;
242 fBindFragDataLocationIndexed = NULL;
bsalomon@google.com56bfc5a2011-09-01 13:28:16 +0000243
244#if GR_GL_PER_GL_FUNC_CALLBACK
245 fCallback = GrGLDefaultInterfaceCallback;
246 fCallbackData = 0;
247#endif
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000248}
249
250
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000251bool GrGLInterface::validateShaderFunctions() const {
252 // required for GrGpuGLShaders
253 if (NULL == fAttachShader ||
254 NULL == fBindAttribLocation ||
255 NULL == fCompileShader ||
256 NULL == fCreateProgram ||
257 NULL == fCreateShader ||
258 NULL == fDeleteProgram ||
259 NULL == fDeleteShader ||
260 NULL == fDisableVertexAttribArray ||
261 NULL == fEnableVertexAttribArray ||
262 NULL == fGetProgramInfoLog ||
263 NULL == fGetProgramiv ||
264 NULL == fGetShaderInfoLog ||
265 NULL == fGetShaderiv ||
266 NULL == fGetUniformLocation ||
267 NULL == fLinkProgram ||
268 NULL == fShaderSource ||
269 NULL == fUniform1f ||
270 NULL == fUniform1i ||
271 NULL == fUniform1fv ||
272 NULL == fUniform1iv ||
273 NULL == fUniform2f ||
274 NULL == fUniform2i ||
275 NULL == fUniform2fv ||
276 NULL == fUniform2iv ||
277 NULL == fUniform3f ||
278 NULL == fUniform3i ||
279 NULL == fUniform3fv ||
280 NULL == fUniform3iv ||
281 NULL == fUniform4f ||
282 NULL == fUniform4i ||
283 NULL == fUniform4fv ||
284 NULL == fUniform4iv ||
285 NULL == fUniformMatrix2fv ||
286 NULL == fUniformMatrix3fv ||
287 NULL == fUniformMatrix4fv ||
288 NULL == fUseProgram ||
289 NULL == fVertexAttrib4fv ||
290 NULL == fVertexAttribPointer) {
291 return false;
292 }
293 return true;
294}
295
296bool GrGLInterface::validateFixedFunctions() const {
297 if (NULL == fClientActiveTexture ||
298 NULL == fColor4ub ||
299 NULL == fColorPointer ||
300 NULL == fDisableClientState ||
301 NULL == fEnableClientState ||
302 NULL == fLoadMatrixf ||
303 NULL == fMatrixMode ||
304 NULL == fPointSize ||
305 NULL == fShadeModel ||
306 NULL == fTexCoordPointer ||
bsalomon@google.com4b9b6a22011-05-04 15:01:16 +0000307 NULL == fTexEnvi ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000308 NULL == fVertexPointer) {
309 return false;
310 }
311 return true;
312}
313
314bool GrGLInterface::validate(GrEngine engine) const {
315
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000316 bool isDesktop = this->supportsDesktop();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000317
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000318 bool isES = this->supportsES();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000319
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000320 if (isDesktop == isES) {
321 // must have one, don't support both in same interface
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000322 return false;
323 }
324
325 // functions that are always required
326 if (NULL == fActiveTexture ||
327 NULL == fBindBuffer ||
328 NULL == fBindTexture ||
329 NULL == fBlendFunc ||
330 NULL == fBufferData ||
331 NULL == fBufferSubData ||
332 NULL == fClear ||
333 NULL == fClearColor ||
334 NULL == fClearStencil ||
335 NULL == fColorMask ||
336 NULL == fCullFace ||
337 NULL == fDeleteBuffers ||
338 NULL == fDeleteTextures ||
339 NULL == fDepthMask ||
340 NULL == fDisable ||
341 NULL == fDrawArrays ||
342 NULL == fDrawElements ||
343 NULL == fEnable ||
344 NULL == fFrontFace ||
345 NULL == fGenBuffers ||
346 NULL == fGenTextures ||
347 NULL == fGetBufferParameteriv ||
348 NULL == fGetError ||
349 NULL == fGetIntegerv ||
350 NULL == fGetString ||
351 NULL == fPixelStorei ||
352 NULL == fReadPixels ||
353 NULL == fScissor ||
354 NULL == fStencilFunc ||
355 NULL == fStencilMask ||
356 NULL == fStencilOp ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000357 NULL == fTexImage2D ||
358 NULL == fTexParameteri ||
359 NULL == fTexSubImage2D ||
360 NULL == fViewport ||
361 NULL == fBindFramebuffer ||
362 NULL == fBindRenderbuffer ||
363 NULL == fCheckFramebufferStatus ||
364 NULL == fDeleteFramebuffers ||
365 NULL == fDeleteRenderbuffers ||
366 NULL == fFramebufferRenderbuffer ||
367 NULL == fFramebufferTexture2D ||
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000368 NULL == fGetFramebufferAttachmentParameteriv ||
369 NULL == fGetRenderbufferParameteriv ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000370 NULL == fGenFramebuffers ||
371 NULL == fGenRenderbuffers ||
372 NULL == fRenderbufferStorage) {
373 return false;
374 }
375
376 switch (engine) {
377 case kOpenGL_Shaders_GrEngine:
378 if (kES1_GrGLBinding == fBindingsExported) {
379 return false;
380 }
381 if (!this->validateShaderFunctions()) {
382 return false;
383 }
384 break;
385 case kOpenGL_Fixed_GrEngine:
386 if (kES1_GrGLBinding == fBindingsExported) {
387 return false;
388 }
389 if (!this->validateFixedFunctions()) {
390 return false;
391 }
392 break;
393 default:
394 return false;
395 }
396
397 int major, minor;
398 const char* ext;
399
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000400 gl_version(this, &major, &minor);
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000401 ext = (const char*)fGetString(GR_GL_EXTENSIONS);
402
403 // Now check that baseline ES/Desktop fns not covered above are present
404 // and that we have fn pointers for any advertised extensions that we will
405 // try to use.
406
407 // these functions are part of ES2, we assume they are available
408 // On the desktop we assume they are available if the extension
409 // is present or GL version is high enough.
410 if ((kES2_GrGLBinding & fBindingsExported)) {
411 if (NULL == fBlendColor ||
412 NULL == fStencilFuncSeparate ||
413 NULL == fStencilMaskSeparate ||
414 NULL == fStencilOpSeparate) {
415 return false;
416 }
417 } else if (kDesktop_GrGLBinding == fBindingsExported) {
418 if (major >= 2) {
419 if (NULL == fStencilFuncSeparate ||
420 NULL == fStencilMaskSeparate ||
421 NULL == fStencilOpSeparate) {
422 return false;
423 }
424 }
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000425 if (major >= 2 ||
426 has_gl_extension_from_string("GL_ARB_draw_buffers", ext)) {
427 if (NULL == fDrawBuffers) {
428 return false;
429 }
430 }
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000431 if (1 < major || (1 == major && 4 <= minor) ||
432 has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
433 if (NULL == fBlendColor) {
434 return false;
435 }
436 }
437 }
438
439 // optional function on desktop before 1.3
440 if (kDesktop_GrGLBinding != fBindingsExported ||
441 (1 < major || (1 == major && 3 <= minor)) ||
442 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
443 if (NULL == fCompressedTexImage2D) {
444 return false;
445 }
446 }
447
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000448 // part of desktop GL, but not ES
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000449 if (kDesktop_GrGLBinding == fBindingsExported &&
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000450 (NULL == fLineWidth ||
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000451 NULL == fGetTexLevelParameteriv ||
bsalomon@google.comc49d66b2011-08-03 14:22:30 +0000452 NULL == fDrawBuffer ||
453 NULL == fReadBuffer)) {
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000454 return false;
455 }
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000456
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000457 // FBO MSAA
458 if (kDesktop_GrGLBinding == fBindingsExported) {
459 // GL 3.0 and the ARB extension have multisample + blit
460 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
461 if (NULL == fRenderbufferStorageMultisample ||
462 NULL == fBlitFramebuffer) {
463 return false;
464 }
465 } else {
466 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
467 NULL == fBlitFramebuffer) {
468 return false;
469 }
470 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
471 NULL == fRenderbufferStorageMultisample) {
472 return false;
473 }
474 }
475 } else {
476 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
477 if (NULL == fRenderbufferStorageMultisample ||
478 NULL == fBlitFramebuffer) {
479 return false;
480 }
481 }
482 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
483 if (NULL == fRenderbufferStorageMultisample ||
484 NULL == fResolveMultisampleFramebuffer) {
485 return false;
486 }
487 }
488 }
489
490 // On ES buffer mapping is an extension. On Desktop
491 // buffer mapping was part of original VBO extension
492 // which we require.
493 if (kDesktop_GrGLBinding == fBindingsExported ||
494 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
495 if (NULL == fMapBuffer ||
496 NULL == fUnmapBuffer) {
497 return false;
498 }
499 }
500
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000501 // Dual source blending
502 if (kDesktop_GrGLBinding == fBindingsExported &&
503 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
504 (3 < major) || (3 == major && 3 <= minor))) {
505 if (NULL == fBindFragDataLocationIndexed) {
506 return false;
507 }
508 }
509
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000510 return true;
511}
512