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