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