180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/* 280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2011 Google Inc. 380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be 580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file. 680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "gl/GrGLInterface.h" 10096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "gl/GrGLExtensions.h" 11096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "gl/GrGLUtil.h" 1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <stdio.h> 1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if GR_GL_PER_GL_FUNC_CALLBACK 1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace { 1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid GrGLDefaultInterfaceCallback(const GrGLInterface*) {} 1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruGrGLInterface::GrGLInterface() { 2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fBindingsExported = kNone_GrGLBinding; 2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if GR_GL_PER_GL_FUNC_CALLBACK 2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fCallback = GrGLDefaultInterfaceCallback; 2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fCallbackData = 0; 2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool GrGLInterface::validate(GrGLBinding binding) const { 3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // kNone must be 0 so that the check we're about to do can never succeed if 3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // binding == kNone. 3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GR_STATIC_ASSERT(kNone_GrGLBinding == 0); 3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (0 == (binding & fBindingsExported)) { 3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 40096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger GrGLExtensions extensions; 41096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (!extensions.init(binding, this)) { 42096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return false; 43096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 44096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // functions that are always required 4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fActiveTexture || 4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fAttachShader || 4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBindAttribLocation || 4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBindBuffer || 5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBindTexture || 5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBlendFunc || 5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBlendColor || // -> GL >= 1.4, ES >= 2.0 or extension 5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBufferData || 5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBufferSubData || 5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fClear || 5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fClearColor || 5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fClearStencil || 5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fColorMask || 5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCompileShader || 607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger NULL == fCopyTexSubImage2D || 6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCreateProgram || 6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCreateShader || 6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCullFace || 6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDeleteBuffers || 6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDeleteProgram || 6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDeleteShader || 6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDeleteTextures || 6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDepthMask || 6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDisable || 7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDisableVertexAttribArray || 7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDrawArrays || 7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDrawElements || 7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fEnable || 7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fEnableVertexAttribArray || 7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fFrontFace || 7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGenBuffers || 7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGenTextures || 7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetBufferParameteriv || 79e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger NULL == fGenerateMipmap || 8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetError || 8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetIntegerv || 8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetProgramInfoLog || 8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetProgramiv || 8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetShaderInfoLog || 8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetShaderiv || 8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetString || 8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetUniformLocation || 8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fLinkProgram || 890a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fLineWidth || 9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPixelStorei || 9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fReadPixels || 9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fScissor || 9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fShaderSource || 9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilFunc || 9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilMask || 9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilOp || 9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fTexImage2D || 9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fTexParameteri || 9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fTexParameteriv || 10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fTexSubImage2D || 10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform1f || 10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform1i || 10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform1fv || 10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform1iv || 10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform2f || 10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform2i || 10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform2fv || 10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform2iv || 10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform3f || 11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform3i || 11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform3fv || 11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform3iv || 11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform4f || 11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform4i || 11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform4fv || 11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniform4iv || 11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniformMatrix2fv || 11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniformMatrix3fv || 11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUniformMatrix4fv || 12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUseProgram || 12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fVertexAttrib4fv || 12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fVertexAttribPointer || 12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fViewport || 12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBindFramebuffer || 12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBindRenderbuffer || 12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCheckFramebufferStatus || 12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDeleteFramebuffers || 12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDeleteRenderbuffers || 12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fFinish || 13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fFlush || 13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fFramebufferRenderbuffer || 13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fFramebufferTexture2D || 13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetFramebufferAttachmentParameteriv || 13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetRenderbufferParameteriv || 13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGenFramebuffers || 13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGenRenderbuffers || 13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fRenderbufferStorage) { 13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru GrGLVersion glVer = GrGLGetVersion(this); 14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1430a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger bool isCoreProfile = false; 1440a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (kDesktop_GrGLBinding == binding && glVer >= GR_GL_VER(3,2)) { 1450a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger GrGLint profileMask; 1460a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger GR_GL_GetIntegerv(this, GR_GL_CONTEXT_PROFILE_MASK, &profileMask); 1470a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger isCoreProfile = SkToBool(profileMask & GR_GL_CONTEXT_CORE_PROFILE_BIT); 1480a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } 1490a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger 15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Now check that baseline ES/Desktop fns not covered above are present 15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // and that we have fn pointers for any advertised extensions that we will 15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // try to use. 15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // these functions are part of ES2, we assume they are available 15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // On the desktop we assume they are available if the extension 15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // is present or GL version is high enough. 1570a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (kES_GrGLBinding == binding) { 15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fStencilFuncSeparate || 15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilMaskSeparate || 16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilOpSeparate) { 16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (kDesktop_GrGLBinding == binding) { 16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (glVer >= GR_GL_VER(2,0)) { 16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fStencilFuncSeparate || 16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilMaskSeparate || 16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilOpSeparate) { 16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (glVer >= GR_GL_VER(3,0) && NULL == fBindFragDataLocation) { 17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 175096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (glVer >= GR_GL_VER(2,0) || extensions.has("GL_ARB_draw_buffers")) { 17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fDrawBuffers) { 17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 181096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (glVer >= GR_GL_VER(1,5) || extensions.has("GL_ARB_occlusion_query")) { 18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fGenQueries || 18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDeleteQueries || 18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBeginQuery || 18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fEndQuery || 18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetQueryiv || 18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetQueryObjectiv || 18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetQueryObjectuiv) { 18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (glVer >= GR_GL_VER(3,3) || 193096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger extensions.has("GL_ARB_timer_query") || 194096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger extensions.has("GL_EXT_timer_query")) { 19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fGetQueryObjecti64v || 19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetQueryObjectui64v) { 19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 200096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) { 20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fQueryCounter) { 20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 2050a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (!isCoreProfile) { 2060a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (NULL == fClientActiveTexture || 2070a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fDisableClientState || 2080a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fEnableClientState || 2090a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fLoadIdentity || 2100a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fLoadMatrixf || 2110a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fMatrixMode || 2120a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fTexGenf || 2130a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fTexGenfv || 2140a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fTexGeni || 2150a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fVertexPointer) { 2160a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger return false; 2170a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } 21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 219096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (false && extensions.has("GL_NV_path_rendering")) { 22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fPathCommands || 22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathCoords || 22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathSubCommands || 22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathSubCoords || 22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathString || 22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathGlyphs || 22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathGlyphRange || 22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fWeightPaths || 22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCopyPath || 22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fInterpolatePaths || 23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fTransformPath || 23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathParameteriv || 23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathParameteri || 23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathParameterfv || 23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathParameterf || 23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathDashArray || 23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGenPaths || 23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDeletePaths || 23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fIsPath || 23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathStencilFunc || 24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathStencilDepthOffset || 24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilFillPath || 24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilStrokePath || 24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilFillPathInstanced || 24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fStencilStrokePathInstanced || 24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathCoverDepthFunc || 24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathColorGen || 24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathTexGen || 24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPathFogGen || 24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCoverFillPath || 25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCoverStrokePath || 25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCoverFillPathInstanced || 25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fCoverStrokePathInstanced || 25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathParameteriv || 25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathParameterfv || 25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathCommands || 25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathCoords || 25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathDashArray || 25880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathMetrics || 25980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathMetricRange || 26080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathSpacing || 26180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathColorGeniv || 26280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathColorGenfv || 26380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathTexGeniv || 26480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathTexGenfv || 26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fIsPointInFillPath || 26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fIsPointInStrokePath || 26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fGetPathLength || 26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fPointAlongPath) { 26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // optional function on desktop before 1.3 27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (kDesktop_GrGLBinding != binding || 276096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger (glVer >= GR_GL_VER(1,3)) || 277096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger extensions.has("GL_ARB_texture_compression")) { 27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fCompressedTexImage2D) { 27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // part of desktop GL, but not ES 28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (kDesktop_GrGLBinding == binding && 2850a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger (NULL == fGetTexLevelParameteriv || 28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fDrawBuffer || 28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fReadBuffer)) { 28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 28980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 29180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // GL_EXT_texture_storage is part of desktop 4.2 29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // There is a desktop ARB extension and an ES+desktop EXT extension 29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (kDesktop_GrGLBinding == binding) { 29480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (glVer >= GR_GL_VER(4,2) || 295096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger extensions.has("GL_ARB_texture_storage") || 296096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger extensions.has("GL_EXT_texture_storage")) { 29780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fTexStorage2D) { 29880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 29980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 30080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 3010a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } else if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_EXT_texture_storage")) { 30280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fTexStorage2D) { 30380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 30480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 30680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3077839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger if (extensions.has("GL_EXT_discard_framebuffer")) { 3087839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger// FIXME: Remove this once Chromium is updated to provide this function 3097839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#if 0 3107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger if (NULL == fDiscardFramebuffer) { 3117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger return false; 3127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger } 3137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#endif 3147839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger } 3157839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger 31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // FBO MSAA 31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (kDesktop_GrGLBinding == binding) { 31880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // GL 3.0 and the ARB extension have multisample + blit 319096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) { 32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fRenderbufferStorageMultisample || 32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBlitFramebuffer) { 32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 325096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (extensions.has("GL_EXT_framebuffer_blit") && 32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBlitFramebuffer) { 32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 329096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (extensions.has("GL_EXT_framebuffer_multisample") && 33080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fRenderbufferStorageMultisample) { 33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 3350a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger#if GR_GL_IGNORE_ES3_MSAA 336096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (extensions.has("GL_CHROMIUM_framebuffer_multisample")) { 33780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fRenderbufferStorageMultisample || 33880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fBlitFramebuffer) { 33980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 34080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 3410a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } else if (extensions.has("GL_APPLE_framebuffer_multisample")) { 3420a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (NULL == fRenderbufferStorageMultisample || 3430a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fResolveMultisampleFramebuffer) { 3440a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger return false; 3450a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } 3460a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } else if (extensions.has("GL_IMG_multisampled_render_to_texture") || 3470a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger extensions.has("GL_EXT_multisampled_render_to_texture")) { 3480a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (NULL == fRenderbufferStorageMultisample || 3490a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fFramebufferTexture2DMultisample) { 3500a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger return false; 3510a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } 35280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 3530a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger#else 3540a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_CHROMIUM_framebuffer_multisample")) { 35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fRenderbufferStorageMultisample || 3560a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger NULL == fBlitFramebuffer) { 3570a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger return false; 3580a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } 3590a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger } 3600a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (extensions.has("GL_APPLE_framebuffer_multisample")) { 3610a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (NULL == fRenderbufferStorageMultisampleES2APPLE || 36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fResolveMultisampleFramebuffer) { 36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 3667839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger if (extensions.has("GL_IMG_multisampled_render_to_texture") || 3677839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger extensions.has("GL_EXT_multisampled_render_to_texture")) { 3680a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (NULL == fRenderbufferStorageMultisampleES2EXT || 369096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger NULL == fFramebufferTexture2DMultisample) { 370096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return false; 371096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 372096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 3730a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger#endif 37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 37680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // On ES buffer mapping is an extension. On Desktop 37780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // buffer mapping was part of original VBO extension 37880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // which we require. 379096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (kDesktop_GrGLBinding == binding || extensions.has("GL_OES_mapbuffer")) { 38080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fMapBuffer || 38180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NULL == fUnmapBuffer) { 38280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 38380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 38480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 38580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 38680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Dual source blending 38780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (kDesktop_GrGLBinding == binding && 388096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_blend_func_extended"))) { 38980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (NULL == fBindFragDataLocationIndexed) { 39080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 39180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 39280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 39380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3940a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger // glGetStringi was added in version 3.0 of both desktop and ES. 3950a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (glVer >= GR_GL_VER(3, 0)) { 396096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (NULL == fGetStringi) { 397096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return false; 398096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 399096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 400096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 401096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (kDesktop_GrGLBinding == binding) { 402096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (glVer >= GR_GL_VER(3, 0) || extensions.has("GL_ARB_vertex_array_object")) { 403096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (NULL == fBindVertexArray || 404096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger NULL == fDeleteVertexArrays || 405096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger NULL == fGenVertexArrays) { 406096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return false; 407096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 408096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 409096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } else { 4100a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_OES_vertex_array_object")) { 411096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger if (NULL == fBindVertexArray || 412096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger NULL == fDeleteVertexArrays || 413096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger NULL == fGenVertexArrays) { 414096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger return false; 415096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 416096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 417096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger } 418096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger 41980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return true; 42080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 421