Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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

+39 -17
+1 -1
drivers/gpu/drm/drm_atomic_helper.c
··· 766 766 if (crtc_state->enable) 767 767 drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); 768 768 769 - plane_state->visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale); 769 + plane_state->visible = drm_rect_clip_scaled(src, dst, &clip); 770 770 771 771 drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); 772 772
+36 -13
drivers/gpu/drm/drm_rect.c
··· 50 50 } 51 51 EXPORT_SYMBOL(drm_rect_intersect); 52 52 53 + static u32 clip_scaled(u32 src, u32 dst, u32 clip) 54 + { 55 + u64 tmp = mul_u32_u32(src, dst - clip); 56 + 57 + /* 58 + * Round toward 1.0 when clipping so that we don't accidentally 59 + * change upscaling to downscaling or vice versa. 60 + */ 61 + if (src < (dst << 16)) 62 + return DIV_ROUND_UP_ULL(tmp, dst); 63 + else 64 + return DIV_ROUND_DOWN_ULL(tmp, dst); 65 + } 66 + 53 67 /** 54 68 * drm_rect_clip_scaled - perform a scaled clip operation 55 69 * @src: source window rectangle 56 70 * @dst: destination window rectangle 57 71 * @clip: clip rectangle 58 - * @hscale: horizontal scaling factor 59 - * @vscale: vertical scaling factor 60 72 * 61 73 * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the 62 74 * same amounts multiplied by @hscale and @vscale. ··· 78 66 * %false otherwise 79 67 */ 80 68 bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, 81 - const struct drm_rect *clip, 82 - int hscale, int vscale) 69 + const struct drm_rect *clip) 83 70 { 84 71 int diff; 85 72 86 73 diff = clip->x1 - dst->x1; 87 74 if (diff > 0) { 88 - int64_t tmp = src->x1 + (int64_t) diff * hscale; 89 - src->x1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX); 75 + u32 new_src_w = clip_scaled(drm_rect_width(src), 76 + drm_rect_width(dst), diff); 77 + 78 + src->x1 = clamp_t(int64_t, src->x2 - new_src_w, INT_MIN, INT_MAX); 79 + dst->x1 = clip->x1; 90 80 } 91 81 diff = clip->y1 - dst->y1; 92 82 if (diff > 0) { 93 - int64_t tmp = src->y1 + (int64_t) diff * vscale; 94 - src->y1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX); 83 + u32 new_src_h = clip_scaled(drm_rect_height(src), 84 + drm_rect_height(dst), diff); 85 + 86 + src->y1 = clamp_t(int64_t, src->y2 - new_src_h, INT_MIN, INT_MAX); 87 + dst->y1 = clip->y1; 95 88 } 96 89 diff = dst->x2 - clip->x2; 97 90 if (diff > 0) { 98 - int64_t tmp = src->x2 - (int64_t) diff * hscale; 99 - src->x2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX); 91 + u32 new_src_w = clip_scaled(drm_rect_width(src), 92 + drm_rect_width(dst), diff); 93 + 94 + src->x2 = clamp_t(int64_t, src->x1 + new_src_w, INT_MIN, INT_MAX); 95 + dst->x2 = clip->x2; 100 96 } 101 97 diff = dst->y2 - clip->y2; 102 98 if (diff > 0) { 103 - int64_t tmp = src->y2 - (int64_t) diff * vscale; 104 - src->y2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX); 99 + u32 new_src_h = clip_scaled(drm_rect_height(src), 100 + drm_rect_height(dst), diff); 101 + 102 + src->y2 = clamp_t(int64_t, src->y1 + new_src_h, INT_MIN, INT_MAX); 103 + dst->y2 = clip->y2; 105 104 } 106 105 107 - return drm_rect_intersect(dst, clip); 106 + return drm_rect_visible(dst); 108 107 } 109 108 EXPORT_SYMBOL(drm_rect_clip_scaled); 110 109
+1 -1
drivers/gpu/drm/i915/intel_sprite.c
··· 1003 1003 drm_mode_get_hv_timing(&crtc_state->base.mode, 1004 1004 &clip.x2, &clip.y2); 1005 1005 1006 - state->base.visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale); 1006 + state->base.visible = drm_rect_clip_scaled(src, dst, &clip); 1007 1007 1008 1008 crtc_x = dst->x1; 1009 1009 crtc_y = dst->y1;
+1 -2
include/drm/drm_rect.h
··· 175 175 176 176 bool drm_rect_intersect(struct drm_rect *r, const struct drm_rect *clip); 177 177 bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, 178 - const struct drm_rect *clip, 179 - int hscale, int vscale); 178 + const struct drm_rect *clip); 180 179 int drm_rect_calc_hscale(const struct drm_rect *src, 181 180 const struct drm_rect *dst, 182 181 int min_hscale, int max_hscale);