You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
7.5 KiB
174 lines
7.5 KiB
// 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);
|