From 08aa0d9bf49ea74f84b19cd11a0f0ace7ce7211a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mathias=20Fr=C3=B6hlich?= Date: Sun, 25 Feb 2018 18:01:07 +0100 Subject: [PATCH] vbo: Implement vbo_loopback_vertex_list in terms of the VAO. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Use the information already present in the VAO to replay a display list node using immediate mode draw commands. Use a hand full of helper methods that will be useful for the next patches also. v2: Insert asserts, constify local variables. Reviewed-by: Brian Paul Signed-off-by: Mathias Fröhlich --- src/mesa/vbo/vbo_save.h | 55 ++++++++++++-- src/mesa/vbo/vbo_save_api.c | 42 +++++------ src/mesa/vbo/vbo_save_draw.c | 28 +++----- src/mesa/vbo/vbo_save_loopback.c | 119 ++++++++++++++++++++----------- 4 files changed, 151 insertions(+), 93 deletions(-) diff --git a/src/mesa/vbo/vbo_save.h b/src/mesa/vbo/vbo_save.h index 14ac831ffd7..44dc8c201f8 100644 --- a/src/mesa/vbo/vbo_save.h +++ b/src/mesa/vbo/vbo_save.h @@ -100,6 +100,52 @@ aligned_vertex_buffer_offset(const struct vbo_save_vertex_list *node) } +/** + * 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 @@ -178,13 +224,8 @@ void vbo_save_fallback(struct gl_context *ctx, GLboolean fallback); /* 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: */ diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c index b6fc7daa356..dc248934f7e 100644 --- a/src/mesa/vbo/vbo_save_api.c +++ b/src/mesa/vbo/vbo_save_api.c @@ -641,6 +641,22 @@ compile_vertex_list(struct gl_context *ctx) 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) { @@ -648,13 +664,8 @@ compile_vertex_list(struct gl_context *ctx) _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); } @@ -693,23 +704,6 @@ compile_vertex_list(struct gl_context *ctx) 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); diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c index 7cb67996689..0358ecd2f90 100644 --- a/src/mesa/vbo/vbo_save_draw.c +++ b/src/mesa/vbo/vbo_save_draw.c @@ -144,26 +144,14 @@ static void 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); } diff --git a/src/mesa/vbo/vbo_save_loopback.c b/src/mesa/vbo/vbo_save_loopback.c index 43d458a7c0a..f1a93d6e434 100644 --- a/src/mesa/vbo/vbo_save_loopback.c +++ b/src/mesa/vbo/vbo_save_loopback.c @@ -81,8 +81,8 @@ static attr_func vert_attrfunc[4] = { struct loopback_attr { - GLint index; - GLint sz; + enum vbo_attrib index; + GLuint offset; attr_func func; }; @@ -94,17 +94,15 @@ struct loopback_attr { */ 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", @@ -112,7 +110,7 @@ loopback_prim(struct gl_context *ctx, prim->begin ? "begin" : "..", prim->end ? "end" : "..", start, end, - vertex_size); + stride); if (prim->begin) { CALL_Begin(GET_DISPATCH(), (prim->mode)); @@ -121,20 +119,13 @@ loopback_prim(struct gl_context *ctx, 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) { @@ -167,36 +158,80 @@ loopback_weak_prim(struct gl_context *ctx, } +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); } } } -- 2.30.2