|  | // 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. | 
|  |  | 
|  | library fuchsia.gpu.magma; | 
|  |  | 
|  | using fuchsia.url; | 
|  | using zx; | 
|  | using fuchsia.memorypressure; | 
|  |  | 
|  | /// Magma is the GPU driver design for 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, Query2); the number is a detail of how the protocols | 
|  | /// have evolved, and can be ignored. | 
|  | /// | 
|  | type QueryId = strict enum { | 
|  | VENDOR_ID = 0; | 
|  | DEVICE_ID = 1; | 
|  | IS_TEST_RESTART_SUPPORTED = 2; | 
|  | IS_TOTAL_TIME_SUPPORTED = 3; | 
|  |  | 
|  | /// Upper 32bits: max inflight messages, lower 32bits: max inflight memory (MB) | 
|  | MAXIMUM_INFLIGHT_PARAMS = 5; | 
|  |  | 
|  | /// Vendor specific query IDs start here | 
|  | VENDOR_QUERY_0 = 10000; | 
|  | }; | 
|  |  | 
|  | type Status = strict enum { | 
|  | INTERNAL_ERROR = 1; | 
|  | INVALID_ARGS = 2; | 
|  | ACCESS_DENIED = 3; | 
|  | MEMORY_ERROR = 4; | 
|  | CONTEXT_KILLED = 5; | 
|  | CONNECTION_LOST = 6; | 
|  | TIMED_OUT = 7; | 
|  | UNIMPLEMENTED = 8; | 
|  | BAD_STATE = 9; | 
|  | }; | 
|  |  | 
|  | /// 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; | 
|  | }; | 
|  |  | 
|  | /// 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. | 
|  | protocol Device { | 
|  | /// On success, returns a value given a QueryId; otherwise returns an error. | 
|  | Query2(struct { | 
|  | query_id uint64; | 
|  | }) -> (struct { | 
|  | result uint64; | 
|  | }) error Status; | 
|  |  | 
|  | /// On success, returns a buffer given a QueryId; otherwise returns an error. | 
|  | QueryReturnsBuffer(struct { | 
|  | query_id uint64; | 
|  | }) -> (resource struct { | 
|  | buffer zx.handle:VMO; | 
|  | }) error 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. | 
|  | Connect(struct { | 
|  | client_id uint64; | 
|  | }) -> (resource struct { | 
|  | primary_channel client_end:Primary; | 
|  | notification_channel zx.handle:CHANNEL; | 
|  | }); | 
|  |  | 
|  | /// Dumps driver and hardware state. | 
|  | DumpState(struct { | 
|  | dump_type uint32; | 
|  | }); | 
|  |  | 
|  | /// 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; | 
|  | }); | 
|  |  | 
|  | /// For testing only. | 
|  | TestRestart(); | 
|  |  | 
|  | /// For testing only - on non-test drivers this will close the channel. | 
|  | GetUnitTestStatus() -> (struct { | 
|  | status zx.status; | 
|  | }); | 
|  | }; | 
|  |  | 
|  | type ObjectType = strict enum { | 
|  | SEMAPHORE = 10; | 
|  | BUFFER = 11; | 
|  | }; | 
|  |  | 
|  | type BufferOp = strict enum { | 
|  | /// Populate the GPU page tables with the pages mapping 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 GPU page table mappings for this range. This prevents the GPU 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; | 
|  |  | 
|  | type MapFlags = flexible bits : uint64 { | 
|  | READ = 0x1; | 
|  | WRITE = 0x2; | 
|  | EXECUTE = 0x4; | 
|  | 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 GPU instructions in a shared buffer (VMO). | 
|  | type CommandBuffer2 = struct { | 
|  | /// Index of the resource containing instructions to start the command buffer. | 
|  | resource_index uint32; | 
|  |  | 
|  | /// Starting offset within the resource. | 
|  | start_offset uint64; | 
|  |  | 
|  | /// Flags. | 
|  | flags CommandBufferFlags; | 
|  | }; | 
|  |  | 
|  | /// 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 PerfCountPoolId = uint64; | 
|  |  | 
|  | type ResultFlags = strict bits { | 
|  | /// This bit is set in result_flags if the performance counters missed some samples, e.g. due to | 
|  | /// the GPU being in protected mode for part of the time. | 
|  | DISCONTINUITY = 1; | 
|  | }; | 
|  |  | 
|  | type BufferRange = struct { | 
|  | buffer_id zx.koid; | 
|  | offset uint64; | 
|  | size uint64; | 
|  | }; | 
|  |  | 
|  | /// If a system driver error occurs, the connection will be closed and a Status sent via epitaph. | 
|  | /// If negative, the Epitaph represents a Zircon error. | 
|  | protocol Primary { | 
|  | /// Imports an object for use in the system driver. | 
|  | ImportObject(resource struct { | 
|  | object zx.handle; | 
|  | object_type ObjectType; | 
|  | }); | 
|  |  | 
|  | /// Destroys the object with `object_id` within this connection. | 
|  | ReleaseObject(struct { | 
|  | object_id zx.koid; | 
|  | object_type ObjectType; | 
|  | }); | 
|  |  | 
|  | /// Creates context `context_id` for use in command execution.  A context may be associated | 
|  | /// with hardware state. | 
|  | CreateContext(struct { | 
|  | context_id uint32; | 
|  | }); | 
|  |  | 
|  | /// Destroys context `context_id`. | 
|  | DestroyContext(struct { | 
|  | context_id uint32; | 
|  | }); | 
|  |  | 
|  | /// Submits a command buffer for execution on the GPU, with associated `resources`. | 
|  | /// `wait_semaphores` must all be signaled before execution begins, and `signal_semaphores` | 
|  | /// will be signaled after the command buffer is completed. | 
|  | ExecuteCommandBufferWithResources2(struct { | 
|  | context_id uint32; | 
|  | command_buffer CommandBuffer2; | 
|  | resources vector<BufferRange>:MAX; | 
|  | wait_semaphores vector<zx.koid>:MAX; | 
|  | signal_semaphores vector<zx.koid>:MAX; | 
|  | }); | 
|  |  | 
|  | /// Submits a series of commands for execution on the GPU without using a command buffer. | 
|  | /// `semaphores` will be signaled after the commands are completed. | 
|  | ExecuteImmediateCommands(struct { | 
|  | context_id uint32; | 
|  | command_data bytes:MAX_IMMEDIATE_COMMANDS_DATA_SIZE; | 
|  | semaphores vector<zx.koid>:MAX; | 
|  | }); | 
|  |  | 
|  | /// Incurs a round-trip to the system driver, used to ensure all previous messages have been | 
|  | /// observed, but not necessarily completed. | 
|  | Flush() -> (); | 
|  |  | 
|  | /// Maps `page_count` pages of `buffer` from `page_offset` onto the GPU in the connection's | 
|  | /// address space at `gpu_va`.  `flags` is a set of flags from MapFlags that specify how the | 
|  | /// GPU can access the buffer. | 
|  | MapBufferGpu(struct { | 
|  | buffer_id zx.koid; | 
|  | gpu_va uint64; | 
|  | page_offset uint64; | 
|  | page_count uint64; | 
|  | flags MapFlags; | 
|  | }); | 
|  |  | 
|  | /// Releases the mapping at `gpu_va` from the GPU for the given `buffer_id`. | 
|  | /// Buffers will also be implicitly unmapped when released. | 
|  | UnmapBufferGpu(struct { | 
|  | buffer_id zx.koid; | 
|  | gpu_va uint64; | 
|  | }); | 
|  |  | 
|  | /// Perform an operation on a range of the buffer, starting at `offset` and `length` bytes | 
|  | /// long. | 
|  | BufferRangeOp(struct { | 
|  | buffer_id zx.koid; | 
|  | op BufferOp; | 
|  | offset uint64; | 
|  | length uint64; | 
|  | }); | 
|  |  | 
|  | /// Tries to enable performance counter FIDL messages. To be successful, |access_token| must | 
|  | /// have been returned by PerformanceCounterAccess.GetPerformanceCountToken() from the matching | 
|  | /// device. | 
|  | AccessPerformanceCounters(resource struct { | 
|  | access_token zx.handle:EVENT; | 
|  | }); | 
|  |  | 
|  | /// Returns true if any AccessPerformanceCounters message has succeeded. | 
|  | IsPerformanceCounterAccessEnabled() -> (struct { | 
|  | enabled bool; | 
|  | }); | 
|  |  | 
|  | /// Enables the events OnNotifyMessagesConsumed and OnNotifyMemoryImported. | 
|  | 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. | 
|  | -> 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; | 
|  | }); | 
|  |  | 
|  | /// Enables a set of performance counters (the precise definition depends on the GPU driver). | 
|  | /// 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 AccessPerformanceCounters before calling this method. | 
|  | EnablePerformanceCounters(struct { | 
|  | counters vector<uint64>:64; | 
|  | }); | 
|  |  | 
|  | /// Creates a pool of buffers that performance counters can be dumped into. |pool| can be an | 
|  | /// arbitrary integer that's currently not in use. Performance counter access must have been | 
|  | /// enabled using AccessPerformanceCounters before calling this method. | 
|  | CreatePerformanceCounterBufferPool(resource struct { | 
|  | pool PerfCountPoolId; | 
|  | event_channel server_end:PerformanceCounterEvents; | 
|  | }); | 
|  |  | 
|  | /// Releases a pool of performance counter buffers. Performance counter access must have been | 
|  | /// enabled using AccessPerformanceCounters before calling this method. | 
|  | ReleasePerformanceCounterBufferPool(struct { | 
|  | pool PerfCountPoolId; | 
|  | }); | 
|  |  | 
|  | /// Adds set of a offsets into buffers to the pool. |offsets[n].buffer_id| is the koid 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 | 
|  | /// |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 AccessPerformanceCounters | 
|  | /// before calling this method. | 
|  | AddPerformanceCounterBufferOffsetsToPool(struct { | 
|  | pool PerfCountPoolId; | 
|  | offsets vector<BufferRange>:64; | 
|  | }); | 
|  |  | 
|  | /// Removes every offset of a buffer from the pool. Once this is 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 | 
|  | /// AccessPerformanceCounters before calling this method. | 
|  | RemovePerformanceCounterBufferFromPool(struct { | 
|  | pool PerfCountPoolId; | 
|  | buffer_id zx.koid; | 
|  | }); | 
|  |  | 
|  | /// 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 AccessPerformanceCounters before calling this method. | 
|  | DumpPerformanceCounters(struct { | 
|  | pool PerfCountPoolId; | 
|  | trigger_id uint32; | 
|  | }); | 
|  |  | 
|  | /// 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 AccessPerformanceCounters | 
|  | /// before calling this method. | 
|  | ClearPerformanceCounters(struct { | 
|  | counters vector<uint64>:64; | 
|  | }); | 
|  | }; | 
|  |  | 
|  | /// 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(struct { | 
|  | trigger_id uint32; | 
|  | buffer_id zx.koid; | 
|  | buffer_offset uint32; | 
|  | timestamp zx.time; | 
|  | 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; | 
|  | }); | 
|  | }; |