LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_damage_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 94 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 5 0.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             : 
      37             : static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
      38             :                                       struct drm_mode_rect *dest,
      39             :                                       uint32_t num_clips, uint32_t src_inc)
      40             : {
      41           0 :         while (num_clips > 0) {
      42           0 :                 dest->x1 = src->x1;
      43           0 :                 dest->y1 = src->y1;
      44           0 :                 dest->x2 = src->x2;
      45           0 :                 dest->y2 = src->y2;
      46           0 :                 src += src_inc;
      47           0 :                 dest++;
      48           0 :                 num_clips--;
      49             :         }
      50             : }
      51             : 
      52             : /**
      53             :  * drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check.
      54             :  * @state: The driver state object.
      55             :  * @plane_state: Plane state for which to verify damage.
      56             :  *
      57             :  * This helper function makes sure that damage from plane state is discarded
      58             :  * for full modeset. If there are more reasons a driver would want to do a full
      59             :  * plane update rather than processing individual damage regions, then those
      60             :  * cases should be taken care of here.
      61             :  *
      62             :  * Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that
      63             :  * full plane update should happen. It also ensure helper iterator will return
      64             :  * &drm_plane_state.src as damage.
      65             :  */
      66           0 : void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
      67             :                                           struct drm_plane_state *plane_state)
      68             : {
      69             :         struct drm_crtc_state *crtc_state;
      70             : 
      71           0 :         if (plane_state->crtc) {
      72           0 :                 crtc_state = drm_atomic_get_new_crtc_state(state,
      73             :                                                            plane_state->crtc);
      74             : 
      75           0 :                 if (WARN_ON(!crtc_state))
      76             :                         return;
      77             : 
      78           0 :                 if (drm_atomic_crtc_needs_modeset(crtc_state)) {
      79           0 :                         drm_property_blob_put(plane_state->fb_damage_clips);
      80           0 :                         plane_state->fb_damage_clips = NULL;
      81             :                 }
      82             :         }
      83             : }
      84             : EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
      85             : 
      86             : /**
      87             :  * drm_atomic_helper_dirtyfb - Helper for dirtyfb.
      88             :  * @fb: DRM framebuffer.
      89             :  * @file_priv: Drm file for the ioctl call.
      90             :  * @flags: Dirty fb annotate flags.
      91             :  * @color: Color for annotate fill.
      92             :  * @clips: Dirty region.
      93             :  * @num_clips: Count of clip in clips.
      94             :  *
      95             :  * A helper to implement &drm_framebuffer_funcs.dirty using damage interface
      96             :  * during plane update. If num_clips is 0 then this helper will do a full plane
      97             :  * update. This is the same behaviour expected by DIRTFB IOCTL.
      98             :  *
      99             :  * Note that this helper is blocking implementation. This is what current
     100             :  * drivers and userspace expect in their DIRTYFB IOCTL implementation, as a way
     101             :  * to rate-limit userspace and make sure its rendering doesn't get ahead of
     102             :  * uploading new data too much.
     103             :  *
     104             :  * Return: Zero on success, negative errno on failure.
     105             :  */
     106           0 : int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
     107             :                               struct drm_file *file_priv, unsigned int flags,
     108             :                               unsigned int color, struct drm_clip_rect *clips,
     109             :                               unsigned int num_clips)
     110             : {
     111             :         struct drm_modeset_acquire_ctx ctx;
     112           0 :         struct drm_property_blob *damage = NULL;
     113           0 :         struct drm_mode_rect *rects = NULL;
     114             :         struct drm_atomic_state *state;
     115             :         struct drm_plane *plane;
     116           0 :         int ret = 0;
     117             : 
     118             :         /*
     119             :          * When called from ioctl, we are interruptible, but not when called
     120             :          * internally (ie. defio worker)
     121             :          */
     122           0 :         drm_modeset_acquire_init(&ctx,
     123             :                 file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0);
     124             : 
     125           0 :         state = drm_atomic_state_alloc(fb->dev);
     126           0 :         if (!state) {
     127             :                 ret = -ENOMEM;
     128             :                 goto out_drop_locks;
     129             :         }
     130           0 :         state->acquire_ctx = &ctx;
     131             : 
     132           0 :         if (clips) {
     133           0 :                 uint32_t inc = 1;
     134             : 
     135           0 :                 if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
     136           0 :                         inc = 2;
     137           0 :                         num_clips /= 2;
     138             :                 }
     139             : 
     140           0 :                 rects = kcalloc(num_clips, sizeof(*rects), GFP_KERNEL);
     141           0 :                 if (!rects) {
     142             :                         ret = -ENOMEM;
     143             :                         goto out;
     144             :                 }
     145             : 
     146           0 :                 convert_clip_rect_to_rect(clips, rects, num_clips, inc);
     147           0 :                 damage = drm_property_create_blob(fb->dev,
     148             :                                                   num_clips * sizeof(*rects),
     149             :                                                   rects);
     150           0 :                 if (IS_ERR(damage)) {
     151           0 :                         ret = PTR_ERR(damage);
     152           0 :                         damage = NULL;
     153           0 :                         goto out;
     154             :                 }
     155             :         }
     156             : 
     157             : retry:
     158           0 :         drm_for_each_plane(plane, fb->dev) {
     159             :                 struct drm_plane_state *plane_state;
     160             : 
     161           0 :                 ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
     162           0 :                 if (ret)
     163             :                         goto out;
     164             : 
     165           0 :                 if (plane->state->fb != fb) {
     166           0 :                         drm_modeset_unlock(&plane->mutex);
     167           0 :                         continue;
     168             :                 }
     169             : 
     170           0 :                 plane_state = drm_atomic_get_plane_state(state, plane);
     171           0 :                 if (IS_ERR(plane_state)) {
     172           0 :                         ret = PTR_ERR(plane_state);
     173           0 :                         goto out;
     174             :                 }
     175             : 
     176           0 :                 drm_property_replace_blob(&plane_state->fb_damage_clips,
     177             :                                           damage);
     178             :         }
     179             : 
     180           0 :         ret = drm_atomic_commit(state);
     181             : 
     182             : out:
     183           0 :         if (ret == -EDEADLK) {
     184           0 :                 drm_atomic_state_clear(state);
     185           0 :                 ret = drm_modeset_backoff(&ctx);
     186           0 :                 if (!ret)
     187             :                         goto retry;
     188             :         }
     189             : 
     190           0 :         drm_property_blob_put(damage);
     191           0 :         kfree(rects);
     192             :         drm_atomic_state_put(state);
     193             : 
     194             : out_drop_locks:
     195           0 :         drm_modeset_drop_locks(&ctx);
     196           0 :         drm_modeset_acquire_fini(&ctx);
     197             : 
     198           0 :         return ret;
     199             : 
     200             : }
     201             : EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
     202             : 
     203             : /**
     204             :  * drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
     205             :  * @iter: The iterator to initialize.
     206             :  * @old_state: Old plane state for validation.
     207             :  * @state: Plane state from which to iterate the damage clips.
     208             :  *
     209             :  * Initialize an iterator, which clips plane damage
     210             :  * &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator
     211             :  * returns full plane src in case damage is not present because either
     212             :  * user-space didn't sent or driver discarded it (it want to do full plane
     213             :  * update). Currently this iterator returns full plane src in case plane src
     214             :  * changed but that can be changed in future to return damage.
     215             :  *
     216             :  * For the case when plane is not visible or plane update should not happen the
     217             :  * first call to iter_next will return false. Note that this helper use clipped
     218             :  * &drm_plane_state.src, so driver calling this helper should have called
     219             :  * drm_atomic_helper_check_plane_state() earlier.
     220             :  */
     221             : void
     222           0 : drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
     223             :                                    const struct drm_plane_state *old_state,
     224             :                                    const struct drm_plane_state *state)
     225             : {
     226           0 :         memset(iter, 0, sizeof(*iter));
     227             : 
     228           0 :         if (!state || !state->crtc || !state->fb || !state->visible)
     229             :                 return;
     230             : 
     231           0 :         iter->clips = (struct drm_rect *)drm_plane_get_damage_clips(state);
     232           0 :         iter->num_clips = drm_plane_get_damage_clips_count(state);
     233             : 
     234             :         /* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
     235           0 :         iter->plane_src.x1 = state->src.x1 >> 16;
     236           0 :         iter->plane_src.y1 = state->src.y1 >> 16;
     237           0 :         iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
     238           0 :         iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
     239             : 
     240           0 :         if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
     241           0 :                 iter->clips = NULL;
     242           0 :                 iter->num_clips = 0;
     243           0 :                 iter->full_update = true;
     244             :         }
     245             : }
     246             : EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init);
     247             : 
     248             : /**
     249             :  * drm_atomic_helper_damage_iter_next - Advance the damage iterator.
     250             :  * @iter: The iterator to advance.
     251             :  * @rect: Return a rectangle in fb coordinate clipped to plane src.
     252             :  *
     253             :  * Since plane src is in 16.16 fixed point and damage clips are whole number,
     254             :  * this iterator round off clips that intersect with plane src. Round down for
     255             :  * x1/y1 and round up for x2/y2 for the intersected coordinate. Similar rounding
     256             :  * off for full plane src, in case it's returned as damage. This iterator will
     257             :  * skip damage clips outside of plane src.
     258             :  *
     259             :  * Return: True if the output is valid, false if reached the end.
     260             :  *
     261             :  * If the first call to iterator next returns false then it means no need to
     262             :  * update the plane.
     263             :  */
     264             : bool
     265           0 : drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
     266             :                                    struct drm_rect *rect)
     267             : {
     268           0 :         bool ret = false;
     269             : 
     270           0 :         if (iter->full_update) {
     271           0 :                 *rect = iter->plane_src;
     272           0 :                 iter->full_update = false;
     273           0 :                 return true;
     274             :         }
     275             : 
     276           0 :         while (iter->curr_clip < iter->num_clips) {
     277           0 :                 *rect = iter->clips[iter->curr_clip];
     278           0 :                 iter->curr_clip++;
     279             : 
     280           0 :                 if (drm_rect_intersect(rect, &iter->plane_src)) {
     281             :                         ret = true;
     282             :                         break;
     283             :                 }
     284             :         }
     285             : 
     286             :         return ret;
     287             : }
     288             : EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
     289             : 
     290             : /**
     291             :  * drm_atomic_helper_damage_merged - Merged plane damage
     292             :  * @old_state: Old plane state for validation.
     293             :  * @state: Plane state from which to iterate the damage clips.
     294             :  * @rect: Returns the merged damage rectangle
     295             :  *
     296             :  * This function merges any valid plane damage clips into one rectangle and
     297             :  * returns it in @rect.
     298             :  *
     299             :  * For details see: drm_atomic_helper_damage_iter_init() and
     300             :  * drm_atomic_helper_damage_iter_next().
     301             :  *
     302             :  * Returns:
     303             :  * True if there is valid plane damage otherwise false.
     304             :  */
     305           0 : bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
     306             :                                      struct drm_plane_state *state,
     307             :                                      struct drm_rect *rect)
     308             : {
     309             :         struct drm_atomic_helper_damage_iter iter;
     310             :         struct drm_rect clip;
     311           0 :         bool valid = false;
     312             : 
     313           0 :         rect->x1 = INT_MAX;
     314           0 :         rect->y1 = INT_MAX;
     315           0 :         rect->x2 = 0;
     316           0 :         rect->y2 = 0;
     317             : 
     318           0 :         drm_atomic_helper_damage_iter_init(&iter, old_state, state);
     319           0 :         drm_atomic_for_each_plane_damage(&iter, &clip) {
     320           0 :                 rect->x1 = min(rect->x1, clip.x1);
     321           0 :                 rect->y1 = min(rect->y1, clip.y1);
     322           0 :                 rect->x2 = max(rect->x2, clip.x2);
     323           0 :                 rect->y2 = max(rect->y2, clip.y2);
     324           0 :                 valid = true;
     325             :         }
     326             : 
     327           0 :         return valid;
     328             : }
     329             : EXPORT_SYMBOL(drm_atomic_helper_damage_merged);

Generated by: LCOV version 1.14