1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#include "gl/GrGLInterface.h"
10#include "gl/GrGLExtensions.h"
11#include "gl/GrGLUtil.h"
12
13#include <stdio.h>
14
15#if GR_GL_PER_GL_FUNC_CALLBACK
16namespace {
17void GrGLDefaultInterfaceCallback(const GrGLInterface*) {}
18}
19#endif
20
21GrGLInterface::GrGLInterface() {
22    fBindingsExported = kNone_GrGLBinding;
23
24#if GR_GL_PER_GL_FUNC_CALLBACK
25    fCallback = GrGLDefaultInterfaceCallback;
26    fCallbackData = 0;
27#endif
28}
29
30bool GrGLInterface::validate(GrGLBinding binding) const {
31
32    // kNone must be 0 so that the check we're about to do can never succeed if
33    // binding == kNone.
34    GR_STATIC_ASSERT(kNone_GrGLBinding == 0);
35
36    if (0 == (binding & fBindingsExported)) {
37        return false;
38    }
39
40    GrGLExtensions extensions;
41    if (!extensions.init(binding, this)) {
42        return false;
43    }
44
45    // functions that are always required
46    if (NULL == fActiveTexture ||
47        NULL == fAttachShader ||
48        NULL == fBindAttribLocation ||
49        NULL == fBindBuffer ||
50        NULL == fBindTexture ||
51        NULL == fBlendFunc ||
52        NULL == fBlendColor ||      // -> GL >= 1.4, ES >= 2.0 or extension
53        NULL == fBufferData ||
54        NULL == fBufferSubData ||
55        NULL == fClear ||
56        NULL == fClearColor ||
57        NULL == fClearStencil ||
58        NULL == fColorMask ||
59        NULL == fCompileShader ||
60        NULL == fCopyTexSubImage2D ||
61        NULL == fCreateProgram ||
62        NULL == fCreateShader ||
63        NULL == fCullFace ||
64        NULL == fDeleteBuffers ||
65        NULL == fDeleteProgram ||
66        NULL == fDeleteShader ||
67        NULL == fDeleteTextures ||
68        NULL == fDepthMask ||
69        NULL == fDisable ||
70        NULL == fDisableVertexAttribArray ||
71        NULL == fDrawArrays ||
72        NULL == fDrawElements ||
73        NULL == fEnable ||
74        NULL == fEnableVertexAttribArray ||
75        NULL == fFrontFace ||
76        NULL == fGenBuffers ||
77        NULL == fGenTextures ||
78        NULL == fGetBufferParameteriv ||
79        NULL == fGenerateMipmap ||
80        NULL == fGetError ||
81        NULL == fGetIntegerv ||
82        NULL == fGetProgramInfoLog ||
83        NULL == fGetProgramiv ||
84        NULL == fGetShaderInfoLog ||
85        NULL == fGetShaderiv ||
86        NULL == fGetString ||
87        NULL == fGetUniformLocation ||
88        NULL == fLinkProgram ||
89        NULL == fLineWidth ||
90        NULL == fPixelStorei ||
91        NULL == fReadPixels ||
92        NULL == fScissor ||
93        NULL == fShaderSource ||
94        NULL == fStencilFunc ||
95        NULL == fStencilMask ||
96        NULL == fStencilOp ||
97        NULL == fTexImage2D ||
98        NULL == fTexParameteri ||
99        NULL == fTexParameteriv ||
100        NULL == fTexSubImage2D ||
101        NULL == fUniform1f ||
102        NULL == fUniform1i ||
103        NULL == fUniform1fv ||
104        NULL == fUniform1iv ||
105        NULL == fUniform2f ||
106        NULL == fUniform2i ||
107        NULL == fUniform2fv ||
108        NULL == fUniform2iv ||
109        NULL == fUniform3f ||
110        NULL == fUniform3i ||
111        NULL == fUniform3fv ||
112        NULL == fUniform3iv ||
113        NULL == fUniform4f ||
114        NULL == fUniform4i ||
115        NULL == fUniform4fv ||
116        NULL == fUniform4iv ||
117        NULL == fUniformMatrix2fv ||
118        NULL == fUniformMatrix3fv ||
119        NULL == fUniformMatrix4fv ||
120        NULL == fUseProgram ||
121        NULL == fVertexAttrib4fv ||
122        NULL == fVertexAttribPointer ||
123        NULL == fViewport ||
124        NULL == fBindFramebuffer ||
125        NULL == fBindRenderbuffer ||
126        NULL == fCheckFramebufferStatus ||
127        NULL == fDeleteFramebuffers ||
128        NULL == fDeleteRenderbuffers ||
129        NULL == fFinish ||
130        NULL == fFlush ||
131        NULL == fFramebufferRenderbuffer ||
132        NULL == fFramebufferTexture2D ||
133        NULL == fGetFramebufferAttachmentParameteriv ||
134        NULL == fGetRenderbufferParameteriv ||
135        NULL == fGenFramebuffers ||
136        NULL == fGenRenderbuffers ||
137        NULL == fRenderbufferStorage) {
138        return false;
139    }
140
141    GrGLVersion glVer = GrGLGetVersion(this);
142
143    bool isCoreProfile = false;
144    if (kDesktop_GrGLBinding == binding && glVer >= GR_GL_VER(3,2)) {
145        GrGLint profileMask;
146        GR_GL_GetIntegerv(this, GR_GL_CONTEXT_PROFILE_MASK, &profileMask);
147        isCoreProfile = SkToBool(profileMask & GR_GL_CONTEXT_CORE_PROFILE_BIT);
148    }
149
150    // Now check that baseline ES/Desktop fns not covered above are present
151    // and that we have fn pointers for any advertised extensions that we will
152    // try to use.
153
154    // these functions are part of ES2, we assume they are available
155    // On the desktop we assume they are available if the extension
156    // is present or GL version is high enough.
157    if (kES_GrGLBinding == binding) {
158        if (NULL == fStencilFuncSeparate ||
159            NULL == fStencilMaskSeparate ||
160            NULL == fStencilOpSeparate) {
161            return false;
162        }
163    } else if (kDesktop_GrGLBinding == binding) {
164
165        if (glVer >= GR_GL_VER(2,0)) {
166            if (NULL == fStencilFuncSeparate ||
167                NULL == fStencilMaskSeparate ||
168                NULL == fStencilOpSeparate) {
169                return false;
170            }
171        }
172        if (glVer >= GR_GL_VER(3,0) && NULL == fBindFragDataLocation) {
173            return false;
174        }
175        if (glVer >= GR_GL_VER(2,0) || extensions.has("GL_ARB_draw_buffers")) {
176            if (NULL == fDrawBuffers) {
177                return false;
178            }
179        }
180
181        if (glVer >= GR_GL_VER(1,5) || extensions.has("GL_ARB_occlusion_query")) {
182            if (NULL == fGenQueries ||
183                NULL == fDeleteQueries ||
184                NULL == fBeginQuery ||
185                NULL == fEndQuery ||
186                NULL == fGetQueryiv ||
187                NULL == fGetQueryObjectiv ||
188                NULL == fGetQueryObjectuiv) {
189                return false;
190            }
191        }
192        if (glVer >= GR_GL_VER(3,3) ||
193            extensions.has("GL_ARB_timer_query") ||
194            extensions.has("GL_EXT_timer_query")) {
195            if (NULL == fGetQueryObjecti64v ||
196                NULL == fGetQueryObjectui64v) {
197                return false;
198            }
199        }
200        if (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) {
201            if (NULL == fQueryCounter) {
202                return false;
203            }
204        }
205        if (!isCoreProfile) {
206            if (NULL == fClientActiveTexture ||
207                NULL == fDisableClientState ||
208                NULL == fEnableClientState ||
209                NULL == fLoadIdentity ||
210                NULL == fLoadMatrixf ||
211                NULL == fMatrixMode ||
212                NULL == fTexGenf ||
213                NULL == fTexGenfv ||
214                NULL == fTexGeni ||
215                NULL == fVertexPointer) {
216                return false;
217            }
218        }
219        if (false && extensions.has("GL_NV_path_rendering")) {
220            if (NULL == fPathCommands ||
221                NULL == fPathCoords ||
222                NULL == fPathSubCommands ||
223                NULL == fPathSubCoords ||
224                NULL == fPathString ||
225                NULL == fPathGlyphs ||
226                NULL == fPathGlyphRange ||
227                NULL == fWeightPaths ||
228                NULL == fCopyPath ||
229                NULL == fInterpolatePaths ||
230                NULL == fTransformPath ||
231                NULL == fPathParameteriv ||
232                NULL == fPathParameteri ||
233                NULL == fPathParameterfv ||
234                NULL == fPathParameterf ||
235                NULL == fPathDashArray ||
236                NULL == fGenPaths ||
237                NULL == fDeletePaths ||
238                NULL == fIsPath ||
239                NULL == fPathStencilFunc ||
240                NULL == fPathStencilDepthOffset ||
241                NULL == fStencilFillPath ||
242                NULL == fStencilStrokePath ||
243                NULL == fStencilFillPathInstanced ||
244                NULL == fStencilStrokePathInstanced ||
245                NULL == fPathCoverDepthFunc ||
246                NULL == fPathColorGen ||
247                NULL == fPathTexGen ||
248                NULL == fPathFogGen ||
249                NULL == fCoverFillPath ||
250                NULL == fCoverStrokePath ||
251                NULL == fCoverFillPathInstanced ||
252                NULL == fCoverStrokePathInstanced ||
253                NULL == fGetPathParameteriv ||
254                NULL == fGetPathParameterfv ||
255                NULL == fGetPathCommands ||
256                NULL == fGetPathCoords ||
257                NULL == fGetPathDashArray ||
258                NULL == fGetPathMetrics ||
259                NULL == fGetPathMetricRange ||
260                NULL == fGetPathSpacing ||
261                NULL == fGetPathColorGeniv ||
262                NULL == fGetPathColorGenfv ||
263                NULL == fGetPathTexGeniv ||
264                NULL == fGetPathTexGenfv ||
265                NULL == fIsPointInFillPath ||
266                NULL == fIsPointInStrokePath ||
267                NULL == fGetPathLength ||
268                NULL == fPointAlongPath) {
269                return false;
270            }
271        }
272    }
273
274    // optional function on desktop before 1.3
275    if (kDesktop_GrGLBinding != binding ||
276        (glVer >= GR_GL_VER(1,3)) ||
277        extensions.has("GL_ARB_texture_compression")) {
278        if (NULL == fCompressedTexImage2D) {
279            return false;
280        }
281    }
282
283    // part of desktop GL, but not ES
284    if (kDesktop_GrGLBinding == binding &&
285        (NULL == fGetTexLevelParameteriv ||
286         NULL == fDrawBuffer ||
287         NULL == fReadBuffer)) {
288        return false;
289    }
290
291    // GL_EXT_texture_storage is part of desktop 4.2
292    // There is a desktop ARB extension and an ES+desktop EXT extension
293    if (kDesktop_GrGLBinding == binding) {
294        if (glVer >= GR_GL_VER(4,2) ||
295            extensions.has("GL_ARB_texture_storage") ||
296            extensions.has("GL_EXT_texture_storage")) {
297            if (NULL == fTexStorage2D) {
298                return false;
299            }
300        }
301    } else if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_EXT_texture_storage")) {
302        if (NULL == fTexStorage2D) {
303            return false;
304        }
305    }
306
307    if (extensions.has("GL_EXT_discard_framebuffer")) {
308// FIXME: Remove this once Chromium is updated to provide this function
309#if 0
310        if (NULL == fDiscardFramebuffer) {
311            return false;
312        }
313#endif
314    }
315
316    // FBO MSAA
317    if (kDesktop_GrGLBinding == binding) {
318        // GL 3.0 and the ARB extension have multisample + blit
319        if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) {
320            if (NULL == fRenderbufferStorageMultisample ||
321                NULL == fBlitFramebuffer) {
322                return false;
323            }
324        } else {
325            if (extensions.has("GL_EXT_framebuffer_blit") &&
326                NULL == fBlitFramebuffer) {
327                return false;
328            }
329            if (extensions.has("GL_EXT_framebuffer_multisample") &&
330                NULL == fRenderbufferStorageMultisample) {
331                return false;
332            }
333        }
334    } else {
335#if GR_GL_IGNORE_ES3_MSAA
336        if (extensions.has("GL_CHROMIUM_framebuffer_multisample")) {
337            if (NULL == fRenderbufferStorageMultisample ||
338                NULL == fBlitFramebuffer) {
339                return false;
340            }
341        } else if (extensions.has("GL_APPLE_framebuffer_multisample")) {
342            if (NULL == fRenderbufferStorageMultisample ||
343                NULL == fResolveMultisampleFramebuffer) {
344                return false;
345            }
346        } else if (extensions.has("GL_IMG_multisampled_render_to_texture") ||
347                   extensions.has("GL_EXT_multisampled_render_to_texture")) {
348            if (NULL == fRenderbufferStorageMultisample ||
349                NULL == fFramebufferTexture2DMultisample) {
350                return false;
351            }
352        }
353#else
354        if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_CHROMIUM_framebuffer_multisample")) {
355            if (NULL == fRenderbufferStorageMultisample ||
356                NULL == fBlitFramebuffer) {
357                return false;
358            }
359        }
360        if (extensions.has("GL_APPLE_framebuffer_multisample")) {
361            if (NULL == fRenderbufferStorageMultisampleES2APPLE ||
362                NULL == fResolveMultisampleFramebuffer) {
363                return false;
364            }
365        }
366        if (extensions.has("GL_IMG_multisampled_render_to_texture") ||
367            extensions.has("GL_EXT_multisampled_render_to_texture")) {
368            if (NULL == fRenderbufferStorageMultisampleES2EXT ||
369                NULL == fFramebufferTexture2DMultisample) {
370                return false;
371            }
372        }
373#endif
374    }
375
376    // On ES buffer mapping is an extension. On Desktop
377    // buffer mapping was part of original VBO extension
378    // which we require.
379    if (kDesktop_GrGLBinding == binding || extensions.has("GL_OES_mapbuffer")) {
380        if (NULL == fMapBuffer ||
381            NULL == fUnmapBuffer) {
382            return false;
383        }
384    }
385
386    // Dual source blending
387    if (kDesktop_GrGLBinding == binding &&
388        (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_blend_func_extended"))) {
389        if (NULL == fBindFragDataLocationIndexed) {
390            return false;
391        }
392    }
393
394    // glGetStringi was added in version 3.0 of both desktop and ES.
395    if (glVer >= GR_GL_VER(3, 0)) {
396        if (NULL == fGetStringi) {
397            return false;
398        }
399    }
400
401    if (kDesktop_GrGLBinding == binding) {
402        if (glVer >= GR_GL_VER(3, 0) || extensions.has("GL_ARB_vertex_array_object")) {
403            if (NULL == fBindVertexArray ||
404                NULL == fDeleteVertexArrays ||
405                NULL == fGenVertexArrays) {
406                return false;
407            }
408        }
409    } else {
410        if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_OES_vertex_array_object")) {
411            if (NULL == fBindVertexArray ||
412                NULL == fDeleteVertexArrays ||
413                NULL == fGenVertexArrays) {
414                return false;
415            }
416        }
417    }
418
419    return true;
420}
421