}
+/**
+ * Return the stride in bytes of the display list node.
+ */
+static inline GLsizei
+_vbo_save_get_stride(const struct vbo_save_vertex_list *node)
+{
+ return node->VAO[0]->BufferBinding[0].Stride;
+}
+
+
+/**
+ * Return the first referenced vertex index in the display list node.
+ */
+static inline GLuint
+_vbo_save_get_min_index(const struct vbo_save_vertex_list *node)
+{
+ assert(node->prim_count > 0);
+ return node->prims[0].start;
+}
+
+
+/**
+ * Return the last referenced vertex index in the display list node.
+ */
+static inline GLuint
+_vbo_save_get_max_index(const struct vbo_save_vertex_list *node)
+{
+ assert(node->prim_count > 0);
+ const struct _mesa_prim *last_prim = &node->prims[node->prim_count - 1];
+ return last_prim->start + last_prim->count - 1;
+}
+
+
+/**
+ * Return the vertex count in the display list node.
+ */
+static inline GLuint
+_vbo_save_get_vertex_count(const struct vbo_save_vertex_list *node)
+{
+ assert(node->prim_count > 0);
+ const struct _mesa_prim *first_prim = &node->prims[0];
+ const struct _mesa_prim *last_prim = &node->prims[node->prim_count - 1];
+ return last_prim->start - first_prim->start + last_prim->count;
+}
+
+
/* These buffers should be a reasonable size to support upload to
* hardware. Current vbo implementation will re-upload on any
* changes, so don't make too big or apps which dynamically create
/* save_loopback.c:
*/
-void vbo_loopback_vertex_list(struct gl_context *ctx,
- const GLfloat *buffer,
- const GLubyte *attrsz,
- const struct _mesa_prim *prim,
- GLuint prim_count,
- GLuint wrap_count,
- GLuint vertex_size);
+void _vbo_loopback_vertex_list(struct gl_context *ctx,
+ const struct vbo_save_vertex_list* node);
/* Callbacks:
*/
merge_prims(node->prims, &node->prim_count);
+ /* Correct the primitive starts, we can only do this here as copy_vertices
+ * and convert_line_loop_to_strip above consume the uncorrected starts.
+ * On the other hand the _vbo_loopback_vertex_list call below needs the
+ * primitves to be corrected already.
+ */
+ if (aligned_vertex_buffer_offset(node)) {
+ const unsigned start_offset =
+ node->buffer_offset / (node->vertex_size * sizeof(GLfloat));
+ for (unsigned i = 0; i < node->prim_count; i++) {
+ node->prims[i].start += start_offset;
+ }
+ node->start_vertex = start_offset;
+ } else {
+ node->start_vertex = 0;
+ }
+
/* Deal with GL_COMPILE_AND_EXECUTE:
*/
if (ctx->ExecuteFlag) {
_glapi_set_dispatch(ctx->Exec);
- const GLfloat *buffer = (const GLfloat *)
- ((const char *) save->vertex_store->buffer_map +
- node->buffer_offset);
-
- vbo_loopback_vertex_list(ctx, buffer,
- node->attrsz, node->prims, node->prim_count,
- node->wrap_count, node->vertex_size);
+ /* Note that the range of referenced vertices must be mapped already */
+ _vbo_loopback_vertex_list(ctx, node);
_glapi_set_dispatch(dispatch);
}
save->prim_store = alloc_prim_store();
}
- /*
- * If the vertex buffer offset is a multiple of the vertex size,
- * we can use the _mesa_prim::start value to indicate where the
- * vertices starts, instead of the buffer offset. Also see the
- * bind_vertex_list() function.
- */
- if (aligned_vertex_buffer_offset(node)) {
- const unsigned start_offset =
- node->buffer_offset / (node->vertex_size * sizeof(GLfloat));
- for (unsigned i = 0; i < save->prim_count; i++) {
- save->prims[i].start += start_offset;
- }
- node->start_vertex = start_offset;
- } else {
- node->start_vertex = 0;
- }
-
/* Reset our structures for the next run of vertices:
*/
reset_counters(ctx);
loopback_vertex_list(struct gl_context *ctx,
const struct vbo_save_vertex_list *list)
{
- const char *buffer =
- ctx->Driver.MapBufferRange(ctx, 0,
- list->vertex_store->bufferobj->Size,
- GL_MAP_READ_BIT, /* ? */
- list->vertex_store->bufferobj,
- MAP_INTERNAL);
-
- unsigned buffer_offset =
- aligned_vertex_buffer_offset(list) ? 0 : list->buffer_offset;
-
- vbo_loopback_vertex_list(ctx,
- (const GLfloat *) (buffer + buffer_offset),
- list->attrsz,
- list->prims,
- list->prim_count,
- list->wrap_count,
- list->vertex_size);
-
- ctx->Driver.UnmapBuffer(ctx, list->vertex_store->bufferobj,
- MAP_INTERNAL);
+ struct gl_buffer_object *bo = list->VAO[0]->BufferBinding[0].BufferObj;
+ ctx->Driver.MapBufferRange(ctx, 0, bo->Size, GL_MAP_READ_BIT, /* ? */
+ bo, MAP_INTERNAL);
+
+ /* Note that the range of referenced vertices must be mapped already */
+ _vbo_loopback_vertex_list(ctx, list);
+
+ ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL);
}
struct loopback_attr {
- GLint index;
- GLint sz;
+ enum vbo_attrib index;
+ GLuint offset;
attr_func func;
};
*/
static void
loopback_prim(struct gl_context *ctx,
- const GLfloat *buffer,
+ const GLubyte *buffer,
const struct _mesa_prim *prim,
GLuint wrap_count,
- GLuint vertex_size,
+ GLuint stride,
const struct loopback_attr *la, GLuint nr)
{
- GLint start = prim->start;
- GLint end = start + prim->count;
- const GLfloat *data;
- GLint j;
- GLuint k;
+ GLuint start = prim->start;
+ const GLuint end = start + prim->count;
+ const GLubyte *data;
if (0)
printf("loopback prim %s(%s,%s) verts %d..%d vsize %d\n",
prim->begin ? "begin" : "..",
prim->end ? "end" : "..",
start, end,
- vertex_size);
+ stride);
if (prim->begin) {
CALL_Begin(GET_DISPATCH(), (prim->mode));
start += wrap_count;
}
- data = buffer + start * vertex_size;
+ data = buffer + start * stride;
- for (j = start; j < end; j++) {
- const GLfloat *tmp = data + la[0].sz;
+ for (GLuint j = start; j < end; j++) {
+ for (GLuint k = 0; k < nr; k++)
+ la[k].func(ctx, la[k].index, (const GLfloat *)(data + la[k].offset));
- for (k = 1; k < nr; k++) {
- la[k].func(ctx, la[k].index, tmp);
- tmp += la[k].sz;
- }
-
- /* Fire the vertex
- */
- la[0].func(ctx, VBO_ATTRIB_POS, data);
- data = tmp;
+ data += stride;
}
if (prim->end) {
}
+static inline void
+append_attr(GLuint *nr, struct loopback_attr la[], int i, int shift,
+ const struct gl_vertex_array_object *vao)
+{
+ la[*nr].index = shift + i;
+ la[*nr].offset = vao->VertexAttrib[i].RelativeOffset;
+ la[*nr].func = vert_attrfunc[vao->VertexAttrib[i].Size - 1];
+ (*nr)++;
+}
+
+
void
-vbo_loopback_vertex_list(struct gl_context *ctx,
- const GLfloat *buffer,
- const GLubyte *attrsz,
- const struct _mesa_prim *prim,
- GLuint prim_count,
- GLuint wrap_count,
- GLuint vertex_size)
+_vbo_loopback_vertex_list(struct gl_context *ctx,
+ const struct vbo_save_vertex_list* node)
{
struct loopback_attr la[VBO_ATTRIB_MAX];
- GLuint i, nr = 0;
+ GLuint nr = 0;
/* All Legacy, NV, ARB and Material attributes are routed through
* the NV attributes entrypoints:
*/
- for (i = 0; i < VBO_ATTRIB_MAX; i++) {
- if (attrsz[i]) {
- la[nr].index = i;
- la[nr].sz = attrsz[i];
- la[nr].func = vert_attrfunc[attrsz[i]-1];
- nr++;
- }
+ const struct gl_vertex_array_object *vao = node->VAO[VP_MODE_FF];
+ GLbitfield mask = vao->_Enabled & VERT_BIT_MAT_ALL;
+ while (mask) {
+ const int i = u_bit_scan(&mask);
+ append_attr(&nr, la, i, VBO_MATERIAL_SHIFT, vao);
+ }
+
+ vao = node->VAO[VP_MODE_SHADER];
+ mask = vao->_Enabled & ~(VERT_BIT_POS | VERT_BIT_GENERIC0);
+ while (mask) {
+ const int i = u_bit_scan(&mask);
+ append_attr(&nr, la, i, 0, vao);
+ }
+
+ /* The last in the list should be the vertex provoking attribute */
+ if (vao->_Enabled & VERT_BIT_GENERIC0) {
+ append_attr(&nr, la, VERT_ATTRIB_GENERIC0, 0, vao);
+ } else if (vao->_Enabled & VERT_BIT_POS) {
+ append_attr(&nr, la, VERT_ATTRIB_POS, 0, vao);
+ }
+
+ const GLuint wrap_count = node->wrap_count;
+ const GLuint stride = _vbo_save_get_stride(node);
+ const GLubyte *buffer = NULL;
+ if (0 < nr) {
+ /* Compute the minimal offset into the vertex buffer object */
+ GLuint offset = ~0u;
+ for (GLuint i = 0; i < nr; ++i)
+ offset = MIN2(offset, la[i].offset);
+ for (GLuint i = 0; i < nr; ++i)
+ la[i].offset -= offset;
+
+ /* Get the mapped base pointer, assert sufficient mapping */
+ struct gl_buffer_object *bufferobj = vao->BufferBinding[0].BufferObj;
+ assert(bufferobj && bufferobj->Mappings[MAP_INTERNAL].Pointer);
+ buffer = bufferobj->Mappings[MAP_INTERNAL].Pointer;
+ assert(bufferobj->Mappings[MAP_INTERNAL].Offset
+ <= vao->BufferBinding[0].Offset + offset
+ + stride*(_vbo_save_get_min_index(node) + wrap_count));
+ buffer += vao->BufferBinding[0].Offset + offset
+ - bufferobj->Mappings[MAP_INTERNAL].Offset;
+ assert(stride*(_vbo_save_get_vertex_count(node) - wrap_count)
+ <= bufferobj->Mappings[MAP_INTERNAL].Length);
}
- for (i = 0; i < prim_count; i++) {
- if ((prim[i].mode & VBO_SAVE_PRIM_WEAK) &&
- _mesa_inside_begin_end(ctx)) {
- loopback_weak_prim(ctx, &prim[i]);
+ /* Replay the primitives */
+ const struct _mesa_prim *prims = node->prims;
+ const GLuint prim_count = node->prim_count;
+ for (GLuint i = 0; i < prim_count; i++) {
+ if ((prims[i].mode & VBO_SAVE_PRIM_WEAK) && _mesa_inside_begin_end(ctx)) {
+ loopback_weak_prim(ctx, &prims[i]);
} else {
- loopback_prim(ctx, buffer, &prim[i], wrap_count, vertex_size, la, nr);
+ loopback_prim(ctx, buffer, &prims[i], wrap_count, stride, la, nr);
}
}
}