1/**************************************************************************
2
3Copyright 2002-2008 VMware, Inc.
4
5All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the "Software"),
9to deal in the Software without restriction, including without limitation
10on the rights to use, copy, modify, merge, publish, distribute, sub
11license, and/or sell copies of the Software, and to permit persons to whom
12the Software is furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice (including the next
15paragraph) shall be included in all copies or substantial portions of the
16Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26**************************************************************************/
27
28/*
29 * Authors:
30 *   Keith Whitwell <keithw@vmware.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/arrayobj.h"
72#include "main/bufferobj.h"
73#include "main/context.h"
74#include "main/dlist.h"
75#include "main/enums.h"
76#include "main/eval.h"
77#include "main/macros.h"
78#include "main/draw_validate.h"
79#include "main/api_arrayelt.h"
80#include "main/vtxfmt.h"
81#include "main/dispatch.h"
82#include "main/state.h"
83#include "main/varray.h"
84#include "util/bitscan.h"
85
86#include "vbo_noop.h"
87#include "vbo_private.h"
88
89
90#ifdef ERROR
91#undef ERROR
92#endif
93
94/**
95 * Display list flag only used by this VBO code.
96 */
97#define DLIST_DANGLING_REFS     0x1
98
99
100/* An interesting VBO number/name to help with debugging */
101#define VBO_BUF_ID  12345
102
103
104/*
105 * NOTE: Old 'parity' issue is gone, but copying can still be
106 * wrong-footed on replay.
107 */
108static GLuint
109copy_vertices(struct gl_context *ctx,
110              const struct vbo_save_vertex_list *node,
111              const fi_type * src_buffer)
112{
113   struct vbo_save_context *save = &vbo_context(ctx)->save;
114   const struct _mesa_prim *prim = &node->prims[node->prim_count - 1];
115   GLuint nr = prim->count;
116   GLuint sz = save->vertex_size;
117   const fi_type *src = src_buffer + prim->start * sz;
118   fi_type *dst = save->copied.buffer;
119   GLuint ovf, i;
120
121   if (prim->end)
122      return 0;
123
124   switch (prim->mode) {
125   case GL_POINTS:
126      return 0;
127   case GL_LINES:
128      ovf = nr & 1;
129      for (i = 0; i < ovf; i++)
130         memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
131                sz * sizeof(GLfloat));
132      return i;
133   case GL_TRIANGLES:
134      ovf = nr % 3;
135      for (i = 0; i < ovf; i++)
136         memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
137                sz * sizeof(GLfloat));
138      return i;
139   case GL_QUADS:
140      ovf = nr & 3;
141      for (i = 0; i < ovf; i++)
142         memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
143                sz * sizeof(GLfloat));
144      return i;
145   case GL_LINE_STRIP:
146      if (nr == 0)
147         return 0;
148      else {
149         memcpy(dst, src + (nr - 1) * sz, sz * sizeof(GLfloat));
150         return 1;
151      }
152   case GL_LINE_LOOP:
153   case GL_TRIANGLE_FAN:
154   case GL_POLYGON:
155      if (nr == 0)
156         return 0;
157      else if (nr == 1) {
158         memcpy(dst, src + 0, sz * sizeof(GLfloat));
159         return 1;
160      }
161      else {
162         memcpy(dst, src + 0, sz * sizeof(GLfloat));
163         memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat));
164         return 2;
165      }
166   case GL_TRIANGLE_STRIP:
167   case GL_QUAD_STRIP:
168      switch (nr) {
169      case 0:
170         ovf = 0;
171         break;
172      case 1:
173         ovf = 1;
174         break;
175      default:
176         ovf = 2 + (nr & 1);
177         break;
178      }
179      for (i = 0; i < ovf; i++)
180         memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
181                sz * sizeof(GLfloat));
182      return i;
183   default:
184      unreachable("Unexpected primitive type");
185      return 0;
186   }
187}
188
189
190static struct vbo_save_vertex_store *
191alloc_vertex_store(struct gl_context *ctx)
192{
193   struct vbo_save_context *save = &vbo_context(ctx)->save;
194   struct vbo_save_vertex_store *vertex_store =
195      CALLOC_STRUCT(vbo_save_vertex_store);
196
197   /* obj->Name needs to be non-zero, but won't ever be examined more
198    * closely than that.  In particular these buffers won't be entered
199    * into the hash and can never be confused with ones visible to the
200    * user.  Perhaps there could be a special number for internal
201    * buffers:
202    */
203   vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID);
204   if (vertex_store->bufferobj) {
205      save->out_of_memory =
206         !ctx->Driver.BufferData(ctx,
207                                 GL_ARRAY_BUFFER_ARB,
208                                 VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
209                                 NULL, GL_STATIC_DRAW_ARB,
210                                 GL_MAP_WRITE_BIT |
211                                 GL_DYNAMIC_STORAGE_BIT,
212                                 vertex_store->bufferobj);
213   }
214   else {
215      save->out_of_memory = GL_TRUE;
216   }
217
218   if (save->out_of_memory) {
219      _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
220      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
221   }
222
223   vertex_store->buffer_map = NULL;
224   vertex_store->used = 0;
225
226   return vertex_store;
227}
228
229
230static void
231free_vertex_store(struct gl_context *ctx,
232                  struct vbo_save_vertex_store *vertex_store)
233{
234   assert(!vertex_store->buffer_map);
235
236   if (vertex_store->bufferobj) {
237      _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
238   }
239
240   free(vertex_store);
241}
242
243
244fi_type *
245vbo_save_map_vertex_store(struct gl_context *ctx,
246                          struct vbo_save_vertex_store *vertex_store)
247{
248   const GLbitfield access = (GL_MAP_WRITE_BIT |
249                              GL_MAP_INVALIDATE_RANGE_BIT |
250                              GL_MAP_UNSYNCHRONIZED_BIT |
251                              GL_MAP_FLUSH_EXPLICIT_BIT);
252
253   assert(vertex_store->bufferobj);
254   assert(!vertex_store->buffer_map);  /* the buffer should not be mapped */
255
256   if (vertex_store->bufferobj->Size > 0) {
257      /* Map the remaining free space in the VBO */
258      GLintptr offset = vertex_store->used * sizeof(GLfloat);
259      GLsizeiptr size = vertex_store->bufferobj->Size - offset;
260      fi_type *range = (fi_type *)
261         ctx->Driver.MapBufferRange(ctx, offset, size, access,
262                                    vertex_store->bufferobj,
263                                    MAP_INTERNAL);
264      if (range) {
265         /* compute address of start of whole buffer (needed elsewhere) */
266         vertex_store->buffer_map = range - vertex_store->used;
267         assert(vertex_store->buffer_map);
268         return range;
269      }
270      else {
271         vertex_store->buffer_map = NULL;
272         return NULL;
273      }
274   }
275   else {
276      /* probably ran out of memory for buffers */
277      return NULL;
278   }
279}
280
281
282void
283vbo_save_unmap_vertex_store(struct gl_context *ctx,
284                            struct vbo_save_vertex_store *vertex_store)
285{
286   if (vertex_store->bufferobj->Size > 0) {
287      GLintptr offset = 0;
288      GLsizeiptr length = vertex_store->used * sizeof(GLfloat)
289         - vertex_store->bufferobj->Mappings[MAP_INTERNAL].Offset;
290
291      /* Explicitly flush the region we wrote to */
292      ctx->Driver.FlushMappedBufferRange(ctx, offset, length,
293                                         vertex_store->bufferobj,
294                                         MAP_INTERNAL);
295
296      ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj, MAP_INTERNAL);
297   }
298   vertex_store->buffer_map = NULL;
299}
300
301
302static struct vbo_save_primitive_store *
303alloc_prim_store(void)
304{
305   struct vbo_save_primitive_store *store =
306      CALLOC_STRUCT(vbo_save_primitive_store);
307   store->used = 0;
308   store->refcount = 1;
309   return store;
310}
311
312
313static void
314reset_counters(struct gl_context *ctx)
315{
316   struct vbo_save_context *save = &vbo_context(ctx)->save;
317
318   save->prims = save->prim_store->prims + save->prim_store->used;
319   save->buffer_map = save->vertex_store->buffer_map + save->vertex_store->used;
320
321   assert(save->buffer_map == save->buffer_ptr);
322
323   if (save->vertex_size)
324      save->max_vert = (VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
325                        save->vertex_size;
326   else
327      save->max_vert = 0;
328
329   save->vert_count = 0;
330   save->prim_count = 0;
331   save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
332   save->dangling_attr_ref = GL_FALSE;
333}
334
335/**
336 * For a list of prims, try merging prims that can just be extensions of the
337 * previous prim.
338 */
339static void
340merge_prims(struct _mesa_prim *prim_list,
341            GLuint *prim_count)
342{
343   GLuint i;
344   struct _mesa_prim *prev_prim = prim_list;
345
346   for (i = 1; i < *prim_count; i++) {
347      struct _mesa_prim *this_prim = prim_list + i;
348
349      vbo_try_prim_conversion(this_prim);
350
351      if (vbo_can_merge_prims(prev_prim, this_prim)) {
352         /* We've found a prim that just extend the previous one.  Tack it
353          * onto the previous one, and let this primitive struct get dropped.
354          */
355         vbo_merge_prims(prev_prim, this_prim);
356         continue;
357      }
358
359      /* If any previous primitives have been dropped, then we need to copy
360       * this later one into the next available slot.
361       */
362      prev_prim++;
363      if (prev_prim != this_prim)
364         *prev_prim = *this_prim;
365   }
366
367   *prim_count = prev_prim - prim_list + 1;
368}
369
370
371/**
372 * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
373 * don't have to worry about handling the _mesa_prim::begin/end flags.
374 * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
375 */
376static void
377convert_line_loop_to_strip(struct vbo_save_context *save,
378                           struct vbo_save_vertex_list *node)
379{
380   struct _mesa_prim *prim = &node->prims[node->prim_count - 1];
381
382   assert(prim->mode == GL_LINE_LOOP);
383
384   if (prim->end) {
385      /* Copy the 0th vertex to end of the buffer and extend the
386       * vertex count by one to finish the line loop.
387       */
388      const GLuint sz = save->vertex_size;
389      /* 0th vertex: */
390      const fi_type *src = save->buffer_map + prim->start * sz;
391      /* end of buffer: */
392      fi_type *dst = save->buffer_map + (prim->start + prim->count) * sz;
393
394      memcpy(dst, src, sz * sizeof(float));
395
396      prim->count++;
397      node->vertex_count++;
398      save->vert_count++;
399      save->buffer_ptr += sz;
400      save->vertex_store->used += sz;
401   }
402
403   if (!prim->begin) {
404      /* Drawing the second or later section of a long line loop.
405       * Skip the 0th vertex.
406       */
407      prim->start++;
408      prim->count--;
409   }
410
411   prim->mode = GL_LINE_STRIP;
412}
413
414
415/* Compare the present vao if it has the same setup. */
416static bool
417compare_vao(gl_vertex_processing_mode mode,
418            const struct gl_vertex_array_object *vao,
419            const struct gl_buffer_object *bo, GLintptr buffer_offset,
420            GLuint stride, GLbitfield64 vao_enabled,
421            const GLubyte size[VBO_ATTRIB_MAX],
422            const GLenum16 type[VBO_ATTRIB_MAX],
423            const GLuint offset[VBO_ATTRIB_MAX])
424{
425   if (!vao)
426      return false;
427
428   /* If the enabled arrays are not the same we are not equal. */
429   if (vao_enabled != vao->Enabled)
430      return false;
431
432   /* Check the buffer binding at 0 */
433   if (vao->BufferBinding[0].BufferObj != bo)
434      return false;
435   /* BufferBinding[0].Offset != buffer_offset is checked per attribute */
436   if (vao->BufferBinding[0].Stride != stride)
437      return false;
438   assert(vao->BufferBinding[0].InstanceDivisor == 0);
439
440   /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */
441   const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
442
443   /* Now check the enabled arrays */
444   GLbitfield mask = vao_enabled;
445   while (mask) {
446      const int attr = u_bit_scan(&mask);
447      const unsigned char vbo_attr = vao_to_vbo_map[attr];
448      const GLenum16 tp = type[vbo_attr];
449      const GLintptr off = offset[vbo_attr] + buffer_offset;
450      const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr];
451      if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off)
452         return false;
453      if (attrib->Format.Type != tp)
454         return false;
455      if (attrib->Format.Size != size[vbo_attr])
456         return false;
457      assert(attrib->Format.Format == GL_RGBA);
458      assert(attrib->Format.Normalized == GL_FALSE);
459      assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp));
460      assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp));
461      assert(attrib->BufferBindingIndex == 0);
462   }
463
464   return true;
465}
466
467
468/* Create or reuse the vao for the vertex processing mode. */
469static void
470update_vao(struct gl_context *ctx,
471           gl_vertex_processing_mode mode,
472           struct gl_vertex_array_object **vao,
473           struct gl_buffer_object *bo, GLintptr buffer_offset,
474           GLuint stride, GLbitfield64 vbo_enabled,
475           const GLubyte size[VBO_ATTRIB_MAX],
476           const GLenum16 type[VBO_ATTRIB_MAX],
477           const GLuint offset[VBO_ATTRIB_MAX])
478{
479   /* Compute the bitmasks of vao_enabled arrays */
480   GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
481
482   /*
483    * Check if we can possibly reuse the exisiting one.
484    * In the long term we should reset them when something changes.
485    */
486   if (compare_vao(mode, *vao, bo, buffer_offset, stride,
487                   vao_enabled, size, type, offset))
488      return;
489
490   /* The initial refcount is 1 */
491   _mesa_reference_vao(ctx, vao, NULL);
492   *vao = _mesa_new_vao(ctx, ~((GLuint)0));
493
494   /*
495    * assert(stride <= ctx->Const.MaxVertexAttribStride);
496    * MaxVertexAttribStride is not set for drivers that does not
497    * expose GL 44 or GLES 31.
498    */
499
500   /* Bind the buffer object at binding point 0 */
501   _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride);
502
503   /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
504    * Note that the position/generic0 aliasing is done in the VAO.
505    */
506   const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
507   /* Now set the enable arrays */
508   GLbitfield mask = vao_enabled;
509   while (mask) {
510      const int vao_attr = u_bit_scan(&mask);
511      const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
512      assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
513
514      _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
515                             size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
516      _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
517   }
518   _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled);
519   assert(vao_enabled == (*vao)->Enabled);
520   assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
521
522   /* Finalize and freeze the VAO */
523   _mesa_set_vao_immutable(ctx, *vao);
524}
525
526
527/**
528 * Insert the active immediate struct onto the display list currently
529 * being built.
530 */
531static void
532compile_vertex_list(struct gl_context *ctx)
533{
534   struct vbo_save_context *save = &vbo_context(ctx)->save;
535   struct vbo_save_vertex_list *node;
536
537   /* Allocate space for this structure in the display list currently
538    * being compiled.
539    */
540   node = (struct vbo_save_vertex_list *)
541      _mesa_dlist_alloc_aligned(ctx, save->opcode_vertex_list, sizeof(*node));
542
543   if (!node)
544      return;
545
546   /* Make sure the pointer is aligned to the size of a pointer */
547   assert((GLintptr) node % sizeof(void *) == 0);
548
549   /* Duplicate our template, increment refcounts to the storage structs:
550    */
551   GLintptr old_offset = 0;
552   if (save->VAO[0]) {
553      old_offset = save->VAO[0]->BufferBinding[0].Offset
554         + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset;
555   }
556   const GLsizei stride = save->vertex_size*sizeof(GLfloat);
557   GLintptr buffer_offset =
558       (save->buffer_map - save->vertex_store->buffer_map) * sizeof(GLfloat);
559   assert(old_offset <= buffer_offset);
560   const GLintptr offset_diff = buffer_offset - old_offset;
561   GLuint start_offset = 0;
562   if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
563      /* The vertex size is an exact multiple of the buffer offset.
564       * This means that we can use zero-based vertex attribute pointers
565       * and specify the start of the primitive with the _mesa_prim::start
566       * field.  This results in issuing several draw calls with identical
567       * vertex attribute information.  This can result in fewer state
568       * changes in drivers.  In particular, the Gallium CSO module will
569       * filter out redundant vertex buffer changes.
570       */
571      /* We cannot immediately update the primitives as some methods below
572       * still need the uncorrected start vertices
573       */
574      start_offset = offset_diff/stride;
575      assert(old_offset == buffer_offset - offset_diff);
576      buffer_offset = old_offset;
577   }
578   GLuint offsets[VBO_ATTRIB_MAX];
579   for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
580      offsets[i] = offset;
581      offset += save->attrsz[i] * sizeof(GLfloat);
582   }
583   node->vertex_count = save->vert_count;
584   node->wrap_count = save->copied.nr;
585   node->prims = save->prims;
586   node->prim_count = save->prim_count;
587   node->prim_store = save->prim_store;
588
589   /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
590    * Note that this may reuse the previous one of possible.
591    */
592   for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
593      /* create or reuse the vao */
594      update_vao(ctx, vpm, &save->VAO[vpm],
595                 save->vertex_store->bufferobj, buffer_offset, stride,
596                 save->enabled, save->attrsz, save->attrtype, offsets);
597      /* Reference the vao in the dlist */
598      node->VAO[vpm] = NULL;
599      _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
600   }
601
602   node->prim_store->refcount++;
603
604   if (save->no_current_update) {
605      node->current_data = NULL;
606   }
607   else {
608      GLuint current_size = save->vertex_size - save->attrsz[0];
609      node->current_data = NULL;
610
611      if (current_size) {
612         node->current_data = malloc(current_size * sizeof(GLfloat));
613         if (node->current_data) {
614            const char *buffer = (const char *)save->buffer_map;
615            unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
616            unsigned vertex_offset = 0;
617
618            if (node->vertex_count)
619               vertex_offset = (node->vertex_count - 1) * stride;
620
621            memcpy(node->current_data, buffer + vertex_offset + attr_offset,
622                   current_size * sizeof(GLfloat));
623         } else {
624            _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
625         }
626      }
627   }
628
629   assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->vertex_count == 0);
630
631   if (save->dangling_attr_ref)
632      ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
633
634   save->vertex_store->used += save->vertex_size * node->vertex_count;
635   save->prim_store->used += node->prim_count;
636
637   /* Copy duplicated vertices
638    */
639   save->copied.nr = copy_vertices(ctx, node, save->buffer_map);
640
641   if (node->prims[node->prim_count - 1].mode == GL_LINE_LOOP) {
642      convert_line_loop_to_strip(save, node);
643   }
644
645   merge_prims(node->prims, &node->prim_count);
646
647   /* Correct the primitive starts, we can only do this here as copy_vertices
648    * and convert_line_loop_to_strip above consume the uncorrected starts.
649    * On the other hand the _vbo_loopback_vertex_list call below needs the
650    * primitves to be corrected already.
651    */
652   for (unsigned i = 0; i < node->prim_count; i++) {
653      node->prims[i].start += start_offset;
654   }
655
656   /* Deal with GL_COMPILE_AND_EXECUTE:
657    */
658   if (ctx->ExecuteFlag) {
659      struct _glapi_table *dispatch = GET_DISPATCH();
660
661      _glapi_set_dispatch(ctx->Exec);
662
663      /* Note that the range of referenced vertices must be mapped already */
664      _vbo_loopback_vertex_list(ctx, node);
665
666      _glapi_set_dispatch(dispatch);
667   }
668
669   /* Decide whether the storage structs are full, or can be used for
670    * the next vertex lists as well.
671    */
672   if (save->vertex_store->used >
673       VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
674
675      /* Unmap old store:
676       */
677      vbo_save_unmap_vertex_store(ctx, save->vertex_store);
678
679      /* Release old reference:
680       */
681      free_vertex_store(ctx, save->vertex_store);
682      save->vertex_store = NULL;
683      /* When we have a new vbo, we will for sure need a new vao */
684      for (gl_vertex_processing_mode vpm = 0; vpm < VP_MODE_MAX; ++vpm)
685         _mesa_reference_vao(ctx, &save->VAO[vpm], NULL);
686
687      /* Allocate and map new store:
688       */
689      save->vertex_store = alloc_vertex_store(ctx);
690      save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
691      save->out_of_memory = save->buffer_ptr == NULL;
692   }
693   else {
694      /* update buffer_ptr for next vertex */
695      save->buffer_ptr = save->vertex_store->buffer_map
696         + save->vertex_store->used;
697   }
698
699   if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
700      save->prim_store->refcount--;
701      assert(save->prim_store->refcount != 0);
702      save->prim_store = alloc_prim_store();
703   }
704
705   /* Reset our structures for the next run of vertices:
706    */
707   reset_counters(ctx);
708}
709
710
711/**
712 * This is called when we fill a vertex buffer before we hit a glEnd().
713 * We
714 * TODO -- If no new vertices have been stored, don't bother saving it.
715 */
716static void
717wrap_buffers(struct gl_context *ctx)
718{
719   struct vbo_save_context *save = &vbo_context(ctx)->save;
720   GLint i = save->prim_count - 1;
721   GLenum mode;
722
723   assert(i < (GLint) save->prim_max);
724   assert(i >= 0);
725
726   /* Close off in-progress primitive.
727    */
728   save->prims[i].count = (save->vert_count - save->prims[i].start);
729   mode = save->prims[i].mode;
730
731   /* store the copied vertices, and allocate a new list.
732    */
733   compile_vertex_list(ctx);
734
735   /* Restart interrupted primitive
736    */
737   save->prims[0].mode = mode;
738   save->prims[0].begin = 0;
739   save->prims[0].end = 0;
740   save->prims[0].pad = 0;
741   save->prims[0].start = 0;
742   save->prims[0].count = 0;
743   save->prims[0].num_instances = 1;
744   save->prims[0].base_instance = 0;
745   save->prims[0].is_indirect = 0;
746   save->prim_count = 1;
747}
748
749
750/**
751 * Called only when buffers are wrapped as the result of filling the
752 * vertex_store struct.
753 */
754static void
755wrap_filled_vertex(struct gl_context *ctx)
756{
757   struct vbo_save_context *save = &vbo_context(ctx)->save;
758   unsigned numComponents;
759
760   /* Emit a glEnd to close off the last vertex list.
761    */
762   wrap_buffers(ctx);
763
764   /* Copy stored stored vertices to start of new list.
765    */
766   assert(save->max_vert - save->vert_count > save->copied.nr);
767
768   numComponents = save->copied.nr * save->vertex_size;
769   memcpy(save->buffer_ptr,
770          save->copied.buffer,
771          numComponents * sizeof(fi_type));
772   save->buffer_ptr += numComponents;
773   save->vert_count += save->copied.nr;
774}
775
776
777static void
778copy_to_current(struct gl_context *ctx)
779{
780   struct vbo_save_context *save = &vbo_context(ctx)->save;
781   GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
782
783   while (enabled) {
784      const int i = u_bit_scan64(&enabled);
785      assert(save->attrsz[i]);
786
787      if (save->attrtype[i] == GL_DOUBLE ||
788          save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
789         memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
790      else
791         COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
792                                     save->attrptr[i], save->attrtype[i]);
793   }
794}
795
796
797static void
798copy_from_current(struct gl_context *ctx)
799{
800   struct vbo_save_context *save = &vbo_context(ctx)->save;
801   GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
802
803   while (enabled) {
804      const int i = u_bit_scan64(&enabled);
805
806      switch (save->attrsz[i]) {
807      case 4:
808         save->attrptr[i][3] = save->current[i][3];
809      case 3:
810         save->attrptr[i][2] = save->current[i][2];
811      case 2:
812         save->attrptr[i][1] = save->current[i][1];
813      case 1:
814         save->attrptr[i][0] = save->current[i][0];
815         break;
816      case 0:
817         unreachable("Unexpected vertex attribute size");
818      }
819   }
820}
821
822
823/**
824 * Called when we increase the size of a vertex attribute.  For example,
825 * if we've seen one or more glTexCoord2f() calls and now we get a
826 * glTexCoord3f() call.
827 * Flush existing data, set new attrib size, replay copied vertices.
828 */
829static void
830upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
831{
832   struct vbo_save_context *save = &vbo_context(ctx)->save;
833   GLuint oldsz;
834   GLuint i;
835   fi_type *tmp;
836
837   /* Store the current run of vertices, and emit a GL_END.  Emit a
838    * BEGIN in the new buffer.
839    */
840   if (save->vert_count)
841      wrap_buffers(ctx);
842   else
843      assert(save->copied.nr == 0);
844
845   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
846    * when the attribute already exists in the vertex and is having
847    * its size increased.
848    */
849   copy_to_current(ctx);
850
851   /* Fix up sizes:
852    */
853   oldsz = save->attrsz[attr];
854   save->attrsz[attr] = newsz;
855   save->enabled |= BITFIELD64_BIT(attr);
856
857   save->vertex_size += newsz - oldsz;
858   save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
859                     save->vertex_size);
860   save->vert_count = 0;
861
862   /* Recalculate all the attrptr[] values:
863    */
864   tmp = save->vertex;
865   for (i = 0; i < VBO_ATTRIB_MAX; i++) {
866      if (save->attrsz[i]) {
867         save->attrptr[i] = tmp;
868         tmp += save->attrsz[i];
869      }
870      else {
871         save->attrptr[i] = NULL;       /* will not be dereferenced. */
872      }
873   }
874
875   /* Copy from current to repopulate the vertex with correct values.
876    */
877   copy_from_current(ctx);
878
879   /* Replay stored vertices to translate them to new format here.
880    *
881    * If there are copied vertices and the new (upgraded) attribute
882    * has not been defined before, this list is somewhat degenerate,
883    * and will need fixup at runtime.
884    */
885   if (save->copied.nr) {
886      const fi_type *data = save->copied.buffer;
887      fi_type *dest = save->buffer_map;
888
889      /* Need to note this and fix up at runtime (or loopback):
890       */
891      if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
892         assert(oldsz == 0);
893         save->dangling_attr_ref = GL_TRUE;
894      }
895
896      for (i = 0; i < save->copied.nr; i++) {
897         GLbitfield64 enabled = save->enabled;
898         while (enabled) {
899            const int j = u_bit_scan64(&enabled);
900            assert(save->attrsz[j]);
901            if (j == attr) {
902               if (oldsz) {
903                  COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
904                                              save->attrtype[j]);
905                  data += oldsz;
906                  dest += newsz;
907               }
908               else {
909                  COPY_SZ_4V(dest, newsz, save->current[attr]);
910                  dest += newsz;
911               }
912            }
913            else {
914               GLint sz = save->attrsz[j];
915               COPY_SZ_4V(dest, sz, data);
916               data += sz;
917               dest += sz;
918            }
919         }
920      }
921
922      save->buffer_ptr = dest;
923      save->vert_count += save->copied.nr;
924   }
925}
926
927
928/**
929 * This is called when the size of a vertex attribute changes.
930 * For example, after seeing one or more glTexCoord2f() calls we
931 * get a glTexCoord4f() or glTexCoord1f() call.
932 */
933static void
934fixup_vertex(struct gl_context *ctx, GLuint attr,
935             GLuint sz, GLenum newType)
936{
937   struct vbo_save_context *save = &vbo_context(ctx)->save;
938
939   if (sz > save->attrsz[attr] ||
940       newType != save->attrtype[attr]) {
941      /* New size is larger.  Need to flush existing vertices and get
942       * an enlarged vertex format.
943       */
944      upgrade_vertex(ctx, attr, sz);
945   }
946   else if (sz < save->active_sz[attr]) {
947      GLuint i;
948      const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
949
950      /* New size is equal or smaller - just need to fill in some
951       * zeros.
952       */
953      for (i = sz; i <= save->attrsz[attr]; i++)
954         save->attrptr[attr][i - 1] = id[i - 1];
955   }
956
957   save->active_sz[attr] = sz;
958}
959
960
961/**
962 * Reset the current size of all vertex attributes to the default
963 * value of 0.  This signals that we haven't yet seen any per-vertex
964 * commands such as glNormal3f() or glTexCoord2f().
965 */
966static void
967reset_vertex(struct gl_context *ctx)
968{
969   struct vbo_save_context *save = &vbo_context(ctx)->save;
970
971   while (save->enabled) {
972      const int i = u_bit_scan64(&save->enabled);
973      assert(save->attrsz[i]);
974      save->attrsz[i] = 0;
975      save->active_sz[i] = 0;
976   }
977
978   save->vertex_size = 0;
979}
980
981
982/**
983 * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
984 * It depends on a few things, including whether we're inside or outside
985 * of glBegin/glEnd.
986 */
987static inline bool
988is_vertex_position(const struct gl_context *ctx, GLuint index)
989{
990   return (index == 0 &&
991           _mesa_attr_zero_aliases_vertex(ctx) &&
992           _mesa_inside_dlist_begin_end(ctx));
993}
994
995
996
997#define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
998
999
1000/* Only one size for each attribute may be active at once.  Eg. if
1001 * Color3f is installed/active, then Color4f may not be, even if the
1002 * vertex actually contains 4 color coordinates.  This is because the
1003 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1004 * of the chooser function when switching between Color4f and Color3f.
1005 */
1006#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)			\
1007do {								\
1008   struct vbo_save_context *save = &vbo_context(ctx)->save;	\
1009   int sz = (sizeof(C) / sizeof(GLfloat));			\
1010								\
1011   if (save->active_sz[A] != N)					\
1012      fixup_vertex(ctx, A, N * sz, T);				\
1013								\
1014   {								\
1015      C *dest = (C *)save->attrptr[A];                          \
1016      if (N>0) dest[0] = V0;					\
1017      if (N>1) dest[1] = V1;					\
1018      if (N>2) dest[2] = V2;					\
1019      if (N>3) dest[3] = V3;					\
1020      save->attrtype[A] = T;					\
1021   }								\
1022								\
1023   if ((A) == 0) {						\
1024      GLuint i;							\
1025								\
1026      for (i = 0; i < save->vertex_size; i++)			\
1027	 save->buffer_ptr[i] = save->vertex[i];			\
1028								\
1029      save->buffer_ptr += save->vertex_size;			\
1030								\
1031      if (++save->vert_count >= save->max_vert)			\
1032	 wrap_filled_vertex(ctx);				\
1033   }								\
1034} while (0)
1035
1036#define TAG(x) _save_##x
1037
1038#include "vbo_attrib_tmp.h"
1039
1040
1041
1042#define MAT( ATTR, N, face, params )			\
1043do {							\
1044   if (face != GL_BACK)					\
1045      MAT_ATTR( ATTR, N, params ); /* front */		\
1046   if (face != GL_FRONT)				\
1047      MAT_ATTR( ATTR + 1, N, params ); /* back */	\
1048} while (0)
1049
1050
1051/**
1052 * Save a glMaterial call found between glBegin/End.
1053 * glMaterial calls outside Begin/End are handled in dlist.c.
1054 */
1055static void GLAPIENTRY
1056_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1057{
1058   GET_CURRENT_CONTEXT(ctx);
1059
1060   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1061      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1062      return;
1063   }
1064
1065   switch (pname) {
1066   case GL_EMISSION:
1067      MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1068      break;
1069   case GL_AMBIENT:
1070      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1071      break;
1072   case GL_DIFFUSE:
1073      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1074      break;
1075   case GL_SPECULAR:
1076      MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1077      break;
1078   case GL_SHININESS:
1079      if (*params < 0 || *params > ctx->Const.MaxShininess) {
1080         _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1081      }
1082      else {
1083         MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1084      }
1085      break;
1086   case GL_COLOR_INDEXES:
1087      MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1088      break;
1089   case GL_AMBIENT_AND_DIFFUSE:
1090      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1091      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1092      break;
1093   default:
1094      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1095      return;
1096   }
1097}
1098
1099
1100/* Cope with EvalCoord/CallList called within a begin/end object:
1101 *     -- Flush current buffer
1102 *     -- Fallback to opcodes for the rest of the begin/end object.
1103 */
1104static void
1105dlist_fallback(struct gl_context *ctx)
1106{
1107   struct vbo_save_context *save = &vbo_context(ctx)->save;
1108
1109   if (save->vert_count || save->prim_count) {
1110      if (save->prim_count > 0) {
1111         /* Close off in-progress primitive. */
1112         GLint i = save->prim_count - 1;
1113         save->prims[i].count = save->vert_count - save->prims[i].start;
1114      }
1115
1116      /* Need to replay this display list with loopback,
1117       * unfortunately, otherwise this primitive won't be handled
1118       * properly:
1119       */
1120      save->dangling_attr_ref = GL_TRUE;
1121
1122      compile_vertex_list(ctx);
1123   }
1124
1125   copy_to_current(ctx);
1126   reset_vertex(ctx);
1127   reset_counters(ctx);
1128   if (save->out_of_memory) {
1129      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1130   }
1131   else {
1132      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1133   }
1134   ctx->Driver.SaveNeedFlush = GL_FALSE;
1135}
1136
1137
1138static void GLAPIENTRY
1139_save_EvalCoord1f(GLfloat u)
1140{
1141   GET_CURRENT_CONTEXT(ctx);
1142   dlist_fallback(ctx);
1143   CALL_EvalCoord1f(ctx->Save, (u));
1144}
1145
1146static void GLAPIENTRY
1147_save_EvalCoord1fv(const GLfloat * v)
1148{
1149   GET_CURRENT_CONTEXT(ctx);
1150   dlist_fallback(ctx);
1151   CALL_EvalCoord1fv(ctx->Save, (v));
1152}
1153
1154static void GLAPIENTRY
1155_save_EvalCoord2f(GLfloat u, GLfloat v)
1156{
1157   GET_CURRENT_CONTEXT(ctx);
1158   dlist_fallback(ctx);
1159   CALL_EvalCoord2f(ctx->Save, (u, v));
1160}
1161
1162static void GLAPIENTRY
1163_save_EvalCoord2fv(const GLfloat * v)
1164{
1165   GET_CURRENT_CONTEXT(ctx);
1166   dlist_fallback(ctx);
1167   CALL_EvalCoord2fv(ctx->Save, (v));
1168}
1169
1170static void GLAPIENTRY
1171_save_EvalPoint1(GLint i)
1172{
1173   GET_CURRENT_CONTEXT(ctx);
1174   dlist_fallback(ctx);
1175   CALL_EvalPoint1(ctx->Save, (i));
1176}
1177
1178static void GLAPIENTRY
1179_save_EvalPoint2(GLint i, GLint j)
1180{
1181   GET_CURRENT_CONTEXT(ctx);
1182   dlist_fallback(ctx);
1183   CALL_EvalPoint2(ctx->Save, (i, j));
1184}
1185
1186static void GLAPIENTRY
1187_save_CallList(GLuint l)
1188{
1189   GET_CURRENT_CONTEXT(ctx);
1190   dlist_fallback(ctx);
1191   CALL_CallList(ctx->Save, (l));
1192}
1193
1194static void GLAPIENTRY
1195_save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1196{
1197   GET_CURRENT_CONTEXT(ctx);
1198   dlist_fallback(ctx);
1199   CALL_CallLists(ctx->Save, (n, type, v));
1200}
1201
1202
1203
1204/**
1205 * Called when a glBegin is getting compiled into a display list.
1206 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1207 */
1208void
1209vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1210                     bool no_current_update)
1211{
1212   struct vbo_save_context *save = &vbo_context(ctx)->save;
1213   const GLuint i = save->prim_count++;
1214
1215   ctx->Driver.CurrentSavePrimitive = mode;
1216
1217   assert(i < save->prim_max);
1218   save->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1219   save->prims[i].begin = 1;
1220   save->prims[i].end = 0;
1221   save->prims[i].pad = 0;
1222   save->prims[i].start = save->vert_count;
1223   save->prims[i].count = 0;
1224   save->prims[i].num_instances = 1;
1225   save->prims[i].base_instance = 0;
1226   save->prims[i].is_indirect = 0;
1227
1228   save->no_current_update = no_current_update;
1229
1230   if (save->out_of_memory) {
1231      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1232   }
1233   else {
1234      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1235   }
1236
1237   /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1238   ctx->Driver.SaveNeedFlush = GL_TRUE;
1239}
1240
1241
1242static void GLAPIENTRY
1243_save_End(void)
1244{
1245   GET_CURRENT_CONTEXT(ctx);
1246   struct vbo_save_context *save = &vbo_context(ctx)->save;
1247   const GLint i = save->prim_count - 1;
1248
1249   ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1250   save->prims[i].end = 1;
1251   save->prims[i].count = (save->vert_count - save->prims[i].start);
1252
1253   if (i == (GLint) save->prim_max - 1) {
1254      compile_vertex_list(ctx);
1255      assert(save->copied.nr == 0);
1256   }
1257
1258   /* Swap out this vertex format while outside begin/end.  Any color,
1259    * etc. received between here and the next begin will be compiled
1260    * as opcodes.
1261    */
1262   if (save->out_of_memory) {
1263      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1264   }
1265   else {
1266      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1267   }
1268}
1269
1270
1271static void GLAPIENTRY
1272_save_Begin(GLenum mode)
1273{
1274   GET_CURRENT_CONTEXT(ctx);
1275   (void) mode;
1276   _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1277}
1278
1279
1280static void GLAPIENTRY
1281_save_PrimitiveRestartNV(void)
1282{
1283   GET_CURRENT_CONTEXT(ctx);
1284   struct vbo_save_context *save = &vbo_context(ctx)->save;
1285
1286   if (save->prim_count == 0) {
1287      /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1288       * is an error.
1289       */
1290      _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1291                          "glPrimitiveRestartNV called outside glBegin/End");
1292   } else {
1293      /* get current primitive mode */
1294      GLenum curPrim = save->prims[save->prim_count - 1].mode;
1295      bool no_current_update = save->no_current_update;
1296
1297      /* restart primitive */
1298      CALL_End(GET_DISPATCH(), ());
1299      vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1300   }
1301}
1302
1303
1304/* Unlike the functions above, these are to be hooked into the vtxfmt
1305 * maintained in ctx->ListState, active when the list is known or
1306 * suspected to be outside any begin/end primitive.
1307 * Note: OBE = Outside Begin/End
1308 */
1309static void GLAPIENTRY
1310_save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1311{
1312   GET_CURRENT_CONTEXT(ctx);
1313   vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1314   CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
1315   CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
1316   CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
1317   CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
1318   CALL_End(GET_DISPATCH(), ());
1319}
1320
1321
1322static void GLAPIENTRY
1323_save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1324{
1325   GET_CURRENT_CONTEXT(ctx);
1326   struct gl_vertex_array_object *vao = ctx->Array.VAO;
1327   struct vbo_save_context *save = &vbo_context(ctx)->save;
1328   GLint i;
1329
1330   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1331      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1332      return;
1333   }
1334   if (count < 0) {
1335      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1336      return;
1337   }
1338
1339   if (save->out_of_memory)
1340      return;
1341
1342   /* Make sure to process any VBO binding changes */
1343   _mesa_update_state(ctx);
1344
1345   _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1346
1347   vbo_save_NotifyBegin(ctx, mode, true);
1348
1349   for (i = 0; i < count; i++)
1350      _mesa_array_element(ctx, start + i);
1351   CALL_End(GET_DISPATCH(), ());
1352
1353   _mesa_vao_unmap_arrays(ctx, vao);
1354}
1355
1356
1357static void GLAPIENTRY
1358_save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1359                          const GLsizei *count, GLsizei primcount)
1360{
1361   GET_CURRENT_CONTEXT(ctx);
1362   GLint i;
1363
1364   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1365      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1366      return;
1367   }
1368
1369   if (primcount < 0) {
1370      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1371                          "glMultiDrawArrays(primcount<0)");
1372      return;
1373   }
1374
1375   for (i = 0; i < primcount; i++) {
1376      if (count[i] < 0) {
1377         _mesa_compile_error(ctx, GL_INVALID_VALUE,
1378                             "glMultiDrawArrays(count[i]<0)");
1379         return;
1380      }
1381   }
1382
1383   for (i = 0; i < primcount; i++) {
1384      if (count[i] > 0) {
1385         _save_OBE_DrawArrays(mode, first[i], count[i]);
1386      }
1387   }
1388}
1389
1390
1391static void
1392array_element(struct gl_context *ctx,
1393              GLint basevertex, GLuint elt, unsigned index_size)
1394{
1395   /* Section 10.3.5 Primitive Restart:
1396    * [...]
1397    *    When one of the *BaseVertex drawing commands specified in section 10.5
1398    * is used, the primitive restart comparison occurs before the basevertex
1399    * offset is added to the array index.
1400    */
1401   /* If PrimitiveRestart is enabled and the index is the RestartIndex
1402    * then we call PrimitiveRestartNV and return.
1403    */
1404   if (ctx->Array._PrimitiveRestart &&
1405       elt == _mesa_primitive_restart_index(ctx, index_size)) {
1406      CALL_PrimitiveRestartNV(GET_DISPATCH(), ());
1407      return;
1408   }
1409
1410   _mesa_array_element(ctx, basevertex + elt);
1411}
1412
1413
1414/* Could do better by copying the arrays and element list intact and
1415 * then emitting an indexed prim at runtime.
1416 */
1417static void GLAPIENTRY
1418_save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1419                                 const GLvoid * indices, GLint basevertex)
1420{
1421   GET_CURRENT_CONTEXT(ctx);
1422   struct vbo_save_context *save = &vbo_context(ctx)->save;
1423   struct gl_vertex_array_object *vao = ctx->Array.VAO;
1424   struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1425   GLint i;
1426
1427   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1428      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1429      return;
1430   }
1431   if (count < 0) {
1432      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1433      return;
1434   }
1435   if (type != GL_UNSIGNED_BYTE &&
1436       type != GL_UNSIGNED_SHORT &&
1437       type != GL_UNSIGNED_INT) {
1438      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1439      return;
1440   }
1441
1442   if (save->out_of_memory)
1443      return;
1444
1445   /* Make sure to process any VBO binding changes */
1446   _mesa_update_state(ctx);
1447
1448   _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1449
1450   if (_mesa_is_bufferobj(indexbuf))
1451      indices =
1452         ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1453
1454   vbo_save_NotifyBegin(ctx, mode, true);
1455
1456   switch (type) {
1457   case GL_UNSIGNED_BYTE:
1458      for (i = 0; i < count; i++)
1459         array_element(ctx, basevertex, ((GLubyte *) indices)[i], 1);
1460      break;
1461   case GL_UNSIGNED_SHORT:
1462      for (i = 0; i < count; i++)
1463         array_element(ctx, basevertex, ((GLushort *) indices)[i], 2);
1464      break;
1465   case GL_UNSIGNED_INT:
1466      for (i = 0; i < count; i++)
1467         array_element(ctx, basevertex, ((GLuint *) indices)[i], 4);
1468      break;
1469   default:
1470      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1471      break;
1472   }
1473
1474   CALL_End(GET_DISPATCH(), ());
1475
1476   _mesa_vao_unmap(ctx, vao);
1477}
1478
1479static void GLAPIENTRY
1480_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1481                       const GLvoid * indices)
1482{
1483   _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1484}
1485
1486
1487static void GLAPIENTRY
1488_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1489                            GLsizei count, GLenum type,
1490                            const GLvoid * indices)
1491{
1492   GET_CURRENT_CONTEXT(ctx);
1493   struct vbo_save_context *save = &vbo_context(ctx)->save;
1494
1495   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1496      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1497      return;
1498   }
1499   if (count < 0) {
1500      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1501                          "glDrawRangeElements(count<0)");
1502      return;
1503   }
1504   if (type != GL_UNSIGNED_BYTE &&
1505       type != GL_UNSIGNED_SHORT &&
1506       type != GL_UNSIGNED_INT) {
1507      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1508      return;
1509   }
1510   if (end < start) {
1511      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1512                          "glDrawRangeElements(end < start)");
1513      return;
1514   }
1515
1516   if (save->out_of_memory)
1517      return;
1518
1519   _save_OBE_DrawElements(mode, count, type, indices);
1520}
1521
1522
1523static void GLAPIENTRY
1524_save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1525                            const GLvoid * const *indices, GLsizei primcount)
1526{
1527   GLsizei i;
1528
1529   for (i = 0; i < primcount; i++) {
1530      if (count[i] > 0) {
1531	 CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
1532      }
1533   }
1534}
1535
1536
1537static void GLAPIENTRY
1538_save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1539                                      GLenum type,
1540                                      const GLvoid * const *indices,
1541                                      GLsizei primcount,
1542                                      const GLint *basevertex)
1543{
1544   GLsizei i;
1545
1546   for (i = 0; i < primcount; i++) {
1547      if (count[i] > 0) {
1548	 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
1549						      indices[i],
1550						      basevertex[i]));
1551      }
1552   }
1553}
1554
1555
1556static void
1557vtxfmt_init(struct gl_context *ctx)
1558{
1559   struct vbo_save_context *save = &vbo_context(ctx)->save;
1560   GLvertexformat *vfmt = &save->vtxfmt;
1561
1562   vfmt->ArrayElement = _ae_ArrayElement;
1563
1564   vfmt->Color3f = _save_Color3f;
1565   vfmt->Color3fv = _save_Color3fv;
1566   vfmt->Color4f = _save_Color4f;
1567   vfmt->Color4fv = _save_Color4fv;
1568   vfmt->EdgeFlag = _save_EdgeFlag;
1569   vfmt->End = _save_End;
1570   vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1571   vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1572   vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1573   vfmt->Indexf = _save_Indexf;
1574   vfmt->Indexfv = _save_Indexfv;
1575   vfmt->Materialfv = _save_Materialfv;
1576   vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1577   vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1578   vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1579   vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1580   vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1581   vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1582   vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1583   vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1584   vfmt->Normal3f = _save_Normal3f;
1585   vfmt->Normal3fv = _save_Normal3fv;
1586   vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1587   vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1588   vfmt->TexCoord1f = _save_TexCoord1f;
1589   vfmt->TexCoord1fv = _save_TexCoord1fv;
1590   vfmt->TexCoord2f = _save_TexCoord2f;
1591   vfmt->TexCoord2fv = _save_TexCoord2fv;
1592   vfmt->TexCoord3f = _save_TexCoord3f;
1593   vfmt->TexCoord3fv = _save_TexCoord3fv;
1594   vfmt->TexCoord4f = _save_TexCoord4f;
1595   vfmt->TexCoord4fv = _save_TexCoord4fv;
1596   vfmt->Vertex2f = _save_Vertex2f;
1597   vfmt->Vertex2fv = _save_Vertex2fv;
1598   vfmt->Vertex3f = _save_Vertex3f;
1599   vfmt->Vertex3fv = _save_Vertex3fv;
1600   vfmt->Vertex4f = _save_Vertex4f;
1601   vfmt->Vertex4fv = _save_Vertex4fv;
1602   vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1603   vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1604   vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1605   vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1606   vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1607   vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1608   vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1609   vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1610
1611   vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1612   vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1613   vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1614   vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1615   vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1616   vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1617   vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1618   vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1619
1620   /* integer-valued */
1621   vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1622   vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1623   vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1624   vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1625   vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1626   vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1627   vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1628
1629   /* unsigned integer-valued */
1630   vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1631   vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1632   vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1633   vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1634   vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1635   vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1636   vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1637
1638   vfmt->VertexP2ui = _save_VertexP2ui;
1639   vfmt->VertexP3ui = _save_VertexP3ui;
1640   vfmt->VertexP4ui = _save_VertexP4ui;
1641   vfmt->VertexP2uiv = _save_VertexP2uiv;
1642   vfmt->VertexP3uiv = _save_VertexP3uiv;
1643   vfmt->VertexP4uiv = _save_VertexP4uiv;
1644
1645   vfmt->TexCoordP1ui = _save_TexCoordP1ui;
1646   vfmt->TexCoordP2ui = _save_TexCoordP2ui;
1647   vfmt->TexCoordP3ui = _save_TexCoordP3ui;
1648   vfmt->TexCoordP4ui = _save_TexCoordP4ui;
1649   vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
1650   vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
1651   vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
1652   vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
1653
1654   vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
1655   vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
1656   vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
1657   vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
1658   vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
1659   vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
1660   vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
1661   vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
1662
1663   vfmt->NormalP3ui = _save_NormalP3ui;
1664   vfmt->NormalP3uiv = _save_NormalP3uiv;
1665
1666   vfmt->ColorP3ui = _save_ColorP3ui;
1667   vfmt->ColorP4ui = _save_ColorP4ui;
1668   vfmt->ColorP3uiv = _save_ColorP3uiv;
1669   vfmt->ColorP4uiv = _save_ColorP4uiv;
1670
1671   vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
1672   vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
1673
1674   vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
1675   vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
1676   vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
1677   vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
1678
1679   vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
1680   vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
1681   vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
1682   vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
1683
1684   vfmt->VertexAttribL1d = _save_VertexAttribL1d;
1685   vfmt->VertexAttribL2d = _save_VertexAttribL2d;
1686   vfmt->VertexAttribL3d = _save_VertexAttribL3d;
1687   vfmt->VertexAttribL4d = _save_VertexAttribL4d;
1688
1689   vfmt->VertexAttribL1dv = _save_VertexAttribL1dv;
1690   vfmt->VertexAttribL2dv = _save_VertexAttribL2dv;
1691   vfmt->VertexAttribL3dv = _save_VertexAttribL3dv;
1692   vfmt->VertexAttribL4dv = _save_VertexAttribL4dv;
1693
1694   vfmt->VertexAttribL1ui64ARB = _save_VertexAttribL1ui64ARB;
1695   vfmt->VertexAttribL1ui64vARB = _save_VertexAttribL1ui64vARB;
1696
1697   /* This will all require us to fallback to saving the list as opcodes:
1698    */
1699   vfmt->CallList = _save_CallList;
1700   vfmt->CallLists = _save_CallLists;
1701
1702   vfmt->EvalCoord1f = _save_EvalCoord1f;
1703   vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1704   vfmt->EvalCoord2f = _save_EvalCoord2f;
1705   vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1706   vfmt->EvalPoint1 = _save_EvalPoint1;
1707   vfmt->EvalPoint2 = _save_EvalPoint2;
1708
1709   /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1710    * only used when we're inside a glBegin/End pair.
1711    */
1712   vfmt->Begin = _save_Begin;
1713}
1714
1715
1716/**
1717 * Initialize the dispatch table with the VBO functions for display
1718 * list compilation.
1719 */
1720void
1721vbo_initialize_save_dispatch(const struct gl_context *ctx,
1722                             struct _glapi_table *exec)
1723{
1724   SET_DrawArrays(exec, _save_OBE_DrawArrays);
1725   SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1726   SET_DrawElements(exec, _save_OBE_DrawElements);
1727   SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1728   SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1729   SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1730   SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1731   SET_Rectf(exec, _save_OBE_Rectf);
1732   /* Note: other glDraw functins aren't compiled into display lists */
1733}
1734
1735
1736
1737void
1738vbo_save_SaveFlushVertices(struct gl_context *ctx)
1739{
1740   struct vbo_save_context *save = &vbo_context(ctx)->save;
1741
1742   /* Noop when we are actually active:
1743    */
1744   if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1745      return;
1746
1747   if (save->vert_count || save->prim_count)
1748      compile_vertex_list(ctx);
1749
1750   copy_to_current(ctx);
1751   reset_vertex(ctx);
1752   reset_counters(ctx);
1753   ctx->Driver.SaveNeedFlush = GL_FALSE;
1754}
1755
1756
1757/**
1758 * Called from glNewList when we're starting to compile a display list.
1759 */
1760void
1761vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1762{
1763   struct vbo_save_context *save = &vbo_context(ctx)->save;
1764
1765   (void) list;
1766   (void) mode;
1767
1768   if (!save->prim_store)
1769      save->prim_store = alloc_prim_store();
1770
1771   if (!save->vertex_store)
1772      save->vertex_store = alloc_vertex_store(ctx);
1773
1774   save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1775
1776   reset_vertex(ctx);
1777   reset_counters(ctx);
1778   ctx->Driver.SaveNeedFlush = GL_FALSE;
1779}
1780
1781
1782/**
1783 * Called from glEndList when we're finished compiling a display list.
1784 */
1785void
1786vbo_save_EndList(struct gl_context *ctx)
1787{
1788   struct vbo_save_context *save = &vbo_context(ctx)->save;
1789
1790   /* EndList called inside a (saved) Begin/End pair?
1791    */
1792   if (_mesa_inside_dlist_begin_end(ctx)) {
1793      if (save->prim_count > 0) {
1794         GLint i = save->prim_count - 1;
1795         ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1796         save->prims[i].end = 0;
1797         save->prims[i].count = save->vert_count - save->prims[i].start;
1798      }
1799
1800      /* Make sure this vertex list gets replayed by the "loopback"
1801       * mechanism:
1802       */
1803      save->dangling_attr_ref = GL_TRUE;
1804      vbo_save_SaveFlushVertices(ctx);
1805
1806      /* Swap out this vertex format while outside begin/end.  Any color,
1807       * etc. received between here and the next begin will be compiled
1808       * as opcodes.
1809       */
1810      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1811   }
1812
1813   vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1814
1815   assert(save->vertex_size == 0);
1816}
1817
1818
1819/**
1820 * Called from the display list code when we're about to execute a
1821 * display list.
1822 */
1823void
1824vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1825{
1826   struct vbo_save_context *save = &vbo_context(ctx)->save;
1827   save->replay_flags |= dlist->Flags;
1828}
1829
1830
1831/**
1832 * Called from the display list code when we're finished executing a
1833 * display list.
1834 */
1835void
1836vbo_save_EndCallList(struct gl_context *ctx)
1837{
1838   struct vbo_save_context *save = &vbo_context(ctx)->save;
1839
1840   if (ctx->ListState.CallDepth == 1)
1841      save->replay_flags = 0;
1842}
1843
1844
1845/**
1846 * Called by display list code when a display list is being deleted.
1847 */
1848static void
1849vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
1850{
1851   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1852
1853   for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm)
1854      _mesa_reference_vao(ctx, &node->VAO[vpm], NULL);
1855
1856   if (--node->prim_store->refcount == 0)
1857      free(node->prim_store);
1858
1859   free(node->current_data);
1860   node->current_data = NULL;
1861}
1862
1863
1864static void
1865vbo_print_vertex_list(struct gl_context *ctx, void *data, FILE *f)
1866{
1867   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1868   GLuint i;
1869   struct gl_buffer_object *buffer = node->VAO[0]->BufferBinding[0].BufferObj;
1870   const GLuint vertex_size = _vbo_save_get_stride(node)/sizeof(GLfloat);
1871   (void) ctx;
1872
1873   fprintf(f, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, "
1874           "buffer %p\n",
1875           node->vertex_count, node->prim_count, vertex_size,
1876           buffer);
1877
1878   for (i = 0; i < node->prim_count; i++) {
1879      struct _mesa_prim *prim = &node->prims[i];
1880      fprintf(f, "   prim %d: %s %d..%d %s %s\n",
1881             i,
1882             _mesa_lookup_prim_by_nr(prim->mode),
1883             prim->start,
1884             prim->start + prim->count,
1885             (prim->begin) ? "BEGIN" : "(wrap)",
1886             (prim->end) ? "END" : "(wrap)");
1887   }
1888}
1889
1890
1891/**
1892 * Called during context creation/init.
1893 */
1894static void
1895current_init(struct gl_context *ctx)
1896{
1897   struct vbo_save_context *save = &vbo_context(ctx)->save;
1898   GLint i;
1899
1900   for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1901      const GLuint j = i - VBO_ATTRIB_POS;
1902      assert(j < VERT_ATTRIB_MAX);
1903      save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1904      save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1905   }
1906
1907   for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1908      const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1909      assert(j < MAT_ATTRIB_MAX);
1910      save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1911      save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
1912   }
1913}
1914
1915
1916/**
1917 * Initialize the display list compiler.  Called during context creation.
1918 */
1919void
1920vbo_save_api_init(struct vbo_save_context *save)
1921{
1922   struct gl_context *ctx = save->ctx;
1923
1924   save->opcode_vertex_list =
1925      _mesa_dlist_alloc_opcode(ctx,
1926                               sizeof(struct vbo_save_vertex_list),
1927                               vbo_save_playback_vertex_list,
1928                               vbo_destroy_vertex_list,
1929                               vbo_print_vertex_list);
1930
1931   vtxfmt_init(ctx);
1932   current_init(ctx);
1933   _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
1934}
1935