filename | src/drivers/gl_vbo.c |
changeset | 1289:ef8b0ddb8185 |
prev | 1164:01b45ca393c6 |
next | 1298:d0eb2307b847 |
author | nkeynes |
date | Fri Jul 13 21:05:10 2012 +1000 (11 years ago) |
permissions | -rw-r--r-- |
last change | Add check that glGenFencesNV is actually defined, to try to guard against installations with a broken libGL |
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 glGenFencesNV ) {
265 glEnableClientState( GL_VERTEX_ARRAY_RANGE_NV );
266 driver->create_vertex_buffer = nv_create_buffer;
267 return;
268 }
269 #endif
270 driver->create_vertex_buffer = def_create_buffer;
271 }
273 void gl_vbo_fallback_init( display_driver_t driver ) {
274 driver->create_vertex_buffer = def_create_buffer;
275 }
.