From: Marek Olšák <marek.ol...@amd.com> This might improve performance on Vega10 and Raven. --- src/gallium/drivers/radeonsi/si_state.h | 46 ++++++++++++-- src/gallium/drivers/radeonsi/si_state_draw.c | 64 ++++++++++++-------- 2 files changed, 81 insertions(+), 29 deletions(-)
diff --git a/src/gallium/drivers/radeonsi/si_state.h b/src/gallium/drivers/radeonsi/si_state.h index d235f31c792..9da58ac9710 100644 --- a/src/gallium/drivers/radeonsi/si_state.h +++ b/src/gallium/drivers/radeonsi/si_state.h @@ -165,22 +165,38 @@ union si_state { struct si_pm4_state *hs; struct si_pm4_state *es; struct si_pm4_state *gs; struct si_pm4_state *vgt_shader_config; struct si_pm4_state *vs; struct si_pm4_state *ps; } named; 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. */ struct si_atom render_cond; struct si_atom streamout_begin; struct si_atom streamout_enable; /* must be after streamout_begin */ struct si_atom framebuffer; struct si_atom msaa_sample_locs; struct si_atom db_render_state; struct si_atom dpbb_state; @@ -193,22 +209,45 @@ union si_state_atoms { struct si_atom shader_pointers; struct si_atom scissors; struct si_atom viewports; struct si_atom stencil_ref; struct si_atom spi_map; struct si_atom scratch_state; } s; 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]; }; /* Private read-write buffer slots. */ enum { SI_ES_RING_ESGS, SI_GS_RING_ESGS, SI_RING_GSVS, @@ -299,42 +338,39 @@ struct si_buffer_resources { enum radeon_bo_usage shader_usage:4; /* READ, WRITE, or READWRITE */ enum radeon_bo_usage shader_usage_constbuf:4; enum radeon_bo_priority priority:6; enum radeon_bo_priority priority_constbuf:6; /* The i-th bit is set if that element is enabled (non-NULL resource). */ 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) #define si_pm4_state_enabled_and_changed(sctx, member) \ ((sctx)->queued.named.member && si_pm4_state_changed(sctx, member)) #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) \ do { \ if ((sctx)->queued.named.member == (value)) { \ (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 */ void si_set_mutable_tex_desc_fields(struct si_screen *sscreen, struct r600_texture *tex, const struct legacy_surf_level *base_level_info, unsigned base_level, unsigned first_level, unsigned block_width, bool is_stencil, uint32_t *state); void si_update_ps_colorbuf0_slot(struct si_context *sctx); diff --git a/src/gallium/drivers/radeonsi/si_state_draw.c b/src/gallium/drivers/radeonsi/si_state_draw.c index 42522c01291..5588c9a2c53 100644 --- a/src/gallium/drivers/radeonsi/si_state_draw.c +++ b/src/gallium/drivers/radeonsi/si_state_draw.c @@ -59,21 +59,21 @@ static unsigned si_conv_pipe_prim(unsigned mode) return prim_conv[mode]; } /** * This calculates the LDS size for tessellation shaders (VS, TCS, TES). * LS.LDS_SIZE is shared by all 3 shader stages. * * 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) { struct radeon_winsys_cs *cs = sctx->gfx_cs; struct si_shader *ls_current; struct si_shader_selector *ls; /* The TES pointer will only be used for sctx->last_tcs. * It would be wrong to think that TCS = TES. */ struct si_shader_selector *tcs = sctx->tcs_shader.cso ? sctx->tcs_shader.cso : sctx->tes_shader.cso; @@ -103,21 +103,21 @@ static void si_emit_derived_tess_state(struct si_context *sctx, ls = sctx->vs_shader.cso; } if (sctx->last_ls == ls_current && sctx->last_tcs == tcs && sctx->last_tes_sh_base == tes_sh_base && sctx->last_num_tcs_input_cp == num_tcs_input_cp && (!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; sctx->last_tcs = tcs; sctx->last_tes_sh_base = tes_sh_base; sctx->last_num_tcs_input_cp = num_tcs_input_cp; sctx->last_tess_uses_primid = tess_uses_primid; /* This calculates how shader inputs and outputs among VS, TCS, and TES * are laid out in LDS. */ @@ -282,21 +282,23 @@ static void si_emit_derived_tess_state(struct si_context *sctx, if (sctx->last_ls_hs_config != ls_hs_config) { if (sctx->chip_class >= CIK) { radeon_set_context_reg_idx(cs, R_028B58_VGT_LS_HS_CONFIG, 2, ls_hs_config); } else { radeon_set_context_reg(cs, R_028B58_VGT_LS_HS_CONFIG, 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) { switch (info->mode) { case PIPE_PRIM_PATCHES: return info->count / info->vertices_per_patch; case SI_PRIM_RECTANGLE_LIST: return info->count / 3; default: @@ -505,47 +507,48 @@ static unsigned si_get_ia_multi_vgt_param(struct si_context *sctx, (info->instance_count > 1 && (info->count_from_stream_output || si_num_prims_for_vertices(info) <= 1)))) sctx->flags |= SI_CONTEXT_VGT_FLUSH; } return ia_multi_vgt_param; } /* 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 && rast_prim != PIPE_PRIM_LINE_LOOP && 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). */ radeon_set_context_reg(cs, R_028A0C_PA_SC_LINE_STIPPLE, rs->pa_sc_line_stipple | S_028A0C_AUTO_RESET_CNTL(rast_prim == PIPE_PRIM_LINES ? 1 : 2)); 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, const struct pipe_draw_info *info) { sctx->current_vs_state &= C_VS_STATE_INDEXED; sctx->current_vs_state |= S_VS_STATE_INDEXED(!!info->index_size); if (sctx->num_vs_blit_sgprs) { /* Re-emit the state after we leave u_blitter. */ @@ -558,20 +561,28 @@ static void si_emit_vs_state(struct si_context *sctx, radeon_set_sh_reg(cs, sctx->shader_pointers.sh_base[PIPE_SHADER_VERTEX] + SI_SGPR_VS_STATE_BITS * 4, sctx->current_vs_state); sctx->last_vs_state = sctx->current_vs_state; } } +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) { struct radeon_winsys_cs *cs = sctx->gfx_cs; unsigned prim = si_conv_pipe_prim(info->mode); unsigned ia_multi_vgt_param; ia_multi_vgt_param = si_get_ia_multi_vgt_param(sctx, info, num_patches); @@ -600,23 +611,21 @@ static void si_emit_draw_registers(struct si_context *sctx, if (sctx->chip_class >= GFX9) radeon_set_uconfig_reg(cs, R_03092C_VGT_MULTI_PRIM_IB_RESET_EN, info->primitive_restart); else radeon_set_context_reg(cs, R_028A94_VGT_MULTI_PRIM_IB_RESET_EN, info->primitive_restart); 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; } } static void si_emit_draw_packets(struct si_context *sctx, const struct pipe_draw_info *info, struct pipe_resource *indexbuf, unsigned index_size, @@ -1145,20 +1154,42 @@ static void si_get_draw_start_count(struct si_context *sctx, } } else { *start = info->start; *count = info->count; } } 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) sctx->atoms.array[u_bit_scan(&mask)].emit(sctx); sctx->dirty_atoms &= skip_atom_mask; /* Emit states. */ mask = sctx->dirty_states; while (mask) { @@ -1167,25 +1198,20 @@ static void si_emit_all_states(struct si_context *sctx, const struct pipe_draw_i if (!state || sctx->emitted.array[i] == state) continue; si_pm4_emit(sctx, state); sctx->emitted.array[i] = state; } 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); } void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) { struct si_context *sctx = (struct si_context *)ctx; struct si_state_rasterizer *rs = sctx->queued.named.rasterizer; struct pipe_resource *indexbuf = info->index.resource; unsigned dirty_tex_counter; @@ -1377,30 +1403,20 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) si_need_gfx_cs_space(sctx); /* Since we've called si_context_add_resource_size for vertex buffers, * this must be called after si_need_cs_space, because we must let * need_cs_space flush before we add buffers to the buffer list. */ 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 | SI_CONTEXT_PS_PARTIAL_FLUSH | SI_CONTEXT_CS_PARTIAL_FLUSH))) { /* If we have to wait for idle, set all states first, so that all * SET packets are processed in parallel with previous draw calls. * Then draw and prefetch at the end. This ensures that the time * the CUs are idle is very short. */ -- 2.17.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev