Mesa (main): st/mesa: don't update vertex elements when GL doesn't change them

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Nov 3 23:50:05 UTC 2021


Module: Mesa
Branch: main
Commit: cdc288993e06224cb5da97f4458fd50ce257e491
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=cdc288993e06224cb5da97f4458fd50ce257e491

Author: Marek Olšák <marek.olsak at amd.com>
Date:   Sun Oct 24 03:57:14 2021 -0400

st/mesa: don't update vertex elements when GL doesn't change them

We rely on mesa/main to tell us whether to update vertex elements.
This decreases overhead for obvious reasons.

The select/feedback code path doesn't use this, which is why you see
unconditional "ALL" in a few codepaths.

This sequence of GL calls doesn't update vertex elements if only
the pointer and stride vary:
    glVertexPointer()
    glDrawElements()
    glVertexPointer()
    glDrawElements()
    glVertexPointer()
    glDrawElements()

Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13512>

---

 src/mesa/state_tracker/st_atom.c          |   1 +
 src/mesa/state_tracker/st_atom_array.cpp  | 113 +++++++++++++++++++++---------
 src/mesa/state_tracker/st_cb_bitmap.c     |   1 +
 src/mesa/state_tracker/st_cb_clear.c      |   1 +
 src/mesa/state_tracker/st_cb_drawpixels.c |   1 +
 src/mesa/state_tracker/st_cb_drawtex.c    |   1 +
 src/mesa/state_tracker/st_cb_readpixels.c |   1 +
 src/mesa/state_tracker/st_cb_texture.c    |   2 +
 src/mesa/state_tracker/st_context.c       |   5 +-
 src/mesa/state_tracker/st_context.h       |   1 +
 src/mesa/state_tracker/st_draw.c          |   4 +-
 src/mesa/state_tracker/st_manager.c       |   4 +-
 src/mesa/state_tracker/st_program.c       |   6 +-
 13 files changed, 102 insertions(+), 39 deletions(-)

diff --git a/src/mesa/state_tracker/st_atom.c b/src/mesa/state_tracker/st_atom.c
index df2c5895fe7..555b375ea46 100644
--- a/src/mesa/state_tracker/st_atom.c
+++ b/src/mesa/state_tracker/st_atom.c
@@ -95,6 +95,7 @@ static void check_program_state( struct st_context *st )
     * properly when transitioning to shaders that don't use them.
     */
    if (unlikely(new_vp != (old_vp ? &old_vp->Base : NULL))) {
+      ctx->Array.NewVertexElements = true;
       if (old_vp)
          dirty |= old_vp->affected_states;
       if (new_vp)
diff --git a/src/mesa/state_tracker/st_atom_array.cpp b/src/mesa/state_tracker/st_atom_array.cpp
index 59a38931a05..6978074c543 100644
--- a/src/mesa/state_tracker/st_atom_array.cpp
+++ b/src/mesa/state_tracker/st_atom_array.cpp
@@ -50,6 +50,11 @@
 #include "main/varray.h"
 #include "main/arrayobj.h"
 
+enum st_update_flag {
+   UPDATE_ALL,
+   UPDATE_BUFFERS_ONLY,
+};
+
 /* Always inline the non-64bit element code, so that the compiler can see
  * that velements is on the stack.
  */
@@ -70,7 +75,7 @@ init_velement(struct pipe_vertex_element *velements,
 /* ALWAYS_INLINE helps the compiler realize that most of the parameters are
  * on the stack.
  */
-template<util_popcnt POPCNT> static void ALWAYS_INLINE
+template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
 setup_arrays(struct st_context *st,
              const struct gl_vertex_array_object *vao,
              const GLbitfield dual_slot_inputs,
@@ -115,6 +120,9 @@ setup_arrays(struct st_context *st,
          }
          vbuffer[bufidx].stride = binding->Stride; /* in bytes */
 
+         if (UPDATE == UPDATE_BUFFERS_ONLY)
+            continue;
+
          /* Set the vertex element. */
          init_velement(velements->velems, &attrib->Format, 0,
                        binding->InstanceDivisor, bufidx,
@@ -152,6 +160,10 @@ setup_arrays(struct st_context *st,
       mask &= ~boundmask;
       /* We can assume that we have array for the binding */
       assert(attrmask);
+
+      if (UPDATE == UPDATE_BUFFERS_ONLY)
+         continue;
+
       /* Walk attributes belonging to the binding */
       do {
          const gl_vert_attrib attr = (gl_vert_attrib)u_bit_scan(&attrmask);
@@ -177,11 +189,11 @@ st_setup_arrays(struct st_context *st,
 {
    struct gl_context *ctx = st->ctx;
 
-   setup_arrays<POPCNT_NO>(st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs,
-                           vp_variant->vert_attrib_mask,
-                           _mesa_draw_nonzero_divisor_bits(ctx),
-                           _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx),
-                           velements, vbuffer, num_vbuffers, has_user_vertex_buffers);
+   setup_arrays<POPCNT_NO, UPDATE_ALL>
+      (st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs,
+       vp_variant->vert_attrib_mask, _mesa_draw_nonzero_divisor_bits(ctx),
+       _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx),
+       velements, vbuffer, num_vbuffers, has_user_vertex_buffers);
 }
 
 /* ALWAYS_INLINE helps the compiler realize that most of the parameters are
@@ -190,7 +202,7 @@ st_setup_arrays(struct st_context *st,
  * Return the index of the vertex buffer where current attribs have been
  * uploaded.
  */
-template<util_popcnt POPCNT> static void ALWAYS_INLINE
+template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
 st_setup_current(struct st_context *st,
                  const struct st_vertex_program *vp,
                  const struct st_common_variant *vp_variant,
@@ -221,9 +233,11 @@ st_setup_current(struct st_context *st,
          if (alignment != size)
             memset(cursor + size, 0, alignment - size);
 
-         init_velement(velements->velems, &attrib->Format, cursor - data,
-                       0, bufidx, dual_slot_inputs & BITFIELD_BIT(attr),
-                       util_bitcount_fast<POPCNT>(inputs_read & BITFIELD_MASK(attr)));
+         if (UPDATE == UPDATE_ALL) {
+            init_velement(velements->velems, &attrib->Format, cursor - data,
+                          0, bufidx, dual_slot_inputs & BITFIELD_BIT(attr),
+                          util_bitcount_fast<POPCNT>(inputs_read & BITFIELD_MASK(attr)));
+         }
 
          cursor += alignment;
       } while (curmask);
@@ -283,10 +297,11 @@ st_setup_current_user(struct st_context *st,
    }
 }
 
-template<util_popcnt POPCNT> inline void
+template<util_popcnt POPCNT, st_update_flag UPDATE> void ALWAYS_INLINE
 st_update_array_templ(struct st_context *st)
 {
    struct gl_context *ctx = st->ctx;
+
    /* vertex program validation must be done before this */
    /* _NEW_PROGRAM, ST_NEW_VS_STATE */
    const struct st_vertex_program *vp = (struct st_vertex_program *)st->vp;
@@ -299,44 +314,74 @@ st_update_array_templ(struct st_context *st)
 
    /* ST_NEW_VERTEX_ARRAYS alias ctx->DriverFlags.NewArray */
    /* Setup arrays */
-   setup_arrays<POPCNT>(st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs,
-                        vp_variant->vert_attrib_mask,
-                        _mesa_draw_nonzero_divisor_bits(ctx),
-                        _mesa_draw_array_bits(ctx),
-                        _mesa_draw_user_array_bits(ctx), &velements, vbuffer,
-                        &num_vbuffers, &uses_user_vertex_buffers);
+   setup_arrays<POPCNT, UPDATE>
+      (st, ctx->Array._DrawVAO, vp->Base.Base.DualSlotInputs,
+       vp_variant->vert_attrib_mask, _mesa_draw_nonzero_divisor_bits(ctx),
+       _mesa_draw_array_bits(ctx), _mesa_draw_user_array_bits(ctx),
+       &velements, vbuffer, &num_vbuffers, &uses_user_vertex_buffers);
 
    /* _NEW_CURRENT_ATTRIB */
    /* Setup zero-stride attribs. */
-   st_setup_current<POPCNT>(st, vp, vp_variant, &velements, vbuffer,
-                            &num_vbuffers);
-
-   velements.count = vp->num_inputs + vp_variant->key.passthrough_edgeflags;
+   st_setup_current<POPCNT, UPDATE>(st, vp, vp_variant, &velements, vbuffer,
+                                    &num_vbuffers);
 
-   /* Set vertex buffers and elements. */
-   struct cso_context *cso = st->cso_context;
    unsigned unbind_trailing_vbuffers =
       st->last_num_vbuffers > num_vbuffers ?
          st->last_num_vbuffers - num_vbuffers : 0;
-   cso_set_vertex_buffers_and_elements(cso, &velements,
-                                       num_vbuffers,
-                                       unbind_trailing_vbuffers,
-                                       true,
-                                       uses_user_vertex_buffers,
-                                       vbuffer);
    st->last_num_vbuffers = num_vbuffers;
+
+   struct cso_context *cso = st->cso_context;
+
+   if (UPDATE == UPDATE_ALL) {
+      velements.count = vp->num_inputs + vp_variant->key.passthrough_edgeflags;
+
+      /* Set vertex buffers and elements. */
+      cso_set_vertex_buffers_and_elements(cso, &velements,
+                                          num_vbuffers,
+                                          unbind_trailing_vbuffers,
+                                          true,
+                                          uses_user_vertex_buffers,
+                                          vbuffer);
+      /* The driver should clear this after it has processed the update. */
+      ctx->Array.NewVertexElements = false;
+      st->uses_user_vertex_buffers = uses_user_vertex_buffers;
+   } else {
+      /* Only vertex buffers. */
+      cso_set_vertex_buffers(cso, 0, num_vbuffers, unbind_trailing_vbuffers,
+                             true, vbuffer);
+      /* This can change only when we update vertex elements. */
+      assert(st->uses_user_vertex_buffers == uses_user_vertex_buffers);
+   }
+}
+
+template<util_popcnt POPCNT> void ALWAYS_INLINE
+st_update_array_impl(struct st_context *st)
+{
+   struct gl_context *ctx = st->ctx;
+
+   /* Changing from user to non-user buffers and vice versa can switch between
+    * cso and u_vbuf, which means that we need to update vertex elements even
+    * when they have not changed.
+    */
+   if (ctx->Array.NewVertexElements ||
+       st->uses_user_vertex_buffers !=
+       !!(st->vp_variant->vert_attrib_mask & _mesa_draw_user_array_bits(ctx))) {
+      st_update_array_templ<POPCNT, UPDATE_ALL>(st);
+   } else {
+      st_update_array_templ<POPCNT, UPDATE_BUFFERS_ONLY>(st);
+   }
 }
 
 void
 st_update_array(struct st_context *st)
 {
-   st_update_array_templ<POPCNT_NO>(st);
+   st_update_array_impl<POPCNT_NO>(st);
 }
 
 void
 st_update_array_with_popcnt(struct st_context *st)
 {
-   st_update_array_templ<POPCNT_YES>(st);
+   st_update_array_impl<POPCNT_YES>(st);
 }
 
 struct pipe_vertex_state *
@@ -353,9 +398,9 @@ st_create_gallium_vertex_state(struct gl_context *ctx,
    struct cso_velems_state velements;
    bool uses_user_vertex_buffers;
 
-   setup_arrays<POPCNT_NO>(st, vao, dual_slot_inputs, inputs_read, 0,
-                           inputs_read, 0, &velements, vbuffer, &num_vbuffers,
-                           &uses_user_vertex_buffers);
+   setup_arrays<POPCNT_NO, UPDATE_ALL>(st, vao, dual_slot_inputs, inputs_read, 0,
+                                inputs_read, 0, &velements, vbuffer, &num_vbuffers,
+                                &uses_user_vertex_buffers);
 
    if (num_vbuffers != 1 || uses_user_vertex_buffers) {
       assert(!"this should never happen with display lists");
diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c
index 0683ccd0c68..f538c081fae 100644
--- a/src/mesa/state_tracker/st_cb_bitmap.c
+++ b/src/mesa/state_tracker/st_cb_bitmap.c
@@ -280,6 +280,7 @@ restore_render_state(struct gl_context *ctx)
    cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS);
    st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0;
 
+   ctx->Array.NewVertexElements = true;
    st->dirty |= ST_NEW_VERTEX_ARRAYS |
                 ST_NEW_FS_SAMPLER_VIEWS;
 }
diff --git a/src/mesa/state_tracker/st_cb_clear.c b/src/mesa/state_tracker/st_cb_clear.c
index 414e61be0ba..623c4355a91 100644
--- a/src/mesa/state_tracker/st_cb_clear.c
+++ b/src/mesa/state_tracker/st_cb_clear.c
@@ -361,6 +361,7 @@ clear_with_quad(struct gl_context *ctx, unsigned clear_buffers)
 
    /* Restore pipe state */
    cso_restore_state(cso, 0);
+   ctx->Array.NewVertexElements = true;
    st->dirty |= ST_NEW_VERTEX_ARRAYS;
 }
 
diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c
index c7c8f94aab4..0c375cc4ea4 100644
--- a/src/mesa/state_tracker/st_cb_drawpixels.c
+++ b/src/mesa/state_tracker/st_cb_drawpixels.c
@@ -949,6 +949,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS);
    st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0;
 
+   ctx->Array.NewVertexElements = true;
    st->dirty |= ST_NEW_VERTEX_ARRAYS |
                 ST_NEW_FS_SAMPLER_VIEWS;
 }
diff --git a/src/mesa/state_tracker/st_cb_drawtex.c b/src/mesa/state_tracker/st_cb_drawtex.c
index 262ce39fbe1..2e4c7c6f603 100644
--- a/src/mesa/state_tracker/st_cb_drawtex.c
+++ b/src/mesa/state_tracker/st_cb_drawtex.c
@@ -349,6 +349,7 @@ st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
 
    /* restore state */
    cso_restore_state(cso, 0);
+   ctx->Array.NewVertexElements = true;
    st->dirty |= ST_NEW_VERTEX_ARRAYS;
 }
 
diff --git a/src/mesa/state_tracker/st_cb_readpixels.c b/src/mesa/state_tracker/st_cb_readpixels.c
index c8d7d9c7d63..aed41ce32a6 100644
--- a/src/mesa/state_tracker/st_cb_readpixels.c
+++ b/src/mesa/state_tracker/st_cb_readpixels.c
@@ -260,6 +260,7 @@ fail:
    cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS | CSO_UNBIND_FS_IMAGE0);
    st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0;
 
+   st->ctx->Array.NewVertexElements = true;
    st->dirty |= ST_NEW_FS_CONSTANTS |
                 ST_NEW_FS_IMAGES |
                 ST_NEW_FS_SAMPLER_VIEWS |
diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c
index 65ef65f1524..950a2242354 100644
--- a/src/mesa/state_tracker/st_cb_texture.c
+++ b/src/mesa/state_tracker/st_cb_texture.c
@@ -1661,6 +1661,7 @@ fail:
    cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS);
    st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0;
 
+   ctx->Array.NewVertexElements = true;
    st->dirty |= ST_NEW_VERTEX_ARRAYS |
                 ST_NEW_FS_CONSTANTS |
                 ST_NEW_FS_SAMPLER_VIEWS;
@@ -1951,6 +1952,7 @@ fail:
    cso_restore_state(cso, CSO_UNBIND_FS_SAMPLERVIEWS | CSO_UNBIND_FS_IMAGE0);
    st->state.num_sampler_views[PIPE_SHADER_FRAGMENT] = 0;
 
+   st->ctx->Array.NewVertexElements = true;
    st->dirty |= ST_NEW_FS_CONSTANTS |
                 ST_NEW_FS_IMAGES |
                 ST_NEW_FS_SAMPLER_VIEWS |
diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
index ab2cc9642f9..919953baf64 100644
--- a/src/mesa/state_tracker/st_context.c
+++ b/src/mesa/state_tracker/st_context.c
@@ -241,8 +241,11 @@ st_invalidate_state(struct gl_context *ctx)
    if (new_state & _NEW_PIXEL)
       st->dirty |= ST_NEW_PIXEL_TRANSFER;
 
-   if (new_state & _NEW_CURRENT_ATTRIB && st_vp_uses_current_values(ctx))
+   if (new_state & _NEW_CURRENT_ATTRIB && st_vp_uses_current_values(ctx)) {
       st->dirty |= ST_NEW_VERTEX_ARRAYS;
+      /* glColor3f -> glColor4f changes the vertex format. */
+      ctx->Array.NewVertexElements = true;
+   }
 
    if (st->clamp_frag_depth_in_shader && (new_state & _NEW_VIEWPORT)) {
       if (ctx->GeometryProgram._Current)
diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h
index 58bc8112429..f79c7506cf9 100644
--- a/src/mesa/state_tracker/st_context.h
+++ b/src/mesa/state_tracker/st_context.h
@@ -345,6 +345,7 @@ struct st_context
 
    /* The number of vertex buffers from the last call of validate_arrays. */
    unsigned last_num_vbuffers;
+   bool uses_user_vertex_buffers;
 
    unsigned last_used_atomic_bindings[PIPE_SHADER_TYPES];
    unsigned last_num_ssbos[PIPE_SHADER_TYPES];
diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c
index e9cf42efcb5..10107153d5b 100644
--- a/src/mesa/state_tracker/st_draw.c
+++ b/src/mesa/state_tracker/st_draw.c
@@ -362,8 +362,10 @@ st_draw_gallium_vertex_state(struct gl_context *ctx,
     *  just flag ST_NEW_VERTEX_ARRAY, which will also completely revalidate
     * edge flags in st_validate_state.
     */
-   if (st->vertdata_edgeflags != old_vertdata_edgeflags)
+   if (st->vertdata_edgeflags != old_vertdata_edgeflags) {
+      ctx->Array.NewVertexElements = true;
       st->dirty |= ST_NEW_VERTEX_ARRAYS;
+   }
 }
 
 void
diff --git a/src/mesa/state_tracker/st_manager.c b/src/mesa/state_tracker/st_manager.c
index 9e0f29a2ccd..aed501e3705 100644
--- a/src/mesa/state_tracker/st_manager.c
+++ b/src/mesa/state_tracker/st_manager.c
@@ -847,8 +847,10 @@ st_context_invalidate_state(struct st_context_iface *stctxi,
       st->dirty |= ST_NEW_FS_CONSTANTS;
    if (flags & ST_INVALIDATE_VS_CONSTBUF0)
       st->dirty |= ST_NEW_VS_CONSTANTS;
-   if (flags & ST_INVALIDATE_VERTEX_BUFFERS)
+   if (flags & ST_INVALIDATE_VERTEX_BUFFERS) {
+      st->ctx->Array.NewVertexElements = true;
       st->dirty |= ST_NEW_VERTEX_ARRAYS;
+   }
 }
 
 
diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
index 349f80c5be3..ece98763bb8 100644
--- a/src/mesa/state_tracker/st_program.c
+++ b/src/mesa/state_tracker/st_program.c
@@ -2022,10 +2022,12 @@ void
 st_finalize_program(struct st_context *st, struct gl_program *prog)
 {
    if (st->current_program[prog->info.stage] == prog) {
-      if (prog->info.stage == MESA_SHADER_VERTEX)
+      if (prog->info.stage == MESA_SHADER_VERTEX) {
+         st->ctx->Array.NewVertexElements = true;
          st->dirty |= ST_NEW_VERTEX_PROGRAM(st, (struct st_program *)prog);
-      else
+      } else {
          st->dirty |= ((struct st_program *)prog)->affected_states;
+      }
    }
 
    if (prog->nir) {



More information about the mesa-commit mailing list