summaryrefslogtreecommitdiff
path: root/host-common/goldfish_sync.h
blob: 4a35759067fbf4a7e996afbe5f2e1934089499ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// 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);