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