blob: 5c6ea054321ae6c4375ce38c5196a26d3eef9caa [file] [log] [blame] [view]
# Sysmem overview
[Sysmem][sysmem] is a [FIDL][fidl] service that allocates shared memory for
use by multiple applications and hardware blocks. This document gives an
overview of its major features and what it provides to the system.
## Motivation
Modern systems have specialized hardware blocks that can perform operations
on data. Some examples of these blocks:
* Rendering computer graphics with a GPU.
* Encoding or decoding video with a hardware codec.
* Capturing high-quality photographs with a camera and DSP.
* Compositing images to a display using the display controller’s overlay
engine.
* Evaluating neural networks with a TPU.
Often, we want to create pipelines passing data between those separate
hardware blocks. Some examples:
* Decoding video with a hardware codec and compositing it to the display
together with user interface content rendered on the GPU.
* Applying a neural network to a live camera feed.
To do this efficiently and avoid copying, drivers and applications must agree
on the format data is in and where the data is located in memory. This
agreement allows the output of one unit to be used directly by the next.
Hardware units have strict constraints on these properties and also
preferences about which data layout will give the best performance.
Sysmem is a global service that can be fed constraints by applications and
allocate buffers such that all the constraints are met. If multiple formats
are supported, it can choose between them based on the expected performance.
Sysmem buffers are often used to represent images and sysmem has special
support for negotiating image formats. However the sysmem interface can also
be used for audio or any other type of data.
Sysmem does not manage the flow of data once buffers have been allocated.
Applications in a pipeline are responsible for coordinating between each
other to ensure synchronization.
## Allocation process (simplified)
1. [Participants](#participants) connect to the
[fuchsia.sysmem2.Allocator][Allocator] service
1. One participant (called the initiator) creates an initial
[buffer collection token](#token).
1. That participant [duplicates] the token and sends the duplicate to other
participants.
1. Those participants can also duplicate and send tokens, recursively, until
all participants have received a token.
1. Each participant [binds][bind] its token to get a buffer collection.
1. Each participant [sets constraints][SetConstraints] on the buffer collection
1. Sysmem chooses a format that can satisfy all the constraints. This can
only happen after every participant has bound its token and set constraints
on the collection.
1. Sysmem allocates a number of [buffers](#Buffers) using that format.
1. Participants retrieve the buffers from sysmem, as well as information
about the allocated format.
The information returned by sysmem is the set of constraints the image
formats in that buffer must satisfy.
At this point participants can use the buffers with the allocated format,
subject to pipeline-specific constraints on the flow of data between
participants. Since multiple image sizes may be usable from a buffer,
participants must work together to choose an image size before they can
determine the precise image format. This allows a pipeline to switch image
sizes on the fly without needing to reallocate buffers.
If a new participant needs to be added to an existing collection which has
already undergone constraint negotiation and allocation, a new token can be
[attached][AttachToken] to the buffer collection. The new participant's
constraints must be satisfied using the already-allocated buffer collection,
or the logical allocation (from the point of view of the new participant) fails.
To increase the chances that the new participant can be added successfully, one
of the participants present during initial allocation can mark a token
[dispensable][SetDispensable]. This allows the token to be used to specify
stand-in constraints so that the buffer collection will be able to later
accommodate a new participant with the same constraints.
## Buffer destruction
Buffer destruction is asynchronous.
To wait for old buffers of an old collection to fully delete (optionally with a
deadline), see [AttachLifetimeTracking][AttachLifetimeTracking].
The buffer destruction sequence begins when the buffer collection fails. In the
normal/success case, this "failure" is typically triggered when a participant
(often the initiator) closes any collection-specific channel without having sent
[`Release`][Release] first. Currently, collection-specific channels are
[`BufferCollectionToken`][BufferCollectionToken],
[`BufferCollection`][BufferCollection], and
[`BufferCollectionTokenGroup`][BufferCollectionTokenGroup] channels.
When the collection enters the failed state, the sysmem server will close the
server end of all the collection-specific channels. All the allocated VMOs
remain usable until participants are done cleaning up (see list below).
At this point all participants are expected to quickly notice (directly or
indirectly via another sufficiently-trusted participant) the collection-specific
channel server-side closure (`ZX_CHANNEL_PEER_CLOSED` signaled at client end).
Each participant then ensures that the list of cleanup conditions below is met
for as many of the buffers as possible. In rare cases keeping a low number of
buffers around for a while longer can make sense, such as for keeping a last
video frame on-screen until a new video frame using a new collection is
available.
All references to a buffer must be removed before sysmem will destroy it and
allow the memory to be reused. These include:
* [Handles][handles] to the VMO.
* [CPU mappings][map] of the VMO.
* [Child VMOs][vmo_create_child] of the VMO.
* [Pins][pmt] of the VMO for use by hardware.
* [Channels][channel] to a Buffer Collection containing that VMOs. The sysmem
server will consider a channel closed whether the close was initiated by the
client or the server. This item does not apply to still-open channels that
sent [`SetWeak`][SetWeak] previously.
Under a non-preferred and less common model, all participants may close all
collection-specific channels (with or without a [`Release`][Release] first)
shortly after allocation, which triggers collection failure early (due to zero
collection-specific channels remaining), but then the participants may continue
to use the VMOs for a while despite the collection having "failed". Then later
they use a separate mechanism to know when they want to clean up the VMOs (see
list above).
The non-preferred model technically works, but it can make the collection
lifetime less clear, and make the sysmem inspect data less clear / less helpful.
Nonetheless, in some rare situations this non-preferred model may be useful to
accommodate constraints imposed by other protocols / interfaces. If considering
this model, first consider having a participant send [`Release`][Release] and
close its collection-specific channel, then learn of collection failure
indirectly via another (sufficiently-trusted) participant; this way the overall
setup still conforms to the preferred model described above. If the only reason
this model is being considered is to allow incremental buffer deallocation,
consider [SetWeak][SetWeak] instead.
## Advanced usage
### Fallback constraints and/or optional participant(s)
A [`BufferCollectionTokenGroup`][BufferCollectionTokenGroup] is used in more
complicated situations where an entire participant is optional / best-effort, or
if there are fallback less-strict constraints that differ from preferred
more-strict constraints (such as for performance reasons).
Only one child token directly under the group (along with the sub-tree starting
at that token) is selected during allocation, with the first child token of the
group preferred, etc.
A group under a token under a group is permitted (etc).
The total number of group child selection combinations attempted during
allocation is capped; if hitting this cap, feel free to reach out to discuss
alternatives.
This is advanced usage that's not directly relevant to most participants. See
docs of [`BufferCollectionTokenGroup`][BufferCollectionTokenGroup].
### Failure isolation and/or late participant join
The [`SetDispensable`][SetDispensable] and [`AttachToken`][AttachToken] messages
can be used to create a failure-isolated sub-tree (defined by token duplication
parentage) and potentially later replace the sub-tree with a new sub-tree
instance after the original sub-tree instance fails, without failing the root.
The first [token][BufferCollectionToken] created by the initiator is what
creates the root; the [collection channel][BufferCollection] later created from
that token is still considered the root node of the tree (different protocol,
but same "node").
When replacing the sub-tree, the new sub-tree participants see what looks like a
normal allocation sequence, but really they're "joining" a buffer collection
"already in progress".
Use of [`AttachToken`][AttachToken] doesn't require prior use of
[`SetDispensable`][SetDispensable].
Currently [`AttachToken`][AttachToken] requires that the collection already have
sufficient buffers to satisfy the newly attached participant instance(s).
This is advanced usage that's not directly relevant to most participants. See
docs of [`SetDispensable`][SetDispensable] and [`AttachToken`][AttachToken].
## Glossary
### Buffers
A buffer represents a single image or other piece of memory an application
will work with. Sysmem currently uses one [VMO][vmo] per buffer. Clients can
[map][map] the memory onto the CPU or [pin][pmt] it to use it with a hardware
block.
### Participants
A participant is any application or driver that wants to access a buffer. All
participants must connect to sysmem to negotiate memory formats.
### Image formats
An [image format][ImageFormat] is the entire set of properties needed for a
client to interpret the memory as a set of pixels. For example, it includes
the pixel format, size in width and height, row pitch in bytes between rows,
and color space.
### Buffer settings
[Buffer settings][SingleBufferSettings] are a complete description of the
properties of a buffer. These include the caching information, and other
properties that participants may need to access the memory. For images the
buffer settings will also have an image format.
Buffer settings do not include the specific memory address, so multiple
different buffers may have the same buffer settings.
### Heaps
A [heap][Heap] represents one specific type of memory on a system. A
system may have multiple heaps with different performance characteristics
from each other. Some heaps may only be usable from a subset of hardware
devices on a system.
Some heaps may not be accessible from the CPU. For those heaps, the VMO
representing a buffer cannot be used directly but is instead used as a key.
An application wishing to use the buffer must send its VMO handle to the heap
driver and the heap driver can return information about what memory to use.
Example heaps:
* Main system memory.
* VRAM on a discrete GPU.
* A carved-out area of system memory that's only usable by some pieces of
hardware.
### Constraints
[Constraints][constraints] specify the set of
[BufferSettings][SingleBufferSettings] that a participant is able to use.
Participants often specify multiple potential buffer settings in a single set
of constraints, which gives sysmem the flexibility to pick any of them and
reduces the risk that there are no settings that can satisfy the constraints
from all participants.
### Negotiation
Negotiation is the process where sysmem looks at all the constraints from
participants and chooses buffer settings that work for all of them. If
multiple settings could work, sysmem can use information about how clients
will use the buffer and the architecture of the system to choose the optimal
settings.
### Buffer collection
A [buffer collection][BufferCollection] is a set of multiple buffers with all
the same buffer settings. Sysmem allocates an entire buffer collection at
once. Multiple participants may have FIDL channels open to the same buffer
collection.
### Buffer collection token {#token}
A [token][BufferCollectionToken] is used in the initial stages of the
negotiation process before memory is allocated. Tokens can be duplicated and
passed between processes before finally being [bound][bind] to a buffer
collection.
[vmo]: /docs/reference/kernel_objects/vm_object.md
[sysmem]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2
[Heap]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#Heap
[ImageFormat]: https://fuchsia.dev/reference/fidl/fuchsia.images2#ImageFormat
[SingleBufferSettings]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#SingleBufferSettings
[duplicates]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollectionToken.Duplicate
[Allocator]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#Allocator
[BufferCollectionToken]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollectionToken
[BufferCollectionTokenGroup]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollectionTokenGroup
[BufferCollection]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollection
[channel]: /docs/reference/kernel_objects/channel.md
[pmt]: /docs/reference/kernel_objects/pinned_memory_token.md
[vmo_create_child]: /reference/syscalls/vmo_create_child.md
[handles]: /docs/concepts/kernel/handles.md
[bind]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#Allocator.BindSharedCollection
[SetConstraints]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollection.SetConstraints
[fidl]: /docs/development/languages/fidl/README.md
[map]: /reference/syscalls/vmar_map.md
[constraints]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollectionConstraints
[AttachToken]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollection.AttachToken
[SetDispensable]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollectionToken.SetDispensable
[AttachLifetimeTracking]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollection.AttachLifetimeTracking
[SetWeak]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollectionToken.SetWeak
[Release]: https://fuchsia.dev/reference/fidl/fuchsia.sysmem2#BufferCollection.Release