mesa; change ctx->Driver.SaveNeedFlush to boolean, and document it.
[mesa.git] / src / mesa / vbo / vbo_save_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
34
35 /* Display list compiler attempts to store lists of vertices with the
36 * same vertex layout. Additionally it attempts to minimize the need
37 * for execute-time fixup of these vertex lists, allowing them to be
38 * cached on hardware.
39 *
40 * There are still some circumstances where this can be thwarted, for
41 * example by building a list that consists of one very long primitive
42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43 * from inside a different begin/end object (Begin(Lines), CallList,
44 * End).
45 *
46 * In that case the code will have to replay the list as individual
47 * commands through the Exec dispatch table, or fix up the copied
48 * vertices at execute-time.
49 *
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
52 * Begin(Lines)
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
55 * End()
56 *
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
59 *
60 *
61 * The list compiler currently doesn't attempt to compile lists
62 * containing EvalCoord or EvalPoint commands. On encountering one of
63 * these, compilation falls back to opcodes.
64 *
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
67 */
68
69
70 #include "main/glheader.h"
71 #include "main/bufferobj.h"
72 #include "main/context.h"
73 #include "main/dlist.h"
74 #include "main/enums.h"
75 #include "main/eval.h"
76 #include "main/macros.h"
77 #include "main/api_validate.h"
78 #include "main/api_arrayelt.h"
79 #include "main/vtxfmt.h"
80 #include "main/dispatch.h"
81
82 #include "vbo_context.h"
83 #include "vbo_noop.h"
84
85
86 #ifdef ERROR
87 #undef ERROR
88 #endif
89
90
91 /* An interesting VBO number/name to help with debugging */
92 #define VBO_BUF_ID 12345
93
94
95 /*
96 * NOTE: Old 'parity' issue is gone, but copying can still be
97 * wrong-footed on replay.
98 */
99 static GLuint
100 _save_copy_vertices(struct gl_context *ctx,
101 const struct vbo_save_vertex_list *node,
102 const GLfloat * src_buffer)
103 {
104 struct vbo_save_context *save = &vbo_context(ctx)->save;
105 const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
106 GLuint nr = prim->count;
107 GLuint sz = save->vertex_size;
108 const GLfloat *src = src_buffer + prim->start * sz;
109 GLfloat *dst = save->copied.buffer;
110 GLuint ovf, i;
111
112 if (prim->end)
113 return 0;
114
115 switch (prim->mode) {
116 case GL_POINTS:
117 return 0;
118 case GL_LINES:
119 ovf = nr & 1;
120 for (i = 0; i < ovf; i++)
121 memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
122 sz * sizeof(GLfloat));
123 return i;
124 case GL_TRIANGLES:
125 ovf = nr % 3;
126 for (i = 0; i < ovf; i++)
127 memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
128 sz * sizeof(GLfloat));
129 return i;
130 case GL_QUADS:
131 ovf = nr & 3;
132 for (i = 0; i < ovf; i++)
133 memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
134 sz * sizeof(GLfloat));
135 return i;
136 case GL_LINE_STRIP:
137 if (nr == 0)
138 return 0;
139 else {
140 memcpy(dst, src + (nr - 1) * sz, sz * sizeof(GLfloat));
141 return 1;
142 }
143 case GL_LINE_LOOP:
144 case GL_TRIANGLE_FAN:
145 case GL_POLYGON:
146 if (nr == 0)
147 return 0;
148 else if (nr == 1) {
149 memcpy(dst, src + 0, sz * sizeof(GLfloat));
150 return 1;
151 }
152 else {
153 memcpy(dst, src + 0, sz * sizeof(GLfloat));
154 memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat));
155 return 2;
156 }
157 case GL_TRIANGLE_STRIP:
158 case GL_QUAD_STRIP:
159 switch (nr) {
160 case 0:
161 ovf = 0;
162 break;
163 case 1:
164 ovf = 1;
165 break;
166 default:
167 ovf = 2 + (nr & 1);
168 break;
169 }
170 for (i = 0; i < ovf; i++)
171 memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
172 sz * sizeof(GLfloat));
173 return i;
174 default:
175 assert(0);
176 return 0;
177 }
178 }
179
180
181 static struct vbo_save_vertex_store *
182 alloc_vertex_store(struct gl_context *ctx)
183 {
184 struct vbo_save_context *save = &vbo_context(ctx)->save;
185 struct vbo_save_vertex_store *vertex_store =
186 CALLOC_STRUCT(vbo_save_vertex_store);
187
188 /* obj->Name needs to be non-zero, but won't ever be examined more
189 * closely than that. In particular these buffers won't be entered
190 * into the hash and can never be confused with ones visible to the
191 * user. Perhaps there could be a special number for internal
192 * buffers:
193 */
194 vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx,
195 VBO_BUF_ID,
196 GL_ARRAY_BUFFER_ARB);
197 if (vertex_store->bufferobj) {
198 save->out_of_memory =
199 !ctx->Driver.BufferData(ctx,
200 GL_ARRAY_BUFFER_ARB,
201 VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
202 NULL, GL_STATIC_DRAW_ARB,
203 vertex_store->bufferobj);
204 }
205 else {
206 save->out_of_memory = GL_TRUE;
207 }
208
209 if (save->out_of_memory) {
210 _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
211 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
212 }
213
214 vertex_store->buffer = NULL;
215 vertex_store->used = 0;
216 vertex_store->refcount = 1;
217
218 return vertex_store;
219 }
220
221
222 static void
223 free_vertex_store(struct gl_context *ctx,
224 struct vbo_save_vertex_store *vertex_store)
225 {
226 assert(!vertex_store->buffer);
227
228 if (vertex_store->bufferobj) {
229 _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
230 }
231
232 free(vertex_store);
233 }
234
235
236 GLfloat *
237 vbo_save_map_vertex_store(struct gl_context *ctx,
238 struct vbo_save_vertex_store *vertex_store)
239 {
240 assert(vertex_store->bufferobj);
241 assert(!vertex_store->buffer);
242 if (vertex_store->bufferobj->Size > 0) {
243 vertex_store->buffer =
244 (GLfloat *) ctx->Driver.MapBufferRange(ctx, 0,
245 vertex_store->bufferobj->Size,
246 GL_MAP_WRITE_BIT, /* not used */
247 vertex_store->bufferobj);
248 assert(vertex_store->buffer);
249 return vertex_store->buffer + vertex_store->used;
250 }
251 else {
252 /* probably ran out of memory for buffers */
253 return NULL;
254 }
255 }
256
257
258 void
259 vbo_save_unmap_vertex_store(struct gl_context *ctx,
260 struct vbo_save_vertex_store *vertex_store)
261 {
262 if (vertex_store->bufferobj->Size > 0) {
263 ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj);
264 }
265 vertex_store->buffer = NULL;
266 }
267
268
269 static struct vbo_save_primitive_store *
270 alloc_prim_store(struct gl_context *ctx)
271 {
272 struct vbo_save_primitive_store *store =
273 CALLOC_STRUCT(vbo_save_primitive_store);
274 (void) ctx;
275 store->used = 0;
276 store->refcount = 1;
277 return store;
278 }
279
280
281 static void
282 _save_reset_counters(struct gl_context *ctx)
283 {
284 struct vbo_save_context *save = &vbo_context(ctx)->save;
285
286 save->prim = save->prim_store->buffer + save->prim_store->used;
287 save->buffer = save->vertex_store->buffer + save->vertex_store->used;
288
289 assert(save->buffer == save->buffer_ptr);
290
291 if (save->vertex_size)
292 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
293 save->vertex_size);
294 else
295 save->max_vert = 0;
296
297 save->vert_count = 0;
298 save->prim_count = 0;
299 save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
300 save->dangling_attr_ref = 0;
301 }
302
303 /**
304 * For a list of prims, try merging prims that can just be extensions of the
305 * previous prim.
306 */
307 static void
308 merge_prims(struct gl_context *ctx,
309 struct _mesa_prim *prim_list,
310 GLuint *prim_count)
311 {
312 GLuint i;
313 struct _mesa_prim *prev_prim = prim_list;
314
315 for (i = 1; i < *prim_count; i++) {
316 struct _mesa_prim *this_prim = prim_list + i;
317
318 vbo_try_prim_conversion(this_prim);
319
320 if (vbo_can_merge_prims(prev_prim, this_prim)) {
321 /* We've found a prim that just extend the previous one. Tack it
322 * onto the previous one, and let this primitive struct get dropped.
323 */
324 vbo_merge_prims(prev_prim, this_prim);
325 continue;
326 }
327
328 /* If any previous primitives have been dropped, then we need to copy
329 * this later one into the next available slot.
330 */
331 prev_prim++;
332 if (prev_prim != this_prim)
333 *prev_prim = *this_prim;
334 }
335
336 *prim_count = prev_prim - prim_list + 1;
337 }
338
339 /**
340 * Insert the active immediate struct onto the display list currently
341 * being built.
342 */
343 static void
344 _save_compile_vertex_list(struct gl_context *ctx)
345 {
346 struct vbo_save_context *save = &vbo_context(ctx)->save;
347 struct vbo_save_vertex_list *node;
348
349 /* Allocate space for this structure in the display list currently
350 * being compiled.
351 */
352 node = (struct vbo_save_vertex_list *)
353 _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node));
354
355 if (!node)
356 return;
357
358 /* Duplicate our template, increment refcounts to the storage structs:
359 */
360 memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
361 memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype));
362 node->vertex_size = save->vertex_size;
363 node->buffer_offset =
364 (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
365 node->count = save->vert_count;
366 node->wrap_count = save->copied.nr;
367 node->dangling_attr_ref = save->dangling_attr_ref;
368 node->prim = save->prim;
369 node->prim_count = save->prim_count;
370 node->vertex_store = save->vertex_store;
371 node->prim_store = save->prim_store;
372
373 node->vertex_store->refcount++;
374 node->prim_store->refcount++;
375
376 if (node->prim[0].no_current_update) {
377 node->current_size = 0;
378 node->current_data = NULL;
379 }
380 else {
381 node->current_size = node->vertex_size - node->attrsz[0];
382 node->current_data = NULL;
383
384 if (node->current_size) {
385 /* If the malloc fails, we just pull the data out of the VBO
386 * later instead.
387 */
388 node->current_data = malloc(node->current_size * sizeof(GLfloat));
389 if (node->current_data) {
390 const char *buffer = (const char *) save->vertex_store->buffer;
391 unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
392 unsigned vertex_offset = 0;
393
394 if (node->count)
395 vertex_offset =
396 (node->count - 1) * node->vertex_size * sizeof(GLfloat);
397
398 memcpy(node->current_data,
399 buffer + node->buffer_offset + vertex_offset + attr_offset,
400 node->current_size * sizeof(GLfloat));
401 }
402 }
403 }
404
405 assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0);
406
407 if (save->dangling_attr_ref)
408 ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
409
410 save->vertex_store->used += save->vertex_size * node->count;
411 save->prim_store->used += node->prim_count;
412
413 /* Copy duplicated vertices
414 */
415 save->copied.nr = _save_copy_vertices(ctx, node, save->buffer);
416
417 merge_prims(ctx, node->prim, &node->prim_count);
418
419 /* Deal with GL_COMPILE_AND_EXECUTE:
420 */
421 if (ctx->ExecuteFlag) {
422 struct _glapi_table *dispatch = GET_DISPATCH();
423
424 _glapi_set_dispatch(ctx->Exec);
425
426 vbo_loopback_vertex_list(ctx,
427 (const GLfloat *) ((const char *) save->
428 vertex_store->buffer +
429 node->buffer_offset),
430 node->attrsz, node->prim, node->prim_count,
431 node->wrap_count, node->vertex_size);
432
433 _glapi_set_dispatch(dispatch);
434 }
435
436 /* Decide whether the storage structs are full, or can be used for
437 * the next vertex lists as well.
438 */
439 if (save->vertex_store->used >
440 VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
441
442 /* Unmap old store:
443 */
444 vbo_save_unmap_vertex_store(ctx, save->vertex_store);
445
446 /* Release old reference:
447 */
448 save->vertex_store->refcount--;
449 assert(save->vertex_store->refcount != 0);
450 save->vertex_store = NULL;
451
452 /* Allocate and map new store:
453 */
454 save->vertex_store = alloc_vertex_store(ctx);
455 save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
456 save->out_of_memory = save->buffer_ptr == NULL;
457 }
458
459 if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
460 save->prim_store->refcount--;
461 assert(save->prim_store->refcount != 0);
462 save->prim_store = alloc_prim_store(ctx);
463 }
464
465 /* Reset our structures for the next run of vertices:
466 */
467 _save_reset_counters(ctx);
468 }
469
470
471 /**
472 * TODO -- If no new vertices have been stored, don't bother saving it.
473 */
474 static void
475 _save_wrap_buffers(struct gl_context *ctx)
476 {
477 struct vbo_save_context *save = &vbo_context(ctx)->save;
478 GLint i = save->prim_count - 1;
479 GLenum mode;
480 GLboolean weak;
481 GLboolean no_current_update;
482
483 assert(i < (GLint) save->prim_max);
484 assert(i >= 0);
485
486 /* Close off in-progress primitive.
487 */
488 save->prim[i].count = (save->vert_count - save->prim[i].start);
489 mode = save->prim[i].mode;
490 weak = save->prim[i].weak;
491 no_current_update = save->prim[i].no_current_update;
492
493 /* store the copied vertices, and allocate a new list.
494 */
495 _save_compile_vertex_list(ctx);
496
497 /* Restart interrupted primitive
498 */
499 save->prim[0].mode = mode;
500 save->prim[0].weak = weak;
501 save->prim[0].no_current_update = no_current_update;
502 save->prim[0].begin = 0;
503 save->prim[0].end = 0;
504 save->prim[0].pad = 0;
505 save->prim[0].start = 0;
506 save->prim[0].count = 0;
507 save->prim[0].num_instances = 1;
508 save->prim[0].base_instance = 0;
509 save->prim_count = 1;
510 }
511
512
513 /**
514 * Called only when buffers are wrapped as the result of filling the
515 * vertex_store struct.
516 */
517 static void
518 _save_wrap_filled_vertex(struct gl_context *ctx)
519 {
520 struct vbo_save_context *save = &vbo_context(ctx)->save;
521 GLfloat *data = save->copied.buffer;
522 GLuint i;
523
524 /* Emit a glEnd to close off the last vertex list.
525 */
526 _save_wrap_buffers(ctx);
527
528 /* Copy stored stored vertices to start of new list.
529 */
530 assert(save->max_vert - save->vert_count > save->copied.nr);
531
532 for (i = 0; i < save->copied.nr; i++) {
533 memcpy(save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
534 data += save->vertex_size;
535 save->buffer_ptr += save->vertex_size;
536 save->vert_count++;
537 }
538 }
539
540
541 static void
542 _save_copy_to_current(struct gl_context *ctx)
543 {
544 struct vbo_save_context *save = &vbo_context(ctx)->save;
545 GLuint i;
546
547 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
548 if (save->attrsz[i]) {
549 save->currentsz[i][0] = save->attrsz[i];
550 COPY_CLEAN_4V_TYPE_AS_FLOAT(save->current[i], save->attrsz[i],
551 save->attrptr[i], save->attrtype[i]);
552 }
553 }
554 }
555
556
557 static void
558 _save_copy_from_current(struct gl_context *ctx)
559 {
560 struct vbo_save_context *save = &vbo_context(ctx)->save;
561 GLint i;
562
563 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
564 switch (save->attrsz[i]) {
565 case 4:
566 save->attrptr[i][3] = save->current[i][3];
567 case 3:
568 save->attrptr[i][2] = save->current[i][2];
569 case 2:
570 save->attrptr[i][1] = save->current[i][1];
571 case 1:
572 save->attrptr[i][0] = save->current[i][0];
573 case 0:
574 break;
575 }
576 }
577 }
578
579
580 /* Flush existing data, set new attrib size, replay copied vertices.
581 */
582 static void
583 _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
584 {
585 struct vbo_save_context *save = &vbo_context(ctx)->save;
586 GLuint oldsz;
587 GLuint i;
588 GLfloat *tmp;
589
590 /* Store the current run of vertices, and emit a GL_END. Emit a
591 * BEGIN in the new buffer.
592 */
593 if (save->vert_count)
594 _save_wrap_buffers(ctx);
595 else
596 assert(save->copied.nr == 0);
597
598 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
599 * when the attribute already exists in the vertex and is having
600 * its size increased.
601 */
602 _save_copy_to_current(ctx);
603
604 /* Fix up sizes:
605 */
606 oldsz = save->attrsz[attr];
607 save->attrsz[attr] = newsz;
608
609 save->vertex_size += newsz - oldsz;
610 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
611 save->vertex_size);
612 save->vert_count = 0;
613
614 /* Recalculate all the attrptr[] values:
615 */
616 for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) {
617 if (save->attrsz[i]) {
618 save->attrptr[i] = tmp;
619 tmp += save->attrsz[i];
620 }
621 else {
622 save->attrptr[i] = NULL; /* will not be dereferenced. */
623 }
624 }
625
626 /* Copy from current to repopulate the vertex with correct values.
627 */
628 _save_copy_from_current(ctx);
629
630 /* Replay stored vertices to translate them to new format here.
631 *
632 * If there are copied vertices and the new (upgraded) attribute
633 * has not been defined before, this list is somewhat degenerate,
634 * and will need fixup at runtime.
635 */
636 if (save->copied.nr) {
637 GLfloat *data = save->copied.buffer;
638 GLfloat *dest = save->buffer;
639 GLuint j;
640
641 /* Need to note this and fix up at runtime (or loopback):
642 */
643 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
644 assert(oldsz == 0);
645 save->dangling_attr_ref = GL_TRUE;
646 }
647
648 for (i = 0; i < save->copied.nr; i++) {
649 for (j = 0; j < VBO_ATTRIB_MAX; j++) {
650 if (save->attrsz[j]) {
651 if (j == attr) {
652 if (oldsz) {
653 COPY_CLEAN_4V_TYPE_AS_FLOAT(dest, oldsz, data,
654 save->attrtype[j]);
655 data += oldsz;
656 dest += newsz;
657 }
658 else {
659 COPY_SZ_4V(dest, newsz, save->current[attr]);
660 dest += newsz;
661 }
662 }
663 else {
664 GLint sz = save->attrsz[j];
665 COPY_SZ_4V(dest, sz, data);
666 data += sz;
667 dest += sz;
668 }
669 }
670 }
671 }
672
673 save->buffer_ptr = dest;
674 save->vert_count += save->copied.nr;
675 }
676 }
677
678
679 static void
680 save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
681 {
682 struct vbo_save_context *save = &vbo_context(ctx)->save;
683
684 if (sz > save->attrsz[attr]) {
685 /* New size is larger. Need to flush existing vertices and get
686 * an enlarged vertex format.
687 */
688 _save_upgrade_vertex(ctx, attr, sz);
689 }
690 else if (sz < save->active_sz[attr]) {
691 GLuint i;
692 const GLfloat *id = vbo_get_default_vals_as_float(save->attrtype[attr]);
693
694 /* New size is equal or smaller - just need to fill in some
695 * zeros.
696 */
697 for (i = sz; i <= save->attrsz[attr]; i++)
698 save->attrptr[attr][i - 1] = id[i - 1];
699 }
700
701 save->active_sz[attr] = sz;
702 }
703
704
705 static void
706 _save_reset_vertex(struct gl_context *ctx)
707 {
708 struct vbo_save_context *save = &vbo_context(ctx)->save;
709 GLuint i;
710
711 for (i = 0; i < VBO_ATTRIB_MAX; i++) {
712 save->attrsz[i] = 0;
713 save->active_sz[i] = 0;
714 }
715
716 save->vertex_size = 0;
717 }
718
719
720
721 #define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__);
722
723
724 /* Only one size for each attribute may be active at once. Eg. if
725 * Color3f is installed/active, then Color4f may not be, even if the
726 * vertex actually contains 4 color coordinates. This is because the
727 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
728 * of the chooser function when switching between Color4f and Color3f.
729 */
730 #define ATTR(A, N, T, V0, V1, V2, V3) \
731 do { \
732 struct vbo_save_context *save = &vbo_context(ctx)->save; \
733 \
734 if (save->active_sz[A] != N) \
735 save_fixup_vertex(ctx, A, N); \
736 \
737 { \
738 GLfloat *dest = save->attrptr[A]; \
739 if (N>0) dest[0] = V0; \
740 if (N>1) dest[1] = V1; \
741 if (N>2) dest[2] = V2; \
742 if (N>3) dest[3] = V3; \
743 save->attrtype[A] = T; \
744 } \
745 \
746 if ((A) == 0) { \
747 GLuint i; \
748 \
749 for (i = 0; i < save->vertex_size; i++) \
750 save->buffer_ptr[i] = save->vertex[i]; \
751 \
752 save->buffer_ptr += save->vertex_size; \
753 \
754 if (++save->vert_count >= save->max_vert) \
755 _save_wrap_filled_vertex(ctx); \
756 } \
757 } while (0)
758
759 #define TAG(x) _save_##x
760
761 #include "vbo_attrib_tmp.h"
762
763
764
765 #define MAT( ATTR, N, face, params ) \
766 do { \
767 if (face != GL_BACK) \
768 MAT_ATTR( ATTR, N, params ); /* front */ \
769 if (face != GL_FRONT) \
770 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
771 } while (0)
772
773
774 /**
775 * Save a glMaterial call found between glBegin/End.
776 * glMaterial calls outside Begin/End are handled in dlist.c.
777 */
778 static void GLAPIENTRY
779 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
780 {
781 GET_CURRENT_CONTEXT(ctx);
782
783 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
784 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
785 return;
786 }
787
788 switch (pname) {
789 case GL_EMISSION:
790 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
791 break;
792 case GL_AMBIENT:
793 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
794 break;
795 case GL_DIFFUSE:
796 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
797 break;
798 case GL_SPECULAR:
799 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
800 break;
801 case GL_SHININESS:
802 if (*params < 0 || *params > ctx->Const.MaxShininess) {
803 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
804 }
805 else {
806 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
807 }
808 break;
809 case GL_COLOR_INDEXES:
810 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
811 break;
812 case GL_AMBIENT_AND_DIFFUSE:
813 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
814 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
815 break;
816 default:
817 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
818 return;
819 }
820 }
821
822
823 /* Cope with EvalCoord/CallList called within a begin/end object:
824 * -- Flush current buffer
825 * -- Fallback to opcodes for the rest of the begin/end object.
826 */
827 static void
828 dlist_fallback(struct gl_context *ctx)
829 {
830 struct vbo_save_context *save = &vbo_context(ctx)->save;
831
832 if (save->vert_count || save->prim_count) {
833 if (save->prim_count > 0) {
834 /* Close off in-progress primitive. */
835 GLint i = save->prim_count - 1;
836 save->prim[i].count = save->vert_count - save->prim[i].start;
837 }
838
839 /* Need to replay this display list with loopback,
840 * unfortunately, otherwise this primitive won't be handled
841 * properly:
842 */
843 save->dangling_attr_ref = 1;
844
845 _save_compile_vertex_list(ctx);
846 }
847
848 _save_copy_to_current(ctx);
849 _save_reset_vertex(ctx);
850 _save_reset_counters(ctx);
851 if (save->out_of_memory) {
852 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
853 }
854 else {
855 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
856 }
857 ctx->Driver.SaveNeedFlush = GL_FALSE;
858 }
859
860
861 static void GLAPIENTRY
862 _save_EvalCoord1f(GLfloat u)
863 {
864 GET_CURRENT_CONTEXT(ctx);
865 dlist_fallback(ctx);
866 CALL_EvalCoord1f(ctx->Save, (u));
867 }
868
869 static void GLAPIENTRY
870 _save_EvalCoord1fv(const GLfloat * v)
871 {
872 GET_CURRENT_CONTEXT(ctx);
873 dlist_fallback(ctx);
874 CALL_EvalCoord1fv(ctx->Save, (v));
875 }
876
877 static void GLAPIENTRY
878 _save_EvalCoord2f(GLfloat u, GLfloat v)
879 {
880 GET_CURRENT_CONTEXT(ctx);
881 dlist_fallback(ctx);
882 CALL_EvalCoord2f(ctx->Save, (u, v));
883 }
884
885 static void GLAPIENTRY
886 _save_EvalCoord2fv(const GLfloat * v)
887 {
888 GET_CURRENT_CONTEXT(ctx);
889 dlist_fallback(ctx);
890 CALL_EvalCoord2fv(ctx->Save, (v));
891 }
892
893 static void GLAPIENTRY
894 _save_EvalPoint1(GLint i)
895 {
896 GET_CURRENT_CONTEXT(ctx);
897 dlist_fallback(ctx);
898 CALL_EvalPoint1(ctx->Save, (i));
899 }
900
901 static void GLAPIENTRY
902 _save_EvalPoint2(GLint i, GLint j)
903 {
904 GET_CURRENT_CONTEXT(ctx);
905 dlist_fallback(ctx);
906 CALL_EvalPoint2(ctx->Save, (i, j));
907 }
908
909 static void GLAPIENTRY
910 _save_CallList(GLuint l)
911 {
912 GET_CURRENT_CONTEXT(ctx);
913 dlist_fallback(ctx);
914 CALL_CallList(ctx->Save, (l));
915 }
916
917 static void GLAPIENTRY
918 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
919 {
920 GET_CURRENT_CONTEXT(ctx);
921 dlist_fallback(ctx);
922 CALL_CallLists(ctx->Save, (n, type, v));
923 }
924
925
926
927 /**
928 * Called via ctx->Driver.NotifySaveBegin() when a glBegin is getting
929 * compiled into a display list.
930 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
931 */
932 GLboolean
933 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
934 {
935 struct vbo_save_context *save = &vbo_context(ctx)->save;
936
937 GLuint i = save->prim_count++;
938
939 assert(i < save->prim_max);
940 save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
941 save->prim[i].begin = 1;
942 save->prim[i].end = 0;
943 save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
944 save->prim[i].no_current_update =
945 (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
946 save->prim[i].pad = 0;
947 save->prim[i].start = save->vert_count;
948 save->prim[i].count = 0;
949 save->prim[i].num_instances = 1;
950 save->prim[i].base_instance = 0;
951
952 if (save->out_of_memory) {
953 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
954 }
955 else {
956 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
957 }
958
959 /* We need to call SaveFlushVertices() if there's state change */
960 ctx->Driver.SaveNeedFlush = GL_TRUE;
961
962 /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
963 * opcode into the display list.
964 */
965 return GL_TRUE;
966 }
967
968
969 static void GLAPIENTRY
970 _save_End(void)
971 {
972 GET_CURRENT_CONTEXT(ctx);
973 struct vbo_save_context *save = &vbo_context(ctx)->save;
974 GLint i = save->prim_count - 1;
975
976 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
977 save->prim[i].end = 1;
978 save->prim[i].count = (save->vert_count - save->prim[i].start);
979
980 if (i == (GLint) save->prim_max - 1) {
981 _save_compile_vertex_list(ctx);
982 assert(save->copied.nr == 0);
983 }
984
985 /* Swap out this vertex format while outside begin/end. Any color,
986 * etc. received between here and the next begin will be compiled
987 * as opcodes.
988 */
989 if (save->out_of_memory) {
990 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
991 }
992 else {
993 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
994 }
995 }
996
997
998 static void GLAPIENTRY
999 _save_Begin(GLenum mode)
1000 {
1001 GET_CURRENT_CONTEXT(ctx);
1002 (void) mode;
1003 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1004 }
1005
1006
1007 static void GLAPIENTRY
1008 _save_PrimitiveRestartNV(void)
1009 {
1010 GLenum curPrim;
1011 GET_CURRENT_CONTEXT(ctx);
1012
1013 curPrim = ctx->Driver.CurrentSavePrimitive;
1014
1015 _save_End();
1016 _save_Begin(curPrim);
1017 }
1018
1019
1020 /* Unlike the functions above, these are to be hooked into the vtxfmt
1021 * maintained in ctx->ListState, active when the list is known or
1022 * suspected to be outside any begin/end primitive.
1023 * Note: OBE = Outside Begin/End
1024 */
1025 static void GLAPIENTRY
1026 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1027 {
1028 GET_CURRENT_CONTEXT(ctx);
1029 vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
1030 CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
1031 CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
1032 CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
1033 CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
1034 CALL_End(GET_DISPATCH(), ());
1035 }
1036
1037
1038 static void GLAPIENTRY
1039 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1040 {
1041 GET_CURRENT_CONTEXT(ctx);
1042 struct vbo_save_context *save = &vbo_context(ctx)->save;
1043 GLint i;
1044
1045 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1046 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1047 return;
1048 }
1049 if (count < 0) {
1050 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1051 return;
1052 }
1053
1054 if (save->out_of_memory)
1055 return;
1056
1057 _ae_map_vbos(ctx);
1058
1059 vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
1060 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1061
1062 for (i = 0; i < count; i++)
1063 CALL_ArrayElement(GET_DISPATCH(), (start + i));
1064 CALL_End(GET_DISPATCH(), ());
1065
1066 _ae_unmap_vbos(ctx);
1067 }
1068
1069
1070 /* Could do better by copying the arrays and element list intact and
1071 * then emitting an indexed prim at runtime.
1072 */
1073 static void GLAPIENTRY
1074 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1075 const GLvoid * indices)
1076 {
1077 GET_CURRENT_CONTEXT(ctx);
1078 struct vbo_save_context *save = &vbo_context(ctx)->save;
1079 GLint i;
1080
1081 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1082 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1083 return;
1084 }
1085 if (count < 0) {
1086 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1087 return;
1088 }
1089 if (type != GL_UNSIGNED_BYTE &&
1090 type != GL_UNSIGNED_SHORT &&
1091 type != GL_UNSIGNED_INT) {
1092 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1093 return;
1094 }
1095
1096 if (save->out_of_memory)
1097 return;
1098
1099 _ae_map_vbos(ctx);
1100
1101 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj))
1102 indices =
1103 ADD_POINTERS(ctx->Array.ArrayObj->ElementArrayBufferObj->Pointer, indices);
1104
1105 vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
1106 VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1107
1108 switch (type) {
1109 case GL_UNSIGNED_BYTE:
1110 for (i = 0; i < count; i++)
1111 CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i]));
1112 break;
1113 case GL_UNSIGNED_SHORT:
1114 for (i = 0; i < count; i++)
1115 CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i]));
1116 break;
1117 case GL_UNSIGNED_INT:
1118 for (i = 0; i < count; i++)
1119 CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i]));
1120 break;
1121 default:
1122 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1123 break;
1124 }
1125
1126 CALL_End(GET_DISPATCH(), ());
1127
1128 _ae_unmap_vbos(ctx);
1129 }
1130
1131
1132 static void GLAPIENTRY
1133 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1134 GLsizei count, GLenum type,
1135 const GLvoid * indices)
1136 {
1137 GET_CURRENT_CONTEXT(ctx);
1138 struct vbo_save_context *save = &vbo_context(ctx)->save;
1139
1140 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1141 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1142 return;
1143 }
1144 if (count < 0) {
1145 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1146 "glDrawRangeElements(count<0)");
1147 return;
1148 }
1149 if (type != GL_UNSIGNED_BYTE &&
1150 type != GL_UNSIGNED_SHORT &&
1151 type != GL_UNSIGNED_INT) {
1152 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1153 return;
1154 }
1155 if (end < start) {
1156 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1157 "glDrawRangeElements(end < start)");
1158 return;
1159 }
1160
1161 if (save->out_of_memory)
1162 return;
1163
1164 _save_OBE_DrawElements(mode, count, type, indices);
1165 }
1166
1167
1168 static void GLAPIENTRY
1169 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1170 const GLvoid **indices, GLsizei primcount)
1171 {
1172 GLsizei i;
1173
1174 for (i = 0; i < primcount; i++) {
1175 if (count[i] > 0) {
1176 CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
1177 }
1178 }
1179 }
1180
1181
1182 static void GLAPIENTRY
1183 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1184 GLenum type,
1185 const GLvoid * const *indices,
1186 GLsizei primcount,
1187 const GLint *basevertex)
1188 {
1189 GLsizei i;
1190
1191 for (i = 0; i < primcount; i++) {
1192 if (count[i] > 0) {
1193 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
1194 indices[i],
1195 basevertex[i]));
1196 }
1197 }
1198 }
1199
1200
1201 static void
1202 _save_vtxfmt_init(struct gl_context *ctx)
1203 {
1204 struct vbo_save_context *save = &vbo_context(ctx)->save;
1205 GLvertexformat *vfmt = &save->vtxfmt;
1206
1207 vfmt->ArrayElement = _ae_ArrayElement;
1208
1209 vfmt->Color3f = _save_Color3f;
1210 vfmt->Color3fv = _save_Color3fv;
1211 vfmt->Color4f = _save_Color4f;
1212 vfmt->Color4fv = _save_Color4fv;
1213 vfmt->EdgeFlag = _save_EdgeFlag;
1214 vfmt->End = _save_End;
1215 vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1216 vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1217 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1218 vfmt->Indexf = _save_Indexf;
1219 vfmt->Indexfv = _save_Indexfv;
1220 vfmt->Materialfv = _save_Materialfv;
1221 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1222 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1223 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1224 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1225 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1226 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1227 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1228 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1229 vfmt->Normal3f = _save_Normal3f;
1230 vfmt->Normal3fv = _save_Normal3fv;
1231 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1232 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1233 vfmt->TexCoord1f = _save_TexCoord1f;
1234 vfmt->TexCoord1fv = _save_TexCoord1fv;
1235 vfmt->TexCoord2f = _save_TexCoord2f;
1236 vfmt->TexCoord2fv = _save_TexCoord2fv;
1237 vfmt->TexCoord3f = _save_TexCoord3f;
1238 vfmt->TexCoord3fv = _save_TexCoord3fv;
1239 vfmt->TexCoord4f = _save_TexCoord4f;
1240 vfmt->TexCoord4fv = _save_TexCoord4fv;
1241 vfmt->Vertex2f = _save_Vertex2f;
1242 vfmt->Vertex2fv = _save_Vertex2fv;
1243 vfmt->Vertex3f = _save_Vertex3f;
1244 vfmt->Vertex3fv = _save_Vertex3fv;
1245 vfmt->Vertex4f = _save_Vertex4f;
1246 vfmt->Vertex4fv = _save_Vertex4fv;
1247 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1248 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1249 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1250 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1251 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1252 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1253 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1254 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1255
1256 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1257 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1258 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1259 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1260 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1261 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1262 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1263 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1264
1265 /* integer-valued */
1266 vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1267 vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1268 vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1269 vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1270 vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1271 vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1272 vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1273
1274 /* unsigned integer-valued */
1275 vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1276 vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1277 vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1278 vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1279 vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1280 vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1281 vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1282
1283 vfmt->VertexP2ui = _save_VertexP2ui;
1284 vfmt->VertexP3ui = _save_VertexP3ui;
1285 vfmt->VertexP4ui = _save_VertexP4ui;
1286 vfmt->VertexP2uiv = _save_VertexP2uiv;
1287 vfmt->VertexP3uiv = _save_VertexP3uiv;
1288 vfmt->VertexP4uiv = _save_VertexP4uiv;
1289
1290 vfmt->TexCoordP1ui = _save_TexCoordP1ui;
1291 vfmt->TexCoordP2ui = _save_TexCoordP2ui;
1292 vfmt->TexCoordP3ui = _save_TexCoordP3ui;
1293 vfmt->TexCoordP4ui = _save_TexCoordP4ui;
1294 vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
1295 vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
1296 vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
1297 vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
1298
1299 vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
1300 vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
1301 vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
1302 vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
1303 vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
1304 vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
1305 vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
1306 vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
1307
1308 vfmt->NormalP3ui = _save_NormalP3ui;
1309 vfmt->NormalP3uiv = _save_NormalP3uiv;
1310
1311 vfmt->ColorP3ui = _save_ColorP3ui;
1312 vfmt->ColorP4ui = _save_ColorP4ui;
1313 vfmt->ColorP3uiv = _save_ColorP3uiv;
1314 vfmt->ColorP4uiv = _save_ColorP4uiv;
1315
1316 vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
1317 vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
1318
1319 vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
1320 vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
1321 vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
1322 vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
1323
1324 vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
1325 vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
1326 vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
1327 vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
1328
1329 /* This will all require us to fallback to saving the list as opcodes:
1330 */
1331 vfmt->CallList = _save_CallList;
1332 vfmt->CallLists = _save_CallLists;
1333
1334 vfmt->EvalCoord1f = _save_EvalCoord1f;
1335 vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1336 vfmt->EvalCoord2f = _save_EvalCoord2f;
1337 vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1338 vfmt->EvalPoint1 = _save_EvalPoint1;
1339 vfmt->EvalPoint2 = _save_EvalPoint2;
1340
1341 /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1342 * only used when we're inside a glBegin/End pair.
1343 */
1344 vfmt->Begin = _save_Begin;
1345 }
1346
1347
1348 /**
1349 * Initialize the dispatch table with the VBO functions for display
1350 * list compilation.
1351 */
1352 void
1353 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1354 struct _glapi_table *exec)
1355 {
1356 SET_DrawArrays(exec, _save_OBE_DrawArrays);
1357 SET_DrawElements(exec, _save_OBE_DrawElements);
1358 SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1359 SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1360 SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1361 SET_Rectf(exec, _save_OBE_Rectf);
1362 /* Note: other glDraw functins aren't compiled into display lists */
1363 }
1364
1365
1366
1367 void
1368 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1369 {
1370 struct vbo_save_context *save = &vbo_context(ctx)->save;
1371
1372 /* Noop when we are actually active:
1373 */
1374 if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1375 return;
1376
1377 if (save->vert_count || save->prim_count)
1378 _save_compile_vertex_list(ctx);
1379
1380 _save_copy_to_current(ctx);
1381 _save_reset_vertex(ctx);
1382 _save_reset_counters(ctx);
1383 ctx->Driver.SaveNeedFlush = GL_FALSE;
1384 }
1385
1386
1387 void
1388 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1389 {
1390 struct vbo_save_context *save = &vbo_context(ctx)->save;
1391
1392 (void) list;
1393 (void) mode;
1394
1395 if (!save->prim_store)
1396 save->prim_store = alloc_prim_store(ctx);
1397
1398 if (!save->vertex_store)
1399 save->vertex_store = alloc_vertex_store(ctx);
1400
1401 save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1402
1403 _save_reset_vertex(ctx);
1404 _save_reset_counters(ctx);
1405 ctx->Driver.SaveNeedFlush = GL_FALSE;
1406 }
1407
1408
1409 void
1410 vbo_save_EndList(struct gl_context *ctx)
1411 {
1412 struct vbo_save_context *save = &vbo_context(ctx)->save;
1413
1414 /* EndList called inside a (saved) Begin/End pair?
1415 */
1416 if (_mesa_inside_dlist_begin_end(ctx)) {
1417 if (save->prim_count > 0) {
1418 GLint i = save->prim_count - 1;
1419 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1420 save->prim[i].end = 0;
1421 save->prim[i].count = (save->vert_count - save->prim[i].start);
1422 }
1423
1424 /* Make sure this vertex list gets replayed by the "loopback"
1425 * mechanism:
1426 */
1427 save->dangling_attr_ref = 1;
1428 vbo_save_SaveFlushVertices(ctx);
1429
1430 /* Swap out this vertex format while outside begin/end. Any color,
1431 * etc. received between here and the next begin will be compiled
1432 * as opcodes.
1433 */
1434 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1435 }
1436
1437 vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1438
1439 assert(save->vertex_size == 0);
1440 }
1441
1442
1443 void
1444 vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1445 {
1446 struct vbo_save_context *save = &vbo_context(ctx)->save;
1447 save->replay_flags |= dlist->Flags;
1448 }
1449
1450
1451 void
1452 vbo_save_EndCallList(struct gl_context *ctx)
1453 {
1454 struct vbo_save_context *save = &vbo_context(ctx)->save;
1455
1456 if (ctx->ListState.CallDepth == 1) {
1457 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1458 * flag, if it is set:
1459 */
1460 save->replay_flags &= VBO_SAVE_FALLBACK;
1461 }
1462 }
1463
1464
1465 static void
1466 vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
1467 {
1468 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1469 (void) ctx;
1470
1471 if (--node->vertex_store->refcount == 0)
1472 free_vertex_store(ctx, node->vertex_store);
1473
1474 if (--node->prim_store->refcount == 0)
1475 free(node->prim_store);
1476
1477 free(node->current_data);
1478 node->current_data = NULL;
1479 }
1480
1481
1482 static void
1483 vbo_print_vertex_list(struct gl_context *ctx, void *data)
1484 {
1485 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1486 GLuint i;
1487 (void) ctx;
1488
1489 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1490 node->count, node->prim_count, node->vertex_size);
1491
1492 for (i = 0; i < node->prim_count; i++) {
1493 struct _mesa_prim *prim = &node->prim[i];
1494 printf(" prim %d: %s%s %d..%d %s %s\n",
1495 i,
1496 _mesa_lookup_prim_by_nr(prim->mode),
1497 prim->weak ? " (weak)" : "",
1498 prim->start,
1499 prim->start + prim->count,
1500 (prim->begin) ? "BEGIN" : "(wrap)",
1501 (prim->end) ? "END" : "(wrap)");
1502 }
1503 }
1504
1505
1506 /**
1507 * Called during context creation/init.
1508 */
1509 static void
1510 _save_current_init(struct gl_context *ctx)
1511 {
1512 struct vbo_save_context *save = &vbo_context(ctx)->save;
1513 GLint i;
1514
1515 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1516 const GLuint j = i - VBO_ATTRIB_POS;
1517 ASSERT(j < VERT_ATTRIB_MAX);
1518 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1519 save->current[i] = ctx->ListState.CurrentAttrib[j];
1520 }
1521
1522 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1523 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1524 ASSERT(j < MAT_ATTRIB_MAX);
1525 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1526 save->current[i] = ctx->ListState.CurrentMaterial[j];
1527 }
1528 }
1529
1530
1531 /**
1532 * Initialize the display list compiler. Called during context creation.
1533 */
1534 void
1535 vbo_save_api_init(struct vbo_save_context *save)
1536 {
1537 struct gl_context *ctx = save->ctx;
1538 GLuint i;
1539
1540 save->opcode_vertex_list =
1541 _mesa_dlist_alloc_opcode(ctx,
1542 sizeof(struct vbo_save_vertex_list),
1543 vbo_save_playback_vertex_list,
1544 vbo_destroy_vertex_list,
1545 vbo_print_vertex_list);
1546
1547 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
1548
1549 _save_vtxfmt_init(ctx);
1550 _save_current_init(ctx);
1551 _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
1552
1553 /* These will actually get set again when binding/drawing */
1554 for (i = 0; i < VBO_ATTRIB_MAX; i++)
1555 save->inputs[i] = &save->arrays[i];
1556 }