/** * For a list of prims, try merging prims that can just be extensions of the * previous prim. */ static void merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list, GLuint *prim_count) { GLuint i; struct _mesa_prim *prev_prim = prim_list; for (i = 1; i < *prim_count; i++) { struct _mesa_prim *this_prim = prim_list + i; vbo_try_prim_conversion(this_prim); if (vbo_can_merge_prims(prev_prim, this_prim)) { /* We've found a prim that just extend the previous one. Tack it * onto the previous one, and let this primitive struct get dropped. */ vbo_merge_prims(prev_prim, this_prim); continue; } /* If any previous primitives have been dropped, then we need to copy * this later one into the next available slot. */ prev_prim++; if (prev_prim != this_prim) *prev_prim = *this_prim; } *prim_count = prev_prim - prim_list + 1; }
/** * Try to merge / concatenate the two most recent VBO primitives. */ static void try_vbo_merge(struct vbo_exec_context *exec) { struct _mesa_prim *cur = &exec->vtx.prim[exec->vtx.prim_count - 1]; assert(exec->vtx.prim_count >= 1); vbo_try_prim_conversion(cur); if (exec->vtx.prim_count >= 2) { struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2]; assert(prev == cur - 1); if (vbo_can_merge_prims(prev, cur)) { assert(cur->begin); assert(cur->end); assert(prev->begin); assert(prev->end); vbo_merge_prims(prev, cur); exec->vtx.prim_count--; /* drop the last primitive */ } } }
/** * Insert the active immediate struct onto the display list currently * being built. */ static void _save_compile_vertex_list(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; struct vbo_save_vertex_list *node; /* Allocate space for this structure in the display list currently * being compiled. */ node = (struct vbo_save_vertex_list *) _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node)); if (!node) return; /* Duplicate our template, increment refcounts to the storage structs: */ memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype)); node->vertex_size = save->vertex_size; node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); node->count = save->vert_count; node->wrap_count = save->copied.nr; node->dangling_attr_ref = save->dangling_attr_ref; node->prim = save->prim; node->prim_count = save->prim_count; node->vertex_store = save->vertex_store; node->prim_store = save->prim_store; node->vertex_store->refcount++; node->prim_store->refcount++; if (node->prim[0].no_current_update) { node->current_size = 0; node->current_data = NULL; } else { node->current_size = node->vertex_size - node->attrsz[0]; node->current_data = NULL; if (node->current_size) { /* If the malloc fails, we just pull the data out of the VBO * later instead. */ node->current_data = malloc(node->current_size * sizeof(GLfloat)); if (node->current_data) { const char *buffer = (const char *) save->vertex_store->buffer; unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat); unsigned vertex_offset = 0; if (node->count) vertex_offset = (node->count - 1) * node->vertex_size * sizeof(GLfloat); memcpy(node->current_data, buffer + node->buffer_offset + vertex_offset + attr_offset, node->current_size * sizeof(GLfloat)); } } } assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0); if (save->dangling_attr_ref) ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS; save->vertex_store->used += save->vertex_size * node->count; save->prim_store->used += node->prim_count; /* Copy duplicated vertices */ save->copied.nr = _save_copy_vertices(ctx, node, save->buffer); vbo_merge_prims(ctx, node->prim, &node->prim_count); /* Deal with GL_COMPILE_AND_EXECUTE: */ if (ctx->ExecuteFlag) { struct _glapi_table *dispatch = GET_DISPATCH(); _glapi_set_dispatch(ctx->Exec); vbo_loopback_vertex_list(ctx, (const GLfloat *) ((const char *) save-> vertex_store->buffer + node->buffer_offset), node->attrsz, node->prim, node->prim_count, node->wrap_count, node->vertex_size); _glapi_set_dispatch(dispatch); } /* Decide whether the storage structs are full, or can be used for * the next vertex lists as well. */ if (save->vertex_store->used > VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) { /* Unmap old store: */ vbo_save_unmap_vertex_store(ctx, save->vertex_store); /* Release old reference: */ save->vertex_store->refcount--; assert(save->vertex_store->refcount != 0); save->vertex_store = NULL; /* Allocate and map new store: */ save->vertex_store = alloc_vertex_store(ctx); save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); save->out_of_memory = save->buffer_ptr == NULL; } if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { save->prim_store->refcount--; assert(save->prim_store->refcount != 0); save->prim_store = alloc_prim_store(ctx); } /* Reset our structures for the next run of vertices: */ _save_reset_counters(ctx); }