diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 3497d827b877a7023e26f93fbc3505400d0397e3..34e678f30328fc79b188c638e64a60636e5c16ec 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -54,6 +54,13 @@ /******************************************************************************* * Private functions ******************************************************************************/ + +static inline void elevate_update_type(enum surface_update_type *original, enum surface_update_type new) +{ + if (new > *original) + *original = new; +} + static void destroy_links(struct dc *dc) { uint32_t i; @@ -1161,77 +1168,88 @@ static unsigned int pixel_format_to_bpp(enum surface_pixel_format format) static enum surface_update_type get_plane_info_update_type(const struct dc_surface_update *u) { - struct dc_plane_info temp_plane_info; - memset(&temp_plane_info, 0, sizeof(temp_plane_info)); + union surface_update_flags *update_flags = &u->surface->update_flags; if (!u->plane_info) return UPDATE_TYPE_FAST; - temp_plane_info = *u->plane_info; + if (u->plane_info->color_space != u->surface->color_space) + update_flags->bits.color_space_change = 1; - /* Copy all parameters that will cause a full update - * from current surface, the rest of the parameters - * from provided plane configuration. - * Perform memory compare and special validation - * for those that can cause fast/medium updates - */ + if (u->plane_info->input_tf != u->surface->input_tf) + update_flags->bits.input_tf_change = 1; - /* Full update parameters */ - temp_plane_info.color_space = u->surface->color_space; - temp_plane_info.input_tf = u->surface->input_tf; - temp_plane_info.horizontal_mirror = u->surface->horizontal_mirror; - temp_plane_info.rotation = u->surface->rotation; - temp_plane_info.stereo_format = u->surface->stereo_format; + if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror) + update_flags->bits.horizontal_mirror_change = 1; - if (memcmp(u->plane_info, &temp_plane_info, - sizeof(struct dc_plane_info)) != 0) - return UPDATE_TYPE_FULL; + if (u->plane_info->rotation != u->surface->rotation) + update_flags->bits.rotation_change = 1; + + if (u->plane_info->stereo_format != u->surface->stereo_format) + update_flags->bits.stereo_format_change = 1; + + if (u->plane_info->per_pixel_alpha != u->surface->per_pixel_alpha) + update_flags->bits.per_pixel_alpha_change = 1; if (pixel_format_to_bpp(u->plane_info->format) != - pixel_format_to_bpp(u->surface->format)) { + pixel_format_to_bpp(u->surface->format)) /* different bytes per element will require full bandwidth * and DML calculation */ - return UPDATE_TYPE_FULL; - } + update_flags->bits.bpp_change = 1; if (memcmp(&u->plane_info->tiling_info, &u->surface->tiling_info, sizeof(union dc_tiling_info)) != 0) { + update_flags->bits.swizzle_change = 1; /* todo: below are HW dependent, we should add a hook to * DCE/N resource and validated there. */ - if (u->plane_info->tiling_info.gfx9.swizzle != DC_SW_LINEAR) { + if (u->plane_info->tiling_info.gfx9.swizzle != DC_SW_LINEAR) /* swizzled mode requires RQ to be setup properly, * thus need to run DML to calculate RQ settings */ - return UPDATE_TYPE_FULL; - } + update_flags->bits.bandwidth_change = 1; } + if (update_flags->bits.rotation_change + || update_flags->bits.stereo_format_change + || update_flags->bits.bpp_change + || update_flags->bits.bandwidth_change) + return UPDATE_TYPE_FULL; + return UPDATE_TYPE_MED; } -static enum surface_update_type get_scaling_info_update_type( +static enum surface_update_type get_scaling_info_update_type( const struct dc_surface_update *u) { + union surface_update_flags *update_flags = &u->surface->update_flags; + if (!u->scaling_info) return UPDATE_TYPE_FAST; if (u->scaling_info->clip_rect.width != u->surface->clip_rect.width || u->scaling_info->clip_rect.height != u->surface->clip_rect.height || u->scaling_info->dst_rect.width != u->surface->dst_rect.width - || u->scaling_info->dst_rect.height != u->surface->dst_rect.height) - return UPDATE_TYPE_FULL; + || u->scaling_info->dst_rect.height != u->surface->dst_rect.height) { + update_flags->bits.scaling_change = 1; + + if ((u->scaling_info->dst_rect.width < u->surface->dst_rect.width + || u->scaling_info->dst_rect.height < u->surface->dst_rect.height) + && (u->scaling_info->dst_rect.width < u->surface->src_rect.width + || u->scaling_info->dst_rect.height < u->surface->src_rect.height)) + /* Making dst rect smaller requires a bandwidth change */ + update_flags->bits.bandwidth_change = 1; + } if (u->scaling_info->src_rect.width != u->surface->src_rect.width || u->scaling_info->src_rect.height != u->surface->src_rect.height) { + update_flags->bits.scaling_change = 1; if (u->scaling_info->src_rect.width > u->surface->src_rect.width && u->scaling_info->src_rect.height > u->surface->src_rect.height) - return UPDATE_TYPE_FULL; - - /* Upscaling does not require a full update */ - return UPDATE_TYPE_MED; + /* Making src rect bigger requires a bandwidth change */ + update_flags->bits.clock_change = 1; } if (u->scaling_info->src_rect.x != u->surface->src_rect.x @@ -1240,33 +1258,50 @@ static enum surface_update_type get_scaling_info_update_type( || u->scaling_info->clip_rect.y != u->surface->clip_rect.y || u->scaling_info->dst_rect.x != u->surface->dst_rect.x || u->scaling_info->dst_rect.y != u->surface->dst_rect.y) + update_flags->bits.position_change = 1; + + if (update_flags->bits.clock_change + || update_flags->bits.bandwidth_change) + return UPDATE_TYPE_FULL; + + if (update_flags->bits.scaling_change + || update_flags->bits.position_change) return UPDATE_TYPE_MED; return UPDATE_TYPE_FAST; } static enum surface_update_type det_surface_update(const struct dc *dc, - const struct dc_surface_update *u) + const struct dc_surface_update *u) { const struct dc_state *context = dc->current_state; - enum surface_update_type type = UPDATE_TYPE_FAST; + enum surface_update_type type; enum surface_update_type overall_type = UPDATE_TYPE_FAST; + union surface_update_flags *update_flags = &u->surface->update_flags; + + update_flags->raw = 0; // Reset all flags - if (!is_surface_in_context(context, u->surface)) + if (!is_surface_in_context(context, u->surface)) { + update_flags->bits.new_plane = 1; return UPDATE_TYPE_FULL; + } type = get_plane_info_update_type(u); - if (overall_type < type) - overall_type = type; + elevate_update_type(&overall_type, type); type = get_scaling_info_update_type(u); - if (overall_type < type) - overall_type = type; + elevate_update_type(&overall_type, type); + + if (u->in_transfer_func) + update_flags->bits.in_transfer_func = 1; + + if (u->input_csc_color_matrix) + update_flags->bits.input_csc_change = 1; - if (u->in_transfer_func || - u->input_csc_color_matrix) { - if (overall_type < UPDATE_TYPE_MED) - overall_type = UPDATE_TYPE_MED; + if (update_flags->bits.in_transfer_func + || update_flags->bits.input_csc_change) { + type = UPDATE_TYPE_MED; + elevate_update_type(&overall_type, type); } return overall_type; @@ -1292,11 +1327,11 @@ enum surface_update_type dc_check_update_surfaces_for_stream( enum surface_update_type type = det_surface_update(dc, &updates[i]); + updates[i].surface->update_type = type; if (type == UPDATE_TYPE_FULL) return type; - if (overall_type < type) - overall_type = type; + elevate_update_type(&overall_type, type); } return overall_type; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 459a1c55b5cfb53d1161d0f5a45424dbb1c89ef4..f6d431a942a19bfe711bf03994c96c7550fbba20 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -99,6 +99,39 @@ struct dc_static_screen_events { bool overlay_update; }; + +/* Surface update type is used by dc_update_surfaces_and_stream + * The update type is determined at the very beginning of the function based + * on parameters passed in and decides how much programming (or updating) is + * going to be done during the call. + * + * UPDATE_TYPE_FAST is used for really fast updates that do not require much + * logical calculations or hardware register programming. This update MUST be + * ISR safe on windows. Currently fast update will only be used to flip surface + * address. + * + * UPDATE_TYPE_MED is used for slower updates which require significant hw + * re-programming however do not affect bandwidth consumption or clock + * requirements. At present, this is the level at which front end updates + * that do not require us to run bw_calcs happen. These are in/out transfer func + * updates, viewport offset changes, recout size changes and pixel depth changes. + * This update can be done at ISR, but we want to minimize how often this happens. + * + * UPDATE_TYPE_FULL is slow. Really slow. This requires us to recalculate our + * bandwidth and clocks, possibly rearrange some pipes and reprogram anything front + * end related. Any time viewport dimensions, recout dimensions, scaling ratios or + * gamma need to be adjusted or pipe needs to be turned on (or disconnected) we do + * a full update. This cannot be done at ISR level and should be a rare event. + * Unless someone is stress testing mpo enter/exit, playing with colour or adjusting + * underscan we don't expect to see this call at all. + */ + +enum surface_update_type { + UPDATE_TYPE_FAST, /* super fast, safe to execute in isr */ + UPDATE_TYPE_MED, /* ISR safe, most of programming needed, no bw/clk change*/ + UPDATE_TYPE_FULL, /* may need to shuffle resources */ +}; + /* Forward declaration*/ struct dc; struct dc_plane_state; @@ -399,6 +432,32 @@ struct dc_plane_status { bool is_right_eye; }; +union surface_update_flags { + + struct { + /* Medium updates */ + uint32_t color_space_change:1; + uint32_t input_tf_change:1; + uint32_t horizontal_mirror_change:1; + uint32_t per_pixel_alpha_change:1; + uint32_t rotation_change:1; + uint32_t swizzle_change:1; + uint32_t scaling_change:1; + uint32_t position_change:1; + uint32_t in_transfer_func:1; + uint32_t input_csc_change:1; + + /* Full updates */ + uint32_t new_plane:1; + uint32_t bpp_change:1; + uint32_t bandwidth_change:1; + uint32_t clock_change:1; + uint32_t stereo_format_change:1; + } bits; + + uint32_t raw; +}; + struct dc_plane_state { struct dc_plane_address address; struct scaling_taps scaling_quality; @@ -432,6 +491,8 @@ struct dc_plane_state { bool flip_immediate; bool horizontal_mirror; + union surface_update_flags update_flags; + enum surface_update_type update_type; /* private to DC core */ struct dc_plane_status status; struct dc_context *ctx; @@ -516,38 +577,6 @@ struct dc_flip_addrs { bool dc_post_update_surfaces_to_stream( struct dc *dc); -/* Surface update type is used by dc_update_surfaces_and_stream - * The update type is determined at the very beginning of the function based - * on parameters passed in and decides how much programming (or updating) is - * going to be done during the call. - * - * UPDATE_TYPE_FAST is used for really fast updates that do not require much - * logical calculations or hardware register programming. This update MUST be - * ISR safe on windows. Currently fast update will only be used to flip surface - * address. - * - * UPDATE_TYPE_MED is used for slower updates which require significant hw - * re-programming however do not affect bandwidth consumption or clock - * requirements. At present, this is the level at which front end updates - * that do not require us to run bw_calcs happen. These are in/out transfer func - * updates, viewport offset changes, recout size changes and pixel depth changes. - * This update can be done at ISR, but we want to minimize how often this happens. - * - * UPDATE_TYPE_FULL is slow. Really slow. This requires us to recalculate our - * bandwidth and clocks, possibly rearrange some pipes and reprogram anything front - * end related. Any time viewport dimensions, recout dimensions, scaling ratios or - * gamma need to be adjusted or pipe needs to be turned on (or disconnected) we do - * a full update. This cannot be done at ISR level and should be a rare event. - * Unless someone is stress testing mpo enter/exit, playing with colour or adjusting - * underscan we don't expect to see this call at all. - */ - -enum surface_update_type { - UPDATE_TYPE_FAST, /* super fast, safe to execute in isr */ - UPDATE_TYPE_MED, /* ISR safe, most of programming needed, no bw/clk change*/ - UPDATE_TYPE_FULL, /* may need to shuffle resources */ -}; - /******************************************************************************* * Stream Interfaces ******************************************************************************/