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