radeonsi/gfx9: implement the scissor bug workaround without performance drop
authorMarek Olšák <marek.olsak@amd.com>
Thu, 31 May 2018 02:02:00 +0000 (22:02 -0400)
committerMarek Olšák <marek.olsak@amd.com>
Thu, 14 Jun 2018 02:00:27 +0000 (22:00 -0400)
This might improve performance on Vega10 and Raven.

Tested-by: Dieter Nützel <Dieter@nuetzel-hh.de>
src/gallium/drivers/radeonsi/si_state.h
src/gallium/drivers/radeonsi/si_state_draw.c

index 8232e34b1b6caa201a2b31cc308d48fef9af30a1..dc05021f4920e2a84ecda56dac965a7c7e407eca 100644 (file)
@@ -172,8 +172,24 @@ union si_state {
        struct si_pm4_state     *array[0];
 };
 
+#define SI_STATE_IDX(name) \
+       (offsetof(union si_state, named.name) / sizeof(struct si_pm4_state *))
+#define SI_STATE_BIT(name) (1 << SI_STATE_IDX(name))
 #define SI_NUM_STATES (sizeof(union si_state) / sizeof(struct si_pm4_state *))
 
+static inline unsigned si_states_that_roll_context(void)
+{
+       return (SI_STATE_BIT(blend) |
+               SI_STATE_BIT(rasterizer) |
+               SI_STATE_BIT(dsa) |
+               SI_STATE_BIT(poly_offset) |
+               SI_STATE_BIT(es) |
+               SI_STATE_BIT(gs) |
+               SI_STATE_BIT(vgt_shader_config) |
+               SI_STATE_BIT(vs) |
+               SI_STATE_BIT(ps));
+}
+
 union si_state_atoms {
        struct {
                /* The order matters. */
@@ -200,8 +216,31 @@ union si_state_atoms {
        struct si_atom array[0];
 };
 
+#define SI_ATOM_BIT(name) (1 << (offsetof(union si_state_atoms, s.name) / \
+                                sizeof(struct si_atom)))
 #define SI_NUM_ATOMS (sizeof(union si_state_atoms)/sizeof(struct si_atom*))
 
+static inline unsigned si_atoms_that_roll_context(void)
+{
+       return (SI_ATOM_BIT(streamout_begin) |
+               SI_ATOM_BIT(streamout_enable) |
+               SI_ATOM_BIT(framebuffer) |
+               SI_ATOM_BIT(msaa_sample_locs) |
+               SI_ATOM_BIT(db_render_state) |
+               SI_ATOM_BIT(dpbb_state) |
+               SI_ATOM_BIT(msaa_config) |
+               SI_ATOM_BIT(sample_mask) |
+               SI_ATOM_BIT(cb_render_state) |
+               SI_ATOM_BIT(blend_color) |
+               SI_ATOM_BIT(clip_regs) |
+               SI_ATOM_BIT(clip_state) |
+               SI_ATOM_BIT(scissors) |
+               SI_ATOM_BIT(viewports) |
+               SI_ATOM_BIT(stencil_ref) |
+               SI_ATOM_BIT(spi_map) |
+               SI_ATOM_BIT(scratch_state));
+}
+
 struct si_shader_data {
        uint32_t                sh_base[SI_NUM_SHADERS];
 };
@@ -343,9 +382,6 @@ struct si_buffer_resources {
        unsigned                        enabled_mask;
 };
 
-#define si_pm4_block_idx(member) \
-       (offsetof(union si_state, named.member) / sizeof(struct si_pm4_state *))
-
 #define si_pm4_state_changed(sctx, member) \
        ((sctx)->queued.named.member != (sctx)->emitted.named.member)
 
@@ -355,7 +391,7 @@ struct si_buffer_resources {
 #define si_pm4_bind_state(sctx, member, value) \
        do { \
                (sctx)->queued.named.member = (value); \
-               (sctx)->dirty_states |= 1 << si_pm4_block_idx(member); \
+               (sctx)->dirty_states |= SI_STATE_BIT(member); \
        } while(0)
 
 #define si_pm4_delete_state(sctx, member, value) \
@@ -364,7 +400,7 @@ struct si_buffer_resources {
                        (sctx)->queued.named.member = NULL; \
                } \
                si_pm4_free_state(sctx, (struct si_pm4_state *)(value), \
-                                 si_pm4_block_idx(member)); \
+                                 SI_STATE_IDX(member)); \
        } while(0)
 
 /* si_descriptors.c */
index 42522c012915b72d58275c4e3abfd09e2ee35f8d..5588c9a2c53955c46a179a76f4abfb6d18bf5071 100644 (file)
@@ -66,7 +66,7 @@ static unsigned si_conv_pipe_prim(unsigned mode)
  * The information about LDS and other non-compile-time parameters is then
  * written to userdata SGPRs.
  */
-static void si_emit_derived_tess_state(struct si_context *sctx,
+static bool si_emit_derived_tess_state(struct si_context *sctx,
                                       const struct pipe_draw_info *info,
                                       unsigned *num_patches)
 {
@@ -110,7 +110,7 @@ static void si_emit_derived_tess_state(struct si_context *sctx,
            (!has_primid_instancing_bug ||
             (sctx->last_tess_uses_primid == tess_uses_primid))) {
                *num_patches = sctx->last_num_patches;
-               return;
+               return false;
        }
 
        sctx->last_ls = ls_current;
@@ -289,7 +289,9 @@ static void si_emit_derived_tess_state(struct si_context *sctx,
                                               ls_hs_config);
                }
                sctx->last_ls_hs_config = ls_hs_config;
+               return true; /* true if the context rolls */
        }
+       return false;
 }
 
 static unsigned si_num_prims_for_vertices(const struct pipe_draw_info *info)
@@ -512,11 +514,11 @@ static unsigned si_get_ia_multi_vgt_param(struct si_context *sctx,
 }
 
 /* rast_prim is the primitive type after GS. */
-static void si_emit_rasterizer_prim_state(struct si_context *sctx)
+static bool si_emit_rasterizer_prim_state(struct si_context *sctx)
 {
        struct radeon_winsys_cs *cs = sctx->gfx_cs;
        enum pipe_prim_type rast_prim = sctx->current_rast_prim;
-       struct si_state_rasterizer *rs = sctx->emitted.named.rasterizer;
+       struct si_state_rasterizer *rs = sctx->queued.named.rasterizer;
 
        /* Skip this if not rendering lines. */
        if (rast_prim != PIPE_PRIM_LINES &&
@@ -524,11 +526,11 @@ static void si_emit_rasterizer_prim_state(struct si_context *sctx)
            rast_prim != PIPE_PRIM_LINE_STRIP &&
            rast_prim != PIPE_PRIM_LINES_ADJACENCY &&
            rast_prim != PIPE_PRIM_LINE_STRIP_ADJACENCY)
-               return;
+               return false;
 
        if (rast_prim == sctx->last_rast_prim &&
            rs->pa_sc_line_stipple == sctx->last_sc_line_stipple)
-               return;
+               return false;
 
        /* For lines, reset the stipple pattern at each primitive. Otherwise,
         * reset the stipple pattern at each packet (line strips, line loops).
@@ -539,6 +541,7 @@ static void si_emit_rasterizer_prim_state(struct si_context *sctx)
 
        sctx->last_rast_prim = rast_prim;
        sctx->last_sc_line_stipple = rs->pa_sc_line_stipple;
+       return true; /* true if the context rolls */
 }
 
 static void si_emit_vs_state(struct si_context *sctx,
@@ -565,6 +568,14 @@ static void si_emit_vs_state(struct si_context *sctx,
        }
 }
 
+static inline bool si_prim_restart_index_changed(struct si_context *sctx,
+                                                const struct pipe_draw_info *info)
+{
+       return info->primitive_restart &&
+              (info->restart_index != sctx->last_restart_index ||
+               sctx->last_restart_index == SI_RESTART_INDEX_UNKNOWN);
+}
+
 static void si_emit_draw_registers(struct si_context *sctx,
                                   const struct pipe_draw_info *info,
                                   unsigned num_patches)
@@ -607,9 +618,7 @@ static void si_emit_draw_registers(struct si_context *sctx,
                sctx->last_primitive_restart_en = info->primitive_restart;
 
        }
-       if (info->primitive_restart &&
-           (info->restart_index != sctx->last_restart_index ||
-            sctx->last_restart_index == SI_RESTART_INDEX_UNKNOWN)) {
+       if (si_prim_restart_index_changed(sctx, info)) {
                radeon_set_context_reg(cs, R_02840C_VGT_MULTI_PRIM_IB_RESET_INDX,
                                       info->restart_index);
                sctx->last_restart_index = info->restart_index;
@@ -1152,6 +1161,28 @@ static void si_get_draw_start_count(struct si_context *sctx,
 static void si_emit_all_states(struct si_context *sctx, const struct pipe_draw_info *info,
                               unsigned skip_atom_mask)
 {
+       unsigned num_patches = 0;
+       bool context_roll = false; /* set correctly for GFX9 only */
+
+       context_roll |= si_emit_rasterizer_prim_state(sctx);
+       if (sctx->tes_shader.cso)
+               context_roll |= si_emit_derived_tess_state(sctx, info, &num_patches);
+       if (info->count_from_stream_output)
+               context_roll = true;
+
+       /* Vega10/Raven scissor bug workaround. When any context register is
+        * written (i.e. the GPU rolls the context), PA_SC_VPORT_SCISSOR
+        * registers must be written too.
+        */
+       if ((sctx->family == CHIP_VEGA10 || sctx->family == CHIP_RAVEN) &&
+           (context_roll ||
+            sctx->dirty_atoms & si_atoms_that_roll_context() ||
+            sctx->dirty_states & si_states_that_roll_context() ||
+            si_prim_restart_index_changed(sctx, info))) {
+               sctx->scissors.dirty_mask = (1 << SI_MAX_VIEWPORTS) - 1;
+               si_mark_atom_dirty(sctx, &sctx->atoms.s.scissors);
+       }
+
        /* Emit state atoms. */
        unsigned mask = sctx->dirty_atoms & ~skip_atom_mask;
        while (mask)
@@ -1174,11 +1205,6 @@ static void si_emit_all_states(struct si_context *sctx, const struct pipe_draw_i
        sctx->dirty_states = 0;
 
        /* Emit draw states. */
-       unsigned num_patches = 0;
-
-       si_emit_rasterizer_prim_state(sctx);
-       if (sctx->tes_shader.cso)
-               si_emit_derived_tess_state(sctx, info, &num_patches);
        si_emit_vs_state(sctx, info);
        si_emit_draw_registers(sctx, info, num_patches);
 }
@@ -1384,16 +1410,6 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
        if (!si_upload_vertex_buffer_descriptors(sctx))
                return;
 
-       /* Vega10/Raven scissor bug workaround. This must be done before VPORT
-        * scissor registers are changed. There is also a more efficient but
-        * more involved alternative workaround.
-        */
-       if ((sctx->family == CHIP_VEGA10 || sctx->family == CHIP_RAVEN) &&
-           si_is_atom_dirty(sctx, &sctx->atoms.s.scissors)) {
-               sctx->flags |= SI_CONTEXT_PS_PARTIAL_FLUSH;
-               si_emit_cache_flush(sctx);
-       }
-
        /* Use optimal packet order based on whether we need to sync the pipeline. */
        if (unlikely(sctx->flags & (SI_CONTEXT_FLUSH_AND_INV_CB |
                                      SI_CONTEXT_FLUSH_AND_INV_DB |