Do more of the vertex array setup at display list compilation time
via the compile_vertex_list() function.

Then, at draw time, just do final vertex array setup dependent on
whether we're using fixed function or a vertex shader.

This can help apps which use a lot of short display list drawing.
---
 src/mesa/vbo/vbo_save.h      |  11 ++-
 src/mesa/vbo/vbo_save_api.c  |  93 ++++++++++++++++++++++---
 src/mesa/vbo/vbo_save_draw.c | 157 ++++++++++++++-----------------------------
 3 files changed, 147 insertions(+), 114 deletions(-)

diff --git a/src/mesa/vbo/vbo_save.h b/src/mesa/vbo/vbo_save.h
index 51ea9cc..62a9d54 100644
--- a/src/mesa/vbo/vbo_save.h
+++ b/src/mesa/vbo/vbo_save.h
@@ -85,6 +85,16 @@ struct vbo_save_vertex_list {
 
    struct vbo_save_vertex_store *vertex_store;
    struct vbo_save_primitive_store *prim_store;
+
+   /* Array [bitcount(enabled)] of gl_vertex_array objects describing
+    * the vertex data contained in this vbo_save_vertex_list.
+    */
+   struct gl_vertex_array *arrays;
+
+   /* The arrays to actually use at draw time.  Some will point at the
+    * 'arrays' field above.  The rest will point at the vbo->currval arrays
+    */
+   const struct gl_vertex_array *inputs[VBO_ATTRIB_MAX];
 };
 
 
@@ -140,7 +150,6 @@ struct vbo_save_context {
    GLvertexformat vtxfmt;
    GLvertexformat vtxfmt_noop;  /**< Used if out_of_memory is true */
    struct gl_vertex_array arrays[VBO_ATTRIB_MAX];
-   const struct gl_vertex_array *inputs[VBO_ATTRIB_MAX];
 
    GLbitfield64 enabled; /**< mask of enabled vbo arrays. */
    GLubyte attrsz[VBO_ATTRIB_MAX];  /**< 1, 2, 3 or 4 */
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
index 11c40a2..e394d88 100644
--- a/src/mesa/vbo/vbo_save_api.c
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -412,8 +412,80 @@ convert_line_loop_to_strip(struct vbo_save_context *save,
 
 
 /**
- * Insert the active immediate struct onto the display list currently
- * being built.
+ * Prepare the vertex arrays which will be used for drawing the primitives
+ * in the given vertex list.  By doing it here, we can avoid doing this
+ * work at display list execution/draw time.
+ */
+static void
+setup_vertex_arrays(struct gl_context *ctx,
+                    struct vbo_save_vertex_list *node)
+{
+   struct vbo_context *vbo = vbo_context(ctx);
+   unsigned buffer_offset = node->buffer_offset;
+   unsigned attr;
+   const unsigned num_arrays = _mesa_bitcount_64(node->enabled);
+   unsigned array_count;
+
+   if (aligned_vertex_buffer_offset(node)) {
+      /* The vertex size is an exact multiple of the buffer offset.
+       * This means that we can use zero-based vertex attribute pointers
+       * and specify the start of the primitive with the _mesa_prim::start
+       * field.  This results in issuing several draw calls with identical
+       * vertex attribute information.  This can result in fewer state
+       * changes in drivers.  In particular, the Gallium CSO module will
+       * filter out redundant vertex buffer changes.
+       */
+      buffer_offset = 0;
+   }
+
+   assert(!node->arrays);
+   node->arrays = calloc(num_arrays, sizeof(struct gl_vertex_array));
+   if (!node->arrays) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                  "compiling vertex data into display list");
+      /* just turn off all arrays */
+      node->enabled = 0;
+      return;
+   }
+
+   array_count = 0;
+   for (attr = 0; attr < VBO_ATTRIB_MAX; attr++) {
+      if (node->attrsz[attr]) {
+         /* this vertex array points at actual per-vertex data in a VB */
+         struct gl_vertex_array *array = &node->arrays[array_count];
+
+         array->Ptr = (const GLubyte *) NULL + buffer_offset;
+         array->Size = node->attrsz[attr];
+         array->StrideB = node->vertex_size * sizeof(GLfloat);
+         array->Type = node->attrtype[attr];
+         array->Integer = vbo_attrtype_to_integer_flag(node->attrtype[attr]);
+         array->Format = GL_RGBA;
+         array->_ElementSize = array->Size * sizeof(GLfloat);
+         _mesa_reference_buffer_object(ctx,
+                                       &array->BufferObj,
+                                       node->vertex_store->bufferobj);
+
+         node->inputs[attr] = array;
+
+         buffer_offset += node->attrsz[attr] * sizeof(GLfloat);
+
+         array_count++;
+      }
+      else {
+         /* this vertex array points at currval/default values */
+         node->inputs[attr] = &vbo->currval[attr];
+      }
+   }
+
+   assert(array_count == num_arrays);
+}
+
+
+/**
+ * Create a new vbo_save_vertex_list object and fill it with the vertices
+ * and primitives accumulated in the vbo_save_context.
+ * The new vbo_save_vertex_list is allocated from display list memory
+ * and will automatically be inserted into the current display list.
  */
 static void
 compile_vertex_list(struct gl_context *ctx)
@@ -430,6 +502,8 @@ compile_vertex_list(struct gl_context *ctx)
    if (!node)
       return;
 
+   memset(node, 0, sizeof(*node));
+
    /* Make sure the pointer is aligned to the size of a pointer */
    assert((GLintptr) node % sizeof(void *) == 0);
 
@@ -568,6 +642,8 @@ compile_vertex_list(struct gl_context *ctx)
       node->start_vertex = 0;
    }
 
+   setup_vertex_arrays(ctx, node);
+
    /* Reset our structures for the next run of vertices:
     */
    reset_counters(ctx);
@@ -1679,7 +1755,6 @@ static void
 vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
 {
    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
-   (void) ctx;
 
    if (--node->vertex_store->refcount == 0)
       free_vertex_store(ctx, node->vertex_store);
@@ -1688,6 +1763,13 @@ vbo_destroy_vertex_list(struct gl_context *ctx, void 
*data)
       free(node->prim_store);
 
    free(node->current_data);
+
+   const unsigned num_arrays = _mesa_bitcount_64(node->enabled);
+   for (unsigned i = 0; i < num_arrays; i++) {
+      _mesa_reference_buffer_object(ctx, &(node->arrays[i].BufferObj), NULL);
+   }
+   free(node->arrays);
+
    node->current_data = NULL;
 }
 
@@ -1752,7 +1834,6 @@ void
 vbo_save_api_init(struct vbo_save_context *save)
 {
    struct gl_context *ctx = save->ctx;
-   GLuint i;
 
    save->opcode_vertex_list =
       _mesa_dlist_alloc_opcode(ctx,
@@ -1764,8 +1845,4 @@ vbo_save_api_init(struct vbo_save_context *save)
    vtxfmt_init(ctx);
    current_init(ctx);
    _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
-
-   /* These will actually get set again when binding/drawing */
-   for (i = 0; i < VBO_ATTRIB_MAX; i++)
-      save->inputs[i] = &save->arrays[i];
 }
diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c
index 5f5dcbe..1ef74d7 100644
--- a/src/mesa/vbo/vbo_save_draw.c
+++ b/src/mesa/vbo/vbo_save_draw.c
@@ -125,69 +125,63 @@ playback_copy_to_current(struct gl_context *ctx,
 }
 
 
-
 /**
- * Treat the vertex storage as a VBO, define vertex arrays pointing
- * into it:
+ * Setup the vertex arrays for drawing the primitives described by 'node'.
+ * This populates the node->inputs[] vertex arrays and calls
+ * _mesa_set_drawing_arrays().  Most of the work was previously done in
+ * the setup_vertex_arrays() function when the display list was compiled.
  */
 static void
 bind_vertex_list(struct gl_context *ctx,
-                 const struct vbo_save_vertex_list *node)
+                 struct vbo_save_vertex_list *node)
 {
    struct vbo_context *vbo = vbo_context(ctx);
-   struct vbo_save_context *save = &vbo->save;
-   struct gl_vertex_array *arrays = save->arrays;
-   GLuint buffer_offset = node->buffer_offset;
-   const GLubyte *map;  /** map from VERT_ATTRIB_x to VBO_ATTRIB_x */
-   GLuint attr;
-   GLubyte node_attrsz[VBO_ATTRIB_MAX];  /* copy of node->attrsz[] */
-   GLenum node_attrtype[VBO_ATTRIB_MAX];  /* copy of node->attrtype[] */
+   const enum vp_mode vp_mode = get_vp_mode(ctx);
+   unsigned array_count = 0;
    GLbitfield64 enabled = node->enabled;
 
-   memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
-   memcpy(node_attrtype, node->attrtype, sizeof(node->attrtype));
-
-   if (aligned_vertex_buffer_offset(node)) {
-      /* The vertex size is an exact multiple of the buffer offset.
-       * This means that we can use zero-based vertex attribute pointers
-       * and specify the start of the primitive with the _mesa_prim::start
-       * field.  This results in issuing several draw calls with identical
-       * vertex attribute information.  This can result in fewer state
-       * changes in drivers.  In particular, the Gallium CSO module will
-       * filter out redundant vertex buffer changes.
-       */
-      buffer_offset = 0;
+   if (vp_mode == VP_SHADER) {
+      /* per-vertex materials are to be ignored when using a VS */
+      enabled &= ~VBO_ATTRIBS_MATERIALS;
    }
 
-   /* Install the default (ie Current) attributes first */
-   for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
-      save->inputs[attr] = &vbo->currval[VBO_ATTRIB_POS + attr];
-   }
+   /* Loop over the attributes which are present in the vertex buffer
+    * and set the node->input vertex arrays to point to those attributes.
+    */
+   GLbitfield64 enabled_scan = enabled;
+   while (enabled_scan) {
+      const int attr = u_bit_scan64(&enabled_scan);
+      unsigned dst;
 
-   /* Overlay other active attributes */
-   switch (get_vp_mode(ctx)) {
-   case VP_FF:
-      /* Point the generic attributes at the legacy material values */
-      for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
-         save->inputs[VERT_ATTRIB_GENERIC(attr)] =
-            &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr];
+      /* Here is where we resolve whether array[16...] points to legacy
+       * material coefficients or generic vertex attributes.
+       */
+      if (vp_mode == VP_FF) {
+         if (attr >= VBO_ATTRIB_FIRST_MATERIAL) {
+            dst = VBO_ATTRIB_GENERIC0 + attr - VBO_ATTRIB_FIRST_MATERIAL;
+         } else {
+            dst = attr;
+         }
+      } else {
+         assert(vp_mode == VP_SHADER);
+         dst = attr;
       }
-      map = vbo->map_vp_none;
 
-      /* shift material attrib flags into generic attribute positions */
+      assert(dst < VERT_ATTRIB_MAX);
+      assert(node->arrays);
+      node->inputs[dst] = &node->arrays[array_count++];
+   }
+
+   /* Final vertex array setup depending on whether we're using fixed
+    * function or a vertex shader.
+    */
+   if (vp_mode == VP_FF) {
+      /* Update the enabled attribute bitfield so the material attrib bits
+       * replace the generic attrib bits.
+       */
       enabled = (enabled & VBO_ATTRIBS_LEGACY)
          | ((enabled & VBO_ATTRIBS_MATERIALS) >> VBO_MATERIAL_SHIFT);
-      break;
-   case VP_SHADER:
-      for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) {
-         save->inputs[VERT_ATTRIB_GENERIC(attr)] =
-            &vbo->currval[VBO_ATTRIB_GENERIC0+attr];
-      }
-      map = vbo->map_vp_arb;
-
-      /* per-vertex materials are to be ignored when using a VS */
-      enabled &= ~VBO_ATTRIBS_MATERIALS;
-
+   } else {
       /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
        * In that case we effectively need to route the data from
        * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
@@ -196,64 +190,19 @@ bind_vertex_list(struct gl_context *ctx,
          ctx->VertexProgram._Current->info.inputs_read;
       if ((inputs_read & VERT_BIT_POS) == 0 &&
           (inputs_read & VERT_BIT_GENERIC0)) {
-         save->inputs[VERT_ATTRIB_GENERIC0] = save->inputs[0];
-         node_attrsz[VERT_ATTRIB_GENERIC0] = node_attrsz[0];
-         node_attrtype[VERT_ATTRIB_GENERIC0] = node_attrtype[0];
-         node_attrsz[0] = 0;
-         enabled = (enabled & ~VERT_BIT_POS) | VERT_BIT_GENERIC0;
-      }
-      break;
-   default:
-      unreachable("Bad vertex program mode");
-   }
-
-#ifdef DEBUG
-   /* verify the enabled bitmask is consistent with attribute size info */
-   {
-      GLbitfield64 used = 0x0;
-      for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
-         const GLuint src = map[attr];
-         if (node_attrsz[src]) {
-            assert(enabled & VERT_BIT(attr));
-            used |= VERT_BIT(attr);
-         } else {
-            assert((enabled & VERT_BIT(attr)) == 0);
-         }
+         node->inputs[VERT_ATTRIB_GENERIC0] = &node->arrays[VBO_ATTRIB_POS];
+         node->inputs[VERT_ATTRIB_POS] = &vbo->currval[VBO_ATTRIB_POS];
+         enabled &= ~BITFIELD64_BIT(VBO_ATTRIB_POS);
+         enabled |= BITFIELD64_BIT(VBO_ATTRIB_GENERIC0);
       }
-      assert(used == enabled);
    }
-#endif
 
-   GLbitfield64 enabled_scan = enabled;
-   while (enabled_scan) {
-      const int attr = u_bit_scan64(&enabled_scan);
-      const GLuint src = map[attr];
-
-      if (node_attrsz[src]) {
-         struct gl_vertex_array *array = &arrays[attr];
-
-         /* override the default array set above */
-         save->inputs[attr] = array;
-
-         array->Ptr = (const GLubyte *) NULL + buffer_offset;
-         array->Size = node_attrsz[src];
-         array->StrideB = node->vertex_size * sizeof(GLfloat);
-         array->Type = node_attrtype[src];
-         array->Integer = vbo_attrtype_to_integer_flag(node_attrtype[src]);
-         array->Format = GL_RGBA;
-         array->_ElementSize = array->Size * sizeof(GLfloat);
-         _mesa_reference_buffer_object(ctx,
-                                       &array->BufferObj,
-                                       node->vertex_store->bufferobj);
-
-         assert(array->BufferObj->Name);
-
-         buffer_offset += node_attrsz[src] * sizeof(GLfloat);
-      }
-   }
+   /* make sure none of the extra VBO_ATTRIB bits are set */
+   assert((enabled & (GLbitfield64) VERT_BIT_ALL) == enabled);
 
    _mesa_set_varying_vp_inputs(ctx, enabled);
-   ctx->NewDriverState |= ctx->DriverFlags.NewArray;
+
+   _mesa_set_drawing_arrays(ctx, node->inputs);
 }
 
 
@@ -292,8 +241,8 @@ loopback_vertex_list(struct gl_context *ctx,
 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_vertex_list *node =
+      (struct vbo_save_vertex_list *) data;
    struct vbo_context *vbo = vbo_context(ctx);
    struct vbo_save_context *save = &vbo->save;
    GLboolean remap_vertex_store = GL_FALSE;
@@ -346,8 +295,6 @@ vbo_save_playback_vertex_list(struct gl_context *ctx, void 
*data)
 
       bind_vertex_list(ctx, node);
 
-      _mesa_set_drawing_arrays(ctx, vbo->save.inputs);
-
       /* Again...
        */
       if (ctx->NewState)
-- 
2.7.4

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to