Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'vmwgfx-next-2018-12-05' of git://people.freedesktop.org/~thomash/linux into drm-next

Pull request of 2018-12-05

Page flip with damage by Deepak and others,
Various vmwgfx minor fixes anc cleanups.

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Thomas Hellstrom <thellstrom@vmware.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181205103554.3675-1-thellstrom@vmware.com

+2521 -565
+12
Documentation/gpu/drm-kms.rst
··· 554 554 .. kernel-doc:: drivers/gpu/drm/drm_blend.c 555 555 :export: 556 556 557 + FB_DAMAGE_CLIPS 558 + ~~~~~~~~~~~~~~~ 559 + 560 + .. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c 561 + :doc: overview 562 + 563 + .. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c 564 + :export: 565 + 566 + .. kernel-doc:: include/drm/drm_damage_helper.h 567 + :internal: 568 + 557 569 Color Management Properties 558 570 --------------------------- 559 571
-2
MAINTAINERS
··· 4781 4781 4782 4782 DRM DRIVER FOR VMWARE VIRTUAL GPU 4783 4783 M: "VMware Graphics" <linux-graphics-maintainer@vmware.com> 4784 - M: Sinclair Yeh <syeh@vmware.com> 4785 4784 M: Thomas Hellstrom <thellstrom@vmware.com> 4786 4785 L: dri-devel@lists.freedesktop.org 4787 - T: git git://people.freedesktop.org/~syeh/repos_linux 4788 4786 T: git git://people.freedesktop.org/~thomash/linux 4789 4787 S: Supported 4790 4788 F: drivers/gpu/drm/vmwgfx/
+1 -1
drivers/gpu/drm/Makefile
··· 37 37 drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ 38 38 drm_simple_kms_helper.o drm_modeset_helper.o \ 39 39 drm_scdc_helper.o drm_gem_framebuffer_helper.o \ 40 - drm_atomic_state_helper.o 40 + drm_atomic_state_helper.o drm_damage_helper.o 41 41 42 42 drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o 43 43 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
+22
drivers/gpu/drm/drm_atomic.c
··· 531 531 struct drm_crtc *crtc = new_plane_state->crtc; 532 532 const struct drm_framebuffer *fb = new_plane_state->fb; 533 533 unsigned int fb_width, fb_height; 534 + struct drm_mode_rect *clips; 535 + uint32_t num_clips; 534 536 int ret; 535 537 536 538 /* either *both* CRTC and FB must be set, or neither */ ··· 604 602 ((new_plane_state->src_y & 0xffff) * 15625) >> 10, 605 603 fb->width, fb->height); 606 604 return -ENOSPC; 605 + } 606 + 607 + clips = drm_plane_get_damage_clips(new_plane_state); 608 + num_clips = drm_plane_get_damage_clips_count(new_plane_state); 609 + 610 + /* Make sure damage clips are valid and inside the fb. */ 611 + while (num_clips > 0) { 612 + if (clips->x1 >= clips->x2 || 613 + clips->y1 >= clips->y2 || 614 + clips->x1 < 0 || 615 + clips->y1 < 0 || 616 + clips->x2 > fb_width || 617 + clips->y2 > fb_height) { 618 + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid damage clip %d %d %d %d\n", 619 + plane->base.id, plane->name, clips->x1, 620 + clips->y1, clips->x2, clips->y2); 621 + return -EINVAL; 622 + } 623 + clips++; 624 + num_clips--; 607 625 } 608 626 609 627 if (plane_switching_crtc(old_plane_state, new_plane_state)) {
+3
drivers/gpu/drm/drm_atomic_helper.c
··· 32 32 #include <drm/drm_crtc_helper.h> 33 33 #include <drm/drm_atomic_helper.h> 34 34 #include <drm/drm_writeback.h> 35 + #include <drm/drm_damage_helper.h> 35 36 #include <linux/dma-fence.h> 36 37 37 38 #include "drm_crtc_helper_internal.h" ··· 862 861 funcs = plane->helper_private; 863 862 864 863 drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane); 864 + 865 + drm_atomic_helper_check_plane_damage(state, new_plane_state); 865 866 866 867 if (!funcs || !funcs->atomic_check) 867 868 continue;
+13
drivers/gpu/drm/drm_atomic_uapi.c
··· 517 517 { 518 518 struct drm_device *dev = plane->dev; 519 519 struct drm_mode_config *config = &dev->mode_config; 520 + bool replaced = false; 521 + int ret; 520 522 521 523 if (property == config->prop_fb_id) { 522 524 struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); ··· 572 570 state->color_encoding = val; 573 571 } else if (property == plane->color_range_property) { 574 572 state->color_range = val; 573 + } else if (property == config->prop_fb_damage_clips) { 574 + ret = drm_atomic_replace_property_blob_from_id(dev, 575 + &state->fb_damage_clips, 576 + val, 577 + -1, 578 + sizeof(struct drm_rect), 579 + &replaced); 580 + return ret; 575 581 } else if (plane->funcs->atomic_set_property) { 576 582 return plane->funcs->atomic_set_property(plane, state, 577 583 property, val); ··· 635 625 *val = state->color_encoding; 636 626 } else if (property == plane->color_range_property) { 637 627 *val = state->color_range; 628 + } else if (property == config->prop_fb_damage_clips) { 629 + *val = (state->fb_damage_clips) ? 630 + state->fb_damage_clips->base.id : 0; 638 631 } else if (plane->funcs->atomic_get_property) { 639 632 return plane->funcs->atomic_get_property(plane, state, property, val); 640 633 } else {
+334
drivers/gpu/drm/drm_damage_helper.c
··· 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 + 36 + /** 37 + * DOC: overview 38 + * 39 + * FB_DAMAGE_CLIPS is an optional plane property which provides a means to 40 + * specify a list of damage rectangles on a plane in framebuffer coordinates of 41 + * the framebuffer attached to the plane. In current context damage is the area 42 + * of plane framebuffer that has changed since last plane update (also called 43 + * page-flip), irrespective of whether currently attached framebuffer is same as 44 + * framebuffer attached during last plane update or not. 45 + * 46 + * FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers 47 + * to optimize internally especially for virtual devices where each framebuffer 48 + * change needs to be transmitted over network, usb, etc. 49 + * 50 + * Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can 51 + * ignore damage clips property and in that case driver will do a full plane 52 + * update. In case damage clips are provided then it is guaranteed that the area 53 + * inside damage clips will be updated to plane. For efficiency driver can do 54 + * full update or can update more than specified in damage clips. Since driver 55 + * is free to read more, user-space must always render the entire visible 56 + * framebuffer. Otherwise there can be corruptions. Also, if a user-space 57 + * provides damage clips which doesn't encompass the actual damage to 58 + * framebuffer (since last plane update) can result in incorrect rendering. 59 + * 60 + * FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an 61 + * array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates, 62 + * damage clips are not in 16.16 fixed point. Similar to plane src in 63 + * framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are 64 + * inclusive and x2/y2 are exclusive. While kernel does not error for overlapped 65 + * damage clips, it is strongly discouraged. 66 + * 67 + * Drivers that are interested in damage interface for plane should enable 68 + * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips(). 69 + * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and 70 + * drm_atomic_helper_damage_iter_next() helper iterator function to get damage 71 + * rectangles clipped to &drm_plane_state.src. 72 + */ 73 + 74 + static void convert_clip_rect_to_rect(const struct drm_clip_rect *src, 75 + struct drm_mode_rect *dest, 76 + uint32_t num_clips, uint32_t src_inc) 77 + { 78 + while (num_clips > 0) { 79 + dest->x1 = src->x1; 80 + dest->y1 = src->y1; 81 + dest->x2 = src->x2; 82 + dest->y2 = src->y2; 83 + src += src_inc; 84 + dest++; 85 + num_clips--; 86 + } 87 + } 88 + 89 + /** 90 + * drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property. 91 + * @plane: Plane on which to enable damage clips property. 92 + * 93 + * This function lets driver to enable the damage clips property on a plane. 94 + */ 95 + void drm_plane_enable_fb_damage_clips(struct drm_plane *plane) 96 + { 97 + struct drm_device *dev = plane->dev; 98 + struct drm_mode_config *config = &dev->mode_config; 99 + 100 + drm_object_attach_property(&plane->base, config->prop_fb_damage_clips, 101 + 0); 102 + } 103 + EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips); 104 + 105 + /** 106 + * drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check. 107 + * @state: The driver state object. 108 + * @plane_state: Plane state for which to verify damage. 109 + * 110 + * This helper function makes sure that damage from plane state is discarded 111 + * for full modeset. If there are more reasons a driver would want to do a full 112 + * plane update rather than processing individual damage regions, then those 113 + * cases should be taken care of here. 114 + * 115 + * Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that 116 + * full plane update should happen. It also ensure helper iterator will return 117 + * &drm_plane_state.src as damage. 118 + */ 119 + void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state, 120 + struct drm_plane_state *plane_state) 121 + { 122 + struct drm_crtc_state *crtc_state; 123 + 124 + if (plane_state->crtc) { 125 + crtc_state = drm_atomic_get_new_crtc_state(state, 126 + plane_state->crtc); 127 + 128 + if (WARN_ON(!crtc_state)) 129 + return; 130 + 131 + if (drm_atomic_crtc_needs_modeset(crtc_state)) { 132 + drm_property_blob_put(plane_state->fb_damage_clips); 133 + plane_state->fb_damage_clips = NULL; 134 + } 135 + } 136 + } 137 + EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage); 138 + 139 + /** 140 + * drm_atomic_helper_dirtyfb - Helper for dirtyfb. 141 + * @fb: DRM framebuffer. 142 + * @file_priv: Drm file for the ioctl call. 143 + * @flags: Dirty fb annotate flags. 144 + * @color: Color for annotate fill. 145 + * @clips: Dirty region. 146 + * @num_clips: Count of clip in clips. 147 + * 148 + * A helper to implement &drm_framebuffer_funcs.dirty using damage interface 149 + * during plane update. If num_clips is 0 then this helper will do a full plane 150 + * update. This is the same behaviour expected by DIRTFB IOCTL. 151 + * 152 + * Note that this helper is blocking implementation. This is what current 153 + * drivers and userspace expect in their DIRTYFB IOCTL implementation, as a way 154 + * to rate-limit userspace and make sure its rendering doesn't get ahead of 155 + * uploading new data too much. 156 + * 157 + * Return: Zero on success, negative errno on failure. 158 + */ 159 + int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb, 160 + struct drm_file *file_priv, unsigned int flags, 161 + unsigned int color, struct drm_clip_rect *clips, 162 + unsigned int num_clips) 163 + { 164 + struct drm_modeset_acquire_ctx ctx; 165 + struct drm_property_blob *damage = NULL; 166 + struct drm_mode_rect *rects = NULL; 167 + struct drm_atomic_state *state; 168 + struct drm_plane *plane; 169 + int ret = 0; 170 + 171 + /* 172 + * When called from ioctl, we are interruptable, but not when called 173 + * internally (ie. defio worker) 174 + */ 175 + drm_modeset_acquire_init(&ctx, 176 + file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0); 177 + 178 + state = drm_atomic_state_alloc(fb->dev); 179 + if (!state) { 180 + ret = -ENOMEM; 181 + goto out; 182 + } 183 + state->acquire_ctx = &ctx; 184 + 185 + if (clips) { 186 + uint32_t inc = 1; 187 + 188 + if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { 189 + inc = 2; 190 + num_clips /= 2; 191 + } 192 + 193 + rects = kcalloc(num_clips, sizeof(*rects), GFP_KERNEL); 194 + if (!rects) { 195 + ret = -ENOMEM; 196 + goto out; 197 + } 198 + 199 + convert_clip_rect_to_rect(clips, rects, num_clips, inc); 200 + damage = drm_property_create_blob(fb->dev, 201 + num_clips * sizeof(*rects), 202 + rects); 203 + if (IS_ERR(damage)) { 204 + ret = PTR_ERR(damage); 205 + damage = NULL; 206 + goto out; 207 + } 208 + } 209 + 210 + retry: 211 + drm_for_each_plane(plane, fb->dev) { 212 + struct drm_plane_state *plane_state; 213 + 214 + if (plane->state->fb != fb) 215 + continue; 216 + 217 + plane_state = drm_atomic_get_plane_state(state, plane); 218 + if (IS_ERR(plane_state)) { 219 + ret = PTR_ERR(plane_state); 220 + goto out; 221 + } 222 + 223 + drm_property_replace_blob(&plane_state->fb_damage_clips, 224 + damage); 225 + } 226 + 227 + ret = drm_atomic_commit(state); 228 + 229 + out: 230 + if (ret == -EDEADLK) { 231 + drm_atomic_state_clear(state); 232 + ret = drm_modeset_backoff(&ctx); 233 + if (!ret) 234 + goto retry; 235 + } 236 + 237 + drm_property_blob_put(damage); 238 + kfree(rects); 239 + drm_atomic_state_put(state); 240 + 241 + drm_modeset_drop_locks(&ctx); 242 + drm_modeset_acquire_fini(&ctx); 243 + 244 + return ret; 245 + 246 + } 247 + EXPORT_SYMBOL(drm_atomic_helper_dirtyfb); 248 + 249 + /** 250 + * drm_atomic_helper_damage_iter_init - Initialize the damage iterator. 251 + * @iter: The iterator to initialize. 252 + * @old_state: Old plane state for validation. 253 + * @new_state: Plane state from which to iterate the damage clips. 254 + * 255 + * Initialize an iterator, which clips plane damage 256 + * &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator 257 + * returns full plane src in case damage is not present because either 258 + * user-space didn't sent or driver discarded it (it want to do full plane 259 + * update). Currently this iterator returns full plane src in case plane src 260 + * changed but that can be changed in future to return damage. 261 + * 262 + * For the case when plane is not visible or plane update should not happen the 263 + * first call to iter_next will return false. Note that this helper use clipped 264 + * &drm_plane_state.src, so driver calling this helper should have called 265 + * drm_atomic_helper_check_plane_state() earlier. 266 + */ 267 + void 268 + drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, 269 + const struct drm_plane_state *old_state, 270 + const struct drm_plane_state *state) 271 + { 272 + memset(iter, 0, sizeof(*iter)); 273 + 274 + if (!state || !state->crtc || !state->fb || !state->visible) 275 + return; 276 + 277 + iter->clips = drm_helper_get_plane_damage_clips(state); 278 + iter->num_clips = drm_plane_get_damage_clips_count(state); 279 + 280 + /* Round down for x1/y1 and round up for x2/y2 to catch all pixels */ 281 + iter->plane_src.x1 = state->src.x1 >> 16; 282 + iter->plane_src.y1 = state->src.y1 >> 16; 283 + iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF); 284 + iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF); 285 + 286 + if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) { 287 + iter->clips = 0; 288 + iter->num_clips = 0; 289 + iter->full_update = true; 290 + } 291 + } 292 + EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init); 293 + 294 + /** 295 + * drm_atomic_helper_damage_iter_next - Advance the damage iterator. 296 + * @iter: The iterator to advance. 297 + * @rect: Return a rectangle in fb coordinate clipped to plane src. 298 + * 299 + * Since plane src is in 16.16 fixed point and damage clips are whole number, 300 + * this iterator round off clips that intersect with plane src. Round down for 301 + * x1/y1 and round up for x2/y2 for the intersected coordinate. Similar rounding 302 + * off for full plane src, in case it's returned as damage. This iterator will 303 + * skip damage clips outside of plane src. 304 + * 305 + * Return: True if the output is valid, false if reached the end. 306 + * 307 + * If the first call to iterator next returns false then it means no need to 308 + * update the plane. 309 + */ 310 + bool 311 + drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter, 312 + struct drm_rect *rect) 313 + { 314 + bool ret = false; 315 + 316 + if (iter->full_update) { 317 + *rect = iter->plane_src; 318 + iter->full_update = false; 319 + return true; 320 + } 321 + 322 + while (iter->curr_clip < iter->num_clips) { 323 + *rect = iter->clips[iter->curr_clip]; 324 + iter->curr_clip++; 325 + 326 + if (drm_rect_intersect(rect, &iter->plane_src)) { 327 + ret = true; 328 + break; 329 + } 330 + } 331 + 332 + return ret; 333 + } 334 + EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
+6
drivers/gpu/drm/drm_mode_config.c
··· 297 297 return -ENOMEM; 298 298 dev->mode_config.prop_crtc_id = prop; 299 299 300 + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "FB_DAMAGE_CLIPS", 301 + 0); 302 + if (!prop) 303 + return -ENOMEM; 304 + dev->mode_config.prop_fb_damage_clips = prop; 305 + 300 306 prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 301 307 "ACTIVE"); 302 308 if (!prop)
+2 -1
drivers/gpu/drm/selftests/Makefile
··· 1 1 test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \ 2 - test-drm_format.o test-drm_framebuffer.o 2 + test-drm_format.o test-drm_framebuffer.o \ 3 + test-drm_damage_helper.o 3 4 4 5 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
+21
drivers/gpu/drm/selftests/drm_modeset_selftests.h
··· 11 11 selftest(check_drm_format_block_height, igt_check_drm_format_block_height) 12 12 selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch) 13 13 selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create) 14 + selftest(damage_iter_no_damage, igt_damage_iter_no_damage) 15 + selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src) 16 + selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved) 17 + selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved) 18 + selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible) 19 + selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc) 20 + selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb) 21 + selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage) 22 + selftest(damage_iter_single_damage, igt_damage_iter_single_damage) 23 + selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src) 24 + selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src) 25 + selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src) 26 + selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src) 27 + selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src) 28 + selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved) 29 + selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved) 30 + selftest(damage_iter_damage, igt_damage_iter_damage) 31 + selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect) 32 + selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside) 33 + selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved) 34 + selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible)
+811
drivers/gpu/drm/selftests/test-drm_damage_helper.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Test case for drm_damage_helper functions 4 + */ 5 + 6 + #define pr_fmt(fmt) "drm_damage_helper: " fmt 7 + 8 + #include <drm/drm_damage_helper.h> 9 + 10 + #include "test-drm_modeset_common.h" 11 + 12 + static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2, 13 + int y2) 14 + { 15 + state->src.x1 = x1; 16 + state->src.y1 = y1; 17 + state->src.x2 = x2; 18 + state->src.y2 = y2; 19 + } 20 + 21 + static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2, 22 + int y2) 23 + { 24 + r->x1 = x1; 25 + r->y1 = y1; 26 + r->x2 = x2; 27 + r->y2 = y2; 28 + } 29 + 30 + static void set_damage_blob(struct drm_property_blob *damage_blob, 31 + struct drm_mode_rect *r, uint32_t size) 32 + { 33 + damage_blob->length = size; 34 + damage_blob->data = r; 35 + } 36 + 37 + static void set_plane_damage(struct drm_plane_state *state, 38 + struct drm_property_blob *damage_blob) 39 + { 40 + state->fb_damage_clips = damage_blob; 41 + } 42 + 43 + static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r, 44 + int x1, int y1, int x2, int y2) 45 + { 46 + /* 47 + * Round down x1/y1 and round up x2/y2. This is because damage is not in 48 + * 16.16 fixed point so to catch all pixels. 49 + */ 50 + int src_x1 = state->src.x1 >> 16; 51 + int src_y1 = state->src.y1 >> 16; 52 + int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF); 53 + int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF); 54 + 55 + if (x1 >= x2 || y1 >= y2) { 56 + pr_err("Cannot have damage clip with no dimention.\n"); 57 + return false; 58 + } 59 + 60 + if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) { 61 + pr_err("Damage cannot be outside rounded plane src.\n"); 62 + return false; 63 + } 64 + 65 + if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) { 66 + pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2); 67 + return false; 68 + } 69 + 70 + return true; 71 + } 72 + 73 + int igt_damage_iter_no_damage(void *ignored) 74 + { 75 + struct drm_atomic_helper_damage_iter iter; 76 + struct drm_plane_state old_state; 77 + struct drm_rect clip; 78 + uint32_t num_hits = 0; 79 + 80 + struct drm_framebuffer fb = { 81 + .width = 2048, 82 + .height = 2048 83 + }; 84 + 85 + struct drm_plane_state state = { 86 + .crtc = ZERO_SIZE_PTR, 87 + .fb = &fb, 88 + .visible = true, 89 + }; 90 + 91 + /* Plane src same as fb size. */ 92 + set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16); 93 + set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16); 94 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 95 + drm_atomic_for_each_plane_damage(&iter, &clip) 96 + num_hits++; 97 + 98 + FAIL(num_hits != 1, "Should return plane src as damage."); 99 + FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048)); 100 + 101 + return 0; 102 + } 103 + 104 + int igt_damage_iter_no_damage_fractional_src(void *ignored) 105 + { 106 + struct drm_atomic_helper_damage_iter iter; 107 + struct drm_plane_state old_state; 108 + struct drm_rect clip; 109 + uint32_t num_hits = 0; 110 + 111 + struct drm_framebuffer fb = { 112 + .width = 2048, 113 + .height = 2048 114 + }; 115 + 116 + struct drm_plane_state state = { 117 + .crtc = ZERO_SIZE_PTR, 118 + .fb = &fb, 119 + .visible = true, 120 + }; 121 + 122 + /* Plane src has fractional part. */ 123 + set_plane_src(&old_state, 0x3fffe, 0x3fffe, 124 + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); 125 + set_plane_src(&state, 0x3fffe, 0x3fffe, 126 + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); 127 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 128 + drm_atomic_for_each_plane_damage(&iter, &clip) 129 + num_hits++; 130 + 131 + FAIL(num_hits != 1, "Should return rounded off plane src as damage."); 132 + FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772)); 133 + 134 + return 0; 135 + } 136 + 137 + int igt_damage_iter_no_damage_src_moved(void *ignored) 138 + { 139 + struct drm_atomic_helper_damage_iter iter; 140 + struct drm_plane_state old_state; 141 + struct drm_rect clip; 142 + uint32_t num_hits = 0; 143 + 144 + struct drm_framebuffer fb = { 145 + .width = 2048, 146 + .height = 2048 147 + }; 148 + 149 + struct drm_plane_state state = { 150 + .crtc = ZERO_SIZE_PTR, 151 + .fb = &fb, 152 + .visible = true, 153 + }; 154 + 155 + /* Plane src moved since old plane state. */ 156 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 157 + set_plane_src(&state, 10 << 16, 10 << 16, 158 + (10 + 1024) << 16, (10 + 768) << 16); 159 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 160 + drm_atomic_for_each_plane_damage(&iter, &clip) 161 + num_hits++; 162 + 163 + FAIL(num_hits != 1, "Should return plane src as damage."); 164 + FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778)); 165 + 166 + return 0; 167 + } 168 + 169 + int igt_damage_iter_no_damage_fractional_src_moved(void *ignored) 170 + { 171 + struct drm_atomic_helper_damage_iter iter; 172 + struct drm_plane_state old_state; 173 + struct drm_rect clip; 174 + uint32_t num_hits = 0; 175 + 176 + struct drm_framebuffer fb = { 177 + .width = 2048, 178 + .height = 2048 179 + }; 180 + 181 + struct drm_plane_state state = { 182 + .crtc = ZERO_SIZE_PTR, 183 + .fb = &fb, 184 + .visible = true, 185 + }; 186 + 187 + /* Plane src has fractional part and it moved since old plane state. */ 188 + set_plane_src(&old_state, 0x3fffe, 0x3fffe, 189 + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); 190 + set_plane_src(&state, 0x40002, 0x40002, 191 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 192 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 193 + drm_atomic_for_each_plane_damage(&iter, &clip) 194 + num_hits++; 195 + 196 + FAIL(num_hits != 1, "Should return plane src as damage."); 197 + FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773)); 198 + 199 + return 0; 200 + } 201 + 202 + int igt_damage_iter_no_damage_not_visible(void *ignored) 203 + { 204 + struct drm_atomic_helper_damage_iter iter; 205 + struct drm_plane_state old_state; 206 + struct drm_rect clip; 207 + uint32_t num_hits = 0; 208 + 209 + struct drm_framebuffer fb = { 210 + .width = 2048, 211 + .height = 2048 212 + }; 213 + 214 + struct drm_plane_state state = { 215 + .crtc = ZERO_SIZE_PTR, 216 + .fb = &fb, 217 + .visible = false, 218 + }; 219 + 220 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 221 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 222 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 223 + drm_atomic_for_each_plane_damage(&iter, &clip) 224 + num_hits++; 225 + 226 + FAIL(num_hits != 0, "Should have no damage."); 227 + 228 + return 0; 229 + } 230 + 231 + int igt_damage_iter_no_damage_no_crtc(void *ignored) 232 + { 233 + struct drm_atomic_helper_damage_iter iter; 234 + struct drm_plane_state old_state; 235 + struct drm_rect clip; 236 + uint32_t num_hits = 0; 237 + 238 + struct drm_framebuffer fb = { 239 + .width = 2048, 240 + .height = 2048 241 + }; 242 + 243 + struct drm_plane_state state = { 244 + .crtc = 0, 245 + .fb = &fb, 246 + }; 247 + 248 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 249 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 250 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 251 + drm_atomic_for_each_plane_damage(&iter, &clip) 252 + num_hits++; 253 + 254 + FAIL(num_hits != 0, "Should have no damage."); 255 + 256 + return 0; 257 + } 258 + 259 + int igt_damage_iter_no_damage_no_fb(void *ignored) 260 + { 261 + struct drm_atomic_helper_damage_iter iter; 262 + struct drm_plane_state old_state; 263 + struct drm_rect clip; 264 + uint32_t num_hits = 0; 265 + 266 + struct drm_plane_state state = { 267 + .crtc = ZERO_SIZE_PTR, 268 + .fb = 0, 269 + }; 270 + 271 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 272 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 273 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 274 + drm_atomic_for_each_plane_damage(&iter, &clip) 275 + num_hits++; 276 + 277 + FAIL(num_hits != 0, "Should have no damage."); 278 + 279 + return 0; 280 + } 281 + 282 + int igt_damage_iter_simple_damage(void *ignored) 283 + { 284 + struct drm_atomic_helper_damage_iter iter; 285 + struct drm_plane_state old_state; 286 + struct drm_property_blob damage_blob; 287 + struct drm_mode_rect damage; 288 + struct drm_rect clip; 289 + uint32_t num_hits = 0; 290 + 291 + struct drm_framebuffer fb = { 292 + .width = 2048, 293 + .height = 2048 294 + }; 295 + 296 + struct drm_plane_state state = { 297 + .crtc = ZERO_SIZE_PTR, 298 + .fb = &fb, 299 + .visible = true, 300 + }; 301 + 302 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 303 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 304 + /* Damage set to plane src */ 305 + set_damage_clip(&damage, 0, 0, 1024, 768); 306 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 307 + set_plane_damage(&state, &damage_blob); 308 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 309 + drm_atomic_for_each_plane_damage(&iter, &clip) 310 + num_hits++; 311 + 312 + FAIL(num_hits != 1, "Should return damage when set."); 313 + FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768)); 314 + 315 + return 0; 316 + } 317 + 318 + int igt_damage_iter_single_damage(void *ignored) 319 + { 320 + struct drm_atomic_helper_damage_iter iter; 321 + struct drm_plane_state old_state; 322 + struct drm_property_blob damage_blob; 323 + struct drm_mode_rect damage; 324 + struct drm_rect clip; 325 + uint32_t num_hits = 0; 326 + 327 + struct drm_framebuffer fb = { 328 + .width = 2048, 329 + .height = 2048 330 + }; 331 + 332 + struct drm_plane_state state = { 333 + .crtc = ZERO_SIZE_PTR, 334 + .fb = &fb, 335 + .visible = true, 336 + }; 337 + 338 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 339 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 340 + set_damage_clip(&damage, 256, 192, 768, 576); 341 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 342 + set_plane_damage(&state, &damage_blob); 343 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 344 + drm_atomic_for_each_plane_damage(&iter, &clip) 345 + num_hits++; 346 + 347 + FAIL(num_hits != 1, "Should return damage when set."); 348 + FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576)); 349 + 350 + return 0; 351 + } 352 + 353 + int igt_damage_iter_single_damage_intersect_src(void *ignored) 354 + { 355 + struct drm_atomic_helper_damage_iter iter; 356 + struct drm_plane_state old_state; 357 + struct drm_property_blob damage_blob; 358 + struct drm_mode_rect damage; 359 + struct drm_rect clip; 360 + uint32_t num_hits = 0; 361 + 362 + struct drm_framebuffer fb = { 363 + .width = 2048, 364 + .height = 2048 365 + }; 366 + 367 + struct drm_plane_state state = { 368 + .crtc = ZERO_SIZE_PTR, 369 + .fb = &fb, 370 + .visible = true, 371 + }; 372 + 373 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 374 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 375 + /* Damage intersect with plane src. */ 376 + set_damage_clip(&damage, 256, 192, 1360, 768); 377 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 378 + set_plane_damage(&state, &damage_blob); 379 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 380 + drm_atomic_for_each_plane_damage(&iter, &clip) 381 + num_hits++; 382 + 383 + FAIL(num_hits != 1, "Should return damage clipped to src."); 384 + FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768)); 385 + 386 + return 0; 387 + } 388 + 389 + int igt_damage_iter_single_damage_outside_src(void *ignored) 390 + { 391 + struct drm_atomic_helper_damage_iter iter; 392 + struct drm_plane_state old_state; 393 + struct drm_property_blob damage_blob; 394 + struct drm_mode_rect damage; 395 + struct drm_rect clip; 396 + uint32_t num_hits = 0; 397 + 398 + struct drm_framebuffer fb = { 399 + .width = 2048, 400 + .height = 2048 401 + }; 402 + 403 + struct drm_plane_state state = { 404 + .crtc = ZERO_SIZE_PTR, 405 + .fb = &fb, 406 + .visible = true, 407 + }; 408 + 409 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 410 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 411 + /* Damage clip outside plane src */ 412 + set_damage_clip(&damage, 1360, 1360, 1380, 1380); 413 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 414 + set_plane_damage(&state, &damage_blob); 415 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 416 + drm_atomic_for_each_plane_damage(&iter, &clip) 417 + num_hits++; 418 + 419 + FAIL(num_hits != 0, "Should have no damage."); 420 + 421 + return 0; 422 + } 423 + 424 + int igt_damage_iter_single_damage_fractional_src(void *ignored) 425 + { 426 + struct drm_atomic_helper_damage_iter iter; 427 + struct drm_plane_state old_state; 428 + struct drm_property_blob damage_blob; 429 + struct drm_mode_rect damage; 430 + struct drm_rect clip; 431 + uint32_t num_hits = 0; 432 + 433 + struct drm_framebuffer fb = { 434 + .width = 2048, 435 + .height = 2048 436 + }; 437 + 438 + struct drm_plane_state state = { 439 + .crtc = ZERO_SIZE_PTR, 440 + .fb = &fb, 441 + .visible = true, 442 + }; 443 + 444 + /* Plane src has fractional part. */ 445 + set_plane_src(&old_state, 0x40002, 0x40002, 446 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 447 + set_plane_src(&state, 0x40002, 0x40002, 448 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 449 + set_damage_clip(&damage, 10, 10, 256, 330); 450 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 451 + set_plane_damage(&state, &damage_blob); 452 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 453 + drm_atomic_for_each_plane_damage(&iter, &clip) 454 + num_hits++; 455 + 456 + FAIL(num_hits != 1, "Should return damage when set."); 457 + FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330)); 458 + 459 + return 0; 460 + } 461 + 462 + int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored) 463 + { 464 + struct drm_atomic_helper_damage_iter iter; 465 + struct drm_plane_state old_state; 466 + struct drm_property_blob damage_blob; 467 + struct drm_mode_rect damage; 468 + struct drm_rect clip; 469 + uint32_t num_hits = 0; 470 + 471 + struct drm_framebuffer fb = { 472 + .width = 2048, 473 + .height = 2048 474 + }; 475 + 476 + struct drm_plane_state state = { 477 + .crtc = ZERO_SIZE_PTR, 478 + .fb = &fb, 479 + .visible = true, 480 + }; 481 + 482 + /* Plane src has fractional part. */ 483 + set_plane_src(&old_state, 0x40002, 0x40002, 484 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 485 + set_plane_src(&state, 0x40002, 0x40002, 486 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 487 + /* Damage intersect with plane src. */ 488 + set_damage_clip(&damage, 10, 1, 1360, 330); 489 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 490 + set_plane_damage(&state, &damage_blob); 491 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 492 + drm_atomic_for_each_plane_damage(&iter, &clip) 493 + num_hits++; 494 + 495 + FAIL(num_hits != 1, "Should return damage clipped to rounded off src."); 496 + FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330)); 497 + 498 + return 0; 499 + } 500 + 501 + int igt_damage_iter_single_damage_outside_fractional_src(void *ignored) 502 + { 503 + struct drm_atomic_helper_damage_iter iter; 504 + struct drm_plane_state old_state; 505 + struct drm_property_blob damage_blob; 506 + struct drm_mode_rect damage; 507 + struct drm_rect clip; 508 + uint32_t num_hits = 0; 509 + 510 + struct drm_framebuffer fb = { 511 + .width = 2048, 512 + .height = 2048 513 + }; 514 + 515 + struct drm_plane_state state = { 516 + .crtc = ZERO_SIZE_PTR, 517 + .fb = &fb, 518 + .visible = true, 519 + }; 520 + 521 + /* Plane src has fractional part. */ 522 + set_plane_src(&old_state, 0x40002, 0x40002, 523 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 524 + set_plane_src(&state, 0x40002, 0x40002, 525 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 526 + /* Damage clip outside plane src */ 527 + set_damage_clip(&damage, 1360, 1360, 1380, 1380); 528 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 529 + set_plane_damage(&state, &damage_blob); 530 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 531 + drm_atomic_for_each_plane_damage(&iter, &clip) 532 + num_hits++; 533 + 534 + FAIL(num_hits != 0, "Should have no damage."); 535 + 536 + return 0; 537 + } 538 + 539 + int igt_damage_iter_single_damage_src_moved(void *ignored) 540 + { 541 + struct drm_atomic_helper_damage_iter iter; 542 + struct drm_plane_state old_state; 543 + struct drm_property_blob damage_blob; 544 + struct drm_mode_rect damage; 545 + struct drm_rect clip; 546 + uint32_t num_hits = 0; 547 + 548 + struct drm_framebuffer fb = { 549 + .width = 2048, 550 + .height = 2048 551 + }; 552 + 553 + struct drm_plane_state state = { 554 + .crtc = ZERO_SIZE_PTR, 555 + .fb = &fb, 556 + .visible = true, 557 + }; 558 + 559 + /* Plane src moved since old plane state. */ 560 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 561 + set_plane_src(&state, 10 << 16, 10 << 16, 562 + (10 + 1024) << 16, (10 + 768) << 16); 563 + set_damage_clip(&damage, 20, 30, 256, 256); 564 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 565 + set_plane_damage(&state, &damage_blob); 566 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 567 + drm_atomic_for_each_plane_damage(&iter, &clip) 568 + num_hits++; 569 + 570 + FAIL(num_hits != 1, "Should return plane src as damage."); 571 + FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778)); 572 + 573 + return 0; 574 + } 575 + 576 + int igt_damage_iter_single_damage_fractional_src_moved(void *ignored) 577 + { 578 + struct drm_atomic_helper_damage_iter iter; 579 + struct drm_plane_state old_state; 580 + struct drm_property_blob damage_blob; 581 + struct drm_mode_rect damage; 582 + struct drm_rect clip; 583 + uint32_t num_hits = 0; 584 + 585 + struct drm_framebuffer fb = { 586 + .width = 2048, 587 + .height = 2048 588 + }; 589 + 590 + struct drm_plane_state state = { 591 + .crtc = ZERO_SIZE_PTR, 592 + .fb = &fb, 593 + .visible = true, 594 + }; 595 + 596 + /* Plane src with fractional part moved since old plane state. */ 597 + set_plane_src(&old_state, 0x3fffe, 0x3fffe, 598 + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); 599 + set_plane_src(&state, 0x40002, 0x40002, 600 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 601 + /* Damage intersect with plane src. */ 602 + set_damage_clip(&damage, 20, 30, 1360, 256); 603 + set_damage_blob(&damage_blob, &damage, sizeof(damage)); 604 + set_plane_damage(&state, &damage_blob); 605 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 606 + drm_atomic_for_each_plane_damage(&iter, &clip) 607 + num_hits++; 608 + 609 + FAIL(num_hits != 1, "Should return rounded off plane src as damage."); 610 + FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773)); 611 + 612 + return 0; 613 + } 614 + 615 + int igt_damage_iter_damage(void *ignored) 616 + { 617 + struct drm_atomic_helper_damage_iter iter; 618 + struct drm_plane_state old_state; 619 + struct drm_property_blob damage_blob; 620 + struct drm_mode_rect damage[2]; 621 + struct drm_rect clip; 622 + uint32_t num_hits = 0; 623 + 624 + struct drm_framebuffer fb = { 625 + .width = 2048, 626 + .height = 2048 627 + }; 628 + 629 + struct drm_plane_state state = { 630 + .crtc = ZERO_SIZE_PTR, 631 + .fb = &fb, 632 + .visible = true, 633 + }; 634 + 635 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 636 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 637 + /* 2 damage clips. */ 638 + set_damage_clip(&damage[0], 20, 30, 200, 180); 639 + set_damage_clip(&damage[1], 240, 200, 280, 250); 640 + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); 641 + set_plane_damage(&state, &damage_blob); 642 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 643 + drm_atomic_for_each_plane_damage(&iter, &clip) { 644 + if (num_hits == 0) 645 + FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180)); 646 + if (num_hits == 1) 647 + FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250)); 648 + num_hits++; 649 + } 650 + 651 + FAIL(num_hits != 2, "Should return damage when set."); 652 + 653 + return 0; 654 + } 655 + 656 + int igt_damage_iter_damage_one_intersect(void *ignored) 657 + { 658 + struct drm_atomic_helper_damage_iter iter; 659 + struct drm_plane_state old_state; 660 + struct drm_property_blob damage_blob; 661 + struct drm_mode_rect damage[2]; 662 + struct drm_rect clip; 663 + uint32_t num_hits = 0; 664 + 665 + struct drm_framebuffer fb = { 666 + .width = 2048, 667 + .height = 2048 668 + }; 669 + 670 + struct drm_plane_state state = { 671 + .crtc = ZERO_SIZE_PTR, 672 + .fb = &fb, 673 + .visible = true, 674 + }; 675 + 676 + set_plane_src(&old_state, 0x40002, 0x40002, 677 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 678 + set_plane_src(&state, 0x40002, 0x40002, 679 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 680 + /* 2 damage clips, one intersect plane src. */ 681 + set_damage_clip(&damage[0], 20, 30, 200, 180); 682 + set_damage_clip(&damage[1], 2, 2, 1360, 1360); 683 + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); 684 + set_plane_damage(&state, &damage_blob); 685 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 686 + drm_atomic_for_each_plane_damage(&iter, &clip) { 687 + if (num_hits == 0) 688 + FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180)); 689 + if (num_hits == 1) 690 + FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773)); 691 + num_hits++; 692 + } 693 + 694 + FAIL(num_hits != 2, "Should return damage when set."); 695 + 696 + return 0; 697 + } 698 + 699 + int igt_damage_iter_damage_one_outside(void *ignored) 700 + { 701 + struct drm_atomic_helper_damage_iter iter; 702 + struct drm_plane_state old_state; 703 + struct drm_property_blob damage_blob; 704 + struct drm_mode_rect damage[2]; 705 + struct drm_rect clip; 706 + uint32_t num_hits = 0; 707 + 708 + struct drm_framebuffer fb = { 709 + .width = 2048, 710 + .height = 2048 711 + }; 712 + 713 + struct drm_plane_state state = { 714 + .crtc = ZERO_SIZE_PTR, 715 + .fb = &fb, 716 + .visible = true, 717 + }; 718 + 719 + set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); 720 + set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); 721 + /* 2 damage clips, one outside plane src. */ 722 + set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); 723 + set_damage_clip(&damage[1], 240, 200, 280, 250); 724 + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); 725 + set_plane_damage(&state, &damage_blob); 726 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 727 + drm_atomic_for_each_plane_damage(&iter, &clip) 728 + num_hits++; 729 + 730 + FAIL(num_hits != 1, "Should return damage when set."); 731 + FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250)); 732 + 733 + return 0; 734 + } 735 + 736 + int igt_damage_iter_damage_src_moved(void *ignored) 737 + { 738 + struct drm_atomic_helper_damage_iter iter; 739 + struct drm_plane_state old_state; 740 + struct drm_property_blob damage_blob; 741 + struct drm_mode_rect damage[2]; 742 + struct drm_rect clip; 743 + uint32_t num_hits = 0; 744 + 745 + struct drm_framebuffer fb = { 746 + .width = 2048, 747 + .height = 2048 748 + }; 749 + 750 + struct drm_plane_state state = { 751 + .crtc = ZERO_SIZE_PTR, 752 + .fb = &fb, 753 + .visible = true, 754 + }; 755 + 756 + set_plane_src(&old_state, 0x40002, 0x40002, 757 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 758 + set_plane_src(&state, 0x3fffe, 0x3fffe, 759 + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); 760 + /* 2 damage clips, one outside plane src. */ 761 + set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); 762 + set_damage_clip(&damage[1], 240, 200, 280, 250); 763 + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); 764 + set_plane_damage(&state, &damage_blob); 765 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 766 + drm_atomic_for_each_plane_damage(&iter, &clip) 767 + num_hits++; 768 + 769 + FAIL(num_hits != 1, "Should return round off plane src as damage."); 770 + FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772)); 771 + 772 + return 0; 773 + } 774 + 775 + int igt_damage_iter_damage_not_visible(void *ignored) 776 + { 777 + struct drm_atomic_helper_damage_iter iter; 778 + struct drm_plane_state old_state; 779 + struct drm_property_blob damage_blob; 780 + struct drm_mode_rect damage[2]; 781 + struct drm_rect clip; 782 + uint32_t num_hits = 0; 783 + 784 + struct drm_framebuffer fb = { 785 + .width = 2048, 786 + .height = 2048 787 + }; 788 + 789 + struct drm_plane_state state = { 790 + .crtc = ZERO_SIZE_PTR, 791 + .fb = &fb, 792 + .visible = false, 793 + }; 794 + 795 + set_plane_src(&old_state, 0x40002, 0x40002, 796 + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); 797 + set_plane_src(&state, 0x3fffe, 0x3fffe, 798 + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); 799 + /* 2 damage clips, one outside plane src. */ 800 + set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); 801 + set_damage_clip(&damage[1], 240, 200, 280, 250); 802 + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); 803 + set_plane_damage(&state, &damage_blob); 804 + drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); 805 + drm_atomic_for_each_plane_damage(&iter, &clip) 806 + num_hits++; 807 + 808 + FAIL(num_hits != 0, "Should not return any damage."); 809 + 810 + return 0; 811 + }
+21
drivers/gpu/drm/selftests/test-drm_modeset_common.h
··· 18 18 int igt_check_drm_format_block_height(void *ignored); 19 19 int igt_check_drm_format_min_pitch(void *ignored); 20 20 int igt_check_drm_framebuffer_create(void *ignored); 21 + int igt_damage_iter_no_damage(void *ignored); 22 + int igt_damage_iter_no_damage_fractional_src(void *ignored); 23 + int igt_damage_iter_no_damage_src_moved(void *ignored); 24 + int igt_damage_iter_no_damage_fractional_src_moved(void *ignored); 25 + int igt_damage_iter_no_damage_not_visible(void *ignored); 26 + int igt_damage_iter_no_damage_no_crtc(void *ignored); 27 + int igt_damage_iter_no_damage_no_fb(void *ignored); 28 + int igt_damage_iter_simple_damage(void *ignored); 29 + int igt_damage_iter_single_damage(void *ignored); 30 + int igt_damage_iter_single_damage_intersect_src(void *ignored); 31 + int igt_damage_iter_single_damage_outside_src(void *ignored); 32 + int igt_damage_iter_single_damage_fractional_src(void *ignored); 33 + int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored); 34 + int igt_damage_iter_single_damage_outside_fractional_src(void *ignored); 35 + int igt_damage_iter_single_damage_src_moved(void *ignored); 36 + int igt_damage_iter_single_damage_fractional_src_moved(void *ignored); 37 + int igt_damage_iter_damage(void *ignored); 38 + int igt_damage_iter_damage_one_intersect(void *ignored); 39 + int igt_damage_iter_damage_one_outside(void *ignored); 40 + int igt_damage_iter_damage_src_moved(void *ignored); 41 + int igt_damage_iter_damage_not_visible(void *ignored); 21 42 22 43 #endif
-1
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
··· 665 665 mutex_init(&dev_priv->cmdbuf_mutex); 666 666 mutex_init(&dev_priv->release_mutex); 667 667 mutex_init(&dev_priv->binding_mutex); 668 - mutex_init(&dev_priv->requested_layout_mutex); 669 668 mutex_init(&dev_priv->global_kms_state_mutex); 670 669 ttm_lock_init(&dev_priv->reservation_sem); 671 670 spin_lock_init(&dev_priv->resource_lock);
-11
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
··· 466 466 uint32_t num_displays; 467 467 468 468 /* 469 - * Currently requested_layout_mutex is used to protect the gui 470 - * positionig state in display unit. With that use case currently this 471 - * mutex is only taken during layout ioctl and atomic check_modeset. 472 - * Other display unit state can be protected with this mutex but that 473 - * needs careful consideration. 474 - */ 475 - struct mutex requested_layout_mutex; 476 - 477 - /* 478 469 * Framebuffer info. 479 470 */ 480 471 ··· 475 484 struct vmw_overlay *overlay_priv; 476 485 struct drm_property *hotplug_mode_update_property; 477 486 struct drm_property *implicit_placement_property; 478 - unsigned num_implicit; 479 - struct vmw_framebuffer *implicit_fb; 480 487 struct mutex global_kms_state_mutex; 481 488 spinlock_t cursor_lock; 482 489 struct drm_atomic_state *suspend_state;
-2
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
··· 1738 1738 void *buf) 1739 1739 { 1740 1740 struct vmw_buffer_object *vmw_bo; 1741 - int ret; 1742 1741 1743 1742 struct { 1744 1743 uint32_t header; ··· 1747 1748 return vmw_translate_guest_ptr(dev_priv, sw_context, 1748 1749 &cmd->body.ptr, 1749 1750 &vmw_bo); 1750 - return ret; 1751 1751 } 1752 1752 1753 1753
-3
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
··· 906 906 container_of(action, struct vmw_event_fence_action, action); 907 907 struct drm_device *dev = eaction->dev; 908 908 struct drm_pending_event *event = eaction->event; 909 - struct drm_file *file_priv; 910 - 911 909 912 910 if (unlikely(event == NULL)) 913 911 return; 914 912 915 - file_priv = event->file_priv; 916 913 spin_lock_irq(&dev->event_lock); 917 914 918 915 if (likely(eaction->tv_sec != NULL)) {
+267 -302
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
··· 30 30 #include <drm/drm_atomic.h> 31 31 #include <drm/drm_atomic_helper.h> 32 32 #include <drm/drm_rect.h> 33 + #include <drm/drm_damage_helper.h> 33 34 34 35 /* Might need a hrtimer here? */ 35 36 #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) ··· 457 456 struct drm_crtc *crtc = state->crtc; 458 457 struct vmw_connector_state *vcs; 459 458 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 460 - struct vmw_private *dev_priv = vmw_priv(crtc->dev); 461 - struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); 462 459 463 460 vcs = vmw_connector_state_to_vcs(du->connector.state); 464 - 465 - /* Only one active implicit framebuffer at a time. */ 466 - mutex_lock(&dev_priv->global_kms_state_mutex); 467 - if (vcs->is_implicit && dev_priv->implicit_fb && 468 - !(dev_priv->num_implicit == 1 && du->active_implicit) 469 - && dev_priv->implicit_fb != vfb) { 470 - DRM_ERROR("Multiple implicit framebuffers " 471 - "not supported.\n"); 472 - ret = -EINVAL; 473 - } 474 - mutex_unlock(&dev_priv->global_kms_state_mutex); 475 461 } 476 462 477 463 ··· 834 846 kfree(vfbs); 835 847 } 836 848 837 - static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, 838 - struct drm_file *file_priv, 839 - unsigned flags, unsigned color, 840 - struct drm_clip_rect *clips, 841 - unsigned num_clips) 842 - { 843 - struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); 844 - struct vmw_framebuffer_surface *vfbs = 845 - vmw_framebuffer_to_vfbs(framebuffer); 846 - struct drm_clip_rect norect; 847 - int ret, inc = 1; 848 - 849 - /* Legacy Display Unit does not support 3D */ 850 - if (dev_priv->active_display_unit == vmw_du_legacy) 851 - return -EINVAL; 852 - 853 - drm_modeset_lock_all(dev_priv->dev); 854 - 855 - ret = ttm_read_lock(&dev_priv->reservation_sem, true); 856 - if (unlikely(ret != 0)) { 857 - drm_modeset_unlock_all(dev_priv->dev); 858 - return ret; 859 - } 860 - 861 - if (!num_clips) { 862 - num_clips = 1; 863 - clips = &norect; 864 - norect.x1 = norect.y1 = 0; 865 - norect.x2 = framebuffer->width; 866 - norect.y2 = framebuffer->height; 867 - } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { 868 - num_clips /= 2; 869 - inc = 2; /* skip source rects */ 870 - } 871 - 872 - if (dev_priv->active_display_unit == vmw_du_screen_object) 873 - ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, 874 - clips, NULL, NULL, 0, 0, 875 - num_clips, inc, NULL, NULL); 876 - else 877 - ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, 878 - clips, NULL, NULL, 0, 0, 879 - num_clips, inc, NULL, NULL); 880 - 881 - vmw_fifo_flush(dev_priv, false); 882 - ttm_read_unlock(&dev_priv->reservation_sem); 883 - 884 - drm_modeset_unlock_all(dev_priv->dev); 885 - 886 - return 0; 887 - } 888 - 889 849 /** 890 850 * vmw_kms_readback - Perform a readback from the screen system to 891 851 * a buffer-object backed framebuffer. ··· 877 941 878 942 static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { 879 943 .destroy = vmw_framebuffer_surface_destroy, 880 - .dirty = vmw_framebuffer_surface_dirty, 944 + .dirty = drm_atomic_helper_dirtyfb, 881 945 }; 882 946 883 947 static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, ··· 1020 1084 } 1021 1085 1022 1086 switch (dev_priv->active_display_unit) { 1023 - case vmw_du_screen_target: 1024 - ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, 1025 - clips, NULL, num_clips, increment, 1026 - true, true, NULL); 1027 - break; 1028 - case vmw_du_screen_object: 1029 - ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base, 1030 - clips, NULL, num_clips, 1031 - increment, true, NULL, NULL); 1032 - break; 1033 1087 case vmw_du_legacy: 1034 1088 ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, 1035 1089 clips, num_clips, increment); ··· 1038 1112 return ret; 1039 1113 } 1040 1114 1115 + static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer, 1116 + struct drm_file *file_priv, 1117 + unsigned int flags, unsigned int color, 1118 + struct drm_clip_rect *clips, 1119 + unsigned int num_clips) 1120 + { 1121 + struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); 1122 + 1123 + if (dev_priv->active_display_unit == vmw_du_legacy) 1124 + return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags, 1125 + color, clips, num_clips); 1126 + 1127 + return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color, 1128 + clips, num_clips); 1129 + } 1130 + 1041 1131 static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { 1042 1132 .destroy = vmw_framebuffer_bo_destroy, 1043 - .dirty = vmw_framebuffer_bo_dirty, 1133 + .dirty = vmw_framebuffer_bo_dirty_ext, 1044 1134 }; 1045 1135 1046 1136 /** ··· 1507 1565 } 1508 1566 1509 1567 /** 1568 + * vmw_crtc_state_and_lock - Return new or current crtc state with locked 1569 + * crtc mutex 1570 + * @state: The atomic state pointer containing the new atomic state 1571 + * @crtc: The crtc 1572 + * 1573 + * This function returns the new crtc state if it's part of the state update. 1574 + * Otherwise returns the current crtc state. It also makes sure that the 1575 + * crtc mutex is locked. 1576 + * 1577 + * Returns: A valid crtc state pointer or NULL. It may also return a 1578 + * pointer error, in particular -EDEADLK if locking needs to be rerun. 1579 + */ 1580 + static struct drm_crtc_state * 1581 + vmw_crtc_state_and_lock(struct drm_atomic_state *state, struct drm_crtc *crtc) 1582 + { 1583 + struct drm_crtc_state *crtc_state; 1584 + 1585 + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 1586 + if (crtc_state) { 1587 + lockdep_assert_held(&crtc->mutex.mutex.base); 1588 + } else { 1589 + int ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx); 1590 + 1591 + if (ret != 0 && ret != -EALREADY) 1592 + return ERR_PTR(ret); 1593 + 1594 + crtc_state = crtc->state; 1595 + } 1596 + 1597 + return crtc_state; 1598 + } 1599 + 1600 + /** 1601 + * vmw_kms_check_implicit - Verify that all implicit display units scan out 1602 + * from the same fb after the new state is committed. 1603 + * @dev: The drm_device. 1604 + * @state: The new state to be checked. 1605 + * 1606 + * Returns: 1607 + * Zero on success, 1608 + * -EINVAL on invalid state, 1609 + * -EDEADLK if modeset locking needs to be rerun. 1610 + */ 1611 + static int vmw_kms_check_implicit(struct drm_device *dev, 1612 + struct drm_atomic_state *state) 1613 + { 1614 + struct drm_framebuffer *implicit_fb = NULL; 1615 + struct drm_crtc *crtc; 1616 + struct drm_crtc_state *crtc_state; 1617 + struct drm_plane_state *plane_state; 1618 + 1619 + drm_for_each_crtc(crtc, dev) { 1620 + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 1621 + 1622 + if (!du->is_implicit) 1623 + continue; 1624 + 1625 + crtc_state = vmw_crtc_state_and_lock(state, crtc); 1626 + if (IS_ERR(crtc_state)) 1627 + return PTR_ERR(crtc_state); 1628 + 1629 + if (!crtc_state || !crtc_state->enable) 1630 + continue; 1631 + 1632 + /* 1633 + * Can't move primary planes across crtcs, so this is OK. 1634 + * It also means we don't need to take the plane mutex. 1635 + */ 1636 + plane_state = du->primary.state; 1637 + if (plane_state->crtc != crtc) 1638 + continue; 1639 + 1640 + if (!implicit_fb) 1641 + implicit_fb = plane_state->fb; 1642 + else if (implicit_fb != plane_state->fb) 1643 + return -EINVAL; 1644 + } 1645 + 1646 + return 0; 1647 + } 1648 + 1649 + /** 1510 1650 * vmw_kms_check_topology - Validates topology in drm_atomic_state 1511 1651 * @dev: DRM device 1512 1652 * @state: the driver state object ··· 1599 1575 static int vmw_kms_check_topology(struct drm_device *dev, 1600 1576 struct drm_atomic_state *state) 1601 1577 { 1602 - struct vmw_private *dev_priv = vmw_priv(dev); 1603 1578 struct drm_crtc_state *old_crtc_state, *new_crtc_state; 1604 1579 struct drm_rect *rects; 1605 1580 struct drm_crtc *crtc; ··· 1610 1587 if (!rects) 1611 1588 return -ENOMEM; 1612 1589 1613 - mutex_lock(&dev_priv->requested_layout_mutex); 1614 - 1615 1590 drm_for_each_crtc(crtc, dev) { 1616 1591 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 1617 - struct drm_crtc_state *crtc_state = crtc->state; 1592 + struct drm_crtc_state *crtc_state; 1618 1593 1619 1594 i = drm_crtc_index(crtc); 1620 1595 1621 - if (crtc_state && crtc_state->enable) { 1596 + crtc_state = vmw_crtc_state_and_lock(state, crtc); 1597 + if (IS_ERR(crtc_state)) { 1598 + ret = PTR_ERR(crtc_state); 1599 + goto clean; 1600 + } 1601 + 1602 + if (!crtc_state) 1603 + continue; 1604 + 1605 + if (crtc_state->enable) { 1622 1606 rects[i].x1 = du->gui_x; 1623 1607 rects[i].y1 = du->gui_y; 1624 1608 rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; 1625 1609 rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; 1610 + } else { 1611 + rects[i].x1 = 0; 1612 + rects[i].y1 = 0; 1613 + rects[i].x2 = 0; 1614 + rects[i].y2 = 0; 1626 1615 } 1627 1616 } 1628 1617 ··· 1645 1610 struct drm_connector *connector; 1646 1611 struct drm_connector_state *conn_state; 1647 1612 struct vmw_connector_state *vmw_conn_state; 1648 - 1649 - if (!new_crtc_state->enable) { 1650 - rects[i].x1 = 0; 1651 - rects[i].y1 = 0; 1652 - rects[i].x2 = 0; 1653 - rects[i].y2 = 0; 1654 - continue; 1655 - } 1656 1613 1657 1614 if (!du->pref_active) { 1658 1615 ret = -EINVAL; ··· 1666 1639 vmw_conn_state = vmw_connector_state_to_vcs(conn_state); 1667 1640 vmw_conn_state->gui_x = du->gui_x; 1668 1641 vmw_conn_state->gui_y = du->gui_y; 1669 - 1670 - rects[i].x1 = du->gui_x; 1671 - rects[i].y1 = du->gui_y; 1672 - rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay; 1673 - rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay; 1674 1642 } 1675 1643 1676 1644 ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, 1677 1645 rects); 1678 1646 1679 1647 clean: 1680 - mutex_unlock(&dev_priv->requested_layout_mutex); 1681 1648 kfree(rects); 1682 1649 return ret; 1683 1650 } ··· 1699 1678 int i, ret; 1700 1679 1701 1680 ret = drm_atomic_helper_check(dev, state); 1681 + if (ret) 1682 + return ret; 1683 + 1684 + ret = vmw_kms_check_implicit(dev, state); 1702 1685 if (ret) 1703 1686 return ret; 1704 1687 ··· 2028 2003 struct vmw_display_unit *du; 2029 2004 struct drm_connector *con; 2030 2005 struct drm_connector_list_iter conn_iter; 2006 + struct drm_modeset_acquire_ctx ctx; 2007 + struct drm_crtc *crtc; 2008 + int ret; 2031 2009 2032 - /* 2033 - * Currently only gui_x/y is protected with requested_layout_mutex. 2034 - */ 2035 - mutex_lock(&dev_priv->requested_layout_mutex); 2010 + /* Currently gui_x/y is protected with the crtc mutex */ 2011 + mutex_lock(&dev->mode_config.mutex); 2012 + drm_modeset_acquire_init(&ctx, 0); 2013 + retry: 2014 + drm_for_each_crtc(crtc, dev) { 2015 + ret = drm_modeset_lock(&crtc->mutex, &ctx); 2016 + if (ret < 0) { 2017 + if (ret == -EDEADLK) { 2018 + drm_modeset_backoff(&ctx); 2019 + goto retry; 2020 + } 2021 + goto out_fini; 2022 + } 2023 + } 2024 + 2036 2025 drm_connector_list_iter_begin(dev, &conn_iter); 2037 2026 drm_for_each_connector_iter(con, &conn_iter) { 2038 2027 du = vmw_connector_to_du(con); ··· 2065 2026 } 2066 2027 } 2067 2028 drm_connector_list_iter_end(&conn_iter); 2068 - mutex_unlock(&dev_priv->requested_layout_mutex); 2069 2029 2070 - mutex_lock(&dev->mode_config.mutex); 2071 2030 list_for_each_entry(con, &dev->mode_config.connector_list, head) { 2072 2031 du = vmw_connector_to_du(con); 2073 2032 if (num_rects > du->unit) { ··· 2085 2048 } 2086 2049 con->status = vmw_du_connector_detect(con, true); 2087 2050 } 2088 - mutex_unlock(&dev->mode_config.mutex); 2089 2051 2090 2052 drm_sysfs_hotplug_event(dev); 2091 - 2053 + out_fini: 2054 + drm_modeset_drop_locks(&ctx); 2055 + drm_modeset_acquire_fini(&ctx); 2056 + mutex_unlock(&dev->mode_config.mutex); 2057 + 2092 2058 return 0; 2093 2059 } 2094 2060 ··· 2313 2273 drm_mode_sort(&connector->modes); 2314 2274 2315 2275 return 1; 2316 - } 2317 - 2318 - int vmw_du_connector_set_property(struct drm_connector *connector, 2319 - struct drm_property *property, 2320 - uint64_t val) 2321 - { 2322 - struct vmw_display_unit *du = vmw_connector_to_du(connector); 2323 - struct vmw_private *dev_priv = vmw_priv(connector->dev); 2324 - 2325 - if (property == dev_priv->implicit_placement_property) 2326 - du->is_implicit = val; 2327 - 2328 - return 0; 2329 - } 2330 - 2331 - 2332 - 2333 - /** 2334 - * vmw_du_connector_atomic_set_property - Atomic version of get property 2335 - * 2336 - * @crtc - crtc the property is associated with 2337 - * 2338 - * Returns: 2339 - * Zero on success, negative errno on failure. 2340 - */ 2341 - int 2342 - vmw_du_connector_atomic_set_property(struct drm_connector *connector, 2343 - struct drm_connector_state *state, 2344 - struct drm_property *property, 2345 - uint64_t val) 2346 - { 2347 - struct vmw_private *dev_priv = vmw_priv(connector->dev); 2348 - struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state); 2349 - struct vmw_display_unit *du = vmw_connector_to_du(connector); 2350 - 2351 - 2352 - if (property == dev_priv->implicit_placement_property) { 2353 - vcs->is_implicit = val; 2354 - 2355 - /* 2356 - * We should really be doing a drm_atomic_commit() to 2357 - * commit the new state, but since this doesn't cause 2358 - * an immedate state change, this is probably ok 2359 - */ 2360 - du->is_implicit = vcs->is_implicit; 2361 - } else { 2362 - return -EINVAL; 2363 - } 2364 - 2365 - return 0; 2366 - } 2367 - 2368 - 2369 - /** 2370 - * vmw_du_connector_atomic_get_property - Atomic version of get property 2371 - * 2372 - * @connector - connector the property is associated with 2373 - * 2374 - * Returns: 2375 - * Zero on success, negative errno on failure. 2376 - */ 2377 - int 2378 - vmw_du_connector_atomic_get_property(struct drm_connector *connector, 2379 - const struct drm_connector_state *state, 2380 - struct drm_property *property, 2381 - uint64_t *val) 2382 - { 2383 - struct vmw_private *dev_priv = vmw_priv(connector->dev); 2384 - struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state); 2385 - 2386 - if (property == dev_priv->implicit_placement_property) 2387 - *val = vcs->is_implicit; 2388 - else { 2389 - DRM_ERROR("Invalid Property %s\n", property->name); 2390 - return -EINVAL; 2391 - } 2392 - 2393 - return 0; 2394 2276 } 2395 2277 2396 2278 /** ··· 2704 2742 } 2705 2743 2706 2744 /** 2707 - * vmw_kms_del_active - unregister a crtc binding to the implicit framebuffer 2708 - * 2709 - * @dev_priv: Pointer to a device private struct. 2710 - * @du: The display unit of the crtc. 2711 - */ 2712 - void vmw_kms_del_active(struct vmw_private *dev_priv, 2713 - struct vmw_display_unit *du) 2714 - { 2715 - mutex_lock(&dev_priv->global_kms_state_mutex); 2716 - if (du->active_implicit) { 2717 - if (--(dev_priv->num_implicit) == 0) 2718 - dev_priv->implicit_fb = NULL; 2719 - du->active_implicit = false; 2720 - } 2721 - mutex_unlock(&dev_priv->global_kms_state_mutex); 2722 - } 2723 - 2724 - /** 2725 - * vmw_kms_add_active - register a crtc binding to an implicit framebuffer 2726 - * 2727 - * @vmw_priv: Pointer to a device private struct. 2728 - * @du: The display unit of the crtc. 2729 - * @vfb: The implicit framebuffer 2730 - * 2731 - * Registers a binding to an implicit framebuffer. 2732 - */ 2733 - void vmw_kms_add_active(struct vmw_private *dev_priv, 2734 - struct vmw_display_unit *du, 2735 - struct vmw_framebuffer *vfb) 2736 - { 2737 - mutex_lock(&dev_priv->global_kms_state_mutex); 2738 - WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb); 2739 - 2740 - if (!du->active_implicit && du->is_implicit) { 2741 - dev_priv->implicit_fb = vfb; 2742 - du->active_implicit = true; 2743 - dev_priv->num_implicit++; 2744 - } 2745 - mutex_unlock(&dev_priv->global_kms_state_mutex); 2746 - } 2747 - 2748 - /** 2749 - * vmw_kms_screen_object_flippable - Check whether we can page-flip a crtc. 2750 - * 2751 - * @dev_priv: Pointer to device-private struct. 2752 - * @crtc: The crtc we want to flip. 2753 - * 2754 - * Returns true or false depending whether it's OK to flip this crtc 2755 - * based on the criterion that we must not have more than one implicit 2756 - * frame-buffer at any one time. 2757 - */ 2758 - bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, 2759 - struct drm_crtc *crtc) 2760 - { 2761 - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 2762 - bool ret; 2763 - 2764 - mutex_lock(&dev_priv->global_kms_state_mutex); 2765 - ret = !du->is_implicit || dev_priv->num_implicit == 1; 2766 - mutex_unlock(&dev_priv->global_kms_state_mutex); 2767 - 2768 - return ret; 2769 - } 2770 - 2771 - /** 2772 - * vmw_kms_update_implicit_fb - Update the implicit fb. 2773 - * 2774 - * @dev_priv: Pointer to device-private struct. 2775 - * @crtc: The crtc the new implicit frame-buffer is bound to. 2776 - */ 2777 - void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, 2778 - struct drm_crtc *crtc) 2779 - { 2780 - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 2781 - struct drm_plane *plane = crtc->primary; 2782 - struct vmw_framebuffer *vfb; 2783 - 2784 - mutex_lock(&dev_priv->global_kms_state_mutex); 2785 - 2786 - if (!du->is_implicit) 2787 - goto out_unlock; 2788 - 2789 - vfb = vmw_framebuffer_to_vfb(plane->state->fb); 2790 - WARN_ON_ONCE(dev_priv->num_implicit != 1 && 2791 - dev_priv->implicit_fb != vfb); 2792 - 2793 - dev_priv->implicit_fb = vfb; 2794 - out_unlock: 2795 - mutex_unlock(&dev_priv->global_kms_state_mutex); 2796 - } 2797 - 2798 - /** 2799 2745 * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement 2800 2746 * property. 2801 2747 * 2802 2748 * @dev_priv: Pointer to a device private struct. 2803 - * @immutable: Whether the property is immutable. 2804 2749 * 2805 2750 * Sets up the implicit placement property unless it's already set up. 2806 2751 */ 2807 2752 void 2808 - vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, 2809 - bool immutable) 2753 + vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv) 2810 2754 { 2811 2755 if (dev_priv->implicit_placement_property) 2812 2756 return; 2813 2757 2814 2758 dev_priv->implicit_placement_property = 2815 2759 drm_property_create_range(dev_priv->dev, 2816 - immutable ? 2817 - DRM_MODE_PROP_IMMUTABLE : 0, 2760 + DRM_MODE_PROP_IMMUTABLE, 2818 2761 "implicit_placement", 0, 1); 2819 - 2820 2762 } 2821 - 2822 - 2823 - /** 2824 - * vmw_kms_set_config - Wrapper around drm_atomic_helper_set_config 2825 - * 2826 - * @set: The configuration to set. 2827 - * 2828 - * The vmwgfx Xorg driver doesn't assign the mode::type member, which 2829 - * when drm_mode_set_crtcinfo is called as part of the configuration setting 2830 - * causes it to return incorrect crtc dimensions causing severe problems in 2831 - * the vmwgfx modesetting. So explicitly clear that member before calling 2832 - * into drm_atomic_helper_set_config. 2833 - */ 2834 - int vmw_kms_set_config(struct drm_mode_set *set, 2835 - struct drm_modeset_acquire_ctx *ctx) 2836 - { 2837 - if (set && set->mode) 2838 - set->mode->type = 0; 2839 - 2840 - return drm_atomic_helper_set_config(set, ctx); 2841 - } 2842 - 2843 2763 2844 2764 /** 2845 2765 * vmw_kms_suspend - Save modesetting state and turn modesetting off. ··· 2778 2934 void vmw_kms_lost_device(struct drm_device *dev) 2779 2935 { 2780 2936 drm_atomic_helper_shutdown(dev); 2937 + } 2938 + 2939 + /** 2940 + * vmw_du_helper_plane_update - Helper to do plane update on a display unit. 2941 + * @update: The closure structure. 2942 + * 2943 + * Call this helper after setting callbacks in &vmw_du_update_plane to do plane 2944 + * update on display unit. 2945 + * 2946 + * Return: 0 on success or a negative error code on failure. 2947 + */ 2948 + int vmw_du_helper_plane_update(struct vmw_du_update_plane *update) 2949 + { 2950 + struct drm_plane_state *state = update->plane->state; 2951 + struct drm_plane_state *old_state = update->old_state; 2952 + struct drm_atomic_helper_damage_iter iter; 2953 + struct drm_rect clip; 2954 + struct drm_rect bb; 2955 + DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 2956 + uint32_t reserved_size = 0; 2957 + uint32_t submit_size = 0; 2958 + uint32_t curr_size = 0; 2959 + uint32_t num_hits = 0; 2960 + void *cmd_start; 2961 + char *cmd_next; 2962 + int ret; 2963 + 2964 + /* 2965 + * Iterate in advance to check if really need plane update and find the 2966 + * number of clips that actually are in plane src for fifo allocation. 2967 + */ 2968 + drm_atomic_helper_damage_iter_init(&iter, old_state, state); 2969 + drm_atomic_for_each_plane_damage(&iter, &clip) 2970 + num_hits++; 2971 + 2972 + if (num_hits == 0) 2973 + return 0; 2974 + 2975 + if (update->vfb->bo) { 2976 + struct vmw_framebuffer_bo *vfbbo = 2977 + container_of(update->vfb, typeof(*vfbbo), base); 2978 + 2979 + ret = vmw_validation_add_bo(&val_ctx, vfbbo->buffer, false, 2980 + update->cpu_blit); 2981 + } else { 2982 + struct vmw_framebuffer_surface *vfbs = 2983 + container_of(update->vfb, typeof(*vfbs), base); 2984 + 2985 + ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res, 2986 + 0, NULL, NULL); 2987 + } 2988 + 2989 + if (ret) 2990 + return ret; 2991 + 2992 + ret = vmw_validation_prepare(&val_ctx, update->mutex, update->intr); 2993 + if (ret) 2994 + goto out_unref; 2995 + 2996 + reserved_size = update->calc_fifo_size(update, num_hits); 2997 + cmd_start = vmw_fifo_reserve(update->dev_priv, reserved_size); 2998 + if (!cmd_start) { 2999 + ret = -ENOMEM; 3000 + goto out_revert; 3001 + } 3002 + 3003 + cmd_next = cmd_start; 3004 + 3005 + if (update->post_prepare) { 3006 + curr_size = update->post_prepare(update, cmd_next); 3007 + cmd_next += curr_size; 3008 + submit_size += curr_size; 3009 + } 3010 + 3011 + if (update->pre_clip) { 3012 + curr_size = update->pre_clip(update, cmd_next, num_hits); 3013 + cmd_next += curr_size; 3014 + submit_size += curr_size; 3015 + } 3016 + 3017 + bb.x1 = INT_MAX; 3018 + bb.y1 = INT_MAX; 3019 + bb.x2 = INT_MIN; 3020 + bb.y2 = INT_MIN; 3021 + 3022 + drm_atomic_helper_damage_iter_init(&iter, old_state, state); 3023 + drm_atomic_for_each_plane_damage(&iter, &clip) { 3024 + uint32_t fb_x = clip.x1; 3025 + uint32_t fb_y = clip.y1; 3026 + 3027 + vmw_du_translate_to_crtc(state, &clip); 3028 + if (update->clip) { 3029 + curr_size = update->clip(update, cmd_next, &clip, fb_x, 3030 + fb_y); 3031 + cmd_next += curr_size; 3032 + submit_size += curr_size; 3033 + } 3034 + bb.x1 = min_t(int, bb.x1, clip.x1); 3035 + bb.y1 = min_t(int, bb.y1, clip.y1); 3036 + bb.x2 = max_t(int, bb.x2, clip.x2); 3037 + bb.y2 = max_t(int, bb.y2, clip.y2); 3038 + } 3039 + 3040 + curr_size = update->post_clip(update, cmd_next, &bb); 3041 + submit_size += curr_size; 3042 + 3043 + if (reserved_size < submit_size) 3044 + submit_size = 0; 3045 + 3046 + vmw_fifo_commit(update->dev_priv, submit_size); 3047 + 3048 + vmw_kms_helper_validation_finish(update->dev_priv, NULL, &val_ctx, 3049 + update->out_fence, NULL); 3050 + return ret; 3051 + 3052 + out_revert: 3053 + vmw_validation_revert(&val_ctx); 3054 + 3055 + out_unref: 3056 + vmw_validation_unref_lists(&val_ctx); 3057 + return ret; 2781 3058 }
+134 -16
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
··· 33 33 #include <drm/drm_encoder.h> 34 34 #include "vmwgfx_drv.h" 35 35 36 + /** 37 + * struct vmw_du_update_plane - Closure structure for vmw_du_helper_plane_update 38 + * @plane: Plane which is being updated. 39 + * @old_state: Old state of plane. 40 + * @dev_priv: Device private. 41 + * @du: Display unit on which to update the plane. 42 + * @vfb: Framebuffer which is blitted to display unit. 43 + * @out_fence: Out fence for resource finish. 44 + * @mutex: The mutex used to protect resource reservation. 45 + * @cpu_blit: True if need cpu blit. 46 + * @intr: Whether to perform waits interruptible if possible. 47 + * 48 + * This structure loosely represent the set of operations needed to perform a 49 + * plane update on a display unit. Implementer will define that functionality 50 + * according to the function callbacks for this structure. In brief it involves 51 + * surface/buffer object validation, populate FIFO commands and command 52 + * submission to the device. 53 + */ 54 + struct vmw_du_update_plane { 55 + /** 56 + * @calc_fifo_size: Calculate fifo size. 57 + * 58 + * Determine fifo size for the commands needed for update. The number of 59 + * damage clips on display unit @num_hits will be passed to allocate 60 + * sufficient fifo space. 61 + * 62 + * Return: Fifo size needed 63 + */ 64 + uint32_t (*calc_fifo_size)(struct vmw_du_update_plane *update, 65 + uint32_t num_hits); 36 66 67 + /** 68 + * @post_prepare: Populate fifo for resource preparation. 69 + * 70 + * Some surface resource or buffer object need some extra cmd submission 71 + * like update GB image for proxy surface and define a GMRFB for screen 72 + * object. That should should be done here as this callback will be 73 + * called after FIFO allocation with the address of command buufer. 74 + * 75 + * This callback is optional. 76 + * 77 + * Return: Size of commands populated to command buffer. 78 + */ 79 + uint32_t (*post_prepare)(struct vmw_du_update_plane *update, void *cmd); 80 + 81 + /** 82 + * @pre_clip: Populate fifo before clip. 83 + * 84 + * This is where pre clip related command should be populated like 85 + * surface copy/DMA, etc. 86 + * 87 + * This callback is optional. 88 + * 89 + * Return: Size of commands populated to command buffer. 90 + */ 91 + uint32_t (*pre_clip)(struct vmw_du_update_plane *update, void *cmd, 92 + uint32_t num_hits); 93 + 94 + /** 95 + * @clip: Populate fifo for clip. 96 + * 97 + * This is where to populate clips for surface copy/dma or blit commands 98 + * if needed. This will be called times have damage in display unit, 99 + * which is one if doing full update. @clip is the damage in destination 100 + * coordinates which is crtc/DU and @src_x, @src_y is damage clip src in 101 + * framebuffer coordinate. 102 + * 103 + * This callback is optional. 104 + * 105 + * Return: Size of commands populated to command buffer. 106 + */ 107 + uint32_t (*clip)(struct vmw_du_update_plane *update, void *cmd, 108 + struct drm_rect *clip, uint32_t src_x, uint32_t src_y); 109 + 110 + /** 111 + * @post_clip: Populate fifo after clip. 112 + * 113 + * This is where to populate display unit update commands or blit 114 + * commands. 115 + * 116 + * Return: Size of commands populated to command buffer. 117 + */ 118 + uint32_t (*post_clip)(struct vmw_du_update_plane *update, void *cmd, 119 + struct drm_rect *bb); 120 + 121 + struct drm_plane *plane; 122 + struct drm_plane_state *old_state; 123 + struct vmw_private *dev_priv; 124 + struct vmw_display_unit *du; 125 + struct vmw_framebuffer *vfb; 126 + struct vmw_fence_obj **out_fence; 127 + struct mutex *mutex; 128 + bool cpu_blit; 129 + bool intr; 130 + }; 131 + 132 + /** 133 + * struct vmw_du_update_plane_surface - closure structure for surface 134 + * @base: base closure structure. 135 + * @cmd_start: FIFO command start address (used by SOU only). 136 + */ 137 + struct vmw_du_update_plane_surface { 138 + struct vmw_du_update_plane base; 139 + /* This member is to handle special case SOU surface update */ 140 + void *cmd_start; 141 + }; 142 + 143 + /** 144 + * struct vmw_du_update_plane_buffer - Closure structure for buffer object 145 + * @base: Base closure structure. 146 + * @fb_left: x1 for fb damage bounding box. 147 + * @fb_top: y1 for fb damage bounding box. 148 + */ 149 + struct vmw_du_update_plane_buffer { 150 + struct vmw_du_update_plane base; 151 + int fb_left, fb_top; 152 + }; 37 153 38 154 /** 39 155 * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty ··· 307 191 struct vmw_connector_state { 308 192 struct drm_connector_state base; 309 193 310 - bool is_implicit; 311 - 312 194 /** 313 195 * @gui_x: 314 196 * ··· 368 254 int gui_x; 369 255 int gui_y; 370 256 bool is_implicit; 371 - bool active_implicit; 372 257 int set_gui_x; 373 258 int set_gui_y; 374 259 }; ··· 447 334 struct drm_crtc **p_crtc, 448 335 struct drm_display_mode **p_mode); 449 336 void vmw_guess_mode_timing(struct drm_display_mode *mode); 450 - void vmw_kms_del_active(struct vmw_private *dev_priv, 451 - struct vmw_display_unit *du); 452 - void vmw_kms_add_active(struct vmw_private *dev_priv, 453 - struct vmw_display_unit *du, 454 - struct vmw_framebuffer *vfb); 455 - bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, 456 - struct drm_crtc *crtc); 457 - void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, 458 - struct drm_crtc *crtc); 459 - void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, 460 - bool immutable); 337 + void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv); 338 + void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); 461 339 462 340 /* Universal Plane Helpers */ 463 341 void vmw_du_primary_plane_destroy(struct drm_plane *plane); ··· 560 456 bool interruptible, 561 457 struct drm_crtc *crtc); 562 458 563 - int vmw_kms_set_config(struct drm_mode_set *set, 564 - struct drm_modeset_acquire_ctx *ctx); 459 + int vmw_du_helper_plane_update(struct vmw_du_update_plane *update); 460 + 461 + /** 462 + * vmw_du_translate_to_crtc - Translate a rect from framebuffer to crtc 463 + * @state: Plane state. 464 + * @r: Rectangle to translate. 465 + */ 466 + static inline void vmw_du_translate_to_crtc(struct drm_plane_state *state, 467 + struct drm_rect *r) 468 + { 469 + int translate_crtc_x = -((state->src_x >> 16) - state->crtc_x); 470 + int translate_crtc_y = -((state->src_y >> 16) - state->crtc_y); 471 + 472 + drm_rect_translate(r, translate_crtc_x, translate_crtc_y); 473 + } 474 + 565 475 #endif
+2 -9
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
··· 233 233 .reset = vmw_du_crtc_reset, 234 234 .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 235 235 .atomic_destroy_state = vmw_du_crtc_destroy_state, 236 - .set_config = vmw_kms_set_config, 236 + .set_config = drm_atomic_helper_set_config, 237 237 }; 238 238 239 239 ··· 263 263 .dpms = vmw_du_connector_dpms, 264 264 .detect = vmw_du_connector_detect, 265 265 .fill_modes = vmw_du_connector_fill_modes, 266 - .set_property = vmw_du_connector_set_property, 267 266 .destroy = vmw_ldu_connector_destroy, 268 267 .reset = vmw_du_connector_reset, 269 268 .atomic_duplicate_state = vmw_du_connector_duplicate_state, 270 269 .atomic_destroy_state = vmw_du_connector_destroy_state, 271 - .atomic_set_property = vmw_du_connector_atomic_set_property, 272 - .atomic_get_property = vmw_du_connector_atomic_get_property, 273 270 }; 274 271 275 272 static const struct ··· 413 416 414 417 drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); 415 418 416 - 417 419 vmw_du_connector_reset(connector); 418 420 ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, 419 421 DRM_MODE_CONNECTOR_VIRTUAL); ··· 423 427 424 428 drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs); 425 429 connector->status = vmw_du_connector_detect(connector, true); 426 - vmw_connector_state_to_vcs(connector->state)->is_implicit = true; 427 - 428 430 429 431 ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, 430 432 DRM_MODE_ENCODER_VIRTUAL, NULL); ··· 440 446 DRM_ERROR("Failed to register connector\n"); 441 447 goto err_free_encoder; 442 448 } 443 - 444 449 445 450 vmw_du_crtc_reset(crtc); 446 451 ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary, ··· 506 513 if (ret != 0) 507 514 goto err_free; 508 515 509 - vmw_kms_create_implicit_placement_property(dev_priv, true); 516 + vmw_kms_create_implicit_placement_property(dev_priv); 510 517 511 518 if (dev_priv->capabilities & SVGA_CAP_MULTIMON) 512 519 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
+278 -81
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
··· 29 29 #include <drm/drm_plane_helper.h> 30 30 #include <drm/drm_atomic.h> 31 31 #include <drm/drm_atomic_helper.h> 32 + #include <drm/drm_damage_helper.h> 32 33 33 34 34 35 #define vmw_crtc_to_sou(x) \ ··· 75 74 struct vmw_kms_sou_dirty_cmd { 76 75 SVGA3dCmdHeader header; 77 76 SVGA3dCmdBlitSurfaceToScreen body; 77 + }; 78 + 79 + struct vmw_kms_sou_define_gmrfb { 80 + uint32_t header; 81 + SVGAFifoCmdDefineGMRFB body; 78 82 }; 79 83 80 84 /** ··· 247 241 sou->buffer = vps->bo; 248 242 sou->buffer_size = vps->bo_size; 249 243 250 - if (sou->base.is_implicit) { 251 - x = crtc->x; 252 - y = crtc->y; 253 - } else { 254 - conn_state = sou->base.connector.state; 255 - vmw_conn_state = vmw_connector_state_to_vcs(conn_state); 244 + conn_state = sou->base.connector.state; 245 + vmw_conn_state = vmw_connector_state_to_vcs(conn_state); 256 246 257 - x = vmw_conn_state->gui_x; 258 - y = vmw_conn_state->gui_y; 259 - } 247 + x = vmw_conn_state->gui_x; 248 + y = vmw_conn_state->gui_y; 260 249 261 250 ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); 262 251 if (ret) 263 252 DRM_ERROR("Failed to define Screen Object %dx%d\n", 264 253 crtc->x, crtc->y); 265 254 266 - vmw_kms_add_active(dev_priv, &sou->base, vfb); 267 255 } else { 268 256 sou->buffer = NULL; 269 257 sou->buffer_size = 0; 270 - 271 - vmw_kms_del_active(dev_priv, &sou->base); 272 258 } 273 259 } 274 260 ··· 315 317 } 316 318 } 317 319 318 - static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, 319 - struct drm_framebuffer *new_fb, 320 - struct drm_pending_vblank_event *event, 321 - uint32_t flags, 322 - struct drm_modeset_acquire_ctx *ctx) 323 - { 324 - struct vmw_private *dev_priv = vmw_priv(crtc->dev); 325 - int ret; 326 - 327 - if (!vmw_kms_crtc_flippable(dev_priv, crtc)) 328 - return -EINVAL; 329 - 330 - ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); 331 - if (ret) { 332 - DRM_ERROR("Page flip error %d.\n", ret); 333 - return ret; 334 - } 335 - 336 - if (vmw_crtc_to_du(crtc)->is_implicit) 337 - vmw_kms_update_implicit_fb(dev_priv, crtc); 338 - 339 - return ret; 340 - } 341 - 342 320 static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { 343 321 .gamma_set = vmw_du_crtc_gamma_set, 344 322 .destroy = vmw_sou_crtc_destroy, 345 323 .reset = vmw_du_crtc_reset, 346 324 .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 347 325 .atomic_destroy_state = vmw_du_crtc_destroy_state, 348 - .set_config = vmw_kms_set_config, 349 - .page_flip = vmw_sou_crtc_page_flip, 326 + .set_config = drm_atomic_helper_set_config, 327 + .page_flip = drm_atomic_helper_page_flip, 350 328 }; 351 329 352 330 /* ··· 351 377 .dpms = vmw_du_connector_dpms, 352 378 .detect = vmw_du_connector_detect, 353 379 .fill_modes = vmw_du_connector_fill_modes, 354 - .set_property = vmw_du_connector_set_property, 355 380 .destroy = vmw_sou_connector_destroy, 356 381 .reset = vmw_du_connector_reset, 357 382 .atomic_duplicate_state = vmw_du_connector_duplicate_state, 358 383 .atomic_destroy_state = vmw_du_connector_destroy_state, 359 - .atomic_set_property = vmw_du_connector_atomic_set_property, 360 - .atomic_get_property = vmw_du_connector_atomic_get_property, 361 384 }; 362 385 363 386 ··· 469 498 return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); 470 499 } 471 500 501 + static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update, 502 + uint32_t num_hits) 503 + { 504 + return sizeof(struct vmw_kms_sou_define_gmrfb) + 505 + sizeof(struct vmw_kms_sou_bo_blit) * num_hits; 506 + } 507 + 508 + static uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update, 509 + void *cmd) 510 + { 511 + struct vmw_framebuffer_bo *vfbbo = 512 + container_of(update->vfb, typeof(*vfbbo), base); 513 + struct vmw_kms_sou_define_gmrfb *gmr = cmd; 514 + int depth = update->vfb->base.format->depth; 515 + 516 + /* Emulate RGBA support, contrary to svga_reg.h this is not 517 + * supported by hosts. This is only a problem if we are reading 518 + * this value later and expecting what we uploaded back. 519 + */ 520 + if (depth == 32) 521 + depth = 24; 522 + 523 + gmr->header = SVGA_CMD_DEFINE_GMRFB; 524 + 525 + gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8; 526 + gmr->body.format.colorDepth = depth; 527 + gmr->body.format.reserved = 0; 528 + gmr->body.bytesPerLine = update->vfb->base.pitches[0]; 529 + vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &gmr->body.ptr); 530 + 531 + return sizeof(*gmr); 532 + } 533 + 534 + static uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane *update, 535 + void *cmd, struct drm_rect *clip, 536 + uint32_t fb_x, uint32_t fb_y) 537 + { 538 + struct vmw_kms_sou_bo_blit *blit = cmd; 539 + 540 + blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; 541 + blit->body.destScreenId = update->du->unit; 542 + blit->body.srcOrigin.x = fb_x; 543 + blit->body.srcOrigin.y = fb_y; 544 + blit->body.destRect.left = clip->x1; 545 + blit->body.destRect.top = clip->y1; 546 + blit->body.destRect.right = clip->x2; 547 + blit->body.destRect.bottom = clip->y2; 548 + 549 + return sizeof(*blit); 550 + } 551 + 552 + static uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane *update, 553 + void *cmd, struct drm_rect *bb) 554 + { 555 + return 0; 556 + } 557 + 558 + /** 559 + * vmw_sou_plane_update_bo - Update display unit for bo backed fb. 560 + * @dev_priv: Device private. 561 + * @plane: Plane state. 562 + * @old_state: Old plane state. 563 + * @vfb: Framebuffer which is blitted to display unit. 564 + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 565 + * The returned fence pointer may be NULL in which case the device 566 + * has already synchronized. 567 + * 568 + * Return: 0 on success or a negative error code on failure. 569 + */ 570 + static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv, 571 + struct drm_plane *plane, 572 + struct drm_plane_state *old_state, 573 + struct vmw_framebuffer *vfb, 574 + struct vmw_fence_obj **out_fence) 575 + { 576 + struct vmw_du_update_plane_buffer bo_update; 577 + 578 + memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); 579 + bo_update.base.plane = plane; 580 + bo_update.base.old_state = old_state; 581 + bo_update.base.dev_priv = dev_priv; 582 + bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); 583 + bo_update.base.vfb = vfb; 584 + bo_update.base.out_fence = out_fence; 585 + bo_update.base.mutex = NULL; 586 + bo_update.base.cpu_blit = false; 587 + bo_update.base.intr = true; 588 + 589 + bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size; 590 + bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb; 591 + bo_update.base.clip = vmw_sou_bo_populate_clip; 592 + bo_update.base.post_clip = vmw_stud_bo_post_clip; 593 + 594 + return vmw_du_helper_plane_update(&bo_update.base); 595 + } 596 + 597 + static uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update, 598 + uint32_t num_hits) 599 + { 600 + return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) * 601 + num_hits; 602 + } 603 + 604 + static uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update, 605 + void *cmd) 606 + { 607 + struct vmw_du_update_plane_surface *srf_update; 608 + 609 + srf_update = container_of(update, typeof(*srf_update), base); 610 + 611 + /* 612 + * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that 613 + * its bounding box is filled before iterating over all the clips. So 614 + * store the FIFO start address and revisit to fill the details. 615 + */ 616 + srf_update->cmd_start = cmd; 617 + 618 + return 0; 619 + } 620 + 621 + static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update, 622 + void *cmd, uint32_t num_hits) 623 + { 624 + struct vmw_kms_sou_dirty_cmd *blit = cmd; 625 + struct vmw_framebuffer_surface *vfbs; 626 + 627 + vfbs = container_of(update->vfb, typeof(*vfbs), base); 628 + 629 + blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; 630 + blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) * 631 + num_hits; 632 + 633 + blit->body.srcImage.sid = vfbs->surface->res.id; 634 + blit->body.destScreenId = update->du->unit; 635 + 636 + /* Update the source and destination bounding box later in post_clip */ 637 + blit->body.srcRect.left = 0; 638 + blit->body.srcRect.top = 0; 639 + blit->body.srcRect.right = 0; 640 + blit->body.srcRect.bottom = 0; 641 + 642 + blit->body.destRect.left = 0; 643 + blit->body.destRect.top = 0; 644 + blit->body.destRect.right = 0; 645 + blit->body.destRect.bottom = 0; 646 + 647 + return sizeof(*blit); 648 + } 649 + 650 + static uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update, 651 + void *cmd, struct drm_rect *clip, 652 + uint32_t src_x, uint32_t src_y) 653 + { 654 + SVGASignedRect *rect = cmd; 655 + 656 + /* 657 + * rects are relative to dest bounding box rect on screen object, so 658 + * translate to it later in post_clip 659 + */ 660 + rect->left = clip->x1; 661 + rect->top = clip->y1; 662 + rect->right = clip->x2; 663 + rect->bottom = clip->y2; 664 + 665 + return sizeof(*rect); 666 + } 667 + 668 + static uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update, 669 + void *cmd, struct drm_rect *bb) 670 + { 671 + struct vmw_du_update_plane_surface *srf_update; 672 + struct drm_plane_state *state = update->plane->state; 673 + struct drm_rect src_bb; 674 + struct vmw_kms_sou_dirty_cmd *blit; 675 + SVGASignedRect *rect; 676 + uint32_t num_hits; 677 + int translate_src_x; 678 + int translate_src_y; 679 + int i; 680 + 681 + srf_update = container_of(update, typeof(*srf_update), base); 682 + 683 + blit = srf_update->cmd_start; 684 + rect = (SVGASignedRect *)&blit[1]; 685 + 686 + num_hits = (blit->header.size - sizeof(blit->body))/ 687 + sizeof(SVGASignedRect); 688 + 689 + src_bb = *bb; 690 + 691 + /* To translate bb back to fb src coord */ 692 + translate_src_x = (state->src_x >> 16) - state->crtc_x; 693 + translate_src_y = (state->src_y >> 16) - state->crtc_y; 694 + 695 + drm_rect_translate(&src_bb, translate_src_x, translate_src_y); 696 + 697 + blit->body.srcRect.left = src_bb.x1; 698 + blit->body.srcRect.top = src_bb.y1; 699 + blit->body.srcRect.right = src_bb.x2; 700 + blit->body.srcRect.bottom = src_bb.y2; 701 + 702 + blit->body.destRect.left = bb->x1; 703 + blit->body.destRect.top = bb->y1; 704 + blit->body.destRect.right = bb->x2; 705 + blit->body.destRect.bottom = bb->y2; 706 + 707 + /* rects are relative to dest bb rect */ 708 + for (i = 0; i < num_hits; i++) { 709 + rect->left -= bb->x1; 710 + rect->top -= bb->y1; 711 + rect->right -= bb->x1; 712 + rect->bottom -= bb->y1; 713 + rect++; 714 + } 715 + 716 + return 0; 717 + } 718 + 719 + /** 720 + * vmw_sou_plane_update_surface - Update display unit for surface backed fb. 721 + * @dev_priv: Device private. 722 + * @plane: Plane state. 723 + * @old_state: Old plane state. 724 + * @vfb: Framebuffer which is blitted to display unit 725 + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 726 + * The returned fence pointer may be NULL in which case the device 727 + * has already synchronized. 728 + * 729 + * Return: 0 on success or a negative error code on failure. 730 + */ 731 + static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv, 732 + struct drm_plane *plane, 733 + struct drm_plane_state *old_state, 734 + struct vmw_framebuffer *vfb, 735 + struct vmw_fence_obj **out_fence) 736 + { 737 + struct vmw_du_update_plane_surface srf_update; 738 + 739 + memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface)); 740 + srf_update.base.plane = plane; 741 + srf_update.base.old_state = old_state; 742 + srf_update.base.dev_priv = dev_priv; 743 + srf_update.base.du = vmw_crtc_to_du(plane->state->crtc); 744 + srf_update.base.vfb = vfb; 745 + srf_update.base.out_fence = out_fence; 746 + srf_update.base.mutex = &dev_priv->cmdbuf_mutex; 747 + srf_update.base.cpu_blit = false; 748 + srf_update.base.intr = true; 749 + 750 + srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size; 751 + srf_update.base.post_prepare = vmw_sou_surface_post_prepare; 752 + srf_update.base.pre_clip = vmw_sou_surface_pre_clip; 753 + srf_update.base.clip = vmw_sou_surface_clip_rect; 754 + srf_update.base.post_clip = vmw_sou_surface_post_clip; 755 + 756 + return vmw_du_helper_plane_update(&srf_update.base); 757 + } 472 758 473 759 static void 474 760 vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, ··· 736 508 struct vmw_fence_obj *fence = NULL; 737 509 int ret; 738 510 511 + /* In case of device error, maintain consistent atomic state */ 739 512 if (crtc && plane->state->fb) { 740 513 struct vmw_private *dev_priv = vmw_priv(crtc->dev); 741 514 struct vmw_framebuffer *vfb = 742 515 vmw_framebuffer_to_vfb(plane->state->fb); 743 - struct drm_vmw_rect vclips; 744 - 745 - vclips.x = crtc->x; 746 - vclips.y = crtc->y; 747 - vclips.w = crtc->mode.hdisplay; 748 - vclips.h = crtc->mode.vdisplay; 749 516 750 517 if (vfb->bo) 751 - ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL, 752 - &vclips, 1, 1, true, 753 - &fence, crtc); 518 + ret = vmw_sou_plane_update_bo(dev_priv, plane, 519 + old_state, vfb, &fence); 754 520 else 755 - ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, 756 - &vclips, NULL, 0, 0, 757 - 1, 1, &fence, crtc); 758 - 759 - /* 760 - * We cannot really fail this function, so if we do, then output 761 - * an error and maintain consistent atomic state. 762 - */ 521 + ret = vmw_sou_plane_update_surface(dev_priv, plane, 522 + old_state, vfb, 523 + &fence); 763 524 if (ret != 0) 764 525 DRM_ERROR("Failed to update screen.\n"); 765 526 } else { 766 - /* 767 - * When disabling a plane, CRTC and FB should always be NULL 768 - * together, otherwise it's an error. 769 - * Here primary plane is being disable so should really blank 770 - * the screen object display unit, if not already done. 771 - */ 527 + /* Do nothing when fb and crtc is NULL (blank crtc) */ 772 528 return; 773 529 } 774 530 531 + /* For error case vblank event is send from vmw_du_crtc_atomic_flush */ 775 532 event = crtc->state->event; 776 - /* 777 - * In case of failure and other cases, vblank event will be sent in 778 - * vmw_du_crtc_atomic_flush. 779 - */ 780 533 if (event && fence) { 781 534 struct drm_file *file_priv = event->base.file_priv; 782 535 ··· 848 639 primary = &sou->base.primary; 849 640 cursor = &sou->base.cursor; 850 641 851 - sou->base.active_implicit = false; 852 642 sou->base.pref_active = (unit == 0); 853 643 sou->base.pref_width = dev_priv->initial_width; 854 644 sou->base.pref_height = dev_priv->initial_height; ··· 873 665 } 874 666 875 667 drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); 668 + drm_plane_enable_fb_damage_clips(primary); 876 669 877 670 /* Initialize cursor plane */ 878 671 vmw_du_plane_reset(cursor); ··· 901 692 902 693 drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); 903 694 connector->status = vmw_du_connector_detect(connector, true); 904 - vmw_connector_state_to_vcs(connector->state)->is_implicit = false; 905 - 906 695 907 696 ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, 908 697 DRM_MODE_ENCODER_VIRTUAL, NULL); ··· 939 732 dev->mode_config.suggested_x_property, 0); 940 733 drm_object_attach_property(&connector->base, 941 734 dev->mode_config.suggested_y_property, 0); 942 - if (dev_priv->implicit_placement_property) 943 - drm_object_attach_property 944 - (&connector->base, 945 - dev_priv->implicit_placement_property, 946 - sou->base.is_implicit); 947 - 948 735 return 0; 949 736 950 737 err_free_unregister: ··· 964 763 } 965 764 966 765 ret = -ENOMEM; 967 - dev_priv->num_implicit = 0; 968 - dev_priv->implicit_fb = NULL; 969 766 970 767 ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); 971 768 if (unlikely(ret != 0)) 972 769 return ret; 973 - 974 - vmw_kms_create_implicit_placement_property(dev_priv, false); 975 770 976 771 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) 977 772 vmw_sou_init(dev_priv, i);
+425 -136
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
··· 30 30 #include <drm/drm_plane_helper.h> 31 31 #include <drm/drm_atomic.h> 32 32 #include <drm/drm_atomic_helper.h> 33 - 33 + #include <drm/drm_damage_helper.h> 34 34 35 35 #define vmw_crtc_to_stdu(x) \ 36 36 container_of(x, struct vmw_screen_target_display_unit, base.crtc) ··· 92 92 SVGA3dCmdSurfaceCopy body; 93 93 }; 94 94 95 + struct vmw_stdu_update_gb_image { 96 + SVGA3dCmdHeader header; 97 + SVGA3dCmdUpdateGBImage body; 98 + }; 95 99 96 100 /** 97 101 * struct vmw_screen_target_display_unit ··· 400 396 if (!crtc->state->enable) 401 397 return; 402 398 403 - if (stdu->base.is_implicit) { 404 - x = crtc->x; 405 - y = crtc->y; 406 - } else { 407 - x = vmw_conn_state->gui_x; 408 - y = vmw_conn_state->gui_y; 409 - } 399 + x = vmw_conn_state->gui_x; 400 + y = vmw_conn_state->gui_y; 410 401 411 402 vmw_svga_enable(dev_priv); 412 403 ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); ··· 416 417 { 417 418 } 418 419 419 - 420 420 static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, 421 421 struct drm_crtc_state *old_state) 422 422 { 423 - struct drm_plane_state *plane_state = crtc->primary->state; 424 - struct vmw_private *dev_priv; 425 - struct vmw_screen_target_display_unit *stdu; 426 - struct vmw_framebuffer *vfb; 427 - struct drm_framebuffer *fb; 428 - 429 - 430 - stdu = vmw_crtc_to_stdu(crtc); 431 - dev_priv = vmw_priv(crtc->dev); 432 - fb = plane_state->fb; 433 - 434 - vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; 435 - 436 - if (vfb) 437 - vmw_kms_add_active(dev_priv, &stdu->base, vfb); 438 - else 439 - vmw_kms_del_active(dev_priv, &stdu->base); 440 423 } 441 424 442 425 static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, ··· 451 470 stdu->content_fb_type = SAME_AS_DISPLAY; 452 471 } 453 472 } 454 - 455 - /** 456 - * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target 457 - * 458 - * @crtc: CRTC to attach FB to 459 - * @fb: FB to attach 460 - * @event: Event to be posted. This event should've been alloced 461 - * using k[mz]alloc, and should've been completely initialized. 462 - * @page_flip_flags: Input flags. 463 - * 464 - * If the STDU uses the same display and content buffers, i.e. a true flip, 465 - * this function will replace the existing display buffer with the new content 466 - * buffer. 467 - * 468 - * If the STDU uses different display and content buffers, i.e. a blit, then 469 - * only the content buffer will be updated. 470 - * 471 - * RETURNS: 472 - * 0 on success, error code on failure 473 - */ 474 - static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, 475 - struct drm_framebuffer *new_fb, 476 - struct drm_pending_vblank_event *event, 477 - uint32_t flags, 478 - struct drm_modeset_acquire_ctx *ctx) 479 - 480 - { 481 - struct vmw_private *dev_priv = vmw_priv(crtc->dev); 482 - struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); 483 - int ret; 484 - 485 - if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) 486 - return -EINVAL; 487 - 488 - ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); 489 - if (ret) { 490 - DRM_ERROR("Page flip error %d.\n", ret); 491 - return ret; 492 - } 493 - 494 - return 0; 495 - } 496 - 497 473 498 474 /** 499 475 * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect ··· 924 986 .reset = vmw_du_crtc_reset, 925 987 .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 926 988 .atomic_destroy_state = vmw_du_crtc_destroy_state, 927 - .set_config = vmw_kms_set_config, 928 - .page_flip = vmw_stdu_crtc_page_flip, 989 + .set_config = drm_atomic_helper_set_config, 990 + .page_flip = drm_atomic_helper_page_flip, 929 991 }; 930 992 931 993 ··· 980 1042 .dpms = vmw_du_connector_dpms, 981 1043 .detect = vmw_du_connector_detect, 982 1044 .fill_modes = vmw_du_connector_fill_modes, 983 - .set_property = vmw_du_connector_set_property, 984 1045 .destroy = vmw_stdu_connector_destroy, 985 1046 .reset = vmw_du_connector_reset, 986 1047 .atomic_duplicate_state = vmw_du_connector_duplicate_state, 987 1048 .atomic_destroy_state = vmw_du_connector_destroy_state, 988 - .atomic_set_property = vmw_du_connector_atomic_set_property, 989 - .atomic_get_property = vmw_du_connector_atomic_get_property, 990 1049 }; 991 1050 992 1051 ··· 1191 1256 return ret; 1192 1257 } 1193 1258 1259 + static uint32_t vmw_stdu_bo_fifo_size(struct vmw_du_update_plane *update, 1260 + uint32_t num_hits) 1261 + { 1262 + return sizeof(struct vmw_stdu_dma) + sizeof(SVGA3dCopyBox) * num_hits + 1263 + sizeof(SVGA3dCmdSurfaceDMASuffix) + 1264 + sizeof(struct vmw_stdu_update); 1265 + } 1194 1266 1267 + static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update, 1268 + uint32_t num_hits) 1269 + { 1270 + return sizeof(struct vmw_stdu_update_gb_image) + 1271 + sizeof(struct vmw_stdu_update); 1272 + } 1273 + 1274 + static uint32_t vmw_stdu_bo_populate_dma(struct vmw_du_update_plane *update, 1275 + void *cmd, uint32_t num_hits) 1276 + { 1277 + struct vmw_screen_target_display_unit *stdu; 1278 + struct vmw_framebuffer_bo *vfbbo; 1279 + struct vmw_stdu_dma *cmd_dma = cmd; 1280 + 1281 + stdu = container_of(update->du, typeof(*stdu), base); 1282 + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); 1283 + 1284 + cmd_dma->header.id = SVGA_3D_CMD_SURFACE_DMA; 1285 + cmd_dma->header.size = sizeof(cmd_dma->body) + 1286 + sizeof(struct SVGA3dCopyBox) * num_hits + 1287 + sizeof(SVGA3dCmdSurfaceDMASuffix); 1288 + vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &cmd_dma->body.guest.ptr); 1289 + cmd_dma->body.guest.pitch = update->vfb->base.pitches[0]; 1290 + cmd_dma->body.host.sid = stdu->display_srf->res.id; 1291 + cmd_dma->body.host.face = 0; 1292 + cmd_dma->body.host.mipmap = 0; 1293 + cmd_dma->body.transfer = SVGA3D_WRITE_HOST_VRAM; 1294 + 1295 + return sizeof(*cmd_dma); 1296 + } 1297 + 1298 + static uint32_t vmw_stdu_bo_populate_clip(struct vmw_du_update_plane *update, 1299 + void *cmd, struct drm_rect *clip, 1300 + uint32_t fb_x, uint32_t fb_y) 1301 + { 1302 + struct SVGA3dCopyBox *box = cmd; 1303 + 1304 + box->srcx = fb_x; 1305 + box->srcy = fb_y; 1306 + box->srcz = 0; 1307 + box->x = clip->x1; 1308 + box->y = clip->y1; 1309 + box->z = 0; 1310 + box->w = drm_rect_width(clip); 1311 + box->h = drm_rect_height(clip); 1312 + box->d = 1; 1313 + 1314 + return sizeof(*box); 1315 + } 1316 + 1317 + static uint32_t vmw_stdu_bo_populate_update(struct vmw_du_update_plane *update, 1318 + void *cmd, struct drm_rect *bb) 1319 + { 1320 + struct vmw_screen_target_display_unit *stdu; 1321 + struct vmw_framebuffer_bo *vfbbo; 1322 + SVGA3dCmdSurfaceDMASuffix *suffix = cmd; 1323 + 1324 + stdu = container_of(update->du, typeof(*stdu), base); 1325 + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); 1326 + 1327 + suffix->suffixSize = sizeof(*suffix); 1328 + suffix->maximumOffset = vfbbo->buffer->base.num_pages * PAGE_SIZE; 1329 + 1330 + vmw_stdu_populate_update(&suffix[1], stdu->base.unit, bb->x1, bb->x2, 1331 + bb->y1, bb->y2); 1332 + 1333 + return sizeof(*suffix) + sizeof(struct vmw_stdu_update); 1334 + } 1335 + 1336 + static uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane *update, 1337 + void *cmd, uint32_t num_hits) 1338 + { 1339 + struct vmw_du_update_plane_buffer *bo_update = 1340 + container_of(update, typeof(*bo_update), base); 1341 + 1342 + bo_update->fb_left = INT_MAX; 1343 + bo_update->fb_top = INT_MAX; 1344 + 1345 + return 0; 1346 + } 1347 + 1348 + static uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane *update, 1349 + void *cmd, struct drm_rect *clip, 1350 + uint32_t fb_x, uint32_t fb_y) 1351 + { 1352 + struct vmw_du_update_plane_buffer *bo_update = 1353 + container_of(update, typeof(*bo_update), base); 1354 + 1355 + bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x); 1356 + bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y); 1357 + 1358 + return 0; 1359 + } 1360 + 1361 + static uint32_t 1362 + vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd, 1363 + struct drm_rect *bb) 1364 + { 1365 + struct vmw_du_update_plane_buffer *bo_update; 1366 + struct vmw_screen_target_display_unit *stdu; 1367 + struct vmw_framebuffer_bo *vfbbo; 1368 + struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0); 1369 + struct vmw_stdu_update_gb_image *cmd_img = cmd; 1370 + struct vmw_stdu_update *cmd_update; 1371 + struct ttm_buffer_object *src_bo, *dst_bo; 1372 + u32 src_offset, dst_offset; 1373 + s32 src_pitch, dst_pitch; 1374 + s32 width, height; 1375 + 1376 + bo_update = container_of(update, typeof(*bo_update), base); 1377 + stdu = container_of(update->du, typeof(*stdu), base); 1378 + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); 1379 + 1380 + width = bb->x2 - bb->x1; 1381 + height = bb->y2 - bb->y1; 1382 + 1383 + diff.cpp = stdu->cpp; 1384 + 1385 + dst_bo = &stdu->display_srf->res.backup->base; 1386 + dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; 1387 + dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp; 1388 + 1389 + src_bo = &vfbbo->buffer->base; 1390 + src_pitch = update->vfb->base.pitches[0]; 1391 + src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left * 1392 + stdu->cpp; 1393 + 1394 + (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo, 1395 + src_offset, src_pitch, width * stdu->cpp, height, 1396 + &diff); 1397 + 1398 + if (drm_rect_visible(&diff.rect)) { 1399 + SVGA3dBox *box = &cmd_img->body.box; 1400 + 1401 + cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 1402 + cmd_img->header.size = sizeof(cmd_img->body); 1403 + cmd_img->body.image.sid = stdu->display_srf->res.id; 1404 + cmd_img->body.image.face = 0; 1405 + cmd_img->body.image.mipmap = 0; 1406 + 1407 + box->x = diff.rect.x1; 1408 + box->y = diff.rect.y1; 1409 + box->z = 0; 1410 + box->w = drm_rect_width(&diff.rect); 1411 + box->h = drm_rect_height(&diff.rect); 1412 + box->d = 1; 1413 + 1414 + cmd_update = (struct vmw_stdu_update *)&cmd_img[1]; 1415 + vmw_stdu_populate_update(cmd_update, stdu->base.unit, 1416 + diff.rect.x1, diff.rect.x2, 1417 + diff.rect.y1, diff.rect.y2); 1418 + 1419 + return sizeof(*cmd_img) + sizeof(*cmd_update); 1420 + } 1421 + 1422 + return 0; 1423 + } 1424 + 1425 + /** 1426 + * vmw_stdu_plane_update_bo - Update display unit for bo backed fb. 1427 + * @dev_priv: device private. 1428 + * @plane: plane state. 1429 + * @old_state: old plane state. 1430 + * @vfb: framebuffer which is blitted to display unit. 1431 + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 1432 + * The returned fence pointer may be NULL in which case the device 1433 + * has already synchronized. 1434 + * 1435 + * Return: 0 on success or a negative error code on failure. 1436 + */ 1437 + static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv, 1438 + struct drm_plane *plane, 1439 + struct drm_plane_state *old_state, 1440 + struct vmw_framebuffer *vfb, 1441 + struct vmw_fence_obj **out_fence) 1442 + { 1443 + struct vmw_du_update_plane_buffer bo_update; 1444 + 1445 + memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); 1446 + bo_update.base.plane = plane; 1447 + bo_update.base.old_state = old_state; 1448 + bo_update.base.dev_priv = dev_priv; 1449 + bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); 1450 + bo_update.base.vfb = vfb; 1451 + bo_update.base.out_fence = out_fence; 1452 + bo_update.base.mutex = NULL; 1453 + bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); 1454 + bo_update.base.intr = false; 1455 + 1456 + /* 1457 + * VM without 3D support don't have surface DMA command and framebuffer 1458 + * should be moved out of VRAM. 1459 + */ 1460 + if (bo_update.base.cpu_blit) { 1461 + bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu; 1462 + bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu; 1463 + bo_update.base.clip = vmw_stdu_bo_clip_cpu; 1464 + bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu; 1465 + } else { 1466 + bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size; 1467 + bo_update.base.pre_clip = vmw_stdu_bo_populate_dma; 1468 + bo_update.base.clip = vmw_stdu_bo_populate_clip; 1469 + bo_update.base.post_clip = vmw_stdu_bo_populate_update; 1470 + } 1471 + 1472 + return vmw_du_helper_plane_update(&bo_update.base); 1473 + } 1474 + 1475 + static uint32_t 1476 + vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update, 1477 + uint32_t num_hits) 1478 + { 1479 + struct vmw_framebuffer_surface *vfbs; 1480 + uint32_t size = 0; 1481 + 1482 + vfbs = container_of(update->vfb, typeof(*vfbs), base); 1483 + 1484 + if (vfbs->is_bo_proxy) 1485 + size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; 1486 + 1487 + size += sizeof(struct vmw_stdu_update); 1488 + 1489 + return size; 1490 + } 1491 + 1492 + static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update, 1493 + uint32_t num_hits) 1494 + { 1495 + struct vmw_framebuffer_surface *vfbs; 1496 + uint32_t size = 0; 1497 + 1498 + vfbs = container_of(update->vfb, typeof(*vfbs), base); 1499 + 1500 + if (vfbs->is_bo_proxy) 1501 + size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; 1502 + 1503 + size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) * 1504 + num_hits + sizeof(struct vmw_stdu_update); 1505 + 1506 + return size; 1507 + } 1508 + 1509 + static uint32_t 1510 + vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd) 1511 + { 1512 + struct vmw_framebuffer_surface *vfbs; 1513 + struct drm_plane_state *state = update->plane->state; 1514 + struct drm_plane_state *old_state = update->old_state; 1515 + struct vmw_stdu_update_gb_image *cmd_update = cmd; 1516 + struct drm_atomic_helper_damage_iter iter; 1517 + struct drm_rect clip; 1518 + uint32_t copy_size = 0; 1519 + 1520 + vfbs = container_of(update->vfb, typeof(*vfbs), base); 1521 + 1522 + /* 1523 + * proxy surface is special where a buffer object type fb is wrapped 1524 + * in a surface and need an update gb image command to sync with device. 1525 + */ 1526 + drm_atomic_helper_damage_iter_init(&iter, old_state, state); 1527 + drm_atomic_for_each_plane_damage(&iter, &clip) { 1528 + SVGA3dBox *box = &cmd_update->body.box; 1529 + 1530 + cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 1531 + cmd_update->header.size = sizeof(cmd_update->body); 1532 + cmd_update->body.image.sid = vfbs->surface->res.id; 1533 + cmd_update->body.image.face = 0; 1534 + cmd_update->body.image.mipmap = 0; 1535 + 1536 + box->x = clip.x1; 1537 + box->y = clip.y1; 1538 + box->z = 0; 1539 + box->w = drm_rect_width(&clip); 1540 + box->h = drm_rect_height(&clip); 1541 + box->d = 1; 1542 + 1543 + copy_size += sizeof(*cmd_update); 1544 + cmd_update++; 1545 + } 1546 + 1547 + return copy_size; 1548 + } 1549 + 1550 + static uint32_t 1551 + vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd, 1552 + uint32_t num_hits) 1553 + { 1554 + struct vmw_screen_target_display_unit *stdu; 1555 + struct vmw_framebuffer_surface *vfbs; 1556 + struct vmw_stdu_surface_copy *cmd_copy = cmd; 1557 + 1558 + stdu = container_of(update->du, typeof(*stdu), base); 1559 + vfbs = container_of(update->vfb, typeof(*vfbs), base); 1560 + 1561 + cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY; 1562 + cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) * 1563 + num_hits; 1564 + cmd_copy->body.src.sid = vfbs->surface->res.id; 1565 + cmd_copy->body.dest.sid = stdu->display_srf->res.id; 1566 + 1567 + return sizeof(*cmd_copy); 1568 + } 1569 + 1570 + static uint32_t 1571 + vmw_stdu_surface_populate_clip(struct vmw_du_update_plane *update, void *cmd, 1572 + struct drm_rect *clip, uint32_t fb_x, 1573 + uint32_t fb_y) 1574 + { 1575 + struct SVGA3dCopyBox *box = cmd; 1576 + 1577 + box->srcx = fb_x; 1578 + box->srcy = fb_y; 1579 + box->srcz = 0; 1580 + box->x = clip->x1; 1581 + box->y = clip->y1; 1582 + box->z = 0; 1583 + box->w = drm_rect_width(clip); 1584 + box->h = drm_rect_height(clip); 1585 + box->d = 1; 1586 + 1587 + return sizeof(*box); 1588 + } 1589 + 1590 + static uint32_t 1591 + vmw_stdu_surface_populate_update(struct vmw_du_update_plane *update, void *cmd, 1592 + struct drm_rect *bb) 1593 + { 1594 + vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1, 1595 + bb->y2); 1596 + 1597 + return sizeof(struct vmw_stdu_update); 1598 + } 1599 + 1600 + /** 1601 + * vmw_stdu_plane_update_surface - Update display unit for surface backed fb 1602 + * @dev_priv: Device private 1603 + * @plane: Plane state 1604 + * @old_state: Old plane state 1605 + * @vfb: Framebuffer which is blitted to display unit 1606 + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 1607 + * The returned fence pointer may be NULL in which case the device 1608 + * has already synchronized. 1609 + * 1610 + * Return: 0 on success or a negative error code on failure. 1611 + */ 1612 + static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, 1613 + struct drm_plane *plane, 1614 + struct drm_plane_state *old_state, 1615 + struct vmw_framebuffer *vfb, 1616 + struct vmw_fence_obj **out_fence) 1617 + { 1618 + struct vmw_du_update_plane srf_update; 1619 + struct vmw_screen_target_display_unit *stdu; 1620 + struct vmw_framebuffer_surface *vfbs; 1621 + 1622 + stdu = vmw_crtc_to_stdu(plane->state->crtc); 1623 + vfbs = container_of(vfb, typeof(*vfbs), base); 1624 + 1625 + memset(&srf_update, 0, sizeof(struct vmw_du_update_plane)); 1626 + srf_update.plane = plane; 1627 + srf_update.old_state = old_state; 1628 + srf_update.dev_priv = dev_priv; 1629 + srf_update.du = vmw_crtc_to_du(plane->state->crtc); 1630 + srf_update.vfb = vfb; 1631 + srf_update.out_fence = out_fence; 1632 + srf_update.mutex = &dev_priv->cmdbuf_mutex; 1633 + srf_update.cpu_blit = false; 1634 + srf_update.intr = true; 1635 + 1636 + if (vfbs->is_bo_proxy) 1637 + srf_update.post_prepare = vmw_stdu_surface_update_proxy; 1638 + 1639 + if (vfbs->surface->res.id != stdu->display_srf->res.id) { 1640 + srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size; 1641 + srf_update.pre_clip = vmw_stdu_surface_populate_copy; 1642 + srf_update.clip = vmw_stdu_surface_populate_clip; 1643 + } else { 1644 + srf_update.calc_fifo_size = 1645 + vmw_stdu_surface_fifo_size_same_display; 1646 + } 1647 + 1648 + srf_update.post_clip = vmw_stdu_surface_populate_update; 1649 + 1650 + return vmw_du_helper_plane_update(&srf_update); 1651 + } 1195 1652 1196 1653 /** 1197 1654 * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane 1198 - * 1199 1655 * @plane: display plane 1200 1656 * @old_state: Only used to get crtc info 1201 1657 * ··· 1603 1277 struct drm_crtc *crtc = plane->state->crtc; 1604 1278 struct vmw_screen_target_display_unit *stdu; 1605 1279 struct drm_pending_vblank_event *event; 1280 + struct vmw_fence_obj *fence = NULL; 1606 1281 struct vmw_private *dev_priv; 1607 1282 int ret; 1608 1283 1609 - /* 1610 - * We cannot really fail this function, so if we do, then output an 1611 - * error and maintain consistent atomic state. 1612 - */ 1284 + /* If case of device error, maintain consistent atomic state */ 1613 1285 if (crtc && plane->state->fb) { 1614 1286 struct vmw_framebuffer *vfb = 1615 1287 vmw_framebuffer_to_vfb(plane->state->fb); 1616 - struct drm_vmw_rect vclips; 1617 1288 stdu = vmw_crtc_to_stdu(crtc); 1618 1289 dev_priv = vmw_priv(crtc->dev); 1619 1290 ··· 1618 1295 stdu->content_fb_type = vps->content_fb_type; 1619 1296 stdu->cpp = vps->cpp; 1620 1297 1621 - vclips.x = crtc->x; 1622 - vclips.y = crtc->y; 1623 - vclips.w = crtc->mode.hdisplay; 1624 - vclips.h = crtc->mode.vdisplay; 1625 - 1626 1298 ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); 1627 1299 if (ret) 1628 1300 DRM_ERROR("Failed to bind surface to STDU.\n"); 1629 1301 1630 1302 if (vfb->bo) 1631 - ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, 1632 - &vclips, 1, 1, true, false, 1633 - crtc); 1303 + ret = vmw_stdu_plane_update_bo(dev_priv, plane, 1304 + old_state, vfb, &fence); 1634 1305 else 1635 - ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, 1636 - &vclips, NULL, 0, 0, 1637 - 1, 1, NULL, crtc); 1306 + ret = vmw_stdu_plane_update_surface(dev_priv, plane, 1307 + old_state, vfb, 1308 + &fence); 1638 1309 if (ret) 1639 1310 DRM_ERROR("Failed to update STDU.\n"); 1640 1311 } else { ··· 1636 1319 stdu = vmw_crtc_to_stdu(crtc); 1637 1320 dev_priv = vmw_priv(crtc->dev); 1638 1321 1639 - /* 1640 - * When disabling a plane, CRTC and FB should always be NULL 1641 - * together, otherwise it's an error. 1642 - * Here primary plane is being disable so blank the screen 1643 - * target display unit, if not already done. 1644 - */ 1322 + /* Blank STDU when fb and crtc are NULL */ 1645 1323 if (!stdu->defined) 1646 1324 return; 1647 1325 ··· 1651 1339 return; 1652 1340 } 1653 1341 1342 + /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */ 1654 1343 event = crtc->state->event; 1655 - /* 1656 - * In case of failure and other cases, vblank event will be sent in 1657 - * vmw_du_crtc_atomic_flush. 1658 - */ 1659 - if (event && (ret == 0)) { 1660 - struct vmw_fence_obj *fence = NULL; 1344 + if (event && fence) { 1661 1345 struct drm_file *file_priv = event->base.file_priv; 1662 1346 1663 - vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 1664 - 1665 - /* 1666 - * If fence is NULL, then already sync. 1667 - */ 1668 - if (fence) { 1669 - ret = vmw_event_fence_action_queue( 1670 - file_priv, fence, &event->base, 1671 - &event->event.vbl.tv_sec, 1672 - &event->event.vbl.tv_usec, 1673 - true); 1674 - if (ret) 1675 - DRM_ERROR("Failed to queue event on fence.\n"); 1676 - else 1677 - crtc->state->event = NULL; 1678 - 1679 - vmw_fence_obj_unreference(&fence); 1680 - } 1681 - } else { 1682 - (void) vmw_fifo_flush(dev_priv, false); 1347 + ret = vmw_event_fence_action_queue(file_priv, 1348 + fence, 1349 + &event->base, 1350 + &event->event.vbl.tv_sec, 1351 + &event->event.vbl.tv_usec, 1352 + true); 1353 + if (ret) 1354 + DRM_ERROR("Failed to queue event on fence.\n"); 1355 + else 1356 + crtc->state->event = NULL; 1683 1357 } 1358 + 1359 + if (fence) 1360 + vmw_fence_obj_unreference(&fence); 1684 1361 } 1685 1362 1686 1363 ··· 1757 1456 stdu->base.pref_active = (unit == 0); 1758 1457 stdu->base.pref_width = dev_priv->initial_width; 1759 1458 stdu->base.pref_height = dev_priv->initial_height; 1760 - 1761 - /* 1762 - * Remove this after enabling atomic because property values can 1763 - * only exist in a state object 1764 - */ 1765 1459 stdu->base.is_implicit = false; 1766 1460 1767 1461 /* Initialize primary plane */ ··· 1773 1477 } 1774 1478 1775 1479 drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs); 1480 + drm_plane_enable_fb_damage_clips(primary); 1776 1481 1777 1482 /* Initialize cursor plane */ 1778 1483 vmw_du_plane_reset(cursor); ··· 1802 1505 1803 1506 drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs); 1804 1507 connector->status = vmw_du_connector_detect(connector, false); 1805 - vmw_connector_state_to_vcs(connector->state)->is_implicit = false; 1806 1508 1807 1509 ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, 1808 1510 DRM_MODE_ENCODER_VIRTUAL, NULL); ··· 1839 1543 dev->mode_config.suggested_x_property, 0); 1840 1544 drm_object_attach_property(&connector->base, 1841 1545 dev->mode_config.suggested_y_property, 0); 1842 - if (dev_priv->implicit_placement_property) 1843 - drm_object_attach_property 1844 - (&connector->base, 1845 - dev_priv->implicit_placement_property, 1846 - stdu->base.is_implicit); 1847 1546 return 0; 1848 1547 1849 1548 err_free_unregister: ··· 1906 1615 return ret; 1907 1616 1908 1617 dev_priv->active_display_unit = vmw_du_screen_target; 1909 - 1910 - vmw_kms_create_implicit_placement_property(dev_priv, false); 1911 1618 1912 1619 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { 1913 1620 ret = vmw_stdu_init(dev_priv, i);
+99
include/drm/drm_damage_helper.h
··· 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 + * 30 + **************************************************************************/ 31 + 32 + #ifndef DRM_DAMAGE_HELPER_H_ 33 + #define DRM_DAMAGE_HELPER_H_ 34 + 35 + #include <drm/drm_atomic_helper.h> 36 + 37 + /** 38 + * drm_atomic_for_each_plane_damage - Iterator macro for plane damage. 39 + * @iter: The iterator to advance. 40 + * @rect: Return a rectangle in fb coordinate clipped to plane src. 41 + * 42 + * Note that if the first call to iterator macro return false then no need to do 43 + * plane update. Iterator will return full plane src when damage is not passed 44 + * by user-space. 45 + */ 46 + #define drm_atomic_for_each_plane_damage(iter, rect) \ 47 + while (drm_atomic_helper_damage_iter_next(iter, rect)) 48 + 49 + /** 50 + * struct drm_atomic_helper_damage_iter - Closure structure for damage iterator. 51 + * 52 + * This structure tracks state needed to walk the list of plane damage clips. 53 + */ 54 + struct drm_atomic_helper_damage_iter { 55 + /* private: Plane src in whole number. */ 56 + struct drm_rect plane_src; 57 + /* private: Rectangles in plane damage blob. */ 58 + const struct drm_rect *clips; 59 + /* private: Number of rectangles in plane damage blob. */ 60 + uint32_t num_clips; 61 + /* private: Current clip iterator is advancing on. */ 62 + uint32_t curr_clip; 63 + /* private: Whether need full plane update. */ 64 + bool full_update; 65 + }; 66 + 67 + void drm_plane_enable_fb_damage_clips(struct drm_plane *plane); 68 + void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state, 69 + struct drm_plane_state *plane_state); 70 + int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb, 71 + struct drm_file *file_priv, unsigned int flags, 72 + unsigned int color, struct drm_clip_rect *clips, 73 + unsigned int num_clips); 74 + void 75 + drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, 76 + const struct drm_plane_state *old_state, 77 + const struct drm_plane_state *new_state); 78 + bool 79 + drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter, 80 + struct drm_rect *rect); 81 + 82 + /** 83 + * drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect. 84 + * @state: Plane state. 85 + * 86 + * Returns plane damage rectangles in internal &drm_rect. Currently &drm_rect 87 + * can be obtained by simply typecasting &drm_mode_rect. This is because both 88 + * are signed 32 and during drm_atomic_check_only() it is verified that damage 89 + * clips are inside fb. 90 + * 91 + * Return: Clips in plane fb_damage_clips blob property. 92 + */ 93 + static inline struct drm_rect * 94 + drm_helper_get_plane_damage_clips(const struct drm_plane_state *state) 95 + { 96 + return (struct drm_rect *)drm_plane_get_damage_clips(state); 97 + } 98 + 99 + #endif
+9
include/drm/drm_mode_config.h
··· 634 634 */ 635 635 struct drm_property *prop_crtc_id; 636 636 /** 637 + * @prop_fb_damage_clips: Optional plane property to mark damaged 638 + * regions on the plane in framebuffer coordinates of the framebuffer 639 + * attached to the plane. 640 + * 641 + * The layout of blob data is simply an array of &drm_mode_rect. Unlike 642 + * plane src coordinates, damage clips are not in 16.16 fixed point. 643 + */ 644 + struct drm_property *prop_fb_damage_clips; 645 + /** 637 646 * @prop_active: Default atomic CRTC property to control the active 638 647 * state, which is the simplified implementation for DPMS in atomic 639 648 * drivers.
+42
include/drm/drm_plane.h
··· 173 173 */ 174 174 enum drm_color_range color_range; 175 175 176 + /** 177 + * @fb_damage_clips: 178 + * 179 + * Blob representing damage (area in plane framebuffer that changed 180 + * since last plane update) as an array of &drm_mode_rect in framebuffer 181 + * coodinates of the attached framebuffer. Note that unlike plane src, 182 + * damage clips are not in 16.16 fixed point. 183 + */ 184 + struct drm_property_blob *fb_damage_clips; 185 + 176 186 /** @src: clipped source coordinates of the plane (in 16.16) */ 177 187 /** @dst: clipped destination coordinates of the plane */ 178 188 struct drm_rect src, dst; ··· 810 800 811 801 bool drm_any_plane_has_format(struct drm_device *dev, 812 802 u32 format, u64 modifier); 803 + /** 804 + * drm_plane_get_damage_clips_count - Returns damage clips count. 805 + * @state: Plane state. 806 + * 807 + * Simple helper to get the number of &drm_mode_rect clips set by user-space 808 + * during plane update. 809 + * 810 + * Return: Number of clips in plane fb_damage_clips blob property. 811 + */ 812 + static inline unsigned int 813 + drm_plane_get_damage_clips_count(const struct drm_plane_state *state) 814 + { 815 + return (state && state->fb_damage_clips) ? 816 + state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0; 817 + } 818 + 819 + /** 820 + * drm_plane_get_damage_clips - Returns damage clips. 821 + * @state: Plane state. 822 + * 823 + * Note that this function returns uapi type &drm_mode_rect. Drivers might 824 + * instead be interested in internal &drm_rect which can be obtained by calling 825 + * drm_helper_get_plane_damage_clips(). 826 + * 827 + * Return: Damage clips in plane fb_damage_clips blob property. 828 + */ 829 + static inline struct drm_mode_rect * 830 + drm_plane_get_damage_clips(const struct drm_plane_state *state) 831 + { 832 + return (struct drm_mode_rect *)((state && state->fb_damage_clips) ? 833 + state->fb_damage_clips->data : NULL); 834 + } 813 835 814 836 #endif
+19
include/uapi/drm/drm_mode.h
··· 888 888 __u32 lessee_id; 889 889 }; 890 890 891 + /** 892 + * struct drm_mode_rect - Two dimensional rectangle. 893 + * @x1: Horizontal starting coordinate (inclusive). 894 + * @y1: Vertical starting coordinate (inclusive). 895 + * @x2: Horizontal ending coordinate (exclusive). 896 + * @y2: Vertical ending coordinate (exclusive). 897 + * 898 + * With drm subsystem using struct drm_rect to manage rectangular area this 899 + * export it to user-space. 900 + * 901 + * Currently used by drm_mode_atomic blob property FB_DAMAGE_CLIPS. 902 + */ 903 + struct drm_mode_rect { 904 + __s32 x1; 905 + __s32 y1; 906 + __s32 x2; 907 + __s32 y2; 908 + }; 909 + 891 910 #if defined(__cplusplus) 892 911 } 893 912 #endif