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