st/oxr: Basic foundation for input and output

This commits lays the foundation for actions in Monado (input and output).
There are lots of things missing and non-conformant in there. But once in
more people then just me can test it out and work on it.
This commit is contained in:
Jakob Bornecrantz 2019-05-07 13:47:18 +01:00
parent b71e143eaa
commit e745a28374
13 changed files with 1746 additions and 105 deletions

View file

@ -39,6 +39,7 @@ set(OXR_SOURCE_FILES
oxr_two_call.h
oxr_verify.cpp
oxr_vulkan.c
oxr_xdev.c
)
# Use OBJECT to not create a archive, since it just gets in the way.

View file

@ -41,12 +41,14 @@ oxr_xrSyncActionData(XrSession session,
}
for (uint32_t i = 0; i < countActionSets; i++) {
struct oxr_action_set* act_set;
struct oxr_action_set* act_set = NULL;
OXR_VERIFY_ARG_TYPE_AND_NULL(&log, (&actionSets[i]),
XR_TYPE_ACTIVE_ACTION_SET);
OXR_VERIFY_ACTIONSET_NOT_NULL(&log, actionSets[i].actionSet,
act_set);
//! @todo verify path.
oxr_verify_subaction_path_sync(&log, sess->sys->inst,
actionSets[i].subactionPath, i);
}
return oxr_action_sync_data(&log, sess, countActionSets, actionSets);
@ -187,6 +189,15 @@ oxr_xrCreateAction(XrActionSet actionSet,
OXR_VERIFY_ARG_LOCALIZED_NAME(&log, createInfo->localizedActionName);
OXR_VERIFY_ARG_NOT_NULL(&log, action);
struct oxr_instance* inst = act_set->sess->sys->inst;
ret = oxr_verify_subaction_paths_create(
&log, inst, createInfo->countSubactionPaths,
createInfo->subactionPaths, "createInfo->subactionPaths");
if (ret != XR_SUCCESS) {
return ret;
}
ret = oxr_action_create(&log, act_set, createInfo, &act);
if (ret != XR_SUCCESS) {
return ret;
@ -213,16 +224,39 @@ oxr_xrGetActionStateBoolean(XrAction action,
const XrPath* subactionPaths,
XrActionStateBoolean* data)
{
XrPath subactionPath = XR_NULL_PATH;
struct oxr_sub_paths sub_paths = {0};
struct oxr_action* act;
struct oxr_logger log;
XrResult ret;
OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
"xrGetActionStateBoolean");
OXR_VERIFY_ARG_TYPE_AND_NULL(&log, data, XR_TYPE_ACTION_STATE_BOOLEAN);
OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
//! @todo verify paths
return oxr_action_get_boolean(&log, act, countSubactionPaths,
subactionPaths, data);
if (act->action_type != XR_INPUT_ACTION_TYPE_BOOLEAN) {
return oxr_error(&log, XR_ERROR_ACTION_TYPE_MISMATCH,
" not created with pose type");
}
// Trust me.
if (countSubactionPaths > 1) {
return oxr_error(&log, XR_ERROR_PATH_INVALID,
" can not handle more then one subactionPath");
}
if (countSubactionPaths == 1) {
subactionPath = subactionPaths[0];
}
ret = oxr_verify_subaction_path_get(&log, act->act_set->sess->sys->inst,
subactionPath, &act->sub_paths,
&sub_paths, "subactionPaths[0]");
if (ret != XR_SUCCESS) {
return ret;
}
return oxr_action_get_boolean(&log, act, sub_paths, data);
}
XrResult
@ -231,16 +265,39 @@ oxr_xrGetActionStateVector1f(XrAction action,
const XrPath* subactionPaths,
XrActionStateVector1f* data)
{
XrPath subactionPath = XR_NULL_PATH;
struct oxr_sub_paths sub_paths = {0};
struct oxr_action* act;
struct oxr_logger log;
XrResult ret;
OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
"xrGetActionStateVector1f");
OXR_VERIFY_ARG_TYPE_AND_NULL(&log, data, XR_TYPE_ACTION_STATE_VECTOR1F);
OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
//! @todo verify paths
return oxr_action_get_vector1f(&log, act, countSubactionPaths,
subactionPaths, data);
if (act->action_type != XR_INPUT_ACTION_TYPE_VECTOR1F) {
return oxr_error(&log, XR_ERROR_ACTION_TYPE_MISMATCH,
" not created with float type");
}
// Trust me.
if (countSubactionPaths > 1) {
return oxr_error(&log, XR_ERROR_PATH_INVALID,
" can not handle more then one subactionPath");
}
if (countSubactionPaths == 1) {
subactionPath = subactionPaths[0];
}
ret = oxr_verify_subaction_path_get(&log, act->act_set->sess->sys->inst,
subactionPath, &act->sub_paths,
&sub_paths, "subactionPaths[0]");
if (ret != XR_SUCCESS) {
return ret;
}
return oxr_action_get_vector1f(&log, act, sub_paths, data);
}
XrResult
@ -249,16 +306,39 @@ oxr_xrGetActionStateVector2f(XrAction action,
const XrPath* subactionPaths,
XrActionStateVector2f* data)
{
XrPath subactionPath = XR_NULL_PATH;
struct oxr_sub_paths sub_paths = {0};
struct oxr_action* act;
struct oxr_logger log;
XrResult ret;
OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
"xrGetActionStateVector2f");
OXR_VERIFY_ARG_TYPE_AND_NULL(&log, data, XR_TYPE_ACTION_STATE_VECTOR2F);
OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
//! @todo verify paths
return oxr_action_get_vector2f(&log, act, countSubactionPaths,
subactionPaths, data);
if (act->action_type != XR_INPUT_ACTION_TYPE_VECTOR2F) {
return oxr_error(&log, XR_ERROR_ACTION_TYPE_MISMATCH,
" not created with float[2] type");
}
// Trust me.
if (countSubactionPaths > 1) {
return oxr_error(&log, XR_ERROR_PATH_INVALID,
" can not handle more then one subactionPath");
}
if (countSubactionPaths == 1) {
subactionPath = subactionPaths[0];
}
ret = oxr_verify_subaction_path_get(&log, act->act_set->sess->sys->inst,
subactionPath, &act->sub_paths,
&sub_paths, "subactionPaths[0]");
if (ret != XR_SUCCESS) {
return ret;
}
return oxr_action_get_vector2f(&log, act, sub_paths, data);
}
XrResult
@ -266,14 +346,27 @@ oxr_xrGetActionStatePose(XrAction action,
XrPath subactionPath,
XrActionStatePose* data)
{
struct oxr_sub_paths sub_paths = {0};
struct oxr_action* act;
struct oxr_logger log;
XrResult ret;
OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
"xrGetActionStatePose");
OXR_VERIFY_ARG_TYPE_AND_NULL(&log, data, XR_TYPE_ACTION_STATE_POSE);
//! @todo verify path
return oxr_action_get_pose(&log, act, subactionPath, data);
if (act->action_type != XR_INPUT_ACTION_TYPE_POSE) {
return oxr_error(&log, XR_ERROR_ACTION_TYPE_MISMATCH,
" not created with pose type");
}
ret = oxr_verify_subaction_path_get(&log, act->act_set->sess->sys->inst,
subactionPath, &act->sub_paths,
&sub_paths, "subactionPath");
if (ret != XR_SUCCESS) {
return ret;
}
return oxr_action_get_pose(&log, act, sub_paths, data);
}
XrResult
@ -311,6 +404,11 @@ oxr_xrApplyHapticFeedback(XrAction hapticAction,
OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
//! @todo verify paths
if (act->action_type != XR_OUTPUT_ACTION_TYPE_VIBRATION) {
return oxr_error(&log, XR_ERROR_ACTION_TYPE_MISMATCH,
" not created with output vibration type");
}
return oxr_action_apply_haptic_feedback(&log, act, countSubactionPaths,
subactionPaths, hapticEvent);
}
@ -327,6 +425,11 @@ oxr_xrStopHapticFeedback(XrAction hapticAction,
OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
//! @todo verify paths
if (act->action_type != XR_OUTPUT_ACTION_TYPE_VIBRATION) {
return oxr_error(&log, XR_ERROR_ACTION_TYPE_MISMATCH,
" not created with output vibration type");
}
return oxr_action_stop_haptic_feedback(&log, act, countSubactionPaths,
subactionPaths);
}

View file

@ -170,6 +170,36 @@ oxr_verify_localized_name(struct oxr_logger*,
uint32_t array_size,
const char* name);
/*!
* Verify a set of subaction paths for action creation.
*/
XrResult
oxr_verify_subaction_paths_create(struct oxr_logger* log,
struct oxr_instance* inst,
uint32_t countSubactionPaths,
const XrPath* subactionPaths,
const char* variable);
/*!
* Verify a set of subaction paths for action sync.
*/
XrResult
oxr_verify_subaction_path_sync(struct oxr_logger* log,
struct oxr_instance* inst,
XrPath path,
uint32_t index);
/*!
* Verify a set of subaction paths for action state get.
*/
XrResult
oxr_verify_subaction_path_get(struct oxr_logger* log,
struct oxr_instance* inst,
XrPath path,
const struct oxr_sub_paths* act_sub_paths,
struct oxr_sub_paths* out_sub_paths,
const char* variable);
XrResult
oxr_verify_XrSessionCreateInfo(struct oxr_logger*,
const struct oxr_instance*,

File diff suppressed because it is too large Load diff

View file

@ -34,12 +34,24 @@ radtodeg_for_display(float radians)
return (int32_t)(radians * 180 * M_1_PI);
}
static inline void
xdev_destroy(struct xrt_device **xdev_ptr)
{
struct xrt_device *xdev = *xdev_ptr;
if (xdev == NULL) {
return;
}
xdev->destroy(xdev);
*xdev_ptr = NULL;
}
static XrResult
oxr_instance_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
{
struct oxr_instance *inst = (struct oxr_instance *)hb;
struct xrt_auto_prober *prober = inst->prober;
struct xrt_device *dev = inst->system.device;
struct xrt_prober *prober = inst->prober;
oxr_path_destroy_all(log, inst);
@ -47,14 +59,12 @@ oxr_instance_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
u_hashset_destroy(&inst->path_store);
}
if (dev != NULL) {
dev->destroy(dev);
inst->system.device = NULL;
}
xdev_destroy(&inst->system.head);
xdev_destroy(&inst->system.left);
xdev_destroy(&inst->system.right);
if (prober != NULL) {
prober->destroy(prober);
inst->prober = NULL;
if (inst->prober != NULL) {
prober->destroy(&inst->prober);
}
time_state_destroy(inst->timekeeping);
@ -65,13 +75,23 @@ oxr_instance_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
return XR_SUCCESS;
}
static void
cache_path(struct oxr_logger *log,
struct oxr_instance *inst,
const char *str,
XrPath *out_path)
{
oxr_path_get_or_create(log, inst, str, strlen(str), out_path);
}
XrResult
oxr_instance_create(struct oxr_logger *log,
const XrInstanceCreateInfo *createInfo,
struct oxr_instance **out_instance)
{
struct oxr_instance *inst = NULL;
int h_ret;
struct xrt_device *xdevs[3] = {0};
int h_ret, p_ret;
OXR_ALLOCATE_HANDLE_OR_RETURN(log, inst, OXR_XR_DEBUG_INSTANCE,
oxr_instance_destroy, NULL);
@ -83,10 +103,35 @@ oxr_instance_create(struct oxr_logger *log,
"Failed to create hashset");
}
inst->prober = xrt_auto_prober_create();
// Cache certain often looked up paths.
cache_path(log, inst, "/user", &inst->path_cache.user);
cache_path(log, inst, "/user/hand/head", &inst->path_cache.head);
cache_path(log, inst, "/user/hand/left", &inst->path_cache.left);
cache_path(log, inst, "/user/hand/right", &inst->path_cache.right);
cache_path(log, inst, "/user/hand/gamepad", &inst->path_cache.gamepad);
struct xrt_device *dev =
inst->prober->lelo_dallas_autoprobe(inst->prober);
p_ret = xrt_prober_create(&inst->prober);
if (p_ret != 0) {
inst->prober->destroy(&inst->prober);
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
"Failed to create prober");
}
p_ret = inst->prober->probe(inst->prober);
if (p_ret != 0) {
inst->prober->destroy(&inst->prober);
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
"Failed to probe device(s)");
}
p_ret = inst->prober->select(inst->prober, xdevs, 3);
if (p_ret != 0) {
inst->prober->destroy(&inst->prober);
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
"Failed to select device");
}
struct xrt_device *dev = xdevs[0];
const float left_override = debug_get_float_option_lfov_left();
if (left_override != 0.0f) {
@ -127,7 +172,8 @@ oxr_instance_create(struct oxr_logger *log,
dev->hmd->views[1].fov.angle_down = down_override;
}
oxr_system_fill_in(log, inst, 1, &inst->system, dev);
oxr_system_fill_in(log, inst, 1, &inst->system, xdevs[0], xdevs[1],
xdevs[2]);
inst->timekeeping = time_state_create();

View file

@ -10,10 +10,12 @@
#pragma once
#include "xrt/xrt_device.h"
#include "xrt/xrt_tracking.h"
#include "xrt/xrt_compositor.h"
#include "xrt/xrt_vulkan_includes.h"
#include "xrt/xrt_openxr_includes.h"
#include "util/u_hashset.h"
#include "util/u_hashmap.h"
#ifdef __cplusplus
extern "C" {
@ -48,6 +50,8 @@ extern "C" {
#define OXR_XR_DEBUG_SWAPCHAIN (*(uint64_t *)"oxrswap\0")
#define OXR_XR_DEBUG_ACTIONSET (*(uint64_t *)"oxraset\0")
#define OXR_XR_DEBUG_MESSENGER (*(uint64_t *)"oxrmess\0")
#define OXR_XR_DEBUG_SOURCESET (*(uint64_t *)"oxrsrcs\0")
#define OXR_XR_DEBUG_SOURCE (*(uint64_t *)"oxrsrc_\0")
// clang-format on
@ -68,6 +72,11 @@ struct oxr_action_set;
struct oxr_action;
struct oxr_debug_messenger;
struct oxr_handle_base;
struct oxr_sub_paths;
struct oxr_source;
struct oxr_source_set;
struct oxr_source_input;
struct oxr_source_output;
#define XRT_MAX_HANDLE_CHILDREN 256
@ -212,6 +221,26 @@ oxr_path_destroy_all(struct oxr_logger *log, struct oxr_instance *inst);
*
*/
/*!
* Helper function to classify sub_paths.
*/
void
oxr_classify_sub_action_paths(struct oxr_logger *log,
struct oxr_instance *inst,
uint32_t num_subaction_paths,
const XrPath *subaction_paths,
struct oxr_sub_paths *sub_paths);
/*!
* Find the pose input for the set of sub_paths
*/
XrResult
oxr_source_get_pose_input(struct oxr_logger *log,
struct oxr_session *sess,
uint32_t key,
const struct oxr_sub_paths *sub_paths,
struct oxr_source_input **out_input);
/*!
* To go back to a OpenXR object.
*/
@ -274,28 +303,25 @@ oxr_action_get_input_source_localized_name(
XrResult
oxr_action_get_boolean(struct oxr_logger *log,
struct oxr_action *act,
uint32_t countSubactionPaths,
const XrPath *subactionPaths,
struct oxr_sub_paths sub_paths,
XrActionStateBoolean *data);
XrResult
oxr_action_get_vector1f(struct oxr_logger *log,
struct oxr_action *act,
uint32_t countSubactionPaths,
const XrPath *subactionPaths,
struct oxr_sub_paths sub_paths,
XrActionStateVector1f *data);
XrResult
oxr_action_get_vector2f(struct oxr_logger *log,
struct oxr_action *act,
uint32_t countSubactionPaths,
const XrPath *subactionPaths,
struct oxr_sub_paths sub_paths,
XrActionStateVector2f *data);
XrResult
oxr_action_get_pose(struct oxr_logger *log,
struct oxr_action *act,
XrPath subactionPath,
struct oxr_sub_paths sub_paths,
XrActionStatePose *data);
XrResult
@ -495,7 +521,9 @@ oxr_system_fill_in(struct oxr_logger *log,
struct oxr_instance *inst,
XrSystemId systemId,
struct oxr_system *sys,
struct xrt_device *dev);
struct xrt_device *head,
struct xrt_device *left,
struct xrt_device *right);
XrResult
oxr_system_verify_id(struct oxr_logger *log,
@ -563,6 +591,34 @@ oxr_event_push_XrEventDataSessionStateChanged(struct oxr_logger *log,
XrTime time);
/*
*
* oxr_xdev.c
*
*/
void
oxr_xdev_update(struct xrt_device* xdev, struct time_state* timekeeping);
void
oxr_xdev_find_input(struct xrt_device *xdev,
enum xrt_input_name name,
struct xrt_input **out_input);
void
oxr_xdev_find_output(struct xrt_device *xdev,
enum xrt_output_name name,
struct xrt_output **out_output);
void
oxr_xdev_get_pose_at(struct oxr_logger *log,
struct oxr_instance *inst,
struct xrt_device *xdev,
enum xrt_input_name name,
struct xrt_pose *pose,
int64_t *timestamp);
/*
*
* OpenGL, located in various files.
@ -687,7 +743,11 @@ struct oxr_handle_base
struct oxr_system
{
struct oxr_instance *inst;
struct xrt_device *device;
struct xrt_device *head;
struct xrt_device *left;
struct xrt_device *right;
XrSystemId systemId;
XrFormFactor form_factor;
@ -707,7 +767,7 @@ struct oxr_instance
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
struct xrt_auto_prober *prober;
struct xrt_prober *prober;
// Enabled extensions
bool headless;
@ -726,6 +786,16 @@ struct oxr_instance
struct oxr_event *last_event;
struct oxr_event *next_event;
struct
{
XrPath user;
XrPath head;
XrPath left;
XrPath right;
XrPath gamepad;
} path_cache;
#ifdef XR_EXT_debug_utils
//! Debug messengers
struct oxr_debug_messenger *messengers[XRT_MAX_HANDLE_CHILDREN];
@ -747,6 +817,9 @@ struct oxr_session
XrSessionState state;
bool frame_started;
struct u_hashmap_int *act_sets;
struct u_hashmap_int *sources;
/*!
* IPD, to be expanded to a proper 3D relation.
*/
@ -763,6 +836,122 @@ struct oxr_session
struct oxr_swapchain **);
};
/*!
* To carry around a sementic selection of sub action paths.
*/
struct oxr_sub_paths
{
bool any;
bool user;
bool head;
bool left;
bool right;
bool gamepad;
};
/*!
* Session input source.
*
* @see oxr_action_set
*/
struct oxr_source_set
{
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
//! Which generation of the XrActionSet was this created from.
uint32_t generation;
};
/*!
* The state of a action input source.
*
* @see oxr_source
*/
struct oxr_source_state
{
union {
struct
{
float x;
} vec1;
struct
{
float x;
float y;
} vec2;
bool boolean;
};
bool active;
// Was this changed.
bool changed;
//! When was this last changed.
XrTime timestamp;
};
/*!
* A input source pair of a @ref xrt_input and a @ref xrt_device.
*
* @see xrt_device
* @see xrt_input
*/
struct oxr_source_input
{
struct xrt_device *xdev;
struct xrt_input *input;
};
/*!
* A output source pair of a @ref xrt_output_name and a @ref xrt_device.
*
* @see xrt_device
* @see xrt_output_name
*/
struct oxr_source_output
{
struct xrt_device *xdev;
enum xrt_output_name name;
};
/*!
* A set of inputs for a single sub action path.
*
* @see oxr_source
*/
struct oxr_source_cache
{
struct oxr_source_state current;
size_t num_inputs;
struct oxr_source_input *inputs;
int64_t stop_output_time;
size_t num_outputs;
struct oxr_source_output *outputs;
};
/*!
* Session input source.
*
* @see oxr_action
*/
struct oxr_source
{
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
struct oxr_source_cache user;
struct oxr_source_cache head;
struct oxr_source_cache left;
struct oxr_source_cache right;
struct oxr_source_cache gamepad;
};
/*!
* Can be one of 3 references or a space that are bound to actions.
*
@ -782,8 +971,14 @@ struct oxr_space
//! What kind of reference space is this, if any.
XrReferenceSpaceType type;
//! Action key from which action this space was created from.
uint32_t act_key;
//! Is this a reference space?
bool is_reference;
//! Which sub action path is this?
struct oxr_sub_paths sub_paths;
};
/*!
@ -839,6 +1034,15 @@ struct oxr_action_set
//! Onwer of this messenger.
struct oxr_session *sess;
/*!
* Every change that is done to a action set will increment this
* counter and trigger a rebinding of inputs when syncing actions.
*/
uint32_t generation;
//! Unique key for the session hashmap.
uint32_t key;
};
/*!
@ -853,6 +1057,18 @@ struct oxr_action
//! Onwer of this messenger.
struct oxr_action_set *act_set;
//! Application supplied name of this action.
char name[XR_MAX_ACTION_NAME_SIZE];
//! Unique key for the session hashmap.
uint32_t key;
//! Type this action was created with.
XrActionType action_type;
//! Which sub action paths that this action was created with.
struct oxr_sub_paths sub_paths;
};
/*!

View file

@ -129,6 +129,7 @@ oxr_session_end(struct oxr_logger *log, struct oxr_session *sess)
return XR_SUCCESS;
}
XrResult
oxr_session_get_view_pose_at(struct oxr_logger *log,
struct oxr_session *sess,
@ -145,33 +146,39 @@ oxr_session_get_view_pose_at(struct oxr_logger *log,
// @todo If using orientation tracking only implement a neck model to
// get at least a slightly better position.
struct xrt_device *xdev = sess->sys->device;
struct xrt_device *xdev = sess->sys->head;
struct xrt_pose *offset = &xdev->tracking->offset;
struct xrt_space_relation relation;
int64_t timestamp;
xdev->get_tracked_pose(xdev, XRT_INPUT_GENERIC_HEAD_RELATION,
sess->sys->inst->timekeeping, &timestamp,
&relation);
if ((relation.relation_flags &
XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0) {
// Add in the offset from the tracking system.
math_relation_accumulate_transform(offset, &relation);
// clang-format off
bool valid_pos = (relation.relation_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) != 0;
bool valid_ori = (relation.relation_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0;
bool valid_vel = (relation.relation_flags & XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT) != 0;
// clang-format on
if (valid_ori) {
pose->orientation = relation.pose.orientation;
} else {
pose->orientation.x = 0;
pose->orientation.y = 0;
pose->orientation.z = 0;
pose->orientation.w = 1;
}
if ((relation.relation_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) !=
0) {
pose->position = relation.pose.position;
} else {
// "nominal height" 1.6m
pose->position.x = 0.0f;
pose->position.y = 1.60f;
pose->position.z = 0.0f;
// If the orientation is not valid just use the offset.
pose->orientation = offset->orientation;
}
if ((relation.relation_flags &
XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT) != 0) {
if (valid_pos) {
pose->position = relation.pose.position;
} else {
// If the position is not valid just use the offset.
pose->position = offset->position;
}
if (valid_vel) {
//! @todo Forcing a fixed amount of prediction for now since
//! devices don't tell us timestamps yet.
int64_t ns_diff = at_time - timestamp;
@ -187,8 +194,8 @@ oxr_session_get_view_pose_at(struct oxr_logger *log,
math_quat_integrate_velocity(&pose->orientation,
&relation.angular_velocity,
interval, &predicted);
if (debug_get_bool_option_views()) {
if (debug_get_bool_option_views()) {
fprintf(stderr,
"\toriginal quat = {%f, %f, %f, %f} "
"(time requested: %li, Interval %li nsec, with "
@ -197,6 +204,7 @@ oxr_session_get_view_pose_at(struct oxr_logger *log,
pose->orientation.z, pose->orientation.w,
at_time, ns_diff, interval);
}
pose->orientation = predicted;
}
@ -238,7 +246,7 @@ oxr_session_views(struct oxr_logger *log,
uint32_t *viewCountOutput,
XrView *views)
{
struct xrt_device *xdev = sess->sys->device;
struct xrt_device *xdev = sess->sys->head;
struct oxr_space *baseSpc = (struct oxr_space *)viewLocateInfo->space;
uint32_t num_views = 2;
@ -276,9 +284,9 @@ oxr_session_views(struct oxr_logger *log,
struct xrt_pose pure = pure_relation.pose;
// @todo the fov information that we get from xdev->views[i].fov is not
// properly filled out in oh_device.c, fix before wasting time on
// debugging weird rendering when adding stuff here.
// @todo the fov information that we get from xdev->hmd->views[i].fov is
// not properly filled out in oh_device.c, fix before wasting time
// on debugging weird rendering when adding stuff here.
for (uint32_t i = 0; i < num_views; i++) {
//! @todo Do not hardcode IPD.
@ -427,7 +435,7 @@ oxr_session_frame_end(struct oxr_logger *log,
"unknown environment blend mode");
}
if ((blend_mode & sess->sys->device->hmd->blend_mode) == 0) {
if ((blend_mode & sess->sys->head->hmd->blend_mode) == 0) {
return oxr_error(log,
XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED,
"(frameEndInfo->environmentBlendMode) "
@ -582,6 +590,9 @@ oxr_session_create(struct oxr_logger *log,
log, sess, XR_SESSION_STATE_READY, 0);
sess->state = XR_SESSION_STATE_READY;
u_hashmap_int_create(&sess->act_sets);
u_hashmap_int_create(&sess->sources);
*out_session = sess;
return ret;

View file

@ -27,7 +27,7 @@ oxr_session_populate_gl_xlib(struct oxr_logger *log,
struct oxr_session *sess)
{
struct xrt_compositor_gl *xcgl = xrt_gfx_provider_create_gl_xlib(
sys->device, sys->inst->timekeeping, next->xDisplay, next->visualid,
sys->head, sys->inst->timekeeping, next->xDisplay, next->visualid,
next->glxFBConfig, next->glxDrawable, next->glxContext);
if (xcgl == NULL) {

View file

@ -30,7 +30,7 @@ oxr_session_populate_vk(struct oxr_logger *log,
struct oxr_session *sess)
{
struct xrt_compositor_vk *xcvk = xrt_gfx_vk_provider_create(
sys->device, sys->inst->timekeeping, next->instance,
sys->head, sys->inst->timekeeping, next->instance,
vkGetInstanceProcAddr, next->physicalDevice, next->device,
next->queueFamilyIndex, next->queueIndex);

View file

@ -58,6 +58,10 @@ oxr_space_action_create(struct oxr_logger *log,
const XrActionSpaceCreateInfo *createInfo,
struct oxr_space **out_space)
{
struct oxr_session *sess = act->act_set->sess;
struct oxr_instance *inst = sess->sys->inst;
struct oxr_sub_paths sub_paths = {0};
struct oxr_space *spc = NULL;
OXR_ALLOCATE_HANDLE_OR_RETURN(log, spc, OXR_XR_DEBUG_SPACE,
oxr_space_destroy, &act->handle);
@ -65,8 +69,12 @@ oxr_space_action_create(struct oxr_logger *log,
//! @todo implement more fully
oxr_warn(log, " not fully implemented");
oxr_classify_sub_action_paths(log, inst, 1, &createInfo->subactionPath,
&sub_paths);
spc->sess = act->act_set->sess;
spc->is_reference = false;
spc->sub_paths = sub_paths;
memcpy(&spc->pose, &createInfo->poseInActionSpace, sizeof(spc->pose));
*out_space = spc;
@ -112,7 +120,7 @@ static const char *
get_ref_space_type_short_str(struct oxr_space *spc)
{
if (!spc->is_reference) {
return "action?";
return "action";
}
switch (spc->type) {
@ -181,6 +189,82 @@ oxr_space_ref_relation(struct oxr_logger *log,
return XR_SUCCESS;
}
/*!
* This returns only the relation between two spaces without any of the app
* given relations applied, assumes that only one is a action space.
*/
XrResult
oxr_space_action_relation(struct oxr_logger *log,
struct oxr_session *sess,
struct oxr_space *spc,
struct oxr_space *baseSpc,
XrTime time,
struct xrt_space_relation *out_relation)
{
struct oxr_source_input *input = NULL;
struct oxr_space *act_spc, *ref_spc = NULL;
int64_t timestamp = 0;
bool invert = false;
// Find the action space
if (baseSpc->is_reference) {
// Note spc, is assumed to be the action space.
act_spc = spc;
ref_spc = baseSpc;
}
// Find the action space.
if (spc->is_reference) {
// Note baseSpc, is assumed to be the action space.
act_spc = baseSpc;
ref_spc = spc;
invert = true;
}
// Internal error check.
if (act_spc == NULL || act_spc->is_reference || ref_spc == NULL ||
!ref_spc->is_reference) {
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "this is bad!");
}
// Reset so no relation is returned.
math_relation_reset(out_relation);
// We treat state and local space as the same.
//! @todo Can not relate to the view space right now.
if (baseSpc->type == XR_REFERENCE_SPACE_TYPE_VIEW) {
//! @todo Error code?
return XR_SUCCESS;
}
oxr_source_get_pose_input(log, sess, act_spc->act_key,
&act_spc->sub_paths, &input);
// If the input isn't active.
if (input == NULL) {
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XR_SUCCESS;
}
oxr_xdev_get_pose_at(log, sess->sys->inst, input->xdev,
input->input->name, &out_relation->pose,
&timestamp);
out_relation->relation_flags = (enum xrt_space_relation_flags)(
XRT_SPACE_RELATION_POSITION_VALID_BIT |
XRT_SPACE_RELATION_POSITION_TRACKED_BIT |
XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
if (invert) {
math_pose_invert(&out_relation->pose, &out_relation->pose);
}
return XR_SUCCESS;
}
/*!
* This returns only the relation between two directly-associated spaces without
* any of the app given relations applied.
@ -211,8 +295,8 @@ get_pure_space_relation(struct oxr_logger *log,
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XR_SUCCESS;
} else {
// @todo deal with action space poses.
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
oxr_space_action_relation(log, sess, spc, baseSpc, time,
out_relation);
return XR_SUCCESS;
}
}

View file

@ -93,15 +93,38 @@ oxr_system_fill_in(struct oxr_logger *log,
struct oxr_instance *inst,
XrSystemId systemId,
struct oxr_system *sys,
struct xrt_device *xdev)
struct xrt_device *head,
struct xrt_device *left,
struct xrt_device *right)
{
if (xdev == NULL) {
if (head == NULL) {
return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED,
" failed to probe device");
}
if (head->tracking->type == XRT_TRACKING_TYPE_NONE) {
// "nominal height" 1.6m
head->tracking->offset.position.x = 0.0f;
head->tracking->offset.position.y = 1.6f;
head->tracking->offset.position.z = 0.0f;
}
if (left != NULL && left->tracking->type == XRT_TRACKING_TYPE_NONE) {
left->tracking->offset.position.x = -0.2f;
left->tracking->offset.position.y = 1.3f;
left->tracking->offset.position.z = -0.5f;
}
if (right != NULL && right->tracking->type == XRT_TRACKING_TYPE_NONE) {
right->tracking->offset.position.x = 0.2f;
right->tracking->offset.position.y = 1.3f;
right->tracking->offset.position.z = -0.5f;
}
// clang-format off
sys->device = xdev;
sys->head = head;
sys->left = left;
sys->right = right;
sys->inst = inst;
sys->systemId = systemId;
sys->form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
@ -109,10 +132,11 @@ oxr_system_fill_in(struct oxr_logger *log,
double scale = debug_get_num_option_scale_percentage() / 100.0;
uint32_t w0 = (uint32_t)(xdev->hmd->views[0].display.w_pixels * scale);
uint32_t h0 = (uint32_t)(xdev->hmd->views[0].display.w_pixels * scale);
uint32_t w1 = (uint32_t)(xdev->hmd->views[1].display.w_pixels * scale);
uint32_t h1 = (uint32_t)(xdev->hmd->views[1].display.w_pixels * scale);
uint32_t w0 = (uint32_t)(head->hmd->views[0].display.w_pixels * scale);
uint32_t h0 = (uint32_t)(head->hmd->views[0].display.w_pixels * scale);
uint32_t w1 = (uint32_t)(head->hmd->views[1].display.w_pixels * scale);
uint32_t h1 = (uint32_t)(head->hmd->views[1].display.w_pixels * scale);
sys->views[0].recommendedImageRectWidth = w0;
sys->views[0].maxImageRectWidth = w0;
@ -130,13 +154,13 @@ oxr_system_fill_in(struct oxr_logger *log,
// clang-format on
uint32_t i = 0;
if (xdev->hmd->blend_mode & XRT_BLEND_MODE_OPAQUE) {
if (head->hmd->blend_mode & XRT_BLEND_MODE_OPAQUE) {
sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
}
if (xdev->hmd->blend_mode & XRT_BLEND_MODE_ADDITIVE) {
if (head->hmd->blend_mode & XRT_BLEND_MODE_ADDITIVE) {
sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE;
}
if (xdev->hmd->blend_mode & XRT_BLEND_MODE_ALPHA_BLEND) {
if (head->hmd->blend_mode & XRT_BLEND_MODE_ALPHA_BLEND) {
sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND;
}
sys->num_blend_modes = i;
@ -157,7 +181,7 @@ oxr_system_get_properties(struct oxr_logger *log,
properties->graphicsProperties.maxViewCount = 2;
// Needed to silence the warnings.
const char *name = sys->device->name;
const char *name = sys->head->name;
snprintf(properties->systemName, XR_MAX_SYSTEM_NAME_SIZE, "Monado: %s",
name);

View file

@ -264,6 +264,185 @@ oxr_verify_full_path(struct oxr_logger* log,
}
/*
*
* Subaction path functions.
*
*/
static XrResult
subaction_path_no_dups(struct oxr_logger* log,
struct oxr_instance* inst,
struct oxr_sub_paths& sub_paths,
XrPath path,
const char* variable,
uint32_t index)
{
bool duplicate = false;
if (path == XR_NULL_PATH) {
return oxr_error(log, XR_ERROR_PATH_INVALID,
"(%s[%u] == XR_NULL_PATH) not a "
"valid subaction path.",
variable, index);
} else if (path == inst->path_cache.user) {
if (sub_paths.user) {
duplicate = true;
} else {
sub_paths.user = true;
}
} else if (path == inst->path_cache.head) {
if (sub_paths.head) {
duplicate = true;
} else {
sub_paths.head = true;
}
} else if (path == inst->path_cache.left) {
if (sub_paths.left) {
duplicate = true;
} else {
sub_paths.left = true;
}
} else if (path == inst->path_cache.right) {
if (sub_paths.right) {
duplicate = true;
} else {
sub_paths.right = true;
}
} else if (path == inst->path_cache.gamepad) {
if (sub_paths.gamepad) {
duplicate = true;
} else {
sub_paths.gamepad = true;
}
} else {
const char* str = NULL;
size_t length = 0;
oxr_path_get_string(log, inst, path, &str, &length);
return oxr_error(log, XR_ERROR_PATH_INVALID,
"(%s[%u] == '%s') path is not a "
"valid subaction path.",
variable, index, str);
}
if (duplicate) {
const char* str = NULL;
size_t length = 0;
oxr_path_get_string(log, inst, path, &str, &length);
return oxr_error(log, XR_ERROR_PATH_INVALID,
"(%s[%u] == '%s') duplicate paths", variable,
index, str);
}
return XR_SUCCESS;
}
extern "C" XrResult
oxr_verify_subaction_paths_create(struct oxr_logger* log,
struct oxr_instance* inst,
uint32_t countSubactionPaths,
const XrPath* subactionPaths,
const char* variable)
{
struct oxr_sub_paths sub_paths = {};
for (uint32_t i = 0; i < countSubactionPaths; i++) {
XrPath path = subactionPaths[i];
XrResult ret = subaction_path_no_dups(log, inst, sub_paths,
path, variable, i);
if (ret != XR_SUCCESS) {
return ret;
}
}
return XR_SUCCESS;
}
extern "C" XrResult
oxr_verify_subaction_path_sync(struct oxr_logger* log,
struct oxr_instance* inst,
XrPath path,
uint32_t index)
{
if (path == XR_NULL_PATH || path == inst->path_cache.user ||
path == inst->path_cache.head || path == inst->path_cache.left ||
path == inst->path_cache.right ||
path == inst->path_cache.gamepad) {
return XR_SUCCESS;
} else {
const char* str = NULL;
size_t length = 0;
oxr_path_get_string(log, inst, path, &str, &length);
return oxr_error(log, XR_ERROR_PATH_INVALID,
"(actionSets[%i].subactionPath == '%s') path "
"is not a valid subaction path.",
index, str);
}
return XR_SUCCESS;
}
extern "C" XrResult
oxr_verify_subaction_path_get(struct oxr_logger* log,
struct oxr_instance* inst,
XrPath path,
const struct oxr_sub_paths* act_sub_paths,
struct oxr_sub_paths* out_sub_paths,
const char* variable)
{
struct oxr_sub_paths sub_paths = {};
if (path == XR_NULL_PATH) {
sub_paths.any = true;
} else if (path == inst->path_cache.user) {
sub_paths.user = true;
} else if (path == inst->path_cache.head) {
sub_paths.head = true;
} else if (path == inst->path_cache.left) {
sub_paths.left = true;
} else if (path == inst->path_cache.right) {
sub_paths.right = true;
} else if (path == inst->path_cache.gamepad) {
sub_paths.gamepad = true;
} else {
const char* str = NULL;
size_t length = 0;
oxr_path_get_string(log, inst, path, &str, &length);
return oxr_error(log, XR_ERROR_PATH_INVALID,
"(%s == '%s') path is not "
"a valid subaction path.",
variable, str);
}
if ((sub_paths.user && !act_sub_paths->user) ||
(sub_paths.head && !act_sub_paths->head) ||
(sub_paths.left && !act_sub_paths->left) ||
(sub_paths.right && !act_sub_paths->right) ||
(sub_paths.gamepad && !act_sub_paths->gamepad)) {
const char* str = NULL;
size_t length = 0;
oxr_path_get_string(log, inst, path, &str, &length);
return oxr_error(log, XR_ERROR_PATH_INVALID,
"(%s == '%s') the subaction path was "
"not specified at action creation",
variable, str);
}
*out_sub_paths = sub_paths;
return XR_SUCCESS;
}
/*
*
* Other verification.

View file

@ -0,0 +1,96 @@
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Various helpers for accessing @ref xrt_device.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup oxr_main
*/
#include "math/m_api.h"
#include "oxr_objects.h"
void
oxr_xdev_update(struct xrt_device* xdev, struct time_state* timekeeping)
{
if (xdev != NULL) {
xdev->update_inputs(xdev, timekeeping);
}
}
void
oxr_xdev_find_input(struct xrt_device *xdev,
enum xrt_input_name name,
struct xrt_input **out_input)
{
*out_input = NULL;
if (xdev == NULL) {
return;
}
for (uint32_t i = 0; i < xdev->num_inputs; i++) {
if (xdev->inputs[i].name != name) {
continue;
}
*out_input = &xdev->inputs[i];
return;
}
}
void
oxr_xdev_find_output(struct xrt_device *xdev,
enum xrt_output_name name,
struct xrt_output **out_output)
{
if (xdev == NULL) {
return;
}
for (uint32_t i = 0; i < xdev->num_outputs; i++) {
if (xdev->outputs[i].name != name) {
continue;
}
*out_output = &xdev->outputs[i];
return;
}
}
void
oxr_xdev_get_pose_at(struct oxr_logger *log,
struct oxr_instance *inst,
struct xrt_device *xdev,
enum xrt_input_name name,
struct xrt_pose *pose,
int64_t *timestamp)
{
struct xrt_pose *offset = &xdev->tracking->offset;
struct xrt_space_relation relation = {0};
xdev->get_tracked_pose(xdev, name, inst->timekeeping, timestamp,
&relation);
// Add in the offset from the tracking system.
math_relation_accumulate_transform(offset, &relation);
// clang-format off
bool valid_pos = (relation.relation_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) != 0;
bool valid_ori = (relation.relation_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0;
// clang-format on
if (valid_ori) {
pose->orientation = relation.pose.orientation;
} else {
// If the orientation is not valid just use the offset.
pose->orientation = offset->orientation;
}
if (valid_pos) {
pose->position = relation.pose.position;
} else {
// If the position is not valid just use the offset.
pose->position = offset->position;
}
}