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