You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
3.1 KiB
75 lines
3.1 KiB
Motivation: |
|
|
|
In complicated DMA pipelines such as graphics (multimedia, camera, gpu, display) |
|
a consumer of a buffer needs to know when the producer has finished producing |
|
it. Likewise the producer needs to know when the consumer is finished with the |
|
buffer so it can reuse it. A particular buffer may be consumed by multiple |
|
consumers which will retain the buffer for different amounts of time. In |
|
addition, a consumer may consume multiple buffers atomically. |
|
The sync framework adds an API which allows synchronization between the |
|
producers and consumers in a generic way while also allowing platforms which |
|
have shared hardware synchronization primitives to exploit them. |
|
|
|
Goals: |
|
* provide a generic API for expressing synchronization dependencies |
|
* allow drivers to exploit hardware synchronization between hardware |
|
blocks |
|
* provide a userspace API that allows a compositor to manage |
|
dependencies. |
|
* provide rich telemetry data to allow debugging slowdowns and stalls of |
|
the graphics pipeline. |
|
|
|
Objects: |
|
* sync_timeline |
|
* sync_pt |
|
* sync_fence |
|
|
|
sync_timeline: |
|
|
|
A sync_timeline is an abstract monotonically increasing counter. In general, |
|
each driver/hardware block context will have one of these. They can be backed |
|
by the appropriate hardware or rely on the generic sw_sync implementation. |
|
Timelines are only ever created through their specific implementations |
|
(i.e. sw_sync.) |
|
|
|
sync_pt: |
|
|
|
A sync_pt is an abstract value which marks a point on a sync_timeline. Sync_pts |
|
have a single timeline parent. They have 3 states: active, signaled, and error. |
|
They start in active state and transition, once, to either signaled (when the |
|
timeline counter advances beyond the sync_pt’s value) or error state. |
|
|
|
sync_fence: |
|
|
|
Sync_fences are the primary primitives used by drivers to coordinate |
|
synchronization of their buffers. They are a collection of sync_pts which may |
|
or may not have the same timeline parent. A sync_pt can only exist in one fence |
|
and the fence's list of sync_pts is immutable once created. Fences can be |
|
waited on synchronously or asynchronously. Two fences can also be merged to |
|
create a third fence containing a copy of the two fences’ sync_pts. Fences are |
|
backed by file descriptors to allow userspace to coordinate the display pipeline |
|
dependencies. |
|
|
|
Use: |
|
|
|
A driver implementing sync support should have a work submission function which: |
|
* takes a fence argument specifying when to begin work |
|
* asynchronously queues that work to kick off when the fence is signaled |
|
* returns a fence to indicate when its work will be done. |
|
* signals the returned fence once the work is completed. |
|
|
|
Consider an imaginary display driver that has the following API: |
|
/* |
|
* assumes buf is ready to be displayed. |
|
* blocks until the buffer is on screen. |
|
*/ |
|
void display_buffer(struct dma_buf *buf); |
|
|
|
The new API will become: |
|
/* |
|
* will display buf when fence is signaled. |
|
* returns immediately with a fence that will signal when buf |
|
* is no longer displayed. |
|
*/ |
|
struct sync_fence* display_buffer(struct dma_buf *buf, |
|
struct sync_fence *fence);
|
|
|