radeonsi: optimize scissor states
authorMarek Olšák <marek.olsak@amd.com>
Fri, 28 Aug 2015 19:08:49 +0000 (21:08 +0200)
committerMarek Olšák <marek.olsak@amd.com>
Tue, 1 Sep 2015 19:51:13 +0000 (21:51 +0200)
- convert 16 states to 1 atom
- only emit 1 scissor if VIEWPORT_INDEX isn't written
- use only one packet when emitting consecutive scissors

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
src/gallium/drivers/radeonsi/si_blit.c
src/gallium/drivers/radeonsi/si_hw_context.c
src/gallium/drivers/radeonsi/si_pipe.c
src/gallium/drivers/radeonsi/si_pipe.h
src/gallium/drivers/radeonsi/si_shader.h
src/gallium/drivers/radeonsi/si_state.c
src/gallium/drivers/radeonsi/si_state.h
src/gallium/drivers/radeonsi/si_state_shaders.c

index b7450b6fcecef7c4ed650f92ef54af8b43c76667..b2f342f4fa15afeaf1e2dfcb4e82de1a341f09b5 100644 (file)
@@ -68,9 +68,7 @@ static void si_blitter_begin(struct pipe_context *ctx, enum si_blitter_op op)
        if (sctx->queued.named.viewport[0]) {
                util_blitter_save_viewport(sctx->blitter, &sctx->queued.named.viewport[0]->viewport);
        }
-       if (sctx->queued.named.scissor[0]) {
-               util_blitter_save_scissor(sctx->blitter, &sctx->queued.named.scissor[0]->scissor);
-       }
+       util_blitter_save_scissor(sctx->blitter, &sctx->scissors.states[0]);
        util_blitter_save_vertex_buffer_slot(sctx->blitter, sctx->vertex_buffer);
        util_blitter_save_so_targets(sctx->blitter, sctx->b.streamout.num_targets,
                                     (struct pipe_stream_output_target**)sctx->b.streamout.targets);
index 563251ddd4b138d6bca03cf2abd039b71ec8cdf5..873a47279767e6e6c50b0ac9f5709d77218866ed 100644 (file)
@@ -194,6 +194,9 @@ void si_begin_new_cs(struct si_context *ctx)
        si_mark_atom_dirty(ctx, &ctx->b.streamout.enable_atom);
        si_all_descriptors_begin_new_cs(ctx);
 
+       ctx->scissors.dirty_mask = (1 << SI_MAX_VIEWPORTS) - 1;
+       si_mark_atom_dirty(ctx, &ctx->scissors.atom);
+
        r600_postflush_resume_features(&ctx->b);
 
        ctx->b.initial_gfx_cs_size = ctx->b.rings.gfx.cs->cdw;
index 92c6ae3de2be1320366b6ab0d1f45fb139dfe774..330b94665b3d2dbd69cecef90d89f1cada2682c7 100644 (file)
@@ -369,7 +369,7 @@ static int si_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
                return 8;
 
        case PIPE_CAP_MAX_VIEWPORTS:
-               return 16;
+               return SI_MAX_VIEWPORTS;
 
        /* Timer queries, present when the clock frequency is non zero. */
        case PIPE_CAP_QUERY_TIMESTAMP:
index 52167f24a9567c89fa655e268c1f269c93aca74b..9060f94897151854171159c7efefca8e59057168 100644 (file)
@@ -85,6 +85,8 @@
 #define SI_IS_TRACE_POINT(x)           (((x) & 0xcafe0000) == 0xcafe0000)
 #define SI_GET_TRACE_POINT_ID(x)       ((x) & 0xffff)
 
+#define SI_MAX_VIEWPORTS       16
+
 struct si_compute;
 
 struct si_screen {
@@ -127,6 +129,12 @@ struct si_framebuffer {
        unsigned                        export_16bpc;
 };
 
+struct si_scissors {
+       struct r600_atom                atom;
+       unsigned                        dirty_mask;
+       struct pipe_scissor_state       states[SI_MAX_VIEWPORTS];
+};
+
 #define SI_NUM_ATOMS(sctx) (sizeof((sctx)->atoms)/sizeof((sctx)->atoms.array[0]))
 
 struct si_context {
@@ -154,6 +162,7 @@ struct si_context {
                        struct r600_atom *msaa_config;
                        struct r600_atom *clip_regs;
                        struct r600_atom *shader_userdata;
+                       struct r600_atom *scissors;
                } s;
                struct r600_atom *array[0];
        } atoms;
@@ -181,6 +190,7 @@ struct si_context {
        struct r600_resource            *border_color_table;
        unsigned                        border_color_offset;
 
+       struct si_scissors              scissors;
        struct r600_atom                clip_regs;
        struct r600_atom                msaa_sample_locs;
        struct r600_atom                msaa_config;
index ad32473b91e5ad88b98cc22381c1887b2d3a496e..c748f71430b4f8d4a115499f503c87a35486d58f 100644 (file)
@@ -278,8 +278,10 @@ static inline struct tgsi_shader_info *si_get_vs_info(struct si_context *sctx)
                return &sctx->gs_shader->info;
        else if (sctx->tes_shader)
                return &sctx->tes_shader->info;
-       else
+       else if (sctx->vs_shader)
                return &sctx->vs_shader->info;
+       else
+               return NULL;
 }
 
 static inline struct si_shader* si_get_vs_state(struct si_context *sctx)
index 62eda97dc7e92be9a90100577b52ec37f99368a4..8bd35a8422eaee1605dc0578b8add8a12e47b4d4 100644 (file)
@@ -526,26 +526,50 @@ static void si_set_scissor_states(struct pipe_context *ctx,
                                   const struct pipe_scissor_state *state)
 {
        struct si_context *sctx = (struct si_context *)ctx;
-       struct si_state_scissor *scissor;
-       struct si_pm4_state *pm4;
        int i;
 
-       for (i = start_slot; i < start_slot + num_scissors; i++) {
-               int idx = i - start_slot;
-               int offset = i * 4 * 2;
+       for (i = 0; i < num_scissors; i++)
+               sctx->scissors.states[start_slot + i] = state[i];
 
-               scissor = CALLOC_STRUCT(si_state_scissor);
-               if (scissor == NULL)
-                       return;
-               pm4 = &scissor->pm4;
-               scissor->scissor = state[idx];
-               si_pm4_set_reg(pm4, R_028250_PA_SC_VPORT_SCISSOR_0_TL + offset,
-                              S_028250_TL_X(state[idx].minx) | S_028250_TL_Y(state[idx].miny) |
-                              S_028250_WINDOW_OFFSET_DISABLE(1));
-               si_pm4_set_reg(pm4, R_028254_PA_SC_VPORT_SCISSOR_0_BR + offset,
-                              S_028254_BR_X(state[idx].maxx) | S_028254_BR_Y(state[idx].maxy));
-               si_pm4_set_state(sctx, scissor[i], scissor);
+       sctx->scissors.dirty_mask |= ((1 << num_scissors) - 1) << start_slot;
+       si_mark_atom_dirty(sctx, &sctx->scissors.atom);
+}
+
+static void si_emit_scissors(struct si_context *sctx, struct r600_atom *atom)
+{
+       struct radeon_winsys_cs *cs = sctx->b.rings.gfx.cs;
+       struct pipe_scissor_state *states = sctx->scissors.states;
+       unsigned mask = sctx->scissors.dirty_mask;
+
+       /* The simple case: Only 1 viewport is active. */
+       if (mask & 1 &&
+           !si_get_vs_info(sctx)->writes_viewport_index) {
+               r600_write_context_reg_seq(cs, R_028250_PA_SC_VPORT_SCISSOR_0_TL, 2);
+               radeon_emit(cs, S_028250_TL_X(states[0].minx) |
+                               S_028250_TL_Y(states[0].miny) |
+                               S_028250_WINDOW_OFFSET_DISABLE(1));
+               radeon_emit(cs, S_028254_BR_X(states[0].maxx) |
+                               S_028254_BR_Y(states[0].maxy));
+               sctx->scissors.dirty_mask &= ~1; /* clear one bit */
+               return;
+       }
+
+       while (mask) {
+               int start, count, i;
+
+               u_bit_scan_consecutive_range(&mask, &start, &count);
+
+               r600_write_context_reg_seq(cs, R_028250_PA_SC_VPORT_SCISSOR_0_TL +
+                                              start * 4 * 2, count * 2);
+               for (i = start; i < start+count; i++) {
+                       radeon_emit(cs, S_028250_TL_X(states[i].minx) |
+                                       S_028250_TL_Y(states[i].miny) |
+                                       S_028250_WINDOW_OFFSET_DISABLE(1));
+                       radeon_emit(cs, S_028254_BR_X(states[i].maxx) |
+                                       S_028254_BR_Y(states[i].maxy));
+               }
        }
+       sctx->scissors.dirty_mask = 0;
 }
 
 static void si_set_viewport_states(struct pipe_context *ctx,
@@ -2986,6 +3010,7 @@ void si_init_state_functions(struct si_context *sctx)
        si_init_atom(&sctx->framebuffer.atom, &sctx->atoms.s.framebuffer, si_emit_framebuffer_state, 0);
        si_init_atom(&sctx->db_render_state, &sctx->atoms.s.db_render_state, si_emit_db_render_state, 10);
        si_init_atom(&sctx->clip_regs, &sctx->atoms.s.clip_regs, si_emit_clip_regs, 6);
+       si_init_atom(&sctx->scissors.atom, &sctx->atoms.s.scissors, si_emit_scissors, 16*4);
 
        sctx->b.b.create_blend_state = si_create_blend_state;
        sctx->b.b.bind_blend_state = si_bind_blend_state;
index bf713c42e867cc7d86eac6cce8007da52f7e77f1..34dbba480507d7dc87f51b03cba7022474a47817 100644 (file)
@@ -48,11 +48,6 @@ struct si_state_sample_mask {
        uint16_t                sample_mask;
 };
 
-struct si_state_scissor {
-       struct si_pm4_state             pm4;
-       struct pipe_scissor_state       scissor;
-};
-
 struct si_state_viewport {
        struct si_pm4_state             pm4;
        struct pipe_viewport_state      viewport;
@@ -96,7 +91,6 @@ union si_state {
                struct si_pm4_state             *blend_color;
                struct si_pm4_state             *clip;
                struct si_state_sample_mask     *sample_mask;
-               struct si_state_scissor         *scissor[16];
                struct si_state_viewport        *viewport[16];
                struct si_state_rasterizer      *rasterizer;
                struct si_state_dsa             *dsa;
index b223e060be3b33a88d7e60211c23035c530689a5..5a9ef29a549b67feb4341e3a9242f8f102e2b1a4 100644 (file)
@@ -760,6 +760,23 @@ static void *si_create_tes_state(struct pipe_context *ctx,
        return si_create_shader_state(ctx, state, PIPE_SHADER_TESS_EVAL);
 }
 
+/**
+ * Normally, we only emit 1 viewport and 1 scissor if no shader is using
+ * the VIEWPORT_INDEX output, and emitting the other viewports and scissors
+ * is delayed. When a shader with VIEWPORT_INDEX appears, this should be
+ * called to emit the rest.
+ */
+static void si_update_viewports_and_scissors(struct si_context *sctx)
+{
+       struct tgsi_shader_info *info = si_get_vs_info(sctx);
+
+       if (!info || !info->writes_viewport_index)
+               return;
+
+       if (sctx->scissors.dirty_mask)
+           si_mark_atom_dirty(sctx, &sctx->scissors.atom);
+}
+
 static void si_bind_vs_shader(struct pipe_context *ctx, void *state)
 {
        struct si_context *sctx = (struct si_context *)ctx;
@@ -770,6 +787,7 @@ static void si_bind_vs_shader(struct pipe_context *ctx, void *state)
 
        sctx->vs_shader = sel;
        si_mark_atom_dirty(sctx, &sctx->clip_regs);
+       si_update_viewports_and_scissors(sctx);
 }
 
 static void si_bind_gs_shader(struct pipe_context *ctx, void *state)
@@ -787,6 +805,7 @@ static void si_bind_gs_shader(struct pipe_context *ctx, void *state)
 
        if (enable_changed)
                si_shader_change_notify(sctx);
+       si_update_viewports_and_scissors(sctx);
 }
 
 static void si_bind_tcs_shader(struct pipe_context *ctx, void *state)
@@ -821,6 +840,7 @@ static void si_bind_tes_shader(struct pipe_context *ctx, void *state)
                si_shader_change_notify(sctx);
                sctx->last_tes_sh_base = -1; /* invalidate derived tess state */
        }
+       si_update_viewports_and_scissors(sctx);
 }
 
 static void si_make_dummy_ps(struct si_context *sctx)