4 * Generic GL vertex buffer/vertex array support
6 * Copyright (c) 2011 Nathan Keynes.
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.
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.
19 #define GL_GLEXT_PROTOTYPES 1
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 )
33 vertex_buffer_t buf = g_malloc(sizeof(struct vertex_buffer));
34 memcpy( buf, vtable, sizeof(struct vertex_buffer));
37 buf->mapped_size = buf->capacity = 0;
42 /******************************* Default ***********************************/
44 static void *def_map( vertex_buffer_t buf, uint32_t size )
46 buf->mapped_size = size;
47 if( size < MIN_VERTEX_ARRAY_SIZE )
48 size = MIN_VERTEX_ARRAY_SIZE;
49 if( size > buf->capacity ) {
51 buf->data = g_malloc(size);
57 static void *def_unmap( vertex_buffer_t buf )
62 static void def_finished( vertex_buffer_t buf )
66 static void def_destroy( vertex_buffer_t buf )
73 static struct vertex_buffer def_vtable = { def_map, def_unmap, def_finished, def_destroy };
75 static vertex_buffer_t def_create_buffer( )
77 return vertex_buffer_new( &def_vtable );
80 /************************** vertex_array_range *****************************/
83 * VAR extensions like the buffer to be allocated on page boundaries.
85 static void var_alloc_pages( vertex_buffer_t buf, uint32_t size )
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 );
94 buf->data = mmap( NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0 );
95 assert( buf->data != MAP_FAILED );
102 static void *apple_map( vertex_buffer_t buf, uint32_t size )
104 glFinishFenceAPPLE(buf->fence);
105 var_alloc_pages( buf, size );
106 glVertexArrayRangeAPPLE(size, buf->data);
107 buf->mapped_size = size;
111 static void *apple_unmap( vertex_buffer_t buf )
113 glFlushVertexArrayRangeAPPLE(buf->mapped_size, buf->data);
117 static void apple_finished( vertex_buffer_t buf )
119 glSetFenceAPPLE(buf->fence);
122 static void apple_destroy( vertex_buffer_t buf )
124 glVertexArrayRangeAPPLE(0,0);
125 glDeleteFencesAPPLE(1, &buf->fence);
126 munmap( buf->data, buf->capacity );
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 )
133 vertex_buffer_t buf = vertex_buffer_new( &apple_vtable );
134 glGenFencesAPPLE(1, &buf->fence);
140 #ifdef GL_VERTEX_ARRAY_RANGE_NV
142 static void *nv_map( vertex_buffer_t buf, uint32_t size )
144 glFinishFenceNV(buf->fence);
145 var_alloc_pages( buf, size );
146 glVertexArrayRangeNV(size, buf->data);
147 buf->mapped_size = size;
150 static void *nv_unmap( vertex_buffer_t buf )
152 glFlushVertexArrayRangeNV();
156 static void nv_finished( vertex_buffer_t buf )
158 glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
161 static void nv_destroy( vertex_buffer_t buf )
163 glVertexArrayRangeNV(0,0);
164 glDeleteFencesNV(1, &buf->fence);
165 munmap( buf->data, buf->capacity );
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 )
173 vertex_buffer_t buf = vertex_buffer_new( &nv_vtable );
174 glGenFencesNV(1, &buf->fence);
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 )
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;
192 buf->data = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
193 buf->mapped_size = buf->capacity;
197 static void *vbo_unmap( vertex_buffer_t buf )
199 glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
203 static void vbo_finished( vertex_buffer_t buf )
205 glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
208 static void vbo_destroy( vertex_buffer_t buf )
210 glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
211 glDeleteBuffersARB( 1, &buf->id );
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 )
218 vertex_buffer_t buf = vertex_buffer_new( &vbo_vtable );
219 glGenBuffersARB( 1, &buf->id );
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.
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.
235 #ifdef GL_ARRAY_BUFFER_ARB
236 if( isGLVertexBufferSupported() ) {
237 driver->create_vertex_buffer = vbo_create_buffer;
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;
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;
260 driver->create_vertex_buffer = def_create_buffer;
263 void gl_vbo_fallback_init( display_driver_t driver ) {
264 driver->create_vertex_buffer = def_create_buffer;
.