Search
lxdream.org :: lxdream/src/drivers/gl_vbo.c :: diff
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 (9 years ago)
permissions -rw-r--r--
last change Add gl_vbo.c
file annotate diff log raw
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.3 @@ -0,0 +1,265 @@
1.4 +/**
1.5 + * $Id$
1.6 + *
1.7 + * Generic GL vertex buffer/vertex array support
1.8 + *
1.9 + * Copyright (c) 2011 Nathan Keynes.
1.10 + *
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.15 + *
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.20 + */
1.21 +
1.22 +#define GL_GLEXT_PROTOTYPES 1
1.23 +
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.31 +
1.32 +#define MIN_VERTEX_ARRAY_SIZE (1024*1024)
1.33 +
1.34 +vertex_buffer_t vertex_buffer_new( vertex_buffer_t vtable )
1.35 +{
1.36 + vertex_buffer_t buf = g_malloc(sizeof(struct vertex_buffer));
1.37 + memcpy( buf, vtable, sizeof(struct vertex_buffer));
1.38 + buf->data = 0;
1.39 + buf->id = 0;
1.40 + buf->mapped_size = buf->capacity = 0;
1.41 + buf->fence = 0;
1.42 + return buf;
1.43 +}
1.44 +
1.45 +/******************************* Default ***********************************/
1.46 +
1.47 +static void *def_map( vertex_buffer_t buf, uint32_t size )
1.48 +{
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.56 + }
1.57 + return buf->data;
1.58 +}
1.59 +
1.60 +static void *def_unmap( vertex_buffer_t buf )
1.61 +{
1.62 + return buf->data;
1.63 +}
1.64 +
1.65 +static void def_finished( vertex_buffer_t buf )
1.66 +{
1.67 +}
1.68 +
1.69 +static void def_destroy( vertex_buffer_t buf )
1.70 +{
1.71 + g_free(buf->data);
1.72 + buf->data = NULL;
1.73 + g_free(buf);
1.74 +}
1.75 +
1.76 +static struct vertex_buffer def_vtable = { def_map, def_unmap, def_finished, def_destroy };
1.77 +
1.78 +static vertex_buffer_t def_create_buffer( )
1.79 +{
1.80 + return vertex_buffer_new( &def_vtable );
1.81 +}
1.82 +
1.83 +/************************** vertex_array_range *****************************/
1.84 +
1.85 +/**
1.86 + * VAR extensions like the buffer to be allocated on page boundaries.
1.87 + */
1.88 +static void var_alloc_pages( vertex_buffer_t buf, uint32_t size )
1.89 +{
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.96 + }
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.100 + }
1.101 +}
1.102 +
1.103 +#ifdef APPLE_BUILD
1.104 +
1.105 +static void *apple_map( vertex_buffer_t buf, uint32_t size )
1.106 +{
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.112 +}
1.113 +
1.114 +static void *apple_unmap( vertex_buffer_t buf )
1.115 +{
1.116 + glFlushVertexArrayRangeAPPLE(buf->mapped_size, buf->data);
1.117 + return buf->data;
1.118 +}
1.119 +
1.120 +static void apple_finished( vertex_buffer_t buf )
1.121 +{
1.122 + glSetFenceAPPLE(buf->fence);
1.123 +}
1.124 +
1.125 +static void apple_destroy( vertex_buffer_t buf )
1.126 +{
1.127 + glVertexArrayRangeAPPLE(0,0);
1.128 + glDeleteFencesAPPLE(1, &buf->fence);
1.129 + munmap( buf->data, buf->capacity );
1.130 + g_free(buf);
1.131 +}
1.132 +static struct vertex_buffer apple_vtable = { apple_map, apple_unmap, apple_finished, apple_destroy };
1.133 +
1.134 +static vertex_buffer_t apple_create_buffer( uint32_t size )
1.135 +{
1.136 + vertex_buffer_t buf = vertex_buffer_new( &apple_vtable );
1.137 + glGenFencesAPPLE(1, &buf->fence);
1.138 + return buf;
1.139 +}
1.140 +
1.141 +#endif
1.142 +
1.143 +#ifdef GL_VERTEX_ARRAY_RANGE_NV
1.144 +
1.145 +static void *nv_map( vertex_buffer_t buf, uint32_t size )
1.146 +{
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.152 +}
1.153 +static void *nv_unmap( vertex_buffer_t buf )
1.154 +{
1.155 + glFlushVertexArrayRangeNV();
1.156 + return buf->data;
1.157 +}
1.158 +
1.159 +static void nv_finished( vertex_buffer_t buf )
1.160 +{
1.161 + glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
1.162 +}
1.163 +
1.164 +static void nv_destroy( vertex_buffer_t buf )
1.165 +{
1.166 + glVertexArrayRangeNV(0,0);
1.167 + glDeleteFencesNV(1, &buf->fence);
1.168 + munmap( buf->data, buf->capacity );
1.169 + g_free(buf);
1.170 +}
1.171 +
1.172 +static struct vertex_buffer nv_vtable = { nv_map, nv_unmap, nv_finished, nv_destroy };
1.173 +
1.174 +static vertex_buffer_t nv_create_buffer( uint32_t size )
1.175 +{
1.176 + vertex_buffer_t buf = vertex_buffer_new( &nv_vtable );
1.177 + glGenFencesNV(1, &buf->fence);
1.178 + return buf;
1.179 +}
1.180 +
1.181 +#endif /* !GL_VERTEX_ARRAY_RANGE_NV */
1.182 +
1.183 +/************************** vertex_buffer_object *****************************/
1.184 +
1.185 +#ifdef GL_ARRAY_BUFFER_ARB
1.186 +
1.187 +static void *vbo_map( vertex_buffer_t buf, uint32_t size )
1.188 +{
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.194 + }
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.198 +}
1.199 +
1.200 +static void *vbo_unmap( vertex_buffer_t buf )
1.201 +{
1.202 + glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
1.203 + return NULL;
1.204 +}
1.205 +
1.206 +static void vbo_finished( vertex_buffer_t buf )
1.207 +{
1.208 + glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
1.209 +}
1.210 +
1.211 +static void vbo_destroy( vertex_buffer_t buf )
1.212 +{
1.213 + glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
1.214 + glDeleteBuffersARB( 1, &buf->id );
1.215 +}
1.216 +
1.217 +static struct vertex_buffer vbo_vtable = { vbo_map, vbo_unmap, vbo_finished, vbo_destroy };
1.218 +
1.219 +static vertex_buffer_t vbo_create_buffer( uint32_t size )
1.220 +{
1.221 + vertex_buffer_t buf = vertex_buffer_new( &vbo_vtable );
1.222 + glGenBuffersARB( 1, &buf->id );
1.223 + return buf;
1.224 +}
1.225 +
1.226 +#endif
1.227 +
1.228 +/**
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.232 + */
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.236 + */
1.237 +#ifdef ENABLE_VBO
1.238 +#ifdef GL_ARRAY_BUFFER_ARB
1.239 + if( isGLVertexBufferSupported() ) {
1.240 + driver->create_vertex_buffer = vbo_create_buffer;
1.241 + return;
1.242 + }
1.243 +#endif
1.244 +#endif
1.245 +
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.251 + return;
1.252 + }
1.253 +#endif
1.254 +
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.260 + return;
1.261 + }
1.262 +#endif
1.263 + driver->create_vertex_buffer = def_create_buffer;
1.264 +}
1.265 +
1.266 +void gl_vbo_fallback_init( display_driver_t driver ) {
1.267 + driver->create_vertex_buffer = def_create_buffer;
1.268 +}
.