mesa: completely rewrite the edge flag state update logic
authorMarek Olšák <marek.olsak@amd.com>
Mon, 21 Nov 2022 09:53:39 +0000 (04:53 -0500)
committerMarge Bot <emma+marge@anholt.net>
Mon, 12 Dec 2022 19:15:34 +0000 (19:15 +0000)
This removes the edge flag logic from st_validate_state, which was always
executed and added overhead there. Now it's done only when needed.

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

15 files changed:
src/mesa/main/arrayobj.h
src/mesa/main/attrib.c
src/mesa/main/draw.c
src/mesa/main/mtypes.h
src/mesa/main/polygon.c
src/mesa/main/varray.c
src/mesa/main/varray.h
src/mesa/state_tracker/st_atom.c
src/mesa/state_tracker/st_atom.h
src/mesa/state_tracker/st_atom_rasterizer.c
src/mesa/state_tracker/st_atom_shader.c
src/mesa/state_tracker/st_context.h
src/mesa/state_tracker/st_draw.c
src/mesa/vbo/vbo_exec_api.c
src/mesa/vbo/vbo_save_draw.c

index 5da0486..8d29bf3 100644 (file)
@@ -314,16 +314,6 @@ _mesa_draw_current_attrib(const struct gl_context *ctx, gl_vert_attrib attr)
 }
 
 
-/**
- * Return true if we have the VERT_ATTRIB_EDGEFLAG array enabled.
- */
-static inline bool
-_mesa_draw_edge_flag_array_enabled(const struct gl_context *ctx)
-{
-   return ctx->Array._DrawVAOEnabledAttribs & VERT_BIT_EDGEFLAG;
-}
-
-
 #ifdef __cplusplus
 }
 #endif
index 754a6e1..30f0299 100644 (file)
@@ -1313,6 +1313,8 @@ restore_array_attrib(struct gl_context *ctx,
                        src->VAO->IndexBufferObj ?
                           src->VAO->IndexBufferObj->Name : 0);
    }
+
+   _mesa_update_edgeflag_state_vao(ctx);
 }
 
 
index 3ea9c62..55b548e 100644 (file)
@@ -110,6 +110,7 @@ _mesa_set_draw_vao(struct gl_context *ctx, struct gl_vertex_array_object *vao)
 
    if (*ptr != vao) {
       _mesa_reference_vao_(ctx, ptr, vao);
+      _mesa_update_edgeflag_state_vao(ctx);
       ctx->Array.NewVAO = true;
    }
 }
@@ -135,6 +136,7 @@ _mesa_restore_draw_vao(struct gl_context *ctx,
 {
    _mesa_reference_vao(ctx, &ctx->Array._DrawVAO, NULL);
    ctx->Array._DrawVAO = saved;
+   _mesa_update_edgeflag_state_vao(ctx);
    ctx->Array.NewVAO = true;
 }
 
index 697361d..e36341b 100644 (file)
@@ -1754,6 +1754,18 @@ struct gl_array_attrib
    GLbitfield _DrawVAOEnabledAttribs;
 
    /**
+    * Whether per-vertex edge flags are enabled and should be processed by
+    * the vertex shader.
+    */
+   bool _PerVertexEdgeFlagsEnabled;
+
+   /**
+    * Whether all edge flags are false, causing all points and lines generated
+    * by polygon mode to be not drawn. (i.e. culled)
+    */
+   bool _PolygonModeAlwaysCulls;
+
+   /**
     * Whether the VAO has been changed.
     */
    bool NewVAO;
index 1297aa4..1b19c48 100644 (file)
@@ -39,6 +39,7 @@
 #include "polygon.h"
 #include "mtypes.h"
 #include "api_exec_decl.h"
+#include "varray.h"
 
 #include "state_tracker/st_context.h"
 
@@ -193,6 +194,7 @@ polygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error)
                      GL_POLYGON_BIT);
       ctx->NewDriverState |= ST_NEW_RASTERIZER;
       ctx->Polygon.FrontMode = mode;
+      _mesa_update_edgeflag_state_vao(ctx);
       break;
    case GL_FRONT_AND_BACK:
       if (ctx->Polygon.FrontMode == mode && ctx->Polygon.BackMode == mode)
@@ -202,6 +204,7 @@ polygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error)
       ctx->NewDriverState |= ST_NEW_RASTERIZER;
       ctx->Polygon.FrontMode = mode;
       ctx->Polygon.BackMode = mode;
+      _mesa_update_edgeflag_state_vao(ctx);
       break;
    case GL_BACK:
       if (!no_error && ctx->API == API_OPENGL_CORE) {
@@ -214,6 +217,7 @@ polygon_mode(struct gl_context *ctx, GLenum face, GLenum mode, bool no_error)
                      GL_POLYGON_BIT);
       ctx->NewDriverState |= ST_NEW_RASTERIZER;
       ctx->Polygon.BackMode = mode;
+      _mesa_update_edgeflag_state_vao(ctx);
       break;
    default:
       if (!no_error)
index 30b6f07..7b694b7 100644 (file)
@@ -44,6 +44,9 @@
 #include "main/dispatch.h"
 #include "api_exec_decl.h"
 
+#include "state_tracker/st_atom.h"
+#include "state_tracker/st_util.h"
+
 
 /** Used to do error checking for GL_EXT_vertex_array_bgra */
 #define BGRA_OR_4  5
@@ -1993,6 +1996,62 @@ _mesa_VertexAttribLPointer(GLuint index, GLint size, GLenum type,
                 stride, GL_FALSE, GL_FALSE, GL_TRUE, ptr);
 }
 
+/**
+ * Set the per-vertex edge flag enablement according to the "enable"
+ * parameter. If "enable" is false, the zero-stride edge flag attribute value
+ * will be used instead.
+ *
+ * This is used by VAOs, glBegin/End and display lists.
+ */
+void
+_mesa_update_edgeflag_state_explicit(struct gl_context *ctx,
+                                     bool per_vertex_enable)
+{
+   if (ctx->API != API_OPENGL_COMPAT)
+      return;
+
+   /* Edge flags take effect only if the polygon mode is not FILL, and they
+    * determine whether a line or point is drawn with that polygon mode.
+    */
+   bool edgeflags_have_effect = ctx->Polygon.FrontMode != GL_FILL ||
+                                ctx->Polygon.BackMode != GL_FILL;
+   per_vertex_enable &= edgeflags_have_effect;
+
+   if (per_vertex_enable != ctx->Array._PerVertexEdgeFlagsEnabled) {
+      ctx->Array._PerVertexEdgeFlagsEnabled = per_vertex_enable;
+
+      struct gl_program *vp = ctx->VertexProgram._Current;
+      if (vp) {
+         ctx->NewDriverState |= ST_NEW_VS_STATE |
+                                ST_NEW_VERTEX_ARRAYS;
+         ctx->Array.NewVertexElements = true;
+      }
+   }
+
+   /* If there are no per-vertex edge flags and the zero-stride edge flag is
+    * false, all front and back points and lines generated by polygon mode
+    * are not drawn.
+    */
+   bool polygon_mode_always_culls = edgeflags_have_effect &&
+                                    !ctx->Array._PerVertexEdgeFlagsEnabled &&
+                                    !ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG][0];
+   if (polygon_mode_always_culls != ctx->Array._PolygonModeAlwaysCulls) {
+      ctx->Array._PolygonModeAlwaysCulls = polygon_mode_always_culls;
+      ctx->NewDriverState |= ST_NEW_RASTERIZER;
+   }
+}
+
+/**
+ * Set the edge flag state using the current VAO and the zero-stride
+ * edge flag attribute value if per-vertex edge flags are disabled.
+ */
+void
+_mesa_update_edgeflag_state_vao(struct gl_context *ctx)
+{
+   _mesa_update_edgeflag_state_explicit(ctx,
+                                        ctx->Array._DrawVAO->Enabled &
+                                        VERT_BIT_EDGEFLAG);
+}
 
 void
 _mesa_enable_vertex_array_attribs(struct gl_context *ctx,
@@ -2015,6 +2074,9 @@ _mesa_enable_vertex_array_attribs(struct gl_context *ctx,
       if (attrib_bits & (VERT_BIT_POS|VERT_BIT_GENERIC0))
          update_attribute_map_mode(ctx, vao);
 
+      if (attrib_bits & VERT_BIT_EDGEFLAG)
+         _mesa_update_edgeflag_state_vao(ctx);
+
       vao->_EnabledWithMapMode =
          _mesa_vao_enable_to_vp_inputs(vao->_AttributeMapMode, vao->Enabled);
    }
@@ -2116,6 +2178,9 @@ _mesa_disable_vertex_array_attribs(struct gl_context *ctx,
       if (attrib_bits & (VERT_BIT_POS|VERT_BIT_GENERIC0))
          update_attribute_map_mode(ctx, vao);
 
+      if (attrib_bits & VERT_BIT_EDGEFLAG)
+         _mesa_update_edgeflag_state_vao(ctx);
+
       vao->_EnabledWithMapMode =
          _mesa_vao_enable_to_vp_inputs(vao->_AttributeMapMode, vao->Enabled);
    }
index 1829896..8c61070 100644 (file)
@@ -168,4 +168,11 @@ _mesa_init_varray(struct gl_context *ctx);
 extern void
 _mesa_free_varray_data(struct gl_context *ctx);
 
+void
+_mesa_update_edgeflag_state_explicit(struct gl_context *ctx,
+                                     bool per_vertex_enable);
+
+void
+_mesa_update_edgeflag_state_vao(struct gl_context *ctx);
+
 #endif
index f2ceb59..0b9f90d 100644 (file)
@@ -70,33 +70,6 @@ void st_destroy_atoms( struct st_context *st )
    /* no-op */
 }
 
-void st_update_edgeflags(struct st_context *st, bool per_vertex_edgeflags)
-{
-   bool edgeflags_enabled = st->ctx->Polygon.FrontMode != GL_FILL ||
-                            st->ctx->Polygon.BackMode != GL_FILL;
-   bool vertdata_edgeflags = edgeflags_enabled && per_vertex_edgeflags;
-
-   if (vertdata_edgeflags != st->vertdata_edgeflags) {
-      st->vertdata_edgeflags = vertdata_edgeflags;
-
-      struct gl_program *vp = st->ctx->VertexProgram._Current;
-      if (vp)
-         st->dirty |= ST_NEW_VERTEX_PROGRAM(st->ctx, vp);
-   }
-
-   bool edgeflag_culls_prims = edgeflags_enabled && !vertdata_edgeflags &&
-                               !st->ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG][0];
-   if (edgeflag_culls_prims != st->edgeflag_culls_prims) {
-      st->edgeflag_culls_prims = edgeflag_culls_prims;
-      st->dirty |= ST_NEW_RASTERIZER;
-   }
-}
-
-static void check_attrib_edgeflag(struct st_context *st)
-{
-   st_update_edgeflags(st, _mesa_draw_edge_flag_array_enabled(st->ctx));
-}
-
 /***********************************************************************
  * Update all derived state:
  */
@@ -118,9 +91,6 @@ void st_validate_state( struct st_context *st, enum st_pipeline pipeline )
    switch (pipeline) {
    case ST_PIPELINE_RENDER:
    case ST_PIPELINE_RENDER_NO_VARRAYS:
-      if (st->ctx->API == API_OPENGL_COMPAT)
-         check_attrib_edgeflag(st);
-
       if (pipeline == ST_PIPELINE_RENDER)
          pipeline_mask = ST_PIPELINE_RENDER_STATE_MASK;
       else
index 58874bd..241d21e 100644 (file)
@@ -62,7 +62,6 @@ enum st_pipeline {
 void st_init_atoms( struct st_context *st );
 void st_destroy_atoms( struct st_context *st );
 void st_validate_state( struct st_context *st, enum st_pipeline pipeline );
-void st_update_edgeflags(struct st_context *st, bool per_vertex_edgeflags);
 
 void
 st_setup_arrays(struct st_context *st,
index 0e6bfdb..fda7f36 100644 (file)
@@ -287,8 +287,7 @@ st_update_rasterizer(struct st_context *st)
       raster->tile_raster_order_increasing_y = ctx->TileRasterOrderIncreasingY;
    }
 
-   if (st->edgeflag_culls_prims) {
-      /* All edge flags are FALSE. Cull the affected faces. */
+   if (ctx->Array._PolygonModeAlwaysCulls) {
       if (raster->fill_front != PIPE_POLYGON_MODE_FILL)
          raster->cull_face |= PIPE_FACE_FRONT;
       if (raster->fill_back != PIPE_POLYGON_MODE_FILL)
index 96f4e1c..643a373 100644 (file)
@@ -195,7 +195,7 @@ st_update_vp( struct st_context *st )
    assert(vp->Target == GL_VERTEX_PROGRAM_ARB);
 
    if (st->shader_has_one_variant[MESA_SHADER_VERTEX] &&
-       !st->vertdata_edgeflags) {
+       !st->ctx->Array._PerVertexEdgeFlagsEnabled) {
       st->vp_variant = st_common_variant(vp->variants);
    } else {
       struct st_common_variant_key key;
@@ -210,7 +210,7 @@ st_update_vp( struct st_context *st )
        * the input to the output.  We'll need to use similar logic to set
        * up the extra vertex_element input for edgeflags.
        */
-      key.passthrough_edgeflags = st->vertdata_edgeflags;
+      key.passthrough_edgeflags = st->ctx->Array._PerVertexEdgeFlagsEnabled;
 
       key.clamp_color = st->clamp_vert_color_in_shader &&
                         st->ctx->Light._ClampVertexColor &&
index 556e074..57024f7 100644 (file)
@@ -254,9 +254,6 @@ struct st_context
    /** This masks out unused shader resources. Only valid in draw calls. */
    uint64_t active_states;
 
-   GLboolean vertdata_edgeflags;
-   GLboolean edgeflag_culls_prims;
-
    /**
     * The number of currently active queries (excluding timer queries).
     * This is used to know if we need to pause any queries for meta ops.
index 080184c..9286231 100644 (file)
@@ -349,12 +349,6 @@ st_draw_gallium_vertex_state(struct gl_context *ctx,
                              bool per_vertex_edgeflags)
 {
    struct st_context *st = st_context(ctx);
-   bool old_vertdata_edgeflags = st->vertdata_edgeflags;
-
-   /* We don't flag any other states to make st_validate state update edge
-    * flags, so we need to update them here.
-    */
-   st_update_edgeflags(st, per_vertex_edgeflags);
 
    prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK_NO_VARRAYS,
                 ST_PIPELINE_RENDER_NO_VARRAYS);
@@ -383,15 +377,6 @@ st_draw_gallium_vertex_state(struct gl_context *ctx,
          }
       }
    }
-
-   /* If per-vertex edge flags are different than the non-display-list state,
-    *  just flag ST_NEW_VERTEX_ARRAY, which will also completely revalidate
-    * edge flags in st_validate_state.
-    */
-   if (st->vertdata_edgeflags != old_vertdata_edgeflags) {
-      ctx->Array.NewVertexElements = true;
-      st->dirty |= ST_NEW_VERTEX_ARRAYS;
-   }
 }
 
 void
index 03f1882..29a7414 100644 (file)
@@ -211,6 +211,9 @@ vbo_exec_copy_to_current(struct vbo_exec_context *exec)
                 i == VBO_ATTRIB_MAT_BACK_SHININESS)
                ctx->NewState |= _NEW_FF_VERT_PROGRAM;
          } else {
+            if (i == VBO_ATTRIB_EDGEFLAG)
+               _mesa_update_edgeflag_state_vao(ctx);
+
             ctx->NewState |= _NEW_CURRENT_ATTRIB;
             ctx->PopAttribState |= GL_CURRENT_BIT;
          }
index 093cbe7..a57faa8 100644 (file)
@@ -78,6 +78,9 @@ copy_vao(struct gl_context *ctx, const struct gl_vertex_array_object *vao,
              current_index == VBO_ATTRIB_MAT_BACK_SHININESS)
             ctx->NewState |= _NEW_FF_VERT_PROGRAM;
 
+         if (current_index == VBO_ATTRIB_EDGEFLAG)
+            _mesa_update_edgeflag_state_vao(ctx);
+
          ctx->NewState |= state;
          ctx->PopAttribState |= pop_state;
       }
@@ -270,6 +273,9 @@ vbo_save_playback_vertex_list_gallium(struct gl_context *ctx,
       info.take_vertex_state_ownership = true;
    }
 
+   /* Set edge flags. */
+   _mesa_update_edgeflag_state_explicit(ctx, enabled & VERT_BIT_EDGEFLAG);
+
    /* Fast path using a pre-built gallium vertex buffer state. */
    if (node->modes || node->num_draws > 1) {
       ctx->Driver.DrawGalliumVertexState(ctx, state, info,
@@ -284,6 +290,9 @@ vbo_save_playback_vertex_list_gallium(struct gl_context *ctx,
                                          enabled & VERT_ATTRIB_EDGEFLAG);
    }
 
+   /* Restore edge flag state. */
+   _mesa_update_edgeflag_state_vao(ctx);
+
    if (copy_to_current)
       playback_copy_to_current(ctx, node);
    return DONE;