void vbo_save_EndList(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; /* EndList called inside a (saved) Begin/End pair? */ if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) { if (save->prim_count > 0) { GLint i = save->prim_count - 1; ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; save->prim[i].end = 0; save->prim[i].count = (save->vert_count - save->prim[i].start); } /* Make sure this vertex list gets replayed by the "loopback" * mechanism: */ save->dangling_attr_ref = 1; vbo_save_SaveFlushVertices(ctx); /* Swap out this vertex format while outside begin/end. Any color, * etc. received between here and the next begin will be compiled * as opcodes. */ _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); } vbo_save_unmap_vertex_store(ctx, save->vertex_store); assert(save->vertex_size == 0); }
/** * Execute the buffer and save copied verts. * This is called from the display list code when executing * a drawing command. */ void vbo_save_playback_vertex_list(struct gl_context *ctx, void *data) { const struct vbo_save_vertex_list *node = (const struct vbo_save_vertex_list *) data; struct vbo_save_context *save = &vbo_context(ctx)->save; GLboolean remap_vertex_store = GL_FALSE; if (save->vertex_store && save->vertex_store->buffer) { /* The vertex store is currently mapped but we're about to replay * a display list. This can happen when a nested display list is * being build with GL_COMPILE_AND_EXECUTE. * We never want to have mapped vertex buffers when we're drawing. * Unmap the vertex store, execute the list, then remap the vertex * store. */ vbo_save_unmap_vertex_store(ctx, save->vertex_store); remap_vertex_store = GL_TRUE; } FLUSH_CURRENT(ctx, 0); if (node->prim_count > 0) { if (_mesa_inside_begin_end(ctx) && node->prim[0].begin) { /* Error: we're about to begin a new primitive but we're already * inside a glBegin/End pair. */ _mesa_error(ctx, GL_INVALID_OPERATION, "draw operation inside glBegin/End"); goto end; } else if (save->replay_flags) { /* Various degenerate cases: translate into immediate mode * calls rather than trying to execute in place. */ vbo_save_loopback_vertex_list( ctx, node ); goto end; } if (ctx->NewState) _mesa_update_state( ctx ); /* XXX also need to check if shader enabled, but invalid */ if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) || (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin (invalid vertex/fragment program)"); return; } vbo_bind_vertex_list( ctx, node ); vbo_draw_method(vbo_context(ctx), DRAW_DISPLAY_LIST); /* Again... */ if (ctx->NewState) _mesa_update_state( ctx ); if (node->count > 0) { vbo_context(ctx)->draw_prims(ctx, node->prim, node->prim_count, NULL, GL_TRUE, 0, /* Node is a VBO, so this is ok */ node->count - 1, NULL, 0, NULL); } } /* Copy to current? */ _playback_copy_to_current( ctx, node ); end: if (remap_vertex_store) { save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); } }
/** * 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)); 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); /* 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); }