LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_damage_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 24 95 25.3 %
Date: 2023-07-19 18:55:55 Functions: 2 5 40.0 %

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

Generated by: LCOV version 1.14