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 <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19859>
This commit is contained in:
Marek Olšák 2022-11-18 06:42:07 -05:00 committed by Marge Bot
parent 0311827337
commit aaa4b0e618
11 changed files with 109 additions and 148 deletions

View file

@ -296,8 +296,7 @@ prepare_compute(struct gl_context *ctx)
_mesa_update_state(ctx); _mesa_update_state(ctx);
if ((st->dirty | ctx->NewDriverState) & st->active_states & if ((st->dirty | ctx->NewDriverState) & st->active_states &
ST_PIPELINE_COMPUTE_STATE_MASK || ST_PIPELINE_COMPUTE_STATE_MASK)
st->compute_shader_may_be_dirty)
st_validate_state(st, ST_PIPELINE_COMPUTE); st_validate_state(st, ST_PIPELINE_COMPUTE);
} }

View file

@ -3581,7 +3581,6 @@ struct gl_context
GLuint TextureStateTimestamp; /**< detect changes to shared state */ 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 */ GLboolean PointSizeIsSet; /**< the glPointSize value in the shader is set */
/** \name For debugging/development only */ /** \name For debugging/development only */

View file

@ -56,6 +56,7 @@
#include "blend.h" #include "blend.h"
#include "state_tracker/st_context.h" #include "state_tracker/st_context.h"
#include "state_tracker/st_util.h"
void void
_mesa_update_allow_draw_out_of_order(struct gl_context *ctx) _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 *prevTCP = ctx->TessCtrlProgram._Current;
const struct gl_program *prevTEP = ctx->TessEvalProgram._Current; const struct gl_program *prevTEP = ctx->TessEvalProgram._Current;
const struct gl_program *prevCP = ctx->ComputeProgram._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 * 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); _mesa_reference_program(ctx, &ctx->ComputeProgram._Current, csProg);
bool vp_changed = ctx->VertexProgram._Current != prevVP; bool vp_changed = ctx->VertexProgram._Current != prevVP;
bool tcp_changed = ctx->TessCtrlProgram._Current != prevTCP;
bool tep_changed = ctx->TessEvalProgram._Current != prevTEP; bool tep_changed = ctx->TessEvalProgram._Current != prevTEP;
bool gp_changed = ctx->GeometryProgram._Current != prevGP; bool gp_changed = ctx->GeometryProgram._Current != prevGP;
if (ctx->GeometryProgram._Current) { bool fp_changed = ctx->FragmentProgram._Current != prevFP;
ctx->LastVertexStageDirty |= gp_changed; bool cp_changed = ctx->ComputeProgram._Current != prevCP;
} else if (ctx->TessEvalProgram._Current) {
ctx->LastVertexStageDirty |= gp_changed | tep_changed; /* Set NewDriverState depending on which shaders have changed. */
} else { uint64_t dirty = 0;
ctx->LastVertexStageDirty |= gp_changed | tep_changed | vp_changed;
/* 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);
} }
/* Let the driver know what's happening: 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) {
last_vertex_stage = ctx->GeometryProgram._Current;
last_vertex_stage_dirty = gp_changed;
} else if (ctx->TessEvalProgram._Current) {
last_vertex_stage = ctx->TessEvalProgram._Current;
last_vertex_stage_dirty = gp_changed | tep_changed;
} else {
last_vertex_stage = ctx->VertexProgram._Current;
last_vertex_stage_dirty = gp_changed | tep_changed | vp_changed;
}
/* Find out the number of viewports. This determines how many scissors
* and viewport states we need to update.
*/ */
if (ctx->FragmentProgram._Current != prevFP || struct st_context *st = ctx->st;
ctx->VertexProgram._Current != prevVP || unsigned num_viewports = 1;
ctx->GeometryProgram._Current != prevGP ||
ctx->TessEvalProgram._Current != prevTEP || if (last_vertex_stage &&
ctx->TessCtrlProgram._Current != prevTCP || last_vertex_stage->info.outputs_written & (
ctx->ComputeProgram._Current != prevCP) 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 _NEW_PROGRAM;
return 0; return 0;

View file

@ -65,104 +65,11 @@ void st_init_atoms( struct st_context *st )
call_once(&flag, init_atoms_once); call_once(&flag, init_atoms_once);
} }
void st_destroy_atoms( struct st_context *st ) void st_destroy_atoms( struct st_context *st )
{ {
/* no-op */ /* 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) void st_update_edgeflags(struct st_context *st, bool per_vertex_edgeflags)
{ {
bool edgeflags_enabled = st->ctx->Polygon.FrontMode != GL_FILL || 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; struct gl_program *vp = st->ctx->VertexProgram._Current;
if (vp) 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 && 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) if (st->ctx->API == API_OPENGL_COMPAT)
check_attrib_edgeflag(st); 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) if (pipeline == ST_PIPELINE_RENDER)
pipeline_mask = ST_PIPELINE_RENDER_STATE_MASK; pipeline_mask = ST_PIPELINE_RENDER_STATE_MASK;
else else
@ -230,11 +132,6 @@ void st_validate_state( struct st_context *st, enum st_pipeline pipeline )
break; break;
case ST_PIPELINE_META: 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; pipeline_mask = ST_PIPELINE_META_STATE_MASK;
break; break;
@ -243,18 +140,6 @@ void st_validate_state( struct st_context *st, enum st_pipeline pipeline )
break; break;
case ST_PIPELINE_COMPUTE: { 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 * We add the ST_NEW_FB_STATE bit here as well, because glBindFramebuffer
* acts as a barrier that breaks feedback loops between the framebuffer * acts as a barrier that breaks feedback loops between the framebuffer

View file

@ -120,8 +120,8 @@ enum {
ST_NEW_SAMPLE_STATE | \ ST_NEW_SAMPLE_STATE | \
ST_NEW_SAMPLE_SHADING) ST_NEW_SAMPLE_SHADING)
#define ST_NEW_VERTEX_PROGRAM(st, p) ((p)->affected_states | \ #define ST_NEW_VERTEX_PROGRAM(ctx, p) ((p)->affected_states | \
(st_user_clip_planes_enabled(st->ctx) ? \ (st_user_clip_planes_enabled(ctx) ? \
ST_NEW_CLIP_STATE : 0)) ST_NEW_CLIP_STATE : 0))
#define ST_NEW_CONSTANTS (ST_NEW_VS_CONSTANTS | \ #define ST_NEW_CONSTANTS (ST_NEW_VS_CONSTANTS | \

View file

@ -618,8 +618,7 @@ st_Bitmap(struct gl_context *ctx, GLint x, GLint y,
* explicitly uploaded in the draw_bitmap_quad() function. * explicitly uploaded in the draw_bitmap_quad() function.
*/ */
if ((st->dirty | ctx->NewDriverState) & st->active_states & if ((st->dirty | ctx->NewDriverState) & st->active_states &
~ST_NEW_CONSTANTS & ST_PIPELINE_RENDER_STATE_MASK || ~ST_NEW_CONSTANTS & ST_PIPELINE_RENDER_STATE_MASK) {
st->gfx_shaders_may_be_dirty) {
st_validate_state(st, ST_PIPELINE_META); st_validate_state(st, ST_PIPELINE_META);
} }

View file

@ -313,7 +313,7 @@ st_RenderMode(struct gl_context *ctx, GLenum newMode )
ctx->Driver.DrawGalliumMultiMode = st_feedback_draw_vbo_multi_mode; ctx->Driver.DrawGalliumMultiMode = st_feedback_draw_vbo_multi_mode;
/* need to generate/use a vertex program that emits pos/color/tex */ /* need to generate/use a vertex program that emits pos/color/tex */
if (vp) 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. */ /* Restore geometry shader states when leaving GL_SELECT mode. */

View file

@ -185,8 +185,6 @@ st_invalidate_state(struct gl_context *ctx)
/* Which shaders are dirty will be determined manually. */ /* Which shaders are dirty will be determined manually. */
if (new_state & _NEW_PROGRAM) { 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. */ /* This will mask out unused shader resources. */
st->active_states = st_get_active_states(ctx); st->active_states = st_get_active_states(ctx);
} }

View file

@ -249,12 +249,6 @@ struct st_context
/** This masks out unused shader resources. Only valid in draw calls. */ /** This masks out unused shader resources. Only valid in draw calls. */
uint64_t active_states; 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 vertdata_edgeflags;
GLboolean edgeflag_culls_prims; GLboolean edgeflag_culls_prims;

View file

@ -86,8 +86,7 @@ prepare_draw(struct st_context *st, struct gl_context *ctx, uint64_t state_mask,
st_invalidate_readpix_cache(st); st_invalidate_readpix_cache(st);
/* Validate state. */ /* Validate state. */
if ((st->dirty | ctx->NewDriverState) & st->active_states & state_mask || if ((st->dirty | ctx->NewDriverState) & st->active_states & state_mask) {
st->gfx_shaders_may_be_dirty) {
st_validate_state(st, pipeline); st_validate_state(st, pipeline);
} }

View 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 (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->ctx->Array.NewVertexElements = true;
st->dirty |= ST_NEW_VERTEX_PROGRAM(st, prog); st->dirty |= ST_NEW_VERTEX_PROGRAM(st->ctx, prog);
} else { } else {
st->dirty |= prog->affected_states; st->dirty |= prog->affected_states;
} }