blob: 0c885d3036fb0e2678f6a10885641ec2f1c7e253 [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.
@available(added=9)
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.
VENDOR_ID = 0;
/// Returns the hardware device ID (simple result)
DEVICE_ID = 1;
/// Returns the version of the vendor interfaces supported by the system driver.
@available(added=12)
VENDOR_VERSION = 2;
/// Returns true if MAGMA_QUERY_TOTAL_TIME is supported (simple result)
IS_TOTAL_TIME_SUPPORTED = 3;
/// Upper 32bits: max inflight messages, lower 32bits: max inflight memory (MB) (simple result)
MAXIMUM_INFLIGHT_PARAMS = 5;
/// Returns a struct magma_total_time_query_result (buffer result); see:
/// src/graphics/lib/magma/include/magma/magma_common_defs.h
MAGMA_QUERY_TOTAL_TIME = 500;
/// 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 {
SUPPORTS_VULKAN = 1;
SUPPORTS_OPENCL = 2;
// Exposes the fuchsia.mediacodec.CodecFactory FIDL interface.
SUPPORTS_MEDIA_CODEC_FACTORY = 4;
};
/// 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).
closed protocol Device {
/// On success, returns a result either in a buffer or a simple value.
strict 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.
strict 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.
closed protocol DiagnosticDevice {
/// Dumps driver and hardware state to the log.
strict DumpState(struct {
dump_type uint32;
});
};
/// Methods implemented by an MSD and exposed for use of an ICD loader.
closed protocol IcdLoaderDevice {
/// Returns a list of ICDs that can be used with this Magma device. The list is sorted in
/// descending order of preference.
strict 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.
closed 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.
closed protocol TestDevice {
compose CombinedDevice;
strict GetUnitTestStatus() -> (struct {
status zx.Status;
});
};
@available(added=13)
type Object = flexible resource union {
1: semaphore zx.Handle:EVENT;
2: buffer zx.Handle:VMO;
3: vmo_semaphore zx.Handle:VMO;
};
type ObjectType = flexible enum : uint32 {
@available(deprecated=17, removed=18, legacy=true)
EVENT = 10;
/// A memory object backeed by a Zircon VMO.
BUFFER = 11;
/// A sync object backed by a Zircon event or VMO.
@available(added=13)
SEMAPHORE = 12;
};
alias ObjectId = uint64;
@available(added=13)
type ImportFlags = flexible bits : uint64 {
SEMAPHORE_ONE_SHOT = 0x1;
};
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.
POPULATE_TABLES = 1;
/// Depopulate page table mappings for this range. This prevents the hardware from accessing
/// pages in that range, but the pages retain their contents.
DEPOPULATE_TABLES = 2;
};
/// The batch size used to send multiple immediate commands in a single message.
const MAX_IMMEDIATE_COMMANDS_DATA_SIZE uint32 = 2048;
/// The batch size used to send multiple inline commands in a single message.
@available(added=15)
const MAX_INLINE_COMMANDS_DATA_SIZE uint32 = 2048;
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.
GROWABLE = 0x8;
/// 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;
};
@available(added=15)
type InlineCommand = table {
1: data vector<uint8>:MAX;
2: semaphores vector<ObjectId>:MAX;
};
/// 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.
DISCONTINUITY = 1;
};
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.
closed protocol Primary {
@available(deprecated=17, removed=18, legacy=true)
strict ImportObject2(resource struct {
object zx.Handle;
object_type ObjectType;
object_id ObjectId;
});
/// Imports an object for use in the system driver.
@available(added=13)
strict ImportObject(resource table {
/// Required.
1: object Object;
/// Required.
2: object_type ObjectType;
/// Required.
3: object_id ObjectId;
/// Optional
4: flags ImportFlags;
});
/// Destroys the object with `object_id` within this connection.
strict 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.
strict CreateContext(struct {
context_id ContextId;
});
/// Destroys context `context_id`.
strict 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.
strict 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.
strict ExecuteImmediateCommands(struct {
context_id ContextId;
command_data vector<uint8>:MAX_IMMEDIATE_COMMANDS_DATA_SIZE;
semaphores vector<ObjectId>:MAX;
});
/// Submits a series of commands for execution on the hardware without using a command buffer.
/// The number of commands sent should be calculated so that the total message size is less than
/// MAX_INLINE_COMMANDS_DATA_SIZE.
@available(added=15)
strict ExecuteInlineCommands(struct {
context_id ContextId;
commands vector<InlineCommand>:MAX;
});
/// Incurs a round-trip to the system driver, used to ensure all previous messages have been
/// observed, but not necessarily completed.
strict 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.
strict 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.
strict UnmapBuffer(table {
/// Required.
1: hw_va uint64;
/// Required.
2: buffer_id ObjectId;
});
/// Perform an operation on a range of the buffer.
strict BufferRangeOp2(struct {
op BufferOp;
range BufferRange;
});
/// Enables the events OnNotifyMessagesConsumed and OnNotifyMemoryImported.
strict EnableFlowControl();
/// 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.
strict -> 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.
strict -> 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.
strict EnablePerformanceCounterAccess(resource struct {
access_token zx.Handle:EVENT;
});
/// Returns true if any EnablePerformanceCounterAccess message has succeeded.
strict 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.
strict 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.
strict 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.
strict 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.
strict 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.
strict 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.
strict 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.
strict ClearPerformanceCounters(struct {
counters PerformanceCounterSet;
});
};
/// This protocol is empty as the message contents are vendor specific.
closed protocol Notification {};
/// This protocol is implemented by ZX_PROTOCOL_GPU_PERFORMANCE_COUNTERS devices.
closed protocol PerformanceCounterAccess {
/// This access token is not used as an event, but is instead passed to
/// Primary.EnablePerformanceCounterAccess.
strict GetPerformanceCountToken() -> (resource struct {
access_token zx.Handle:EVENT;
});
};
closed protocol PerformanceCounterEvents {
/// Signals that a performance counter buffer has data. These will be output in the order of
/// when the reads are completed.
strict -> 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.
closed protocol DependencyInjection {
/// Provides a `fuchsia.memorypressure.Provider` implementation to the MSD.
strict SetMemoryPressureProvider(resource struct {
provider client_end:fuchsia.memorypressure.Provider;
});
};