/* Copyright 2010 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include "GrGLConfig.h" #include bool has_gl_extension(const char* ext) { const char* glstr = (const char*) glGetString(GL_EXTENSIONS); int extLength = strlen(ext); while (true) { int n = strcspn(glstr, " "); if (n == extLength && 0 == strncmp(ext, glstr, n)) { return true; } if (0 == glstr[n]) { return false; } glstr += n+1; } } void gl_version(int* major, int* minor) { const char* v = (const char*) glGetString(GL_VERSION); if (NULL == v) { GrAssert(0); *major = 0; *minor = 0; return; } #if GR_SUPPORT_GLDESKTOP int n = sscanf(v, "%d.%d", major, minor); if (n != 2) { GrAssert(0); *major = 0; *minor = 0; return; } #else char profile[2]; int n = sscanf(v, "OpenGL ES-%c%c %d.%d", profile, profile+1, major, minor); bool ok = 4 == n; if (!ok) { int n = sscanf(v, "OpenGL ES %d.%d", major, minor); ok = 2 == n; } if (!ok) { GrAssert(0); *major = 0; *minor = 0; return; } #endif } #if defined(GR_GL_PROC_ADDRESS_HEADER) #include GR_GL_PROC_ADDRESS_HEADER #endif typedef void (*glProc)(void); #define GET_PROC(EXT_STRUCT, PROC_NAME) \ *((glProc*) &(EXT_STRUCT-> PROC_NAME)) = (glProc) GR_GL_PROC_ADDRESS((gl ## PROC_NAME)); \ GrAssert(NULL != EXT_STRUCT-> PROC_NAME) #define GET_SUFFIX_PROC(EXT_STRUCT, PROC_NAME, SUFFIX) \ *((glProc*) &(EXT_STRUCT-> PROC_NAME)) = (glProc) GR_GL_PROC_ADDRESS((gl ## PROC_NAME ## SUFFIX)); \ GrAssert(NULL != EXT_STRUCT-> PROC_NAME) extern void GrGLInitExtensions(GrGLExts* exts) { exts->GenFramebuffers = NULL; exts->BindFramebuffer = NULL; exts->FramebufferTexture2D = NULL; exts->CheckFramebufferStatus = NULL; exts->DeleteFramebuffers = NULL; exts->RenderbufferStorage = NULL; exts->GenRenderbuffers = NULL; exts->DeleteRenderbuffers = NULL; exts->FramebufferRenderbuffer = NULL; exts->BindRenderbuffer = NULL; exts->RenderbufferStorageMultisample = NULL; exts->BlitFramebuffer = NULL; exts->ResolveMultisampleFramebuffer = NULL; exts->FramebufferTexture2DMultisample = NULL; exts->MapBuffer = NULL; exts->UnmapBuffer = NULL; GLint major, minor; gl_version(&major, &minor); bool fboFound = false; #if GR_SUPPORT_GLDESKTOP #if GL_VERSION_3_0 if (!fboFound && major >= 3) { // all of ARB_fbo is in 3.x exts->GenFramebuffers = glGenFramebuffers; exts->BindFramebuffer = glBindFramebuffer; exts->FramebufferTexture2D = glFramebufferTexture2D; exts->CheckFramebufferStatus = glCheckFramebufferStatus; exts->DeleteFramebuffers = glDeleteFramebuffers; exts->RenderbufferStorage = glRenderbufferStorage; exts->GenRenderbuffers = glGenRenderbuffers; exts->DeleteRenderbuffers = glDeleteRenderbuffers; exts->FramebufferRenderbuffer = glFramebufferRenderbuffer; exts->BindRenderbuffer = glBindRenderbuffer; exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample; exts->BlitFramebuffer = glBlitFramebuffer; fboFound = true; } #endif #if GL_ARB_framebuffer_object if (!fboFound && has_gl_extension("GL_ARB_framebuffer_object")) { // GL_ARB_framebuffer_object doesn't use ARB suffix. GET_PROC(exts, GenFramebuffers); GET_PROC(exts, BindFramebuffer); GET_PROC(exts, FramebufferTexture2D); GET_PROC(exts, CheckFramebufferStatus); GET_PROC(exts, DeleteFramebuffers); GET_PROC(exts, RenderbufferStorage); GET_PROC(exts, GenRenderbuffers); GET_PROC(exts, DeleteRenderbuffers); GET_PROC(exts, FramebufferRenderbuffer); GET_PROC(exts, BindRenderbuffer); GET_PROC(exts, RenderbufferStorageMultisample); GET_PROC(exts, BlitFramebuffer); fboFound = true; } #endif // Mac doesn't declare prototypes for EXT FBO extensions #if GL_EXT_framebuffer_object && !GR_MAC_BUILD if (!fboFound && has_gl_extension("GL_EXT_framebuffer_object")) { GET_SUFFIX_PROC(exts, GenFramebuffers, EXT); GET_SUFFIX_PROC(exts, BindFramebuffer, EXT); GET_SUFFIX_PROC(exts, FramebufferTexture2D, EXT); GET_SUFFIX_PROC(exts, CheckFramebufferStatus, EXT); GET_SUFFIX_PROC(exts, DeleteFramebuffers, EXT); GET_SUFFIX_PROC(exts, RenderbufferStorage, EXT); GET_SUFFIX_PROC(exts, GenRenderbuffers, EXT); GET_SUFFIX_PROC(exts, DeleteRenderbuffers, EXT); GET_SUFFIX_PROC(exts, FramebufferRenderbuffer, EXT); GET_SUFFIX_PROC(exts, BindRenderbuffer, EXT); fboFound = true; // check for fbo ms and fbo blit #if GL_EXT_framebuffer_multisample if (has_gl_extension("GL_EXT_framebuffer_multisample")) { GET_SUFFIX_PROC(exts, RenderbufferStorageMultisample, EXT); } #endif #if GL_EXT_framebuffer_blit if (has_gl_extension("GL_EXT_framebuffer_blit")) { GET_SUFFIX_PROC(exts, BlitFramebuffer, EXT); } #endif } #endif if (!fboFound) { // we require some form of FBO GrAssert(!"No FBOs supported?"); } // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5) exts->MapBuffer = glMapBuffer; exts->UnmapBuffer = glUnmapBuffer; #else // !GR_SUPPORT_GLDESKTOP #if GR_SUPPORT_GLES2 if (!fboFound && major >= 2) {// ES 2.0 supports FBO exts->GenFramebuffers = glGenFramebuffers; exts->BindFramebuffer = glBindFramebuffer; exts->FramebufferTexture2D = glFramebufferTexture2D; exts->CheckFramebufferStatus = glCheckFramebufferStatus; exts->DeleteFramebuffers = glDeleteFramebuffers; exts->RenderbufferStorage = glRenderbufferStorage; exts->GenRenderbuffers = glGenRenderbuffers; exts->DeleteRenderbuffers = glDeleteRenderbuffers; exts->FramebufferRenderbuffer = glFramebufferRenderbuffer; exts->BindRenderbuffer = glBindRenderbuffer; fboFound = true; } #endif #if GL_OES_framebuffer_object if (!fboFound && has_gl_extension("GL_OES_framebuffer_object")) { GET_SUFFIX_PROC(exts, GenFramebuffers, OES); GET_SUFFIX_PROC(exts, BindFramebuffer, OES); GET_SUFFIX_PROC(exts, FramebufferTexture2D, OES); GET_SUFFIX_PROC(exts, CheckFramebufferStatus, OES); GET_SUFFIX_PROC(exts, DeleteFramebuffers, OES); GET_SUFFIX_PROC(exts, RenderbufferStorage, OES); GET_SUFFIX_PROC(exts, GenRenderbuffers, OES); GET_SUFFIX_PROC(exts, DeleteRenderbuffers, OES); GET_SUFFIX_PROC(exts, FramebufferRenderbuffer, OES); GET_SUFFIX_PROC(exts, BindRenderbuffer, OES); } #endif if (!fboFound) { // we require some form of FBO GrAssert(!"No FBOs supported?"); } #if GL_APPLE_framebuffer_multisample if (has_gl_extension("GL_APPLE_framebuffer_multisample")) { GET_SUFFIX_PROC(exts, ResolveMultisampleFramebuffer, APPLE); } #endif #if GL_IMG_multisampled_render_to_texture if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) { GET_SUFFIX_PROC(exts, FramebufferTexture2DMultisample, IMG); } #endif #if GL_OES_mapbuffer if (has_gl_extension("GL_OES_mapbuffer")) { GET_SUFFIX_PROC(exts, MapBuffer, OES); GET_SUFFIX_PROC(exts, UnmapBuffer, OES); } #endif #endif // !GR_SUPPORT_GLDESKTOP } /////////////////////////////////////////////////////////////////////////////// void GrGLCheckErr(const char* location, const char* call) { uint32_t err = glGetError(); if (GL_NO_ERROR != err) { GrPrintf("---- glGetError %x", err); if (NULL != location) { GrPrintf(" at\n\t%s", location); } if (NULL != call) { GrPrintf("\n\t\t%s", call); } GrPrintf("\n"); } } /////////////////////////////////////////////////////////////////////////////// bool gPrintGL = true;