vbo: Implement vbo_loopback_vertex_list in terms of the VAO.
authorMathias Fröhlich <mathias.froehlich@web.de>
Sun, 25 Feb 2018 17:01:07 +0000 (18:01 +0100)
committerMathias Fröhlich <mathias.froehlich@web.de>
Thu, 1 Mar 2018 03:06:23 +0000 (04:06 +0100)
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 <brianp@vmware.com>
Signed-off-by: Mathias Fröhlich <Mathias.Froehlich@web.de>
src/mesa/vbo/vbo_save.h
src/mesa/vbo/vbo_save_api.c
src/mesa/vbo/vbo_save_draw.c
src/mesa/vbo/vbo_save_loopback.c

index 14ac831ffd7ba5f21b842ee022ba1dfaa18d3b58..44dc8c201f865f8d25b31d35360e5452641d7534 100644 (file)
@@ -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:
  */
index b6fc7daa3567f8c605aa82fd16775342a6e0e047..dc248934f7e63ca61c2ca0518ac6a772eb7dafbb 100644 (file)
@@ -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);
index 7cb679966892853341e6ce6725735b33d3f70851..0358ecd2f90b0a7a142eafdf09e3407710996093 100644 (file)
@@ -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);
 }
 
 
index 43d458a7c0a515fe3eeac07044731fe49fb3930d..f1a93d6e434841e6e585c5f45de97cf9059a122f 100644 (file)
@@ -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);
       }
    }
 }