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
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     return buf;
   136 }
   138 #endif
   140 #ifdef GL_VERTEX_ARRAY_RANGE_NV
   142 static void *nv_map( vertex_buffer_t buf, uint32_t size )
   143 {
   144     glFinishFenceNV(buf->fence);
   145     var_alloc_pages( buf, size );
   146     glVertexArrayRangeNV(size, buf->data);
   147     buf->mapped_size = size;
   148     return buf->data;
   149 }
   150 static void *nv_unmap( vertex_buffer_t buf )
   151 {
   152     glFlushVertexArrayRangeNV();
   153     return buf->data;
   154 }
   156 static void nv_finished( vertex_buffer_t buf )
   157 {
   158     glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
   159 }
   161 static void nv_destroy( vertex_buffer_t buf )
   162 {
   163     glVertexArrayRangeNV(0,0);
   164     glDeleteFencesNV(1, &buf->fence);
   165     munmap( buf->data, buf->capacity );
   166     g_free(buf);
   167 }
   169 static struct vertex_buffer nv_vtable = { nv_map, nv_unmap, nv_finished, nv_destroy };
   171 static vertex_buffer_t nv_create_buffer( uint32_t size )
   172 {
   173     vertex_buffer_t buf = vertex_buffer_new( &nv_vtable );
   174     glGenFencesNV(1, &buf->fence);
   175     return buf;
   176 }
   178 #endif /* !GL_VERTEX_ARRAY_RANGE_NV */
   180 /************************** vertex_buffer_object *****************************/
   182 #ifdef GL_ARRAY_BUFFER_ARB
   184 static void *vbo_map( vertex_buffer_t buf, uint32_t size )
   185 {
   186     glBindBufferARB( GL_ARRAY_BUFFER_ARB, buf->id );
   187      if( size > buf->capacity ) {
   188          glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, NULL, GL_STREAM_DRAW_ARB );
   189          assert( gl_check_error("Allocating vbo data") );
   190          buf->capacity = size;
   191     }
   192     buf->data = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
   193     buf->mapped_size = buf->capacity;
   194     return buf->data;
   195 }
   197 static void *vbo_unmap( vertex_buffer_t buf )
   198 {
   199     glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
   200     return NULL;
   201 }
   203 static void vbo_finished( vertex_buffer_t buf )
   204 {
   205     glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
   206 }
   208 static void vbo_destroy( vertex_buffer_t buf )
   209 {
   210     glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
   211     glDeleteBuffersARB( 1, &buf->id );
   212 }
   214 static struct vertex_buffer vbo_vtable = { vbo_map, vbo_unmap, vbo_finished, vbo_destroy };
   216 static vertex_buffer_t vbo_create_buffer( uint32_t size )
   217 {
   218     vertex_buffer_t buf = vertex_buffer_new( &vbo_vtable );
   219     glGenBuffersARB( 1, &buf->id );
   220     return buf;
   221 }
   223 #endif
   225 /**
   226  * Auto-detect the supported vertex buffer types, and select between them.
   227  * Use vertex_buffer_object if available, otherwise vertex_array_range,
   228  * otherwise just pure host buffers.
   229  */
   230 void gl_vbo_init( display_driver_t driver ) {
   231 /* VBOs are disabled for now as they won't work with the triangle sorting,
   232  * plus they seem to be slower than the other options anyway.
   233  */
   234 #ifdef ENABLE_VBO
   235 #ifdef GL_ARRAY_BUFFER_ARB
   236     if( isGLVertexBufferSupported() ) {
   237         driver->create_vertex_buffer = vbo_create_buffer;
   238         return;
   239     }
   240 #endif
   241 #endif
   243 #ifdef APPLE_BUILD
   244     if( isGLExtensionSupported("GL_APPLE_vertex_array_range") &&
   245             isGLExtensionSupported("GL_APPLE_fence") ) {
   246         glEnableClientState( GL_VERTEX_ARRAY_RANGE_APPLE );
   247         driver->create_vertex_buffer = apple_create_buffer;
   248         return;
   249     }
   250 #endif
   252 #ifdef GL_VERTEX_ARRAY_RANGE_NV
   253     if( isGLExtensionSupported("GL_NV_vertex_array_range") &&
   254             isGLExtensionSupported("GL_NV_fence") ) {
   255         glEnableClientState( GL_VERTEX_ARRAY_RANGE_NV );
   256         driver->create_vertex_buffer = nv_create_buffer;
   257         return;
   258     }
   259 #endif
   260     driver->create_vertex_buffer = def_create_buffer;
   261 }
   263 void gl_vbo_fallback_init( display_driver_t driver ) {
   264     driver->create_vertex_buffer = def_create_buffer;
   265 }
.