xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/drm_damage_helper.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0 OR MIT
2*4882a593Smuzhiyun /**************************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA
5*4882a593Smuzhiyun  * All Rights Reserved.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
8*4882a593Smuzhiyun  * copy of this software and associated documentation files (the
9*4882a593Smuzhiyun  * "Software"), to deal in the Software without restriction, including
10*4882a593Smuzhiyun  * without limitation the rights to use, copy, modify, merge, publish,
11*4882a593Smuzhiyun  * distribute, sub license, and/or sell copies of the Software, and to
12*4882a593Smuzhiyun  * permit persons to whom the Software is furnished to do so, subject to
13*4882a593Smuzhiyun  * the following conditions:
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the
16*4882a593Smuzhiyun  * next paragraph) shall be included in all copies or substantial portions
17*4882a593Smuzhiyun  * of the Software.
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22*4882a593Smuzhiyun  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23*4882a593Smuzhiyun  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24*4882a593Smuzhiyun  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25*4882a593Smuzhiyun  * USE OR OTHER DEALINGS IN THE SOFTWARE.
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * Authors:
28*4882a593Smuzhiyun  * Deepak Rawat <drawat@vmware.com>
29*4882a593Smuzhiyun  * Rob Clark <robdclark@gmail.com>
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  **************************************************************************/
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include <drm/drm_atomic.h>
34*4882a593Smuzhiyun #include <drm/drm_damage_helper.h>
35*4882a593Smuzhiyun #include <drm/drm_device.h>
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /**
38*4882a593Smuzhiyun  * DOC: overview
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * FB_DAMAGE_CLIPS is an optional plane property which provides a means to
41*4882a593Smuzhiyun  * specify a list of damage rectangles on a plane in framebuffer coordinates of
42*4882a593Smuzhiyun  * the framebuffer attached to the plane. In current context damage is the area
43*4882a593Smuzhiyun  * of plane framebuffer that has changed since last plane update (also called
44*4882a593Smuzhiyun  * page-flip), irrespective of whether currently attached framebuffer is same as
45*4882a593Smuzhiyun  * framebuffer attached during last plane update or not.
46*4882a593Smuzhiyun  *
47*4882a593Smuzhiyun  * FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers
48*4882a593Smuzhiyun  * to optimize internally especially for virtual devices where each framebuffer
49*4882a593Smuzhiyun  * change needs to be transmitted over network, usb, etc.
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  * Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can
52*4882a593Smuzhiyun  * ignore damage clips property and in that case driver will do a full plane
53*4882a593Smuzhiyun  * update. In case damage clips are provided then it is guaranteed that the area
54*4882a593Smuzhiyun  * inside damage clips will be updated to plane. For efficiency driver can do
55*4882a593Smuzhiyun  * full update or can update more than specified in damage clips. Since driver
56*4882a593Smuzhiyun  * is free to read more, user-space must always render the entire visible
57*4882a593Smuzhiyun  * framebuffer. Otherwise there can be corruptions. Also, if a user-space
58*4882a593Smuzhiyun  * provides damage clips which doesn't encompass the actual damage to
59*4882a593Smuzhiyun  * framebuffer (since last plane update) can result in incorrect rendering.
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  * FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an
62*4882a593Smuzhiyun  * array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates,
63*4882a593Smuzhiyun  * damage clips are not in 16.16 fixed point. Similar to plane src in
64*4882a593Smuzhiyun  * framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are
65*4882a593Smuzhiyun  * inclusive and x2/y2 are exclusive. While kernel does not error for overlapped
66*4882a593Smuzhiyun  * damage clips, it is strongly discouraged.
67*4882a593Smuzhiyun  *
68*4882a593Smuzhiyun  * Drivers that are interested in damage interface for plane should enable
69*4882a593Smuzhiyun  * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips().
70*4882a593Smuzhiyun  * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and
71*4882a593Smuzhiyun  * drm_atomic_helper_damage_iter_next() helper iterator function to get damage
72*4882a593Smuzhiyun  * rectangles clipped to &drm_plane_state.src.
73*4882a593Smuzhiyun  */
74*4882a593Smuzhiyun 
convert_clip_rect_to_rect(const struct drm_clip_rect * src,struct drm_mode_rect * dest,uint32_t num_clips,uint32_t src_inc)75*4882a593Smuzhiyun static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
76*4882a593Smuzhiyun 				      struct drm_mode_rect *dest,
77*4882a593Smuzhiyun 				      uint32_t num_clips, uint32_t src_inc)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	while (num_clips > 0) {
80*4882a593Smuzhiyun 		dest->x1 = src->x1;
81*4882a593Smuzhiyun 		dest->y1 = src->y1;
82*4882a593Smuzhiyun 		dest->x2 = src->x2;
83*4882a593Smuzhiyun 		dest->y2 = src->y2;
84*4882a593Smuzhiyun 		src += src_inc;
85*4882a593Smuzhiyun 		dest++;
86*4882a593Smuzhiyun 		num_clips--;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /**
91*4882a593Smuzhiyun  * drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property.
92*4882a593Smuzhiyun  * @plane: Plane on which to enable damage clips property.
93*4882a593Smuzhiyun  *
94*4882a593Smuzhiyun  * This function lets driver to enable the damage clips property on a plane.
95*4882a593Smuzhiyun  */
drm_plane_enable_fb_damage_clips(struct drm_plane * plane)96*4882a593Smuzhiyun void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	struct drm_device *dev = plane->dev;
99*4882a593Smuzhiyun 	struct drm_mode_config *config = &dev->mode_config;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	drm_object_attach_property(&plane->base, config->prop_fb_damage_clips,
102*4882a593Smuzhiyun 				   0);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /**
107*4882a593Smuzhiyun  * drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check.
108*4882a593Smuzhiyun  * @state: The driver state object.
109*4882a593Smuzhiyun  * @plane_state: Plane state for which to verify damage.
110*4882a593Smuzhiyun  *
111*4882a593Smuzhiyun  * This helper function makes sure that damage from plane state is discarded
112*4882a593Smuzhiyun  * for full modeset. If there are more reasons a driver would want to do a full
113*4882a593Smuzhiyun  * plane update rather than processing individual damage regions, then those
114*4882a593Smuzhiyun  * cases should be taken care of here.
115*4882a593Smuzhiyun  *
116*4882a593Smuzhiyun  * Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that
117*4882a593Smuzhiyun  * full plane update should happen. It also ensure helper iterator will return
118*4882a593Smuzhiyun  * &drm_plane_state.src as damage.
119*4882a593Smuzhiyun  */
drm_atomic_helper_check_plane_damage(struct drm_atomic_state * state,struct drm_plane_state * plane_state)120*4882a593Smuzhiyun void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
121*4882a593Smuzhiyun 					  struct drm_plane_state *plane_state)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	struct drm_crtc_state *crtc_state;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	if (plane_state->crtc) {
126*4882a593Smuzhiyun 		crtc_state = drm_atomic_get_new_crtc_state(state,
127*4882a593Smuzhiyun 							   plane_state->crtc);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 		if (WARN_ON(!crtc_state))
130*4882a593Smuzhiyun 			return;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 		if (drm_atomic_crtc_needs_modeset(crtc_state)) {
133*4882a593Smuzhiyun 			drm_property_blob_put(plane_state->fb_damage_clips);
134*4882a593Smuzhiyun 			plane_state->fb_damage_clips = NULL;
135*4882a593Smuzhiyun 		}
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun /**
141*4882a593Smuzhiyun  * drm_atomic_helper_dirtyfb - Helper for dirtyfb.
142*4882a593Smuzhiyun  * @fb: DRM framebuffer.
143*4882a593Smuzhiyun  * @file_priv: Drm file for the ioctl call.
144*4882a593Smuzhiyun  * @flags: Dirty fb annotate flags.
145*4882a593Smuzhiyun  * @color: Color for annotate fill.
146*4882a593Smuzhiyun  * @clips: Dirty region.
147*4882a593Smuzhiyun  * @num_clips: Count of clip in clips.
148*4882a593Smuzhiyun  *
149*4882a593Smuzhiyun  * A helper to implement &drm_framebuffer_funcs.dirty using damage interface
150*4882a593Smuzhiyun  * during plane update. If num_clips is 0 then this helper will do a full plane
151*4882a593Smuzhiyun  * update. This is the same behaviour expected by DIRTFB IOCTL.
152*4882a593Smuzhiyun  *
153*4882a593Smuzhiyun  * Note that this helper is blocking implementation. This is what current
154*4882a593Smuzhiyun  * drivers and userspace expect in their DIRTYFB IOCTL implementation, as a way
155*4882a593Smuzhiyun  * to rate-limit userspace and make sure its rendering doesn't get ahead of
156*4882a593Smuzhiyun  * uploading new data too much.
157*4882a593Smuzhiyun  *
158*4882a593Smuzhiyun  * Return: Zero on success, negative errno on failure.
159*4882a593Smuzhiyun  */
drm_atomic_helper_dirtyfb(struct drm_framebuffer * fb,struct drm_file * file_priv,unsigned int flags,unsigned int color,struct drm_clip_rect * clips,unsigned int num_clips)160*4882a593Smuzhiyun int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
161*4882a593Smuzhiyun 			      struct drm_file *file_priv, unsigned int flags,
162*4882a593Smuzhiyun 			      unsigned int color, struct drm_clip_rect *clips,
163*4882a593Smuzhiyun 			      unsigned int num_clips)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	struct drm_modeset_acquire_ctx ctx;
166*4882a593Smuzhiyun 	struct drm_property_blob *damage = NULL;
167*4882a593Smuzhiyun 	struct drm_mode_rect *rects = NULL;
168*4882a593Smuzhiyun 	struct drm_atomic_state *state;
169*4882a593Smuzhiyun 	struct drm_plane *plane;
170*4882a593Smuzhiyun 	int ret = 0;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	/*
173*4882a593Smuzhiyun 	 * When called from ioctl, we are interruptable, but not when called
174*4882a593Smuzhiyun 	 * internally (ie. defio worker)
175*4882a593Smuzhiyun 	 */
176*4882a593Smuzhiyun 	drm_modeset_acquire_init(&ctx,
177*4882a593Smuzhiyun 		file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	state = drm_atomic_state_alloc(fb->dev);
180*4882a593Smuzhiyun 	if (!state) {
181*4882a593Smuzhiyun 		ret = -ENOMEM;
182*4882a593Smuzhiyun 		goto out_drop_locks;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 	state->acquire_ctx = &ctx;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	if (clips) {
187*4882a593Smuzhiyun 		uint32_t inc = 1;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 		if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
190*4882a593Smuzhiyun 			inc = 2;
191*4882a593Smuzhiyun 			num_clips /= 2;
192*4882a593Smuzhiyun 		}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 		rects = kcalloc(num_clips, sizeof(*rects), GFP_KERNEL);
195*4882a593Smuzhiyun 		if (!rects) {
196*4882a593Smuzhiyun 			ret = -ENOMEM;
197*4882a593Smuzhiyun 			goto out;
198*4882a593Smuzhiyun 		}
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 		convert_clip_rect_to_rect(clips, rects, num_clips, inc);
201*4882a593Smuzhiyun 		damage = drm_property_create_blob(fb->dev,
202*4882a593Smuzhiyun 						  num_clips * sizeof(*rects),
203*4882a593Smuzhiyun 						  rects);
204*4882a593Smuzhiyun 		if (IS_ERR(damage)) {
205*4882a593Smuzhiyun 			ret = PTR_ERR(damage);
206*4882a593Smuzhiyun 			damage = NULL;
207*4882a593Smuzhiyun 			goto out;
208*4882a593Smuzhiyun 		}
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun retry:
212*4882a593Smuzhiyun 	drm_for_each_plane(plane, fb->dev) {
213*4882a593Smuzhiyun 		struct drm_plane_state *plane_state;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 		ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
216*4882a593Smuzhiyun 		if (ret)
217*4882a593Smuzhiyun 			goto out;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 		if (plane->state->fb != fb) {
220*4882a593Smuzhiyun 			drm_modeset_unlock(&plane->mutex);
221*4882a593Smuzhiyun 			continue;
222*4882a593Smuzhiyun 		}
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 		plane_state = drm_atomic_get_plane_state(state, plane);
225*4882a593Smuzhiyun 		if (IS_ERR(plane_state)) {
226*4882a593Smuzhiyun 			ret = PTR_ERR(plane_state);
227*4882a593Smuzhiyun 			goto out;
228*4882a593Smuzhiyun 		}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 		drm_property_replace_blob(&plane_state->fb_damage_clips,
231*4882a593Smuzhiyun 					  damage);
232*4882a593Smuzhiyun 	}
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	ret = drm_atomic_commit(state);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun out:
237*4882a593Smuzhiyun 	if (ret == -EDEADLK) {
238*4882a593Smuzhiyun 		drm_atomic_state_clear(state);
239*4882a593Smuzhiyun 		ret = drm_modeset_backoff(&ctx);
240*4882a593Smuzhiyun 		if (!ret)
241*4882a593Smuzhiyun 			goto retry;
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	drm_property_blob_put(damage);
245*4882a593Smuzhiyun 	kfree(rects);
246*4882a593Smuzhiyun 	drm_atomic_state_put(state);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun out_drop_locks:
249*4882a593Smuzhiyun 	drm_modeset_drop_locks(&ctx);
250*4882a593Smuzhiyun 	drm_modeset_acquire_fini(&ctx);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	return ret;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun /**
258*4882a593Smuzhiyun  * drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
259*4882a593Smuzhiyun  * @iter: The iterator to initialize.
260*4882a593Smuzhiyun  * @old_state: Old plane state for validation.
261*4882a593Smuzhiyun  * @state: Plane state from which to iterate the damage clips.
262*4882a593Smuzhiyun  *
263*4882a593Smuzhiyun  * Initialize an iterator, which clips plane damage
264*4882a593Smuzhiyun  * &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator
265*4882a593Smuzhiyun  * returns full plane src in case damage is not present because either
266*4882a593Smuzhiyun  * user-space didn't sent or driver discarded it (it want to do full plane
267*4882a593Smuzhiyun  * update). Currently this iterator returns full plane src in case plane src
268*4882a593Smuzhiyun  * changed but that can be changed in future to return damage.
269*4882a593Smuzhiyun  *
270*4882a593Smuzhiyun  * For the case when plane is not visible or plane update should not happen the
271*4882a593Smuzhiyun  * first call to iter_next will return false. Note that this helper use clipped
272*4882a593Smuzhiyun  * &drm_plane_state.src, so driver calling this helper should have called
273*4882a593Smuzhiyun  * drm_atomic_helper_check_plane_state() earlier.
274*4882a593Smuzhiyun  */
275*4882a593Smuzhiyun void
drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter * iter,const struct drm_plane_state * old_state,const struct drm_plane_state * state)276*4882a593Smuzhiyun drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
277*4882a593Smuzhiyun 				   const struct drm_plane_state *old_state,
278*4882a593Smuzhiyun 				   const struct drm_plane_state *state)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	memset(iter, 0, sizeof(*iter));
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	if (!state || !state->crtc || !state->fb || !state->visible)
283*4882a593Smuzhiyun 		return;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	iter->clips = drm_helper_get_plane_damage_clips(state);
286*4882a593Smuzhiyun 	iter->num_clips = drm_plane_get_damage_clips_count(state);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
289*4882a593Smuzhiyun 	iter->plane_src.x1 = state->src.x1 >> 16;
290*4882a593Smuzhiyun 	iter->plane_src.y1 = state->src.y1 >> 16;
291*4882a593Smuzhiyun 	iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
292*4882a593Smuzhiyun 	iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
295*4882a593Smuzhiyun 		iter->clips = NULL;
296*4882a593Smuzhiyun 		iter->num_clips = 0;
297*4882a593Smuzhiyun 		iter->full_update = true;
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun /**
303*4882a593Smuzhiyun  * drm_atomic_helper_damage_iter_next - Advance the damage iterator.
304*4882a593Smuzhiyun  * @iter: The iterator to advance.
305*4882a593Smuzhiyun  * @rect: Return a rectangle in fb coordinate clipped to plane src.
306*4882a593Smuzhiyun  *
307*4882a593Smuzhiyun  * Since plane src is in 16.16 fixed point and damage clips are whole number,
308*4882a593Smuzhiyun  * this iterator round off clips that intersect with plane src. Round down for
309*4882a593Smuzhiyun  * x1/y1 and round up for x2/y2 for the intersected coordinate. Similar rounding
310*4882a593Smuzhiyun  * off for full plane src, in case it's returned as damage. This iterator will
311*4882a593Smuzhiyun  * skip damage clips outside of plane src.
312*4882a593Smuzhiyun  *
313*4882a593Smuzhiyun  * Return: True if the output is valid, false if reached the end.
314*4882a593Smuzhiyun  *
315*4882a593Smuzhiyun  * If the first call to iterator next returns false then it means no need to
316*4882a593Smuzhiyun  * update the plane.
317*4882a593Smuzhiyun  */
318*4882a593Smuzhiyun bool
drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter * iter,struct drm_rect * rect)319*4882a593Smuzhiyun drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
320*4882a593Smuzhiyun 				   struct drm_rect *rect)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	bool ret = false;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	if (iter->full_update) {
325*4882a593Smuzhiyun 		*rect = iter->plane_src;
326*4882a593Smuzhiyun 		iter->full_update = false;
327*4882a593Smuzhiyun 		return true;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	while (iter->curr_clip < iter->num_clips) {
331*4882a593Smuzhiyun 		*rect = iter->clips[iter->curr_clip];
332*4882a593Smuzhiyun 		iter->curr_clip++;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 		if (drm_rect_intersect(rect, &iter->plane_src)) {
335*4882a593Smuzhiyun 			ret = true;
336*4882a593Smuzhiyun 			break;
337*4882a593Smuzhiyun 		}
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	return ret;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun /**
345*4882a593Smuzhiyun  * drm_atomic_helper_damage_merged - Merged plane damage
346*4882a593Smuzhiyun  * @old_state: Old plane state for validation.
347*4882a593Smuzhiyun  * @state: Plane state from which to iterate the damage clips.
348*4882a593Smuzhiyun  * @rect: Returns the merged damage rectangle
349*4882a593Smuzhiyun  *
350*4882a593Smuzhiyun  * This function merges any valid plane damage clips into one rectangle and
351*4882a593Smuzhiyun  * returns it in @rect.
352*4882a593Smuzhiyun  *
353*4882a593Smuzhiyun  * For details see: drm_atomic_helper_damage_iter_init() and
354*4882a593Smuzhiyun  * drm_atomic_helper_damage_iter_next().
355*4882a593Smuzhiyun  *
356*4882a593Smuzhiyun  * Returns:
357*4882a593Smuzhiyun  * True if there is valid plane damage otherwise false.
358*4882a593Smuzhiyun  */
drm_atomic_helper_damage_merged(const struct drm_plane_state * old_state,struct drm_plane_state * state,struct drm_rect * rect)359*4882a593Smuzhiyun bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
360*4882a593Smuzhiyun 				     struct drm_plane_state *state,
361*4882a593Smuzhiyun 				     struct drm_rect *rect)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	struct drm_atomic_helper_damage_iter iter;
364*4882a593Smuzhiyun 	struct drm_rect clip;
365*4882a593Smuzhiyun 	bool valid = false;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	rect->x1 = INT_MAX;
368*4882a593Smuzhiyun 	rect->y1 = INT_MAX;
369*4882a593Smuzhiyun 	rect->x2 = 0;
370*4882a593Smuzhiyun 	rect->y2 = 0;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
373*4882a593Smuzhiyun 	drm_atomic_for_each_plane_damage(&iter, &clip) {
374*4882a593Smuzhiyun 		rect->x1 = min(rect->x1, clip.x1);
375*4882a593Smuzhiyun 		rect->y1 = min(rect->y1, clip.y1);
376*4882a593Smuzhiyun 		rect->x2 = max(rect->x2, clip.x2);
377*4882a593Smuzhiyun 		rect->y2 = max(rect->y2, clip.y2);
378*4882a593Smuzhiyun 		valid = true;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	return valid;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun EXPORT_SYMBOL(drm_atomic_helper_damage_merged);
384