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 May 27 09:42:24 2015 +1000 (8 years ago)
permissions -rw-r--r--
last change Fix stack alignment when calling the end-block callback (broken on OS X)
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 ENABLE_VBO
   192 #ifdef GL_ARRAY_BUFFER_ARB
   194 static void *vbo_map( vertex_buffer_t buf, uint32_t size )
   195 {
   196     glBindBufferARB( GL_ARRAY_BUFFER_ARB, buf->id );
   197      if( size > buf->capacity ) {
   198          glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, NULL, GL_STREAM_DRAW_ARB );
   199          assert( gl_check_error("Allocating vbo data") );
   200          buf->capacity = size;
   201     }
   202     buf->data = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
   203     buf->mapped_size = buf->capacity;
   204     return buf->data;
   205 }
   207 static void *vbo_unmap( vertex_buffer_t buf )
   208 {
   209     glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
   210     return NULL;
   211 }
   213 static void vbo_finished( vertex_buffer_t buf )
   214 {
   215     glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
   216 }
   218 static void vbo_destroy( vertex_buffer_t buf )
   219 {
   220     glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
   221     glDeleteBuffersARB( 1, &buf->id );
   222 }
   224 static struct vertex_buffer vbo_vtable = { vbo_map, vbo_unmap, vbo_finished, vbo_destroy };
   226 static vertex_buffer_t vbo_create_buffer( uint32_t size )
   227 {
   228     vertex_buffer_t buf = vertex_buffer_new( &vbo_vtable );
   229     glGenBuffersARB( 1, &buf->id );
   230     return buf;
   231 }
   233 #endif
   234 #endif
   236 /**
   237  * Auto-detect the supported vertex buffer types, and select between them.
   238  * Use vertex_buffer_object if available, otherwise vertex_array_range,
   239  * otherwise just pure host buffers.
   240  */
   241 void gl_vbo_init( display_driver_t driver ) {
   242 /* VBOs are disabled for now as they won't work with the triangle sorting,
   243  * plus they seem to be slower than the other options anyway.
   244  */
   245 #ifdef ENABLE_VBO
   246 #ifdef GL_ARRAY_BUFFER_ARB
   247     if( isGLVertexBufferSupported() ) {
   248         driver->create_vertex_buffer = vbo_create_buffer;
   249         return;
   250     }
   251 #endif
   252 #endif
   254 #ifdef APPLE_BUILD
   255     if( isGLExtensionSupported("GL_APPLE_vertex_array_range") &&
   256             isGLExtensionSupported("GL_APPLE_fence") ) {
   257         glEnableClientState( GL_VERTEX_ARRAY_RANGE_APPLE );
   258         driver->create_vertex_buffer = apple_create_buffer;
   259         return;
   260     }
   261 #endif
   263 #ifdef GL_VERTEX_ARRAY_RANGE_NV
   264     if( isGLExtensionSupported("GL_NV_vertex_array_range") &&
   265             isGLExtensionSupported("GL_NV_fence") &&
   266             glGenFencesNV ) {
   267         glEnableClientState( GL_VERTEX_ARRAY_RANGE_NV );
   268         driver->create_vertex_buffer = nv_create_buffer;
   269         return;
   270     }
   271 #endif
   272     driver->create_vertex_buffer = def_create_buffer;
   273 }
   275 void gl_vbo_fallback_init( display_driver_t driver ) {
   276     driver->create_vertex_buffer = def_create_buffer;
   277 }
.