2021-03-07 16:41:57 +00:00
|
|
|
// Copyright 2018-2021, Collabora, Ltd.
|
2019-03-18 05:52:32 +00:00
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Holds session related functions.
|
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
2021-03-07 16:41:57 +00:00
|
|
|
* @author Moses Turner <mosesturner@protonmail.com>
|
2019-03-18 05:52:32 +00:00
|
|
|
* @ingroup oxr_main
|
|
|
|
*/
|
|
|
|
|
2020-08-21 11:15:57 +00:00
|
|
|
#include "xrt/xrt_device.h"
|
2020-08-26 16:45:59 +00:00
|
|
|
#include "xrt/xrt_config_build.h"
|
|
|
|
#include "xrt/xrt_config_have.h"
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-08-21 11:15:57 +00:00
|
|
|
#ifdef XR_USE_PLATFORM_XLIB
|
|
|
|
#include "xrt/xrt_gfx_xlib.h"
|
|
|
|
#endif // XR_USE_PLATFORM_XLIB
|
|
|
|
|
|
|
|
#ifdef XRT_HAVE_VULKAN
|
|
|
|
#include "xrt/xrt_gfx_vk.h"
|
|
|
|
#endif // XRT_HAVE_VULKAN
|
|
|
|
|
|
|
|
#include "os/os_time.h"
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
#include "util/u_debug.h"
|
2019-03-23 01:11:14 +00:00
|
|
|
#include "util/u_misc.h"
|
2019-03-18 05:52:32 +00:00
|
|
|
#include "util/u_time.h"
|
2021-04-10 00:28:26 +00:00
|
|
|
#include "util/u_verify.h"
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-04-16 12:23:12 +00:00
|
|
|
#include "math/m_api.h"
|
2020-08-21 11:15:57 +00:00
|
|
|
#include "math/m_mathinclude.h"
|
2020-07-23 11:12:29 +00:00
|
|
|
#include "math/m_space.h"
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
#include "oxr_objects.h"
|
|
|
|
#include "oxr_logger.h"
|
|
|
|
#include "oxr_two_call.h"
|
2019-04-05 19:18:03 +00:00
|
|
|
#include "oxr_handle.h"
|
2019-06-03 19:17:45 +00:00
|
|
|
#include "oxr_chain.h"
|
2020-05-22 11:53:23 +00:00
|
|
|
#include "oxr_api_verify.h"
|
2020-08-24 00:09:21 +00:00
|
|
|
#include "oxr_chain.h"
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-08-21 11:15:57 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
DEBUG_GET_ONCE_NUM_OPTION(ipd, "OXR_DEBUG_IPD_MM", 63)
|
2020-11-05 19:07:53 +00:00
|
|
|
DEBUG_GET_ONCE_BOOL_OPTION(frame_timing_spew, "OXR_FRAME_TIMING_SPEW", false)
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define CALL_CHK(call) \
|
|
|
|
if ((call) == XRT_ERROR_IPC_FAILURE) { \
|
|
|
|
return oxr_error(log, XR_ERROR_INSTANCE_LOST, "Error in function call over IPC"); \
|
2020-06-04 14:56:25 +00:00
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
static bool
|
2020-05-30 17:30:27 +00:00
|
|
|
is_running(struct oxr_session *sess)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
2020-05-30 17:30:27 +00:00
|
|
|
return sess->has_begun;
|
2019-07-13 16:17:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
should_render(XrSessionState state)
|
|
|
|
{
|
|
|
|
switch (state) {
|
2019-03-18 05:52:32 +00:00
|
|
|
case XR_SESSION_STATE_VISIBLE: return true;
|
|
|
|
case XR_SESSION_STATE_FOCUSED: return true;
|
2019-10-22 12:35:09 +00:00
|
|
|
case XR_SESSION_STATE_STOPPING: return true;
|
2019-03-18 05:52:32 +00:00
|
|
|
default: return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-30 17:30:27 +00:00
|
|
|
XRT_MAYBE_UNUSED static const char *
|
|
|
|
to_string(XrSessionState state)
|
|
|
|
{
|
|
|
|
switch (state) {
|
|
|
|
case XR_SESSION_STATE_UNKNOWN: return "XR_SESSION_STATE_UNKNOWN";
|
|
|
|
case XR_SESSION_STATE_IDLE: return "XR_SESSION_STATE_IDLE";
|
|
|
|
case XR_SESSION_STATE_READY: return "XR_SESSION_STATE_READY";
|
2021-01-14 14:13:48 +00:00
|
|
|
case XR_SESSION_STATE_SYNCHRONIZED: return "XR_SESSION_STATE_SYNCHRONIZED";
|
2020-05-30 17:30:27 +00:00
|
|
|
case XR_SESSION_STATE_VISIBLE: return "XR_SESSION_STATE_VISIBLE";
|
|
|
|
case XR_SESSION_STATE_FOCUSED: return "XR_SESSION_STATE_FOCUSED";
|
|
|
|
case XR_SESSION_STATE_STOPPING: return "XR_SESSION_STATE_STOPPING";
|
2021-01-14 14:13:48 +00:00
|
|
|
case XR_SESSION_STATE_LOSS_PENDING: return "XR_SESSION_STATE_LOSS_PENDING";
|
2020-05-30 17:30:27 +00:00
|
|
|
case XR_SESSION_STATE_EXITING: return "XR_SESSION_STATE_EXITING";
|
|
|
|
case XR_SESSION_STATE_MAX_ENUM: return "XR_SESSION_STATE_MAX_ENUM";
|
|
|
|
default: return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-22 12:35:09 +00:00
|
|
|
static void
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_change_state(struct oxr_logger *log, struct oxr_session *sess, XrSessionState state)
|
2019-10-22 12:35:09 +00:00
|
|
|
{
|
|
|
|
oxr_event_push_XrEventDataSessionStateChanged(log, sess, state, 0);
|
|
|
|
sess->state = state;
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
XrResult
|
|
|
|
oxr_session_enumerate_formats(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
uint32_t formatCapacityInput,
|
|
|
|
uint32_t *formatCountOutput,
|
|
|
|
int64_t *formats)
|
|
|
|
{
|
2021-02-16 17:52:42 +00:00
|
|
|
struct oxr_instance *inst = sess->sys->inst;
|
2019-03-18 05:52:32 +00:00
|
|
|
struct xrt_compositor *xc = sess->compositor;
|
2019-06-05 19:14:18 +00:00
|
|
|
if (formatCountOutput == NULL) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(formatCountOutput == NULL) can not be null");
|
2019-06-05 19:14:18 +00:00
|
|
|
}
|
2019-03-23 01:11:14 +00:00
|
|
|
if (xc == NULL) {
|
2019-06-05 19:14:18 +00:00
|
|
|
if (formatCountOutput != NULL) {
|
|
|
|
*formatCountOutput = 0;
|
|
|
|
}
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-23 01:11:14 +00:00
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2021-02-16 17:52:42 +00:00
|
|
|
uint32_t filtered_count = 0;
|
|
|
|
int64_t filtered_formats[XRT_MAX_SWAPCHAIN_FORMATS];
|
|
|
|
for (uint32_t i = 0; i < xc->info.num_formats; i++) {
|
|
|
|
int64_t format = xc->info.formats[i];
|
|
|
|
|
|
|
|
if (inst->quirks.disable_vulkan_format_depth_stencil &&
|
|
|
|
format == 130 /* VK_FORMAT_D32_SFLOAT_S8_UINT */) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
filtered_formats[filtered_count++] = format;
|
|
|
|
}
|
|
|
|
|
|
|
|
OXR_TWO_CALL_HELPER(log, formatCapacityInput, formatCountOutput, formats, filtered_count, filtered_formats,
|
|
|
|
oxr_session_success_result(sess));
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_begin(struct oxr_logger *log, struct oxr_session *sess, const XrSessionBeginInfo *beginInfo)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
2020-05-30 17:30:27 +00:00
|
|
|
if (is_running(sess)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SESSION_RUNNING, "Session is already running");
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
2020-05-30 17:30:27 +00:00
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
struct xrt_compositor *xc = sess->compositor;
|
2019-03-23 01:11:14 +00:00
|
|
|
if (xc != NULL) {
|
2021-01-14 14:13:48 +00:00
|
|
|
XrViewConfigurationType view_type = beginInfo->primaryViewConfigurationType;
|
2019-08-14 22:15:15 +00:00
|
|
|
|
|
|
|
if (view_type != sess->sys->view_config_type) {
|
|
|
|
/*! @todo we only support a single view config type per
|
|
|
|
* system right now */
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED,
|
|
|
|
"(beginInfo->primaryViewConfigurationType == "
|
|
|
|
"0x%08x) view configuration type not supported",
|
|
|
|
view_type);
|
2019-08-14 22:15:15 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
CALL_CHK(xrt_comp_begin_session(xc, (enum xrt_view_type)beginInfo->primaryViewConfigurationType));
|
2019-03-23 01:11:14 +00:00
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-05-30 17:30:27 +00:00
|
|
|
sess->has_begun = true;
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
|
|
|
oxr_session_end(struct oxr_logger *log, struct oxr_session *sess)
|
|
|
|
{
|
|
|
|
struct xrt_compositor *xc = sess->compositor;
|
|
|
|
|
2020-05-30 17:30:27 +00:00
|
|
|
if (!is_running(sess)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING, "Session is not running");
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
2019-10-22 12:35:09 +00:00
|
|
|
if (sess->state != XR_SESSION_STATE_STOPPING) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SESSION_NOT_STOPPING, "Session is not stopping");
|
2019-10-22 12:35:09 +00:00
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2019-03-23 01:11:14 +00:00
|
|
|
if (xc != NULL) {
|
2020-06-23 16:11:39 +00:00
|
|
|
if (sess->frame_id.waited > 0) {
|
|
|
|
xrt_comp_discard_frame(xc, sess->frame_id.waited);
|
|
|
|
sess->frame_id.waited = -1;
|
2019-03-23 01:11:14 +00:00
|
|
|
}
|
2020-06-23 16:11:39 +00:00
|
|
|
if (sess->frame_id.begun > 0) {
|
|
|
|
xrt_comp_discard_frame(xc, sess->frame_id.begun);
|
|
|
|
sess->frame_id.begun = -1;
|
|
|
|
}
|
|
|
|
sess->frame_started = false;
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-06-04 14:56:25 +00:00
|
|
|
CALL_CHK(xrt_comp_end_session(xc));
|
2019-03-23 01:11:14 +00:00
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2019-10-22 12:35:09 +00:00
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE);
|
2019-10-22 18:51:37 +00:00
|
|
|
if (sess->exiting) {
|
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_EXITING);
|
|
|
|
}
|
2020-05-30 17:30:27 +00:00
|
|
|
|
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_READY);
|
|
|
|
|
|
|
|
sess->has_begun = false;
|
|
|
|
|
2019-10-22 12:35:09 +00:00
|
|
|
return oxr_session_success_result(sess);
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2019-10-22 12:35:09 +00:00
|
|
|
XrResult
|
|
|
|
oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess)
|
|
|
|
{
|
2020-05-30 17:30:27 +00:00
|
|
|
if (!is_running(sess)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING, "Session is not running");
|
2019-10-22 12:35:09 +00:00
|
|
|
}
|
2020-05-30 17:30:27 +00:00
|
|
|
|
2019-10-22 12:35:09 +00:00
|
|
|
if (sess->state == XR_SESSION_STATE_FOCUSED) {
|
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE);
|
|
|
|
}
|
|
|
|
if (sess->state == XR_SESSION_STATE_VISIBLE) {
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED);
|
2019-10-22 12:35:09 +00:00
|
|
|
}
|
2020-10-20 18:27:48 +00:00
|
|
|
if (!sess->has_ended_once) {
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED);
|
2020-05-30 17:30:27 +00:00
|
|
|
// Fake the synchronization.
|
2020-10-20 18:27:48 +00:00
|
|
|
sess->has_ended_once = true;
|
2020-05-30 17:30:27 +00:00
|
|
|
}
|
|
|
|
|
2019-10-22 12:35:09 +00:00
|
|
|
//! @todo start fading out the app.
|
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_STOPPING);
|
2019-10-22 18:51:37 +00:00
|
|
|
sess->exiting = true;
|
2019-10-22 12:35:09 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2019-10-08 15:24:16 +00:00
|
|
|
void
|
2020-06-17 06:36:38 +00:00
|
|
|
oxr_session_poll(struct oxr_logger *log, struct oxr_session *sess)
|
2019-10-08 15:24:16 +00:00
|
|
|
{
|
|
|
|
struct xrt_compositor *xc = sess->compositor;
|
2020-08-10 14:50:28 +00:00
|
|
|
if (xc == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-03 22:11:09 +00:00
|
|
|
bool read_more_events = true;
|
|
|
|
while (read_more_events) {
|
2020-08-10 14:50:28 +00:00
|
|
|
union xrt_compositor_event xce = {0};
|
2020-06-17 06:36:38 +00:00
|
|
|
xc->poll_events(xc, &xce);
|
|
|
|
|
|
|
|
// dispatch based on event type
|
|
|
|
switch (xce.type) {
|
|
|
|
case XRT_COMPOSITOR_EVENT_NONE:
|
|
|
|
// No more events.
|
2020-11-03 22:11:09 +00:00
|
|
|
read_more_events = false;
|
|
|
|
break;
|
2020-06-17 06:36:38 +00:00
|
|
|
case XRT_COMPOSITOR_EVENT_STATE_CHANGE:
|
2020-11-03 22:11:09 +00:00
|
|
|
sess->compositor_visible = xce.state.visible;
|
|
|
|
sess->compositor_focused = xce.state.focused;
|
2020-06-17 06:36:38 +00:00
|
|
|
break;
|
|
|
|
case XRT_COMPOSITOR_EVENT_OVERLAY_CHANGE:
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_event_push_XrEventDataMainSessionVisibilityChangedEXTX(log, sess, xce.overlay.visible);
|
2020-06-17 06:36:38 +00:00
|
|
|
break;
|
2020-12-16 17:20:51 +00:00
|
|
|
default: U_LOG_W("unhandled event type! %d", xce.type); break;
|
2020-06-17 06:36:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-03 22:11:09 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
if (sess->state == XR_SESSION_STATE_SYNCHRONIZED && sess->compositor_visible) {
|
2020-11-03 22:11:09 +00:00
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE);
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
if (sess->state == XR_SESSION_STATE_VISIBLE && sess->compositor_focused) {
|
2020-11-03 22:11:09 +00:00
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED);
|
|
|
|
}
|
2019-10-08 15:24:16 +00:00
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
XrResult
|
2020-07-23 11:12:29 +00:00
|
|
|
oxr_session_get_view_relation_at(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
XrTime at_time,
|
|
|
|
struct xrt_space_relation *out_relation)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
|
|
|
// @todo This function needs to be massively expanded to support all
|
|
|
|
// use cases this drive. The main use of this function is to get
|
|
|
|
// either the predicted position of the headset device. Right now
|
|
|
|
// it only returns the current position. But it must also deal
|
|
|
|
// with past values are allowed by the spec. See displayTime
|
|
|
|
// argument on the xrLocateViews function. It will also drive
|
|
|
|
// the function xrLocateSpace view using the view space.
|
|
|
|
// @todo If using orientation tracking only implement a neck model to
|
|
|
|
// get at least a slightly better position.
|
|
|
|
|
2020-07-07 00:14:29 +00:00
|
|
|
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-04-16 12:23:12 +00:00
|
|
|
// Applies the offset in the function.
|
2020-07-23 11:12:29 +00:00
|
|
|
struct xrt_space_graph xsg = {0};
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_xdev_get_space_graph(log, sess->sys->inst, xdev, XRT_INPUT_GENERIC_HEAD_POSE, at_time, &xsg);
|
2020-07-23 11:12:29 +00:00
|
|
|
m_space_graph_resolve(&xsg, out_relation);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-14 14:13:48 +00:00
|
|
|
print_view_fov(struct oxr_session *sess, uint32_t index, const struct xrt_fov *fov)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
2019-10-22 10:47:25 +00:00
|
|
|
if (!sess->sys->inst->debug_views) {
|
2019-03-18 05:52:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
U_LOG_D("views[%i].fov = {%f, %f, %f, %f}", index, fov->angle_left, fov->angle_right, fov->angle_up,
|
|
|
|
fov->angle_down);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-14 14:13:48 +00:00
|
|
|
print_view_pose(struct oxr_session *sess, uint32_t index, const struct xrt_pose *pose)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
2019-10-22 10:47:25 +00:00
|
|
|
if (!sess->sys->inst->debug_views) {
|
2019-03-18 05:52:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
U_LOG_D("views[%i].pose = {{%f, %f, %f, %f}, {%f, %f, %f}}", index, pose->orientation.x, pose->orientation.y,
|
|
|
|
pose->orientation.z, pose->orientation.w, pose->position.x, pose->position.y, pose->position.z);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2020-09-07 23:23:23 +00:00
|
|
|
static inline XrViewStateFlags
|
|
|
|
xrt_to_view_state_flags(enum xrt_space_relation_flags flags)
|
|
|
|
{
|
|
|
|
XrViewStateFlags res = 0;
|
|
|
|
if (flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) {
|
|
|
|
res |= XR_VIEW_STATE_ORIENTATION_VALID_BIT;
|
|
|
|
}
|
|
|
|
if (flags & XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT) {
|
|
|
|
res |= XR_VIEW_STATE_ORIENTATION_TRACKED_BIT;
|
|
|
|
}
|
|
|
|
if (flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) {
|
|
|
|
res |= XR_VIEW_STATE_POSITION_VALID_BIT;
|
|
|
|
}
|
|
|
|
if (flags & XRT_SPACE_RELATION_POSITION_TRACKED_BIT) {
|
|
|
|
res |= XR_VIEW_STATE_POSITION_TRACKED_BIT;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
XrResult
|
2021-04-27 00:43:35 +00:00
|
|
|
oxr_session_locate_views(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
const XrViewLocateInfo *viewLocateInfo,
|
|
|
|
XrViewState *viewState,
|
|
|
|
uint32_t viewCapacityInput,
|
|
|
|
uint32_t *viewCountOutput,
|
|
|
|
XrView *views)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
2020-07-07 00:14:29 +00:00
|
|
|
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_space *baseSpc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_space *, viewLocateInfo->space);
|
2019-03-18 05:52:32 +00:00
|
|
|
uint32_t num_views = 2;
|
|
|
|
|
|
|
|
// Does this apply for all calls?
|
|
|
|
if (!baseSpc->is_reference) {
|
|
|
|
viewState->viewStateFlags = 0;
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Start two call handling.
|
|
|
|
if (viewCountOutput != NULL) {
|
|
|
|
*viewCountOutput = num_views;
|
|
|
|
}
|
|
|
|
if (viewCapacityInput == 0) {
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
if (viewCapacityInput < num_views) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT, "(viewCapacityInput == %u) need %u",
|
2019-03-18 05:52:32 +00:00
|
|
|
viewCapacityInput, num_views);
|
|
|
|
}
|
|
|
|
// End two call handling.
|
|
|
|
|
2019-10-22 10:47:25 +00:00
|
|
|
if (sess->sys->inst->debug_views) {
|
2021-01-14 14:13:48 +00:00
|
|
|
U_LOG_D("viewLocateInfo->displayTime %" PRIu64, viewLocateInfo->displayTime);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the viewLocateInfo->space to view space relation.
|
|
|
|
struct xrt_space_relation pure_relation;
|
2021-04-26 23:54:37 +00:00
|
|
|
oxr_space_ref_relation( //
|
|
|
|
log, //
|
|
|
|
sess, //
|
|
|
|
XR_REFERENCE_SPACE_TYPE_VIEW, //
|
|
|
|
baseSpc->type, //
|
|
|
|
viewLocateInfo->displayTime, //
|
|
|
|
&pure_relation); //
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
// @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.
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-09-07 23:23:23 +00:00
|
|
|
viewState->viewStateFlags = 0;
|
|
|
|
|
2021-04-26 23:54:37 +00:00
|
|
|
//! @todo Do not hardcode IPD.
|
|
|
|
const struct xrt_vec3 eye_relation = {
|
|
|
|
sess->ipd_meters,
|
|
|
|
0.0f,
|
|
|
|
0.0f,
|
|
|
|
};
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
for (uint32_t i = 0; i < num_views; i++) {
|
2021-04-26 23:54:37 +00:00
|
|
|
struct xrt_pose view_pose = XRT_POSE_IDENTITY;
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
// Get the per view pose from the device.
|
2021-04-26 23:54:37 +00:00
|
|
|
xrt_device_get_view_pose(xdev, &eye_relation, i, &view_pose);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
// Do the magical space relation dance here.
|
2020-07-23 11:12:29 +00:00
|
|
|
struct xrt_space_relation result = {0};
|
|
|
|
struct xrt_space_graph xsg = {0};
|
|
|
|
m_space_graph_add_pose_if_not_identity(&xsg, &view_pose);
|
|
|
|
m_space_graph_add_relation(&xsg, &pure_relation);
|
|
|
|
m_space_graph_add_pose_if_not_identity(&xsg, &baseSpc->pose);
|
|
|
|
m_space_graph_resolve(&xsg, &result);
|
|
|
|
union {
|
|
|
|
struct xrt_pose xrt;
|
|
|
|
struct XrPosef oxr;
|
|
|
|
} safe_copy_pose = {0};
|
|
|
|
safe_copy_pose.xrt = result.pose;
|
|
|
|
views[i].pose = safe_copy_pose.oxr;
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
// Copy the fov information directly from the device.
|
2019-09-06 14:35:41 +00:00
|
|
|
union {
|
|
|
|
struct xrt_fov xrt;
|
|
|
|
XrFovf oxr;
|
2020-07-23 11:12:29 +00:00
|
|
|
} safe_copy_fov = {0};
|
|
|
|
safe_copy_fov.xrt = xdev->hmd->views[i].fov;
|
|
|
|
views[i].fov = safe_copy_fov.oxr;
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-06-17 11:19:34 +00:00
|
|
|
struct xrt_pose *pose = (struct xrt_pose *)&views[i].pose;
|
2021-01-14 14:13:48 +00:00
|
|
|
if ((result.relation_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0 &&
|
2020-09-09 12:49:58 +00:00
|
|
|
!math_quat_ensure_normalized(&pose->orientation)) {
|
2020-08-17 10:37:11 +00:00
|
|
|
struct xrt_quat *q = &pose->orientation;
|
|
|
|
struct xrt_quat norm = *q;
|
|
|
|
math_quat_normalize(&norm);
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"Quaternion %a %a %a %a (normalized %a %a %a %a) "
|
|
|
|
"in xrLocateViews was invalid",
|
|
|
|
q->x, q->y, q->z, q->w, norm.x, norm.y, norm.z, norm.w);
|
2020-06-16 13:39:16 +00:00
|
|
|
}
|
|
|
|
|
2019-10-22 10:47:25 +00:00
|
|
|
print_view_fov(sess, i, (struct xrt_fov *)&views[i].fov);
|
|
|
|
print_view_pose(sess, i, (struct xrt_pose *)&views[i].pose);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-09-07 23:23:23 +00:00
|
|
|
if (i == 0) {
|
2021-01-14 14:13:48 +00:00
|
|
|
viewState->viewStateFlags = xrt_to_view_state_flags(result.relation_flags);
|
2020-09-07 23:23:23 +00:00
|
|
|
} else {
|
2021-01-14 14:13:48 +00:00
|
|
|
viewState->viewStateFlags &= xrt_to_view_state_flags(result.relation_flags);
|
2020-09-07 23:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2020-11-05 19:07:53 +00:00
|
|
|
static double
|
|
|
|
ns_to_ms(int64_t ns)
|
|
|
|
{
|
|
|
|
double ms = ((double)ns) * 1. / 1000. * 1. / 1000.;
|
|
|
|
return ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
static double
|
|
|
|
ts_ms(struct oxr_session *sess)
|
|
|
|
{
|
|
|
|
timepoint_ns now = time_state_get_now(sess->sys->inst->timekeeping);
|
2021-01-14 14:13:48 +00:00
|
|
|
int64_t monotonic = time_state_ts_to_monotonic_ns(sess->sys->inst->timekeeping, now);
|
2020-11-05 19:07:53 +00:00
|
|
|
return ns_to_ms(monotonic);
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
XrResult
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_frame_wait(struct oxr_logger *log, struct oxr_session *sess, XrFrameState *frameState)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
2020-05-30 17:30:27 +00:00
|
|
|
if (!is_running(sess)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING, "Session is not running");
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2020-06-23 17:02:08 +00:00
|
|
|
|
2019-03-18 03:34:07 +00:00
|
|
|
//! @todo this should be carefully synchronized, because there may be
|
|
|
|
//! more than one session per instance.
|
2021-01-14 14:13:48 +00:00
|
|
|
XRT_MAYBE_UNUSED timepoint_ns now = time_state_get_now_and_update(sess->sys->inst->timekeeping);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
struct xrt_compositor *xc = sess->compositor;
|
2020-05-26 17:22:09 +00:00
|
|
|
if (xc == NULL) {
|
2019-10-22 15:53:07 +00:00
|
|
|
frameState->shouldRender = XR_FALSE;
|
2020-05-26 17:22:09 +00:00
|
|
|
return oxr_session_success_result(sess);
|
|
|
|
}
|
|
|
|
|
2020-11-03 19:54:34 +00:00
|
|
|
os_mutex_lock(&sess->active_wait_frames_lock);
|
|
|
|
sess->active_wait_frames++;
|
|
|
|
os_mutex_unlock(&sess->active_wait_frames_lock);
|
|
|
|
|
2020-11-05 19:07:53 +00:00
|
|
|
if (sess->frame_timing_spew) {
|
|
|
|
oxr_log(log, "Called at %8.3fms", ts_ms(sess));
|
|
|
|
}
|
|
|
|
|
2020-11-03 19:54:34 +00:00
|
|
|
// A subsequent xrWaitFrame call must: block until the previous frame
|
|
|
|
// has been begun
|
2020-06-23 17:02:08 +00:00
|
|
|
os_semaphore_wait(&sess->sem, 0);
|
|
|
|
|
2020-11-05 19:07:53 +00:00
|
|
|
if (sess->frame_timing_spew) {
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_log(log, "Finished waiting for previous frame begin at %8.3fms", ts_ms(sess));
|
2020-11-05 19:07:53 +00:00
|
|
|
}
|
|
|
|
|
2020-05-26 17:22:09 +00:00
|
|
|
uint64_t predicted_display_time;
|
|
|
|
uint64_t predicted_display_period;
|
2021-01-14 14:13:48 +00:00
|
|
|
CALL_CHK(xrt_comp_wait_frame(xc, &sess->frame_id.waited, &predicted_display_time, &predicted_display_period));
|
2020-05-26 17:22:09 +00:00
|
|
|
|
2020-05-27 17:02:24 +00:00
|
|
|
if ((int64_t)predicted_display_time <= 0) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Got a negative display time '%" PRIi64 "'",
|
2020-05-26 17:22:09 +00:00
|
|
|
(int64_t)predicted_display_time);
|
|
|
|
}
|
|
|
|
|
|
|
|
frameState->shouldRender = should_render(sess->state);
|
|
|
|
frameState->predictedDisplayPeriod = predicted_display_period;
|
2021-01-14 14:13:48 +00:00
|
|
|
frameState->predictedDisplayTime =
|
|
|
|
time_state_monotonic_to_ts_ns(sess->sys->inst->timekeeping, predicted_display_time);
|
2020-05-26 17:22:09 +00:00
|
|
|
|
|
|
|
if (frameState->predictedDisplayTime <= 0) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Time_state_monotonic_to_ts_ns returned '%" PRIi64 "'",
|
|
|
|
frameState->predictedDisplayTime);
|
2019-10-22 15:53:07 +00:00
|
|
|
}
|
2019-07-13 16:17:57 +00:00
|
|
|
|
2020-11-05 19:07:53 +00:00
|
|
|
if (sess->frame_timing_spew) {
|
|
|
|
oxr_log(log,
|
|
|
|
"Waiting finished at %8.3fms. Predicted display time "
|
|
|
|
"%8.3fms, "
|
|
|
|
"period %8.3fms",
|
2021-01-14 14:13:48 +00:00
|
|
|
ts_ms(sess), ns_to_ms(predicted_display_time), ns_to_ms(predicted_display_period));
|
2020-11-05 19:07:53 +00:00
|
|
|
}
|
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
|
|
|
oxr_session_frame_begin(struct oxr_logger *log, struct oxr_session *sess)
|
|
|
|
{
|
2020-05-30 17:30:27 +00:00
|
|
|
if (!is_running(sess)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING, "Session is not running");
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct xrt_compositor *xc = sess->compositor;
|
|
|
|
|
2020-11-03 19:54:34 +00:00
|
|
|
os_mutex_lock(&sess->active_wait_frames_lock);
|
|
|
|
int active_wait_frames = sess->active_wait_frames;
|
|
|
|
os_mutex_unlock(&sess->active_wait_frames_lock);
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
XrResult ret;
|
2020-11-03 19:54:34 +00:00
|
|
|
if (active_wait_frames == 0) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID, "xrBeginFrame without xrWaitFrame");
|
2020-11-03 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
if (sess->frame_started) {
|
2020-11-03 19:54:34 +00:00
|
|
|
// max 2 xrWaitFrame can be in flight so a second xrBeginFrame
|
|
|
|
// is only valid if we have a second xrWaitFrame in flight
|
|
|
|
if (active_wait_frames != 2) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID, "xrBeginFrame without xrWaitFrame");
|
2020-11-03 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
ret = XR_FRAME_DISCARDED;
|
2019-03-26 20:43:15 +00:00
|
|
|
if (xc != NULL) {
|
2021-01-14 14:13:48 +00:00
|
|
|
CALL_CHK(xrt_comp_discard_frame(xc, sess->frame_id.begun));
|
2020-06-23 16:11:39 +00:00
|
|
|
sess->frame_id.begun = -1;
|
2020-11-03 19:54:34 +00:00
|
|
|
|
|
|
|
os_mutex_lock(&sess->active_wait_frames_lock);
|
|
|
|
sess->active_wait_frames--;
|
|
|
|
os_mutex_unlock(&sess->active_wait_frames_lock);
|
2019-03-26 20:43:15 +00:00
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
} else {
|
2019-09-26 20:25:05 +00:00
|
|
|
ret = oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
sess->frame_started = true;
|
|
|
|
}
|
2019-03-26 20:43:15 +00:00
|
|
|
if (xc != NULL) {
|
2020-06-23 16:11:39 +00:00
|
|
|
CALL_CHK(xrt_comp_begin_frame(xc, sess->frame_id.waited));
|
|
|
|
sess->frame_id.begun = sess->frame_id.waited;
|
|
|
|
sess->frame_id.waited = -1;
|
2019-03-26 20:43:15 +00:00
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-06-23 17:02:08 +00:00
|
|
|
os_semaphore_release(&sess->sem);
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum xrt_blend_mode
|
|
|
|
oxr_blend_mode_to_xrt(XrEnvironmentBlendMode blend_mode)
|
|
|
|
{
|
|
|
|
switch (blend_mode) {
|
|
|
|
case XR_ENVIRONMENT_BLEND_MODE_OPAQUE: return XRT_BLEND_MODE_OPAQUE;
|
|
|
|
case XR_ENVIRONMENT_BLEND_MODE_ADDITIVE: return XRT_BLEND_MODE_ADDITIVE;
|
|
|
|
case XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND: return XRT_BLEND_MODE_ALPHA_BLEND;
|
|
|
|
default: return (enum xrt_blend_mode)0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
static XrResult
|
|
|
|
verify_space(struct oxr_logger *log, uint32_t layer_index, XrSpace space)
|
|
|
|
{
|
|
|
|
if (space == XR_NULL_HANDLE) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->space == "
|
|
|
|
"XR_NULL_HANDLE) XrSpace must not be XR_NULL_HANDLE",
|
|
|
|
layer_index);
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-05-30 20:05:55 +00:00
|
|
|
static XrResult
|
|
|
|
is_rect_neg(const XrRect2Di *imageRect)
|
|
|
|
{
|
|
|
|
if (imageRect->offset.x < 0 || imageRect->offset.y < 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static XrResult
|
|
|
|
is_rect_out_of_bounds(const XrRect2Di *imageRect, struct oxr_swapchain *sc)
|
|
|
|
{
|
|
|
|
uint32_t total_width = imageRect->offset.x + imageRect->extent.width;
|
|
|
|
if (total_width > sc->width) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
uint32_t total_height = imageRect->offset.y + imageRect->extent.height;
|
|
|
|
if (total_height > sc->height) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
static XrResult
|
|
|
|
verify_quad_layer(struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
uint32_t layer_index,
|
|
|
|
XrCompositionLayerQuad *quad,
|
|
|
|
struct xrt_device *head,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, quad->subImage.swapchain);
|
2020-04-22 12:59:07 +00:00
|
|
|
|
2020-06-01 16:37:43 +00:00
|
|
|
if (sc == NULL) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain is NULL!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
XrResult ret = verify_space(log, layer_index, quad->space);
|
|
|
|
if (ret != XR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-01-20 13:38:33 +00:00
|
|
|
if (!math_quat_validate_within_1_percent((struct xrt_quat *)&quad->pose.orientation)) {
|
2020-05-28 12:13:31 +00:00
|
|
|
XrQuaternionf *q = &quad->pose.orientation;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.orientation "
|
|
|
|
"== {%f %f %f %f}) is not a valid quat",
|
|
|
|
layer_index, q->x, q->y, q->z, q->w);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!math_vec3_validate((struct xrt_vec3 *)&quad->pose.position)) {
|
|
|
|
XrVector3f *p = &quad->pose.position;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.position "
|
|
|
|
"== {%f %f %f}) is not valid",
|
|
|
|
layer_index, p->x, p->y, p->z);
|
|
|
|
}
|
2020-05-22 11:53:23 +00:00
|
|
|
|
2020-05-30 20:05:55 +00:00
|
|
|
if (sc->num_array_layers <= quad->subImage.imageArrayIndex) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageArrayIndex == "
|
|
|
|
"%u) Invalid swapchain array "
|
|
|
|
"index for quad layer (%u).",
|
|
|
|
layer_index, quad->subImage.imageArrayIndex, sc->num_array_layers);
|
2020-05-22 12:11:20 +00:00
|
|
|
}
|
|
|
|
|
2020-05-30 16:01:00 +00:00
|
|
|
if (!sc->released.yes) {
|
2020-04-22 12:59:07 +00:00
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain has not been released!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
2020-05-30 16:01:00 +00:00
|
|
|
if (sc->released.index >= (int)sc->swapchain->num_images) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.swapchain) internal "
|
|
|
|
"image index out of bounds",
|
|
|
|
layer_index);
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-30 20:05:55 +00:00
|
|
|
if (is_rect_neg(&quad->subImage.imageRect)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageRect.offset == "
|
|
|
|
"{%i, %i}) has negative component(s)",
|
|
|
|
layer_index, quad->subImage.imageRect.offset.x, quad->subImage.imageRect.offset.y);
|
2020-05-22 13:00:04 +00:00
|
|
|
}
|
|
|
|
|
2020-05-30 20:05:55 +00:00
|
|
|
if (is_rect_out_of_bounds(&quad->subImage.imageRect, sc)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageRect == {{%i, "
|
|
|
|
"%i}, {%u, %u}}) imageRect out of image bounds (%u, %u)",
|
|
|
|
layer_index, quad->subImage.imageRect.offset.x, quad->subImage.imageRect.offset.y,
|
|
|
|
quad->subImage.imageRect.extent.width, quad->subImage.imageRect.extent.height,
|
|
|
|
sc->width, sc->height);
|
2020-05-22 11:47:13 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-08-24 00:09:21 +00:00
|
|
|
static XrResult
|
|
|
|
verify_depth_layer(struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
uint32_t layer_index,
|
|
|
|
uint32_t i,
|
|
|
|
const XrCompositionLayerDepthInfoKHR *depth)
|
|
|
|
{
|
|
|
|
if (depth->subImage.swapchain == XR_NULL_HANDLE) {
|
|
|
|
return oxr_error(log, XR_ERROR_HANDLE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.subImage."
|
|
|
|
"swapchain) is XR_NULL_HANDLE",
|
|
|
|
layer_index, i);
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, depth->subImage.swapchain);
|
2020-08-24 00:09:21 +00:00
|
|
|
|
|
|
|
if (!sc->released.yes) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.subImage."
|
|
|
|
"swapchain) swapchain has not been released",
|
|
|
|
layer_index, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->released.index >= (int)sc->swapchain->num_images) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.subImage."
|
|
|
|
"swapchain) internal image index out of bounds",
|
|
|
|
layer_index, i);
|
2020-08-24 00:09:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->num_array_layers <= depth->subImage.imageArrayIndex) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.subImage."
|
|
|
|
"imageArrayIndex == %u) Invalid swapchain array "
|
|
|
|
"index for projection layer (%u).",
|
|
|
|
layer_index, i, depth->subImage.imageArrayIndex, sc->num_array_layers);
|
2020-08-24 00:09:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_neg(&depth->subImage.imageRect)) {
|
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.subImage."
|
|
|
|
"imageRect.offset == {%i, "
|
|
|
|
"%i}) has negative component(s)",
|
2021-01-14 14:13:48 +00:00
|
|
|
layer_index, i, depth->subImage.imageRect.offset.x,
|
2020-08-24 00:09:21 +00:00
|
|
|
depth->subImage.imageRect.offset.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_out_of_bounds(&depth->subImage.imageRect, sc)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.subImage."
|
|
|
|
"imageRect == {{%i, %i}, {%u, %u}}) imageRect out "
|
|
|
|
"of image bounds (%u, %u)",
|
|
|
|
layer_index, i, depth->subImage.imageRect.offset.x, depth->subImage.imageRect.offset.y,
|
|
|
|
depth->subImage.imageRect.extent.width, depth->subImage.imageRect.extent.height,
|
|
|
|
sc->width, sc->height);
|
2020-08-24 00:09:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (depth->minDepth < 0.0f || depth->minDepth > 1.0f) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.minDepth) %f "
|
|
|
|
"must be in [0.0,1.0]",
|
|
|
|
layer_index, i, depth->minDepth);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (depth->maxDepth < 0.0f || depth->maxDepth > 1.0f) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.maxDepth) %f "
|
|
|
|
"must be in [0.0,1.0]",
|
|
|
|
layer_index, i, depth->maxDepth);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (depth->minDepth > depth->maxDepth) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.minDepth) %f "
|
|
|
|
"must be <= maxDepth %f ",
|
2021-01-14 14:13:48 +00:00
|
|
|
layer_index, i, depth->minDepth, depth->maxDepth);
|
2020-08-24 00:09:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (depth->nearZ == depth->farZ) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->next<"
|
|
|
|
"XrCompositionLayerDepthInfoKHR>.nearZ) %f "
|
|
|
|
"must be != farZ %f ",
|
|
|
|
layer_index, i, depth->nearZ, depth->farZ);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
static XrResult
|
|
|
|
verify_projection_layer(struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
uint32_t layer_index,
|
|
|
|
XrCompositionLayerProjection *proj,
|
|
|
|
struct xrt_device *head,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
|
|
|
XrResult ret = verify_space(log, layer_index, proj->space);
|
|
|
|
if (ret != XR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proj->viewCount != 2) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->viewCount == %u) must be 2 for "
|
|
|
|
"projection layers and the current view configuration",
|
|
|
|
layer_index, proj->viewCount);
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
|
|
|
|
2020-08-24 10:29:26 +00:00
|
|
|
// number of depth layers must be 0 or proj->viewCount
|
|
|
|
uint32_t num_depth_layers = 0;
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
// Check for valid swapchain states.
|
|
|
|
for (uint32_t i = 0; i < proj->viewCount; i++) {
|
2020-05-30 20:05:55 +00:00
|
|
|
const XrCompositionLayerProjectionView *view = &proj->views[i];
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
//! @todo More validation?
|
2021-01-20 13:38:33 +00:00
|
|
|
if (!math_quat_validate_within_1_percent((struct xrt_quat *)&view->pose.orientation)) {
|
2020-05-30 20:05:55 +00:00
|
|
|
const XrQuaternionf *q = &view->pose.orientation;
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->pose."
|
|
|
|
"orientation == {%f %f %f %f}) is not a valid quat",
|
|
|
|
layer_index, i, q->x, q->y, q->z, q->w);
|
2020-05-28 12:13:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
if (!math_vec3_validate((struct xrt_vec3 *)&view->pose.position)) {
|
2020-05-30 20:05:55 +00:00
|
|
|
const XrVector3f *p = &view->pose.position;
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->pose."
|
|
|
|
"position == {%f %f %f}) is not valid",
|
|
|
|
layer_index, i, p->x, p->y, p->z);
|
2020-05-28 12:13:31 +00:00
|
|
|
}
|
|
|
|
|
2020-08-24 08:17:07 +00:00
|
|
|
if (view->subImage.swapchain == XR_NULL_HANDLE) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_HANDLE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->subImage."
|
|
|
|
"swapchain is XR_NULL_HANDLE",
|
|
|
|
layer_index, i);
|
2020-08-24 08:17:07 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, view->subImage.swapchain);
|
2020-04-22 12:59:07 +00:00
|
|
|
|
2020-05-30 16:01:00 +00:00
|
|
|
if (!sc->released.yes) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i].subImage."
|
|
|
|
"swapchain) swapchain has not been released",
|
|
|
|
layer_index, i);
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-30 16:01:00 +00:00
|
|
|
if (sc->released.index >= (int)sc->swapchain->num_images) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i].subImage."
|
|
|
|
"swapchain) internal image index out of bounds",
|
|
|
|
layer_index, i);
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
2020-05-30 20:05:55 +00:00
|
|
|
|
|
|
|
if (sc->num_array_layers <= view->subImage.imageArrayIndex) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->subImage."
|
|
|
|
"imageArrayIndex == %u) Invalid swapchain array "
|
|
|
|
"index for projection layer (%u).",
|
|
|
|
layer_index, i, view->subImage.imageArrayIndex, sc->num_array_layers);
|
2020-05-30 20:05:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_neg(&view->subImage.imageRect)) {
|
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]-"
|
|
|
|
">subImage.imageRect.offset == {%i, "
|
|
|
|
"%i}) has negative component(s)",
|
2021-01-14 14:13:48 +00:00
|
|
|
layer_index, i, view->subImage.imageRect.offset.x,
|
2020-05-30 20:05:55 +00:00
|
|
|
view->subImage.imageRect.offset.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_out_of_bounds(&view->subImage.imageRect, sc)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->views[%i]->subImage."
|
|
|
|
"imageRect == {{%i, %i}, {%u, %u}}) imageRect out "
|
|
|
|
"of image bounds (%u, %u)",
|
|
|
|
layer_index, i, view->subImage.imageRect.offset.x,
|
|
|
|
view->subImage.imageRect.offset.y, view->subImage.imageRect.extent.width,
|
|
|
|
view->subImage.imageRect.extent.height, sc->width, sc->height);
|
2020-05-30 20:05:55 +00:00
|
|
|
}
|
2020-08-24 00:09:21 +00:00
|
|
|
|
2020-08-26 16:45:59 +00:00
|
|
|
#ifdef XRT_FEATURE_OPENXR_LAYER_DEPTH
|
2021-01-14 14:13:48 +00:00
|
|
|
const XrCompositionLayerDepthInfoKHR *depth_info = OXR_GET_INPUT_FROM_CHAIN(
|
|
|
|
view, XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR, XrCompositionLayerDepthInfoKHR);
|
2020-08-24 00:09:21 +00:00
|
|
|
|
|
|
|
if (depth_info) {
|
2021-01-14 14:13:48 +00:00
|
|
|
ret = verify_depth_layer(xc, log, layer_index, i, depth_info);
|
2020-08-24 00:09:21 +00:00
|
|
|
if (ret != XR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2020-08-24 10:29:26 +00:00
|
|
|
num_depth_layers++;
|
2020-08-24 00:09:21 +00:00
|
|
|
}
|
2020-08-26 16:45:59 +00:00
|
|
|
#endif // XRT_FEATURE_OPENXR_LAYER_DEPTH
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 16:45:59 +00:00
|
|
|
#ifdef XRT_FEATURE_OPENXR_LAYER_DEPTH
|
2020-08-24 10:29:26 +00:00
|
|
|
if (num_depth_layers > 0 && num_depth_layers != proj->viewCount) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u] projection layer must have %u "
|
|
|
|
"depth layers or none, but has: %u)",
|
|
|
|
layer_index, proj->viewCount, num_depth_layers);
|
2020-08-24 10:29:26 +00:00
|
|
|
}
|
2020-08-26 16:45:59 +00:00
|
|
|
#endif // XRT_FEATURE_OPENXR_LAYER_DEPTH
|
2020-08-24 10:29:26 +00:00
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-08-10 19:15:18 +00:00
|
|
|
static XrResult
|
|
|
|
verify_cube_layer(struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
uint32_t layer_index,
|
|
|
|
const XrCompositionLayerCubeKHR *cube,
|
|
|
|
struct xrt_device *head,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
|
|
|
#ifndef XRT_FEATURE_OPENXR_LAYER_CUBE
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->type) layer type "
|
|
|
|
"XrCompositionLayerCubeKHR not supported",
|
|
|
|
layer_index);
|
|
|
|
#else
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, cube->swapchain);
|
2020-08-12 14:14:17 +00:00
|
|
|
|
|
|
|
if (sc == NULL) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain is NULL!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
XrResult ret = verify_space(log, layer_index, cube->space);
|
|
|
|
if (ret != XR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-01-20 13:38:33 +00:00
|
|
|
if (!math_quat_validate_within_1_percent((struct xrt_quat *)&cube->orientation)) {
|
2020-08-12 14:14:17 +00:00
|
|
|
const XrQuaternionf *q = &cube->orientation;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.orientation "
|
|
|
|
"== {%f %f %f %f}) is not a valid quat",
|
|
|
|
layer_index, q->x, q->y, q->z, q->w);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->num_array_layers <= cube->imageArrayIndex) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->imageArrayIndex == %u) Invalid "
|
|
|
|
"swapchain array index for cube layer (%u).",
|
|
|
|
layer_index, cube->imageArrayIndex, sc->num_array_layers);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!sc->released.yes) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->swapchain) "
|
|
|
|
"swapchain has not been released!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->released.index >= (int)sc->swapchain->num_images) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.swapchain) internal "
|
|
|
|
"image index out of bounds",
|
|
|
|
layer_index);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
2020-08-10 19:15:18 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static XrResult
|
|
|
|
verify_cylinder_layer(struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
uint32_t layer_index,
|
|
|
|
const XrCompositionLayerCylinderKHR *cylinder,
|
|
|
|
struct xrt_device *head,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
|
|
|
#ifndef XRT_FEATURE_OPENXR_LAYER_CYLINDER
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->type) layer type "
|
|
|
|
"XrCompositionLayerCylinderKHR not supported",
|
|
|
|
layer_index);
|
|
|
|
#else
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, cylinder->subImage.swapchain);
|
2020-08-12 14:14:17 +00:00
|
|
|
|
|
|
|
if (sc == NULL) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain is NULL!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
XrResult ret = verify_space(log, layer_index, cylinder->space);
|
|
|
|
if (ret != XR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-01-20 13:38:33 +00:00
|
|
|
if (!math_quat_validate_within_1_percent((struct xrt_quat *)&cylinder->pose.orientation)) {
|
2020-08-12 14:14:17 +00:00
|
|
|
const XrQuaternionf *q = &cylinder->pose.orientation;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.orientation "
|
|
|
|
"== {%f %f %f %f}) is not a valid quat",
|
|
|
|
layer_index, q->x, q->y, q->z, q->w);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!math_vec3_validate((struct xrt_vec3 *)&cylinder->pose.position)) {
|
|
|
|
const XrVector3f *p = &cylinder->pose.position;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.position == "
|
|
|
|
"{%f %f %f}) is not valid",
|
|
|
|
layer_index, p->x, p->y, p->z);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->num_array_layers <= cylinder->subImage.imageArrayIndex) {
|
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"imageArrayIndex == %u) Invalid swapchain "
|
|
|
|
"array index for cylinder layer (%u).",
|
2021-01-14 14:13:48 +00:00
|
|
|
layer_index, cylinder->subImage.imageArrayIndex, sc->num_array_layers);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!sc->released.yes) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain has not been released!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->released.index >= (int)sc->swapchain->num_images) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.swapchain) internal "
|
|
|
|
"image index out of bounds",
|
|
|
|
layer_index);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_neg(&cylinder->subImage.imageRect)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageRect.offset == "
|
|
|
|
"{%i, %i}) has negative component(s)",
|
|
|
|
layer_index, cylinder->subImage.imageRect.offset.x,
|
|
|
|
cylinder->subImage.imageRect.offset.y);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_out_of_bounds(&cylinder->subImage.imageRect, sc)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageRect == {{%i, "
|
|
|
|
"%i}, {%u, %u}}) imageRect out of image bounds (%u, %u)",
|
|
|
|
layer_index, cylinder->subImage.imageRect.offset.x,
|
|
|
|
cylinder->subImage.imageRect.offset.y, cylinder->subImage.imageRect.extent.width,
|
|
|
|
cylinder->subImage.imageRect.extent.height, sc->width, sc->height);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cylinder->radius < 0.f) {
|
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->radius == %f) "
|
|
|
|
"radius can not be negative",
|
|
|
|
layer_index, cylinder->radius);
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
if (cylinder->centralAngle < 0.f || cylinder->centralAngle > (M_PI * 2)) {
|
2020-08-12 14:14:17 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->centralAngle == "
|
|
|
|
"%f) centralAngle out of bounds",
|
|
|
|
layer_index, cylinder->centralAngle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cylinder->aspectRatio <= 0.f) {
|
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->aspectRatio == "
|
|
|
|
"%f) aspectRatio out of bounds",
|
|
|
|
layer_index, cylinder->aspectRatio);
|
|
|
|
}
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
2020-08-10 19:15:18 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static XrResult
|
2020-12-02 13:18:00 +00:00
|
|
|
verify_equirect1_layer(struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
uint32_t layer_index,
|
|
|
|
const XrCompositionLayerEquirectKHR *equirect,
|
|
|
|
struct xrt_device *head,
|
|
|
|
uint64_t timestamp)
|
2020-08-10 19:15:18 +00:00
|
|
|
{
|
2020-12-02 13:18:00 +00:00
|
|
|
#ifndef XRT_FEATURE_OPENXR_LAYER_EQUIRECT1
|
2020-08-10 19:15:18 +00:00
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->type) layer type "
|
|
|
|
"XrCompositionLayerEquirectKHR not supported",
|
|
|
|
layer_index);
|
|
|
|
#else
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, equirect->subImage.swapchain);
|
2020-08-12 14:14:17 +00:00
|
|
|
|
|
|
|
if (sc == NULL) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain is NULL!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
XrResult ret = verify_space(log, layer_index, equirect->space);
|
|
|
|
if (ret != XR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-01-20 13:38:33 +00:00
|
|
|
if (!math_quat_validate_within_1_percent((struct xrt_quat *)&equirect->pose.orientation)) {
|
2020-08-12 14:14:17 +00:00
|
|
|
const XrQuaternionf *q = &equirect->pose.orientation;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.orientation "
|
|
|
|
"== {%f %f %f %f}) is not a valid quat",
|
|
|
|
layer_index, q->x, q->y, q->z, q->w);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!math_vec3_validate((struct xrt_vec3 *)&equirect->pose.position)) {
|
|
|
|
const XrVector3f *p = &equirect->pose.position;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.position == "
|
|
|
|
"{%f %f %f}) is not valid",
|
|
|
|
layer_index, p->x, p->y, p->z);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->num_array_layers <= equirect->subImage.imageArrayIndex) {
|
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"imageArrayIndex == %u) Invalid swapchain "
|
|
|
|
"array index for equirect layer (%u).",
|
2021-01-14 14:13:48 +00:00
|
|
|
layer_index, equirect->subImage.imageArrayIndex, sc->num_array_layers);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!sc->released.yes) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain has not been released!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->released.index >= (int)sc->swapchain->num_images) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.swapchain) internal "
|
|
|
|
"image index out of bounds",
|
|
|
|
layer_index);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_neg(&equirect->subImage.imageRect)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageRect.offset == "
|
|
|
|
"{%i, %i}) has negative component(s)",
|
|
|
|
layer_index, equirect->subImage.imageRect.offset.x,
|
|
|
|
equirect->subImage.imageRect.offset.y);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_out_of_bounds(&equirect->subImage.imageRect, sc)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageRect == {{%i, "
|
|
|
|
"%i}, {%u, %u}}) imageRect out of image bounds (%u, %u)",
|
|
|
|
layer_index, equirect->subImage.imageRect.offset.x,
|
|
|
|
equirect->subImage.imageRect.offset.y, equirect->subImage.imageRect.extent.width,
|
|
|
|
equirect->subImage.imageRect.extent.height, sc->width, sc->height);
|
2020-08-12 14:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (equirect->radius < .0f) {
|
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->radius == %f) "
|
|
|
|
"radius out of bounds",
|
|
|
|
layer_index, equirect->radius);
|
|
|
|
}
|
|
|
|
|
2020-12-02 13:46:41 +00:00
|
|
|
return XR_SUCCESS;
|
2020-08-10 19:15:18 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-10-09 14:34:15 +00:00
|
|
|
static XrResult
|
|
|
|
verify_equirect2_layer(struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
uint32_t layer_index,
|
|
|
|
const XrCompositionLayerEquirect2KHR *equirect,
|
|
|
|
struct xrt_device *head,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
2020-12-02 13:20:54 +00:00
|
|
|
#ifndef XRT_FEATURE_OPENXR_LAYER_EQUIRECT2
|
2020-10-09 14:34:15 +00:00
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->type) layer type "
|
|
|
|
"XrCompositionLayerEquirect2KHR not supported",
|
|
|
|
layer_index);
|
|
|
|
#else
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, equirect->subImage.swapchain);
|
2020-10-09 14:34:15 +00:00
|
|
|
|
|
|
|
if (sc == NULL) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain is NULL!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
XrResult ret = verify_space(log, layer_index, equirect->space);
|
|
|
|
if (ret != XR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-01-20 13:38:33 +00:00
|
|
|
if (!math_quat_validate_within_1_percent((struct xrt_quat *)&equirect->pose.orientation)) {
|
2020-10-09 14:34:15 +00:00
|
|
|
const XrQuaternionf *q = &equirect->pose.orientation;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.orientation "
|
|
|
|
"== {%f %f %f %f}) is not a valid quat",
|
|
|
|
layer_index, q->x, q->y, q->z, q->w);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!math_vec3_validate((struct xrt_vec3 *)&equirect->pose.position)) {
|
|
|
|
const XrVector3f *p = &equirect->pose.position;
|
|
|
|
return oxr_error(log, XR_ERROR_POSE_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->pose.position == "
|
|
|
|
"{%f %f %f}) is not valid",
|
|
|
|
layer_index, p->x, p->y, p->z);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->num_array_layers <= equirect->subImage.imageArrayIndex) {
|
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"imageArrayIndex == %u) Invalid swapchain "
|
|
|
|
"array index for equirect layer (%u).",
|
2021-01-14 14:13:48 +00:00
|
|
|
layer_index, equirect->subImage.imageArrayIndex, sc->num_array_layers);
|
2020-10-09 14:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!sc->released.yes) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage."
|
|
|
|
"swapchain) swapchain has not been released!",
|
|
|
|
layer_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->released.index >= (int)sc->swapchain->num_images) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.swapchain) internal "
|
|
|
|
"image index out of bounds",
|
|
|
|
layer_index);
|
2020-10-09 14:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_neg(&equirect->subImage.imageRect)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageRect.offset == "
|
|
|
|
"{%i, %i}) has negative component(s)",
|
|
|
|
layer_index, equirect->subImage.imageRect.offset.x,
|
|
|
|
equirect->subImage.imageRect.offset.y);
|
2020-10-09 14:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rect_out_of_bounds(&equirect->subImage.imageRect, sc)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_RECT_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u]->subImage.imageRect == {{%i, "
|
|
|
|
"%i}, {%u, %u}}) imageRect out of image bounds (%u, %u)",
|
|
|
|
layer_index, equirect->subImage.imageRect.offset.x,
|
|
|
|
equirect->subImage.imageRect.offset.y, equirect->subImage.imageRect.extent.width,
|
|
|
|
equirect->subImage.imageRect.extent.height, sc->width, sc->height);
|
2020-10-09 14:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (equirect->centralHorizontalAngle < .0f) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"(frameEndInfo->layers[%u]->centralHorizontalAngle == %f) "
|
|
|
|
"centralHorizontalAngle out of bounds",
|
|
|
|
layer_index, equirect->centralHorizontalAngle);
|
2020-10-09 14:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Accept all angle ranges here, since we are dealing with π
|
|
|
|
* and we don't want floating point errors to prevent the client
|
|
|
|
* to display the full sphere.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-06-09 18:51:39 +00:00
|
|
|
static enum xrt_layer_composition_flags
|
|
|
|
convert_layer_flags(XrSwapchainUsageFlags xr_flags)
|
|
|
|
{
|
|
|
|
enum xrt_layer_composition_flags flags = 0;
|
|
|
|
|
|
|
|
if ((xr_flags & XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT) != 0) {
|
|
|
|
flags |= XRT_LAYER_COMPOSITION_CORRECT_CHROMATIC_ABERRATION_BIT;
|
|
|
|
}
|
|
|
|
if ((xr_flags & XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT) != 0) {
|
|
|
|
flags |= XRT_LAYER_COMPOSITION_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
|
|
|
}
|
|
|
|
if ((xr_flags & XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT) != 0) {
|
|
|
|
flags |= XRT_LAYER_COMPOSITION_UNPREMULTIPLIED_ALPHA_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum xrt_layer_eye_visibility
|
|
|
|
convert_eye_visibility(XrSwapchainUsageFlags xr_visibility)
|
|
|
|
{
|
2020-06-13 12:57:59 +00:00
|
|
|
enum xrt_layer_eye_visibility visibility = 0;
|
2020-06-09 18:51:39 +00:00
|
|
|
|
|
|
|
if (xr_visibility == XR_EYE_VISIBILITY_BOTH) {
|
|
|
|
visibility = XRT_LAYER_EYE_VISIBILITY_BOTH;
|
|
|
|
}
|
|
|
|
if (xr_visibility == XR_EYE_VISIBILITY_LEFT) {
|
|
|
|
visibility = XRT_LAYER_EYE_VISIBILITY_LEFT_BIT;
|
|
|
|
}
|
|
|
|
if (xr_visibility == XR_EYE_VISIBILITY_RIGHT) {
|
|
|
|
visibility = XRT_LAYER_EYE_VISIBILITY_RIGHT_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return visibility;
|
|
|
|
}
|
|
|
|
|
2020-08-12 20:30:19 +00:00
|
|
|
static bool
|
|
|
|
handle_space(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_space *spc,
|
|
|
|
const struct xrt_pose *pose_ptr,
|
|
|
|
const struct xrt_pose *inv_offset,
|
|
|
|
uint64_t timestamp,
|
|
|
|
struct xrt_pose *out_pose)
|
2020-04-22 12:59:07 +00:00
|
|
|
{
|
2020-06-15 17:35:14 +00:00
|
|
|
struct xrt_pose pose = *pose_ptr;
|
|
|
|
|
2021-01-20 13:38:33 +00:00
|
|
|
// The pose might be valid for OpenXR, but not good enough for math.
|
|
|
|
if (!math_quat_validate(&pose.orientation)) {
|
|
|
|
math_quat_normalize(&pose.orientation);
|
|
|
|
}
|
|
|
|
|
2020-06-15 17:35:14 +00:00
|
|
|
if (spc->is_reference && spc->type == XR_REFERENCE_SPACE_TYPE_VIEW) {
|
|
|
|
// The space might have a pose, transform that in as well.
|
|
|
|
math_pose_transform(&spc->pose, &pose, &pose);
|
2020-07-17 11:08:07 +00:00
|
|
|
} else if (spc->is_reference) {
|
|
|
|
// The space might have a pose, transform that in as well.
|
|
|
|
math_pose_transform(&spc->pose, &pose, &pose);
|
|
|
|
|
|
|
|
// Remove the tracking system origin offset.
|
|
|
|
math_pose_transform(inv_offset, &pose, &pose);
|
2020-07-19 21:44:24 +00:00
|
|
|
|
|
|
|
if (spc->type == XR_REFERENCE_SPACE_TYPE_LOCAL) {
|
|
|
|
if (!initial_head_relation_valid(sess)) {
|
2020-08-12 20:30:19 +00:00
|
|
|
return false;
|
2020-07-19 21:44:24 +00:00
|
|
|
}
|
2021-01-14 14:13:48 +00:00
|
|
|
math_pose_transform(&sess->initial_head_relation.pose, &pose, &pose);
|
2020-07-19 21:44:24 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 17:35:14 +00:00
|
|
|
} else {
|
2020-07-16 17:34:46 +00:00
|
|
|
//! @todo Action space handling not very complete
|
|
|
|
|
|
|
|
struct oxr_action_input *input = NULL;
|
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
oxr_action_get_pose_input(log, sess, spc->act_key, &spc->subaction_paths, &input);
|
2020-07-16 17:34:46 +00:00
|
|
|
|
|
|
|
// If the input isn't active.
|
|
|
|
if (input == NULL) {
|
|
|
|
//! @todo just don't render the quad here?
|
2020-08-12 20:30:19 +00:00
|
|
|
return false;
|
2020-07-16 17:34:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct xrt_space_relation out_relation;
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_xdev_get_space_relation(log, sess->sys->inst, input->xdev, input->input->name, timestamp,
|
2020-07-23 11:12:29 +00:00
|
|
|
&out_relation);
|
2020-07-16 17:34:46 +00:00
|
|
|
|
|
|
|
struct xrt_pose device_pose = out_relation.pose;
|
2020-06-15 17:35:14 +00:00
|
|
|
|
|
|
|
// The space might have a pose, transform that in as well.
|
2020-07-16 17:34:46 +00:00
|
|
|
math_pose_transform(&spc->pose, &device_pose, &device_pose);
|
|
|
|
|
|
|
|
math_pose_transform(&device_pose, &pose, &pose);
|
2020-06-15 17:35:14 +00:00
|
|
|
|
|
|
|
// Remove the tracking system origin offset.
|
|
|
|
math_pose_transform(inv_offset, &pose, &pose);
|
|
|
|
}
|
2020-05-23 11:24:12 +00:00
|
|
|
|
2020-08-12 20:30:19 +00:00
|
|
|
|
|
|
|
*out_pose = pose;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static XrResult
|
|
|
|
submit_quad_layer(struct oxr_session *sess,
|
|
|
|
struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
XrCompositionLayerQuad *quad,
|
|
|
|
struct xrt_device *head,
|
|
|
|
struct xrt_pose *inv_offset,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, quad->subImage.swapchain);
|
|
|
|
struct oxr_space *spc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_space *, quad->space);
|
2020-08-12 20:30:19 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
enum xrt_layer_composition_flags flags = convert_layer_flags(quad->layerFlags);
|
2020-08-12 20:30:19 +00:00
|
|
|
|
|
|
|
struct xrt_pose *pose_ptr = (struct xrt_pose *)&quad->pose;
|
|
|
|
|
|
|
|
struct xrt_pose pose;
|
2021-01-14 14:13:48 +00:00
|
|
|
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, timestamp, &pose)) {
|
2020-08-12 20:30:19 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spc->is_reference && spc->type == XR_REFERENCE_SPACE_TYPE_VIEW) {
|
|
|
|
flags |= XRT_LAYER_COMPOSITION_VIEW_SPACE_BIT;
|
|
|
|
}
|
|
|
|
|
2020-06-09 18:02:04 +00:00
|
|
|
struct xrt_layer_data data;
|
|
|
|
U_ZERO(&data);
|
|
|
|
data.type = XRT_LAYER_QUAD;
|
|
|
|
data.name = XRT_INPUT_GENERIC_HEAD_POSE;
|
|
|
|
data.timestamp = timestamp;
|
|
|
|
data.flags = flags;
|
|
|
|
|
|
|
|
struct xrt_vec2 *size = (struct xrt_vec2 *)&quad->size;
|
|
|
|
struct xrt_rect *rect = (struct xrt_rect *)&quad->subImage.imageRect;
|
|
|
|
|
2020-06-09 18:51:39 +00:00
|
|
|
data.quad.visibility = convert_eye_visibility(quad->eyeVisibility);
|
2020-06-09 19:31:36 +00:00
|
|
|
data.quad.sub.image_index = sc->released.index;
|
|
|
|
data.quad.sub.array_index = quad->subImage.imageArrayIndex;
|
|
|
|
data.quad.sub.rect = *rect;
|
2020-06-09 18:02:04 +00:00
|
|
|
data.quad.pose = pose;
|
|
|
|
data.quad.size = *size;
|
|
|
|
|
|
|
|
CALL_CHK(xrt_comp_layer_quad(xc, head, sc->swapchain, &data));
|
2020-06-04 14:56:25 +00:00
|
|
|
|
|
|
|
return XR_SUCCESS;
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
|
|
|
|
2020-06-04 14:56:25 +00:00
|
|
|
static XrResult
|
2020-04-22 12:59:07 +00:00
|
|
|
submit_projection_layer(struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
XrCompositionLayerProjection *proj,
|
|
|
|
struct xrt_device *head,
|
2020-05-23 11:24:12 +00:00
|
|
|
struct xrt_pose *inv_offset,
|
2020-04-22 12:59:07 +00:00
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_space *spc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_space *, proj->space);
|
2020-08-25 13:53:44 +00:00
|
|
|
struct oxr_swapchain *d_scs[2] = {NULL, NULL};
|
2020-04-22 12:59:07 +00:00
|
|
|
struct oxr_swapchain *scs[2];
|
2020-06-15 17:35:14 +00:00
|
|
|
struct xrt_pose *pose_ptr[2];
|
|
|
|
struct xrt_pose pose[2];
|
2020-04-22 12:59:07 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
enum xrt_layer_composition_flags flags = convert_layer_flags(proj->layerFlags);
|
2020-04-22 12:59:07 +00:00
|
|
|
|
2020-06-09 18:51:39 +00:00
|
|
|
uint32_t num_chains = ARRAY_SIZE(scs);
|
2020-04-22 12:59:07 +00:00
|
|
|
for (uint32_t i = 0; i < num_chains; i++) {
|
2021-01-14 14:13:48 +00:00
|
|
|
scs[i] = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, proj->views[i].subImage.swapchain);
|
2020-06-15 17:35:14 +00:00
|
|
|
pose_ptr[i] = (struct xrt_pose *)&proj->views[i].pose;
|
|
|
|
pose[i] = *pose_ptr[i];
|
2021-01-20 13:38:33 +00:00
|
|
|
|
|
|
|
// The pose might be valid for OpenXR, but not good enough for math.
|
|
|
|
if (!math_quat_validate(&pose[i].orientation)) {
|
|
|
|
math_quat_normalize(&pose[i].orientation);
|
|
|
|
}
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 17:35:14 +00:00
|
|
|
if (spc->is_reference && spc->type == XR_REFERENCE_SPACE_TYPE_VIEW) {
|
|
|
|
flags |= XRT_LAYER_COMPOSITION_VIEW_SPACE_BIT;
|
|
|
|
// The space might have a pose, transform that in as well.
|
|
|
|
math_pose_transform(&spc->pose, &pose[0], &pose[0]);
|
|
|
|
math_pose_transform(&spc->pose, &pose[1], &pose[1]);
|
|
|
|
} else {
|
|
|
|
//! @todo Handle action spaces.
|
|
|
|
|
|
|
|
// The space might have a pose, transform that in as well.
|
|
|
|
math_pose_transform(&spc->pose, &pose[0], &pose[0]);
|
|
|
|
math_pose_transform(&spc->pose, &pose[1], &pose[1]);
|
|
|
|
|
|
|
|
// Remove the tracking system origin offset.
|
|
|
|
math_pose_transform(inv_offset, &pose[0], &pose[0]);
|
|
|
|
math_pose_transform(inv_offset, &pose[1], &pose[1]);
|
|
|
|
}
|
2020-05-23 11:24:12 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_rect *l_rect = (struct xrt_rect *)&proj->views[0].subImage.imageRect;
|
2020-06-09 18:02:04 +00:00
|
|
|
struct xrt_fov *l_fov = (struct xrt_fov *)&proj->views[0].fov;
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_rect *r_rect = (struct xrt_rect *)&proj->views[1].subImage.imageRect;
|
2020-06-09 18:02:04 +00:00
|
|
|
struct xrt_fov *r_fov = (struct xrt_fov *)&proj->views[1].fov;
|
|
|
|
|
|
|
|
struct xrt_layer_data data;
|
|
|
|
U_ZERO(&data);
|
|
|
|
data.type = XRT_LAYER_STEREO_PROJECTION;
|
|
|
|
data.name = XRT_INPUT_GENERIC_HEAD_POSE;
|
|
|
|
data.timestamp = timestamp;
|
|
|
|
data.flags = flags;
|
|
|
|
|
2020-06-09 19:31:36 +00:00
|
|
|
data.stereo.l.sub.image_index = scs[0]->released.index;
|
|
|
|
data.stereo.l.sub.array_index = proj->views[0].subImage.imageArrayIndex;
|
|
|
|
data.stereo.l.sub.rect = *l_rect;
|
2020-06-09 18:02:04 +00:00
|
|
|
data.stereo.l.fov = *l_fov;
|
|
|
|
data.stereo.l.pose = pose[0];
|
|
|
|
|
2020-06-09 19:31:36 +00:00
|
|
|
data.stereo.r.sub.image_index = scs[1]->released.index;
|
|
|
|
data.stereo.r.sub.array_index = proj->views[1].subImage.imageArrayIndex;
|
|
|
|
data.stereo.r.sub.rect = *r_rect;
|
2020-06-09 18:02:04 +00:00
|
|
|
data.stereo.r.fov = *r_fov;
|
|
|
|
data.stereo.r.pose = pose[1];
|
|
|
|
|
2020-08-24 00:54:35 +00:00
|
|
|
|
|
|
|
|
2020-08-26 16:45:59 +00:00
|
|
|
#ifdef XRT_FEATURE_OPENXR_LAYER_DEPTH
|
2020-08-24 00:54:35 +00:00
|
|
|
const XrCompositionLayerDepthInfoKHR *d_l = OXR_GET_INPUT_FROM_CHAIN(
|
2021-01-14 14:13:48 +00:00
|
|
|
&proj->views[0], XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR, XrCompositionLayerDepthInfoKHR);
|
2020-08-24 00:54:35 +00:00
|
|
|
if (d_l) {
|
|
|
|
data.stereo_depth.l_d.far_z = d_l->farZ;
|
|
|
|
data.stereo_depth.l_d.near_z = d_l->nearZ;
|
|
|
|
data.stereo_depth.l_d.max_depth = d_l->maxDepth;
|
|
|
|
data.stereo_depth.l_d.min_depth = d_l->minDepth;
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, d_l->subImage.swapchain);
|
2020-08-24 00:54:35 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_rect *d_l_rect = (struct xrt_rect *)&d_l->subImage.imageRect;
|
2020-08-24 00:54:35 +00:00
|
|
|
data.stereo_depth.l_d.sub.image_index = sc->released.index;
|
2021-01-14 14:13:48 +00:00
|
|
|
data.stereo_depth.l_d.sub.array_index = d_l->subImage.imageArrayIndex;
|
2020-08-24 00:54:35 +00:00
|
|
|
data.stereo_depth.l_d.sub.rect = *d_l_rect;
|
2020-08-25 13:53:44 +00:00
|
|
|
|
|
|
|
// Need to pass this in.
|
|
|
|
d_scs[0] = sc;
|
2020-08-24 00:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const XrCompositionLayerDepthInfoKHR *d_r = OXR_GET_INPUT_FROM_CHAIN(
|
2021-01-14 14:13:48 +00:00
|
|
|
&proj->views[1], XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR, XrCompositionLayerDepthInfoKHR);
|
2020-08-24 00:54:35 +00:00
|
|
|
|
|
|
|
if (d_r) {
|
|
|
|
data.stereo_depth.r_d.far_z = d_r->farZ;
|
|
|
|
data.stereo_depth.r_d.near_z = d_r->nearZ;
|
|
|
|
data.stereo_depth.r_d.max_depth = d_r->maxDepth;
|
|
|
|
data.stereo_depth.r_d.min_depth = d_r->minDepth;
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, d_r->subImage.swapchain);
|
2020-08-24 00:54:35 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_rect *d_l_rect = (struct xrt_rect *)&d_r->subImage.imageRect;
|
2020-08-24 00:54:35 +00:00
|
|
|
data.stereo_depth.r_d.sub.image_index = sc->released.index;
|
2021-01-14 14:13:48 +00:00
|
|
|
data.stereo_depth.r_d.sub.array_index = d_r->subImage.imageArrayIndex;
|
2020-08-24 00:54:35 +00:00
|
|
|
data.stereo_depth.r_d.sub.rect = *d_l_rect;
|
2020-08-25 13:53:44 +00:00
|
|
|
|
|
|
|
// Need to pass this in.
|
|
|
|
d_scs[1] = sc;
|
2020-08-24 00:54:35 +00:00
|
|
|
}
|
2020-08-26 16:45:59 +00:00
|
|
|
#endif // XRT_FEATURE_OPENXR_LAYER_DEPTH
|
2020-08-24 00:54:35 +00:00
|
|
|
|
2020-08-25 13:53:44 +00:00
|
|
|
if (d_scs[0] != NULL && d_scs[1] != NULL) {
|
2020-08-26 16:45:59 +00:00
|
|
|
#ifdef XRT_FEATURE_OPENXR_LAYER_DEPTH
|
2020-08-25 13:53:44 +00:00
|
|
|
data.type = XRT_LAYER_STEREO_PROJECTION_DEPTH;
|
2021-01-14 14:13:48 +00:00
|
|
|
CALL_CHK(xrt_comp_layer_stereo_projection_depth(xc, head,
|
|
|
|
scs[0]->swapchain, // Left
|
|
|
|
scs[1]->swapchain, // Right
|
|
|
|
d_scs[0]->swapchain, // Left
|
|
|
|
d_scs[1]->swapchain, // Right
|
|
|
|
&data));
|
2020-08-26 16:45:59 +00:00
|
|
|
#else
|
|
|
|
assert(false && "Should not get here");
|
|
|
|
#endif // XRT_FEATURE_OPENXR_LAYER_DEPTH
|
2020-08-25 13:53:44 +00:00
|
|
|
} else {
|
2021-01-14 14:13:48 +00:00
|
|
|
CALL_CHK(xrt_comp_layer_stereo_projection(xc, head,
|
|
|
|
scs[0]->swapchain, // Left
|
|
|
|
scs[1]->swapchain, // Right
|
|
|
|
&data));
|
2020-08-25 13:53:44 +00:00
|
|
|
}
|
2020-08-24 00:54:35 +00:00
|
|
|
|
2020-06-04 14:56:25 +00:00
|
|
|
return XR_SUCCESS;
|
2020-04-22 12:59:07 +00:00
|
|
|
}
|
|
|
|
|
2020-08-10 19:15:18 +00:00
|
|
|
static void
|
|
|
|
submit_cube_layer(struct oxr_session *sess,
|
|
|
|
struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
const XrCompositionLayerCubeKHR *cube,
|
|
|
|
struct xrt_device *head,
|
|
|
|
struct xrt_pose *inv_offset,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
|
|
|
// Not implemented
|
|
|
|
}
|
|
|
|
|
2020-08-12 20:30:19 +00:00
|
|
|
static XrResult
|
2020-08-10 19:15:18 +00:00
|
|
|
submit_cylinder_layer(struct oxr_session *sess,
|
|
|
|
struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
const XrCompositionLayerCylinderKHR *cylinder,
|
|
|
|
struct xrt_device *head,
|
|
|
|
struct xrt_pose *inv_offset,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, cylinder->subImage.swapchain);
|
|
|
|
struct oxr_space *spc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_space *, cylinder->space);
|
2020-08-12 20:30:19 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
enum xrt_layer_composition_flags flags = convert_layer_flags(cylinder->layerFlags);
|
|
|
|
enum xrt_layer_eye_visibility visibility = convert_eye_visibility(cylinder->eyeVisibility);
|
2020-08-12 20:30:19 +00:00
|
|
|
|
|
|
|
struct xrt_pose *pose_ptr = (struct xrt_pose *)&cylinder->pose;
|
|
|
|
|
|
|
|
struct xrt_pose pose;
|
2021-01-14 14:13:48 +00:00
|
|
|
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, timestamp, &pose)) {
|
2020-08-12 20:30:19 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spc->is_reference && spc->type == XR_REFERENCE_SPACE_TYPE_VIEW) {
|
|
|
|
flags |= XRT_LAYER_COMPOSITION_VIEW_SPACE_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xrt_layer_data data;
|
|
|
|
U_ZERO(&data);
|
|
|
|
data.type = XRT_LAYER_CYLINDER;
|
|
|
|
data.name = XRT_INPUT_GENERIC_HEAD_POSE;
|
|
|
|
data.timestamp = timestamp;
|
|
|
|
data.flags = flags;
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_rect *rect = (struct xrt_rect *)&cylinder->subImage.imageRect;
|
2020-08-20 01:56:36 +00:00
|
|
|
|
|
|
|
data.cylinder.visibility = visibility;
|
2020-08-12 20:30:19 +00:00
|
|
|
data.cylinder.sub.image_index = sc->released.index;
|
|
|
|
data.cylinder.sub.array_index = cylinder->subImage.imageArrayIndex;
|
2020-08-20 01:56:36 +00:00
|
|
|
data.cylinder.sub.rect = *rect;
|
2020-08-12 20:30:19 +00:00
|
|
|
data.cylinder.pose = pose;
|
|
|
|
data.cylinder.radius = cylinder->radius;
|
|
|
|
data.cylinder.central_angle = cylinder->centralAngle;
|
|
|
|
data.cylinder.aspect_ratio = cylinder->aspectRatio;
|
|
|
|
|
|
|
|
CALL_CHK(xrt_comp_layer_cylinder(xc, head, sc->swapchain, &data));
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
2020-08-10 19:15:18 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 13:46:41 +00:00
|
|
|
static XrResult
|
2020-12-02 13:18:00 +00:00
|
|
|
submit_equirect1_layer(struct oxr_session *sess,
|
|
|
|
struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
const XrCompositionLayerEquirectKHR *equirect,
|
|
|
|
struct xrt_device *head,
|
|
|
|
struct xrt_pose *inv_offset,
|
|
|
|
uint64_t timestamp)
|
2020-08-10 19:15:18 +00:00
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, equirect->subImage.swapchain);
|
|
|
|
struct oxr_space *spc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_space *, equirect->space);
|
2020-12-02 13:46:41 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
enum xrt_layer_composition_flags flags = convert_layer_flags(equirect->layerFlags);
|
2020-12-02 13:46:41 +00:00
|
|
|
|
|
|
|
struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose;
|
|
|
|
|
|
|
|
struct xrt_pose pose;
|
2021-01-14 14:13:48 +00:00
|
|
|
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, timestamp, &pose)) {
|
2020-12-02 13:46:41 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spc->is_reference && spc->type == XR_REFERENCE_SPACE_TYPE_VIEW) {
|
|
|
|
flags |= XRT_LAYER_COMPOSITION_VIEW_SPACE_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xrt_layer_data data;
|
|
|
|
U_ZERO(&data);
|
|
|
|
data.type = XRT_LAYER_EQUIRECT1;
|
|
|
|
data.name = XRT_INPUT_GENERIC_HEAD_POSE;
|
|
|
|
data.timestamp = timestamp;
|
|
|
|
data.flags = flags;
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_rect *rect = (struct xrt_rect *)&equirect->subImage.imageRect;
|
2020-12-02 13:46:41 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
data.equirect1.visibility = convert_eye_visibility(equirect->eyeVisibility);
|
2020-12-02 13:46:41 +00:00
|
|
|
data.equirect1.sub.image_index = sc->released.index;
|
|
|
|
data.equirect1.sub.array_index = equirect->subImage.imageArrayIndex;
|
|
|
|
data.equirect1.sub.rect = *rect;
|
|
|
|
data.equirect1.pose = pose;
|
|
|
|
|
|
|
|
data.equirect1.radius = equirect->radius;
|
|
|
|
|
|
|
|
struct xrt_vec2 *scale = (struct xrt_vec2 *)&equirect->scale;
|
|
|
|
struct xrt_vec2 *bias = (struct xrt_vec2 *)&equirect->bias;
|
|
|
|
|
|
|
|
data.equirect1.scale = *scale;
|
|
|
|
data.equirect1.bias = *bias;
|
|
|
|
|
|
|
|
CALL_CHK(xrt_comp_layer_equirect1(xc, head, sc->swapchain, &data));
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
2020-08-10 19:15:18 +00:00
|
|
|
}
|
|
|
|
|
2020-10-20 18:27:48 +00:00
|
|
|
static void
|
|
|
|
do_synchronize_state_change(struct oxr_logger *log, struct oxr_session *sess)
|
|
|
|
{
|
|
|
|
if (!sess->has_ended_once && sess->state < XR_SESSION_STATE_VISIBLE) {
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED);
|
2020-10-20 18:27:48 +00:00
|
|
|
sess->has_ended_once = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-09 14:34:15 +00:00
|
|
|
static XrResult
|
|
|
|
submit_equirect2_layer(struct oxr_session *sess,
|
|
|
|
struct xrt_compositor *xc,
|
|
|
|
struct oxr_logger *log,
|
|
|
|
const XrCompositionLayerEquirect2KHR *equirect,
|
|
|
|
struct xrt_device *head,
|
|
|
|
struct xrt_pose *inv_offset,
|
|
|
|
uint64_t timestamp)
|
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_swapchain *sc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_swapchain *, equirect->subImage.swapchain);
|
|
|
|
struct oxr_space *spc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_space *, equirect->space);
|
2020-10-09 14:34:15 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
enum xrt_layer_composition_flags flags = convert_layer_flags(equirect->layerFlags);
|
2020-10-09 14:34:15 +00:00
|
|
|
|
|
|
|
struct xrt_pose *pose_ptr = (struct xrt_pose *)&equirect->pose;
|
|
|
|
|
|
|
|
struct xrt_pose pose;
|
2021-01-14 14:13:48 +00:00
|
|
|
if (!handle_space(log, sess, spc, pose_ptr, inv_offset, timestamp, &pose)) {
|
2020-10-09 14:34:15 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spc->is_reference && spc->type == XR_REFERENCE_SPACE_TYPE_VIEW) {
|
|
|
|
flags |= XRT_LAYER_COMPOSITION_VIEW_SPACE_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xrt_layer_data data;
|
|
|
|
U_ZERO(&data);
|
2020-12-02 13:20:54 +00:00
|
|
|
data.type = XRT_LAYER_EQUIRECT2;
|
2020-10-09 14:34:15 +00:00
|
|
|
data.name = XRT_INPUT_GENERIC_HEAD_POSE;
|
|
|
|
data.timestamp = timestamp;
|
|
|
|
data.flags = flags;
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_rect *rect = (struct xrt_rect *)&equirect->subImage.imageRect;
|
2020-10-09 14:34:15 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
data.equirect2.visibility = convert_eye_visibility(equirect->eyeVisibility);
|
2020-12-02 13:20:54 +00:00
|
|
|
data.equirect2.sub.image_index = sc->released.index;
|
|
|
|
data.equirect2.sub.array_index = equirect->subImage.imageArrayIndex;
|
|
|
|
data.equirect2.sub.rect = *rect;
|
|
|
|
data.equirect2.pose = pose;
|
2020-10-09 14:34:15 +00:00
|
|
|
|
2020-12-02 13:20:54 +00:00
|
|
|
data.equirect2.radius = equirect->radius;
|
2021-01-14 14:13:48 +00:00
|
|
|
data.equirect2.central_horizontal_angle = equirect->centralHorizontalAngle;
|
2020-12-02 13:20:54 +00:00
|
|
|
data.equirect2.upper_vertical_angle = equirect->upperVerticalAngle;
|
|
|
|
data.equirect2.lower_vertical_angle = equirect->lowerVerticalAngle;
|
2020-10-09 14:34:15 +00:00
|
|
|
|
2020-12-02 13:20:54 +00:00
|
|
|
CALL_CHK(xrt_comp_layer_equirect2(xc, head, sc->swapchain, &data));
|
2020-10-09 14:34:15 +00:00
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
XrResult
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const XrFrameEndInfo *frameEndInfo)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Session state and call order.
|
|
|
|
*/
|
|
|
|
|
2020-05-30 17:30:27 +00:00
|
|
|
if (!is_running(sess)) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING, "Session is not running");
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
if (!sess->frame_started) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID, "Frame not begun with xrBeginFrame");
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 02:15:53 +00:00
|
|
|
if (frameEndInfo->displayTime <= 0) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_TIME_INVALID,
|
|
|
|
"(frameEndInfo->displayTime == %" PRIi64
|
|
|
|
") zero or a negative value is not a valid XrTime",
|
|
|
|
frameEndInfo->displayTime);
|
2020-02-25 02:15:53 +00:00
|
|
|
}
|
|
|
|
|
2021-04-05 16:52:44 +00:00
|
|
|
int64_t display_time_ns =
|
|
|
|
time_state_ts_to_monotonic_ns(sess->sys->inst->timekeeping, frameEndInfo->displayTime);
|
2020-11-05 19:07:53 +00:00
|
|
|
if (sess->frame_timing_spew) {
|
2021-04-05 16:52:44 +00:00
|
|
|
oxr_log(log, "End frame at %8.3fms with display time %8.3fms", ts_ms(sess), ns_to_ms(display_time_ns));
|
2020-11-05 19:07:53 +00:00
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
struct xrt_compositor *xc = sess->compositor;
|
|
|
|
|
2019-03-26 20:43:15 +00:00
|
|
|
/*
|
|
|
|
* early out for headless sessions.
|
|
|
|
*/
|
|
|
|
if (xc == NULL) {
|
|
|
|
sess->frame_started = false;
|
|
|
|
|
2020-11-03 19:54:34 +00:00
|
|
|
os_mutex_lock(&sess->active_wait_frames_lock);
|
|
|
|
sess->active_wait_frames--;
|
|
|
|
os_mutex_unlock(&sess->active_wait_frames_lock);
|
|
|
|
|
2020-10-20 18:27:48 +00:00
|
|
|
do_synchronize_state_change(log, sess);
|
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-26 20:43:15 +00:00
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
/*
|
|
|
|
* Blend mode.
|
2020-02-25 02:25:36 +00:00
|
|
|
* XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED must always be reported,
|
|
|
|
* even with 0 layers.
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
enum xrt_blend_mode blend_mode = oxr_blend_mode_to_xrt(frameEndInfo->environmentBlendMode);
|
2021-04-10 00:28:26 +00:00
|
|
|
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2021-04-10 00:28:26 +00:00
|
|
|
if (!u_verify_blend_mode_valid(blend_mode)) {
|
2019-03-18 05:52:32 +00:00
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
2020-05-26 16:54:13 +00:00
|
|
|
"(frameEndInfo->environmentBlendMode == "
|
|
|
|
"0x%08x) unknown environment blend mode",
|
|
|
|
frameEndInfo->environmentBlendMode);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2021-04-10 00:28:26 +00:00
|
|
|
if (!u_verify_blend_mode_supported(xdev, blend_mode)) {
|
2020-05-26 16:54:13 +00:00
|
|
|
//! @todo Make integer print to string.
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED,
|
2020-05-26 16:54:13 +00:00
|
|
|
"(frameEndInfo->environmentBlendMode == %u) "
|
|
|
|
"is not supported",
|
|
|
|
frameEndInfo->environmentBlendMode);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 02:25:36 +00:00
|
|
|
/*
|
|
|
|
* Early out for discarded frame if layer count is 0.
|
|
|
|
*/
|
|
|
|
if (frameEndInfo->layerCount == 0) {
|
2020-11-03 19:54:34 +00:00
|
|
|
|
2020-11-04 13:24:26 +00:00
|
|
|
os_mutex_lock(&sess->active_wait_frames_lock);
|
2020-11-03 19:54:34 +00:00
|
|
|
sess->active_wait_frames--;
|
2020-11-04 13:24:26 +00:00
|
|
|
os_mutex_unlock(&sess->active_wait_frames_lock);
|
2020-11-03 19:54:34 +00:00
|
|
|
|
2020-06-23 16:11:39 +00:00
|
|
|
CALL_CHK(xrt_comp_discard_frame(xc, sess->frame_id.begun));
|
|
|
|
sess->frame_id.begun = -1;
|
2020-02-25 02:25:36 +00:00
|
|
|
sess->frame_started = false;
|
|
|
|
|
2020-10-20 18:27:48 +00:00
|
|
|
do_synchronize_state_change(log, sess);
|
|
|
|
|
2020-02-25 02:25:36 +00:00
|
|
|
return oxr_session_success_result(sess);
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-10-20 18:27:48 +00:00
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
/*
|
|
|
|
* Layers.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (frameEndInfo->layers == NULL) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID, "(frameEndInfo->layers == NULL)");
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
for (uint32_t i = 0; i < frameEndInfo->layerCount; i++) {
|
2021-01-14 14:13:48 +00:00
|
|
|
const XrCompositionLayerBaseHeader *layer = frameEndInfo->layers[i];
|
2020-04-22 12:59:07 +00:00
|
|
|
if (layer == NULL) {
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
|
|
|
"(frameEndInfo->layers[%u] == NULL) "
|
|
|
|
"layer can not be null",
|
|
|
|
i);
|
|
|
|
}
|
2019-06-28 14:55:45 +00:00
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
XrResult res;
|
|
|
|
|
|
|
|
switch (layer->type) {
|
|
|
|
case XR_TYPE_COMPOSITION_LAYER_PROJECTION:
|
2021-01-14 14:13:48 +00:00
|
|
|
res = verify_projection_layer(xc, log, i, (XrCompositionLayerProjection *)layer, xdev,
|
|
|
|
frameEndInfo->displayTime);
|
2020-04-22 12:59:07 +00:00
|
|
|
break;
|
|
|
|
case XR_TYPE_COMPOSITION_LAYER_QUAD:
|
2021-01-14 14:13:48 +00:00
|
|
|
res = verify_quad_layer(xc, log, i, (XrCompositionLayerQuad *)layer, xdev,
|
|
|
|
frameEndInfo->displayTime);
|
2020-04-22 12:59:07 +00:00
|
|
|
break;
|
2020-08-10 19:15:18 +00:00
|
|
|
case XR_TYPE_COMPOSITION_LAYER_CUBE_KHR:
|
2021-01-14 14:13:48 +00:00
|
|
|
res = verify_cube_layer(xc, log, i, (XrCompositionLayerCubeKHR *)layer, xdev,
|
|
|
|
frameEndInfo->displayTime);
|
2020-08-10 19:15:18 +00:00
|
|
|
break;
|
|
|
|
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR:
|
2021-01-14 14:13:48 +00:00
|
|
|
res = verify_cylinder_layer(xc, log, i, (XrCompositionLayerCylinderKHR *)layer, xdev,
|
|
|
|
frameEndInfo->displayTime);
|
2020-08-10 19:15:18 +00:00
|
|
|
break;
|
|
|
|
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR:
|
2021-01-14 14:13:48 +00:00
|
|
|
res = verify_equirect1_layer(xc, log, i, (XrCompositionLayerEquirectKHR *)layer, xdev,
|
|
|
|
frameEndInfo->displayTime);
|
2020-08-10 19:15:18 +00:00
|
|
|
break;
|
2020-10-09 14:34:15 +00:00
|
|
|
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR:
|
2021-01-14 14:13:48 +00:00
|
|
|
res = verify_equirect2_layer(xc, log, i, (XrCompositionLayerEquirect2KHR *)layer, xdev,
|
|
|
|
frameEndInfo->displayTime);
|
2020-10-09 14:34:15 +00:00
|
|
|
break;
|
2020-04-22 12:59:07 +00:00
|
|
|
default:
|
|
|
|
return oxr_error(log, XR_ERROR_LAYER_INVALID,
|
2021-04-14 18:54:33 +00:00
|
|
|
"(frameEndInfo->layers[%u]->type) layer type not supported (%u)", i,
|
|
|
|
layer->type);
|
2019-06-28 14:55:45 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
if (res != XR_SUCCESS) {
|
|
|
|
return res;
|
2019-06-28 14:55:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
/*
|
2020-04-22 12:59:07 +00:00
|
|
|
* Done verifying.
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
|
2020-10-20 18:27:48 +00:00
|
|
|
// Do state change if needed.
|
|
|
|
do_synchronize_state_change(log, sess);
|
|
|
|
|
2020-05-23 11:24:12 +00:00
|
|
|
struct xrt_pose inv_offset = {0};
|
2020-07-07 00:14:29 +00:00
|
|
|
math_pose_invert(&xdev->tracking_origin->offset, &inv_offset);
|
2020-05-23 11:24:12 +00:00
|
|
|
|
2021-04-05 16:52:44 +00:00
|
|
|
CALL_CHK(xrt_comp_layer_begin(xc, sess->frame_id.begun, display_time_ns, blend_mode));
|
2020-04-22 12:59:07 +00:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < frameEndInfo->layerCount; i++) {
|
2021-01-14 14:13:48 +00:00
|
|
|
const XrCompositionLayerBaseHeader *layer = frameEndInfo->layers[i];
|
2020-04-22 12:59:07 +00:00
|
|
|
assert(layer != NULL);
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
int64_t timestamp =
|
|
|
|
time_state_ts_to_monotonic_ns(sess->sys->inst->timekeeping, frameEndInfo->displayTime);
|
2020-11-05 19:07:05 +00:00
|
|
|
|
2020-04-22 12:59:07 +00:00
|
|
|
switch (layer->type) {
|
|
|
|
case XR_TYPE_COMPOSITION_LAYER_PROJECTION:
|
2021-01-14 14:13:48 +00:00
|
|
|
submit_projection_layer(xc, log, (XrCompositionLayerProjection *)layer, xdev, &inv_offset,
|
|
|
|
timestamp);
|
2020-04-22 12:59:07 +00:00
|
|
|
break;
|
|
|
|
case XR_TYPE_COMPOSITION_LAYER_QUAD:
|
2021-01-14 14:13:48 +00:00
|
|
|
submit_quad_layer(sess, xc, log, (XrCompositionLayerQuad *)layer, xdev, &inv_offset, timestamp);
|
2020-04-22 12:59:07 +00:00
|
|
|
break;
|
2020-08-10 19:15:18 +00:00
|
|
|
case XR_TYPE_COMPOSITION_LAYER_CUBE_KHR:
|
2021-01-14 14:13:48 +00:00
|
|
|
submit_cube_layer(sess, xc, log, (XrCompositionLayerCubeKHR *)layer, xdev, &inv_offset,
|
|
|
|
timestamp);
|
2020-08-10 19:15:18 +00:00
|
|
|
break;
|
|
|
|
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR:
|
2021-01-14 14:13:48 +00:00
|
|
|
submit_cylinder_layer(sess, xc, log, (XrCompositionLayerCylinderKHR *)layer, xdev, &inv_offset,
|
|
|
|
timestamp);
|
2020-08-10 19:15:18 +00:00
|
|
|
break;
|
|
|
|
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR:
|
2021-01-14 14:13:48 +00:00
|
|
|
submit_equirect1_layer(sess, xc, log, (XrCompositionLayerEquirectKHR *)layer, xdev, &inv_offset,
|
|
|
|
timestamp);
|
2020-08-10 19:15:18 +00:00
|
|
|
break;
|
2020-10-09 14:34:15 +00:00
|
|
|
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR:
|
2021-01-14 14:13:48 +00:00
|
|
|
submit_equirect2_layer(sess, xc, log, (XrCompositionLayerEquirect2KHR *)layer, xdev,
|
|
|
|
&inv_offset, timestamp);
|
2020-10-09 14:34:15 +00:00
|
|
|
break;
|
2020-04-22 12:59:07 +00:00
|
|
|
default: assert(false && "invalid layer type");
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
CALL_CHK(xrt_comp_layer_commit(xc, sess->frame_id.begun, XRT_GRAPHICS_SYNC_HANDLE_INVALID));
|
2020-06-23 16:11:39 +00:00
|
|
|
sess->frame_id.begun = -1;
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
sess->frame_started = false;
|
|
|
|
|
2020-11-03 19:54:34 +00:00
|
|
|
os_mutex_lock(&sess->active_wait_frames_lock);
|
|
|
|
sess->active_wait_frames--;
|
|
|
|
os_mutex_unlock(&sess->active_wait_frames_lock);
|
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2019-04-05 22:13:58 +00:00
|
|
|
static XrResult
|
|
|
|
oxr_session_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
|
|
|
|
{
|
|
|
|
struct oxr_session *sess = (struct oxr_session *)hb;
|
2019-10-28 21:00:36 +00:00
|
|
|
|
2020-05-30 12:26:46 +00:00
|
|
|
XrResult ret = oxr_event_remove_session_events(log, sess);
|
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
for (size_t i = 0; i < sess->num_action_set_attachments; ++i) {
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_action_set_attachment_teardown(&sess->act_set_attachments[i]);
|
2020-06-15 21:46:21 +00:00
|
|
|
}
|
|
|
|
free(sess->act_set_attachments);
|
|
|
|
sess->act_set_attachments = NULL;
|
|
|
|
sess->num_action_set_attachments = 0;
|
|
|
|
|
|
|
|
// If we tore everything down correctly, these are empty now.
|
2021-01-14 14:13:48 +00:00
|
|
|
assert(sess->act_sets_attachments_by_key == NULL || u_hashmap_int_empty(sess->act_sets_attachments_by_key));
|
|
|
|
assert(sess->act_attachments_by_key == NULL || u_hashmap_int_empty(sess->act_attachments_by_key));
|
2019-10-28 21:00:36 +00:00
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
u_hashmap_int_destroy(&sess->act_sets_attachments_by_key);
|
|
|
|
u_hashmap_int_destroy(&sess->act_attachments_by_key);
|
2019-11-13 20:53:16 +00:00
|
|
|
|
2020-10-04 11:56:43 +00:00
|
|
|
xrt_comp_destroy(&sess->compositor);
|
2021-01-12 19:25:16 +00:00
|
|
|
xrt_comp_native_destroy(&sess->xcn);
|
2020-10-04 11:56:43 +00:00
|
|
|
|
2020-11-03 19:54:34 +00:00
|
|
|
os_semaphore_destroy(&sess->sem);
|
|
|
|
os_mutex_destroy(&sess->active_wait_frames_lock);
|
|
|
|
|
2019-04-05 22:13:58 +00:00
|
|
|
free(sess);
|
|
|
|
|
2020-05-30 12:26:46 +00:00
|
|
|
return ret;
|
2019-04-05 22:13:58 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 19:25:16 +00:00
|
|
|
|
2021-01-20 13:06:40 +00:00
|
|
|
#define OXR_ALLOCATE_NATIVE_COMPOSITOR(LOG, XSI, SESS) \
|
2021-01-12 19:25:16 +00:00
|
|
|
do { \
|
2021-01-20 13:06:40 +00:00
|
|
|
xrt_result_t xret = xrt_syscomp_create_native_compositor((SESS)->sys->xsysc, (XSI), &(SESS)->xcn); \
|
2021-01-12 19:25:16 +00:00
|
|
|
if (xret == XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED) { \
|
|
|
|
return oxr_error((LOG), XR_ERROR_LIMIT_REACHED, "Per instance multi-session not supported."); \
|
|
|
|
} else if (xret != XRT_SUCCESS) { \
|
|
|
|
return oxr_error((LOG), XR_ERROR_RUNTIME_FAILURE, "Failed to create native compositor! '%i'", \
|
|
|
|
xret); \
|
|
|
|
} \
|
2021-04-13 01:15:17 +00:00
|
|
|
if ((SESS)->sys->xsysc->xmcc != NULL) { \
|
|
|
|
xrt_syscomp_set_state((SESS)->sys->xsysc, &(SESS)->xcn->base, true, true); \
|
|
|
|
xrt_syscomp_set_z_order((SESS)->sys->xsysc, &(SESS)->xcn->base, 0); \
|
|
|
|
} \
|
2021-01-12 19:25:16 +00:00
|
|
|
} while (false)
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define OXR_SESSION_ALLOCATE(LOG, SYS, OUT) \
|
|
|
|
do { \
|
|
|
|
OXR_ALLOCATE_HANDLE_OR_RETURN(LOG, OUT, OXR_XR_DEBUG_SESSION, oxr_session_destroy, \
|
|
|
|
&(SYS)->inst->handle); \
|
|
|
|
(OUT)->sys = (SYS); \
|
2019-04-05 22:13:58 +00:00
|
|
|
} while (0)
|
|
|
|
|
2021-01-12 19:25:16 +00:00
|
|
|
|
2019-06-03 19:17:45 +00:00
|
|
|
/* Just the allocation and populate part, so we can use early-returns to
|
|
|
|
* simplify code flow and avoid weird if/else */
|
|
|
|
static XrResult
|
|
|
|
oxr_session_create_impl(struct oxr_logger *log,
|
|
|
|
struct oxr_system *sys,
|
|
|
|
const XrSessionCreateInfo *createInfo,
|
2021-01-20 13:06:40 +00:00
|
|
|
const struct xrt_session_info *xsi,
|
2019-06-03 19:17:45 +00:00
|
|
|
struct oxr_session **out_session)
|
|
|
|
{
|
2019-12-03 19:08:10 +00:00
|
|
|
#if defined(XR_USE_PLATFORM_XLIB) && defined(XR_USE_GRAPHICS_API_OPENGL)
|
2021-01-14 14:13:48 +00:00
|
|
|
XrGraphicsBindingOpenGLXlibKHR const *opengl_xlib = OXR_GET_INPUT_FROM_CHAIN(
|
|
|
|
createInfo, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, XrGraphicsBindingOpenGLXlibKHR);
|
2019-06-03 19:17:45 +00:00
|
|
|
if (opengl_xlib != NULL) {
|
2020-05-30 11:42:41 +00:00
|
|
|
if (!sys->gotten_requirements) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
|
|
|
|
"Has not called "
|
|
|
|
"xrGetOpenGL[ES]GraphicsRequirementsKHR");
|
2020-05-30 11:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-06-03 19:17:45 +00:00
|
|
|
OXR_SESSION_ALLOCATE(log, sys, *out_session);
|
2021-01-20 13:06:40 +00:00
|
|
|
OXR_ALLOCATE_NATIVE_COMPOSITOR(log, xsi, *out_session);
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_session_populate_gl_xlib(log, sys, opengl_xlib, *out_session);
|
2019-06-03 19:17:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-08-14 23:07:14 +00:00
|
|
|
|
|
|
|
#if defined(XR_USE_PLATFORM_ANDROID) && defined(XR_USE_GRAPHICS_API_OPENGL_ES)
|
2021-01-14 14:13:48 +00:00
|
|
|
XrGraphicsBindingOpenGLESAndroidKHR const *opengles_android = OXR_GET_INPUT_FROM_CHAIN(
|
|
|
|
createInfo, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR, XrGraphicsBindingOpenGLESAndroidKHR);
|
2020-08-14 23:07:14 +00:00
|
|
|
if (opengles_android != NULL) {
|
|
|
|
if (!sys->gotten_requirements) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
|
|
|
|
"Has not called "
|
|
|
|
"xrGetOpenGLESGraphicsRequirementsKHR");
|
2020-08-14 23:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
OXR_SESSION_ALLOCATE(log, sys, *out_session);
|
2021-01-20 13:06:40 +00:00
|
|
|
OXR_ALLOCATE_NATIVE_COMPOSITOR(log, xsi, *out_session);
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_session_populate_gles_android(log, sys, opengles_android, *out_session);
|
2020-08-14 23:07:14 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-06-03 19:17:45 +00:00
|
|
|
#ifdef XR_USE_GRAPHICS_API_VULKAN
|
2021-01-14 14:13:48 +00:00
|
|
|
XrGraphicsBindingVulkanKHR const *vulkan =
|
|
|
|
OXR_GET_INPUT_FROM_CHAIN(createInfo, XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, XrGraphicsBindingVulkanKHR);
|
2019-06-03 19:17:45 +00:00
|
|
|
if (vulkan != NULL) {
|
2020-05-30 11:42:41 +00:00
|
|
|
if (!sys->gotten_requirements) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
|
|
|
|
"Has not called "
|
|
|
|
"xrGetVulkanGraphicsRequirementsKHR");
|
2020-05-30 11:42:41 +00:00
|
|
|
}
|
|
|
|
|
2021-05-06 22:34:47 +00:00
|
|
|
if (sys->suggested_vulkan_physical_device == VK_NULL_HANDLE) {
|
|
|
|
char *fn = sys->inst->extensions.KHR_vulkan_enable ? "xrGetVulkanGraphicsDeviceKHR"
|
|
|
|
: "xrGetVulkanGraphicsDevice2KHR";
|
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "Has not called %s", fn);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sys->suggested_vulkan_physical_device != vulkan->physicalDevice) {
|
|
|
|
char *fn = sys->inst->extensions.KHR_vulkan_enable ? "xrGetVulkanGraphicsDeviceKHR"
|
|
|
|
: "xrGetVulkanGraphicsDevice2KHR";
|
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_VALIDATION_FAILURE,
|
|
|
|
"XrGraphicsBindingVulkanKHR::physicalDevice %p must match device %p specified by %s",
|
|
|
|
(void *)vulkan->physicalDevice, (void *)sys->suggested_vulkan_physical_device, fn);
|
|
|
|
}
|
|
|
|
|
2019-06-03 19:17:45 +00:00
|
|
|
OXR_SESSION_ALLOCATE(log, sys, *out_session);
|
2021-01-20 13:06:40 +00:00
|
|
|
OXR_ALLOCATE_NATIVE_COMPOSITOR(log, xsi, *out_session);
|
2019-06-03 19:17:45 +00:00
|
|
|
return oxr_session_populate_vk(log, sys, vulkan, *out_session);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-10-29 16:11:48 +00:00
|
|
|
#ifdef XR_USE_PLATFORM_EGL
|
2021-01-14 14:13:48 +00:00
|
|
|
XrGraphicsBindingEGLMNDX const *egl =
|
|
|
|
OXR_GET_INPUT_FROM_CHAIN(createInfo, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, XrGraphicsBindingEGLMNDX);
|
2019-10-29 16:11:48 +00:00
|
|
|
if (egl != NULL) {
|
2020-05-30 11:42:41 +00:00
|
|
|
if (!sys->gotten_requirements) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
|
|
|
|
"Has not called "
|
|
|
|
"xrGetOpenGL[ES]GraphicsRequirementsKHR");
|
2020-05-30 11:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-10-29 16:11:48 +00:00
|
|
|
OXR_SESSION_ALLOCATE(log, sys, *out_session);
|
2021-01-20 13:06:40 +00:00
|
|
|
OXR_ALLOCATE_NATIVE_COMPOSITOR(log, xsi, *out_session);
|
2019-10-29 16:11:48 +00:00
|
|
|
return oxr_session_populate_egl(log, sys, egl, *out_session);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-06-03 19:17:45 +00:00
|
|
|
/*
|
|
|
|
* Add any new graphics binding structs here - before the headless
|
|
|
|
* check. (order for non-headless checks not specified in standard.)
|
|
|
|
* Any new addition will also need to be added to
|
|
|
|
* oxr_verify_XrSessionCreateInfo and have its own associated verify
|
|
|
|
* function added.
|
|
|
|
*/
|
|
|
|
|
2019-08-19 17:37:50 +00:00
|
|
|
if (sys->inst->extensions.MND_headless) {
|
2019-06-03 19:17:45 +00:00
|
|
|
OXR_SESSION_ALLOCATE(log, sys, *out_session);
|
|
|
|
(*out_session)->compositor = NULL;
|
|
|
|
(*out_session)->create_swapchain = NULL;
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
|
2020-05-31 15:49:25 +00:00
|
|
|
"(createInfo->next->type) doesn't contain a valid "
|
|
|
|
"graphics binding structs");
|
2019-06-03 19:17:45 +00:00
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
XrResult
|
|
|
|
oxr_session_create(struct oxr_logger *log,
|
|
|
|
struct oxr_system *sys,
|
2019-06-03 19:17:45 +00:00
|
|
|
const XrSessionCreateInfo *createInfo,
|
2019-03-18 05:52:32 +00:00
|
|
|
struct oxr_session **out_session)
|
|
|
|
{
|
2019-08-16 22:02:38 +00:00
|
|
|
struct oxr_session *sess = NULL;
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2021-01-20 13:06:40 +00:00
|
|
|
struct xrt_session_info xsi = {0};
|
|
|
|
const XrSessionCreateInfoOverlayEXTX *overlay_info = OXR_GET_INPUT_FROM_CHAIN(
|
|
|
|
createInfo, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX, XrSessionCreateInfoOverlayEXTX);
|
|
|
|
if (overlay_info) {
|
|
|
|
xsi.is_overlay = true;
|
|
|
|
xsi.flags = overlay_info->createFlags;
|
|
|
|
xsi.z_order = overlay_info->sessionLayersPlacement;
|
|
|
|
}
|
|
|
|
|
2019-06-03 19:17:45 +00:00
|
|
|
/* Try allocating and populating. */
|
2021-01-20 13:06:40 +00:00
|
|
|
XrResult ret = oxr_session_create_impl(log, sys, createInfo, &xsi, &sess);
|
2019-03-18 05:52:32 +00:00
|
|
|
if (ret != XR_SUCCESS) {
|
2019-08-16 22:02:38 +00:00
|
|
|
if (sess != NULL) {
|
|
|
|
/* clean up allocation first */
|
2021-01-14 14:13:48 +00:00
|
|
|
XrResult cleanup_result = oxr_handle_destroy(log, &sess->handle);
|
2019-08-16 22:02:38 +00:00
|
|
|
assert(cleanup_result == XR_SUCCESS);
|
|
|
|
(void)cleanup_result;
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-06-17 06:36:38 +00:00
|
|
|
// Init the begin/wait frame semaphore.
|
2020-06-23 17:02:08 +00:00
|
|
|
os_semaphore_init(&sess->sem, 1);
|
|
|
|
|
2020-11-03 19:54:34 +00:00
|
|
|
sess->active_wait_frames = 0;
|
|
|
|
os_mutex_init(&sess->active_wait_frames_lock);
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
sess->ipd_meters = debug_get_num_option_ipd() / 1000.0f;
|
2020-11-05 19:07:53 +00:00
|
|
|
sess->frame_timing_spew = debug_get_bool_option_frame_timing_spew();
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-05-30 17:30:27 +00:00
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE);
|
|
|
|
oxr_session_change_state(log, sess, XR_SESSION_STATE_READY);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
u_hashmap_int_create(&sess->act_sets_attachments_by_key);
|
|
|
|
u_hashmap_int_create(&sess->act_attachments_by_key);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
*out_session = sess;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2020-10-12 00:09:19 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
xrt_to_xr_pose(struct xrt_pose *xrt_pose, XrPosef *xr_pose)
|
|
|
|
{
|
|
|
|
xr_pose->orientation.x = xrt_pose->orientation.x;
|
|
|
|
xr_pose->orientation.y = xrt_pose->orientation.y;
|
|
|
|
xr_pose->orientation.z = xrt_pose->orientation.z;
|
|
|
|
xr_pose->orientation.w = xrt_pose->orientation.w;
|
|
|
|
|
|
|
|
xr_pose->position.x = xrt_pose->position.x;
|
|
|
|
xr_pose->position.y = xrt_pose->position.y;
|
|
|
|
xr_pose->position.z = xrt_pose->position.z;
|
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
|
|
|
oxr_session_hand_joints(struct oxr_logger *log,
|
|
|
|
struct oxr_hand_tracker *hand_tracker,
|
|
|
|
const XrHandJointsLocateInfoEXT *locateInfo,
|
|
|
|
XrHandJointLocationsEXT *locations)
|
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_space *baseSpc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_space *, locateInfo->baseSpace);
|
2020-10-12 00:09:19 +00:00
|
|
|
|
|
|
|
struct oxr_session *sess = hand_tracker->sess;
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
XrHandJointVelocitiesEXT *vel =
|
|
|
|
OXR_GET_OUTPUT_FROM_CHAIN(locations, XR_TYPE_HAND_JOINT_VELOCITIES_EXT, XrHandJointVelocitiesEXT);
|
2020-11-18 22:42:14 +00:00
|
|
|
|
2021-04-08 18:32:55 +00:00
|
|
|
if (hand_tracker->xdev == NULL) {
|
|
|
|
locations->isActive = false;
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-11-24 02:26:27 +00:00
|
|
|
struct xrt_device *xdev = hand_tracker->xdev;
|
|
|
|
enum xrt_input_name name = hand_tracker->input_name;
|
2020-10-12 00:09:19 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_pose *tracking_origin_offset = &xdev->tracking_origin->offset;
|
2020-10-12 00:09:19 +00:00
|
|
|
|
|
|
|
XrTime at_time = locateInfo->time;
|
2020-11-13 00:30:25 +00:00
|
|
|
struct xrt_hand_joint_set value;
|
2020-10-12 00:09:19 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_xdev_get_hand_tracking_at(log, sess->sys->inst, xdev, name, at_time, &value);
|
2020-10-12 00:09:19 +00:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < locations->jointCount; i++) {
|
2020-11-13 00:30:25 +00:00
|
|
|
locations->jointLocations[i].locationFlags =
|
2021-01-14 14:13:48 +00:00
|
|
|
xrt_to_xr_space_location_flags(value.values.hand_joint_set_default[i].relation.relation_flags);
|
|
|
|
locations->jointLocations[i].radius = value.values.hand_joint_set_default[i].radius;
|
2020-10-12 00:09:19 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_space_relation r = value.values.hand_joint_set_default[i].relation;
|
2020-10-12 00:09:19 +00:00
|
|
|
|
|
|
|
struct xrt_space_relation result;
|
|
|
|
struct xrt_space_graph graph = {0};
|
|
|
|
m_space_graph_add_relation(&graph, &r);
|
2020-11-13 00:30:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (baseSpc->type == XR_REFERENCE_SPACE_TYPE_STAGE) {
|
|
|
|
|
2020-12-27 22:52:38 +00:00
|
|
|
m_space_graph_add_relation(&graph, &value.hand_pose);
|
2021-01-14 14:13:48 +00:00
|
|
|
m_space_graph_add_pose_if_not_identity(&graph, tracking_origin_offset);
|
2020-11-13 00:30:25 +00:00
|
|
|
|
|
|
|
} else if (baseSpc->type == XR_REFERENCE_SPACE_TYPE_LOCAL) {
|
|
|
|
|
|
|
|
// for local space, first do stage space and transform
|
|
|
|
// result to local @todo: improve local space
|
2020-12-27 22:52:38 +00:00
|
|
|
m_space_graph_add_relation(&graph, &value.hand_pose);
|
2021-01-14 14:13:48 +00:00
|
|
|
m_space_graph_add_pose_if_not_identity(&graph, tracking_origin_offset);
|
2020-11-13 00:30:25 +00:00
|
|
|
|
2020-11-19 16:42:22 +00:00
|
|
|
} else if (baseSpc->type == XR_REFERENCE_SPACE_TYPE_VIEW) {
|
|
|
|
/*! @todo: testing, relating to view space unsupported
|
|
|
|
* in other parts of monado */
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_device *head_xdev = GET_XDEV_BY_ROLE(sess->sys, head);
|
2020-11-19 16:42:22 +00:00
|
|
|
|
|
|
|
struct xrt_space_relation view_relation;
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_get_view_relation_at(log, sess, at_time, &view_relation);
|
2020-11-19 16:42:22 +00:00
|
|
|
|
2020-12-27 22:52:38 +00:00
|
|
|
m_space_graph_add_relation(&graph, &value.hand_pose);
|
2021-01-14 14:13:48 +00:00
|
|
|
m_space_graph_add_pose_if_not_identity(&graph, tracking_origin_offset);
|
2020-11-19 16:42:22 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
m_space_graph_add_inverted_relation(&graph, &view_relation);
|
|
|
|
m_space_graph_add_inverted_pose_if_not_identity(&graph, &head_xdev->tracking_origin->offset);
|
2020-11-19 16:42:22 +00:00
|
|
|
|
2020-11-13 00:30:25 +00:00
|
|
|
} else if (!baseSpc->is_reference) {
|
|
|
|
// action space
|
|
|
|
|
|
|
|
struct oxr_action_input *input = NULL;
|
2020-10-23 12:39:59 +00:00
|
|
|
oxr_action_get_pose_input(log, sess, baseSpc->act_key, &baseSpc->subaction_paths, &input);
|
2020-11-13 00:30:25 +00:00
|
|
|
|
|
|
|
// If the input isn't active.
|
|
|
|
if (input == NULL) {
|
|
|
|
locations->isActive = false;
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xrt_space_relation act_space_relation;
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_xdev_get_space_relation(log, sess->sys->inst, input->xdev, input->input->name, at_time,
|
|
|
|
&act_space_relation);
|
2020-11-13 00:30:25 +00:00
|
|
|
|
|
|
|
|
2020-12-27 22:52:38 +00:00
|
|
|
m_space_graph_add_relation(&graph, &value.hand_pose);
|
2021-01-14 14:13:48 +00:00
|
|
|
m_space_graph_add_pose_if_not_identity(&graph, tracking_origin_offset);
|
2020-11-13 00:30:25 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
m_space_graph_add_inverted_relation(&graph, &act_space_relation);
|
|
|
|
m_space_graph_add_inverted_pose_if_not_identity(&graph, &input->xdev->tracking_origin->offset);
|
2020-11-13 00:30:25 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
m_space_graph_add_inverted_pose_if_not_identity(&graph, &baseSpc->pose);
|
2020-10-12 00:09:19 +00:00
|
|
|
m_space_graph_resolve(&graph, &result);
|
|
|
|
|
|
|
|
if (baseSpc->type == XR_REFERENCE_SPACE_TYPE_LOCAL) {
|
2020-11-13 00:30:25 +00:00
|
|
|
if (!global_to_local_space(sess, &result)) {
|
|
|
|
locations->isActive = false;
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
2020-10-12 00:09:19 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
xrt_to_xr_pose(&result.pose, &locations->jointLocations[i].pose);
|
2020-11-18 22:42:14 +00:00
|
|
|
|
|
|
|
if (vel) {
|
|
|
|
XrHandJointVelocityEXT *v = &vel->jointVelocities[i];
|
|
|
|
|
|
|
|
v->velocityFlags = 0;
|
2021-01-14 14:13:48 +00:00
|
|
|
if ((result.relation_flags & XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT)) {
|
|
|
|
v->velocityFlags |= XR_SPACE_VELOCITY_LINEAR_VALID_BIT;
|
2020-11-18 22:42:14 +00:00
|
|
|
}
|
2021-01-14 14:13:48 +00:00
|
|
|
if ((result.relation_flags & XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT)) {
|
|
|
|
v->velocityFlags |= XR_SPACE_VELOCITY_ANGULAR_VALID_BIT;
|
2020-11-18 22:42:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
v->linearVelocity.x = result.linear_velocity.x;
|
|
|
|
v->linearVelocity.y = result.linear_velocity.y;
|
|
|
|
v->linearVelocity.z = result.linear_velocity.z;
|
|
|
|
|
|
|
|
v->angularVelocity.x = result.angular_velocity.x;
|
|
|
|
v->angularVelocity.y = result.angular_velocity.y;
|
|
|
|
v->angularVelocity.z = result.angular_velocity.z;
|
|
|
|
}
|
2020-10-12 00:09:19 +00:00
|
|
|
}
|
|
|
|
|
2021-03-07 16:41:57 +00:00
|
|
|
if (value.is_active) {
|
|
|
|
locations->isActive = true;
|
|
|
|
} else {
|
|
|
|
locations->isActive = false;
|
|
|
|
for (uint32_t i = 0; i < locations->jointCount; i++) {
|
|
|
|
locations->jointLocations[i].locationFlags = XRT_SPACE_RELATION_BITMASK_NONE;
|
|
|
|
}
|
|
|
|
}
|
2020-10-12 00:09:19 +00:00
|
|
|
|
2020-11-13 00:30:25 +00:00
|
|
|
return XR_SUCCESS;
|
2020-10-12 00:09:19 +00:00
|
|
|
}
|