1 /**************************************************************************
3 Copyright 2002-2008 VMware, Inc.
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:
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
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.
26 **************************************************************************/
30 * Keith Whitwell <keithw@vmware.com>
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
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,
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.
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
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.
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
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.
86 * The layout of this buffer for two display lists is:
87 * V0A0|V0A1|V1A0|V1A1|P0I0|P0I1|V0A0V0A1V0A2|V1A1V1A1V1A2|...
89 * - VxAy: vertex x, attributes y
90 * - PxIy: draw x, index y
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).
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
103 #include "main/glheader.h"
104 #include "main/arrayobj.h"
105 #include "main/bufferobj.h"
106 #include "main/context.h"
107 #include "main/dlist.h"
108 #include "main/enums.h"
109 #include "main/eval.h"
110 #include "main/macros.h"
111 #include "main/draw_validate.h"
112 #include "main/api_arrayelt.h"
113 #include "main/vtxfmt.h"
114 #include "main/dispatch.h"
115 #include "main/state.h"
116 #include "main/varray.h"
117 #include "util/bitscan.h"
118 #include "util/u_memory.h"
119 #include "util/hash_table.h"
121 #include "gallium/include/pipe/p_state.h"
123 #include "vbo_noop.h"
124 #include "vbo_private.h"
131 /* An interesting VBO number/name to help with debugging */
132 #define VBO_BUF_ID 12345
134 static void GLAPIENTRY
135 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
137 static void GLAPIENTRY
138 _save_EvalCoord1f(GLfloat u);
140 static void GLAPIENTRY
141 _save_EvalCoord2f(GLfloat u, GLfloat v);
144 handle_out_of_memory(struct gl_context *ctx)
146 struct vbo_save_context *save = &vbo_context(ctx)->save;
147 _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt);
148 save->out_of_memory = true;
152 * NOTE: Old 'parity' issue is gone, but copying can still be
153 * wrong-footed on replay.
156 copy_vertices(struct gl_context *ctx,
157 const struct vbo_save_vertex_list *node,
158 const fi_type * src_buffer)
160 struct vbo_save_context *save = &vbo_context(ctx)->save;
161 struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
162 GLuint sz = save->vertex_size;
164 if (prim->end || !prim->count || !sz)
167 const fi_type *src = src_buffer + prim->start * sz;
168 assert(save->copied.buffer == NULL);
169 save->copied.buffer = malloc(sizeof(fi_type) * sz * prim->count);
171 return vbo_copy_vertices(ctx, prim->mode, prim->start, &prim->count,
172 prim->begin, sz, true, save->copied.buffer, src);
176 static struct vbo_save_vertex_store *
177 realloc_vertex_store(struct vbo_save_vertex_store *store, uint32_t vertex_size, int vertex_count)
180 store = CALLOC_STRUCT(vbo_save_vertex_store);
182 int new_size = MAX2(vertex_count * vertex_size * sizeof(GLfloat), 1024 * 1024);
183 if (new_size > store->buffer_in_ram_size) {
184 store->buffer_in_ram_size = new_size;
185 store->buffer_in_ram = realloc(store->buffer_in_ram, store->buffer_in_ram_size);
192 static struct vbo_save_primitive_store *
193 realloc_prim_store(struct vbo_save_primitive_store *store, int prim_count)
196 store = CALLOC_STRUCT(vbo_save_primitive_store);
198 uint32_t old_size = store->size;
199 store->size = prim_count;
200 assert (old_size < store->size);
201 store->prims = realloc(store->prims, store->size * sizeof(struct _mesa_prim));
202 memset(&store->prims[old_size], 0, (store->size - old_size) * sizeof(struct _mesa_prim));
209 reset_counters(struct gl_context *ctx)
211 struct vbo_save_context *save = &vbo_context(ctx)->save;
213 save->vertex_store->used = 0;
214 save->prim_store->used = 0;
215 save->dangling_attr_ref = GL_FALSE;
219 * For a list of prims, try merging prims that can just be extensions of the
223 merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list,
227 struct _mesa_prim *prev_prim = prim_list;
229 for (i = 1; i < *prim_count; i++) {
230 struct _mesa_prim *this_prim = prim_list + i;
232 vbo_try_prim_conversion(&this_prim->mode, &this_prim->count);
234 if (vbo_merge_draws(ctx, true,
235 prev_prim->mode, this_prim->mode,
236 prev_prim->start, this_prim->start,
237 &prev_prim->count, this_prim->count,
238 prev_prim->basevertex, this_prim->basevertex,
240 this_prim->begin, this_prim->end)) {
241 /* We've found a prim that just extend the previous one. Tack it
242 * onto the previous one, and let this primitive struct get dropped.
247 /* If any previous primitives have been dropped, then we need to copy
248 * this later one into the next available slot.
251 if (prev_prim != this_prim)
252 *prev_prim = *this_prim;
255 *prim_count = prev_prim - prim_list + 1;
260 * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
261 * don't have to worry about handling the _mesa_prim::begin/end flags.
262 * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
265 convert_line_loop_to_strip(struct vbo_save_context *save,
266 struct vbo_save_vertex_list *node)
268 struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
270 assert(prim->mode == GL_LINE_LOOP);
273 /* Copy the 0th vertex to end of the buffer and extend the
274 * vertex count by one to finish the line loop.
276 const GLuint sz = save->vertex_size;
278 const fi_type *src = save->vertex_store->buffer_in_ram + prim->start * sz;
280 fi_type *dst = save->vertex_store->buffer_in_ram + (prim->start + prim->count) * sz;
282 memcpy(dst, src, sz * sizeof(float));
285 node->cold->vertex_count++;
286 save->vertex_store->used += sz;
290 /* Drawing the second or later section of a long line loop.
291 * Skip the 0th vertex.
297 prim->mode = GL_LINE_STRIP;
301 /* Compare the present vao if it has the same setup. */
303 compare_vao(gl_vertex_processing_mode mode,
304 const struct gl_vertex_array_object *vao,
305 const struct gl_buffer_object *bo, GLintptr buffer_offset,
306 GLuint stride, GLbitfield64 vao_enabled,
307 const GLubyte size[VBO_ATTRIB_MAX],
308 const GLenum16 type[VBO_ATTRIB_MAX],
309 const GLuint offset[VBO_ATTRIB_MAX])
314 /* If the enabled arrays are not the same we are not equal. */
315 if (vao_enabled != vao->Enabled)
318 /* Check the buffer binding at 0 */
319 if (vao->BufferBinding[0].BufferObj != bo)
321 /* BufferBinding[0].Offset != buffer_offset is checked per attribute */
322 if (vao->BufferBinding[0].Stride != stride)
324 assert(vao->BufferBinding[0].InstanceDivisor == 0);
326 /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */
327 const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
329 /* Now check the enabled arrays */
330 GLbitfield mask = vao_enabled;
332 const int attr = u_bit_scan(&mask);
333 const unsigned char vbo_attr = vao_to_vbo_map[attr];
334 const GLenum16 tp = type[vbo_attr];
335 const GLintptr off = offset[vbo_attr] + buffer_offset;
336 const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr];
337 if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off)
339 if (attrib->Format.Type != tp)
341 if (attrib->Format.Size != size[vbo_attr])
343 assert(attrib->Format.Format == GL_RGBA);
344 assert(attrib->Format.Normalized == GL_FALSE);
345 assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp));
346 assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp));
347 assert(attrib->BufferBindingIndex == 0);
354 /* Create or reuse the vao for the vertex processing mode. */
356 update_vao(struct gl_context *ctx,
357 gl_vertex_processing_mode mode,
358 struct gl_vertex_array_object **vao,
359 struct gl_buffer_object *bo, GLintptr buffer_offset,
360 GLuint stride, GLbitfield64 vbo_enabled,
361 const GLubyte size[VBO_ATTRIB_MAX],
362 const GLenum16 type[VBO_ATTRIB_MAX],
363 const GLuint offset[VBO_ATTRIB_MAX])
365 /* Compute the bitmasks of vao_enabled arrays */
366 GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
369 * Check if we can possibly reuse the exisiting one.
370 * In the long term we should reset them when something changes.
372 if (compare_vao(mode, *vao, bo, buffer_offset, stride,
373 vao_enabled, size, type, offset))
376 /* The initial refcount is 1 */
377 _mesa_reference_vao(ctx, vao, NULL);
378 *vao = _mesa_new_vao(ctx, ~((GLuint)0));
381 * assert(stride <= ctx->Const.MaxVertexAttribStride);
382 * MaxVertexAttribStride is not set for drivers that does not
383 * expose GL 44 or GLES 31.
386 /* Bind the buffer object at binding point 0 */
387 _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false,
390 /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
391 * Note that the position/generic0 aliasing is done in the VAO.
393 const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
394 /* Now set the enable arrays */
395 GLbitfield mask = vao_enabled;
397 const int vao_attr = u_bit_scan(&mask);
398 const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
399 assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
401 _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
402 size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
403 _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
405 _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled);
406 assert(vao_enabled == (*vao)->Enabled);
407 assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
409 /* Finalize and freeze the VAO */
410 _mesa_set_vao_immutable(ctx, *vao);
414 static void wrap_filled_vertex(struct gl_context *ctx);
415 static void compile_vertex_list(struct gl_context *ctx);
418 realloc_storage(struct gl_context *ctx, int vertex_count)
420 struct vbo_save_context *save = &vbo_context(ctx)->save;
422 /* Limit how much memory we allocate. */
423 if (save->prim_store->used > 0 &&
425 vertex_count * save->vertex_size > VBO_SAVE_BUFFER_SIZE) {
426 wrap_filled_vertex(ctx);
427 vertex_count = VBO_SAVE_BUFFER_SIZE / save->vertex_size;
430 if (vertex_count >= 0)
431 save->vertex_store = realloc_vertex_store(save->vertex_store, save->vertex_size, vertex_count);
433 if (save->vertex_store->buffer_in_ram == NULL)
434 handle_out_of_memory(ctx);
438 unsigned vertex_size;
439 fi_type *vertex_attributes;
442 static uint32_t _hash_vertex_key(const void *key)
444 struct vertex_key *k = (struct vertex_key*)key;
445 unsigned sz = k->vertex_size;
447 return _mesa_hash_data(k->vertex_attributes, sz * sizeof(float));
450 static bool _compare_vertex_key(const void *key1, const void *key2)
452 struct vertex_key *k1 = (struct vertex_key*)key1;
453 struct vertex_key *k2 = (struct vertex_key*)key2;
454 /* All the compared vertices are going to be drawn with the same VAO,
455 * so we can compare the attributes. */
456 assert (k1->vertex_size == k2->vertex_size);
457 return memcmp(k1->vertex_attributes,
458 k2->vertex_attributes,
459 k1->vertex_size * sizeof(float)) == 0;
462 static void _free_entry(struct hash_entry *entry)
464 free((void*)entry->key);
467 /* Add vertex to the vertex buffer and return its index. If this vertex is a duplicate
468 * of an existing vertex, return the original index instead.
471 add_vertex(struct vbo_save_context *save, struct hash_table *hash_to_index,
472 uint32_t index, fi_type *new_buffer, uint32_t *max_index)
474 /* If vertex deduplication is disabled return the original index. */
478 fi_type *vert = save->vertex_store->buffer_in_ram + save->vertex_size * index;
480 struct vertex_key *key = malloc(sizeof(struct vertex_key));
481 key->vertex_size = save->vertex_size;
482 key->vertex_attributes = vert;
484 struct hash_entry *entry = _mesa_hash_table_search(hash_to_index, key);
487 /* We found an existing vertex with the same hash, return its index. */
488 return (uintptr_t) entry->data;
490 /* This is a new vertex. Determine a new index and copy its attributes to the vertex
491 * buffer. Note that 'new_buffer' is created at each list compilation so we write vertices
492 * starting at index 0.
494 uint32_t n = _mesa_hash_table_num_entries(hash_to_index);
495 *max_index = MAX2(n, *max_index);
497 memcpy(&new_buffer[save->vertex_size * n],
499 save->vertex_size * sizeof(fi_type));
501 _mesa_hash_table_insert(hash_to_index, key, (void*)(uintptr_t)(n));
503 /* The index buffer is shared between list compilations, so add the base index to get
512 get_vertex_count(struct vbo_save_context *save)
514 if (!save->vertex_size)
516 return save->vertex_store->used / save->vertex_size;
521 * Insert the active immediate struct onto the display list currently
525 compile_vertex_list(struct gl_context *ctx)
527 struct vbo_save_context *save = &vbo_context(ctx)->save;
528 struct vbo_save_vertex_list *node;
530 /* Allocate space for this structure in the display list currently
533 node = (struct vbo_save_vertex_list *)
534 _mesa_dlist_alloc_vertex_list(ctx, !save->dangling_attr_ref && !save->no_current_update);
539 memset(node, 0, sizeof(struct vbo_save_vertex_list));
540 node->cold = calloc(1, sizeof(*node->cold));
542 /* Make sure the pointer is aligned to the size of a pointer */
543 assert((GLintptr) node % sizeof(void *) == 0);
545 const GLsizei stride = save->vertex_size*sizeof(GLfloat);
547 node->cold->vertex_count = get_vertex_count(save);
548 node->cold->wrap_count = save->copied.nr;
549 node->cold->prims = malloc(sizeof(struct _mesa_prim) * save->prim_store->used);
550 memcpy(node->cold->prims, save->prim_store->prims, sizeof(struct _mesa_prim) * save->prim_store->used);
551 node->cold->ib.obj = NULL;
552 node->cold->prim_count = save->prim_store->used;
554 if (save->no_current_update) {
555 node->cold->current_data = NULL;
558 GLuint current_size = save->vertex_size - save->attrsz[0];
559 node->cold->current_data = NULL;
562 node->cold->current_data = malloc(current_size * sizeof(GLfloat));
563 if (node->cold->current_data) {
564 const char *buffer = (const char *)save->vertex_store->buffer_in_ram;
565 unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
566 unsigned vertex_offset = 0;
568 if (node->cold->vertex_count)
569 vertex_offset = (node->cold->vertex_count - 1) * stride;
571 memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset,
572 current_size * sizeof(GLfloat));
574 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
575 handle_out_of_memory(ctx);
580 assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0);
582 if (save->dangling_attr_ref)
583 ctx->ListState.Current.UseLoopback = true;
585 /* Copy duplicated vertices
587 save->copied.nr = copy_vertices(ctx, node, save->vertex_store->buffer_in_ram);
589 if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) {
590 convert_line_loop_to_strip(save, node);
593 merge_prims(ctx, node->cold->prims, &node->cold->prim_count);
595 GLintptr buffer_offset = 0;
596 GLuint start_offset = 0;
598 /* Create an index buffer. */
599 node->cold->min_index = node->cold->max_index = 0;
600 if (node->cold->vertex_count == 0 || node->cold->prim_count == 0)
603 /* We won't modify node->prims, so use a const alias to avoid unintended
605 const struct _mesa_prim *original_prims = node->cold->prims;
607 int end = original_prims[node->cold->prim_count - 1].start +
608 original_prims[node->cold->prim_count - 1].count;
609 int total_vert_count = end - original_prims[0].start;
611 node->cold->min_index = node->cold->prims[0].start;
612 node->cold->max_index = end - 1;
614 int max_index_count = total_vert_count * 2;
616 int size = max_index_count * sizeof(uint32_t);
617 uint32_t* indices = (uint32_t*) malloc(size);
618 struct _mesa_prim *merged_prims = NULL;
621 struct hash_table *vertex_to_index = NULL;
622 fi_type *temp_vertices_buffer = NULL;
624 /* The loopback replay code doesn't use the index buffer, so we can't
625 * dedup vertices in this case.
627 if (!ctx->ListState.Current.UseLoopback) {
628 vertex_to_index = _mesa_hash_table_create(NULL, _hash_vertex_key, _compare_vertex_key);
629 temp_vertices_buffer = malloc(save->vertex_store->buffer_in_ram_size);
632 uint32_t max_index = 0;
634 int last_valid_prim = -1;
635 /* Construct indices array. */
636 for (unsigned i = 0; i < node->cold->prim_count; i++) {
637 assert(original_prims[i].basevertex == 0);
638 GLubyte mode = original_prims[i].mode;
640 int vertex_count = original_prims[i].count;
645 /* Line strips may get converted to lines */
646 if (mode == GL_LINE_STRIP)
649 /* If 2 consecutive prims use the same mode => merge them. */
650 bool merge_prims = last_valid_prim >= 0 &&
651 mode == merged_prims[last_valid_prim].mode &&
652 mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
653 mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
656 /* To be able to merge consecutive triangle strips we need to insert
657 * a degenerate triangle.
660 mode == GL_TRIANGLE_STRIP) {
661 /* Insert a degenerate triangle */
662 assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
663 unsigned tri_count = merged_prims[last_valid_prim].count - 2;
665 indices[idx] = indices[idx - 1];
666 indices[idx + 1] = add_vertex(save, vertex_to_index, original_prims[i].start,
667 temp_vertices_buffer, &max_index);
669 merged_prims[last_valid_prim].count += 2;
672 /* Add another index to preserve winding order */
673 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start,
674 temp_vertices_buffer, &max_index);
675 merged_prims[last_valid_prim].count++;
681 /* Convert line strips to lines if it'll allow if the previous
682 * prim mode is GL_LINES (so merge_prims is true) or if the next
683 * primitive mode is GL_LINES or GL_LINE_LOOP.
685 if (original_prims[i].mode == GL_LINE_STRIP &&
687 (i < node->cold->prim_count - 1 &&
688 (original_prims[i + 1].mode == GL_LINE_STRIP ||
689 original_prims[i + 1].mode == GL_LINES)))) {
690 for (unsigned j = 0; j < vertex_count; j++) {
691 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
692 temp_vertices_buffer, &max_index);
693 /* Repeat all but the first/last indices. */
694 if (j && j != vertex_count - 1) {
695 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
696 temp_vertices_buffer, &max_index);
700 /* We didn't convert to LINES, so restore the original mode */
701 mode = original_prims[i].mode;
703 for (unsigned j = 0; j < vertex_count; j++) {
704 indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
705 temp_vertices_buffer, &max_index);
710 /* Update vertex count. */
711 merged_prims[last_valid_prim].count += idx - start;
713 /* Keep this primitive */
714 last_valid_prim += 1;
715 assert(last_valid_prim <= i);
716 merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
717 merged_prims[last_valid_prim] = original_prims[i];
718 merged_prims[last_valid_prim].start = start;
719 merged_prims[last_valid_prim].count = idx - start;
721 merged_prims[last_valid_prim].mode = mode;
724 assert(idx > 0 && idx <= max_index_count);
726 unsigned merged_prim_count = last_valid_prim + 1;
727 node->cold->ib.ptr = NULL;
728 node->cold->ib.count = idx;
729 node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
731 /* How many bytes do we need to store the indices and the vertices */
732 total_vert_count = vertex_to_index ? (max_index + 1) : idx;
733 unsigned total_bytes_needed = idx * sizeof(uint32_t) +
734 total_vert_count * save->vertex_size * sizeof(fi_type);
736 const GLintptr old_offset = save->VAO[0] ?
737 save->VAO[0]->BufferBinding[0].Offset + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset : 0;
738 if (old_offset != save->current_bo_bytes_used && stride > 0) {
739 GLintptr offset_diff = save->current_bo_bytes_used - old_offset;
740 while (offset_diff > 0 &&
741 save->current_bo_bytes_used < save->current_bo->Size &&
742 offset_diff % stride != 0) {
743 save->current_bo_bytes_used++;
744 offset_diff = save->current_bo_bytes_used - old_offset;
747 buffer_offset = save->current_bo_bytes_used;
749 /* Can we reuse the previous bo or should we allocate a new one? */
750 int available_bytes = save->current_bo ? save->current_bo->Size - save->current_bo_bytes_used : 0;
751 if (total_bytes_needed > available_bytes) {
752 if (save->current_bo)
753 _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
754 save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
755 bool success = ctx->Driver.BufferData(ctx,
756 GL_ELEMENT_ARRAY_BUFFER_ARB,
757 MAX2(total_bytes_needed, VBO_SAVE_BUFFER_SIZE),
759 GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
762 _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
763 _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
764 handle_out_of_memory(ctx);
766 save->current_bo_bytes_used = 0;
767 available_bytes = save->current_bo->Size;
771 assert(old_offset <= buffer_offset);
772 const GLintptr offset_diff = buffer_offset - old_offset;
773 if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
774 /* The vertex size is an exact multiple of the buffer offset.
775 * This means that we can use zero-based vertex attribute pointers
776 * and specify the start of the primitive with the _mesa_prim::start
777 * field. This results in issuing several draw calls with identical
778 * vertex attribute information. This can result in fewer state
779 * changes in drivers. In particular, the Gallium CSO module will
780 * filter out redundant vertex buffer changes.
782 /* We cannot immediately update the primitives as some methods below
783 * still need the uncorrected start vertices
785 start_offset = offset_diff/stride;
786 assert(old_offset == buffer_offset - offset_diff);
787 buffer_offset = old_offset;
790 /* Correct the primitive starts, we can only do this here as copy_vertices
791 * and convert_line_loop_to_strip above consume the uncorrected starts.
792 * On the other hand the _vbo_loopback_vertex_list call below needs the
793 * primitives to be corrected already.
795 for (unsigned i = 0; i < node->cold->prim_count; i++) {
796 node->cold->prims[i].start += start_offset;
798 /* start_offset shifts vertices (so v[0] becomes v[start_offset]), so we have
799 * to apply this transformation to all indices and max_index.
801 for (unsigned i = 0; i < idx; i++)
802 indices[i] += start_offset;
803 max_index += start_offset;
806 _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->current_bo);
808 /* Upload the vertices first (see buffer_offset) */
809 ctx->Driver.BufferSubData(ctx,
810 save->current_bo_bytes_used,
811 total_vert_count * save->vertex_size * sizeof(fi_type),
812 vertex_to_index ? temp_vertices_buffer : save->vertex_store->buffer_in_ram,
814 save->current_bo_bytes_used += total_vert_count * save->vertex_size * sizeof(fi_type);
816 if (vertex_to_index) {
817 _mesa_hash_table_destroy(vertex_to_index, _free_entry);
818 free(temp_vertices_buffer);
821 /* Since we're append the indices to an existing buffer, we need to adjust the start value of each
822 * primitive (not the indices themselves). */
823 save->current_bo_bytes_used += align(save->current_bo_bytes_used, 4) - save->current_bo_bytes_used;
824 int indices_offset = save->current_bo_bytes_used / 4;
825 for (int i = 0; i < merged_prim_count; i++) {
826 merged_prims[i].start += indices_offset;
829 /* Then upload the indices. */
830 if (node->cold->ib.obj) {
831 ctx->Driver.BufferSubData(ctx,
832 save->current_bo_bytes_used,
833 idx * sizeof(uint32_t),
836 save->current_bo_bytes_used += idx * sizeof(uint32_t);
838 node->cold->vertex_count = 0;
839 node->cold->prim_count = 0;
842 /* Prepare for DrawGallium */
843 memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
844 /* The other info fields will be updated in vbo_save_playback_vertex_list */
845 node->merged.info.index_size = 4;
846 node->merged.info.instance_count = 1;
847 node->merged.info.index.gl_bo = node->cold->ib.obj;
848 if (merged_prim_count == 1) {
849 node->merged.info.mode = merged_prims[0].mode;
850 node->merged.start_count.start = merged_prims[0].start;
851 node->merged.start_count.count = merged_prims[0].count;
852 node->merged.start_count.index_bias = 0;
853 node->merged.mode = NULL;
855 node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
856 node->merged.start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
857 for (unsigned i = 0; i < merged_prim_count; i++) {
858 node->merged.start_counts[i].start = merged_prims[i].start;
859 node->merged.start_counts[i].count = merged_prims[i].count;
860 node->merged.start_counts[i].index_bias = 0;
861 node->merged.mode[i] = merged_prims[i].mode;
864 node->merged.num_draws = merged_prim_count;
865 if (node->merged.num_draws > 1) {
866 bool same_mode = true;
867 for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
868 same_mode = node->merged.mode[i] == node->merged.mode[0];
871 /* All primitives use the same mode, so we can simplify a bit */
872 node->merged.info.mode = node->merged.mode[0];
873 free(node->merged.mode);
874 node->merged.mode = NULL;
883 if (!save->current_bo) {
884 save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
885 bool success = ctx->Driver.BufferData(ctx,
886 GL_ELEMENT_ARRAY_BUFFER_ARB,
887 VBO_SAVE_BUFFER_SIZE,
889 GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
892 handle_out_of_memory(ctx);
895 GLuint offsets[VBO_ATTRIB_MAX];
896 for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
898 offset += save->attrsz[i] * sizeof(GLfloat);
900 /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
901 * Note that this may reuse the previous one of possible.
903 for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
904 /* create or reuse the vao */
905 update_vao(ctx, vpm, &save->VAO[vpm],
906 save->current_bo, buffer_offset, stride,
907 save->enabled, save->attrsz, save->attrtype, offsets);
908 /* Reference the vao in the dlist */
909 node->VAO[vpm] = NULL;
910 _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
914 /* Deal with GL_COMPILE_AND_EXECUTE:
916 if (ctx->ExecuteFlag) {
917 struct _glapi_table *dispatch = GET_DISPATCH();
919 _glapi_set_dispatch(ctx->Exec);
921 /* _vbo_loopback_vertex_list doesn't use the index buffer, so we have to
922 * use buffer_in_ram instead of current_bo which contains all vertices instead
923 * of the deduplicated vertices only in the !UseLoopback case.
925 * The problem is that the VAO offset is based on current_bo's layout,
926 * so we have to use a temp value.
928 struct gl_vertex_array_object *vao = node->VAO[VP_MODE_SHADER];
929 GLintptr original = vao->BufferBinding[0].Offset;
930 if (!ctx->ListState.Current.UseLoopback) {
931 GLintptr new_offset = 0;
932 /* 'start_offset' has been added to all primitives 'start', so undo it here. */
933 new_offset -= start_offset * stride;
934 vao->BufferBinding[0].Offset = new_offset;
936 _vbo_loopback_vertex_list(ctx, node, save->vertex_store->buffer_in_ram);
937 vao->BufferBinding[0].Offset = original;
939 _glapi_set_dispatch(dispatch);
942 /* Reset our structures for the next run of vertices:
949 * This is called when we fill a vertex buffer before we hit a glEnd().
951 * TODO -- If no new vertices have been stored, don't bother saving it.
954 wrap_buffers(struct gl_context *ctx)
956 struct vbo_save_context *save = &vbo_context(ctx)->save;
957 GLint i = save->prim_store->used - 1;
960 assert(i < (GLint) save->prim_store->size);
963 /* Close off in-progress primitive.
965 save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start);
966 mode = save->prim_store->prims[i].mode;
968 /* store the copied vertices, and allocate a new list.
970 compile_vertex_list(ctx);
972 /* Restart interrupted primitive
974 save->prim_store->prims[0].mode = mode;
975 save->prim_store->prims[0].begin = 0;
976 save->prim_store->prims[0].end = 0;
977 save->prim_store->prims[0].start = 0;
978 save->prim_store->prims[0].count = 0;
979 save->prim_store->used = 1;
984 * Called only when buffers are wrapped as the result of filling the
985 * vertex_store struct.
988 wrap_filled_vertex(struct gl_context *ctx)
990 struct vbo_save_context *save = &vbo_context(ctx)->save;
991 unsigned numComponents;
993 /* Emit a glEnd to close off the last vertex list.
997 assert(save->vertex_store->used == 0 && save->vertex_store->used == 0);
999 /* Copy stored stored vertices to start of new list.
1001 numComponents = save->copied.nr * save->vertex_size;
1003 fi_type *buffer_ptr = save->vertex_store->buffer_in_ram;
1004 if (numComponents) {
1005 assert(save->copied.buffer);
1007 save->copied.buffer,
1008 numComponents * sizeof(fi_type));
1009 free(save->copied.buffer);
1010 save->copied.buffer = NULL;
1012 save->vertex_store->used = numComponents;
1017 copy_to_current(struct gl_context *ctx)
1019 struct vbo_save_context *save = &vbo_context(ctx)->save;
1020 GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1023 const int i = u_bit_scan64(&enabled);
1024 assert(save->attrsz[i]);
1026 if (save->attrtype[i] == GL_DOUBLE ||
1027 save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
1028 memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
1030 COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
1031 save->attrptr[i], save->attrtype[i]);
1037 copy_from_current(struct gl_context *ctx)
1039 struct vbo_save_context *save = &vbo_context(ctx)->save;
1040 GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1043 const int i = u_bit_scan64(&enabled);
1045 switch (save->attrsz[i]) {
1047 save->attrptr[i][3] = save->current[i][3];
1050 save->attrptr[i][2] = save->current[i][2];
1053 save->attrptr[i][1] = save->current[i][1];
1056 save->attrptr[i][0] = save->current[i][0];
1059 unreachable("Unexpected vertex attribute size");
1066 * Called when we increase the size of a vertex attribute. For example,
1067 * if we've seen one or more glTexCoord2f() calls and now we get a
1068 * glTexCoord3f() call.
1069 * Flush existing data, set new attrib size, replay copied vertices.
1072 upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
1074 struct vbo_save_context *save = &vbo_context(ctx)->save;
1079 /* Store the current run of vertices, and emit a GL_END. Emit a
1080 * BEGIN in the new buffer.
1082 if (save->vertex_store->used)
1085 assert(save->copied.nr == 0);
1087 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
1088 * when the attribute already exists in the vertex and is having
1089 * its size increased.
1091 copy_to_current(ctx);
1095 oldsz = save->attrsz[attr];
1096 save->attrsz[attr] = newsz;
1097 save->enabled |= BITFIELD64_BIT(attr);
1099 save->vertex_size += newsz - oldsz;
1101 /* Recalculate all the attrptr[] values:
1104 for (i = 0; i < VBO_ATTRIB_MAX; i++) {
1105 if (save->attrsz[i]) {
1106 save->attrptr[i] = tmp;
1107 tmp += save->attrsz[i];
1110 save->attrptr[i] = NULL; /* will not be dereferenced. */
1114 /* Copy from current to repopulate the vertex with correct values.
1116 copy_from_current(ctx);
1118 /* Replay stored vertices to translate them to new format here.
1120 * If there are copied vertices and the new (upgraded) attribute
1121 * has not been defined before, this list is somewhat degenerate,
1122 * and will need fixup at runtime.
1124 if (save->copied.nr) {
1125 assert(save->copied.buffer);
1126 const fi_type *data = save->copied.buffer;
1127 fi_type *dest = save->vertex_store->buffer_in_ram;
1129 /* Need to note this and fix up at runtime (or loopback):
1131 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
1133 save->dangling_attr_ref = GL_TRUE;
1136 for (i = 0; i < save->copied.nr; i++) {
1137 GLbitfield64 enabled = save->enabled;
1139 const int j = u_bit_scan64(&enabled);
1140 assert(save->attrsz[j]);
1143 COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
1149 COPY_SZ_4V(dest, newsz, save->current[attr]);
1154 GLint sz = save->attrsz[j];
1155 COPY_SZ_4V(dest, sz, data);
1162 save->vertex_store->used += save->vertex_size * save->copied.nr;
1163 free(save->copied.buffer);
1164 save->copied.buffer = NULL;
1170 * This is called when the size of a vertex attribute changes.
1171 * For example, after seeing one or more glTexCoord2f() calls we
1172 * get a glTexCoord4f() or glTexCoord1f() call.
1175 fixup_vertex(struct gl_context *ctx, GLuint attr,
1176 GLuint sz, GLenum newType)
1178 struct vbo_save_context *save = &vbo_context(ctx)->save;
1180 if (sz > save->attrsz[attr] ||
1181 newType != save->attrtype[attr]) {
1182 /* New size is larger. Need to flush existing vertices and get
1183 * an enlarged vertex format.
1185 upgrade_vertex(ctx, attr, sz);
1187 else if (sz < save->active_sz[attr]) {
1189 const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
1191 /* New size is equal or smaller - just need to fill in some
1194 for (i = sz; i <= save->attrsz[attr]; i++)
1195 save->attrptr[attr][i - 1] = id[i - 1];
1198 save->active_sz[attr] = sz;
1203 * Reset the current size of all vertex attributes to the default
1204 * value of 0. This signals that we haven't yet seen any per-vertex
1205 * commands such as glNormal3f() or glTexCoord2f().
1208 reset_vertex(struct gl_context *ctx)
1210 struct vbo_save_context *save = &vbo_context(ctx)->save;
1212 while (save->enabled) {
1213 const int i = u_bit_scan64(&save->enabled);
1214 assert(save->attrsz[i]);
1215 save->attrsz[i] = 0;
1216 save->active_sz[i] = 0;
1219 save->vertex_size = 0;
1224 * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
1225 * It depends on a few things, including whether we're inside or outside
1229 is_vertex_position(const struct gl_context *ctx, GLuint index)
1231 return (index == 0 &&
1232 _mesa_attr_zero_aliases_vertex(ctx) &&
1233 _mesa_inside_dlist_begin_end(ctx));
1238 #define ERROR(err) _mesa_compile_error(ctx, err, __func__);
1241 /* Only one size for each attribute may be active at once. Eg. if
1242 * Color3f is installed/active, then Color4f may not be, even if the
1243 * vertex actually contains 4 color coordinates. This is because the
1244 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1245 * of the chooser function when switching between Color4f and Color3f.
1247 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \
1249 struct vbo_save_context *save = &vbo_context(ctx)->save; \
1250 int sz = (sizeof(C) / sizeof(GLfloat)); \
1252 if (save->active_sz[A] != N) \
1253 fixup_vertex(ctx, A, N * sz, T); \
1256 C *dest = (C *)save->attrptr[A]; \
1257 if (N>0) dest[0] = V0; \
1258 if (N>1) dest[1] = V1; \
1259 if (N>2) dest[2] = V2; \
1260 if (N>3) dest[3] = V3; \
1261 save->attrtype[A] = T; \
1266 fi_type *buffer_ptr = save->vertex_store->buffer_in_ram + save->vertex_store->used; \
1268 for (i = 0; i < save->vertex_size; i++) \
1269 buffer_ptr[i] = save->vertex[i]; \
1271 save->vertex_store->used += save->vertex_size; \
1272 if ((save->vertex_store->used + save->vertex_size) * sizeof(float) >= save->vertex_store->buffer_in_ram_size) { \
1273 realloc_storage(ctx, get_vertex_count(save) * 2); \
1274 assert((save->vertex_store->used + save->vertex_size) * sizeof(float) < save->vertex_store->buffer_in_ram_size); \
1279 #define TAG(x) _save_##x
1281 #include "vbo_attrib_tmp.h"
1285 #define MAT( ATTR, N, face, params ) \
1287 if (face != GL_BACK) \
1288 MAT_ATTR( ATTR, N, params ); /* front */ \
1289 if (face != GL_FRONT) \
1290 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1295 * Save a glMaterial call found between glBegin/End.
1296 * glMaterial calls outside Begin/End are handled in dlist.c.
1298 static void GLAPIENTRY
1299 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1301 GET_CURRENT_CONTEXT(ctx);
1303 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1304 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1310 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1313 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1316 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1319 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1322 if (*params < 0 || *params > ctx->Const.MaxShininess) {
1323 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1326 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1329 case GL_COLOR_INDEXES:
1330 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1332 case GL_AMBIENT_AND_DIFFUSE:
1333 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1334 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1337 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1343 /* Cope with EvalCoord/CallList called within a begin/end object:
1344 * -- Flush current buffer
1345 * -- Fallback to opcodes for the rest of the begin/end object.
1348 dlist_fallback(struct gl_context *ctx)
1350 struct vbo_save_context *save = &vbo_context(ctx)->save;
1352 if (save->vertex_store->used || save->prim_store->used) {
1353 if (save->prim_store->used > 0 && save->vertex_store->used > 0) {
1354 assert(save->vertex_size);
1355 /* Close off in-progress primitive. */
1356 GLint i = save->prim_store->used - 1;
1357 save->prim_store->prims[i].count =
1358 get_vertex_count(save) -
1359 save->prim_store->prims[i].start;
1362 /* Need to replay this display list with loopback,
1363 * unfortunately, otherwise this primitive won't be handled
1366 save->dangling_attr_ref = GL_TRUE;
1368 compile_vertex_list(ctx);
1371 copy_to_current(ctx);
1373 if (save->out_of_memory) {
1374 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1377 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1379 ctx->Driver.SaveNeedFlush = GL_FALSE;
1383 static void GLAPIENTRY
1384 _save_EvalCoord1f(GLfloat u)
1386 GET_CURRENT_CONTEXT(ctx);
1387 dlist_fallback(ctx);
1388 CALL_EvalCoord1f(ctx->Save, (u));
1391 static void GLAPIENTRY
1392 _save_EvalCoord1fv(const GLfloat * v)
1394 GET_CURRENT_CONTEXT(ctx);
1395 dlist_fallback(ctx);
1396 CALL_EvalCoord1fv(ctx->Save, (v));
1399 static void GLAPIENTRY
1400 _save_EvalCoord2f(GLfloat u, GLfloat v)
1402 GET_CURRENT_CONTEXT(ctx);
1403 dlist_fallback(ctx);
1404 CALL_EvalCoord2f(ctx->Save, (u, v));
1407 static void GLAPIENTRY
1408 _save_EvalCoord2fv(const GLfloat * v)
1410 GET_CURRENT_CONTEXT(ctx);
1411 dlist_fallback(ctx);
1412 CALL_EvalCoord2fv(ctx->Save, (v));
1415 static void GLAPIENTRY
1416 _save_EvalPoint1(GLint i)
1418 GET_CURRENT_CONTEXT(ctx);
1419 dlist_fallback(ctx);
1420 CALL_EvalPoint1(ctx->Save, (i));
1423 static void GLAPIENTRY
1424 _save_EvalPoint2(GLint i, GLint j)
1426 GET_CURRENT_CONTEXT(ctx);
1427 dlist_fallback(ctx);
1428 CALL_EvalPoint2(ctx->Save, (i, j));
1431 static void GLAPIENTRY
1432 _save_CallList(GLuint l)
1434 GET_CURRENT_CONTEXT(ctx);
1435 dlist_fallback(ctx);
1436 CALL_CallList(ctx->Save, (l));
1439 static void GLAPIENTRY
1440 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1442 GET_CURRENT_CONTEXT(ctx);
1443 dlist_fallback(ctx);
1444 CALL_CallLists(ctx->Save, (n, type, v));
1450 * Called when a glBegin is getting compiled into a display list.
1451 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1454 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1455 bool no_current_update)
1457 struct vbo_save_context *save = &vbo_context(ctx)->save;
1458 const GLuint i = save->prim_store->used++;
1460 ctx->Driver.CurrentSavePrimitive = mode;
1462 if (!save->prim_store || i >= save->prim_store->size) {
1463 save->prim_store = realloc_prim_store(save->prim_store, i * 2);
1465 save->prim_store->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1466 save->prim_store->prims[i].begin = 1;
1467 save->prim_store->prims[i].end = 0;
1468 save->prim_store->prims[i].start = get_vertex_count(save);
1469 save->prim_store->prims[i].count = 0;
1471 save->no_current_update = no_current_update;
1473 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1475 /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1476 ctx->Driver.SaveNeedFlush = GL_TRUE;
1480 static void GLAPIENTRY
1483 GET_CURRENT_CONTEXT(ctx);
1484 struct vbo_save_context *save = &vbo_context(ctx)->save;
1485 const GLint i = save->prim_store->used - 1;
1487 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1488 save->prim_store->prims[i].end = 1;
1489 save->prim_store->prims[i].count = (get_vertex_count(save) - save->prim_store->prims[i].start);
1491 /* Swap out this vertex format while outside begin/end. Any color,
1492 * etc. received between here and the next begin will be compiled
1495 if (save->out_of_memory) {
1496 _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1499 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1504 static void GLAPIENTRY
1505 _save_Begin(GLenum mode)
1507 GET_CURRENT_CONTEXT(ctx);
1509 _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1513 static void GLAPIENTRY
1514 _save_PrimitiveRestartNV(void)
1516 GET_CURRENT_CONTEXT(ctx);
1517 struct vbo_save_context *save = &vbo_context(ctx)->save;
1519 if (save->prim_store->used == 0) {
1520 /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1523 _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1524 "glPrimitiveRestartNV called outside glBegin/End");
1526 /* get current primitive mode */
1527 GLenum curPrim = save->prim_store->prims[save->prim_store->used - 1].mode;
1528 bool no_current_update = save->no_current_update;
1530 /* restart primitive */
1531 CALL_End(ctx->CurrentServerDispatch, ());
1532 vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1537 /* Unlike the functions above, these are to be hooked into the vtxfmt
1538 * maintained in ctx->ListState, active when the list is known or
1539 * suspected to be outside any begin/end primitive.
1540 * Note: OBE = Outside Begin/End
1542 static void GLAPIENTRY
1543 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1545 GET_CURRENT_CONTEXT(ctx);
1546 struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1548 vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1549 CALL_Vertex2f(dispatch, (x1, y1));
1550 CALL_Vertex2f(dispatch, (x2, y1));
1551 CALL_Vertex2f(dispatch, (x2, y2));
1552 CALL_Vertex2f(dispatch, (x1, y2));
1553 CALL_End(dispatch, ());
1557 static void GLAPIENTRY
1558 _save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1560 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1563 static void GLAPIENTRY
1564 _save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2)
1566 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1569 static void GLAPIENTRY
1570 _save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2)
1572 _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]);
1575 static void GLAPIENTRY
1576 _save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1578 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1581 static void GLAPIENTRY
1582 _save_OBE_Rectiv(const GLint *v1, const GLint *v2)
1584 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1587 static void GLAPIENTRY
1588 _save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1590 _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1593 static void GLAPIENTRY
1594 _save_OBE_Rectsv(const GLshort *v1, const GLshort *v2)
1596 _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1600 _ensure_draws_fits_in_storage(struct gl_context *ctx, int vertcount)
1602 struct vbo_save_context *save = &vbo_context(ctx)->save;
1604 if (save->vertex_size &&
1605 (save->vertex_store->used + vertcount * save->vertex_size) >=
1606 save->vertex_store->buffer_in_ram_size)
1607 realloc_storage(ctx, vertcount);
1611 static void GLAPIENTRY
1612 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1614 GET_CURRENT_CONTEXT(ctx);
1615 struct gl_vertex_array_object *vao = ctx->Array.VAO;
1616 struct vbo_save_context *save = &vbo_context(ctx)->save;
1619 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1620 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1624 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1628 if (save->out_of_memory)
1631 _ensure_draws_fits_in_storage(ctx, count);
1633 /* Make sure to process any VBO binding changes */
1634 _mesa_update_state(ctx);
1636 _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1638 vbo_save_NotifyBegin(ctx, mode, true);
1640 for (i = 0; i < count; i++)
1641 _mesa_array_element(ctx, start + i);
1642 CALL_End(ctx->CurrentServerDispatch, ());
1644 _mesa_vao_unmap_arrays(ctx, vao);
1648 static void GLAPIENTRY
1649 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1650 const GLsizei *count, GLsizei primcount)
1652 GET_CURRENT_CONTEXT(ctx);
1655 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1656 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1660 if (primcount < 0) {
1661 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1662 "glMultiDrawArrays(primcount<0)");
1666 unsigned vertcount = 0;
1667 for (i = 0; i < primcount; i++) {
1669 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1670 "glMultiDrawArrays(count[i]<0)");
1673 vertcount += count[i];
1676 _ensure_draws_fits_in_storage(ctx, vertcount);
1678 for (i = 0; i < primcount; i++) {
1680 _save_OBE_DrawArrays(mode, first[i], count[i]);
1687 array_element(struct gl_context *ctx,
1688 GLint basevertex, GLuint elt, unsigned index_size_shift)
1690 /* Section 10.3.5 Primitive Restart:
1692 * When one of the *BaseVertex drawing commands specified in section 10.5
1693 * is used, the primitive restart comparison occurs before the basevertex
1694 * offset is added to the array index.
1696 /* If PrimitiveRestart is enabled and the index is the RestartIndex
1697 * then we call PrimitiveRestartNV and return.
1699 if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1700 elt == ctx->Array._RestartIndex[index_size_shift]) {
1701 CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1705 _mesa_array_element(ctx, basevertex + elt);
1709 /* Could do better by copying the arrays and element list intact and
1710 * then emitting an indexed prim at runtime.
1712 static void GLAPIENTRY
1713 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1714 const GLvoid * indices, GLint basevertex)
1716 GET_CURRENT_CONTEXT(ctx);
1717 struct vbo_save_context *save = &vbo_context(ctx)->save;
1718 struct gl_vertex_array_object *vao = ctx->Array.VAO;
1719 struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1722 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1723 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1727 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1730 if (type != GL_UNSIGNED_BYTE &&
1731 type != GL_UNSIGNED_SHORT &&
1732 type != GL_UNSIGNED_INT) {
1733 _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1737 if (save->out_of_memory)
1740 _ensure_draws_fits_in_storage(ctx, count);
1742 /* Make sure to process any VBO binding changes */
1743 _mesa_update_state(ctx);
1745 _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1749 ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1751 vbo_save_NotifyBegin(ctx, mode, true);
1754 case GL_UNSIGNED_BYTE:
1755 for (i = 0; i < count; i++)
1756 array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1758 case GL_UNSIGNED_SHORT:
1759 for (i = 0; i < count; i++)
1760 array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1762 case GL_UNSIGNED_INT:
1763 for (i = 0; i < count; i++)
1764 array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1767 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1771 CALL_End(ctx->CurrentServerDispatch, ());
1773 _mesa_vao_unmap(ctx, vao);
1776 static void GLAPIENTRY
1777 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1778 const GLvoid * indices)
1780 _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1784 static void GLAPIENTRY
1785 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1786 GLsizei count, GLenum type,
1787 const GLvoid * indices)
1789 GET_CURRENT_CONTEXT(ctx);
1790 struct vbo_save_context *save = &vbo_context(ctx)->save;
1792 if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1793 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1797 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1798 "glDrawRangeElements(count<0)");
1801 if (type != GL_UNSIGNED_BYTE &&
1802 type != GL_UNSIGNED_SHORT &&
1803 type != GL_UNSIGNED_INT) {
1804 _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1808 _mesa_compile_error(ctx, GL_INVALID_VALUE,
1809 "glDrawRangeElements(end < start)");
1813 if (save->out_of_memory)
1816 _save_OBE_DrawElements(mode, count, type, indices);
1820 static void GLAPIENTRY
1821 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1822 const GLvoid * const *indices, GLsizei primcount)
1824 GET_CURRENT_CONTEXT(ctx);
1825 struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1829 for (i = 0; i < primcount; i++) {
1830 vertcount += count[i];
1832 _ensure_draws_fits_in_storage(ctx, vertcount);
1834 for (i = 0; i < primcount; i++) {
1836 CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1842 static void GLAPIENTRY
1843 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1845 const GLvoid * const *indices,
1847 const GLint *basevertex)
1849 GET_CURRENT_CONTEXT(ctx);
1850 struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1854 for (i = 0; i < primcount; i++) {
1855 vertcount += count[i];
1857 _ensure_draws_fits_in_storage(ctx, vertcount);
1859 for (i = 0; i < primcount; i++) {
1861 CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1870 vtxfmt_init(struct gl_context *ctx)
1872 struct vbo_save_context *save = &vbo_context(ctx)->save;
1873 GLvertexformat *vfmt = &save->vtxfmt;
1875 #define NAME_AE(x) _ae_##x
1876 #define NAME_CALLLIST(x) _save_##x
1877 #define NAME(x) _save_##x
1878 #define NAME_ES(x) _save_##x##ARB
1880 #include "vbo_init_tmp.h"
1885 * Initialize the dispatch table with the VBO functions for display
1889 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1890 struct _glapi_table *exec)
1892 SET_DrawArrays(exec, _save_OBE_DrawArrays);
1893 SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1894 SET_DrawElements(exec, _save_OBE_DrawElements);
1895 SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1896 SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1897 SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1898 SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1899 SET_Rectf(exec, _save_OBE_Rectf);
1900 SET_Rectd(exec, _save_OBE_Rectd);
1901 SET_Rectdv(exec, _save_OBE_Rectdv);
1902 SET_Rectfv(exec, _save_OBE_Rectfv);
1903 SET_Recti(exec, _save_OBE_Recti);
1904 SET_Rectiv(exec, _save_OBE_Rectiv);
1905 SET_Rects(exec, _save_OBE_Rects);
1906 SET_Rectsv(exec, _save_OBE_Rectsv);
1908 /* Note: other glDraw functins aren't compiled into display lists */
1914 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1916 struct vbo_save_context *save = &vbo_context(ctx)->save;
1918 /* Noop when we are actually active:
1920 if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1923 if (save->vertex_store->used || save->prim_store->used)
1924 compile_vertex_list(ctx);
1926 copy_to_current(ctx);
1928 ctx->Driver.SaveNeedFlush = GL_FALSE;
1933 * Called from glNewList when we're starting to compile a display list.
1936 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1938 struct vbo_save_context *save = &vbo_context(ctx)->save;
1943 if (!save->prim_store)
1944 save->prim_store = realloc_prim_store(NULL, 8);
1946 if (!save->vertex_store)
1947 save->vertex_store = realloc_vertex_store(NULL, save->vertex_size, 8);
1950 ctx->Driver.SaveNeedFlush = GL_FALSE;
1955 * Called from glEndList when we're finished compiling a display list.
1958 vbo_save_EndList(struct gl_context *ctx)
1960 struct vbo_save_context *save = &vbo_context(ctx)->save;
1962 /* EndList called inside a (saved) Begin/End pair?
1964 if (_mesa_inside_dlist_begin_end(ctx)) {
1965 if (save->prim_store->used > 0) {
1966 GLint i = save->prim_store->used - 1;
1967 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1968 save->prim_store->prims[i].end = 0;
1969 save->prim_store->prims[i].count = get_vertex_count(save) - save->prim_store->prims[i].start;
1972 /* Make sure this vertex list gets replayed by the "loopback"
1975 save->dangling_attr_ref = GL_TRUE;
1976 vbo_save_SaveFlushVertices(ctx);
1978 /* Swap out this vertex format while outside begin/end. Any color,
1979 * etc. received between here and the next begin will be compiled
1982 _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1985 assert(save->vertex_size == 0);
1989 * Called during context creation/init.
1992 current_init(struct gl_context *ctx)
1994 struct vbo_save_context *save = &vbo_context(ctx)->save;
1997 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_EDGEFLAG; i++) {
1998 const GLuint j = i - VBO_ATTRIB_POS;
1999 assert(j < VERT_ATTRIB_MAX);
2000 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
2001 save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
2004 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
2005 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
2006 assert(j < MAT_ATTRIB_MAX);
2007 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
2008 save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
2014 * Initialize the display list compiler. Called during context creation.
2017 vbo_save_api_init(struct vbo_save_context *save)
2019 struct gl_context *ctx = gl_context_from_vbo_save(save);