Cell: generalize the batch buffer code for vertex buffers...
[mesa.git] / src / mesa / vbo / vbo_exec_api.c
1 /**************************************************************************
2
3 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
4
5 All Rights Reserved.
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Keith Whitwell <keith@tungstengraphics.com>
31 */
32
33 #include "main/glheader.h"
34 #include "main/context.h"
35 #include "main/macros.h"
36 #include "main/vtxfmt.h"
37 #include "main/dlist.h"
38 #include "main/state.h"
39 #include "main/light.h"
40 #include "main/api_arrayelt.h"
41 #include "main/api_noop.h"
42 #include "glapi/dispatch.h"
43
44 #include "vbo_context.h"
45
46 #ifdef ERROR
47 #undef ERROR
48 #endif
49
50
51 static void reset_attrfv( struct vbo_exec_context *exec );
52
53
54 /* Close off the last primitive, execute the buffer, restart the
55 * primitive.
56 */
57 static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
58 {
59 if (exec->vtx.prim_count == 0) {
60 exec->vtx.copied.nr = 0;
61 exec->vtx.vert_count = 0;
62 exec->vtx.vbptr = (GLfloat *)exec->vtx.buffer_map;
63 }
64 else {
65 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
66 GLuint last_count;
67
68 if (exec->ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
69 GLint i = exec->vtx.prim_count - 1;
70 assert(i >= 0);
71 exec->vtx.prim[i].count = (exec->vtx.vert_count -
72 exec->vtx.prim[i].start);
73 }
74
75 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
76
77 /* Execute the buffer and save copied vertices.
78 */
79 if (exec->vtx.vert_count)
80 vbo_exec_vtx_flush( exec );
81 else {
82 exec->vtx.prim_count = 0;
83 exec->vtx.copied.nr = 0;
84 }
85
86 /* Emit a glBegin to start the new list.
87 */
88 assert(exec->vtx.prim_count == 0);
89
90 if (exec->ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
91 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
92 exec->vtx.prim[0].start = 0;
93 exec->vtx.prim[0].count = 0;
94 exec->vtx.prim_count++;
95
96 if (exec->vtx.copied.nr == last_count)
97 exec->vtx.prim[0].begin = last_begin;
98 }
99 }
100 }
101
102
103 /* Deal with buffer wrapping where provoked by the vertex buffer
104 * filling up, as opposed to upgrade_vertex().
105 */
106 void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
107 {
108 GLfloat *data = exec->vtx.copied.buffer;
109 GLuint i;
110
111 /* Run pipeline on current vertices, copy wrapped vertices
112 * to exec->vtx.copied.
113 */
114 vbo_exec_wrap_buffers( exec );
115
116 /* Copy stored stored vertices to start of new list.
117 */
118 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
119
120 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
121 _mesa_memcpy( exec->vtx.vbptr, data,
122 exec->vtx.vertex_size * sizeof(GLfloat));
123 exec->vtx.vbptr += exec->vtx.vertex_size;
124 data += exec->vtx.vertex_size;
125 exec->vtx.vert_count++;
126 }
127
128 exec->vtx.copied.nr = 0;
129 }
130
131
132 /*
133 * Copy the active vertex's values to the ctx->Current fields.
134 */
135 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
136 {
137 GLcontext *ctx = exec->ctx;
138 struct vbo_context *vbo = vbo_context(ctx);
139 GLuint i;
140
141 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
142 if (exec->vtx.attrsz[i]) {
143 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
144
145 /* Note: the exec->vtx.current[i] pointers point into the
146 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
147 */
148 COPY_CLEAN_4V(current,
149 exec->vtx.attrsz[i],
150 exec->vtx.attrptr[i]);
151
152
153 /* Given that we explicitly state size here, there is no need
154 * for the COPY_CLEAN above, could just copy 16 bytes and be
155 * done. The only problem is when Mesa accesses ctx->Current
156 * directly.
157 */
158 vbo->currval[i].Size = exec->vtx.attrsz[i];
159
160 /* This triggers rather too much recalculation of Mesa state
161 * that doesn't get used (eg light positions).
162 */
163 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
164 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
165 ctx->NewState |= _NEW_LIGHT;
166 }
167 }
168
169 /* Colormaterial -- this kindof sucks.
170 */
171 if (ctx->Light.ColorMaterialEnabled &&
172 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
173 _mesa_update_color_material(ctx,
174 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
175 }
176
177 ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
178 }
179
180
181 static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
182 {
183 GLcontext *ctx = exec->ctx;
184 struct vbo_context *vbo = vbo_context(ctx);
185 GLint i;
186
187 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
188 const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
189 switch (exec->vtx.attrsz[i]) {
190 case 4: exec->vtx.attrptr[i][3] = current[3];
191 case 3: exec->vtx.attrptr[i][2] = current[2];
192 case 2: exec->vtx.attrptr[i][1] = current[1];
193 case 1: exec->vtx.attrptr[i][0] = current[0];
194 break;
195 }
196 }
197
198 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
199 }
200
201
202 /* Flush existing data, set new attrib size, replay copied vertices.
203 */
204 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
205 GLuint attr,
206 GLuint newsz )
207 {
208 GLcontext *ctx = exec->ctx;
209 struct vbo_context *vbo = vbo_context(ctx);
210 GLint lastcount = exec->vtx.vert_count;
211 GLfloat *tmp;
212 GLuint oldsz;
213 GLuint i;
214
215 /* Run pipeline on current vertices, copy wrapped vertices
216 * to exec->vtx.copied.
217 */
218 vbo_exec_wrap_buffers( exec );
219
220
221 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
222 * when the attribute already exists in the vertex and is having
223 * its size increased.
224 */
225 vbo_exec_copy_to_current( exec );
226
227
228 /* Heuristic: Attempt to isolate attributes received outside
229 * begin/end so that they don't bloat the vertices.
230 */
231 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
232 exec->vtx.attrsz[attr] == 0 &&
233 lastcount > 8 &&
234 exec->vtx.vertex_size) {
235 reset_attrfv( exec );
236 }
237
238 /* Fix up sizes:
239 */
240 oldsz = exec->vtx.attrsz[attr];
241 exec->vtx.attrsz[attr] = newsz;
242
243 exec->vtx.vertex_size += newsz - oldsz;
244 exec->vtx.max_vert = VBO_VERT_BUFFER_SIZE / exec->vtx.vertex_size;
245 exec->vtx.vert_count = 0;
246 exec->vtx.vbptr = (GLfloat *)exec->vtx.buffer_map;
247
248
249 /* Recalculate all the attrptr[] values
250 */
251 for (i = 0, tmp = exec->vtx.vertex ; i < VBO_ATTRIB_MAX ; i++) {
252 if (exec->vtx.attrsz[i]) {
253 exec->vtx.attrptr[i] = tmp;
254 tmp += exec->vtx.attrsz[i];
255 }
256 else
257 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
258 }
259
260 /* Copy from current to repopulate the vertex with correct values.
261 */
262 vbo_exec_copy_from_current( exec );
263
264 /* Replay stored vertices to translate them
265 * to new format here.
266 *
267 * -- No need to replay - just copy piecewise
268 */
269 if (exec->vtx.copied.nr)
270 {
271 GLfloat *data = exec->vtx.copied.buffer;
272 GLfloat *dest = exec->vtx.vbptr;
273 GLuint j;
274
275 assert(exec->vtx.vbptr == (GLfloat *)exec->vtx.buffer_map);
276
277 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
278 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
279 if (exec->vtx.attrsz[j]) {
280 if (j == attr) {
281 if (oldsz) {
282 COPY_CLEAN_4V( dest, oldsz, data );
283 data += oldsz;
284 dest += newsz;
285 } else {
286 const GLfloat *current = (const GLfloat *)vbo->currval[j].Ptr;
287 COPY_SZ_4V( dest, newsz, current );
288 dest += newsz;
289 }
290 }
291 else {
292 GLuint sz = exec->vtx.attrsz[j];
293 COPY_SZ_4V( dest, sz, data );
294 dest += sz;
295 data += sz;
296 }
297 }
298 }
299 }
300
301 exec->vtx.vbptr = dest;
302 exec->vtx.vert_count += exec->vtx.copied.nr;
303 exec->vtx.copied.nr = 0;
304 }
305 }
306
307
308 static void vbo_exec_fixup_vertex( GLcontext *ctx,
309 GLuint attr, GLuint sz )
310 {
311 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
312 int i;
313
314 if (sz > exec->vtx.attrsz[attr]) {
315 /* New size is larger. Need to flush existing vertices and get
316 * an enlarged vertex format.
317 */
318 vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
319 }
320 else if (sz < exec->vtx.active_sz[attr]) {
321 static const GLfloat id[4] = { 0, 0, 0, 1 };
322
323 /* New size is smaller - just need to fill in some
324 * zeros. Don't need to flush or wrap.
325 */
326 for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
327 exec->vtx.attrptr[attr][i-1] = id[i-1];
328 }
329
330 exec->vtx.active_sz[attr] = sz;
331
332 /* Does setting NeedFlush belong here? Necessitates resetting
333 * vtxfmt on each flush (otherwise flags won't get reset
334 * afterwards).
335 */
336 if (attr == 0)
337 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
338 else
339 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
340 }
341
342
343
344
345 /*
346 */
347 #define ATTR( A, N, V0, V1, V2, V3 ) \
348 do { \
349 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
350 \
351 if (exec->vtx.active_sz[A] != N) \
352 vbo_exec_fixup_vertex(ctx, A, N); \
353 \
354 { \
355 GLfloat *dest = exec->vtx.attrptr[A]; \
356 if (N>0) dest[0] = V0; \
357 if (N>1) dest[1] = V1; \
358 if (N>2) dest[2] = V2; \
359 if (N>3) dest[3] = V3; \
360 } \
361 \
362 if ((A) == 0) { \
363 GLuint i; \
364 \
365 for (i = 0; i < exec->vtx.vertex_size; i++) \
366 exec->vtx.vbptr[i] = exec->vtx.vertex[i]; \
367 \
368 exec->vtx.vbptr += exec->vtx.vertex_size; \
369 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
370 \
371 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
372 vbo_exec_vtx_wrap( exec ); \
373 } \
374 } while (0)
375
376
377 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
378 #define TAG(x) vbo_##x
379
380 #include "vbo_attrib_tmp.h"
381
382
383
384
385
386 /* Eval
387 */
388 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
389 {
390 GET_CURRENT_CONTEXT( ctx );
391 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
392
393 {
394 GLint i;
395 if (exec->eval.recalculate_maps)
396 vbo_exec_eval_update( exec );
397
398 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
399 if (exec->eval.map1[i].map)
400 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
401 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
402 }
403 }
404
405
406 _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
407 exec->vtx.vertex_size * sizeof(GLfloat));
408
409 vbo_exec_do_EvalCoord1f( exec, u );
410
411 _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
412 exec->vtx.vertex_size * sizeof(GLfloat));
413 }
414
415 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
416 {
417 GET_CURRENT_CONTEXT( ctx );
418 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
419
420 {
421 GLint i;
422 if (exec->eval.recalculate_maps)
423 vbo_exec_eval_update( exec );
424
425 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
426 if (exec->eval.map2[i].map)
427 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
428 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
429 }
430
431 if (ctx->Eval.AutoNormal)
432 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
433 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
434 }
435
436 _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
437 exec->vtx.vertex_size * sizeof(GLfloat));
438
439 vbo_exec_do_EvalCoord2f( exec, u, v );
440
441 _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
442 exec->vtx.vertex_size * sizeof(GLfloat));
443 }
444
445 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
446 {
447 vbo_exec_EvalCoord1f( u[0] );
448 }
449
450 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
451 {
452 vbo_exec_EvalCoord2f( u[0], u[1] );
453 }
454
455 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
456 {
457 GET_CURRENT_CONTEXT( ctx );
458 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
459 (GLfloat) ctx->Eval.MapGrid1un);
460 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
461
462 vbo_exec_EvalCoord1f( u );
463 }
464
465
466 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
467 {
468 GET_CURRENT_CONTEXT( ctx );
469 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
470 (GLfloat) ctx->Eval.MapGrid2un);
471 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
472 (GLfloat) ctx->Eval.MapGrid2vn);
473 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
474 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
475
476 vbo_exec_EvalCoord2f( u, v );
477 }
478
479
480 /* Build a list of primitives on the fly. Keep
481 * ctx->Driver.CurrentExecPrimitive uptodate as well.
482 */
483 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
484 {
485 GET_CURRENT_CONTEXT( ctx );
486
487 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
488 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
489 int i;
490
491 if (ctx->NewState) {
492 _mesa_update_state( ctx );
493
494 /* XXX also need to check if shader enabled, but invalid */
495 if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
496 (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
497 _mesa_error(ctx, GL_INVALID_OPERATION,
498 "glBegin (invalid vertex/fragment program)");
499 return;
500 }
501
502 CALL_Begin(ctx->Exec, (mode));
503 return;
504 }
505
506 /* Heuristic: attempt to isolate attributes occuring outside
507 * begin/end pairs.
508 */
509 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
510 vbo_exec_FlushVertices( ctx, ~0 );
511
512 i = exec->vtx.prim_count++;
513 exec->vtx.prim[i].mode = mode;
514 exec->vtx.prim[i].begin = 1;
515 exec->vtx.prim[i].end = 0;
516 exec->vtx.prim[i].indexed = 0;
517 exec->vtx.prim[i].weak = 0;
518 exec->vtx.prim[i].pad = 0;
519 exec->vtx.prim[i].start = exec->vtx.vert_count;
520 exec->vtx.prim[i].count = 0;
521
522 ctx->Driver.CurrentExecPrimitive = mode;
523 }
524 else
525 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
526
527 }
528
529 static void GLAPIENTRY vbo_exec_End( void )
530 {
531 GET_CURRENT_CONTEXT( ctx );
532
533 if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
534 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
535 int idx = exec->vtx.vert_count;
536 int i = exec->vtx.prim_count - 1;
537
538 exec->vtx.prim[i].end = 1;
539 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
540
541 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
542
543 if (exec->vtx.prim_count == VBO_MAX_PRIM)
544 vbo_exec_vtx_flush( exec );
545 }
546 else
547 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
548 }
549
550
551 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
552 {
553 GLvertexformat *vfmt = &exec->vtxfmt;
554
555 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
556 vfmt->Begin = vbo_exec_Begin;
557 vfmt->CallList = _mesa_CallList;
558 vfmt->CallLists = _mesa_CallLists;
559 vfmt->End = vbo_exec_End;
560 vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
561 vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
562 vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
563 vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
564 vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
565 vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
566
567 vfmt->Rectf = _mesa_noop_Rectf;
568 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
569 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
570
571
572 /* from attrib_tmp.h:
573 */
574 vfmt->Color3f = vbo_Color3f;
575 vfmt->Color3fv = vbo_Color3fv;
576 vfmt->Color4f = vbo_Color4f;
577 vfmt->Color4fv = vbo_Color4fv;
578 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
579 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
580 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
581 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
582 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
583 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
584 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
585 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
586 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
587 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
588 vfmt->Normal3f = vbo_Normal3f;
589 vfmt->Normal3fv = vbo_Normal3fv;
590 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
591 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
592 vfmt->TexCoord1f = vbo_TexCoord1f;
593 vfmt->TexCoord1fv = vbo_TexCoord1fv;
594 vfmt->TexCoord2f = vbo_TexCoord2f;
595 vfmt->TexCoord2fv = vbo_TexCoord2fv;
596 vfmt->TexCoord3f = vbo_TexCoord3f;
597 vfmt->TexCoord3fv = vbo_TexCoord3fv;
598 vfmt->TexCoord4f = vbo_TexCoord4f;
599 vfmt->TexCoord4fv = vbo_TexCoord4fv;
600 vfmt->Vertex2f = vbo_Vertex2f;
601 vfmt->Vertex2fv = vbo_Vertex2fv;
602 vfmt->Vertex3f = vbo_Vertex3f;
603 vfmt->Vertex3fv = vbo_Vertex3fv;
604 vfmt->Vertex4f = vbo_Vertex4f;
605 vfmt->Vertex4fv = vbo_Vertex4fv;
606
607 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
608 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
609 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
610 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
611 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
612 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
613 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
614 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
615
616 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
617 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
618 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
619 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
620 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
621 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
622 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
623 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
624
625 vfmt->Materialfv = vbo_Materialfv;
626
627 vfmt->EdgeFlag = vbo_EdgeFlag;
628 vfmt->Indexf = vbo_Indexf;
629 vfmt->Indexfv = vbo_Indexfv;
630
631 }
632
633
634 /**
635 * Tell the VBO module to use a real OpenGL vertex buffer object to
636 * store accumulated immediate-mode vertex data.
637 * This replaces the malloced buffer which was created in
638 * vb_exec_vtx_init() below.
639 */
640 void vbo_use_buffer_objects(GLcontext *ctx)
641 {
642 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
643 /* Any buffer name but 0 can be used here since this bufferobj won't
644 * go into the bufferobj hashtable.
645 */
646 GLuint bufName = 0xaabbccdd;
647 GLenum target = GL_ARRAY_BUFFER_ARB;
648 GLenum access = GL_READ_WRITE_ARB;
649 GLenum usage = GL_STREAM_DRAW_ARB;
650 GLsizei size = VBO_VERT_BUFFER_SIZE * sizeof(GLfloat);
651
652 /* Make sure this func is only used once */
653 assert(exec->vtx.bufferobj == ctx->Array.NullBufferObj);
654 if (exec->vtx.buffer_map) {
655 _mesa_align_free(exec->vtx.buffer_map);
656 }
657
658 /* Allocate a real buffer object now */
659 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
660 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
661
662 /* and map it */
663 exec->vtx.buffer_map
664 = ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj);
665 }
666
667
668
669 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
670 {
671 GLcontext *ctx = exec->ctx;
672 struct vbo_context *vbo = vbo_context(ctx);
673 GLuint i;
674
675 /* Allocate a buffer object. Will just reuse this object
676 * continuously, unless vbo_use_buffer_objects() is called to enable
677 * use of real VBOs.
678 */
679 exec->vtx.bufferobj = ctx->Array.NullBufferObj;
680 exec->vtx.buffer_map = ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE * sizeof(GLfloat), 64);
681
682 vbo_exec_vtxfmt_init( exec );
683
684 /* Hook our functions into the dispatch table.
685 */
686 _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
687
688 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
689 exec->vtx.attrsz[i] = 0;
690 exec->vtx.active_sz[i] = 0;
691 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
692 }
693
694 {
695 struct gl_client_array *arrays = exec->vtx.arrays;
696 memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
697 memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
698 }
699
700 exec->vtx.vertex_size = 0;
701 }
702
703
704 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
705 {
706 GLcontext *ctx = exec->ctx;
707 if (exec->vtx.bufferobj->Name) {
708 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, exec->vtx.bufferobj);
709 ctx->Driver.DeleteBuffer(ctx, exec->vtx.bufferobj);
710 exec->vtx.bufferobj = NULL;
711 }
712 else {
713 if (exec->vtx.buffer_map) {
714 ALIGN_FREE(exec->vtx.buffer_map);
715 exec->vtx.buffer_map = NULL;
716 }
717 }
718 }
719
720
721 void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags )
722 {
723 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
724
725 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
726 return;
727
728 if (exec->vtx.vert_count) {
729 vbo_exec_vtx_flush( exec );
730 }
731
732 if (exec->vtx.vertex_size) {
733 vbo_exec_copy_to_current( exec );
734 reset_attrfv( exec );
735 }
736
737 exec->ctx->Driver.NeedFlush = 0;
738 }
739
740
741 static void reset_attrfv( struct vbo_exec_context *exec )
742 {
743 GLuint i;
744
745 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
746 exec->vtx.attrsz[i] = 0;
747 exec->vtx.active_sz[i] = 0;
748 }
749
750 exec->vtx.vertex_size = 0;
751 }
752