mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	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
					
				
					 4 changed files with 39 additions and 17 deletions
				
			
		|  | @ -766,7 +766,7 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, | ||||||
| 	if (crtc_state->enable) | 	if (crtc_state->enable) | ||||||
| 		drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); | 		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); | 	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); | 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 |  * drm_rect_clip_scaled - perform a scaled clip operation | ||||||
|  * @src: source window rectangle |  * @src: source window rectangle | ||||||
|  * @dst: destination window rectangle |  * @dst: destination window rectangle | ||||||
|  * @clip: clip rectangle |  * @clip: clip rectangle | ||||||
|  * @hscale: horizontal scaling factor |  | ||||||
|  * @vscale: vertical scaling factor |  | ||||||
|  * |  * | ||||||
|  * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the |  * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the | ||||||
|  * same amounts multiplied by @hscale and @vscale. |  * same amounts multiplied by @hscale and @vscale. | ||||||
|  | @ -66,33 +78,44 @@ EXPORT_SYMBOL(drm_rect_intersect); | ||||||
|  * %false otherwise |  * %false otherwise | ||||||
|  */ |  */ | ||||||
| bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, | bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, | ||||||
| 			  const struct drm_rect *clip, | 			  const struct drm_rect *clip) | ||||||
| 			  int hscale, int vscale) |  | ||||||
| { | { | ||||||
| 	int diff; | 	int diff; | ||||||
| 
 | 
 | ||||||
| 	diff = clip->x1 - dst->x1; | 	diff = clip->x1 - dst->x1; | ||||||
| 	if (diff > 0) { | 	if (diff > 0) { | ||||||
| 		int64_t tmp = src->x1 + (int64_t) diff * hscale; | 		u32 new_src_w = clip_scaled(drm_rect_width(src), | ||||||
| 		src->x1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX); | 					    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; | 	diff = clip->y1 - dst->y1; | ||||||
| 	if (diff > 0) { | 	if (diff > 0) { | ||||||
| 		int64_t tmp = src->y1 + (int64_t) diff * vscale; | 		u32 new_src_h = clip_scaled(drm_rect_height(src), | ||||||
| 		src->y1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX); | 					    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; | 	diff = dst->x2 - clip->x2; | ||||||
| 	if (diff > 0) { | 	if (diff > 0) { | ||||||
| 		int64_t tmp = src->x2 - (int64_t) diff * hscale; | 		u32 new_src_w = clip_scaled(drm_rect_width(src), | ||||||
| 		src->x2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX); | 					    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; | 	diff = dst->y2 - clip->y2; | ||||||
| 	if (diff > 0) { | 	if (diff > 0) { | ||||||
| 		int64_t tmp = src->y2 - (int64_t) diff * vscale; | 		u32 new_src_h = clip_scaled(drm_rect_height(src), | ||||||
| 		src->y2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX); | 					    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); | 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, | 		drm_mode_get_hv_timing(&crtc_state->base.mode, | ||||||
| 				       &clip.x2, &clip.y2); | 				       &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_x = dst->x1; | ||||||
| 	crtc_y = dst->y1; | 	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_intersect(struct drm_rect *r, const struct drm_rect *clip); | ||||||
| bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, | bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, | ||||||
| 			  const struct drm_rect *clip, | 			  const struct drm_rect *clip); | ||||||
| 			  int hscale, int vscale); |  | ||||||
| int drm_rect_calc_hscale(const struct drm_rect *src, | int drm_rect_calc_hscale(const struct drm_rect *src, | ||||||
| 			 const struct drm_rect *dst, | 			 const struct drm_rect *dst, | ||||||
| 			 int min_hscale, int max_hscale); | 			 int min_hscale, int max_hscale); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Maarten Lankhorst
						Maarten Lankhorst