st/mesa: move check_program_state code into _mesa_update_state
authorMarek Olšák <marek.olsak@amd.com>
Fri, 18 Nov 2022 11:42:07 +0000 (06:42 -0500)
committerMarge Bot <emma+marge@anholt.net>
Wed, 7 Dec 2022 09:12:41 +0000 (09:12 +0000)
_mesa_update_state() receives the _NEW_PROGRAM flag, so we can handle
any shader changes there.

There may be some overhead reduction because gfx_shaders_may_be_dirty
is removed.

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

src/mesa/main/compute.c
src/mesa/main/mtypes.h
src/mesa/main/state.c
src/mesa/state_tracker/st_atom.c
src/mesa/state_tracker/st_atom.h
src/mesa/state_tracker/st_cb_bitmap.c
src/mesa/state_tracker/st_cb_feedback.c
src/mesa/state_tracker/st_context.c
src/mesa/state_tracker/st_context.h
src/mesa/state_tracker/st_draw.c
src/mesa/state_tracker/st_program.c

index 8e585fdf39acb63134f239a68326a097f100a96a..1705ec6805f54e988a1ee9b33dfa04f6801e0e63 100644 (file)
@@ -296,8 +296,7 @@ prepare_compute(struct gl_context *ctx)
       _mesa_update_state(ctx);
 
    if ((st->dirty | ctx->NewDriverState) & st->active_states &
-       ST_PIPELINE_COMPUTE_STATE_MASK ||
-       st->compute_shader_may_be_dirty)
+       ST_PIPELINE_COMPUTE_STATE_MASK)
       st_validate_state(st, ST_PIPELINE_COMPUTE);
 
 }
index 6bd289476ab08430842bae55c7f7e12758b7dda7..80033bd0fa688bcfd666c2c6689581682ac07282 100644 (file)
@@ -3581,7 +3581,6 @@ struct gl_context
 
    GLuint TextureStateTimestamp; /**< detect changes to shared state */
 
-   GLboolean LastVertexStageDirty; /**< the last vertex stage has changed */
    GLboolean PointSizeIsSet; /**< the glPointSize value in the shader is set */
 
    /** \name For debugging/development only */
index 13d62d0ca53c591e0261d3baa7e690a4c44a1495..daf5688fe4a5bacf7c29a594b1367412f0569e13 100644 (file)
@@ -56,6 +56,7 @@
 #include "blend.h"
 
 #include "state_tracker/st_context.h"
+#include "state_tracker/st_util.h"
 
 void
 _mesa_update_allow_draw_out_of_order(struct gl_context *ctx)
@@ -184,6 +185,12 @@ update_program(struct gl_context *ctx)
    const struct gl_program *prevTCP = ctx->TessCtrlProgram._Current;
    const struct gl_program *prevTEP = ctx->TessEvalProgram._Current;
    const struct gl_program *prevCP = ctx->ComputeProgram._Current;
+   uint64_t prev_vp_affected_states = prevVP ? prevVP->affected_states : 0;
+   uint64_t prev_tcp_affected_states = prevTCP ? prevTCP->affected_states : 0;
+   uint64_t prev_tep_affected_states = prevTEP ? prevTEP->affected_states : 0;
+   uint64_t prev_gp_affected_states = prevGP ? prevGP->affected_states : 0;
+   uint64_t prev_fp_affected_states = prevFP ? prevFP->affected_states : 0;
+   uint64_t prev_cp_affected_states = prevCP ? prevCP->affected_states : 0;
 
    /*
     * Set the ctx->VertexProgram._Current and ctx->FragmentProgram._Current
@@ -259,24 +266,105 @@ update_program(struct gl_context *ctx)
    _mesa_reference_program(ctx, &ctx->ComputeProgram._Current, csProg);
 
    bool vp_changed = ctx->VertexProgram._Current != prevVP;
+   bool tcp_changed = ctx->TessCtrlProgram._Current != prevTCP;
    bool tep_changed = ctx->TessEvalProgram._Current != prevTEP;
    bool gp_changed = ctx->GeometryProgram._Current != prevGP;
+   bool fp_changed = ctx->FragmentProgram._Current != prevFP;
+   bool cp_changed = ctx->ComputeProgram._Current != prevCP;
+
+   /* Set NewDriverState depending on which shaders have changed. */
+   uint64_t dirty = 0;
+
+   /* Flag states used by both new and old shaders to rebind shader resources
+    * (because shaders pack them and reorder them) and to unbind shader
+    * resources properly when transitioning to shaders that don't use them.
+    */
+   if (vp_changed) {
+      ctx->Array.NewVertexElements = true;
+      dirty |= prev_vp_affected_states;
+      if (ctx->VertexProgram._Current)
+         dirty |= ST_NEW_VERTEX_PROGRAM(ctx, ctx->VertexProgram._Current);
+   }
+
+   if (tcp_changed) {
+      dirty |= prev_tcp_affected_states;
+      if (ctx->TessCtrlProgram._Current)
+         dirty |= ctx->TessCtrlProgram._Current->affected_states;
+   }
+
+   if (tep_changed) {
+      dirty |= prev_tep_affected_states;
+      if (ctx->TessEvalProgram._Current)
+         dirty |= ctx->TessEvalProgram._Current->affected_states;
+   }
+
+   if (gp_changed) {
+      dirty |= prev_gp_affected_states;
+      if (ctx->GeometryProgram._Current)
+         dirty |= ctx->GeometryProgram._Current->affected_states;
+   }
+
+   if (fp_changed) {
+      dirty |= prev_fp_affected_states;
+      if (ctx->FragmentProgram._Current)
+         dirty |= ctx->FragmentProgram._Current->affected_states;
+   }
+
+   if (cp_changed) {
+      dirty |= prev_cp_affected_states;
+      if (ctx->ComputeProgram._Current)
+         dirty |= ctx->ComputeProgram._Current->affected_states;
+   }
+
+   struct gl_program *last_vertex_stage;
+   bool last_vertex_stage_dirty;
+
    if (ctx->GeometryProgram._Current) {
-      ctx->LastVertexStageDirty |= gp_changed;
+      last_vertex_stage = ctx->GeometryProgram._Current;
+      last_vertex_stage_dirty = gp_changed;
    } else if (ctx->TessEvalProgram._Current) {
-      ctx->LastVertexStageDirty |= gp_changed | tep_changed;
+      last_vertex_stage = ctx->TessEvalProgram._Current;
+      last_vertex_stage_dirty = gp_changed | tep_changed;
    } else {
-      ctx->LastVertexStageDirty |= gp_changed | tep_changed | vp_changed;
+      last_vertex_stage = ctx->VertexProgram._Current;
+      last_vertex_stage_dirty = gp_changed | tep_changed | vp_changed;
    }
 
-   /* Let the driver know what's happening:
+   /* Find out the number of viewports. This determines how many scissors
+    * and viewport states we need to update.
     */
-   if (ctx->FragmentProgram._Current != prevFP ||
-       ctx->VertexProgram._Current != prevVP ||
-       ctx->GeometryProgram._Current != prevGP ||
-       ctx->TessEvalProgram._Current != prevTEP ||
-       ctx->TessCtrlProgram._Current != prevTCP ||
-       ctx->ComputeProgram._Current != prevCP)
+   struct st_context *st = ctx->st;
+   unsigned num_viewports = 1;
+
+   if (last_vertex_stage &&
+       last_vertex_stage->info.outputs_written & (
+             VARYING_BIT_VIEWPORT | VARYING_BIT_VIEWPORT_MASK))
+      num_viewports = ctx->Const.MaxViewports;
+
+   if (st->state.num_viewports != num_viewports) {
+      st->state.num_viewports = num_viewports;
+      dirty |= ST_NEW_VIEWPORT;
+
+      if (ctx->Scissor.EnableFlags & u_bit_consecutive(0, num_viewports))
+         dirty |= ST_NEW_SCISSOR;
+   }
+
+   if (st->lower_point_size && last_vertex_stage_dirty &&
+       !ctx->VertexProgram.PointSizeEnabled && !ctx->PointSizeIsSet) {
+      if (ctx->GeometryProgram._Current) {
+         st->dirty |= ST_NEW_GS_CONSTANTS;
+      } else if (ctx->TessEvalProgram._Current) {
+         st->dirty |= ST_NEW_TES_CONSTANTS;
+      } else {
+         st->dirty |= ST_NEW_VS_CONSTANTS;
+      }
+   }
+
+   ctx->NewDriverState |= dirty;
+
+   /* Let the driver know what's happening: */
+   if (fp_changed || vp_changed || gp_changed || tep_changed ||
+       tcp_changed || cp_changed)
       return _NEW_PROGRAM;
 
    return 0;
index 0bb8e11e8aac13cdf8c32f59fafbc187c4b888bd..f2ceb59c4a114e9d18002c6d5122f2062a6a2039 100644 (file)
@@ -65,104 +65,11 @@ void st_init_atoms( struct st_context *st )
    call_once(&flag, init_atoms_once);
 }
 
-
 void st_destroy_atoms( struct st_context *st )
 {
    /* no-op */
 }
 
-
-/* Too complex to figure out, just check every time:
- */
-static void check_program_state( struct st_context *st )
-{
-   struct gl_context *ctx = st->ctx;
-   struct gl_program *old_vp = st->vp;
-   struct gl_program *old_tcp = st->tcp;
-   struct gl_program *old_tep = st->tep;
-   struct gl_program *old_gp = st->gp;
-   struct gl_program *old_fp = st->fp;
-
-   struct gl_program *new_vp = ctx->VertexProgram._Current;
-   struct gl_program *new_tcp = ctx->TessCtrlProgram._Current;
-   struct gl_program *new_tep = ctx->TessEvalProgram._Current;
-   struct gl_program *new_gp = ctx->GeometryProgram._Current;
-   struct gl_program *new_fp = ctx->FragmentProgram._Current;
-   uint64_t dirty = 0;
-   unsigned num_viewports = 1;
-
-   /* Flag states used by both new and old shaders to unbind shader resources
-    * properly when transitioning to shaders that don't use them.
-    */
-   if (unlikely(new_vp != old_vp)) {
-      ctx->Array.NewVertexElements = true;
-      if (old_vp)
-         dirty |= old_vp->affected_states;
-      if (new_vp)
-         dirty |= ST_NEW_VERTEX_PROGRAM(st, new_vp);
-   }
-
-   if (unlikely(new_tcp != old_tcp)) {
-      if (old_tcp)
-         dirty |= old_tcp->affected_states;
-      if (new_tcp)
-         dirty |= new_tcp->affected_states;
-   }
-
-   if (unlikely(new_tep != old_tep)) {
-      if (old_tep)
-         dirty |= old_tep->affected_states;
-      if (new_tep)
-         dirty |= new_tep->affected_states;
-   }
-
-   if (unlikely(new_gp != old_gp)) {
-      if (old_gp)
-         dirty |= old_gp->affected_states;
-      if (new_gp)
-         dirty |= new_gp->affected_states;
-   }
-
-   if (unlikely(new_fp != old_fp)) {
-      if (old_fp)
-         dirty |= old_fp->affected_states;
-      if (new_fp)
-         dirty |= new_fp->affected_states;
-   }
-
-   /* Find out the number of viewports. This determines how many scissors
-    * and viewport states we need to update.
-    */
-   struct gl_program *last_prim_shader = new_gp ? new_gp :
-                                         new_tep ? new_tep : new_vp;
-   if (last_prim_shader &&
-       last_prim_shader->info.outputs_written & (
-             VARYING_BIT_VIEWPORT | VARYING_BIT_VIEWPORT_MASK))
-      num_viewports = ctx->Const.MaxViewports;
-
-   if (st->state.num_viewports != num_viewports) {
-      st->state.num_viewports = num_viewports;
-      dirty |= ST_NEW_VIEWPORT;
-
-      if (ctx->Scissor.EnableFlags & u_bit_consecutive(0, num_viewports))
-         dirty |= ST_NEW_SCISSOR;
-   }
-
-   if (st->lower_point_size && st->ctx->LastVertexStageDirty &&
-       !st->ctx->VertexProgram.PointSizeEnabled && !st->ctx->PointSizeIsSet) {
-      if (new_gp) {
-         st->dirty |= ST_NEW_GS_CONSTANTS;
-      } else if (new_tep) {
-         st->dirty |= ST_NEW_TES_CONSTANTS;
-      } else {
-         st->dirty |= ST_NEW_VS_CONSTANTS;
-      }
-   }
-   st->ctx->LastVertexStageDirty = false;
-
-   st->dirty |= dirty;
-}
-
 void st_update_edgeflags(struct st_context *st, bool per_vertex_edgeflags)
 {
    bool edgeflags_enabled = st->ctx->Polygon.FrontMode != GL_FILL ||
@@ -174,7 +81,7 @@ void st_update_edgeflags(struct st_context *st, bool per_vertex_edgeflags)
 
       struct gl_program *vp = st->ctx->VertexProgram._Current;
       if (vp)
-         st->dirty |= ST_NEW_VERTEX_PROGRAM(st, vp);
+         st->dirty |= ST_NEW_VERTEX_PROGRAM(st->ctx, vp);
    }
 
    bool edgeflag_culls_prims = edgeflags_enabled && !vertdata_edgeflags &&
@@ -214,11 +121,6 @@ void st_validate_state( struct st_context *st, enum st_pipeline pipeline )
       if (st->ctx->API == API_OPENGL_COMPAT)
          check_attrib_edgeflag(st);
 
-      if (st->gfx_shaders_may_be_dirty) {
-         check_program_state(st);
-         st->gfx_shaders_may_be_dirty = false;
-      }
-
       if (pipeline == ST_PIPELINE_RENDER)
          pipeline_mask = ST_PIPELINE_RENDER_STATE_MASK;
       else
@@ -230,11 +132,6 @@ void st_validate_state( struct st_context *st, enum st_pipeline pipeline )
       break;
 
    case ST_PIPELINE_META:
-      if (st->gfx_shaders_may_be_dirty) {
-         check_program_state(st);
-         st->gfx_shaders_may_be_dirty = false;
-      }
-
       pipeline_mask = ST_PIPELINE_META_STATE_MASK;
       break;
 
@@ -243,18 +140,6 @@ void st_validate_state( struct st_context *st, enum st_pipeline pipeline )
       break;
 
    case ST_PIPELINE_COMPUTE: {
-      struct gl_program *old_cp = st->cp;
-      struct gl_program *new_cp = ctx->ComputeProgram._Current;
-
-      if (new_cp != old_cp) {
-         if (old_cp)
-            st->dirty |= old_cp->affected_states;
-         assert(new_cp);
-         st->dirty |= new_cp->affected_states;
-      }
-
-      st->compute_shader_may_be_dirty = false;
-
       /*
        * We add the ST_NEW_FB_STATE bit here as well, because glBindFramebuffer
        * acts as a barrier that breaks feedback loops between the framebuffer
index 938a1cf88b7614d0858c456ff85ac1fe8a127448..010f2e5f4e6e3782b7236f7dfadc646f40caf2c6 100644 (file)
@@ -120,8 +120,8 @@ enum {
                                  ST_NEW_SAMPLE_STATE | \
                                  ST_NEW_SAMPLE_SHADING)
 
-#define ST_NEW_VERTEX_PROGRAM(st, p) ((p)->affected_states | \
-                                      (st_user_clip_planes_enabled(st->ctx) ? \
+#define ST_NEW_VERTEX_PROGRAM(ctx, p) ((p)->affected_states | \
+                                      (st_user_clip_planes_enabled(ctx) ? \
                                        ST_NEW_CLIP_STATE : 0))
 
 #define ST_NEW_CONSTANTS        (ST_NEW_VS_CONSTANTS | \
index bfe8de4fd0c07e062f8cc9d47fafcebb2efcd1f6..7b2433ec5a78b25f84fb15125509a0b9eef09932 100644 (file)
@@ -618,8 +618,7 @@ st_Bitmap(struct gl_context *ctx, GLint x, GLint y,
     * explicitly uploaded in the draw_bitmap_quad() function.
     */
    if ((st->dirty | ctx->NewDriverState) & st->active_states &
-       ~ST_NEW_CONSTANTS & ST_PIPELINE_RENDER_STATE_MASK ||
-       st->gfx_shaders_may_be_dirty) {
+       ~ST_NEW_CONSTANTS & ST_PIPELINE_RENDER_STATE_MASK) {
       st_validate_state(st, ST_PIPELINE_META);
    }
 
index e5ae1296266e4ca1ad7cff19d91ea5db48aac8c7..ec62a0a077be8cd5182fba04e9df462cadf9d2aa 100644 (file)
@@ -313,7 +313,7 @@ st_RenderMode(struct gl_context *ctx, GLenum newMode )
       ctx->Driver.DrawGalliumMultiMode = st_feedback_draw_vbo_multi_mode;
       /* need to generate/use a vertex program that emits pos/color/tex */
       if (vp)
-         st->dirty |= ST_NEW_VERTEX_PROGRAM(st, vp);
+         st->dirty |= ST_NEW_VERTEX_PROGRAM(ctx, vp);
    }
 
    /* Restore geometry shader states when leaving GL_SELECT mode. */
index d711bd1750cf75d2b95110e87e14a07e5c05c586..f46eee4f3200efe4753394569f35e1e9068069ae 100644 (file)
@@ -185,8 +185,6 @@ st_invalidate_state(struct gl_context *ctx)
 
    /* Which shaders are dirty will be determined manually. */
    if (new_state & _NEW_PROGRAM) {
-      st->gfx_shaders_may_be_dirty = true;
-      st->compute_shader_may_be_dirty = true;
       /* This will mask out unused shader resources. */
       st->active_states = st_get_active_states(ctx);
    }
index 7f5c5dc65b9faaa0fe9f5e94a5eb420e2771336e..cc952951a89b67cd309b69676e6e59c5e1ef4f11 100644 (file)
@@ -249,12 +249,6 @@ struct st_context
    /** This masks out unused shader resources. Only valid in draw calls. */
    uint64_t active_states;
 
-   /* If true, further analysis of states is required to know if something
-    * has changed. Used mainly for shaders.
-    */
-   bool gfx_shaders_may_be_dirty;
-   bool compute_shader_may_be_dirty;
-
    GLboolean vertdata_edgeflags;
    GLboolean edgeflag_culls_prims;
 
index 18c27c7f4595bee332fc15c15857116d321c2ac8..4bff75bbdf555304e2563af0259bcffb12ba8b59 100644 (file)
@@ -86,8 +86,7 @@ prepare_draw(struct st_context *st, struct gl_context *ctx, uint64_t state_mask,
    st_invalidate_readpix_cache(st);
 
    /* Validate state. */
-   if ((st->dirty | ctx->NewDriverState) & st->active_states & state_mask ||
-       st->gfx_shaders_may_be_dirty) {
+   if ((st->dirty | ctx->NewDriverState) & st->active_states & state_mask) {
       st_validate_state(st, pipeline);
    }
 
index ff784a4480351b1e690f9213084cb6233cacbd44..d041d60addd7743b950166946c330b91348ea163 100644 (file)
@@ -1314,7 +1314,7 @@ 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) {
          st->ctx->Array.NewVertexElements = true;
-         st->dirty |= ST_NEW_VERTEX_PROGRAM(st, prog);
+         st->dirty |= ST_NEW_VERTEX_PROGRAM(st->ctx, prog);
       } else {
          st->dirty |= prog->affected_states;
       }