1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/drivers/gl_vbo.c Thu Jan 20 06:51:15 2011 +1000
1.7 + * Generic GL vertex buffer/vertex array support
1.9 + * Copyright (c) 2011 Nathan Keynes.
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.22 +#define GL_GLEXT_PROTOTYPES 1
1.24 +#include <assert.h>
1.25 +#include <stdlib.h>
1.26 +#include <sys/mman.h>
1.27 +#include "lxdream.h"
1.28 +#include "display.h"
1.29 +#include "drivers/video_gl.h"
1.30 +#include "pvr2/glutil.h"
1.32 +#define MIN_VERTEX_ARRAY_SIZE (1024*1024)
1.34 +vertex_buffer_t vertex_buffer_new( vertex_buffer_t vtable )
1.36 + vertex_buffer_t buf = g_malloc(sizeof(struct vertex_buffer));
1.37 + memcpy( buf, vtable, sizeof(struct vertex_buffer));
1.40 + buf->mapped_size = buf->capacity = 0;
1.45 +/******************************* Default ***********************************/
1.47 +static void *def_map( vertex_buffer_t buf, uint32_t size )
1.49 + buf->mapped_size = size;
1.50 + if( size < MIN_VERTEX_ARRAY_SIZE )
1.51 + size = MIN_VERTEX_ARRAY_SIZE;
1.52 + if( size > buf->capacity ) {
1.53 + g_free(buf->data);
1.54 + buf->data = g_malloc(size);
1.55 + buf->capacity = size;
1.60 +static void *def_unmap( vertex_buffer_t buf )
1.65 +static void def_finished( vertex_buffer_t buf )
1.69 +static void def_destroy( vertex_buffer_t buf )
1.71 + g_free(buf->data);
1.76 +static struct vertex_buffer def_vtable = { def_map, def_unmap, def_finished, def_destroy };
1.78 +static vertex_buffer_t def_create_buffer( )
1.80 + return vertex_buffer_new( &def_vtable );
1.83 +/************************** vertex_array_range *****************************/
1.86 + * VAR extensions like the buffer to be allocated on page boundaries.
1.88 +static void var_alloc_pages( vertex_buffer_t buf, uint32_t size )
1.90 + if( size < MIN_VERTEX_ARRAY_SIZE )
1.91 + size = MIN_VERTEX_ARRAY_SIZE;
1.92 + if( size > buf->capacity ) {
1.93 + size = (size + 4096-1) & (~(4096-1));
1.94 + if( buf->data != NULL ) {
1.95 + munmap( buf->data, buf->capacity );
1.97 + buf->data = mmap( NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0 );
1.98 + assert( buf->data != MAP_FAILED );
1.99 + buf->capacity = size;
1.103 +#ifdef APPLE_BUILD
1.105 +static void *apple_map( vertex_buffer_t buf, uint32_t size )
1.107 + glFinishFenceAPPLE(buf->fence);
1.108 + var_alloc_pages( buf, size );
1.109 + glVertexArrayRangeAPPLE(size, buf->data);
1.110 + buf->mapped_size = size;
1.111 + return buf->data;
1.114 +static void *apple_unmap( vertex_buffer_t buf )
1.116 + glFlushVertexArrayRangeAPPLE(buf->mapped_size, buf->data);
1.117 + return buf->data;
1.120 +static void apple_finished( vertex_buffer_t buf )
1.122 + glSetFenceAPPLE(buf->fence);
1.125 +static void apple_destroy( vertex_buffer_t buf )
1.127 + glVertexArrayRangeAPPLE(0,0);
1.128 + glDeleteFencesAPPLE(1, &buf->fence);
1.129 + munmap( buf->data, buf->capacity );
1.132 +static struct vertex_buffer apple_vtable = { apple_map, apple_unmap, apple_finished, apple_destroy };
1.134 +static vertex_buffer_t apple_create_buffer( uint32_t size )
1.136 + vertex_buffer_t buf = vertex_buffer_new( &apple_vtable );
1.137 + glGenFencesAPPLE(1, &buf->fence);
1.143 +#ifdef GL_VERTEX_ARRAY_RANGE_NV
1.145 +static void *nv_map( vertex_buffer_t buf, uint32_t size )
1.147 + glFinishFenceNV(buf->fence);
1.148 + var_alloc_pages( buf, size );
1.149 + glVertexArrayRangeNV(size, buf->data);
1.150 + buf->mapped_size = size;
1.151 + return buf->data;
1.153 +static void *nv_unmap( vertex_buffer_t buf )
1.155 + glFlushVertexArrayRangeNV();
1.156 + return buf->data;
1.159 +static void nv_finished( vertex_buffer_t buf )
1.161 + glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
1.164 +static void nv_destroy( vertex_buffer_t buf )
1.166 + glVertexArrayRangeNV(0,0);
1.167 + glDeleteFencesNV(1, &buf->fence);
1.168 + munmap( buf->data, buf->capacity );
1.172 +static struct vertex_buffer nv_vtable = { nv_map, nv_unmap, nv_finished, nv_destroy };
1.174 +static vertex_buffer_t nv_create_buffer( uint32_t size )
1.176 + vertex_buffer_t buf = vertex_buffer_new( &nv_vtable );
1.177 + glGenFencesNV(1, &buf->fence);
1.181 +#endif /* !GL_VERTEX_ARRAY_RANGE_NV */
1.183 +/************************** vertex_buffer_object *****************************/
1.185 +#ifdef GL_ARRAY_BUFFER_ARB
1.187 +static void *vbo_map( vertex_buffer_t buf, uint32_t size )
1.189 + glBindBufferARB( GL_ARRAY_BUFFER_ARB, buf->id );
1.190 + if( size > buf->capacity ) {
1.191 + glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, NULL, GL_STREAM_DRAW_ARB );
1.192 + assert( gl_check_error("Allocating vbo data") );
1.193 + buf->capacity = size;
1.195 + buf->data = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
1.196 + buf->mapped_size = buf->capacity;
1.197 + return buf->data;
1.200 +static void *vbo_unmap( vertex_buffer_t buf )
1.202 + glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
1.206 +static void vbo_finished( vertex_buffer_t buf )
1.208 + glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
1.211 +static void vbo_destroy( vertex_buffer_t buf )
1.213 + glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
1.214 + glDeleteBuffersARB( 1, &buf->id );
1.217 +static struct vertex_buffer vbo_vtable = { vbo_map, vbo_unmap, vbo_finished, vbo_destroy };
1.219 +static vertex_buffer_t vbo_create_buffer( uint32_t size )
1.221 + vertex_buffer_t buf = vertex_buffer_new( &vbo_vtable );
1.222 + glGenBuffersARB( 1, &buf->id );
1.229 + * Auto-detect the supported vertex buffer types, and select between them.
1.230 + * Use vertex_buffer_object if available, otherwise vertex_array_range,
1.231 + * otherwise just pure host buffers.
1.233 +void gl_vbo_init( display_driver_t driver ) {
1.234 +/* VBOs are disabled for now as they won't work with the triangle sorting,
1.235 + * plus they seem to be slower than the other options anyway.
1.238 +#ifdef GL_ARRAY_BUFFER_ARB
1.239 + if( isGLVertexBufferSupported() ) {
1.240 + driver->create_vertex_buffer = vbo_create_buffer;
1.246 +#ifdef APPLE_BUILD
1.247 + if( isGLExtensionSupported("GL_APPLE_vertex_array_range") &&
1.248 + isGLExtensionSupported("GL_APPLE_fence") ) {
1.249 + glEnableClientState( GL_VERTEX_ARRAY_RANGE_APPLE );
1.250 + driver->create_vertex_buffer = apple_create_buffer;
1.255 +#ifdef GL_VERTEX_ARRAY_RANGE_NV
1.256 + if( isGLExtensionSupported("GL_NV_vertex_array_range") &&
1.257 + isGLExtensionSupported("GL_NV_fence") ) {
1.258 + glEnableClientState( GL_VERTEX_ARRAY_RANGE_NV );
1.259 + driver->create_vertex_buffer = nv_create_buffer;
1.263 + driver->create_vertex_buffer = def_create_buffer;
1.266 +void gl_vbo_fallback_init( display_driver_t driver ) {
1.267 + driver->create_vertex_buffer = def_create_buffer;