Home | History | Annotate | Download | only in gl
      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
     16 namespace {
     17 void GrGLDefaultInterfaceCallback(const GrGLInterface*) {}
     18 }
     19 #endif
     20 
     21 const GrGLInterface* GrGLInterfaceAddTestDebugMarker(const GrGLInterface* interface,
     22                                                      GrGLInsertEventMarkerProc insertEventMarkerFn,
     23                                                      GrGLPushGroupMarkerProc pushGroupMarkerFn,
     24                                                      GrGLPopGroupMarkerProc popGroupMarkerFn) {
     25     GrGLInterface* newInterface = GrGLInterface::NewClone(interface);
     26 
     27     if (!newInterface->fExtensions.has("GL_EXT_debug_marker")) {
     28         newInterface->fExtensions.add("GL_EXT_debug_marker");
     29     }
     30 
     31     newInterface->fFunctions.fInsertEventMarker = insertEventMarkerFn;
     32     newInterface->fFunctions.fPushGroupMarker = pushGroupMarkerFn;
     33     newInterface->fFunctions.fPopGroupMarker = popGroupMarkerFn;
     34 
     35     return newInterface;
     36 }
     37 
     38 const GrGLInterface* GrGLInterfaceRemoveNVPR(const GrGLInterface* interface) {
     39     GrGLInterface* newInterface = GrGLInterface::NewClone(interface);
     40 
     41     newInterface->fExtensions.remove("GL_NV_path_rendering");
     42 
     43     newInterface->fFunctions.fPathCommands = NULL;
     44     newInterface->fFunctions.fPathCoords = NULL;
     45     newInterface->fFunctions.fPathSubCommands = NULL;
     46     newInterface->fFunctions.fPathSubCoords = NULL;
     47     newInterface->fFunctions.fPathString = NULL;
     48     newInterface->fFunctions.fPathGlyphs = NULL;
     49     newInterface->fFunctions.fPathGlyphRange = NULL;
     50     newInterface->fFunctions.fWeightPaths = NULL;
     51     newInterface->fFunctions.fCopyPath = NULL;
     52     newInterface->fFunctions.fInterpolatePaths = NULL;
     53     newInterface->fFunctions.fTransformPath = NULL;
     54     newInterface->fFunctions.fPathParameteriv = NULL;
     55     newInterface->fFunctions.fPathParameteri = NULL;
     56     newInterface->fFunctions.fPathParameterfv = NULL;
     57     newInterface->fFunctions.fPathParameterf = NULL;
     58     newInterface->fFunctions.fPathDashArray = NULL;
     59     newInterface->fFunctions.fGenPaths = NULL;
     60     newInterface->fFunctions.fDeletePaths = NULL;
     61     newInterface->fFunctions.fIsPath = NULL;
     62     newInterface->fFunctions.fPathStencilFunc = NULL;
     63     newInterface->fFunctions.fPathStencilDepthOffset = NULL;
     64     newInterface->fFunctions.fStencilFillPath = NULL;
     65     newInterface->fFunctions.fStencilStrokePath = NULL;
     66     newInterface->fFunctions.fStencilFillPathInstanced = NULL;
     67     newInterface->fFunctions.fStencilStrokePathInstanced = NULL;
     68     newInterface->fFunctions.fPathCoverDepthFunc = NULL;
     69     newInterface->fFunctions.fPathColorGen = NULL;
     70     newInterface->fFunctions.fPathTexGen = NULL;
     71     newInterface->fFunctions.fPathFogGen = NULL;
     72     newInterface->fFunctions.fCoverFillPath = NULL;
     73     newInterface->fFunctions.fCoverStrokePath = NULL;
     74     newInterface->fFunctions.fCoverFillPathInstanced = NULL;
     75     newInterface->fFunctions.fCoverStrokePathInstanced = NULL;
     76     newInterface->fFunctions.fGetPathParameteriv = NULL;
     77     newInterface->fFunctions.fGetPathParameterfv = NULL;
     78     newInterface->fFunctions.fGetPathCommands = NULL;
     79     newInterface->fFunctions.fGetPathCoords = NULL;
     80     newInterface->fFunctions.fGetPathDashArray = NULL;
     81     newInterface->fFunctions.fGetPathMetrics = NULL;
     82     newInterface->fFunctions.fGetPathMetricRange = NULL;
     83     newInterface->fFunctions.fGetPathSpacing = NULL;
     84     newInterface->fFunctions.fGetPathColorGeniv = NULL;
     85     newInterface->fFunctions.fGetPathColorGenfv = NULL;
     86     newInterface->fFunctions.fGetPathTexGeniv = NULL;
     87     newInterface->fFunctions.fGetPathTexGenfv = NULL;
     88     newInterface->fFunctions.fIsPointInFillPath = NULL;
     89     newInterface->fFunctions.fIsPointInStrokePath = NULL;
     90     newInterface->fFunctions.fGetPathLength = NULL;
     91     newInterface->fFunctions.fPointAlongPath = NULL;
     92 
     93     return newInterface;
     94 }
     95 
     96 GrGLInterface::GrGLInterface() {
     97     fStandard = kNone_GrGLStandard;
     98 
     99 #if GR_GL_PER_GL_FUNC_CALLBACK
    100     fCallback = GrGLDefaultInterfaceCallback;
    101     fCallbackData = 0;
    102 #endif
    103 }
    104 
    105 GrGLInterface* GrGLInterface::NewClone(const GrGLInterface* interface) {
    106     SkASSERT(NULL != interface);
    107 
    108     GrGLInterface* clone = SkNEW(GrGLInterface);
    109     clone->fStandard = interface->fStandard;
    110     clone->fExtensions = interface->fExtensions;
    111     clone->fFunctions = interface->fFunctions;
    112 #if GR_GL_PER_GL_FUNC_CALLBACK
    113     clone->fCallback = interface->fCallback;
    114     clone->fCallbackData = interface->fCallbackData;
    115 #endif
    116     return clone;
    117 }
    118 
    119 #ifdef SK_DEBUG
    120     static int kIsDebug = 1;
    121 #else
    122     static int kIsDebug = 0;
    123 #endif
    124 
    125 #define RETURN_FALSE_INTERFACE                                                                   \
    126     if (kIsDebug) { SkDebugf("%s:%d GrGLInterface::validate() failed.\n", __FILE__, __LINE__); } \
    127     return false;
    128 
    129 bool GrGLInterface::validate() const {
    130 
    131     if (kNone_GrGLStandard == fStandard) {
    132         RETURN_FALSE_INTERFACE
    133     }
    134 
    135     if (!fExtensions.isInitialized()) {
    136         RETURN_FALSE_INTERFACE
    137     }
    138 
    139     // functions that are always required
    140     if (NULL == fFunctions.fActiveTexture ||
    141         NULL == fFunctions.fAttachShader ||
    142         NULL == fFunctions.fBindAttribLocation ||
    143         NULL == fFunctions.fBindBuffer ||
    144         NULL == fFunctions.fBindTexture ||
    145         NULL == fFunctions.fBlendFunc ||
    146         NULL == fFunctions.fBlendColor ||      // -> GL >= 1.4, ES >= 2.0 or extension
    147         NULL == fFunctions.fBufferData ||
    148         NULL == fFunctions.fBufferSubData ||
    149         NULL == fFunctions.fClear ||
    150         NULL == fFunctions.fClearColor ||
    151         NULL == fFunctions.fClearStencil ||
    152         NULL == fFunctions.fColorMask ||
    153         NULL == fFunctions.fCompileShader ||
    154         NULL == fFunctions.fCopyTexSubImage2D ||
    155         NULL == fFunctions.fCreateProgram ||
    156         NULL == fFunctions.fCreateShader ||
    157         NULL == fFunctions.fCullFace ||
    158         NULL == fFunctions.fDeleteBuffers ||
    159         NULL == fFunctions.fDeleteProgram ||
    160         NULL == fFunctions.fDeleteShader ||
    161         NULL == fFunctions.fDeleteTextures ||
    162         NULL == fFunctions.fDepthMask ||
    163         NULL == fFunctions.fDisable ||
    164         NULL == fFunctions.fDisableVertexAttribArray ||
    165         NULL == fFunctions.fDrawArrays ||
    166         NULL == fFunctions.fDrawElements ||
    167         NULL == fFunctions.fEnable ||
    168         NULL == fFunctions.fEnableVertexAttribArray ||
    169         NULL == fFunctions.fFrontFace ||
    170         NULL == fFunctions.fGenBuffers ||
    171         NULL == fFunctions.fGenTextures ||
    172         NULL == fFunctions.fGetBufferParameteriv ||
    173         NULL == fFunctions.fGenerateMipmap ||
    174         NULL == fFunctions.fGetError ||
    175         NULL == fFunctions.fGetIntegerv ||
    176         NULL == fFunctions.fGetProgramInfoLog ||
    177         NULL == fFunctions.fGetProgramiv ||
    178         NULL == fFunctions.fGetShaderInfoLog ||
    179         NULL == fFunctions.fGetShaderiv ||
    180         NULL == fFunctions.fGetString ||
    181         NULL == fFunctions.fGetUniformLocation ||
    182         NULL == fFunctions.fLinkProgram ||
    183         NULL == fFunctions.fLineWidth ||
    184         NULL == fFunctions.fPixelStorei ||
    185         NULL == fFunctions.fReadPixels ||
    186         NULL == fFunctions.fScissor ||
    187         NULL == fFunctions.fShaderSource ||
    188         NULL == fFunctions.fStencilFunc ||
    189         NULL == fFunctions.fStencilMask ||
    190         NULL == fFunctions.fStencilOp ||
    191         NULL == fFunctions.fTexImage2D ||
    192         NULL == fFunctions.fTexParameteri ||
    193         NULL == fFunctions.fTexParameteriv ||
    194         NULL == fFunctions.fTexSubImage2D ||
    195         NULL == fFunctions.fUniform1f ||
    196         NULL == fFunctions.fUniform1i ||
    197         NULL == fFunctions.fUniform1fv ||
    198         NULL == fFunctions.fUniform1iv ||
    199         NULL == fFunctions.fUniform2f ||
    200         NULL == fFunctions.fUniform2i ||
    201         NULL == fFunctions.fUniform2fv ||
    202         NULL == fFunctions.fUniform2iv ||
    203         NULL == fFunctions.fUniform3f ||
    204         NULL == fFunctions.fUniform3i ||
    205         NULL == fFunctions.fUniform3fv ||
    206         NULL == fFunctions.fUniform3iv ||
    207         NULL == fFunctions.fUniform4f ||
    208         NULL == fFunctions.fUniform4i ||
    209         NULL == fFunctions.fUniform4fv ||
    210         NULL == fFunctions.fUniform4iv ||
    211         NULL == fFunctions.fUniformMatrix2fv ||
    212         NULL == fFunctions.fUniformMatrix3fv ||
    213         NULL == fFunctions.fUniformMatrix4fv ||
    214         NULL == fFunctions.fUseProgram ||
    215         NULL == fFunctions.fVertexAttrib4fv ||
    216         NULL == fFunctions.fVertexAttribPointer ||
    217         NULL == fFunctions.fViewport ||
    218         NULL == fFunctions.fBindFramebuffer ||
    219         NULL == fFunctions.fBindRenderbuffer ||
    220         NULL == fFunctions.fCheckFramebufferStatus ||
    221         NULL == fFunctions.fDeleteFramebuffers ||
    222         NULL == fFunctions.fDeleteRenderbuffers ||
    223         NULL == fFunctions.fFinish ||
    224         NULL == fFunctions.fFlush ||
    225         NULL == fFunctions.fFramebufferRenderbuffer ||
    226         NULL == fFunctions.fFramebufferTexture2D ||
    227         NULL == fFunctions.fGetFramebufferAttachmentParameteriv ||
    228         NULL == fFunctions.fGetRenderbufferParameteriv ||
    229         NULL == fFunctions.fGenFramebuffers ||
    230         NULL == fFunctions.fGenRenderbuffers ||
    231         NULL == fFunctions.fRenderbufferStorage) {
    232         RETURN_FALSE_INTERFACE
    233     }
    234 
    235     GrGLVersion glVer = GrGLGetVersion(this);
    236     if (GR_GL_INVALID_VER == glVer) {
    237         RETURN_FALSE_INTERFACE
    238     }
    239 
    240     // Now check that baseline ES/Desktop fns not covered above are present
    241     // and that we have fn pointers for any advertised fExtensions that we will
    242     // try to use.
    243 
    244     // these functions are part of ES2, we assume they are available
    245     // On the desktop we assume they are available if the extension
    246     // is present or GL version is high enough.
    247     if (kGLES_GrGLStandard == fStandard) {
    248         if (NULL == fFunctions.fStencilFuncSeparate ||
    249             NULL == fFunctions.fStencilMaskSeparate ||
    250             NULL == fFunctions.fStencilOpSeparate) {
    251             RETURN_FALSE_INTERFACE
    252         }
    253     } else if (kGL_GrGLStandard == fStandard) {
    254 
    255         if (glVer >= GR_GL_VER(2,0)) {
    256             if (NULL == fFunctions.fStencilFuncSeparate ||
    257                 NULL == fFunctions.fStencilMaskSeparate ||
    258                 NULL == fFunctions.fStencilOpSeparate) {
    259                 RETURN_FALSE_INTERFACE
    260             }
    261         }
    262         if (glVer >= GR_GL_VER(3,0) && NULL == fFunctions.fBindFragDataLocation) {
    263             RETURN_FALSE_INTERFACE
    264         }
    265         if (glVer >= GR_GL_VER(2,0) || fExtensions.has("GL_ARB_draw_buffers")) {
    266             if (NULL == fFunctions.fDrawBuffers) {
    267                 RETURN_FALSE_INTERFACE
    268             }
    269         }
    270 
    271         if (glVer >= GR_GL_VER(1,5) || fExtensions.has("GL_ARB_occlusion_query")) {
    272             if (NULL == fFunctions.fGenQueries ||
    273                 NULL == fFunctions.fDeleteQueries ||
    274                 NULL == fFunctions.fBeginQuery ||
    275                 NULL == fFunctions.fEndQuery ||
    276                 NULL == fFunctions.fGetQueryiv ||
    277                 NULL == fFunctions.fGetQueryObjectiv ||
    278                 NULL == fFunctions.fGetQueryObjectuiv) {
    279                 RETURN_FALSE_INTERFACE
    280             }
    281         }
    282         if (glVer >= GR_GL_VER(3,3) ||
    283             fExtensions.has("GL_ARB_timer_query") ||
    284             fExtensions.has("GL_EXT_timer_query")) {
    285             if (NULL == fFunctions.fGetQueryObjecti64v ||
    286                 NULL == fFunctions.fGetQueryObjectui64v) {
    287                 RETURN_FALSE_INTERFACE
    288             }
    289         }
    290         if (glVer >= GR_GL_VER(3,3) || fExtensions.has("GL_ARB_timer_query")) {
    291             if (NULL == fFunctions.fQueryCounter) {
    292                 RETURN_FALSE_INTERFACE
    293             }
    294         }
    295         if (fExtensions.has("GL_EXT_direct_state_access")) {
    296             if (NULL == fFunctions.fMatrixLoadf ||
    297                 NULL == fFunctions.fMatrixLoadIdentity) {
    298                 RETURN_FALSE_INTERFACE
    299             }
    300         }
    301         if (fExtensions.has("GL_NV_path_rendering")) {
    302             if (NULL == fFunctions.fPathCommands ||
    303                 NULL == fFunctions.fPathCoords ||
    304                 NULL == fFunctions.fPathSubCommands ||
    305                 NULL == fFunctions.fPathSubCoords ||
    306                 NULL == fFunctions.fPathString ||
    307                 NULL == fFunctions.fPathGlyphs ||
    308                 NULL == fFunctions.fPathGlyphRange ||
    309                 NULL == fFunctions.fWeightPaths ||
    310                 NULL == fFunctions.fCopyPath ||
    311                 NULL == fFunctions.fInterpolatePaths ||
    312                 NULL == fFunctions.fTransformPath ||
    313                 NULL == fFunctions.fPathParameteriv ||
    314                 NULL == fFunctions.fPathParameteri ||
    315                 NULL == fFunctions.fPathParameterfv ||
    316                 NULL == fFunctions.fPathParameterf ||
    317                 NULL == fFunctions.fPathDashArray ||
    318                 NULL == fFunctions.fGenPaths ||
    319                 NULL == fFunctions.fDeletePaths ||
    320                 NULL == fFunctions.fIsPath ||
    321                 NULL == fFunctions.fPathStencilFunc ||
    322                 NULL == fFunctions.fPathStencilDepthOffset ||
    323                 NULL == fFunctions.fStencilFillPath ||
    324                 NULL == fFunctions.fStencilStrokePath ||
    325                 NULL == fFunctions.fStencilFillPathInstanced ||
    326                 NULL == fFunctions.fStencilStrokePathInstanced ||
    327                 NULL == fFunctions.fPathCoverDepthFunc ||
    328                 NULL == fFunctions.fPathColorGen ||
    329                 NULL == fFunctions.fPathTexGen ||
    330                 NULL == fFunctions.fPathFogGen ||
    331                 NULL == fFunctions.fCoverFillPath ||
    332                 NULL == fFunctions.fCoverStrokePath ||
    333                 NULL == fFunctions.fCoverFillPathInstanced ||
    334                 NULL == fFunctions.fCoverStrokePathInstanced ||
    335                 NULL == fFunctions.fGetPathParameteriv ||
    336                 NULL == fFunctions.fGetPathParameterfv ||
    337                 NULL == fFunctions.fGetPathCommands ||
    338                 NULL == fFunctions.fGetPathCoords ||
    339                 NULL == fFunctions.fGetPathDashArray ||
    340                 NULL == fFunctions.fGetPathMetrics ||
    341                 NULL == fFunctions.fGetPathMetricRange ||
    342                 NULL == fFunctions.fGetPathSpacing ||
    343                 NULL == fFunctions.fGetPathColorGeniv ||
    344                 NULL == fFunctions.fGetPathColorGenfv ||
    345                 NULL == fFunctions.fGetPathTexGeniv ||
    346                 NULL == fFunctions.fGetPathTexGenfv ||
    347                 NULL == fFunctions.fIsPointInFillPath ||
    348                 NULL == fFunctions.fIsPointInStrokePath ||
    349                 NULL == fFunctions.fGetPathLength ||
    350                 NULL == fFunctions.fPointAlongPath) {
    351                 RETURN_FALSE_INTERFACE
    352             }
    353         }
    354     }
    355 
    356     // optional function on desktop before 1.3
    357     if (kGL_GrGLStandard != fStandard ||
    358         (glVer >= GR_GL_VER(1,3)) ||
    359         fExtensions.has("GL_ARB_texture_compression")) {
    360         if (NULL == fFunctions.fCompressedTexImage2D
    361 #if 0
    362             || NULL == fFunctions.fCompressedTexSubImage2D
    363 #endif
    364             ) {
    365             RETURN_FALSE_INTERFACE
    366         }
    367     }
    368 
    369     // part of desktop GL, but not ES
    370     if (kGL_GrGLStandard == fStandard &&
    371         (NULL == fFunctions.fGetTexLevelParameteriv ||
    372          NULL == fFunctions.fDrawBuffer ||
    373          NULL == fFunctions.fReadBuffer)) {
    374         RETURN_FALSE_INTERFACE
    375     }
    376 
    377     // GL_EXT_texture_storage is part of desktop 4.2
    378     // There is a desktop ARB extension and an ES+desktop EXT extension
    379     if (kGL_GrGLStandard == fStandard) {
    380         if (glVer >= GR_GL_VER(4,2) ||
    381             fExtensions.has("GL_ARB_texture_storage") ||
    382             fExtensions.has("GL_EXT_texture_storage")) {
    383             if (NULL == fFunctions.fTexStorage2D) {
    384                 RETURN_FALSE_INTERFACE
    385             }
    386         }
    387     } else if (glVer >= GR_GL_VER(3,0) || fExtensions.has("GL_EXT_texture_storage")) {
    388         if (NULL == fFunctions.fTexStorage2D) {
    389             RETURN_FALSE_INTERFACE
    390         }
    391     }
    392 
    393     if (fExtensions.has("GL_EXT_discard_framebuffer")) {
    394 // FIXME: Remove this once Chromium is updated to provide this function
    395 #if 0
    396         if (NULL == fFunctions.fDiscardFramebuffer) {
    397             RETURN_FALSE_INTERFACE
    398         }
    399 #endif
    400     }
    401 
    402     // FBO MSAA
    403     if (kGL_GrGLStandard == fStandard) {
    404         // GL 3.0 and the ARB extension have multisample + blit
    405         if (glVer >= GR_GL_VER(3,0) || fExtensions.has("GL_ARB_framebuffer_object")) {
    406             if (NULL == fFunctions.fRenderbufferStorageMultisample ||
    407                 NULL == fFunctions.fBlitFramebuffer) {
    408                 RETURN_FALSE_INTERFACE
    409             }
    410         } else {
    411             if (fExtensions.has("GL_EXT_framebuffer_blit") &&
    412                 NULL == fFunctions.fBlitFramebuffer) {
    413                 RETURN_FALSE_INTERFACE
    414             }
    415             if (fExtensions.has("GL_EXT_framebuffer_multisample") &&
    416                 NULL == fFunctions.fRenderbufferStorageMultisample) {
    417                 RETURN_FALSE_INTERFACE
    418             }
    419         }
    420     } else {
    421         if (glVer >= GR_GL_VER(3,0) || fExtensions.has("GL_CHROMIUM_framebuffer_multisample")) {
    422             if (NULL == fFunctions.fRenderbufferStorageMultisample ||
    423                 NULL == fFunctions.fBlitFramebuffer) {
    424                 RETURN_FALSE_INTERFACE
    425             }
    426         }
    427         if (fExtensions.has("GL_APPLE_framebuffer_multisample")) {
    428             if (NULL == fFunctions.fRenderbufferStorageMultisampleES2APPLE ||
    429                 NULL == fFunctions.fResolveMultisampleFramebuffer) {
    430                 RETURN_FALSE_INTERFACE
    431             }
    432         }
    433         if (fExtensions.has("GL_IMG_multisampled_render_to_texture") ||
    434             fExtensions.has("GL_EXT_multisampled_render_to_texture")) {
    435             if (NULL == fFunctions.fRenderbufferStorageMultisampleES2EXT ||
    436                 NULL == fFunctions.fFramebufferTexture2DMultisample) {
    437                 RETURN_FALSE_INTERFACE
    438             }
    439         }
    440     }
    441 
    442     // On ES buffer mapping is an extension. On Desktop
    443     // buffer mapping was part of original VBO extension
    444     // which we require.
    445     if (kGL_GrGLStandard == fStandard || fExtensions.has("GL_OES_mapbuffer")) {
    446         if (NULL == fFunctions.fMapBuffer ||
    447             NULL == fFunctions.fUnmapBuffer) {
    448             RETURN_FALSE_INTERFACE
    449         }
    450     }
    451 
    452     // Dual source blending
    453     if (kGL_GrGLStandard == fStandard &&
    454         (glVer >= GR_GL_VER(3,3) || fExtensions.has("GL_ARB_blend_func_extended"))) {
    455         if (NULL == fFunctions.fBindFragDataLocationIndexed) {
    456             RETURN_FALSE_INTERFACE
    457         }
    458     }
    459 
    460     // glGetStringi was added in version 3.0 of both desktop and ES.
    461     if (glVer >= GR_GL_VER(3, 0)) {
    462         if (NULL == fFunctions.fGetStringi) {
    463             RETURN_FALSE_INTERFACE
    464         }
    465     }
    466 
    467     if (kGL_GrGLStandard == fStandard) {
    468         if (glVer >= GR_GL_VER(3, 0) || fExtensions.has("GL_ARB_vertex_array_object")) {
    469             if (NULL == fFunctions.fBindVertexArray ||
    470                 NULL == fFunctions.fDeleteVertexArrays ||
    471                 NULL == fFunctions.fGenVertexArrays) {
    472                 RETURN_FALSE_INTERFACE
    473             }
    474         }
    475     } else {
    476         if (glVer >= GR_GL_VER(3,0) || fExtensions.has("GL_OES_vertex_array_object")) {
    477             if (NULL == fFunctions.fBindVertexArray ||
    478                 NULL == fFunctions.fDeleteVertexArrays ||
    479                 NULL == fFunctions.fGenVertexArrays) {
    480                 RETURN_FALSE_INTERFACE
    481             }
    482         }
    483     }
    484 
    485     if (fExtensions.has("GL_EXT_debug_marker")) {
    486         if (NULL == fFunctions.fInsertEventMarker ||
    487             NULL == fFunctions.fPushGroupMarker ||
    488             NULL == fFunctions.fPopGroupMarker) {
    489             RETURN_FALSE_INTERFACE
    490         }
    491     }
    492 
    493     if ((kGL_GrGLStandard == fStandard && glVer >= GR_GL_VER(4,3)) ||
    494         fExtensions.has("GL_ARB_invalidate_subdata")) {
    495         if (NULL == fFunctions.fInvalidateBufferData ||
    496             NULL == fFunctions.fInvalidateBufferSubData ||
    497             NULL == fFunctions.fInvalidateFramebuffer ||
    498             NULL == fFunctions.fInvalidateSubFramebuffer ||
    499             NULL == fFunctions.fInvalidateTexImage ||
    500             NULL == fFunctions.fInvalidateTexSubImage) {
    501             RETURN_FALSE_INTERFACE;
    502         }
    503     } else if (kGLES_GrGLStandard == fStandard && glVer >= GR_GL_VER(3,0)) {
    504         // ES 3.0 adds the framebuffer functions but not the others.
    505         if (NULL == fFunctions.fInvalidateFramebuffer ||
    506             NULL == fFunctions.fInvalidateSubFramebuffer) {
    507             RETURN_FALSE_INTERFACE;
    508         }
    509     }
    510 
    511     if (kGLES_GrGLStandard == fStandard && fExtensions.has("GL_CHROMIUM_map_sub")) {
    512         if (NULL == fFunctions.fMapBufferSubData ||
    513             NULL == fFunctions.fMapTexSubImage2D ||
    514             NULL == fFunctions.fUnmapBufferSubData ||
    515             NULL == fFunctions.fUnmapTexSubImage2D) {
    516             RETURN_FALSE_INTERFACE;
    517         }
    518     }
    519 
    520     // These functions are added to the 3.0 version of both GLES and GL.
    521     if (glVer >= GR_GL_VER(3,0) ||
    522         (kGLES_GrGLStandard == fStandard && fExtensions.has("GL_EXT_map_buffer_range")) ||
    523         (kGL_GrGLStandard == fStandard && fExtensions.has("GL_ARB_map_buffer_range"))) {
    524         if (NULL == fFunctions.fMapBufferRange ||
    525             NULL == fFunctions.fFlushMappedBufferRange) {
    526             RETURN_FALSE_INTERFACE;
    527         }
    528     }
    529     return true;
    530 }
    531