• 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
_save_copy_vertices(struct gl_context * ctx,const struct vbo_save_vertex_list * node,const fi_type * src_buffer)102 _save_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->prim[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 = 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);
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);  /* 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 = range - vertex_store->used;
261          assert(vertex_store->buffer);
262          return range;
263       }
264       else {
265          vertex_store->buffer = 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 = NULL;
293 }
294 
295 
296 static struct vbo_save_primitive_store *
alloc_prim_store(struct gl_context * ctx)297 alloc_prim_store(struct gl_context *ctx)
298 {
299    struct vbo_save_primitive_store *store =
300       CALLOC_STRUCT(vbo_save_primitive_store);
301    (void) ctx;
302    store->used = 0;
303    store->refcount = 1;
304    return store;
305 }
306 
307 
308 static void
_save_reset_counters(struct gl_context * ctx)309 _save_reset_counters(struct gl_context *ctx)
310 {
311    struct vbo_save_context *save = &vbo_context(ctx)->save;
312 
313    save->prim = save->prim_store->buffer + save->prim_store->used;
314    save->buffer = save->vertex_store->buffer + save->vertex_store->used;
315 
316    assert(save->buffer == save->buffer_ptr);
317 
318    if (save->vertex_size)
319       save->max_vert = (VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
320                         save->vertex_size;
321    else
322       save->max_vert = 0;
323 
324    save->vert_count = 0;
325    save->prim_count = 0;
326    save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
327    save->dangling_attr_ref = GL_FALSE;
328 }
329 
330 /**
331  * For a list of prims, try merging prims that can just be extensions of the
332  * previous prim.
333  */
334 static void
merge_prims(struct _mesa_prim * prim_list,GLuint * prim_count)335 merge_prims(struct _mesa_prim *prim_list,
336             GLuint *prim_count)
337 {
338    GLuint i;
339    struct _mesa_prim *prev_prim = prim_list;
340 
341    for (i = 1; i < *prim_count; i++) {
342       struct _mesa_prim *this_prim = prim_list + i;
343 
344       vbo_try_prim_conversion(this_prim);
345 
346       if (vbo_can_merge_prims(prev_prim, this_prim)) {
347          /* We've found a prim that just extend the previous one.  Tack it
348           * onto the previous one, and let this primitive struct get dropped.
349           */
350          vbo_merge_prims(prev_prim, this_prim);
351          continue;
352       }
353 
354       /* If any previous primitives have been dropped, then we need to copy
355        * this later one into the next available slot.
356        */
357       prev_prim++;
358       if (prev_prim != this_prim)
359          *prev_prim = *this_prim;
360    }
361 
362    *prim_count = prev_prim - prim_list + 1;
363 }
364 
365 
366 /**
367  * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
368  * don't have to worry about handling the _mesa_prim::begin/end flags.
369  * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
370  */
371 static void
convert_line_loop_to_strip(struct vbo_save_context * save,struct vbo_save_vertex_list * node)372 convert_line_loop_to_strip(struct vbo_save_context *save,
373                            struct vbo_save_vertex_list *node)
374 {
375    struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
376 
377    assert(prim->mode == GL_LINE_LOOP);
378 
379    if (prim->end) {
380       /* Copy the 0th vertex to end of the buffer and extend the
381        * vertex count by one to finish the line loop.
382        */
383       const GLuint sz = save->vertex_size;
384       /* 0th vertex: */
385       const fi_type *src = save->buffer + prim->start * sz;
386       /* end of buffer: */
387       fi_type *dst = save->buffer + (prim->start + prim->count) * sz;
388 
389       memcpy(dst, src, sz * sizeof(float));
390 
391       prim->count++;
392       node->count++;
393       save->vert_count++;
394       save->buffer_ptr += sz;
395       save->vertex_store->used += sz;
396    }
397 
398    if (!prim->begin) {
399       /* Drawing the second or later section of a long line loop.
400        * Skip the 0th vertex.
401        */
402       prim->start++;
403       prim->count--;
404    }
405 
406    prim->mode = GL_LINE_STRIP;
407 }
408 
409 
410 /**
411  * Insert the active immediate struct onto the display list currently
412  * being built.
413  */
414 static void
_save_compile_vertex_list(struct gl_context * ctx)415 _save_compile_vertex_list(struct gl_context *ctx)
416 {
417    struct vbo_save_context *save = &vbo_context(ctx)->save;
418    struct vbo_save_vertex_list *node;
419 
420    /* Allocate space for this structure in the display list currently
421     * being compiled.
422     */
423    node = (struct vbo_save_vertex_list *)
424       _mesa_dlist_alloc_aligned(ctx, save->opcode_vertex_list, sizeof(*node));
425 
426    if (!node)
427       return;
428 
429    /* Make sure the pointer is aligned to the size of a pointer */
430    assert((GLintptr) node % sizeof(void *) == 0);
431 
432    /* Duplicate our template, increment refcounts to the storage structs:
433     */
434    node->enabled = save->enabled;
435    memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
436    memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype));
437    node->vertex_size = save->vertex_size;
438    node->buffer_offset =
439       (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
440    node->count = save->vert_count;
441    node->wrap_count = save->copied.nr;
442    node->dangling_attr_ref = save->dangling_attr_ref;
443    node->prim = save->prim;
444    node->prim_count = save->prim_count;
445    node->vertex_store = save->vertex_store;
446    node->prim_store = save->prim_store;
447 
448    node->vertex_store->refcount++;
449    node->prim_store->refcount++;
450 
451    if (node->prim[0].no_current_update) {
452       node->current_size = 0;
453       node->current_data = NULL;
454    }
455    else {
456       node->current_size = node->vertex_size - node->attrsz[0];
457       node->current_data = NULL;
458 
459       if (node->current_size) {
460          /* If the malloc fails, we just pull the data out of the VBO
461           * later instead.
462           */
463          node->current_data = malloc(node->current_size * sizeof(GLfloat));
464          if (node->current_data) {
465             const char *buffer = (const char *) save->vertex_store->buffer;
466             unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
467             unsigned vertex_offset = 0;
468 
469             if (node->count)
470                vertex_offset =
471                   (node->count - 1) * node->vertex_size * sizeof(GLfloat);
472 
473             memcpy(node->current_data,
474                    buffer + node->buffer_offset + vertex_offset + attr_offset,
475                    node->current_size * sizeof(GLfloat));
476          }
477       }
478    }
479 
480    assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0);
481 
482    if (save->dangling_attr_ref)
483       ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
484 
485    save->vertex_store->used += save->vertex_size * node->count;
486    save->prim_store->used += node->prim_count;
487 
488    /* Copy duplicated vertices
489     */
490    save->copied.nr = _save_copy_vertices(ctx, node, save->buffer);
491 
492    if (node->prim[node->prim_count - 1].mode == GL_LINE_LOOP) {
493       convert_line_loop_to_strip(save, node);
494    }
495 
496    merge_prims(node->prim, &node->prim_count);
497 
498    /* Deal with GL_COMPILE_AND_EXECUTE:
499     */
500    if (ctx->ExecuteFlag) {
501       struct _glapi_table *dispatch = GET_DISPATCH();
502 
503       _glapi_set_dispatch(ctx->Exec);
504 
505       vbo_loopback_vertex_list(ctx,
506                                (const GLfloat *) ((const char *) save->
507                                                   vertex_store->buffer +
508                                                   node->buffer_offset),
509                                node->attrsz, node->prim, 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 + save->vertex_store->used;
540    }
541 
542    if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
543       save->prim_store->refcount--;
544       assert(save->prim_store->refcount != 0);
545       save->prim_store = alloc_prim_store(ctx);
546    }
547 
548    /* Reset our structures for the next run of vertices:
549     */
550    _save_reset_counters(ctx);
551 }
552 
553 
554 /**
555  * This is called when we fill a vertex buffer before we hit a glEnd().
556  * We
557  * TODO -- If no new vertices have been stored, don't bother saving it.
558  */
559 static void
_save_wrap_buffers(struct gl_context * ctx)560 _save_wrap_buffers(struct gl_context *ctx)
561 {
562    struct vbo_save_context *save = &vbo_context(ctx)->save;
563    GLint i = save->prim_count - 1;
564    GLenum mode;
565    GLboolean weak;
566    GLboolean no_current_update;
567 
568    assert(i < (GLint) save->prim_max);
569    assert(i >= 0);
570 
571    /* Close off in-progress primitive.
572     */
573    save->prim[i].count = (save->vert_count - save->prim[i].start);
574    mode = save->prim[i].mode;
575    weak = save->prim[i].weak;
576    no_current_update = save->prim[i].no_current_update;
577 
578    /* store the copied vertices, and allocate a new list.
579     */
580    _save_compile_vertex_list(ctx);
581 
582    /* Restart interrupted primitive
583     */
584    save->prim[0].mode = mode;
585    save->prim[0].weak = weak;
586    save->prim[0].no_current_update = no_current_update;
587    save->prim[0].begin = 0;
588    save->prim[0].end = 0;
589    save->prim[0].pad = 0;
590    save->prim[0].start = 0;
591    save->prim[0].count = 0;
592    save->prim[0].num_instances = 1;
593    save->prim[0].base_instance = 0;
594    save->prim[0].is_indirect = 0;
595    save->prim_count = 1;
596 }
597 
598 
599 /**
600  * Called only when buffers are wrapped as the result of filling the
601  * vertex_store struct.
602  */
603 static void
_save_wrap_filled_vertex(struct gl_context * ctx)604 _save_wrap_filled_vertex(struct gl_context *ctx)
605 {
606    struct vbo_save_context *save = &vbo_context(ctx)->save;
607    unsigned numComponents;
608 
609    /* Emit a glEnd to close off the last vertex list.
610     */
611    _save_wrap_buffers(ctx);
612 
613    /* Copy stored stored vertices to start of new list.
614     */
615    assert(save->max_vert - save->vert_count > save->copied.nr);
616 
617    numComponents = save->copied.nr * save->vertex_size;
618    memcpy(save->buffer_ptr,
619           save->copied.buffer,
620           numComponents * sizeof(fi_type));
621    save->buffer_ptr += numComponents;
622    save->vert_count += save->copied.nr;
623 }
624 
625 
626 static void
_save_copy_to_current(struct gl_context * ctx)627 _save_copy_to_current(struct gl_context *ctx)
628 {
629    struct vbo_save_context *save = &vbo_context(ctx)->save;
630    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
631 
632    while (enabled) {
633       const int i = u_bit_scan64(&enabled);
634       assert(save->attrsz[i]);
635 
636       save->currentsz[i][0] = save->attrsz[i];
637       COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
638                                   save->attrptr[i], save->attrtype[i]);
639    }
640 }
641 
642 
643 static void
_save_copy_from_current(struct gl_context * ctx)644 _save_copy_from_current(struct gl_context *ctx)
645 {
646    struct vbo_save_context *save = &vbo_context(ctx)->save;
647    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
648 
649    while (enabled) {
650       const int i = u_bit_scan64(&enabled);
651 
652       switch (save->attrsz[i]) {
653       case 4:
654          save->attrptr[i][3] = save->current[i][3];
655       case 3:
656          save->attrptr[i][2] = save->current[i][2];
657       case 2:
658          save->attrptr[i][1] = save->current[i][1];
659       case 1:
660          save->attrptr[i][0] = save->current[i][0];
661          break;
662       case 0:
663          assert(0);
664          break;
665       }
666    }
667 }
668 
669 
670 /**
671  * Called when we increase the size of a vertex attribute.  For example,
672  * if we've seen one or more glTexCoord2f() calls and now we get a
673  * glTexCoord3f() call.
674  * Flush existing data, set new attrib size, replay copied vertices.
675  */
676 static void
_save_upgrade_vertex(struct gl_context * ctx,GLuint attr,GLuint newsz)677 _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
678 {
679    struct vbo_save_context *save = &vbo_context(ctx)->save;
680    GLuint oldsz;
681    GLuint i;
682    fi_type *tmp;
683 
684    /* Store the current run of vertices, and emit a GL_END.  Emit a
685     * BEGIN in the new buffer.
686     */
687    if (save->vert_count)
688       _save_wrap_buffers(ctx);
689    else
690       assert(save->copied.nr == 0);
691 
692    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
693     * when the attribute already exists in the vertex and is having
694     * its size increased.
695     */
696    _save_copy_to_current(ctx);
697 
698    /* Fix up sizes:
699     */
700    oldsz = save->attrsz[attr];
701    save->attrsz[attr] = newsz;
702    save->enabled |= BITFIELD64_BIT(attr);
703 
704    save->vertex_size += newsz - oldsz;
705    save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
706                      save->vertex_size);
707    save->vert_count = 0;
708 
709    /* Recalculate all the attrptr[] values:
710     */
711    tmp = save->vertex;
712    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
713       if (save->attrsz[i]) {
714          save->attrptr[i] = tmp;
715          tmp += save->attrsz[i];
716       }
717       else {
718          save->attrptr[i] = NULL;       /* will not be dereferenced. */
719       }
720    }
721 
722    /* Copy from current to repopulate the vertex with correct values.
723     */
724    _save_copy_from_current(ctx);
725 
726    /* Replay stored vertices to translate them to new format here.
727     *
728     * If there are copied vertices and the new (upgraded) attribute
729     * has not been defined before, this list is somewhat degenerate,
730     * and will need fixup at runtime.
731     */
732    if (save->copied.nr) {
733       const fi_type *data = save->copied.buffer;
734       fi_type *dest = save->buffer;
735 
736       /* Need to note this and fix up at runtime (or loopback):
737        */
738       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
739          assert(oldsz == 0);
740          save->dangling_attr_ref = GL_TRUE;
741       }
742 
743       for (i = 0; i < save->copied.nr; i++) {
744          GLbitfield64 enabled = save->enabled;
745          while (enabled) {
746             const int j = u_bit_scan64(&enabled);
747             assert(save->attrsz[j]);
748             if (j == attr) {
749                if (oldsz) {
750                   COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
751                                               save->attrtype[j]);
752                   data += oldsz;
753                   dest += newsz;
754                }
755                else {
756                   COPY_SZ_4V(dest, newsz, save->current[attr]);
757                   dest += newsz;
758                }
759             }
760             else {
761                GLint sz = save->attrsz[j];
762                COPY_SZ_4V(dest, sz, data);
763                data += sz;
764                dest += sz;
765             }
766          }
767       }
768 
769       save->buffer_ptr = dest;
770       save->vert_count += save->copied.nr;
771    }
772 }
773 
774 
775 /**
776  * This is called when the size of a vertex attribute changes.
777  * For example, after seeing one or more glTexCoord2f() calls we
778  * get a glTexCoord4f() or glTexCoord1f() call.
779  */
780 static void
save_fixup_vertex(struct gl_context * ctx,GLuint attr,GLuint sz)781 save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
782 {
783    struct vbo_save_context *save = &vbo_context(ctx)->save;
784 
785    if (sz > save->attrsz[attr]) {
786       /* New size is larger.  Need to flush existing vertices and get
787        * an enlarged vertex format.
788        */
789       _save_upgrade_vertex(ctx, attr, sz);
790    }
791    else if (sz < save->active_sz[attr]) {
792       GLuint i;
793       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
794 
795       /* New size is equal or smaller - just need to fill in some
796        * zeros.
797        */
798       for (i = sz; i <= save->attrsz[attr]; i++)
799          save->attrptr[attr][i - 1] = id[i - 1];
800    }
801 
802    save->active_sz[attr] = sz;
803 }
804 
805 
806 /**
807  * Reset the current size of all vertex attributes to the default
808  * value of 0.  This signals that we haven't yet seen any per-vertex
809  * commands such as glNormal3f() or glTexCoord2f().
810  */
811 static void
_save_reset_vertex(struct gl_context * ctx)812 _save_reset_vertex(struct gl_context *ctx)
813 {
814    struct vbo_save_context *save = &vbo_context(ctx)->save;
815 
816    while (save->enabled) {
817       const int i = u_bit_scan64(&save->enabled);
818       assert(save->attrsz[i]);
819       save->attrsz[i] = 0;
820       save->active_sz[i] = 0;
821    }
822 
823    save->vertex_size = 0;
824 }
825 
826 
827 
828 #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
829 
830 
831 /* Only one size for each attribute may be active at once.  Eg. if
832  * Color3f is installed/active, then Color4f may not be, even if the
833  * vertex actually contains 4 color coordinates.  This is because the
834  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
835  * of the chooser function when switching between Color4f and Color3f.
836  */
837 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)			\
838 do {								\
839    struct vbo_save_context *save = &vbo_context(ctx)->save;	\
840 								\
841    if (save->active_sz[A] != N)					\
842       save_fixup_vertex(ctx, A, N);				\
843 								\
844    {								\
845       C *dest = (C *)save->attrptr[A];                          \
846       if (N>0) dest[0] = V0;					\
847       if (N>1) dest[1] = V1;					\
848       if (N>2) dest[2] = V2;					\
849       if (N>3) dest[3] = V3;					\
850       save->attrtype[A] = T;					\
851    }								\
852 								\
853    if ((A) == 0) {						\
854       GLuint i;							\
855 								\
856       for (i = 0; i < save->vertex_size; i++)			\
857 	 save->buffer_ptr[i] = save->vertex[i];			\
858 								\
859       save->buffer_ptr += save->vertex_size;			\
860 								\
861       if (++save->vert_count >= save->max_vert)			\
862 	 _save_wrap_filled_vertex(ctx);				\
863    }								\
864 } while (0)
865 
866 #define TAG(x) _save_##x
867 
868 #include "vbo_attrib_tmp.h"
869 
870 
871 
872 #define MAT( ATTR, N, face, params )			\
873 do {							\
874    if (face != GL_BACK)					\
875       MAT_ATTR( ATTR, N, params ); /* front */		\
876    if (face != GL_FRONT)				\
877       MAT_ATTR( ATTR + 1, N, params ); /* back */	\
878 } while (0)
879 
880 
881 /**
882  * Save a glMaterial call found between glBegin/End.
883  * glMaterial calls outside Begin/End are handled in dlist.c.
884  */
885 static void GLAPIENTRY
_save_Materialfv(GLenum face,GLenum pname,const GLfloat * params)886 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
887 {
888    GET_CURRENT_CONTEXT(ctx);
889 
890    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
891       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
892       return;
893    }
894 
895    switch (pname) {
896    case GL_EMISSION:
897       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
898       break;
899    case GL_AMBIENT:
900       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
901       break;
902    case GL_DIFFUSE:
903       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
904       break;
905    case GL_SPECULAR:
906       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
907       break;
908    case GL_SHININESS:
909       if (*params < 0 || *params > ctx->Const.MaxShininess) {
910          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
911       }
912       else {
913          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
914       }
915       break;
916    case GL_COLOR_INDEXES:
917       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
918       break;
919    case GL_AMBIENT_AND_DIFFUSE:
920       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
921       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
922       break;
923    default:
924       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
925       return;
926    }
927 }
928 
929 
930 /* Cope with EvalCoord/CallList called within a begin/end object:
931  *     -- Flush current buffer
932  *     -- Fallback to opcodes for the rest of the begin/end object.
933  */
934 static void
dlist_fallback(struct gl_context * ctx)935 dlist_fallback(struct gl_context *ctx)
936 {
937    struct vbo_save_context *save = &vbo_context(ctx)->save;
938 
939    if (save->vert_count || save->prim_count) {
940       if (save->prim_count > 0) {
941          /* Close off in-progress primitive. */
942          GLint i = save->prim_count - 1;
943          save->prim[i].count = save->vert_count - save->prim[i].start;
944       }
945 
946       /* Need to replay this display list with loopback,
947        * unfortunately, otherwise this primitive won't be handled
948        * properly:
949        */
950       save->dangling_attr_ref = GL_TRUE;
951 
952       _save_compile_vertex_list(ctx);
953    }
954 
955    _save_copy_to_current(ctx);
956    _save_reset_vertex(ctx);
957    _save_reset_counters(ctx);
958    if (save->out_of_memory) {
959       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
960    }
961    else {
962       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
963    }
964    ctx->Driver.SaveNeedFlush = GL_FALSE;
965 }
966 
967 
968 static void GLAPIENTRY
_save_EvalCoord1f(GLfloat u)969 _save_EvalCoord1f(GLfloat u)
970 {
971    GET_CURRENT_CONTEXT(ctx);
972    dlist_fallback(ctx);
973    CALL_EvalCoord1f(ctx->Save, (u));
974 }
975 
976 static void GLAPIENTRY
_save_EvalCoord1fv(const GLfloat * v)977 _save_EvalCoord1fv(const GLfloat * v)
978 {
979    GET_CURRENT_CONTEXT(ctx);
980    dlist_fallback(ctx);
981    CALL_EvalCoord1fv(ctx->Save, (v));
982 }
983 
984 static void GLAPIENTRY
_save_EvalCoord2f(GLfloat u,GLfloat v)985 _save_EvalCoord2f(GLfloat u, GLfloat v)
986 {
987    GET_CURRENT_CONTEXT(ctx);
988    dlist_fallback(ctx);
989    CALL_EvalCoord2f(ctx->Save, (u, v));
990 }
991 
992 static void GLAPIENTRY
_save_EvalCoord2fv(const GLfloat * v)993 _save_EvalCoord2fv(const GLfloat * v)
994 {
995    GET_CURRENT_CONTEXT(ctx);
996    dlist_fallback(ctx);
997    CALL_EvalCoord2fv(ctx->Save, (v));
998 }
999 
1000 static void GLAPIENTRY
_save_EvalPoint1(GLint i)1001 _save_EvalPoint1(GLint i)
1002 {
1003    GET_CURRENT_CONTEXT(ctx);
1004    dlist_fallback(ctx);
1005    CALL_EvalPoint1(ctx->Save, (i));
1006 }
1007 
1008 static void GLAPIENTRY
_save_EvalPoint2(GLint i,GLint j)1009 _save_EvalPoint2(GLint i, GLint j)
1010 {
1011    GET_CURRENT_CONTEXT(ctx);
1012    dlist_fallback(ctx);
1013    CALL_EvalPoint2(ctx->Save, (i, j));
1014 }
1015 
1016 static void GLAPIENTRY
_save_CallList(GLuint l)1017 _save_CallList(GLuint l)
1018 {
1019    GET_CURRENT_CONTEXT(ctx);
1020    dlist_fallback(ctx);
1021    CALL_CallList(ctx->Save, (l));
1022 }
1023 
1024 static void GLAPIENTRY
_save_CallLists(GLsizei n,GLenum type,const GLvoid * v)1025 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1026 {
1027    GET_CURRENT_CONTEXT(ctx);
1028    dlist_fallback(ctx);
1029    CALL_CallLists(ctx->Save, (n, type, v));
1030 }
1031 
1032 
1033 
1034 /**
1035  * Called when a glBegin is getting compiled into a display list.
1036  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1037  */
1038 GLboolean
vbo_save_NotifyBegin(struct gl_context * ctx,GLenum mode)1039 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
1040 {
1041    struct vbo_save_context *save = &vbo_context(ctx)->save;
1042    const GLuint i = save->prim_count++;
1043 
1044    assert(i < save->prim_max);
1045    save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1046    save->prim[i].begin = 1;
1047    save->prim[i].end = 0;
1048    save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
1049    save->prim[i].no_current_update =
1050       (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
1051    save->prim[i].pad = 0;
1052    save->prim[i].start = save->vert_count;
1053    save->prim[i].count = 0;
1054    save->prim[i].num_instances = 1;
1055    save->prim[i].base_instance = 0;
1056    save->prim[i].is_indirect = 0;
1057 
1058    if (save->out_of_memory) {
1059       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1060    }
1061    else {
1062       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1063    }
1064 
1065    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1066    ctx->Driver.SaveNeedFlush = GL_TRUE;
1067 
1068    /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
1069     * opcode into the display list.
1070     */
1071    return GL_TRUE;
1072 }
1073 
1074 
1075 static void GLAPIENTRY
_save_End(void)1076 _save_End(void)
1077 {
1078    GET_CURRENT_CONTEXT(ctx);
1079    struct vbo_save_context *save = &vbo_context(ctx)->save;
1080    const GLint i = save->prim_count - 1;
1081 
1082    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1083    save->prim[i].end = 1;
1084    save->prim[i].count = (save->vert_count - save->prim[i].start);
1085 
1086    if (i == (GLint) save->prim_max - 1) {
1087       _save_compile_vertex_list(ctx);
1088       assert(save->copied.nr == 0);
1089    }
1090 
1091    /* Swap out this vertex format while outside begin/end.  Any color,
1092     * etc. received between here and the next begin will be compiled
1093     * as opcodes.
1094     */
1095    if (save->out_of_memory) {
1096       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1097    }
1098    else {
1099       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1100    }
1101 }
1102 
1103 
1104 static void GLAPIENTRY
_save_Begin(GLenum mode)1105 _save_Begin(GLenum mode)
1106 {
1107    GET_CURRENT_CONTEXT(ctx);
1108    (void) mode;
1109    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1110 }
1111 
1112 
1113 static void GLAPIENTRY
_save_PrimitiveRestartNV(void)1114 _save_PrimitiveRestartNV(void)
1115 {
1116    GLenum curPrim;
1117    GET_CURRENT_CONTEXT(ctx);
1118 
1119    curPrim = ctx->Driver.CurrentSavePrimitive;
1120 
1121    _save_End();
1122    _save_Begin(curPrim);
1123 }
1124 
1125 
1126 /* Unlike the functions above, these are to be hooked into the vtxfmt
1127  * maintained in ctx->ListState, active when the list is known or
1128  * suspected to be outside any begin/end primitive.
1129  * Note: OBE = Outside Begin/End
1130  */
1131 static void GLAPIENTRY
_save_OBE_Rectf(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)1132 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1133 {
1134    GET_CURRENT_CONTEXT(ctx);
1135    vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
1136    CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
1137    CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
1138    CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
1139    CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
1140    CALL_End(GET_DISPATCH(), ());
1141 }
1142 
1143 
1144 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode,GLint start,GLsizei count)1145 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1146 {
1147    GET_CURRENT_CONTEXT(ctx);
1148    struct vbo_save_context *save = &vbo_context(ctx)->save;
1149    GLint i;
1150 
1151    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1152       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1153       return;
1154    }
1155    if (count < 0) {
1156       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1157       return;
1158    }
1159 
1160    if (save->out_of_memory)
1161       return;
1162 
1163    /* Make sure to process any VBO binding changes */
1164    _mesa_update_state(ctx);
1165 
1166    _ae_map_vbos(ctx);
1167 
1168    vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
1169                               | VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1170 
1171    for (i = 0; i < count; i++)
1172       CALL_ArrayElement(GET_DISPATCH(), (start + i));
1173    CALL_End(GET_DISPATCH(), ());
1174 
1175    _ae_unmap_vbos(ctx);
1176 }
1177 
1178 
1179 /* Could do better by copying the arrays and element list intact and
1180  * then emitting an indexed prim at runtime.
1181  */
1182 static void GLAPIENTRY
_save_OBE_DrawElementsBaseVertex(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)1183 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1184                                  const GLvoid * indices, GLint basevertex)
1185 {
1186    GET_CURRENT_CONTEXT(ctx);
1187    struct vbo_save_context *save = &vbo_context(ctx)->save;
1188    struct gl_buffer_object *indexbuf = ctx->Array.VAO->IndexBufferObj;
1189    GLint i;
1190 
1191    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1192       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1193       return;
1194    }
1195    if (count < 0) {
1196       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1197       return;
1198    }
1199    if (type != GL_UNSIGNED_BYTE &&
1200        type != GL_UNSIGNED_SHORT &&
1201        type != GL_UNSIGNED_INT) {
1202       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1203       return;
1204    }
1205 
1206    if (save->out_of_memory)
1207       return;
1208 
1209    /* Make sure to process any VBO binding changes */
1210    _mesa_update_state(ctx);
1211 
1212    _ae_map_vbos(ctx);
1213 
1214    if (_mesa_is_bufferobj(indexbuf))
1215       indices =
1216          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1217 
1218    vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
1219                               VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1220 
1221    switch (type) {
1222    case GL_UNSIGNED_BYTE:
1223       for (i = 0; i < count; i++)
1224          CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLubyte *) indices)[i]));
1225       break;
1226    case GL_UNSIGNED_SHORT:
1227       for (i = 0; i < count; i++)
1228          CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLushort *) indices)[i]));
1229       break;
1230    case GL_UNSIGNED_INT:
1231       for (i = 0; i < count; i++)
1232          CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLuint *) indices)[i]));
1233       break;
1234    default:
1235       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1236       break;
1237    }
1238 
1239    CALL_End(GET_DISPATCH(), ());
1240 
1241    _ae_unmap_vbos(ctx);
1242 }
1243 
1244 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices)1245 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1246                        const GLvoid * indices)
1247 {
1248    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1249 }
1250 
1251 
1252 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid * indices)1253 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1254                             GLsizei count, GLenum type,
1255                             const GLvoid * indices)
1256 {
1257    GET_CURRENT_CONTEXT(ctx);
1258    struct vbo_save_context *save = &vbo_context(ctx)->save;
1259 
1260    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1261       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1262       return;
1263    }
1264    if (count < 0) {
1265       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1266                           "glDrawRangeElements(count<0)");
1267       return;
1268    }
1269    if (type != GL_UNSIGNED_BYTE &&
1270        type != GL_UNSIGNED_SHORT &&
1271        type != GL_UNSIGNED_INT) {
1272       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1273       return;
1274    }
1275    if (end < start) {
1276       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1277                           "glDrawRangeElements(end < start)");
1278       return;
1279    }
1280 
1281    if (save->out_of_memory)
1282       return;
1283 
1284    _save_OBE_DrawElements(mode, count, type, indices);
1285 }
1286 
1287 
1288 static void GLAPIENTRY
_save_OBE_MultiDrawElements(GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei primcount)1289 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1290                             const GLvoid * const *indices, GLsizei primcount)
1291 {
1292    GLsizei i;
1293 
1294    for (i = 0; i < primcount; i++) {
1295       if (count[i] > 0) {
1296 	 CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
1297       }
1298    }
1299 }
1300 
1301 
1302 static void GLAPIENTRY
_save_OBE_MultiDrawElementsBaseVertex(GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei primcount,const GLint * basevertex)1303 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1304                                       GLenum type,
1305                                       const GLvoid * const *indices,
1306                                       GLsizei primcount,
1307                                       const GLint *basevertex)
1308 {
1309    GLsizei i;
1310 
1311    for (i = 0; i < primcount; i++) {
1312       if (count[i] > 0) {
1313 	 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
1314 						      indices[i],
1315 						      basevertex[i]));
1316       }
1317    }
1318 }
1319 
1320 
1321 static void
_save_vtxfmt_init(struct gl_context * ctx)1322 _save_vtxfmt_init(struct gl_context *ctx)
1323 {
1324    struct vbo_save_context *save = &vbo_context(ctx)->save;
1325    GLvertexformat *vfmt = &save->vtxfmt;
1326 
1327    vfmt->ArrayElement = _ae_ArrayElement;
1328 
1329    vfmt->Color3f = _save_Color3f;
1330    vfmt->Color3fv = _save_Color3fv;
1331    vfmt->Color4f = _save_Color4f;
1332    vfmt->Color4fv = _save_Color4fv;
1333    vfmt->EdgeFlag = _save_EdgeFlag;
1334    vfmt->End = _save_End;
1335    vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1336    vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1337    vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1338    vfmt->Indexf = _save_Indexf;
1339    vfmt->Indexfv = _save_Indexfv;
1340    vfmt->Materialfv = _save_Materialfv;
1341    vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1342    vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1343    vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1344    vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1345    vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1346    vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1347    vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1348    vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1349    vfmt->Normal3f = _save_Normal3f;
1350    vfmt->Normal3fv = _save_Normal3fv;
1351    vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1352    vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1353    vfmt->TexCoord1f = _save_TexCoord1f;
1354    vfmt->TexCoord1fv = _save_TexCoord1fv;
1355    vfmt->TexCoord2f = _save_TexCoord2f;
1356    vfmt->TexCoord2fv = _save_TexCoord2fv;
1357    vfmt->TexCoord3f = _save_TexCoord3f;
1358    vfmt->TexCoord3fv = _save_TexCoord3fv;
1359    vfmt->TexCoord4f = _save_TexCoord4f;
1360    vfmt->TexCoord4fv = _save_TexCoord4fv;
1361    vfmt->Vertex2f = _save_Vertex2f;
1362    vfmt->Vertex2fv = _save_Vertex2fv;
1363    vfmt->Vertex3f = _save_Vertex3f;
1364    vfmt->Vertex3fv = _save_Vertex3fv;
1365    vfmt->Vertex4f = _save_Vertex4f;
1366    vfmt->Vertex4fv = _save_Vertex4fv;
1367    vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1368    vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1369    vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1370    vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1371    vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1372    vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1373    vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1374    vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1375 
1376    vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1377    vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1378    vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1379    vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1380    vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1381    vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1382    vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1383    vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1384 
1385    /* integer-valued */
1386    vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1387    vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1388    vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1389    vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1390    vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1391    vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1392    vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1393 
1394    /* unsigned integer-valued */
1395    vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1396    vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1397    vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1398    vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1399    vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1400    vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1401    vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1402 
1403    vfmt->VertexP2ui = _save_VertexP2ui;
1404    vfmt->VertexP3ui = _save_VertexP3ui;
1405    vfmt->VertexP4ui = _save_VertexP4ui;
1406    vfmt->VertexP2uiv = _save_VertexP2uiv;
1407    vfmt->VertexP3uiv = _save_VertexP3uiv;
1408    vfmt->VertexP4uiv = _save_VertexP4uiv;
1409 
1410    vfmt->TexCoordP1ui = _save_TexCoordP1ui;
1411    vfmt->TexCoordP2ui = _save_TexCoordP2ui;
1412    vfmt->TexCoordP3ui = _save_TexCoordP3ui;
1413    vfmt->TexCoordP4ui = _save_TexCoordP4ui;
1414    vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
1415    vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
1416    vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
1417    vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
1418 
1419    vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
1420    vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
1421    vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
1422    vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
1423    vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
1424    vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
1425    vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
1426    vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
1427 
1428    vfmt->NormalP3ui = _save_NormalP3ui;
1429    vfmt->NormalP3uiv = _save_NormalP3uiv;
1430 
1431    vfmt->ColorP3ui = _save_ColorP3ui;
1432    vfmt->ColorP4ui = _save_ColorP4ui;
1433    vfmt->ColorP3uiv = _save_ColorP3uiv;
1434    vfmt->ColorP4uiv = _save_ColorP4uiv;
1435 
1436    vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
1437    vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
1438 
1439    vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
1440    vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
1441    vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
1442    vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
1443 
1444    vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
1445    vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
1446    vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
1447    vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
1448 
1449    vfmt->VertexAttribL1d = _save_VertexAttribL1d;
1450    vfmt->VertexAttribL2d = _save_VertexAttribL2d;
1451    vfmt->VertexAttribL3d = _save_VertexAttribL3d;
1452    vfmt->VertexAttribL4d = _save_VertexAttribL4d;
1453 
1454    vfmt->VertexAttribL1dv = _save_VertexAttribL1dv;
1455    vfmt->VertexAttribL2dv = _save_VertexAttribL2dv;
1456    vfmt->VertexAttribL3dv = _save_VertexAttribL3dv;
1457    vfmt->VertexAttribL4dv = _save_VertexAttribL4dv;
1458 
1459    /* This will all require us to fallback to saving the list as opcodes:
1460     */
1461    vfmt->CallList = _save_CallList;
1462    vfmt->CallLists = _save_CallLists;
1463 
1464    vfmt->EvalCoord1f = _save_EvalCoord1f;
1465    vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1466    vfmt->EvalCoord2f = _save_EvalCoord2f;
1467    vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1468    vfmt->EvalPoint1 = _save_EvalPoint1;
1469    vfmt->EvalPoint2 = _save_EvalPoint2;
1470 
1471    /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1472     * only used when we're inside a glBegin/End pair.
1473     */
1474    vfmt->Begin = _save_Begin;
1475 }
1476 
1477 
1478 /**
1479  * Initialize the dispatch table with the VBO functions for display
1480  * list compilation.
1481  */
1482 void
vbo_initialize_save_dispatch(const struct gl_context * ctx,struct _glapi_table * exec)1483 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1484                              struct _glapi_table *exec)
1485 {
1486    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1487    SET_DrawElements(exec, _save_OBE_DrawElements);
1488    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1489    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1490    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1491    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1492    SET_Rectf(exec, _save_OBE_Rectf);
1493    /* Note: other glDraw functins aren't compiled into display lists */
1494 }
1495 
1496 
1497 
1498 void
vbo_save_SaveFlushVertices(struct gl_context * ctx)1499 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1500 {
1501    struct vbo_save_context *save = &vbo_context(ctx)->save;
1502 
1503    /* Noop when we are actually active:
1504     */
1505    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1506       return;
1507 
1508    if (save->vert_count || save->prim_count)
1509       _save_compile_vertex_list(ctx);
1510 
1511    _save_copy_to_current(ctx);
1512    _save_reset_vertex(ctx);
1513    _save_reset_counters(ctx);
1514    ctx->Driver.SaveNeedFlush = GL_FALSE;
1515 }
1516 
1517 
1518 void
vbo_save_NewList(struct gl_context * ctx,GLuint list,GLenum mode)1519 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1520 {
1521    struct vbo_save_context *save = &vbo_context(ctx)->save;
1522 
1523    (void) list;
1524    (void) mode;
1525 
1526    if (!save->prim_store)
1527       save->prim_store = alloc_prim_store(ctx);
1528 
1529    if (!save->vertex_store)
1530       save->vertex_store = alloc_vertex_store(ctx);
1531 
1532    save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1533 
1534    _save_reset_vertex(ctx);
1535    _save_reset_counters(ctx);
1536    ctx->Driver.SaveNeedFlush = GL_FALSE;
1537 }
1538 
1539 
1540 void
vbo_save_EndList(struct gl_context * ctx)1541 vbo_save_EndList(struct gl_context *ctx)
1542 {
1543    struct vbo_save_context *save = &vbo_context(ctx)->save;
1544 
1545    /* EndList called inside a (saved) Begin/End pair?
1546     */
1547    if (_mesa_inside_dlist_begin_end(ctx)) {
1548       if (save->prim_count > 0) {
1549          GLint i = save->prim_count - 1;
1550          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1551          save->prim[i].end = 0;
1552          save->prim[i].count = save->vert_count - save->prim[i].start;
1553       }
1554 
1555       /* Make sure this vertex list gets replayed by the "loopback"
1556        * mechanism:
1557        */
1558       save->dangling_attr_ref = GL_TRUE;
1559       vbo_save_SaveFlushVertices(ctx);
1560 
1561       /* Swap out this vertex format while outside begin/end.  Any color,
1562        * etc. received between here and the next begin will be compiled
1563        * as opcodes.
1564        */
1565       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1566    }
1567 
1568    vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1569 
1570    assert(save->vertex_size == 0);
1571 }
1572 
1573 
1574 void
vbo_save_BeginCallList(struct gl_context * ctx,struct gl_display_list * dlist)1575 vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1576 {
1577    struct vbo_save_context *save = &vbo_context(ctx)->save;
1578    save->replay_flags |= dlist->Flags;
1579 }
1580 
1581 
1582 void
vbo_save_EndCallList(struct gl_context * ctx)1583 vbo_save_EndCallList(struct gl_context *ctx)
1584 {
1585    struct vbo_save_context *save = &vbo_context(ctx)->save;
1586 
1587    if (ctx->ListState.CallDepth == 1) {
1588       /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1589        * flag, if it is set:
1590        */
1591       save->replay_flags &= VBO_SAVE_FALLBACK;
1592    }
1593 }
1594 
1595 
1596 static void
vbo_destroy_vertex_list(struct gl_context * ctx,void * data)1597 vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
1598 {
1599    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1600    (void) ctx;
1601 
1602    if (--node->vertex_store->refcount == 0)
1603       free_vertex_store(ctx, node->vertex_store);
1604 
1605    if (--node->prim_store->refcount == 0)
1606       free(node->prim_store);
1607 
1608    free(node->current_data);
1609    node->current_data = NULL;
1610 }
1611 
1612 
1613 static void
vbo_print_vertex_list(struct gl_context * ctx,void * data,FILE * f)1614 vbo_print_vertex_list(struct gl_context *ctx, void *data, FILE *f)
1615 {
1616    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1617    GLuint i;
1618    struct gl_buffer_object *buffer = node->vertex_store ?
1619       node->vertex_store->bufferobj : NULL;
1620    (void) ctx;
1621 
1622    fprintf(f, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, "
1623            "buffer %p\n",
1624            node->count, node->prim_count, node->vertex_size,
1625            buffer);
1626 
1627    for (i = 0; i < node->prim_count; i++) {
1628       struct _mesa_prim *prim = &node->prim[i];
1629       fprintf(f, "   prim %d: %s%s %d..%d %s %s\n",
1630              i,
1631              _mesa_lookup_prim_by_nr(prim->mode),
1632              prim->weak ? " (weak)" : "",
1633              prim->start,
1634              prim->start + prim->count,
1635              (prim->begin) ? "BEGIN" : "(wrap)",
1636              (prim->end) ? "END" : "(wrap)");
1637    }
1638 }
1639 
1640 
1641 /**
1642  * Called during context creation/init.
1643  */
1644 static void
_save_current_init(struct gl_context * ctx)1645 _save_current_init(struct gl_context *ctx)
1646 {
1647    struct vbo_save_context *save = &vbo_context(ctx)->save;
1648    GLint i;
1649 
1650    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1651       const GLuint j = i - VBO_ATTRIB_POS;
1652       assert(j < VERT_ATTRIB_MAX);
1653       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1654       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1655    }
1656 
1657    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1658       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1659       assert(j < MAT_ATTRIB_MAX);
1660       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1661       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
1662    }
1663 }
1664 
1665 
1666 /**
1667  * Initialize the display list compiler.  Called during context creation.
1668  */
1669 void
vbo_save_api_init(struct vbo_save_context * save)1670 vbo_save_api_init(struct vbo_save_context *save)
1671 {
1672    struct gl_context *ctx = save->ctx;
1673    GLuint i;
1674 
1675    save->opcode_vertex_list =
1676       _mesa_dlist_alloc_opcode(ctx,
1677                                sizeof(struct vbo_save_vertex_list),
1678                                vbo_save_playback_vertex_list,
1679                                vbo_destroy_vertex_list,
1680                                vbo_print_vertex_list);
1681 
1682    _save_vtxfmt_init(ctx);
1683    _save_current_init(ctx);
1684    _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
1685 
1686    /* These will actually get set again when binding/drawing */
1687    for (i = 0; i < VBO_ATTRIB_MAX; i++)
1688       save->inputs[i] = &save->arrays[i];
1689 }
1690