diff mbox series

drm/syncobj: Add better overview documentation for syncobj

Message ID 20190802174033.10505-1-jason@jlekstrand.net (mailing list archive)
State New, archived
Headers show
Series drm/syncobj: Add better overview documentation for syncobj | expand

Commit Message

Jason Ekstrand Aug. 2, 2019, 5:40 p.m. UTC
This patch only brings the syncobj documentation up-to-date for the
original form of syncobj.  It does not contain any information about the
design of timeline syncobjs.
---
 drivers/gpu/drm/drm_syncobj.c | 81 +++++++++++++++++++++++++++++++----
 1 file changed, 73 insertions(+), 8 deletions(-)

Comments

Lionel Landwerlin Aug. 3, 2019, 8:19 a.m. UTC | #1
Thanks a lot for writing this :)
I now have a canvas to add stuff on!

Just a couple of questions below.

-Lionel

On 02/08/2019 20:40, Jason Ekstrand wrote:
> This patch only brings the syncobj documentation up-to-date for the
> original form of syncobj.  It does not contain any information about the
> design of timeline syncobjs.
> ---
>   drivers/gpu/drm/drm_syncobj.c | 81 +++++++++++++++++++++++++++++++----
>   1 file changed, 73 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
> index 1438dcb3ebb1..03cc888744fb 100644
> --- a/drivers/gpu/drm/drm_syncobj.c
> +++ b/drivers/gpu/drm/drm_syncobj.c
> @@ -29,17 +29,82 @@
>   /**
>    * DOC: Overview
>    *
> - * DRM synchronisation objects (syncobj, see struct &drm_syncobj) are
> - * persistent objects that contain an optional fence. The fence can be updated
> - * with a new fence, or be NULL.
> + * DRM synchronisation objects (syncobj, see struct &drm_syncobj) provide a
> + * synchronization primitive which can be used by userspace to explicitly
> + * synchronize GPU commands, can be shared between userspace processes, and
> + * can be shared between different DRM drivers.


I've been wondering whether we should call it a container for a 
synchronization primitive rather than a primitive itself.

Sync files are also a container, just we fewer features (no host 
operations).

It's not really important :)


> + * Their primary use-case is to implement Vulkan fences and semaphores.
> + * The syncobj userspace API provides ioctls for several operations:
>    *
> - * syncobj's can be waited upon, where it will wait for the underlying
> - * fence.
> + *  - Creation and destruction of syncobjs
> + *  - Import and export of syncobjs to/from a syncobj file descriptor
> + *  - Import and export a syncobj's underlying fence to/from a sync file
> + *  - Reset a syncobj (set its fence to NULL)
> + *  - Signal a syncobj (set a trivially signaled fence)
> + *  - Wait a syncobj's fence to be signaled
>    *
> - * syncobj's can be export to fd's and back, these fd's are opaque and
> - * have no other use case, except passing the syncobj between processes.
> + * At it's core, a syncobj simply a wrapper around a pointer to a struct
> + * &dma_fence which may be NULL.
> + * When GPU work which signals a syncobj is enqueued in a DRM driver,
> + * the syncobj fence is replaced with a fence which will be signaled by the
> + * completion of that work.
> + * When GPU work which waits on a syncobj is enqueued in a DRM driver, the
> + * driver retrieves syncobj's current fence at the time the work is enqueued
> + * waits on that fence before submitting the work to hardware.
> + * If the syncobj's fence is NULL, the enqueue operation is expected to fail.
> + * All manipulation of the syncobjs's fence happens in terms of the current
> + * fence at the time the ioctl is called by userspace regardless of whether
> + * that operation is an immediate host-side operation (signal or reset) or
> + * or an operation which is enqueued in some driver queue.
>    *
> - * Their primary use-case is to implement Vulkan fences and semaphores.


Maybe add a line about creation (and its signaled flag)?


> + *
> + * Host-side wait on syncobjs
> + * --------------------------
> + *
> + * The userspace syncobj API provides an ioctl for waiting on a set of
> + * syncobjs.
> + * The wait ioctl takes an array of syncobj handles and a flag indicating
> + * whether it should return immediately once one syncobj has been signaled
> + * or if it should wait for all the syncobjs to be signaled.
> + * Unlike the enqueued GPU work dependencies, the host-side wait ioctl
> + * will also optionally wait for the syncobj to first receive a fence and
> + * then wait on that fence.
> + * Assuming the syncobj starts off with a NULL fence, this allows a client
> + * to do a host wait in one thread (or process) which waits on GPU work
> + * submitted in another thread (or process) without having to manually
> + * synchronize between the two.
> + * This requirement is inherited from the Vulkan fence API.


Should we list the flags & ioctl names?


> + *
> + *
> + * Import/export of syncobjs
> + * -------------------------
> + *
> + * The userspace syncobj API provides two mechanisms for import/export of
> + * syncobjs.
> + *
> + * The first lets the client import or export an entire syncobj to a file
> + * descriptor.
> + * These fd's are opaque and have no other use case, except passing the
> + * syncobj between processes.
> + * All syncobj handles which are created as the result of such an import
> + * operation refer to the same underlying syncobj as was used for the
> + * export and the syncobj can be used persistently across all the processes
> + * with which it is shared.
> + * Unlike dma-buf, importing a syncobj creates a new handle for every
> + * import instead of de-duplicating.
> + * The primary use-case of this persistent import/export is for shared
> + * Vulkan fences and semaphores.
> + *
> + * The second import/export mechanism lets the client export the syncobj's
> + * current fence to/from a &sync_file.
> + * When a syncobj is exported to a sync file, that sync file wraps the
> + * sycnobj's fence at the time of export and any later signal or reset
> + * operations on the syncobj will not affect the exported sync file.
> + * When a sync file is imported into a syncobj, the syncobj's fence is set
> + * to the fence wrapped by that sync file.
> + * Because sync files are immutable, resetting or signaling the syncobj
> + * will not affect any sync files whose fences have been imported into the
> + * syncobj.
>    *


This 3 lines below seem to be redundant now?

Maybe rephrase with something like :


"Sharing a syncobj increases its refcount. The syncobj is destroyed when 
a client release the last reference."


>    * syncobj have a kref reference count, but also have an optional file.
>    * The file is only created once the syncobj is exported.
Jason Ekstrand Aug. 5, 2019, 5:01 p.m. UTC | #2
On Sat, Aug 3, 2019 at 3:19 AM Lionel Landwerlin <
lionel.g.landwerlin@intel.com> wrote:

> Thanks a lot for writing this :)
> I now have a canvas to add stuff on!
>
> Just a couple of questions below.
>
> -Lionel
>
> On 02/08/2019 20:40, Jason Ekstrand wrote:
> > This patch only brings the syncobj documentation up-to-date for the
> > original form of syncobj.  It does not contain any information about the
> > design of timeline syncobjs.
> > ---
> >   drivers/gpu/drm/drm_syncobj.c | 81 +++++++++++++++++++++++++++++++----
> >   1 file changed, 73 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_syncobj.c
> b/drivers/gpu/drm/drm_syncobj.c
> > index 1438dcb3ebb1..03cc888744fb 100644
> > --- a/drivers/gpu/drm/drm_syncobj.c
> > +++ b/drivers/gpu/drm/drm_syncobj.c
> > @@ -29,17 +29,82 @@
> >   /**
> >    * DOC: Overview
> >    *
> > - * DRM synchronisation objects (syncobj, see struct &drm_syncobj) are
> > - * persistent objects that contain an optional fence. The fence can be
> updated
> > - * with a new fence, or be NULL.
> > + * DRM synchronisation objects (syncobj, see struct &drm_syncobj)
> provide a
> > + * synchronization primitive which can be used by userspace to
> explicitly
> > + * synchronize GPU commands, can be shared between userspace processes,
> and
> > + * can be shared between different DRM drivers.
>
>
> I've been wondering whether we should call it a container for a
> synchronization primitive rather than a primitive itself.
>
> Sync files are also a container, just we fewer features (no host
> operations).
>
> It's not really important :)
>

That's a fun philosophical question and I think the answer entirely depends
on which side of the ioctl you're on. :-)


> > + * Their primary use-case is to implement Vulkan fences and semaphores.
> > + * The syncobj userspace API provides ioctls for several operations:
> >    *
> > - * syncobj's can be waited upon, where it will wait for the underlying
> > - * fence.
> > + *  - Creation and destruction of syncobjs
> > + *  - Import and export of syncobjs to/from a syncobj file descriptor
> > + *  - Import and export a syncobj's underlying fence to/from a sync file
> > + *  - Reset a syncobj (set its fence to NULL)
> > + *  - Signal a syncobj (set a trivially signaled fence)
> > + *  - Wait a syncobj's fence to be signaled
> >    *
> > - * syncobj's can be export to fd's and back, these fd's are opaque and
> > - * have no other use case, except passing the syncobj between processes.
> > + * At it's core, a syncobj simply a wrapper around a pointer to a struct
> > + * &dma_fence which may be NULL.
> > + * When GPU work which signals a syncobj is enqueued in a DRM driver,
> > + * the syncobj fence is replaced with a fence which will be signaled by
> the
> > + * completion of that work.
> > + * When GPU work which waits on a syncobj is enqueued in a DRM driver,
> the
> > + * driver retrieves syncobj's current fence at the time the work is
> enqueued
> > + * waits on that fence before submitting the work to hardware.
> > + * If the syncobj's fence is NULL, the enqueue operation is expected to
> fail.
> > + * All manipulation of the syncobjs's fence happens in terms of the
> current
> > + * fence at the time the ioctl is called by userspace regardless of
> whether
> > + * that operation is an immediate host-side operation (signal or reset)
> or
> > + * or an operation which is enqueued in some driver queue.
> >    *
> > - * Their primary use-case is to implement Vulkan fences and semaphores.
>
>
> Maybe add a line about creation (and its signaled flag)?
>

Sure, I'll also make a comment about reset and signal.


> > + *
> > + * Host-side wait on syncobjs
> > + * --------------------------
> > + *
> > + * The userspace syncobj API provides an ioctl for waiting on a set of
> > + * syncobjs.
> > + * The wait ioctl takes an array of syncobj handles and a flag
> indicating
> > + * whether it should return immediately once one syncobj has been
> signaled
> > + * or if it should wait for all the syncobjs to be signaled.
> > + * Unlike the enqueued GPU work dependencies, the host-side wait ioctl
> > + * will also optionally wait for the syncobj to first receive a fence
> and
> > + * then wait on that fence.
> > + * Assuming the syncobj starts off with a NULL fence, this allows a
> client
> > + * to do a host wait in one thread (or process) which waits on GPU work
> > + * submitted in another thread (or process) without having to manually
> > + * synchronize between the two.
> > + * This requirement is inherited from the Vulkan fence API.
>
>
> Should we list the flags & ioctl names?
>

I don't know.  Maybe Dave or Daniel can tell me how these things are
usually done?


> > + *
> > + *
> > + * Import/export of syncobjs
> > + * -------------------------
> > + *
> > + * The userspace syncobj API provides two mechanisms for import/export
> of
> > + * syncobjs.
> > + *
> > + * The first lets the client import or export an entire syncobj to a
> file
> > + * descriptor.
> > + * These fd's are opaque and have no other use case, except passing the
> > + * syncobj between processes.
> > + * All syncobj handles which are created as the result of such an import
> > + * operation refer to the same underlying syncobj as was used for the
> > + * export and the syncobj can be used persistently across all the
> processes
> > + * with which it is shared.
> > + * Unlike dma-buf, importing a syncobj creates a new handle for every
> > + * import instead of de-duplicating.
> > + * The primary use-case of this persistent import/export is for shared
> > + * Vulkan fences and semaphores.
> > + *
> > + * The second import/export mechanism lets the client export the
> syncobj's
> > + * current fence to/from a &sync_file.
> > + * When a syncobj is exported to a sync file, that sync file wraps the
> > + * sycnobj's fence at the time of export and any later signal or reset
> > + * operations on the syncobj will not affect the exported sync file.
> > + * When a sync file is imported into a syncobj, the syncobj's fence is
> set
> > + * to the fence wrapped by that sync file.
> > + * Because sync files are immutable, resetting or signaling the syncobj
> > + * will not affect any sync files whose fences have been imported into
> the
> > + * syncobj.
> >    *
>
>
> This 3 lines below seem to be redundant now?
>

Which three lines are you referring to?  The thing about krefs?  I agree
that it feels a bit odd with the rest of the documentation because it's a
very internal detail and the rest of what I've written is an overview.
Maybe the bit about krefs should go in the top section and the bit about
the file should stay here?


> Maybe rephrase with something like :
>
>
> "Sharing a syncobj increases its refcount. The syncobj is destroyed when
> a client release the last reference."
>

I don't think we need to describe how reference counting works.


> >    * syncobj have a kref reference count, but also have an optional file.
> >    * The file is only created once the syncobj is exported.
>
>
>
Christian König Aug. 6, 2019, 7:37 a.m. UTC | #3
I somehow totally missed that patch, looks like it maybe ended up in the spam folder.

Am 05.08.19 um 19:01 schrieb Jason Ekstrand:

On Sat, Aug 3, 2019 at 3:19 AM Lionel Landwerlin <lionel.g.landwerlin@intel.com<mailto:lionel.g.landwerlin@intel.com>> wrote:
Thanks a lot for writing this :)
I now have a canvas to add stuff on!

Just a couple of questions below.

-Lionel

On 02/08/2019 20:40, Jason Ekstrand wrote:
> This patch only brings the syncobj documentation up-to-date for the
> original form of syncobj.  It does not contain any information about the
> design of timeline syncobjs.
> ---
>   drivers/gpu/drm/drm_syncobj.c | 81 +++++++++++++++++++++++++++++++----
>   1 file changed, 73 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
> index 1438dcb3ebb1..03cc888744fb 100644
> --- a/drivers/gpu/drm/drm_syncobj.c
> +++ b/drivers/gpu/drm/drm_syncobj.c
> @@ -29,17 +29,82 @@
>   /**
>    * DOC: Overview
>    *
> - * DRM synchronisation objects (syncobj, see struct &drm_syncobj) are
> - * persistent objects that contain an optional fence. The fence can be updated
> - * with a new fence, or be NULL.
> + * DRM synchronisation objects (syncobj, see struct &drm_syncobj) provide a
> + * synchronization primitive which can be used by userspace to explicitly
> + * synchronize GPU commands, can be shared between userspace processes, and
> + * can be shared between different DRM drivers.


I've been wondering whether we should call it a container for a
synchronization primitive rather than a primitive itself.

Sync files are also a container, just we fewer features (no host
operations).

It's not really important :)

That's a fun philosophical question and I think the answer entirely depends on which side of the ioctl you're on. :-)

Yeah, but this is kernel documentation, not userspace documentation. So I agree that syncobjs are just a container inside the kernel.


> + * Their primary use-case is to implement Vulkan fences and semaphores.
> + * The syncobj userspace API provides ioctls for several operations:
>    *
> - * syncobj's can be waited upon, where it will wait for the underlying
> - * fence.
> + *  - Creation and destruction of syncobjs
> + *  - Import and export of syncobjs to/from a syncobj file descriptor
> + *  - Import and export a syncobj's underlying fence to/from a sync file
> + *  - Reset a syncobj (set its fence to NULL)
> + *  - Signal a syncobj (set a trivially signaled fence)
> + *  - Wait a syncobj's fence to be signaled

Wait for a fence to appear.

>    *
> - * syncobj's can be export to fd's and back, these fd's are opaque and
> - * have no other use case, except passing the syncobj between processes.
> + * At it's core, a syncobj simply a wrapper around a pointer to a struct
> + * &dma_fence which may be NULL.
> + * When GPU work which signals a syncobj is enqueued in a DRM driver,
> + * the syncobj fence is replaced with a fence which will be signaled by the
> + * completion of that work.
> + * When GPU work which waits on a syncobj is enqueued in a DRM driver, the
> + * driver retrieves syncobj's current fence at the time the work is enqueued
> + * waits on that fence before submitting the work to hardware.
> + * If the syncobj's fence is NULL, the enqueue operation is expected to fail.
> + * All manipulation of the syncobjs's fence happens in terms of the current
> + * fence at the time the ioctl is called by userspace regardless of whether
> + * that operation is an immediate host-side operation (signal or reset) or
> + * or an operation which is enqueued in some driver queue.
>    *
> - * Their primary use-case is to implement Vulkan fences and semaphores.


Maybe add a line about creation (and its signaled flag)?

Sure, I'll also make a comment about reset and signal.

> + *
> + * Host-side wait on syncobjs
> + * --------------------------
> + *
> + * The userspace syncobj API provides an ioctl for waiting on a set of
> + * syncobjs.
> + * The wait ioctl takes an array of syncobj handles and a flag indicating
> + * whether it should return immediately once one syncobj has been signaled
> + * or if it should wait for all the syncobjs to be signaled.
> + * Unlike the enqueued GPU work dependencies, the host-side wait ioctl
> + * will also optionally wait for the syncobj to first receive a fence and
> + * then wait on that fence.
> + * Assuming the syncobj starts off with a NULL fence, this allows a client
> + * to do a host wait in one thread (or process) which waits on GPU work
> + * submitted in another thread (or process) without having to manually
> + * synchronize between the two.
> + * This requirement is inherited from the Vulkan fence API.


Should we list the flags & ioctl names?

I don't know.  Maybe Dave or Daniel can tell me how these things are usually done?

You could & reference the enum/defines of the IOCTL numbers in the first sentence or something like this.


> + *
> + *
> + * Import/export of syncobjs
> + * -------------------------
> + *
> + * The userspace syncobj API provides two mechanisms for import/export of
> + * syncobjs.
> + *
> + * The first lets the client import or export an entire syncobj to a file
> + * descriptor.
> + * These fd's are opaque and have no other use case, except passing the
> + * syncobj between processes.
> + * All syncobj handles which are created as the result of such an import
> + * operation refer to the same underlying syncobj as was used for the
> + * export and the syncobj can be used persistently across all the processes
> + * with which it is shared.
> + * Unlike dma-buf, importing a syncobj creates a new handle for every
> + * import instead of de-duplicating.
> + * The primary use-case of this persistent import/export is for shared
> + * Vulkan fences and semaphores.
> + *
> + * The second import/export mechanism lets the client export the syncobj's
> + * current fence to/from a &sync_file.
> + * When a syncobj is exported to a sync file, that sync file wraps the
> + * sycnobj's fence at the time of export and any later signal or reset
> + * operations on the syncobj will not affect the exported sync file.
> + * When a sync file is imported into a syncobj, the syncobj's fence is set
> + * to the fence wrapped by that sync file.
> + * Because sync files are immutable, resetting or signaling the syncobj
> + * will not affect any sync files whose fences have been imported into the
> + * syncobj.
>    *


This 3 lines below seem to be redundant now?

Which three lines are you referring to?  The thing about krefs?  I agree that it feels a bit odd with the rest of the documentation because it's a very internal detail and the rest of what I've written is an overview.  Maybe the bit about krefs should go in the top section and the bit about the file should stay here?

Maybe rephrase with something like :


"Sharing a syncobj increases its refcount. The syncobj is destroyed when
a client release the last reference."

I don't think we need to describe how reference counting works.

Agreed, we should just mention that things are referenced instead of copied. How this referencing works is out of scope here.


>    * syncobj have a kref reference count, but also have an optional file.
>    * The file is only created once the syncobj is exported.

To much detail.

Regards,
Christian.
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 1438dcb3ebb1..03cc888744fb 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -29,17 +29,82 @@ 
 /**
  * DOC: Overview
  *
- * DRM synchronisation objects (syncobj, see struct &drm_syncobj) are
- * persistent objects that contain an optional fence. The fence can be updated
- * with a new fence, or be NULL.
+ * DRM synchronisation objects (syncobj, see struct &drm_syncobj) provide a
+ * synchronization primitive which can be used by userspace to explicitly
+ * synchronize GPU commands, can be shared between userspace processes, and
+ * can be shared between different DRM drivers.
+ * Their primary use-case is to implement Vulkan fences and semaphores.
+ * The syncobj userspace API provides ioctls for several operations:
  *
- * syncobj's can be waited upon, where it will wait for the underlying
- * fence.
+ *  - Creation and destruction of syncobjs
+ *  - Import and export of syncobjs to/from a syncobj file descriptor
+ *  - Import and export a syncobj's underlying fence to/from a sync file
+ *  - Reset a syncobj (set its fence to NULL)
+ *  - Signal a syncobj (set a trivially signaled fence)
+ *  - Wait a syncobj's fence to be signaled
  *
- * syncobj's can be export to fd's and back, these fd's are opaque and
- * have no other use case, except passing the syncobj between processes.
+ * At it's core, a syncobj simply a wrapper around a pointer to a struct
+ * &dma_fence which may be NULL.
+ * When GPU work which signals a syncobj is enqueued in a DRM driver,
+ * the syncobj fence is replaced with a fence which will be signaled by the
+ * completion of that work.
+ * When GPU work which waits on a syncobj is enqueued in a DRM driver, the
+ * driver retrieves syncobj's current fence at the time the work is enqueued
+ * waits on that fence before submitting the work to hardware.
+ * If the syncobj's fence is NULL, the enqueue operation is expected to fail.
+ * All manipulation of the syncobjs's fence happens in terms of the current
+ * fence at the time the ioctl is called by userspace regardless of whether
+ * that operation is an immediate host-side operation (signal or reset) or
+ * or an operation which is enqueued in some driver queue.
  *
- * Their primary use-case is to implement Vulkan fences and semaphores.
+ *
+ * Host-side wait on syncobjs
+ * --------------------------
+ *
+ * The userspace syncobj API provides an ioctl for waiting on a set of
+ * syncobjs.
+ * The wait ioctl takes an array of syncobj handles and a flag indicating
+ * whether it should return immediately once one syncobj has been signaled
+ * or if it should wait for all the syncobjs to be signaled.
+ * Unlike the enqueued GPU work dependencies, the host-side wait ioctl
+ * will also optionally wait for the syncobj to first receive a fence and
+ * then wait on that fence.
+ * Assuming the syncobj starts off with a NULL fence, this allows a client
+ * to do a host wait in one thread (or process) which waits on GPU work
+ * submitted in another thread (or process) without having to manually
+ * synchronize between the two.
+ * This requirement is inherited from the Vulkan fence API.
+ *
+ *
+ * Import/export of syncobjs
+ * -------------------------
+ *
+ * The userspace syncobj API provides two mechanisms for import/export of
+ * syncobjs.
+ *
+ * The first lets the client import or export an entire syncobj to a file
+ * descriptor.
+ * These fd's are opaque and have no other use case, except passing the
+ * syncobj between processes.
+ * All syncobj handles which are created as the result of such an import
+ * operation refer to the same underlying syncobj as was used for the
+ * export and the syncobj can be used persistently across all the processes
+ * with which it is shared.
+ * Unlike dma-buf, importing a syncobj creates a new handle for every
+ * import instead of de-duplicating.
+ * The primary use-case of this persistent import/export is for shared
+ * Vulkan fences and semaphores.
+ *
+ * The second import/export mechanism lets the client export the syncobj's
+ * current fence to/from a &sync_file.
+ * When a syncobj is exported to a sync file, that sync file wraps the
+ * sycnobj's fence at the time of export and any later signal or reset
+ * operations on the syncobj will not affect the exported sync file.
+ * When a sync file is imported into a syncobj, the syncobj's fence is set
+ * to the fence wrapped by that sync file.
+ * Because sync files are immutable, resetting or signaling the syncobj
+ * will not affect any sync files whose fences have been imported into the
+ * syncobj.
  *
  * syncobj have a kref reference count, but also have an optional file.
  * The file is only created once the syncobj is exported.