/** * Copy the active vertex's values to the ctx->Current fields. */ static void vbo_exec_copy_to_current( struct vbo_exec_context *exec ) { struct gl_context *ctx = exec->ctx; struct vbo_context *vbo = vbo_context(ctx); GLuint i; for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { if (exec->vtx.attrsz[i]) { /* Note: the exec->vtx.current[i] pointers point into the * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. */ GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; GLfloat tmp[4]; COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp, exec->vtx.attrsz[i], exec->vtx.attrptr[i], exec->vtx.attrtype[i]); if (exec->vtx.attrtype[i] != vbo->currval[i].Type || memcmp(current, tmp, sizeof(tmp)) != 0) { memcpy(current, tmp, sizeof(tmp)); /* Given that we explicitly state size here, there is no need * for the COPY_CLEAN above, could just copy 16 bytes and be * done. The only problem is when Mesa accesses ctx->Current * directly. */ vbo->currval[i].Size = exec->vtx.attrsz[i]; vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat); vbo->currval[i].Type = exec->vtx.attrtype[i]; vbo->currval[i].Integer = vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]); /* This triggers rather too much recalculation of Mesa state * that doesn't get used (eg light positions). */ if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && i <= VBO_ATTRIB_MAT_BACK_INDEXES) ctx->NewState |= _NEW_LIGHT; ctx->NewState |= _NEW_CURRENT_ATTRIB; } } } /* Colormaterial -- this kindof sucks. */ if (ctx->Light.ColorMaterialEnabled && exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) { _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); } }
static void _save_copy_to_current(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; GLuint i; for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { if (save->attrsz[i]) { save->currentsz[i][0] = save->attrsz[i]; COPY_CLEAN_4V_TYPE_AS_FLOAT(save->current[i], save->attrsz[i], save->attrptr[i], save->attrtype[i]); } } }
/* Flush existing data, set new attrib size, replay copied vertices. */ static void _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) { struct vbo_save_context *save = &vbo_context(ctx)->save; GLuint oldsz; GLuint i; GLfloat *tmp; /* Store the current run of vertices, and emit a GL_END. Emit a * BEGIN in the new buffer. */ if (save->vert_count) _save_wrap_buffers(ctx); else assert(save->copied.nr == 0); /* Do a COPY_TO_CURRENT to ensure back-copying works for the case * when the attribute already exists in the vertex and is having * its size increased. */ _save_copy_to_current(ctx); /* Fix up sizes: */ oldsz = save->attrsz[attr]; save->attrsz[attr] = newsz; save->vertex_size += newsz - oldsz; save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / save->vertex_size); save->vert_count = 0; /* Recalculate all the attrptr[] values: */ for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) { if (save->attrsz[i]) { save->attrptr[i] = tmp; tmp += save->attrsz[i]; } else { save->attrptr[i] = NULL; /* will not be dereferenced. */ } } /* Copy from current to repopulate the vertex with correct values. */ _save_copy_from_current(ctx); /* Replay stored vertices to translate them to new format here. * * If there are copied vertices and the new (upgraded) attribute * has not been defined before, this list is somewhat degenerate, * and will need fixup at runtime. */ if (save->copied.nr) { GLfloat *data = save->copied.buffer; GLfloat *dest = save->buffer; GLuint j; /* Need to note this and fix up at runtime (or loopback): */ if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) { assert(oldsz == 0); save->dangling_attr_ref = GL_TRUE; } for (i = 0; i < save->copied.nr; i++) { for (j = 0; j < VBO_ATTRIB_MAX; j++) { if (save->attrsz[j]) { if (j == attr) { if (oldsz) { COPY_CLEAN_4V_TYPE_AS_FLOAT(dest, oldsz, data, save->attrtype[j]); data += oldsz; dest += newsz; } else { COPY_SZ_4V(dest, newsz, save->current[attr]); dest += newsz; } } else { GLint sz = save->attrsz[j]; COPY_SZ_4V(dest, sz, data); data += sz; dest += sz; } } } } save->buffer_ptr = dest; save->vert_count += save->copied.nr; } }
/** * Flush existing data, set new attrib size, replay copied vertices. * This is called when we transition from a small vertex attribute size * to a larger one. Ex: glTexCoord2f -> glTexCoord4f. * We need to go back over the previous 2-component texcoords and insert * zero and one values. */ static void vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec, GLuint attr, GLuint newSize ) { struct gl_context *ctx = exec->ctx; struct vbo_context *vbo = vbo_context(ctx); const GLint lastcount = exec->vtx.vert_count; GLfloat *old_attrptr[VBO_ATTRIB_MAX]; const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */ const GLuint oldSize = exec->vtx.attrsz[attr]; GLuint i; /* Run pipeline on current vertices, copy wrapped vertices * to exec->vtx.copied. */ vbo_exec_wrap_buffers( exec ); if (unlikely(exec->vtx.copied.nr)) { /* We're in the middle of a primitive, keep the old vertex * format around to be able to translate the copied vertices to * the new format. */ memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr)); } if (unlikely(oldSize)) { /* Do a COPY_TO_CURRENT to ensure back-copying works for the * case when the attribute already exists in the vertex and is * having its size increased. */ vbo_exec_copy_to_current( exec ); } /* Heuristic: Attempt to isolate attributes received outside * begin/end so that they don't bloat the vertices. */ if (!_mesa_inside_begin_end(ctx) && !oldSize && lastcount > 8 && exec->vtx.vertex_size) { vbo_exec_copy_to_current( exec ); reset_attrfv( exec ); } /* Fix up sizes: */ exec->vtx.attrsz[attr] = newSize; exec->vtx.vertex_size += newSize - oldSize; exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) / (exec->vtx.vertex_size * sizeof(GLfloat))); exec->vtx.vert_count = 0; exec->vtx.buffer_ptr = exec->vtx.buffer_map; if (unlikely(oldSize)) { /* Size changed, recalculate all the attrptr[] values */ GLfloat *tmp = exec->vtx.vertex; for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { if (exec->vtx.attrsz[i]) { exec->vtx.attrptr[i] = tmp; tmp += exec->vtx.attrsz[i]; } else exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */ } /* Copy from current to repopulate the vertex with correct * values. */ vbo_exec_copy_from_current( exec ); } else { /* Just have to append the new attribute at the end */ exec->vtx.attrptr[attr] = exec->vtx.vertex + exec->vtx.vertex_size - newSize; } /* Replay stored vertices to translate them * to new format here. * * -- No need to replay - just copy piecewise */ if (unlikely(exec->vtx.copied.nr)) { GLfloat *data = exec->vtx.copied.buffer; GLfloat *dest = exec->vtx.buffer_ptr; GLuint j; assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map); for (i = 0 ; i < exec->vtx.copied.nr ; i++) { for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) { GLuint sz = exec->vtx.attrsz[j]; if (sz) { GLint old_offset = old_attrptr[j] - exec->vtx.vertex; GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex; if (j == attr) { if (oldSize) { GLfloat tmp[4]; COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp, oldSize, data + old_offset, exec->vtx.attrtype[j]); COPY_SZ_4V(dest + new_offset, newSize, tmp); } else { GLfloat *current = (GLfloat *)vbo->currval[j].Ptr; COPY_SZ_4V(dest + new_offset, sz, current); } } else { COPY_SZ_4V(dest + new_offset, sz, data + old_offset); } } } data += old_vtx_size; dest += exec->vtx.vertex_size; } exec->vtx.buffer_ptr = dest; exec->vtx.vert_count += exec->vtx.copied.nr; exec->vtx.copied.nr = 0; } }
/** * After playback, copy everything but the position from the * last vertex to the saved state */ static void _playback_copy_to_current(struct gl_context *ctx, const struct vbo_save_vertex_list *node) { struct vbo_context *vbo = vbo_context(ctx); GLfloat vertex[VBO_ATTRIB_MAX * 4]; GLfloat *data; GLuint i, offset; if (node->current_size == 0) return; if (node->current_data) { data = node->current_data; } else { data = vertex; if (node->count) offset = (node->buffer_offset + (node->count-1) * node->vertex_size * sizeof(GLfloat)); else offset = node->buffer_offset; ctx->Driver.GetBufferSubData( ctx, offset, node->vertex_size * sizeof(GLfloat), data, node->vertex_store->bufferobj ); data += node->attrsz[0]; /* skip vertex position */ } for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { if (node->attrsz[i]) { GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; GLfloat tmp[4]; COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp, node->attrsz[i], data, node->attrtype[i]); if (node->attrtype[i] != vbo->currval[i].Type || memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) { memcpy(current, tmp, 4 * sizeof(GLfloat)); vbo->currval[i].Size = node->attrsz[i]; vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat); vbo->currval[i].Type = node->attrtype[i]; vbo->currval[i].Integer = vbo_attrtype_to_integer_flag(node->attrtype[i]); if (i >= VBO_ATTRIB_FIRST_MATERIAL && i <= VBO_ATTRIB_LAST_MATERIAL) ctx->NewState |= _NEW_LIGHT; ctx->NewState |= _NEW_CURRENT_ATTRIB; } data += node->attrsz[i]; } } /* Colormaterial -- this kindof sucks. */ if (ctx->Light.ColorMaterialEnabled) { _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); } /* CurrentExecPrimitive */ if (node->prim_count) { const struct _mesa_prim *prim = &node->prim[node->prim_count - 1]; if (prim->end) ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; else ctx->Driver.CurrentExecPrimitive = prim->mode; } }