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