diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2014-10-18 10:58:03 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2014-10-20 21:20:12 +0100 |
commit | 316155db98aac4d5d0a7077e86453e4d41a3029d (patch) | |
tree | 4f9965eb192947700bd45f28ff9e57036c2d4f32 /src/sna/gen6_render.c | |
parent | bf7b5a24bbfc8a3553be6baa457ec92559dd3d65 (diff) |
sna/gen6: Apply gen7 flushing
Clemens Eisserer noticed that glyphs would randomly disapper whilst
being rendered on his Sandybridge, a sign that the GPU is not flushing
its internal state on pipeline changes. As a precaution, adopt the
Ivybridge flush semantics (whilst preserving the required Sandybridge
workarounds).
Reported-and-tested-by: Clemens Eisserer <linuxhippy@gmail.com>
Reported-and-tested-by: Ilia Mirkin <imirkin@alum.mit.edu>
References: https://bugs.freedesktop.org/show_bug.cgi?id=85158
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna/gen6_render.c')
-rw-r--r-- | src/sna/gen6_render.c | 129 |
1 files changed, 84 insertions, 45 deletions
diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c index a05196a5..95eb415d 100644 --- a/src/sna/gen6_render.c +++ b/src/sna/gen6_render.c @@ -47,6 +47,10 @@ #include "gen4_source.h" #include "gen4_vertex.h" +#define ALWAYS_INVALIDATE 0 +#define ALWAYS_FLUSH 0 +#define ALWAYS_STALL 0 + #define NO_COMPOSITE 0 #define NO_COMPOSITE_SPANS 0 #define NO_COPY 0 @@ -397,6 +401,42 @@ gen6_choose_composite_kernel(int op, bool has_mask, bool is_ca, bool is_affine) return base + !is_affine; } +inline static void +gen6_emit_pipe_invalidate(struct sna *sna) +{ + OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); + OUT_BATCH(GEN6_PIPE_CONTROL_WC_FLUSH | + GEN6_PIPE_CONTROL_TC_FLUSH | + GEN6_PIPE_CONTROL_CS_STALL); + OUT_BATCH(0); + OUT_BATCH(0); +} + +inline static void +gen6_emit_pipe_flush(struct sna *sna, bool need_stall) +{ + unsigned stall; + + stall = 0; + if (need_stall) + stall = GEN6_PIPE_CONTROL_CS_STALL; + + OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); + OUT_BATCH(GEN6_PIPE_CONTROL_WC_FLUSH | stall); + OUT_BATCH(0); + OUT_BATCH(0); +} + +inline static void +gen6_emit_pipe_stall(struct sna *sna) +{ + OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); + OUT_BATCH(GEN6_PIPE_CONTROL_CS_STALL | + GEN6_PIPE_CONTROL_STALL_AT_SCOREBOARD); + OUT_BATCH(0); + OUT_BATCH(0); +} + static void gen6_emit_urb(struct sna *sna) { @@ -547,13 +587,13 @@ gen6_emit_invariant(struct sna *sna) sna->render_state.gen6.needs_invariant = false; } -static bool +static void gen6_emit_cc(struct sna *sna, int blend) { struct gen6_render_state *render = &sna->render_state.gen6; if (render->blend == blend) - return blend != NO_BLEND; + return; DBG(("%s: blend = %x\n", __FUNCTION__, blend)); @@ -568,7 +608,6 @@ gen6_emit_cc(struct sna *sna, int blend) } render->blend = blend; - return blend != NO_BLEND; } static void @@ -692,7 +731,7 @@ gen6_emit_drawing_rectangle(struct sna *sna, if (sna->render_state.gen6.drawrect_limit == limit && sna->render_state.gen6.drawrect_offset == offset) - return false; + return true; /* [DevSNB-C+{W/A}] Before any depth stall flush (including those * produced by non-pipelined state commands), software needs to first @@ -703,13 +742,8 @@ gen6_emit_drawing_rectangle(struct sna *sna, * BEFORE the pipe-control with a post-sync op and no write-cache * flushes. */ - if (!sna->render_state.gen6.first_state_packet) { - OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); - OUT_BATCH(GEN6_PIPE_CONTROL_CS_STALL | - GEN6_PIPE_CONTROL_STALL_AT_SCOREBOARD); - OUT_BATCH(0); - OUT_BATCH(0); - } + if (!sna->render_state.gen6.first_state_packet) + gen6_emit_pipe_stall(sna); OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); OUT_BATCH(GEN6_PIPE_CONTROL_WRITE_TIME); @@ -729,7 +763,7 @@ gen6_emit_drawing_rectangle(struct sna *sna, sna->render_state.gen6.drawrect_offset = offset; sna->render_state.gen6.drawrect_limit = limit; - return true; + return false; } static void @@ -853,51 +887,56 @@ gen6_emit_vertex_elements(struct sna *sna, } static void -gen6_emit_flush(struct sna *sna) -{ - OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); - OUT_BATCH(GEN6_PIPE_CONTROL_WC_FLUSH | - GEN6_PIPE_CONTROL_TC_FLUSH | - GEN6_PIPE_CONTROL_CS_STALL); - OUT_BATCH(0); - OUT_BATCH(0); -} - -static void gen6_emit_state(struct sna *sna, const struct sna_composite_op *op, uint16_t wm_binding_table) { - bool need_flush, need_stall; + bool need_invalidate; + bool need_flush; + bool need_stall; assert(op->dst.bo->exec); - need_stall = wm_binding_table & 1; - need_flush = false; - if (gen6_emit_cc(sna, GEN6_BLEND(op->u.gen6.flags))) - need_flush = need_stall; - gen6_emit_sampler(sna, GEN6_SAMPLER(op->u.gen6.flags)); - gen6_emit_sf(sna, GEN6_VERTEX(op->u.gen6.flags) >> 2); - gen6_emit_wm(sna, GEN6_KERNEL(op->u.gen6.flags), GEN6_VERTEX(op->u.gen6.flags) >> 2); - gen6_emit_vertex_elements(sna, op); + need_flush = wm_binding_table & 1; + if (ALWAYS_FLUSH) + need_flush = true; - need_stall |= gen6_emit_binding_table(sna, wm_binding_table & ~1); - if (gen6_emit_drawing_rectangle(sna, op)) - need_stall = false; - if (need_flush || kgem_bo_is_dirty(op->src.bo) || kgem_bo_is_dirty(op->mask.bo)) { - gen6_emit_flush(sna); + wm_binding_table &= ~1; + need_stall = sna->render_state.gen6.surface_table != wm_binding_table; + if (ALWAYS_STALL) + need_stall = true; + + need_invalidate = kgem_bo_is_dirty(op->src.bo) || kgem_bo_is_dirty(op->mask.bo); + if (ALWAYS_INVALIDATE) + need_invalidate = true; + + if (need_invalidate) { + gen6_emit_pipe_invalidate(sna); kgem_clear_dirty(&sna->kgem); assert(op->dst.bo->exec); kgem_bo_mark_dirty(op->dst.bo); + + need_flush = false; need_stall = false; + sna->render_state.gen6.first_state_packet = true; } - if (need_stall) { - OUT_BATCH(GEN6_PIPE_CONTROL | (4 - 2)); - OUT_BATCH(GEN6_PIPE_CONTROL_CS_STALL | - GEN6_PIPE_CONTROL_STALL_AT_SCOREBOARD); - OUT_BATCH(0); - OUT_BATCH(0); + if (need_flush) { + gen6_emit_pipe_flush(sna, need_stall); + need_stall = false; + sna->render_state.gen6.first_state_packet = true; } + + need_stall &= gen6_emit_drawing_rectangle(sna, op); + if (need_stall) + gen6_emit_pipe_stall(sna); + + gen6_emit_cc(sna, GEN6_BLEND(op->u.gen6.flags)); + gen6_emit_sampler(sna, GEN6_SAMPLER(op->u.gen6.flags)); + gen6_emit_sf(sna, GEN6_VERTEX(op->u.gen6.flags) >> 2); + gen6_emit_wm(sna, GEN6_KERNEL(op->u.gen6.flags), GEN6_VERTEX(op->u.gen6.flags) >> 2); + gen6_emit_vertex_elements(sna, op); + gen6_emit_binding_table(sna, wm_binding_table); + sna->render_state.gen6.first_state_packet = false; } @@ -912,7 +951,7 @@ static bool gen6_magic_ca_pass(struct sna *sna, DBG(("%s: CA fixup (%d -> %d)\n", __FUNCTION__, sna->render.vertex_start, sna->render.vertex_index)); - gen6_emit_flush(sna); + gen6_emit_pipe_stall(sna); gen6_emit_cc(sna, gen6_get_blend(PictOpAdd, true, op->dst.format)); gen6_emit_wm(sna, @@ -1176,7 +1215,7 @@ static int gen6_get_rectangles__flush(struct sna *sna, if (sna->render.vertex_offset) { gen4_vertex_flush(sna); if (gen6_magic_ca_pass(sna, op)) { - gen6_emit_flush(sna); + gen6_emit_pipe_stall(sna); gen6_emit_cc(sna, GEN6_BLEND(op->u.gen6.flags)); gen6_emit_wm(sna, GEN6_KERNEL(op->u.gen6.flags), |