From aaa4b0e6186842e40a858e82f31d146a712ab082 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Fri, 18 Nov 2022 06:42:07 -0500 Subject: [PATCH] st/mesa: move check_program_state code into _mesa_update_state _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 Part-of: --- src/mesa/main/compute.c | 3 +- src/mesa/main/mtypes.h | 1 - src/mesa/main/state.c | 108 ++++++++++++++++++++++++++--- src/mesa/state_tracker/st_atom.c | 117 +------------------------------- src/mesa/state_tracker/st_atom.h | 4 +- src/mesa/state_tracker/st_cb_bitmap.c | 3 +- src/mesa/state_tracker/st_cb_feedback.c | 2 +- src/mesa/state_tracker/st_context.c | 2 - src/mesa/state_tracker/st_context.h | 6 -- src/mesa/state_tracker/st_draw.c | 3 +- src/mesa/state_tracker/st_program.c | 2 +- 11 files changed, 106 insertions(+), 145 deletions(-) diff --git a/src/mesa/main/compute.c b/src/mesa/main/compute.c index 8e585fd..1705ec6 100644 --- a/src/mesa/main/compute.c +++ b/src/mesa/main/compute.c @@ -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); } diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 6bd2894..80033bd 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -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 */ diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index 13d62d0..daf5688 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -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; diff --git a/src/mesa/state_tracker/st_atom.c b/src/mesa/state_tracker/st_atom.c index 0bb8e11..f2ceb59 100644 --- a/src/mesa/state_tracker/st_atom.c +++ b/src/mesa/state_tracker/st_atom.c @@ -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 diff --git a/src/mesa/state_tracker/st_atom.h b/src/mesa/state_tracker/st_atom.h index 938a1cf..010f2e5 100644 --- a/src/mesa/state_tracker/st_atom.h +++ b/src/mesa/state_tracker/st_atom.h @@ -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 | \ diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c index bfe8de4..7b2433e 100644 --- a/src/mesa/state_tracker/st_cb_bitmap.c +++ b/src/mesa/state_tracker/st_cb_bitmap.c @@ -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); } diff --git a/src/mesa/state_tracker/st_cb_feedback.c b/src/mesa/state_tracker/st_cb_feedback.c index e5ae129..ec62a0a 100644 --- a/src/mesa/state_tracker/st_cb_feedback.c +++ b/src/mesa/state_tracker/st_cb_feedback.c @@ -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. */ diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index d711bd1..f46eee4 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -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); } diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index 7f5c5dc..cc95295 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -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; diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index 18c27c7..4bff75b 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -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); } diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index ff784a4..d041d60 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -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; } -- 2.7.4