nkeynes@635: /** nkeynes@636: * $Id$ nkeynes@635: * nkeynes@635: * GL-based support functions nkeynes@635: * nkeynes@635: * Copyright (c) 2005 Nathan Keynes. nkeynes@635: * nkeynes@635: * This program is free software; you can redistribute it and/or modify nkeynes@635: * it under the terms of the GNU General Public License as published by nkeynes@635: * the Free Software Foundation; either version 2 of the License, or nkeynes@635: * (at your option) any later version. nkeynes@635: * nkeynes@635: * This program is distributed in the hope that it will be useful, nkeynes@635: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@635: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@635: * GNU General Public License for more details. nkeynes@635: */ nkeynes@736: nkeynes@645: #include nkeynes@1129: #include nkeynes@687: #include nkeynes@635: #include "pvr2/glutil.h" nkeynes@635: nkeynes@1258: gboolean isOpenGLES2() nkeynes@1258: { nkeynes@1258: const char *str = glGetString(GL_VERSION); nkeynes@1258: if( strncmp(str, "OpenGL ES 2.", 12) == 0 ) { nkeynes@1258: return TRUE; nkeynes@1258: } nkeynes@1276: return FALSE; nkeynes@1258: } nkeynes@1258: nkeynes@667: gboolean isGLSecondaryColorSupported() nkeynes@667: { nkeynes@736: return isGLExtensionSupported("GL_EXT_secondary_color"); nkeynes@667: } nkeynes@667: nkeynes@667: gboolean isGLVertexBufferSupported() nkeynes@667: { nkeynes@736: return isGLExtensionSupported("GL_ARB_vertex_buffer_object"); nkeynes@667: } nkeynes@667: nkeynes@667: gboolean isGLPixelBufferSupported() nkeynes@667: { nkeynes@736: return isGLExtensionSupported("GL_ARB_pixel_buffer_object"); nkeynes@667: } nkeynes@667: nkeynes@667: gboolean isGLMirroredTextureSupported() nkeynes@667: { nkeynes@736: return isGLExtensionSupported("GL_ARB_texture_mirrored_repeat"); nkeynes@667: } nkeynes@667: nkeynes@1275: gboolean isGLBGRATextureSupported() nkeynes@1275: { nkeynes@1275: /* Note: e.g. Tegra 3 reports GL_EXT_bgra, but it doesn't actually work. nkeynes@1275: * Need to check this with NVIDIA, in meantime assume GLES2 doesn't have nkeynes@1275: * BGRA support */ nkeynes@1275: return !isOpenGLES2() && isGLExtensionSupported("GL_EXT_bgra"); nkeynes@1275: } nkeynes@1275: nkeynes@1258: nkeynes@1258: gboolean isGLShaderSupported() nkeynes@1245: { nkeynes@1258: return isOpenGLES2() || (isGLExtensionSupported("GL_ARB_fragment_shader") && nkeynes@1258: isGLExtensionSupported("GL_ARB_vertex_shader") && nkeynes@1258: isGLExtensionSupported("GL_ARB_shading_language_100")); nkeynes@1245: } nkeynes@1245: nkeynes@1140: /** nkeynes@1140: * Check if there's at least 2 texture units nkeynes@1140: */ nkeynes@1140: gboolean isGLMultitextureSupported() nkeynes@1140: { nkeynes@1248: if( !isOpenGLES2() && !isGLExtensionSupported("GL_ARB_multitexture") ) nkeynes@1140: return FALSE; nkeynes@1140: int units = 0; nkeynes@1219: nkeynes@1219: #if defined(GL_MAX_TEXTURE_UNITS) nkeynes@1219: glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units); nkeynes@1219: #elif defined(GL_MAX_TEXTURE_IMAGE_UNITS) nkeynes@1219: glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &units); nkeynes@1219: #endif nkeynes@1140: return units >= 2; nkeynes@1140: } nkeynes@1140: nkeynes@1134: gboolean isGLVertexRangeSupported() nkeynes@1134: { nkeynes@1134: return isGLExtensionSupported("GL_APPLE_vertex_array_range") || nkeynes@1134: isGLExtensionSupported("GL_NV_vertex_array_range"); nkeynes@1134: } nkeynes@1134: nkeynes@635: /** nkeynes@635: * Test if a specific extension is supported. From opengl.org nkeynes@635: * @param extension extension name to check for nkeynes@635: * @return TRUE if supported, otherwise FALSE. nkeynes@635: */ nkeynes@635: gboolean isGLExtensionSupported( const char *extension ) nkeynes@635: { nkeynes@635: const GLubyte *extensions = NULL; nkeynes@635: const GLubyte *start; nkeynes@635: GLubyte *where, *terminator; nkeynes@635: nkeynes@635: /* Extension names should not have spaces. */ nkeynes@635: where = (GLubyte *) strchr(extension, ' '); nkeynes@635: if (where || *extension == '\0') nkeynes@736: return 0; nkeynes@635: extensions = glGetString(GL_EXTENSIONS); nkeynes@645: if( extensions == NULL ) { nkeynes@736: /* No GL available, so we're pretty sure the extension isn't nkeynes@736: * available either. */ nkeynes@736: return FALSE; nkeynes@645: } nkeynes@635: /* It takes a bit of care to be fool-proof about parsing the nkeynes@635: OpenGL extensions string. Don't be fooled by sub-strings, nkeynes@635: etc. */ nkeynes@635: start = extensions; nkeynes@635: for (;;) { nkeynes@736: where = (GLubyte *) strstr((const char *) start, extension); nkeynes@736: if (!where) nkeynes@736: break; nkeynes@736: terminator = where + strlen(extension); nkeynes@736: if (where == start || *(where - 1) == ' ') nkeynes@736: if (*terminator == ' ' || *terminator == '\0') nkeynes@736: return TRUE; nkeynes@736: start = terminator; nkeynes@635: } nkeynes@635: return FALSE; nkeynes@635: } nkeynes@687: nkeynes@1129: int compare_charp( const void *a, const void *b ) nkeynes@1129: { nkeynes@1129: const char **ca = (const char **)a; nkeynes@1129: const char **cb = (const char **)b; nkeynes@1129: return strcmp(*ca, *cb); nkeynes@1129: } nkeynes@1129: nkeynes@1134: #define DEFAULT_TERMINAL_COLUMNS 80 nkeynes@1134: #define DEFAULT_COLUMN_WIDTH 34 nkeynes@1134: nkeynes@1223: int glGetMaxColourAttachments() nkeynes@1223: { nkeynes@1223: #ifdef GL_MAX_COLOR_ATTACHMENTS nkeynes@1223: GLint result = 0; nkeynes@1223: glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &result); nkeynes@1223: return result; nkeynes@1223: #else nkeynes@1223: return 1; nkeynes@1223: #endif nkeynes@1223: } nkeynes@1223: nkeynes@1223: nkeynes@1134: /** nkeynes@1236: * Define an orthographic projection matrix nkeynes@1236: * Note: row-major order nkeynes@1236: */ nkeynes@1236: void defineOrthoMatrix( GLfloat *matrix, GLfloat width, GLfloat height, GLfloat znear, GLfloat zfar ) nkeynes@1236: { nkeynes@1236: matrix[0] = 2/width; nkeynes@1236: matrix[1] = 0; nkeynes@1236: matrix[2] = 0; nkeynes@1236: matrix[3] = 0; nkeynes@1236: nkeynes@1236: matrix[4] = 0; nkeynes@1236: matrix[5] = -2/height; nkeynes@1236: matrix[6] = 0; nkeynes@1236: matrix[7] = 0; nkeynes@1236: nkeynes@1236: matrix[8] = 0; nkeynes@1236: matrix[9] = 0; nkeynes@1236: matrix[10]= -2/(zfar-znear); nkeynes@1236: matrix[11]= 0; nkeynes@1236: nkeynes@1236: matrix[12]= -1; nkeynes@1236: matrix[13]= 1; nkeynes@1236: matrix[14]= -(zfar+znear)/(zfar-znear); nkeynes@1236: matrix[15]= 1; nkeynes@1236: } nkeynes@1236: nkeynes@1236: /** nkeynes@1134: * Format a GL extension list (or other space-separated string) nicely, and nkeynes@1134: * print to the given output stream. nkeynes@1134: */ nkeynes@1134: nkeynes@1134: void fprint_extensions( FILE *out, const char *extensions ) nkeynes@687: { nkeynes@1134: unsigned int i, j, count, maxlen = DEFAULT_COLUMN_WIDTH, columns, per_column, terminal_columns; nkeynes@1134: const char *terminal_columns_str = getenv("COLUMNS"); nkeynes@1134: if( terminal_columns_str == NULL || (terminal_columns = strtol(terminal_columns_str,0,10)) == 0 ) nkeynes@1134: terminal_columns = DEFAULT_TERMINAL_COLUMNS; nkeynes@1129: nkeynes@1134: if( extensions == NULL || extensions[0] == '\0' ) nkeynes@1134: return; nkeynes@1134: nkeynes@1134: gchar *ext_dup = g_strdup(extensions); nkeynes@1134: gchar **ext_split = g_strsplit(g_strstrip(extensions), " ", 0); nkeynes@1134: for( count = 0; ext_split[count] != NULL; count++ ) { nkeynes@1134: unsigned len = strlen(ext_split[count]); nkeynes@1134: if( len > maxlen ) nkeynes@1134: maxlen = len; nkeynes@1134: } nkeynes@1134: nkeynes@1134: columns = terminal_columns / (maxlen+2); nkeynes@1134: if( columns == 0 ) nkeynes@1134: columns = 1; nkeynes@1134: per_column = (count+columns-1) / columns; nkeynes@1129: nkeynes@1129: qsort(ext_split, count, sizeof(gchar *), compare_charp); nkeynes@736: nkeynes@1134: for( i=0; iprint_info ) { nkeynes@1134: fprintf( out, "\n"); nkeynes@1134: display_driver->print_info(out); nkeynes@687: } nkeynes@687: } nkeynes@1150: nkeynes@1150: gboolean gl_check_error(const char *context) nkeynes@1150: { nkeynes@1150: GLint err = glGetError(); nkeynes@1150: if( err != 0 ) { nkeynes@1150: const char *s; nkeynes@1150: switch( err ) { nkeynes@1150: case GL_INVALID_ENUM: s = "Invalid enum"; break; nkeynes@1150: case GL_INVALID_VALUE: s = "Invalid value"; break; nkeynes@1150: case GL_INVALID_OPERATION: s = "Invalid operation"; break; nkeynes@1219: #ifdef GL_STACK_OVERFLOW nkeynes@1150: case GL_STACK_OVERFLOW: s = "Stack overflow"; break; nkeynes@1220: #endif nkeynes@1220: #ifdef GL_STACK_UNDERFLOW nkeynes@1150: case GL_STACK_UNDERFLOW: s = "Stack underflow"; break; nkeynes@1220: #endif nkeynes@1150: case GL_OUT_OF_MEMORY: s = "Out of memory"; break; nkeynes@1150: default: s = "Unknown error"; break; nkeynes@1150: } nkeynes@1150: if( context ) { nkeynes@1150: WARN( "%s: GL error: %x (%s)\n", context, err, s ); nkeynes@1150: } else { nkeynes@1150: WARN( "GL error: %x (%s)\n", err, s ); nkeynes@1150: } nkeynes@1159: return FALSE; nkeynes@1150: } nkeynes@1159: return TRUE; nkeynes@1150: }