75 lines
3.1 KiB
Text
75 lines
3.1 KiB
Text
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);
|