blob: 4bbcfa55c0f3058859a659e21a29c5532b563500 [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;
118 fBindTexture = NULL;
119 fBlendColor = NULL;
120 fBlendFunc = NULL;
121 fBufferData = NULL;
122 fBufferSubData = NULL;
123 fClear = NULL;
124 fClearColor = NULL;
125 fClearStencil = NULL;
126 fClientActiveTexture = NULL;
127 fColor4ub = NULL;
128 fColorMask = NULL;
129 fColorPointer = NULL;
130 fCompileShader = NULL;
131 fCompressedTexImage2D = NULL;
132 fCreateProgram = NULL;
133 fCreateShader = NULL;
134 fCullFace = NULL;
135 fDeleteBuffers = NULL;
136 fDeleteProgram = NULL;
137 fDeleteShader = NULL;
138 fDeleteTextures = NULL;
139 fDepthMask = NULL;
140 fDisable = NULL;
141 fDisableClientState = NULL;
142 fDisableVertexAttribArray = NULL;
143 fDrawArrays = NULL;
144 fDrawBuffer = NULL;
145 fDrawBuffers = NULL;
146 fDrawElements = NULL;
147 fEnable = NULL;
148 fEnableClientState = NULL;
149 fEnableVertexAttribArray = NULL;
150 fFrontFace = NULL;
151 fGenBuffers = NULL;
152 fGenTextures = NULL;
153 fGetBufferParameteriv = NULL;
154 fGetError = NULL;
155 fGetIntegerv = NULL;
156 fGetProgramInfoLog = NULL;
157 fGetProgramiv = NULL;
158 fGetShaderInfoLog = NULL;
159 fGetShaderiv = NULL;
160 fGetString = NULL;
161 fGetTexLevelParameteriv = NULL;
162 fGetUniformLocation = NULL;
163 fLineWidth = NULL;
164 fLinkProgram = NULL;
165 fLoadMatrixf = NULL;
166 fMatrixMode = NULL;
167 fPixelStorei = NULL;
168 fPointSize = NULL;
169 fReadBuffer = NULL;
170 fReadPixels = NULL;
171 fScissor = NULL;
172 fShadeModel = NULL;
173 fShaderSource = NULL;
174 fStencilFunc = NULL;
175 fStencilFuncSeparate = NULL;
176 fStencilMask = NULL;
177 fStencilMaskSeparate = NULL;
178 fStencilOp = NULL;
179 fStencilOpSeparate = NULL;
180 fTexCoordPointer = NULL;
181 fTexEnvi = NULL;
182 fTexImage2D = NULL;
183 fTexParameteri = NULL;
184 fTexSubImage2D = NULL;
185 fUniform1f = NULL;
186 fUniform1i = NULL;
187 fUniform1fv = NULL;
188 fUniform1iv = NULL;
189 fUniform2f = NULL;
190 fUniform2i = NULL;
191 fUniform2fv = NULL;
192 fUniform2iv = NULL;
193 fUniform3f = NULL;
194 fUniform3i = NULL;
195 fUniform3fv = NULL;
196 fUniform3iv = NULL;
197 fUniform4f = NULL;
198 fUniform4i = NULL;
199 fUniform4fv = NULL;
200 fUniform4iv = NULL;
201 fUniformMatrix2fv = NULL;
202 fUniformMatrix3fv = NULL;
203 fUniformMatrix4fv = NULL;
204 fUseProgram = NULL;
205 fVertexAttrib4fv = NULL;
206 fVertexAttribPointer = NULL;
207 fVertexPointer = NULL;
208 fViewport = NULL;
209 fBindFramebuffer = NULL;
210 fBindRenderbuffer = NULL;
211 fCheckFramebufferStatus = NULL;
212 fDeleteFramebuffers = NULL;
213 fDeleteRenderbuffers = NULL;
214 fFramebufferRenderbuffer = NULL;
215 fFramebufferTexture2D = NULL;
216 fGenFramebuffers = NULL;
217 fGenRenderbuffers = NULL;
218 fGetFramebufferAttachmentParameteriv = NULL;
219 fGetRenderbufferParameteriv = NULL;
220 fRenderbufferStorage = NULL;
221 fRenderbufferStorageMultisample = NULL;
222 fBlitFramebuffer = NULL;
223 fResolveMultisampleFramebuffer = NULL;
224 fMapBuffer = NULL;
225 fUnmapBuffer = NULL;
226 fBindFragDataLocationIndexed = NULL;
bsalomon@google.com56bfc5a2011-09-01 13:28:16 +0000227
228#if GR_GL_PER_GL_FUNC_CALLBACK
229 fCallback = GrGLDefaultInterfaceCallback;
230 fCallbackData = 0;
231#endif
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000232}
233
234
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000235bool GrGLInterface::validateShaderFunctions() const {
236 // required for GrGpuGLShaders
237 if (NULL == fAttachShader ||
238 NULL == fBindAttribLocation ||
239 NULL == fCompileShader ||
240 NULL == fCreateProgram ||
241 NULL == fCreateShader ||
242 NULL == fDeleteProgram ||
243 NULL == fDeleteShader ||
244 NULL == fDisableVertexAttribArray ||
245 NULL == fEnableVertexAttribArray ||
246 NULL == fGetProgramInfoLog ||
247 NULL == fGetProgramiv ||
248 NULL == fGetShaderInfoLog ||
249 NULL == fGetShaderiv ||
250 NULL == fGetUniformLocation ||
251 NULL == fLinkProgram ||
252 NULL == fShaderSource ||
253 NULL == fUniform1f ||
254 NULL == fUniform1i ||
255 NULL == fUniform1fv ||
256 NULL == fUniform1iv ||
257 NULL == fUniform2f ||
258 NULL == fUniform2i ||
259 NULL == fUniform2fv ||
260 NULL == fUniform2iv ||
261 NULL == fUniform3f ||
262 NULL == fUniform3i ||
263 NULL == fUniform3fv ||
264 NULL == fUniform3iv ||
265 NULL == fUniform4f ||
266 NULL == fUniform4i ||
267 NULL == fUniform4fv ||
268 NULL == fUniform4iv ||
269 NULL == fUniformMatrix2fv ||
270 NULL == fUniformMatrix3fv ||
271 NULL == fUniformMatrix4fv ||
272 NULL == fUseProgram ||
273 NULL == fVertexAttrib4fv ||
274 NULL == fVertexAttribPointer) {
275 return false;
276 }
277 return true;
278}
279
280bool GrGLInterface::validateFixedFunctions() const {
281 if (NULL == fClientActiveTexture ||
282 NULL == fColor4ub ||
283 NULL == fColorPointer ||
284 NULL == fDisableClientState ||
285 NULL == fEnableClientState ||
286 NULL == fLoadMatrixf ||
287 NULL == fMatrixMode ||
288 NULL == fPointSize ||
289 NULL == fShadeModel ||
290 NULL == fTexCoordPointer ||
bsalomon@google.com4b9b6a22011-05-04 15:01:16 +0000291 NULL == fTexEnvi ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000292 NULL == fVertexPointer) {
293 return false;
294 }
295 return true;
296}
297
298bool GrGLInterface::validate(GrEngine engine) const {
299
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000300 bool isDesktop = this->supportsDesktop();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000301
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000302 bool isES = this->supportsES();
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000303
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000304 if (isDesktop == isES) {
305 // must have one, don't support both in same interface
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000306 return false;
307 }
308
309 // functions that are always required
310 if (NULL == fActiveTexture ||
311 NULL == fBindBuffer ||
312 NULL == fBindTexture ||
313 NULL == fBlendFunc ||
314 NULL == fBufferData ||
315 NULL == fBufferSubData ||
316 NULL == fClear ||
317 NULL == fClearColor ||
318 NULL == fClearStencil ||
319 NULL == fColorMask ||
320 NULL == fCullFace ||
321 NULL == fDeleteBuffers ||
322 NULL == fDeleteTextures ||
323 NULL == fDepthMask ||
324 NULL == fDisable ||
325 NULL == fDrawArrays ||
326 NULL == fDrawElements ||
327 NULL == fEnable ||
328 NULL == fFrontFace ||
329 NULL == fGenBuffers ||
330 NULL == fGenTextures ||
331 NULL == fGetBufferParameteriv ||
332 NULL == fGetError ||
333 NULL == fGetIntegerv ||
334 NULL == fGetString ||
335 NULL == fPixelStorei ||
336 NULL == fReadPixels ||
337 NULL == fScissor ||
338 NULL == fStencilFunc ||
339 NULL == fStencilMask ||
340 NULL == fStencilOp ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000341 NULL == fTexImage2D ||
342 NULL == fTexParameteri ||
343 NULL == fTexSubImage2D ||
344 NULL == fViewport ||
345 NULL == fBindFramebuffer ||
346 NULL == fBindRenderbuffer ||
347 NULL == fCheckFramebufferStatus ||
348 NULL == fDeleteFramebuffers ||
349 NULL == fDeleteRenderbuffers ||
350 NULL == fFramebufferRenderbuffer ||
351 NULL == fFramebufferTexture2D ||
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000352 NULL == fGetFramebufferAttachmentParameteriv ||
353 NULL == fGetRenderbufferParameteriv ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000354 NULL == fGenFramebuffers ||
355 NULL == fGenRenderbuffers ||
356 NULL == fRenderbufferStorage) {
357 return false;
358 }
359
360 switch (engine) {
361 case kOpenGL_Shaders_GrEngine:
362 if (kES1_GrGLBinding == fBindingsExported) {
363 return false;
364 }
365 if (!this->validateShaderFunctions()) {
366 return false;
367 }
368 break;
369 case kOpenGL_Fixed_GrEngine:
370 if (kES1_GrGLBinding == fBindingsExported) {
371 return false;
372 }
373 if (!this->validateFixedFunctions()) {
374 return false;
375 }
376 break;
377 default:
378 return false;
379 }
380
381 int major, minor;
382 const char* ext;
383
bsalomon@google.com0b77d682011-08-19 13:28:54 +0000384 gl_version(this, &major, &minor);
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000385 ext = (const char*)fGetString(GR_GL_EXTENSIONS);
386
387 // Now check that baseline ES/Desktop fns not covered above are present
388 // and that we have fn pointers for any advertised extensions that we will
389 // try to use.
390
391 // these functions are part of ES2, we assume they are available
392 // On the desktop we assume they are available if the extension
393 // is present or GL version is high enough.
394 if ((kES2_GrGLBinding & fBindingsExported)) {
395 if (NULL == fBlendColor ||
396 NULL == fStencilFuncSeparate ||
397 NULL == fStencilMaskSeparate ||
398 NULL == fStencilOpSeparate) {
399 return false;
400 }
401 } else if (kDesktop_GrGLBinding == fBindingsExported) {
402 if (major >= 2) {
403 if (NULL == fStencilFuncSeparate ||
404 NULL == fStencilMaskSeparate ||
405 NULL == fStencilOpSeparate) {
406 return false;
407 }
408 }
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000409 if (major >= 2 ||
410 has_gl_extension_from_string("GL_ARB_draw_buffers", ext)) {
411 if (NULL == fDrawBuffers) {
412 return false;
413 }
414 }
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000415 if (1 < major || (1 == major && 4 <= minor) ||
416 has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
417 if (NULL == fBlendColor) {
418 return false;
419 }
420 }
421 }
422
423 // optional function on desktop before 1.3
424 if (kDesktop_GrGLBinding != fBindingsExported ||
425 (1 < major || (1 == major && 3 <= minor)) ||
426 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
427 if (NULL == fCompressedTexImage2D) {
428 return false;
429 }
430 }
431
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000432 // part of desktop GL, but not ES
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000433 if (kDesktop_GrGLBinding == fBindingsExported &&
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000434 (NULL == fLineWidth ||
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000435 NULL == fGetTexLevelParameteriv ||
bsalomon@google.comc49d66b2011-08-03 14:22:30 +0000436 NULL == fDrawBuffer ||
437 NULL == fReadBuffer)) {
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000438 return false;
439 }
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000440
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000441 // FBO MSAA
442 if (kDesktop_GrGLBinding == fBindingsExported) {
443 // GL 3.0 and the ARB extension have multisample + blit
444 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
445 if (NULL == fRenderbufferStorageMultisample ||
446 NULL == fBlitFramebuffer) {
447 return false;
448 }
449 } else {
450 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
451 NULL == fBlitFramebuffer) {
452 return false;
453 }
454 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
455 NULL == fRenderbufferStorageMultisample) {
456 return false;
457 }
458 }
459 } else {
460 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
461 if (NULL == fRenderbufferStorageMultisample ||
462 NULL == fBlitFramebuffer) {
463 return false;
464 }
465 }
466 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
467 if (NULL == fRenderbufferStorageMultisample ||
468 NULL == fResolveMultisampleFramebuffer) {
469 return false;
470 }
471 }
472 }
473
474 // On ES buffer mapping is an extension. On Desktop
475 // buffer mapping was part of original VBO extension
476 // which we require.
477 if (kDesktop_GrGLBinding == fBindingsExported ||
478 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
479 if (NULL == fMapBuffer ||
480 NULL == fUnmapBuffer) {
481 return false;
482 }
483 }
484
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000485 // Dual source blending
486 if (kDesktop_GrGLBinding == fBindingsExported &&
487 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
488 (3 < major) || (3 == major && 3 <= minor))) {
489 if (NULL == fBindFragDataLocationIndexed) {
490 return false;
491 }
492 }
493
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000494 return true;
495}
496