filename | src/drivers/gl_vbo.c |
changeset | 1164:01b45ca393c6 |
prev | 1160:219d05b638de |
next | 1289:ef8b0ddb8185 |
author | nkeynes |
date | Sat Jan 22 06:07:17 2011 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Mark the NV vertex range functions as weak (to keep things working on drivers that don't provide the entry points) Set the fence at the start (really just to prevent an error the first time around) |
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 glEnableClientState( GL_VERTEX_ARRAY_RANGE_NV );
265 driver->create_vertex_buffer = nv_create_buffer;
266 return;
267 }
268 #endif
269 driver->create_vertex_buffer = def_create_buffer;
270 }
272 void gl_vbo_fallback_init( display_driver_t driver ) {
273 driver->create_vertex_buffer = def_create_buffer;
274 }
.