vbo_save_api.c revision 01e04c3f
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->Type != tp)
454         return false;
455      if (attrib->Size != size[vbo_attr])
456         return false;
457      assert(attrib->Format == GL_RGBA);
458      assert(attrib->Enabled == GL_TRUE);
459      assert(attrib->Normalized == GL_FALSE);
460      assert(attrib->Integer == vbo_attrtype_to_integer_flag(tp));
461      assert(attrib->Doubles == vbo_attrtype_to_double_flag(tp));
462      assert(attrib->BufferBindingIndex == 0);
463   }
464
465   return true;
466}
467
468
469/* Create or reuse the vao for the vertex processing mode. */
470static void
471update_vao(struct gl_context *ctx,
472           gl_vertex_processing_mode mode,
473           struct gl_vertex_array_object **vao,
474           struct gl_buffer_object *bo, GLintptr buffer_offset,
475           GLuint stride, GLbitfield64 vbo_enabled,
476           const GLubyte size[VBO_ATTRIB_MAX],
477           const GLenum16 type[VBO_ATTRIB_MAX],
478           const GLuint offset[VBO_ATTRIB_MAX])
479{
480   /* Compute the bitmasks of vao_enabled arrays */
481   GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
482
483   /*
484    * Check if we can possibly reuse the exisiting one.
485    * In the long term we should reset them when something changes.
486    */
487   if (compare_vao(mode, *vao, bo, buffer_offset, stride,
488                   vao_enabled, size, type, offset))
489      return;
490
491   /* The initial refcount is 1 */
492   _mesa_reference_vao(ctx, vao, NULL);
493   *vao = _mesa_new_vao(ctx, ~((GLuint)0));
494
495   /*
496    * assert(stride <= ctx->Const.MaxVertexAttribStride);
497    * MaxVertexAttribStride is not set for drivers that does not
498    * expose GL 44 or GLES 31.
499    */
500
501   /* Bind the buffer object at binding point 0 */
502   _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride);
503
504   /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
505    * Note that the position/generic0 aliasing is done in the VAO.
506    */
507   const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
508   /* Now set the enable arrays */
509   GLbitfield mask = vao_enabled;
510   while (mask) {
511      const int vao_attr = u_bit_scan(&mask);
512      const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
513      assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
514
515      _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
516                             size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
517      _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
518      _mesa_enable_vertex_array_attrib(ctx, *vao, vao_attr);
519   }
520   assert(vao_enabled == (*vao)->_Enabled);
521   assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
522
523   /* Finalize and freeze the VAO */
524   _mesa_set_vao_immutable(ctx, *vao);
525}
526
527
528/**
529 * Insert the active immediate struct onto the display list currently
530 * being built.
531 */
532static void
533compile_vertex_list(struct gl_context *ctx)
534{
535   struct vbo_save_context *save = &vbo_context(ctx)->save;
536   struct vbo_save_vertex_list *node;
537
538   /* Allocate space for this structure in the display list currently
539    * being compiled.
540    */
541   node = (struct vbo_save_vertex_list *)
542      _mesa_dlist_alloc_aligned(ctx, save->opcode_vertex_list, sizeof(*node));
543
544   if (!node)
545      return;
546
547   /* Make sure the pointer is aligned to the size of a pointer */
548   assert((GLintptr) node % sizeof(void *) == 0);
549
550   /* Duplicate our template, increment refcounts to the storage structs:
551    */
552   GLintptr old_offset = 0;
553   if (save->VAO[0]) {
554      old_offset = save->VAO[0]->BufferBinding[0].Offset
555         + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset;
556   }
557   const GLsizei stride = save->vertex_size*sizeof(GLfloat);
558   GLintptr buffer_offset =
559       (save->buffer_map - save->vertex_store->buffer_map) * sizeof(GLfloat);
560   assert(old_offset <= buffer_offset);
561   const GLintptr offset_diff = buffer_offset - old_offset;
562   GLuint start_offset = 0;
563   if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
564      /* The vertex size is an exact multiple of the buffer offset.
565       * This means that we can use zero-based vertex attribute pointers
566       * and specify the start of the primitive with the _mesa_prim::start
567       * field.  This results in issuing several draw calls with identical
568       * vertex attribute information.  This can result in fewer state
569       * changes in drivers.  In particular, the Gallium CSO module will
570       * filter out redundant vertex buffer changes.
571       */
572      /* We cannot immediately update the primitives as some methods below
573       * still need the uncorrected start vertices
574       */
575      start_offset = offset_diff/stride;
576      assert(old_offset == buffer_offset - offset_diff);
577      buffer_offset = old_offset;
578   }
579   GLuint offsets[VBO_ATTRIB_MAX];
580   for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
581      offsets[i] = offset;
582      offset += save->attrsz[i] * sizeof(GLfloat);
583   }
584   node->vertex_count = save->vert_count;
585   node->wrap_count = save->copied.nr;
586   node->prims = save->prims;
587   node->prim_count = save->prim_count;
588   node->prim_store = save->prim_store;
589
590   /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
591    * Note that this may reuse the previous one of possible.
592    */
593   for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
594      /* create or reuse the vao */
595      update_vao(ctx, vpm, &save->VAO[vpm],
596                 save->vertex_store->bufferobj, buffer_offset, stride,
597                 save->enabled, save->attrsz, save->attrtype, offsets);
598      /* Reference the vao in the dlist */
599      node->VAO[vpm] = NULL;
600      _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
601   }
602
603   node->prim_store->refcount++;
604
605   if (save->no_current_update) {
606      node->current_data = NULL;
607   }
608   else {
609      GLuint current_size = save->vertex_size - save->attrsz[0];
610      node->current_data = NULL;
611
612      if (current_size) {
613         node->current_data = malloc(current_size * sizeof(GLfloat));
614         if (node->current_data) {
615            const char *buffer = (const char *)save->buffer_map;
616            unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
617            unsigned vertex_offset = 0;
618
619            if (node->vertex_count)
620               vertex_offset = (node->vertex_count - 1) * stride;
621
622            memcpy(node->current_data, buffer + vertex_offset + attr_offset,
623                   current_size * sizeof(GLfloat));
624         } else {
625            _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
626         }
627      }
628   }
629
630   assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->vertex_count == 0);
631
632   if (save->dangling_attr_ref)
633      ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
634
635   save->vertex_store->used += save->vertex_size * node->vertex_count;
636   save->prim_store->used += node->prim_count;
637
638   /* Copy duplicated vertices
639    */
640   save->copied.nr = copy_vertices(ctx, node, save->buffer_map);
641
642   if (node->prims[node->prim_count - 1].mode == GL_LINE_LOOP) {
643      convert_line_loop_to_strip(save, node);
644   }
645
646   merge_prims(node->prims, &node->prim_count);
647
648   /* Correct the primitive starts, we can only do this here as copy_vertices
649    * and convert_line_loop_to_strip above consume the uncorrected starts.
650    * On the other hand the _vbo_loopback_vertex_list call below needs the
651    * primitves to be corrected already.
652    */
653   for (unsigned i = 0; i < node->prim_count; i++) {
654      node->prims[i].start += start_offset;
655   }
656
657   /* Deal with GL_COMPILE_AND_EXECUTE:
658    */
659   if (ctx->ExecuteFlag) {
660      struct _glapi_table *dispatch = GET_DISPATCH();
661
662      _glapi_set_dispatch(ctx->Exec);
663
664      /* Note that the range of referenced vertices must be mapped already */
665      _vbo_loopback_vertex_list(ctx, node);
666
667      _glapi_set_dispatch(dispatch);
668   }
669
670   /* Decide whether the storage structs are full, or can be used for
671    * the next vertex lists as well.
672    */
673   if (save->vertex_store->used >
674       VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
675
676      /* Unmap old store:
677       */
678      vbo_save_unmap_vertex_store(ctx, save->vertex_store);
679
680      /* Release old reference:
681       */
682      free_vertex_store(ctx, save->vertex_store);
683      save->vertex_store = NULL;
684      /* When we have a new vbo, we will for sure need a new vao */
685      for (gl_vertex_processing_mode vpm = 0; vpm < VP_MODE_MAX; ++vpm)
686         _mesa_reference_vao(ctx, &save->VAO[vpm], NULL);
687
688      /* Allocate and map new store:
689       */
690      save->vertex_store = alloc_vertex_store(ctx);
691      save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
692      save->out_of_memory = save->buffer_ptr == NULL;
693   }
694   else {
695      /* update buffer_ptr for next vertex */
696      save->buffer_ptr = save->vertex_store->buffer_map
697         + save->vertex_store->used;
698   }
699
700   if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
701      save->prim_store->refcount--;
702      assert(save->prim_store->refcount != 0);
703      save->prim_store = alloc_prim_store();
704   }
705
706   /* Reset our structures for the next run of vertices:
707    */
708   reset_counters(ctx);
709}
710
711
712/**
713 * This is called when we fill a vertex buffer before we hit a glEnd().
714 * We
715 * TODO -- If no new vertices have been stored, don't bother saving it.
716 */
717static void
718wrap_buffers(struct gl_context *ctx)
719{
720   struct vbo_save_context *save = &vbo_context(ctx)->save;
721   GLint i = save->prim_count - 1;
722   GLenum mode;
723
724   assert(i < (GLint) save->prim_max);
725   assert(i >= 0);
726
727   /* Close off in-progress primitive.
728    */
729   save->prims[i].count = (save->vert_count - save->prims[i].start);
730   mode = save->prims[i].mode;
731
732   /* store the copied vertices, and allocate a new list.
733    */
734   compile_vertex_list(ctx);
735
736   /* Restart interrupted primitive
737    */
738   save->prims[0].mode = mode;
739   save->prims[0].begin = 0;
740   save->prims[0].end = 0;
741   save->prims[0].pad = 0;
742   save->prims[0].start = 0;
743   save->prims[0].count = 0;
744   save->prims[0].num_instances = 1;
745   save->prims[0].base_instance = 0;
746   save->prims[0].is_indirect = 0;
747   save->prim_count = 1;
748}
749
750
751/**
752 * Called only when buffers are wrapped as the result of filling the
753 * vertex_store struct.
754 */
755static void
756wrap_filled_vertex(struct gl_context *ctx)
757{
758   struct vbo_save_context *save = &vbo_context(ctx)->save;
759   unsigned numComponents;
760
761   /* Emit a glEnd to close off the last vertex list.
762    */
763   wrap_buffers(ctx);
764
765   /* Copy stored stored vertices to start of new list.
766    */
767   assert(save->max_vert - save->vert_count > save->copied.nr);
768
769   numComponents = save->copied.nr * save->vertex_size;
770   memcpy(save->buffer_ptr,
771          save->copied.buffer,
772          numComponents * sizeof(fi_type));
773   save->buffer_ptr += numComponents;
774   save->vert_count += save->copied.nr;
775}
776
777
778static void
779copy_to_current(struct gl_context *ctx)
780{
781   struct vbo_save_context *save = &vbo_context(ctx)->save;
782   GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
783
784   while (enabled) {
785      const int i = u_bit_scan64(&enabled);
786      assert(save->attrsz[i]);
787
788      if (save->attrtype[i] == GL_DOUBLE ||
789          save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
790         memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
791      else
792         COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
793                                     save->attrptr[i], save->attrtype[i]);
794   }
795}
796
797
798static void
799copy_from_current(struct gl_context *ctx)
800{
801   struct vbo_save_context *save = &vbo_context(ctx)->save;
802   GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
803
804   while (enabled) {
805      const int i = u_bit_scan64(&enabled);
806
807      switch (save->attrsz[i]) {
808      case 4:
809         save->attrptr[i][3] = save->current[i][3];
810      case 3:
811         save->attrptr[i][2] = save->current[i][2];
812      case 2:
813         save->attrptr[i][1] = save->current[i][1];
814      case 1:
815         save->attrptr[i][0] = save->current[i][0];
816         break;
817      case 0:
818         unreachable("Unexpected vertex attribute size");
819      }
820   }
821}
822
823
824/**
825 * Called when we increase the size of a vertex attribute.  For example,
826 * if we've seen one or more glTexCoord2f() calls and now we get a
827 * glTexCoord3f() call.
828 * Flush existing data, set new attrib size, replay copied vertices.
829 */
830static void
831upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
832{
833   struct vbo_save_context *save = &vbo_context(ctx)->save;
834   GLuint oldsz;
835   GLuint i;
836   fi_type *tmp;
837
838   /* Store the current run of vertices, and emit a GL_END.  Emit a
839    * BEGIN in the new buffer.
840    */
841   if (save->vert_count)
842      wrap_buffers(ctx);
843   else
844      assert(save->copied.nr == 0);
845
846   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
847    * when the attribute already exists in the vertex and is having
848    * its size increased.
849    */
850   copy_to_current(ctx);
851
852   /* Fix up sizes:
853    */
854   oldsz = save->attrsz[attr];
855   save->attrsz[attr] = newsz;
856   save->enabled |= BITFIELD64_BIT(attr);
857
858   save->vertex_size += newsz - oldsz;
859   save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
860                     save->vertex_size);
861   save->vert_count = 0;
862
863   /* Recalculate all the attrptr[] values:
864    */
865   tmp = save->vertex;
866   for (i = 0; i < VBO_ATTRIB_MAX; i++) {
867      if (save->attrsz[i]) {
868         save->attrptr[i] = tmp;
869         tmp += save->attrsz[i];
870      }
871      else {
872         save->attrptr[i] = NULL;       /* will not be dereferenced. */
873      }
874   }
875
876   /* Copy from current to repopulate the vertex with correct values.
877    */
878   copy_from_current(ctx);
879
880   /* Replay stored vertices to translate them to new format here.
881    *
882    * If there are copied vertices and the new (upgraded) attribute
883    * has not been defined before, this list is somewhat degenerate,
884    * and will need fixup at runtime.
885    */
886   if (save->copied.nr) {
887      const fi_type *data = save->copied.buffer;
888      fi_type *dest = save->buffer_map;
889
890      /* Need to note this and fix up at runtime (or loopback):
891       */
892      if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
893         assert(oldsz == 0);
894         save->dangling_attr_ref = GL_TRUE;
895      }
896
897      for (i = 0; i < save->copied.nr; i++) {
898         GLbitfield64 enabled = save->enabled;
899         while (enabled) {
900            const int j = u_bit_scan64(&enabled);
901            assert(save->attrsz[j]);
902            if (j == attr) {
903               if (oldsz) {
904                  COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
905                                              save->attrtype[j]);
906                  data += oldsz;
907                  dest += newsz;
908               }
909               else {
910                  COPY_SZ_4V(dest, newsz, save->current[attr]);
911                  dest += newsz;
912               }
913            }
914            else {
915               GLint sz = save->attrsz[j];
916               COPY_SZ_4V(dest, sz, data);
917               data += sz;
918               dest += sz;
919            }
920         }
921      }
922
923      save->buffer_ptr = dest;
924      save->vert_count += save->copied.nr;
925   }
926}
927
928
929/**
930 * This is called when the size of a vertex attribute changes.
931 * For example, after seeing one or more glTexCoord2f() calls we
932 * get a glTexCoord4f() or glTexCoord1f() call.
933 */
934static void
935fixup_vertex(struct gl_context *ctx, GLuint attr,
936             GLuint sz, GLenum newType)
937{
938   struct vbo_save_context *save = &vbo_context(ctx)->save;
939
940   if (sz > save->attrsz[attr] ||
941       newType != save->attrtype[attr]) {
942      /* New size is larger.  Need to flush existing vertices and get
943       * an enlarged vertex format.
944       */
945      upgrade_vertex(ctx, attr, sz);
946   }
947   else if (sz < save->active_sz[attr]) {
948      GLuint i;
949      const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
950
951      /* New size is equal or smaller - just need to fill in some
952       * zeros.
953       */
954      for (i = sz; i <= save->attrsz[attr]; i++)
955         save->attrptr[attr][i - 1] = id[i - 1];
956   }
957
958   save->active_sz[attr] = sz;
959}
960
961
962/**
963 * Reset the current size of all vertex attributes to the default
964 * value of 0.  This signals that we haven't yet seen any per-vertex
965 * commands such as glNormal3f() or glTexCoord2f().
966 */
967static void
968reset_vertex(struct gl_context *ctx)
969{
970   struct vbo_save_context *save = &vbo_context(ctx)->save;
971
972   while (save->enabled) {
973      const int i = u_bit_scan64(&save->enabled);
974      assert(save->attrsz[i]);
975      save->attrsz[i] = 0;
976      save->active_sz[i] = 0;
977   }
978
979   save->vertex_size = 0;
980}
981
982
983
984#define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
985
986
987/* Only one size for each attribute may be active at once.  Eg. if
988 * Color3f is installed/active, then Color4f may not be, even if the
989 * vertex actually contains 4 color coordinates.  This is because the
990 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
991 * of the chooser function when switching between Color4f and Color3f.
992 */
993#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)			\
994do {								\
995   struct vbo_save_context *save = &vbo_context(ctx)->save;	\
996   int sz = (sizeof(C) / sizeof(GLfloat));			\
997								\
998   if (save->active_sz[A] != N)					\
999      fixup_vertex(ctx, A, N * sz, T);				\
1000								\
1001   {								\
1002      C *dest = (C *)save->attrptr[A];                          \
1003      if (N>0) dest[0] = V0;					\
1004      if (N>1) dest[1] = V1;					\
1005      if (N>2) dest[2] = V2;					\
1006      if (N>3) dest[3] = V3;					\
1007      save->attrtype[A] = T;					\
1008   }								\
1009								\
1010   if ((A) == 0) {						\
1011      GLuint i;							\
1012								\
1013      for (i = 0; i < save->vertex_size; i++)			\
1014	 save->buffer_ptr[i] = save->vertex[i];			\
1015								\
1016      save->buffer_ptr += save->vertex_size;			\
1017								\
1018      if (++save->vert_count >= save->max_vert)			\
1019	 wrap_filled_vertex(ctx);				\
1020   }								\
1021} while (0)
1022
1023#define TAG(x) _save_##x
1024
1025#include "vbo_attrib_tmp.h"
1026
1027
1028
1029#define MAT( ATTR, N, face, params )			\
1030do {							\
1031   if (face != GL_BACK)					\
1032      MAT_ATTR( ATTR, N, params ); /* front */		\
1033   if (face != GL_FRONT)				\
1034      MAT_ATTR( ATTR + 1, N, params ); /* back */	\
1035} while (0)
1036
1037
1038/**
1039 * Save a glMaterial call found between glBegin/End.
1040 * glMaterial calls outside Begin/End are handled in dlist.c.
1041 */
1042static void GLAPIENTRY
1043_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1044{
1045   GET_CURRENT_CONTEXT(ctx);
1046
1047   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1048      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1049      return;
1050   }
1051
1052   switch (pname) {
1053   case GL_EMISSION:
1054      MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1055      break;
1056   case GL_AMBIENT:
1057      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1058      break;
1059   case GL_DIFFUSE:
1060      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1061      break;
1062   case GL_SPECULAR:
1063      MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1064      break;
1065   case GL_SHININESS:
1066      if (*params < 0 || *params > ctx->Const.MaxShininess) {
1067         _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1068      }
1069      else {
1070         MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1071      }
1072      break;
1073   case GL_COLOR_INDEXES:
1074      MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1075      break;
1076   case GL_AMBIENT_AND_DIFFUSE:
1077      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1078      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1079      break;
1080   default:
1081      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1082      return;
1083   }
1084}
1085
1086
1087/* Cope with EvalCoord/CallList called within a begin/end object:
1088 *     -- Flush current buffer
1089 *     -- Fallback to opcodes for the rest of the begin/end object.
1090 */
1091static void
1092dlist_fallback(struct gl_context *ctx)
1093{
1094   struct vbo_save_context *save = &vbo_context(ctx)->save;
1095
1096   if (save->vert_count || save->prim_count) {
1097      if (save->prim_count > 0) {
1098         /* Close off in-progress primitive. */
1099         GLint i = save->prim_count - 1;
1100         save->prims[i].count = save->vert_count - save->prims[i].start;
1101      }
1102
1103      /* Need to replay this display list with loopback,
1104       * unfortunately, otherwise this primitive won't be handled
1105       * properly:
1106       */
1107      save->dangling_attr_ref = GL_TRUE;
1108
1109      compile_vertex_list(ctx);
1110   }
1111
1112   copy_to_current(ctx);
1113   reset_vertex(ctx);
1114   reset_counters(ctx);
1115   if (save->out_of_memory) {
1116      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1117   }
1118   else {
1119      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1120   }
1121   ctx->Driver.SaveNeedFlush = GL_FALSE;
1122}
1123
1124
1125static void GLAPIENTRY
1126_save_EvalCoord1f(GLfloat u)
1127{
1128   GET_CURRENT_CONTEXT(ctx);
1129   dlist_fallback(ctx);
1130   CALL_EvalCoord1f(ctx->Save, (u));
1131}
1132
1133static void GLAPIENTRY
1134_save_EvalCoord1fv(const GLfloat * v)
1135{
1136   GET_CURRENT_CONTEXT(ctx);
1137   dlist_fallback(ctx);
1138   CALL_EvalCoord1fv(ctx->Save, (v));
1139}
1140
1141static void GLAPIENTRY
1142_save_EvalCoord2f(GLfloat u, GLfloat v)
1143{
1144   GET_CURRENT_CONTEXT(ctx);
1145   dlist_fallback(ctx);
1146   CALL_EvalCoord2f(ctx->Save, (u, v));
1147}
1148
1149static void GLAPIENTRY
1150_save_EvalCoord2fv(const GLfloat * v)
1151{
1152   GET_CURRENT_CONTEXT(ctx);
1153   dlist_fallback(ctx);
1154   CALL_EvalCoord2fv(ctx->Save, (v));
1155}
1156
1157static void GLAPIENTRY
1158_save_EvalPoint1(GLint i)
1159{
1160   GET_CURRENT_CONTEXT(ctx);
1161   dlist_fallback(ctx);
1162   CALL_EvalPoint1(ctx->Save, (i));
1163}
1164
1165static void GLAPIENTRY
1166_save_EvalPoint2(GLint i, GLint j)
1167{
1168   GET_CURRENT_CONTEXT(ctx);
1169   dlist_fallback(ctx);
1170   CALL_EvalPoint2(ctx->Save, (i, j));
1171}
1172
1173static void GLAPIENTRY
1174_save_CallList(GLuint l)
1175{
1176   GET_CURRENT_CONTEXT(ctx);
1177   dlist_fallback(ctx);
1178   CALL_CallList(ctx->Save, (l));
1179}
1180
1181static void GLAPIENTRY
1182_save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1183{
1184   GET_CURRENT_CONTEXT(ctx);
1185   dlist_fallback(ctx);
1186   CALL_CallLists(ctx->Save, (n, type, v));
1187}
1188
1189
1190
1191/**
1192 * Called when a glBegin is getting compiled into a display list.
1193 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1194 */
1195void
1196vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1197                     bool no_current_update)
1198{
1199   struct vbo_save_context *save = &vbo_context(ctx)->save;
1200   const GLuint i = save->prim_count++;
1201
1202   assert(i < save->prim_max);
1203   save->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1204   save->prims[i].begin = 1;
1205   save->prims[i].end = 0;
1206   save->prims[i].pad = 0;
1207   save->prims[i].start = save->vert_count;
1208   save->prims[i].count = 0;
1209   save->prims[i].num_instances = 1;
1210   save->prims[i].base_instance = 0;
1211   save->prims[i].is_indirect = 0;
1212
1213   save->no_current_update = no_current_update;
1214
1215   if (save->out_of_memory) {
1216      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1217   }
1218   else {
1219      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1220   }
1221
1222   /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1223   ctx->Driver.SaveNeedFlush = GL_TRUE;
1224}
1225
1226
1227static void GLAPIENTRY
1228_save_End(void)
1229{
1230   GET_CURRENT_CONTEXT(ctx);
1231   struct vbo_save_context *save = &vbo_context(ctx)->save;
1232   const GLint i = save->prim_count - 1;
1233
1234   ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1235   save->prims[i].end = 1;
1236   save->prims[i].count = (save->vert_count - save->prims[i].start);
1237
1238   if (i == (GLint) save->prim_max - 1) {
1239      compile_vertex_list(ctx);
1240      assert(save->copied.nr == 0);
1241   }
1242
1243   /* Swap out this vertex format while outside begin/end.  Any color,
1244    * etc. received between here and the next begin will be compiled
1245    * as opcodes.
1246    */
1247   if (save->out_of_memory) {
1248      _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1249   }
1250   else {
1251      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1252   }
1253}
1254
1255
1256static void GLAPIENTRY
1257_save_Begin(GLenum mode)
1258{
1259   GET_CURRENT_CONTEXT(ctx);
1260   (void) mode;
1261   _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1262}
1263
1264
1265static void GLAPIENTRY
1266_save_PrimitiveRestartNV(void)
1267{
1268   GET_CURRENT_CONTEXT(ctx);
1269   struct vbo_save_context *save = &vbo_context(ctx)->save;
1270
1271   if (save->prim_count == 0) {
1272      /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1273       * is an error.
1274       */
1275      _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1276                          "glPrimitiveRestartNV called outside glBegin/End");
1277   } else {
1278      /* get current primitive mode */
1279      GLenum curPrim = save->prims[save->prim_count - 1].mode;
1280      bool no_current_update = save->no_current_update;
1281
1282      /* restart primitive */
1283      CALL_End(GET_DISPATCH(), ());
1284      vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1285   }
1286}
1287
1288
1289/* Unlike the functions above, these are to be hooked into the vtxfmt
1290 * maintained in ctx->ListState, active when the list is known or
1291 * suspected to be outside any begin/end primitive.
1292 * Note: OBE = Outside Begin/End
1293 */
1294static void GLAPIENTRY
1295_save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1296{
1297   GET_CURRENT_CONTEXT(ctx);
1298   vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1299   CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
1300   CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
1301   CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
1302   CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
1303   CALL_End(GET_DISPATCH(), ());
1304}
1305
1306
1307static void GLAPIENTRY
1308_save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1309{
1310   GET_CURRENT_CONTEXT(ctx);
1311   struct vbo_save_context *save = &vbo_context(ctx)->save;
1312   GLint i;
1313
1314   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1315      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1316      return;
1317   }
1318   if (count < 0) {
1319      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1320      return;
1321   }
1322
1323   if (save->out_of_memory)
1324      return;
1325
1326   /* Make sure to process any VBO binding changes */
1327   _mesa_update_state(ctx);
1328
1329   _ae_map_vbos(ctx);
1330
1331   vbo_save_NotifyBegin(ctx, mode, true);
1332
1333   for (i = 0; i < count; i++)
1334      CALL_ArrayElement(GET_DISPATCH(), (start + i));
1335   CALL_End(GET_DISPATCH(), ());
1336
1337   _ae_unmap_vbos(ctx);
1338}
1339
1340
1341static void GLAPIENTRY
1342_save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1343                          const GLsizei *count, GLsizei primcount)
1344{
1345   GET_CURRENT_CONTEXT(ctx);
1346   GLint i;
1347
1348   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1349      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1350      return;
1351   }
1352
1353   if (primcount < 0) {
1354      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1355                          "glMultiDrawArrays(primcount<0)");
1356      return;
1357   }
1358
1359   for (i = 0; i < primcount; i++) {
1360      if (count[i] < 0) {
1361         _mesa_compile_error(ctx, GL_INVALID_VALUE,
1362                             "glMultiDrawArrays(count[i]<0)");
1363         return;
1364      }
1365   }
1366
1367   for (i = 0; i < primcount; i++) {
1368      if (count[i] > 0) {
1369         _save_OBE_DrawArrays(mode, first[i], count[i]);
1370      }
1371   }
1372}
1373
1374
1375/* Could do better by copying the arrays and element list intact and
1376 * then emitting an indexed prim at runtime.
1377 */
1378static void GLAPIENTRY
1379_save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1380                                 const GLvoid * indices, GLint basevertex)
1381{
1382   GET_CURRENT_CONTEXT(ctx);
1383   struct vbo_save_context *save = &vbo_context(ctx)->save;
1384   struct gl_buffer_object *indexbuf = ctx->Array.VAO->IndexBufferObj;
1385   GLint i;
1386
1387   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1388      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1389      return;
1390   }
1391   if (count < 0) {
1392      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1393      return;
1394   }
1395   if (type != GL_UNSIGNED_BYTE &&
1396       type != GL_UNSIGNED_SHORT &&
1397       type != GL_UNSIGNED_INT) {
1398      _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1399      return;
1400   }
1401
1402   if (save->out_of_memory)
1403      return;
1404
1405   /* Make sure to process any VBO binding changes */
1406   _mesa_update_state(ctx);
1407
1408   _ae_map_vbos(ctx);
1409
1410   if (_mesa_is_bufferobj(indexbuf))
1411      indices =
1412         ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1413
1414   vbo_save_NotifyBegin(ctx, mode, true);
1415
1416   switch (type) {
1417   case GL_UNSIGNED_BYTE:
1418      for (i = 0; i < count; i++)
1419         CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLubyte *) indices)[i]));
1420      break;
1421   case GL_UNSIGNED_SHORT:
1422      for (i = 0; i < count; i++)
1423         CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLushort *) indices)[i]));
1424      break;
1425   case GL_UNSIGNED_INT:
1426      for (i = 0; i < count; i++)
1427         CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLuint *) indices)[i]));
1428      break;
1429   default:
1430      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1431      break;
1432   }
1433
1434   CALL_End(GET_DISPATCH(), ());
1435
1436   _ae_unmap_vbos(ctx);
1437}
1438
1439static void GLAPIENTRY
1440_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1441                       const GLvoid * indices)
1442{
1443   _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1444}
1445
1446
1447static void GLAPIENTRY
1448_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1449                            GLsizei count, GLenum type,
1450                            const GLvoid * indices)
1451{
1452   GET_CURRENT_CONTEXT(ctx);
1453   struct vbo_save_context *save = &vbo_context(ctx)->save;
1454
1455   if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1456      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1457      return;
1458   }
1459   if (count < 0) {
1460      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1461                          "glDrawRangeElements(count<0)");
1462      return;
1463   }
1464   if (type != GL_UNSIGNED_BYTE &&
1465       type != GL_UNSIGNED_SHORT &&
1466       type != GL_UNSIGNED_INT) {
1467      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1468      return;
1469   }
1470   if (end < start) {
1471      _mesa_compile_error(ctx, GL_INVALID_VALUE,
1472                          "glDrawRangeElements(end < start)");
1473      return;
1474   }
1475
1476   if (save->out_of_memory)
1477      return;
1478
1479   _save_OBE_DrawElements(mode, count, type, indices);
1480}
1481
1482
1483static void GLAPIENTRY
1484_save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1485                            const GLvoid * const *indices, GLsizei primcount)
1486{
1487   GLsizei i;
1488
1489   for (i = 0; i < primcount; i++) {
1490      if (count[i] > 0) {
1491	 CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
1492      }
1493   }
1494}
1495
1496
1497static void GLAPIENTRY
1498_save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1499                                      GLenum type,
1500                                      const GLvoid * const *indices,
1501                                      GLsizei primcount,
1502                                      const GLint *basevertex)
1503{
1504   GLsizei i;
1505
1506   for (i = 0; i < primcount; i++) {
1507      if (count[i] > 0) {
1508	 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
1509						      indices[i],
1510						      basevertex[i]));
1511      }
1512   }
1513}
1514
1515
1516static void
1517vtxfmt_init(struct gl_context *ctx)
1518{
1519   struct vbo_save_context *save = &vbo_context(ctx)->save;
1520   GLvertexformat *vfmt = &save->vtxfmt;
1521
1522   vfmt->ArrayElement = _ae_ArrayElement;
1523
1524   vfmt->Color3f = _save_Color3f;
1525   vfmt->Color3fv = _save_Color3fv;
1526   vfmt->Color4f = _save_Color4f;
1527   vfmt->Color4fv = _save_Color4fv;
1528   vfmt->EdgeFlag = _save_EdgeFlag;
1529   vfmt->End = _save_End;
1530   vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1531   vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1532   vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1533   vfmt->Indexf = _save_Indexf;
1534   vfmt->Indexfv = _save_Indexfv;
1535   vfmt->Materialfv = _save_Materialfv;
1536   vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1537   vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1538   vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1539   vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1540   vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1541   vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1542   vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1543   vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1544   vfmt->Normal3f = _save_Normal3f;
1545   vfmt->Normal3fv = _save_Normal3fv;
1546   vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1547   vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1548   vfmt->TexCoord1f = _save_TexCoord1f;
1549   vfmt->TexCoord1fv = _save_TexCoord1fv;
1550   vfmt->TexCoord2f = _save_TexCoord2f;
1551   vfmt->TexCoord2fv = _save_TexCoord2fv;
1552   vfmt->TexCoord3f = _save_TexCoord3f;
1553   vfmt->TexCoord3fv = _save_TexCoord3fv;
1554   vfmt->TexCoord4f = _save_TexCoord4f;
1555   vfmt->TexCoord4fv = _save_TexCoord4fv;
1556   vfmt->Vertex2f = _save_Vertex2f;
1557   vfmt->Vertex2fv = _save_Vertex2fv;
1558   vfmt->Vertex3f = _save_Vertex3f;
1559   vfmt->Vertex3fv = _save_Vertex3fv;
1560   vfmt->Vertex4f = _save_Vertex4f;
1561   vfmt->Vertex4fv = _save_Vertex4fv;
1562   vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1563   vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1564   vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1565   vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1566   vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1567   vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1568   vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1569   vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1570
1571   vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1572   vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1573   vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1574   vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1575   vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1576   vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1577   vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1578   vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1579
1580   /* integer-valued */
1581   vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1582   vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1583   vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1584   vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1585   vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1586   vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1587   vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1588
1589   /* unsigned integer-valued */
1590   vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1591   vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1592   vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1593   vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1594   vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1595   vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1596   vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1597
1598   vfmt->VertexP2ui = _save_VertexP2ui;
1599   vfmt->VertexP3ui = _save_VertexP3ui;
1600   vfmt->VertexP4ui = _save_VertexP4ui;
1601   vfmt->VertexP2uiv = _save_VertexP2uiv;
1602   vfmt->VertexP3uiv = _save_VertexP3uiv;
1603   vfmt->VertexP4uiv = _save_VertexP4uiv;
1604
1605   vfmt->TexCoordP1ui = _save_TexCoordP1ui;
1606   vfmt->TexCoordP2ui = _save_TexCoordP2ui;
1607   vfmt->TexCoordP3ui = _save_TexCoordP3ui;
1608   vfmt->TexCoordP4ui = _save_TexCoordP4ui;
1609   vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
1610   vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
1611   vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
1612   vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
1613
1614   vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
1615   vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
1616   vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
1617   vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
1618   vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
1619   vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
1620   vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
1621   vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
1622
1623   vfmt->NormalP3ui = _save_NormalP3ui;
1624   vfmt->NormalP3uiv = _save_NormalP3uiv;
1625
1626   vfmt->ColorP3ui = _save_ColorP3ui;
1627   vfmt->ColorP4ui = _save_ColorP4ui;
1628   vfmt->ColorP3uiv = _save_ColorP3uiv;
1629   vfmt->ColorP4uiv = _save_ColorP4uiv;
1630
1631   vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
1632   vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
1633
1634   vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
1635   vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
1636   vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
1637   vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
1638
1639   vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
1640   vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
1641   vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
1642   vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
1643
1644   vfmt->VertexAttribL1d = _save_VertexAttribL1d;
1645   vfmt->VertexAttribL2d = _save_VertexAttribL2d;
1646   vfmt->VertexAttribL3d = _save_VertexAttribL3d;
1647   vfmt->VertexAttribL4d = _save_VertexAttribL4d;
1648
1649   vfmt->VertexAttribL1dv = _save_VertexAttribL1dv;
1650   vfmt->VertexAttribL2dv = _save_VertexAttribL2dv;
1651   vfmt->VertexAttribL3dv = _save_VertexAttribL3dv;
1652   vfmt->VertexAttribL4dv = _save_VertexAttribL4dv;
1653
1654   vfmt->VertexAttribL1ui64ARB = _save_VertexAttribL1ui64ARB;
1655   vfmt->VertexAttribL1ui64vARB = _save_VertexAttribL1ui64vARB;
1656
1657   /* This will all require us to fallback to saving the list as opcodes:
1658    */
1659   vfmt->CallList = _save_CallList;
1660   vfmt->CallLists = _save_CallLists;
1661
1662   vfmt->EvalCoord1f = _save_EvalCoord1f;
1663   vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1664   vfmt->EvalCoord2f = _save_EvalCoord2f;
1665   vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1666   vfmt->EvalPoint1 = _save_EvalPoint1;
1667   vfmt->EvalPoint2 = _save_EvalPoint2;
1668
1669   /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1670    * only used when we're inside a glBegin/End pair.
1671    */
1672   vfmt->Begin = _save_Begin;
1673}
1674
1675
1676/**
1677 * Initialize the dispatch table with the VBO functions for display
1678 * list compilation.
1679 */
1680void
1681vbo_initialize_save_dispatch(const struct gl_context *ctx,
1682                             struct _glapi_table *exec)
1683{
1684   SET_DrawArrays(exec, _save_OBE_DrawArrays);
1685   SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1686   SET_DrawElements(exec, _save_OBE_DrawElements);
1687   SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1688   SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1689   SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1690   SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1691   SET_Rectf(exec, _save_OBE_Rectf);
1692   /* Note: other glDraw functins aren't compiled into display lists */
1693}
1694
1695
1696
1697void
1698vbo_save_SaveFlushVertices(struct gl_context *ctx)
1699{
1700   struct vbo_save_context *save = &vbo_context(ctx)->save;
1701
1702   /* Noop when we are actually active:
1703    */
1704   if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1705      return;
1706
1707   if (save->vert_count || save->prim_count)
1708      compile_vertex_list(ctx);
1709
1710   copy_to_current(ctx);
1711   reset_vertex(ctx);
1712   reset_counters(ctx);
1713   ctx->Driver.SaveNeedFlush = GL_FALSE;
1714}
1715
1716
1717/**
1718 * Called from glNewList when we're starting to compile a display list.
1719 */
1720void
1721vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1722{
1723   struct vbo_save_context *save = &vbo_context(ctx)->save;
1724
1725   (void) list;
1726   (void) mode;
1727
1728   if (!save->prim_store)
1729      save->prim_store = alloc_prim_store();
1730
1731   if (!save->vertex_store)
1732      save->vertex_store = alloc_vertex_store(ctx);
1733
1734   save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1735
1736   reset_vertex(ctx);
1737   reset_counters(ctx);
1738   ctx->Driver.SaveNeedFlush = GL_FALSE;
1739}
1740
1741
1742/**
1743 * Called from glEndList when we're finished compiling a display list.
1744 */
1745void
1746vbo_save_EndList(struct gl_context *ctx)
1747{
1748   struct vbo_save_context *save = &vbo_context(ctx)->save;
1749
1750   /* EndList called inside a (saved) Begin/End pair?
1751    */
1752   if (_mesa_inside_dlist_begin_end(ctx)) {
1753      if (save->prim_count > 0) {
1754         GLint i = save->prim_count - 1;
1755         ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1756         save->prims[i].end = 0;
1757         save->prims[i].count = save->vert_count - save->prims[i].start;
1758      }
1759
1760      /* Make sure this vertex list gets replayed by the "loopback"
1761       * mechanism:
1762       */
1763      save->dangling_attr_ref = GL_TRUE;
1764      vbo_save_SaveFlushVertices(ctx);
1765
1766      /* Swap out this vertex format while outside begin/end.  Any color,
1767       * etc. received between here and the next begin will be compiled
1768       * as opcodes.
1769       */
1770      _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1771   }
1772
1773   vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1774
1775   assert(save->vertex_size == 0);
1776}
1777
1778
1779/**
1780 * Called from the display list code when we're about to execute a
1781 * display list.
1782 */
1783void
1784vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1785{
1786   struct vbo_save_context *save = &vbo_context(ctx)->save;
1787   save->replay_flags |= dlist->Flags;
1788}
1789
1790
1791/**
1792 * Called from the display list code when we're finished executing a
1793 * display list.
1794 */
1795void
1796vbo_save_EndCallList(struct gl_context *ctx)
1797{
1798   struct vbo_save_context *save = &vbo_context(ctx)->save;
1799
1800   if (ctx->ListState.CallDepth == 1)
1801      save->replay_flags = 0;
1802}
1803
1804
1805/**
1806 * Called by display list code when a display list is being deleted.
1807 */
1808static void
1809vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
1810{
1811   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1812
1813   for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm)
1814      _mesa_reference_vao(ctx, &node->VAO[vpm], NULL);
1815
1816   if (--node->prim_store->refcount == 0)
1817      free(node->prim_store);
1818
1819   free(node->current_data);
1820   node->current_data = NULL;
1821}
1822
1823
1824static void
1825vbo_print_vertex_list(struct gl_context *ctx, void *data, FILE *f)
1826{
1827   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1828   GLuint i;
1829   struct gl_buffer_object *buffer = node->VAO[0]->BufferBinding[0].BufferObj;
1830   const GLuint vertex_size = _vbo_save_get_stride(node)/sizeof(GLfloat);
1831   (void) ctx;
1832
1833   fprintf(f, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, "
1834           "buffer %p\n",
1835           node->vertex_count, node->prim_count, vertex_size,
1836           buffer);
1837
1838   for (i = 0; i < node->prim_count; i++) {
1839      struct _mesa_prim *prim = &node->prims[i];
1840      fprintf(f, "   prim %d: %s %d..%d %s %s\n",
1841             i,
1842             _mesa_lookup_prim_by_nr(prim->mode),
1843             prim->start,
1844             prim->start + prim->count,
1845             (prim->begin) ? "BEGIN" : "(wrap)",
1846             (prim->end) ? "END" : "(wrap)");
1847   }
1848}
1849
1850
1851/**
1852 * Called during context creation/init.
1853 */
1854static void
1855current_init(struct gl_context *ctx)
1856{
1857   struct vbo_save_context *save = &vbo_context(ctx)->save;
1858   GLint i;
1859
1860   for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1861      const GLuint j = i - VBO_ATTRIB_POS;
1862      assert(j < VERT_ATTRIB_MAX);
1863      save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1864      save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1865   }
1866
1867   for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1868      const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1869      assert(j < MAT_ATTRIB_MAX);
1870      save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1871      save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
1872   }
1873}
1874
1875
1876/**
1877 * Initialize the display list compiler.  Called during context creation.
1878 */
1879void
1880vbo_save_api_init(struct vbo_save_context *save)
1881{
1882   struct gl_context *ctx = save->ctx;
1883
1884   save->opcode_vertex_list =
1885      _mesa_dlist_alloc_opcode(ctx,
1886                               sizeof(struct vbo_save_vertex_list),
1887                               vbo_save_playback_vertex_list,
1888                               vbo_destroy_vertex_list,
1889                               vbo_print_vertex_list);
1890
1891   vtxfmt_init(ctx);
1892   current_init(ctx);
1893   _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
1894}
1895