mesa: add const qualifier to glMultiDrawElementsEXT() indices param
[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 * This is called when we fill a vertex buffer before we hit a glEnd().
473 * We
474 * TODO -- If no new vertices have been stored, don't bother saving it.
475 */
476 static void
477 _save_wrap_buffers(struct gl_context *ctx)
478 {
479 struct vbo_save_context *save = &vbo_context(ctx)->save;
480 GLint i = save->prim_count - 1;
481 GLenum mode;
482 GLboolean weak;
483 GLboolean no_current_update;
484
485 assert(i < (GLint) save->prim_max);
486 assert(i >= 0);
487
488 /* Close off in-progress primitive.
489 */
490 save->prim[i].count = (save->vert_count - save->prim[i].start);
491 mode = save->prim[i].mode;
492 weak = save->prim[i].weak;
493 no_current_update = save->prim[i].no_current_update;
494
495 /* store the copied vertices, and allocate a new list.
496 */
497 _save_compile_vertex_list(ctx);
498
499 /* Restart interrupted primitive
500 */
501 save->prim[0].mode = mode;
502 save->prim[0].weak = weak;
503 save->prim[0].no_current_update = no_current_update;
504 save->prim[0].begin = 0;
505 save->prim[0].end = 0;
506 save->prim[0].pad = 0;
507 save->prim[0].start = 0;
508 save->prim[0].count = 0;
509 save->prim[0].num_instances = 1;
510 save->prim[0].base_instance = 0;
511 save->prim_count = 1;
512 }
513
514
515 /**
516 * Called only when buffers are wrapped as the result of filling the
517 * vertex_store struct.
518 */
519 static void
520 _save_wrap_filled_vertex(struct gl_context *ctx)
521 {
522 struct vbo_save_context *save = &vbo_context(ctx)->save;
523 GLfloat *data = save->copied.buffer;
524 GLuint i;
525
526 /* Emit a glEnd to close off the last vertex list.
527 */
528 _save_wrap_buffers(ctx);
529
530 /* Copy stored stored vertices to start of new list.
531 */
532 assert(save->max_vert - save->vert_count > save->copied.nr);
533
534 for (i = 0; i < save->copied.nr; i++) {
535 memcpy(save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
536 data += save->vertex_size;
537 save->buffer_ptr += save->vertex_size;
538 save->vert_count++;
539 }
540 }
541
542
543 static void
544 _save_copy_to_current(struct gl_context *ctx)
545 {
546 struct vbo_save_context *save = &vbo_context(ctx)->save;
547 GLuint i;
548
549 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
550 if (save->attrsz[i]) {
551 save->currentsz[i][0] = save->attrsz[i];
552 COPY_CLEAN_4V_TYPE_AS_FLOAT(save->current[i], save->attrsz[i],
553 save->attrptr[i], save->attrtype[i]);
554 }
555 }
556 }
557
558
559 static void
560 _save_copy_from_current(struct gl_context *ctx)
561 {
562 struct vbo_save_context *save = &vbo_context(ctx)->save;
563 GLint i;
564
565 for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
566 switch (save->attrsz[i]) {
567 case 4:
568 save->attrptr[i][3] = save->current[i][3];
569 case 3:
570 save->attrptr[i][2] = save->current[i][2];
571 case 2:
572 save->attrptr[i][1] = save->current[i][1];
573 case 1:
574 save->attrptr[i][0] = save->current[i][0];
575 case 0:
576 break;
577 }
578 }
579 }
580
581
582 /**
583 * Called when we increase the size of a vertex attribute. For example,
584 * if we've seen one or more glTexCoord2f() calls and now we get a
585 * glTexCoord3f() call.
586 * Flush existing data, set new attrib size, replay copied vertices.
587 */
588 static void
589 _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
590 {
591 struct vbo_save_context *save = &vbo_context(ctx)->save;
592 GLuint oldsz;
593 GLuint i;
594 GLfloat *tmp;
595
596 /* Store the current run of vertices, and emit a GL_END. Emit a
597 * BEGIN in the new buffer.
598 */
599 if (save->vert_count)
600 _save_wrap_buffers(ctx);
601 else
602 assert(save->copied.nr == 0);
603
604 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
605 * when the attribute already exists in the vertex and is having
606 * its size increased.
607 */
608 _save_copy_to_current(ctx);
609
610 /* Fix up sizes:
611 */
612 oldsz = save->attrsz[attr];
613 save->attrsz[attr] = newsz;
614
615 save->vertex_size += newsz - oldsz;
616 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
617 save->vertex_size);
618 save->vert_count = 0;
619
620 /* Recalculate all the attrptr[] values:
621 */
622 for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) {
623 if (save->attrsz[i]) {
624 save->attrptr[i] = tmp;
625 tmp += save->attrsz[i];
626 }
627 else {
628 save->attrptr[i] = NULL; /* will not be dereferenced. */
629 }
630 }
631
632 /* Copy from current to repopulate the vertex with correct values.
633 */
634 _save_copy_from_current(ctx);
635
636 /* Replay stored vertices to translate them to new format here.
637 *
638 * If there are copied vertices and the new (upgraded) attribute
639 * has not been defined before, this list is somewhat degenerate,
640 * and will need fixup at runtime.
641 */
642 if (save->copied.nr) {
643 const GLfloat *data = save->copied.buffer;
644 GLfloat *dest = save->buffer;
645 GLuint j;
646
647 /* Need to note this and fix up at runtime (or loopback):
648 */
649 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
650 assert(oldsz == 0);
651 save->dangling_attr_ref = GL_TRUE;
652 }
653
654 for (i = 0; i < save->copied.nr; i++) {
655 for (j = 0; j < VBO_ATTRIB_MAX; j++) {
656 if (save->attrsz[j]) {
657 if (j == attr) {
658 if (oldsz) {
659 COPY_CLEAN_4V_TYPE_AS_FLOAT(dest, oldsz, data,
660 save->attrtype[j]);
661 data += oldsz;
662 dest += newsz;
663 }
664 else {
665 COPY_SZ_4V(dest, newsz, save->current[attr]);
666 dest += newsz;
667 }
668 }
669 else {
670 GLint sz = save->attrsz[j];
671 COPY_SZ_4V(dest, sz, data);
672 data += sz;
673 dest += sz;
674 }
675 }
676 }
677 }
678
679 save->buffer_ptr = dest;
680 save->vert_count += save->copied.nr;
681 }
682 }
683
684
685 /**
686 * This is called when the size of a vertex attribute changes.
687 * For example, after seeing one or more glTexCoord2f() calls we
688 * get a glTexCoord4f() or glTexCoord1f() call.
689 */
690 static void
691 save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
692 {
693 struct vbo_save_context *save = &vbo_context(ctx)->save;
694
695 if (sz > save->attrsz[attr]) {
696 /* New size is larger. Need to flush existing vertices and get
697 * an enlarged vertex format.
698 */
699 _save_upgrade_vertex(ctx, attr, sz);
700 }
701 else if (sz < save->active_sz[attr]) {
702 GLuint i;
703 const GLfloat *id = vbo_get_default_vals_as_float(save->attrtype[attr]);
704
705 /* New size is equal or smaller - just need to fill in some
706 * zeros.
707 */
708 for (i = sz; i <= save->attrsz[attr]; i++)
709 save->attrptr[attr][i - 1] = id[i - 1];
710 }
711
712 save->active_sz[attr] = sz;
713 }
714
715
716 /**
717 * Reset the current size of all vertex attributes to the default
718 * value of 0. This signals that we haven't yet seen any per-vertex
719 * commands such as glNormal3f() or glTexCoord2f().
720 */
721 static void
722 _save_reset_vertex(struct gl_context *ctx)
723 {
724 struct vbo_save_context *save = &vbo_context(ctx)->save;
725 GLuint i;
726
727 for (i = 0; i < VBO_ATTRIB_MAX; i++) {
728 save->attrsz[i] = 0;
729 save->active_sz[i] = 0;
730 }
731
732 save->vertex_size = 0;
733 }
734
735
736
737 #define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__);
738
739
740 /* Only one size for each attribute may be active at once. Eg. if
741 * Color3f is installed/active, then Color4f may not be, even if the
742 * vertex actually contains 4 color coordinates. This is because the
743 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
744 * of the chooser function when switching between Color4f and Color3f.
745 */
746 #define ATTR(A, N, T, V0, V1, V2, V3) \
747 do { \
748 struct vbo_save_context *save = &vbo_context(ctx)->save; \
749 \
750 if (save->active_sz[A] != N) \
751 save_fixup_vertex(ctx, A, N); \
752 \
753 { \
754 GLfloat *dest = save->attrptr[A]; \
755 if (N>0) dest[0] = V0; \
756 if (N>1) dest[1] = V1; \
757 if (N>2) dest[2] = V2; \
758 if (N>3) dest[3] = V3; \
759 save->attrtype[A] = T; \
760 } \
761 \
762 if ((A) == 0) { \
763 GLuint i; \
764 \
765 for (i = 0; i < save->vertex_size; i++) \
766 save->buffer_ptr[i] = save->vertex[i]; \
767 \
768 save->buffer_ptr += save->vertex_size; \
769 \
770 if (++save->vert_count >= save->max_vert) \
771 _save_wrap_filled_vertex(ctx); \
772 } \
773 } while (0)
774
775 #define TAG(x) _save_##x
776
777 #include "vbo_attrib_tmp.h"
778
779
780
781 #define MAT( ATTR, N, face, params ) \
782 do { \
783 if (face != GL_BACK) \
784 MAT_ATTR( ATTR, N, params ); /* front */ \
785 if (face != GL_FRONT) \
786 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
787 } while (0)
788
789
790 /**
791 * Save a glMaterial call found between glBegin/End.
792 * glMaterial calls outside Begin/End are handled in dlist.c.
793 */
794 static void GLAPIENTRY
795 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
796 {
797 GET_CURRENT_CONTEXT(ctx);
798
799 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
800 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
801 return;
802 }
803
804 switch (pname) {
805 case GL_EMISSION:
806 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
807 break;
808 case GL_AMBIENT:
809 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
810 break;
811 case GL_DIFFUSE:
812 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
813 break;
814 case GL_SPECULAR:
815 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
816 break;
817 case GL_SHININESS:
818 if (*params < 0 || *params > ctx->Const.MaxShininess) {
819 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
820 }
821 else {
822 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
823 }
824 break;
825 case GL_COLOR_INDEXES:
826 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
827 break;
828 case GL_AMBIENT_AND_DIFFUSE:
829 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
830 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
831 break;
832 default:
833 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
834 return;
835 }
836 }
837
838
839 /* Cope with EvalCoord/CallList called within a begin/end object:
840 * -- Flush current buffer
841 * -- Fallback to opcodes for the rest of the begin/end object.
842 */
843 static void
844 dlist_fallback(struct gl_context *ctx)
845 {
846 struct vbo_save_context *save = &vbo_context(ctx)->save;
847
848 if (save->vert_count || save->prim_count) {
849 if (save->prim_count > 0) {
850 /* Close off in-progress primitive. */
851 GLint i = save->prim_count - 1;
852 save->prim[i].count = save->vert_count - save->prim[i].start;
853 }
854
855 /* Need to replay this display list with loopback,
856 * unfortunately, otherwise this primitive won't be handled
857 * properly:
858 */
859 save->dangling_attr_ref = 1;
860
861 _save_compile_vertex_list(ctx);
862 }
863
864 _save_copy_to_current(ctx);
865 _save_reset_vertex(ctx);
866 _save_reset_counters(ctx);
867 if (save->out_of_memory) {
868 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
869 }
870 else {
871 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
872 }
873 ctx->Driver.SaveNeedFlush = GL_FALSE;
874 }
875
876
877 static void GLAPIENTRY
878 _save_EvalCoord1f(GLfloat u)
879 {
880 GET_CURRENT_CONTEXT(ctx);
881 dlist_fallback(ctx);
882 CALL_EvalCoord1f(ctx->Save, (u));
883 }
884
885 static void GLAPIENTRY
886 _save_EvalCoord1fv(const GLfloat * v)
887 {
888 GET_CURRENT_CONTEXT(ctx);
889 dlist_fallback(ctx);
890 CALL_EvalCoord1fv(ctx->Save, (v));
891 }
892
893 static void GLAPIENTRY
894 _save_EvalCoord2f(GLfloat u, GLfloat v)
895 {
896 GET_CURRENT_CONTEXT(ctx);
897 dlist_fallback(ctx);
898 CALL_EvalCoord2f(ctx->Save, (u, v));
899 }
900
901 static void GLAPIENTRY
902 _save_EvalCoord2fv(const GLfloat * v)
903 {
904 GET_CURRENT_CONTEXT(ctx);
905 dlist_fallback(ctx);
906 CALL_EvalCoord2fv(ctx->Save, (v));
907 }
908
909 static void GLAPIENTRY
910 _save_EvalPoint1(GLint i)
911 {
912 GET_CURRENT_CONTEXT(ctx);
913 dlist_fallback(ctx);
914 CALL_EvalPoint1(ctx->Save, (i));
915 }
916
917 static void GLAPIENTRY
918 _save_EvalPoint2(GLint i, GLint j)
919 {
920 GET_CURRENT_CONTEXT(ctx);
921 dlist_fallback(ctx);
922 CALL_EvalPoint2(ctx->Save, (i, j));
923 }
924
925 static void GLAPIENTRY
926 _save_CallList(GLuint l)
927 {
928 GET_CURRENT_CONTEXT(ctx);
929 dlist_fallback(ctx);
930 CALL_CallList(ctx->Save, (l));
931 }
932
933 static void GLAPIENTRY
934 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
935 {
936 GET_CURRENT_CONTEXT(ctx);
937 dlist_fallback(ctx);
938 CALL_CallLists(ctx->Save, (n, type, v));
939 }
940
941
942
943 /**
944 * Called via ctx->Driver.NotifySaveBegin() when a glBegin is getting
945 * compiled into a display list.
946 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
947 */
948 GLboolean
949 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
950 {
951 struct vbo_save_context *save = &vbo_context(ctx)->save;
952 const GLuint i = save->prim_count++;
953
954 assert(i < save->prim_max);
955 save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
956 save->prim[i].begin = 1;
957 save->prim[i].end = 0;
958 save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
959 save->prim[i].no_current_update =
960 (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
961 save->prim[i].pad = 0;
962 save->prim[i].start = save->vert_count;
963 save->prim[i].count = 0;
964 save->prim[i].num_instances = 1;
965 save->prim[i].base_instance = 0;
966
967 if (save->out_of_memory) {
968 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
969 }
970 else {
971 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
972 }
973
974 /* We need to call SaveFlushVertices() if there's state change */
975 ctx->Driver.SaveNeedFlush = GL_TRUE;
976
977 /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
978 * opcode into the display list.
979 */
980 return GL_TRUE;
981 }
982
983
984 static void GLAPIENTRY
985 _save_End(void)
986 {
987 GET_CURRENT_CONTEXT(ctx);
988 struct vbo_save_context *save = &vbo_context(ctx)->save;
989 const GLint i = save->prim_count - 1;
990
991 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
992 save->prim[i].end = 1;
993 save->prim[i].count = (save->vert_count - save->prim[i].start);
994
995 if (i == (GLint) save->prim_max - 1) {
996 _save_compile_vertex_list(ctx);
997 assert(save->copied.nr == 0);
998 }
999
1000 /* Swap out this vertex format while outside begin/end. Any color,
1001 * etc. received between here and the next begin will be compiled
1002 * as opcodes.
1003 */
1004 if (save->out_of_memory) {
1005 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1006 }
1007 else {
1008 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1009 }
1010 }
1011
1012
1013 static void GLAPIENTRY
1014 _save_Begin(GLenum mode)
1015 {
1016 GET_CURRENT_CONTEXT(ctx);
1017 (void) mode;
1018 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1019 }
1020
1021
1022 static void GLAPIENTRY
1023 _save_PrimitiveRestartNV(void)
1024 {
1025 GLenum curPrim;
1026 GET_CURRENT_CONTEXT(ctx);
1027
1028 curPrim = ctx->Driver.CurrentSavePrimitive;
1029
1030 _save_End();
1031 _save_Begin(curPrim);
1032 }
1033
1034
1035 /* Unlike the functions above, these are to be hooked into the vtxfmt
1036 * maintained in ctx->ListState, active when the list is known or
1037 * suspected to be outside any begin/end primitive.
1038 * Note: OBE = Outside Begin/End
1039 */
1040 static void GLAPIENTRY
1041 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1042 {
1043 GET_CURRENT_CONTEXT(ctx);
1044 vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
1045 CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
1046 CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
1047 CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
1048 CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
1049 CALL_End(GET_DISPATCH(), ());
1050 }
1051
1052
1053 static void GLAPIENTRY
1054 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1055 {
1056 GET_CURRENT_CONTEXT(ctx);
1057 struct vbo_save_context *save = &vbo_context(ctx)->save;
1058 GLint i;
1059
1060 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1061 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1062 return;
1063 }
1064 if (count < 0) {
1065 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1066 return;
1067 }
1068
1069 if (save->out_of_memory)
1070 return;
1071
1072 _ae_map_vbos(ctx);
1073
1074 vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
1075 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1076
1077 for (i = 0; i < count; i++)
1078 CALL_ArrayElement(GET_DISPATCH(), (start + i));
1079 CALL_End(GET_DISPATCH(), ());
1080
1081 _ae_unmap_vbos(ctx);
1082 }
1083
1084
1085 /* Could do better by copying the arrays and element list intact and
1086 * then emitting an indexed prim at runtime.
1087 */
1088 static void GLAPIENTRY
1089 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1090 const GLvoid * indices)
1091 {
1092 GET_CURRENT_CONTEXT(ctx);
1093 struct vbo_save_context *save = &vbo_context(ctx)->save;
1094 GLint i;
1095
1096 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1097 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1098 return;
1099 }
1100 if (count < 0) {
1101 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1102 return;
1103 }
1104 if (type != GL_UNSIGNED_BYTE &&
1105 type != GL_UNSIGNED_SHORT &&
1106 type != GL_UNSIGNED_INT) {
1107 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1108 return;
1109 }
1110
1111 if (save->out_of_memory)
1112 return;
1113
1114 _ae_map_vbos(ctx);
1115
1116 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj))
1117 indices =
1118 ADD_POINTERS(ctx->Array.ArrayObj->ElementArrayBufferObj->Pointer, indices);
1119
1120 vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
1121 VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1122
1123 switch (type) {
1124 case GL_UNSIGNED_BYTE:
1125 for (i = 0; i < count; i++)
1126 CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i]));
1127 break;
1128 case GL_UNSIGNED_SHORT:
1129 for (i = 0; i < count; i++)
1130 CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i]));
1131 break;
1132 case GL_UNSIGNED_INT:
1133 for (i = 0; i < count; i++)
1134 CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i]));
1135 break;
1136 default:
1137 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1138 break;
1139 }
1140
1141 CALL_End(GET_DISPATCH(), ());
1142
1143 _ae_unmap_vbos(ctx);
1144 }
1145
1146
1147 static void GLAPIENTRY
1148 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1149 GLsizei count, GLenum type,
1150 const GLvoid * indices)
1151 {
1152 GET_CURRENT_CONTEXT(ctx);
1153 struct vbo_save_context *save = &vbo_context(ctx)->save;
1154
1155 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1156 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1157 return;
1158 }
1159 if (count < 0) {
1160 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1161 "glDrawRangeElements(count<0)");
1162 return;
1163 }
1164 if (type != GL_UNSIGNED_BYTE &&
1165 type != GL_UNSIGNED_SHORT &&
1166 type != GL_UNSIGNED_INT) {
1167 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1168 return;
1169 }
1170 if (end < start) {
1171 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1172 "glDrawRangeElements(end < start)");
1173 return;
1174 }
1175
1176 if (save->out_of_memory)
1177 return;
1178
1179 _save_OBE_DrawElements(mode, count, type, indices);
1180 }
1181
1182
1183 static void GLAPIENTRY
1184 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1185 const GLvoid * const *indices, GLsizei primcount)
1186 {
1187 GLsizei i;
1188
1189 for (i = 0; i < primcount; i++) {
1190 if (count[i] > 0) {
1191 CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
1192 }
1193 }
1194 }
1195
1196
1197 static void GLAPIENTRY
1198 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1199 GLenum type,
1200 const GLvoid * const *indices,
1201 GLsizei primcount,
1202 const GLint *basevertex)
1203 {
1204 GLsizei i;
1205
1206 for (i = 0; i < primcount; i++) {
1207 if (count[i] > 0) {
1208 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
1209 indices[i],
1210 basevertex[i]));
1211 }
1212 }
1213 }
1214
1215
1216 static void
1217 _save_vtxfmt_init(struct gl_context *ctx)
1218 {
1219 struct vbo_save_context *save = &vbo_context(ctx)->save;
1220 GLvertexformat *vfmt = &save->vtxfmt;
1221
1222 vfmt->ArrayElement = _ae_ArrayElement;
1223
1224 vfmt->Color3f = _save_Color3f;
1225 vfmt->Color3fv = _save_Color3fv;
1226 vfmt->Color4f = _save_Color4f;
1227 vfmt->Color4fv = _save_Color4fv;
1228 vfmt->EdgeFlag = _save_EdgeFlag;
1229 vfmt->End = _save_End;
1230 vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1231 vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1232 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1233 vfmt->Indexf = _save_Indexf;
1234 vfmt->Indexfv = _save_Indexfv;
1235 vfmt->Materialfv = _save_Materialfv;
1236 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1237 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1238 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1239 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1240 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1241 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1242 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1243 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1244 vfmt->Normal3f = _save_Normal3f;
1245 vfmt->Normal3fv = _save_Normal3fv;
1246 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1247 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1248 vfmt->TexCoord1f = _save_TexCoord1f;
1249 vfmt->TexCoord1fv = _save_TexCoord1fv;
1250 vfmt->TexCoord2f = _save_TexCoord2f;
1251 vfmt->TexCoord2fv = _save_TexCoord2fv;
1252 vfmt->TexCoord3f = _save_TexCoord3f;
1253 vfmt->TexCoord3fv = _save_TexCoord3fv;
1254 vfmt->TexCoord4f = _save_TexCoord4f;
1255 vfmt->TexCoord4fv = _save_TexCoord4fv;
1256 vfmt->Vertex2f = _save_Vertex2f;
1257 vfmt->Vertex2fv = _save_Vertex2fv;
1258 vfmt->Vertex3f = _save_Vertex3f;
1259 vfmt->Vertex3fv = _save_Vertex3fv;
1260 vfmt->Vertex4f = _save_Vertex4f;
1261 vfmt->Vertex4fv = _save_Vertex4fv;
1262 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1263 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1264 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1265 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1266 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1267 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1268 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1269 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1270
1271 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1272 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1273 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1274 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1275 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1276 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1277 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1278 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1279
1280 /* integer-valued */
1281 vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1282 vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1283 vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1284 vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1285 vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1286 vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1287 vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1288
1289 /* unsigned integer-valued */
1290 vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1291 vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1292 vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1293 vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1294 vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1295 vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1296 vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1297
1298 vfmt->VertexP2ui = _save_VertexP2ui;
1299 vfmt->VertexP3ui = _save_VertexP3ui;
1300 vfmt->VertexP4ui = _save_VertexP4ui;
1301 vfmt->VertexP2uiv = _save_VertexP2uiv;
1302 vfmt->VertexP3uiv = _save_VertexP3uiv;
1303 vfmt->VertexP4uiv = _save_VertexP4uiv;
1304
1305 vfmt->TexCoordP1ui = _save_TexCoordP1ui;
1306 vfmt->TexCoordP2ui = _save_TexCoordP2ui;
1307 vfmt->TexCoordP3ui = _save_TexCoordP3ui;
1308 vfmt->TexCoordP4ui = _save_TexCoordP4ui;
1309 vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
1310 vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
1311 vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
1312 vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
1313
1314 vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
1315 vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
1316 vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
1317 vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
1318 vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
1319 vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
1320 vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
1321 vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
1322
1323 vfmt->NormalP3ui = _save_NormalP3ui;
1324 vfmt->NormalP3uiv = _save_NormalP3uiv;
1325
1326 vfmt->ColorP3ui = _save_ColorP3ui;
1327 vfmt->ColorP4ui = _save_ColorP4ui;
1328 vfmt->ColorP3uiv = _save_ColorP3uiv;
1329 vfmt->ColorP4uiv = _save_ColorP4uiv;
1330
1331 vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
1332 vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
1333
1334 vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
1335 vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
1336 vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
1337 vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
1338
1339 vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
1340 vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
1341 vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
1342 vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
1343
1344 /* This will all require us to fallback to saving the list as opcodes:
1345 */
1346 vfmt->CallList = _save_CallList;
1347 vfmt->CallLists = _save_CallLists;
1348
1349 vfmt->EvalCoord1f = _save_EvalCoord1f;
1350 vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1351 vfmt->EvalCoord2f = _save_EvalCoord2f;
1352 vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1353 vfmt->EvalPoint1 = _save_EvalPoint1;
1354 vfmt->EvalPoint2 = _save_EvalPoint2;
1355
1356 /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1357 * only used when we're inside a glBegin/End pair.
1358 */
1359 vfmt->Begin = _save_Begin;
1360 }
1361
1362
1363 /**
1364 * Initialize the dispatch table with the VBO functions for display
1365 * list compilation.
1366 */
1367 void
1368 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1369 struct _glapi_table *exec)
1370 {
1371 SET_DrawArrays(exec, _save_OBE_DrawArrays);
1372 SET_DrawElements(exec, _save_OBE_DrawElements);
1373 SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1374 SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1375 SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1376 SET_Rectf(exec, _save_OBE_Rectf);
1377 /* Note: other glDraw functins aren't compiled into display lists */
1378 }
1379
1380
1381
1382 void
1383 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1384 {
1385 struct vbo_save_context *save = &vbo_context(ctx)->save;
1386
1387 /* Noop when we are actually active:
1388 */
1389 if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1390 return;
1391
1392 if (save->vert_count || save->prim_count)
1393 _save_compile_vertex_list(ctx);
1394
1395 _save_copy_to_current(ctx);
1396 _save_reset_vertex(ctx);
1397 _save_reset_counters(ctx);
1398 ctx->Driver.SaveNeedFlush = GL_FALSE;
1399 }
1400
1401
1402 void
1403 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1404 {
1405 struct vbo_save_context *save = &vbo_context(ctx)->save;
1406
1407 (void) list;
1408 (void) mode;
1409
1410 if (!save->prim_store)
1411 save->prim_store = alloc_prim_store(ctx);
1412
1413 if (!save->vertex_store)
1414 save->vertex_store = alloc_vertex_store(ctx);
1415
1416 save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1417
1418 _save_reset_vertex(ctx);
1419 _save_reset_counters(ctx);
1420 ctx->Driver.SaveNeedFlush = GL_FALSE;
1421 }
1422
1423
1424 void
1425 vbo_save_EndList(struct gl_context *ctx)
1426 {
1427 struct vbo_save_context *save = &vbo_context(ctx)->save;
1428
1429 /* EndList called inside a (saved) Begin/End pair?
1430 */
1431 if (_mesa_inside_dlist_begin_end(ctx)) {
1432 if (save->prim_count > 0) {
1433 GLint i = save->prim_count - 1;
1434 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1435 save->prim[i].end = 0;
1436 save->prim[i].count = (save->vert_count - save->prim[i].start);
1437 }
1438
1439 /* Make sure this vertex list gets replayed by the "loopback"
1440 * mechanism:
1441 */
1442 save->dangling_attr_ref = 1;
1443 vbo_save_SaveFlushVertices(ctx);
1444
1445 /* Swap out this vertex format while outside begin/end. Any color,
1446 * etc. received between here and the next begin will be compiled
1447 * as opcodes.
1448 */
1449 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1450 }
1451
1452 vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1453
1454 assert(save->vertex_size == 0);
1455 }
1456
1457
1458 void
1459 vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1460 {
1461 struct vbo_save_context *save = &vbo_context(ctx)->save;
1462 save->replay_flags |= dlist->Flags;
1463 }
1464
1465
1466 void
1467 vbo_save_EndCallList(struct gl_context *ctx)
1468 {
1469 struct vbo_save_context *save = &vbo_context(ctx)->save;
1470
1471 if (ctx->ListState.CallDepth == 1) {
1472 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1473 * flag, if it is set:
1474 */
1475 save->replay_flags &= VBO_SAVE_FALLBACK;
1476 }
1477 }
1478
1479
1480 static void
1481 vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
1482 {
1483 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1484 (void) ctx;
1485
1486 if (--node->vertex_store->refcount == 0)
1487 free_vertex_store(ctx, node->vertex_store);
1488
1489 if (--node->prim_store->refcount == 0)
1490 free(node->prim_store);
1491
1492 free(node->current_data);
1493 node->current_data = NULL;
1494 }
1495
1496
1497 static void
1498 vbo_print_vertex_list(struct gl_context *ctx, void *data)
1499 {
1500 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1501 GLuint i;
1502 (void) ctx;
1503
1504 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1505 node->count, node->prim_count, node->vertex_size);
1506
1507 for (i = 0; i < node->prim_count; i++) {
1508 struct _mesa_prim *prim = &node->prim[i];
1509 printf(" prim %d: %s%s %d..%d %s %s\n",
1510 i,
1511 _mesa_lookup_prim_by_nr(prim->mode),
1512 prim->weak ? " (weak)" : "",
1513 prim->start,
1514 prim->start + prim->count,
1515 (prim->begin) ? "BEGIN" : "(wrap)",
1516 (prim->end) ? "END" : "(wrap)");
1517 }
1518 }
1519
1520
1521 /**
1522 * Called during context creation/init.
1523 */
1524 static void
1525 _save_current_init(struct gl_context *ctx)
1526 {
1527 struct vbo_save_context *save = &vbo_context(ctx)->save;
1528 GLint i;
1529
1530 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1531 const GLuint j = i - VBO_ATTRIB_POS;
1532 ASSERT(j < VERT_ATTRIB_MAX);
1533 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1534 save->current[i] = ctx->ListState.CurrentAttrib[j];
1535 }
1536
1537 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1538 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1539 ASSERT(j < MAT_ATTRIB_MAX);
1540 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1541 save->current[i] = ctx->ListState.CurrentMaterial[j];
1542 }
1543 }
1544
1545
1546 /**
1547 * Initialize the display list compiler. Called during context creation.
1548 */
1549 void
1550 vbo_save_api_init(struct vbo_save_context *save)
1551 {
1552 struct gl_context *ctx = save->ctx;
1553 GLuint i;
1554
1555 save->opcode_vertex_list =
1556 _mesa_dlist_alloc_opcode(ctx,
1557 sizeof(struct vbo_save_vertex_list),
1558 vbo_save_playback_vertex_list,
1559 vbo_destroy_vertex_list,
1560 vbo_print_vertex_list);
1561
1562 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
1563
1564 _save_vtxfmt_init(ctx);
1565 _save_current_init(ctx);
1566 _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
1567
1568 /* These will actually get set again when binding/drawing */
1569 for (i = 0; i < VBO_ATTRIB_MAX; i++)
1570 save->inputs[i] = &save->arrays[i];
1571 }