Search
lxdream.org :: lxdream/src/drivers/gl_vbo.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/gl_vbo.c
changeset 1160:219d05b638de
next1164:01b45ca393c6
author nkeynes
date Thu Jan 20 06:51:15 2011 +1000 (13 years ago)
permissions -rw-r--r--
last change Add gl_vbo.c
file annotate diff log raw
nkeynes@1160
     1
/**
nkeynes@1160
     2
 * $Id$
nkeynes@1160
     3
 *
nkeynes@1160
     4
 * Generic GL vertex buffer/vertex array support
nkeynes@1160
     5
 *
nkeynes@1160
     6
 * Copyright (c) 2011 Nathan Keynes.
nkeynes@1160
     7
 *
nkeynes@1160
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@1160
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@1160
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1160
    11
 * (at your option) any later version.
nkeynes@1160
    12
 *
nkeynes@1160
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@1160
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1160
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1160
    16
 * GNU General Public License for more details.
nkeynes@1160
    17
 */
nkeynes@1160
    18
nkeynes@1160
    19
#define GL_GLEXT_PROTOTYPES 1
nkeynes@1160
    20
nkeynes@1160
    21
#include <assert.h>
nkeynes@1160
    22
#include <stdlib.h>
nkeynes@1160
    23
#include <sys/mman.h>
nkeynes@1160
    24
#include "lxdream.h"
nkeynes@1160
    25
#include "display.h"
nkeynes@1160
    26
#include "drivers/video_gl.h"
nkeynes@1160
    27
#include "pvr2/glutil.h"
nkeynes@1160
    28
nkeynes@1160
    29
#define MIN_VERTEX_ARRAY_SIZE (1024*1024)
nkeynes@1160
    30
nkeynes@1160
    31
vertex_buffer_t vertex_buffer_new( vertex_buffer_t vtable )
nkeynes@1160
    32
{
nkeynes@1160
    33
    vertex_buffer_t buf = g_malloc(sizeof(struct vertex_buffer));
nkeynes@1160
    34
    memcpy( buf, vtable, sizeof(struct vertex_buffer));
nkeynes@1160
    35
    buf->data = 0;
nkeynes@1160
    36
    buf->id = 0;
nkeynes@1160
    37
    buf->mapped_size = buf->capacity = 0;
nkeynes@1160
    38
    buf->fence = 0;
nkeynes@1160
    39
    return buf;
nkeynes@1160
    40
}
nkeynes@1160
    41
nkeynes@1160
    42
/******************************* Default ***********************************/
nkeynes@1160
    43
nkeynes@1160
    44
static void *def_map( vertex_buffer_t buf, uint32_t size )
nkeynes@1160
    45
{
nkeynes@1160
    46
    buf->mapped_size = size;
nkeynes@1160
    47
    if( size < MIN_VERTEX_ARRAY_SIZE )
nkeynes@1160
    48
        size = MIN_VERTEX_ARRAY_SIZE;
nkeynes@1160
    49
    if( size > buf->capacity ) {
nkeynes@1160
    50
        g_free(buf->data);
nkeynes@1160
    51
        buf->data = g_malloc(size);
nkeynes@1160
    52
        buf->capacity = size;
nkeynes@1160
    53
    }
nkeynes@1160
    54
    return buf->data;
nkeynes@1160
    55
}
nkeynes@1160
    56
nkeynes@1160
    57
static void *def_unmap( vertex_buffer_t buf )
nkeynes@1160
    58
{
nkeynes@1160
    59
    return buf->data;
nkeynes@1160
    60
}
nkeynes@1160
    61
nkeynes@1160
    62
static void def_finished( vertex_buffer_t buf )
nkeynes@1160
    63
{
nkeynes@1160
    64
}
nkeynes@1160
    65
nkeynes@1160
    66
static void def_destroy( vertex_buffer_t buf )
nkeynes@1160
    67
{
nkeynes@1160
    68
    g_free(buf->data);
nkeynes@1160
    69
    buf->data = NULL;
nkeynes@1160
    70
    g_free(buf);
nkeynes@1160
    71
}
nkeynes@1160
    72
nkeynes@1160
    73
static struct vertex_buffer def_vtable = { def_map, def_unmap, def_finished, def_destroy };
nkeynes@1160
    74
nkeynes@1160
    75
static vertex_buffer_t def_create_buffer( )
nkeynes@1160
    76
{
nkeynes@1160
    77
    return vertex_buffer_new( &def_vtable );
nkeynes@1160
    78
}
nkeynes@1160
    79
nkeynes@1160
    80
/************************** vertex_array_range *****************************/
nkeynes@1160
    81
nkeynes@1160
    82
/**
nkeynes@1160
    83
 * VAR extensions like the buffer to be allocated on page boundaries.
nkeynes@1160
    84
 */
nkeynes@1160
    85
static void var_alloc_pages( vertex_buffer_t buf, uint32_t size )
nkeynes@1160
    86
{
nkeynes@1160
    87
    if( size < MIN_VERTEX_ARRAY_SIZE )
nkeynes@1160
    88
        size = MIN_VERTEX_ARRAY_SIZE;
nkeynes@1160
    89
    if( size > buf->capacity ) {
nkeynes@1160
    90
        size = (size + 4096-1) & (~(4096-1));
nkeynes@1160
    91
        if( buf->data != NULL ) {
nkeynes@1160
    92
            munmap( buf->data, buf->capacity );
nkeynes@1160
    93
        }
nkeynes@1160
    94
        buf->data = mmap( NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0 );
nkeynes@1160
    95
        assert( buf->data != MAP_FAILED );
nkeynes@1160
    96
        buf->capacity = size;
nkeynes@1160
    97
    }
nkeynes@1160
    98
}
nkeynes@1160
    99
nkeynes@1160
   100
#ifdef APPLE_BUILD
nkeynes@1160
   101
nkeynes@1160
   102
static void *apple_map( vertex_buffer_t buf, uint32_t size )
nkeynes@1160
   103
{
nkeynes@1160
   104
    glFinishFenceAPPLE(buf->fence);
nkeynes@1160
   105
    var_alloc_pages( buf, size );
nkeynes@1160
   106
    glVertexArrayRangeAPPLE(size, buf->data);
nkeynes@1160
   107
    buf->mapped_size = size;
nkeynes@1160
   108
    return buf->data;
nkeynes@1160
   109
}
nkeynes@1160
   110
nkeynes@1160
   111
static void *apple_unmap( vertex_buffer_t buf )
nkeynes@1160
   112
{
nkeynes@1160
   113
    glFlushVertexArrayRangeAPPLE(buf->mapped_size, buf->data);
nkeynes@1160
   114
    return buf->data;
nkeynes@1160
   115
}
nkeynes@1160
   116
nkeynes@1160
   117
static void apple_finished( vertex_buffer_t buf )
nkeynes@1160
   118
{
nkeynes@1160
   119
    glSetFenceAPPLE(buf->fence);
nkeynes@1160
   120
}
nkeynes@1160
   121
nkeynes@1160
   122
static void apple_destroy( vertex_buffer_t buf )
nkeynes@1160
   123
{
nkeynes@1160
   124
    glVertexArrayRangeAPPLE(0,0);
nkeynes@1160
   125
    glDeleteFencesAPPLE(1, &buf->fence);
nkeynes@1160
   126
    munmap( buf->data, buf->capacity );
nkeynes@1160
   127
    g_free(buf);
nkeynes@1160
   128
}
nkeynes@1160
   129
static struct vertex_buffer apple_vtable = { apple_map, apple_unmap, apple_finished, apple_destroy };
nkeynes@1160
   130
nkeynes@1160
   131
static vertex_buffer_t apple_create_buffer( uint32_t size )
nkeynes@1160
   132
{
nkeynes@1160
   133
    vertex_buffer_t buf = vertex_buffer_new( &apple_vtable );
nkeynes@1160
   134
    glGenFencesAPPLE(1, &buf->fence);
nkeynes@1160
   135
    return buf;
nkeynes@1160
   136
}
nkeynes@1160
   137
nkeynes@1160
   138
#endif
nkeynes@1160
   139
nkeynes@1160
   140
#ifdef GL_VERTEX_ARRAY_RANGE_NV
nkeynes@1160
   141
nkeynes@1160
   142
static void *nv_map( vertex_buffer_t buf, uint32_t size )
nkeynes@1160
   143
{
nkeynes@1160
   144
    glFinishFenceNV(buf->fence);
nkeynes@1160
   145
    var_alloc_pages( buf, size );
nkeynes@1160
   146
    glVertexArrayRangeNV(size, buf->data);
nkeynes@1160
   147
    buf->mapped_size = size;
nkeynes@1160
   148
    return buf->data;
nkeynes@1160
   149
}
nkeynes@1160
   150
static void *nv_unmap( vertex_buffer_t buf )
nkeynes@1160
   151
{
nkeynes@1160
   152
    glFlushVertexArrayRangeNV();
nkeynes@1160
   153
    return buf->data;
nkeynes@1160
   154
}
nkeynes@1160
   155
nkeynes@1160
   156
static void nv_finished( vertex_buffer_t buf )
nkeynes@1160
   157
{
nkeynes@1160
   158
    glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
nkeynes@1160
   159
}
nkeynes@1160
   160
nkeynes@1160
   161
static void nv_destroy( vertex_buffer_t buf )
nkeynes@1160
   162
{
nkeynes@1160
   163
    glVertexArrayRangeNV(0,0);
nkeynes@1160
   164
    glDeleteFencesNV(1, &buf->fence);
nkeynes@1160
   165
    munmap( buf->data, buf->capacity );
nkeynes@1160
   166
    g_free(buf);
nkeynes@1160
   167
}
nkeynes@1160
   168
nkeynes@1160
   169
static struct vertex_buffer nv_vtable = { nv_map, nv_unmap, nv_finished, nv_destroy };
nkeynes@1160
   170
nkeynes@1160
   171
static vertex_buffer_t nv_create_buffer( uint32_t size )
nkeynes@1160
   172
{
nkeynes@1160
   173
    vertex_buffer_t buf = vertex_buffer_new( &nv_vtable );
nkeynes@1160
   174
    glGenFencesNV(1, &buf->fence);
nkeynes@1160
   175
    return buf;
nkeynes@1160
   176
}
nkeynes@1160
   177
nkeynes@1160
   178
#endif /* !GL_VERTEX_ARRAY_RANGE_NV */
nkeynes@1160
   179
nkeynes@1160
   180
/************************** vertex_buffer_object *****************************/
nkeynes@1160
   181
nkeynes@1160
   182
#ifdef GL_ARRAY_BUFFER_ARB
nkeynes@1160
   183
nkeynes@1160
   184
static void *vbo_map( vertex_buffer_t buf, uint32_t size )
nkeynes@1160
   185
{
nkeynes@1160
   186
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, buf->id );
nkeynes@1160
   187
     if( size > buf->capacity ) {
nkeynes@1160
   188
         glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, NULL, GL_STREAM_DRAW_ARB );
nkeynes@1160
   189
         assert( gl_check_error("Allocating vbo data") );
nkeynes@1160
   190
         buf->capacity = size;
nkeynes@1160
   191
    }
nkeynes@1160
   192
    buf->data = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
nkeynes@1160
   193
    buf->mapped_size = buf->capacity;
nkeynes@1160
   194
    return buf->data;
nkeynes@1160
   195
}
nkeynes@1160
   196
nkeynes@1160
   197
static void *vbo_unmap( vertex_buffer_t buf )
nkeynes@1160
   198
{
nkeynes@1160
   199
    glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
nkeynes@1160
   200
    return NULL;
nkeynes@1160
   201
}
nkeynes@1160
   202
nkeynes@1160
   203
static void vbo_finished( vertex_buffer_t buf )
nkeynes@1160
   204
{
nkeynes@1160
   205
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
nkeynes@1160
   206
}
nkeynes@1160
   207
nkeynes@1160
   208
static void vbo_destroy( vertex_buffer_t buf )
nkeynes@1160
   209
{
nkeynes@1160
   210
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
nkeynes@1160
   211
    glDeleteBuffersARB( 1, &buf->id );
nkeynes@1160
   212
}
nkeynes@1160
   213
nkeynes@1160
   214
static struct vertex_buffer vbo_vtable = { vbo_map, vbo_unmap, vbo_finished, vbo_destroy };
nkeynes@1160
   215
nkeynes@1160
   216
static vertex_buffer_t vbo_create_buffer( uint32_t size )
nkeynes@1160
   217
{
nkeynes@1160
   218
    vertex_buffer_t buf = vertex_buffer_new( &vbo_vtable );
nkeynes@1160
   219
    glGenBuffersARB( 1, &buf->id );
nkeynes@1160
   220
    return buf;
nkeynes@1160
   221
}
nkeynes@1160
   222
nkeynes@1160
   223
#endif
nkeynes@1160
   224
nkeynes@1160
   225
/**
nkeynes@1160
   226
 * Auto-detect the supported vertex buffer types, and select between them.
nkeynes@1160
   227
 * Use vertex_buffer_object if available, otherwise vertex_array_range,
nkeynes@1160
   228
 * otherwise just pure host buffers.
nkeynes@1160
   229
 */
nkeynes@1160
   230
void gl_vbo_init( display_driver_t driver ) {
nkeynes@1160
   231
/* VBOs are disabled for now as they won't work with the triangle sorting,
nkeynes@1160
   232
 * plus they seem to be slower than the other options anyway.
nkeynes@1160
   233
 */
nkeynes@1160
   234
#ifdef ENABLE_VBO
nkeynes@1160
   235
#ifdef GL_ARRAY_BUFFER_ARB
nkeynes@1160
   236
    if( isGLVertexBufferSupported() ) {
nkeynes@1160
   237
        driver->create_vertex_buffer = vbo_create_buffer;
nkeynes@1160
   238
        return;
nkeynes@1160
   239
    }
nkeynes@1160
   240
#endif
nkeynes@1160
   241
#endif
nkeynes@1160
   242
nkeynes@1160
   243
#ifdef APPLE_BUILD
nkeynes@1160
   244
    if( isGLExtensionSupported("GL_APPLE_vertex_array_range") &&
nkeynes@1160
   245
            isGLExtensionSupported("GL_APPLE_fence") ) {
nkeynes@1160
   246
        glEnableClientState( GL_VERTEX_ARRAY_RANGE_APPLE );
nkeynes@1160
   247
        driver->create_vertex_buffer = apple_create_buffer;
nkeynes@1160
   248
        return;
nkeynes@1160
   249
    }
nkeynes@1160
   250
#endif
nkeynes@1160
   251
nkeynes@1160
   252
#ifdef GL_VERTEX_ARRAY_RANGE_NV
nkeynes@1160
   253
    if( isGLExtensionSupported("GL_NV_vertex_array_range") &&
nkeynes@1160
   254
            isGLExtensionSupported("GL_NV_fence") ) {
nkeynes@1160
   255
        glEnableClientState( GL_VERTEX_ARRAY_RANGE_NV );
nkeynes@1160
   256
        driver->create_vertex_buffer = nv_create_buffer;
nkeynes@1160
   257
        return;
nkeynes@1160
   258
    }
nkeynes@1160
   259
#endif
nkeynes@1160
   260
    driver->create_vertex_buffer = def_create_buffer;
nkeynes@1160
   261
}
nkeynes@1160
   262
nkeynes@1160
   263
void gl_vbo_fallback_init( display_driver_t driver ) {
nkeynes@1160
   264
    driver->create_vertex_buffer = def_create_buffer;
nkeynes@1160
   265
}
.