blob: f58d3566b7037dd2e327dc253f930a3bbbddf08c [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// Magma is the driver model for GPUs/NPUs on Fuchsia.
/// Magma has two driver components: a hardware-specific library loaded into each application’s
/// address space ("client driver", sometimes known as "Installable client driver" or "ICD");
/// and the Magma system driver that interfaces with the hardware.
/// The communication protocols between the two driver pieces are defined here.
/// Some names have a numeric suffix (eg, BufferRangeOp2); the number is a detail of how the
/// protocols have evolved, and can be ignored.
library fuchsia.gpu.magma;
using fuchsia.url;
using zx;
using fuchsia.memorypressure;
/// Types of information about the hardware and driver that can be queried from the Magma system
/// driver. Vendor-specific ID numbers may be used, but those IDs will be listed elsewhere.
type QueryId = flexible enum : uint64 {
/// Returns the hardware vendor ID (simple result) - should be the PCI ID of the hardware
/// vendor if possible, or the Khronos vendor ID otherwise.
/// Returns the hardware device ID (simple result)
/// Returns the version of the vendor interfaces supported by the system driver.
/// Returns true if MAGMA_QUERY_TOTAL_TIME is supported (simple result)
/// Upper 32bits: max inflight messages, lower 32bits: max inflight memory (MB) (simple result)
/// Returns a struct magma_total_time_query_result (buffer result); see:
/// src/graphics/lib/magma/include/magma/magma_common_defs.h
/// Vendor specific query IDs start here
VENDOR_QUERY_0 = 10000;
/// The maximum number of ICDs supported by a Magma system driver.
const MAX_ICD_COUNT uint64 = 8;
type IcdFlags = flexible bits : uint32 {
// Exposes the fuchsia.mediacodec.CodecFactory FIDL interface.
/// Information about an ICD implementation that can be used with a Magma device.
type IcdInfo = table {
/// URL of the component implementation that provides the ICD.
1: component_url fuchsia.url.Url;
/// Flags describing the basic capabilities of the ICD, including what APIs it supports.
2: flags IcdFlags;
/// The Magma Device protocol allow clients to learn about the hardware by making queries, such as
/// device and vendor IDs, and which client drivers are supported by the device's system driver.
/// To engage further with the device, clients may establish connections formed of channel pairs:
/// a primary channel for making requests (see Primary protocol below), and a secondary channel
/// for receiving notification messages (see Notification protocol below).
protocol Device {
/// On success, returns a result either in a buffer or a simple value.
Query(struct {
query_id QueryId;
}) -> (strict resource union {
1: simple_result uint64;
2: buffer_result zx.handle:VMO;
}) error zx.status;
/// Creates a connection to the device comprised of two IPC channels.
/// The primary channel is for the Primary protocol (see below). The notification channel is
/// used for vendor-specific messages which are sent only in the reverse (server-client)
/// direction, typically in response to client command completion.
Connect2(resource struct {
client_id uint64;
primary_channel server_end:Primary;
notification_channel server_end:Notification;
/// Methods used to expose diagnostics from the Magma device.
protocol DiagnosticDevice {
/// Dumps driver and hardware state to the log.
DumpState(struct {
dump_type uint32;
/// Methods implemented by an MSD and exposed for use of an ICD loader.
protocol IcdLoaderDevice {
/// Returns a list of ICDs that can be used with this Magma device. The list is sorted in
/// descending order of preference.
GetIcdList() -> (struct {
icd_list vector<IcdInfo>:MAX_ICD_COUNT;
/// A combination of all the production |Device| protocols. This protocol is implemented on the
/// Magma service side and should not be used by clients.
protocol CombinedDevice {
compose Device;
compose DiagnosticDevice;
compose IcdLoaderDevice;
/// Additional device methods for the purposes of testing the MSD and should not be used by ICDs.
protocol TestDevice {
compose CombinedDevice;
GetUnitTestStatus() -> (struct {
status zx.status;
type ObjectType = flexible enum : uint32 {
/// A sync object backed by a Zircon event.
EVENT = 10;
/// A memory object backeed by a Zircon VMO.
BUFFER = 11;
type BufferOp = flexible enum : uint32 {
/// Populate the hardware page tables with the pages mapped in this range, committing pages
/// as needed. This is not needed for allocations mapped GROWABLE, since the page tables will
/// be populated on demand.
/// Depopulate page table mappings for this range. This prevents the hardware from accessing
/// pages in that range, but the pages retain their contents.
/// The batch size used to send multiple immediate commands in a single message.
type MapFlags = flexible bits : uint64 {
READ = 0x1;
WRITE = 0x2;
EXECUTE = 0x4;
/// Uncommitted pages may be comitted on a hardware fault. If this flag is not set, access
/// faults should cause an error.
/// Vendor specific definitions start here
VENDOR_FLAG_0 = 0x10000;
type CommandBufferFlags = flexible bits : uint64 {
/// Vendor specific definitions start here
VENDOR_FLAG_0 = 0x10000;
/// A command buffer may be used to pass hardware instructions in a shared buffer (VMO).
type CommandBuffer = struct {
/// Index of the resource containing instructions to start the command buffer.
resource_index uint32;
/// Starting offset within the resource.
start_offset uint64;
/// Performance counter pools contain byte ranges of buffers. Whenever a performance counter dump is
/// triggered, the driver removes a range from the pool, writes the performance counter values from
/// the hardware into it, then signals the client using OnPerformanceCounterReadCompleted. Pool IDs
/// are arbitrary uint64 values that are allocated by the client.
alias PerformanceCounterPoolId = uint64;
type ResultFlags = flexible bits {
/// This bit is set in result_flags if the performance counters missed some samples, e.g. due to
/// the hardware being in protected mode for part of the time.
alias ObjectId = uint64;
type BufferRange = struct {
buffer_id ObjectId;
offset uint64;
size uint64;
alias ContextId = uint32;
alias PerformanceCounterTriggerId = uint32;
/// Describes a set of performance counters. The exact meaning depends on the specific driver, but
/// often is a bitvector representing whether each performance counter is enabled or disabled.
alias PerformanceCounterSet = vector<uint64>:64;
/// If a system driver error occurs, or if the client sends a message that the client should have
/// known is invalid, the connection will be closed and a zx.status sent via epitaph.
protocol Primary {
/// Imports an object for use in the system driver.
ImportObject2(resource struct {
object zx.handle;
object_type ObjectType;
object_id ObjectId;
/// Destroys the object with `object_id` within this connection.
ReleaseObject(struct {
object_id ObjectId;
object_type ObjectType;
/// Creates context `context_id` for use in command execution. A context may be associated
/// with hardware state.
CreateContext(struct {
context_id ContextId;
/// Destroys context `context_id`.
DestroyContext(struct {
context_id ContextId;
/// Submits command buffers for execution on the hardware, with associated `resources`.
/// `resources` must refer to buffers that have been imported.
/// `wait_semaphores` and `signal_semaphores` must refer to events that have been imported.
/// `wait_semaphores` must all be signaled before execution begins, then are reset.
/// `signal_semaphores` will be signaled after the command buffer is completed.
ExecuteCommand(struct {
context_id ContextId;
resources vector<BufferRange>:MAX;
command_buffers vector<CommandBuffer>:MAX;
wait_semaphores vector<ObjectId>:MAX;
signal_semaphores vector<ObjectId>:MAX;
flags CommandBufferFlags;
/// Submits a series of commands for execution on the hardware without using a command buffer.
/// `semaphores` must refer to events that have been imported, and will be signaled after
/// the commands are completed.
ExecuteImmediateCommands(struct {
context_id ContextId;
command_data vector<uint8>:MAX_IMMEDIATE_COMMANDS_DATA_SIZE;
semaphores vector<ObjectId>:MAX;
/// Incurs a round-trip to the system driver, used to ensure all previous messages have been
/// observed, but not necessarily completed.
Flush() -> ();
/// Maps a page range onto the hardware in the connection's address space at address `hw_va`.
/// `flags` is a set of flags from MapFlags that specify how the hardware can access the buffer.
MapBuffer(table {
/// Required.
1: hw_va uint64;
/// Required.
2: range BufferRange;
3: flags MapFlags;
/// Releases the mapping at address `hw_va` from the hardware for the given `buffer_id`.
/// Buffers will also be implicitly unmapped when released.
UnmapBuffer(table {
/// Required.
1: hw_va uint64;
/// Required.
2: buffer_id ObjectId;
/// Perform an operation on a range of the buffer.
BufferRangeOp2(struct {
op BufferOp;
range BufferRange;
/// Enables the events OnNotifyMessagesConsumed and OnNotifyMemoryImported.
/// Indicates the given number of messages were consumed by the server.
/// The caller should limit the number of inflight messages:
/// (messages sent - server consumed) <= MaxMessages (see QueryId::MAXIMUM_INFLIGHT_PARAMS).
/// Messages are actually consumed by the server as quickly as possible, however this event
/// is sent by the server only when the consumed count reaches half the maximum.
-> OnNotifyMessagesConsumed(struct {
count uint64;
/// Indicates the given number of buffer memory bytes were imported by the server.
/// The caller should limit the amount of memory from inflight ImportBuffer messages:
/// (bytes sent - server imported) <= MaxBytes (see QueryId::MAXIMUM_INFLIGHT_PARAMS).
/// This is a soft limit designed to prevent excessive memory consumption, but for large
/// messages the client may exceed the limit.
/// Memory is imported by the server as quickly as possible, however this event
/// is sent only when the consumed byte count reaches half the maximum; therefore,
/// if the client's count of inflight bytes is less than max/2, the client should send the
/// ImportBuffer message regardless of its size.
-> OnNotifyMemoryImported(struct {
bytes uint64;
/// Tries to enable performance counter FIDL messages. To be successful, |access_token| must
/// have been returned by PerformanceCounterAccess.GetPerformanceCountToken() from the matching
/// device.
EnablePerformanceCounterAccess(resource struct {
access_token zx.handle:EVENT;
/// Returns true if any EnablePerformanceCounterAccess message has succeeded.
IsPerformanceCounterAccessAllowed() -> (struct {
enabled bool;
/// Enables a set of performance counters. Disables enabled performance counters that are not
/// in the new set. Performance counters will also be automatically disabled on connection
/// close. Performance counter access must have been enabled using
/// EnablePerformanceCounterAccess before calling this method.
EnablePerformanceCounters(struct {
counters PerformanceCounterSet;
/// Creates a pool of buffers that performance counters can be dumped into. Performance counter
/// access must have been enabled using EnablePerformanceCounterAccess before calling this
/// method.
CreatePerformanceCounterBufferPool(resource struct {
pool_id PerformanceCounterPoolId;
event_channel server_end:PerformanceCounterEvents;
/// Releases a pool of performance counter buffers. Performance counter access must have been
/// enabled using EnablePerformanceCounterAccess before calling this method.
ReleasePerformanceCounterBufferPool(struct {
pool_id PerformanceCounterPoolId;
/// Adds a set of offsets into buffers to the pool. |offsets[n].buffer_id| is the id of a
/// buffer that was previously imported using ImportBuffer(). The same buffer may be added to
/// multiple pools. The pool will hold on to a reference to the buffer even after ReleaseBuffer
/// is called. When dumped into this entry, counters will be written starting at
/// |offsets[n].buffer_offset| bytes into the buffer, and up to |offsets[n].buffer_offset| +
/// |offsets[n].buffer_size|. |offsets[n].buffer_size| must be large enough to fit all enabled
/// counters. Performance counter access must have been enabled using
/// EnablePerformanceCounterAccess before calling this method.
AddPerformanceCounterBufferOffsetsToPool(struct {
pool_id PerformanceCounterPoolId;
offsets vector<BufferRange>:64;
/// Removes every offset of a buffer from the pool. Once this method is finished being handled
/// on the server, no more dumps will be processed into this buffer. In-flight dumps into this
/// buffer may be lost. Performance counter access must have been enabled using
/// EnablePerformanceCounterAccess before calling this method.
RemovePerformanceCounterBufferFromPool(struct {
pool_id PerformanceCounterPoolId;
buffer_id ObjectId;
/// Triggers dumping of the performance counters into a buffer pool. May fail silently if there
/// are no buffers in the pool. |trigger_id| is an arbitrary ID assigned by the client that can
/// be returned in OnPerformanceCounterReadCompleted. Performance counter access must have been
/// enabled using EnablePerformanceCounterAccess before calling this method.
DumpPerformanceCounters(struct {
pool_id PerformanceCounterPoolId;
trigger_id PerformanceCounterTriggerId;
/// Sets the values of all listed performance counters to 0. May not be supported by some
/// hardware. Performance counter access must have been enabled using
/// EnablePerformanceCounterAccess before calling this method.
ClearPerformanceCounters(struct {
counters PerformanceCounterSet;
/// This protocol is empty as the message contents are vendor specific.
protocol Notification {};
/// This protocol is implemented by ZX_PROTOCOL_GPU_PERFORMANCE_COUNTERS devices.
protocol PerformanceCounterAccess {
/// This access token is not used as an event, but is instead passed to
/// Primary.EnablePerformanceCounterAccess.
GetPerformanceCountToken() -> (resource struct {
access_token zx.handle:EVENT;
protocol PerformanceCounterEvents {
/// Signals that a performance counter buffer has data. These will be output in the order of
/// when the reads are completed.
-> OnPerformanceCounterReadCompleted(table {
/// Required.
1: trigger_id PerformanceCounterTriggerId;
/// Required.
2: buffer_id ObjectId;
/// Required.
3: buffer_offset uint32;
/// Required.
4: timestamp zx.time;
/// Required.
5: flags ResultFlags;
/// This protocol is implemented by ZX_PROTOCOL_GPU_DEPENDENCY_INJECTION devices. It's used
/// to inject dependencies on other services into the MSD. It can be used
/// only by a privileged process.
protocol DependencyInjection {
/// Provides a `fuchsia.memorypressure.Provider` implementation to the MSD.
SetMemoryPressureProvider(resource struct {
provider client_end:fuchsia.memorypressure.Provider;