_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);
}
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 */
#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)
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
_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;
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 ||
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 &&
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
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;
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
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 | \
* 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);
}
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. */
/* 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);
}
/** 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;
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);
}
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;
}