/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrTypes.h" #include "GrGLInterface.h" #include "GrGLDefines.h" #include #if GR_GL_PER_GL_FUNC_CALLBACK namespace { void GrGLDefaultInterfaceCallback(const GrGLInterface*) {} } #endif GrGLVersion GrGLGetVersionFromString(const char* versionString) { if (NULL == versionString) { GrAssert(!"NULL GL version string."); return 0; } int major, minor; int n = sscanf(versionString, "%d.%d", &major, &minor); if (2 == n) { return GR_GL_VER(major, minor); } char profile[2]; n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1, &major, &minor); if (4 == n) { return GR_GL_VER(major, minor); } n = sscanf(versionString, "OpenGL ES %d.%d", &major, &minor); if (2 == n) { return GR_GL_VER(major, minor); } return 0; } GrGLSLVersion GrGLGetGLSLVersionFromString(const char* versionString) { if (NULL == versionString) { GrAssert(!"NULL GLSL version string."); return 0; } int major, minor; int n = sscanf(versionString, "%d.%d", &major, &minor); if (2 == n) { return GR_GLSL_VER(major, minor); } n = sscanf(versionString, "OpenGL ES GLSL ES %d.%d", &major, &minor); if (2 == n) { return GR_GLSL_VER(major, minor); } return 0; } bool GrGLHasExtensionFromString(const char* ext, const char* extensionString) { int extLength = strlen(ext); while (true) { int n = strcspn(extensionString, " "); if (n == extLength && 0 == strncmp(ext, extensionString, n)) { return true; } if (0 == extensionString[n]) { return false; } extensionString += n+1; } return false; } bool GrGLHasExtension(const GrGLInterface* gl, const char* ext) { const GrGLubyte* glstr; GR_GL_CALL_RET(gl, glstr, GetString(GR_GL_EXTENSIONS)); return GrGLHasExtensionFromString(ext, (const char*) glstr); } GrGLVersion GrGLGetVersion(const GrGLInterface* gl) { const GrGLubyte* v; GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION)); return GrGLGetVersionFromString((const char*) v); } GrGLSLVersion GrGLGetGLSLVersion(const GrGLInterface* gl) { const GrGLubyte* v; GR_GL_CALL_RET(gl, v, GetString(GR_GL_SHADING_LANGUAGE_VERSION)); return GrGLGetGLSLVersionFromString((const char*) v); } GrGLInterface::GrGLInterface() { fBindingsExported = (GrGLBinding)0; fActiveTexture = NULL; fAttachShader = NULL; fBeginQuery = NULL; fBindAttribLocation = NULL; fBindBuffer = NULL; fBindFragDataLocation = NULL; fBindTexture = NULL; fBlendColor = NULL; fBlendFunc = NULL; fBufferData = NULL; fBufferSubData = NULL; fClear = NULL; fClearColor = NULL; fClearStencil = NULL; fColorMask = NULL; fColorPointer = NULL; fCompileShader = NULL; fCompressedTexImage2D = NULL; fCreateProgram = NULL; fCreateShader = NULL; fCullFace = NULL; fDeleteBuffers = NULL; fDeleteProgram = NULL; fDeleteQueries = NULL; fDeleteShader = NULL; fDeleteTextures = NULL; fDepthMask = NULL; fDisable = NULL; fDisableVertexAttribArray = NULL; fDrawArrays = NULL; fDrawBuffer = NULL; fDrawBuffers = NULL; fDrawElements = NULL; fEndQuery = NULL; fFinish = NULL; fFlush = NULL; fEnable = NULL; fEnableVertexAttribArray = NULL; fFrontFace = NULL; fGenBuffers = NULL; fGenQueries = NULL; fGenTextures = NULL; fGetBufferParameteriv = NULL; fGetError = NULL; fGetIntegerv = NULL; fGetQueryiv = NULL; fGetQueryObjecti64v = NULL; fGetQueryObjectiv = NULL; fGetQueryObjectui64v = NULL; fGetQueryObjectuiv = NULL; fGetProgramInfoLog = NULL; fGetProgramiv = NULL; fGetShaderInfoLog = NULL; fGetShaderiv = NULL; fGetString = NULL; fGetTexLevelParameteriv = NULL; fGetUniformLocation = NULL; fLineWidth = NULL; fLinkProgram = NULL; fPixelStorei = NULL; fQueryCounter = NULL; fReadBuffer = NULL; fReadPixels = NULL; fScissor = NULL; fShaderSource = NULL; fStencilFunc = NULL; fStencilFuncSeparate = NULL; fStencilMask = NULL; fStencilMaskSeparate = NULL; fStencilOp = NULL; fStencilOpSeparate = NULL; fTexImage2D = NULL; fTexParameteri = NULL; fTexSubImage2D = NULL; fUniform1f = NULL; fUniform1i = NULL; fUniform1fv = NULL; fUniform1iv = NULL; fUniform2f = NULL; fUniform2i = NULL; fUniform2fv = NULL; fUniform2iv = NULL; fUniform3f = NULL; fUniform3i = NULL; fUniform3fv = NULL; fUniform3iv = NULL; fUniform4f = NULL; fUniform4i = NULL; fUniform4fv = NULL; fUniform4iv = NULL; fUniformMatrix2fv = NULL; fUniformMatrix3fv = NULL; fUniformMatrix4fv = NULL; fUseProgram = NULL; fVertexAttrib4fv = NULL; fVertexAttribPointer = NULL; fViewport = NULL; fBindFramebuffer = NULL; fBindRenderbuffer = NULL; fCheckFramebufferStatus = NULL; fDeleteFramebuffers = NULL; fDeleteRenderbuffers = NULL; fFramebufferRenderbuffer = NULL; fFramebufferTexture2D = NULL; fGenFramebuffers = NULL; fGenRenderbuffers = NULL; fGetFramebufferAttachmentParameteriv = NULL; fGetRenderbufferParameteriv = NULL; fRenderbufferStorage = NULL; fRenderbufferStorageMultisample = NULL; fBlitFramebuffer = NULL; fResolveMultisampleFramebuffer = NULL; fMapBuffer = NULL; fUnmapBuffer = NULL; fBindFragDataLocationIndexed = NULL; #if GR_GL_PER_GL_FUNC_CALLBACK fCallback = GrGLDefaultInterfaceCallback; fCallbackData = 0; #endif } bool GrGLInterface::validate() const { bool isDesktop = this->supportsDesktop(); bool isES2 = this->supportsES2(); if (isDesktop == isES2) { // must have one, don't support both in same interface return false; } // functions that are always required if (NULL == fActiveTexture || NULL == fAttachShader || NULL == fBindAttribLocation || NULL == fBindBuffer || NULL == fBindTexture || NULL == fBlendFunc || NULL == fBufferData || NULL == fBufferSubData || NULL == fClear || NULL == fClearColor || NULL == fClearStencil || NULL == fColorMask || NULL == fCompileShader || NULL == fCreateProgram || NULL == fCreateShader || NULL == fCullFace || NULL == fDeleteBuffers || NULL == fDeleteProgram || NULL == fDeleteShader || NULL == fDeleteTextures || NULL == fDepthMask || NULL == fDisable || NULL == fDisableVertexAttribArray || NULL == fDrawArrays || NULL == fDrawElements || NULL == fEnable || NULL == fEnableVertexAttribArray || NULL == fFrontFace || NULL == fGenBuffers || NULL == fGenTextures || NULL == fGetBufferParameteriv || NULL == fGetError || NULL == fGetIntegerv || NULL == fGetProgramInfoLog || NULL == fGetProgramiv || NULL == fGetShaderInfoLog || NULL == fGetShaderiv || NULL == fGetString || NULL == fGetUniformLocation || NULL == fLinkProgram || NULL == fPixelStorei || NULL == fReadPixels || NULL == fScissor || NULL == fShaderSource || NULL == fStencilFunc || NULL == fStencilMask || NULL == fStencilOp || NULL == fTexImage2D || NULL == fTexParameteri || NULL == fTexSubImage2D || NULL == fUniform1f || NULL == fUniform1i || NULL == fUniform1fv || NULL == fUniform1iv || NULL == fUniform2f || NULL == fUniform2i || NULL == fUniform2fv || NULL == fUniform2iv || NULL == fUniform3f || NULL == fUniform3i || NULL == fUniform3fv || NULL == fUniform3iv || NULL == fUniform4f || NULL == fUniform4i || NULL == fUniform4fv || NULL == fUniform4iv || NULL == fUniformMatrix2fv || NULL == fUniformMatrix3fv || NULL == fUniformMatrix4fv || NULL == fUseProgram || NULL == fVertexAttrib4fv || NULL == fVertexAttribPointer || NULL == fViewport || NULL == fBindFramebuffer || NULL == fBindRenderbuffer || NULL == fCheckFramebufferStatus || NULL == fDeleteFramebuffers || NULL == fDeleteRenderbuffers || NULL == fFinish || NULL == fFlush || NULL == fFramebufferRenderbuffer || NULL == fFramebufferTexture2D || NULL == fGetFramebufferAttachmentParameteriv || NULL == fGetRenderbufferParameteriv || NULL == fGenFramebuffers || NULL == fGenRenderbuffers || NULL == fRenderbufferStorage) { return false; } const char* ext; GrGLVersion glVer = GrGLGetVersion(this); ext = (const char*)fGetString(GR_GL_EXTENSIONS); // Now check that baseline ES/Desktop fns not covered above are present // and that we have fn pointers for any advertised extensions that we will // try to use. // these functions are part of ES2, we assume they are available // On the desktop we assume they are available if the extension // is present or GL version is high enough. if ((kES2_GrGLBinding & fBindingsExported)) { if (NULL == fBlendColor || NULL == fStencilFuncSeparate || NULL == fStencilMaskSeparate || NULL == fStencilOpSeparate) { return false; } } else if (kDesktop_GrGLBinding == fBindingsExported) { if (glVer >= GR_GL_VER(2,0)) { if (NULL == fStencilFuncSeparate || NULL == fStencilMaskSeparate || NULL == fStencilOpSeparate) { return false; } } if (glVer >= GR_GL_VER(3,0) && NULL == fBindFragDataLocation) { return false; } if (glVer >= GR_GL_VER(2,0) || GrGLHasExtensionFromString("GL_ARB_draw_buffers", ext)) { if (NULL == fDrawBuffers) { return false; } } if (glVer >= GR_GL_VER(1,4) || GrGLHasExtensionFromString("GL_EXT_blend_color", ext)) { if (NULL == fBlendColor) { return false; } } if (glVer >= GR_GL_VER(1,5) || GrGLHasExtensionFromString("GL_ARB_occlusion_query", ext)) { if (NULL == fGenQueries || NULL == fDeleteQueries || NULL == fBeginQuery || NULL == fEndQuery || NULL == fGetQueryiv || NULL == fGetQueryObjectiv || NULL == fGetQueryObjectuiv) { return false; } } if (glVer >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_timer_query", ext) || GrGLHasExtensionFromString("GL_EXT_timer_query", ext)) { if (NULL == fGetQueryObjecti64v || NULL == fGetQueryObjectui64v) { return false; } } if (glVer >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_timer_query", ext)) { if (NULL == fQueryCounter) { return false; } } } // optional function on desktop before 1.3 if (kDesktop_GrGLBinding != fBindingsExported || (glVer >= GR_GL_VER(1,3) || GrGLHasExtensionFromString("GL_ARB_texture_compression", ext))) { if (NULL == fCompressedTexImage2D) { return false; } } // part of desktop GL, but not ES if (kDesktop_GrGLBinding == fBindingsExported && (NULL == fLineWidth || NULL == fGetTexLevelParameteriv || NULL == fDrawBuffer || NULL == fReadBuffer)) { return false; } // FBO MSAA if (kDesktop_GrGLBinding == fBindingsExported) { // GL 3.0 and the ARB extension have multisample + blit if (glVer >= GR_GL_VER(3,0) || GrGLHasExtensionFromString("GL_ARB_framebuffer_object", ext)) { if (NULL == fRenderbufferStorageMultisample || NULL == fBlitFramebuffer) { return false; } } else { if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit", ext) && NULL == fBlitFramebuffer) { return false; } if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", ext) && NULL == fRenderbufferStorageMultisample) { return false; } } } else { if (GrGLHasExtensionFromString("GL_CHROMIUM_framebuffer_multisample", ext)) { if (NULL == fRenderbufferStorageMultisample || NULL == fBlitFramebuffer) { return false; } } if (GrGLHasExtensionFromString("GL_APPLE_framebuffer_multisample", ext)) { if (NULL == fRenderbufferStorageMultisample || NULL == fResolveMultisampleFramebuffer) { return false; } } } // On ES buffer mapping is an extension. On Desktop // buffer mapping was part of original VBO extension // which we require. if (kDesktop_GrGLBinding == fBindingsExported || GrGLHasExtensionFromString("GL_OES_mapbuffer", ext)) { if (NULL == fMapBuffer || NULL == fUnmapBuffer) { return false; } } // Dual source blending if (kDesktop_GrGLBinding == fBindingsExported && (glVer >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_blend_func_extended", ext))) { if (NULL == fBindFragDataLocationIndexed) { return false; } } return true; }