summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2019-06-11 11:56:26 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2019-06-11 11:56:26 +0000
commitdd6ae7182489d0084e5041ed0cae6612d0244258 (patch)
tree6b998c7b7fe273989edc9e14fe6e74e7c8272d5c
parentd100eb08d0951298cac358fd8e49ae5ace1ccfed (diff)
drm: don't block fb changes for async plane updates
From Helen Koike fbb7e114e6e690c46f170dedd6fd2fb22f241519 in linux 4.19.y/4.19.50 89a4aac0ab0e6f5eea10d7bf4869dd15c3de2cd4 in mainline linux
-rw-r--r--sys/dev/pci/drm/drm_atomic_helper.c22
-rw-r--r--sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h8
2 files changed, 20 insertions, 10 deletions
diff --git a/sys/dev/pci/drm/drm_atomic_helper.c b/sys/dev/pci/drm/drm_atomic_helper.c
index 37fcd892de4..57a1d3d6dbb 100644
--- a/sys/dev/pci/drm/drm_atomic_helper.c
+++ b/sys/dev/pci/drm/drm_atomic_helper.c
@@ -1578,15 +1578,6 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
if (old_plane_state->fb != new_plane_state->fb)
return -EINVAL;
- /*
- * FIXME: Since prepare_fb and cleanup_fb are always called on
- * the new_plane_state for async updates we need to block framebuffer
- * changes. This prevents use of a fb that's been cleaned up and
- * double cleanups from occuring.
- */
- if (old_plane_state->fb != new_plane_state->fb)
- return -EINVAL;
-
funcs = plane->helper_private;
if (!funcs->atomic_async_update)
return -EINVAL;
@@ -1617,6 +1608,8 @@ EXPORT_SYMBOL(drm_atomic_helper_async_check);
* drm_atomic_async_check() succeeds. Async commits are not supposed to swap
* the states like normal sync commits, but just do in-place changes on the
* current state.
+ *
+ * TODO: Implement full swap instead of doing in-place changes.
*/
void drm_atomic_helper_async_commit(struct drm_device *dev,
struct drm_atomic_state *state)
@@ -1627,6 +1620,9 @@ void drm_atomic_helper_async_commit(struct drm_device *dev,
int i;
for_each_new_plane_in_state(state, plane, plane_state, i) {
+ struct drm_framebuffer *new_fb = plane_state->fb;
+ struct drm_framebuffer *old_fb = plane->state->fb;
+
funcs = plane->helper_private;
funcs->atomic_async_update(plane, plane_state);
@@ -1635,11 +1631,17 @@ void drm_atomic_helper_async_commit(struct drm_device *dev,
* plane->state in-place, make sure at least common
* properties have been properly updated.
*/
- WARN_ON_ONCE(plane->state->fb != plane_state->fb);
+ WARN_ON_ONCE(plane->state->fb != new_fb);
WARN_ON_ONCE(plane->state->crtc_x != plane_state->crtc_x);
WARN_ON_ONCE(plane->state->crtc_y != plane_state->crtc_y);
WARN_ON_ONCE(plane->state->src_x != plane_state->src_x);
WARN_ON_ONCE(plane->state->src_y != plane_state->src_y);
+
+ /*
+ * Make sure the FBs have been swapped so that cleanups in the
+ * new_state performs a cleanup in the old FB.
+ */
+ WARN_ON_ONCE(plane_state->fb != old_fb);
}
}
EXPORT_SYMBOL(drm_atomic_helper_async_commit);
diff --git a/sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h b/sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h
index 61142aa0ab2..0eb3372d031 100644
--- a/sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h
+++ b/sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h
@@ -1174,6 +1174,14 @@ struct drm_plane_helper_funcs {
* current one with the new plane configurations in the new
* plane_state.
*
+ * Drivers should also swap the framebuffers between current plane
+ * state (&drm_plane.state) and new_state.
+ * This is required since cleanup for async commits is performed on
+ * the new state, rather than old state like for traditional commits.
+ * Since we want to give up the reference on the current (old) fb
+ * instead of our brand new one, swap them in the driver during the
+ * async commit.
+ *
* FIXME:
* - It only works for single plane updates
* - Async Pageflips are not supported yet