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