/* | |
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 "GrTypes.h" | |
#include <stdio.h> | |
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) \ | |
*(GrTCast<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) \ | |
*(GrTCast<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 defined(GL_VERSION_3_0) && 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; | |