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 1298:d0eb2307b847
prev1289:ef8b0ddb8185
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (5 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
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@1164
   135
    glSetFenceAPPLE(buf->fence);    
nkeynes@1160
   136
    return buf;
nkeynes@1160
   137
}
nkeynes@1160
   138
nkeynes@1160
   139
#endif
nkeynes@1160
   140
nkeynes@1160
   141
#ifdef GL_VERTEX_ARRAY_RANGE_NV
nkeynes@1160
   142
nkeynes@1164
   143
#pragma weak glVertexArrayRangeNV
nkeynes@1164
   144
#pragma weak glFlushVertexArrayRangeNV
nkeynes@1164
   145
#pragma weak glFinishFenceNV
nkeynes@1164
   146
#pragma weak glSetFenceNV
nkeynes@1164
   147
#pragma weak glGenFencesNV
nkeynes@1164
   148
#pragma weak glDeleteFencesNV
nkeynes@1164
   149
nkeynes@1160
   150
static void *nv_map( vertex_buffer_t buf, uint32_t size )
nkeynes@1160
   151
{
nkeynes@1160
   152
    glFinishFenceNV(buf->fence);
nkeynes@1160
   153
    var_alloc_pages( buf, size );
nkeynes@1160
   154
    glVertexArrayRangeNV(size, buf->data);
nkeynes@1160
   155
    buf->mapped_size = size;
nkeynes@1160
   156
    return buf->data;
nkeynes@1160
   157
}
nkeynes@1160
   158
static void *nv_unmap( vertex_buffer_t buf )
nkeynes@1160
   159
{
nkeynes@1160
   160
    glFlushVertexArrayRangeNV();
nkeynes@1160
   161
    return buf->data;
nkeynes@1160
   162
}
nkeynes@1160
   163
nkeynes@1160
   164
static void nv_finished( vertex_buffer_t buf )
nkeynes@1160
   165
{
nkeynes@1160
   166
    glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
nkeynes@1160
   167
}
nkeynes@1160
   168
nkeynes@1160
   169
static void nv_destroy( vertex_buffer_t buf )
nkeynes@1160
   170
{
nkeynes@1160
   171
    glVertexArrayRangeNV(0,0);
nkeynes@1160
   172
    glDeleteFencesNV(1, &buf->fence);
nkeynes@1160
   173
    munmap( buf->data, buf->capacity );
nkeynes@1160
   174
    g_free(buf);
nkeynes@1160
   175
}
nkeynes@1160
   176
nkeynes@1160
   177
static struct vertex_buffer nv_vtable = { nv_map, nv_unmap, nv_finished, nv_destroy };
nkeynes@1160
   178
nkeynes@1160
   179
static vertex_buffer_t nv_create_buffer( uint32_t size )
nkeynes@1160
   180
{
nkeynes@1160
   181
    vertex_buffer_t buf = vertex_buffer_new( &nv_vtable );
nkeynes@1160
   182
    glGenFencesNV(1, &buf->fence);
nkeynes@1164
   183
    glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
nkeynes@1160
   184
    return buf;
nkeynes@1160
   185
}
nkeynes@1160
   186
nkeynes@1160
   187
#endif /* !GL_VERTEX_ARRAY_RANGE_NV */
nkeynes@1160
   188
nkeynes@1160
   189
/************************** vertex_buffer_object *****************************/
nkeynes@1160
   190
nkeynes@1298
   191
#ifdef ENABLE_VBO
nkeynes@1160
   192
#ifdef GL_ARRAY_BUFFER_ARB
nkeynes@1160
   193
nkeynes@1160
   194
static void *vbo_map( vertex_buffer_t buf, uint32_t size )
nkeynes@1160
   195
{
nkeynes@1160
   196
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, buf->id );
nkeynes@1160
   197
     if( size > buf->capacity ) {
nkeynes@1160
   198
         glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, NULL, GL_STREAM_DRAW_ARB );
nkeynes@1160
   199
         assert( gl_check_error("Allocating vbo data") );
nkeynes@1160
   200
         buf->capacity = size;
nkeynes@1160
   201
    }
nkeynes@1160
   202
    buf->data = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
nkeynes@1160
   203
    buf->mapped_size = buf->capacity;
nkeynes@1160
   204
    return buf->data;
nkeynes@1160
   205
}
nkeynes@1160
   206
nkeynes@1160
   207
static void *vbo_unmap( vertex_buffer_t buf )
nkeynes@1160
   208
{
nkeynes@1160
   209
    glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
nkeynes@1160
   210
    return NULL;
nkeynes@1160
   211
}
nkeynes@1160
   212
nkeynes@1160
   213
static void vbo_finished( vertex_buffer_t buf )
nkeynes@1160
   214
{
nkeynes@1160
   215
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
nkeynes@1160
   216
}
nkeynes@1160
   217
nkeynes@1160
   218
static void vbo_destroy( vertex_buffer_t buf )
nkeynes@1160
   219
{
nkeynes@1160
   220
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
nkeynes@1160
   221
    glDeleteBuffersARB( 1, &buf->id );
nkeynes@1160
   222
}
nkeynes@1160
   223
nkeynes@1160
   224
static struct vertex_buffer vbo_vtable = { vbo_map, vbo_unmap, vbo_finished, vbo_destroy };
nkeynes@1160
   225
nkeynes@1160
   226
static vertex_buffer_t vbo_create_buffer( uint32_t size )
nkeynes@1160
   227
{
nkeynes@1160
   228
    vertex_buffer_t buf = vertex_buffer_new( &vbo_vtable );
nkeynes@1160
   229
    glGenBuffersARB( 1, &buf->id );
nkeynes@1160
   230
    return buf;
nkeynes@1160
   231
}
nkeynes@1160
   232
nkeynes@1160
   233
#endif
nkeynes@1298
   234
#endif
nkeynes@1160
   235
nkeynes@1160
   236
/**
nkeynes@1160
   237
 * Auto-detect the supported vertex buffer types, and select between them.
nkeynes@1160
   238
 * Use vertex_buffer_object if available, otherwise vertex_array_range,
nkeynes@1160
   239
 * otherwise just pure host buffers.
nkeynes@1160
   240
 */
nkeynes@1160
   241
void gl_vbo_init( display_driver_t driver ) {
nkeynes@1160
   242
/* VBOs are disabled for now as they won't work with the triangle sorting,
nkeynes@1160
   243
 * plus they seem to be slower than the other options anyway.
nkeynes@1160
   244
 */
nkeynes@1160
   245
#ifdef ENABLE_VBO
nkeynes@1160
   246
#ifdef GL_ARRAY_BUFFER_ARB
nkeynes@1160
   247
    if( isGLVertexBufferSupported() ) {
nkeynes@1160
   248
        driver->create_vertex_buffer = vbo_create_buffer;
nkeynes@1160
   249
        return;
nkeynes@1160
   250
    }
nkeynes@1160
   251
#endif
nkeynes@1160
   252
#endif
nkeynes@1160
   253
nkeynes@1160
   254
#ifdef APPLE_BUILD
nkeynes@1160
   255
    if( isGLExtensionSupported("GL_APPLE_vertex_array_range") &&
nkeynes@1160
   256
            isGLExtensionSupported("GL_APPLE_fence") ) {
nkeynes@1160
   257
        glEnableClientState( GL_VERTEX_ARRAY_RANGE_APPLE );
nkeynes@1160
   258
        driver->create_vertex_buffer = apple_create_buffer;
nkeynes@1160
   259
        return;
nkeynes@1160
   260
    }
nkeynes@1160
   261
#endif
nkeynes@1160
   262
nkeynes@1160
   263
#ifdef GL_VERTEX_ARRAY_RANGE_NV
nkeynes@1160
   264
    if( isGLExtensionSupported("GL_NV_vertex_array_range") &&
nkeynes@1289
   265
            isGLExtensionSupported("GL_NV_fence") &&
nkeynes@1289
   266
            glGenFencesNV ) {
nkeynes@1160
   267
        glEnableClientState( GL_VERTEX_ARRAY_RANGE_NV );
nkeynes@1160
   268
        driver->create_vertex_buffer = nv_create_buffer;
nkeynes@1160
   269
        return;
nkeynes@1160
   270
    }
nkeynes@1160
   271
#endif
nkeynes@1160
   272
    driver->create_vertex_buffer = def_create_buffer;
nkeynes@1160
   273
}
nkeynes@1160
   274
nkeynes@1160
   275
void gl_vbo_fallback_init( display_driver_t driver ) {
nkeynes@1160
   276
    driver->create_vertex_buffer = def_create_buffer;
nkeynes@1160
   277
}
.