mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-17 04:15:44 +00:00
d/survive: Use thread for processing events
Due to an oversight libsurvive events were only processed when inputs were updated. If only triggering event processing when an event is needed, we would need to process a random number of events, causing random overhead. Rather, follow the model of other drivers and process events in a thread. This required creating a local copy of the xrt_input arrays. Fixes #113 Fixes !679 v2: Use a mutex for get_tracked_pose and update_inputs
This commit is contained in:
parent
1e24602ca0
commit
484d63a4eb
|
@ -25,6 +25,8 @@
|
|||
#include "util/u_device.h"
|
||||
#include "util/u_distortion_mesh.h"
|
||||
|
||||
#include "os/os_threading.h"
|
||||
|
||||
#include "../auxiliary/os/os_time.h"
|
||||
|
||||
#include "xrt/xrt_prober.h"
|
||||
|
@ -120,6 +122,11 @@ struct survive_device
|
|||
struct xrt_space_relation last_relation;
|
||||
timepoint_ns last_relation_ts;
|
||||
|
||||
//! Number of inputs.
|
||||
size_t num_last_inputs;
|
||||
//! Array of input structs.
|
||||
struct xrt_input *last_inputs;
|
||||
|
||||
enum DeviceType device_type;
|
||||
|
||||
union {
|
||||
|
@ -152,11 +159,18 @@ struct survive_system
|
|||
struct survive_device *hmd;
|
||||
struct survive_device *controllers[MAX_TRACKED_DEVICE_COUNT];
|
||||
enum u_logging_level ll;
|
||||
|
||||
struct os_thread_helper event_thread;
|
||||
struct os_mutex lock;
|
||||
};
|
||||
|
||||
static void
|
||||
survive_device_destroy(struct xrt_device *xdev)
|
||||
{
|
||||
if (!xdev) {
|
||||
return;
|
||||
}
|
||||
|
||||
U_LOG_D("destroying survive device");
|
||||
struct survive_device *survive = (struct survive_device *)xdev;
|
||||
|
||||
|
@ -178,11 +192,19 @@ survive_device_destroy(struct xrt_device *xdev)
|
|||
|
||||
if (survive->sys->hmd == NULL && all_null) {
|
||||
U_LOG_D("Tearing down libsurvive context");
|
||||
survive_simple_close(survive->sys->ctx);
|
||||
os_thread_helper_stop(&survive->sys->event_thread);
|
||||
os_thread_helper_destroy(&survive->sys->event_thread);
|
||||
|
||||
// Now that the thread is not running we can destroy the lock.
|
||||
os_mutex_destroy(&survive->sys->lock);
|
||||
|
||||
U_LOG_D("Stopped libsurvive event thread");
|
||||
|
||||
survive_simple_close(survive->sys->ctx);
|
||||
free(survive->sys);
|
||||
}
|
||||
|
||||
free(survive->last_inputs);
|
||||
free(survive);
|
||||
}
|
||||
|
||||
|
@ -312,7 +334,9 @@ survive_device_get_tracked_pose(struct xrt_device *xdev,
|
|||
return;
|
||||
}
|
||||
|
||||
os_mutex_lock(&survive->sys->lock);
|
||||
_predict_pose(survive, at_timestamp_ns, out_relation);
|
||||
os_mutex_unlock(&survive->sys->lock);
|
||||
|
||||
struct xrt_pose *p = &out_relation->pose;
|
||||
SURVIVE_TRACE(survive, "GET_POSITION (%f %f %f) GET_ORIENTATION (%f, %f, %f, %f)", p->position.x, p->position.y,
|
||||
|
@ -388,10 +412,10 @@ survive_controller_get_hand_tracking(struct xrt_device *xdev,
|
|||
|
||||
float thumb_curl = 0.0f;
|
||||
//! @todo place thumb preciely on the button that is touched/pressed
|
||||
if (survive->base.inputs[VIVE_CONTROLLER_A_TOUCH].value.boolean ||
|
||||
survive->base.inputs[VIVE_CONTROLLER_B_TOUCH].value.boolean ||
|
||||
survive->base.inputs[VIVE_CONTROLLER_THUMBSTICK_TOUCH].value.boolean ||
|
||||
survive->base.inputs[VIVE_CONTROLLER_TRACKPAD_TOUCH].value.boolean) {
|
||||
if (survive->last_inputs[VIVE_CONTROLLER_A_TOUCH].value.boolean ||
|
||||
survive->last_inputs[VIVE_CONTROLLER_B_TOUCH].value.boolean ||
|
||||
survive->last_inputs[VIVE_CONTROLLER_THUMBSTICK_TOUCH].value.boolean ||
|
||||
survive->last_inputs[VIVE_CONTROLLER_TRACKPAD_TOUCH].value.boolean) {
|
||||
thumb_curl = 1.0;
|
||||
}
|
||||
|
||||
|
@ -502,7 +526,7 @@ update_axis(struct survive_device *survive, struct Axis *axis, const SurviveSimp
|
|||
return false;
|
||||
}
|
||||
|
||||
struct xrt_input *in = &survive->base.inputs[axis->input];
|
||||
struct xrt_input *in = &survive->last_inputs[axis->input];
|
||||
|
||||
float fval = e->axis_val[i];
|
||||
|
||||
|
@ -560,22 +584,22 @@ update_button(struct survive_device *survive, const struct SurviveSimpleButtonEv
|
|||
|
||||
if (e_type == SURVIVE_INPUT_EVENT_BUTTON_UP) {
|
||||
enum input_index index = buttons[btn_id].click;
|
||||
struct xrt_input *input = &survive->base.inputs[index];
|
||||
struct xrt_input *input = &survive->last_inputs[index];
|
||||
input->value.boolean = false;
|
||||
input->timestamp = ts;
|
||||
} else if (e_type == SURVIVE_INPUT_EVENT_BUTTON_DOWN) {
|
||||
enum input_index index = buttons[btn_id].click;
|
||||
struct xrt_input *input = &survive->base.inputs[index];
|
||||
struct xrt_input *input = &survive->last_inputs[index];
|
||||
input->value.boolean = true;
|
||||
input->timestamp = ts;
|
||||
} else if (e_type == SURVIVE_INPUT_EVENT_TOUCH_UP) {
|
||||
enum input_index index = buttons[btn_id].touch;
|
||||
struct xrt_input *input = &survive->base.inputs[index];
|
||||
struct xrt_input *input = &survive->last_inputs[index];
|
||||
input->value.boolean = false;
|
||||
input->timestamp = ts;
|
||||
} else if (e_type == SURVIVE_INPUT_EVENT_TOUCH_DOWN) {
|
||||
enum input_index index = buttons[btn_id].touch;
|
||||
struct xrt_input *input = &survive->base.inputs[index];
|
||||
struct xrt_input *input = &survive->last_inputs[index];
|
||||
input->value.boolean = true;
|
||||
input->timestamp = ts;
|
||||
}
|
||||
|
@ -624,7 +648,7 @@ _process_button_event(struct survive_device *survive, const struct SurviveSimple
|
|||
SURVIVE_DEBUG(survive, "axis id: %d val %f", e->axis_ids[i], e->axis_val[i]);
|
||||
}
|
||||
}
|
||||
struct xrt_input *squeeze_value_in = &survive->base.inputs[VIVE_CONTROLLER_SQUEEZE_VALUE];
|
||||
struct xrt_input *squeeze_value_in = &survive->last_inputs[VIVE_CONTROLLER_SQUEEZE_VALUE];
|
||||
float prev_squeeze_value = squeeze_value_in->value.vec1.x;
|
||||
float squeeze_value = _calculate_squeeze_value(survive);
|
||||
if (prev_squeeze_value != squeeze_value) {
|
||||
|
@ -685,7 +709,7 @@ _process_hmd_button_event(struct survive_device *survive, const struct SurviveSi
|
|||
static struct survive_device *
|
||||
get_device_by_object(struct survive_system *sys, const SurviveSimpleObject *object)
|
||||
{
|
||||
if (sys->hmd->survive_obj == object) {
|
||||
if (sys->hmd != NULL && sys->hmd->survive_obj == object) {
|
||||
return sys->hmd;
|
||||
}
|
||||
|
||||
|
@ -713,26 +737,20 @@ _process_pose_event(struct survive_device *survive, const struct SurviveSimplePo
|
|||
}
|
||||
|
||||
static void
|
||||
_process_event(struct survive_system *ss, struct survive_device *survive, struct SurviveSimpleEvent *event)
|
||||
_process_event(struct survive_system *ss, struct SurviveSimpleEvent *event)
|
||||
{
|
||||
switch (event->event_type) {
|
||||
case SurviveSimpleEventType_ButtonEvent: {
|
||||
const struct SurviveSimpleButtonEvent *e = survive_simple_get_button_event(event);
|
||||
|
||||
struct survive_device *event_device = NULL;
|
||||
if (e->object == survive->survive_obj) {
|
||||
event_device = survive;
|
||||
} else {
|
||||
event_device = get_device_by_object(survive->sys, e->object);
|
||||
}
|
||||
|
||||
struct survive_device *event_device = get_device_by_object(ss, e->object);
|
||||
if (event_device == NULL) {
|
||||
SURVIVE_ERROR(survive, "Event for unknown object not handled");
|
||||
U_LOG_IFL_E(ss->ll, "Event for unknown object not handled");
|
||||
return;
|
||||
}
|
||||
|
||||
// hmd & controller axes have overlapping enum indices
|
||||
if (event_device == survive->sys->hmd) {
|
||||
if (event_device == ss->hmd) {
|
||||
_process_hmd_button_event(event_device, e);
|
||||
} else {
|
||||
_process_button_event(event_device, e);
|
||||
|
@ -748,15 +766,9 @@ _process_event(struct survive_system *ss, struct survive_device *survive, struct
|
|||
case SurviveSimpleEventType_PoseUpdateEvent: {
|
||||
const struct SurviveSimplePoseUpdatedEvent *e = survive_simple_get_pose_updated_event(event);
|
||||
|
||||
struct survive_device *event_device = NULL;
|
||||
if (e->object == survive->survive_obj) {
|
||||
event_device = survive;
|
||||
} else {
|
||||
event_device = get_device_by_object(survive->sys, e->object);
|
||||
}
|
||||
|
||||
struct survive_device *event_device = get_device_by_object(ss, e->object);
|
||||
if (event_device == NULL) {
|
||||
SURVIVE_ERROR(survive, "Pose Event for unknown object not handled");
|
||||
U_LOG_IFL_E(ss->ll, "Event for unknown object not handled");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -764,27 +776,26 @@ _process_event(struct survive_system *ss, struct survive_device *survive, struct
|
|||
break;
|
||||
}
|
||||
case SurviveSimpleEventType_DeviceAdded: {
|
||||
SURVIVE_WARN(survive, "Device added event, but hotplugging not implemented yet");
|
||||
U_LOG_IFL_W(ss->ll, "Device added event, but hotplugging not implemented yet");
|
||||
break;
|
||||
}
|
||||
case SurviveSimpleEventType_None: break;
|
||||
default: SURVIVE_ERROR(survive, "Unknown event %d", event->event_type);
|
||||
default: U_LOG_IFL_E(ss->ll, "Unknown event %d", event->event_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
survive_device_update_inputs(struct xrt_device *xdev)
|
||||
{
|
||||
struct survive_device *survive = (struct survive_device *)xdev;
|
||||
|
||||
/* one event queue for all devices. _process_events() updates all
|
||||
devices, not just this survive device. */
|
||||
os_mutex_lock(&survive->sys->lock);
|
||||
|
||||
struct SurviveSimpleEvent event = {0};
|
||||
while (survive_simple_next_event(survive->sys->ctx, &event) != SurviveSimpleEventType_None) {
|
||||
_process_event(NULL, survive, &event);
|
||||
for (size_t i = 0; i < survive->base.num_inputs; i++) {
|
||||
survive->base.inputs[i] = survive->last_inputs[i];
|
||||
}
|
||||
|
||||
os_mutex_unlock(&survive->sys->lock);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -899,6 +910,12 @@ _create_hmd_device(struct survive_system *sys, const struct SurviveSimpleObject
|
|||
|
||||
survive->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
|
||||
|
||||
survive->last_inputs = U_TYPED_ARRAY_CALLOC(struct xrt_input, survive->base.num_inputs);
|
||||
survive->num_last_inputs = survive->base.num_inputs;
|
||||
for (size_t i = 0; i < survive->base.num_inputs; i++) {
|
||||
survive->last_inputs[i] = survive->base.inputs[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1115,6 +1132,12 @@ _create_controller_device(struct survive_system *sys,
|
|||
survive->base.orientation_tracking_supported = true;
|
||||
survive->base.position_tracking_supported = true;
|
||||
|
||||
survive->last_inputs = U_TYPED_ARRAY_CALLOC(struct xrt_input, survive->base.num_inputs);
|
||||
survive->num_last_inputs = survive->base.num_inputs;
|
||||
for (size_t i = 0; i < survive->base.num_inputs; i++) {
|
||||
survive->last_inputs[i] = survive->base.inputs[i];
|
||||
}
|
||||
|
||||
SURVIVE_DEBUG(survive, "Created Controller %d", idx);
|
||||
|
||||
return true;
|
||||
|
@ -1171,12 +1194,12 @@ add_connected_devices(struct survive_system *ss)
|
|||
struct SurviveSimpleEvent event = {0};
|
||||
while (survive_simple_next_event(ss->ctx, &event) != SurviveSimpleEventType_None) {
|
||||
if (event.event_type == SurviveSimpleEventType_ConfigEvent) {
|
||||
_process_event(ss, NULL, &event);
|
||||
_process_event(ss, &event);
|
||||
|
||||
// libsurvive processes sequentially, restart timeout
|
||||
start = os_monotonic_get_ns();
|
||||
} else {
|
||||
U_LOG_IFL_D(ss->ll, "Skipping event\n");
|
||||
U_LOG_IFL_T(ss->ll, "Skipping event\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1188,6 +1211,32 @@ add_connected_devices(struct survive_system *ss)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void *
|
||||
run_event_thread(void *ptr)
|
||||
{
|
||||
struct survive_system *ss = (struct survive_system *)ptr;
|
||||
|
||||
os_thread_helper_lock(&ss->event_thread);
|
||||
while (os_thread_helper_is_running_locked(&ss->event_thread)) {
|
||||
os_thread_helper_unlock(&ss->event_thread);
|
||||
|
||||
// one event queue for all devices. _process_events() updates all devices
|
||||
struct SurviveSimpleEvent event = {0};
|
||||
survive_simple_wait_for_event(ss->ctx, &event);
|
||||
|
||||
os_mutex_lock(&ss->lock);
|
||||
_process_event(ss, &event);
|
||||
os_mutex_unlock(&ss->lock);
|
||||
|
||||
// Just keep swimming.
|
||||
os_thread_helper_lock(&ss->event_thread);
|
||||
}
|
||||
|
||||
os_thread_helper_unlock(&ss->event_thread);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
survive_device_autoprobe(struct xrt_auto_prober *xap,
|
||||
cJSON *attached_data,
|
||||
|
@ -1267,5 +1316,27 @@ survive_device_autoprobe(struct xrt_auto_prober *xap,
|
|||
}
|
||||
|
||||
survive_already_initialized = true;
|
||||
|
||||
// Mutex before thread.
|
||||
int ret = os_mutex_init(&ss->lock);
|
||||
if (ret != 0) {
|
||||
U_LOG_IFL_E(ss->ll, "Failed to init mutex!");
|
||||
survive_device_destroy((struct xrt_device *)ss->hmd);
|
||||
for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) {
|
||||
survive_device_destroy((struct xrt_device *)ss->controllers[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = os_thread_helper_start(&ss->event_thread, run_event_thread, ss);
|
||||
if (ret != 0) {
|
||||
U_LOG_IFL_E(ss->ll, "Failed to start event thread!");
|
||||
survive_device_destroy((struct xrt_device *)ss->hmd);
|
||||
for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) {
|
||||
survive_device_destroy((struct xrt_device *)ss->controllers[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return out_idx;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue