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