/* * Cogl * * An object oriented GL/GLES Abstraction/Utility Layer * * Copyright (C) 2007,2008,2009 Intel Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "cogl.h" #ifdef HAVE_CLUTTER_GLX #include #include typedef CoglFuncPtr (*GLXGetProcAddressProc) (const guint8 *procName); #endif #include "cogl-internal.h" #include "cogl-context.h" CoglFuncPtr cogl_get_proc_address (const gchar* name) { /* Sucks to ifdef here but not other option..? would be nice to * split the code up for more reuse (once more backends use this */ #if defined(HAVE_CLUTTER_GLX) static GLXGetProcAddressProc get_proc_func = NULL; static void *dlhand = NULL; if (get_proc_func == NULL && dlhand == NULL) { dlhand = dlopen (NULL, RTLD_LAZY); if (dlhand) { dlerror (); get_proc_func = (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddress"); if (dlerror () != NULL) { get_proc_func = (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddressARB"); } if (dlerror () != NULL) { get_proc_func = NULL; g_warning ("failed to bind GLXGetProcAddress " "or GLXGetProcAddressARB"); } } } if (get_proc_func) return get_proc_func ((unsigned char*) name); #elif defined(HAVE_CLUTTER_WIN32) return (CoglFuncPtr) wglGetProcAddress ((LPCSTR) name); #else /* HAVE_CLUTTER_WIN32 */ /* this should find the right function if the program is linked against a * library providing it */ static GModule *module = NULL; if (module == NULL) module = g_module_open (NULL, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); if (module) { gpointer symbol; if (g_module_symbol (module, name, &symbol)) return symbol; } #endif /* HAVE_CLUTTER_WIN32 */ return NULL; } gboolean cogl_check_extension (const gchar *name, const gchar *ext) { gchar *end; gint name_len, n; if (name == NULL || ext == NULL) return FALSE; end = (gchar*)(ext + strlen(ext)); name_len = strlen(name); while (ext < end) { n = strcspn(ext, " "); if ((name_len == n) && (!strncmp(name, ext, n))) return TRUE; ext += (n + 1); } return FALSE; } #ifdef HAVE_CLUTTER_OSX static gboolean really_enable_npot (void) { /* OSX backend + ATI Radeon X1600 + NPOT texture + GL_REPEAT seems to crash * http://bugzilla.openedhand.com/show_bug.cgi?id=929 * * Temporary workaround until post 0.8 we rejig the features set up a * little to allow the backend to overide. */ const char *gl_renderer; const char *env_string; /* Regardless of hardware, allow user to decide. */ env_string = g_getenv ("COGL_ENABLE_NPOT"); if (env_string != NULL) return env_string[0] == '1'; gl_renderer = (char*)glGetString (GL_RENDERER); if (strstr (gl_renderer, "ATI Radeon X1600") != NULL) return FALSE; return TRUE; } #endif void _cogl_features_init (void) { CoglFeatureFlags flags = 0; const gchar *gl_extensions; GLint max_clip_planes = 0; GLint num_stencil_bits = 0; _COGL_GET_CONTEXT (ctx, NO_RETVAL); flags = COGL_FEATURE_TEXTURE_READ_PIXELS; gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS); if (cogl_check_extension ("GL_ARB_texture_non_power_of_two", gl_extensions)) { #ifdef HAVE_CLUTTER_OSX if (really_enable_npot ()) #endif flags |= COGL_FEATURE_TEXTURE_NPOT; } #ifdef GL_YCBCR_MESA if (cogl_check_extension ("GL_MESA_ycbcr_texture", gl_extensions)) { flags |= COGL_FEATURE_TEXTURE_YUV; } #endif if (cogl_check_extension ("GL_ARB_shader_objects", gl_extensions) && cogl_check_extension ("GL_ARB_vertex_shader", gl_extensions) && cogl_check_extension ("GL_ARB_fragment_shader", gl_extensions)) { ctx->drv.pf_glCreateProgramObjectARB = (COGL_PFNGLCREATEPROGRAMOBJECTARBPROC) cogl_get_proc_address ("glCreateProgramObjectARB"); ctx->drv.pf_glCreateShaderObjectARB = (COGL_PFNGLCREATESHADEROBJECTARBPROC) cogl_get_proc_address ("glCreateShaderObjectARB"); ctx->drv.pf_glShaderSourceARB = (COGL_PFNGLSHADERSOURCEARBPROC) cogl_get_proc_address ("glShaderSourceARB"); ctx->drv.pf_glCompileShaderARB = (COGL_PFNGLCOMPILESHADERARBPROC) cogl_get_proc_address ("glCompileShaderARB"); ctx->drv.pf_glAttachObjectARB = (COGL_PFNGLATTACHOBJECTARBPROC) cogl_get_proc_address ("glAttachObjectARB"); ctx->drv.pf_glLinkProgramARB = (COGL_PFNGLLINKPROGRAMARBPROC) cogl_get_proc_address ("glLinkProgramARB"); ctx->drv.pf_glUseProgramObjectARB = (COGL_PFNGLUSEPROGRAMOBJECTARBPROC) cogl_get_proc_address ("glUseProgramObjectARB"); ctx->drv.pf_glGetUniformLocationARB = (COGL_PFNGLGETUNIFORMLOCATIONARBPROC) cogl_get_proc_address ("glGetUniformLocationARB"); ctx->drv.pf_glDeleteObjectARB = (COGL_PFNGLDELETEOBJECTARBPROC) cogl_get_proc_address ("glDeleteObjectARB"); ctx->drv.pf_glGetInfoLogARB = (COGL_PFNGLGETINFOLOGARBPROC) cogl_get_proc_address ("glGetInfoLogARB"); ctx->drv.pf_glGetObjectParameterivARB = (COGL_PFNGLGETOBJECTPARAMETERIVARBPROC) cogl_get_proc_address ("glGetObjectParameterivARB"); ctx->drv.pf_glUniform1fARB = (COGL_PFNGLUNIFORM1FARBPROC) cogl_get_proc_address ("glUniform1fARB"); ctx->drv.pf_glVertexAttribPointerARB = (COGL_PFNGLVERTEXATTRIBPOINTERARBPROC) cogl_get_proc_address ("glVertexAttribPointerARB"); ctx->drv.pf_glEnableVertexAttribArrayARB = (COGL_PFNGLENABLEVERTEXATTRIBARRAYARBPROC) cogl_get_proc_address ("glEnableVertexAttribArrayARB"); ctx->drv.pf_glDisableVertexAttribArrayARB = (COGL_PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) cogl_get_proc_address ("glDisableVertexAttribArrayARB"); ctx->drv.pf_glUniform2fARB = (COGL_PFNGLUNIFORM2FARBPROC) cogl_get_proc_address ("glUniform2fARB"); ctx->drv.pf_glUniform3fARB = (COGL_PFNGLUNIFORM3FARBPROC) cogl_get_proc_address ("glUniform3fARB"); ctx->drv.pf_glUniform4fARB = (COGL_PFNGLUNIFORM4FARBPROC) cogl_get_proc_address ("glUniform4fARB"); ctx->drv.pf_glUniform1fvARB = (COGL_PFNGLUNIFORM1FVARBPROC) cogl_get_proc_address ("glUniform1fvARB"); ctx->drv.pf_glUniform2fvARB = (COGL_PFNGLUNIFORM2FVARBPROC) cogl_get_proc_address ("glUniform2fvARB"); ctx->drv.pf_glUniform3fvARB = (COGL_PFNGLUNIFORM3FVARBPROC) cogl_get_proc_address ("glUniform3fvARB"); ctx->drv.pf_glUniform4fvARB = (COGL_PFNGLUNIFORM4FVARBPROC) cogl_get_proc_address ("glUniform4fvARB"); ctx->drv.pf_glUniform1iARB = (COGL_PFNGLUNIFORM1IARBPROC) cogl_get_proc_address ("glUniform1iARB"); ctx->drv.pf_glUniform2iARB = (COGL_PFNGLUNIFORM2IARBPROC) cogl_get_proc_address ("glUniform2iARB"); ctx->drv.pf_glUniform3iARB = (COGL_PFNGLUNIFORM3IARBPROC) cogl_get_proc_address ("glUniform3iARB"); ctx->drv.pf_glUniform4iARB = (COGL_PFNGLUNIFORM4IARBPROC) cogl_get_proc_address ("glUniform4iARB"); ctx->drv.pf_glUniform1ivARB = (COGL_PFNGLUNIFORM1IVARBPROC) cogl_get_proc_address ("glUniform1ivARB"); ctx->drv.pf_glUniform2ivARB = (COGL_PFNGLUNIFORM2IVARBPROC) cogl_get_proc_address ("glUniform2ivARB"); ctx->drv.pf_glUniform3ivARB = (COGL_PFNGLUNIFORM3IVARBPROC) cogl_get_proc_address ("glUniform3ivARB"); ctx->drv.pf_glUniform4ivARB = (COGL_PFNGLUNIFORM4IVARBPROC) cogl_get_proc_address ("glUniform4ivARB"); ctx->drv.pf_glUniformMatrix2fvARB = (COGL_PFNGLUNIFORMMATRIX2FVARBPROC) cogl_get_proc_address ("glUniformMatrix2fvARB"); ctx->drv.pf_glUniformMatrix3fvARB = (COGL_PFNGLUNIFORMMATRIX3FVARBPROC) cogl_get_proc_address ("glUniformMatrix3fvARB"); ctx->drv.pf_glUniformMatrix4fvARB = (COGL_PFNGLUNIFORMMATRIX4FVARBPROC) cogl_get_proc_address ("glUniformMatrix4fvARB"); if (ctx->drv.pf_glCreateProgramObjectARB && ctx->drv.pf_glCreateShaderObjectARB && ctx->drv.pf_glShaderSourceARB && ctx->drv.pf_glCompileShaderARB && ctx->drv.pf_glAttachObjectARB && ctx->drv.pf_glLinkProgramARB && ctx->drv.pf_glUseProgramObjectARB && ctx->drv.pf_glGetUniformLocationARB && ctx->drv.pf_glDeleteObjectARB && ctx->drv.pf_glGetInfoLogARB && ctx->drv.pf_glGetObjectParameterivARB && ctx->drv.pf_glUniform1fARB && ctx->drv.pf_glUniform2fARB && ctx->drv.pf_glUniform3fARB && ctx->drv.pf_glUniform4fARB && ctx->drv.pf_glUniform1fvARB && ctx->drv.pf_glUniform2fvARB && ctx->drv.pf_glUniform3fvARB && ctx->drv.pf_glUniform4fvARB && ctx->drv.pf_glUniform1iARB && ctx->drv.pf_glUniform2iARB && ctx->drv.pf_glUniform3iARB && ctx->drv.pf_glUniform4iARB && ctx->drv.pf_glUniform1ivARB && ctx->drv.pf_glUniform2ivARB && ctx->drv.pf_glUniform3ivARB && ctx->drv.pf_glUniform4ivARB && ctx->drv.pf_glUniformMatrix2fvARB && ctx->drv.pf_glUniformMatrix3fvARB && ctx->drv.pf_glUniformMatrix4fvARB && ctx->drv.pf_glVertexAttribPointerARB && ctx->drv.pf_glEnableVertexAttribArrayARB && ctx->drv.pf_glDisableVertexAttribArrayARB) flags |= COGL_FEATURE_SHADERS_GLSL; } if (cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions) || cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions)) { ctx->drv.pf_glGenRenderbuffersEXT = (COGL_PFNGLGENRENDERBUFFERSEXTPROC) cogl_get_proc_address ("glGenRenderbuffersEXT"); ctx->drv.pf_glDeleteRenderbuffersEXT = (COGL_PFNGLDELETERENDERBUFFERSEXTPROC) cogl_get_proc_address ("glDeleteRenderbuffersEXT"); ctx->drv.pf_glBindRenderbufferEXT = (COGL_PFNGLBINDRENDERBUFFEREXTPROC) cogl_get_proc_address ("glBindRenderbufferEXT"); ctx->drv.pf_glRenderbufferStorageEXT = (COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC) cogl_get_proc_address ("glRenderbufferStorageEXT"); ctx->drv.pf_glGenFramebuffersEXT = (COGL_PFNGLGENFRAMEBUFFERSEXTPROC) cogl_get_proc_address ("glGenFramebuffersEXT"); ctx->drv.pf_glBindFramebufferEXT = (COGL_PFNGLBINDFRAMEBUFFEREXTPROC) cogl_get_proc_address ("glBindFramebufferEXT"); ctx->drv.pf_glFramebufferTexture2DEXT = (COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) cogl_get_proc_address ("glFramebufferTexture2DEXT"); ctx->drv.pf_glFramebufferRenderbufferEXT = (COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) cogl_get_proc_address ("glFramebufferRenderbufferEXT"); ctx->drv.pf_glCheckFramebufferStatusEXT = (COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) cogl_get_proc_address ("glCheckFramebufferStatusEXT"); ctx->drv.pf_glDeleteFramebuffersEXT = (COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) cogl_get_proc_address ("glDeleteFramebuffersEXT"); ctx->drv.pf_glGenerateMipmapEXT = (COGL_PFNGLGENERATEMIPMAPEXTPROC) cogl_get_proc_address ("glGenerateMipmapEXT"); if (ctx->drv.pf_glGenRenderbuffersEXT && ctx->drv.pf_glBindRenderbufferEXT && ctx->drv.pf_glRenderbufferStorageEXT && ctx->drv.pf_glGenFramebuffersEXT && ctx->drv.pf_glBindFramebufferEXT && ctx->drv.pf_glFramebufferTexture2DEXT && ctx->drv.pf_glFramebufferRenderbufferEXT && ctx->drv.pf_glCheckFramebufferStatusEXT && ctx->drv.pf_glDeleteFramebuffersEXT && ctx->drv.pf_glGenerateMipmapEXT) flags |= COGL_FEATURE_OFFSCREEN; } if (cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions)) { ctx->drv.pf_glBlitFramebufferEXT = (COGL_PFNGLBLITFRAMEBUFFEREXTPROC) cogl_get_proc_address ("glBlitFramebufferEXT"); if (ctx->drv.pf_glBlitFramebufferEXT) flags |= COGL_FEATURE_OFFSCREEN_BLIT; } if (cogl_check_extension ("GL_EXT_framebuffer_multisample", gl_extensions)) { ctx->drv.pf_glRenderbufferStorageMultisampleEXT = (COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) cogl_get_proc_address ("glRenderbufferStorageMultisampleEXT"); if (ctx->drv.pf_glRenderbufferStorageMultisampleEXT) flags |= COGL_FEATURE_OFFSCREEN_MULTISAMPLE; } GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) ); /* We need at least three stencil bits to combine clips */ if (num_stencil_bits > 2) flags |= COGL_FEATURE_STENCIL_BUFFER; GE( glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) ); if (max_clip_planes >= 4) flags |= COGL_FEATURE_FOUR_CLIP_PLANES; if (cogl_check_extension ("GL_ARB_vertex_buffer_object", gl_extensions)) { ctx->drv.pf_glGenBuffersARB = (COGL_PFNGLGENBUFFERSARBPROC) cogl_get_proc_address ("glGenBuffersARB"); ctx->drv.pf_glBindBufferARB = (COGL_PFNGLBINDBUFFERARBPROC) cogl_get_proc_address ("glBindBufferARB"); ctx->drv.pf_glBufferDataARB = (COGL_PFNGLBUFFERDATAARBPROC) cogl_get_proc_address ("glBufferDataARB"); ctx->drv.pf_glBufferSubDataARB = (COGL_PFNGLBUFFERSUBDATAARBPROC) cogl_get_proc_address ("glBufferSubDataARB"); ctx->drv.pf_glDeleteBuffersARB = (COGL_PFNGLDELETEBUFFERSARBPROC) cogl_get_proc_address ("glDeleteBuffersARB"); ctx->drv.pf_glMapBufferARB = (COGL_PFNGLMAPBUFFERARBPROC) cogl_get_proc_address ("glMapBufferARB"); ctx->drv.pf_glUnmapBufferARB = (COGL_PFNGLUNMAPBUFFERARBPROC) cogl_get_proc_address ("glUnmapBufferARB"); if (ctx->drv.pf_glGenBuffersARB && ctx->drv.pf_glBindBufferARB && ctx->drv.pf_glBufferDataARB && ctx->drv.pf_glBufferSubDataARB && ctx->drv.pf_glDeleteBuffersARB && ctx->drv.pf_glMapBufferARB && ctx->drv.pf_glUnmapBufferARB) flags |= COGL_FEATURE_VBOS; } /* These should always be available because they are defined in GL 1.2, but we can't call it directly because under Windows functions > 1.1 aren't exported */ ctx->drv.pf_glDrawRangeElements = (COGL_PFNGLDRAWRANGEELEMENTSPROC) cogl_get_proc_address ("glDrawRangeElements"); ctx->drv.pf_glActiveTexture = (COGL_PFNGLACTIVETEXTUREPROC) cogl_get_proc_address ("glActiveTexture"); ctx->drv.pf_glClientActiveTexture = (COGL_PFNGLCLIENTACTIVETEXTUREPROC) cogl_get_proc_address ("glClientActiveTexture"); ctx->drv.pf_glBlendEquation = (COGL_PFNGLBLENDEQUATIONPROC) cogl_get_proc_address ("glBlendEquation"); ctx->drv.pf_glBlendColor = (COGL_PFNGLBLENDCOLORPROC) cogl_get_proc_address ("glBlendColor"); /* Available in 1.4 */ ctx->drv.pf_glBlendFuncSeparate = (COGL_PFNGLBLENDFUNCSEPARATEPROC) cogl_get_proc_address ("glBlendFuncSeparate"); /* Available in 2.0 */ ctx->drv.pf_glBlendEquationSeparate = (COGL_PFNGLBLENDEQUATIONSEPARATEPROC) cogl_get_proc_address ("glBlendEquationSeparate"); /* Cache features */ ctx->feature_flags = flags; ctx->features_cached = TRUE; }