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