diff mbox

[4/7] drm/i915/skl+: calculate plane pixel rate.

Message ID 1452772968-24772-5-git-send-email-shobhit.kumar@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kumar, Shobhit Jan. 14, 2016, 12:02 p.m. UTC
From: "Kumar, Mahesh" <mahesh1.kumar@intel.com>

Don't use pipe pixel rate for plane pixel rate.
Calculate plane pixel according to formula

adjusted plane_pixel_rate = adjusted pipe_pixel_rate * downscale ammount

downscale amount = max[1, src_h/dst_h] * max[1, src_w/dst_w]
if 90/270 rotation use rotated width & height

Signed-off-by: Kumar, Mahesh <mahesh1.kumar@intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h |  2 +
 drivers/gpu/drm/i915/intel_pm.c  | 95 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 95 insertions(+), 2 deletions(-)

Comments

Matt Roper Jan. 15, 2016, 12:57 a.m. UTC | #1
On Thu, Jan 14, 2016 at 05:32:45PM +0530, Shobhit Kumar wrote:
> From: "Kumar, Mahesh" <mahesh1.kumar@intel.com>
> 
> Don't use pipe pixel rate for plane pixel rate.
> Calculate plane pixel according to formula
> 
> adjusted plane_pixel_rate = adjusted pipe_pixel_rate * downscale ammount
> 
> downscale amount = max[1, src_h/dst_h] * max[1, src_w/dst_w]
> if 90/270 rotation use rotated width & height
> 
> Signed-off-by: Kumar, Mahesh <mahesh1.kumar@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_drv.h |  2 +
>  drivers/gpu/drm/i915/intel_pm.c  | 95 +++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 95 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 059b46e..49f237e 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -661,6 +661,8 @@ struct intel_plane_wm_parameters {
>  	u64 tiling;
>  	unsigned int rotation;
>  	uint16_t fifo_size;
> +	 /* Stores the adjusted plane pixel rate for WM calculation */
> +	uint32_t plane_pixel_rate;
>  };
>  
>  struct intel_plane {
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 64b39ec..ffcc56a 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2841,6 +2841,54 @@ skl_wm_plane_id(const struct intel_plane *plane)
>  	}
>  }
>  
> +/*
> + * This function takes drm_plane_state as input
> + * and decides the downscale amount according to the formula
> + *
> + * downscale amount = Max[1, Horizontal source size / Horizontal dest size]
> + *
> + * Return value is multiplied by 1000 to retain fractional part
> + * Caller should take care of dividing & Rounding off the value

Would it be simpler to just continue using 16.16 fixed point format?
Also, are there any helpers in drm_rect.c that we can use to simplify
this at all?

> + */
> +static uint32_t
> +skl_plane_downscale_amount(const struct intel_plane *intel_plane)
> +{
> +	struct drm_plane_state *pstate = intel_plane->base.state;
> +	struct intel_crtc *crtc = to_intel_crtc(pstate->crtc);
> +	struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate);
> +	uint32_t downscale_h, downscale_w;
> +	uint32_t src_w, src_h, dst_w, dst_h, tmp;
> +
> +	if (drm_rect_width(&intel_pstate->src)) {
> +		src_w = drm_rect_width(&intel_pstate->src) >> 16;
> +		src_h = drm_rect_height(&intel_pstate->src) >> 16;
> +	} else {
> +		src_w = crtc->config->pipe_src_w;
> +		src_h = crtc->config->pipe_src_h;
> +	}
> +
> +	dst_w = drm_rect_width(&intel_pstate->dst);
> +	dst_h = drm_rect_height(&intel_pstate->dst);
> +
> +	if (intel_rotation_90_or_270(pstate->rotation))
> +		swap(dst_w, dst_h);
> +
> +	/* If destination height & wight are zero return amount as unity */
> +	if (dst_w == 0 || dst_h == 0)
> +		return 1000;
> +
> +	/* Multiply by 1000 for precision */
> +	tmp = (1000 * src_h) / dst_h;
> +	downscale_h = max_t(uint32_t, 1000, tmp);
> +
> +	tmp = (1000 * src_w) / dst_w;
> +	downscale_w = max_t(uint32_t, 1000, tmp);
> +
> +	/* Reducing precision to 3 decimal places */
> +	return DIV_ROUND_UP(downscale_h * downscale_w, 1000);
> +}
> +
> +
>  static void
>  skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
>  				   const struct intel_crtc_state *cstate,
> @@ -3265,10 +3313,10 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
>  	bytes_per_pixel = (fb->pixel_format == DRM_FORMAT_NV12) ?
>  				drm_format_plane_cpp(fb->pixel_format, 1) :
>  				drm_format_plane_cpp(fb->pixel_format, 0);
> -	method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate),
> +	method1 = skl_wm_method1(intel_plane->wm.plane_pixel_rate,
>  				 bytes_per_pixel,
>  				 latency);
> -	method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate),
> +	method2 = skl_wm_method2(intel_plane->wm.plane_pixel_rate,
>  				 cstate->base.adjusted_mode.crtc_htotal,
>  				 width,
>  				 bytes_per_pixel,
> @@ -3709,6 +3757,46 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
>  	}
>  }
>  
> +static uint32_t
> +skl_plane_pixel_rate(struct intel_crtc_state *cstate, struct intel_plane *plane)
> +{
> +	uint32_t adjusted_pixel_rate;
> +	uint32_t downscale_amount;
> +
> +	/*
> +	 * adjusted plane pixel rate = adjusted pipe pixel rate
> +	 * Plane pixel rate = adjusted plane pixel rate * plane down scale
> +	 * amount
> +	 */
> +	adjusted_pixel_rate = skl_pipe_pixel_rate(cstate);
> +	downscale_amount = skl_plane_downscale_amount(plane);
> +
> +	return DIV_ROUND_UP(adjusted_pixel_rate * downscale_amount,
> +			1000);
> +}
> +
> +static void skl_set_plane_pixel_rate(struct drm_crtc *crtc)
> +{
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
> +	struct intel_plane *intel_plane = NULL;
> +	struct drm_device *dev = crtc->dev;
> +
> +	if (!intel_crtc->active)
> +		return;
> +	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
> +		struct drm_plane *plane = &intel_plane->base;
> +		struct drm_framebuffer *fb = plane->state->fb;
> +
> +		if (fb == NULL)
> +			continue;

Maybe change this to a test of intel_plane_state->visible instead so
that we're not bothering with this for planes that actually do have an
FB assigned but are fully clipped?

Then you'll also be able to eliminate the 'else' block of the non-zero
width test farther up.


Matt

> +
> +		intel_plane->wm.plane_pixel_rate = skl_plane_pixel_rate(cstate,
> +				intel_plane);
> +	}
> +
> +}
> +
>  static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe)
>  {
>  	watermarks->wm_linetime[pipe] = 0;
> @@ -3744,6 +3832,9 @@ static void skl_update_wm(struct drm_crtc *crtc)
>  
>  	skl_clear_wm(results, intel_crtc->pipe);
>  
> +	/* Calculate plane pixel rate for each plane in advance */
> +	skl_set_plane_pixel_rate(crtc);
> +
>  	if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm))
>  		return;
>  
> -- 
> 2.4.3
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 059b46e..49f237e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -661,6 +661,8 @@  struct intel_plane_wm_parameters {
 	u64 tiling;
 	unsigned int rotation;
 	uint16_t fifo_size;
+	 /* Stores the adjusted plane pixel rate for WM calculation */
+	uint32_t plane_pixel_rate;
 };
 
 struct intel_plane {
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 64b39ec..ffcc56a 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2841,6 +2841,54 @@  skl_wm_plane_id(const struct intel_plane *plane)
 	}
 }
 
+/*
+ * This function takes drm_plane_state as input
+ * and decides the downscale amount according to the formula
+ *
+ * downscale amount = Max[1, Horizontal source size / Horizontal dest size]
+ *
+ * Return value is multiplied by 1000 to retain fractional part
+ * Caller should take care of dividing & Rounding off the value
+ */
+static uint32_t
+skl_plane_downscale_amount(const struct intel_plane *intel_plane)
+{
+	struct drm_plane_state *pstate = intel_plane->base.state;
+	struct intel_crtc *crtc = to_intel_crtc(pstate->crtc);
+	struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate);
+	uint32_t downscale_h, downscale_w;
+	uint32_t src_w, src_h, dst_w, dst_h, tmp;
+
+	if (drm_rect_width(&intel_pstate->src)) {
+		src_w = drm_rect_width(&intel_pstate->src) >> 16;
+		src_h = drm_rect_height(&intel_pstate->src) >> 16;
+	} else {
+		src_w = crtc->config->pipe_src_w;
+		src_h = crtc->config->pipe_src_h;
+	}
+
+	dst_w = drm_rect_width(&intel_pstate->dst);
+	dst_h = drm_rect_height(&intel_pstate->dst);
+
+	if (intel_rotation_90_or_270(pstate->rotation))
+		swap(dst_w, dst_h);
+
+	/* If destination height & wight are zero return amount as unity */
+	if (dst_w == 0 || dst_h == 0)
+		return 1000;
+
+	/* Multiply by 1000 for precision */
+	tmp = (1000 * src_h) / dst_h;
+	downscale_h = max_t(uint32_t, 1000, tmp);
+
+	tmp = (1000 * src_w) / dst_w;
+	downscale_w = max_t(uint32_t, 1000, tmp);
+
+	/* Reducing precision to 3 decimal places */
+	return DIV_ROUND_UP(downscale_h * downscale_w, 1000);
+}
+
+
 static void
 skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
 				   const struct intel_crtc_state *cstate,
@@ -3265,10 +3313,10 @@  static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 	bytes_per_pixel = (fb->pixel_format == DRM_FORMAT_NV12) ?
 				drm_format_plane_cpp(fb->pixel_format, 1) :
 				drm_format_plane_cpp(fb->pixel_format, 0);
-	method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate),
+	method1 = skl_wm_method1(intel_plane->wm.plane_pixel_rate,
 				 bytes_per_pixel,
 				 latency);
-	method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate),
+	method2 = skl_wm_method2(intel_plane->wm.plane_pixel_rate,
 				 cstate->base.adjusted_mode.crtc_htotal,
 				 width,
 				 bytes_per_pixel,
@@ -3709,6 +3757,46 @@  static void skl_update_other_pipe_wm(struct drm_device *dev,
 	}
 }
 
+static uint32_t
+skl_plane_pixel_rate(struct intel_crtc_state *cstate, struct intel_plane *plane)
+{
+	uint32_t adjusted_pixel_rate;
+	uint32_t downscale_amount;
+
+	/*
+	 * adjusted plane pixel rate = adjusted pipe pixel rate
+	 * Plane pixel rate = adjusted plane pixel rate * plane down scale
+	 * amount
+	 */
+	adjusted_pixel_rate = skl_pipe_pixel_rate(cstate);
+	downscale_amount = skl_plane_downscale_amount(plane);
+
+	return DIV_ROUND_UP(adjusted_pixel_rate * downscale_amount,
+			1000);
+}
+
+static void skl_set_plane_pixel_rate(struct drm_crtc *crtc)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+	struct intel_plane *intel_plane = NULL;
+	struct drm_device *dev = crtc->dev;
+
+	if (!intel_crtc->active)
+		return;
+	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+		struct drm_plane *plane = &intel_plane->base;
+		struct drm_framebuffer *fb = plane->state->fb;
+
+		if (fb == NULL)
+			continue;
+
+		intel_plane->wm.plane_pixel_rate = skl_plane_pixel_rate(cstate,
+				intel_plane);
+	}
+
+}
+
 static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe)
 {
 	watermarks->wm_linetime[pipe] = 0;
@@ -3744,6 +3832,9 @@  static void skl_update_wm(struct drm_crtc *crtc)
 
 	skl_clear_wm(results, intel_crtc->pipe);
 
+	/* Calculate plane pixel rate for each plane in advance */
+	skl_set_plane_pixel_rate(crtc);
+
 	if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm))
 		return;