All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/7] drm: asynchronous atomic plane update
@ 2017-04-10  0:24 Gustavo Padovan
  2017-04-10  0:24 ` [RFC 1/7] drm/atomic: initial support for asynchronous " Gustavo Padovan
                   ` (6 more replies)
  0 siblings, 7 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  0:24 UTC (permalink / raw)
  To: dri-devel; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.com>

Hi,

First version of Asynchronous Plane Update over Atomic. Here I looked
to msm, vc4 and i915 to identify a common pattern to create atomic helpers
for async updates. So in patch 1 drm_atomic_async_check() and
drm_atomic_helper_async_commit() are introduced along with driver's plane hooks:
->atomic_async_check() and ->atomic_async_commit().

For now we only support async update for one plane at a time and there can't
be any update for that plane in the current pending commit. Also the async
update can't modify the CRTC so no modesets are allowed.

Then the other patches add support for it in the drivers. I did virtio mostly
for testing. i915 have been converted and I've been using the it for four days
already without any problem. I tried to run i-g-t on it but as of now
drm-misc-next is failing a bit already. I'll get back to this for v2.
vc4 and msm are only build tested.

TODO

 - async updates when an update for the same plane is already queued
 - improve i-g-t tests where needed
 - support async page flips (that can be done after uptreaming this part)

Comments are welcome!

Regards,

Gustavo

---
Gustavo Padovan (7):
  drm/atomic: initial support for asynchronous plane update
  drm/virtio: support async cursor updates
  drm/i915: update cursors asynchronously through atomic
  drm/i915: remove intel_cursor_plane_funcs
  drm/msm: update cursors asynchronously through atomic
  drm/msm: remove mdp5_cursor_plane_funcs
  drm/vc4: update cursors asynchronously through atomic

 drivers/gpu/drm/drm_atomic.c              |  75 ++++++++++++++
 drivers/gpu/drm/drm_atomic_helper.c       |  41 ++++++++
 drivers/gpu/drm/i915/intel_atomic_plane.c |  58 +++++++++++
 drivers/gpu/drm/i915/intel_display.c      | 158 ++++------------------------
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 165 ++++++++++--------------------
 drivers/gpu/drm/vc4/vc4_plane.c           |  94 +++++------------
 drivers/gpu/drm/virtio/virtgpu_plane.c    |  42 ++++++++
 include/drm/drm_atomic.h                  |   4 +
 include/drm/drm_atomic_helper.h           |   2 +
 include/drm/drm_modeset_helper_vtables.h  |  47 +++++++++
 10 files changed, 373 insertions(+), 313 deletions(-)

-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-04-10  0:24 [RFC 0/7] drm: asynchronous atomic plane update Gustavo Padovan
@ 2017-04-10  0:24 ` Gustavo Padovan
  2017-04-10  7:13   ` Emil Velikov
  2017-04-10 19:55   ` Eric Anholt
  2017-04-10  0:24 ` [RFC 2/7] drm/virtio: support async cursor updates Gustavo Padovan
                   ` (5 subsequent siblings)
  6 siblings, 2 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  0:24 UTC (permalink / raw)
  To: dri-devel; +Cc: Gustavo Padovan, Daniel Vetter

From: Gustavo Padovan <gustavo.padovan@collabora.com>

In some cases, like cursor updates, it is interesting to update the
plane in an asynchronous fashion to avoid big delays.

The current queued update could be still waiting for a fence to signal and
thus block and subsequent update until its scan out. In cases like this if
we update the cursor synchronously it will cause significant delays on
some platforms that would be noticed by the final user.

This patch creates a fast path to jump ahead the current queued state and
do single planes updates without going through all atomic step in
drm_atomic_helper_commit().

For now only single plane updates are supported and only if there is no
update to that plane in the queued state.

We plan to support async PageFlips through this interface as well in the
near future.

Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Rob Clark <robdclark@gmail.com>
Cc: Eric Anholt <eric@anholt.net>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
---
 drivers/gpu/drm/drm_atomic.c             | 75 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_atomic_helper.c      | 41 +++++++++++++++++
 include/drm/drm_atomic.h                 |  4 ++
 include/drm/drm_atomic_helper.h          |  2 +
 include/drm/drm_modeset_helper_vtables.h | 47 ++++++++++++++++++++
 5 files changed, 169 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index f32506a..cae0122 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -631,6 +631,79 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
 	return 0;
 }
 
+static bool drm_atomic_async_check(struct drm_atomic_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc_commit *commit;
+	struct drm_plane *__plane, *plane = NULL;
+	struct drm_plane_state *__plane_state, *plane_state = NULL;
+	const struct drm_plane_helper_funcs *funcs;
+	int i, n_planes = 0;
+
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		if (drm_atomic_crtc_needs_modeset(crtc_state))
+			return false;
+	}
+
+	for_each_new_plane_in_state(state, __plane, __plane_state, i) {
+		n_planes++;
+		plane = __plane;
+		plane_state = __plane_state;
+	}
+
+	if (!plane || n_planes != 1)
+		return false;
+
+	if (!plane->state->crtc)
+		return false;
+
+	if (plane_state->fence)
+		return false;
+
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		if (plane->crtc != crtc)
+			continue;
+
+		spin_lock(&crtc->commit_lock);
+		commit = list_first_entry_or_null(&crtc->commit_list,
+						  struct drm_crtc_commit,
+						  commit_entry);
+		if (!commit) {
+			spin_unlock(&crtc->commit_lock);
+			continue;
+		}
+		spin_unlock(&crtc->commit_lock);
+
+		for_each_plane_in_state(crtc_state->state, __plane,
+					__plane_state, i) {
+			if (__plane == plane) {
+				return false;
+			}
+		}
+	}
+
+	/* Not configuring new scaling in the async path. */
+	if (plane->state->crtc_w != plane_state->crtc_w ||
+	    plane->state->crtc_h != plane_state->crtc_h ||
+	    plane->state->src_w != plane_state->src_w ||
+	    plane->state->src_h != plane_state->src_h) {
+		return false;
+	}
+
+	funcs = plane->helper_private;
+
+	if (!funcs->atomic_async_update)
+		return false;
+
+	if (funcs->atomic_async_check) {
+		if (funcs->atomic_async_check(plane, plane_state) < 0)
+			return false;
+	}
+
+	return true;
+}
+
 static void drm_atomic_crtc_print_state(struct drm_printer *p,
 		const struct drm_crtc_state *state)
 {
@@ -1591,6 +1664,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 		}
 	}
 
+	state->async_update = drm_atomic_async_check(state);
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_check_only);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 8be9719..a79e06c 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1235,6 +1235,36 @@ static void commit_work(struct work_struct *work)
 }
 
 /**
+ * drm_atomic_helper_async_commit - commit state asynchronously
+ *
+ * This function commits a state asynchronously. It should be used
+ * on a state only when drm_atomic_async_check() succeds. Async
+ * commits are not supposed to swap the states like normal sync commits,
+ * but just do in-place change on the current state.
+ */
+void drm_atomic_helper_async_commit(struct drm_device *dev,
+				    struct drm_atomic_state *state)
+{
+	struct drm_plane *plane;
+	struct drm_plane_state *plane_state;
+	const struct drm_plane_helper_funcs *funcs;
+	int i;
+
+	for_each_new_plane_in_state(state, plane, plane_state, i) {
+		funcs = plane->helper_private;
+
+		plane->state->src_x = plane_state->src_x;
+		plane->state->src_y = plane_state->src_y;
+		plane->state->crtc_x = plane_state->crtc_x;
+		plane->state->crtc_y = plane_state->crtc_y;
+
+		if (funcs && funcs->atomic_async_update)
+			funcs->atomic_async_update(plane, plane_state);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_helper_async_commit);
+
+/**
  * drm_atomic_helper_commit - commit validated state object
  * @dev: DRM device
  * @state: the driver state object
@@ -1258,6 +1288,17 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 {
 	int ret;
 
+	if (state->async_update) {
+		ret = drm_atomic_helper_prepare_planes(dev, state);
+		if (ret)
+			return ret;
+
+		drm_atomic_helper_async_commit(dev, state);
+		drm_atomic_helper_cleanup_planes(dev, state);
+
+		return 0;
+	}
+
 	ret = drm_atomic_helper_setup_commit(state, nonblock);
 	if (ret)
 		return ret;
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 788daf7..c00c565 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -160,6 +160,8 @@ struct __drm_connnectors_state {
  * @dev: parent DRM device
  * @allow_modeset: allow full modeset
  * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics
+ * @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL.
+ * @async_update: hint for asynchronous plane update
  * @planes: pointer to array of structures with per-plane data
  * @crtcs: pointer to array of CRTC pointers
  * @num_connector: size of the @connectors and @connector_states arrays
@@ -172,6 +174,8 @@ struct drm_atomic_state {
 	struct drm_device *dev;
 	bool allow_modeset : 1;
 	bool legacy_cursor_update : 1;
+	bool legacy_set_config : 1;
+	bool async_update : 1;
 	struct __drm_planes_state *planes;
 	struct __drm_crtcs_state *crtcs;
 	int num_connector;
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index f0a8678..8571b51 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -44,6 +44,8 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *state);
 int drm_atomic_helper_commit(struct drm_device *dev,
 			     struct drm_atomic_state *state,
 			     bool nonblock);
+void drm_atomic_helper_async_commit(struct drm_device *dev,
+				    struct drm_atomic_state *state);
 
 int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
 					struct drm_atomic_state *state,
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index c01c328..3efa4cc 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -1048,6 +1048,53 @@ struct drm_plane_helper_funcs {
 	 */
 	void (*atomic_disable)(struct drm_plane *plane,
 			       struct drm_plane_state *old_state);
+
+	/**
+	 * @atomic_async_check:
+	 *
+	 * Drivers should use this function check if the plane state
+	 * can be updated in a async fashion.
+	 *
+	 * This hook is called by drm_atomic_async_check() in the process
+	 * to figure out if an given update can be committed asynchronously,
+	 * that is, if it can jump ahead the state currently queued for
+	 * update.
+	 *
+	 * Check drm_atomic_async_check() to see what is already there
+	 * to discover potential async updates.
+	 *
+	 * RETURNS:
+	 *
+	 * Return 0 on success and -EINVAL if the update can't be async.
+	 * Error return doesn't mean that the update can't be applied,
+	 * it just mean that it can't be an async one.
+	 *
+	 * FIXME:
+	 *  - It only works for single plane updates
+	 *  - It can't do async update if the plane is already being update
+	 *  by the queued state
+	 *  - Async Pageflips are not supported yet
+	 */
+	int (*atomic_async_check)(struct drm_plane *plane,
+				  struct drm_plane_state *state);
+
+	/**
+	 * @atomic_async_update:
+	 *
+	 * Drivers should use this functions to perform asynchronous
+	 * updates of planes, that is jump ahead the currently queued
+	 * state for and update the plane.
+	 *
+	 * This hook is called by drm_atomic_helper_async_commit().
+	 *
+	 * Note that differently from the &drm_plane_helper_funcs.atomic_update
+	 * this hook takes the new &drm_plane_state as parameter. When doing
+	 * async_update drivers shouldn't replace the &drm_plane_state but
+	 * just, update the current one with the new plane configurations in
+	 * the new plane_state.
+	 */
+	void (*atomic_async_update)(struct drm_plane *plane,
+				    struct drm_plane_state *new_state);
 };
 
 /**
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC 2/7] drm/virtio: support async cursor updates
  2017-04-10  0:24 [RFC 0/7] drm: asynchronous atomic plane update Gustavo Padovan
  2017-04-10  0:24 ` [RFC 1/7] drm/atomic: initial support for asynchronous " Gustavo Padovan
@ 2017-04-10  0:24 ` Gustavo Padovan
  2017-04-10  0:24 ` [RFC 3/7] drm/i915: update cursors asynchronously through atomic Gustavo Padovan
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  0:24 UTC (permalink / raw)
  To: dri-devel; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.com>

Short circuit the update path for cursors and use the drm async update
infrastructure.

Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>

---
I wrote this mostly for testing purposes, not sure if its something that
we actually for virtio.
---
 drivers/gpu/drm/virtio/virtgpu_plane.c | 42 ++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index 76d5fed..4d6e40b 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -260,6 +260,46 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
 	virtio_gpu_cursor_ping(vgdev, output);
 }
 
+static int virtio_gpu_cursor_plane_async_check(struct drm_plane *plane,
+					       struct drm_plane_state *new_state)
+{
+	struct virtio_gpu_output *output;
+
+	if (!plane->state->crtc)
+		return -EINVAL;
+
+	output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
+	if (!output)
+		return -EINVAL;
+
+	if (plane->state->fb != new_state->fb)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void virtio_gpu_cursor_plane_async_update(struct drm_plane *plane,
+						 struct drm_plane_state *new_state)
+{
+	struct drm_device *dev = plane->dev;
+	struct virtio_gpu_device *vgdev = dev->dev_private;
+	struct virtio_gpu_output *output = NULL;
+
+	output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
+	if (WARN_ON(!output))
+		return;
+
+	if (plane->state->fb != new_state->fb)
+		return;
+
+	DRM_DEBUG("move +%d+%d\n", plane->state->crtc_x, plane->state->crtc_y);
+
+	output->cursor.hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR);
+	output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x);
+	output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y);
+	virtio_gpu_cursor_ping(vgdev, output);
+}
+
 static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = {
 	.atomic_check		= virtio_gpu_plane_atomic_check,
 	.atomic_update		= virtio_gpu_primary_plane_update,
@@ -268,6 +308,8 @@ static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = {
 static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = {
 	.atomic_check		= virtio_gpu_plane_atomic_check,
 	.atomic_update		= virtio_gpu_cursor_plane_update,
+	.atomic_async_check	= virtio_gpu_cursor_plane_async_check,
+	.atomic_async_update	= virtio_gpu_cursor_plane_async_update,
 };
 
 struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC 3/7] drm/i915: update cursors asynchronously through atomic
  2017-04-10  0:24 [RFC 0/7] drm: asynchronous atomic plane update Gustavo Padovan
  2017-04-10  0:24 ` [RFC 1/7] drm/atomic: initial support for asynchronous " Gustavo Padovan
  2017-04-10  0:24 ` [RFC 2/7] drm/virtio: support async cursor updates Gustavo Padovan
@ 2017-04-10  0:24 ` Gustavo Padovan
  2017-04-10  0:24 ` [RFC 4/7] drm/i915: remove intel_cursor_plane_funcs Gustavo Padovan
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  0:24 UTC (permalink / raw)
  To: dri-devel; +Cc: Gustavo Padovan, Daniel Vetter

From: Gustavo Padovan <gustavo.padovan@collabora.com>

Add support to async updates of cursors by using the new atomic
interface for that. Basically what this commit does is do what
intel_legacy_cursor_update() did but through atomic.

Cc: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
---
 drivers/gpu/drm/i915/intel_atomic_plane.c |  58 ++++++++++++
 drivers/gpu/drm/i915/intel_display.c      | 147 +++++-------------------------
 2 files changed, 79 insertions(+), 126 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index cfb4729..37924bb 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -246,11 +246,69 @@ static void intel_plane_atomic_update(struct drm_plane *plane,
 	}
 }
 
+static int intel_plane_atomic_async_check(struct drm_plane *plane,
+					  struct drm_plane_state *state)
+{
+	struct drm_crtc *crtc = plane->state->crtc;
+	struct drm_crtc_state *crtc_state = crtc->state;
+
+	if (plane->type != DRM_PLANE_TYPE_CURSOR)
+		return -EINVAL;
+
+	/*
+	 * When crtc is inactive or there is a modeset pending,
+	 * wait for it to complete in the slowpath
+	 */
+	if (!crtc_state->active || to_intel_crtc_state(crtc_state)->update_pipe)
+		return -EINVAL;
+
+	/* Only changing fb should be in the fastpath.  */
+	if (plane->state->crtc != state->crtc ||
+	    !plane->state->fb != !state->fb)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void intel_plane_atomic_async_update(struct drm_plane *plane,
+					    struct drm_plane_state *new_state)
+{
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct drm_crtc *crtc = plane->state->crtc;
+	struct drm_framebuffer *old_fb;
+	struct i915_vma *old_vma;
+
+	old_fb = plane->state->fb;
+	old_vma = to_intel_plane_state(plane->state)->vma;
+
+	i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(new_state->fb),
+			  intel_plane->frontbuffer_bit);
+
+	plane->state->fb = new_state->fb;
+	*to_intel_plane_state(plane->state) = *to_intel_plane_state(new_state);
+	new_state->fb = old_fb;
+	to_intel_plane_state(new_state)->vma = old_vma;
+
+	plane->state->visible = new_state->visible;
+
+	if (plane->state->visible) {
+		trace_intel_update_plane(plane, to_intel_crtc(crtc));
+		intel_plane->update_plane(plane,
+					  to_intel_crtc_state(crtc->state),
+					  to_intel_plane_state(plane->state));
+	} else {
+		trace_intel_disable_plane(plane, to_intel_crtc(crtc));
+		intel_plane->disable_plane(plane, crtc);
+	}
+}
+
 const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
 	.prepare_fb = intel_prepare_plane_fb,
 	.cleanup_fb = intel_cleanup_plane_fb,
 	.atomic_check = intel_plane_atomic_check,
 	.atomic_update = intel_plane_atomic_update,
+	.atomic_async_check = intel_plane_atomic_async_check,
+	.atomic_async_update = intel_plane_atomic_async_update,
 };
 
 /**
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e217d04..c854c87 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12993,13 +12993,29 @@ static int intel_atomic_commit(struct drm_device *dev,
 	int ret = 0;
 
 	/*
-	 * The intel_legacy_cursor_update() fast path takes care
+	 * The atomic async update fast path takes care
 	 * of avoiding the vblank waits for simple cursor
 	 * movement and flips. For cursor on/off and size changes,
 	 * we want to perform the vblank waits so that watermark
 	 * updates happen during the correct frames. Gen9+ have
 	 * double buffered watermarks and so shouldn't need this.
 	 */
+	if (state->async_update) {
+		ret = mutex_lock_interruptible(&dev->struct_mutex);
+		if (ret)
+			return ret;
+
+		ret = drm_atomic_helper_prepare_planes(dev, state);
+		mutex_unlock(&dev->struct_mutex);
+
+		drm_atomic_helper_async_commit(dev, state);
+
+		mutex_lock(&dev->struct_mutex);
+		drm_atomic_helper_cleanup_planes(dev, state);
+		mutex_unlock(&dev->struct_mutex);
+		return 0;
+	}
+
 	if (INTEL_GEN(dev_priv) < 9)
 		state->legacy_cursor_update = false;
 
@@ -13141,6 +13157,9 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 		}
 	}
 
+	if (new_state->state->async_update)
+		return 0;
+
 	if (!obj && !old_obj)
 		return 0;
 
@@ -13360,132 +13379,8 @@ const struct drm_plane_funcs intel_plane_funcs = {
 	.atomic_destroy_state = intel_plane_destroy_state,
 };
 
-static int
-intel_legacy_cursor_update(struct drm_plane *plane,
-			   struct drm_crtc *crtc,
-			   struct drm_framebuffer *fb,
-			   int crtc_x, int crtc_y,
-			   unsigned int crtc_w, unsigned int crtc_h,
-			   uint32_t src_x, uint32_t src_y,
-			   uint32_t src_w, uint32_t src_h,
-			   struct drm_modeset_acquire_ctx *ctx)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-	int ret;
-	struct drm_plane_state *old_plane_state, *new_plane_state;
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct drm_framebuffer *old_fb;
-	struct drm_crtc_state *crtc_state = crtc->state;
-	struct i915_vma *old_vma;
-
-	/*
-	 * When crtc is inactive or there is a modeset pending,
-	 * wait for it to complete in the slowpath
-	 */
-	if (!crtc_state->active || needs_modeset(crtc_state) ||
-	    to_intel_crtc_state(crtc_state)->update_pipe)
-		goto slow;
-
-	old_plane_state = plane->state;
-
-	/*
-	 * If any parameters change that may affect watermarks,
-	 * take the slowpath. Only changing fb or position should be
-	 * in the fastpath.
-	 */
-	if (old_plane_state->crtc != crtc ||
-	    old_plane_state->src_w != src_w ||
-	    old_plane_state->src_h != src_h ||
-	    old_plane_state->crtc_w != crtc_w ||
-	    old_plane_state->crtc_h != crtc_h ||
-	    !old_plane_state->fb != !fb)
-		goto slow;
-
-	new_plane_state = intel_plane_duplicate_state(plane);
-	if (!new_plane_state)
-		return -ENOMEM;
-
-	drm_atomic_set_fb_for_plane(new_plane_state, fb);
-
-	new_plane_state->src_x = src_x;
-	new_plane_state->src_y = src_y;
-	new_plane_state->src_w = src_w;
-	new_plane_state->src_h = src_h;
-	new_plane_state->crtc_x = crtc_x;
-	new_plane_state->crtc_y = crtc_y;
-	new_plane_state->crtc_w = crtc_w;
-	new_plane_state->crtc_h = crtc_h;
-
-	ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
-						  to_intel_plane_state(new_plane_state));
-	if (ret)
-		goto out_free;
-
-	ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
-	if (ret)
-		goto out_free;
-
-	if (INTEL_INFO(dev_priv)->cursor_needs_physical) {
-		int align = IS_I830(dev_priv) ? 16 * 1024 : 256;
-
-		ret = i915_gem_object_attach_phys(intel_fb_obj(fb), align);
-		if (ret) {
-			DRM_DEBUG_KMS("failed to attach phys object\n");
-			goto out_unlock;
-		}
-	} else {
-		struct i915_vma *vma;
-
-		vma = intel_pin_and_fence_fb_obj(fb, new_plane_state->rotation);
-		if (IS_ERR(vma)) {
-			DRM_DEBUG_KMS("failed to pin object\n");
-
-			ret = PTR_ERR(vma);
-			goto out_unlock;
-		}
-
-		to_intel_plane_state(new_plane_state)->vma = vma;
-	}
-
-	old_fb = old_plane_state->fb;
-	old_vma = to_intel_plane_state(old_plane_state)->vma;
-
-	i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb),
-			  intel_plane->frontbuffer_bit);
-
-	/* Swap plane state */
-	new_plane_state->fence = old_plane_state->fence;
-	*to_intel_plane_state(old_plane_state) = *to_intel_plane_state(new_plane_state);
-	new_plane_state->fence = NULL;
-	new_plane_state->fb = old_fb;
-	to_intel_plane_state(new_plane_state)->vma = old_vma;
-
-	if (plane->state->visible) {
-		trace_intel_update_plane(plane, to_intel_crtc(crtc));
-		intel_plane->update_plane(plane,
-					  to_intel_crtc_state(crtc->state),
-					  to_intel_plane_state(plane->state));
-	} else {
-		trace_intel_disable_plane(plane, to_intel_crtc(crtc));
-		intel_plane->disable_plane(plane, crtc);
-	}
-
-	intel_cleanup_plane_fb(plane, new_plane_state);
-
-out_unlock:
-	mutex_unlock(&dev_priv->drm.struct_mutex);
-out_free:
-	intel_plane_destroy_state(plane, new_plane_state);
-	return ret;
-
-slow:
-	return drm_atomic_helper_update_plane(plane, crtc, fb,
-					      crtc_x, crtc_y, crtc_w, crtc_h,
-					      src_x, src_y, src_w, src_h, ctx);
-}
-
 static const struct drm_plane_funcs intel_cursor_plane_funcs = {
-	.update_plane = intel_legacy_cursor_update,
+	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
 	.destroy = intel_plane_destroy,
 	.set_property = drm_atomic_helper_plane_set_property,
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC 4/7] drm/i915: remove intel_cursor_plane_funcs
  2017-04-10  0:24 [RFC 0/7] drm: asynchronous atomic plane update Gustavo Padovan
                   ` (2 preceding siblings ...)
  2017-04-10  0:24 ` [RFC 3/7] drm/i915: update cursors asynchronously through atomic Gustavo Padovan
@ 2017-04-10  0:24 ` Gustavo Padovan
  2017-04-10  0:24 ` [RFC 5/7] drm/msm: update cursors asynchronously through atomic Gustavo Padovan
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  0:24 UTC (permalink / raw)
  To: dri-devel; +Cc: Gustavo Padovan, Daniel Vetter

From: Gustavo Padovan <gustavo.padovan@collabora.com>

After converting legacy cursor updates to atomic async commits
intel_cursor_plane_funcs just duplicates intel_plane_funcs now.

Cc: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
---
 drivers/gpu/drm/i915/intel_display.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c854c87..26d20e5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13379,17 +13379,6 @@ const struct drm_plane_funcs intel_plane_funcs = {
 	.atomic_destroy_state = intel_plane_destroy_state,
 };
 
-static const struct drm_plane_funcs intel_cursor_plane_funcs = {
-	.update_plane = drm_atomic_helper_update_plane,
-	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
-	.set_property = drm_atomic_helper_plane_set_property,
-	.atomic_get_property = intel_plane_atomic_get_property,
-	.atomic_set_property = intel_plane_atomic_set_property,
-	.atomic_duplicate_state = intel_plane_duplicate_state,
-	.atomic_destroy_state = intel_plane_destroy_state,
-};
-
 static struct intel_plane *
 intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
@@ -13636,7 +13625,7 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
 	cursor->disable_plane = intel_disable_cursor_plane;
 
 	ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
-				       0, &intel_cursor_plane_funcs,
+				       0, &intel_plane_funcs,
 				       intel_cursor_formats,
 				       ARRAY_SIZE(intel_cursor_formats),
 				       DRM_PLANE_TYPE_CURSOR,
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC 5/7] drm/msm: update cursors asynchronously through atomic
  2017-04-10  0:24 [RFC 0/7] drm: asynchronous atomic plane update Gustavo Padovan
                   ` (3 preceding siblings ...)
  2017-04-10  0:24 ` [RFC 4/7] drm/i915: remove intel_cursor_plane_funcs Gustavo Padovan
@ 2017-04-10  0:24 ` Gustavo Padovan
  2017-04-10  0:24 ` [RFC 6/7] drm/msm: remove mdp5_cursor_plane_funcs Gustavo Padovan
  2017-04-10  0:24 ` [RFC 7/7] drm/vc4: update cursors asynchronously through atomic Gustavo Padovan
  6 siblings, 0 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  0:24 UTC (permalink / raw)
  To: dri-devel; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.com>

Add support to async updates of cursors by using the new atomic
interface for that. Basically what this commit does is do what
mdp5_update_cursor_plane_legacy() did but through atomic.

Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
---
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 141 ++++++++++++------------------
 1 file changed, 54 insertions(+), 87 deletions(-)

diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 60a5451..c72bc99 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -31,15 +31,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
 		struct drm_crtc *crtc, struct drm_framebuffer *fb,
 		struct drm_rect *src, struct drm_rect *dest);
 
-static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane,
-		struct drm_crtc *crtc,
-		struct drm_framebuffer *fb,
-		int crtc_x, int crtc_y,
-		unsigned int crtc_w, unsigned int crtc_h,
-		uint32_t src_x, uint32_t src_y,
-		uint32_t src_w, uint32_t src_h,
-		struct drm_modeset_acquire_ctx *ctx);
-
 static void set_scanout_locked(struct drm_plane *plane,
 		struct drm_framebuffer *fb);
 
@@ -253,7 +244,7 @@ static const struct drm_plane_funcs mdp5_plane_funcs = {
 };
 
 static const struct drm_plane_funcs mdp5_cursor_plane_funcs = {
-		.update_plane = mdp5_update_cursor_plane_legacy,
+		.update_plane = drm_atomic_helper_update_plane,
 		.disable_plane = drm_atomic_helper_disable_plane,
 		.destroy = mdp5_plane_destroy,
 		.set_property = drm_atomic_helper_plane_set_property,
@@ -430,11 +421,64 @@ static void mdp5_plane_atomic_update(struct drm_plane *plane,
 	}
 }
 
+static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
+					 struct drm_plane_state *state)
+{
+	struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
+	struct drm_crtc_state *crtc_state;
+
+	crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+							state->crtc);
+	if (WARN_ON(!crtc_state))
+		return -EINVAL;
+
+	if (!crtc_state->active)
+		return -EINVAL;
+
+	mdp5_state = to_mdp5_plane_state(state);
+
+	/* don't use fast path if we don't have a hwpipe allocated yet */
+	if (!mdp5_state->hwpipe)
+		return -EINVAL;
+
+	/* only allow changing of position(crtc x/y or src x/y) in fast path */
+	if (plane->state->crtc != state->crtc ||
+	    !state->fb || plane->state->fb != state->fb)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
+					   struct drm_plane_state *new_state)
+{
+	struct drm_plane_state *state = plane->state;
+
+	if (plane_enabled(state)) {
+		struct mdp5_ctl *ctl;
+		int ret;
+
+		ret = mdp5_plane_mode_set(plane,
+				state->crtc, state->fb,
+				&state->src, &state->dst);
+		WARN_ON(ret < 0);
+
+		ctl = mdp5_crtc_get_ctl(state->crtc);
+
+		mdp5_ctl_commit(ctl, mdp5_plane_get_flush(plane));
+	}
+
+	*to_mdp5_plane_state(plane->state) =
+		*to_mdp5_plane_state(new_state);
+}
+
 static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
 		.prepare_fb = mdp5_plane_prepare_fb,
 		.cleanup_fb = mdp5_plane_cleanup_fb,
 		.atomic_check = mdp5_plane_atomic_check,
 		.atomic_update = mdp5_plane_atomic_update,
+		.atomic_async_check = mdp5_plane_atomic_async_check,
+		.atomic_async_update = mdp5_plane_atomic_async_update,
 };
 
 static void set_scanout_locked(struct drm_plane *plane,
@@ -882,83 +926,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
 	return ret;
 }
 
-static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane,
-			struct drm_crtc *crtc, struct drm_framebuffer *fb,
-			int crtc_x, int crtc_y,
-			unsigned int crtc_w, unsigned int crtc_h,
-			uint32_t src_x, uint32_t src_y,
-			uint32_t src_w, uint32_t src_h,
-			struct drm_modeset_acquire_ctx *ctx)
-{
-	struct drm_plane_state *plane_state, *new_plane_state;
-	struct mdp5_plane_state *mdp5_pstate;
-	struct drm_crtc_state *crtc_state = crtc->state;
-	int ret;
-
-	if (!crtc_state->active || drm_atomic_crtc_needs_modeset(crtc_state))
-		goto slow;
-
-	plane_state = plane->state;
-	mdp5_pstate = to_mdp5_plane_state(plane_state);
-
-	/* don't use fast path if we don't have a hwpipe allocated yet */
-	if (!mdp5_pstate->hwpipe)
-		goto slow;
-
-	/* only allow changing of position(crtc x/y or src x/y) in fast path */
-	if (plane_state->crtc != crtc ||
-	    plane_state->src_w != src_w ||
-	    plane_state->src_h != src_h ||
-	    plane_state->crtc_w != crtc_w ||
-	    plane_state->crtc_h != crtc_h ||
-	    !plane_state->fb ||
-	    plane_state->fb != fb)
-		goto slow;
-
-	new_plane_state = mdp5_plane_duplicate_state(plane);
-	if (!new_plane_state)
-		return -ENOMEM;
-
-	new_plane_state->src_x = src_x;
-	new_plane_state->src_y = src_y;
-	new_plane_state->src_w = src_w;
-	new_plane_state->src_h = src_h;
-	new_plane_state->crtc_x = crtc_x;
-	new_plane_state->crtc_y = crtc_y;
-	new_plane_state->crtc_w = crtc_w;
-	new_plane_state->crtc_h = crtc_h;
-
-	ret = mdp5_plane_atomic_check_with_state(crtc_state, new_plane_state);
-	if (ret)
-		goto slow_free;
-
-	if (new_plane_state->visible) {
-		struct mdp5_ctl *ctl;
-
-		ret = mdp5_plane_mode_set(plane, crtc, fb,
-					  &new_plane_state->src,
-					  &new_plane_state->dst);
-		WARN_ON(ret < 0);
-
-		ctl = mdp5_crtc_get_ctl(crtc);
-
-		mdp5_ctl_commit(ctl, mdp5_plane_get_flush(plane));
-	}
-
-	*to_mdp5_plane_state(plane_state) =
-		*to_mdp5_plane_state(new_plane_state);
-
-	mdp5_plane_destroy_state(plane, new_plane_state);
-
-	return 0;
-slow_free:
-	mdp5_plane_destroy_state(plane, new_plane_state);
-slow:
-	return drm_atomic_helper_update_plane(plane, crtc, fb,
-					      crtc_x, crtc_y, crtc_w, crtc_h,
-					      src_x, src_y, src_w, src_h, ctx);
-}
-
 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
 {
 	struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC 6/7] drm/msm: remove mdp5_cursor_plane_funcs
  2017-04-10  0:24 [RFC 0/7] drm: asynchronous atomic plane update Gustavo Padovan
                   ` (4 preceding siblings ...)
  2017-04-10  0:24 ` [RFC 5/7] drm/msm: update cursors asynchronously through atomic Gustavo Padovan
@ 2017-04-10  0:24 ` Gustavo Padovan
  2017-04-10  0:24 ` [RFC 7/7] drm/vc4: update cursors asynchronously through atomic Gustavo Padovan
  6 siblings, 0 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  0:24 UTC (permalink / raw)
  To: dri-devel; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.com>

After converting legacy cursor updates to atomic async commits
mdp5_cursor_plane_funcs just duplicates mdp5_plane_funcs now.

Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
---
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 26 +++-----------------------
 1 file changed, 3 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index c72bc99..371c301 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -243,19 +243,6 @@ static const struct drm_plane_funcs mdp5_plane_funcs = {
 		.atomic_print_state = mdp5_plane_atomic_print_state,
 };
 
-static const struct drm_plane_funcs mdp5_cursor_plane_funcs = {
-		.update_plane = drm_atomic_helper_update_plane,
-		.disable_plane = drm_atomic_helper_disable_plane,
-		.destroy = mdp5_plane_destroy,
-		.set_property = drm_atomic_helper_plane_set_property,
-		.atomic_set_property = mdp5_plane_atomic_set_property,
-		.atomic_get_property = mdp5_plane_atomic_get_property,
-		.reset = mdp5_plane_reset,
-		.atomic_duplicate_state = mdp5_plane_duplicate_state,
-		.atomic_destroy_state = mdp5_plane_destroy_state,
-		.atomic_print_state = mdp5_plane_atomic_print_state,
-};
-
 static int mdp5_plane_prepare_fb(struct drm_plane *plane,
 				 struct drm_plane_state *new_state)
 {
@@ -965,16 +952,9 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
 	mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
 		ARRAY_SIZE(mdp5_plane->formats), false);
 
-	if (type == DRM_PLANE_TYPE_CURSOR)
-		ret = drm_universal_plane_init(dev, plane, 0xff,
-				&mdp5_cursor_plane_funcs,
-				mdp5_plane->formats, mdp5_plane->nformats,
-				type, NULL);
-	else
-		ret = drm_universal_plane_init(dev, plane, 0xff,
-				&mdp5_plane_funcs,
-				mdp5_plane->formats, mdp5_plane->nformats,
-				type, NULL);
+	ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
+				       mdp5_plane->formats,
+				       mdp5_plane->nformats, type, NULL);
 	if (ret)
 		goto fail;
 
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC 7/7] drm/vc4: update cursors asynchronously through atomic
  2017-04-10  0:24 [RFC 0/7] drm: asynchronous atomic plane update Gustavo Padovan
                   ` (5 preceding siblings ...)
  2017-04-10  0:24 ` [RFC 6/7] drm/msm: remove mdp5_cursor_plane_funcs Gustavo Padovan
@ 2017-04-10  0:24 ` Gustavo Padovan
  2017-04-10 20:06   ` Eric Anholt
  2017-05-18 22:52   ` Robert Foss
  6 siblings, 2 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  0:24 UTC (permalink / raw)
  To: dri-devel; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.com>

Add support to async updates of cursors by using the new atomic
interface for that. Basically what this commit does is do what
vc4_update_plane() did but through atomic.

Cc: Eric Anholt <eric@anholt.net>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
---
 drivers/gpu/drm/vc4/vc4_plane.c | 94 ++++++++++++-----------------------------
 1 file changed, 27 insertions(+), 67 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index d34cd53..e33c75b 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -735,70 +735,27 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
 	vc4_state->dlist[vc4_state->ptr0_offset] = addr;
 }
 
-static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
-	.atomic_check = vc4_plane_atomic_check,
-	.atomic_update = vc4_plane_atomic_update,
-};
-
-static void vc4_plane_destroy(struct drm_plane *plane)
-{
-	drm_plane_helper_disable(plane);
-	drm_plane_cleanup(plane);
-}
-
-/* Implements immediate (non-vblank-synced) updates of the cursor
- * position, or falls back to the atomic helper otherwise.
- */
-static int
-vc4_update_plane(struct drm_plane *plane,
-		 struct drm_crtc *crtc,
-		 struct drm_framebuffer *fb,
-		 int crtc_x, int crtc_y,
-		 unsigned int crtc_w, unsigned int crtc_h,
-		 uint32_t src_x, uint32_t src_y,
-		 uint32_t src_w, uint32_t src_h,
-		 struct drm_modeset_acquire_ctx *ctx)
+static int vc4_plane_atomic_async_check(struct drm_plane *plane,
+					struct drm_plane_state *state)
 {
-	struct drm_plane_state *plane_state;
-	struct vc4_plane_state *vc4_state;
-
-	if (plane != crtc->cursor)
-		goto out;
-
-	plane_state = plane->state;
-	vc4_state = to_vc4_plane_state(plane_state);
-
-	if (!plane_state)
-		goto out;
+	if (plane != state->crtc->cursor)
+		return -EINVAL;
 
-	/* No configuring new scaling in the fast path. */
-	if (crtc_w != plane_state->crtc_w ||
-	    crtc_h != plane_state->crtc_h ||
-	    src_w != plane_state->src_w ||
-	    src_h != plane_state->src_h) {
-		goto out;
-	}
+	if (!plane->state)
+		return -EINVAL;
 
-	if (fb != plane_state->fb) {
-		drm_atomic_set_fb_for_plane(plane->state, fb);
-		vc4_plane_async_set_fb(plane, fb);
-	}
+	return 0;
+}
 
-	/* Set the cursor's position on the screen.  This is the
-	 * expected change from the drm_mode_cursor_universal()
-	 * helper.
-	 */
-	plane_state->crtc_x = crtc_x;
-	plane_state->crtc_y = crtc_y;
+static void vc4_plane_atomic_async_update(struct drm_plane *plane,
+					  struct drm_plane_state *new_state)
+{
+	struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
 
-	/* Allow changing the start position within the cursor BO, if
-	 * that matters.
-	 */
-	plane_state->src_x = src_x;
-	plane_state->src_y = src_y;
+	if (plane->state->fb != new_state->fb)
+		vc4_plane_async_set_fb(plane, new_state->fb);
 
-	/* Update the display list based on the new crtc_x/y. */
-	vc4_plane_atomic_check(plane, plane_state);
+	plane->state->fb = new_state->fb;
 
 	/* Note that we can't just call vc4_plane_write_dlist()
 	 * because that would smash the context data that the HVS is
@@ -810,20 +767,23 @@ vc4_update_plane(struct drm_plane *plane,
 	       &vc4_state->hw_dlist[vc4_state->pos2_offset]);
 	writel(vc4_state->dlist[vc4_state->ptr0_offset],
 	       &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
+}
 
-	return 0;
+static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
+	.atomic_check = vc4_plane_atomic_check,
+	.atomic_update = vc4_plane_atomic_update,
+	.atomic_async_check = vc4_plane_atomic_async_check,
+	.atomic_async_update = vc4_plane_atomic_async_update,
+};
 
-out:
-	return drm_atomic_helper_update_plane(plane, crtc, fb,
-					      crtc_x, crtc_y,
-					      crtc_w, crtc_h,
-					      src_x, src_y,
-					      src_w, src_h,
-					      ctx);
+static void vc4_plane_destroy(struct drm_plane *plane)
+{
+	drm_plane_helper_disable(plane);
+	drm_plane_cleanup(plane);
 }
 
 static const struct drm_plane_funcs vc4_plane_funcs = {
-	.update_plane = vc4_update_plane,
+	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
 	.destroy = vc4_plane_destroy,
 	.set_property = NULL,
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-04-10  0:24 ` [RFC 1/7] drm/atomic: initial support for asynchronous " Gustavo Padovan
@ 2017-04-10  7:13   ` Emil Velikov
  2017-04-10  9:39     ` Gustavo Padovan
  2017-04-10 19:55   ` Eric Anholt
  1 sibling, 1 reply; 20+ messages in thread
From: Emil Velikov @ 2017-04-10  7:13 UTC (permalink / raw)
  To: Gustavo Padovan; +Cc: Gustavo Padovan, ML dri-devel, Daniel Vetter

Hi Gustavo,

Mostly some documentation suggestions below. Hope that I've not lost
the plot and they seem ok :-)

On 10 April 2017 at 01:24, Gustavo Padovan <gustavo@padovan.org> wrote:

> +static bool drm_atomic_async_check(struct drm_atomic_state *state)
> +{

/* FIXME: we support single plane updates for now */
> +       if (!plane || n_planes != 1)
> +               return false;
> +

> +       if (!funcs->atomic_async_update)
> +               return false;


> +void drm_atomic_helper_async_commit(struct drm_device *dev,
> +                                   struct drm_atomic_state *state)
> +{
> +       struct drm_plane *plane;
> +       struct drm_plane_state *plane_state;
> +       const struct drm_plane_helper_funcs *funcs;
> +       int i;
> +
> +       for_each_new_plane_in_state(state, plane, plane_state, i) {
> +               funcs = plane->helper_private;
> +
> +               plane->state->src_x = plane_state->src_x;
> +               plane->state->src_y = plane_state->src_y;
> +               plane->state->crtc_x = plane_state->crtc_x;
> +               plane->state->crtc_y = plane_state->crtc_y;
> +
> +               if (funcs && funcs->atomic_async_update)
> +                       funcs->atomic_async_update(plane, plane_state);

This looks a bit strange. We don't want to change any state if the
hook is missing right?
Actually the if will always be true, since we've already validated
that in drm_atomic_async_check().

Should we unconditionally call funcs->atomic_async_update()?


> @@ -172,6 +174,8 @@ struct drm_atomic_state {
>         struct drm_device *dev;
>         bool allow_modeset : 1;
>         bool legacy_cursor_update : 1;
> +       bool legacy_set_config : 1;
Seems unused in this patch. Introduce at a later stage?


> --- a/include/drm/drm_modeset_helper_vtables.h
> +++ b/include/drm/drm_modeset_helper_vtables.h
> @@ -1048,6 +1048,53 @@ struct drm_plane_helper_funcs {
>          */
>         void (*atomic_disable)(struct drm_plane *plane,
>                                struct drm_plane_state *old_state);
> +
> +       /**
> +        * @atomic_async_check:
> +        *
> +        * Drivers should use this function check if the plane state
s/use this function check/set this function pointer/

> +        * can be updated in a async fashion.
> +        *
> +        * This hook is called by drm_atomic_async_check() in the process
> +        * to figure out if an given update can be committed asynchronously,
s/in the process to figure out if an/to establish if a/ s/,/./

> +        * that is, if it can jump ahead the state currently queued for
> +        * update.
> +        *
> +        * Check drm_atomic_async_check() to see what is already there
> +        * to discover potential async updates.
Remove these two sentences? They don't seem to bring much.

> +        *
> +        * RETURNS:
> +        *
> +        * Return 0 on success and -EINVAL if the update can't be async.
s/if the update can't be async/on error/

> +        * Error return doesn't mean that the update can't be applied,
> +        * it just mean that it can't be an async one.
> +        *
Any error returned indicates that the update can not be applied in
asynchronous manner.
Side-note: suggest who/how to retry synchronously ?

> +        * FIXME:
> +        *  - It only works for single plane updates
> +        *  - It can't do async update if the plane is already being update
> +        *  by the queued state
> +        *  - Async Pageflips are not supported yet
> +        */
> +       int (*atomic_async_check)(struct drm_plane *plane,
> +                                 struct drm_plane_state *state);
> +
> +       /**
> +        * @atomic_async_update:
> +        *
> +        * Drivers should use this functions to perform asynchronous
As above - drivers do not use this function. They only provide the
function pointer, right?

> +        * updates of planes, that is jump ahead the currently queued
> +        * state for and update the plane.
> +        *
> +        * This hook is called by drm_atomic_helper_async_commit().
> +        *
> +        * Note that differently from the &drm_plane_helper_funcs.atomic_update
s/differently from the/unlike/

> +        * this hook takes the new &drm_plane_state as parameter. When doing
> +        * async_update drivers shouldn't replace the &drm_plane_state but
> +        * just, update the current one with the new plane configurations in
s/just,// or s/just,/simply/

Regards,
Emil
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-04-10  7:13   ` Emil Velikov
@ 2017-04-10  9:39     ` Gustavo Padovan
  0 siblings, 0 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-10  9:39 UTC (permalink / raw)
  To: Emil Velikov; +Cc: Gustavo Padovan, ML dri-devel, Daniel Vetter

Hi Emil,

Thank you for your review!

2017-04-10 Emil Velikov <emil.l.velikov@gmail.com>:

> Hi Gustavo,
> 
> Mostly some documentation suggestions below. Hope that I've not lost
> the plot and they seem ok :-)
> 
> On 10 April 2017 at 01:24, Gustavo Padovan <gustavo@padovan.org> wrote:
> 
> > +static bool drm_atomic_async_check(struct drm_atomic_state *state)
> > +{
> 
> /* FIXME: we support single plane updates for now */
> > +       if (!plane || n_planes != 1)
> > +               return false;
> > +
> 
> > +       if (!funcs->atomic_async_update)
> > +               return false;
> 
> 
> > +void drm_atomic_helper_async_commit(struct drm_device *dev,
> > +                                   struct drm_atomic_state *state)
> > +{
> > +       struct drm_plane *plane;
> > +       struct drm_plane_state *plane_state;
> > +       const struct drm_plane_helper_funcs *funcs;
> > +       int i;
> > +
> > +       for_each_new_plane_in_state(state, plane, plane_state, i) {
> > +               funcs = plane->helper_private;
> > +
> > +               plane->state->src_x = plane_state->src_x;
> > +               plane->state->src_y = plane_state->src_y;
> > +               plane->state->crtc_x = plane_state->crtc_x;
> > +               plane->state->crtc_y = plane_state->crtc_y;
> > +
> > +               if (funcs && funcs->atomic_async_update)
> > +                       funcs->atomic_async_update(plane, plane_state);
> 
> This looks a bit strange. We don't want to change any state if the
> hook is missing right?
> Actually the if will always be true, since we've already validated
> that in drm_atomic_async_check().
> 
> Should we unconditionally call funcs->atomic_async_update()?

That would be much better. I'll do that.

> 
> 
> > @@ -172,6 +174,8 @@ struct drm_atomic_state {
> >         struct drm_device *dev;
> >         bool allow_modeset : 1;
> >         bool legacy_cursor_update : 1;
> > +       bool legacy_set_config : 1;
> Seems unused in this patch. Introduce at a later stage?

Hmm, rebase garbage. :(  Sorry about that.

> 
> 
> > --- a/include/drm/drm_modeset_helper_vtables.h
> > +++ b/include/drm/drm_modeset_helper_vtables.h
> > @@ -1048,6 +1048,53 @@ struct drm_plane_helper_funcs {
> >          */
> >         void (*atomic_disable)(struct drm_plane *plane,
> >                                struct drm_plane_state *old_state);
> > +
> > +       /**
> > +        * @atomic_async_check:
> > +        *
> > +        * Drivers should use this function check if the plane state
> s/use this function check/set this function pointer/
> 
> > +        * can be updated in a async fashion.
> > +        *
> > +        * This hook is called by drm_atomic_async_check() in the process
> > +        * to figure out if an given update can be committed asynchronously,
> s/in the process to figure out if an/to establish if a/ s/,/./
> 
> > +        * that is, if it can jump ahead the state currently queued for
> > +        * update.
> > +        *
> > +        * Check drm_atomic_async_check() to see what is already there
> > +        * to discover potential async updates.
> Remove these two sentences? They don't seem to bring much.
> 
> > +        *
> > +        * RETURNS:
> > +        *
> > +        * Return 0 on success and -EINVAL if the update can't be async.
> s/if the update can't be async/on error/

I don't think that is an error, it just can't be async so the regular 
atomic sync commit will be performed. For async page flip this would be
a show stopper error, but we are not there yet.

> 
> > +        * Error return doesn't mean that the update can't be applied,
> > +        * it just mean that it can't be an async one.
> > +        *
> Any error returned indicates that the update can not be applied in
> asynchronous manner.
> Side-note: suggest who/how to retry synchronously ?

Retry synchronously is the default fallback. Actually it is the
opposite, async is a special shortcut of sync.

Gustavo
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-04-10  0:24 ` [RFC 1/7] drm/atomic: initial support for asynchronous " Gustavo Padovan
  2017-04-10  7:13   ` Emil Velikov
@ 2017-04-10 19:55   ` Eric Anholt
  2017-04-11 20:23     ` Daniel Vetter
  1 sibling, 1 reply; 20+ messages in thread
From: Eric Anholt @ 2017-04-10 19:55 UTC (permalink / raw)
  To: Gustavo Padovan, dri-devel; +Cc: Gustavo Padovan, Daniel Vetter


[-- Attachment #1.1: Type: text/plain, Size: 8630 bytes --]

Gustavo Padovan <gustavo@padovan.org> writes:

> From: Gustavo Padovan <gustavo.padovan@collabora.com>
>
> In some cases, like cursor updates, it is interesting to update the
> plane in an asynchronous fashion to avoid big delays.
>
> The current queued update could be still waiting for a fence to signal and
> thus block and subsequent update until its scan out. In cases like this if
> we update the cursor synchronously it will cause significant delays on
> some platforms that would be noticed by the final user.
>
> This patch creates a fast path to jump ahead the current queued state and
> do single planes updates without going through all atomic step in
> drm_atomic_helper_commit().
>
> For now only single plane updates are supported and only if there is no
> update to that plane in the queued state.
>
> We plan to support async PageFlips through this interface as well in the
> near future.

This looks really nice -- the vc4 code for cursors was really gross to
write, and I got it wrong a couple of times.  Couple of comments inline.

> ---
>  drivers/gpu/drm/drm_atomic.c             | 75 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_atomic_helper.c      | 41 +++++++++++++++++
>  include/drm/drm_atomic.h                 |  4 ++
>  include/drm/drm_atomic_helper.h          |  2 +
>  include/drm/drm_modeset_helper_vtables.h | 47 ++++++++++++++++++++
>  5 files changed, 169 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index f32506a..cae0122 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -631,6 +631,79 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
>  	return 0;
>  }
>  
> +static bool drm_atomic_async_check(struct drm_atomic_state *state)
> +{
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *crtc_state;
> +	struct drm_crtc_commit *commit;
> +	struct drm_plane *__plane, *plane = NULL;
> +	struct drm_plane_state *__plane_state, *plane_state = NULL;
> +	const struct drm_plane_helper_funcs *funcs;
> +	int i, n_planes = 0;
> +
> +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> +		if (drm_atomic_crtc_needs_modeset(crtc_state))
> +			return false;
> +	}
> +
> +	for_each_new_plane_in_state(state, __plane, __plane_state, i) {
> +		n_planes++;
> +		plane = __plane;
> +		plane_state = __plane_state;
> +	}
> +
> +	if (!plane || n_planes != 1)
> +		return false;
> +
> +	if (!plane->state->crtc)
> +		return false;
> +
> +	if (plane_state->fence)
> +		return false;
> +
> +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> +		if (plane->crtc != crtc)
> +			continue;
> +
> +		spin_lock(&crtc->commit_lock);
> +		commit = list_first_entry_or_null(&crtc->commit_list,
> +						  struct drm_crtc_commit,
> +						  commit_entry);
> +		if (!commit) {
> +			spin_unlock(&crtc->commit_lock);
> +			continue;
> +		}
> +		spin_unlock(&crtc->commit_lock);
> +
> +		for_each_plane_in_state(crtc_state->state, __plane,
> +					__plane_state, i) {
> +			if (__plane == plane) {
> +				return false;
> +			}
> +		}
> +	}
> +
> +	/* Not configuring new scaling in the async path. */

s/Not/No/

> +	if (plane->state->crtc_w != plane_state->crtc_w ||
> +	    plane->state->crtc_h != plane_state->crtc_h ||
> +	    plane->state->src_w != plane_state->src_w ||
> +	    plane->state->src_h != plane_state->src_h) {
> +		return false;
> +	}
> +
> +	funcs = plane->helper_private;
> +
> +	if (!funcs->atomic_async_update)
> +		return false;
> +
> +	if (funcs->atomic_async_check) {
> +		if (funcs->atomic_async_check(plane, plane_state) < 0)
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
>  static void drm_atomic_crtc_print_state(struct drm_printer *p,
>  		const struct drm_crtc_state *state)
>  {
> @@ -1591,6 +1664,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
>  		}
>  	}
>  
> +	state->async_update = drm_atomic_async_check(state);
> +
>  	return ret;
>  }

The promotion of any modeset that passes the async_check test to async
seems weird -- shouldn't we only be doing that if userspace requested
async?  Right now it seems like we're just getting lucky because only
cursor planes have it set, and the cursor update ioctls imply async.

>  EXPORT_SYMBOL(drm_atomic_check_only);
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 8be9719..a79e06c 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1235,6 +1235,36 @@ static void commit_work(struct work_struct *work)
>  }
>  
>  /**
> + * drm_atomic_helper_async_commit - commit state asynchronously
> + *
> + * This function commits a state asynchronously. It should be used
> + * on a state only when drm_atomic_async_check() succeds. Async
> + * commits are not supposed to swap the states like normal sync commits,
> + * but just do in-place change on the current state.
> + */
> +void drm_atomic_helper_async_commit(struct drm_device *dev,
> +				    struct drm_atomic_state *state)
> +{
> +	struct drm_plane *plane;
> +	struct drm_plane_state *plane_state;
> +	const struct drm_plane_helper_funcs *funcs;
> +	int i;
> +
> +	for_each_new_plane_in_state(state, plane, plane_state, i) {
> +		funcs = plane->helper_private;
> +
> +		plane->state->src_x = plane_state->src_x;
> +		plane->state->src_y = plane_state->src_y;
> +		plane->state->crtc_x = plane_state->crtc_x;
> +		plane->state->crtc_y = plane_state->crtc_y;
> +
> +		if (funcs && funcs->atomic_async_update)
> +			funcs->atomic_async_update(plane, plane_state);
> +	}
> +}

It seems strange to me that the async_update() implementation in the
driver needs to update the state->fb but not the x/y.  Could we move the
core's x/y update after the call into the driver, and then update
plane->state->fb in the core instead of the driver?

> +EXPORT_SYMBOL(drm_atomic_helper_async_commit);
> +
> +/**
>   * drm_atomic_helper_commit - commit validated state object
>   * @dev: DRM device
>   * @state: the driver state object
> @@ -1258,6 +1288,17 @@ int drm_atomic_helper_commit(struct drm_device *dev,
>  {
>  	int ret;
>  
> +	if (state->async_update) {
> +		ret = drm_atomic_helper_prepare_planes(dev, state);
> +		if (ret)
> +			return ret;
> +
> +		drm_atomic_helper_async_commit(dev, state);
> +		drm_atomic_helper_cleanup_planes(dev, state);
> +
> +		return 0;
> +	}
> +
>  	ret = drm_atomic_helper_setup_commit(state, nonblock);
>  	if (ret)
>  		return ret;
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 788daf7..c00c565 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h

> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> index c01c328..3efa4cc 100644
> --- a/include/drm/drm_modeset_helper_vtables.h
> +++ b/include/drm/drm_modeset_helper_vtables.h

> +	 *
> +	 * Check drm_atomic_async_check() to see what is already there
> +	 * to discover potential async updates.
> +	 *
> +	 * RETURNS:
> +	 *
> +	 * Return 0 on success and -EINVAL if the update can't be async.
> +	 * Error return doesn't mean that the update can't be applied,
> +	 * it just mean that it can't be an async one.
> +	 *
> +	 * FIXME:
> +	 *  - It only works for single plane updates
> +	 *  - It can't do async update if the plane is already being update
> +	 *  by the queued state

"already being updated"

> +	 *  - Async Pageflips are not supported yet
> +	 */
> +	int (*atomic_async_check)(struct drm_plane *plane,
> +				  struct drm_plane_state *state);
> +
> +	/**
> +	 * @atomic_async_update:
> +	 *
> +	 * Drivers should use this functions to perform asynchronous

"this function"

Also, maybe clarify that "async" means "not vblank synchronized"?

> +	 * updates of planes, that is jump ahead the currently queued
> +	 * state for and update the plane.
> +	 *
> +	 * This hook is called by drm_atomic_helper_async_commit().
> +	 *
> +	 * Note that differently from the &drm_plane_helper_funcs.atomic_update
> +	 * this hook takes the new &drm_plane_state as parameter. When doing
> +	 * async_update drivers shouldn't replace the &drm_plane_state but
> +	 * just, update the current one with the new plane configurations in
> +	 * the new plane_state.
> +	 */
> +	void (*atomic_async_update)(struct drm_plane *plane,
> +				    struct drm_plane_state *new_state);
>  };
>  
>  /**
> -- 
> 2.9.3

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 7/7] drm/vc4: update cursors asynchronously through atomic
  2017-04-10  0:24 ` [RFC 7/7] drm/vc4: update cursors asynchronously through atomic Gustavo Padovan
@ 2017-04-10 20:06   ` Eric Anholt
  2017-04-11 20:27     ` Daniel Vetter
  2017-05-18 22:52   ` Robert Foss
  1 sibling, 1 reply; 20+ messages in thread
From: Eric Anholt @ 2017-04-10 20:06 UTC (permalink / raw)
  To: Gustavo Padovan, dri-devel; +Cc: Gustavo Padovan


[-- Attachment #1.1: Type: text/plain, Size: 4212 bytes --]

Gustavo Padovan <gustavo@padovan.org> writes:

> From: Gustavo Padovan <gustavo.padovan@collabora.com>
>
> Add support to async updates of cursors by using the new atomic
> interface for that. Basically what this commit does is do what
> vc4_update_plane() did but through atomic.
>
> Cc: Eric Anholt <eric@anholt.net>
> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
> ---
>  drivers/gpu/drm/vc4/vc4_plane.c | 94 ++++++++++++-----------------------------
>  1 file changed, 27 insertions(+), 67 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
> index d34cd53..e33c75b 100644
> --- a/drivers/gpu/drm/vc4/vc4_plane.c
> +++ b/drivers/gpu/drm/vc4/vc4_plane.c
> @@ -735,70 +735,27 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
>  	vc4_state->dlist[vc4_state->ptr0_offset] = addr;
>  }
>  
> -static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
> -	.atomic_check = vc4_plane_atomic_check,
> -	.atomic_update = vc4_plane_atomic_update,
> -};
> -
> -static void vc4_plane_destroy(struct drm_plane *plane)
> -{
> -	drm_plane_helper_disable(plane);
> -	drm_plane_cleanup(plane);
> -}
> -
> -/* Implements immediate (non-vblank-synced) updates of the cursor
> - * position, or falls back to the atomic helper otherwise.
> - */
> -static int
> -vc4_update_plane(struct drm_plane *plane,
> -		 struct drm_crtc *crtc,
> -		 struct drm_framebuffer *fb,
> -		 int crtc_x, int crtc_y,
> -		 unsigned int crtc_w, unsigned int crtc_h,
> -		 uint32_t src_x, uint32_t src_y,
> -		 uint32_t src_w, uint32_t src_h,
> -		 struct drm_modeset_acquire_ctx *ctx)
> +static int vc4_plane_atomic_async_check(struct drm_plane *plane,
> +					struct drm_plane_state *state)
>  {
> -	struct drm_plane_state *plane_state;
> -	struct vc4_plane_state *vc4_state;
> -
> -	if (plane != crtc->cursor)
> -		goto out;
> -
> -	plane_state = plane->state;
> -	vc4_state = to_vc4_plane_state(plane_state);
> -
> -	if (!plane_state)
> -		goto out;
> +	if (plane != state->crtc->cursor)
> +		return -EINVAL;
>  
> -	/* No configuring new scaling in the fast path. */
> -	if (crtc_w != plane_state->crtc_w ||
> -	    crtc_h != plane_state->crtc_h ||
> -	    src_w != plane_state->src_w ||
> -	    src_h != plane_state->src_h) {
> -		goto out;
> -	}
> +	if (!plane->state)
> +		return -EINVAL;
>  
> -	if (fb != plane_state->fb) {
> -		drm_atomic_set_fb_for_plane(plane->state, fb);
> -		vc4_plane_async_set_fb(plane, fb);
> -	}
> +	return 0;
> +}
>  
> -	/* Set the cursor's position on the screen.  This is the
> -	 * expected change from the drm_mode_cursor_universal()
> -	 * helper.
> -	 */
> -	plane_state->crtc_x = crtc_x;
> -	plane_state->crtc_y = crtc_y;
> +static void vc4_plane_atomic_async_update(struct drm_plane *plane,
> +					  struct drm_plane_state *new_state)
> +{
> +	struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
>  
> -	/* Allow changing the start position within the cursor BO, if
> -	 * that matters.
> -	 */
> -	plane_state->src_x = src_x;
> -	plane_state->src_y = src_y;
> +	if (plane->state->fb != new_state->fb)
> +		vc4_plane_async_set_fb(plane, new_state->fb);
>  
> -	/* Update the display list based on the new crtc_x/y. */
> -	vc4_plane_atomic_check(plane, plane_state);
> +	plane->state->fb = new_state->fb;

The vc4_plane_atomic_check() is what sets up the dlist[]'s position
fields that are used right after this, so this call needs to stay in
place, and x/y need to be updated already (since we're looking at
plane->state, not new_state).

Also, I think we'll need to make sure that you're not trying to
enable/disable the plane in the fast path, since we're not updating the
CTL0_VALID field.

>  	/* Note that we can't just call vc4_plane_write_dlist()
>  	 * because that would smash the context data that the HVS is
> @@ -810,20 +767,23 @@ vc4_update_plane(struct drm_plane *plane,
>  	       &vc4_state->hw_dlist[vc4_state->pos2_offset]);
>  	writel(vc4_state->dlist[vc4_state->ptr0_offset],
>  	       &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
> +}

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-04-10 19:55   ` Eric Anholt
@ 2017-04-11 20:23     ` Daniel Vetter
  2017-04-12 18:17       ` Gustavo Padovan
  2017-04-21 18:41       ` Gustavo Padovan
  0 siblings, 2 replies; 20+ messages in thread
From: Daniel Vetter @ 2017-04-11 20:23 UTC (permalink / raw)
  To: Eric Anholt; +Cc: Daniel Vetter, dri-devel, Gustavo Padovan

On Mon, Apr 10, 2017 at 12:55:33PM -0700, Eric Anholt wrote:
> Gustavo Padovan <gustavo@padovan.org> writes:
> 
> > From: Gustavo Padovan <gustavo.padovan@collabora.com>
> >
> > In some cases, like cursor updates, it is interesting to update the
> > plane in an asynchronous fashion to avoid big delays.
> >
> > The current queued update could be still waiting for a fence to signal and
> > thus block and subsequent update until its scan out. In cases like this if
> > we update the cursor synchronously it will cause significant delays on
> > some platforms that would be noticed by the final user.
> >
> > This patch creates a fast path to jump ahead the current queued state and
> > do single planes updates without going through all atomic step in
> > drm_atomic_helper_commit().
> >
> > For now only single plane updates are supported and only if there is no
> > update to that plane in the queued state.
> >
> > We plan to support async PageFlips through this interface as well in the
> > near future.
> 
> This looks really nice -- the vc4 code for cursors was really gross to
> write, and I got it wrong a couple of times.  Couple of comments inline.

Some more comments below.
-Daniel

> 
> > ---
> >  drivers/gpu/drm/drm_atomic.c             | 75 ++++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/drm_atomic_helper.c      | 41 +++++++++++++++++
> >  include/drm/drm_atomic.h                 |  4 ++
> >  include/drm/drm_atomic_helper.h          |  2 +
> >  include/drm/drm_modeset_helper_vtables.h | 47 ++++++++++++++++++++
> >  5 files changed, 169 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > index f32506a..cae0122 100644
> > --- a/drivers/gpu/drm/drm_atomic.c
> > +++ b/drivers/gpu/drm/drm_atomic.c
> > @@ -631,6 +631,79 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
> >  	return 0;
> >  }
> >  
> > +static bool drm_atomic_async_check(struct drm_atomic_state *state)
> > +{
> > +	struct drm_crtc *crtc;
> > +	struct drm_crtc_state *crtc_state;
> > +	struct drm_crtc_commit *commit;
> > +	struct drm_plane *__plane, *plane = NULL;
> > +	struct drm_plane_state *__plane_state, *plane_state = NULL;
> > +	const struct drm_plane_helper_funcs *funcs;
> > +	int i, n_planes = 0;
> > +
> > +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> > +		if (drm_atomic_crtc_needs_modeset(crtc_state))
> > +			return false;
> > +	}
> > +
> > +	for_each_new_plane_in_state(state, __plane, __plane_state, i) {
> > +		n_planes++;
> > +		plane = __plane;
> > +		plane_state = __plane_state;
> > +	}
> > +
> > +	if (!plane || n_planes != 1)
> > +		return false;
> > +
> > +	if (!plane->state->crtc)
> > +		return false;
> > +
> > +	if (plane_state->fence)
> > +		return false;
> > +
> > +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> > +		if (plane->crtc != crtc)
> > +			continue;
> > +
> > +		spin_lock(&crtc->commit_lock);
> > +		commit = list_first_entry_or_null(&crtc->commit_list,
> > +						  struct drm_crtc_commit,
> > +						  commit_entry);
> > +		if (!commit) {
> > +			spin_unlock(&crtc->commit_lock);
> > +			continue;
> > +		}
> > +		spin_unlock(&crtc->commit_lock);
> > +
> > +		for_each_plane_in_state(crtc_state->state, __plane,
> > +					__plane_state, i) {
> > +			if (__plane == plane) {
> > +				return false;
> > +			}
> > +		}
> > +	}
> > +
> > +	/* Not configuring new scaling in the async path. */
> 
> s/Not/No/
> 
> > +	if (plane->state->crtc_w != plane_state->crtc_w ||
> > +	    plane->state->crtc_h != plane_state->crtc_h ||
> > +	    plane->state->src_w != plane_state->src_w ||
> > +	    plane->state->src_h != plane_state->src_h) {
> > +		return false;
> > +	}
> > +
> > +	funcs = plane->helper_private;
> > +
> > +	if (!funcs->atomic_async_update)
> > +		return false;

I kinda feel like we should check this first, to bail out for all the
drivers that don't implement this before any of the more expensive checks.
> > +
> > +	if (funcs->atomic_async_check) {

This is redundant.

> > +		if (funcs->atomic_async_check(plane, plane_state) < 0)
> > +			return false;

Of course the callback should be still called at the end, so it doesn't
have to check stuff.

> > +	}
> > +
> > +	return true;
> > +}
> > +
> >  static void drm_atomic_crtc_print_state(struct drm_printer *p,
> >  		const struct drm_crtc_state *state)
> >  {
> > @@ -1591,6 +1664,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
> >  		}
> >  	}
> >  
> > +	state->async_update = drm_atomic_async_check(state);
> > +
> >  	return ret;
> >  }
> 
> The promotion of any modeset that passes the async_check test to async
> seems weird -- shouldn't we only be doing that if userspace requested
> async?  Right now it seems like we're just getting lucky because only
> cursor planes have it set, and the cursor update ioctls imply async.

Yeah, we should only do this when the async flag is set, and set that both
in the page_flip helpers and the cursor helpers.

One thing I wonder is whether we need to differentiate between "pls do
async if you can" and "I want async or let the update fail". Cursors would
be the former, page_flips probably too, but for async through atomic we
might also need the later. But that's just an aside, we can easily wire
this up when we have userspace asking for it (it might come real handy for
VR).

> 
> >  EXPORT_SYMBOL(drm_atomic_check_only);
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index 8be9719..a79e06c 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -1235,6 +1235,36 @@ static void commit_work(struct work_struct *work)
> >  }
> >  
> >  /**
> > + * drm_atomic_helper_async_commit - commit state asynchronously
> > + *
> > + * This function commits a state asynchronously. It should be used
> > + * on a state only when drm_atomic_async_check() succeds. Async
> > + * commits are not supposed to swap the states like normal sync commits,
> > + * but just do in-place change on the current state.
> > + */
> > +void drm_atomic_helper_async_commit(struct drm_device *dev,
> > +				    struct drm_atomic_state *state)
> > +{
> > +	struct drm_plane *plane;
> > +	struct drm_plane_state *plane_state;
> > +	const struct drm_plane_helper_funcs *funcs;
> > +	int i;
> > +
> > +	for_each_new_plane_in_state(state, plane, plane_state, i) {
> > +		funcs = plane->helper_private;
> > +
> > +		plane->state->src_x = plane_state->src_x;
> > +		plane->state->src_y = plane_state->src_y;
> > +		plane->state->crtc_x = plane_state->crtc_x;
> > +		plane->state->crtc_y = plane_state->crtc_y;
> > +
> > +		if (funcs && funcs->atomic_async_update)
> > +			funcs->atomic_async_update(plane, plane_state);
> > +	}
> > +}
> 
> It seems strange to me that the async_update() implementation in the
> driver needs to update the state->fb but not the x/y.  Could we move the
> core's x/y update after the call into the driver, and then update
> plane->state->fb in the core instead of the driver?

Yeah, consistency would be real good here ...

> > +EXPORT_SYMBOL(drm_atomic_helper_async_commit);
> > +
> > +/**
> >   * drm_atomic_helper_commit - commit validated state object
> >   * @dev: DRM device
> >   * @state: the driver state object
> > @@ -1258,6 +1288,17 @@ int drm_atomic_helper_commit(struct drm_device *dev,
> >  {
> >  	int ret;
> >  
> > +	if (state->async_update) {
> > +		ret = drm_atomic_helper_prepare_planes(dev, state);
> > +		if (ret)
> > +			return ret;
> > +
> > +		drm_atomic_helper_async_commit(dev, state);
> > +		drm_atomic_helper_cleanup_planes(dev, state);

Some async cursor updates are not 100% async, as in the hw might still
scan out the old buffer until the next vblank. Could/should we handle this
in core? Or are we going to shrug this off with "meh, you asked for
tearing, you got tearing"?

> > +
> > +		return 0;
> > +	}
> > +
> >  	ret = drm_atomic_helper_setup_commit(state, nonblock);
> >  	if (ret)
> >  		return ret;
> > diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> > index 788daf7..c00c565 100644
> > --- a/include/drm/drm_atomic.h
> > +++ b/include/drm/drm_atomic.h
> 
> > diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> > index c01c328..3efa4cc 100644
> > --- a/include/drm/drm_modeset_helper_vtables.h
> > +++ b/include/drm/drm_modeset_helper_vtables.h
> 
> > +	 *
> > +	 * Check drm_atomic_async_check() to see what is already there
> > +	 * to discover potential async updates.
> > +	 *
> > +	 * RETURNS:
> > +	 *
> > +	 * Return 0 on success and -EINVAL if the update can't be async.
> > +	 * Error return doesn't mean that the update can't be applied,
> > +	 * it just mean that it can't be an async one.
> > +	 *
> > +	 * FIXME:
> > +	 *  - It only works for single plane updates
> > +	 *  - It can't do async update if the plane is already being update
> > +	 *  by the queued state
> 
> "already being updated"
> 
> > +	 *  - Async Pageflips are not supported yet
> > +	 */
> > +	int (*atomic_async_check)(struct drm_plane *plane,
> > +				  struct drm_plane_state *state);
> > +
> > +	/**
> > +	 * @atomic_async_update:
> > +	 *
> > +	 * Drivers should use this functions to perform asynchronous
> 
> "this function"
> 
> Also, maybe clarify that "async" means "not vblank synchronized"?
> 
> > +	 * updates of planes, that is jump ahead the currently queued
> > +	 * state for and update the plane.
> > +	 *
> > +	 * This hook is called by drm_atomic_helper_async_commit().
> > +	 *
> > +	 * Note that differently from the &drm_plane_helper_funcs.atomic_update
> > +	 * this hook takes the new &drm_plane_state as parameter. When doing
> > +	 * async_update drivers shouldn't replace the &drm_plane_state but
> > +	 * just, update the current one with the new plane configurations in
> > +	 * the new plane_state.
> > +	 */
> > +	void (*atomic_async_update)(struct drm_plane *plane,
> > +				    struct drm_plane_state *new_state);
> >  };
> >  
> >  /**
> > -- 
> > 2.9.3



> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 7/7] drm/vc4: update cursors asynchronously through atomic
  2017-04-10 20:06   ` Eric Anholt
@ 2017-04-11 20:27     ` Daniel Vetter
  0 siblings, 0 replies; 20+ messages in thread
From: Daniel Vetter @ 2017-04-11 20:27 UTC (permalink / raw)
  To: Eric Anholt; +Cc: dri-devel, Gustavo Padovan

On Mon, Apr 10, 2017 at 01:06:46PM -0700, Eric Anholt wrote:
> Gustavo Padovan <gustavo@padovan.org> writes:
> 
> > From: Gustavo Padovan <gustavo.padovan@collabora.com>
> >
> > Add support to async updates of cursors by using the new atomic
> > interface for that. Basically what this commit does is do what
> > vc4_update_plane() did but through atomic.
> >
> > Cc: Eric Anholt <eric@anholt.net>
> > Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
> > ---
> >  drivers/gpu/drm/vc4/vc4_plane.c | 94 ++++++++++++-----------------------------
> >  1 file changed, 27 insertions(+), 67 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
> > index d34cd53..e33c75b 100644
> > --- a/drivers/gpu/drm/vc4/vc4_plane.c
> > +++ b/drivers/gpu/drm/vc4/vc4_plane.c
> > @@ -735,70 +735,27 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
> >  	vc4_state->dlist[vc4_state->ptr0_offset] = addr;
> >  }
> >  
> > -static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
> > -	.atomic_check = vc4_plane_atomic_check,
> > -	.atomic_update = vc4_plane_atomic_update,
> > -};
> > -
> > -static void vc4_plane_destroy(struct drm_plane *plane)
> > -{
> > -	drm_plane_helper_disable(plane);
> > -	drm_plane_cleanup(plane);
> > -}
> > -
> > -/* Implements immediate (non-vblank-synced) updates of the cursor
> > - * position, or falls back to the atomic helper otherwise.
> > - */
> > -static int
> > -vc4_update_plane(struct drm_plane *plane,
> > -		 struct drm_crtc *crtc,
> > -		 struct drm_framebuffer *fb,
> > -		 int crtc_x, int crtc_y,
> > -		 unsigned int crtc_w, unsigned int crtc_h,
> > -		 uint32_t src_x, uint32_t src_y,
> > -		 uint32_t src_w, uint32_t src_h,
> > -		 struct drm_modeset_acquire_ctx *ctx)
> > +static int vc4_plane_atomic_async_check(struct drm_plane *plane,
> > +					struct drm_plane_state *state)
> >  {
> > -	struct drm_plane_state *plane_state;
> > -	struct vc4_plane_state *vc4_state;
> > -
> > -	if (plane != crtc->cursor)
> > -		goto out;
> > -
> > -	plane_state = plane->state;
> > -	vc4_state = to_vc4_plane_state(plane_state);
> > -
> > -	if (!plane_state)
> > -		goto out;
> > +	if (plane != state->crtc->cursor)
> > +		return -EINVAL;
> >  
> > -	/* No configuring new scaling in the fast path. */
> > -	if (crtc_w != plane_state->crtc_w ||
> > -	    crtc_h != plane_state->crtc_h ||
> > -	    src_w != plane_state->src_w ||
> > -	    src_h != plane_state->src_h) {
> > -		goto out;
> > -	}
> > +	if (!plane->state)
> > +		return -EINVAL;
> >  
> > -	if (fb != plane_state->fb) {
> > -		drm_atomic_set_fb_for_plane(plane->state, fb);
> > -		vc4_plane_async_set_fb(plane, fb);
> > -	}
> > +	return 0;
> > +}
> >  
> > -	/* Set the cursor's position on the screen.  This is the
> > -	 * expected change from the drm_mode_cursor_universal()
> > -	 * helper.
> > -	 */
> > -	plane_state->crtc_x = crtc_x;
> > -	plane_state->crtc_y = crtc_y;
> > +static void vc4_plane_atomic_async_update(struct drm_plane *plane,
> > +					  struct drm_plane_state *new_state)
> > +{
> > +	struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
> >  
> > -	/* Allow changing the start position within the cursor BO, if
> > -	 * that matters.
> > -	 */
> > -	plane_state->src_x = src_x;
> > -	plane_state->src_y = src_y;
> > +	if (plane->state->fb != new_state->fb)
> > +		vc4_plane_async_set_fb(plane, new_state->fb);
> >  
> > -	/* Update the display list based on the new crtc_x/y. */
> > -	vc4_plane_atomic_check(plane, plane_state);
> > +	plane->state->fb = new_state->fb;
> 
> The vc4_plane_atomic_check() is what sets up the dlist[]'s position
> fields that are used right after this, so this call needs to stay in
> place, and x/y need to be updated already (since we're looking at
> plane->state, not new_state).
> 
> Also, I think we'll need to make sure that you're not trying to
> enable/disable the plane in the fast path, since we're not updating the
> CTL0_VALID field.

Yeah, I think the core should even check for that, by comparing
old/new_state->crtc, and if they don't match, fall back to full commit.

We already check a massive pile of other stuff anyway.
-Daniel

> 
> >  	/* Note that we can't just call vc4_plane_write_dlist()
> >  	 * because that would smash the context data that the HVS is
> > @@ -810,20 +767,23 @@ vc4_update_plane(struct drm_plane *plane,
> >  	       &vc4_state->hw_dlist[vc4_state->pos2_offset]);
> >  	writel(vc4_state->dlist[vc4_state->ptr0_offset],
> >  	       &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
> > +}



> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-04-11 20:23     ` Daniel Vetter
@ 2017-04-12 18:17       ` Gustavo Padovan
  2017-04-21 18:41       ` Gustavo Padovan
  1 sibling, 0 replies; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-12 18:17 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, dri-devel, Gustavo Padovan

2017-04-11 Daniel Vetter <daniel@ffwll.ch>:

> On Mon, Apr 10, 2017 at 12:55:33PM -0700, Eric Anholt wrote:
> > Gustavo Padovan <gustavo@padovan.org> writes:
> > 
> > > From: Gustavo Padovan <gustavo.padovan@collabora.com>
> > >
> > > In some cases, like cursor updates, it is interesting to update the
> > > plane in an asynchronous fashion to avoid big delays.
> > >
> > > The current queued update could be still waiting for a fence to signal and
> > > thus block and subsequent update until its scan out. In cases like this if
> > > we update the cursor synchronously it will cause significant delays on
> > > some platforms that would be noticed by the final user.
> > >
> > > This patch creates a fast path to jump ahead the current queued state and
> > > do single planes updates without going through all atomic step in
> > > drm_atomic_helper_commit().
> > >
> > > For now only single plane updates are supported and only if there is no
> > > update to that plane in the queued state.
> > >
> > > We plan to support async PageFlips through this interface as well in the
> > > near future.
> > 
> > This looks really nice -- the vc4 code for cursors was really gross to
> > write, and I got it wrong a couple of times.  Couple of comments inline.
> 
> Some more comments below.
> -Daniel
> 
> > 
> > > ---
> > >  drivers/gpu/drm/drm_atomic.c             | 75 ++++++++++++++++++++++++++++++++
> > >  drivers/gpu/drm/drm_atomic_helper.c      | 41 +++++++++++++++++
> > >  include/drm/drm_atomic.h                 |  4 ++
> > >  include/drm/drm_atomic_helper.h          |  2 +
> > >  include/drm/drm_modeset_helper_vtables.h | 47 ++++++++++++++++++++
> > >  5 files changed, 169 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > index f32506a..cae0122 100644
> > > --- a/drivers/gpu/drm/drm_atomic.c
> > > +++ b/drivers/gpu/drm/drm_atomic.c
> > > @@ -631,6 +631,79 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
> > >  	return 0;
> > >  }
> > >  
> > > +static bool drm_atomic_async_check(struct drm_atomic_state *state)
> > > +{
> > > +	struct drm_crtc *crtc;
> > > +	struct drm_crtc_state *crtc_state;
> > > +	struct drm_crtc_commit *commit;
> > > +	struct drm_plane *__plane, *plane = NULL;
> > > +	struct drm_plane_state *__plane_state, *plane_state = NULL;
> > > +	const struct drm_plane_helper_funcs *funcs;
> > > +	int i, n_planes = 0;
> > > +
> > > +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> > > +		if (drm_atomic_crtc_needs_modeset(crtc_state))
> > > +			return false;
> > > +	}
> > > +
> > > +	for_each_new_plane_in_state(state, __plane, __plane_state, i) {
> > > +		n_planes++;
> > > +		plane = __plane;
> > > +		plane_state = __plane_state;
> > > +	}
> > > +
> > > +	if (!plane || n_planes != 1)
> > > +		return false;
> > > +
> > > +	if (!plane->state->crtc)
> > > +		return false;
> > > +
> > > +	if (plane_state->fence)
> > > +		return false;
> > > +
> > > +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> > > +		if (plane->crtc != crtc)
> > > +			continue;
> > > +
> > > +		spin_lock(&crtc->commit_lock);
> > > +		commit = list_first_entry_or_null(&crtc->commit_list,
> > > +						  struct drm_crtc_commit,
> > > +						  commit_entry);
> > > +		if (!commit) {
> > > +			spin_unlock(&crtc->commit_lock);
> > > +			continue;
> > > +		}
> > > +		spin_unlock(&crtc->commit_lock);
> > > +
> > > +		for_each_plane_in_state(crtc_state->state, __plane,
> > > +					__plane_state, i) {
> > > +			if (__plane == plane) {
> > > +				return false;
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	/* Not configuring new scaling in the async path. */
> > 
> > s/Not/No/
> > 
> > > +	if (plane->state->crtc_w != plane_state->crtc_w ||
> > > +	    plane->state->crtc_h != plane_state->crtc_h ||
> > > +	    plane->state->src_w != plane_state->src_w ||
> > > +	    plane->state->src_h != plane_state->src_h) {
> > > +		return false;
> > > +	}
> > > +
> > > +	funcs = plane->helper_private;
> > > +
> > > +	if (!funcs->atomic_async_update)
> > > +		return false;
> 
> I kinda feel like we should check this first, to bail out for all the
> drivers that don't implement this before any of the more expensive checks.
> > > +
> > > +	if (funcs->atomic_async_check) {
> 
> This is redundant.
> 
> > > +		if (funcs->atomic_async_check(plane, plane_state) < 0)
> > > +			return false;
> 
> Of course the callback should be still called at the end, so it doesn't
> have to check stuff.
> 
> > > +	}
> > > +
> > > +	return true;
> > > +}
> > > +
> > >  static void drm_atomic_crtc_print_state(struct drm_printer *p,
> > >  		const struct drm_crtc_state *state)
> > >  {
> > > @@ -1591,6 +1664,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
> > >  		}
> > >  	}
> > >  
> > > +	state->async_update = drm_atomic_async_check(state);
> > > +
> > >  	return ret;
> > >  }
> > 
> > The promotion of any modeset that passes the async_check test to async
> > seems weird -- shouldn't we only be doing that if userspace requested
> > async?  Right now it seems like we're just getting lucky because only
> > cursor planes have it set, and the cursor update ioctls imply async.
> 
> Yeah, we should only do this when the async flag is set, and set that both
> in the page_flip helpers and the cursor helpers.
> 
> One thing I wonder is whether we need to differentiate between "pls do
> async if you can" and "I want async or let the update fail". Cursors would
> be the former, page_flips probably too, but for async through atomic we
> might also need the later. But that's just an aside, we can easily wire
> this up when we have userspace asking for it (it might come real handy for
> VR).

Adding a flag makes a lot of sense, I'll have that changed for v2.

> 
> > 
> > >  EXPORT_SYMBOL(drm_atomic_check_only);
> > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > index 8be9719..a79e06c 100644
> > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > @@ -1235,6 +1235,36 @@ static void commit_work(struct work_struct *work)
> > >  }
> > >  
> > >  /**
> > > + * drm_atomic_helper_async_commit - commit state asynchronously
> > > + *
> > > + * This function commits a state asynchronously. It should be used
> > > + * on a state only when drm_atomic_async_check() succeds. Async
> > > + * commits are not supposed to swap the states like normal sync commits,
> > > + * but just do in-place change on the current state.
> > > + */
> > > +void drm_atomic_helper_async_commit(struct drm_device *dev,
> > > +				    struct drm_atomic_state *state)
> > > +{
> > > +	struct drm_plane *plane;
> > > +	struct drm_plane_state *plane_state;
> > > +	const struct drm_plane_helper_funcs *funcs;
> > > +	int i;
> > > +
> > > +	for_each_new_plane_in_state(state, plane, plane_state, i) {
> > > +		funcs = plane->helper_private;
> > > +
> > > +		plane->state->src_x = plane_state->src_x;
> > > +		plane->state->src_y = plane_state->src_y;
> > > +		plane->state->crtc_x = plane_state->crtc_x;
> > > +		plane->state->crtc_y = plane_state->crtc_y;
> > > +
> > > +		if (funcs && funcs->atomic_async_update)
> > > +			funcs->atomic_async_update(plane, plane_state);
> > > +	}
> > > +}
> > 
> > It seems strange to me that the async_update() implementation in the
> > driver needs to update the state->fb but not the x/y.  Could we move the
> > core's x/y update after the call into the driver, and then update
> > plane->state->fb in the core instead of the driver?
> 
> Yeah, consistency would be real good here ...

Rigth, I didn't think about this lack of consistency.

> 
> > > +EXPORT_SYMBOL(drm_atomic_helper_async_commit);
> > > +
> > > +/**
> > >   * drm_atomic_helper_commit - commit validated state object
> > >   * @dev: DRM device
> > >   * @state: the driver state object
> > > @@ -1258,6 +1288,17 @@ int drm_atomic_helper_commit(struct drm_device *dev,
> > >  {
> > >  	int ret;
> > >  
> > > +	if (state->async_update) {
> > > +		ret = drm_atomic_helper_prepare_planes(dev, state);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		drm_atomic_helper_async_commit(dev, state);
> > > +		drm_atomic_helper_cleanup_planes(dev, state);
> 
> Some async cursor updates are not 100% async, as in the hw might still
> scan out the old buffer until the next vblank. Could/should we handle this
> in core? Or are we going to shrug this off with "meh, you asked for
> tearing, you got tearing"?

Okay. It will be good to avoid any sort of tearing. For that we may need
to move the cleanup phase to the driver I think or have some sort of
callback.

Gustavo
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-04-11 20:23     ` Daniel Vetter
  2017-04-12 18:17       ` Gustavo Padovan
@ 2017-04-21 18:41       ` Gustavo Padovan
  2017-05-02  8:10         ` Daniel Vetter
  1 sibling, 1 reply; 20+ messages in thread
From: Gustavo Padovan @ 2017-04-21 18:41 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, dri-devel, Gustavo Padovan

2017-04-11 Daniel Vetter <daniel@ffwll.ch>:

> On Mon, Apr 10, 2017 at 12:55:33PM -0700, Eric Anholt wrote:
> > Gustavo Padovan <gustavo@padovan.org> writes:
> > 
> > > From: Gustavo Padovan <gustavo.padovan@collabora.com>
> > >
> > > In some cases, like cursor updates, it is interesting to update the
> > > plane in an asynchronous fashion to avoid big delays.
> > >
> > > The current queued update could be still waiting for a fence to signal and
> > > thus block and subsequent update until its scan out. In cases like this if
> > > we update the cursor synchronously it will cause significant delays on
> > > some platforms that would be noticed by the final user.
> > >
> > > This patch creates a fast path to jump ahead the current queued state and
> > > do single planes updates without going through all atomic step in
> > > drm_atomic_helper_commit().
> > >
> > > For now only single plane updates are supported and only if there is no
> > > update to that plane in the queued state.
> > >
> > > We plan to support async PageFlips through this interface as well in the
> > > near future.
> > 
> > This looks really nice -- the vc4 code for cursors was really gross to
> > write, and I got it wrong a couple of times.  Couple of comments inline.
> 
> Some more comments below.
> -Daniel
> 
> > 
> > > ---
> > >  drivers/gpu/drm/drm_atomic.c             | 75 ++++++++++++++++++++++++++++++++
> > >  drivers/gpu/drm/drm_atomic_helper.c      | 41 +++++++++++++++++
> > >  include/drm/drm_atomic.h                 |  4 ++
> > >  include/drm/drm_atomic_helper.h          |  2 +
> > >  include/drm/drm_modeset_helper_vtables.h | 47 ++++++++++++++++++++
> > >  5 files changed, 169 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > index f32506a..cae0122 100644
> > > --- a/drivers/gpu/drm/drm_atomic.c
> > > +++ b/drivers/gpu/drm/drm_atomic.c
> > > @@ -631,6 +631,79 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
> > >  	return 0;
> > >  }
> > >  
> > > +static bool drm_atomic_async_check(struct drm_atomic_state *state)
> > > +{
> > > +	struct drm_crtc *crtc;
> > > +	struct drm_crtc_state *crtc_state;
> > > +	struct drm_crtc_commit *commit;
> > > +	struct drm_plane *__plane, *plane = NULL;
> > > +	struct drm_plane_state *__plane_state, *plane_state = NULL;
> > > +	const struct drm_plane_helper_funcs *funcs;
> > > +	int i, n_planes = 0;
> > > +
> > > +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> > > +		if (drm_atomic_crtc_needs_modeset(crtc_state))
> > > +			return false;
> > > +	}
> > > +
> > > +	for_each_new_plane_in_state(state, __plane, __plane_state, i) {
> > > +		n_planes++;
> > > +		plane = __plane;
> > > +		plane_state = __plane_state;
> > > +	}
> > > +
> > > +	if (!plane || n_planes != 1)
> > > +		return false;
> > > +
> > > +	if (!plane->state->crtc)
> > > +		return false;
> > > +
> > > +	if (plane_state->fence)
> > > +		return false;
> > > +
> > > +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> > > +		if (plane->crtc != crtc)
> > > +			continue;
> > > +
> > > +		spin_lock(&crtc->commit_lock);
> > > +		commit = list_first_entry_or_null(&crtc->commit_list,
> > > +						  struct drm_crtc_commit,
> > > +						  commit_entry);
> > > +		if (!commit) {
> > > +			spin_unlock(&crtc->commit_lock);
> > > +			continue;
> > > +		}
> > > +		spin_unlock(&crtc->commit_lock);
> > > +
> > > +		for_each_plane_in_state(crtc_state->state, __plane,
> > > +					__plane_state, i) {
> > > +			if (__plane == plane) {
> > > +				return false;
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	/* Not configuring new scaling in the async path. */
> > 
> > s/Not/No/
> > 
> > > +	if (plane->state->crtc_w != plane_state->crtc_w ||
> > > +	    plane->state->crtc_h != plane_state->crtc_h ||
> > > +	    plane->state->src_w != plane_state->src_w ||
> > > +	    plane->state->src_h != plane_state->src_h) {
> > > +		return false;
> > > +	}
> > > +
> > > +	funcs = plane->helper_private;
> > > +
> > > +	if (!funcs->atomic_async_update)
> > > +		return false;
> 
> I kinda feel like we should check this first, to bail out for all the
> drivers that don't implement this before any of the more expensive checks.
> > > +
> > > +	if (funcs->atomic_async_check) {
> 
> This is redundant.
> 
> > > +		if (funcs->atomic_async_check(plane, plane_state) < 0)
> > > +			return false;
> 
> Of course the callback should be still called at the end, so it doesn't
> have to check stuff.
> 
> > > +	}
> > > +
> > > +	return true;
> > > +}
> > > +
> > >  static void drm_atomic_crtc_print_state(struct drm_printer *p,
> > >  		const struct drm_crtc_state *state)
> > >  {
> > > @@ -1591,6 +1664,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
> > >  		}
> > >  	}
> > >  
> > > +	state->async_update = drm_atomic_async_check(state);
> > > +
> > >  	return ret;
> > >  }
> > 
> > The promotion of any modeset that passes the async_check test to async
> > seems weird -- shouldn't we only be doing that if userspace requested
> > async?  Right now it seems like we're just getting lucky because only
> > cursor planes have it set, and the cursor update ioctls imply async.
> 
> Yeah, we should only do this when the async flag is set, and set that both
> in the page_flip helpers and the cursor helpers.
> 
> One thing I wonder is whether we need to differentiate between "pls do
> async if you can" and "I want async or let the update fail". Cursors would
> be the former, page_flips probably too, but for async through atomic we
> might also need the later. But that's just an aside, we can easily wire
> this up when we have userspace asking for it (it might come real handy for
> VR).
> 
> > 
> > >  EXPORT_SYMBOL(drm_atomic_check_only);
> > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > index 8be9719..a79e06c 100644
> > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > @@ -1235,6 +1235,36 @@ static void commit_work(struct work_struct *work)
> > >  }
> > >  
> > >  /**
> > > + * drm_atomic_helper_async_commit - commit state asynchronously
> > > + *
> > > + * This function commits a state asynchronously. It should be used
> > > + * on a state only when drm_atomic_async_check() succeds. Async
> > > + * commits are not supposed to swap the states like normal sync commits,
> > > + * but just do in-place change on the current state.
> > > + */
> > > +void drm_atomic_helper_async_commit(struct drm_device *dev,
> > > +				    struct drm_atomic_state *state)
> > > +{
> > > +	struct drm_plane *plane;
> > > +	struct drm_plane_state *plane_state;
> > > +	const struct drm_plane_helper_funcs *funcs;
> > > +	int i;
> > > +
> > > +	for_each_new_plane_in_state(state, plane, plane_state, i) {
> > > +		funcs = plane->helper_private;
> > > +
> > > +		plane->state->src_x = plane_state->src_x;
> > > +		plane->state->src_y = plane_state->src_y;
> > > +		plane->state->crtc_x = plane_state->crtc_x;
> > > +		plane->state->crtc_y = plane_state->crtc_y;
> > > +
> > > +		if (funcs && funcs->atomic_async_update)
> > > +			funcs->atomic_async_update(plane, plane_state);
> > > +	}
> > > +}
> > 
> > It seems strange to me that the async_update() implementation in the
> > driver needs to update the state->fb but not the x/y.  Could we move the
> > core's x/y update after the call into the driver, and then update
> > plane->state->fb in the core instead of the driver?
> 
> Yeah, consistency would be real good here ...
> 
> > > +EXPORT_SYMBOL(drm_atomic_helper_async_commit);
> > > +
> > > +/**
> > >   * drm_atomic_helper_commit - commit validated state object
> > >   * @dev: DRM device
> > >   * @state: the driver state object
> > > @@ -1258,6 +1288,17 @@ int drm_atomic_helper_commit(struct drm_device *dev,
> > >  {
> > >  	int ret;
> > >  
> > > +	if (state->async_update) {
> > > +		ret = drm_atomic_helper_prepare_planes(dev, state);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		drm_atomic_helper_async_commit(dev, state);
> > > +		drm_atomic_helper_cleanup_planes(dev, state);
> 
> Some async cursor updates are not 100% async, as in the hw might still
> scan out the old buffer until the next vblank. Could/should we handle this
> in core? Or are we going to shrug this off with "meh, you asked for
> tearing, you got tearing"?

Do you know which hw would that be? I don't know. Maybe we should just
don't care for now and see how drivers will solve this to then extract
helpers like we did for atomic nonblocking commits.

Gustavo
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-04-21 18:41       ` Gustavo Padovan
@ 2017-05-02  8:10         ` Daniel Vetter
  2017-05-02 10:58           ` Daniel Stone
  0 siblings, 1 reply; 20+ messages in thread
From: Daniel Vetter @ 2017-05-02  8:10 UTC (permalink / raw)
  To: Gustavo Padovan, Daniel Vetter, Eric Anholt, dri-devel,
	Gustavo Padovan, Daniel Vetter

On Fri, Apr 21, 2017 at 03:41:10PM -0300, Gustavo Padovan wrote:
> 2017-04-11 Daniel Vetter <daniel@ffwll.ch>:
> 
> > On Mon, Apr 10, 2017 at 12:55:33PM -0700, Eric Anholt wrote:
> > > Gustavo Padovan <gustavo@padovan.org> writes:
> > > 
> > > > From: Gustavo Padovan <gustavo.padovan@collabora.com>
> > Some async cursor updates are not 100% async, as in the hw might still
> > scan out the old buffer until the next vblank. Could/should we handle this
> > in core? Or are we going to shrug this off with "meh, you asked for
> > tearing, you got tearing"?
> 
> Do you know which hw would that be? I don't know. Maybe we should just
> don't care for now and see how drivers will solve this to then extract
> helpers like we did for atomic nonblocking commits.

i915 is one. The only way to do true async updates is throught the CS flip
command with a special bit set, and that one only works for the primary
plane. All other updates are synced to vblank, i.e. the hw will keep
scanning out the old address.

But I checked the current code, it's no better than what you've done.

More special is iirc rockchip (or some other arm-soc display ip), which on top
also has an iommu which falls over if the mapping disappears right away.
Easy solution is to not allow fb changes (but that kinda sucks), more
involved is delaying the fb cleanup into a worker (but since we don't
rate-limit this is tricky too ...).

Maybe just go with a FIXME comment here?
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 1/7] drm/atomic: initial support for asynchronous plane update
  2017-05-02  8:10         ` Daniel Vetter
@ 2017-05-02 10:58           ` Daniel Stone
  0 siblings, 0 replies; 20+ messages in thread
From: Daniel Stone @ 2017-05-02 10:58 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, dri-devel

Hi,

On 2 May 2017 at 09:10, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Fri, Apr 21, 2017 at 03:41:10PM -0300, Gustavo Padovan wrote:
>> Do you know which hw would that be? I don't know. Maybe we should just
>> don't care for now and see how drivers will solve this to then extract
>> helpers like we did for atomic nonblocking commits.
>
> i915 is one. The only way to do true async updates is throught the CS flip
> command with a special bit set, and that one only works for the primary
> plane. All other updates are synced to vblank, i.e. the hw will keep
> scanning out the old address.
>
> But I checked the current code, it's no better than what you've done.
>
> More special is iirc rockchip (or some other arm-soc display ip), which on top
> also has an iommu which falls over if the mapping disappears right away.
> Easy solution is to not allow fb changes (but that kinda sucks), more
> involved is delaying the fb cleanup into a worker (but since we don't
> rate-limit this is tricky too ...).

Most ARM display IP these days has it (notable exception is VC4 and I
think also i.MX?), and will do that. Exynos also has no way to update
the base address during scanout, and will not like it if it starts
smashing into faults from its IOMMU.

Cheers,
Daniel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 7/7] drm/vc4: update cursors asynchronously through atomic
  2017-04-10  0:24 ` [RFC 7/7] drm/vc4: update cursors asynchronously through atomic Gustavo Padovan
  2017-04-10 20:06   ` Eric Anholt
@ 2017-05-18 22:52   ` Robert Foss
  2017-05-18 22:55     ` Robert Foss
  1 sibling, 1 reply; 20+ messages in thread
From: Robert Foss @ 2017-05-18 22:52 UTC (permalink / raw)
  To: dri-devel

Hey,

I ran the series on a RPi2 and the cursor seems to behave correctly.

Tested-by: Robert Foss <robert.foss@collabora.com>

On 2017-04-09 08:24 PM, Gustavo Padovan wrote:
> From: Gustavo Padovan <gustavo.padovan@collabora.com>
> 
> Add support to async updates of cursors by using the new atomic
> interface for that. Basically what this commit does is do what
> vc4_update_plane() did but through atomic.
> 
> Cc: Eric Anholt <eric@anholt.net>
> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
> ---
>   drivers/gpu/drm/vc4/vc4_plane.c | 94 ++++++++++++-----------------------------
>   1 file changed, 27 insertions(+), 67 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
> index d34cd53..e33c75b 100644
> --- a/drivers/gpu/drm/vc4/vc4_plane.c
> +++ b/drivers/gpu/drm/vc4/vc4_plane.c
> @@ -735,70 +735,27 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
>   	vc4_state->dlist[vc4_state->ptr0_offset] = addr;
>   }
>   
> -static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
> -	.atomic_check = vc4_plane_atomic_check,
> -	.atomic_update = vc4_plane_atomic_update,
> -};
> -
> -static void vc4_plane_destroy(struct drm_plane *plane)
> -{
> -	drm_plane_helper_disable(plane);
> -	drm_plane_cleanup(plane);
> -}
> -
> -/* Implements immediate (non-vblank-synced) updates of the cursor
> - * position, or falls back to the atomic helper otherwise.
> - */
> -static int
> -vc4_update_plane(struct drm_plane *plane,
> -		 struct drm_crtc *crtc,
> -		 struct drm_framebuffer *fb,
> -		 int crtc_x, int crtc_y,
> -		 unsigned int crtc_w, unsigned int crtc_h,
> -		 uint32_t src_x, uint32_t src_y,
> -		 uint32_t src_w, uint32_t src_h,
> -		 struct drm_modeset_acquire_ctx *ctx)
> +static int vc4_plane_atomic_async_check(struct drm_plane *plane,
> +					struct drm_plane_state *state)
>   {
> -	struct drm_plane_state *plane_state;
> -	struct vc4_plane_state *vc4_state;
> -
> -	if (plane != crtc->cursor)
> -		goto out;
> -
> -	plane_state = plane->state;
> -	vc4_state = to_vc4_plane_state(plane_state);
> -
> -	if (!plane_state)
> -		goto out;
> +	if (plane != state->crtc->cursor)
> +		return -EINVAL;
>   
> -	/* No configuring new scaling in the fast path. */
> -	if (crtc_w != plane_state->crtc_w ||
> -	    crtc_h != plane_state->crtc_h ||
> -	    src_w != plane_state->src_w ||
> -	    src_h != plane_state->src_h) {
> -		goto out;
> -	}
> +	if (!plane->state)
> +		return -EINVAL;
>   
> -	if (fb != plane_state->fb) {
> -		drm_atomic_set_fb_for_plane(plane->state, fb);
> -		vc4_plane_async_set_fb(plane, fb);
> -	}
> +	return 0;
> +}
>   
> -	/* Set the cursor's position on the screen.  This is the
> -	 * expected change from the drm_mode_cursor_universal()
> -	 * helper.
> -	 */
> -	plane_state->crtc_x = crtc_x;
> -	plane_state->crtc_y = crtc_y;
> +static void vc4_plane_atomic_async_update(struct drm_plane *plane,
> +					  struct drm_plane_state *new_state)
> +{
> +	struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
>   
> -	/* Allow changing the start position within the cursor BO, if
> -	 * that matters.
> -	 */
> -	plane_state->src_x = src_x;
> -	plane_state->src_y = src_y;
> +	if (plane->state->fb != new_state->fb)
> +		vc4_plane_async_set_fb(plane, new_state->fb);
>   
> -	/* Update the display list based on the new crtc_x/y. */
> -	vc4_plane_atomic_check(plane, plane_state);
> +	plane->state->fb = new_state->fb;
>   
>   	/* Note that we can't just call vc4_plane_write_dlist()
>   	 * because that would smash the context data that the HVS is
> @@ -810,20 +767,23 @@ vc4_update_plane(struct drm_plane *plane,
>   	       &vc4_state->hw_dlist[vc4_state->pos2_offset]);
>   	writel(vc4_state->dlist[vc4_state->ptr0_offset],
>   	       &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
> +}
>   
> -	return 0;
> +static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
> +	.atomic_check = vc4_plane_atomic_check,
> +	.atomic_update = vc4_plane_atomic_update,
> +	.atomic_async_check = vc4_plane_atomic_async_check,
> +	.atomic_async_update = vc4_plane_atomic_async_update,
> +};
>   
> -out:
> -	return drm_atomic_helper_update_plane(plane, crtc, fb,
> -					      crtc_x, crtc_y,
> -					      crtc_w, crtc_h,
> -					      src_x, src_y,
> -					      src_w, src_h,
> -					      ctx);
> +static void vc4_plane_destroy(struct drm_plane *plane)
> +{
> +	drm_plane_helper_disable(plane);
> +	drm_plane_cleanup(plane);
>   }
>   
>   static const struct drm_plane_funcs vc4_plane_funcs = {
> -	.update_plane = vc4_update_plane,
> +	.update_plane = drm_atomic_helper_update_plane,
>   	.disable_plane = drm_atomic_helper_disable_plane,
>   	.destroy = vc4_plane_destroy,
>   	.set_property = NULL,
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC 7/7] drm/vc4: update cursors asynchronously through atomic
  2017-05-18 22:52   ` Robert Foss
@ 2017-05-18 22:55     ` Robert Foss
  0 siblings, 0 replies; 20+ messages in thread
From: Robert Foss @ 2017-05-18 22:55 UTC (permalink / raw)
  To: dri-devel

Sorry about the spam, but the previous reply was intended for
[RFC v3 7/8] drm/vc4: update cursors asynchronously through atomic


On 2017-05-18 06:52 PM, Robert Foss wrote:
> Hey,
> 
> I ran the series on a RPi2 and the cursor seems to behave correctly.
> 
> Tested-by: Robert Foss <robert.foss@collabora.com>
> 
> On 2017-04-09 08:24 PM, Gustavo Padovan wrote:
>> From: Gustavo Padovan <gustavo.padovan@collabora.com>
>>
>> Add support to async updates of cursors by using the new atomic
>> interface for that. Basically what this commit does is do what
>> vc4_update_plane() did but through atomic.
>>
>> Cc: Eric Anholt <eric@anholt.net>
>> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com>
>> ---
>>   drivers/gpu/drm/vc4/vc4_plane.c | 94 ++++++++++++-----------------------------
>>   1 file changed, 27 insertions(+), 67 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
>> index d34cd53..e33c75b 100644
>> --- a/drivers/gpu/drm/vc4/vc4_plane.c
>> +++ b/drivers/gpu/drm/vc4/vc4_plane.c
>> @@ -735,70 +735,27 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, 
>> struct drm_framebuffer *fb)
>>       vc4_state->dlist[vc4_state->ptr0_offset] = addr;
>>   }
>> -static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
>> -    .atomic_check = vc4_plane_atomic_check,
>> -    .atomic_update = vc4_plane_atomic_update,
>> -};
>> -
>> -static void vc4_plane_destroy(struct drm_plane *plane)
>> -{
>> -    drm_plane_helper_disable(plane);
>> -    drm_plane_cleanup(plane);
>> -}
>> -
>> -/* Implements immediate (non-vblank-synced) updates of the cursor
>> - * position, or falls back to the atomic helper otherwise.
>> - */
>> -static int
>> -vc4_update_plane(struct drm_plane *plane,
>> -         struct drm_crtc *crtc,
>> -         struct drm_framebuffer *fb,
>> -         int crtc_x, int crtc_y,
>> -         unsigned int crtc_w, unsigned int crtc_h,
>> -         uint32_t src_x, uint32_t src_y,
>> -         uint32_t src_w, uint32_t src_h,
>> -         struct drm_modeset_acquire_ctx *ctx)
>> +static int vc4_plane_atomic_async_check(struct drm_plane *plane,
>> +                    struct drm_plane_state *state)
>>   {
>> -    struct drm_plane_state *plane_state;
>> -    struct vc4_plane_state *vc4_state;
>> -
>> -    if (plane != crtc->cursor)
>> -        goto out;
>> -
>> -    plane_state = plane->state;
>> -    vc4_state = to_vc4_plane_state(plane_state);
>> -
>> -    if (!plane_state)
>> -        goto out;
>> +    if (plane != state->crtc->cursor)
>> +        return -EINVAL;
>> -    /* No configuring new scaling in the fast path. */
>> -    if (crtc_w != plane_state->crtc_w ||
>> -        crtc_h != plane_state->crtc_h ||
>> -        src_w != plane_state->src_w ||
>> -        src_h != plane_state->src_h) {
>> -        goto out;
>> -    }
>> +    if (!plane->state)
>> +        return -EINVAL;
>> -    if (fb != plane_state->fb) {
>> -        drm_atomic_set_fb_for_plane(plane->state, fb);
>> -        vc4_plane_async_set_fb(plane, fb);
>> -    }
>> +    return 0;
>> +}
>> -    /* Set the cursor's position on the screen.  This is the
>> -     * expected change from the drm_mode_cursor_universal()
>> -     * helper.
>> -     */
>> -    plane_state->crtc_x = crtc_x;
>> -    plane_state->crtc_y = crtc_y;
>> +static void vc4_plane_atomic_async_update(struct drm_plane *plane,
>> +                      struct drm_plane_state *new_state)
>> +{
>> +    struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
>> -    /* Allow changing the start position within the cursor BO, if
>> -     * that matters.
>> -     */
>> -    plane_state->src_x = src_x;
>> -    plane_state->src_y = src_y;
>> +    if (plane->state->fb != new_state->fb)
>> +        vc4_plane_async_set_fb(plane, new_state->fb);
>> -    /* Update the display list based on the new crtc_x/y. */
>> -    vc4_plane_atomic_check(plane, plane_state);
>> +    plane->state->fb = new_state->fb;
>>       /* Note that we can't just call vc4_plane_write_dlist()
>>        * because that would smash the context data that the HVS is
>> @@ -810,20 +767,23 @@ vc4_update_plane(struct drm_plane *plane,
>>              &vc4_state->hw_dlist[vc4_state->pos2_offset]);
>>       writel(vc4_state->dlist[vc4_state->ptr0_offset],
>>              &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
>> +}
>> -    return 0;
>> +static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
>> +    .atomic_check = vc4_plane_atomic_check,
>> +    .atomic_update = vc4_plane_atomic_update,
>> +    .atomic_async_check = vc4_plane_atomic_async_check,
>> +    .atomic_async_update = vc4_plane_atomic_async_update,
>> +};
>> -out:
>> -    return drm_atomic_helper_update_plane(plane, crtc, fb,
>> -                          crtc_x, crtc_y,
>> -                          crtc_w, crtc_h,
>> -                          src_x, src_y,
>> -                          src_w, src_h,
>> -                          ctx);
>> +static void vc4_plane_destroy(struct drm_plane *plane)
>> +{
>> +    drm_plane_helper_disable(plane);
>> +    drm_plane_cleanup(plane);
>>   }
>>   static const struct drm_plane_funcs vc4_plane_funcs = {
>> -    .update_plane = vc4_update_plane,
>> +    .update_plane = drm_atomic_helper_update_plane,
>>       .disable_plane = drm_atomic_helper_disable_plane,
>>       .destroy = vc4_plane_destroy,
>>       .set_property = NULL,
>>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2017-05-18 22:56 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-10  0:24 [RFC 0/7] drm: asynchronous atomic plane update Gustavo Padovan
2017-04-10  0:24 ` [RFC 1/7] drm/atomic: initial support for asynchronous " Gustavo Padovan
2017-04-10  7:13   ` Emil Velikov
2017-04-10  9:39     ` Gustavo Padovan
2017-04-10 19:55   ` Eric Anholt
2017-04-11 20:23     ` Daniel Vetter
2017-04-12 18:17       ` Gustavo Padovan
2017-04-21 18:41       ` Gustavo Padovan
2017-05-02  8:10         ` Daniel Vetter
2017-05-02 10:58           ` Daniel Stone
2017-04-10  0:24 ` [RFC 2/7] drm/virtio: support async cursor updates Gustavo Padovan
2017-04-10  0:24 ` [RFC 3/7] drm/i915: update cursors asynchronously through atomic Gustavo Padovan
2017-04-10  0:24 ` [RFC 4/7] drm/i915: remove intel_cursor_plane_funcs Gustavo Padovan
2017-04-10  0:24 ` [RFC 5/7] drm/msm: update cursors asynchronously through atomic Gustavo Padovan
2017-04-10  0:24 ` [RFC 6/7] drm/msm: remove mdp5_cursor_plane_funcs Gustavo Padovan
2017-04-10  0:24 ` [RFC 7/7] drm/vc4: update cursors asynchronously through atomic Gustavo Padovan
2017-04-10 20:06   ` Eric Anholt
2017-04-11 20:27     ` Daniel Vetter
2017-05-18 22:52   ` Robert Foss
2017-05-18 22:55     ` Robert Foss

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.