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