OSDN Git Service

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