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);
135 glSetFenceAPPLE(buf->fence);
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 )
152 glFinishFenceNV(buf->fence);
153 var_alloc_pages( buf, size );
154 glVertexArrayRangeNV(size, buf->data);
155 buf->mapped_size = size;
158 static void *nv_unmap( vertex_buffer_t buf )
160 glFlushVertexArrayRangeNV();
164 static void nv_finished( vertex_buffer_t buf )
166 glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
169 static void nv_destroy( vertex_buffer_t buf )
171 glVertexArrayRangeNV(0,0);
172 glDeleteFencesNV(1, &buf->fence);
173 munmap( buf->data, buf->capacity );
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 )
181 vertex_buffer_t buf = vertex_buffer_new( &nv_vtable );
182 glGenFencesNV(1, &buf->fence);
183 glSetFenceNV(buf->fence, GL_ALL_COMPLETED_NV);
187 #endif /* !GL_VERTEX_ARRAY_RANGE_NV */
189 /************************** vertex_buffer_object *****************************/
192 #ifdef GL_ARRAY_BUFFER_ARB
194 static void *vbo_map( vertex_buffer_t buf, uint32_t size )
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;
202 buf->data = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
203 buf->mapped_size = buf->capacity;
207 static void *vbo_unmap( vertex_buffer_t buf )
209 glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
213 static void vbo_finished( vertex_buffer_t buf )
215 glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
218 static void vbo_destroy( vertex_buffer_t buf )
220 glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
221 glDeleteBuffersARB( 1, &buf->id );
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 )
228 vertex_buffer_t buf = vertex_buffer_new( &vbo_vtable );
229 glGenBuffersARB( 1, &buf->id );
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.
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.
246 #ifdef GL_ARRAY_BUFFER_ARB
247 if( isGLVertexBufferSupported() ) {
248 driver->create_vertex_buffer = vbo_create_buffer;
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;
263 #ifdef GL_VERTEX_ARRAY_RANGE_NV
264 if( isGLExtensionSupported("GL_NV_vertex_array_range") &&
265 isGLExtensionSupported("GL_NV_fence") &&
267 glEnableClientState( GL_VERTEX_ARRAY_RANGE_NV );
268 driver->create_vertex_buffer = nv_create_buffer;
272 driver->create_vertex_buffer = def_create_buffer;
275 void gl_vbo_fallback_init( display_driver_t driver ) {
276 driver->create_vertex_buffer = def_create_buffer;
.