blob: 2a8ffaaeb482274114aaf3bdc07afdedae460211 [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
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
twiz@google.com59a190b2011-03-14 21:23:01 +000011#include "GrTypes.h"
bsalomon@google.comf987d1b2011-04-04 17:13:52 +000012#include "GrGLInterface.h"
13#include "GrGLDefines.h"
twiz@google.com59a190b2011-03-14 21:23:01 +000014
15#include <stdio.h>
16
bsalomon@google.comf987d1b2011-04-04 17:13:52 +000017GrGLInterface* gGLInterface = NULL;
twiz@google.com59a190b2011-03-14 21:23:01 +000018
19void gl_version_from_string(int* major, int* minor,
20 const char* versionString) {
21 if (NULL == versionString) {
22 GrAssert(0);
23 *major = 0;
24 *minor = 0;
25 return;
26 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000027
twiz@google.com59a190b2011-03-14 21:23:01 +000028 int n = sscanf(versionString, "%d.%d", major, minor);
twiz@google.com0f31ca72011-03-18 17:38:11 +000029 if (2 == n) {
30 return;
twiz@google.com59a190b2011-03-14 21:23:01 +000031 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000032
twiz@google.com59a190b2011-03-14 21:23:01 +000033 char profile[2];
twiz@google.com0f31ca72011-03-18 17:38:11 +000034 n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
35 major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000036 bool ok = 4 == n;
37 if (!ok) {
twiz@google.com0f31ca72011-03-18 17:38:11 +000038 n = sscanf(versionString, "OpenGL ES %d.%d", major, minor);
twiz@google.com59a190b2011-03-14 21:23:01 +000039 ok = 2 == n;
40 }
twiz@google.com0f31ca72011-03-18 17:38:11 +000041
twiz@google.com59a190b2011-03-14 21:23:01 +000042 if (!ok) {
43 GrAssert(0);
44 *major = 0;
45 *minor = 0;
46 return;
47 }
twiz@google.com59a190b2011-03-14 21:23:01 +000048}
49
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +000050float gl_version_as_float_from_string(const char* versionString) {
51 int major, minor;
52 gl_version_from_string(&major, &minor, versionString);
53 GrAssert(minor >= 0);
54 // AFAIK there are only single digit minor numbers
55 if (minor < 10) {
56 return major + minor / 10.f;
57 } else if (minor < 100) {
58 return major + minor / 100.f;
59 } else if (minor < 1000) {
60 return major + minor / 1000.f;
61 } else {
62 GrAssert(!"Why so many digits in minor revision number?");
63 char temp[32];
64 sprintf(temp, "%d.%d", major, minor);
65 return (float) atof(temp);
66 }
67}
68
twiz@google.com59a190b2011-03-14 21:23:01 +000069bool has_gl_extension_from_string(const char* ext,
70 const char* extensionString) {
71 int extLength = strlen(ext);
72
73 while (true) {
74 int n = strcspn(extensionString, " ");
75 if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
76 return true;
77 }
78 if (0 == extensionString[n]) {
79 return false;
80 }
81 extensionString += n+1;
82 }
83
84 return false;
85}
86
bsalomon@google.com91826102011-03-21 19:51:57 +000087GR_API void GrGLSetGLInterface(GrGLInterface* gl_interface) {
twiz@google.com59a190b2011-03-14 21:23:01 +000088 gGLInterface = gl_interface;
89}
90
bsalomon@google.com91826102011-03-21 19:51:57 +000091GR_API GrGLInterface* GrGLGetGLInterface() {
twiz@google.com59a190b2011-03-14 21:23:01 +000092 return gGLInterface;
93}
94
twiz@google.com59a190b2011-03-14 21:23:01 +000095bool has_gl_extension(const char* ext) {
96 const char* glstr = reinterpret_cast<const char*>(
bsalomon@google.comf987d1b2011-04-04 17:13:52 +000097 GrGLGetGLInterface()->fGetString(GR_GL_EXTENSIONS));
twiz@google.com59a190b2011-03-14 21:23:01 +000098
99 return has_gl_extension_from_string(ext, glstr);
100}
101
102void gl_version(int* major, int* minor) {
103 const char* v = reinterpret_cast<const char*>(
bsalomon@google.comf987d1b2011-04-04 17:13:52 +0000104 GrGLGetGLInterface()->fGetString(GR_GL_VERSION));
twiz@google.com59a190b2011-03-14 21:23:01 +0000105 gl_version_from_string(major, minor, v);
106}
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000107
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000108float gl_version_as_float() {
109 const char* v = reinterpret_cast<const char*>(
110 GrGLGetGLInterface()->fGetString(GR_GL_VERSION));
111 return gl_version_as_float_from_string(v);
112}
113
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000114bool GrGLInterface::validateShaderFunctions() const {
115 // required for GrGpuGLShaders
116 if (NULL == fAttachShader ||
117 NULL == fBindAttribLocation ||
118 NULL == fCompileShader ||
119 NULL == fCreateProgram ||
120 NULL == fCreateShader ||
121 NULL == fDeleteProgram ||
122 NULL == fDeleteShader ||
123 NULL == fDisableVertexAttribArray ||
124 NULL == fEnableVertexAttribArray ||
125 NULL == fGetProgramInfoLog ||
126 NULL == fGetProgramiv ||
127 NULL == fGetShaderInfoLog ||
128 NULL == fGetShaderiv ||
129 NULL == fGetUniformLocation ||
130 NULL == fLinkProgram ||
131 NULL == fShaderSource ||
132 NULL == fUniform1f ||
133 NULL == fUniform1i ||
134 NULL == fUniform1fv ||
135 NULL == fUniform1iv ||
136 NULL == fUniform2f ||
137 NULL == fUniform2i ||
138 NULL == fUniform2fv ||
139 NULL == fUniform2iv ||
140 NULL == fUniform3f ||
141 NULL == fUniform3i ||
142 NULL == fUniform3fv ||
143 NULL == fUniform3iv ||
144 NULL == fUniform4f ||
145 NULL == fUniform4i ||
146 NULL == fUniform4fv ||
147 NULL == fUniform4iv ||
148 NULL == fUniformMatrix2fv ||
149 NULL == fUniformMatrix3fv ||
150 NULL == fUniformMatrix4fv ||
151 NULL == fUseProgram ||
152 NULL == fVertexAttrib4fv ||
153 NULL == fVertexAttribPointer) {
154 return false;
155 }
156 return true;
157}
158
159bool GrGLInterface::validateFixedFunctions() const {
160 if (NULL == fClientActiveTexture ||
161 NULL == fColor4ub ||
162 NULL == fColorPointer ||
163 NULL == fDisableClientState ||
164 NULL == fEnableClientState ||
165 NULL == fLoadMatrixf ||
166 NULL == fMatrixMode ||
167 NULL == fPointSize ||
168 NULL == fShadeModel ||
169 NULL == fTexCoordPointer ||
bsalomon@google.com4b9b6a22011-05-04 15:01:16 +0000170 NULL == fTexEnvi ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000171 NULL == fVertexPointer) {
172 return false;
173 }
174 return true;
175}
176
177bool GrGLInterface::validate(GrEngine engine) const {
178
179 bool isDesktop = kDesktop_GrGLBinding == fBindingsExported;
180
181 // ES1 and 2 can be supported in the same interface
182 bool isES = ((kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported &&
183 !(~(kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported));
184
185 if (!isDesktop && !isES) {
186 return false;
187 }
188
189 // functions that are always required
190 if (NULL == fActiveTexture ||
191 NULL == fBindBuffer ||
192 NULL == fBindTexture ||
193 NULL == fBlendFunc ||
194 NULL == fBufferData ||
195 NULL == fBufferSubData ||
196 NULL == fClear ||
197 NULL == fClearColor ||
198 NULL == fClearStencil ||
199 NULL == fColorMask ||
200 NULL == fCullFace ||
201 NULL == fDeleteBuffers ||
202 NULL == fDeleteTextures ||
203 NULL == fDepthMask ||
204 NULL == fDisable ||
205 NULL == fDrawArrays ||
206 NULL == fDrawElements ||
207 NULL == fEnable ||
208 NULL == fFrontFace ||
209 NULL == fGenBuffers ||
210 NULL == fGenTextures ||
211 NULL == fGetBufferParameteriv ||
212 NULL == fGetError ||
213 NULL == fGetIntegerv ||
214 NULL == fGetString ||
215 NULL == fPixelStorei ||
216 NULL == fReadPixels ||
217 NULL == fScissor ||
218 NULL == fStencilFunc ||
219 NULL == fStencilMask ||
220 NULL == fStencilOp ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000221 NULL == fTexImage2D ||
222 NULL == fTexParameteri ||
223 NULL == fTexSubImage2D ||
224 NULL == fViewport ||
225 NULL == fBindFramebuffer ||
226 NULL == fBindRenderbuffer ||
227 NULL == fCheckFramebufferStatus ||
228 NULL == fDeleteFramebuffers ||
229 NULL == fDeleteRenderbuffers ||
230 NULL == fFramebufferRenderbuffer ||
231 NULL == fFramebufferTexture2D ||
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000232 NULL == fGetFramebufferAttachmentParameteriv ||
233 NULL == fGetRenderbufferParameteriv ||
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000234 NULL == fGenFramebuffers ||
235 NULL == fGenRenderbuffers ||
236 NULL == fRenderbufferStorage) {
237 return false;
238 }
239
240 switch (engine) {
241 case kOpenGL_Shaders_GrEngine:
242 if (kES1_GrGLBinding == fBindingsExported) {
243 return false;
244 }
245 if (!this->validateShaderFunctions()) {
246 return false;
247 }
248 break;
249 case kOpenGL_Fixed_GrEngine:
250 if (kES1_GrGLBinding == fBindingsExported) {
251 return false;
252 }
253 if (!this->validateFixedFunctions()) {
254 return false;
255 }
256 break;
257 default:
258 return false;
259 }
260
261 int major, minor;
262 const char* ext;
263
264 gl_version(&major, &minor);
265 ext = (const char*)fGetString(GR_GL_EXTENSIONS);
266
267 // Now check that baseline ES/Desktop fns not covered above are present
268 // and that we have fn pointers for any advertised extensions that we will
269 // try to use.
270
271 // these functions are part of ES2, we assume they are available
272 // On the desktop we assume they are available if the extension
273 // is present or GL version is high enough.
274 if ((kES2_GrGLBinding & fBindingsExported)) {
275 if (NULL == fBlendColor ||
276 NULL == fStencilFuncSeparate ||
277 NULL == fStencilMaskSeparate ||
278 NULL == fStencilOpSeparate) {
279 return false;
280 }
281 } else if (kDesktop_GrGLBinding == fBindingsExported) {
282 if (major >= 2) {
283 if (NULL == fStencilFuncSeparate ||
284 NULL == fStencilMaskSeparate ||
285 NULL == fStencilOpSeparate) {
286 return false;
287 }
288 }
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000289 if (major >= 2 ||
290 has_gl_extension_from_string("GL_ARB_draw_buffers", ext)) {
291 if (NULL == fDrawBuffers) {
292 return false;
293 }
294 }
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000295 if (1 < major || (1 == major && 4 <= minor) ||
296 has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
297 if (NULL == fBlendColor) {
298 return false;
299 }
300 }
301 }
302
303 // optional function on desktop before 1.3
304 if (kDesktop_GrGLBinding != fBindingsExported ||
305 (1 < major || (1 == major && 3 <= minor)) ||
306 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
307 if (NULL == fCompressedTexImage2D) {
308 return false;
309 }
310 }
311
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000312 // part of desktop GL, but not ES
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000313 if (kDesktop_GrGLBinding == fBindingsExported &&
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000314 (NULL == fLineWidth ||
bsalomon@google.comd32c5f52011-08-02 19:29:03 +0000315 NULL == fGetTexLevelParameteriv ||
bsalomon@google.comc49d66b2011-08-03 14:22:30 +0000316 NULL == fDrawBuffer ||
317 NULL == fReadBuffer)) {
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000318 return false;
319 }
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000320
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000321 // FBO MSAA
322 if (kDesktop_GrGLBinding == fBindingsExported) {
323 // GL 3.0 and the ARB extension have multisample + blit
324 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
325 if (NULL == fRenderbufferStorageMultisample ||
326 NULL == fBlitFramebuffer) {
327 return false;
328 }
329 } else {
330 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
331 NULL == fBlitFramebuffer) {
332 return false;
333 }
334 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
335 NULL == fRenderbufferStorageMultisample) {
336 return false;
337 }
338 }
339 } else {
340 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
341 if (NULL == fRenderbufferStorageMultisample ||
342 NULL == fBlitFramebuffer) {
343 return false;
344 }
345 }
346 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
347 if (NULL == fRenderbufferStorageMultisample ||
348 NULL == fResolveMultisampleFramebuffer) {
349 return false;
350 }
351 }
352 }
353
354 // On ES buffer mapping is an extension. On Desktop
355 // buffer mapping was part of original VBO extension
356 // which we require.
357 if (kDesktop_GrGLBinding == fBindingsExported ||
358 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
359 if (NULL == fMapBuffer ||
360 NULL == fUnmapBuffer) {
361 return false;
362 }
363 }
364
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000365 // Dual source blending
366 if (kDesktop_GrGLBinding == fBindingsExported &&
367 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
368 (3 < major) || (3 == major && 3 <= minor))) {
369 if (NULL == fBindFragDataLocationIndexed) {
370 return false;
371 }
372 }
373
bsalomon@google.combf2a4692011-05-04 12:35:39 +0000374 return true;
375}
376