1d3b21767SLukasz Spintzyk // SPDX-License-Identifier: GPL-2.0 OR MIT
2d3b21767SLukasz Spintzyk /**************************************************************************
3d3b21767SLukasz Spintzyk  *
4d3b21767SLukasz Spintzyk  * Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA
5d3b21767SLukasz Spintzyk  * All Rights Reserved.
6d3b21767SLukasz Spintzyk  *
7d3b21767SLukasz Spintzyk  * Permission is hereby granted, free of charge, to any person obtaining a
8d3b21767SLukasz Spintzyk  * copy of this software and associated documentation files (the
9d3b21767SLukasz Spintzyk  * "Software"), to deal in the Software without restriction, including
10d3b21767SLukasz Spintzyk  * without limitation the rights to use, copy, modify, merge, publish,
11d3b21767SLukasz Spintzyk  * distribute, sub license, and/or sell copies of the Software, and to
12d3b21767SLukasz Spintzyk  * permit persons to whom the Software is furnished to do so, subject to
13d3b21767SLukasz Spintzyk  * the following conditions:
14d3b21767SLukasz Spintzyk  *
15d3b21767SLukasz Spintzyk  * The above copyright notice and this permission notice (including the
16d3b21767SLukasz Spintzyk  * next paragraph) shall be included in all copies or substantial portions
17d3b21767SLukasz Spintzyk  * of the Software.
18d3b21767SLukasz Spintzyk  *
19d3b21767SLukasz Spintzyk  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20d3b21767SLukasz Spintzyk  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21d3b21767SLukasz Spintzyk  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22d3b21767SLukasz Spintzyk  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23d3b21767SLukasz Spintzyk  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24d3b21767SLukasz Spintzyk  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25d3b21767SLukasz Spintzyk  * USE OR OTHER DEALINGS IN THE SOFTWARE.
26d3b21767SLukasz Spintzyk  *
27d3b21767SLukasz Spintzyk  * Authors:
28d3b21767SLukasz Spintzyk  * Deepak Rawat <drawat@vmware.com>
29b9fc5e01SRob Clark  * Rob Clark <robdclark@gmail.com>
30d3b21767SLukasz Spintzyk  *
31d3b21767SLukasz Spintzyk  **************************************************************************/
32d3b21767SLukasz Spintzyk 
33d9778b40SDeepak Rawat #include <drm/drm_atomic.h>
34d3b21767SLukasz Spintzyk #include <drm/drm_damage_helper.h>
35d713e330SSam Ravnborg #include <drm/drm_device.h>
36720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
37d3b21767SLukasz Spintzyk 
convert_clip_rect_to_rect(const struct drm_clip_rect * src,struct drm_mode_rect * dest,uint32_t num_clips,uint32_t src_inc)38b9fc5e01SRob Clark static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
39b9fc5e01SRob Clark 				      struct drm_mode_rect *dest,
40b9fc5e01SRob Clark 				      uint32_t num_clips, uint32_t src_inc)
41b9fc5e01SRob Clark {
42b9fc5e01SRob Clark 	while (num_clips > 0) {
43b9fc5e01SRob Clark 		dest->x1 = src->x1;
44b9fc5e01SRob Clark 		dest->y1 = src->y1;
45b9fc5e01SRob Clark 		dest->x2 = src->x2;
46b9fc5e01SRob Clark 		dest->y2 = src->y2;
47b9fc5e01SRob Clark 		src += src_inc;
48b9fc5e01SRob Clark 		dest++;
49b9fc5e01SRob Clark 		num_clips--;
50b9fc5e01SRob Clark 	}
51b9fc5e01SRob Clark }
52b9fc5e01SRob Clark 
53d3b21767SLukasz Spintzyk /**
54d9778b40SDeepak Rawat  * drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check.
55d9778b40SDeepak Rawat  * @state: The driver state object.
56d9778b40SDeepak Rawat  * @plane_state: Plane state for which to verify damage.
57d9778b40SDeepak Rawat  *
58d9778b40SDeepak Rawat  * This helper function makes sure that damage from plane state is discarded
59d9778b40SDeepak Rawat  * for full modeset. If there are more reasons a driver would want to do a full
60d9778b40SDeepak Rawat  * plane update rather than processing individual damage regions, then those
61d9778b40SDeepak Rawat  * cases should be taken care of here.
62d9778b40SDeepak Rawat  *
63d9778b40SDeepak Rawat  * Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that
64d9778b40SDeepak Rawat  * full plane update should happen. It also ensure helper iterator will return
65d9778b40SDeepak Rawat  * &drm_plane_state.src as damage.
66d9778b40SDeepak Rawat  */
drm_atomic_helper_check_plane_damage(struct drm_atomic_state * state,struct drm_plane_state * plane_state)67d9778b40SDeepak Rawat void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
68d9778b40SDeepak Rawat 					  struct drm_plane_state *plane_state)
69d9778b40SDeepak Rawat {
70d9778b40SDeepak Rawat 	struct drm_crtc_state *crtc_state;
71d9778b40SDeepak Rawat 
72d9778b40SDeepak Rawat 	if (plane_state->crtc) {
73d9778b40SDeepak Rawat 		crtc_state = drm_atomic_get_new_crtc_state(state,
74d9778b40SDeepak Rawat 							   plane_state->crtc);
75d9778b40SDeepak Rawat 
76d9778b40SDeepak Rawat 		if (WARN_ON(!crtc_state))
77d9778b40SDeepak Rawat 			return;
78d9778b40SDeepak Rawat 
79d9778b40SDeepak Rawat 		if (drm_atomic_crtc_needs_modeset(crtc_state)) {
80d9778b40SDeepak Rawat 			drm_property_blob_put(plane_state->fb_damage_clips);
81d9778b40SDeepak Rawat 			plane_state->fb_damage_clips = NULL;
82d9778b40SDeepak Rawat 		}
83d9778b40SDeepak Rawat 	}
84d9778b40SDeepak Rawat }
85d9778b40SDeepak Rawat EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
86d2780b1fSDeepak Rawat 
87d2780b1fSDeepak Rawat /**
88b9fc5e01SRob Clark  * drm_atomic_helper_dirtyfb - Helper for dirtyfb.
89b9fc5e01SRob Clark  * @fb: DRM framebuffer.
90b9fc5e01SRob Clark  * @file_priv: Drm file for the ioctl call.
91b9fc5e01SRob Clark  * @flags: Dirty fb annotate flags.
92b9fc5e01SRob Clark  * @color: Color for annotate fill.
93b9fc5e01SRob Clark  * @clips: Dirty region.
94b9fc5e01SRob Clark  * @num_clips: Count of clip in clips.
95b9fc5e01SRob Clark  *
96b9fc5e01SRob Clark  * A helper to implement &drm_framebuffer_funcs.dirty using damage interface
97b9fc5e01SRob Clark  * during plane update. If num_clips is 0 then this helper will do a full plane
98b9fc5e01SRob Clark  * update. This is the same behaviour expected by DIRTFB IOCTL.
99b9fc5e01SRob Clark  *
100b9fc5e01SRob Clark  * Note that this helper is blocking implementation. This is what current
101b9fc5e01SRob Clark  * drivers and userspace expect in their DIRTYFB IOCTL implementation, as a way
102b9fc5e01SRob Clark  * to rate-limit userspace and make sure its rendering doesn't get ahead of
103b9fc5e01SRob Clark  * uploading new data too much.
104b9fc5e01SRob Clark  *
105b9fc5e01SRob Clark  * Return: Zero on success, negative errno on failure.
106b9fc5e01SRob Clark  */
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)107b9fc5e01SRob Clark int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
108b9fc5e01SRob Clark 			      struct drm_file *file_priv, unsigned int flags,
109b9fc5e01SRob Clark 			      unsigned int color, struct drm_clip_rect *clips,
110b9fc5e01SRob Clark 			      unsigned int num_clips)
111b9fc5e01SRob Clark {
112b9fc5e01SRob Clark 	struct drm_modeset_acquire_ctx ctx;
113b9fc5e01SRob Clark 	struct drm_property_blob *damage = NULL;
114b9fc5e01SRob Clark 	struct drm_mode_rect *rects = NULL;
115b9fc5e01SRob Clark 	struct drm_atomic_state *state;
116b9fc5e01SRob Clark 	struct drm_plane *plane;
117b9fc5e01SRob Clark 	int ret = 0;
118b9fc5e01SRob Clark 
119b9fc5e01SRob Clark 	/*
1200ae865efSCai Huoqing 	 * When called from ioctl, we are interruptible, but not when called
121b9fc5e01SRob Clark 	 * internally (ie. defio worker)
122b9fc5e01SRob Clark 	 */
123b9fc5e01SRob Clark 	drm_modeset_acquire_init(&ctx,
124b9fc5e01SRob Clark 		file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0);
125b9fc5e01SRob Clark 
126b9fc5e01SRob Clark 	state = drm_atomic_state_alloc(fb->dev);
127b9fc5e01SRob Clark 	if (!state) {
128b9fc5e01SRob Clark 		ret = -ENOMEM;
129cbdd2663SColin Ian King 		goto out_drop_locks;
130b9fc5e01SRob Clark 	}
131b9fc5e01SRob Clark 	state->acquire_ctx = &ctx;
132b9fc5e01SRob Clark 
133b9fc5e01SRob Clark 	if (clips) {
134b9fc5e01SRob Clark 		uint32_t inc = 1;
135b9fc5e01SRob Clark 
136b9fc5e01SRob Clark 		if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
137b9fc5e01SRob Clark 			inc = 2;
138b9fc5e01SRob Clark 			num_clips /= 2;
139b9fc5e01SRob Clark 		}
140b9fc5e01SRob Clark 
141b9fc5e01SRob Clark 		rects = kcalloc(num_clips, sizeof(*rects), GFP_KERNEL);
142b9fc5e01SRob Clark 		if (!rects) {
143b9fc5e01SRob Clark 			ret = -ENOMEM;
144b9fc5e01SRob Clark 			goto out;
145b9fc5e01SRob Clark 		}
146b9fc5e01SRob Clark 
147b9fc5e01SRob Clark 		convert_clip_rect_to_rect(clips, rects, num_clips, inc);
148b9fc5e01SRob Clark 		damage = drm_property_create_blob(fb->dev,
149b9fc5e01SRob Clark 						  num_clips * sizeof(*rects),
150b9fc5e01SRob Clark 						  rects);
151b9fc5e01SRob Clark 		if (IS_ERR(damage)) {
152b9fc5e01SRob Clark 			ret = PTR_ERR(damage);
153b9fc5e01SRob Clark 			damage = NULL;
154b9fc5e01SRob Clark 			goto out;
155b9fc5e01SRob Clark 		}
156b9fc5e01SRob Clark 	}
157b9fc5e01SRob Clark 
158b9fc5e01SRob Clark retry:
159b9fc5e01SRob Clark 	drm_for_each_plane(plane, fb->dev) {
160b9fc5e01SRob Clark 		struct drm_plane_state *plane_state;
161b9fc5e01SRob Clark 
162354c2d31SSean Paul 		ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
163354c2d31SSean Paul 		if (ret)
164354c2d31SSean Paul 			goto out;
165354c2d31SSean Paul 
166354c2d31SSean Paul 		if (plane->state->fb != fb) {
167354c2d31SSean Paul 			drm_modeset_unlock(&plane->mutex);
168b9fc5e01SRob Clark 			continue;
169354c2d31SSean Paul 		}
170b9fc5e01SRob Clark 
171b9fc5e01SRob Clark 		plane_state = drm_atomic_get_plane_state(state, plane);
172b9fc5e01SRob Clark 		if (IS_ERR(plane_state)) {
173b9fc5e01SRob Clark 			ret = PTR_ERR(plane_state);
174b9fc5e01SRob Clark 			goto out;
175b9fc5e01SRob Clark 		}
176b9fc5e01SRob Clark 
177b9fc5e01SRob Clark 		drm_property_replace_blob(&plane_state->fb_damage_clips,
178b9fc5e01SRob Clark 					  damage);
179b9fc5e01SRob Clark 	}
180b9fc5e01SRob Clark 
181b9fc5e01SRob Clark 	ret = drm_atomic_commit(state);
182b9fc5e01SRob Clark 
183b9fc5e01SRob Clark out:
184b9fc5e01SRob Clark 	if (ret == -EDEADLK) {
185b9fc5e01SRob Clark 		drm_atomic_state_clear(state);
186b9fc5e01SRob Clark 		ret = drm_modeset_backoff(&ctx);
187b9fc5e01SRob Clark 		if (!ret)
188b9fc5e01SRob Clark 			goto retry;
189b9fc5e01SRob Clark 	}
190b9fc5e01SRob Clark 
191b9fc5e01SRob Clark 	drm_property_blob_put(damage);
192b9fc5e01SRob Clark 	kfree(rects);
193b9fc5e01SRob Clark 	drm_atomic_state_put(state);
194b9fc5e01SRob Clark 
195cbdd2663SColin Ian King out_drop_locks:
196b9fc5e01SRob Clark 	drm_modeset_drop_locks(&ctx);
197b9fc5e01SRob Clark 	drm_modeset_acquire_fini(&ctx);
198b9fc5e01SRob Clark 
199b9fc5e01SRob Clark 	return ret;
200b9fc5e01SRob Clark 
201b9fc5e01SRob Clark }
202b9fc5e01SRob Clark EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
203b9fc5e01SRob Clark 
204b9fc5e01SRob Clark /**
205d2780b1fSDeepak Rawat  * drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
206d2780b1fSDeepak Rawat  * @iter: The iterator to initialize.
207d2780b1fSDeepak Rawat  * @old_state: Old plane state for validation.
2080660d8cdSDeepak Rawat  * @state: Plane state from which to iterate the damage clips.
209d2780b1fSDeepak Rawat  *
210d2780b1fSDeepak Rawat  * Initialize an iterator, which clips plane damage
211d2780b1fSDeepak Rawat  * &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator
212d2780b1fSDeepak Rawat  * returns full plane src in case damage is not present because either
213d2780b1fSDeepak Rawat  * user-space didn't sent or driver discarded it (it want to do full plane
214d2780b1fSDeepak Rawat  * update). Currently this iterator returns full plane src in case plane src
215d2780b1fSDeepak Rawat  * changed but that can be changed in future to return damage.
216d2780b1fSDeepak Rawat  *
217d2780b1fSDeepak Rawat  * For the case when plane is not visible or plane update should not happen the
218d2780b1fSDeepak Rawat  * first call to iter_next will return false. Note that this helper use clipped
219d2780b1fSDeepak Rawat  * &drm_plane_state.src, so driver calling this helper should have called
220d2780b1fSDeepak Rawat  * drm_atomic_helper_check_plane_state() earlier.
221d2780b1fSDeepak Rawat  */
222d2780b1fSDeepak Rawat 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)223d2780b1fSDeepak Rawat drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
224d2780b1fSDeepak Rawat 				   const struct drm_plane_state *old_state,
225d2780b1fSDeepak Rawat 				   const struct drm_plane_state *state)
226d2780b1fSDeepak Rawat {
227dd9b18e7SJouni Högander 	struct drm_rect src;
228d2780b1fSDeepak Rawat 	memset(iter, 0, sizeof(*iter));
229d2780b1fSDeepak Rawat 
230d2780b1fSDeepak Rawat 	if (!state || !state->crtc || !state->fb || !state->visible)
231d2780b1fSDeepak Rawat 		return;
232d2780b1fSDeepak Rawat 
2336f11f374SDaniel Vetter 	iter->clips = (struct drm_rect *)drm_plane_get_damage_clips(state);
234d2780b1fSDeepak Rawat 	iter->num_clips = drm_plane_get_damage_clips_count(state);
235d2780b1fSDeepak Rawat 
236d2780b1fSDeepak Rawat 	/* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
237dd9b18e7SJouni Högander 	src = drm_plane_state_src(state);
238dd9b18e7SJouni Högander 
239dd9b18e7SJouni Högander 	iter->plane_src.x1 = src.x1 >> 16;
240dd9b18e7SJouni Högander 	iter->plane_src.y1 = src.y1 >> 16;
241dd9b18e7SJouni Högander 	iter->plane_src.x2 = (src.x2 >> 16) + !!(src.x2 & 0xFFFF);
242dd9b18e7SJouni Högander 	iter->plane_src.y2 = (src.y2 >> 16) + !!(src.y2 & 0xFFFF);
243d2780b1fSDeepak Rawat 
244*45aafb50SJavier Martinez Canillas 	if (!iter->clips || state->ignore_damage_clips ||
245*45aafb50SJavier Martinez Canillas 	    !drm_rect_equals(&state->src, &old_state->src)) {
246fd86575fSFabio Estevam 		iter->clips = NULL;
247d2780b1fSDeepak Rawat 		iter->num_clips = 0;
248d2780b1fSDeepak Rawat 		iter->full_update = true;
249d2780b1fSDeepak Rawat 	}
250d2780b1fSDeepak Rawat }
251d2780b1fSDeepak Rawat EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init);
252d2780b1fSDeepak Rawat 
253d2780b1fSDeepak Rawat /**
254d2780b1fSDeepak Rawat  * drm_atomic_helper_damage_iter_next - Advance the damage iterator.
255d2780b1fSDeepak Rawat  * @iter: The iterator to advance.
256d2780b1fSDeepak Rawat  * @rect: Return a rectangle in fb coordinate clipped to plane src.
257d2780b1fSDeepak Rawat  *
258d2780b1fSDeepak Rawat  * Since plane src is in 16.16 fixed point and damage clips are whole number,
259d2780b1fSDeepak Rawat  * this iterator round off clips that intersect with plane src. Round down for
260d2780b1fSDeepak Rawat  * x1/y1 and round up for x2/y2 for the intersected coordinate. Similar rounding
261d2780b1fSDeepak Rawat  * off for full plane src, in case it's returned as damage. This iterator will
262d2780b1fSDeepak Rawat  * skip damage clips outside of plane src.
263d2780b1fSDeepak Rawat  *
264d2780b1fSDeepak Rawat  * Return: True if the output is valid, false if reached the end.
265d2780b1fSDeepak Rawat  *
266d2780b1fSDeepak Rawat  * If the first call to iterator next returns false then it means no need to
267d2780b1fSDeepak Rawat  * update the plane.
268d2780b1fSDeepak Rawat  */
269d2780b1fSDeepak Rawat bool
drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter * iter,struct drm_rect * rect)270d2780b1fSDeepak Rawat drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
271d2780b1fSDeepak Rawat 				   struct drm_rect *rect)
272d2780b1fSDeepak Rawat {
273d2780b1fSDeepak Rawat 	bool ret = false;
274d2780b1fSDeepak Rawat 
275d2780b1fSDeepak Rawat 	if (iter->full_update) {
276d2780b1fSDeepak Rawat 		*rect = iter->plane_src;
277d2780b1fSDeepak Rawat 		iter->full_update = false;
278d2780b1fSDeepak Rawat 		return true;
279d2780b1fSDeepak Rawat 	}
280d2780b1fSDeepak Rawat 
281d2780b1fSDeepak Rawat 	while (iter->curr_clip < iter->num_clips) {
282d2780b1fSDeepak Rawat 		*rect = iter->clips[iter->curr_clip];
283d2780b1fSDeepak Rawat 		iter->curr_clip++;
284d2780b1fSDeepak Rawat 
285d2780b1fSDeepak Rawat 		if (drm_rect_intersect(rect, &iter->plane_src)) {
286d2780b1fSDeepak Rawat 			ret = true;
287d2780b1fSDeepak Rawat 			break;
288d2780b1fSDeepak Rawat 		}
289d2780b1fSDeepak Rawat 	}
290d2780b1fSDeepak Rawat 
291d2780b1fSDeepak Rawat 	return ret;
292d2780b1fSDeepak Rawat }
293d2780b1fSDeepak Rawat EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
294255f6fe7SNoralf Trønnes 
295255f6fe7SNoralf Trønnes /**
296255f6fe7SNoralf Trønnes  * drm_atomic_helper_damage_merged - Merged plane damage
297255f6fe7SNoralf Trønnes  * @old_state: Old plane state for validation.
298255f6fe7SNoralf Trønnes  * @state: Plane state from which to iterate the damage clips.
299255f6fe7SNoralf Trønnes  * @rect: Returns the merged damage rectangle
300255f6fe7SNoralf Trønnes  *
301255f6fe7SNoralf Trønnes  * This function merges any valid plane damage clips into one rectangle and
302255f6fe7SNoralf Trønnes  * returns it in @rect.
303255f6fe7SNoralf Trønnes  *
304255f6fe7SNoralf Trønnes  * For details see: drm_atomic_helper_damage_iter_init() and
305255f6fe7SNoralf Trønnes  * drm_atomic_helper_damage_iter_next().
306255f6fe7SNoralf Trønnes  *
307255f6fe7SNoralf Trønnes  * Returns:
308255f6fe7SNoralf Trønnes  * True if there is valid plane damage otherwise false.
309255f6fe7SNoralf Trønnes  */
drm_atomic_helper_damage_merged(const struct drm_plane_state * old_state,struct drm_plane_state * state,struct drm_rect * rect)310255f6fe7SNoralf Trønnes bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
311255f6fe7SNoralf Trønnes 				     struct drm_plane_state *state,
312255f6fe7SNoralf Trønnes 				     struct drm_rect *rect)
313255f6fe7SNoralf Trønnes {
314255f6fe7SNoralf Trønnes 	struct drm_atomic_helper_damage_iter iter;
315255f6fe7SNoralf Trønnes 	struct drm_rect clip;
316255f6fe7SNoralf Trønnes 	bool valid = false;
317255f6fe7SNoralf Trønnes 
318255f6fe7SNoralf Trønnes 	rect->x1 = INT_MAX;
319255f6fe7SNoralf Trønnes 	rect->y1 = INT_MAX;
320255f6fe7SNoralf Trønnes 	rect->x2 = 0;
321255f6fe7SNoralf Trønnes 	rect->y2 = 0;
322255f6fe7SNoralf Trønnes 
323255f6fe7SNoralf Trønnes 	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
324255f6fe7SNoralf Trønnes 	drm_atomic_for_each_plane_damage(&iter, &clip) {
325255f6fe7SNoralf Trønnes 		rect->x1 = min(rect->x1, clip.x1);
326255f6fe7SNoralf Trønnes 		rect->y1 = min(rect->y1, clip.y1);
327255f6fe7SNoralf Trønnes 		rect->x2 = max(rect->x2, clip.x2);
328255f6fe7SNoralf Trønnes 		rect->y2 = max(rect->y2, clip.y2);
329255f6fe7SNoralf Trønnes 		valid = true;
330255f6fe7SNoralf Trønnes 	}
331255f6fe7SNoralf Trønnes 
332255f6fe7SNoralf Trønnes 	return valid;
333255f6fe7SNoralf Trønnes }
334255f6fe7SNoralf Trønnes EXPORT_SYMBOL(drm_atomic_helper_damage_merged);
335