Search
lxdream.org :: lxdream/src/pvr2/glutil.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/glutil.c
changeset 1282:9f445c5e252b
prev1276:e20a69167093
next1296:30ecee61f811
author nkeynes
date Tue Mar 27 08:23:52 2012 +1000 (8 years ago)
permissions -rw-r--r--
last change Android: Preserve render buffers when switching away from app.
- fix gl_read_render_buffer + gl_load_frame_buffer to work in GLES
a) glReadPixels only (guaranteed to) work for GL_RGBA,GL_UNSIGNED_BYTE
b) glTexSubImage2D can only load GL_RGBA into a GL_RGBA render buffer.
file annotate diff log raw
nkeynes@635
     1
/**
nkeynes@636
     2
 * $Id$
nkeynes@635
     3
 *
nkeynes@635
     4
 * GL-based support functions 
nkeynes@635
     5
 *
nkeynes@635
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@635
     7
 *
nkeynes@635
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@635
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@635
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@635
    11
 * (at your option) any later version.
nkeynes@635
    12
 *
nkeynes@635
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@635
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@635
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@635
    16
 * GNU General Public License for more details.
nkeynes@635
    17
 */
nkeynes@736
    18
nkeynes@1282
    19
#include <assert.h>
nkeynes@645
    20
#include <string.h>
nkeynes@1129
    21
#include <stdlib.h>
nkeynes@687
    22
#include <glib/gstrfuncs.h>
nkeynes@635
    23
#include "pvr2/glutil.h"
nkeynes@635
    24
nkeynes@1258
    25
gboolean isOpenGLES2()
nkeynes@1258
    26
{
nkeynes@1258
    27
    const char *str = glGetString(GL_VERSION);
nkeynes@1258
    28
    if( strncmp(str, "OpenGL ES 2.", 12) == 0 ) {
nkeynes@1258
    29
        return TRUE;
nkeynes@1258
    30
    }
nkeynes@1276
    31
    return FALSE;
nkeynes@1258
    32
}
nkeynes@1258
    33
nkeynes@667
    34
gboolean isGLSecondaryColorSupported()
nkeynes@667
    35
{
nkeynes@736
    36
    return isGLExtensionSupported("GL_EXT_secondary_color");
nkeynes@667
    37
}
nkeynes@667
    38
nkeynes@667
    39
gboolean isGLVertexBufferSupported()
nkeynes@667
    40
{
nkeynes@736
    41
    return isGLExtensionSupported("GL_ARB_vertex_buffer_object");
nkeynes@667
    42
}
nkeynes@667
    43
nkeynes@667
    44
gboolean isGLPixelBufferSupported()
nkeynes@667
    45
{
nkeynes@736
    46
    return isGLExtensionSupported("GL_ARB_pixel_buffer_object");
nkeynes@667
    47
}
nkeynes@667
    48
nkeynes@667
    49
gboolean isGLMirroredTextureSupported()
nkeynes@667
    50
{
nkeynes@736
    51
    return isGLExtensionSupported("GL_ARB_texture_mirrored_repeat");
nkeynes@667
    52
}
nkeynes@667
    53
nkeynes@1275
    54
gboolean isGLBGRATextureSupported()
nkeynes@1275
    55
{
nkeynes@1275
    56
    /* Note: e.g. Tegra 3 reports GL_EXT_bgra, but it doesn't actually work.
nkeynes@1275
    57
     * Need to check this with NVIDIA, in meantime assume GLES2 doesn't have
nkeynes@1275
    58
     * BGRA support */
nkeynes@1275
    59
    return !isOpenGLES2() && isGLExtensionSupported("GL_EXT_bgra");
nkeynes@1275
    60
}
nkeynes@1275
    61
nkeynes@1258
    62
gboolean isGLShaderSupported()
nkeynes@1245
    63
{
nkeynes@1258
    64
    return isOpenGLES2() || (isGLExtensionSupported("GL_ARB_fragment_shader") &&
nkeynes@1258
    65
    isGLExtensionSupported("GL_ARB_vertex_shader") &&
nkeynes@1258
    66
    isGLExtensionSupported("GL_ARB_shading_language_100"));
nkeynes@1245
    67
}
nkeynes@1245
    68
nkeynes@1140
    69
/**
nkeynes@1140
    70
 * Check if there's at least 2 texture units
nkeynes@1140
    71
 */
nkeynes@1140
    72
gboolean isGLMultitextureSupported()
nkeynes@1140
    73
{
nkeynes@1248
    74
    if( !isOpenGLES2() && !isGLExtensionSupported("GL_ARB_multitexture") )
nkeynes@1140
    75
        return FALSE;
nkeynes@1140
    76
    int units = 0;
nkeynes@1219
    77
nkeynes@1219
    78
#if defined(GL_MAX_TEXTURE_UNITS)
nkeynes@1219
    79
        glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units);
nkeynes@1219
    80
#elif defined(GL_MAX_TEXTURE_IMAGE_UNITS)
nkeynes@1219
    81
        glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &units);
nkeynes@1219
    82
#endif
nkeynes@1140
    83
    return units >= 2;
nkeynes@1140
    84
}
nkeynes@1140
    85
nkeynes@1134
    86
gboolean isGLVertexRangeSupported()
nkeynes@1134
    87
{
nkeynes@1134
    88
    return isGLExtensionSupported("GL_APPLE_vertex_array_range") ||
nkeynes@1134
    89
            isGLExtensionSupported("GL_NV_vertex_array_range");
nkeynes@1134
    90
}
nkeynes@1134
    91
nkeynes@635
    92
/**
nkeynes@635
    93
 * Test if a specific extension is supported. From opengl.org
nkeynes@635
    94
 * @param extension extension name to check for
nkeynes@635
    95
 * @return TRUE if supported, otherwise FALSE.
nkeynes@635
    96
 */
nkeynes@635
    97
gboolean isGLExtensionSupported( const char *extension )
nkeynes@635
    98
{
nkeynes@635
    99
    const GLubyte *extensions = NULL;
nkeynes@635
   100
    const GLubyte *start;
nkeynes@635
   101
    GLubyte *where, *terminator;
nkeynes@635
   102
nkeynes@635
   103
    /* Extension names should not have spaces. */
nkeynes@635
   104
    where = (GLubyte *) strchr(extension, ' ');
nkeynes@635
   105
    if (where || *extension == '\0')
nkeynes@736
   106
        return 0;
nkeynes@635
   107
    extensions = glGetString(GL_EXTENSIONS);
nkeynes@645
   108
    if( extensions == NULL ) {
nkeynes@736
   109
        /* No GL available, so we're pretty sure the extension isn't
nkeynes@736
   110
         * available either. */
nkeynes@736
   111
        return FALSE;
nkeynes@645
   112
    }
nkeynes@635
   113
    /* It takes a bit of care to be fool-proof about parsing the
nkeynes@635
   114
       OpenGL extensions string. Don't be fooled by sub-strings,
nkeynes@635
   115
       etc. */
nkeynes@635
   116
    start = extensions;
nkeynes@635
   117
    for (;;) {
nkeynes@736
   118
        where = (GLubyte *) strstr((const char *) start, extension);
nkeynes@736
   119
        if (!where)
nkeynes@736
   120
            break;
nkeynes@736
   121
        terminator = where + strlen(extension);
nkeynes@736
   122
        if (where == start || *(where - 1) == ' ')
nkeynes@736
   123
            if (*terminator == ' ' || *terminator == '\0')
nkeynes@736
   124
                return TRUE;
nkeynes@736
   125
        start = terminator;
nkeynes@635
   126
    }
nkeynes@635
   127
    return FALSE;
nkeynes@635
   128
}
nkeynes@687
   129
nkeynes@1129
   130
int compare_charp( const void *a, const void *b )
nkeynes@1129
   131
{
nkeynes@1129
   132
    const char **ca = (const char **)a;
nkeynes@1129
   133
    const char **cb = (const char **)b;
nkeynes@1129
   134
    return strcmp(*ca, *cb);
nkeynes@1129
   135
}
nkeynes@1129
   136
nkeynes@1134
   137
#define DEFAULT_TERMINAL_COLUMNS 80
nkeynes@1134
   138
#define DEFAULT_COLUMN_WIDTH 34
nkeynes@1134
   139
nkeynes@1223
   140
int glGetMaxColourAttachments()
nkeynes@1223
   141
{
nkeynes@1223
   142
#ifdef GL_MAX_COLOR_ATTACHMENTS
nkeynes@1223
   143
    GLint result = 0;
nkeynes@1223
   144
    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &result);
nkeynes@1223
   145
    return result;
nkeynes@1223
   146
#else
nkeynes@1223
   147
    return 1;
nkeynes@1223
   148
#endif
nkeynes@1223
   149
}
nkeynes@1223
   150
nkeynes@1223
   151
nkeynes@1134
   152
/**
nkeynes@1236
   153
 * Define an orthographic projection matrix
nkeynes@1236
   154
 * Note: row-major order
nkeynes@1236
   155
 */
nkeynes@1236
   156
void defineOrthoMatrix( GLfloat *matrix, GLfloat width, GLfloat height, GLfloat znear, GLfloat zfar )
nkeynes@1236
   157
{
nkeynes@1236
   158
    matrix[0] =  2/width;
nkeynes@1236
   159
    matrix[1] =  0;
nkeynes@1236
   160
    matrix[2] =  0;
nkeynes@1236
   161
    matrix[3] =  0;
nkeynes@1236
   162
nkeynes@1236
   163
    matrix[4] =  0;
nkeynes@1236
   164
    matrix[5] = -2/height;
nkeynes@1236
   165
    matrix[6] =  0;
nkeynes@1236
   166
    matrix[7] =  0;
nkeynes@1236
   167
nkeynes@1236
   168
    matrix[8] =  0;
nkeynes@1236
   169
    matrix[9] =  0;
nkeynes@1236
   170
    matrix[10]= -2/(zfar-znear);
nkeynes@1236
   171
    matrix[11]=  0;
nkeynes@1236
   172
nkeynes@1236
   173
    matrix[12]= -1;
nkeynes@1236
   174
    matrix[13]=  1;
nkeynes@1236
   175
    matrix[14]= -(zfar+znear)/(zfar-znear);
nkeynes@1236
   176
    matrix[15]=  1;
nkeynes@1236
   177
}
nkeynes@1236
   178
nkeynes@1236
   179
/**
nkeynes@1134
   180
 * Format a GL extension list (or other space-separated string) nicely, and
nkeynes@1134
   181
 * print to the given output stream.
nkeynes@1134
   182
 */
nkeynes@1134
   183
nkeynes@1134
   184
void fprint_extensions( FILE *out, const char *extensions )
nkeynes@687
   185
{
nkeynes@1134
   186
    unsigned int i, j, count, maxlen = DEFAULT_COLUMN_WIDTH, columns, per_column, terminal_columns;
nkeynes@1134
   187
    const char *terminal_columns_str = getenv("COLUMNS");
nkeynes@1134
   188
    if( terminal_columns_str == NULL || (terminal_columns = strtol(terminal_columns_str,0,10)) == 0 )
nkeynes@1134
   189
        terminal_columns = DEFAULT_TERMINAL_COLUMNS;
nkeynes@1129
   190
nkeynes@1134
   191
    if( extensions == NULL || extensions[0] == '\0' )
nkeynes@1134
   192
        return;
nkeynes@1134
   193
nkeynes@1134
   194
    gchar *ext_dup = g_strdup(extensions);
nkeynes@1134
   195
    gchar **ext_split = g_strsplit(g_strstrip(extensions), " ", 0);
nkeynes@1134
   196
    for( count = 0; ext_split[count] != NULL; count++ ) {
nkeynes@1134
   197
        unsigned len = strlen(ext_split[count]);
nkeynes@1134
   198
        if( len > maxlen )
nkeynes@1134
   199
            maxlen = len;
nkeynes@1134
   200
    }
nkeynes@1134
   201
nkeynes@1134
   202
    columns = terminal_columns / (maxlen+2);
nkeynes@1134
   203
    if( columns == 0 )
nkeynes@1134
   204
        columns = 1;
nkeynes@1134
   205
    per_column = (count+columns-1) / columns;
nkeynes@1129
   206
nkeynes@1129
   207
    qsort(ext_split, count, sizeof(gchar *), compare_charp);
nkeynes@736
   208
nkeynes@1134
   209
    for( i=0; i<per_column; i++ ) {
nkeynes@1134
   210
        for( j=0; j<columns; j++ ) {
nkeynes@1134
   211
            unsigned idx = i + (j*per_column);
nkeynes@1134
   212
            if( idx < count )
nkeynes@1134
   213
                fprintf( out, "  %-*s", maxlen, ext_split[idx] );
nkeynes@1134
   214
        }
nkeynes@1134
   215
        fprintf( out, "\n" );
nkeynes@1134
   216
    }
nkeynes@1134
   217
    g_strfreev(ext_split);
nkeynes@1134
   218
    g_free(ext_dup);
nkeynes@1134
   219
}
nkeynes@1134
   220
nkeynes@1134
   221
void glPrintInfo( FILE *out )
nkeynes@1134
   222
{
nkeynes@687
   223
    fprintf( out, "GL Vendor: %s\n", glGetString(GL_VENDOR) );
nkeynes@687
   224
    fprintf( out, "GL Renderer: %s\n", glGetString(GL_RENDERER) );
nkeynes@687
   225
    fprintf( out, "GL Version: %s\n", glGetString(GL_VERSION) );
nkeynes@1258
   226
    if( isGLShaderSupported() ) {
nkeynes@1258
   227
         fprintf( out, "SL Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION) );
nkeynes@1134
   228
    }
nkeynes@736
   229
nkeynes@1134
   230
    fprintf( out, "GL Extensions:\n" );
nkeynes@1134
   231
nkeynes@1134
   232
    fprint_extensions( out, (const gchar *)glGetString(GL_EXTENSIONS) );
nkeynes@1134
   233
    if( display_driver && display_driver->print_info ) {
nkeynes@1134
   234
        fprintf( out, "\n");
nkeynes@1134
   235
        display_driver->print_info(out);
nkeynes@687
   236
    }
nkeynes@687
   237
}
nkeynes@1150
   238
nkeynes@1150
   239
gboolean gl_check_error(const char *context)
nkeynes@1150
   240
{
nkeynes@1150
   241
    GLint err = glGetError();
nkeynes@1150
   242
    if( err != 0 ) {
nkeynes@1150
   243
        const char *s;
nkeynes@1150
   244
        switch( err ) {
nkeynes@1150
   245
        case GL_INVALID_ENUM: s = "Invalid enum"; break;
nkeynes@1150
   246
        case GL_INVALID_VALUE: s = "Invalid value"; break;
nkeynes@1150
   247
        case GL_INVALID_OPERATION: s = "Invalid operation"; break;
nkeynes@1219
   248
#ifdef GL_STACK_OVERFLOW
nkeynes@1150
   249
        case GL_STACK_OVERFLOW: s = "Stack overflow"; break;
nkeynes@1220
   250
#endif
nkeynes@1220
   251
#ifdef GL_STACK_UNDERFLOW
nkeynes@1150
   252
        case GL_STACK_UNDERFLOW: s = "Stack underflow"; break;
nkeynes@1220
   253
#endif
nkeynes@1150
   254
        case GL_OUT_OF_MEMORY:   s = "Out of memory"; break;
nkeynes@1150
   255
        default: s = "Unknown error"; break;
nkeynes@1150
   256
        }
nkeynes@1150
   257
        if( context ) {
nkeynes@1282
   258
            WARN( "%s: GL error: %x (%s)", context, err, s );
nkeynes@1150
   259
        } else {
nkeynes@1282
   260
            WARN( "GL error: %x (%s)", err, s );
nkeynes@1150
   261
        }
nkeynes@1159
   262
        return FALSE;
nkeynes@1150
   263
    }
nkeynes@1159
   264
    return TRUE;
nkeynes@1150
   265
}
nkeynes@1282
   266
nkeynes@1282
   267
static int bgra_to_rgba_type( int glFormatType )
nkeynes@1282
   268
{
nkeynes@1282
   269
    switch( glFormatType ) {
nkeynes@1282
   270
    case GL_UNSIGNED_SHORT_1_5_5_5_REV:
nkeynes@1282
   271
        return GL_UNSIGNED_SHORT_5_5_5_1;
nkeynes@1282
   272
    case GL_UNSIGNED_SHORT_4_4_4_4_REV:
nkeynes@1282
   273
        return GL_UNSIGNED_SHORT_4_4_4_4;
nkeynes@1282
   274
    case GL_UNSIGNED_BYTE:
nkeynes@1282
   275
        return GL_UNSIGNED_BYTE;
nkeynes@1282
   276
    default:
nkeynes@1282
   277
        assert( 0 && "Unsupported BGRA format" );
nkeynes@1282
   278
        return glFormatType;
nkeynes@1282
   279
    }
nkeynes@1282
   280
}
nkeynes@1282
   281
nkeynes@1282
   282
/**
nkeynes@1282
   283
 * Convert BGRA data in buffer to RGBA format in-place (for systems that don't natively
nkeynes@1282
   284
 * support BGRA).
nkeynes@1282
   285
 * @return converted format type
nkeynes@1282
   286
 * @param data BGRA pixel data
nkeynes@1282
   287
 * @param nPixels total number of pixels (width*height)
nkeynes@1282
   288
 * @param glFormatType GL format of source data. One of
nkeynes@1282
   289
 *    GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_UNSIGNED_SHORT_4_4_4_4_REV, or GL_UNSIGNED_BYTE
nkeynes@1282
   290
 */
nkeynes@1282
   291
static int bgra_to_rgba( unsigned char *data, unsigned nPixels, int glFormatType )
nkeynes@1282
   292
{
nkeynes@1282
   293
    unsigned i;
nkeynes@1282
   294
    switch( glFormatType ) {
nkeynes@1282
   295
    case GL_UNSIGNED_SHORT_1_5_5_5_REV: {
nkeynes@1282
   296
        uint16_t *p = (uint16_t *)data;
nkeynes@1282
   297
        uint16_t *end = p + nPixels;
nkeynes@1282
   298
        while( p != end ) {
nkeynes@1282
   299
            uint16_t v = *p;
nkeynes@1282
   300
            *p = (v >> 15) | (v<<1);
nkeynes@1282
   301
            p++;
nkeynes@1282
   302
        }
nkeynes@1282
   303
        return GL_UNSIGNED_SHORT_5_5_5_1;
nkeynes@1282
   304
    }
nkeynes@1282
   305
    case GL_UNSIGNED_SHORT_4_4_4_4_REV: { /* ARGB => RGBA */
nkeynes@1282
   306
        uint16_t *p = (uint16_t *)data;
nkeynes@1282
   307
        uint16_t *end = p + nPixels;
nkeynes@1282
   308
        while( p != end ) {
nkeynes@1282
   309
            uint16_t v = *p;
nkeynes@1282
   310
            *p = (v >> 12) | (v<<4);
nkeynes@1282
   311
            p++;
nkeynes@1282
   312
        }
nkeynes@1282
   313
        return GL_UNSIGNED_SHORT_4_4_4_4;
nkeynes@1282
   314
    }
nkeynes@1282
   315
    case GL_UNSIGNED_BYTE: { /* ARGB => ABGR */
nkeynes@1282
   316
        uint32_t *p = (uint32_t *)data;
nkeynes@1282
   317
        uint32_t *end = p + nPixels;
nkeynes@1282
   318
        while( p != end ) {
nkeynes@1282
   319
            uint32_t v = *p;
nkeynes@1282
   320
            *p = (v&0xFF000000) | ((v<<16) & 0x00FF0000) | (v & 0x0000FF00) | ((v>>16) & 0x000000FF);
nkeynes@1282
   321
            p++;
nkeynes@1282
   322
        }
nkeynes@1282
   323
        return GL_UNSIGNED_BYTE;
nkeynes@1282
   324
    }
nkeynes@1282
   325
    default:
nkeynes@1282
   326
        assert( 0 && "Unsupported BGRA format" );
nkeynes@1282
   327
        return glFormatType;
nkeynes@1282
   328
    }
nkeynes@1282
   329
}
nkeynes@1282
   330
nkeynes@1282
   331
void glTexImage2DBGRA( int level, GLint intFormat, int width, int height, GLint format, GLint type, unsigned char *data, int preserveData )
nkeynes@1282
   332
{
nkeynes@1282
   333
    if( format == GL_BGRA && !display_driver->capabilities.has_bgra ) {
nkeynes@1282
   334
        if( preserveData ) {
nkeynes@1282
   335
            size_t size = width * height * (type == GL_UNSIGNED_BYTE ? 4 : 2);
nkeynes@1282
   336
            char buf[size];
nkeynes@1282
   337
            memcpy(buf, data, size);
nkeynes@1282
   338
            GLint rgbaType = bgra_to_rgba( buf, width*height, type );
nkeynes@1282
   339
            glTexImage2D( GL_TEXTURE_2D, level, intFormat, width, height, 0, GL_RGBA, rgbaType,
nkeynes@1282
   340
                    buf );
nkeynes@1282
   341
        } else {
nkeynes@1282
   342
            GLint rgbaType = bgra_to_rgba( data, width*height, type );
nkeynes@1282
   343
            glTexImage2D( GL_TEXTURE_2D, level, intFormat, width, height, 0, GL_RGBA, rgbaType,
nkeynes@1282
   344
                    data );
nkeynes@1282
   345
        }
nkeynes@1282
   346
    } else {
nkeynes@1282
   347
        glTexImage2D( GL_TEXTURE_2D, level, intFormat, width, height, 0, format, type,
nkeynes@1282
   348
                data );
nkeynes@1282
   349
    }
nkeynes@1282
   350
}
nkeynes@1282
   351
nkeynes@1282
   352
void glTexSubImage2DBGRA( int level, int xoff, int yoff, int width, int height, GLint format, GLint type, unsigned char *data, int preserveData )
nkeynes@1282
   353
{
nkeynes@1282
   354
    if( format == GL_BGRA && !display_driver->capabilities.has_bgra ) {
nkeynes@1282
   355
        if( preserveData ) {
nkeynes@1282
   356
            size_t size = width * height * (type == GL_UNSIGNED_BYTE ? 4 : 2);
nkeynes@1282
   357
            char buf[size];
nkeynes@1282
   358
            memcpy(buf, data, size);
nkeynes@1282
   359
            GLint rgbaType = bgra_to_rgba( buf, width*height, type );
nkeynes@1282
   360
            glTexSubImage2D( GL_TEXTURE_2D, level, xoff, yoff, width, height, GL_RGBA, rgbaType,
nkeynes@1282
   361
                    buf );
nkeynes@1282
   362
        } else {
nkeynes@1282
   363
            GLint rgbaType = bgra_to_rgba( data, width*height, type );
nkeynes@1282
   364
            glTexSubImage2D( GL_TEXTURE_2D, level, xoff, yoff, width, height, GL_RGBA, rgbaType,
nkeynes@1282
   365
                    data );
nkeynes@1282
   366
        }
nkeynes@1282
   367
    } else {
nkeynes@1282
   368
        glTexSubImage2D( GL_TEXTURE_2D, level, xoff, yoff, width, height, format, type,
nkeynes@1282
   369
                data );
nkeynes@1282
   370
    }
nkeynes@1282
   371
}
.