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