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  * The compilation process works as follows. All vertex attributes
69  * except position are copied to vbo_save_context::attrptr (see ATTR_UNION).
70  * 'attrptr' are pointers to vbo_save_context::vertex ordered according to the enabled
71  * attributes (se upgrade_vertex).
72  * When the position attribute is received, all the attributes are then
73  * copied to the vertex_store (see the end of ATTR_UNION).
74  * The vertex_store is simply an extensible float array.
75  * When the vertex list needs to be compiled (see compile_vertex_list),
76  * several transformations are performed:
77  *   - some primitives are merged together (eg: two consecutive GL_TRIANGLES
78  * with 3 vertices can be merged in a single GL_TRIANGLES with 6 vertices).
79  *   - an index buffer is built.
80  *   - identical vertices are detected and only one is kept.
81  * At the end of this transformation, the index buffer and the vertex buffer
82  * are uploaded in vRAM in the same buffer object.
83  * This buffer object is shared between multiple display list to allow
84  * draw calls merging later.
85  *
86  * The layout of this buffer for two display lists is:
87  *    V0A0|V0A1|V1A0|V1A1|P0I0|P0I1|V0A0V0A1V0A2|V1A1V1A1V1A2|...
88  *                                 ` new list starts
89  *        - VxAy: vertex x, attributes y
90  *        - PxIy: draw x, index y
91  *
92  * To allow draw call merging, display list must use the same VAO, including
93  * the same Offset in the buffer object. To achieve this, the start values of
94  * the primitive are shifted and the indices adjusted (see offset_diff and
95  * start_offset in compile_vertex_list).
96  *
97  * Display list using the loopback code (see vbo_save_playback_vertex_list_loopback),
98  * can't be drawn with an index buffer so this transformation is disabled
99  * in this case.
100  */
101 
102 
103 #include "main/glheader.h"
104 #include "main/arrayobj.h"
105 #include "main/bufferobj.h"
106 #include "main/context.h"
107 #include "main/dlist.h"
108 #include "main/enums.h"
109 #include "main/eval.h"
110 #include "main/macros.h"
111 #include "main/draw_validate.h"
112 #include "main/api_arrayelt.h"
113 #include "main/vtxfmt.h"
114 #include "main/dispatch.h"
115 #include "main/state.h"
116 #include "main/varray.h"
117 #include "util/bitscan.h"
118 #include "util/u_memory.h"
119 #include "util/hash_table.h"
120 #include "util/u_prim.h"
121 
122 #include "gallium/include/pipe/p_state.h"
123 
124 #include "vbo_noop.h"
125 #include "vbo_private.h"
126 
127 
128 #ifdef ERROR
129 #undef ERROR
130 #endif
131 
132 /* An interesting VBO number/name to help with debugging */
133 #define VBO_BUF_ID  12345
134 
135 static void GLAPIENTRY
136 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
137 
138 static void GLAPIENTRY
139 _save_EvalCoord1f(GLfloat u);
140 
141 static void GLAPIENTRY
142 _save_EvalCoord2f(GLfloat u, GLfloat v);
143 
144 static void
handle_out_of_memory(struct gl_context * ctx)145 handle_out_of_memory(struct gl_context *ctx)
146 {
147    struct vbo_save_context *save = &vbo_context(ctx)->save;
148    _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt);
149    save->out_of_memory = true;
150 }
151 
152 /*
153  * NOTE: Old 'parity' issue is gone, but copying can still be
154  * wrong-footed on replay.
155  */
156 static GLuint
copy_vertices(struct gl_context * ctx,const struct vbo_save_vertex_list * node,const fi_type * src_buffer)157 copy_vertices(struct gl_context *ctx,
158               const struct vbo_save_vertex_list *node,
159               const fi_type * src_buffer)
160 {
161    struct vbo_save_context *save = &vbo_context(ctx)->save;
162    struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
163    GLuint sz = save->vertex_size;
164 
165    if (prim->end || !prim->count || !sz)
166       return 0;
167 
168    const fi_type *src = src_buffer + prim->start * sz;
169    assert(save->copied.buffer == NULL);
170    save->copied.buffer = malloc(sizeof(fi_type) * sz * prim->count);
171 
172    unsigned r = vbo_copy_vertices(ctx, prim->mode, prim->start, &prim->count,
173                                   prim->begin, sz, true, save->copied.buffer, src);
174    if (!r) {
175       free(save->copied.buffer);
176       save->copied.buffer = NULL;
177    }
178    return r;
179 }
180 
181 
182 static struct vbo_save_primitive_store *
realloc_prim_store(struct vbo_save_primitive_store * store,int prim_count)183 realloc_prim_store(struct vbo_save_primitive_store *store, int prim_count)
184 {
185    if (store == NULL)
186       store = CALLOC_STRUCT(vbo_save_primitive_store);
187 
188    uint32_t old_size = store->size;
189    store->size = prim_count;
190    assert (old_size < store->size);
191    store->prims = realloc(store->prims, store->size * sizeof(struct _mesa_prim));
192    memset(&store->prims[old_size], 0, (store->size - old_size) * sizeof(struct _mesa_prim));
193 
194    return store;
195 }
196 
197 
198 static void
reset_counters(struct gl_context * ctx)199 reset_counters(struct gl_context *ctx)
200 {
201    struct vbo_save_context *save = &vbo_context(ctx)->save;
202 
203    save->vertex_store->used = 0;
204    save->prim_store->used = 0;
205    save->dangling_attr_ref = GL_FALSE;
206 }
207 
208 /**
209  * For a list of prims, try merging prims that can just be extensions of the
210  * previous prim.
211  */
212 static void
merge_prims(struct gl_context * ctx,struct _mesa_prim * prim_list,GLuint * prim_count)213 merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list,
214             GLuint *prim_count)
215 {
216    GLuint i;
217    struct _mesa_prim *prev_prim = prim_list;
218 
219    for (i = 1; i < *prim_count; i++) {
220       struct _mesa_prim *this_prim = prim_list + i;
221 
222       vbo_try_prim_conversion(&this_prim->mode, &this_prim->count);
223 
224       if (vbo_merge_draws(ctx, true,
225                           prev_prim->mode, this_prim->mode,
226                           prev_prim->start, this_prim->start,
227                           &prev_prim->count, this_prim->count,
228                           prev_prim->basevertex, this_prim->basevertex,
229                           &prev_prim->end,
230                           this_prim->begin, this_prim->end)) {
231          /* We've found a prim that just extend the previous one.  Tack it
232           * onto the previous one, and let this primitive struct get dropped.
233           */
234          continue;
235       }
236 
237       /* If any previous primitives have been dropped, then we need to copy
238        * this later one into the next available slot.
239        */
240       prev_prim++;
241       if (prev_prim != this_prim)
242          *prev_prim = *this_prim;
243    }
244 
245    *prim_count = prev_prim - prim_list + 1;
246 }
247 
248 
249 /**
250  * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
251  * don't have to worry about handling the _mesa_prim::begin/end flags.
252  * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
253  */
254 static void
convert_line_loop_to_strip(struct vbo_save_context * save,struct vbo_save_vertex_list * node)255 convert_line_loop_to_strip(struct vbo_save_context *save,
256                            struct vbo_save_vertex_list *node)
257 {
258    struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
259 
260    assert(prim->mode == GL_LINE_LOOP);
261 
262    if (prim->end) {
263       /* Copy the 0th vertex to end of the buffer and extend the
264        * vertex count by one to finish the line loop.
265        */
266       const GLuint sz = save->vertex_size;
267       /* 0th vertex: */
268       const fi_type *src = save->vertex_store->buffer_in_ram + prim->start * sz;
269       /* end of buffer: */
270       fi_type *dst = save->vertex_store->buffer_in_ram + (prim->start + prim->count) * sz;
271 
272       memcpy(dst, src, sz * sizeof(float));
273 
274       prim->count++;
275       node->cold->vertex_count++;
276       save->vertex_store->used += sz;
277    }
278 
279    if (!prim->begin) {
280       /* Drawing the second or later section of a long line loop.
281        * Skip the 0th vertex.
282        */
283       prim->start++;
284       prim->count--;
285    }
286 
287    prim->mode = GL_LINE_STRIP;
288 }
289 
290 
291 /* Compare the present vao if it has the same setup. */
292 static bool
compare_vao(gl_vertex_processing_mode mode,const struct gl_vertex_array_object * vao,const struct gl_buffer_object * bo,GLintptr buffer_offset,GLuint stride,GLbitfield64 vao_enabled,const GLubyte size[VBO_ATTRIB_MAX],const GLenum16 type[VBO_ATTRIB_MAX],const GLuint offset[VBO_ATTRIB_MAX])293 compare_vao(gl_vertex_processing_mode mode,
294             const struct gl_vertex_array_object *vao,
295             const struct gl_buffer_object *bo, GLintptr buffer_offset,
296             GLuint stride, GLbitfield64 vao_enabled,
297             const GLubyte size[VBO_ATTRIB_MAX],
298             const GLenum16 type[VBO_ATTRIB_MAX],
299             const GLuint offset[VBO_ATTRIB_MAX])
300 {
301    if (!vao)
302       return false;
303 
304    /* If the enabled arrays are not the same we are not equal. */
305    if (vao_enabled != vao->Enabled)
306       return false;
307 
308    /* Check the buffer binding at 0 */
309    if (vao->BufferBinding[0].BufferObj != bo)
310       return false;
311    /* BufferBinding[0].Offset != buffer_offset is checked per attribute */
312    if (vao->BufferBinding[0].Stride != stride)
313       return false;
314    assert(vao->BufferBinding[0].InstanceDivisor == 0);
315 
316    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */
317    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
318 
319    /* Now check the enabled arrays */
320    GLbitfield mask = vao_enabled;
321    while (mask) {
322       const int attr = u_bit_scan(&mask);
323       const unsigned char vbo_attr = vao_to_vbo_map[attr];
324       const GLenum16 tp = type[vbo_attr];
325       const GLintptr off = offset[vbo_attr] + buffer_offset;
326       const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr];
327       if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off)
328          return false;
329       if (attrib->Format.Type != tp)
330          return false;
331       if (attrib->Format.Size != size[vbo_attr])
332          return false;
333       assert(attrib->Format.Format == GL_RGBA);
334       assert(attrib->Format.Normalized == GL_FALSE);
335       assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp));
336       assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp));
337       assert(attrib->BufferBindingIndex == 0);
338    }
339 
340    return true;
341 }
342 
343 
344 /* Create or reuse the vao for the vertex processing mode. */
345 static void
update_vao(struct gl_context * ctx,gl_vertex_processing_mode mode,struct gl_vertex_array_object ** vao,struct gl_buffer_object * bo,GLintptr buffer_offset,GLuint stride,GLbitfield64 vbo_enabled,const GLubyte size[VBO_ATTRIB_MAX],const GLenum16 type[VBO_ATTRIB_MAX],const GLuint offset[VBO_ATTRIB_MAX])346 update_vao(struct gl_context *ctx,
347            gl_vertex_processing_mode mode,
348            struct gl_vertex_array_object **vao,
349            struct gl_buffer_object *bo, GLintptr buffer_offset,
350            GLuint stride, GLbitfield64 vbo_enabled,
351            const GLubyte size[VBO_ATTRIB_MAX],
352            const GLenum16 type[VBO_ATTRIB_MAX],
353            const GLuint offset[VBO_ATTRIB_MAX])
354 {
355    /* Compute the bitmasks of vao_enabled arrays */
356    GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
357 
358    /*
359     * Check if we can possibly reuse the exisiting one.
360     * In the long term we should reset them when something changes.
361     */
362    if (compare_vao(mode, *vao, bo, buffer_offset, stride,
363                    vao_enabled, size, type, offset))
364       return;
365 
366    /* The initial refcount is 1 */
367    _mesa_reference_vao(ctx, vao, NULL);
368    *vao = _mesa_new_vao(ctx, ~((GLuint)0));
369 
370    /*
371     * assert(stride <= ctx->Const.MaxVertexAttribStride);
372     * MaxVertexAttribStride is not set for drivers that does not
373     * expose GL 44 or GLES 31.
374     */
375 
376    /* Bind the buffer object at binding point 0 */
377    _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false,
378                             false);
379 
380    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
381     * Note that the position/generic0 aliasing is done in the VAO.
382     */
383    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
384    /* Now set the enable arrays */
385    GLbitfield mask = vao_enabled;
386    while (mask) {
387       const int vao_attr = u_bit_scan(&mask);
388       const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
389       assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
390 
391       _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
392                              size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
393       _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
394    }
395    _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled);
396    assert(vao_enabled == (*vao)->Enabled);
397    assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
398 
399    /* Finalize and freeze the VAO */
400    _mesa_set_vao_immutable(ctx, *vao);
401 }
402 
403 static void wrap_filled_vertex(struct gl_context *ctx);
404 
405 /* Grow the vertex storage to accomodate for vertex_count new vertices */
406 static void
grow_vertex_storage(struct gl_context * ctx,int vertex_count)407 grow_vertex_storage(struct gl_context *ctx, int vertex_count)
408 {
409    struct vbo_save_context *save = &vbo_context(ctx)->save;
410    assert (save->vertex_store);
411 
412    int new_size = (save->vertex_store->used +
413                    vertex_count * save->vertex_size) * sizeof(GLfloat);
414 
415    /* Limit how much memory we allocate. */
416    if (save->prim_store->used > 0 &&
417        vertex_count > 0 &&
418        new_size > VBO_SAVE_BUFFER_SIZE) {
419       wrap_filled_vertex(ctx);
420       new_size = VBO_SAVE_BUFFER_SIZE;
421    }
422 
423    if (new_size > save->vertex_store->buffer_in_ram_size) {
424       save->vertex_store->buffer_in_ram_size = new_size;
425       save->vertex_store->buffer_in_ram = realloc(save->vertex_store->buffer_in_ram,
426                                                   save->vertex_store->buffer_in_ram_size);
427       if (save->vertex_store->buffer_in_ram == NULL)
428          handle_out_of_memory(ctx);
429    }
430 
431 }
432 
433 struct vertex_key {
434    unsigned vertex_size;
435    fi_type *vertex_attributes;
436 };
437 
_hash_vertex_key(const void * key)438 static uint32_t _hash_vertex_key(const void *key)
439 {
440    struct vertex_key *k = (struct vertex_key*)key;
441    unsigned sz = k->vertex_size;
442    assert(sz);
443    return _mesa_hash_data(k->vertex_attributes, sz * sizeof(float));
444 }
445 
_compare_vertex_key(const void * key1,const void * key2)446 static bool _compare_vertex_key(const void *key1, const void *key2)
447 {
448    struct vertex_key *k1 = (struct vertex_key*)key1;
449    struct vertex_key *k2 = (struct vertex_key*)key2;
450    /* All the compared vertices are going to be drawn with the same VAO,
451     * so we can compare the attributes. */
452    assert (k1->vertex_size == k2->vertex_size);
453    return memcmp(k1->vertex_attributes,
454                  k2->vertex_attributes,
455                  k1->vertex_size * sizeof(float)) == 0;
456 }
457 
_free_entry(struct hash_entry * entry)458 static void _free_entry(struct hash_entry *entry)
459 {
460    free((void*)entry->key);
461 }
462 
463 /* Add vertex to the vertex buffer and return its index. If this vertex is a duplicate
464  * of an existing vertex, return the original index instead.
465  */
466 static uint32_t
add_vertex(struct vbo_save_context * save,struct hash_table * hash_to_index,uint32_t index,fi_type * new_buffer,uint32_t * max_index)467 add_vertex(struct vbo_save_context *save, struct hash_table *hash_to_index,
468            uint32_t index, fi_type *new_buffer, uint32_t *max_index)
469 {
470    /* If vertex deduplication is disabled return the original index. */
471    if (!hash_to_index)
472       return index;
473 
474    fi_type *vert = save->vertex_store->buffer_in_ram + save->vertex_size * index;
475 
476    struct vertex_key *key = malloc(sizeof(struct vertex_key));
477    key->vertex_size = save->vertex_size;
478    key->vertex_attributes = vert;
479 
480    struct hash_entry *entry = _mesa_hash_table_search(hash_to_index, key);
481    if (entry) {
482       free(key);
483       /* We found an existing vertex with the same hash, return its index. */
484       return (uintptr_t) entry->data;
485    } else {
486       /* This is a new vertex. Determine a new index and copy its attributes to the vertex
487        * buffer. Note that 'new_buffer' is created at each list compilation so we write vertices
488        * starting at index 0.
489        */
490       uint32_t n = _mesa_hash_table_num_entries(hash_to_index);
491       *max_index = MAX2(n, *max_index);
492 
493       memcpy(&new_buffer[save->vertex_size * n],
494              vert,
495              save->vertex_size * sizeof(fi_type));
496 
497       _mesa_hash_table_insert(hash_to_index, key, (void*)(uintptr_t)(n));
498 
499       /* The index buffer is shared between list compilations, so add the base index to get
500        * the final index.
501        */
502       return n;
503    }
504 }
505 
506 
507 static uint32_t
get_vertex_count(struct vbo_save_context * save)508 get_vertex_count(struct vbo_save_context *save)
509 {
510    if (!save->vertex_size)
511       return 0;
512    return save->vertex_store->used / save->vertex_size;
513 }
514 
515 
516 /**
517  * Insert the active immediate struct onto the display list currently
518  * being built.
519  */
520 static void
compile_vertex_list(struct gl_context * ctx)521 compile_vertex_list(struct gl_context *ctx)
522 {
523    struct vbo_save_context *save = &vbo_context(ctx)->save;
524    struct vbo_save_vertex_list *node;
525 
526    /* Allocate space for this structure in the display list currently
527     * being compiled.
528     */
529    node = (struct vbo_save_vertex_list *)
530       _mesa_dlist_alloc_vertex_list(ctx, !save->dangling_attr_ref && !save->no_current_update);
531 
532    if (!node)
533       return;
534 
535    memset(node, 0, sizeof(struct vbo_save_vertex_list));
536    node->cold = calloc(1, sizeof(*node->cold));
537 
538    /* Make sure the pointer is aligned to the size of a pointer */
539    assert((GLintptr) node % sizeof(void *) == 0);
540 
541    const GLsizei stride = save->vertex_size*sizeof(GLfloat);
542 
543    node->cold->vertex_count = get_vertex_count(save);
544    node->cold->wrap_count = save->copied.nr;
545    node->cold->prims = malloc(sizeof(struct _mesa_prim) * save->prim_store->used);
546    memcpy(node->cold->prims, save->prim_store->prims, sizeof(struct _mesa_prim) * save->prim_store->used);
547    node->cold->ib.obj = NULL;
548    node->cold->prim_count = save->prim_store->used;
549 
550    if (save->no_current_update) {
551       node->cold->current_data = NULL;
552    }
553    else {
554       GLuint current_size = save->vertex_size - save->attrsz[0];
555       node->cold->current_data = NULL;
556 
557       if (current_size) {
558          node->cold->current_data = malloc(current_size * sizeof(GLfloat));
559          if (node->cold->current_data) {
560             const char *buffer = (const char *)save->vertex_store->buffer_in_ram;
561             unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
562             unsigned vertex_offset = 0;
563 
564             if (node->cold->vertex_count)
565                vertex_offset = (node->cold->vertex_count - 1) * stride;
566 
567             memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset,
568                    current_size * sizeof(GLfloat));
569          } else {
570             _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
571             handle_out_of_memory(ctx);
572          }
573       }
574    }
575 
576    assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0);
577 
578    if (save->dangling_attr_ref)
579       ctx->ListState.Current.UseLoopback = true;
580 
581    /* Copy duplicated vertices
582     */
583    save->copied.nr = copy_vertices(ctx, node, save->vertex_store->buffer_in_ram);
584 
585    if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) {
586       convert_line_loop_to_strip(save, node);
587    }
588 
589    merge_prims(ctx, node->cold->prims, &node->cold->prim_count);
590 
591    GLintptr buffer_offset = 0;
592    GLuint start_offset = 0;
593 
594    /* Create an index buffer. */
595    node->cold->min_index = node->cold->max_index = 0;
596    if (node->cold->vertex_count == 0 || node->cold->prim_count == 0)
597       goto end;
598 
599    /* We won't modify node->prims, so use a const alias to avoid unintended
600     * writes to it. */
601    const struct _mesa_prim *original_prims = node->cold->prims;
602 
603    int end = original_prims[node->cold->prim_count - 1].start +
604              original_prims[node->cold->prim_count - 1].count;
605    int total_vert_count = end - original_prims[0].start;
606 
607    node->cold->min_index = node->cold->prims[0].start;
608    node->cold->max_index = end - 1;
609 
610    int max_index_count = total_vert_count * 2;
611    uint32_t* indices = (uint32_t*) malloc(max_index_count * sizeof(uint32_t));
612    struct _mesa_prim *merged_prims = NULL;
613 
614    int idx = 0;
615    struct hash_table *vertex_to_index = NULL;
616    fi_type *temp_vertices_buffer = NULL;
617 
618    /* The loopback replay code doesn't use the index buffer, so we can't
619     * dedup vertices in this case.
620     */
621    if (!ctx->ListState.Current.UseLoopback) {
622       vertex_to_index = _mesa_hash_table_create(NULL, _hash_vertex_key, _compare_vertex_key);
623       temp_vertices_buffer = malloc(save->vertex_store->buffer_in_ram_size);
624    }
625 
626    uint32_t max_index = 0;
627 
628    int last_valid_prim = -1;
629    /* Construct indices array. */
630    for (unsigned i = 0; i < node->cold->prim_count; i++) {
631       assert(original_prims[i].basevertex == 0);
632       GLubyte mode = original_prims[i].mode;
633 
634       int vertex_count = original_prims[i].count;
635       if (!vertex_count) {
636          continue;
637       }
638 
639       /* Increase indices storage if the original estimation was too small. */
640       if (idx + 3 * vertex_count > max_index_count) {
641          max_index_count = max_index_count + 3 * vertex_count;
642          indices = (uint32_t*) realloc(indices, max_index_count * sizeof(uint32_t));
643       }
644 
645       /* Line strips may get converted to lines */
646       if (mode == GL_LINE_STRIP)
647          mode = GL_LINES;
648 
649       /* If 2 consecutive prims use the same mode => merge them. */
650       bool merge_prims = last_valid_prim >= 0 &&
651                          mode == merged_prims[last_valid_prim].mode &&
652                          mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
653                          mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
654                          mode != GL_PATCHES;
655 
656       /* To be able to merge consecutive triangle strips we need to insert
657        * a degenerate triangle.
658        */
659       if (merge_prims &&
660           mode == GL_TRIANGLE_STRIP) {
661          /* Insert a degenerate triangle */
662          assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
663          unsigned tri_count = merged_prims[last_valid_prim].count - 2;
664 
665          indices[idx] = indices[idx - 1];
666          indices[idx + 1] = add_vertex(save, vertex_to_index, original_prims[i].start,
667                                        temp_vertices_buffer, &max_index);
668          idx += 2;
669          merged_prims[last_valid_prim].count += 2;
670 
671          if (tri_count % 2) {
672             /* Add another index to preserve winding order */
673             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start,
674                                         temp_vertices_buffer, &max_index);
675             merged_prims[last_valid_prim].count++;
676          }
677       }
678 
679       int start = idx;
680 
681       /* Convert line strips to lines if it'll allow if the previous
682        * prim mode is GL_LINES (so merge_prims is true) or if the next
683        * primitive mode is GL_LINES or GL_LINE_LOOP.
684        */
685       if (original_prims[i].mode == GL_LINE_STRIP &&
686           (merge_prims ||
687            (i < node->cold->prim_count - 1 &&
688             (original_prims[i + 1].mode == GL_LINE_STRIP ||
689              original_prims[i + 1].mode == GL_LINES)))) {
690          for (unsigned j = 0; j < vertex_count; j++) {
691             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
692                                         temp_vertices_buffer, &max_index);
693             /* Repeat all but the first/last indices. */
694             if (j && j != vertex_count - 1) {
695                indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
696                                            temp_vertices_buffer, &max_index);
697             }
698          }
699       } else {
700          /* We didn't convert to LINES, so restore the original mode */
701          mode = original_prims[i].mode;
702 
703          for (unsigned j = 0; j < vertex_count; j++) {
704             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
705                                         temp_vertices_buffer, &max_index);
706          }
707       }
708 
709       /* Duplicate the last vertex for incomplete primitives */
710       unsigned min_vert = u_prim_vertex_count(mode)->min;
711       for (unsigned j = vertex_count; j < min_vert; j++) {
712          indices[idx++] = add_vertex(save, vertex_to_index,
713                                      original_prims[i].start + vertex_count - 1,
714                                      temp_vertices_buffer, &max_index);
715       }
716 
717       if (merge_prims) {
718          /* Update vertex count. */
719          merged_prims[last_valid_prim].count += idx - start;
720       } else {
721          /* Keep this primitive */
722          last_valid_prim += 1;
723          assert(last_valid_prim <= i);
724          merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
725          merged_prims[last_valid_prim] = original_prims[i];
726          merged_prims[last_valid_prim].start = start;
727          merged_prims[last_valid_prim].count = idx - start;
728       }
729       merged_prims[last_valid_prim].mode = mode;
730    }
731 
732    assert(idx > 0 && idx <= max_index_count);
733 
734    unsigned merged_prim_count = last_valid_prim + 1;
735    node->cold->ib.ptr = NULL;
736    node->cold->ib.count = idx;
737    node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
738 
739    /* How many bytes do we need to store the indices and the vertices */
740    total_vert_count = vertex_to_index ? (max_index + 1) : idx;
741    unsigned total_bytes_needed = idx * sizeof(uint32_t) +
742                                  total_vert_count * save->vertex_size * sizeof(fi_type);
743 
744    const GLintptr old_offset = save->VAO[0] ?
745       save->VAO[0]->BufferBinding[0].Offset + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset : 0;
746    if (old_offset != save->current_bo_bytes_used && stride > 0) {
747       GLintptr offset_diff = save->current_bo_bytes_used - old_offset;
748       while (offset_diff > 0 &&
749              save->current_bo_bytes_used < save->current_bo->Size &&
750              offset_diff % stride != 0) {
751          save->current_bo_bytes_used++;
752          offset_diff = save->current_bo_bytes_used - old_offset;
753       }
754    }
755    buffer_offset = save->current_bo_bytes_used;
756 
757    /* Can we reuse the previous bo or should we allocate a new one? */
758    int available_bytes = save->current_bo ? save->current_bo->Size - save->current_bo_bytes_used : 0;
759    if (total_bytes_needed > available_bytes) {
760       if (save->current_bo)
761          _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
762       save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
763       bool success = ctx->Driver.BufferData(ctx,
764                                             GL_ELEMENT_ARRAY_BUFFER_ARB,
765                                             MAX2(total_bytes_needed, VBO_SAVE_BUFFER_SIZE),
766                                             NULL,
767                                             GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
768                                             save->current_bo);
769       if (!success) {
770          _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
771          _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
772          handle_out_of_memory(ctx);
773       } else {
774          save->current_bo_bytes_used = 0;
775          available_bytes = save->current_bo->Size;
776       }
777       buffer_offset = 0;
778    } else {
779       assert(old_offset <= buffer_offset);
780       const GLintptr offset_diff = buffer_offset - old_offset;
781       if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
782          /* The vertex size is an exact multiple of the buffer offset.
783           * This means that we can use zero-based vertex attribute pointers
784           * and specify the start of the primitive with the _mesa_prim::start
785           * field.  This results in issuing several draw calls with identical
786           * vertex attribute information.  This can result in fewer state
787           * changes in drivers.  In particular, the Gallium CSO module will
788           * filter out redundant vertex buffer changes.
789           */
790          /* We cannot immediately update the primitives as some methods below
791           * still need the uncorrected start vertices
792           */
793          start_offset = offset_diff/stride;
794          assert(old_offset == buffer_offset - offset_diff);
795          buffer_offset = old_offset;
796       }
797 
798       /* Correct the primitive starts, we can only do this here as copy_vertices
799        * and convert_line_loop_to_strip above consume the uncorrected starts.
800        * On the other hand the _vbo_loopback_vertex_list call below needs the
801        * primitives to be corrected already.
802        */
803       for (unsigned i = 0; i < node->cold->prim_count; i++) {
804          node->cold->prims[i].start += start_offset;
805       }
806       /* start_offset shifts vertices (so v[0] becomes v[start_offset]), so we have
807        * to apply this transformation to all indices and max_index.
808        */
809       for (unsigned i = 0; i < idx; i++)
810          indices[i] += start_offset;
811       max_index += start_offset;
812    }
813 
814    _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->current_bo);
815 
816    /* Upload the vertices first (see buffer_offset) */
817    ctx->Driver.BufferSubData(ctx,
818                              save->current_bo_bytes_used,
819                              total_vert_count * save->vertex_size * sizeof(fi_type),
820                              vertex_to_index ? temp_vertices_buffer : save->vertex_store->buffer_in_ram,
821                              node->cold->ib.obj);
822    save->current_bo_bytes_used += total_vert_count * save->vertex_size * sizeof(fi_type);
823 
824   if (vertex_to_index) {
825       _mesa_hash_table_destroy(vertex_to_index, _free_entry);
826       free(temp_vertices_buffer);
827    }
828 
829    /* Since we append the indices to an existing buffer, we need to adjust the start value of each
830     * primitive (not the indices themselves). */
831    if (!ctx->ListState.Current.UseLoopback) {
832       save->current_bo_bytes_used += align(save->current_bo_bytes_used, 4) - save->current_bo_bytes_used;
833       int indices_offset = save->current_bo_bytes_used / 4;
834       for (int i = 0; i < merged_prim_count; i++) {
835          merged_prims[i].start += indices_offset;
836       }
837    }
838 
839    /* Then upload the indices. */
840    if (node->cold->ib.obj) {
841       ctx->Driver.BufferSubData(ctx,
842                                 save->current_bo_bytes_used,
843                                 idx * sizeof(uint32_t),
844                                 indices,
845                                 node->cold->ib.obj);
846       save->current_bo_bytes_used += idx * sizeof(uint32_t);
847    } else {
848       node->cold->vertex_count = 0;
849       node->cold->prim_count = 0;
850    }
851 
852    /* Prepare for DrawGallium */
853    memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
854    /* The other info fields will be updated in vbo_save_playback_vertex_list */
855    node->merged.info.index_size = 4;
856    node->merged.info.instance_count = 1;
857    node->merged.info.index.gl_bo = node->cold->ib.obj;
858    if (merged_prim_count == 1) {
859       node->merged.info.mode = merged_prims[0].mode;
860       node->merged.start_count.start = merged_prims[0].start;
861       node->merged.start_count.count = merged_prims[0].count;
862       node->merged.start_count.index_bias = 0;
863       node->merged.mode = NULL;
864    } else {
865       node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
866       node->merged.start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
867       for (unsigned i = 0; i < merged_prim_count; i++) {
868          node->merged.start_counts[i].start = merged_prims[i].start;
869          node->merged.start_counts[i].count = merged_prims[i].count;
870          node->merged.start_counts[i].index_bias = 0;
871          node->merged.mode[i] = merged_prims[i].mode;
872       }
873    }
874    node->merged.num_draws = merged_prim_count;
875    if (node->merged.num_draws > 1) {
876       bool same_mode = true;
877       for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
878          same_mode = node->merged.mode[i] == node->merged.mode[0];
879       }
880       if (same_mode) {
881          /* All primitives use the same mode, so we can simplify a bit */
882          node->merged.info.mode = node->merged.mode[0];
883          free(node->merged.mode);
884          node->merged.mode = NULL;
885       }
886    }
887 
888    free(indices);
889    free(merged_prims);
890 
891 end:
892 
893    if (!save->current_bo) {
894       save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
895       bool success = ctx->Driver.BufferData(ctx,
896                                             GL_ELEMENT_ARRAY_BUFFER_ARB,
897                                             VBO_SAVE_BUFFER_SIZE,
898                                             NULL,
899                                             GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
900                                             save->current_bo);
901       if (!success)
902          handle_out_of_memory(ctx);
903    }
904 
905    GLuint offsets[VBO_ATTRIB_MAX];
906    for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
907       offsets[i] = offset;
908       offset += save->attrsz[i] * sizeof(GLfloat);
909    }
910    /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
911     * Note that this may reuse the previous one of possible.
912     */
913    for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
914       /* create or reuse the vao */
915       update_vao(ctx, vpm, &save->VAO[vpm],
916                  save->current_bo, buffer_offset, stride,
917                  save->enabled, save->attrsz, save->attrtype, offsets);
918       /* Reference the vao in the dlist */
919       node->VAO[vpm] = NULL;
920       _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
921    }
922 
923    /* Prepare for DrawGalliumVertexState */
924    if (node->merged.num_draws && ctx->Driver.DrawGalliumVertexState) {
925       for (unsigned i = 0; i < VP_MODE_MAX; i++) {
926          uint32_t enabled_attribs = _vbo_get_vao_filter(i) &
927                                     node->VAO[i]->_EnabledWithMapMode;
928 
929          node->merged.gallium.state[i] =
930             ctx->Driver.CreateGalliumVertexState(ctx, node->VAO[i],
931                                                  node->cold->ib.obj,
932                                                  enabled_attribs);
933          node->merged.gallium.private_refcount[i] = 0;
934          node->merged.gallium.enabled_attribs[i] = enabled_attribs;
935       }
936 
937       node->merged.gallium.ctx = ctx;
938       node->merged.gallium.info.mode = node->merged.info.mode;
939       node->merged.gallium.info.take_vertex_state_ownership = false;
940       assert(node->merged.info.index_size == 4);
941    }
942 
943    /* Deal with GL_COMPILE_AND_EXECUTE:
944     */
945    if (ctx->ExecuteFlag) {
946       struct _glapi_table *dispatch = GET_DISPATCH();
947 
948       _glapi_set_dispatch(ctx->Exec);
949 
950       /* _vbo_loopback_vertex_list doesn't use the index buffer, so we have to
951        * use buffer_in_ram (which contains all vertices) instead of current_bo
952        * (which contains deduplicated vertices *when* UseLoopback is false).
953        *
954        * The problem is that the VAO offset is based on current_bo's layout,
955        * so we have to use a temp value.
956        */
957       struct gl_vertex_array_object *vao = node->VAO[VP_MODE_SHADER];
958       GLintptr original = vao->BufferBinding[0].Offset;
959       /* 'start_offset' has been added to all primitives 'start', so undo it here. */
960       vao->BufferBinding[0].Offset = -(GLintptr)(start_offset * stride);
961       _vbo_loopback_vertex_list(ctx, node, save->vertex_store->buffer_in_ram);
962       vao->BufferBinding[0].Offset = original;
963 
964       _glapi_set_dispatch(dispatch);
965    }
966 
967    /* Reset our structures for the next run of vertices:
968     */
969    reset_counters(ctx);
970 }
971 
972 
973 /**
974  * This is called when we fill a vertex buffer before we hit a glEnd().
975  * We
976  * TODO -- If no new vertices have been stored, don't bother saving it.
977  */
978 static void
wrap_buffers(struct gl_context * ctx)979 wrap_buffers(struct gl_context *ctx)
980 {
981    struct vbo_save_context *save = &vbo_context(ctx)->save;
982    GLint i = save->prim_store->used - 1;
983    GLenum mode;
984 
985    assert(i < (GLint) save->prim_store->size);
986    assert(i >= 0);
987 
988    /* Close off in-progress primitive.
989     */
990    save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start);
991    mode = save->prim_store->prims[i].mode;
992 
993    /* store the copied vertices, and allocate a new list.
994     */
995    compile_vertex_list(ctx);
996 
997    /* Restart interrupted primitive
998     */
999    save->prim_store->prims[0].mode = mode;
1000    save->prim_store->prims[0].begin = 0;
1001    save->prim_store->prims[0].end = 0;
1002    save->prim_store->prims[0].start = 0;
1003    save->prim_store->prims[0].count = 0;
1004    save->prim_store->used = 1;
1005 }
1006 
1007 
1008 /**
1009  * Called only when buffers are wrapped as the result of filling the
1010  * vertex_store struct.
1011  */
1012 static void
wrap_filled_vertex(struct gl_context * ctx)1013 wrap_filled_vertex(struct gl_context *ctx)
1014 {
1015    struct vbo_save_context *save = &vbo_context(ctx)->save;
1016    unsigned numComponents;
1017 
1018    /* Emit a glEnd to close off the last vertex list.
1019     */
1020    wrap_buffers(ctx);
1021 
1022    assert(save->vertex_store->used == 0 && save->vertex_store->used == 0);
1023 
1024    /* Copy stored stored vertices to start of new list.
1025     */
1026    numComponents = save->copied.nr * save->vertex_size;
1027 
1028    fi_type *buffer_ptr = save->vertex_store->buffer_in_ram;
1029    if (numComponents) {
1030       assert(save->copied.buffer);
1031       memcpy(buffer_ptr,
1032              save->copied.buffer,
1033              numComponents * sizeof(fi_type));
1034       free(save->copied.buffer);
1035       save->copied.buffer = NULL;
1036    }
1037    save->vertex_store->used = numComponents;
1038 }
1039 
1040 
1041 static void
copy_to_current(struct gl_context * ctx)1042 copy_to_current(struct gl_context *ctx)
1043 {
1044    struct vbo_save_context *save = &vbo_context(ctx)->save;
1045    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1046 
1047    while (enabled) {
1048       const int i = u_bit_scan64(&enabled);
1049       assert(save->attrsz[i]);
1050 
1051       if (save->attrtype[i] == GL_DOUBLE ||
1052           save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
1053          memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
1054       else
1055          COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
1056                                      save->attrptr[i], save->attrtype[i]);
1057    }
1058 }
1059 
1060 
1061 static void
copy_from_current(struct gl_context * ctx)1062 copy_from_current(struct gl_context *ctx)
1063 {
1064    struct vbo_save_context *save = &vbo_context(ctx)->save;
1065    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1066 
1067    while (enabled) {
1068       const int i = u_bit_scan64(&enabled);
1069 
1070       switch (save->attrsz[i]) {
1071       case 4:
1072          save->attrptr[i][3] = save->current[i][3];
1073          FALLTHROUGH;
1074       case 3:
1075          save->attrptr[i][2] = save->current[i][2];
1076          FALLTHROUGH;
1077       case 2:
1078          save->attrptr[i][1] = save->current[i][1];
1079          FALLTHROUGH;
1080       case 1:
1081          save->attrptr[i][0] = save->current[i][0];
1082          break;
1083       case 0:
1084          unreachable("Unexpected vertex attribute size");
1085       }
1086    }
1087 }
1088 
1089 
1090 /**
1091  * Called when we increase the size of a vertex attribute.  For example,
1092  * if we've seen one or more glTexCoord2f() calls and now we get a
1093  * glTexCoord3f() call.
1094  * Flush existing data, set new attrib size, replay copied vertices.
1095  */
1096 static void
upgrade_vertex(struct gl_context * ctx,GLuint attr,GLuint newsz)1097 upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
1098 {
1099    struct vbo_save_context *save = &vbo_context(ctx)->save;
1100    GLuint oldsz;
1101    GLuint i;
1102    fi_type *tmp;
1103 
1104    /* Store the current run of vertices, and emit a GL_END.  Emit a
1105     * BEGIN in the new buffer.
1106     */
1107    if (save->vertex_store->used)
1108       wrap_buffers(ctx);
1109    else
1110       assert(save->copied.nr == 0);
1111 
1112    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
1113     * when the attribute already exists in the vertex and is having
1114     * its size increased.
1115     */
1116    copy_to_current(ctx);
1117 
1118    /* Fix up sizes:
1119     */
1120    oldsz = save->attrsz[attr];
1121    save->attrsz[attr] = newsz;
1122    save->enabled |= BITFIELD64_BIT(attr);
1123 
1124    save->vertex_size += newsz - oldsz;
1125 
1126    /* Recalculate all the attrptr[] values:
1127     */
1128    tmp = save->vertex;
1129    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
1130       if (save->attrsz[i]) {
1131          save->attrptr[i] = tmp;
1132          tmp += save->attrsz[i];
1133       }
1134       else {
1135          save->attrptr[i] = NULL;       /* will not be dereferenced. */
1136       }
1137    }
1138 
1139    /* Copy from current to repopulate the vertex with correct values.
1140     */
1141    copy_from_current(ctx);
1142 
1143    /* Replay stored vertices to translate them to new format here.
1144     *
1145     * If there are copied vertices and the new (upgraded) attribute
1146     * has not been defined before, this list is somewhat degenerate,
1147     * and will need fixup at runtime.
1148     */
1149    if (save->copied.nr) {
1150       assert(save->copied.buffer);
1151       const fi_type *data = save->copied.buffer;
1152       grow_vertex_storage(ctx, save->copied.nr);
1153       fi_type *dest = save->vertex_store->buffer_in_ram;
1154 
1155       /* Need to note this and fix up at runtime (or loopback):
1156        */
1157       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
1158          assert(oldsz == 0);
1159          save->dangling_attr_ref = GL_TRUE;
1160       }
1161 
1162       for (i = 0; i < save->copied.nr; i++) {
1163          GLbitfield64 enabled = save->enabled;
1164          while (enabled) {
1165             const int j = u_bit_scan64(&enabled);
1166             assert(save->attrsz[j]);
1167             if (j == attr) {
1168                int k;
1169                const fi_type *src = oldsz ? data : save->current[attr];
1170                int copy = oldsz ? oldsz : newsz;
1171                for (k = 0; k < copy; k++)
1172                   dest[k] = src[k];
1173                for (; k < newsz; k++) {
1174                   switch (save->attrtype[j]) {
1175                      case GL_FLOAT:
1176                         dest[k] = FLOAT_AS_UNION(k == 3);
1177                         break;
1178                      case GL_INT:
1179                         dest[k] = INT_AS_UNION(k == 3);
1180                         break;
1181                      case GL_UNSIGNED_INT:
1182                         dest[k] = UINT_AS_UNION(k == 3);
1183                         break;
1184                      default:
1185                         dest[k] = FLOAT_AS_UNION(k == 3);
1186                         assert(!"Unexpected type in upgrade_vertex");
1187                         break;
1188                   }
1189                }
1190                dest += newsz;
1191                data += oldsz;
1192             } else {
1193                GLint sz = save->attrsz[j];
1194                for (int k = 0; k < sz; k++)
1195                   dest[k] = data[k];
1196                data += sz;
1197                dest += sz;
1198             }
1199          }
1200       }
1201 
1202       save->vertex_store->used += save->vertex_size * save->copied.nr;
1203       free(save->copied.buffer);
1204       save->copied.buffer = NULL;
1205    }
1206 }
1207 
1208 
1209 /**
1210  * This is called when the size of a vertex attribute changes.
1211  * For example, after seeing one or more glTexCoord2f() calls we
1212  * get a glTexCoord4f() or glTexCoord1f() call.
1213  */
1214 static void
fixup_vertex(struct gl_context * ctx,GLuint attr,GLuint sz,GLenum newType)1215 fixup_vertex(struct gl_context *ctx, GLuint attr,
1216              GLuint sz, GLenum newType)
1217 {
1218    struct vbo_save_context *save = &vbo_context(ctx)->save;
1219 
1220    if (sz > save->attrsz[attr] ||
1221        newType != save->attrtype[attr]) {
1222       /* New size is larger.  Need to flush existing vertices and get
1223        * an enlarged vertex format.
1224        */
1225       upgrade_vertex(ctx, attr, sz);
1226    }
1227    else if (sz < save->active_sz[attr]) {
1228       GLuint i;
1229       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
1230 
1231       /* New size is equal or smaller - just need to fill in some
1232        * zeros.
1233        */
1234       for (i = sz; i <= save->attrsz[attr]; i++)
1235          save->attrptr[attr][i - 1] = id[i - 1];
1236    }
1237 
1238    save->active_sz[attr] = sz;
1239 
1240    grow_vertex_storage(ctx, 1);
1241 }
1242 
1243 
1244 /**
1245  * Reset the current size of all vertex attributes to the default
1246  * value of 0.  This signals that we haven't yet seen any per-vertex
1247  * commands such as glNormal3f() or glTexCoord2f().
1248  */
1249 static void
reset_vertex(struct gl_context * ctx)1250 reset_vertex(struct gl_context *ctx)
1251 {
1252    struct vbo_save_context *save = &vbo_context(ctx)->save;
1253 
1254    while (save->enabled) {
1255       const int i = u_bit_scan64(&save->enabled);
1256       assert(save->attrsz[i]);
1257       save->attrsz[i] = 0;
1258       save->active_sz[i] = 0;
1259    }
1260 
1261    save->vertex_size = 0;
1262 }
1263 
1264 
1265 /**
1266  * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
1267  * It depends on a few things, including whether we're inside or outside
1268  * of glBegin/glEnd.
1269  */
1270 static inline bool
is_vertex_position(const struct gl_context * ctx,GLuint index)1271 is_vertex_position(const struct gl_context *ctx, GLuint index)
1272 {
1273    return (index == 0 &&
1274            _mesa_attr_zero_aliases_vertex(ctx) &&
1275            _mesa_inside_dlist_begin_end(ctx));
1276 }
1277 
1278 
1279 
1280 #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
1281 
1282 
1283 /* Only one size for each attribute may be active at once.  Eg. if
1284  * Color3f is installed/active, then Color4f may not be, even if the
1285  * vertex actually contains 4 color coordinates.  This is because the
1286  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1287  * of the chooser function when switching between Color4f and Color3f.
1288  */
1289 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
1290 do {                                                            \
1291    struct vbo_save_context *save = &vbo_context(ctx)->save;     \
1292    int sz = (sizeof(C) / sizeof(GLfloat));                      \
1293                                                                 \
1294    if (save->active_sz[A] != N)                                 \
1295       fixup_vertex(ctx, A, N * sz, T);                          \
1296                                                                 \
1297    {                                                            \
1298       C *dest = (C *)save->attrptr[A];                          \
1299       if (N>0) dest[0] = V0;                                    \
1300       if (N>1) dest[1] = V1;                                    \
1301       if (N>2) dest[2] = V2;                                    \
1302       if (N>3) dest[3] = V3;                                    \
1303       save->attrtype[A] = T;                                    \
1304    }                                                            \
1305                                                                 \
1306    if ((A) == VBO_ATTRIB_POS) {                                 \
1307       fi_type *buffer_ptr = save->vertex_store->buffer_in_ram + \
1308                             save->vertex_store->used;           \
1309                                                                 \
1310       for (int i = 0; i < save->vertex_size; i++)               \
1311         buffer_ptr[i] = save->vertex[i];                        \
1312                                                                 \
1313       save->vertex_store->used += save->vertex_size;            \
1314       unsigned used_next = (save->vertex_store->used +          \
1315                             save->vertex_size) * sizeof(float); \
1316       if (used_next > save->vertex_store->buffer_in_ram_size) { \
1317          grow_vertex_storage(ctx, get_vertex_count(save));      \
1318          assert(used_next <=                                    \
1319                 save->vertex_store->buffer_in_ram_size);        \
1320       }                                                         \
1321    }                                                            \
1322 } while (0)
1323 
1324 #define TAG(x) _save_##x
1325 
1326 #include "vbo_attrib_tmp.h"
1327 
1328 
1329 #define MAT( ATTR, N, face, params )                            \
1330 do {                                                            \
1331    if (face != GL_BACK)                                         \
1332       MAT_ATTR( ATTR, N, params ); /* front */                  \
1333    if (face != GL_FRONT)                                        \
1334       MAT_ATTR( ATTR + 1, N, params ); /* back */               \
1335 } while (0)
1336 
1337 
1338 /**
1339  * Save a glMaterial call found between glBegin/End.
1340  * glMaterial calls outside Begin/End are handled in dlist.c.
1341  */
1342 static void GLAPIENTRY
_save_Materialfv(GLenum face,GLenum pname,const GLfloat * params)1343 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1344 {
1345    GET_CURRENT_CONTEXT(ctx);
1346 
1347    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1348       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1349       return;
1350    }
1351 
1352    switch (pname) {
1353    case GL_EMISSION:
1354       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1355       break;
1356    case GL_AMBIENT:
1357       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1358       break;
1359    case GL_DIFFUSE:
1360       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1361       break;
1362    case GL_SPECULAR:
1363       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1364       break;
1365    case GL_SHININESS:
1366       if (*params < 0 || *params > ctx->Const.MaxShininess) {
1367          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1368       }
1369       else {
1370          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1371       }
1372       break;
1373    case GL_COLOR_INDEXES:
1374       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1375       break;
1376    case GL_AMBIENT_AND_DIFFUSE:
1377       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1378       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1379       break;
1380    default:
1381       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1382       return;
1383    }
1384 }
1385 
1386 
1387 /* Cope with EvalCoord/CallList called within a begin/end object:
1388  *     -- Flush current buffer
1389  *     -- Fallback to opcodes for the rest of the begin/end object.
1390  */
1391 static void
dlist_fallback(struct gl_context * ctx)1392 dlist_fallback(struct gl_context *ctx)
1393 {
1394    struct vbo_save_context *save = &vbo_context(ctx)->save;
1395 
1396    if (save->vertex_store->used || save->prim_store->used) {
1397       if (save->prim_store->used > 0 && save->vertex_store->used > 0) {
1398          assert(save->vertex_size);
1399          /* Close off in-progress primitive. */
1400          GLint i = save->prim_store->used - 1;
1401          save->prim_store->prims[i].count =
1402             get_vertex_count(save) -
1403             save->prim_store->prims[i].start;
1404       }
1405 
1406       /* Need to replay this display list with loopback,
1407        * unfortunately, otherwise this primitive won't be handled
1408        * properly:
1409        */
1410       save->dangling_attr_ref = GL_TRUE;
1411 
1412       compile_vertex_list(ctx);
1413    }
1414 
1415    copy_to_current(ctx);
1416    reset_vertex(ctx);
1417    if (save->out_of_memory) {
1418       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1419    }
1420    else {
1421       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1422    }
1423    ctx->Driver.SaveNeedFlush = GL_FALSE;
1424 }
1425 
1426 
1427 static void GLAPIENTRY
_save_EvalCoord1f(GLfloat u)1428 _save_EvalCoord1f(GLfloat u)
1429 {
1430    GET_CURRENT_CONTEXT(ctx);
1431    dlist_fallback(ctx);
1432    CALL_EvalCoord1f(ctx->Save, (u));
1433 }
1434 
1435 static void GLAPIENTRY
_save_EvalCoord1fv(const GLfloat * v)1436 _save_EvalCoord1fv(const GLfloat * v)
1437 {
1438    GET_CURRENT_CONTEXT(ctx);
1439    dlist_fallback(ctx);
1440    CALL_EvalCoord1fv(ctx->Save, (v));
1441 }
1442 
1443 static void GLAPIENTRY
_save_EvalCoord2f(GLfloat u,GLfloat v)1444 _save_EvalCoord2f(GLfloat u, GLfloat v)
1445 {
1446    GET_CURRENT_CONTEXT(ctx);
1447    dlist_fallback(ctx);
1448    CALL_EvalCoord2f(ctx->Save, (u, v));
1449 }
1450 
1451 static void GLAPIENTRY
_save_EvalCoord2fv(const GLfloat * v)1452 _save_EvalCoord2fv(const GLfloat * v)
1453 {
1454    GET_CURRENT_CONTEXT(ctx);
1455    dlist_fallback(ctx);
1456    CALL_EvalCoord2fv(ctx->Save, (v));
1457 }
1458 
1459 static void GLAPIENTRY
_save_EvalPoint1(GLint i)1460 _save_EvalPoint1(GLint i)
1461 {
1462    GET_CURRENT_CONTEXT(ctx);
1463    dlist_fallback(ctx);
1464    CALL_EvalPoint1(ctx->Save, (i));
1465 }
1466 
1467 static void GLAPIENTRY
_save_EvalPoint2(GLint i,GLint j)1468 _save_EvalPoint2(GLint i, GLint j)
1469 {
1470    GET_CURRENT_CONTEXT(ctx);
1471    dlist_fallback(ctx);
1472    CALL_EvalPoint2(ctx->Save, (i, j));
1473 }
1474 
1475 static void GLAPIENTRY
_save_CallList(GLuint l)1476 _save_CallList(GLuint l)
1477 {
1478    GET_CURRENT_CONTEXT(ctx);
1479    dlist_fallback(ctx);
1480    CALL_CallList(ctx->Save, (l));
1481 }
1482 
1483 static void GLAPIENTRY
_save_CallLists(GLsizei n,GLenum type,const GLvoid * v)1484 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1485 {
1486    GET_CURRENT_CONTEXT(ctx);
1487    dlist_fallback(ctx);
1488    CALL_CallLists(ctx->Save, (n, type, v));
1489 }
1490 
1491 
1492 
1493 /**
1494  * Called when a glBegin is getting compiled into a display list.
1495  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1496  */
1497 void
vbo_save_NotifyBegin(struct gl_context * ctx,GLenum mode,bool no_current_update)1498 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1499                      bool no_current_update)
1500 {
1501    struct vbo_save_context *save = &vbo_context(ctx)->save;
1502    const GLuint i = save->prim_store->used++;
1503 
1504    ctx->Driver.CurrentSavePrimitive = mode;
1505 
1506    if (!save->prim_store || i >= save->prim_store->size) {
1507       save->prim_store = realloc_prim_store(save->prim_store, i * 2);
1508    }
1509    save->prim_store->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1510    save->prim_store->prims[i].begin = 1;
1511    save->prim_store->prims[i].end = 0;
1512    save->prim_store->prims[i].start = get_vertex_count(save);
1513    save->prim_store->prims[i].count = 0;
1514 
1515    save->no_current_update = no_current_update;
1516 
1517    _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1518 
1519    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1520    ctx->Driver.SaveNeedFlush = GL_TRUE;
1521 }
1522 
1523 
1524 static void GLAPIENTRY
_save_End(void)1525 _save_End(void)
1526 {
1527    GET_CURRENT_CONTEXT(ctx);
1528    struct vbo_save_context *save = &vbo_context(ctx)->save;
1529    const GLint i = save->prim_store->used - 1;
1530 
1531    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1532    save->prim_store->prims[i].end = 1;
1533    save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start);
1534 
1535    /* Swap out this vertex format while outside begin/end.  Any color,
1536     * etc. received between here and the next begin will be compiled
1537     * as opcodes.
1538     */
1539    if (save->out_of_memory) {
1540       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1541    }
1542    else {
1543       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1544    }
1545 }
1546 
1547 
1548 static void GLAPIENTRY
_save_Begin(GLenum mode)1549 _save_Begin(GLenum mode)
1550 {
1551    GET_CURRENT_CONTEXT(ctx);
1552    (void) mode;
1553    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1554 }
1555 
1556 
1557 static void GLAPIENTRY
_save_PrimitiveRestartNV(void)1558 _save_PrimitiveRestartNV(void)
1559 {
1560    GET_CURRENT_CONTEXT(ctx);
1561    struct vbo_save_context *save = &vbo_context(ctx)->save;
1562 
1563    if (save->prim_store->used == 0) {
1564       /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1565        * is an error.
1566        */
1567       _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1568                           "glPrimitiveRestartNV called outside glBegin/End");
1569    } else {
1570       /* get current primitive mode */
1571       GLenum curPrim = save->prim_store->prims[save->prim_store->used - 1].mode;
1572       bool no_current_update = save->no_current_update;
1573 
1574       /* restart primitive */
1575       CALL_End(ctx->CurrentServerDispatch, ());
1576       vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1577    }
1578 }
1579 
1580 
1581 /* Unlike the functions above, these are to be hooked into the vtxfmt
1582  * maintained in ctx->ListState, active when the list is known or
1583  * suspected to be outside any begin/end primitive.
1584  * Note: OBE = Outside Begin/End
1585  */
1586 static void GLAPIENTRY
_save_OBE_Rectf(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)1587 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1588 {
1589    GET_CURRENT_CONTEXT(ctx);
1590    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1591 
1592    vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1593    CALL_Vertex2f(dispatch, (x1, y1));
1594    CALL_Vertex2f(dispatch, (x2, y1));
1595    CALL_Vertex2f(dispatch, (x2, y2));
1596    CALL_Vertex2f(dispatch, (x1, y2));
1597    CALL_End(dispatch, ());
1598 }
1599 
1600 
1601 static void GLAPIENTRY
_save_OBE_Rectd(GLdouble x1,GLdouble y1,GLdouble x2,GLdouble y2)1602 _save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1603 {
1604    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1605 }
1606 
1607 static void GLAPIENTRY
_save_OBE_Rectdv(const GLdouble * v1,const GLdouble * v2)1608 _save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2)
1609 {
1610    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1611 }
1612 
1613 static void GLAPIENTRY
_save_OBE_Rectfv(const GLfloat * v1,const GLfloat * v2)1614 _save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2)
1615 {
1616    _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]);
1617 }
1618 
1619 static void GLAPIENTRY
_save_OBE_Recti(GLint x1,GLint y1,GLint x2,GLint y2)1620 _save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1621 {
1622    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1623 }
1624 
1625 static void GLAPIENTRY
_save_OBE_Rectiv(const GLint * v1,const GLint * v2)1626 _save_OBE_Rectiv(const GLint *v1, const GLint *v2)
1627 {
1628    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1629 }
1630 
1631 static void GLAPIENTRY
_save_OBE_Rects(GLshort x1,GLshort y1,GLshort x2,GLshort y2)1632 _save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1633 {
1634    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1635 }
1636 
1637 static void GLAPIENTRY
_save_OBE_Rectsv(const GLshort * v1,const GLshort * v2)1638 _save_OBE_Rectsv(const GLshort *v1, const GLshort *v2)
1639 {
1640    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1641 }
1642 
1643 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode,GLint start,GLsizei count)1644 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1645 {
1646    GET_CURRENT_CONTEXT(ctx);
1647    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1648    struct vbo_save_context *save = &vbo_context(ctx)->save;
1649    GLint i;
1650 
1651    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1652       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1653       return;
1654    }
1655    if (count < 0) {
1656       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1657       return;
1658    }
1659 
1660    if (save->out_of_memory)
1661       return;
1662 
1663    grow_vertex_storage(ctx, count);
1664 
1665    /* Make sure to process any VBO binding changes */
1666    _mesa_update_state(ctx);
1667 
1668    _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1669 
1670    vbo_save_NotifyBegin(ctx, mode, true);
1671 
1672    for (i = 0; i < count; i++)
1673       _mesa_array_element(ctx, start + i);
1674    CALL_End(ctx->CurrentServerDispatch, ());
1675 
1676    _mesa_vao_unmap_arrays(ctx, vao);
1677 }
1678 
1679 
1680 static void GLAPIENTRY
_save_OBE_MultiDrawArrays(GLenum mode,const GLint * first,const GLsizei * count,GLsizei primcount)1681 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1682                           const GLsizei *count, GLsizei primcount)
1683 {
1684    GET_CURRENT_CONTEXT(ctx);
1685    GLint i;
1686 
1687    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1688       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1689       return;
1690    }
1691 
1692    if (primcount < 0) {
1693       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1694                           "glMultiDrawArrays(primcount<0)");
1695       return;
1696    }
1697 
1698    unsigned vertcount = 0;
1699    for (i = 0; i < primcount; i++) {
1700       if (count[i] < 0) {
1701          _mesa_compile_error(ctx, GL_INVALID_VALUE,
1702                              "glMultiDrawArrays(count[i]<0)");
1703          return;
1704       }
1705       vertcount += count[i];
1706    }
1707 
1708    grow_vertex_storage(ctx, vertcount);
1709 
1710    for (i = 0; i < primcount; i++) {
1711       if (count[i] > 0) {
1712          _save_OBE_DrawArrays(mode, first[i], count[i]);
1713       }
1714    }
1715 }
1716 
1717 
1718 static void
array_element(struct gl_context * ctx,GLint basevertex,GLuint elt,unsigned index_size_shift)1719 array_element(struct gl_context *ctx,
1720               GLint basevertex, GLuint elt, unsigned index_size_shift)
1721 {
1722    /* Section 10.3.5 Primitive Restart:
1723     * [...]
1724     *    When one of the *BaseVertex drawing commands specified in section 10.5
1725     * is used, the primitive restart comparison occurs before the basevertex
1726     * offset is added to the array index.
1727     */
1728    /* If PrimitiveRestart is enabled and the index is the RestartIndex
1729     * then we call PrimitiveRestartNV and return.
1730     */
1731    if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1732        elt == ctx->Array._RestartIndex[index_size_shift]) {
1733       CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1734       return;
1735    }
1736 
1737    _mesa_array_element(ctx, basevertex + elt);
1738 }
1739 
1740 
1741 /* Could do better by copying the arrays and element list intact and
1742  * then emitting an indexed prim at runtime.
1743  */
1744 static void GLAPIENTRY
_save_OBE_DrawElementsBaseVertex(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)1745 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1746                                  const GLvoid * indices, GLint basevertex)
1747 {
1748    GET_CURRENT_CONTEXT(ctx);
1749    struct vbo_save_context *save = &vbo_context(ctx)->save;
1750    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1751    struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1752    GLint i;
1753 
1754    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1755       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1756       return;
1757    }
1758    if (count < 0) {
1759       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1760       return;
1761    }
1762    if (type != GL_UNSIGNED_BYTE &&
1763        type != GL_UNSIGNED_SHORT &&
1764        type != GL_UNSIGNED_INT) {
1765       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1766       return;
1767    }
1768 
1769    if (save->out_of_memory)
1770       return;
1771 
1772    grow_vertex_storage(ctx, count);
1773 
1774    /* Make sure to process any VBO binding changes */
1775    _mesa_update_state(ctx);
1776 
1777    _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1778 
1779    if (indexbuf)
1780       indices =
1781          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1782 
1783    vbo_save_NotifyBegin(ctx, mode, true);
1784 
1785    switch (type) {
1786    case GL_UNSIGNED_BYTE:
1787       for (i = 0; i < count; i++)
1788          array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1789       break;
1790    case GL_UNSIGNED_SHORT:
1791       for (i = 0; i < count; i++)
1792          array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1793       break;
1794    case GL_UNSIGNED_INT:
1795       for (i = 0; i < count; i++)
1796          array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1797       break;
1798    default:
1799       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1800       break;
1801    }
1802 
1803    CALL_End(ctx->CurrentServerDispatch, ());
1804 
1805    _mesa_vao_unmap(ctx, vao);
1806 }
1807 
1808 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices)1809 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1810                        const GLvoid * indices)
1811 {
1812    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1813 }
1814 
1815 
1816 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid * indices)1817 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1818                             GLsizei count, GLenum type,
1819                             const GLvoid * indices)
1820 {
1821    GET_CURRENT_CONTEXT(ctx);
1822    struct vbo_save_context *save = &vbo_context(ctx)->save;
1823 
1824    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1825       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1826       return;
1827    }
1828    if (count < 0) {
1829       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1830                           "glDrawRangeElements(count<0)");
1831       return;
1832    }
1833    if (type != GL_UNSIGNED_BYTE &&
1834        type != GL_UNSIGNED_SHORT &&
1835        type != GL_UNSIGNED_INT) {
1836       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1837       return;
1838    }
1839    if (end < start) {
1840       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1841                           "glDrawRangeElements(end < start)");
1842       return;
1843    }
1844 
1845    if (save->out_of_memory)
1846       return;
1847 
1848    _save_OBE_DrawElements(mode, count, type, indices);
1849 }
1850 
1851 
1852 static void GLAPIENTRY
_save_OBE_MultiDrawElements(GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei primcount)1853 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1854                             const GLvoid * const *indices, GLsizei primcount)
1855 {
1856    GET_CURRENT_CONTEXT(ctx);
1857    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1858    GLsizei i;
1859 
1860    int vertcount = 0;
1861    for (i = 0; i < primcount; i++) {
1862       vertcount += count[i];
1863    }
1864    grow_vertex_storage(ctx, vertcount);
1865 
1866    for (i = 0; i < primcount; i++) {
1867       if (count[i] > 0) {
1868          CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1869       }
1870    }
1871 }
1872 
1873 
1874 static void GLAPIENTRY
_save_OBE_MultiDrawElementsBaseVertex(GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei primcount,const GLint * basevertex)1875 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1876                                       GLenum type,
1877                                       const GLvoid * const *indices,
1878                                       GLsizei primcount,
1879                                       const GLint *basevertex)
1880 {
1881    GET_CURRENT_CONTEXT(ctx);
1882    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1883    GLsizei i;
1884 
1885    int vertcount = 0;
1886    for (i = 0; i < primcount; i++) {
1887       vertcount += count[i];
1888    }
1889    grow_vertex_storage(ctx, vertcount);
1890 
1891    for (i = 0; i < primcount; i++) {
1892       if (count[i] > 0) {
1893          CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1894                                      indices[i],
1895                                      basevertex[i]));
1896       }
1897    }
1898 }
1899 
1900 
1901 static void
vtxfmt_init(struct gl_context * ctx)1902 vtxfmt_init(struct gl_context *ctx)
1903 {
1904    struct vbo_save_context *save = &vbo_context(ctx)->save;
1905    GLvertexformat *vfmt = &save->vtxfmt;
1906 
1907 #define NAME_AE(x) _ae_##x
1908 #define NAME_CALLLIST(x) _save_##x
1909 #define NAME(x) _save_##x
1910 #define NAME_ES(x) _save_##x##ARB
1911 
1912 #include "vbo_init_tmp.h"
1913 }
1914 
1915 
1916 /**
1917  * Initialize the dispatch table with the VBO functions for display
1918  * list compilation.
1919  */
1920 void
vbo_initialize_save_dispatch(const struct gl_context * ctx,struct _glapi_table * exec)1921 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1922                              struct _glapi_table *exec)
1923 {
1924    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1925    SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1926    SET_DrawElements(exec, _save_OBE_DrawElements);
1927    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1928    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1929    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1930    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1931    SET_Rectf(exec, _save_OBE_Rectf);
1932    SET_Rectd(exec, _save_OBE_Rectd);
1933    SET_Rectdv(exec, _save_OBE_Rectdv);
1934    SET_Rectfv(exec, _save_OBE_Rectfv);
1935    SET_Recti(exec, _save_OBE_Recti);
1936    SET_Rectiv(exec, _save_OBE_Rectiv);
1937    SET_Rects(exec, _save_OBE_Rects);
1938    SET_Rectsv(exec, _save_OBE_Rectsv);
1939 
1940    /* Note: other glDraw functins aren't compiled into display lists */
1941 }
1942 
1943 
1944 
1945 void
vbo_save_SaveFlushVertices(struct gl_context * ctx)1946 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1947 {
1948    struct vbo_save_context *save = &vbo_context(ctx)->save;
1949 
1950    /* Noop when we are actually active:
1951     */
1952    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1953       return;
1954 
1955    if (save->vertex_store->used || save->prim_store->used)
1956       compile_vertex_list(ctx);
1957 
1958    copy_to_current(ctx);
1959    reset_vertex(ctx);
1960    ctx->Driver.SaveNeedFlush = GL_FALSE;
1961 }
1962 
1963 
1964 /**
1965  * Called from glNewList when we're starting to compile a display list.
1966  */
1967 void
vbo_save_NewList(struct gl_context * ctx,GLuint list,GLenum mode)1968 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1969 {
1970    struct vbo_save_context *save = &vbo_context(ctx)->save;
1971 
1972    (void) list;
1973    (void) mode;
1974 
1975    if (!save->prim_store)
1976       save->prim_store = realloc_prim_store(NULL, 8);
1977 
1978    if (!save->vertex_store)
1979       save->vertex_store = CALLOC_STRUCT(vbo_save_vertex_store);
1980 
1981    reset_vertex(ctx);
1982    ctx->Driver.SaveNeedFlush = GL_FALSE;
1983 }
1984 
1985 
1986 /**
1987  * Called from glEndList when we're finished compiling a display list.
1988  */
1989 void
vbo_save_EndList(struct gl_context * ctx)1990 vbo_save_EndList(struct gl_context *ctx)
1991 {
1992    struct vbo_save_context *save = &vbo_context(ctx)->save;
1993 
1994    /* EndList called inside a (saved) Begin/End pair?
1995     */
1996    if (_mesa_inside_dlist_begin_end(ctx)) {
1997       if (save->prim_store->used > 0) {
1998          GLint i = save->prim_store->used - 1;
1999          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
2000          save->prim_store->prims[i].end = 0;
2001          save->prim_store->prims[i].count = get_vertex_count(save) - save->prim_store->prims[i].start;
2002       }
2003 
2004       /* Make sure this vertex list gets replayed by the "loopback"
2005        * mechanism:
2006        */
2007       save->dangling_attr_ref = GL_TRUE;
2008       vbo_save_SaveFlushVertices(ctx);
2009 
2010       /* Swap out this vertex format while outside begin/end.  Any color,
2011        * etc. received between here and the next begin will be compiled
2012        * as opcodes.
2013        */
2014       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
2015    }
2016 
2017    assert(save->vertex_size == 0);
2018 }
2019 
2020 /**
2021  * Called during context creation/init.
2022  */
2023 static void
current_init(struct gl_context * ctx)2024 current_init(struct gl_context *ctx)
2025 {
2026    struct vbo_save_context *save = &vbo_context(ctx)->save;
2027    GLint i;
2028 
2029    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_EDGEFLAG; i++) {
2030       const GLuint j = i - VBO_ATTRIB_POS;
2031       assert(j < VERT_ATTRIB_MAX);
2032       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
2033       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
2034    }
2035 
2036    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
2037       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
2038       assert(j < MAT_ATTRIB_MAX);
2039       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
2040       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
2041    }
2042 }
2043 
2044 
2045 /**
2046  * Initialize the display list compiler.  Called during context creation.
2047  */
2048 void
vbo_save_api_init(struct vbo_save_context * save)2049 vbo_save_api_init(struct vbo_save_context *save)
2050 {
2051    struct gl_context *ctx = gl_context_from_vbo_save(save);
2052 
2053    vtxfmt_init(ctx);
2054    current_init(ctx);
2055 }
2056