summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlyssa Rosenzweig <alyssa@rosenzweig.io>2022-09-04 21:47:52 -0400
committerMarge Bot <emma+marge@anholt.net>2022-09-06 21:01:28 +0000
commit22f6efde023dab3a7e2929eee391c38a0a2ec25d (patch)
tree00d6a53ccb3056232718828ab3e8b0a661affb12
parent44853b4d01a4ef4da57e79efefd56fa61c85c6f8 (diff)
asahi: Dirty track everything
Now that we have fine grained state emit code, let's use it to reduce driver overhead. Dirty tracking is delicate: while this seems to work, I've also added an ASAHI_MESA_DEBUG=dirty option in debug builds to disable the optimizations here for future debug. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421>
-rw-r--r--src/asahi/lib/agx_device.h1
-rw-r--r--src/gallium/drivers/asahi/agx_pipe.c5
-rw-r--r--src/gallium/drivers/asahi/agx_state.c269
-rw-r--r--src/gallium/drivers/asahi/agx_state.h28
4 files changed, 206 insertions, 97 deletions
diff --git a/src/asahi/lib/agx_device.h b/src/asahi/lib/agx_device.h
index 3b02971665c..a4a92c9636c 100644
--- a/src/asahi/lib/agx_device.h
+++ b/src/asahi/lib/agx_device.h
@@ -37,6 +37,7 @@ enum agx_dbg {
AGX_DBG_TRACE = BITFIELD_BIT(0),
AGX_DBG_DEQP = BITFIELD_BIT(1),
AGX_DBG_NO16 = BITFIELD_BIT(2),
+ AGX_DBG_DIRTY = BITFIELD_BIT(3),
};
struct agx_device {
diff --git a/src/gallium/drivers/asahi/agx_pipe.c b/src/gallium/drivers/asahi/agx_pipe.c
index b6df82755c2..acf6237f46b 100644
--- a/src/gallium/drivers/asahi/agx_pipe.c
+++ b/src/gallium/drivers/asahi/agx_pipe.c
@@ -52,6 +52,9 @@ static const struct debug_named_value agx_debug_options[] = {
{"trace", AGX_DBG_TRACE, "Trace the command stream"},
{"deqp", AGX_DBG_DEQP, "Hacks for dEQP"},
{"no16", AGX_DBG_NO16, "Disable 16-bit support"},
+#ifndef NDEBUG
+ {"dirty", AGX_DBG_DIRTY, "Disable dirty tracking"},
+#endif
DEBUG_NAMED_VALUE_END
};
@@ -571,8 +574,8 @@ agx_flush(struct pipe_context *pctx,
ctx->batch->load = 0;
ctx->batch->encoder_current = ctx->batch->encoder->ptr.cpu;
ctx->batch->scissor.count = 0;
- ctx->dirty = ~0;
+ agx_dirty_all(ctx);
agx_batch_init_state(ctx->batch);
}
diff --git a/src/gallium/drivers/asahi/agx_state.c b/src/gallium/drivers/asahi/agx_state.c
index 0eb849e9253..94f31e8d62c 100644
--- a/src/gallium/drivers/asahi/agx_state.c
+++ b/src/gallium/drivers/asahi/agx_state.c
@@ -31,6 +31,7 @@
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "util/u_transfer.h"
+#include "util/u_prim.h"
#include "gallium/auxiliary/util/u_draw.h"
#include "gallium/auxiliary/util/u_helpers.h"
#include "gallium/auxiliary/util/u_viewport.h"
@@ -108,6 +109,8 @@ agx_set_blend_color(struct pipe_context *pctx,
if (state)
memcpy(&ctx->blend_color, state, sizeof(*state));
+
+ ctx->stage[PIPE_SHADER_FRAGMENT].dirty = ~0;
}
static void *
@@ -252,6 +255,7 @@ agx_bind_zsa_state(struct pipe_context *pctx, void *cso)
{
struct agx_context *ctx = agx_context(pctx);
ctx->zs = cso;
+ ctx->dirty |= AGX_DIRTY_ZS;
}
static void *
@@ -284,17 +288,24 @@ agx_bind_rasterizer_state(struct pipe_context *pctx, void *cso)
struct agx_context *ctx = agx_context(pctx);
struct agx_rasterizer *so = cso;
+ bool base_cso_changed = (cso == NULL) || (ctx->rast == NULL);
+
/* Check if scissor or depth bias state has changed, since scissor/depth bias
* enable is part of the rasterizer state but everything else needed for
* scissors and depth bias is part of the scissor/depth bias arrays */
- bool scissor_zbias_changed = (cso == NULL) || (ctx->rast == NULL) ||
+ bool scissor_zbias_changed = base_cso_changed ||
(ctx->rast->base.scissor != so->base.scissor) ||
(ctx->rast->base.offset_tri != so->base.offset_tri);
ctx->rast = so;
+ ctx->dirty |= AGX_DIRTY_RS;
if (scissor_zbias_changed)
ctx->dirty |= AGX_DIRTY_SCISSOR_ZBIAS;
+
+ if (base_cso_changed || (ctx->rast->base.sprite_coord_mode !=
+ so->base.sprite_coord_mode))
+ ctx->dirty |= AGX_DIRTY_SPRITE_COORD_MODE;
}
static enum agx_wrap
@@ -374,6 +385,7 @@ agx_bind_sampler_states(struct pipe_context *pctx,
struct agx_context *ctx = agx_context(pctx);
ctx->stage[shader].sampler_count = states ? count : 0;
+ ctx->stage[shader].dirty = ~0;
memcpy(&ctx->stage[shader].samplers[start], states,
sizeof(struct agx_sampler_state *) * count);
@@ -538,6 +550,7 @@ agx_set_sampler_views(struct pipe_context *pctx,
&ctx->stage[shader].textures[i], NULL);
}
ctx->stage[shader].texture_count = new_nr;
+ ctx->stage[shader].dirty = ~0;
}
static void
@@ -612,6 +625,7 @@ agx_set_stencil_ref(struct pipe_context *pctx,
{
struct agx_context *ctx = agx_context(pctx);
ctx->stencil_ref = state;
+ ctx->dirty |= AGX_DIRTY_STENCIL_REF;
}
static void
@@ -802,6 +816,8 @@ agx_set_constant_buffer(struct pipe_context *pctx,
s->cb_mask |= mask;
else
s->cb_mask &= ~mask;
+
+ ctx->stage[shader].dirty = ~0;
}
static void
@@ -833,6 +849,7 @@ agx_set_vertex_buffers(struct pipe_context *pctx,
start_slot, count, unbind_num_trailing_slots, take_ownership);
ctx->dirty |= AGX_DIRTY_VERTEX;
+ ctx->stage[PIPE_SHADER_VERTEX].dirty = ~0;
}
static void *
@@ -1473,6 +1490,9 @@ agx_batch_init_state(struct agx_batch *batch)
agx_ppp_fini(&out, &ppp);
batch->encoder_current = out;
+
+ /* We need to emit prim state at the start. Max collides with all. */
+ batch->reduced_prim = PIPE_PRIM_MAX;
}
static enum agx_object_type
@@ -1485,30 +1505,29 @@ agx_point_object_type(struct agx_rasterizer *rast)
static uint8_t *
agx_encode_state(struct agx_context *ctx, uint8_t *out,
- uint32_t pipeline_vertex, uint32_t pipeline_fragment, uint32_t varyings,
bool is_lines, bool is_points)
{
struct agx_rasterizer *rast = ctx->rast;
- unsigned tex_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;
- agx_pack(out, BIND_VERTEX_PIPELINE, cfg) {
- cfg.pipeline = pipeline_vertex;
- cfg.output_count_1 = ctx->vs->info.varyings.vs.nr_index;
- cfg.output_count_2 = cfg.output_count_1;
+#define IS_DIRTY(ST) !!(ctx->dirty & AGX_DIRTY_##ST)
- cfg.groups_of_8_immediate_textures = DIV_ROUND_UP(tex_count, 8);
- cfg.groups_of_4_samplers = DIV_ROUND_UP(tex_count, 4);
- cfg.more_than_4_textures = tex_count >= 4;
- }
+ if (IS_DIRTY(VS)) {
+ unsigned tex_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;
+ agx_pack(out, BIND_VERTEX_PIPELINE, cfg) {
+ cfg.pipeline = agx_build_pipeline(ctx, ctx->vs, PIPE_SHADER_VERTEX);
+ cfg.output_count_1 = ctx->vs->info.varyings.vs.nr_index;
+ cfg.output_count_2 = cfg.output_count_1;
- out += AGX_BIND_VERTEX_PIPELINE_LENGTH;
+ cfg.groups_of_8_immediate_textures = DIV_ROUND_UP(tex_count, 8);
+ cfg.groups_of_4_samplers = DIV_ROUND_UP(tex_count, 4);
+ cfg.more_than_4_textures = tex_count >= 4;
+ }
+
+ out += AGX_BIND_VERTEX_PIPELINE_LENGTH;
+ }
struct agx_pool *pool = &ctx->batch->pool;
struct agx_compiled_shader *vs = ctx->vs, *fs = ctx->fs;
- bool reads_tib = ctx->fs->info.reads_tib;
- bool sample_mask_from_shader = ctx->fs->info.writes_sample_mask;
- bool no_colour_output = ctx->fs->info.no_colour_output;
-
unsigned zbias = 0;
if (ctx->rast->base.offset_tri) {
@@ -1522,6 +1541,26 @@ agx_encode_state(struct agx_context *ctx, uint8_t *out,
zbias);
}
+ bool varyings_dirty = false;
+
+ if (IS_DIRTY(VS_PROG) || IS_DIRTY(FS_PROG) || IS_DIRTY(RS)) {
+ ctx->batch->varyings = agx_link_varyings_vs_fs(&ctx->batch->pipeline_pool,
+ &ctx->vs->info.varyings.vs,
+ &ctx->fs->info.varyings.fs,
+ ctx->rast->base.flatshade_first);
+
+ varyings_dirty = true;
+ }
+
+ bool object_type_dirty = IS_DIRTY(PRIM) ||
+ (is_points && IS_DIRTY(SPRITE_COORD_MODE));
+
+ bool fragment_control_dirty = IS_DIRTY(ZS) || IS_DIRTY(RS) ||
+ IS_DIRTY(PRIM);
+
+ bool fragment_face_dirty = IS_DIRTY(ZS) || IS_DIRTY(STENCIL_REF) ||
+ IS_DIRTY(RS);
+
enum agx_object_type object_type =
is_points ? agx_point_object_type(rast) :
is_lines ? AGX_OBJECT_TYPE_LINE :
@@ -1529,92 +1568,122 @@ agx_encode_state(struct agx_context *ctx, uint8_t *out,
/* For now, we re-emit almost all state every draw. TODO: perf */
struct agx_ppp_update ppp = agx_new_ppp_update(pool, (struct AGX_PPP_HEADER) {
- .fragment_control = true,
- .fragment_control_2 = true,
- .fragment_front_face = true,
- .fragment_front_face_2 = true,
- .fragment_front_stencil = true,
- .fragment_back_face = true,
- .fragment_back_face_2 = true,
- .fragment_back_stencil = true,
- .output_select = true,
- .varying_word_0 = true,
- .cull = true,
- .fragment_shader = true,
- .output_size = true,
+ .fragment_control = fragment_control_dirty,
+ .fragment_control_2 = IS_DIRTY(PRIM) || IS_DIRTY(FS_PROG),
+ .fragment_front_face = fragment_face_dirty,
+ .fragment_front_face_2 = object_type_dirty,
+ .fragment_front_stencil = IS_DIRTY(ZS),
+ .fragment_back_face = fragment_face_dirty,
+ .fragment_back_face_2 = object_type_dirty,
+ .fragment_back_stencil = IS_DIRTY(ZS),
+ .output_select = IS_DIRTY(VS_PROG) || IS_DIRTY(FS_PROG),
+ .varying_word_0 = IS_DIRTY(VS_PROG),
+ .cull = IS_DIRTY(RS),
+ .fragment_shader = IS_DIRTY(FS) || varyings_dirty,
+ .output_size = IS_DIRTY(VS_PROG),
});
- agx_ppp_push(&ppp, FRAGMENT_CONTROL, cfg) {
- cfg.stencil_test_enable = ctx->zs->base.stencil[0].enabled;
- cfg.two_sided_stencil = ctx->zs->base.stencil[1].enabled;
- cfg.depth_bias_enable = rast->base.offset_tri;
+ if (fragment_control_dirty) {
+ agx_ppp_push(&ppp, FRAGMENT_CONTROL, cfg) {
+ cfg.stencil_test_enable = ctx->zs->base.stencil[0].enabled;
+ cfg.two_sided_stencil = ctx->zs->base.stencil[1].enabled;
+ cfg.depth_bias_enable = rast->base.offset_tri;
- cfg.unk_fill_lines = is_points; /* XXX: what is this? */
+ cfg.unk_fill_lines = is_points; /* XXX: what is this? */
- /* Always enable scissoring so we may scissor to the viewport (TODO:
- * optimize this out if the viewport is the default and the app does not
- * use the scissor test) */
- cfg.scissor_enable = true;
- };
+ /* Always enable scissoring so we may scissor to the viewport (TODO:
+ * optimize this out if the viewport is the default and the app does
+ * not use the scissor test)
+ */
+ cfg.scissor_enable = true;
+ }
+ }
- agx_ppp_push(&ppp, FRAGMENT_CONTROL_2, cfg) {
- cfg.no_colour_output = no_colour_output;
- cfg.lines_or_points = (is_lines || is_points);
- cfg.reads_tilebuffer = reads_tib;
- cfg.sample_mask_from_shader = sample_mask_from_shader;
- };
+ if (IS_DIRTY(PRIM) || IS_DIRTY(FS_PROG)) {
+ agx_ppp_push(&ppp, FRAGMENT_CONTROL_2, cfg) {
+ cfg.lines_or_points = (is_lines || is_points);
+ cfg.no_colour_output = ctx->fs->info.no_colour_output;
+ cfg.reads_tilebuffer = ctx->fs->info.reads_tib;
+ cfg.sample_mask_from_shader = ctx->fs->info.writes_sample_mask;
+ }
+ }
struct agx_fragment_face_packed front_face, back_face;
- agx_pack(&front_face, FRAGMENT_FACE, cfg) {
- cfg.stencil_reference = ctx->stencil_ref.ref_value[0];
- cfg.line_width = rast->line_width;
- cfg.polygon_mode = AGX_POLYGON_MODE_FILL;
- };
- front_face.opaque[0] |= ctx->zs->depth.opaque[0];
- agx_ppp_push_packed(&ppp, &front_face, FRAGMENT_FACE);
- agx_ppp_push(&ppp, FRAGMENT_FACE_2, cfg) cfg.object_type = object_type;
- agx_ppp_push_packed(&ppp, ctx->zs->front_stencil.opaque, FRAGMENT_STENCIL);
+ if (fragment_face_dirty) {
+ agx_pack(&front_face, FRAGMENT_FACE, cfg) {
+ cfg.stencil_reference = ctx->stencil_ref.ref_value[0];
+ cfg.line_width = rast->line_width;
+ cfg.polygon_mode = AGX_POLYGON_MODE_FILL;
+ };
- agx_pack(&back_face, FRAGMENT_FACE, cfg) {
- bool twosided = ctx->zs->base.stencil[1].enabled;
- cfg.stencil_reference = ctx->stencil_ref.ref_value[twosided ? 1 : 0];
+ agx_pack(&back_face, FRAGMENT_FACE, cfg) {
+ bool twosided = ctx->zs->base.stencil[1].enabled;
+ cfg.stencil_reference = ctx->stencil_ref.ref_value[twosided ? 1 : 0];
- cfg.line_width = rast->line_width;
- cfg.polygon_mode = AGX_POLYGON_MODE_FILL;
- };
- back_face.opaque[0] |= ctx->zs->depth.opaque[0];
- agx_ppp_push_packed(&ppp, &back_face, FRAGMENT_FACE);
+ cfg.line_width = rast->line_width;
+ cfg.polygon_mode = AGX_POLYGON_MODE_FILL;
+ };
- agx_ppp_push(&ppp, FRAGMENT_FACE_2, cfg) cfg.object_type = object_type;
- agx_ppp_push_packed(&ppp, ctx->zs->back_stencil.opaque, FRAGMENT_STENCIL);
+ front_face.opaque[0] |= ctx->zs->depth.opaque[0];
+ back_face.opaque[0] |= ctx->zs->depth.opaque[0];
- agx_ppp_push(&ppp, OUTPUT_SELECT, cfg) {
- cfg.varyings = !!fs->info.varyings.fs.nr_bindings;
- cfg.point_size = vs->info.writes_psiz;
- cfg.frag_coord_z = fs->info.varyings.fs.reads_z;
+ agx_ppp_push_packed(&ppp, &front_face, FRAGMENT_FACE);
}
- agx_ppp_push(&ppp, VARYING_0, cfg) {
- cfg.count = agx_num_general_outputs(&ctx->vs->info.varyings.vs);
+ if (object_type_dirty)
+ agx_ppp_push(&ppp, FRAGMENT_FACE_2, cfg) cfg.object_type = object_type;
+
+ if (IS_DIRTY(ZS))
+ agx_ppp_push_packed(&ppp, ctx->zs->front_stencil.opaque, FRAGMENT_STENCIL);
+
+ if (fragment_face_dirty)
+ agx_ppp_push_packed(&ppp, &back_face, FRAGMENT_FACE);
+
+ if (object_type_dirty)
+ agx_ppp_push(&ppp, FRAGMENT_FACE_2, cfg) cfg.object_type = object_type;
+
+ if (IS_DIRTY(ZS))
+ agx_ppp_push_packed(&ppp, ctx->zs->back_stencil.opaque, FRAGMENT_STENCIL);
+
+ if (IS_DIRTY(VS_PROG) || IS_DIRTY(FS_PROG)) {
+ agx_ppp_push(&ppp, OUTPUT_SELECT, cfg) {
+ cfg.varyings = !!fs->info.varyings.fs.nr_bindings;
+ cfg.point_size = vs->info.writes_psiz;
+ cfg.frag_coord_z = fs->info.varyings.fs.reads_z;
+ }
}
- agx_ppp_push_packed(&ppp, ctx->rast->cull, CULL);
+ if (IS_DIRTY(VS_PROG)) {
+ agx_ppp_push(&ppp, VARYING_0, cfg) {
+ cfg.count = agx_num_general_outputs(&ctx->vs->info.varyings.vs);
+ }
+ }
- unsigned frag_tex_count = ctx->stage[PIPE_SHADER_FRAGMENT].texture_count;
- agx_ppp_push(&ppp, FRAGMENT_SHADER, cfg) {
- cfg.groups_of_8_immediate_textures = DIV_ROUND_UP(frag_tex_count, 8);
- cfg.groups_of_4_samplers = DIV_ROUND_UP(frag_tex_count, 4);
- cfg.more_than_4_textures = frag_tex_count >= 4;
- cfg.cf_binding_count = ctx->fs->info.varyings.fs.nr_bindings;
- cfg.pipeline = pipeline_fragment;
- cfg.cf_bindings = varyings;
+ if (IS_DIRTY(RS))
+ agx_ppp_push_packed(&ppp, ctx->rast->cull, CULL);
+
+ if (IS_DIRTY(FS) || varyings_dirty) {
+ unsigned frag_tex_count = ctx->stage[PIPE_SHADER_FRAGMENT].texture_count;
+ agx_ppp_push(&ppp, FRAGMENT_SHADER, cfg) {
+ cfg.pipeline = agx_build_pipeline(ctx, ctx->fs, PIPE_SHADER_FRAGMENT),
+ cfg.groups_of_8_immediate_textures = DIV_ROUND_UP(frag_tex_count, 8);
+ cfg.groups_of_4_samplers = DIV_ROUND_UP(frag_tex_count, 4);
+ cfg.more_than_4_textures = frag_tex_count >= 4;
+ cfg.cf_binding_count = ctx->fs->info.varyings.fs.nr_bindings;
+ cfg.cf_bindings = ctx->batch->varyings;
+ }
}
- agx_ppp_push(&ppp, OUTPUT_SIZE, cfg) cfg.count = vs->info.varyings.vs.nr_index;
+ if (IS_DIRTY(VS_PROG)) {
+ agx_ppp_push(&ppp, OUTPUT_SIZE, cfg)
+ cfg.count = vs->info.varyings.vs.nr_index;
+ }
agx_ppp_fini(&out, &ppp);
+#undef IS_DIRTY
+
return out;
}
@@ -1684,35 +1753,43 @@ agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
if (agx_scissor_culls_everything(ctx))
return;
+#ifndef NDEBUG
+ /* For debugging dirty tracking, mark all state as dirty every draw, forcing
+ * everything to be re-emitted fresh.
+ */
+ if (unlikely(agx_device(pctx->screen)->debug & AGX_DBG_DIRTY))
+ agx_dirty_all(ctx);
+#endif
+
+ /* Dirty track the reduced prim: lines vs points vs triangles */
+ enum pipe_prim_type reduced_prim = u_reduced_prim(info->mode);
+ if (reduced_prim != batch->reduced_prim) ctx->dirty |= AGX_DIRTY_PRIM;
+ batch->reduced_prim = reduced_prim;
+
/* TODO: masks */
ctx->batch->draw |= ~0;
ctx->batch->load |= ~0;
- /* TODO: Dirty track */
- agx_update_vs(ctx);
- agx_update_fs(ctx);
+ /* TODO: These are expensive calls, consider finer dirty tracking */
+ if (agx_update_vs(ctx))
+ ctx->dirty |= AGX_DIRTY_VS | AGX_DIRTY_VS_PROG;
+ else if (ctx->stage[PIPE_SHADER_VERTEX].dirty)
+ ctx->dirty |= AGX_DIRTY_VS;
- /* TODO: Cache or dirty track */
- uint32_t varyings = agx_link_varyings_vs_fs(&ctx->batch->pipeline_pool,
- &ctx->vs->info.varyings.vs,
- &ctx->fs->info.varyings.fs,
- ctx->rast->base.flatshade_first);
+ if (agx_update_fs(ctx))
+ ctx->dirty |= AGX_DIRTY_FS | AGX_DIRTY_FS_PROG;
+ else if (ctx->stage[PIPE_SHADER_FRAGMENT].dirty)
+ ctx->dirty |= AGX_DIRTY_FS;
agx_batch_add_bo(batch, ctx->vs->bo);
agx_batch_add_bo(batch, ctx->fs->bo);
- bool is_lines =
- (info->mode == PIPE_PRIM_LINES) ||
- (info->mode == PIPE_PRIM_LINE_STRIP) ||
- (info->mode == PIPE_PRIM_LINE_LOOP);
-
ptrdiff_t encoder_use = batch->encoder_current - (uint8_t *) batch->encoder->ptr.cpu;
assert((encoder_use + 1024) < batch->encoder->size && "todo: how to expand encoder?");
uint8_t *out = agx_encode_state(ctx, batch->encoder_current,
- agx_build_pipeline(ctx, ctx->vs, PIPE_SHADER_VERTEX),
- agx_build_pipeline(ctx, ctx->fs, PIPE_SHADER_FRAGMENT),
- varyings, is_lines, info->mode == PIPE_PRIM_POINTS);
+ reduced_prim == PIPE_PRIM_LINES,
+ reduced_prim == PIPE_PRIM_POINTS);
enum agx_primitive prim = agx_primitive_for_pipe(info->mode);
unsigned idx_size = info->index_size;
diff --git a/src/gallium/drivers/asahi/agx_state.h b/src/gallium/drivers/asahi/agx_state.h
index d1db2f771fa..2221ea5d7f3 100644
--- a/src/gallium/drivers/asahi/agx_state.h
+++ b/src/gallium/drivers/asahi/agx_state.h
@@ -104,6 +104,12 @@ struct agx_batch {
double clear_depth;
unsigned clear_stencil;
+ /* Whether we're drawing points, lines, or triangles */
+ enum pipe_prim_type reduced_prim;
+
+ /* Current varyings linkage structures */
+ uint32_t varyings;
+
/* Resource list requirements, represented as a bit set indexed by BO
* handles (GEM handles on Linux, or IOGPU's equivalent on macOS) */
BITSET_WORD bo_list[256];
@@ -142,6 +148,19 @@ enum agx_dirty {
AGX_DIRTY_VERTEX = BITFIELD_BIT(0),
AGX_DIRTY_VIEWPORT = BITFIELD_BIT(1),
AGX_DIRTY_SCISSOR_ZBIAS = BITFIELD_BIT(2),
+ AGX_DIRTY_ZS = BITFIELD_BIT(3),
+ AGX_DIRTY_STENCIL_REF = BITFIELD_BIT(4),
+ AGX_DIRTY_RS = BITFIELD_BIT(5),
+ AGX_DIRTY_SPRITE_COORD_MODE = BITFIELD_BIT(6),
+ AGX_DIRTY_PRIM = BITFIELD_BIT(7),
+
+ /* Vertex/fragment pipelines, including uniforms and textures */
+ AGX_DIRTY_VS = BITFIELD_BIT(8),
+ AGX_DIRTY_FS = BITFIELD_BIT(9),
+
+ /* Just the progs themselves */
+ AGX_DIRTY_VS_PROG = BITFIELD_BIT(10),
+ AGX_DIRTY_FS_PROG = BITFIELD_BIT(11),
};
struct agx_context {
@@ -184,6 +203,15 @@ agx_context(struct pipe_context *pctx)
return (struct agx_context *) pctx;
}
+static inline void
+agx_dirty_all(struct agx_context *ctx)
+{
+ ctx->dirty = ~0;
+
+ for (unsigned i = 0; i < ARRAY_SIZE(ctx->stage); ++i)
+ ctx->stage[i].dirty = ~0;
+}
+
struct agx_rasterizer {
struct pipe_rasterizer_state base;
uint8_t cull[AGX_CULL_LENGTH];