LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_damage_helper.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 115 0.0 %
Date: 2022-04-01 14:17:54 Functions: 0 6 0.0 %
Branches: 0 60 0.0 %

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

Generated by: LCOV version 1.14