diff options
| author | Dave Airlie <airlied@redhat.com> | 2018-12-05 22:43:22 -0500 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2018-12-05 22:43:56 -0500 |
| commit | 1f9a5dce3548d54d810b23e4e0b1d8c6d73a52d4 (patch) | |
| tree | 1d257e265325b04909278b52fe18cea616bf674f | |
| parent | fb878d106b7738ae7cdb513f98876b22bd6a485f (diff) | |
| parent | 9a01135b98b9d5a7033c544245da7aad0d886758 (diff) | |
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
25 files changed, 2521 insertions, 565 deletions
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 8da2a178cf85..75c882e09fee 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst | |||
| @@ -554,6 +554,18 @@ Plane Composition Properties | |||
| 554 | .. kernel-doc:: drivers/gpu/drm/drm_blend.c | 554 | .. kernel-doc:: drivers/gpu/drm/drm_blend.c |
| 555 | :export: | 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 | Color Management Properties | 569 | Color Management Properties |
| 558 | --------------------------- | 570 | --------------------------- |
| 559 | 571 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 254b7b267731..e12da05e2feb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -4781,10 +4781,8 @@ T: git git://anongit.freedesktop.org/drm/drm-misc | |||
| 4781 | 4781 | ||
| 4782 | DRM DRIVER FOR VMWARE VIRTUAL GPU | 4782 | DRM DRIVER FOR VMWARE VIRTUAL GPU |
| 4783 | M: "VMware Graphics" <linux-graphics-maintainer@vmware.com> | 4783 | M: "VMware Graphics" <linux-graphics-maintainer@vmware.com> |
| 4784 | M: Sinclair Yeh <syeh@vmware.com> | ||
| 4785 | M: Thomas Hellstrom <thellstrom@vmware.com> | 4784 | M: Thomas Hellstrom <thellstrom@vmware.com> |
| 4786 | L: dri-devel@lists.freedesktop.org | 4785 | L: dri-devel@lists.freedesktop.org |
| 4787 | T: git git://people.freedesktop.org/~syeh/repos_linux | ||
| 4788 | T: git git://people.freedesktop.org/~thomash/linux | 4786 | T: git git://people.freedesktop.org/~thomash/linux |
| 4789 | S: Supported | 4787 | S: Supported |
| 4790 | F: drivers/gpu/drm/vmwgfx/ | 4788 | F: drivers/gpu/drm/vmwgfx/ |
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index e490fe2687db..ce8d1d384319 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
| @@ -37,7 +37,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper | |||
| 37 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ | 37 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ |
| 38 | drm_simple_kms_helper.o drm_modeset_helper.o \ | 38 | drm_simple_kms_helper.o drm_modeset_helper.o \ |
| 39 | drm_scdc_helper.o drm_gem_framebuffer_helper.o \ | 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 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o | 42 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o |
| 43 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o | 43 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o |
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9ac26437051b..48ec378fb27e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
| @@ -531,6 +531,8 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, | |||
| 531 | struct drm_crtc *crtc = new_plane_state->crtc; | 531 | struct drm_crtc *crtc = new_plane_state->crtc; |
| 532 | const struct drm_framebuffer *fb = new_plane_state->fb; | 532 | const struct drm_framebuffer *fb = new_plane_state->fb; |
| 533 | unsigned int fb_width, fb_height; | 533 | unsigned int fb_width, fb_height; |
| 534 | struct drm_mode_rect *clips; | ||
| 535 | uint32_t num_clips; | ||
| 534 | int ret; | 536 | int ret; |
| 535 | 537 | ||
| 536 | /* either *both* CRTC and FB must be set, or neither */ | 538 | /* either *both* CRTC and FB must be set, or neither */ |
| @@ -604,6 +606,26 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, | |||
| 604 | return -ENOSPC; | 606 | return -ENOSPC; |
| 605 | } | 607 | } |
| 606 | 608 | ||
| 609 | clips = drm_plane_get_damage_clips(new_plane_state); | ||
| 610 | num_clips = drm_plane_get_damage_clips_count(new_plane_state); | ||
| 611 | |||
| 612 | /* Make sure damage clips are valid and inside the fb. */ | ||
| 613 | while (num_clips > 0) { | ||
| 614 | if (clips->x1 >= clips->x2 || | ||
| 615 | clips->y1 >= clips->y2 || | ||
| 616 | clips->x1 < 0 || | ||
| 617 | clips->y1 < 0 || | ||
| 618 | clips->x2 > fb_width || | ||
| 619 | clips->y2 > fb_height) { | ||
| 620 | DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid damage clip %d %d %d %d\n", | ||
| 621 | plane->base.id, plane->name, clips->x1, | ||
| 622 | clips->y1, clips->x2, clips->y2); | ||
| 623 | return -EINVAL; | ||
| 624 | } | ||
| 625 | clips++; | ||
| 626 | num_clips--; | ||
| 627 | } | ||
| 628 | |||
| 607 | if (plane_switching_crtc(old_plane_state, new_plane_state)) { | 629 | if (plane_switching_crtc(old_plane_state, new_plane_state)) { |
| 608 | DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n", | 630 | DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n", |
| 609 | plane->base.id, plane->name); | 631 | plane->base.id, plane->name); |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bc9fc9665614..5ed12144ceb7 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <drm/drm_crtc_helper.h> | 32 | #include <drm/drm_crtc_helper.h> |
| 33 | #include <drm/drm_atomic_helper.h> | 33 | #include <drm/drm_atomic_helper.h> |
| 34 | #include <drm/drm_writeback.h> | 34 | #include <drm/drm_writeback.h> |
| 35 | #include <drm/drm_damage_helper.h> | ||
| 35 | #include <linux/dma-fence.h> | 36 | #include <linux/dma-fence.h> |
| 36 | 37 | ||
| 37 | #include "drm_crtc_helper_internal.h" | 38 | #include "drm_crtc_helper_internal.h" |
| @@ -862,6 +863,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev, | |||
| 862 | 863 | ||
| 863 | drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane); | 864 | drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane); |
| 864 | 865 | ||
| 866 | drm_atomic_helper_check_plane_damage(state, new_plane_state); | ||
| 867 | |||
| 865 | if (!funcs || !funcs->atomic_check) | 868 | if (!funcs || !funcs->atomic_check) |
| 866 | continue; | 869 | continue; |
| 867 | 870 | ||
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 30a6d1edd5fe..c40889888a16 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c | |||
| @@ -517,6 +517,8 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, | |||
| 517 | { | 517 | { |
| 518 | struct drm_device *dev = plane->dev; | 518 | struct drm_device *dev = plane->dev; |
| 519 | struct drm_mode_config *config = &dev->mode_config; | 519 | struct drm_mode_config *config = &dev->mode_config; |
| 520 | bool replaced = false; | ||
| 521 | int ret; | ||
| 520 | 522 | ||
| 521 | if (property == config->prop_fb_id) { | 523 | if (property == config->prop_fb_id) { |
| 522 | struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); | 524 | struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); |
| @@ -570,6 +572,14 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, | |||
| 570 | state->color_encoding = val; | 572 | state->color_encoding = val; |
| 571 | } else if (property == plane->color_range_property) { | 573 | } else if (property == plane->color_range_property) { |
| 572 | state->color_range = val; | 574 | state->color_range = val; |
| 575 | } else if (property == config->prop_fb_damage_clips) { | ||
| 576 | ret = drm_atomic_replace_property_blob_from_id(dev, | ||
| 577 | &state->fb_damage_clips, | ||
| 578 | val, | ||
| 579 | -1, | ||
| 580 | sizeof(struct drm_rect), | ||
| 581 | &replaced); | ||
| 582 | return ret; | ||
| 573 | } else if (plane->funcs->atomic_set_property) { | 583 | } else if (plane->funcs->atomic_set_property) { |
| 574 | return plane->funcs->atomic_set_property(plane, state, | 584 | return plane->funcs->atomic_set_property(plane, state, |
| 575 | property, val); | 585 | property, val); |
| @@ -625,6 +635,9 @@ drm_atomic_plane_get_property(struct drm_plane *plane, | |||
| 625 | *val = state->color_encoding; | 635 | *val = state->color_encoding; |
| 626 | } else if (property == plane->color_range_property) { | 636 | } else if (property == plane->color_range_property) { |
| 627 | *val = state->color_range; | 637 | *val = state->color_range; |
| 638 | } else if (property == config->prop_fb_damage_clips) { | ||
| 639 | *val = (state->fb_damage_clips) ? | ||
| 640 | state->fb_damage_clips->base.id : 0; | ||
| 628 | } else if (plane->funcs->atomic_get_property) { | 641 | } else if (plane->funcs->atomic_get_property) { |
| 629 | return plane->funcs->atomic_get_property(plane, state, property, val); | 642 | return plane->funcs->atomic_get_property(plane, state, property, val); |
| 630 | } else { | 643 | } else { |
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c new file mode 100644 index 000000000000..05c8e7267165 --- /dev/null +++ b/drivers/gpu/drm/drm_damage_helper.c | |||
| @@ -0,0 +1,334 @@ | |||
| 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); | ||
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 5670c67f28d4..703bfce975bb 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c | |||
| @@ -297,6 +297,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) | |||
| 297 | return -ENOMEM; | 297 | return -ENOMEM; |
| 298 | dev->mode_config.prop_crtc_id = prop; | 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 | prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, | 306 | prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, |
| 301 | "ACTIVE"); | 307 | "ACTIVE"); |
| 302 | if (!prop) | 308 | if (!prop) |
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile index 383d8d6c5847..1bb73dc4c88c 100644 --- a/drivers/gpu/drm/selftests/Makefile +++ b/drivers/gpu/drm/selftests/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \ | 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 | obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o | 5 | obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o |
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h index 92601defd8f6..464753746013 100644 --- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h +++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h | |||
| @@ -11,3 +11,24 @@ selftest(check_drm_format_block_width, igt_check_drm_format_block_width) | |||
| 11 | selftest(check_drm_format_block_height, igt_check_drm_format_block_height) | 11 | selftest(check_drm_format_block_height, igt_check_drm_format_block_height) |
| 12 | selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch) | 12 | selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch) |
| 13 | selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create) | 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) | ||
diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c new file mode 100644 index 000000000000..a2f753205a3e --- /dev/null +++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c | |||
| @@ -0,0 +1,811 @@ | |||
| 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 | } | ||
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h index d5df5bd51b05..8c76f09c12d1 100644 --- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h +++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h | |||
| @@ -18,5 +18,26 @@ int igt_check_drm_format_block_width(void *ignored); | |||
| 18 | int igt_check_drm_format_block_height(void *ignored); | 18 | int igt_check_drm_format_block_height(void *ignored); |
| 19 | int igt_check_drm_format_min_pitch(void *ignored); | 19 | int igt_check_drm_format_min_pitch(void *ignored); |
| 20 | int igt_check_drm_framebuffer_create(void *ignored); | 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 | #endif | 43 | #endif |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index b9c078860a7c..9fd8b4e75a8c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
| @@ -665,7 +665,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
| 665 | mutex_init(&dev_priv->cmdbuf_mutex); | 665 | mutex_init(&dev_priv->cmdbuf_mutex); |
| 666 | mutex_init(&dev_priv->release_mutex); | 666 | mutex_init(&dev_priv->release_mutex); |
| 667 | mutex_init(&dev_priv->binding_mutex); | 667 | mutex_init(&dev_priv->binding_mutex); |
| 668 | mutex_init(&dev_priv->requested_layout_mutex); | ||
| 669 | mutex_init(&dev_priv->global_kms_state_mutex); | 668 | mutex_init(&dev_priv->global_kms_state_mutex); |
| 670 | ttm_lock_init(&dev_priv->reservation_sem); | 669 | ttm_lock_init(&dev_priv->reservation_sem); |
| 671 | spin_lock_init(&dev_priv->resource_lock); | 670 | spin_lock_init(&dev_priv->resource_lock); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 28df788da44e..d7f6cb9331de 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
| @@ -466,15 +466,6 @@ struct vmw_private { | |||
| 466 | uint32_t num_displays; | 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 | * Framebuffer info. | 469 | * Framebuffer info. |
| 479 | */ | 470 | */ |
| 480 | 471 | ||
| @@ -484,8 +475,6 @@ struct vmw_private { | |||
| 484 | struct vmw_overlay *overlay_priv; | 475 | struct vmw_overlay *overlay_priv; |
| 485 | struct drm_property *hotplug_mode_update_property; | 476 | struct drm_property *hotplug_mode_update_property; |
| 486 | struct drm_property *implicit_placement_property; | 477 | struct drm_property *implicit_placement_property; |
| 487 | unsigned num_implicit; | ||
| 488 | struct vmw_framebuffer *implicit_fb; | ||
| 489 | struct mutex global_kms_state_mutex; | 478 | struct mutex global_kms_state_mutex; |
| 490 | spinlock_t cursor_lock; | 479 | spinlock_t cursor_lock; |
| 491 | struct drm_atomic_state *suspend_state; | 480 | struct drm_atomic_state *suspend_state; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 5a6b70ba137a..260650bb5560 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | |||
| @@ -1738,7 +1738,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, | |||
| 1738 | void *buf) | 1738 | void *buf) |
| 1739 | { | 1739 | { |
| 1740 | struct vmw_buffer_object *vmw_bo; | 1740 | struct vmw_buffer_object *vmw_bo; |
| 1741 | int ret; | ||
| 1742 | 1741 | ||
| 1743 | struct { | 1742 | struct { |
| 1744 | uint32_t header; | 1743 | uint32_t header; |
| @@ -1748,7 +1747,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, | |||
| 1748 | return vmw_translate_guest_ptr(dev_priv, sw_context, | 1747 | return vmw_translate_guest_ptr(dev_priv, sw_context, |
| 1749 | &cmd->body.ptr, | 1748 | &cmd->body.ptr, |
| 1750 | &vmw_bo); | 1749 | &vmw_bo); |
| 1751 | return ret; | ||
| 1752 | } | 1750 | } |
| 1753 | 1751 | ||
| 1754 | 1752 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index f87261545f2c..301260e23e52 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | |||
| @@ -906,13 +906,10 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action) | |||
| 906 | container_of(action, struct vmw_event_fence_action, action); | 906 | container_of(action, struct vmw_event_fence_action, action); |
| 907 | struct drm_device *dev = eaction->dev; | 907 | struct drm_device *dev = eaction->dev; |
| 908 | struct drm_pending_event *event = eaction->event; | 908 | struct drm_pending_event *event = eaction->event; |
| 909 | struct drm_file *file_priv; | ||
| 910 | |||
| 911 | 909 | ||
| 912 | if (unlikely(event == NULL)) | 910 | if (unlikely(event == NULL)) |
| 913 | return; | 911 | return; |
| 914 | 912 | ||
| 915 | file_priv = event->file_priv; | ||
| 916 | spin_lock_irq(&dev->event_lock); | 913 | spin_lock_irq(&dev->event_lock); |
| 917 | 914 | ||
| 918 | if (likely(eaction->tv_sec != NULL)) { | 915 | if (likely(eaction->tv_sec != NULL)) { |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index e6b11f6ae2e4..b351fb5214d3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <drm/drm_atomic.h> | 30 | #include <drm/drm_atomic.h> |
| 31 | #include <drm/drm_atomic_helper.h> | 31 | #include <drm/drm_atomic_helper.h> |
| 32 | #include <drm/drm_rect.h> | 32 | #include <drm/drm_rect.h> |
| 33 | #include <drm/drm_damage_helper.h> | ||
| 33 | 34 | ||
| 34 | /* Might need a hrtimer here? */ | 35 | /* Might need a hrtimer here? */ |
| 35 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) | 36 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) |
| @@ -456,21 +457,8 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, | |||
| 456 | struct drm_crtc *crtc = state->crtc; | 457 | struct drm_crtc *crtc = state->crtc; |
| 457 | struct vmw_connector_state *vcs; | 458 | struct vmw_connector_state *vcs; |
| 458 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); | 459 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
| 459 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); | ||
| 460 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); | ||
| 461 | 460 | ||
| 462 | vcs = vmw_connector_state_to_vcs(du->connector.state); | 461 | vcs = vmw_connector_state_to_vcs(du->connector.state); |
| 463 | |||
| 464 | /* Only one active implicit framebuffer at a time. */ | ||
| 465 | mutex_lock(&dev_priv->global_kms_state_mutex); | ||
| 466 | if (vcs->is_implicit && dev_priv->implicit_fb && | ||
| 467 | !(dev_priv->num_implicit == 1 && du->active_implicit) | ||
| 468 | && dev_priv->implicit_fb != vfb) { | ||
| 469 | DRM_ERROR("Multiple implicit framebuffers " | ||
| 470 | "not supported.\n"); | ||
| 471 | ret = -EINVAL; | ||
| 472 | } | ||
| 473 | mutex_unlock(&dev_priv->global_kms_state_mutex); | ||
| 474 | } | 462 | } |
| 475 | 463 | ||
| 476 | 464 | ||
| @@ -846,58 +834,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) | |||
| 846 | kfree(vfbs); | 834 | kfree(vfbs); |
| 847 | } | 835 | } |
| 848 | 836 | ||
| 849 | static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, | ||
| 850 | struct drm_file *file_priv, | ||
| 851 | unsigned flags, unsigned color, | ||
| 852 | struct drm_clip_rect *clips, | ||
| 853 | unsigned num_clips) | ||
| 854 | { | ||
| 855 | struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); | ||
| 856 | struct vmw_framebuffer_surface *vfbs = | ||
| 857 | vmw_framebuffer_to_vfbs(framebuffer); | ||
| 858 | struct drm_clip_rect norect; | ||
| 859 | int ret, inc = 1; | ||
| 860 | |||
| 861 | /* Legacy Display Unit does not support 3D */ | ||
| 862 | if (dev_priv->active_display_unit == vmw_du_legacy) | ||
| 863 | return -EINVAL; | ||
| 864 | |||
| 865 | drm_modeset_lock_all(dev_priv->dev); | ||
| 866 | |||
| 867 | ret = ttm_read_lock(&dev_priv->reservation_sem, true); | ||
| 868 | if (unlikely(ret != 0)) { | ||
| 869 | drm_modeset_unlock_all(dev_priv->dev); | ||
| 870 | return ret; | ||
| 871 | } | ||
| 872 | |||
| 873 | if (!num_clips) { | ||
| 874 | num_clips = 1; | ||
| 875 | clips = &norect; | ||
| 876 | norect.x1 = norect.y1 = 0; | ||
| 877 | norect.x2 = framebuffer->width; | ||
| 878 | norect.y2 = framebuffer->height; | ||
| 879 | } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { | ||
| 880 | num_clips /= 2; | ||
| 881 | inc = 2; /* skip source rects */ | ||
| 882 | } | ||
| 883 | |||
| 884 | if (dev_priv->active_display_unit == vmw_du_screen_object) | ||
| 885 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, | ||
| 886 | clips, NULL, NULL, 0, 0, | ||
| 887 | num_clips, inc, NULL, NULL); | ||
| 888 | else | ||
| 889 | ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, | ||
| 890 | clips, NULL, NULL, 0, 0, | ||
| 891 | num_clips, inc, NULL, NULL); | ||
| 892 | |||
| 893 | vmw_fifo_flush(dev_priv, false); | ||
| 894 | ttm_read_unlock(&dev_priv->reservation_sem); | ||
| 895 | |||
| 896 | drm_modeset_unlock_all(dev_priv->dev); | ||
| 897 | |||
| 898 | return 0; | ||
| 899 | } | ||
| 900 | |||
| 901 | /** | 837 | /** |
| 902 | * vmw_kms_readback - Perform a readback from the screen system to | 838 | * vmw_kms_readback - Perform a readback from the screen system to |
| 903 | * a buffer-object backed framebuffer. | 839 | * a buffer-object backed framebuffer. |
| @@ -941,7 +877,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv, | |||
| 941 | 877 | ||
| 942 | static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { | 878 | static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { |
| 943 | .destroy = vmw_framebuffer_surface_destroy, | 879 | .destroy = vmw_framebuffer_surface_destroy, |
| 944 | .dirty = vmw_framebuffer_surface_dirty, | 880 | .dirty = drm_atomic_helper_dirtyfb, |
| 945 | }; | 881 | }; |
| 946 | 882 | ||
| 947 | static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, | 883 | static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, |
| @@ -1084,16 +1020,6 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, | |||
| 1084 | } | 1020 | } |
| 1085 | 1021 | ||
| 1086 | switch (dev_priv->active_display_unit) { | 1022 | switch (dev_priv->active_display_unit) { |
| 1087 | case vmw_du_screen_target: | ||
| 1088 | ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, | ||
| 1089 | clips, NULL, num_clips, increment, | ||
| 1090 | true, true, NULL); | ||
| 1091 | break; | ||
| 1092 | case vmw_du_screen_object: | ||
| 1093 | ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base, | ||
| 1094 | clips, NULL, num_clips, | ||
| 1095 | increment, true, NULL, NULL); | ||
| 1096 | break; | ||
| 1097 | case vmw_du_legacy: | 1023 | case vmw_du_legacy: |
| 1098 | ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, | 1024 | ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, |
| 1099 | clips, num_clips, increment); | 1025 | clips, num_clips, increment); |
| @@ -1112,9 +1038,25 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, | |||
| 1112 | return ret; | 1038 | return ret; |
| 1113 | } | 1039 | } |
| 1114 | 1040 | ||
| 1041 | static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer, | ||
| 1042 | struct drm_file *file_priv, | ||
| 1043 | unsigned int flags, unsigned int color, | ||
| 1044 | struct drm_clip_rect *clips, | ||
| 1045 | unsigned int num_clips) | ||
| 1046 | { | ||
| 1047 | struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); | ||
| 1048 | |||
| 1049 | if (dev_priv->active_display_unit == vmw_du_legacy) | ||
| 1050 | return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags, | ||
| 1051 | color, clips, num_clips); | ||
| 1052 | |||
| 1053 | return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color, | ||
| 1054 | clips, num_clips); | ||
| 1055 | } | ||
| 1056 | |||
| 1115 | static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { | 1057 | static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { |
| 1116 | .destroy = vmw_framebuffer_bo_destroy, | 1058 | .destroy = vmw_framebuffer_bo_destroy, |
| 1117 | .dirty = vmw_framebuffer_bo_dirty, | 1059 | .dirty = vmw_framebuffer_bo_dirty_ext, |
| 1118 | }; | 1060 | }; |
| 1119 | 1061 | ||
| 1120 | /** | 1062 | /** |
| @@ -1565,6 +1507,88 @@ static int vmw_kms_check_display_memory(struct drm_device *dev, | |||
| 1565 | } | 1507 | } |
| 1566 | 1508 | ||
| 1567 | /** | 1509 | /** |
| 1510 | * vmw_crtc_state_and_lock - Return new or current crtc state with locked | ||
| 1511 | * crtc mutex | ||
| 1512 | * @state: The atomic state pointer containing the new atomic state | ||
| 1513 | * @crtc: The crtc | ||
| 1514 | * | ||
| 1515 | * This function returns the new crtc state if it's part of the state update. | ||
| 1516 | * Otherwise returns the current crtc state. It also makes sure that the | ||
| 1517 | * crtc mutex is locked. | ||
| 1518 | * | ||
| 1519 | * Returns: A valid crtc state pointer or NULL. It may also return a | ||
| 1520 | * pointer error, in particular -EDEADLK if locking needs to be rerun. | ||
| 1521 | */ | ||
| 1522 | static struct drm_crtc_state * | ||
| 1523 | vmw_crtc_state_and_lock(struct drm_atomic_state *state, struct drm_crtc *crtc) | ||
| 1524 | { | ||
| 1525 | struct drm_crtc_state *crtc_state; | ||
| 1526 | |||
| 1527 | crtc_state = drm_atomic_get_new_crtc_state(state, crtc); | ||
| 1528 | if (crtc_state) { | ||
| 1529 | lockdep_assert_held(&crtc->mutex.mutex.base); | ||
| 1530 | } else { | ||
| 1531 | int ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx); | ||
| 1532 | |||
| 1533 | if (ret != 0 && ret != -EALREADY) | ||
| 1534 | return ERR_PTR(ret); | ||
| 1535 | |||
| 1536 | crtc_state = crtc->state; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | return crtc_state; | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | /** | ||
| 1543 | * vmw_kms_check_implicit - Verify that all implicit display units scan out | ||
| 1544 | * from the same fb after the new state is committed. | ||
| 1545 | * @dev: The drm_device. | ||
| 1546 | * @state: The new state to be checked. | ||
| 1547 | * | ||
| 1548 | * Returns: | ||
| 1549 | * Zero on success, | ||
| 1550 | * -EINVAL on invalid state, | ||
| 1551 | * -EDEADLK if modeset locking needs to be rerun. | ||
| 1552 | */ | ||
| 1553 | static int vmw_kms_check_implicit(struct drm_device *dev, | ||
| 1554 | struct drm_atomic_state *state) | ||
| 1555 | { | ||
| 1556 | struct drm_framebuffer *implicit_fb = NULL; | ||
| 1557 | struct drm_crtc *crtc; | ||
| 1558 | struct drm_crtc_state *crtc_state; | ||
| 1559 | struct drm_plane_state *plane_state; | ||
| 1560 | |||
| 1561 | drm_for_each_crtc(crtc, dev) { | ||
| 1562 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); | ||
| 1563 | |||
| 1564 | if (!du->is_implicit) | ||
| 1565 | continue; | ||
| 1566 | |||
| 1567 | crtc_state = vmw_crtc_state_and_lock(state, crtc); | ||
| 1568 | if (IS_ERR(crtc_state)) | ||
| 1569 | return PTR_ERR(crtc_state); | ||
| 1570 | |||
| 1571 | if (!crtc_state || !crtc_state->enable) | ||
| 1572 | continue; | ||
| 1573 | |||
| 1574 | /* | ||
| 1575 | * Can't move primary planes across crtcs, so this is OK. | ||
| 1576 | * It also means we don't need to take the plane mutex. | ||
| 1577 | */ | ||
| 1578 | plane_state = du->primary.state; | ||
| 1579 | if (plane_state->crtc != crtc) | ||
| 1580 | continue; | ||
| 1581 | |||
| 1582 | if (!implicit_fb) | ||
| 1583 | implicit_fb = plane_state->fb; | ||
| 1584 | else if (implicit_fb != plane_state->fb) | ||
| 1585 | return -EINVAL; | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | return 0; | ||
| 1589 | } | ||
| 1590 | |||
| 1591 | /** | ||
| 1568 | * vmw_kms_check_topology - Validates topology in drm_atomic_state | 1592 | * vmw_kms_check_topology - Validates topology in drm_atomic_state |
| 1569 | * @dev: DRM device | 1593 | * @dev: DRM device |
| 1570 | * @state: the driver state object | 1594 | * @state: the driver state object |
| @@ -1575,7 +1599,6 @@ static int vmw_kms_check_display_memory(struct drm_device *dev, | |||
| 1575 | static int vmw_kms_check_topology(struct drm_device *dev, | 1599 | static int vmw_kms_check_topology(struct drm_device *dev, |
| 1576 | struct drm_atomic_state *state) | 1600 | struct drm_atomic_state *state) |
| 1577 | { | 1601 | { |
| 1578 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
| 1579 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; | 1602 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; |
| 1580 | struct drm_rect *rects; | 1603 | struct drm_rect *rects; |
| 1581 | struct drm_crtc *crtc; | 1604 | struct drm_crtc *crtc; |
| @@ -1587,19 +1610,31 @@ static int vmw_kms_check_topology(struct drm_device *dev, | |||
| 1587 | if (!rects) | 1610 | if (!rects) |
| 1588 | return -ENOMEM; | 1611 | return -ENOMEM; |
| 1589 | 1612 | ||
| 1590 | mutex_lock(&dev_priv->requested_layout_mutex); | ||
| 1591 | |||
| 1592 | drm_for_each_crtc(crtc, dev) { | 1613 | drm_for_each_crtc(crtc, dev) { |
| 1593 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); | 1614 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
| 1594 | struct drm_crtc_state *crtc_state = crtc->state; | 1615 | struct drm_crtc_state *crtc_state; |
| 1595 | 1616 | ||
| 1596 | i = drm_crtc_index(crtc); | 1617 | i = drm_crtc_index(crtc); |
| 1597 | 1618 | ||
| 1598 | if (crtc_state && crtc_state->enable) { | 1619 | crtc_state = vmw_crtc_state_and_lock(state, crtc); |
| 1620 | if (IS_ERR(crtc_state)) { | ||
| 1621 | ret = PTR_ERR(crtc_state); | ||
| 1622 | goto clean; | ||
| 1623 | } | ||
| 1624 | |||
| 1625 | if (!crtc_state) | ||
| 1626 | continue; | ||
| 1627 | |||
| 1628 | if (crtc_state->enable) { | ||
| 1599 | rects[i].x1 = du->gui_x; | 1629 | rects[i].x1 = du->gui_x; |
| 1600 | rects[i].y1 = du->gui_y; | 1630 | rects[i].y1 = du->gui_y; |
| 1601 | rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; | 1631 | rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; |
| 1602 | rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; | 1632 | rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; |
| 1633 | } else { | ||
| 1634 | rects[i].x1 = 0; | ||
| 1635 | rects[i].y1 = 0; | ||
| 1636 | rects[i].x2 = 0; | ||
| 1637 | rects[i].y2 = 0; | ||
| 1603 | } | 1638 | } |
| 1604 | } | 1639 | } |
| 1605 | 1640 | ||
| @@ -1611,14 +1646,6 @@ static int vmw_kms_check_topology(struct drm_device *dev, | |||
| 1611 | struct drm_connector_state *conn_state; | 1646 | struct drm_connector_state *conn_state; |
| 1612 | struct vmw_connector_state *vmw_conn_state; | 1647 | struct vmw_connector_state *vmw_conn_state; |
| 1613 | 1648 | ||
| 1614 | if (!new_crtc_state->enable) { | ||
| 1615 | rects[i].x1 = 0; | ||
| 1616 | rects[i].y1 = 0; | ||
| 1617 | rects[i].x2 = 0; | ||
| 1618 | rects[i].y2 = 0; | ||
| 1619 | continue; | ||
| 1620 | } | ||
| 1621 | |||
| 1622 | if (!du->pref_active) { | 1649 | if (!du->pref_active) { |
| 1623 | ret = -EINVAL; | 1650 | ret = -EINVAL; |
| 1624 | goto clean; | 1651 | goto clean; |
| @@ -1639,18 +1666,12 @@ static int vmw_kms_check_topology(struct drm_device *dev, | |||
| 1639 | vmw_conn_state = vmw_connector_state_to_vcs(conn_state); | 1666 | vmw_conn_state = vmw_connector_state_to_vcs(conn_state); |
| 1640 | vmw_conn_state->gui_x = du->gui_x; | 1667 | vmw_conn_state->gui_x = du->gui_x; |
| 1641 | vmw_conn_state->gui_y = du->gui_y; | 1668 | vmw_conn_state->gui_y = du->gui_y; |
| 1642 | |||
| 1643 | rects[i].x1 = du->gui_x; | ||
| 1644 | rects[i].y1 = du->gui_y; | ||
| 1645 | rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay; | ||
| 1646 | rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay; | ||
| 1647 | } | 1669 | } |
| 1648 | 1670 | ||
| 1649 | ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, | 1671 | ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, |
| 1650 | rects); | 1672 | rects); |
| 1651 | 1673 | ||
| 1652 | clean: | 1674 | clean: |
| 1653 | mutex_unlock(&dev_priv->requested_layout_mutex); | ||
| 1654 | kfree(rects); | 1675 | kfree(rects); |
| 1655 | return ret; | 1676 | return ret; |
| 1656 | } | 1677 | } |
| @@ -1681,6 +1702,10 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev, | |||
| 1681 | if (ret) | 1702 | if (ret) |
| 1682 | return ret; | 1703 | return ret; |
| 1683 | 1704 | ||
| 1705 | ret = vmw_kms_check_implicit(dev, state); | ||
| 1706 | if (ret) | ||
| 1707 | return ret; | ||
| 1708 | |||
| 1684 | if (!state->allow_modeset) | 1709 | if (!state->allow_modeset) |
| 1685 | return ret; | 1710 | return ret; |
| 1686 | 1711 | ||
| @@ -2003,11 +2028,25 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, | |||
| 2003 | struct vmw_display_unit *du; | 2028 | struct vmw_display_unit *du; |
| 2004 | struct drm_connector *con; | 2029 | struct drm_connector *con; |
| 2005 | struct drm_connector_list_iter conn_iter; | 2030 | struct drm_connector_list_iter conn_iter; |
| 2031 | struct drm_modeset_acquire_ctx ctx; | ||
| 2032 | struct drm_crtc *crtc; | ||
| 2033 | int ret; | ||
| 2034 | |||
| 2035 | /* Currently gui_x/y is protected with the crtc mutex */ | ||
| 2036 | mutex_lock(&dev->mode_config.mutex); | ||
| 2037 | drm_modeset_acquire_init(&ctx, 0); | ||
| 2038 | retry: | ||
| 2039 | drm_for_each_crtc(crtc, dev) { | ||
| 2040 | ret = drm_modeset_lock(&crtc->mutex, &ctx); | ||
| 2041 | if (ret < 0) { | ||
| 2042 | if (ret == -EDEADLK) { | ||
| 2043 | drm_modeset_backoff(&ctx); | ||
| 2044 | goto retry; | ||
| 2045 | } | ||
| 2046 | goto out_fini; | ||
| 2047 | } | ||
| 2048 | } | ||
| 2006 | 2049 | ||
| 2007 | /* | ||
| 2008 | * Currently only gui_x/y is protected with requested_layout_mutex. | ||
| 2009 | */ | ||
| 2010 | mutex_lock(&dev_priv->requested_layout_mutex); | ||
| 2011 | drm_connector_list_iter_begin(dev, &conn_iter); | 2050 | drm_connector_list_iter_begin(dev, &conn_iter); |
| 2012 | drm_for_each_connector_iter(con, &conn_iter) { | 2051 | drm_for_each_connector_iter(con, &conn_iter) { |
| 2013 | du = vmw_connector_to_du(con); | 2052 | du = vmw_connector_to_du(con); |
| @@ -2026,9 +2065,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, | |||
| 2026 | } | 2065 | } |
| 2027 | } | 2066 | } |
| 2028 | drm_connector_list_iter_end(&conn_iter); | 2067 | drm_connector_list_iter_end(&conn_iter); |
| 2029 | mutex_unlock(&dev_priv->requested_layout_mutex); | ||
| 2030 | 2068 | ||
| 2031 | mutex_lock(&dev->mode_config.mutex); | ||
| 2032 | list_for_each_entry(con, &dev->mode_config.connector_list, head) { | 2069 | list_for_each_entry(con, &dev->mode_config.connector_list, head) { |
| 2033 | du = vmw_connector_to_du(con); | 2070 | du = vmw_connector_to_du(con); |
| 2034 | if (num_rects > du->unit) { | 2071 | if (num_rects > du->unit) { |
| @@ -2048,10 +2085,13 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, | |||
| 2048 | } | 2085 | } |
| 2049 | con->status = vmw_du_connector_detect(con, true); | 2086 | con->status = vmw_du_connector_detect(con, true); |
| 2050 | } | 2087 | } |
| 2051 | mutex_unlock(&dev->mode_config.mutex); | ||
| 2052 | 2088 | ||
| 2053 | drm_sysfs_hotplug_event(dev); | 2089 | drm_sysfs_hotplug_event(dev); |
| 2054 | 2090 | out_fini: | |
| 2091 | drm_modeset_drop_locks(&ctx); | ||
| 2092 | drm_modeset_acquire_fini(&ctx); | ||
| 2093 | mutex_unlock(&dev->mode_config.mutex); | ||
| 2094 | |||
| 2055 | return 0; | 2095 | return 0; |
| 2056 | } | 2096 | } |
| 2057 | 2097 | ||
| @@ -2275,84 +2315,6 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, | |||
| 2275 | return 1; | 2315 | return 1; |
| 2276 | } | 2316 | } |
| 2277 | 2317 | ||
| 2278 | int vmw_du_connector_set_property(struct drm_connector *connector, | ||
| 2279 | struct drm_property *property, | ||
| 2280 | uint64_t val) | ||
| 2281 | { | ||
| 2282 | struct vmw_display_unit *du = vmw_connector_to_du(connector); | ||
| 2283 | struct vmw_private *dev_priv = vmw_priv(connector->dev); | ||
| 2284 | |||
| 2285 | if (property == dev_priv->implicit_placement_property) | ||
| 2286 | du->is_implicit = val; | ||
| 2287 | |||
| 2288 | return 0; | ||
| 2289 | } | ||
| 2290 | |||
| 2291 | |||
| 2292 | |||
| 2293 | /** | ||
| 2294 | * vmw_du_connector_atomic_set_property - Atomic version of get property | ||
| 2295 | * | ||
| 2296 | * @crtc - crtc the property is associated with | ||
| 2297 | * | ||
| 2298 | * Returns: | ||
| 2299 | * Zero on success, negative errno on failure. | ||
| 2300 | */ | ||
| 2301 | int | ||
| 2302 | vmw_du_connector_atomic_set_property(struct drm_connector *connector, | ||
| 2303 | struct drm_connector_state *state, | ||
| 2304 | struct drm_property *property, | ||
| 2305 | uint64_t val) | ||
| 2306 | { | ||
| 2307 | struct vmw_private *dev_priv = vmw_priv(connector->dev); | ||
| 2308 | struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state); | ||
| 2309 | struct vmw_display_unit *du = vmw_connector_to_du(connector); | ||
| 2310 | |||
| 2311 | |||
| 2312 | if (property == dev_priv->implicit_placement_property) { | ||
| 2313 | vcs->is_implicit = val; | ||
| 2314 | |||
| 2315 | /* | ||
| 2316 | * We should really be doing a drm_atomic_commit() to | ||
| 2317 | * commit the new state, but since this doesn't cause | ||
| 2318 | * an immedate state change, this is probably ok | ||
| 2319 | */ | ||
| 2320 | du->is_implicit = vcs->is_implicit; | ||
| 2321 | } else { | ||
| 2322 | return -EINVAL; | ||
| 2323 | } | ||
| 2324 | |||
| 2325 | return 0; | ||
| 2326 | } | ||
| 2327 | |||
| 2328 | |||
| 2329 | /** | ||
| 2330 | * vmw_du_connector_atomic_get_property - Atomic version of get property | ||
| 2331 | * | ||
| 2332 | * @connector - connector the property is associated with | ||
| 2333 | * | ||
| 2334 | * Returns: | ||
| 2335 | * Zero on success, negative errno on failure. | ||
| 2336 | */ | ||
| 2337 | int | ||
| 2338 | vmw_du_connector_atomic_get_property(struct drm_connector *connector, | ||
| 2339 | const struct drm_connector_state *state, | ||
| 2340 | struct drm_property *property, | ||
| 2341 | uint64_t *val) | ||
| 2342 | { | ||
| 2343 | struct vmw_private *dev_priv = vmw_priv(connector->dev); | ||
| 2344 | struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state); | ||
| 2345 | |||
| 2346 | if (property == dev_priv->implicit_placement_property) | ||
| 2347 | *val = vcs->is_implicit; | ||
| 2348 | else { | ||
| 2349 | DRM_ERROR("Invalid Property %s\n", property->name); | ||
| 2350 | return -EINVAL; | ||
| 2351 | } | ||
| 2352 | |||
| 2353 | return 0; | ||
| 2354 | } | ||
| 2355 | |||
| 2356 | /** | 2318 | /** |
| 2357 | * vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl | 2319 | * vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl |
| 2358 | * @dev: drm device for the ioctl | 2320 | * @dev: drm device for the ioctl |
| @@ -2742,143 +2704,25 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, | |||
| 2742 | } | 2704 | } |
| 2743 | 2705 | ||
| 2744 | /** | 2706 | /** |
| 2745 | * vmw_kms_del_active - unregister a crtc binding to the implicit framebuffer | ||
| 2746 | * | ||
| 2747 | * @dev_priv: Pointer to a device private struct. | ||
| 2748 | * @du: The display unit of the crtc. | ||
| 2749 | */ | ||
| 2750 | void vmw_kms_del_active(struct vmw_private *dev_priv, | ||
| 2751 | struct vmw_display_unit *du) | ||
| 2752 | { | ||
| 2753 | mutex_lock(&dev_priv->global_kms_state_mutex); | ||
| 2754 | if (du->active_implicit) { | ||
| 2755 | if (--(dev_priv->num_implicit) == 0) | ||
| 2756 | dev_priv->implicit_fb = NULL; | ||
| 2757 | du->active_implicit = false; | ||
| 2758 | } | ||
| 2759 | mutex_unlock(&dev_priv->global_kms_state_mutex); | ||
| 2760 | } | ||
| 2761 | |||
| 2762 | /** | ||
| 2763 | * vmw_kms_add_active - register a crtc binding to an implicit framebuffer | ||
| 2764 | * | ||
| 2765 | * @vmw_priv: Pointer to a device private struct. | ||
| 2766 | * @du: The display unit of the crtc. | ||
| 2767 | * @vfb: The implicit framebuffer | ||
| 2768 | * | ||
| 2769 | * Registers a binding to an implicit framebuffer. | ||
| 2770 | */ | ||
| 2771 | void vmw_kms_add_active(struct vmw_private *dev_priv, | ||
| 2772 | struct vmw_display_unit *du, | ||
| 2773 | struct vmw_framebuffer *vfb) | ||
| 2774 | { | ||
| 2775 | mutex_lock(&dev_priv->global_kms_state_mutex); | ||
| 2776 | WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb); | ||
| 2777 | |||
| 2778 | if (!du->active_implicit && du->is_implicit) { | ||
| 2779 | dev_priv->implicit_fb = vfb; | ||
| 2780 | du->active_implicit = true; | ||
| 2781 | dev_priv->num_implicit++; | ||
| 2782 | } | ||
| 2783 | mutex_unlock(&dev_priv->global_kms_state_mutex); | ||
| 2784 | } | ||
| 2785 | |||
| 2786 | /** | ||
| 2787 | * vmw_kms_screen_object_flippable - Check whether we can page-flip a crtc. | ||
| 2788 | * | ||
| 2789 | * @dev_priv: Pointer to device-private struct. | ||
| 2790 | * @crtc: The crtc we want to flip. | ||
| 2791 | * | ||
| 2792 | * Returns true or false depending whether it's OK to flip this crtc | ||
| 2793 | * based on the criterion that we must not have more than one implicit | ||
| 2794 | * frame-buffer at any one time. | ||
| 2795 | */ | ||
| 2796 | bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, | ||
| 2797 | struct drm_crtc *crtc) | ||
| 2798 | { | ||
| 2799 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); | ||
| 2800 | bool ret; | ||
| 2801 | |||
| 2802 | mutex_lock(&dev_priv->global_kms_state_mutex); | ||
| 2803 | ret = !du->is_implicit || dev_priv->num_implicit == 1; | ||
| 2804 | mutex_unlock(&dev_priv->global_kms_state_mutex); | ||
| 2805 | |||
| 2806 | return ret; | ||
| 2807 | } | ||
| 2808 | |||
| 2809 | /** | ||
| 2810 | * vmw_kms_update_implicit_fb - Update the implicit fb. | ||
| 2811 | * | ||
| 2812 | * @dev_priv: Pointer to device-private struct. | ||
| 2813 | * @crtc: The crtc the new implicit frame-buffer is bound to. | ||
| 2814 | */ | ||
| 2815 | void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, | ||
| 2816 | struct drm_crtc *crtc) | ||
| 2817 | { | ||
| 2818 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); | ||
| 2819 | struct drm_plane *plane = crtc->primary; | ||
| 2820 | struct vmw_framebuffer *vfb; | ||
| 2821 | |||
| 2822 | mutex_lock(&dev_priv->global_kms_state_mutex); | ||
| 2823 | |||
| 2824 | if (!du->is_implicit) | ||
| 2825 | goto out_unlock; | ||
| 2826 | |||
| 2827 | vfb = vmw_framebuffer_to_vfb(plane->state->fb); | ||
| 2828 | WARN_ON_ONCE(dev_priv->num_implicit != 1 && | ||
| 2829 | dev_priv->implicit_fb != vfb); | ||
| 2830 | |||
| 2831 | dev_priv->implicit_fb = vfb; | ||
| 2832 | out_unlock: | ||
| 2833 | mutex_unlock(&dev_priv->global_kms_state_mutex); | ||
| 2834 | } | ||
| 2835 | |||
| 2836 | /** | ||
| 2837 | * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement | 2707 | * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement |
| 2838 | * property. | 2708 | * property. |
| 2839 | * | 2709 | * |
| 2840 | * @dev_priv: Pointer to a device private struct. | 2710 | * @dev_priv: Pointer to a device private struct. |
| 2841 | * @immutable: Whether the property is immutable. | ||
| 2842 | * | 2711 | * |
| 2843 | * Sets up the implicit placement property unless it's already set up. | 2712 | * Sets up the implicit placement property unless it's already set up. |
| 2844 | */ | 2713 | */ |
| 2845 | void | 2714 | void |
| 2846 | vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, | 2715 | vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv) |
| 2847 | bool immutable) | ||
| 2848 | { | 2716 | { |
| 2849 | if (dev_priv->implicit_placement_property) | 2717 | if (dev_priv->implicit_placement_property) |
| 2850 | return; | 2718 | return; |
| 2851 | 2719 | ||
| 2852 | dev_priv->implicit_placement_property = | 2720 | dev_priv->implicit_placement_property = |
| 2853 | drm_property_create_range(dev_priv->dev, | 2721 | drm_property_create_range(dev_priv->dev, |
| 2854 | immutable ? | 2722 | DRM_MODE_PROP_IMMUTABLE, |
| 2855 | DRM_MODE_PROP_IMMUTABLE : 0, | ||
| 2856 | "implicit_placement", 0, 1); | 2723 | "implicit_placement", 0, 1); |
| 2857 | |||
| 2858 | } | ||
| 2859 | |||
| 2860 | |||
| 2861 | /** | ||
| 2862 | * vmw_kms_set_config - Wrapper around drm_atomic_helper_set_config | ||
| 2863 | * | ||
| 2864 | * @set: The configuration to set. | ||
| 2865 | * | ||
| 2866 | * The vmwgfx Xorg driver doesn't assign the mode::type member, which | ||
| 2867 | * when drm_mode_set_crtcinfo is called as part of the configuration setting | ||
| 2868 | * causes it to return incorrect crtc dimensions causing severe problems in | ||
| 2869 | * the vmwgfx modesetting. So explicitly clear that member before calling | ||
| 2870 | * into drm_atomic_helper_set_config. | ||
| 2871 | */ | ||
| 2872 | int vmw_kms_set_config(struct drm_mode_set *set, | ||
| 2873 | struct drm_modeset_acquire_ctx *ctx) | ||
| 2874 | { | ||
| 2875 | if (set && set->mode) | ||
| 2876 | set->mode->type = 0; | ||
| 2877 | |||
| 2878 | return drm_atomic_helper_set_config(set, ctx); | ||
| 2879 | } | 2724 | } |
| 2880 | 2725 | ||
| 2881 | |||
| 2882 | /** | 2726 | /** |
| 2883 | * vmw_kms_suspend - Save modesetting state and turn modesetting off. | 2727 | * vmw_kms_suspend - Save modesetting state and turn modesetting off. |
| 2884 | * | 2728 | * |
| @@ -2935,3 +2779,124 @@ void vmw_kms_lost_device(struct drm_device *dev) | |||
| 2935 | { | 2779 | { |
| 2936 | drm_atomic_helper_shutdown(dev); | 2780 | drm_atomic_helper_shutdown(dev); |
| 2937 | } | 2781 | } |
| 2782 | |||
| 2783 | /** | ||
| 2784 | * vmw_du_helper_plane_update - Helper to do plane update on a display unit. | ||
| 2785 | * @update: The closure structure. | ||
| 2786 | * | ||
| 2787 | * Call this helper after setting callbacks in &vmw_du_update_plane to do plane | ||
| 2788 | * update on display unit. | ||
| 2789 | * | ||
| 2790 | * Return: 0 on success or a negative error code on failure. | ||
| 2791 | */ | ||
| 2792 | int vmw_du_helper_plane_update(struct vmw_du_update_plane *update) | ||
| 2793 | { | ||
| 2794 | struct drm_plane_state *state = update->plane->state; | ||
| 2795 | struct drm_plane_state *old_state = update->old_state; | ||
| 2796 | struct drm_atomic_helper_damage_iter iter; | ||
| 2797 | struct drm_rect clip; | ||
| 2798 | struct drm_rect bb; | ||
| 2799 | DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); | ||
| 2800 | uint32_t reserved_size = 0; | ||
| 2801 | uint32_t submit_size = 0; | ||
| 2802 | uint32_t curr_size = 0; | ||
| 2803 | uint32_t num_hits = 0; | ||
| 2804 | void *cmd_start; | ||
| 2805 | char *cmd_next; | ||
| 2806 | int ret; | ||
| 2807 | |||
| 2808 | /* | ||
| 2809 | * Iterate in advance to check if really need plane update and find the | ||
| 2810 | * number of clips that actually are in plane src for fifo allocation. | ||
| 2811 | */ | ||
| 2812 | drm_atomic_helper_damage_iter_init(&iter, old_state, state); | ||
| 2813 | drm_atomic_for_each_plane_damage(&iter, &clip) | ||
| 2814 | num_hits++; | ||
| 2815 | |||
| 2816 | if (num_hits == 0) | ||
| 2817 | return 0; | ||
| 2818 | |||
| 2819 | if (update->vfb->bo) { | ||
| 2820 | struct vmw_framebuffer_bo *vfbbo = | ||
| 2821 | container_of(update->vfb, typeof(*vfbbo), base); | ||
| 2822 | |||
| 2823 | ret = vmw_validation_add_bo(&val_ctx, vfbbo->buffer, false, | ||
| 2824 | update->cpu_blit); | ||
| 2825 | } else { | ||
| 2826 | struct vmw_framebuffer_surface *vfbs = | ||
| 2827 | container_of(update->vfb, typeof(*vfbs), base); | ||
| 2828 | |||
| 2829 | ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res, | ||
| 2830 | 0, NULL, NULL); | ||
| 2831 | } | ||
| 2832 | |||
| 2833 | if (ret) | ||
| 2834 | return ret; | ||
| 2835 | |||
| 2836 | ret = vmw_validation_prepare(&val_ctx, update->mutex, update->intr); | ||
| 2837 | if (ret) | ||
| 2838 | goto out_unref; | ||
| 2839 | |||
| 2840 | reserved_size = update->calc_fifo_size(update, num_hits); | ||
| 2841 | cmd_start = vmw_fifo_reserve(update->dev_priv, reserved_size); | ||
| 2842 | if (!cmd_start) { | ||
| 2843 | ret = -ENOMEM; | ||
| 2844 | goto out_revert; | ||
| 2845 | } | ||
| 2846 | |||
| 2847 | cmd_next = cmd_start; | ||
| 2848 | |||
| 2849 | if (update->post_prepare) { | ||
| 2850 | curr_size = update->post_prepare(update, cmd_next); | ||
| 2851 | cmd_next += curr_size; | ||
| 2852 | submit_size += curr_size; | ||
| 2853 | } | ||
| 2854 | |||
| 2855 | if (update->pre_clip) { | ||
| 2856 | curr_size = update->pre_clip(update, cmd_next, num_hits); | ||
| 2857 | cmd_next += curr_size; | ||
| 2858 | submit_size += curr_size; | ||
| 2859 | } | ||
| 2860 | |||
| 2861 | bb.x1 = INT_MAX; | ||
| 2862 | bb.y1 = INT_MAX; | ||
| 2863 | bb.x2 = INT_MIN; | ||
| 2864 | bb.y2 = INT_MIN; | ||
| 2865 | |||
| 2866 | drm_atomic_helper_damage_iter_init(&iter, old_state, state); | ||
| 2867 | drm_atomic_for_each_plane_damage(&iter, &clip) { | ||
| 2868 | uint32_t fb_x = clip.x1; | ||
| 2869 | uint32_t fb_y = clip.y1; | ||
| 2870 | |||
| 2871 | vmw_du_translate_to_crtc(state, &clip); | ||
| 2872 | if (update->clip) { | ||
| 2873 | curr_size = update->clip(update, cmd_next, &clip, fb_x, | ||
| 2874 | fb_y); | ||
| 2875 | cmd_next += curr_size; | ||
| 2876 | submit_size += curr_size; | ||
| 2877 | } | ||
| 2878 | bb.x1 = min_t(int, bb.x1, clip.x1); | ||
| 2879 | bb.y1 = min_t(int, bb.y1, clip.y1); | ||
| 2880 | bb.x2 = max_t(int, bb.x2, clip.x2); | ||
| 2881 | bb.y2 = max_t(int, bb.y2, clip.y2); | ||
| 2882 | } | ||
| 2883 | |||
| 2884 | curr_size = update->post_clip(update, cmd_next, &bb); | ||
| 2885 | submit_size += curr_size; | ||
| 2886 | |||
| 2887 | if (reserved_size < submit_size) | ||
| 2888 | submit_size = 0; | ||
| 2889 | |||
| 2890 | vmw_fifo_commit(update->dev_priv, submit_size); | ||
| 2891 | |||
| 2892 | vmw_kms_helper_validation_finish(update->dev_priv, NULL, &val_ctx, | ||
| 2893 | update->out_fence, NULL); | ||
| 2894 | return ret; | ||
| 2895 | |||
| 2896 | out_revert: | ||
| 2897 | vmw_validation_revert(&val_ctx); | ||
| 2898 | |||
| 2899 | out_unref: | ||
| 2900 | vmw_validation_unref_lists(&val_ctx); | ||
| 2901 | return ret; | ||
| 2902 | } | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 76ec570c0684..655abbcd4058 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | |||
| @@ -33,7 +33,123 @@ | |||
| 33 | #include <drm/drm_encoder.h> | 33 | #include <drm/drm_encoder.h> |
| 34 | #include "vmwgfx_drv.h" | 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); | ||
| 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 | }; | ||
| 36 | 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 | * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty | 155 | * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty |
| @@ -191,8 +307,6 @@ struct vmw_plane_state { | |||
| 191 | struct vmw_connector_state { | 307 | struct vmw_connector_state { |
| 192 | struct drm_connector_state base; | 308 | struct drm_connector_state base; |
| 193 | 309 | ||
| 194 | bool is_implicit; | ||
| 195 | |||
| 196 | /** | 310 | /** |
| 197 | * @gui_x: | 311 | * @gui_x: |
| 198 | * | 312 | * |
| @@ -254,7 +368,6 @@ struct vmw_display_unit { | |||
| 254 | int gui_x; | 368 | int gui_x; |
| 255 | int gui_y; | 369 | int gui_y; |
| 256 | bool is_implicit; | 370 | bool is_implicit; |
| 257 | bool active_implicit; | ||
| 258 | int set_gui_x; | 371 | int set_gui_x; |
| 259 | int set_gui_y; | 372 | int set_gui_y; |
| 260 | }; | 373 | }; |
| @@ -334,17 +447,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, | |||
| 334 | struct drm_crtc **p_crtc, | 447 | struct drm_crtc **p_crtc, |
| 335 | struct drm_display_mode **p_mode); | 448 | struct drm_display_mode **p_mode); |
| 336 | void vmw_guess_mode_timing(struct drm_display_mode *mode); | 449 | void vmw_guess_mode_timing(struct drm_display_mode *mode); |
| 337 | void vmw_kms_del_active(struct vmw_private *dev_priv, | 450 | void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv); |
| 338 | struct vmw_display_unit *du); | 451 | void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); |
| 339 | void vmw_kms_add_active(struct vmw_private *dev_priv, | ||
| 340 | struct vmw_display_unit *du, | ||
| 341 | struct vmw_framebuffer *vfb); | ||
| 342 | bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, | ||
| 343 | struct drm_crtc *crtc); | ||
| 344 | void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, | ||
| 345 | struct drm_crtc *crtc); | ||
| 346 | void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, | ||
| 347 | bool immutable); | ||
| 348 | 452 | ||
| 349 | /* Universal Plane Helpers */ | 453 | /* Universal Plane Helpers */ |
| 350 | void vmw_du_primary_plane_destroy(struct drm_plane *plane); | 454 | void vmw_du_primary_plane_destroy(struct drm_plane *plane); |
| @@ -456,6 +560,20 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, | |||
| 456 | bool interruptible, | 560 | bool interruptible, |
| 457 | struct drm_crtc *crtc); | 561 | struct drm_crtc *crtc); |
| 458 | 562 | ||
| 459 | int vmw_kms_set_config(struct drm_mode_set *set, | 563 | int vmw_du_helper_plane_update(struct vmw_du_update_plane *update); |
| 460 | struct drm_modeset_acquire_ctx *ctx); | 564 | |
| 565 | /** | ||
| 566 | * vmw_du_translate_to_crtc - Translate a rect from framebuffer to crtc | ||
| 567 | * @state: Plane state. | ||
| 568 | * @r: Rectangle to translate. | ||
| 569 | */ | ||
| 570 | static inline void vmw_du_translate_to_crtc(struct drm_plane_state *state, | ||
| 571 | struct drm_rect *r) | ||
| 572 | { | ||
| 573 | int translate_crtc_x = -((state->src_x >> 16) - state->crtc_x); | ||
| 574 | int translate_crtc_y = -((state->src_y >> 16) - state->crtc_y); | ||
| 575 | |||
| 576 | drm_rect_translate(r, translate_crtc_x, translate_crtc_y); | ||
| 577 | } | ||
| 578 | |||
| 461 | #endif | 579 | #endif |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 4b5378495eea..16be515c4c0f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | |||
| @@ -233,7 +233,7 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = { | |||
| 233 | .reset = vmw_du_crtc_reset, | 233 | .reset = vmw_du_crtc_reset, |
| 234 | .atomic_duplicate_state = vmw_du_crtc_duplicate_state, | 234 | .atomic_duplicate_state = vmw_du_crtc_duplicate_state, |
| 235 | .atomic_destroy_state = vmw_du_crtc_destroy_state, | 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,13 +263,10 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = { | |||
| 263 | .dpms = vmw_du_connector_dpms, | 263 | .dpms = vmw_du_connector_dpms, |
| 264 | .detect = vmw_du_connector_detect, | 264 | .detect = vmw_du_connector_detect, |
| 265 | .fill_modes = vmw_du_connector_fill_modes, | 265 | .fill_modes = vmw_du_connector_fill_modes, |
| 266 | .set_property = vmw_du_connector_set_property, | ||
| 267 | .destroy = vmw_ldu_connector_destroy, | 266 | .destroy = vmw_ldu_connector_destroy, |
| 268 | .reset = vmw_du_connector_reset, | 267 | .reset = vmw_du_connector_reset, |
| 269 | .atomic_duplicate_state = vmw_du_connector_duplicate_state, | 268 | .atomic_duplicate_state = vmw_du_connector_duplicate_state, |
| 270 | .atomic_destroy_state = vmw_du_connector_destroy_state, | 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 | static const struct | 272 | static const struct |
| @@ -416,7 +413,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 416 | 413 | ||
| 417 | drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); | 414 | drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); |
| 418 | 415 | ||
| 419 | |||
| 420 | vmw_du_connector_reset(connector); | 416 | vmw_du_connector_reset(connector); |
| 421 | ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, | 417 | ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, |
| 422 | DRM_MODE_CONNECTOR_VIRTUAL); | 418 | DRM_MODE_CONNECTOR_VIRTUAL); |
| @@ -427,8 +423,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 427 | 423 | ||
| 428 | drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs); | 424 | drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs); |
| 429 | connector->status = vmw_du_connector_detect(connector, true); | 425 | connector->status = vmw_du_connector_detect(connector, true); |
| 430 | vmw_connector_state_to_vcs(connector->state)->is_implicit = true; | ||
| 431 | |||
| 432 | 426 | ||
| 433 | ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, | 427 | ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, |
| 434 | DRM_MODE_ENCODER_VIRTUAL, NULL); | 428 | DRM_MODE_ENCODER_VIRTUAL, NULL); |
| @@ -447,7 +441,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 447 | goto err_free_encoder; | 441 | goto err_free_encoder; |
| 448 | } | 442 | } |
| 449 | 443 | ||
| 450 | |||
| 451 | vmw_du_crtc_reset(crtc); | 444 | vmw_du_crtc_reset(crtc); |
| 452 | ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary, | 445 | ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary, |
| 453 | &ldu->base.cursor, | 446 | &ldu->base.cursor, |
| @@ -513,7 +506,7 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) | |||
| 513 | if (ret != 0) | 506 | if (ret != 0) |
| 514 | goto err_free; | 507 | goto err_free; |
| 515 | 508 | ||
| 516 | vmw_kms_create_implicit_placement_property(dev_priv, true); | 509 | vmw_kms_create_implicit_placement_property(dev_priv); |
| 517 | 510 | ||
| 518 | if (dev_priv->capabilities & SVGA_CAP_MULTIMON) | 511 | if (dev_priv->capabilities & SVGA_CAP_MULTIMON) |
| 519 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) | 512 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 333418dc259f..cd586c52af7e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <drm/drm_plane_helper.h> | 29 | #include <drm/drm_plane_helper.h> |
| 30 | #include <drm/drm_atomic.h> | 30 | #include <drm/drm_atomic.h> |
| 31 | #include <drm/drm_atomic_helper.h> | 31 | #include <drm/drm_atomic_helper.h> |
| 32 | #include <drm/drm_damage_helper.h> | ||
| 32 | 33 | ||
| 33 | 34 | ||
| 34 | #define vmw_crtc_to_sou(x) \ | 35 | #define vmw_crtc_to_sou(x) \ |
| @@ -76,6 +77,11 @@ struct vmw_kms_sou_dirty_cmd { | |||
| 76 | SVGA3dCmdBlitSurfaceToScreen body; | 77 | SVGA3dCmdBlitSurfaceToScreen body; |
| 77 | }; | 78 | }; |
| 78 | 79 | ||
| 80 | struct vmw_kms_sou_define_gmrfb { | ||
| 81 | uint32_t header; | ||
| 82 | SVGAFifoCmdDefineGMRFB body; | ||
| 83 | }; | ||
| 84 | |||
| 79 | /** | 85 | /** |
| 80 | * Display unit using screen objects. | 86 | * Display unit using screen objects. |
| 81 | */ | 87 | */ |
| @@ -241,28 +247,20 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
| 241 | sou->buffer = vps->bo; | 247 | sou->buffer = vps->bo; |
| 242 | sou->buffer_size = vps->bo_size; | 248 | sou->buffer_size = vps->bo_size; |
| 243 | 249 | ||
| 244 | if (sou->base.is_implicit) { | 250 | conn_state = sou->base.connector.state; |
| 245 | x = crtc->x; | 251 | vmw_conn_state = vmw_connector_state_to_vcs(conn_state); |
| 246 | y = crtc->y; | ||
| 247 | } else { | ||
| 248 | conn_state = sou->base.connector.state; | ||
| 249 | vmw_conn_state = vmw_connector_state_to_vcs(conn_state); | ||
| 250 | 252 | ||
| 251 | x = vmw_conn_state->gui_x; | 253 | x = vmw_conn_state->gui_x; |
| 252 | y = vmw_conn_state->gui_y; | 254 | y = vmw_conn_state->gui_y; |
| 253 | } | ||
| 254 | 255 | ||
| 255 | ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); | 256 | ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); |
| 256 | if (ret) | 257 | if (ret) |
| 257 | DRM_ERROR("Failed to define Screen Object %dx%d\n", | 258 | DRM_ERROR("Failed to define Screen Object %dx%d\n", |
| 258 | crtc->x, crtc->y); | 259 | crtc->x, crtc->y); |
| 259 | 260 | ||
| 260 | vmw_kms_add_active(dev_priv, &sou->base, vfb); | ||
| 261 | } else { | 261 | } else { |
| 262 | sou->buffer = NULL; | 262 | sou->buffer = NULL; |
| 263 | sou->buffer_size = 0; | 263 | sou->buffer_size = 0; |
| 264 | |||
| 265 | vmw_kms_del_active(dev_priv, &sou->base); | ||
| 266 | } | 264 | } |
| 267 | } | 265 | } |
| 268 | 266 | ||
| @@ -317,38 +315,14 @@ static void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc, | |||
| 317 | } | 315 | } |
| 318 | } | 316 | } |
| 319 | 317 | ||
| 320 | static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, | ||
| 321 | struct drm_framebuffer *new_fb, | ||
| 322 | struct drm_pending_vblank_event *event, | ||
| 323 | uint32_t flags, | ||
| 324 | struct drm_modeset_acquire_ctx *ctx) | ||
| 325 | { | ||
| 326 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); | ||
| 327 | int ret; | ||
| 328 | |||
| 329 | if (!vmw_kms_crtc_flippable(dev_priv, crtc)) | ||
| 330 | return -EINVAL; | ||
| 331 | |||
| 332 | ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); | ||
| 333 | if (ret) { | ||
| 334 | DRM_ERROR("Page flip error %d.\n", ret); | ||
| 335 | return ret; | ||
| 336 | } | ||
| 337 | |||
| 338 | if (vmw_crtc_to_du(crtc)->is_implicit) | ||
| 339 | vmw_kms_update_implicit_fb(dev_priv, crtc); | ||
| 340 | |||
| 341 | return ret; | ||
| 342 | } | ||
| 343 | |||
| 344 | static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { | 318 | static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { |
| 345 | .gamma_set = vmw_du_crtc_gamma_set, | 319 | .gamma_set = vmw_du_crtc_gamma_set, |
| 346 | .destroy = vmw_sou_crtc_destroy, | 320 | .destroy = vmw_sou_crtc_destroy, |
| 347 | .reset = vmw_du_crtc_reset, | 321 | .reset = vmw_du_crtc_reset, |
| 348 | .atomic_duplicate_state = vmw_du_crtc_duplicate_state, | 322 | .atomic_duplicate_state = vmw_du_crtc_duplicate_state, |
| 349 | .atomic_destroy_state = vmw_du_crtc_destroy_state, | 323 | .atomic_destroy_state = vmw_du_crtc_destroy_state, |
| 350 | .set_config = vmw_kms_set_config, | 324 | .set_config = drm_atomic_helper_set_config, |
| 351 | .page_flip = vmw_sou_crtc_page_flip, | 325 | .page_flip = drm_atomic_helper_page_flip, |
| 352 | }; | 326 | }; |
| 353 | 327 | ||
| 354 | /* | 328 | /* |
| @@ -377,13 +351,10 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = { | |||
| 377 | .dpms = vmw_du_connector_dpms, | 351 | .dpms = vmw_du_connector_dpms, |
| 378 | .detect = vmw_du_connector_detect, | 352 | .detect = vmw_du_connector_detect, |
| 379 | .fill_modes = vmw_du_connector_fill_modes, | 353 | .fill_modes = vmw_du_connector_fill_modes, |
| 380 | .set_property = vmw_du_connector_set_property, | ||
| 381 | .destroy = vmw_sou_connector_destroy, | 354 | .destroy = vmw_sou_connector_destroy, |
| 382 | .reset = vmw_du_connector_reset, | 355 | .reset = vmw_du_connector_reset, |
| 383 | .atomic_duplicate_state = vmw_du_connector_duplicate_state, | 356 | .atomic_duplicate_state = vmw_du_connector_duplicate_state, |
| 384 | .atomic_destroy_state = vmw_du_connector_destroy_state, | 357 | .atomic_destroy_state = vmw_du_connector_destroy_state, |
| 385 | .atomic_set_property = vmw_du_connector_atomic_set_property, | ||
| 386 | .atomic_get_property = vmw_du_connector_atomic_get_property, | ||
| 387 | }; | 358 | }; |
| 388 | 359 | ||
| 389 | 360 | ||
| @@ -498,6 +469,263 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, | |||
| 498 | return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); | 469 | return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); |
| 499 | } | 470 | } |
| 500 | 471 | ||
| 472 | static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update, | ||
| 473 | uint32_t num_hits) | ||
| 474 | { | ||
| 475 | return sizeof(struct vmw_kms_sou_define_gmrfb) + | ||
| 476 | sizeof(struct vmw_kms_sou_bo_blit) * num_hits; | ||
| 477 | } | ||
| 478 | |||
| 479 | static uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update, | ||
| 480 | void *cmd) | ||
| 481 | { | ||
| 482 | struct vmw_framebuffer_bo *vfbbo = | ||
| 483 | container_of(update->vfb, typeof(*vfbbo), base); | ||
| 484 | struct vmw_kms_sou_define_gmrfb *gmr = cmd; | ||
| 485 | int depth = update->vfb->base.format->depth; | ||
| 486 | |||
| 487 | /* Emulate RGBA support, contrary to svga_reg.h this is not | ||
| 488 | * supported by hosts. This is only a problem if we are reading | ||
| 489 | * this value later and expecting what we uploaded back. | ||
| 490 | */ | ||
| 491 | if (depth == 32) | ||
| 492 | depth = 24; | ||
| 493 | |||
| 494 | gmr->header = SVGA_CMD_DEFINE_GMRFB; | ||
| 495 | |||
| 496 | gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8; | ||
| 497 | gmr->body.format.colorDepth = depth; | ||
| 498 | gmr->body.format.reserved = 0; | ||
| 499 | gmr->body.bytesPerLine = update->vfb->base.pitches[0]; | ||
| 500 | vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &gmr->body.ptr); | ||
| 501 | |||
| 502 | return sizeof(*gmr); | ||
| 503 | } | ||
| 504 | |||
| 505 | static uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane *update, | ||
| 506 | void *cmd, struct drm_rect *clip, | ||
| 507 | uint32_t fb_x, uint32_t fb_y) | ||
| 508 | { | ||
| 509 | struct vmw_kms_sou_bo_blit *blit = cmd; | ||
| 510 | |||
| 511 | blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; | ||
| 512 | blit->body.destScreenId = update->du->unit; | ||
| 513 | blit->body.srcOrigin.x = fb_x; | ||
| 514 | blit->body.srcOrigin.y = fb_y; | ||
| 515 | blit->body.destRect.left = clip->x1; | ||
| 516 | blit->body.destRect.top = clip->y1; | ||
| 517 | blit->body.destRect.right = clip->x2; | ||
| 518 | blit->body.destRect.bottom = clip->y2; | ||
| 519 | |||
| 520 | return sizeof(*blit); | ||
| 521 | } | ||
| 522 | |||
| 523 | static uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane *update, | ||
| 524 | void *cmd, struct drm_rect *bb) | ||
| 525 | { | ||
| 526 | return 0; | ||
| 527 | } | ||
| 528 | |||
| 529 | /** | ||
| 530 | * vmw_sou_plane_update_bo - Update display unit for bo backed fb. | ||
| 531 | * @dev_priv: Device private. | ||
| 532 | * @plane: Plane state. | ||
| 533 | * @old_state: Old plane state. | ||
| 534 | * @vfb: Framebuffer which is blitted to display unit. | ||
| 535 | * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. | ||
| 536 | * The returned fence pointer may be NULL in which case the device | ||
| 537 | * has already synchronized. | ||
| 538 | * | ||
| 539 | * Return: 0 on success or a negative error code on failure. | ||
| 540 | */ | ||
| 541 | static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv, | ||
| 542 | struct drm_plane *plane, | ||
| 543 | struct drm_plane_state *old_state, | ||
| 544 | struct vmw_framebuffer *vfb, | ||
| 545 | struct vmw_fence_obj **out_fence) | ||
| 546 | { | ||
| 547 | struct vmw_du_update_plane_buffer bo_update; | ||
| 548 | |||
| 549 | memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); | ||
| 550 | bo_update.base.plane = plane; | ||
| 551 | bo_update.base.old_state = old_state; | ||
| 552 | bo_update.base.dev_priv = dev_priv; | ||
| 553 | bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); | ||
| 554 | bo_update.base.vfb = vfb; | ||
| 555 | bo_update.base.out_fence = out_fence; | ||
| 556 | bo_update.base.mutex = NULL; | ||
| 557 | bo_update.base.cpu_blit = false; | ||
| 558 | bo_update.base.intr = true; | ||
| 559 | |||
| 560 | bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size; | ||
| 561 | bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb; | ||
| 562 | bo_update.base.clip = vmw_sou_bo_populate_clip; | ||
| 563 | bo_update.base.post_clip = vmw_stud_bo_post_clip; | ||
| 564 | |||
| 565 | return vmw_du_helper_plane_update(&bo_update.base); | ||
| 566 | } | ||
| 567 | |||
| 568 | static uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update, | ||
| 569 | uint32_t num_hits) | ||
| 570 | { | ||
| 571 | return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) * | ||
| 572 | num_hits; | ||
| 573 | } | ||
| 574 | |||
| 575 | static uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update, | ||
| 576 | void *cmd) | ||
| 577 | { | ||
| 578 | struct vmw_du_update_plane_surface *srf_update; | ||
| 579 | |||
| 580 | srf_update = container_of(update, typeof(*srf_update), base); | ||
| 581 | |||
| 582 | /* | ||
| 583 | * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that | ||
| 584 | * its bounding box is filled before iterating over all the clips. So | ||
| 585 | * store the FIFO start address and revisit to fill the details. | ||
| 586 | */ | ||
| 587 | srf_update->cmd_start = cmd; | ||
| 588 | |||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 592 | static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update, | ||
| 593 | void *cmd, uint32_t num_hits) | ||
| 594 | { | ||
| 595 | struct vmw_kms_sou_dirty_cmd *blit = cmd; | ||
| 596 | struct vmw_framebuffer_surface *vfbs; | ||
| 597 | |||
| 598 | vfbs = container_of(update->vfb, typeof(*vfbs), base); | ||
| 599 | |||
| 600 | blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; | ||
| 601 | blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) * | ||
| 602 | num_hits; | ||
| 603 | |||
| 604 | blit->body.srcImage.sid = vfbs->surface->res.id; | ||
| 605 | blit->body.destScreenId = update->du->unit; | ||
| 606 | |||
| 607 | /* Update the source and destination bounding box later in post_clip */ | ||
| 608 | blit->body.srcRect.left = 0; | ||
| 609 | blit->body.srcRect.top = 0; | ||
| 610 | blit->body.srcRect.right = 0; | ||
| 611 | blit->body.srcRect.bottom = 0; | ||
| 612 | |||
| 613 | blit->body.destRect.left = 0; | ||
| 614 | blit->body.destRect.top = 0; | ||
| 615 | blit->body.destRect.right = 0; | ||
| 616 | blit->body.destRect.bottom = 0; | ||
| 617 | |||
| 618 | return sizeof(*blit); | ||
| 619 | } | ||
| 620 | |||
| 621 | static uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update, | ||
| 622 | void *cmd, struct drm_rect *clip, | ||
| 623 | uint32_t src_x, uint32_t src_y) | ||
| 624 | { | ||
| 625 | SVGASignedRect *rect = cmd; | ||
| 626 | |||
| 627 | /* | ||
| 628 | * rects are relative to dest bounding box rect on screen object, so | ||
| 629 | * translate to it later in post_clip | ||
| 630 | */ | ||
| 631 | rect->left = clip->x1; | ||
| 632 | rect->top = clip->y1; | ||
| 633 | rect->right = clip->x2; | ||
| 634 | rect->bottom = clip->y2; | ||
| 635 | |||
| 636 | return sizeof(*rect); | ||
| 637 | } | ||
| 638 | |||
| 639 | static uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update, | ||
| 640 | void *cmd, struct drm_rect *bb) | ||
| 641 | { | ||
| 642 | struct vmw_du_update_plane_surface *srf_update; | ||
| 643 | struct drm_plane_state *state = update->plane->state; | ||
| 644 | struct drm_rect src_bb; | ||
| 645 | struct vmw_kms_sou_dirty_cmd *blit; | ||
| 646 | SVGASignedRect *rect; | ||
| 647 | uint32_t num_hits; | ||
| 648 | int translate_src_x; | ||
| 649 | int translate_src_y; | ||
| 650 | int i; | ||
| 651 | |||
| 652 | srf_update = container_of(update, typeof(*srf_update), base); | ||
| 653 | |||
| 654 | blit = srf_update->cmd_start; | ||
| 655 | rect = (SVGASignedRect *)&blit[1]; | ||
| 656 | |||
| 657 | num_hits = (blit->header.size - sizeof(blit->body))/ | ||
| 658 | sizeof(SVGASignedRect); | ||
| 659 | |||
| 660 | src_bb = *bb; | ||
| 661 | |||
| 662 | /* To translate bb back to fb src coord */ | ||
| 663 | translate_src_x = (state->src_x >> 16) - state->crtc_x; | ||
| 664 | translate_src_y = (state->src_y >> 16) - state->crtc_y; | ||
| 665 | |||
| 666 | drm_rect_translate(&src_bb, translate_src_x, translate_src_y); | ||
| 667 | |||
| 668 | blit->body.srcRect.left = src_bb.x1; | ||
| 669 | blit->body.srcRect.top = src_bb.y1; | ||
| 670 | blit->body.srcRect.right = src_bb.x2; | ||
| 671 | blit->body.srcRect.bottom = src_bb.y2; | ||
| 672 | |||
| 673 | blit->body.destRect.left = bb->x1; | ||
| 674 | blit->body.destRect.top = bb->y1; | ||
| 675 | blit->body.destRect.right = bb->x2; | ||
| 676 | blit->body.destRect.bottom = bb->y2; | ||
| 677 | |||
| 678 | /* rects are relative to dest bb rect */ | ||
| 679 | for (i = 0; i < num_hits; i++) { | ||
| 680 | rect->left -= bb->x1; | ||
| 681 | rect->top -= bb->y1; | ||
| 682 | rect->right -= bb->x1; | ||
| 683 | rect->bottom -= bb->y1; | ||
| 684 | rect++; | ||
| 685 | } | ||
| 686 | |||
| 687 | return 0; | ||
| 688 | } | ||
| 689 | |||
| 690 | /** | ||
| 691 | * vmw_sou_plane_update_surface - Update display unit for surface backed fb. | ||
| 692 | * @dev_priv: Device private. | ||
| 693 | * @plane: Plane state. | ||
| 694 | * @old_state: Old plane state. | ||
| 695 | * @vfb: Framebuffer which is blitted to display unit | ||
| 696 | * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. | ||
| 697 | * The returned fence pointer may be NULL in which case the device | ||
| 698 | * has already synchronized. | ||
| 699 | * | ||
| 700 | * Return: 0 on success or a negative error code on failure. | ||
| 701 | */ | ||
| 702 | static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv, | ||
| 703 | struct drm_plane *plane, | ||
| 704 | struct drm_plane_state *old_state, | ||
| 705 | struct vmw_framebuffer *vfb, | ||
| 706 | struct vmw_fence_obj **out_fence) | ||
| 707 | { | ||
| 708 | struct vmw_du_update_plane_surface srf_update; | ||
| 709 | |||
| 710 | memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface)); | ||
| 711 | srf_update.base.plane = plane; | ||
| 712 | srf_update.base.old_state = old_state; | ||
| 713 | srf_update.base.dev_priv = dev_priv; | ||
| 714 | srf_update.base.du = vmw_crtc_to_du(plane->state->crtc); | ||
| 715 | srf_update.base.vfb = vfb; | ||
| 716 | srf_update.base.out_fence = out_fence; | ||
| 717 | srf_update.base.mutex = &dev_priv->cmdbuf_mutex; | ||
| 718 | srf_update.base.cpu_blit = false; | ||
| 719 | srf_update.base.intr = true; | ||
| 720 | |||
| 721 | srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size; | ||
| 722 | srf_update.base.post_prepare = vmw_sou_surface_post_prepare; | ||
| 723 | srf_update.base.pre_clip = vmw_sou_surface_pre_clip; | ||
| 724 | srf_update.base.clip = vmw_sou_surface_clip_rect; | ||
| 725 | srf_update.base.post_clip = vmw_sou_surface_post_clip; | ||
| 726 | |||
| 727 | return vmw_du_helper_plane_update(&srf_update.base); | ||
| 728 | } | ||
| 501 | 729 | ||
| 502 | static void | 730 | static void |
| 503 | vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, | 731 | vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, |
| @@ -508,47 +736,28 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, | |||
| 508 | struct vmw_fence_obj *fence = NULL; | 736 | struct vmw_fence_obj *fence = NULL; |
| 509 | int ret; | 737 | int ret; |
| 510 | 738 | ||
| 739 | /* In case of device error, maintain consistent atomic state */ | ||
| 511 | if (crtc && plane->state->fb) { | 740 | if (crtc && plane->state->fb) { |
| 512 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); | 741 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
| 513 | struct vmw_framebuffer *vfb = | 742 | struct vmw_framebuffer *vfb = |
| 514 | vmw_framebuffer_to_vfb(plane->state->fb); | 743 | vmw_framebuffer_to_vfb(plane->state->fb); |
| 515 | struct drm_vmw_rect vclips; | ||
| 516 | |||
| 517 | vclips.x = crtc->x; | ||
| 518 | vclips.y = crtc->y; | ||
| 519 | vclips.w = crtc->mode.hdisplay; | ||
| 520 | vclips.h = crtc->mode.vdisplay; | ||
| 521 | 744 | ||
| 522 | if (vfb->bo) | 745 | if (vfb->bo) |
| 523 | ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL, | 746 | ret = vmw_sou_plane_update_bo(dev_priv, plane, |
| 524 | &vclips, 1, 1, true, | 747 | old_state, vfb, &fence); |
| 525 | &fence, crtc); | ||
| 526 | else | 748 | else |
| 527 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, | 749 | ret = vmw_sou_plane_update_surface(dev_priv, plane, |
| 528 | &vclips, NULL, 0, 0, | 750 | old_state, vfb, |
| 529 | 1, 1, &fence, crtc); | 751 | &fence); |
| 530 | |||
| 531 | /* | ||
| 532 | * We cannot really fail this function, so if we do, then output | ||
| 533 | * an error and maintain consistent atomic state. | ||
| 534 | */ | ||
| 535 | if (ret != 0) | 752 | if (ret != 0) |
| 536 | DRM_ERROR("Failed to update screen.\n"); | 753 | DRM_ERROR("Failed to update screen.\n"); |
| 537 | } else { | 754 | } else { |
| 538 | /* | 755 | /* Do nothing when fb and crtc is NULL (blank crtc) */ |
| 539 | * When disabling a plane, CRTC and FB should always be NULL | ||
| 540 | * together, otherwise it's an error. | ||
| 541 | * Here primary plane is being disable so should really blank | ||
| 542 | * the screen object display unit, if not already done. | ||
| 543 | */ | ||
| 544 | return; | 756 | return; |
| 545 | } | 757 | } |
| 546 | 758 | ||
| 759 | /* For error case vblank event is send from vmw_du_crtc_atomic_flush */ | ||
| 547 | event = crtc->state->event; | 760 | event = crtc->state->event; |
| 548 | /* | ||
| 549 | * In case of failure and other cases, vblank event will be sent in | ||
| 550 | * vmw_du_crtc_atomic_flush. | ||
| 551 | */ | ||
| 552 | if (event && fence) { | 761 | if (event && fence) { |
| 553 | struct drm_file *file_priv = event->base.file_priv; | 762 | struct drm_file *file_priv = event->base.file_priv; |
| 554 | 763 | ||
| @@ -639,7 +848,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 639 | primary = &sou->base.primary; | 848 | primary = &sou->base.primary; |
| 640 | cursor = &sou->base.cursor; | 849 | cursor = &sou->base.cursor; |
| 641 | 850 | ||
| 642 | sou->base.active_implicit = false; | ||
| 643 | sou->base.pref_active = (unit == 0); | 851 | sou->base.pref_active = (unit == 0); |
| 644 | sou->base.pref_width = dev_priv->initial_width; | 852 | sou->base.pref_width = dev_priv->initial_width; |
| 645 | sou->base.pref_height = dev_priv->initial_height; | 853 | sou->base.pref_height = dev_priv->initial_height; |
| @@ -665,6 +873,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 665 | } | 873 | } |
| 666 | 874 | ||
| 667 | drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); | 875 | drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); |
| 876 | drm_plane_enable_fb_damage_clips(primary); | ||
| 668 | 877 | ||
| 669 | /* Initialize cursor plane */ | 878 | /* Initialize cursor plane */ |
| 670 | vmw_du_plane_reset(cursor); | 879 | vmw_du_plane_reset(cursor); |
| @@ -692,8 +901,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 692 | 901 | ||
| 693 | drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); | 902 | drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); |
| 694 | connector->status = vmw_du_connector_detect(connector, true); | 903 | connector->status = vmw_du_connector_detect(connector, true); |
| 695 | vmw_connector_state_to_vcs(connector->state)->is_implicit = false; | ||
| 696 | |||
| 697 | 904 | ||
| 698 | ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, | 905 | ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, |
| 699 | DRM_MODE_ENCODER_VIRTUAL, NULL); | 906 | DRM_MODE_ENCODER_VIRTUAL, NULL); |
| @@ -732,12 +939,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 732 | dev->mode_config.suggested_x_property, 0); | 939 | dev->mode_config.suggested_x_property, 0); |
| 733 | drm_object_attach_property(&connector->base, | 940 | drm_object_attach_property(&connector->base, |
| 734 | dev->mode_config.suggested_y_property, 0); | 941 | dev->mode_config.suggested_y_property, 0); |
| 735 | if (dev_priv->implicit_placement_property) | ||
| 736 | drm_object_attach_property | ||
| 737 | (&connector->base, | ||
| 738 | dev_priv->implicit_placement_property, | ||
| 739 | sou->base.is_implicit); | ||
| 740 | |||
| 741 | return 0; | 942 | return 0; |
| 742 | 943 | ||
| 743 | err_free_unregister: | 944 | err_free_unregister: |
| @@ -763,15 +964,11 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) | |||
| 763 | } | 964 | } |
| 764 | 965 | ||
| 765 | ret = -ENOMEM; | 966 | ret = -ENOMEM; |
| 766 | dev_priv->num_implicit = 0; | ||
| 767 | dev_priv->implicit_fb = NULL; | ||
| 768 | 967 | ||
| 769 | ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); | 968 | ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); |
| 770 | if (unlikely(ret != 0)) | 969 | if (unlikely(ret != 0)) |
| 771 | return ret; | 970 | return ret; |
| 772 | 971 | ||
| 773 | vmw_kms_create_implicit_placement_property(dev_priv, false); | ||
| 774 | |||
| 775 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) | 972 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) |
| 776 | vmw_sou_init(dev_priv, i); | 973 | vmw_sou_init(dev_priv, i); |
| 777 | 974 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index c3e435f444c1..096c2941a8e4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | #include <drm/drm_plane_helper.h> | 30 | #include <drm/drm_plane_helper.h> |
| 31 | #include <drm/drm_atomic.h> | 31 | #include <drm/drm_atomic.h> |
| 32 | #include <drm/drm_atomic_helper.h> | 32 | #include <drm/drm_atomic_helper.h> |
| 33 | 33 | #include <drm/drm_damage_helper.h> | |
| 34 | 34 | ||
| 35 | #define vmw_crtc_to_stdu(x) \ | 35 | #define vmw_crtc_to_stdu(x) \ |
| 36 | container_of(x, struct vmw_screen_target_display_unit, base.crtc) | 36 | container_of(x, struct vmw_screen_target_display_unit, base.crtc) |
| @@ -92,6 +92,10 @@ struct vmw_stdu_surface_copy { | |||
| 92 | SVGA3dCmdSurfaceCopy body; | 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 | * struct vmw_screen_target_display_unit | 101 | * struct vmw_screen_target_display_unit |
| @@ -396,13 +400,8 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
| 396 | if (!crtc->state->enable) | 400 | if (!crtc->state->enable) |
| 397 | return; | 401 | return; |
| 398 | 402 | ||
| 399 | if (stdu->base.is_implicit) { | 403 | x = vmw_conn_state->gui_x; |
| 400 | x = crtc->x; | 404 | y = vmw_conn_state->gui_y; |
| 401 | y = crtc->y; | ||
| 402 | } else { | ||
| 403 | x = vmw_conn_state->gui_x; | ||
| 404 | y = vmw_conn_state->gui_y; | ||
| 405 | } | ||
| 406 | 405 | ||
| 407 | vmw_svga_enable(dev_priv); | 406 | vmw_svga_enable(dev_priv); |
| 408 | ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); | 407 | ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); |
| @@ -417,27 +416,9 @@ static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc) | |||
| 417 | { | 416 | { |
| 418 | } | 417 | } |
| 419 | 418 | ||
| 420 | |||
| 421 | static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, | 419 | static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, |
| 422 | struct drm_crtc_state *old_state) | 420 | struct drm_crtc_state *old_state) |
| 423 | { | 421 | { |
| 424 | struct drm_plane_state *plane_state = crtc->primary->state; | ||
| 425 | struct vmw_private *dev_priv; | ||
| 426 | struct vmw_screen_target_display_unit *stdu; | ||
| 427 | struct vmw_framebuffer *vfb; | ||
| 428 | struct drm_framebuffer *fb; | ||
| 429 | |||
| 430 | |||
| 431 | stdu = vmw_crtc_to_stdu(crtc); | ||
| 432 | dev_priv = vmw_priv(crtc->dev); | ||
| 433 | fb = plane_state->fb; | ||
| 434 | |||
| 435 | vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; | ||
| 436 | |||
| 437 | if (vfb) | ||
| 438 | vmw_kms_add_active(dev_priv, &stdu->base, vfb); | ||
| 439 | else | ||
| 440 | vmw_kms_del_active(dev_priv, &stdu->base); | ||
| 441 | } | 422 | } |
| 442 | 423 | ||
| 443 | static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, | 424 | static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, |
| @@ -472,49 +453,6 @@ static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, | |||
| 472 | } | 453 | } |
| 473 | 454 | ||
| 474 | /** | 455 | /** |
| 475 | * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target | ||
| 476 | * | ||
| 477 | * @crtc: CRTC to attach FB to | ||
| 478 | * @fb: FB to attach | ||
| 479 | * @event: Event to be posted. This event should've been alloced | ||
| 480 | * using k[mz]alloc, and should've been completely initialized. | ||
| 481 | * @page_flip_flags: Input flags. | ||
| 482 | * | ||
| 483 | * If the STDU uses the same display and content buffers, i.e. a true flip, | ||
| 484 | * this function will replace the existing display buffer with the new content | ||
| 485 | * buffer. | ||
| 486 | * | ||
| 487 | * If the STDU uses different display and content buffers, i.e. a blit, then | ||
| 488 | * only the content buffer will be updated. | ||
| 489 | * | ||
| 490 | * RETURNS: | ||
| 491 | * 0 on success, error code on failure | ||
| 492 | */ | ||
| 493 | static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, | ||
| 494 | struct drm_framebuffer *new_fb, | ||
| 495 | struct drm_pending_vblank_event *event, | ||
| 496 | uint32_t flags, | ||
| 497 | struct drm_modeset_acquire_ctx *ctx) | ||
| 498 | |||
| 499 | { | ||
| 500 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); | ||
| 501 | struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); | ||
| 502 | int ret; | ||
| 503 | |||
| 504 | if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) | ||
| 505 | return -EINVAL; | ||
| 506 | |||
| 507 | ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); | ||
| 508 | if (ret) { | ||
| 509 | DRM_ERROR("Page flip error %d.\n", ret); | ||
| 510 | return ret; | ||
| 511 | } | ||
| 512 | |||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | |||
| 516 | |||
| 517 | /** | ||
| 518 | * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect | 456 | * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect |
| 519 | * | 457 | * |
| 520 | * @dirty: The closure structure. | 458 | * @dirty: The closure structure. |
| @@ -986,8 +924,8 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = { | |||
| 986 | .reset = vmw_du_crtc_reset, | 924 | .reset = vmw_du_crtc_reset, |
| 987 | .atomic_duplicate_state = vmw_du_crtc_duplicate_state, | 925 | .atomic_duplicate_state = vmw_du_crtc_duplicate_state, |
| 988 | .atomic_destroy_state = vmw_du_crtc_destroy_state, | 926 | .atomic_destroy_state = vmw_du_crtc_destroy_state, |
| 989 | .set_config = vmw_kms_set_config, | 927 | .set_config = drm_atomic_helper_set_config, |
| 990 | .page_flip = vmw_stdu_crtc_page_flip, | 928 | .page_flip = drm_atomic_helper_page_flip, |
| 991 | }; | 929 | }; |
| 992 | 930 | ||
| 993 | 931 | ||
| @@ -1042,13 +980,10 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = { | |||
| 1042 | .dpms = vmw_du_connector_dpms, | 980 | .dpms = vmw_du_connector_dpms, |
| 1043 | .detect = vmw_du_connector_detect, | 981 | .detect = vmw_du_connector_detect, |
| 1044 | .fill_modes = vmw_du_connector_fill_modes, | 982 | .fill_modes = vmw_du_connector_fill_modes, |
| 1045 | .set_property = vmw_du_connector_set_property, | ||
| 1046 | .destroy = vmw_stdu_connector_destroy, | 983 | .destroy = vmw_stdu_connector_destroy, |
| 1047 | .reset = vmw_du_connector_reset, | 984 | .reset = vmw_du_connector_reset, |
| 1048 | .atomic_duplicate_state = vmw_du_connector_duplicate_state, | 985 | .atomic_duplicate_state = vmw_du_connector_duplicate_state, |
| 1049 | .atomic_destroy_state = vmw_du_connector_destroy_state, | 986 | .atomic_destroy_state = vmw_du_connector_destroy_state, |
| 1050 | .atomic_set_property = vmw_du_connector_atomic_set_property, | ||
| 1051 | .atomic_get_property = vmw_du_connector_atomic_get_property, | ||
| 1052 | }; | 987 | }; |
| 1053 | 988 | ||
| 1054 | 989 | ||
| @@ -1256,11 +1191,402 @@ out_srf_unref: | |||
| 1256 | return ret; | 1191 | return ret; |
| 1257 | } | 1192 | } |
| 1258 | 1193 | ||
| 1194 | static uint32_t vmw_stdu_bo_fifo_size(struct vmw_du_update_plane *update, | ||
| 1195 | uint32_t num_hits) | ||
| 1196 | { | ||
| 1197 | return sizeof(struct vmw_stdu_dma) + sizeof(SVGA3dCopyBox) * num_hits + | ||
| 1198 | sizeof(SVGA3dCmdSurfaceDMASuffix) + | ||
| 1199 | sizeof(struct vmw_stdu_update); | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update, | ||
| 1203 | uint32_t num_hits) | ||
| 1204 | { | ||
| 1205 | return sizeof(struct vmw_stdu_update_gb_image) + | ||
| 1206 | sizeof(struct vmw_stdu_update); | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | static uint32_t vmw_stdu_bo_populate_dma(struct vmw_du_update_plane *update, | ||
| 1210 | void *cmd, uint32_t num_hits) | ||
| 1211 | { | ||
| 1212 | struct vmw_screen_target_display_unit *stdu; | ||
| 1213 | struct vmw_framebuffer_bo *vfbbo; | ||
| 1214 | struct vmw_stdu_dma *cmd_dma = cmd; | ||
| 1215 | |||
| 1216 | stdu = container_of(update->du, typeof(*stdu), base); | ||
| 1217 | vfbbo = container_of(update->vfb, typeof(*vfbbo), base); | ||
| 1218 | |||
| 1219 | cmd_dma->header.id = SVGA_3D_CMD_SURFACE_DMA; | ||
| 1220 | cmd_dma->header.size = sizeof(cmd_dma->body) + | ||
| 1221 | sizeof(struct SVGA3dCopyBox) * num_hits + | ||
| 1222 | sizeof(SVGA3dCmdSurfaceDMASuffix); | ||
| 1223 | vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &cmd_dma->body.guest.ptr); | ||
| 1224 | cmd_dma->body.guest.pitch = update->vfb->base.pitches[0]; | ||
| 1225 | cmd_dma->body.host.sid = stdu->display_srf->res.id; | ||
| 1226 | cmd_dma->body.host.face = 0; | ||
| 1227 | cmd_dma->body.host.mipmap = 0; | ||
| 1228 | cmd_dma->body.transfer = SVGA3D_WRITE_HOST_VRAM; | ||
| 1229 | |||
| 1230 | return sizeof(*cmd_dma); | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | static uint32_t vmw_stdu_bo_populate_clip(struct vmw_du_update_plane *update, | ||
| 1234 | void *cmd, struct drm_rect *clip, | ||
| 1235 | uint32_t fb_x, uint32_t fb_y) | ||
| 1236 | { | ||
| 1237 | struct SVGA3dCopyBox *box = cmd; | ||
| 1238 | |||
| 1239 | box->srcx = fb_x; | ||
| 1240 | box->srcy = fb_y; | ||
| 1241 | box->srcz = 0; | ||
| 1242 | box->x = clip->x1; | ||
| 1243 | box->y = clip->y1; | ||
| 1244 | box->z = 0; | ||
| 1245 | box->w = drm_rect_width(clip); | ||
| 1246 | box->h = drm_rect_height(clip); | ||
| 1247 | box->d = 1; | ||
| 1248 | |||
| 1249 | return sizeof(*box); | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | static uint32_t vmw_stdu_bo_populate_update(struct vmw_du_update_plane *update, | ||
| 1253 | void *cmd, struct drm_rect *bb) | ||
| 1254 | { | ||
| 1255 | struct vmw_screen_target_display_unit *stdu; | ||
| 1256 | struct vmw_framebuffer_bo *vfbbo; | ||
| 1257 | SVGA3dCmdSurfaceDMASuffix *suffix = cmd; | ||
| 1258 | |||
| 1259 | stdu = container_of(update->du, typeof(*stdu), base); | ||
| 1260 | vfbbo = container_of(update->vfb, typeof(*vfbbo), base); | ||
| 1261 | |||
| 1262 | suffix->suffixSize = sizeof(*suffix); | ||
| 1263 | suffix->maximumOffset = vfbbo->buffer->base.num_pages * PAGE_SIZE; | ||
| 1264 | |||
| 1265 | vmw_stdu_populate_update(&suffix[1], stdu->base.unit, bb->x1, bb->x2, | ||
| 1266 | bb->y1, bb->y2); | ||
| 1267 | |||
| 1268 | return sizeof(*suffix) + sizeof(struct vmw_stdu_update); | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | static uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane *update, | ||
| 1272 | void *cmd, uint32_t num_hits) | ||
| 1273 | { | ||
| 1274 | struct vmw_du_update_plane_buffer *bo_update = | ||
| 1275 | container_of(update, typeof(*bo_update), base); | ||
| 1276 | |||
| 1277 | bo_update->fb_left = INT_MAX; | ||
| 1278 | bo_update->fb_top = INT_MAX; | ||
| 1279 | |||
| 1280 | return 0; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | static uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane *update, | ||
| 1284 | void *cmd, struct drm_rect *clip, | ||
| 1285 | uint32_t fb_x, uint32_t fb_y) | ||
| 1286 | { | ||
| 1287 | struct vmw_du_update_plane_buffer *bo_update = | ||
| 1288 | container_of(update, typeof(*bo_update), base); | ||
| 1289 | |||
| 1290 | bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x); | ||
| 1291 | bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y); | ||
| 1292 | |||
| 1293 | return 0; | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | static uint32_t | ||
| 1297 | vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd, | ||
| 1298 | struct drm_rect *bb) | ||
| 1299 | { | ||
| 1300 | struct vmw_du_update_plane_buffer *bo_update; | ||
| 1301 | struct vmw_screen_target_display_unit *stdu; | ||
| 1302 | struct vmw_framebuffer_bo *vfbbo; | ||
| 1303 | struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0); | ||
| 1304 | struct vmw_stdu_update_gb_image *cmd_img = cmd; | ||
| 1305 | struct vmw_stdu_update *cmd_update; | ||
| 1306 | struct ttm_buffer_object *src_bo, *dst_bo; | ||
| 1307 | u32 src_offset, dst_offset; | ||
| 1308 | s32 src_pitch, dst_pitch; | ||
| 1309 | s32 width, height; | ||
| 1310 | |||
| 1311 | bo_update = container_of(update, typeof(*bo_update), base); | ||
| 1312 | stdu = container_of(update->du, typeof(*stdu), base); | ||
| 1313 | vfbbo = container_of(update->vfb, typeof(*vfbbo), base); | ||
| 1314 | |||
| 1315 | width = bb->x2 - bb->x1; | ||
| 1316 | height = bb->y2 - bb->y1; | ||
| 1317 | |||
| 1318 | diff.cpp = stdu->cpp; | ||
| 1319 | |||
| 1320 | dst_bo = &stdu->display_srf->res.backup->base; | ||
| 1321 | dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; | ||
| 1322 | dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp; | ||
| 1323 | |||
| 1324 | src_bo = &vfbbo->buffer->base; | ||
| 1325 | src_pitch = update->vfb->base.pitches[0]; | ||
| 1326 | src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left * | ||
| 1327 | stdu->cpp; | ||
| 1328 | |||
| 1329 | (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo, | ||
| 1330 | src_offset, src_pitch, width * stdu->cpp, height, | ||
| 1331 | &diff); | ||
| 1332 | |||
| 1333 | if (drm_rect_visible(&diff.rect)) { | ||
| 1334 | SVGA3dBox *box = &cmd_img->body.box; | ||
| 1335 | |||
| 1336 | cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; | ||
| 1337 | cmd_img->header.size = sizeof(cmd_img->body); | ||
| 1338 | cmd_img->body.image.sid = stdu->display_srf->res.id; | ||
| 1339 | cmd_img->body.image.face = 0; | ||
| 1340 | cmd_img->body.image.mipmap = 0; | ||
| 1341 | |||
| 1342 | box->x = diff.rect.x1; | ||
| 1343 | box->y = diff.rect.y1; | ||
| 1344 | box->z = 0; | ||
| 1345 | box->w = drm_rect_width(&diff.rect); | ||
| 1346 | box->h = drm_rect_height(&diff.rect); | ||
| 1347 | box->d = 1; | ||
| 1348 | |||
| 1349 | cmd_update = (struct vmw_stdu_update *)&cmd_img[1]; | ||
| 1350 | vmw_stdu_populate_update(cmd_update, stdu->base.unit, | ||
| 1351 | diff.rect.x1, diff.rect.x2, | ||
| 1352 | diff.rect.y1, diff.rect.y2); | ||
| 1353 | |||
| 1354 | return sizeof(*cmd_img) + sizeof(*cmd_update); | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | return 0; | ||
| 1358 | } | ||
| 1359 | |||
| 1360 | /** | ||
| 1361 | * vmw_stdu_plane_update_bo - Update display unit for bo backed fb. | ||
| 1362 | * @dev_priv: device private. | ||
| 1363 | * @plane: plane state. | ||
| 1364 | * @old_state: old plane state. | ||
| 1365 | * @vfb: framebuffer which is blitted to display unit. | ||
| 1366 | * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. | ||
| 1367 | * The returned fence pointer may be NULL in which case the device | ||
| 1368 | * has already synchronized. | ||
| 1369 | * | ||
| 1370 | * Return: 0 on success or a negative error code on failure. | ||
| 1371 | */ | ||
| 1372 | static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv, | ||
| 1373 | struct drm_plane *plane, | ||
| 1374 | struct drm_plane_state *old_state, | ||
| 1375 | struct vmw_framebuffer *vfb, | ||
| 1376 | struct vmw_fence_obj **out_fence) | ||
| 1377 | { | ||
| 1378 | struct vmw_du_update_plane_buffer bo_update; | ||
| 1379 | |||
| 1380 | memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); | ||
| 1381 | bo_update.base.plane = plane; | ||
| 1382 | bo_update.base.old_state = old_state; | ||
| 1383 | bo_update.base.dev_priv = dev_priv; | ||
| 1384 | bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); | ||
| 1385 | bo_update.base.vfb = vfb; | ||
| 1386 | bo_update.base.out_fence = out_fence; | ||
| 1387 | bo_update.base.mutex = NULL; | ||
| 1388 | bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); | ||
| 1389 | bo_update.base.intr = false; | ||
| 1390 | |||
| 1391 | /* | ||
| 1392 | * VM without 3D support don't have surface DMA command and framebuffer | ||
| 1393 | * should be moved out of VRAM. | ||
| 1394 | */ | ||
| 1395 | if (bo_update.base.cpu_blit) { | ||
| 1396 | bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu; | ||
| 1397 | bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu; | ||
| 1398 | bo_update.base.clip = vmw_stdu_bo_clip_cpu; | ||
| 1399 | bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu; | ||
| 1400 | } else { | ||
| 1401 | bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size; | ||
| 1402 | bo_update.base.pre_clip = vmw_stdu_bo_populate_dma; | ||
| 1403 | bo_update.base.clip = vmw_stdu_bo_populate_clip; | ||
| 1404 | bo_update.base.post_clip = vmw_stdu_bo_populate_update; | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | return vmw_du_helper_plane_update(&bo_update.base); | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | static uint32_t | ||
| 1411 | vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update, | ||
| 1412 | uint32_t num_hits) | ||
| 1413 | { | ||
| 1414 | struct vmw_framebuffer_surface *vfbs; | ||
| 1415 | uint32_t size = 0; | ||
| 1416 | |||
| 1417 | vfbs = container_of(update->vfb, typeof(*vfbs), base); | ||
| 1418 | |||
| 1419 | if (vfbs->is_bo_proxy) | ||
| 1420 | size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; | ||
| 1421 | |||
| 1422 | size += sizeof(struct vmw_stdu_update); | ||
| 1423 | |||
| 1424 | return size; | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update, | ||
| 1428 | uint32_t num_hits) | ||
| 1429 | { | ||
| 1430 | struct vmw_framebuffer_surface *vfbs; | ||
| 1431 | uint32_t size = 0; | ||
| 1432 | |||
| 1433 | vfbs = container_of(update->vfb, typeof(*vfbs), base); | ||
| 1434 | |||
| 1435 | if (vfbs->is_bo_proxy) | ||
| 1436 | size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; | ||
| 1437 | |||
| 1438 | size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) * | ||
| 1439 | num_hits + sizeof(struct vmw_stdu_update); | ||
| 1440 | |||
| 1441 | return size; | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | static uint32_t | ||
| 1445 | vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd) | ||
| 1446 | { | ||
| 1447 | struct vmw_framebuffer_surface *vfbs; | ||
| 1448 | struct drm_plane_state *state = update->plane->state; | ||
| 1449 | struct drm_plane_state *old_state = update->old_state; | ||
| 1450 | struct vmw_stdu_update_gb_image *cmd_update = cmd; | ||
| 1451 | struct drm_atomic_helper_damage_iter iter; | ||
| 1452 | struct drm_rect clip; | ||
| 1453 | uint32_t copy_size = 0; | ||
| 1454 | |||
| 1455 | vfbs = container_of(update->vfb, typeof(*vfbs), base); | ||
| 1456 | |||
| 1457 | /* | ||
| 1458 | * proxy surface is special where a buffer object type fb is wrapped | ||
| 1459 | * in a surface and need an update gb image command to sync with device. | ||
| 1460 | */ | ||
| 1461 | drm_atomic_helper_damage_iter_init(&iter, old_state, state); | ||
| 1462 | drm_atomic_for_each_plane_damage(&iter, &clip) { | ||
| 1463 | SVGA3dBox *box = &cmd_update->body.box; | ||
| 1464 | |||
| 1465 | cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; | ||
| 1466 | cmd_update->header.size = sizeof(cmd_update->body); | ||
| 1467 | cmd_update->body.image.sid = vfbs->surface->res.id; | ||
| 1468 | cmd_update->body.image.face = 0; | ||
| 1469 | cmd_update->body.image.mipmap = 0; | ||
| 1470 | |||
| 1471 | box->x = clip.x1; | ||
| 1472 | box->y = clip.y1; | ||
| 1473 | box->z = 0; | ||
| 1474 | box->w = drm_rect_width(&clip); | ||
| 1475 | box->h = drm_rect_height(&clip); | ||
| 1476 | box->d = 1; | ||
| 1477 | |||
| 1478 | copy_size += sizeof(*cmd_update); | ||
| 1479 | cmd_update++; | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | return copy_size; | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | static uint32_t | ||
| 1486 | vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd, | ||
| 1487 | uint32_t num_hits) | ||
| 1488 | { | ||
| 1489 | struct vmw_screen_target_display_unit *stdu; | ||
| 1490 | struct vmw_framebuffer_surface *vfbs; | ||
| 1491 | struct vmw_stdu_surface_copy *cmd_copy = cmd; | ||
| 1492 | |||
| 1493 | stdu = container_of(update->du, typeof(*stdu), base); | ||
| 1494 | vfbs = container_of(update->vfb, typeof(*vfbs), base); | ||
| 1495 | |||
| 1496 | cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY; | ||
| 1497 | cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) * | ||
| 1498 | num_hits; | ||
| 1499 | cmd_copy->body.src.sid = vfbs->surface->res.id; | ||
| 1500 | cmd_copy->body.dest.sid = stdu->display_srf->res.id; | ||
| 1501 | |||
| 1502 | return sizeof(*cmd_copy); | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | static uint32_t | ||
| 1506 | vmw_stdu_surface_populate_clip(struct vmw_du_update_plane *update, void *cmd, | ||
| 1507 | struct drm_rect *clip, uint32_t fb_x, | ||
| 1508 | uint32_t fb_y) | ||
| 1509 | { | ||
| 1510 | struct SVGA3dCopyBox *box = cmd; | ||
| 1511 | |||
| 1512 | box->srcx = fb_x; | ||
| 1513 | box->srcy = fb_y; | ||
| 1514 | box->srcz = 0; | ||
| 1515 | box->x = clip->x1; | ||
| 1516 | box->y = clip->y1; | ||
| 1517 | box->z = 0; | ||
| 1518 | box->w = drm_rect_width(clip); | ||
| 1519 | box->h = drm_rect_height(clip); | ||
| 1520 | box->d = 1; | ||
| 1521 | |||
| 1522 | return sizeof(*box); | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | static uint32_t | ||
| 1526 | vmw_stdu_surface_populate_update(struct vmw_du_update_plane *update, void *cmd, | ||
| 1527 | struct drm_rect *bb) | ||
| 1528 | { | ||
| 1529 | vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1, | ||
| 1530 | bb->y2); | ||
| 1259 | 1531 | ||
| 1532 | return sizeof(struct vmw_stdu_update); | ||
| 1533 | } | ||
| 1260 | 1534 | ||
| 1261 | /** | 1535 | /** |
| 1262 | * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane | 1536 | * vmw_stdu_plane_update_surface - Update display unit for surface backed fb |
| 1537 | * @dev_priv: Device private | ||
| 1538 | * @plane: Plane state | ||
| 1539 | * @old_state: Old plane state | ||
| 1540 | * @vfb: Framebuffer which is blitted to display unit | ||
| 1541 | * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. | ||
| 1542 | * The returned fence pointer may be NULL in which case the device | ||
| 1543 | * has already synchronized. | ||
| 1263 | * | 1544 | * |
| 1545 | * Return: 0 on success or a negative error code on failure. | ||
| 1546 | */ | ||
| 1547 | static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, | ||
| 1548 | struct drm_plane *plane, | ||
| 1549 | struct drm_plane_state *old_state, | ||
| 1550 | struct vmw_framebuffer *vfb, | ||
| 1551 | struct vmw_fence_obj **out_fence) | ||
| 1552 | { | ||
| 1553 | struct vmw_du_update_plane srf_update; | ||
| 1554 | struct vmw_screen_target_display_unit *stdu; | ||
| 1555 | struct vmw_framebuffer_surface *vfbs; | ||
| 1556 | |||
| 1557 | stdu = vmw_crtc_to_stdu(plane->state->crtc); | ||
| 1558 | vfbs = container_of(vfb, typeof(*vfbs), base); | ||
| 1559 | |||
| 1560 | memset(&srf_update, 0, sizeof(struct vmw_du_update_plane)); | ||
| 1561 | srf_update.plane = plane; | ||
| 1562 | srf_update.old_state = old_state; | ||
| 1563 | srf_update.dev_priv = dev_priv; | ||
| 1564 | srf_update.du = vmw_crtc_to_du(plane->state->crtc); | ||
| 1565 | srf_update.vfb = vfb; | ||
| 1566 | srf_update.out_fence = out_fence; | ||
| 1567 | srf_update.mutex = &dev_priv->cmdbuf_mutex; | ||
| 1568 | srf_update.cpu_blit = false; | ||
| 1569 | srf_update.intr = true; | ||
| 1570 | |||
| 1571 | if (vfbs->is_bo_proxy) | ||
| 1572 | srf_update.post_prepare = vmw_stdu_surface_update_proxy; | ||
| 1573 | |||
| 1574 | if (vfbs->surface->res.id != stdu->display_srf->res.id) { | ||
| 1575 | srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size; | ||
| 1576 | srf_update.pre_clip = vmw_stdu_surface_populate_copy; | ||
| 1577 | srf_update.clip = vmw_stdu_surface_populate_clip; | ||
| 1578 | } else { | ||
| 1579 | srf_update.calc_fifo_size = | ||
| 1580 | vmw_stdu_surface_fifo_size_same_display; | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | srf_update.post_clip = vmw_stdu_surface_populate_update; | ||
| 1584 | |||
| 1585 | return vmw_du_helper_plane_update(&srf_update); | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | /** | ||
| 1589 | * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane | ||
| 1264 | * @plane: display plane | 1590 | * @plane: display plane |
| 1265 | * @old_state: Only used to get crtc info | 1591 | * @old_state: Only used to get crtc info |
| 1266 | * | 1592 | * |
| @@ -1277,17 +1603,14 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, | |||
| 1277 | struct drm_crtc *crtc = plane->state->crtc; | 1603 | struct drm_crtc *crtc = plane->state->crtc; |
| 1278 | struct vmw_screen_target_display_unit *stdu; | 1604 | struct vmw_screen_target_display_unit *stdu; |
| 1279 | struct drm_pending_vblank_event *event; | 1605 | struct drm_pending_vblank_event *event; |
| 1606 | struct vmw_fence_obj *fence = NULL; | ||
| 1280 | struct vmw_private *dev_priv; | 1607 | struct vmw_private *dev_priv; |
| 1281 | int ret; | 1608 | int ret; |
| 1282 | 1609 | ||
| 1283 | /* | 1610 | /* If case of device error, maintain consistent atomic state */ |
| 1284 | * We cannot really fail this function, so if we do, then output an | ||
| 1285 | * error and maintain consistent atomic state. | ||
| 1286 | */ | ||
| 1287 | if (crtc && plane->state->fb) { | 1611 | if (crtc && plane->state->fb) { |
| 1288 | struct vmw_framebuffer *vfb = | 1612 | struct vmw_framebuffer *vfb = |
| 1289 | vmw_framebuffer_to_vfb(plane->state->fb); | 1613 | vmw_framebuffer_to_vfb(plane->state->fb); |
| 1290 | struct drm_vmw_rect vclips; | ||
| 1291 | stdu = vmw_crtc_to_stdu(crtc); | 1614 | stdu = vmw_crtc_to_stdu(crtc); |
| 1292 | dev_priv = vmw_priv(crtc->dev); | 1615 | dev_priv = vmw_priv(crtc->dev); |
| 1293 | 1616 | ||
| @@ -1295,23 +1618,17 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, | |||
| 1295 | stdu->content_fb_type = vps->content_fb_type; | 1618 | stdu->content_fb_type = vps->content_fb_type; |
| 1296 | stdu->cpp = vps->cpp; | 1619 | stdu->cpp = vps->cpp; |
| 1297 | 1620 | ||
| 1298 | vclips.x = crtc->x; | ||
| 1299 | vclips.y = crtc->y; | ||
| 1300 | vclips.w = crtc->mode.hdisplay; | ||
| 1301 | vclips.h = crtc->mode.vdisplay; | ||
| 1302 | |||
| 1303 | ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); | 1621 | ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); |
| 1304 | if (ret) | 1622 | if (ret) |
| 1305 | DRM_ERROR("Failed to bind surface to STDU.\n"); | 1623 | DRM_ERROR("Failed to bind surface to STDU.\n"); |
| 1306 | 1624 | ||
| 1307 | if (vfb->bo) | 1625 | if (vfb->bo) |
| 1308 | ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, | 1626 | ret = vmw_stdu_plane_update_bo(dev_priv, plane, |
| 1309 | &vclips, 1, 1, true, false, | 1627 | old_state, vfb, &fence); |
| 1310 | crtc); | ||
| 1311 | else | 1628 | else |
| 1312 | ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, | 1629 | ret = vmw_stdu_plane_update_surface(dev_priv, plane, |
| 1313 | &vclips, NULL, 0, 0, | 1630 | old_state, vfb, |
| 1314 | 1, 1, NULL, crtc); | 1631 | &fence); |
| 1315 | if (ret) | 1632 | if (ret) |
| 1316 | DRM_ERROR("Failed to update STDU.\n"); | 1633 | DRM_ERROR("Failed to update STDU.\n"); |
| 1317 | } else { | 1634 | } else { |
| @@ -1319,12 +1636,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, | |||
| 1319 | stdu = vmw_crtc_to_stdu(crtc); | 1636 | stdu = vmw_crtc_to_stdu(crtc); |
| 1320 | dev_priv = vmw_priv(crtc->dev); | 1637 | dev_priv = vmw_priv(crtc->dev); |
| 1321 | 1638 | ||
| 1322 | /* | 1639 | /* Blank STDU when fb and crtc are NULL */ |
| 1323 | * When disabling a plane, CRTC and FB should always be NULL | ||
| 1324 | * together, otherwise it's an error. | ||
| 1325 | * Here primary plane is being disable so blank the screen | ||
| 1326 | * target display unit, if not already done. | ||
| 1327 | */ | ||
| 1328 | if (!stdu->defined) | 1640 | if (!stdu->defined) |
| 1329 | return; | 1641 | return; |
| 1330 | 1642 | ||
| @@ -1339,36 +1651,25 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, | |||
| 1339 | return; | 1651 | return; |
| 1340 | } | 1652 | } |
| 1341 | 1653 | ||
| 1654 | /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */ | ||
| 1342 | event = crtc->state->event; | 1655 | event = crtc->state->event; |
| 1343 | /* | 1656 | if (event && fence) { |
| 1344 | * In case of failure and other cases, vblank event will be sent in | ||
| 1345 | * vmw_du_crtc_atomic_flush. | ||
| 1346 | */ | ||
| 1347 | if (event && (ret == 0)) { | ||
| 1348 | struct vmw_fence_obj *fence = NULL; | ||
| 1349 | struct drm_file *file_priv = event->base.file_priv; | 1657 | struct drm_file *file_priv = event->base.file_priv; |
| 1350 | 1658 | ||
| 1351 | vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); | 1659 | ret = vmw_event_fence_action_queue(file_priv, |
| 1352 | 1660 | fence, | |
| 1353 | /* | 1661 | &event->base, |
| 1354 | * If fence is NULL, then already sync. | 1662 | &event->event.vbl.tv_sec, |
| 1355 | */ | 1663 | &event->event.vbl.tv_usec, |
| 1356 | if (fence) { | 1664 | true); |
| 1357 | ret = vmw_event_fence_action_queue( | 1665 | if (ret) |
| 1358 | file_priv, fence, &event->base, | 1666 | DRM_ERROR("Failed to queue event on fence.\n"); |
| 1359 | &event->event.vbl.tv_sec, | 1667 | else |
| 1360 | &event->event.vbl.tv_usec, | 1668 | crtc->state->event = NULL; |
| 1361 | true); | ||
| 1362 | if (ret) | ||
| 1363 | DRM_ERROR("Failed to queue event on fence.\n"); | ||
| 1364 | else | ||
| 1365 | crtc->state->event = NULL; | ||
| 1366 | |||
| 1367 | vmw_fence_obj_unreference(&fence); | ||
| 1368 | } | ||
| 1369 | } else { | ||
| 1370 | (void) vmw_fifo_flush(dev_priv, false); | ||
| 1371 | } | 1669 | } |
| 1670 | |||
| 1671 | if (fence) | ||
| 1672 | vmw_fence_obj_unreference(&fence); | ||
| 1372 | } | 1673 | } |
| 1373 | 1674 | ||
| 1374 | 1675 | ||
| @@ -1456,11 +1757,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 1456 | stdu->base.pref_active = (unit == 0); | 1757 | stdu->base.pref_active = (unit == 0); |
| 1457 | stdu->base.pref_width = dev_priv->initial_width; | 1758 | stdu->base.pref_width = dev_priv->initial_width; |
| 1458 | stdu->base.pref_height = dev_priv->initial_height; | 1759 | stdu->base.pref_height = dev_priv->initial_height; |
| 1459 | |||
| 1460 | /* | ||
| 1461 | * Remove this after enabling atomic because property values can | ||
| 1462 | * only exist in a state object | ||
| 1463 | */ | ||
| 1464 | stdu->base.is_implicit = false; | 1760 | stdu->base.is_implicit = false; |
| 1465 | 1761 | ||
| 1466 | /* Initialize primary plane */ | 1762 | /* Initialize primary plane */ |
| @@ -1477,6 +1773,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 1477 | } | 1773 | } |
| 1478 | 1774 | ||
| 1479 | drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs); | 1775 | drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs); |
| 1776 | drm_plane_enable_fb_damage_clips(primary); | ||
| 1480 | 1777 | ||
| 1481 | /* Initialize cursor plane */ | 1778 | /* Initialize cursor plane */ |
| 1482 | vmw_du_plane_reset(cursor); | 1779 | vmw_du_plane_reset(cursor); |
| @@ -1505,7 +1802,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 1505 | 1802 | ||
| 1506 | drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs); | 1803 | drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs); |
| 1507 | connector->status = vmw_du_connector_detect(connector, false); | 1804 | connector->status = vmw_du_connector_detect(connector, false); |
| 1508 | vmw_connector_state_to_vcs(connector->state)->is_implicit = false; | ||
| 1509 | 1805 | ||
| 1510 | ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, | 1806 | ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, |
| 1511 | DRM_MODE_ENCODER_VIRTUAL, NULL); | 1807 | DRM_MODE_ENCODER_VIRTUAL, NULL); |
| @@ -1543,11 +1839,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) | |||
| 1543 | dev->mode_config.suggested_x_property, 0); | 1839 | dev->mode_config.suggested_x_property, 0); |
| 1544 | drm_object_attach_property(&connector->base, | 1840 | drm_object_attach_property(&connector->base, |
| 1545 | dev->mode_config.suggested_y_property, 0); | 1841 | dev->mode_config.suggested_y_property, 0); |
| 1546 | if (dev_priv->implicit_placement_property) | ||
| 1547 | drm_object_attach_property | ||
| 1548 | (&connector->base, | ||
| 1549 | dev_priv->implicit_placement_property, | ||
| 1550 | stdu->base.is_implicit); | ||
| 1551 | return 0; | 1842 | return 0; |
| 1552 | 1843 | ||
| 1553 | err_free_unregister: | 1844 | err_free_unregister: |
| @@ -1616,8 +1907,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) | |||
| 1616 | 1907 | ||
| 1617 | dev_priv->active_display_unit = vmw_du_screen_target; | 1908 | dev_priv->active_display_unit = vmw_du_screen_target; |
| 1618 | 1909 | ||
| 1619 | vmw_kms_create_implicit_placement_property(dev_priv, false); | ||
| 1620 | |||
| 1621 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { | 1910 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { |
| 1622 | ret = vmw_stdu_init(dev_priv, i); | 1911 | ret = vmw_stdu_init(dev_priv, i); |
| 1623 | 1912 | ||
diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h new file mode 100644 index 000000000000..4487660b26b8 --- /dev/null +++ b/include/drm/drm_damage_helper.h | |||
| @@ -0,0 +1,99 @@ | |||
| 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 | ||
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 9db59a1caf5b..572274ccbec7 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h | |||
| @@ -634,6 +634,15 @@ struct drm_mode_config { | |||
| 634 | */ | 634 | */ |
| 635 | struct drm_property *prop_crtc_id; | 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 | * @prop_active: Default atomic CRTC property to control the active | 646 | * @prop_active: Default atomic CRTC property to control the active |
| 638 | * state, which is the simplified implementation for DPMS in atomic | 647 | * state, which is the simplified implementation for DPMS in atomic |
| 639 | * drivers. | 648 | * drivers. |
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 3701f56c3362..6078c700d9ba 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h | |||
| @@ -173,6 +173,16 @@ struct drm_plane_state { | |||
| 173 | */ | 173 | */ |
| 174 | enum drm_color_range color_range; | 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 | /** @src: clipped source coordinates of the plane (in 16.16) */ | 186 | /** @src: clipped source coordinates of the plane (in 16.16) */ |
| 177 | /** @dst: clipped destination coordinates of the plane */ | 187 | /** @dst: clipped destination coordinates of the plane */ |
| 178 | struct drm_rect src, dst; | 188 | struct drm_rect src, dst; |
| @@ -800,5 +810,37 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, | |||
| 800 | 810 | ||
| 801 | bool drm_any_plane_has_format(struct drm_device *dev, | 811 | bool drm_any_plane_has_format(struct drm_device *dev, |
| 802 | u32 format, u64 modifier); | 812 | u32 format, u64 modifier); |
| 813 | /** | ||
| 814 | * drm_plane_get_damage_clips_count - Returns damage clips count. | ||
| 815 | * @state: Plane state. | ||
| 816 | * | ||
| 817 | * Simple helper to get the number of &drm_mode_rect clips set by user-space | ||
| 818 | * during plane update. | ||
| 819 | * | ||
| 820 | * Return: Number of clips in plane fb_damage_clips blob property. | ||
| 821 | */ | ||
| 822 | static inline unsigned int | ||
| 823 | drm_plane_get_damage_clips_count(const struct drm_plane_state *state) | ||
| 824 | { | ||
| 825 | return (state && state->fb_damage_clips) ? | ||
| 826 | state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0; | ||
| 827 | } | ||
| 828 | |||
| 829 | /** | ||
| 830 | * drm_plane_get_damage_clips - Returns damage clips. | ||
| 831 | * @state: Plane state. | ||
| 832 | * | ||
| 833 | * Note that this function returns uapi type &drm_mode_rect. Drivers might | ||
| 834 | * instead be interested in internal &drm_rect which can be obtained by calling | ||
| 835 | * drm_helper_get_plane_damage_clips(). | ||
| 836 | * | ||
| 837 | * Return: Damage clips in plane fb_damage_clips blob property. | ||
| 838 | */ | ||
| 839 | static inline struct drm_mode_rect * | ||
| 840 | drm_plane_get_damage_clips(const struct drm_plane_state *state) | ||
| 841 | { | ||
| 842 | return (struct drm_mode_rect *)((state && state->fb_damage_clips) ? | ||
| 843 | state->fb_damage_clips->data : NULL); | ||
| 844 | } | ||
| 803 | 845 | ||
| 804 | #endif | 846 | #endif |
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index d3e0fe31efc5..a439c2e67896 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h | |||
| @@ -888,6 +888,25 @@ struct drm_mode_revoke_lease { | |||
| 888 | __u32 lessee_id; | 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 | #if defined(__cplusplus) | 910 | #if defined(__cplusplus) |
| 892 | } | 911 | } |
| 893 | #endif | 912 | #endif |
