vbo: Avoid unnecessary copy to/from current in vertex format upgrade.
[mesa.git] / src / mesa / vbo / vbo_exec_api.c
1 /**************************************************************************
2
3 Copyright 2002-2008 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/bufferobj.h"
35 #include "main/context.h"
36 #include "main/macros.h"
37 #include "main/vtxfmt.h"
38 #include "main/dlist.h"
39 #include "main/eval.h"
40 #include "main/state.h"
41 #include "main/light.h"
42 #include "main/api_arrayelt.h"
43 #include "main/api_noop.h"
44 #include "main/dispatch.h"
45
46 #include "vbo_context.h"
47
48 #ifdef ERROR
49 #undef ERROR
50 #endif
51
52
53 /** ID/name for immediate-mode VBO */
54 #define IMM_BUFFER_NAME 0xaabbccdd
55
56
57 static void reset_attrfv( struct vbo_exec_context *exec );
58
59
60 /**
61 * Close off the last primitive, execute the buffer, restart the
62 * primitive.
63 */
64 static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
65 {
66 if (exec->vtx.prim_count == 0) {
67 exec->vtx.copied.nr = 0;
68 exec->vtx.vert_count = 0;
69 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
70 }
71 else {
72 GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
73 GLuint last_count;
74
75 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
76 GLint i = exec->vtx.prim_count - 1;
77 assert(i >= 0);
78 exec->vtx.prim[i].count = (exec->vtx.vert_count -
79 exec->vtx.prim[i].start);
80 }
81
82 last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
83
84 /* Execute the buffer and save copied vertices.
85 */
86 if (exec->vtx.vert_count)
87 vbo_exec_vtx_flush( exec, GL_FALSE );
88 else {
89 exec->vtx.prim_count = 0;
90 exec->vtx.copied.nr = 0;
91 }
92
93 /* Emit a glBegin to start the new list.
94 */
95 assert(exec->vtx.prim_count == 0);
96
97 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
98 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
99 exec->vtx.prim[0].start = 0;
100 exec->vtx.prim[0].count = 0;
101 exec->vtx.prim_count++;
102
103 if (exec->vtx.copied.nr == last_count)
104 exec->vtx.prim[0].begin = last_begin;
105 }
106 }
107 }
108
109
110 /**
111 * Deal with buffer wrapping where provoked by the vertex buffer
112 * filling up, as opposed to upgrade_vertex().
113 */
114 void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
115 {
116 GLfloat *data = exec->vtx.copied.buffer;
117 GLuint i;
118
119 /* Run pipeline on current vertices, copy wrapped vertices
120 * to exec->vtx.copied.
121 */
122 vbo_exec_wrap_buffers( exec );
123
124 /* Copy stored stored vertices to start of new list.
125 */
126 assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
127
128 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
129 memcpy( exec->vtx.buffer_ptr, data,
130 exec->vtx.vertex_size * sizeof(GLfloat));
131 exec->vtx.buffer_ptr += exec->vtx.vertex_size;
132 data += exec->vtx.vertex_size;
133 exec->vtx.vert_count++;
134 }
135
136 exec->vtx.copied.nr = 0;
137 }
138
139
140 /**
141 * Copy the active vertex's values to the ctx->Current fields.
142 */
143 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
144 {
145 struct gl_context *ctx = exec->ctx;
146 struct vbo_context *vbo = vbo_context(ctx);
147 GLuint i;
148
149 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
150 if (exec->vtx.attrsz[i]) {
151 /* Note: the exec->vtx.current[i] pointers point into the
152 * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
153 */
154 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
155 GLfloat tmp[4];
156
157 COPY_CLEAN_4V(tmp,
158 exec->vtx.attrsz[i],
159 exec->vtx.attrptr[i]);
160
161 if (memcmp(current, tmp, sizeof(tmp)) != 0)
162 {
163 memcpy(current, tmp, sizeof(tmp));
164
165 /* Given that we explicitly state size here, there is no need
166 * for the COPY_CLEAN above, could just copy 16 bytes and be
167 * done. The only problem is when Mesa accesses ctx->Current
168 * directly.
169 */
170 vbo->currval[i].Size = exec->vtx.attrsz[i];
171
172 /* This triggers rather too much recalculation of Mesa state
173 * that doesn't get used (eg light positions).
174 */
175 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
176 i <= VBO_ATTRIB_MAT_BACK_INDEXES)
177 ctx->NewState |= _NEW_LIGHT;
178
179 ctx->NewState |= _NEW_CURRENT_ATTRIB;
180 }
181 }
182 }
183
184 /* Colormaterial -- this kindof sucks.
185 */
186 if (ctx->Light.ColorMaterialEnabled &&
187 exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
188 _mesa_update_color_material(ctx,
189 ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
190 }
191 }
192
193
194 static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
195 {
196 struct gl_context *ctx = exec->ctx;
197 struct vbo_context *vbo = vbo_context(ctx);
198 GLint i;
199
200 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
201 const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
202 switch (exec->vtx.attrsz[i]) {
203 case 4: exec->vtx.attrptr[i][3] = current[3];
204 case 3: exec->vtx.attrptr[i][2] = current[2];
205 case 2: exec->vtx.attrptr[i][1] = current[1];
206 case 1: exec->vtx.attrptr[i][0] = current[0];
207 break;
208 }
209 }
210 }
211
212
213 /**
214 * Flush existing data, set new attrib size, replay copied vertices.
215 */
216 static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
217 GLuint attr,
218 GLuint newsz )
219 {
220 struct gl_context *ctx = exec->ctx;
221 struct vbo_context *vbo = vbo_context(ctx);
222 GLint lastcount = exec->vtx.vert_count;
223 GLfloat *old_attrptr[VBO_ATTRIB_MAX];
224 GLuint old_vtx_size = exec->vtx.vertex_size;
225 GLuint oldsz = exec->vtx.attrsz[attr];
226 GLuint i;
227
228 /* Run pipeline on current vertices, copy wrapped vertices
229 * to exec->vtx.copied.
230 */
231 vbo_exec_wrap_buffers( exec );
232
233 if (unlikely(exec->vtx.copied.nr)) {
234 /* We're in the middle of a primitive, keep the old vertex
235 * format around to be able to translate the copied vertices to
236 * the new format.
237 */
238 memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
239 }
240
241 if (unlikely(oldsz)) {
242 /* Do a COPY_TO_CURRENT to ensure back-copying works for the
243 * case when the attribute already exists in the vertex and is
244 * having its size increased.
245 */
246 vbo_exec_copy_to_current( exec );
247 }
248
249 /* Heuristic: Attempt to isolate attributes received outside
250 * begin/end so that they don't bloat the vertices.
251 */
252 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
253 !oldsz && lastcount > 8 && exec->vtx.vertex_size) {
254 vbo_exec_copy_to_current( exec );
255 reset_attrfv( exec );
256 }
257
258 /* Fix up sizes:
259 */
260 exec->vtx.attrsz[attr] = newsz;
261 exec->vtx.vertex_size += newsz - oldsz;
262 exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
263 (exec->vtx.vertex_size * sizeof(GLfloat)));
264 exec->vtx.vert_count = 0;
265 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
266
267 if (unlikely(oldsz)) {
268 /* Size changed, recalculate all the attrptr[] values
269 */
270 GLfloat *tmp = exec->vtx.vertex;
271
272 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
273 if (exec->vtx.attrsz[i]) {
274 exec->vtx.attrptr[i] = tmp;
275 tmp += exec->vtx.attrsz[i];
276 }
277 else
278 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
279 }
280
281 /* Copy from current to repopulate the vertex with correct
282 * values.
283 */
284 vbo_exec_copy_from_current( exec );
285
286 } else {
287 /* Just have to append the new attribute at the end */
288 exec->vtx.attrptr[attr] = exec->vtx.vertex +
289 exec->vtx.vertex_size - newsz;
290 }
291
292 /* Replay stored vertices to translate them
293 * to new format here.
294 *
295 * -- No need to replay - just copy piecewise
296 */
297 if (unlikely(exec->vtx.copied.nr)) {
298 GLfloat *data = exec->vtx.copied.buffer;
299 GLfloat *dest = exec->vtx.buffer_ptr;
300 GLuint j;
301
302 assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
303
304 for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
305 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
306 GLuint sz = exec->vtx.attrsz[j];
307
308 if (sz) {
309 GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
310 GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
311
312 if (j == attr) {
313 if (oldsz) {
314 GLfloat tmp[4];
315 COPY_CLEAN_4V(tmp, oldsz, data + old_offset);
316 COPY_SZ_4V(dest + new_offset, newsz, tmp);
317 } else {
318 GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
319 COPY_SZ_4V(dest + new_offset, sz, current);
320 }
321 }
322 else {
323 COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
324 }
325 }
326 }
327
328 data += old_vtx_size;
329 dest += exec->vtx.vertex_size;
330 }
331
332 exec->vtx.buffer_ptr = dest;
333 exec->vtx.vert_count += exec->vtx.copied.nr;
334 exec->vtx.copied.nr = 0;
335 }
336 }
337
338
339 static void vbo_exec_fixup_vertex( struct gl_context *ctx,
340 GLuint attr, GLuint sz )
341 {
342 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
343 int i;
344
345 if (sz > exec->vtx.attrsz[attr]) {
346 /* New size is larger. Need to flush existing vertices and get
347 * an enlarged vertex format.
348 */
349 vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
350 }
351 else if (sz < exec->vtx.active_sz[attr]) {
352 static const GLfloat id[4] = { 0, 0, 0, 1 };
353
354 /* New size is smaller - just need to fill in some
355 * zeros. Don't need to flush or wrap.
356 */
357 for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
358 exec->vtx.attrptr[attr][i-1] = id[i-1];
359 }
360
361 exec->vtx.active_sz[attr] = sz;
362
363 /* Does setting NeedFlush belong here? Necessitates resetting
364 * vtxfmt on each flush (otherwise flags won't get reset
365 * afterwards).
366 */
367 if (attr == 0)
368 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
369 }
370
371
372 #if FEATURE_beginend
373
374 /*
375 */
376 #define ATTR( A, N, V0, V1, V2, V3 ) \
377 do { \
378 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
379 \
380 if (unlikely(!(exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
381 ctx->Driver.BeginVertices( ctx ); \
382 if (unlikely(exec->vtx.active_sz[A] != N)) \
383 vbo_exec_fixup_vertex(ctx, A, N); \
384 \
385 { \
386 GLfloat *dest = exec->vtx.attrptr[A]; \
387 if (N>0) dest[0] = V0; \
388 if (N>1) dest[1] = V1; \
389 if (N>2) dest[2] = V2; \
390 if (N>3) dest[3] = V3; \
391 } \
392 \
393 if ((A) == 0) { \
394 GLuint i; \
395 \
396 for (i = 0; i < exec->vtx.vertex_size; i++) \
397 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
398 \
399 exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
400 exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
401 \
402 if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
403 vbo_exec_vtx_wrap( exec ); \
404 } \
405 } while (0)
406
407
408 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
409 #define TAG(x) vbo_##x
410
411 #include "vbo_attrib_tmp.h"
412
413
414
415
416
417 #if FEATURE_evaluators
418
419 static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
420 {
421 GET_CURRENT_CONTEXT( ctx );
422 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
423
424 {
425 GLint i;
426 if (exec->eval.recalculate_maps)
427 vbo_exec_eval_update( exec );
428
429 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
430 if (exec->eval.map1[i].map)
431 if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
432 vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
433 }
434 }
435
436
437 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
438 exec->vtx.vertex_size * sizeof(GLfloat));
439
440 vbo_exec_do_EvalCoord1f( exec, u );
441
442 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
443 exec->vtx.vertex_size * sizeof(GLfloat));
444 }
445
446 static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
447 {
448 GET_CURRENT_CONTEXT( ctx );
449 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
450
451 {
452 GLint i;
453 if (exec->eval.recalculate_maps)
454 vbo_exec_eval_update( exec );
455
456 for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
457 if (exec->eval.map2[i].map)
458 if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
459 vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
460 }
461
462 if (ctx->Eval.AutoNormal)
463 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
464 vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
465 }
466
467 memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
468 exec->vtx.vertex_size * sizeof(GLfloat));
469
470 vbo_exec_do_EvalCoord2f( exec, u, v );
471
472 memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
473 exec->vtx.vertex_size * sizeof(GLfloat));
474 }
475
476 static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
477 {
478 vbo_exec_EvalCoord1f( u[0] );
479 }
480
481 static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
482 {
483 vbo_exec_EvalCoord2f( u[0], u[1] );
484 }
485
486 static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
487 {
488 GET_CURRENT_CONTEXT( ctx );
489 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
490 (GLfloat) ctx->Eval.MapGrid1un);
491 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
492
493 vbo_exec_EvalCoord1f( u );
494 }
495
496
497 static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
498 {
499 GET_CURRENT_CONTEXT( ctx );
500 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
501 (GLfloat) ctx->Eval.MapGrid2un);
502 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
503 (GLfloat) ctx->Eval.MapGrid2vn);
504 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
505 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
506
507 vbo_exec_EvalCoord2f( u, v );
508 }
509
510 /* use noop eval mesh */
511 #define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
512 #define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
513
514 #endif /* FEATURE_evaluators */
515
516
517 /**
518 * Called via glBegin.
519 */
520 static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
521 {
522 GET_CURRENT_CONTEXT( ctx );
523
524 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
525 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
526 int i;
527
528 if (ctx->NewState) {
529 _mesa_update_state( ctx );
530
531 CALL_Begin(ctx->Exec, (mode));
532 return;
533 }
534
535 if (!_mesa_valid_to_render(ctx, "glBegin")) {
536 return;
537 }
538
539 /* Heuristic: attempt to isolate attributes occuring outside
540 * begin/end pairs.
541 */
542 if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
543 vbo_exec_FlushVertices_internal( ctx, GL_FALSE );
544
545 i = exec->vtx.prim_count++;
546 exec->vtx.prim[i].mode = mode;
547 exec->vtx.prim[i].begin = 1;
548 exec->vtx.prim[i].end = 0;
549 exec->vtx.prim[i].indexed = 0;
550 exec->vtx.prim[i].weak = 0;
551 exec->vtx.prim[i].pad = 0;
552 exec->vtx.prim[i].start = exec->vtx.vert_count;
553 exec->vtx.prim[i].count = 0;
554 exec->vtx.prim[i].num_instances = 1;
555
556 ctx->Driver.CurrentExecPrimitive = mode;
557 }
558 else
559 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
560
561 }
562
563
564 /**
565 * Called via glEnd.
566 */
567 static void GLAPIENTRY vbo_exec_End( void )
568 {
569 GET_CURRENT_CONTEXT( ctx );
570
571 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
572 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
573 int idx = exec->vtx.vert_count;
574 int i = exec->vtx.prim_count - 1;
575
576 exec->vtx.prim[i].end = 1;
577 exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
578
579 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
580
581 if (exec->vtx.prim_count == VBO_MAX_PRIM)
582 vbo_exec_vtx_flush( exec, GL_FALSE );
583 }
584 else
585 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
586 }
587
588
589 /**
590 * Called via glPrimitiveRestartNV()
591 */
592 static void GLAPIENTRY
593 vbo_exec_PrimitiveRestartNV(void)
594 {
595 GLenum curPrim;
596 GET_CURRENT_CONTEXT( ctx );
597
598 curPrim = ctx->Driver.CurrentExecPrimitive;
599
600 if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
601 _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
602 }
603 else {
604 vbo_exec_End();
605 vbo_exec_Begin(curPrim);
606 }
607 }
608
609
610
611 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
612 {
613 GLvertexformat *vfmt = &exec->vtxfmt;
614
615 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
616
617 vfmt->Begin = vbo_exec_Begin;
618 vfmt->End = vbo_exec_End;
619 vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
620
621 _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
622 _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
623
624 vfmt->Rectf = _mesa_noop_Rectf;
625
626 /* from attrib_tmp.h:
627 */
628 vfmt->Color3f = vbo_Color3f;
629 vfmt->Color3fv = vbo_Color3fv;
630 vfmt->Color4f = vbo_Color4f;
631 vfmt->Color4fv = vbo_Color4fv;
632 vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
633 vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
634 vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
635 vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
636 vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
637 vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
638 vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
639 vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
640 vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
641 vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
642 vfmt->Normal3f = vbo_Normal3f;
643 vfmt->Normal3fv = vbo_Normal3fv;
644 vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
645 vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
646 vfmt->TexCoord1f = vbo_TexCoord1f;
647 vfmt->TexCoord1fv = vbo_TexCoord1fv;
648 vfmt->TexCoord2f = vbo_TexCoord2f;
649 vfmt->TexCoord2fv = vbo_TexCoord2fv;
650 vfmt->TexCoord3f = vbo_TexCoord3f;
651 vfmt->TexCoord3fv = vbo_TexCoord3fv;
652 vfmt->TexCoord4f = vbo_TexCoord4f;
653 vfmt->TexCoord4fv = vbo_TexCoord4fv;
654 vfmt->Vertex2f = vbo_Vertex2f;
655 vfmt->Vertex2fv = vbo_Vertex2fv;
656 vfmt->Vertex3f = vbo_Vertex3f;
657 vfmt->Vertex3fv = vbo_Vertex3fv;
658 vfmt->Vertex4f = vbo_Vertex4f;
659 vfmt->Vertex4fv = vbo_Vertex4fv;
660
661 vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
662 vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
663 vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
664 vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
665 vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
666 vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
667 vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
668 vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
669
670 vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
671 vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
672 vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
673 vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
674 vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
675 vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
676 vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
677 vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
678
679 /* integer-valued */
680 vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
681 vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
682 vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
683 vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
684 vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
685 vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
686 vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
687
688 /* unsigned integer-valued */
689 vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
690 vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
691 vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
692 vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
693 vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
694 vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
695 vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
696
697 vfmt->Materialfv = vbo_Materialfv;
698
699 vfmt->EdgeFlag = vbo_EdgeFlag;
700 vfmt->Indexf = vbo_Indexf;
701 vfmt->Indexfv = vbo_Indexfv;
702
703 }
704
705
706 #else /* FEATURE_beginend */
707
708
709 #define ATTR( A, N, V0, V1, V2, V3 ) \
710 do { \
711 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
712 \
713 /* FLUSH_UPDATE_CURRENT needs to be set manually */ \
714 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
715 \
716 if (exec->vtx.active_sz[A] != N) \
717 vbo_exec_fixup_vertex(ctx, A, N); \
718 \
719 { \
720 GLfloat *dest = exec->vtx.attrptr[A]; \
721 if (N>0) dest[0] = V0; \
722 if (N>1) dest[1] = V1; \
723 if (N>2) dest[2] = V2; \
724 if (N>3) dest[3] = V3; \
725 } \
726 } while (0)
727
728 #define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
729 #define TAG(x) vbo_##x
730
731 #include "vbo_attrib_tmp.h"
732
733 static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
734 {
735 /* silence warnings */
736 (void) vbo_Color3f;
737 (void) vbo_Color3fv;
738 (void) vbo_Color4f;
739 (void) vbo_Color4fv;
740 (void) vbo_FogCoordfEXT;
741 (void) vbo_FogCoordfvEXT;
742 (void) vbo_MultiTexCoord1f;
743 (void) vbo_MultiTexCoord1fv;
744 (void) vbo_MultiTexCoord2f;
745 (void) vbo_MultiTexCoord2fv;
746 (void) vbo_MultiTexCoord3f;
747 (void) vbo_MultiTexCoord3fv;
748 (void) vbo_MultiTexCoord4f;
749 (void) vbo_MultiTexCoord4fv;
750 (void) vbo_Normal3f;
751 (void) vbo_Normal3fv;
752 (void) vbo_SecondaryColor3fEXT;
753 (void) vbo_SecondaryColor3fvEXT;
754 (void) vbo_TexCoord1f;
755 (void) vbo_TexCoord1fv;
756 (void) vbo_TexCoord2f;
757 (void) vbo_TexCoord2fv;
758 (void) vbo_TexCoord3f;
759 (void) vbo_TexCoord3fv;
760 (void) vbo_TexCoord4f;
761 (void) vbo_TexCoord4fv;
762 (void) vbo_Vertex2f;
763 (void) vbo_Vertex2fv;
764 (void) vbo_Vertex3f;
765 (void) vbo_Vertex3fv;
766 (void) vbo_Vertex4f;
767 (void) vbo_Vertex4fv;
768
769 (void) vbo_VertexAttrib1fARB;
770 (void) vbo_VertexAttrib1fvARB;
771 (void) vbo_VertexAttrib2fARB;
772 (void) vbo_VertexAttrib2fvARB;
773 (void) vbo_VertexAttrib3fARB;
774 (void) vbo_VertexAttrib3fvARB;
775 (void) vbo_VertexAttrib4fARB;
776 (void) vbo_VertexAttrib4fvARB;
777
778 (void) vbo_VertexAttrib1fNV;
779 (void) vbo_VertexAttrib1fvNV;
780 (void) vbo_VertexAttrib2fNV;
781 (void) vbo_VertexAttrib2fvNV;
782 (void) vbo_VertexAttrib3fNV;
783 (void) vbo_VertexAttrib3fvNV;
784 (void) vbo_VertexAttrib4fNV;
785 (void) vbo_VertexAttrib4fvNV;
786
787 (void) vbo_Materialfv;
788
789 (void) vbo_EdgeFlag;
790 (void) vbo_Indexf;
791 (void) vbo_Indexfv;
792 }
793
794
795 #endif /* FEATURE_beginend */
796
797
798 /**
799 * Tell the VBO module to use a real OpenGL vertex buffer object to
800 * store accumulated immediate-mode vertex data.
801 * This replaces the malloced buffer which was created in
802 * vb_exec_vtx_init() below.
803 */
804 void vbo_use_buffer_objects(struct gl_context *ctx)
805 {
806 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
807 /* Any buffer name but 0 can be used here since this bufferobj won't
808 * go into the bufferobj hashtable.
809 */
810 GLuint bufName = IMM_BUFFER_NAME;
811 GLenum target = GL_ARRAY_BUFFER_ARB;
812 GLenum usage = GL_STREAM_DRAW_ARB;
813 GLsizei size = VBO_VERT_BUFFER_SIZE;
814
815 /* Make sure this func is only used once */
816 assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
817 if (exec->vtx.buffer_map) {
818 _mesa_align_free(exec->vtx.buffer_map);
819 exec->vtx.buffer_map = NULL;
820 exec->vtx.buffer_ptr = NULL;
821 }
822
823 /* Allocate a real buffer object now */
824 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
825 exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
826 ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
827 }
828
829
830
831 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
832 {
833 struct gl_context *ctx = exec->ctx;
834 struct vbo_context *vbo = vbo_context(ctx);
835 GLuint i;
836
837 /* Allocate a buffer object. Will just reuse this object
838 * continuously, unless vbo_use_buffer_objects() is called to enable
839 * use of real VBOs.
840 */
841 _mesa_reference_buffer_object(ctx,
842 &exec->vtx.bufferobj,
843 ctx->Shared->NullBufferObj);
844
845 ASSERT(!exec->vtx.buffer_map);
846 exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
847 exec->vtx.buffer_ptr = exec->vtx.buffer_map;
848
849 vbo_exec_vtxfmt_init( exec );
850
851 /* Hook our functions into the dispatch table.
852 */
853 _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
854
855 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
856 ASSERT(i < Elements(exec->vtx.attrsz));
857 exec->vtx.attrsz[i] = 0;
858 ASSERT(i < Elements(exec->vtx.active_sz));
859 exec->vtx.active_sz[i] = 0;
860 }
861 for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
862 ASSERT(i < Elements(exec->vtx.inputs));
863 ASSERT(i < Elements(exec->vtx.arrays));
864 exec->vtx.inputs[i] = &exec->vtx.arrays[i];
865 }
866
867 {
868 struct gl_client_array *arrays = exec->vtx.arrays;
869 unsigned i;
870
871 memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
872 memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
873
874 for (i = 0; i < 16; ++i) {
875 arrays[i ].BufferObj = NULL;
876 arrays[i + 16].BufferObj = NULL;
877 _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj,
878 vbo->legacy_currval[i].BufferObj);
879 _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
880 vbo->generic_currval[i].BufferObj);
881 }
882 }
883
884 exec->vtx.vertex_size = 0;
885 }
886
887
888 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
889 {
890 /* using a real VBO for vertex data */
891 struct gl_context *ctx = exec->ctx;
892 unsigned i;
893
894 /* True VBOs should already be unmapped
895 */
896 if (exec->vtx.buffer_map) {
897 ASSERT(exec->vtx.bufferobj->Name == 0 ||
898 exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
899 if (exec->vtx.bufferobj->Name == 0) {
900 _mesa_align_free(exec->vtx.buffer_map);
901 exec->vtx.buffer_map = NULL;
902 exec->vtx.buffer_ptr = NULL;
903 }
904 }
905
906 /* Drop any outstanding reference to the vertex buffer
907 */
908 for (i = 0; i < Elements(exec->vtx.arrays); i++) {
909 _mesa_reference_buffer_object(ctx,
910 &exec->vtx.arrays[i].BufferObj,
911 NULL);
912 }
913
914 /* Free the vertex buffer. Unmap first if needed.
915 */
916 if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
917 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
918 }
919 _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
920 }
921
922 void vbo_exec_BeginVertices( struct gl_context *ctx )
923 {
924 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
925 if (0) printf("%s\n", __FUNCTION__);
926 vbo_exec_vtx_map( exec );
927
928 assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
929 exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
930 }
931
932 void vbo_exec_FlushVertices_internal( struct gl_context *ctx, GLboolean unmap )
933 {
934 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
935
936 if (exec->vtx.vert_count || unmap) {
937 vbo_exec_vtx_flush( exec, unmap );
938 }
939
940 if (exec->vtx.vertex_size) {
941 vbo_exec_copy_to_current( exec );
942 reset_attrfv( exec );
943 }
944 }
945
946
947 /**
948 * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
949 */
950 void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
951 {
952 struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
953
954 #ifdef DEBUG
955 /* debug check: make sure we don't get called recursively */
956 exec->flush_call_depth++;
957 assert(exec->flush_call_depth == 1);
958 #endif
959
960 if (0) printf("%s\n", __FUNCTION__);
961
962 if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
963 if (0) printf("%s - inside begin/end\n", __FUNCTION__);
964 #ifdef DEBUG
965 exec->flush_call_depth--;
966 assert(exec->flush_call_depth == 0);
967 #endif
968 return;
969 }
970
971 vbo_exec_FlushVertices_internal( ctx, GL_TRUE );
972
973 /* Need to do this to ensure BeginVertices gets called again:
974 */
975 if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)
976 exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
977
978 exec->ctx->Driver.NeedFlush &= ~flags;
979
980 #ifdef DEBUG
981 exec->flush_call_depth--;
982 assert(exec->flush_call_depth == 0);
983 #endif
984 }
985
986
987 static void reset_attrfv( struct vbo_exec_context *exec )
988 {
989 GLuint i;
990
991 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
992 exec->vtx.attrsz[i] = 0;
993 exec->vtx.active_sz[i] = 0;
994 }
995
996 exec->vtx.vertex_size = 0;
997 }
998
999
1000 void GLAPIENTRY
1001 _vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1002 {
1003 vbo_Color4f(r, g, b, a);
1004 }
1005
1006
1007 void GLAPIENTRY
1008 _vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1009 {
1010 vbo_Normal3f(x, y, z);
1011 }
1012
1013
1014 void GLAPIENTRY
1015 _vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1016 {
1017 vbo_MultiTexCoord4f(target, s, t, r, q);
1018 }
1019
1020
1021 void GLAPIENTRY
1022 _vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1023 {
1024 vbo_Materialfv(face, pname, params);
1025 }
1026
1027
1028 void GLAPIENTRY
1029 _vbo_Materialf(GLenum face, GLenum pname, GLfloat param)
1030 {
1031 GLfloat p[4];
1032 p[0] = param;
1033 p[1] = p[2] = p[3] = 0.0F;
1034 vbo_Materialfv(face, pname, p);
1035 }
1036
1037
1038 void GLAPIENTRY
1039 _vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1040 {
1041 vbo_VertexAttrib4fARB(index, x, y, z, w);
1042 }
1043
1044
1045 void GLAPIENTRY
1046 _vbo_VertexAttrib1f(GLuint indx, GLfloat x)
1047 {
1048 vbo_VertexAttrib1fARB(indx, x);
1049 }
1050
1051
1052 void GLAPIENTRY
1053 _vbo_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1054 {
1055 vbo_VertexAttrib1fvARB(indx, values);
1056 }
1057
1058
1059 void GLAPIENTRY
1060 _vbo_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1061 {
1062 vbo_VertexAttrib2fARB(indx, x, y);
1063 }
1064
1065
1066 void GLAPIENTRY
1067 _vbo_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1068 {
1069 vbo_VertexAttrib2fvARB(indx, values);
1070 }
1071
1072
1073 void GLAPIENTRY
1074 _vbo_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1075 {
1076 vbo_VertexAttrib3fARB(indx, x, y, z);
1077 }
1078
1079
1080 void GLAPIENTRY
1081 _vbo_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1082 {
1083 vbo_VertexAttrib3fvARB(indx, values);
1084 }
1085
1086
1087 void GLAPIENTRY
1088 _vbo_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1089 {
1090 vbo_VertexAttrib4fvARB(indx, values);
1091 }