| // Copyright 2020 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #pragma once |
| |
| #include <inttypes.h> |
| #include <stdbool.h> |
| |
| // GOLDFISH SYNC DEVICE |
| // The Goldfish sync driver is designed to provide a interface |
| // between the underlying host's sync device and the kernel's |
| // sw_sync. |
| // The purpose of the device/driver is to enable lightweight |
| // creation and signaling of timelines and fences |
| // in order to synchronize the guest with host-side graphics events. |
| |
| // Each time the interrupt trips, the driver |
| // may perform a sw_sync operation. |
| |
| // The operations are: |
| |
| // Ready signal - used to mark when irq should lower |
| #define CMD_SYNC_READY 0 |
| |
| // Create a new timeline. writes timeline handle |
| #define CMD_CREATE_SYNC_TIMELINE 1 |
| |
| // Create a fence object. reads timeline handle and time argument. |
| // Writes fence fd to the SYNC_REG_HANDLE register. |
| #define CMD_CREATE_SYNC_FENCE 2 |
| |
| // Increments timeline. reads timeline handle and time argument |
| #define CMD_SYNC_TIMELINE_INC 3 |
| |
| // Destroys a timeline. reads timeline handle |
| #define CMD_DESTROY_SYNC_TIMELINE 4 |
| |
| // Starts a wait on the host with |
| // the given glsync object and sync thread handle. |
| #define CMD_TRIGGER_HOST_WAIT 5 |
| |
| // The register layout is: |
| |
| #define SYNC_REG_BATCH_COMMAND 0x00 // host->guest batch commands |
| #define SYNC_REG_BATCH_GUESTCOMMAND 0x04 // guest->host batch commands |
| #define SYNC_REG_BATCH_COMMAND_ADDR 0x08 // communicate physical address of host->guest batch commands |
| #define SYNC_REG_BATCH_COMMAND_ADDR_HIGH 0x0c // 64-bit part |
| #define SYNC_REG_BATCH_GUESTCOMMAND_ADDR 0x10 // communicate physical address of guest->host commands |
| #define SYNC_REG_BATCH_GUESTCOMMAND_ADDR_HIGH 0x14 // 64-bit part |
| #define SYNC_REG_INIT 0x18 // to signal that the device has been detected by the kernel |
| |
| #define GUEST_TRIGGERED(cmd) (cmd == CMD_SYNC_READY || \ |
| cmd == CMD_TRIGGER_HOST_WAIT) |
| |
| typedef void (*trigger_wait_fn_t)(uint64_t, uint64_t, uint64_t); |
| |
| // The commands below operate on Android sync "timelines" and |
| // "fences". The basic concept is as follows. |
| // - Timeline and fences work together as a state to determine |
| // which events have completed. The timeline abstraction |
| // is used to represent a monotonic ordering of events, |
| // while fences represent levels of progress along |
| // timelines. By having different threads wait on fences |
| // until their associated timelines make the required progress, |
| // we can synchronize multiple threads within a process |
| // and with binder, across processes. |
| // - What follows is an abstract definition of that concept |
| // that does not match implementation exactly, but is |
| // sufficient for our purposes: |
| // - A timeline is a represnted by a single uint32_t, known as |
| // its "value". Over time, the value may increase. |
| // timeline : value |
| // - Let "timeline-id" be a uint64_t that uniquely identifies each |
| // timeline. |
| // A fence is an immutable map from timeline-id's to values: |
| // fence : map(timeline-id -> value). We will refer to the |
| // "timeline-id-values" of a fence to be the set of all pairs |
| // (timeline-id, value) that comprise the mapping. |
| // - Let "fence-id" be an int that uniquely identifies each fence. |
| // This is also known as a "fence fd". |
| // The important state is represented by a pair of maps: |
| // (T = map(timeline-id -> timeline), F = map(fence-id -> fence)). |
| // This state may change over time, with timelines and fences |
| // being added or removed. |
| // For any state, we care primarily about the "signaled" status |
| // of the fences within. |
| // - Each fence in the map from fence-id's to fences is |
| // signaled if: |
| // - For all timeline-id-values = (timeline-id, value) |
| // of that fence, T[timeline-id] >= value. |
| // Or, timeline-id does not exist in T's keys. |
| // - Otherwise, it is considered "unsignaled." |
| // The functions below operate with the above abstraction in mind. |
| // They all mutate a particular collection of fences and timelines. |
| // We can think of them as implicitly taking a state (T, F) |
| // as input and returning a new one (T', F') that is possibly updated, |
| // according to the changes described. The new collection then |
| // serves as the true abstract state for all further operations. |
| |
| // |goldfish_sync_create_timeline| creates a new timeline |
| // with value 0. The timeline id is returned. |
| uint64_t goldfish_sync_create_timeline(); |
| |
| // |goldfish_sync_create_fence| creates a fence |
| // that has a single timeline-id-value pair as its map. |
| // The first two arguments comprise the pair. |
| // Returns a unique identifier for the fence. |
| // Note that this implementation only allows the creation of |
| // fences associated with a single timeline-id-value pair. |
| int goldfish_sync_create_fence(uint64_t timeline, uint32_t pt); |
| |
| // |goldfish_sync_timeline_inc| advances the value component |
| // of a given timeline by |howmuch|; that is, if |
| // (t, v) is the timeline-id and value of a timeline before this call, |
| // (t, v + |howmuch|) is the value after. |
| // Thus, this may end up changing some fence objects to signaled state. |
| void goldfish_sync_timeline_inc(uint64_t timeline, uint32_t howmuch); |
| |
| // |goldfish_sync_destroy_timeline| removes the key |timeline| |
| // from the global timeline map. |
| // Any fence objects whose only timeline-id-value (t, v) is such that |
| // t == |timeline| would be considered signaled. |
| // If there are any other timeline-id-values, the fence may still be |
| // unsignaled. We would need the other timelines referenced by this fence |
| // to have reached the target value of this fence, fence[timeline]. |
| void goldfish_sync_destroy_timeline(uint64_t timeline); |
| |
| // Registering callbacks for goldfish sync ops |
| // Currently, only trigger_wait is supported. |
| void goldfish_sync_register_trigger_wait(trigger_wait_fn_t trigger_fn); |
| |
| // If the virtual device doesn't actually exist (e.g., when |
| // using QEMU1), query that using this function: |
| bool goldfish_sync_device_exists(); |
| |
| // Function types for sending commands to the virtual device. |
| typedef void (*queue_device_command_t) |
| (uint32_t cmd, uint64_t handle, uint32_t time_arg, |
| uint64_t hostcmd_handle); |
| |
| typedef struct GoldfishSyncDeviceInterface { |
| // Callback for all communications with virtual device |
| queue_device_command_t doHostCommand; |
| |
| // Callbacks to register other callbacks for triggering |
| // OpenGL waits from the guest |
| void (*registerTriggerWait)(trigger_wait_fn_t); |
| } GoldfishSyncDeviceInterface; |
| |
| // The virtual device will call |goldfish_sync_set_hw_funcs| |
| // to connect up to the AndroidEmu part. |
| extern void |
| goldfish_sync_set_hw_funcs(GoldfishSyncDeviceInterface* hw_funcs); |
| |
| // The virtual device calls this |goldfish_sync_receive_hostcmd_result| |
| // when it receives a reply for host->guest commands that support |
| // that protocol. |
| extern void |
| goldfish_sync_receive_hostcmd_result(uint32_t cmd, |
| uint64_t handle, |
| uint32_t time_arg, |
| uint64_t hostcmd_handle); |