Revert "st/mesa: Always recalculate invalid index bounds."
[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_count = 1;
422 }
423
424
425
426 /* Called only when buffers are wrapped as the result of filling the
427 * vertex_store struct.
428 */
429 static void _save_wrap_filled_vertex( GLcontext *ctx )
430 {
431 struct vbo_save_context *save = &vbo_context(ctx)->save;
432 GLfloat *data = save->copied.buffer;
433 GLuint i;
434
435 /* Emit a glEnd to close off the last vertex list.
436 */
437 _save_wrap_buffers( ctx );
438
439 /* Copy stored stored vertices to start of new list.
440 */
441 assert(save->max_vert - save->vert_count > save->copied.nr);
442
443 for (i = 0 ; i < save->copied.nr ; i++) {
444 memcpy( save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
445 data += save->vertex_size;
446 save->buffer_ptr += save->vertex_size;
447 save->vert_count++;
448 }
449 }
450
451
452 static void _save_copy_to_current( GLcontext *ctx )
453 {
454 struct vbo_save_context *save = &vbo_context(ctx)->save;
455 GLuint i;
456
457 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
458 if (save->attrsz[i]) {
459 save->currentsz[i][0] = save->attrsz[i];
460 COPY_CLEAN_4V(save->current[i],
461 save->attrsz[i],
462 save->attrptr[i]);
463 }
464 }
465 }
466
467
468 static void _save_copy_from_current( GLcontext *ctx )
469 {
470 struct vbo_save_context *save = &vbo_context(ctx)->save;
471 GLint i;
472
473 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
474 switch (save->attrsz[i]) {
475 case 4: save->attrptr[i][3] = save->current[i][3];
476 case 3: save->attrptr[i][2] = save->current[i][2];
477 case 2: save->attrptr[i][1] = save->current[i][1];
478 case 1: save->attrptr[i][0] = save->current[i][0];
479 case 0: break;
480 }
481 }
482 }
483
484
485
486
487 /* Flush existing data, set new attrib size, replay copied vertices.
488 */
489 static void _save_upgrade_vertex( GLcontext *ctx,
490 GLuint attr,
491 GLuint newsz )
492 {
493 struct vbo_save_context *save = &vbo_context(ctx)->save;
494 GLuint oldsz;
495 GLuint i;
496 GLfloat *tmp;
497
498 /* Store the current run of vertices, and emit a GL_END. Emit a
499 * BEGIN in the new buffer.
500 */
501 if (save->vert_count)
502 _save_wrap_buffers( ctx );
503 else
504 assert( save->copied.nr == 0 );
505
506 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
507 * when the attribute already exists in the vertex and is having
508 * its size increased.
509 */
510 _save_copy_to_current( ctx );
511
512 /* Fix up sizes:
513 */
514 oldsz = save->attrsz[attr];
515 save->attrsz[attr] = newsz;
516
517 save->vertex_size += newsz - oldsz;
518 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
519 save->vertex_size);
520 save->vert_count = 0;
521
522 /* Recalculate all the attrptr[] values:
523 */
524 for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) {
525 if (save->attrsz[i]) {
526 save->attrptr[i] = tmp;
527 tmp += save->attrsz[i];
528 }
529 else
530 save->attrptr[i] = NULL; /* will not be dereferenced. */
531 }
532
533 /* Copy from current to repopulate the vertex with correct values.
534 */
535 _save_copy_from_current( ctx );
536
537 /* Replay stored vertices to translate them to new format here.
538 *
539 * If there are copied vertices and the new (upgraded) attribute
540 * has not been defined before, this list is somewhat degenerate,
541 * and will need fixup at runtime.
542 */
543 if (save->copied.nr)
544 {
545 GLfloat *data = save->copied.buffer;
546 GLfloat *dest = save->buffer;
547 GLuint j;
548
549 /* Need to note this and fix up at runtime (or loopback):
550 */
551 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
552 assert(oldsz == 0);
553 save->dangling_attr_ref = GL_TRUE;
554 }
555
556 for (i = 0 ; i < save->copied.nr ; i++) {
557 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
558 if (save->attrsz[j]) {
559 if (j == attr) {
560 if (oldsz) {
561 COPY_CLEAN_4V( dest, oldsz, data );
562 data += oldsz;
563 dest += newsz;
564 }
565 else {
566 COPY_SZ_4V( dest, newsz, save->current[attr] );
567 dest += newsz;
568 }
569 }
570 else {
571 GLint sz = save->attrsz[j];
572 COPY_SZ_4V( dest, sz, data );
573 data += sz;
574 dest += sz;
575 }
576 }
577 }
578 }
579
580 save->buffer_ptr = dest;
581 save->vert_count += save->copied.nr;
582 }
583 }
584
585 static void save_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
586 {
587 struct vbo_save_context *save = &vbo_context(ctx)->save;
588
589 if (sz > save->attrsz[attr]) {
590 /* New size is larger. Need to flush existing vertices and get
591 * an enlarged vertex format.
592 */
593 _save_upgrade_vertex( ctx, attr, sz );
594 }
595 else if (sz < save->active_sz[attr]) {
596 static GLfloat id[4] = { 0, 0, 0, 1 };
597 GLuint i;
598
599 /* New size is equal or smaller - just need to fill in some
600 * zeros.
601 */
602 for (i = sz ; i <= save->attrsz[attr] ; i++)
603 save->attrptr[attr][i-1] = id[i-1];
604 }
605
606 save->active_sz[attr] = sz;
607 }
608
609 static void _save_reset_vertex( GLcontext *ctx )
610 {
611 struct vbo_save_context *save = &vbo_context(ctx)->save;
612 GLuint i;
613
614 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
615 save->attrsz[i] = 0;
616 save->active_sz[i] = 0;
617 }
618
619 save->vertex_size = 0;
620 }
621
622
623
624 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
625
626
627 /* Only one size for each attribute may be active at once. Eg. if
628 * Color3f is installed/active, then Color4f may not be, even if the
629 * vertex actually contains 4 color coordinates. This is because the
630 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
631 * of the chooser function when switching between Color4f and Color3f.
632 */
633 #define ATTR( A, N, V0, V1, V2, V3 ) \
634 do { \
635 struct vbo_save_context *save = &vbo_context(ctx)->save; \
636 \
637 if (save->active_sz[A] != N) \
638 save_fixup_vertex(ctx, A, N); \
639 \
640 { \
641 GLfloat *dest = save->attrptr[A]; \
642 if (N>0) dest[0] = V0; \
643 if (N>1) dest[1] = V1; \
644 if (N>2) dest[2] = V2; \
645 if (N>3) dest[3] = V3; \
646 } \
647 \
648 if ((A) == 0) { \
649 GLuint i; \
650 \
651 for (i = 0; i < save->vertex_size; i++) \
652 save->buffer_ptr[i] = save->vertex[i]; \
653 \
654 save->buffer_ptr += save->vertex_size; \
655 \
656 if (++save->vert_count >= save->max_vert) \
657 _save_wrap_filled_vertex( ctx ); \
658 } \
659 } while (0)
660
661 #define TAG(x) _save_##x
662
663 #include "vbo_attrib_tmp.h"
664
665
666
667
668 /* Cope with EvalCoord/CallList called within a begin/end object:
669 * -- Flush current buffer
670 * -- Fallback to opcodes for the rest of the begin/end object.
671 */
672 static void DO_FALLBACK( GLcontext *ctx )
673 {
674 struct vbo_save_context *save = &vbo_context(ctx)->save;
675
676 if (save->vert_count || save->prim_count) {
677 GLint i = save->prim_count - 1;
678
679 /* Close off in-progress primitive.
680 */
681 save->prim[i].count = (save->vert_count -
682 save->prim[i].start);
683
684 /* Need to replay this display list with loopback,
685 * unfortunately, otherwise this primitive won't be handled
686 * properly:
687 */
688 save->dangling_attr_ref = 1;
689
690 _save_compile_vertex_list( ctx );
691 }
692
693 _save_copy_to_current( ctx );
694 _save_reset_vertex( ctx );
695 _save_reset_counters( ctx );
696 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
697 ctx->Driver.SaveNeedFlush = 0;
698 }
699
700 static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
701 {
702 GET_CURRENT_CONTEXT(ctx);
703 DO_FALLBACK(ctx);
704 ctx->Save->EvalCoord1f( u );
705 }
706
707 static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
708 {
709 GET_CURRENT_CONTEXT(ctx);
710 DO_FALLBACK(ctx);
711 ctx->Save->EvalCoord1fv( v );
712 }
713
714 static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
715 {
716 GET_CURRENT_CONTEXT(ctx);
717 DO_FALLBACK(ctx);
718 ctx->Save->EvalCoord2f( u, v );
719 }
720
721 static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
722 {
723 GET_CURRENT_CONTEXT(ctx);
724 DO_FALLBACK(ctx);
725 ctx->Save->EvalCoord2fv( v );
726 }
727
728 static void GLAPIENTRY _save_EvalPoint1( GLint i )
729 {
730 GET_CURRENT_CONTEXT(ctx);
731 DO_FALLBACK(ctx);
732 ctx->Save->EvalPoint1( i );
733 }
734
735 static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
736 {
737 GET_CURRENT_CONTEXT(ctx);
738 DO_FALLBACK(ctx);
739 ctx->Save->EvalPoint2( i, j );
740 }
741
742 static void GLAPIENTRY _save_CallList( GLuint l )
743 {
744 GET_CURRENT_CONTEXT(ctx);
745 DO_FALLBACK(ctx);
746 ctx->Save->CallList( l );
747 }
748
749 static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
750 {
751 GET_CURRENT_CONTEXT(ctx);
752 DO_FALLBACK(ctx);
753 ctx->Save->CallLists( n, type, v );
754 }
755
756
757
758
759 /* This begin is hooked into ... Updating of
760 * ctx->Driver.CurrentSavePrimitive is already taken care of.
761 */
762 GLboolean vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode )
763 {
764 struct vbo_save_context *save = &vbo_context(ctx)->save;
765
766 GLuint i = save->prim_count++;
767
768 assert(i < save->prim_max);
769 save->prim[i].mode = mode & ~VBO_SAVE_PRIM_WEAK;
770 save->prim[i].begin = 1;
771 save->prim[i].end = 0;
772 save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
773 save->prim[i].pad = 0;
774 save->prim[i].start = save->vert_count;
775 save->prim[i].count = 0;
776
777 _mesa_install_save_vtxfmt( ctx, &save->vtxfmt );
778 ctx->Driver.SaveNeedFlush = 1;
779 return GL_TRUE;
780 }
781
782
783
784 static void GLAPIENTRY _save_End( void )
785 {
786 GET_CURRENT_CONTEXT( ctx );
787 struct vbo_save_context *save = &vbo_context(ctx)->save;
788 GLint i = save->prim_count - 1;
789
790 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
791 save->prim[i].end = 1;
792 save->prim[i].count = (save->vert_count -
793 save->prim[i].start);
794
795 if (i == (GLint) save->prim_max - 1) {
796 _save_compile_vertex_list( ctx );
797 assert(save->copied.nr == 0);
798 }
799
800 /* Swap out this vertex format while outside begin/end. Any color,
801 * etc. received between here and the next begin will be compiled
802 * as opcodes.
803 */
804 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
805 }
806
807
808 /* These are all errors as this vtxfmt is only installed inside
809 * begin/end pairs.
810 */
811 static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
812 const GLvoid *indices)
813 {
814 GET_CURRENT_CONTEXT(ctx);
815 (void) mode; (void) count; (void) type; (void) indices;
816 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
817 }
818
819
820 static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
821 GLuint start, GLuint end,
822 GLsizei count, GLenum type,
823 const GLvoid *indices)
824 {
825 GET_CURRENT_CONTEXT(ctx);
826 (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
827 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
828 }
829
830 static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode,
831 GLsizei count,
832 GLenum type,
833 const GLvoid *indices,
834 GLint basevertex)
835 {
836 GET_CURRENT_CONTEXT(ctx);
837 (void) mode; (void) count; (void) type; (void) indices; (void)basevertex;
838
839 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
840 }
841
842 static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode,
843 GLuint start,
844 GLuint end,
845 GLsizei count,
846 GLenum type,
847 const GLvoid *indices,
848 GLint basevertex)
849 {
850 GET_CURRENT_CONTEXT(ctx);
851 (void) mode; (void) start; (void) end; (void) count; (void) type;
852 (void) indices; (void)basevertex;
853
854 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
855 }
856
857 static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
858 {
859 GET_CURRENT_CONTEXT(ctx);
860 (void) mode; (void) start; (void) count;
861 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
862 }
863
864 static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
865 {
866 GET_CURRENT_CONTEXT(ctx);
867 (void) x1; (void) y1; (void) x2; (void) y2;
868 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
869 }
870
871 static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
872 {
873 GET_CURRENT_CONTEXT(ctx);
874 (void) mode; (void) i1; (void) i2;
875 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
876 }
877
878 static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
879 GLint j1, GLint j2 )
880 {
881 GET_CURRENT_CONTEXT(ctx);
882 (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
883 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
884 }
885
886 static void GLAPIENTRY _save_Begin( GLenum mode )
887 {
888 GET_CURRENT_CONTEXT( ctx );
889 (void) mode;
890 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
891 }
892
893
894 /* Unlike the functions above, these are to be hooked into the vtxfmt
895 * maintained in ctx->ListState, active when the list is known or
896 * suspected to be outside any begin/end primitive.
897 */
898 static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
899 {
900 GET_CURRENT_CONTEXT(ctx);
901 vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK );
902 CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 ));
903 CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 ));
904 CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 ));
905 CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 ));
906 CALL_End(GET_DISPATCH(), ());
907 }
908
909
910 static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
911 {
912 GET_CURRENT_CONTEXT(ctx);
913 GLint i;
914
915 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
916 return;
917
918 _ae_map_vbos( ctx );
919
920 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
921
922 for (i = 0; i < count; i++)
923 CALL_ArrayElement(GET_DISPATCH(), (start + i));
924 CALL_End(GET_DISPATCH(), ());
925
926 _ae_unmap_vbos( ctx );
927 }
928
929 /* Could do better by copying the arrays and element list intact and
930 * then emitting an indexed prim at runtime.
931 */
932 static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
933 const GLvoid *indices)
934 {
935 GET_CURRENT_CONTEXT(ctx);
936 GLint i;
937
938 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
939 return;
940
941 _ae_map_vbos( ctx );
942
943 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj))
944 indices = ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices);
945
946 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
947
948 switch (type) {
949 case GL_UNSIGNED_BYTE:
950 for (i = 0 ; i < count ; i++)
951 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
952 break;
953 case GL_UNSIGNED_SHORT:
954 for (i = 0 ; i < count ; i++)
955 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
956 break;
957 case GL_UNSIGNED_INT:
958 for (i = 0 ; i < count ; i++)
959 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
960 break;
961 default:
962 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
963 break;
964 }
965
966 CALL_End(GET_DISPATCH(), ());
967
968 _ae_unmap_vbos( ctx );
969 }
970
971 static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
972 GLuint start, GLuint end,
973 GLsizei count, GLenum type,
974 const GLvoid *indices)
975 {
976 GET_CURRENT_CONTEXT(ctx);
977 if (_mesa_validate_DrawRangeElements( ctx, mode,
978 start, end,
979 count, type, indices, 0 ))
980 _save_OBE_DrawElements( mode, count, type, indices );
981 }
982
983
984
985
986
987 static void _save_vtxfmt_init( GLcontext *ctx )
988 {
989 struct vbo_save_context *save = &vbo_context(ctx)->save;
990 GLvertexformat *vfmt = &save->vtxfmt;
991
992 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
993
994 vfmt->Begin = _save_Begin;
995 vfmt->Color3f = _save_Color3f;
996 vfmt->Color3fv = _save_Color3fv;
997 vfmt->Color4f = _save_Color4f;
998 vfmt->Color4fv = _save_Color4fv;
999 vfmt->EdgeFlag = _save_EdgeFlag;
1000 vfmt->End = _save_End;
1001 vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1002 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1003 vfmt->Indexf = _save_Indexf;
1004 vfmt->Indexfv = _save_Indexfv;
1005 vfmt->Materialfv = _save_Materialfv;
1006 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1007 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1008 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1009 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1010 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1011 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1012 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1013 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1014 vfmt->Normal3f = _save_Normal3f;
1015 vfmt->Normal3fv = _save_Normal3fv;
1016 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1017 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1018 vfmt->TexCoord1f = _save_TexCoord1f;
1019 vfmt->TexCoord1fv = _save_TexCoord1fv;
1020 vfmt->TexCoord2f = _save_TexCoord2f;
1021 vfmt->TexCoord2fv = _save_TexCoord2fv;
1022 vfmt->TexCoord3f = _save_TexCoord3f;
1023 vfmt->TexCoord3fv = _save_TexCoord3fv;
1024 vfmt->TexCoord4f = _save_TexCoord4f;
1025 vfmt->TexCoord4fv = _save_TexCoord4fv;
1026 vfmt->Vertex2f = _save_Vertex2f;
1027 vfmt->Vertex2fv = _save_Vertex2fv;
1028 vfmt->Vertex3f = _save_Vertex3f;
1029 vfmt->Vertex3fv = _save_Vertex3fv;
1030 vfmt->Vertex4f = _save_Vertex4f;
1031 vfmt->Vertex4fv = _save_Vertex4fv;
1032 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1033 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1034 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1035 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1036 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1037 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1038 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1039 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1040
1041 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1042 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1043 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1044 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1045 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1046 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1047 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1048 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1049
1050 /* This will all require us to fallback to saving the list as opcodes:
1051 */
1052 _MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */
1053
1054 _MESA_INIT_EVAL_VTXFMT(vfmt, _save_);
1055
1056 /* These are all errors as we at least know we are in some sort of
1057 * begin/end pair:
1058 */
1059 vfmt->Begin = _save_Begin;
1060 vfmt->Rectf = _save_Rectf;
1061 vfmt->DrawArrays = _save_DrawArrays;
1062 vfmt->DrawElements = _save_DrawElements;
1063 vfmt->DrawRangeElements = _save_DrawRangeElements;
1064 vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex;
1065 vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex;
1066 /* Loops back into vfmt->DrawElements */
1067 vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
1068 vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
1069 }
1070
1071
1072 void vbo_save_SaveFlushVertices( GLcontext *ctx )
1073 {
1074 struct vbo_save_context *save = &vbo_context(ctx)->save;
1075
1076 /* Noop when we are actually active:
1077 */
1078 if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
1079 ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
1080 return;
1081
1082 if (save->vert_count ||
1083 save->prim_count)
1084 _save_compile_vertex_list( ctx );
1085
1086 _save_copy_to_current( ctx );
1087 _save_reset_vertex( ctx );
1088 _save_reset_counters( ctx );
1089 ctx->Driver.SaveNeedFlush = 0;
1090 }
1091
1092 void vbo_save_NewList( GLcontext *ctx, GLuint list, GLenum mode )
1093 {
1094 struct vbo_save_context *save = &vbo_context(ctx)->save;
1095
1096 (void) list; (void) mode;
1097
1098 if (!save->prim_store)
1099 save->prim_store = alloc_prim_store( ctx );
1100
1101 if (!save->vertex_store)
1102 save->vertex_store = alloc_vertex_store( ctx );
1103
1104 save->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
1105
1106 _save_reset_vertex( ctx );
1107 _save_reset_counters( ctx );
1108 ctx->Driver.SaveNeedFlush = 0;
1109 }
1110
1111 void vbo_save_EndList( GLcontext *ctx )
1112 {
1113 struct vbo_save_context *save = &vbo_context(ctx)->save;
1114
1115 /* EndList called inside a (saved) Begin/End pair?
1116 */
1117 if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) {
1118
1119 if (save->prim_count > 0) {
1120 GLint i = save->prim_count - 1;
1121 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1122 save->prim[i].end = 0;
1123 save->prim[i].count = (save->vert_count -
1124 save->prim[i].start);
1125 }
1126
1127 /* Make sure this vertex list gets replayed by the "loopback"
1128 * mechanism:
1129 */
1130 save->dangling_attr_ref = 1;
1131 vbo_save_SaveFlushVertices( ctx );
1132
1133 /* Swap out this vertex format while outside begin/end. Any color,
1134 * etc. received between here and the next begin will be compiled
1135 * as opcodes.
1136 */
1137 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1138 }
1139
1140 unmap_vertex_store( ctx, save->vertex_store );
1141
1142 assert(save->vertex_size == 0);
1143 }
1144
1145 void vbo_save_BeginCallList( GLcontext *ctx, struct gl_display_list *dlist )
1146 {
1147 struct vbo_save_context *save = &vbo_context(ctx)->save;
1148 save->replay_flags |= dlist->Flags;
1149 }
1150
1151 void vbo_save_EndCallList( GLcontext *ctx )
1152 {
1153 struct vbo_save_context *save = &vbo_context(ctx)->save;
1154
1155 if (ctx->ListState.CallDepth == 1) {
1156 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1157 * flag, if it is set:
1158 */
1159 save->replay_flags &= VBO_SAVE_FALLBACK;
1160 }
1161 }
1162
1163
1164 static void vbo_destroy_vertex_list( GLcontext *ctx, void *data )
1165 {
1166 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
1167 (void) ctx;
1168
1169 if ( --node->vertex_store->refcount == 0 )
1170 free_vertex_store( ctx, node->vertex_store );
1171
1172 if ( --node->prim_store->refcount == 0 )
1173 FREE( node->prim_store );
1174
1175 if (node->current_data) {
1176 FREE(node->current_data);
1177 node->current_data = NULL;
1178 }
1179 }
1180
1181
1182 static void vbo_print_vertex_list( GLcontext *ctx, void *data )
1183 {
1184 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
1185 GLuint i;
1186 (void) ctx;
1187
1188 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1189 node->count,
1190 node->prim_count,
1191 node->vertex_size);
1192
1193 for (i = 0 ; i < node->prim_count ; i++) {
1194 struct _mesa_prim *prim = &node->prim[i];
1195 _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n",
1196 i,
1197 _mesa_lookup_prim_by_nr(prim->mode),
1198 prim->weak ? " (weak)" : "",
1199 prim->start,
1200 prim->start + prim->count,
1201 (prim->begin) ? "BEGIN" : "(wrap)",
1202 (prim->end) ? "END" : "(wrap)");
1203 }
1204 }
1205
1206
1207 static void _save_current_init( GLcontext *ctx )
1208 {
1209 struct vbo_save_context *save = &vbo_context(ctx)->save;
1210 GLint i;
1211
1212 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1213 const GLuint j = i - VBO_ATTRIB_POS;
1214 ASSERT(j < VERT_ATTRIB_MAX);
1215 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1216 save->current[i] = ctx->ListState.CurrentAttrib[j];
1217 }
1218
1219 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1220 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1221 ASSERT(j < MAT_ATTRIB_MAX);
1222 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1223 save->current[i] = ctx->ListState.CurrentMaterial[j];
1224 }
1225 }
1226
1227 /**
1228 * Initialize the display list compiler
1229 */
1230 void vbo_save_api_init( struct vbo_save_context *save )
1231 {
1232 GLcontext *ctx = save->ctx;
1233 GLuint i;
1234
1235 save->opcode_vertex_list =
1236 _mesa_dlist_alloc_opcode( ctx,
1237 sizeof(struct vbo_save_vertex_list),
1238 vbo_save_playback_vertex_list,
1239 vbo_destroy_vertex_list,
1240 vbo_print_vertex_list );
1241
1242 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
1243
1244 _save_vtxfmt_init( ctx );
1245 _save_current_init( ctx );
1246
1247 /* These will actually get set again when binding/drawing */
1248 for (i = 0; i < VBO_ATTRIB_MAX; i++)
1249 save->inputs[i] = &save->arrays[i];
1250
1251 /* Hook our array functions into the outside-begin-end vtxfmt in
1252 * ctx->ListState.
1253 */
1254 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
1255 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
1256 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
1257 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
1258 /* loops back into _save_OBE_DrawElements */
1259 ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
1260 ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
1261 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1262 }
1263