mesa: implement core Mesa support for GL_ARB_draw_instanced
[mesa.git] / src / mesa / vbo / vbo_save_api.c
1 /**************************************************************************
2
3 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
4
5 All Rights Reserved.
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Keith Whitwell <keith@tungstengraphics.com>
31 */
32
33
34
35 /* Display list compiler attempts to store lists of vertices with the
36 * same vertex layout. Additionally it attempts to minimize the need
37 * for execute-time fixup of these vertex lists, allowing them to be
38 * cached on hardware.
39 *
40 * There are still some circumstances where this can be thwarted, for
41 * example by building a list that consists of one very long primitive
42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43 * from inside a different begin/end object (Begin(Lines), CallList,
44 * End).
45 *
46 * In that case the code will have to replay the list as individual
47 * commands through the Exec dispatch table, or fix up the copied
48 * vertices at execute-time.
49 *
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
52 * Begin(Lines)
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
55 * End()
56 *
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
59 *
60 *
61 * The list compiler currently doesn't attempt to compile lists
62 * containing EvalCoord or EvalPoint commands. On encountering one of
63 * these, compilation falls back to opcodes.
64 *
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
67 */
68
69
70 #include "main/glheader.h"
71 #include "main/bufferobj.h"
72 #include "main/context.h"
73 #include "main/dlist.h"
74 #include "main/enums.h"
75 #include "main/eval.h"
76 #include "main/macros.h"
77 #include "main/api_noop.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
85
86 #ifdef ERROR
87 #undef ERROR
88 #endif
89
90
91 /* An interesting VBO number/name to help with debugging */
92 #define VBO_BUF_ID 12345
93
94
95 /*
96 * NOTE: Old 'parity' issue is gone, but copying can still be
97 * wrong-footed on replay.
98 */
99 static GLuint _save_copy_vertices( GLcontext *ctx,
100 const struct vbo_save_vertex_list *node,
101 const GLfloat *src_buffer)
102 {
103 struct vbo_save_context *save = &vbo_context( ctx )->save;
104 const struct _mesa_prim *prim = &node->prim[node->prim_count-1];
105 GLuint nr = prim->count;
106 GLuint sz = save->vertex_size;
107 const GLfloat *src = src_buffer + prim->start * sz;
108 GLfloat *dst = save->copied.buffer;
109 GLuint ovf, i;
110
111 if (prim->end)
112 return 0;
113
114 switch( prim->mode )
115 {
116 case GL_POINTS:
117 return 0;
118 case GL_LINES:
119 ovf = nr&1;
120 for (i = 0 ; i < ovf ; i++)
121 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
122 return i;
123 case GL_TRIANGLES:
124 ovf = nr%3;
125 for (i = 0 ; i < ovf ; i++)
126 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
127 return i;
128 case GL_QUADS:
129 ovf = nr&3;
130 for (i = 0 ; i < ovf ; i++)
131 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
132 return i;
133 case GL_LINE_STRIP:
134 if (nr == 0)
135 return 0;
136 else {
137 memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
138 return 1;
139 }
140 case GL_LINE_LOOP:
141 case GL_TRIANGLE_FAN:
142 case GL_POLYGON:
143 if (nr == 0)
144 return 0;
145 else if (nr == 1) {
146 memcpy( dst, src+0, sz*sizeof(GLfloat) );
147 return 1;
148 } else {
149 memcpy( dst, src+0, sz*sizeof(GLfloat) );
150 memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
151 return 2;
152 }
153 case GL_TRIANGLE_STRIP:
154 case GL_QUAD_STRIP:
155 switch (nr) {
156 case 0: ovf = 0; break;
157 case 1: ovf = 1; break;
158 default: ovf = 2 + (nr&1); break;
159 }
160 for (i = 0 ; i < ovf ; i++)
161 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
162 return i;
163 default:
164 assert(0);
165 return 0;
166 }
167 }
168
169
170 static struct vbo_save_vertex_store *alloc_vertex_store( GLcontext *ctx )
171 {
172 struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store);
173
174 /* obj->Name needs to be non-zero, but won't ever be examined more
175 * closely than that. In particular these buffers won't be entered
176 * into the hash and can never be confused with ones visible to the
177 * user. Perhaps there could be a special number for internal
178 * buffers:
179 */
180 vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx,
181 VBO_BUF_ID,
182 GL_ARRAY_BUFFER_ARB);
183
184 ctx->Driver.BufferData( ctx,
185 GL_ARRAY_BUFFER_ARB,
186 VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
187 NULL,
188 GL_STATIC_DRAW_ARB,
189 vertex_store->bufferobj);
190
191 vertex_store->buffer = NULL;
192 vertex_store->used = 0;
193 vertex_store->refcount = 1;
194
195 return vertex_store;
196 }
197
198 static void free_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
199 {
200 assert(!vertex_store->buffer);
201
202 if (vertex_store->bufferobj) {
203 _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
204 }
205
206 FREE( vertex_store );
207 }
208
209 static GLfloat *map_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
210 {
211 assert(vertex_store->bufferobj);
212 assert(!vertex_store->buffer);
213 vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx,
214 GL_ARRAY_BUFFER_ARB, /* not used */
215 GL_WRITE_ONLY, /* not used */
216 vertex_store->bufferobj);
217
218 assert(vertex_store->buffer);
219 return vertex_store->buffer + vertex_store->used;
220 }
221
222 static void unmap_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
223 {
224 ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj );
225 vertex_store->buffer = NULL;
226 }
227
228
229 static struct vbo_save_primitive_store *alloc_prim_store( GLcontext *ctx )
230 {
231 struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store);
232 (void) ctx;
233 store->used = 0;
234 store->refcount = 1;
235 return store;
236 }
237
238 static void _save_reset_counters( GLcontext *ctx )
239 {
240 struct vbo_save_context *save = &vbo_context(ctx)->save;
241
242 save->prim = save->prim_store->buffer + save->prim_store->used;
243 save->buffer = (save->vertex_store->buffer +
244 save->vertex_store->used);
245
246 assert(save->buffer == save->buffer_ptr);
247
248 if (save->vertex_size)
249 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
250 save->vertex_size);
251 else
252 save->max_vert = 0;
253
254 save->vert_count = 0;
255 save->prim_count = 0;
256 save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
257 save->dangling_attr_ref = 0;
258 }
259
260
261 /* Insert the active immediate struct onto the display list currently
262 * being built.
263 */
264 static void _save_compile_vertex_list( GLcontext *ctx )
265 {
266 struct vbo_save_context *save = &vbo_context(ctx)->save;
267 struct vbo_save_vertex_list *node;
268
269 /* Allocate space for this structure in the display list currently
270 * being compiled.
271 */
272 node = (struct vbo_save_vertex_list *)
273 _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node));
274
275 if (!node)
276 return;
277
278 /* Duplicate our template, increment refcounts to the storage structs:
279 */
280 memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
281 node->vertex_size = save->vertex_size;
282 node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
283 node->count = save->vert_count;
284 node->wrap_count = save->copied.nr;
285 node->dangling_attr_ref = save->dangling_attr_ref;
286 node->prim = save->prim;
287 node->prim_count = save->prim_count;
288 node->vertex_store = save->vertex_store;
289 node->prim_store = save->prim_store;
290
291 node->vertex_store->refcount++;
292 node->prim_store->refcount++;
293
294
295 node->current_size = node->vertex_size - node->attrsz[0];
296 node->current_data = NULL;
297
298 if (node->current_size) {
299 /* If the malloc fails, we just pull the data out of the VBO
300 * later instead.
301 */
302 node->current_data = MALLOC( node->current_size * sizeof(GLfloat) );
303 if (node->current_data) {
304 const char *buffer = (const char *)save->vertex_store->buffer;
305 unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
306 unsigned vertex_offset = 0;
307
308 if (node->count)
309 vertex_offset = (node->count-1) * node->vertex_size * sizeof(GLfloat);
310
311 memcpy( node->current_data,
312 buffer + node->buffer_offset + vertex_offset + attr_offset,
313 node->current_size * sizeof(GLfloat) );
314 }
315 }
316
317
318
319 assert(node->attrsz[VBO_ATTRIB_POS] != 0 ||
320 node->count == 0);
321
322 if (save->dangling_attr_ref)
323 ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
324
325 save->vertex_store->used += save->vertex_size * node->count;
326 save->prim_store->used += node->prim_count;
327
328
329 /* Copy duplicated vertices
330 */
331 save->copied.nr = _save_copy_vertices( ctx, node, save->buffer );
332
333
334 /* Deal with GL_COMPILE_AND_EXECUTE:
335 */
336 if (ctx->ExecuteFlag) {
337 struct _glapi_table *dispatch = GET_DISPATCH();
338
339 _glapi_set_dispatch(ctx->Exec);
340
341 vbo_loopback_vertex_list( ctx,
342 (const GLfloat *)((const char *)save->vertex_store->buffer +
343 node->buffer_offset),
344 node->attrsz,
345 node->prim,
346 node->prim_count,
347 node->wrap_count,
348 node->vertex_size);
349
350 _glapi_set_dispatch(dispatch);
351 }
352
353
354 /* Decide whether the storage structs are full, or can be used for
355 * the next vertex lists as well.
356 */
357 if (save->vertex_store->used >
358 VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
359
360 /* Unmap old store:
361 */
362 unmap_vertex_store( ctx, save->vertex_store );
363
364 /* Release old reference:
365 */
366 save->vertex_store->refcount--;
367 assert(save->vertex_store->refcount != 0);
368 save->vertex_store = NULL;
369
370 /* Allocate and map new store:
371 */
372 save->vertex_store = alloc_vertex_store( ctx );
373 save->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
374 }
375
376 if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
377 save->prim_store->refcount--;
378 assert(save->prim_store->refcount != 0);
379 save->prim_store = alloc_prim_store( ctx );
380 }
381
382 /* Reset our structures for the next run of vertices:
383 */
384 _save_reset_counters( ctx );
385 }
386
387
388 /* TODO -- If no new vertices have been stored, don't bother saving
389 * it.
390 */
391 static void _save_wrap_buffers( GLcontext *ctx )
392 {
393 struct vbo_save_context *save = &vbo_context(ctx)->save;
394 GLint i = save->prim_count - 1;
395 GLenum mode;
396 GLboolean weak;
397
398 assert(i < (GLint) save->prim_max);
399 assert(i >= 0);
400
401 /* Close off in-progress primitive.
402 */
403 save->prim[i].count = (save->vert_count -
404 save->prim[i].start);
405 mode = save->prim[i].mode;
406 weak = save->prim[i].weak;
407
408 /* store the copied vertices, and allocate a new list.
409 */
410 _save_compile_vertex_list( ctx );
411
412 /* Restart interrupted primitive
413 */
414 save->prim[0].mode = mode;
415 save->prim[0].weak = weak;
416 save->prim[0].begin = 0;
417 save->prim[0].end = 0;
418 save->prim[0].pad = 0;
419 save->prim[0].start = 0;
420 save->prim[0].count = 0;
421 save->prim[0].num_instances = 1;
422 save->prim_count = 1;
423 }
424
425
426
427 /* Called only when buffers are wrapped as the result of filling the
428 * vertex_store struct.
429 */
430 static void _save_wrap_filled_vertex( GLcontext *ctx )
431 {
432 struct vbo_save_context *save = &vbo_context(ctx)->save;
433 GLfloat *data = save->copied.buffer;
434 GLuint i;
435
436 /* Emit a glEnd to close off the last vertex list.
437 */
438 _save_wrap_buffers( ctx );
439
440 /* Copy stored stored vertices to start of new list.
441 */
442 assert(save->max_vert - save->vert_count > save->copied.nr);
443
444 for (i = 0 ; i < save->copied.nr ; i++) {
445 memcpy( save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
446 data += save->vertex_size;
447 save->buffer_ptr += save->vertex_size;
448 save->vert_count++;
449 }
450 }
451
452
453 static void _save_copy_to_current( GLcontext *ctx )
454 {
455 struct vbo_save_context *save = &vbo_context(ctx)->save;
456 GLuint i;
457
458 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
459 if (save->attrsz[i]) {
460 save->currentsz[i][0] = save->attrsz[i];
461 COPY_CLEAN_4V(save->current[i],
462 save->attrsz[i],
463 save->attrptr[i]);
464 }
465 }
466 }
467
468
469 static void _save_copy_from_current( GLcontext *ctx )
470 {
471 struct vbo_save_context *save = &vbo_context(ctx)->save;
472 GLint i;
473
474 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
475 switch (save->attrsz[i]) {
476 case 4: save->attrptr[i][3] = save->current[i][3];
477 case 3: save->attrptr[i][2] = save->current[i][2];
478 case 2: save->attrptr[i][1] = save->current[i][1];
479 case 1: save->attrptr[i][0] = save->current[i][0];
480 case 0: break;
481 }
482 }
483 }
484
485
486
487
488 /* Flush existing data, set new attrib size, replay copied vertices.
489 */
490 static void _save_upgrade_vertex( GLcontext *ctx,
491 GLuint attr,
492 GLuint newsz )
493 {
494 struct vbo_save_context *save = &vbo_context(ctx)->save;
495 GLuint oldsz;
496 GLuint i;
497 GLfloat *tmp;
498
499 /* Store the current run of vertices, and emit a GL_END. Emit a
500 * BEGIN in the new buffer.
501 */
502 if (save->vert_count)
503 _save_wrap_buffers( ctx );
504 else
505 assert( save->copied.nr == 0 );
506
507 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
508 * when the attribute already exists in the vertex and is having
509 * its size increased.
510 */
511 _save_copy_to_current( ctx );
512
513 /* Fix up sizes:
514 */
515 oldsz = save->attrsz[attr];
516 save->attrsz[attr] = newsz;
517
518 save->vertex_size += newsz - oldsz;
519 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
520 save->vertex_size);
521 save->vert_count = 0;
522
523 /* Recalculate all the attrptr[] values:
524 */
525 for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) {
526 if (save->attrsz[i]) {
527 save->attrptr[i] = tmp;
528 tmp += save->attrsz[i];
529 }
530 else
531 save->attrptr[i] = NULL; /* will not be dereferenced. */
532 }
533
534 /* Copy from current to repopulate the vertex with correct values.
535 */
536 _save_copy_from_current( ctx );
537
538 /* Replay stored vertices to translate them to new format here.
539 *
540 * If there are copied vertices and the new (upgraded) attribute
541 * has not been defined before, this list is somewhat degenerate,
542 * and will need fixup at runtime.
543 */
544 if (save->copied.nr)
545 {
546 GLfloat *data = save->copied.buffer;
547 GLfloat *dest = save->buffer;
548 GLuint j;
549
550 /* Need to note this and fix up at runtime (or loopback):
551 */
552 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
553 assert(oldsz == 0);
554 save->dangling_attr_ref = GL_TRUE;
555 }
556
557 for (i = 0 ; i < save->copied.nr ; i++) {
558 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
559 if (save->attrsz[j]) {
560 if (j == attr) {
561 if (oldsz) {
562 COPY_CLEAN_4V( dest, oldsz, data );
563 data += oldsz;
564 dest += newsz;
565 }
566 else {
567 COPY_SZ_4V( dest, newsz, save->current[attr] );
568 dest += newsz;
569 }
570 }
571 else {
572 GLint sz = save->attrsz[j];
573 COPY_SZ_4V( dest, sz, data );
574 data += sz;
575 dest += sz;
576 }
577 }
578 }
579 }
580
581 save->buffer_ptr = dest;
582 save->vert_count += save->copied.nr;
583 }
584 }
585
586 static void save_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
587 {
588 struct vbo_save_context *save = &vbo_context(ctx)->save;
589
590 if (sz > save->attrsz[attr]) {
591 /* New size is larger. Need to flush existing vertices and get
592 * an enlarged vertex format.
593 */
594 _save_upgrade_vertex( ctx, attr, sz );
595 }
596 else if (sz < save->active_sz[attr]) {
597 static GLfloat id[4] = { 0, 0, 0, 1 };
598 GLuint i;
599
600 /* New size is equal or smaller - just need to fill in some
601 * zeros.
602 */
603 for (i = sz ; i <= save->attrsz[attr] ; i++)
604 save->attrptr[attr][i-1] = id[i-1];
605 }
606
607 save->active_sz[attr] = sz;
608 }
609
610 static void _save_reset_vertex( GLcontext *ctx )
611 {
612 struct vbo_save_context *save = &vbo_context(ctx)->save;
613 GLuint i;
614
615 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
616 save->attrsz[i] = 0;
617 save->active_sz[i] = 0;
618 }
619
620 save->vertex_size = 0;
621 }
622
623
624
625 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
626
627
628 /* Only one size for each attribute may be active at once. Eg. if
629 * Color3f is installed/active, then Color4f may not be, even if the
630 * vertex actually contains 4 color coordinates. This is because the
631 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
632 * of the chooser function when switching between Color4f and Color3f.
633 */
634 #define ATTR( A, N, V0, V1, V2, V3 ) \
635 do { \
636 struct vbo_save_context *save = &vbo_context(ctx)->save; \
637 \
638 if (save->active_sz[A] != N) \
639 save_fixup_vertex(ctx, A, N); \
640 \
641 { \
642 GLfloat *dest = save->attrptr[A]; \
643 if (N>0) dest[0] = V0; \
644 if (N>1) dest[1] = V1; \
645 if (N>2) dest[2] = V2; \
646 if (N>3) dest[3] = V3; \
647 } \
648 \
649 if ((A) == 0) { \
650 GLuint i; \
651 \
652 for (i = 0; i < save->vertex_size; i++) \
653 save->buffer_ptr[i] = save->vertex[i]; \
654 \
655 save->buffer_ptr += save->vertex_size; \
656 \
657 if (++save->vert_count >= save->max_vert) \
658 _save_wrap_filled_vertex( ctx ); \
659 } \
660 } while (0)
661
662 #define TAG(x) _save_##x
663
664 #include "vbo_attrib_tmp.h"
665
666
667
668
669 /* Cope with EvalCoord/CallList called within a begin/end object:
670 * -- Flush current buffer
671 * -- Fallback to opcodes for the rest of the begin/end object.
672 */
673 static void DO_FALLBACK( GLcontext *ctx )
674 {
675 struct vbo_save_context *save = &vbo_context(ctx)->save;
676
677 if (save->vert_count || save->prim_count) {
678 GLint i = save->prim_count - 1;
679
680 /* Close off in-progress primitive.
681 */
682 save->prim[i].count = (save->vert_count -
683 save->prim[i].start);
684
685 /* Need to replay this display list with loopback,
686 * unfortunately, otherwise this primitive won't be handled
687 * properly:
688 */
689 save->dangling_attr_ref = 1;
690
691 _save_compile_vertex_list( ctx );
692 }
693
694 _save_copy_to_current( ctx );
695 _save_reset_vertex( ctx );
696 _save_reset_counters( ctx );
697 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
698 ctx->Driver.SaveNeedFlush = 0;
699 }
700
701 static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
702 {
703 GET_CURRENT_CONTEXT(ctx);
704 DO_FALLBACK(ctx);
705 ctx->Save->EvalCoord1f( u );
706 }
707
708 static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
709 {
710 GET_CURRENT_CONTEXT(ctx);
711 DO_FALLBACK(ctx);
712 ctx->Save->EvalCoord1fv( v );
713 }
714
715 static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
716 {
717 GET_CURRENT_CONTEXT(ctx);
718 DO_FALLBACK(ctx);
719 ctx->Save->EvalCoord2f( u, v );
720 }
721
722 static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
723 {
724 GET_CURRENT_CONTEXT(ctx);
725 DO_FALLBACK(ctx);
726 ctx->Save->EvalCoord2fv( v );
727 }
728
729 static void GLAPIENTRY _save_EvalPoint1( GLint i )
730 {
731 GET_CURRENT_CONTEXT(ctx);
732 DO_FALLBACK(ctx);
733 ctx->Save->EvalPoint1( i );
734 }
735
736 static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
737 {
738 GET_CURRENT_CONTEXT(ctx);
739 DO_FALLBACK(ctx);
740 ctx->Save->EvalPoint2( i, j );
741 }
742
743 static void GLAPIENTRY _save_CallList( GLuint l )
744 {
745 GET_CURRENT_CONTEXT(ctx);
746 DO_FALLBACK(ctx);
747 ctx->Save->CallList( l );
748 }
749
750 static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
751 {
752 GET_CURRENT_CONTEXT(ctx);
753 DO_FALLBACK(ctx);
754 ctx->Save->CallLists( n, type, v );
755 }
756
757
758
759
760 /* This begin is hooked into ... Updating of
761 * ctx->Driver.CurrentSavePrimitive is already taken care of.
762 */
763 GLboolean vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode )
764 {
765 struct vbo_save_context *save = &vbo_context(ctx)->save;
766
767 GLuint i = save->prim_count++;
768
769 assert(i < save->prim_max);
770 save->prim[i].mode = mode & ~VBO_SAVE_PRIM_WEAK;
771 save->prim[i].begin = 1;
772 save->prim[i].end = 0;
773 save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
774 save->prim[i].pad = 0;
775 save->prim[i].start = save->vert_count;
776 save->prim[i].count = 0;
777 save->prim[i].num_instances = 1;
778
779 _mesa_install_save_vtxfmt( ctx, &save->vtxfmt );
780 ctx->Driver.SaveNeedFlush = 1;
781 return GL_TRUE;
782 }
783
784
785
786 static void GLAPIENTRY _save_End( void )
787 {
788 GET_CURRENT_CONTEXT( ctx );
789 struct vbo_save_context *save = &vbo_context(ctx)->save;
790 GLint i = save->prim_count - 1;
791
792 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
793 save->prim[i].end = 1;
794 save->prim[i].count = (save->vert_count -
795 save->prim[i].start);
796
797 if (i == (GLint) save->prim_max - 1) {
798 _save_compile_vertex_list( ctx );
799 assert(save->copied.nr == 0);
800 }
801
802 /* Swap out this vertex format while outside begin/end. Any color,
803 * etc. received between here and the next begin will be compiled
804 * as opcodes.
805 */
806 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
807 }
808
809
810 /* These are all errors as this vtxfmt is only installed inside
811 * begin/end pairs.
812 */
813 static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
814 const GLvoid *indices)
815 {
816 GET_CURRENT_CONTEXT(ctx);
817 (void) mode; (void) count; (void) type; (void) indices;
818 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
819 }
820
821
822 static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
823 GLuint start, GLuint end,
824 GLsizei count, GLenum type,
825 const GLvoid *indices)
826 {
827 GET_CURRENT_CONTEXT(ctx);
828 (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
829 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
830 }
831
832 static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode,
833 GLsizei count,
834 GLenum type,
835 const GLvoid *indices,
836 GLint basevertex)
837 {
838 GET_CURRENT_CONTEXT(ctx);
839 (void) mode; (void) count; (void) type; (void) indices; (void)basevertex;
840
841 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
842 }
843
844 static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode,
845 GLuint start,
846 GLuint end,
847 GLsizei count,
848 GLenum type,
849 const GLvoid *indices,
850 GLint basevertex)
851 {
852 GET_CURRENT_CONTEXT(ctx);
853 (void) mode; (void) start; (void) end; (void) count; (void) type;
854 (void) indices; (void)basevertex;
855
856 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
857 }
858
859 static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
860 {
861 GET_CURRENT_CONTEXT(ctx);
862 (void) mode; (void) start; (void) count;
863 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
864 }
865
866 static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
867 {
868 GET_CURRENT_CONTEXT(ctx);
869 (void) x1; (void) y1; (void) x2; (void) y2;
870 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
871 }
872
873 static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
874 {
875 GET_CURRENT_CONTEXT(ctx);
876 (void) mode; (void) i1; (void) i2;
877 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
878 }
879
880 static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
881 GLint j1, GLint j2 )
882 {
883 GET_CURRENT_CONTEXT(ctx);
884 (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
885 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
886 }
887
888 static void GLAPIENTRY _save_Begin( GLenum mode )
889 {
890 GET_CURRENT_CONTEXT( ctx );
891 (void) mode;
892 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
893 }
894
895
896 /* Unlike the functions above, these are to be hooked into the vtxfmt
897 * maintained in ctx->ListState, active when the list is known or
898 * suspected to be outside any begin/end primitive.
899 */
900 static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
901 {
902 GET_CURRENT_CONTEXT(ctx);
903 vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK );
904 CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 ));
905 CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 ));
906 CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 ));
907 CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 ));
908 CALL_End(GET_DISPATCH(), ());
909 }
910
911
912 static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
913 {
914 GET_CURRENT_CONTEXT(ctx);
915 GLint i;
916
917 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
918 return;
919
920 _ae_map_vbos( ctx );
921
922 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
923
924 for (i = 0; i < count; i++)
925 CALL_ArrayElement(GET_DISPATCH(), (start + i));
926 CALL_End(GET_DISPATCH(), ());
927
928 _ae_unmap_vbos( ctx );
929 }
930
931 /* Could do better by copying the arrays and element list intact and
932 * then emitting an indexed prim at runtime.
933 */
934 static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
935 const GLvoid *indices)
936 {
937 GET_CURRENT_CONTEXT(ctx);
938 GLint i;
939
940 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
941 return;
942
943 _ae_map_vbos( ctx );
944
945 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj))
946 indices = ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices);
947
948 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
949
950 switch (type) {
951 case GL_UNSIGNED_BYTE:
952 for (i = 0 ; i < count ; i++)
953 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
954 break;
955 case GL_UNSIGNED_SHORT:
956 for (i = 0 ; i < count ; i++)
957 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
958 break;
959 case GL_UNSIGNED_INT:
960 for (i = 0 ; i < count ; i++)
961 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
962 break;
963 default:
964 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
965 break;
966 }
967
968 CALL_End(GET_DISPATCH(), ());
969
970 _ae_unmap_vbos( ctx );
971 }
972
973 static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
974 GLuint start, GLuint end,
975 GLsizei count, GLenum type,
976 const GLvoid *indices)
977 {
978 GET_CURRENT_CONTEXT(ctx);
979 if (_mesa_validate_DrawRangeElements( ctx, mode,
980 start, end,
981 count, type, indices, 0 ))
982 _save_OBE_DrawElements( mode, count, type, indices );
983 }
984
985
986
987
988
989 static void _save_vtxfmt_init( GLcontext *ctx )
990 {
991 struct vbo_save_context *save = &vbo_context(ctx)->save;
992 GLvertexformat *vfmt = &save->vtxfmt;
993
994 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
995
996 vfmt->Begin = _save_Begin;
997 vfmt->Color3f = _save_Color3f;
998 vfmt->Color3fv = _save_Color3fv;
999 vfmt->Color4f = _save_Color4f;
1000 vfmt->Color4fv = _save_Color4fv;
1001 vfmt->EdgeFlag = _save_EdgeFlag;
1002 vfmt->End = _save_End;
1003 vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1004 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1005 vfmt->Indexf = _save_Indexf;
1006 vfmt->Indexfv = _save_Indexfv;
1007 vfmt->Materialfv = _save_Materialfv;
1008 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1009 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1010 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1011 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1012 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1013 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1014 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1015 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1016 vfmt->Normal3f = _save_Normal3f;
1017 vfmt->Normal3fv = _save_Normal3fv;
1018 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1019 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1020 vfmt->TexCoord1f = _save_TexCoord1f;
1021 vfmt->TexCoord1fv = _save_TexCoord1fv;
1022 vfmt->TexCoord2f = _save_TexCoord2f;
1023 vfmt->TexCoord2fv = _save_TexCoord2fv;
1024 vfmt->TexCoord3f = _save_TexCoord3f;
1025 vfmt->TexCoord3fv = _save_TexCoord3fv;
1026 vfmt->TexCoord4f = _save_TexCoord4f;
1027 vfmt->TexCoord4fv = _save_TexCoord4fv;
1028 vfmt->Vertex2f = _save_Vertex2f;
1029 vfmt->Vertex2fv = _save_Vertex2fv;
1030 vfmt->Vertex3f = _save_Vertex3f;
1031 vfmt->Vertex3fv = _save_Vertex3fv;
1032 vfmt->Vertex4f = _save_Vertex4f;
1033 vfmt->Vertex4fv = _save_Vertex4fv;
1034 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1035 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1036 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1037 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1038 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1039 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1040 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1041 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1042
1043 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1044 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1045 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1046 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1047 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1048 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1049 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1050 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1051
1052 /* This will all require us to fallback to saving the list as opcodes:
1053 */
1054 _MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */
1055
1056 _MESA_INIT_EVAL_VTXFMT(vfmt, _save_);
1057
1058 /* These are all errors as we at least know we are in some sort of
1059 * begin/end pair:
1060 */
1061 vfmt->Begin = _save_Begin;
1062 vfmt->Rectf = _save_Rectf;
1063 vfmt->DrawArrays = _save_DrawArrays;
1064 vfmt->DrawElements = _save_DrawElements;
1065 vfmt->DrawRangeElements = _save_DrawRangeElements;
1066 vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex;
1067 vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex;
1068 /* Loops back into vfmt->DrawElements */
1069 vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
1070 vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
1071 }
1072
1073
1074 void vbo_save_SaveFlushVertices( GLcontext *ctx )
1075 {
1076 struct vbo_save_context *save = &vbo_context(ctx)->save;
1077
1078 /* Noop when we are actually active:
1079 */
1080 if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
1081 ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
1082 return;
1083
1084 if (save->vert_count ||
1085 save->prim_count)
1086 _save_compile_vertex_list( ctx );
1087
1088 _save_copy_to_current( ctx );
1089 _save_reset_vertex( ctx );
1090 _save_reset_counters( ctx );
1091 ctx->Driver.SaveNeedFlush = 0;
1092 }
1093
1094 void vbo_save_NewList( GLcontext *ctx, GLuint list, GLenum mode )
1095 {
1096 struct vbo_save_context *save = &vbo_context(ctx)->save;
1097
1098 (void) list; (void) mode;
1099
1100 if (!save->prim_store)
1101 save->prim_store = alloc_prim_store( ctx );
1102
1103 if (!save->vertex_store)
1104 save->vertex_store = alloc_vertex_store( ctx );
1105
1106 save->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
1107
1108 _save_reset_vertex( ctx );
1109 _save_reset_counters( ctx );
1110 ctx->Driver.SaveNeedFlush = 0;
1111 }
1112
1113 void vbo_save_EndList( GLcontext *ctx )
1114 {
1115 struct vbo_save_context *save = &vbo_context(ctx)->save;
1116
1117 /* EndList called inside a (saved) Begin/End pair?
1118 */
1119 if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) {
1120
1121 if (save->prim_count > 0) {
1122 GLint i = save->prim_count - 1;
1123 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1124 save->prim[i].end = 0;
1125 save->prim[i].count = (save->vert_count -
1126 save->prim[i].start);
1127 }
1128
1129 /* Make sure this vertex list gets replayed by the "loopback"
1130 * mechanism:
1131 */
1132 save->dangling_attr_ref = 1;
1133 vbo_save_SaveFlushVertices( ctx );
1134
1135 /* Swap out this vertex format while outside begin/end. Any color,
1136 * etc. received between here and the next begin will be compiled
1137 * as opcodes.
1138 */
1139 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1140 }
1141
1142 unmap_vertex_store( ctx, save->vertex_store );
1143
1144 assert(save->vertex_size == 0);
1145 }
1146
1147 void vbo_save_BeginCallList( GLcontext *ctx, struct gl_display_list *dlist )
1148 {
1149 struct vbo_save_context *save = &vbo_context(ctx)->save;
1150 save->replay_flags |= dlist->Flags;
1151 }
1152
1153 void vbo_save_EndCallList( GLcontext *ctx )
1154 {
1155 struct vbo_save_context *save = &vbo_context(ctx)->save;
1156
1157 if (ctx->ListState.CallDepth == 1) {
1158 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1159 * flag, if it is set:
1160 */
1161 save->replay_flags &= VBO_SAVE_FALLBACK;
1162 }
1163 }
1164
1165
1166 static void vbo_destroy_vertex_list( GLcontext *ctx, void *data )
1167 {
1168 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
1169 (void) ctx;
1170
1171 if ( --node->vertex_store->refcount == 0 )
1172 free_vertex_store( ctx, node->vertex_store );
1173
1174 if ( --node->prim_store->refcount == 0 )
1175 FREE( node->prim_store );
1176
1177 if (node->current_data) {
1178 FREE(node->current_data);
1179 node->current_data = NULL;
1180 }
1181 }
1182
1183
1184 static void vbo_print_vertex_list( GLcontext *ctx, void *data )
1185 {
1186 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
1187 GLuint i;
1188 (void) ctx;
1189
1190 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1191 node->count,
1192 node->prim_count,
1193 node->vertex_size);
1194
1195 for (i = 0 ; i < node->prim_count ; i++) {
1196 struct _mesa_prim *prim = &node->prim[i];
1197 _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n",
1198 i,
1199 _mesa_lookup_prim_by_nr(prim->mode),
1200 prim->weak ? " (weak)" : "",
1201 prim->start,
1202 prim->start + prim->count,
1203 (prim->begin) ? "BEGIN" : "(wrap)",
1204 (prim->end) ? "END" : "(wrap)");
1205 }
1206 }
1207
1208
1209 static void _save_current_init( GLcontext *ctx )
1210 {
1211 struct vbo_save_context *save = &vbo_context(ctx)->save;
1212 GLint i;
1213
1214 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1215 const GLuint j = i - VBO_ATTRIB_POS;
1216 ASSERT(j < VERT_ATTRIB_MAX);
1217 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1218 save->current[i] = ctx->ListState.CurrentAttrib[j];
1219 }
1220
1221 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1222 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1223 ASSERT(j < MAT_ATTRIB_MAX);
1224 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1225 save->current[i] = ctx->ListState.CurrentMaterial[j];
1226 }
1227 }
1228
1229 /**
1230 * Initialize the display list compiler
1231 */
1232 void vbo_save_api_init( struct vbo_save_context *save )
1233 {
1234 GLcontext *ctx = save->ctx;
1235 GLuint i;
1236
1237 save->opcode_vertex_list =
1238 _mesa_dlist_alloc_opcode( ctx,
1239 sizeof(struct vbo_save_vertex_list),
1240 vbo_save_playback_vertex_list,
1241 vbo_destroy_vertex_list,
1242 vbo_print_vertex_list );
1243
1244 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
1245
1246 _save_vtxfmt_init( ctx );
1247 _save_current_init( ctx );
1248
1249 /* These will actually get set again when binding/drawing */
1250 for (i = 0; i < VBO_ATTRIB_MAX; i++)
1251 save->inputs[i] = &save->arrays[i];
1252
1253 /* Hook our array functions into the outside-begin-end vtxfmt in
1254 * ctx->ListState.
1255 */
1256 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
1257 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
1258 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
1259 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
1260 /* loops back into _save_OBE_DrawElements */
1261 ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
1262 ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
1263 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1264 }
1265