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 |