forked from Minki/linux
drm/rect: Handle rounding errors in drm_rect_clip_scaled, v3.
Instead of relying on a scale which may increase rounding errors, clip src by doing: src * (dst - clip) / dst and rounding the result away from 1, so the new coordinates get closer to 1. We won't need to fix up with a magic macro afterwards, because our scaling factor will never go to the other side of 1. Changes since v1: - Adjust dst immediately, else drm_rect_width/height on dst gives bogus results. Change since v2: - Get rid of macros and use 64-bits math. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> [mlankhorst: Add Villes comment, and rename newsrc to tmp. (Ville)] Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180503112217.37292-3-maarten.lankhorst@linux.intel.com
This commit is contained in:
parent
6f96f2000a
commit
f96bdf564f
@ -766,7 +766,7 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
|
||||
if (crtc_state->enable)
|
||||
drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2);
|
||||
|
||||
plane_state->visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale);
|
||||
plane_state->visible = drm_rect_clip_scaled(src, dst, &clip);
|
||||
|
||||
drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
|
||||
|
||||
|
@ -50,13 +50,25 @@ bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_rect_intersect);
|
||||
|
||||
static u32 clip_scaled(u32 src, u32 dst, u32 clip)
|
||||
{
|
||||
u64 tmp = mul_u32_u32(src, dst - clip);
|
||||
|
||||
/*
|
||||
* Round toward 1.0 when clipping so that we don't accidentally
|
||||
* change upscaling to downscaling or vice versa.
|
||||
*/
|
||||
if (src < (dst << 16))
|
||||
return DIV_ROUND_UP_ULL(tmp, dst);
|
||||
else
|
||||
return DIV_ROUND_DOWN_ULL(tmp, dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_rect_clip_scaled - perform a scaled clip operation
|
||||
* @src: source window rectangle
|
||||
* @dst: destination window rectangle
|
||||
* @clip: clip rectangle
|
||||
* @hscale: horizontal scaling factor
|
||||
* @vscale: vertical scaling factor
|
||||
*
|
||||
* Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the
|
||||
* same amounts multiplied by @hscale and @vscale.
|
||||
@ -66,33 +78,44 @@ EXPORT_SYMBOL(drm_rect_intersect);
|
||||
* %false otherwise
|
||||
*/
|
||||
bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
|
||||
const struct drm_rect *clip,
|
||||
int hscale, int vscale)
|
||||
const struct drm_rect *clip)
|
||||
{
|
||||
int diff;
|
||||
|
||||
diff = clip->x1 - dst->x1;
|
||||
if (diff > 0) {
|
||||
int64_t tmp = src->x1 + (int64_t) diff * hscale;
|
||||
src->x1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
|
||||
u32 new_src_w = clip_scaled(drm_rect_width(src),
|
||||
drm_rect_width(dst), diff);
|
||||
|
||||
src->x1 = clamp_t(int64_t, src->x2 - new_src_w, INT_MIN, INT_MAX);
|
||||
dst->x1 = clip->x1;
|
||||
}
|
||||
diff = clip->y1 - dst->y1;
|
||||
if (diff > 0) {
|
||||
int64_t tmp = src->y1 + (int64_t) diff * vscale;
|
||||
src->y1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
|
||||
u32 new_src_h = clip_scaled(drm_rect_height(src),
|
||||
drm_rect_height(dst), diff);
|
||||
|
||||
src->y1 = clamp_t(int64_t, src->y2 - new_src_h, INT_MIN, INT_MAX);
|
||||
dst->y1 = clip->y1;
|
||||
}
|
||||
diff = dst->x2 - clip->x2;
|
||||
if (diff > 0) {
|
||||
int64_t tmp = src->x2 - (int64_t) diff * hscale;
|
||||
src->x2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
|
||||
u32 new_src_w = clip_scaled(drm_rect_width(src),
|
||||
drm_rect_width(dst), diff);
|
||||
|
||||
src->x2 = clamp_t(int64_t, src->x1 + new_src_w, INT_MIN, INT_MAX);
|
||||
dst->x2 = clip->x2;
|
||||
}
|
||||
diff = dst->y2 - clip->y2;
|
||||
if (diff > 0) {
|
||||
int64_t tmp = src->y2 - (int64_t) diff * vscale;
|
||||
src->y2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
|
||||
u32 new_src_h = clip_scaled(drm_rect_height(src),
|
||||
drm_rect_height(dst), diff);
|
||||
|
||||
src->y2 = clamp_t(int64_t, src->y1 + new_src_h, INT_MIN, INT_MAX);
|
||||
dst->y2 = clip->y2;
|
||||
}
|
||||
|
||||
return drm_rect_intersect(dst, clip);
|
||||
return drm_rect_visible(dst);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_rect_clip_scaled);
|
||||
|
||||
|
@ -1003,7 +1003,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
|
||||
drm_mode_get_hv_timing(&crtc_state->base.mode,
|
||||
&clip.x2, &clip.y2);
|
||||
|
||||
state->base.visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale);
|
||||
state->base.visible = drm_rect_clip_scaled(src, dst, &clip);
|
||||
|
||||
crtc_x = dst->x1;
|
||||
crtc_y = dst->y1;
|
||||
|
@ -175,8 +175,7 @@ static inline bool drm_rect_equals(const struct drm_rect *r1,
|
||||
|
||||
bool drm_rect_intersect(struct drm_rect *r, const struct drm_rect *clip);
|
||||
bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
|
||||
const struct drm_rect *clip,
|
||||
int hscale, int vscale);
|
||||
const struct drm_rect *clip);
|
||||
int drm_rect_calc_hscale(const struct drm_rect *src,
|
||||
const struct drm_rect *dst,
|
||||
int min_hscale, int max_hscale);
|
||||
|
Loading…
Reference in New Issue
Block a user