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