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