drm/amd/display: Add update flags in to determine surface update type
authorAndrew Jiang <Andrew.Jiang@amd.com>
Mon, 6 Nov 2017 22:00:07 +0000 (17:00 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 6 Dec 2017 17:47:41 +0000 (12:47 -0500)
This way, we can know exactly what triggered the update type we're
looking at, and we can simplify the logic for determining what exactly
needs to be updated in the future.

Also allow a dst rect size increase to go through a medium update,
since that does not require us to increase clock or bandwidth.

Signed-off-by: Andrew Jiang <Andrew.Jiang@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dc.h

index 3497d827b877a7023e26f93fbc3505400d0397e3..34e678f30328fc79b188c638e64a60636e5c16ec 100644 (file)
 /*******************************************************************************
  * 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;
index 459a1c55b5cfb53d1161d0f5a45424dbb1c89ef4..f6d431a942a19bfe711bf03994c96c7550fbba20 100644 (file)
@@ -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
  ******************************************************************************/