blob: e943d58e5e806386dad3b896bc81a6ba09ada2f4 [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
twiz@google.com59a190b2011-03-14 21:23:01 +000022void gl_version_from_string(int* major, int* minor,
23 const char* versionString) {
24 if (NULL == versionString) {
25 GrAssert(0);
26 *major = 0;
27 *minor = 0;
28 return;
29 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000030
twiz@google.com59a190b2011-03-14 21:23:01 +000031 int n = sscanf(versionString, "%d.%d", major, minor);
twiz@google.com0f31ca72011-03-18 17:38:11 +000032 if (2 == n) {
bsalomon@google.com56bfc5a2011-09-01 13:28:16 +000033 return;
twiz@google.com59a190b2011-03-14 21:23:01 +000034 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000035
twiz@google.com59a190b2011-03-14 21:23:01 +000036 char profile[2];
twiz@google.com0f31ca72011-03-18 17:38:11 +000037 n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
38 major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000039 bool ok = 4 == n;
40 if (!ok) {
twiz@google.com0f31ca72011-03-18 17:38:11 +000041 n = sscanf(versionString, "OpenGL ES %d.%d", major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000042 ok = 2 == n;
43 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000044
twiz@google.com59a190b2011-03-14 21:23:01 +000045 if (!ok) {
46 GrAssert(0);
47 *major = 0;
48 *minor = 0;
49 return;
50 }
twiz@google.com59a190b2011-03-14 21:23:01 +000051}
52
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +000053float gl_version_as_float_from_string(const char* versionString) {
54 int major, minor;
55 gl_version_from_string(&major, &minor, versionString);
56 GrAssert(minor >= 0);
57 // AFAIK there are only single digit minor numbers
58 if (minor < 10) {
59 return major + minor / 10.f;
60 } else if (minor < 100) {
61 return major + minor / 100.f;
62 } else if (minor < 1000) {
63 return major + minor / 1000.f;
64 } else {
65 GrAssert(!"Why so many digits in minor revision number?");
66 char temp[32];
67 sprintf(temp, "%d.%d", major, minor);
68 return (float) atof(temp);
69 }
70}
71
twiz@google.com59a190b2011-03-14 21:23:01 +000072bool has_gl_extension_from_string(const char* ext,
73 const char* extensionString) {
74 int extLength = strlen(ext);
75
76 while (true) {
77 int n = strcspn(extensionString, " ");
78 if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
79 return true;
80 }
81 if (0 == extensionString[n]) {
82 return false;
83 }
84 extensionString += n+1;
85 }
86
87 return false;
88}
89
bsalomon@google.com0b77d682011-08-19 13:28:54 +000090bool has_gl_extension(const GrGLInterface* gl, const char* ext) {
bsalomon@google.comdca4aab2011-09-06 19:05:24 +000091 const GrGLubyte* glstr;
92 GR_GL_CALL_RET(gl, glstr, GetString(GR_GL_EXTENSIONS));
93 return has_gl_extension_from_string(ext, (const char*) glstr);
twiz@google.com59a190b2011-03-14 21:23:01 +000094}
95
bsalomon@google.com0b77d682011-08-19 13:28:54 +000096void gl_version(const GrGLInterface* gl, int* major, int* minor) {
bsalomon@google.comdca4aab2011-09-06 19:05:24 +000097 const GrGLubyte* v;
98 GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION));
99 gl_version_from_string(major, minor, (const char*) v);
twiz@google.com59a190b2011-03-14 21:23:01 +0000100}
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000101
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000102float gl_version_as_float(const GrGLInterface* gl) {
bsalomon@google.comdca4aab2011-09-06 19:05:24 +0000103 const GrGLubyte* v;
104 GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION));
105 return gl_version_as_float_from_string((const char*)v);
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000106}
107
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000108GrGLInterface::GrGLInterface() {
109 fBindingsExported = (GrGLBinding)0;
110 fNPOTRenderTargetSupport = kProbe_GrGLCapability;
111 fMinRenderTargetHeight = kProbe_GrGLCapability;
112 fMinRenderTargetWidth = kProbe_GrGLCapability;
113
114 fActiveTexture = NULL;
115 fAttachShader = NULL;
116 fBindAttribLocation = NULL;
117 fBindBuffer = NULL;
bsalomon@google.combc5cf512011-09-21 16:21:07 +0000118 fBindFragDataLocation = NULL;
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000119 fBindTexture = NULL;
120 fBlendColor = NULL;
121 fBlendFunc = NULL;
122 fBufferData = NULL;
123 fBufferSubData = NULL;
124 fClear = NULL;
125 fClearColor = NULL;
126 fClearStencil = NULL;
127 fClientActiveTexture = NULL;
128 fColor4ub = NULL;
129 fColorMask = NULL;
130 fColorPointer = NULL;
131 fCompileShader = NULL;
132 fCompressedTexImage2D = NULL;
133 fCreateProgram = NULL;
134 fCreateShader = NULL;
135 fCullFace = NULL;
136 fDeleteBuffers = NULL;
137 fDeleteProgram = NULL;
138 fDeleteShader = NULL;
139 fDeleteTextures = NULL;
140 fDepthMask = NULL;
141 fDisable = NULL;
142 fDisableClientState = NULL;
143 fDisableVertexAttribArray = NULL;
144 fDrawArrays = NULL;
145 fDrawBuffer = NULL;
146 fDrawBuffers = NULL;
147 fDrawElements = NULL;
148 fEnable = NULL;
149 fEnableClientState = NULL;
150 fEnableVertexAttribArray = NULL;
151 fFrontFace = NULL;
152 fGenBuffers = NULL;
153 fGenTextures = NULL;
154 fGetBufferParameteriv = NULL;
155 fGetError = NULL;
156 fGetIntegerv = NULL;
157 fGetProgramInfoLog = NULL;
158 fGetProgramiv = NULL;
159 fGetShaderInfoLog = NULL;
160 fGetShaderiv = NULL;
161 fGetString = NULL;
162 fGetTexLevelParameteriv = NULL;
163 fGetUniformLocation = NULL;
164 fLineWidth = NULL;
165 fLinkProgram = NULL;
166 fLoadMatrixf = NULL;
167 fMatrixMode = NULL;
168 fPixelStorei = NULL;
169 fPointSize = NULL;
170 fReadBuffer = NULL;
171 fReadPixels = NULL;
172 fScissor = NULL;
173 fShadeModel = NULL;
174 fShaderSource = NULL;
175 fStencilFunc = NULL;
176 fStencilFuncSeparate = NULL;
177 fStencilMask = NULL;
178 fStencilMaskSeparate = NULL;
179 fStencilOp = NULL;
180 fStencilOpSeparate = NULL;
181 fTexCoordPointer = NULL;
182 fTexEnvi = NULL;
183 fTexImage2D = NULL;
184 fTexParameteri = NULL;
185 fTexSubImage2D = NULL;
186 fUniform1f = NULL;
187 fUniform1i = NULL;
188 fUniform1fv = NULL;
189 fUniform1iv = NULL;
190 fUniform2f = NULL;
191 fUniform2i = NULL;
192 fUniform2fv = NULL;
193 fUniform2iv = NULL;
194 fUniform3f = NULL;
195 fUniform3i = NULL;
196 fUniform3fv = NULL;
197 fUniform3iv = NULL;
198 fUniform4f = NULL;
199 fUniform4i = NULL;
200 fUniform4fv = NULL;
201 fUniform4iv = NULL;
202 fUniformMatrix2fv = NULL;
203 fUniformMatrix3fv = NULL;
204 fUniformMatrix4fv = NULL;
205 fUseProgram = NULL;
206 fVertexAttrib4fv = NULL;
207 fVertexAttribPointer = NULL;
208 fVertexPointer = NULL;
209 fViewport = NULL;
210 fBindFramebuffer = NULL;
211 fBindRenderbuffer = NULL;
212 fCheckFramebufferStatus = NULL;
213 fDeleteFramebuffers = NULL;
214 fDeleteRenderbuffers = NULL;
215 fFramebufferRenderbuffer = NULL;
216 fFramebufferTexture2D = NULL;
217 fGenFramebuffers = NULL;
218 fGenRenderbuffers = NULL;
219 fGetFramebufferAttachmentParameteriv = NULL;
220 fGetRenderbufferParameteriv = NULL;
221 fRenderbufferStorage = NULL;
222 fRenderbufferStorageMultisample = NULL;
223 fBlitFramebuffer = NULL;
224 fResolveMultisampleFramebuffer = NULL;
225 fMapBuffer = NULL;
226 fUnmapBuffer = NULL;
227 fBindFragDataLocationIndexed = NULL;
bsalomon@google.com56bfc5a2011-09-01 13:28:16 +0000228
229#if GR_GL_PER_GL_FUNC_CALLBACK
230 fCallback = GrGLDefaultInterfaceCallback;
231 fCallbackData = 0;
232#endif
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000233}
234
235
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000236bool GrGLInterface::validateShaderFunctions() const {
237 // required for GrGpuGLShaders
238 if (NULL == fAttachShader ||
239 NULL == fBindAttribLocation ||
240 NULL == fCompileShader ||
241 NULL == fCreateProgram ||
242 NULL == fCreateShader ||
243 NULL == fDeleteProgram ||
244 NULL == fDeleteShader ||
245 NULL == fDisableVertexAttribArray ||
246 NULL == fEnableVertexAttribArray ||
247 NULL == fGetProgramInfoLog ||
248 NULL == fGetProgramiv ||
249 NULL == fGetShaderInfoLog ||
250 NULL == fGetShaderiv ||
251 NULL == fGetUniformLocation ||
252 NULL == fLinkProgram ||
253 NULL == fShaderSource ||
254 NULL == fUniform1f ||
255 NULL == fUniform1i ||
256 NULL == fUniform1fv ||
257 NULL == fUniform1iv ||
258 NULL == fUniform2f ||
259 NULL == fUniform2i ||
260 NULL == fUniform2fv ||
261 NULL == fUniform2iv ||
262 NULL == fUniform3f ||
263 NULL == fUniform3i ||
264 NULL == fUniform3fv ||
265 NULL == fUniform3iv ||
266 NULL == fUniform4f ||
267 NULL == fUniform4i ||
268 NULL == fUniform4fv ||
269 NULL == fUniform4iv ||
270 NULL == fUniformMatrix2fv ||
271 NULL == fUniformMatrix3fv ||
272 NULL == fUniformMatrix4fv ||
273 NULL == fUseProgram ||
274 NULL == fVertexAttrib4fv ||
275 NULL == fVertexAttribPointer) {
276 return false;
277 }
278 return true;
279}
280
281bool GrGLInterface::validateFixedFunctions() const {
282 if (NULL == fClientActiveTexture ||
283 NULL == fColor4ub ||
284 NULL == fColorPointer ||
285 NULL == fDisableClientState ||
286 NULL == fEnableClientState ||
287 NULL == fLoadMatrixf ||
288 NULL == fMatrixMode ||
289 NULL == fPointSize ||
290 NULL == fShadeModel ||
291 NULL == fTexCoordPointer ||
bsalomon@google.com4b9b6a22011-05-04 15:01:16 +0000292 NULL == fTexEnvi ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000293 NULL == fVertexPointer) {
294 return false;
295 }
296 return true;
297}
298
299bool GrGLInterface::validate(GrEngine engine) const {
300
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000301 bool isDesktop = this->supportsDesktop();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000302
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000303 bool isES = this->supportsES();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000304
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000305 if (isDesktop == isES) {
306 // must have one, don't support both in same interface
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000307 return false;
308 }
309
310 // functions that are always required
311 if (NULL == fActiveTexture ||
312 NULL == fBindBuffer ||
313 NULL == fBindTexture ||
314 NULL == fBlendFunc ||
315 NULL == fBufferData ||
316 NULL == fBufferSubData ||
317 NULL == fClear ||
318 NULL == fClearColor ||
319 NULL == fClearStencil ||
320 NULL == fColorMask ||
321 NULL == fCullFace ||
322 NULL == fDeleteBuffers ||
323 NULL == fDeleteTextures ||
324 NULL == fDepthMask ||
325 NULL == fDisable ||
326 NULL == fDrawArrays ||
327 NULL == fDrawElements ||
328 NULL == fEnable ||
329 NULL == fFrontFace ||
330 NULL == fGenBuffers ||
331 NULL == fGenTextures ||
332 NULL == fGetBufferParameteriv ||
333 NULL == fGetError ||
334 NULL == fGetIntegerv ||
335 NULL == fGetString ||
336 NULL == fPixelStorei ||
337 NULL == fReadPixels ||
338 NULL == fScissor ||
339 NULL == fStencilFunc ||
340 NULL == fStencilMask ||
341 NULL == fStencilOp ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000342 NULL == fTexImage2D ||
343 NULL == fTexParameteri ||
344 NULL == fTexSubImage2D ||
345 NULL == fViewport ||
346 NULL == fBindFramebuffer ||
347 NULL == fBindRenderbuffer ||
348 NULL == fCheckFramebufferStatus ||
349 NULL == fDeleteFramebuffers ||
350 NULL == fDeleteRenderbuffers ||
351 NULL == fFramebufferRenderbuffer ||
352 NULL == fFramebufferTexture2D ||
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000353 NULL == fGetFramebufferAttachmentParameteriv ||
354 NULL == fGetRenderbufferParameteriv ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000355 NULL == fGenFramebuffers ||
356 NULL == fGenRenderbuffers ||
357 NULL == fRenderbufferStorage) {
358 return false;
359 }
360
361 switch (engine) {
362 case kOpenGL_Shaders_GrEngine:
363 if (kES1_GrGLBinding == fBindingsExported) {
364 return false;
365 }
366 if (!this->validateShaderFunctions()) {
367 return false;
368 }
369 break;
370 case kOpenGL_Fixed_GrEngine:
371 if (kES1_GrGLBinding == fBindingsExported) {
372 return false;
373 }
374 if (!this->validateFixedFunctions()) {
375 return false;
376 }
377 break;
378 default:
379 return false;
380 }
381
382 int major, minor;
383 const char* ext;
384
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000385 gl_version(this, &major, &minor);
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000386 ext = (const char*)fGetString(GR_GL_EXTENSIONS);
387
388 // Now check that baseline ES/Desktop fns not covered above are present
389 // and that we have fn pointers for any advertised extensions that we will
390 // try to use.
391
392 // these functions are part of ES2, we assume they are available
393 // On the desktop we assume they are available if the extension
394 // is present or GL version is high enough.
395 if ((kES2_GrGLBinding & fBindingsExported)) {
396 if (NULL == fBlendColor ||
397 NULL == fStencilFuncSeparate ||
398 NULL == fStencilMaskSeparate ||
399 NULL == fStencilOpSeparate) {
400 return false;
401 }
402 } else if (kDesktop_GrGLBinding == fBindingsExported) {
403 if (major >= 2) {
404 if (NULL == fStencilFuncSeparate ||
405 NULL == fStencilMaskSeparate ||
406 NULL == fStencilOpSeparate) {
407 return false;
408 }
409 }
bsalomon@google.combc5cf512011-09-21 16:21:07 +0000410 if (major >= 3 && NULL == fBindFragDataLocation) {
411 return false;
412 }
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000413 if (major >= 2 ||
414 has_gl_extension_from_string("GL_ARB_draw_buffers", ext)) {
415 if (NULL == fDrawBuffers) {
416 return false;
417 }
418 }
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000419 if (1 < major || (1 == major && 4 <= minor) ||
420 has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
421 if (NULL == fBlendColor) {
422 return false;
423 }
424 }
425 }
426
427 // optional function on desktop before 1.3
428 if (kDesktop_GrGLBinding != fBindingsExported ||
429 (1 < major || (1 == major && 3 <= minor)) ||
430 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
431 if (NULL == fCompressedTexImage2D) {
432 return false;
433 }
434 }
435
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000436 // part of desktop GL, but not ES
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000437 if (kDesktop_GrGLBinding == fBindingsExported &&
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000438 (NULL == fLineWidth ||
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000439 NULL == fGetTexLevelParameteriv ||
bsalomon@google.comc49d66b2011-08-03 14:22:30 +0000440 NULL == fDrawBuffer ||
441 NULL == fReadBuffer)) {
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000442 return false;
443 }
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000444
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000445 // FBO MSAA
446 if (kDesktop_GrGLBinding == fBindingsExported) {
447 // GL 3.0 and the ARB extension have multisample + blit
448 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
449 if (NULL == fRenderbufferStorageMultisample ||
450 NULL == fBlitFramebuffer) {
451 return false;
452 }
453 } else {
454 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
455 NULL == fBlitFramebuffer) {
456 return false;
457 }
458 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
459 NULL == fRenderbufferStorageMultisample) {
460 return false;
461 }
462 }
463 } else {
464 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
465 if (NULL == fRenderbufferStorageMultisample ||
466 NULL == fBlitFramebuffer) {
467 return false;
468 }
469 }
470 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
471 if (NULL == fRenderbufferStorageMultisample ||
472 NULL == fResolveMultisampleFramebuffer) {
473 return false;
474 }
475 }
476 }
477
478 // On ES buffer mapping is an extension. On Desktop
479 // buffer mapping was part of original VBO extension
480 // which we require.
481 if (kDesktop_GrGLBinding == fBindingsExported ||
482 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
483 if (NULL == fMapBuffer ||
484 NULL == fUnmapBuffer) {
485 return false;
486 }
487 }
488
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000489 // Dual source blending
490 if (kDesktop_GrGLBinding == fBindingsExported &&
491 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
492 (3 < major) || (3 == major && 3 <= minor))) {
493 if (NULL == fBindFragDataLocationIndexed) {
494 return false;
495 }
496 }
497
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000498 return true;
499}
500