Commit a958fd28 authored by Ryan Pavlik's avatar Ryan Pavlik

st/oxr: Provide handle lifecycle management

parent 1a85fef0
......@@ -19,6 +19,7 @@ set(OXR_SOURCE_FILES
oxr/oxr_api_system.c
oxr/oxr_api_verify.h
oxr/oxr_event.cpp
oxr/oxr_handle_base.c
oxr/oxr_instance.c
oxr/oxr_logger.cpp
oxr/oxr_logger.h
......
......@@ -86,7 +86,7 @@ oxr_xrDestroyInstance(XrInstance instance)
OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
"xrDestroyInstance");
return oxr_instance_destroy(&log, inst);
return oxr_handle_destroy(&log, &inst->handle);
}
XrResult
......
......@@ -60,7 +60,7 @@ oxr_xrDestroySession(XrSession session)
OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
"xrDestroySession");
return oxr_session_destroy(&log, sess);
return oxr_handle_destroy(&log, &sess->handle);
}
XrResult
......
......@@ -122,5 +122,5 @@ oxr_xrDestroySpace(XrSpace space)
struct oxr_logger log;
OXR_VERIFY_SPACE_AND_INIT_LOG(&log, space, spc, "xrDestroySpace");
return oxr_space_destroy(&log, spc);
return oxr_handle_destroy(&log, &spc->handle);
}
......@@ -76,7 +76,7 @@ oxr_xrDestroySwapchain(XrSwapchain swapchain)
OXR_VERIFY_SWAPCHAIN_AND_INIT_LOG(&log, swapchain, sc,
"xrDestroySwapchain");
return sc->destroy(&log, sc);
return oxr_handle_destroy(&log, &sc->handle);
}
XrResult
......
......@@ -23,7 +23,7 @@ extern "C" {
"(" #thing " == NULL)"); \
} \
new_thing = (__typeof__(new_thing))thing; \
if (new_thing->debug != OXR_XR_DEBUG_##THING) { \
if (new_thing->handle.debug != OXR_XR_DEBUG_##THING) { \
return oxr_error(log, XR_ERROR_HANDLE_INVALID, \
"(" #thing " == %p)", \
(void*)new_thing); \
......@@ -38,7 +38,7 @@ extern "C" {
"(" #arg " == NULL)"); \
} \
new_arg = (__typeof__(new_arg))arg; \
if (new_arg->debug != OXR_XR_DEBUG_##THING) { \
if (new_arg->handle.debug != OXR_XR_DEBUG_##THING) { \
return oxr_error(log, XR_ERROR_HANDLE_INVALID, \
"(" #arg " == %p)", (void*)new_arg); \
} \
......
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Contains handle-related functions and defines only required in a few
* locations.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup oxr_main
*/
#pragma once
#include "oxr_objects.h"
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
*
* oxr_handle_base.c
*
*/
/*!
* Initialize a handle holder, and if a parent is specified, update its child
* list to include this handle.
*/
XrResult
oxr_handle_init(struct oxr_logger *log,
struct oxr_handle_base *hb,
uint64_t debug,
oxr_handle_destroyer destroy,
struct oxr_handle_base *parent);
/*!
* Allocate some memory for use as a handle, and initialize it as a handle.
*
* Mainly for internal use - use OXR_ALLOCATE_HANDLE instead which wraps this.
*/
XrResult
oxr_handle_allocate_and_init(struct oxr_logger *log,
size_t size,
uint64_t debug,
oxr_handle_destroyer destroy,
struct oxr_handle_base *parent,
void **out);
/*!
* Allocates memory for a handle and evaluates to an XrResult.
*
* @param LOG pointer to struct oxr_logger
* @param OUT the pointer to handle struct type you already created.
* @param DEBUG Magic per-type debugging constant
* @param DESTROY Handle destructor function
* @param PARENT a parent handle, if any
*
* Use when you want to do something other than immediately returning in case of
* failure. If returning immediately is OK, see OXR_ALLOCATE_HANDLE_OR_RETURN().
*/
#define OXR_ALLOCATE_HANDLE(LOG, OUT, DEBUG, DESTROY, PARENT) \
oxr_handle_allocate_and_init(LOG, sizeof(*OUT), DEBUG, DESTROY, \
PARENT, (void **)&OUT)
/*!
* Allocate memory for a handle, returning in case of failure.
*
* @param LOG pointer to struct oxr_logger
* @param OUT the pointer to handle struct type you already created.
* @param DEBUG Magic per-type debugging constant
* @param DESTROY Handle destructor function
* @param PARENT a parent handle, if any
*
* Will return an XrResult from the current function if something fails.
* If that's not OK, see OXR_ALLOCATE_HANDLE().
*/
#define OXR_ALLOCATE_HANDLE_OR_RETURN(LOG, OUT, DEBUG, DESTROY, PARENT) \
do { \
XrResult allocResult = \
OXR_ALLOCATE_HANDLE(LOG, OUT, DEBUG, DESTROY, PARENT); \
if (allocResult != XR_SUCCESS) { \
return allocResult; \
} \
} while (0)
#ifdef __cplusplus
}
#endif
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Implementation
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
#include "util/u_debug.h"
#include "oxr_objects.h"
#include "oxr_logger.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
DEBUG_GET_ONCE_BOOL_OPTION(lifecycle_verbose, "OXR_LIFECYCLE_VERBOSE", false)
#define HANDLE_LIFECYCLE_LOG(log, ...) \
if (debug_get_bool_option_lifecycle_verbose()) { \
oxr_log(log, " Handle Lifecycle: " __VA_ARGS__); \
}
const char *
oxr_handle_state_to_string(enum oxr_handle_state state)
{
switch (state) {
case OXR_HANDLE_STATE_UNINITIALIZED: return "UNINITIALIZED";
case OXR_HANDLE_STATE_LIVE: return "LIVE";
case OXR_HANDLE_STATE_DESTROYED: return "DESTROYED";
default: return "<UNKNOWN>";
}
}
XrResult
oxr_handle_init(struct oxr_logger *log,
struct oxr_handle_base *hb,
uint64_t debug,
oxr_handle_destroyer destroy,
struct oxr_handle_base *parent)
{
assert(log != NULL);
assert(hb != NULL);
assert(destroy != NULL);
assert(debug != 0);
HANDLE_LIFECYCLE_LOG(
log, "[init %p] Initializing handle, parent handle = %p",
(void *)hb, (void *)parent);
hb->state = OXR_HANDLE_STATE_UNINITIALIZED;
if (parent != NULL) {
if (parent->state != OXR_HANDLE_STATE_LIVE) {
return oxr_error(
log, XR_ERROR_RUNTIME_FAILURE,
" Handle %p given parent %p in invalid state: %s",
(void *)parent, (void *)hb,
oxr_handle_state_to_string(parent->state));
}
bool placed = false;
for (int i = 0; i < XRT_MAX_HANDLE_CHILDREN; ++i) {
if (parent->children[i] == NULL) {
HANDLE_LIFECYCLE_LOG(log,
"[init %p] Assigned to "
"child slot %d in parent",
(void *)hb, i);
parent->children[i] = hb;
placed = true;
break;
}
}
if (!placed) {
return oxr_error(log, XR_ERROR_LIMIT_REACHED,
" parent handle has no more room for "
"child handles");
}
}
memset(hb, 0, sizeof(*hb));
hb->debug = debug;
hb->parent = parent;
hb->state = OXR_HANDLE_STATE_LIVE;
hb->destroy = destroy;
return XR_SUCCESS;
}
XrResult
oxr_handle_allocate_and_init(struct oxr_logger *log,
size_t size,
uint64_t debug,
oxr_handle_destroyer destroy,
struct oxr_handle_base *parent,
void **out)
{
/*
* This bare calloc call, taking a size, not a type, is why this
* function isn't recommended for direct use.
*/
struct oxr_handle_base *hb = (struct oxr_handle_base *)calloc(1, size);
XrResult result = oxr_handle_init(log, hb, debug, destroy, parent);
if (result != XR_SUCCESS) {
free(hb);
return result;
}
*out = (void *)hb;
return result;
}
/*!
* This is the actual recursive call that destroys handles.
*
* oxr_handle_destroy wraps this to provide some extra output and start `level`
* at 0. `level`, which is reported in debug output, is the current depth of
* recursion.
*/
static XrResult
oxr_handle_do_destroy(struct oxr_logger *log,
struct oxr_handle_base *hb,
int level)
{
HANDLE_LIFECYCLE_LOG(log,
"[%d: destroying %p] Destroying handle and all "
"contained handles (recursively)",
level, (void *)hb);
/* Remove from parent, if any. */
if (hb->parent != NULL) {
bool found = false;
struct oxr_handle_base *parent = hb->parent;
for (int i = 0; i < XRT_MAX_HANDLE_CHILDREN; ++i) {
if (parent->children[i] == hb) {
HANDLE_LIFECYCLE_LOG(
log,
"[%d: destroying %p] Removing handle from "
"child slot %d in parent %p",
level, (void *)hb, i, (void *)hb->parent);
parent->children[i] = NULL;
found = true;
break;
}
}
if (!found) {
return oxr_error(
log, XR_ERROR_RUNTIME_FAILURE,
" parent handle does not refer to this handle");
}
/* clear parent pointer */
hb->parent = NULL;
}
/* Destroy child handles */
for (size_t i = 0; i < XRT_MAX_HANDLE_CHILDREN; ++i) {
struct oxr_handle_base *child = hb->children[i];
if (child != NULL) {
XrResult result =
oxr_handle_do_destroy(log, child, level + 1);
if (result != XR_SUCCESS) {
return result;
}
}
}
/* Destroy self */
HANDLE_LIFECYCLE_LOG(
log, "[%d: destroying %p] Calling handle object destructor", level,
(void *)hb);
hb->state = OXR_HANDLE_STATE_DESTROYED;
XrResult result = hb->destroy(log, hb);
if (result != XR_SUCCESS) {
return result;
}
HANDLE_LIFECYCLE_LOG(log, "[%d: destroying %p] Done", level,
(void *)hb);
return XR_SUCCESS;
}
XrResult
oxr_handle_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
{
assert(log != NULL);
assert(hb != NULL);
HANDLE_LIFECYCLE_LOG(
log, "[~: destroying %p] oxr_handle_destroy starting", (void *)hb);
XrResult result = oxr_handle_do_destroy(log, hb, 0);
HANDLE_LIFECYCLE_LOG(
log, "[~: destroying %p] oxr_handle_destroy finished", (void *)hb);
return result;
}
......@@ -21,6 +21,7 @@
#include "oxr_objects.h"
#include "oxr_logger.h"
#include "oxr_handle.h"
DEBUG_GET_ONCE_FLOAT_OPTION(lfov_left, "OXR_OVERRIDE_LFOV_LEFT", 0.0f)
DEBUG_GET_ONCE_FLOAT_OPTION(lfov_right, "OXR_OVERRIDE_LFOV_RIGHT", 0.0f)
......@@ -33,13 +34,40 @@ radtodeg_for_display(float radians)
return (int32_t)(radians * 180 * M_1_PI);
}
static XrResult
oxr_instance_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
{
struct oxr_instance *inst = (struct oxr_instance *)hb;
struct xrt_prober *prober = inst->prober;
struct xrt_device *dev = inst->system.device;
if (dev != NULL) {
dev->destroy(dev);
inst->system.device = NULL;
}
if (prober != NULL) {
prober->destroy(prober);
inst->prober = NULL;
}
time_state_destroy(inst->timekeeping);
inst->timekeeping = NULL;
free(inst);
return XR_SUCCESS;
}
XrResult
oxr_instance_create(struct oxr_logger *log,
const XrInstanceCreateInfo *createInfo,
struct oxr_instance **out_instance)
{
struct oxr_instance *inst = U_TYPED_CALLOC(struct oxr_instance);
inst->debug = OXR_XR_DEBUG_INSTANCE;
struct oxr_instance *inst = NULL;
OXR_ALLOCATE_HANDLE_OR_RETURN(log, inst, OXR_XR_DEBUG_INSTANCE,
oxr_instance_destroy, NULL);
inst->prober = xrt_create_prober();
struct xrt_device *dev =
......@@ -111,29 +139,6 @@ oxr_instance_create(struct oxr_logger *log,
return XR_SUCCESS;
}
XrResult
oxr_instance_destroy(struct oxr_logger *log, struct oxr_instance *inst)
{
struct xrt_prober *prober = inst->prober;
struct xrt_device *dev = inst->system.device;
if (dev != NULL) {
dev->destroy(dev);
inst->system.device = NULL;
}
if (prober != NULL) {
prober->destroy(prober);
inst->prober = NULL;
}
time_state_destroy(inst->timekeeping);
inst->timekeeping = NULL;
free(inst);
return XR_SUCCESS;
}
XrResult
oxr_instance_get_properties(struct oxr_logger *log,
......
......@@ -2,7 +2,7 @@
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Contains the instance struct that a lot of things hangs of on.
* @brief Contains the instance struct that a lot of things hang from.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup oxr_main
*/
......@@ -64,8 +64,50 @@ struct oxr_swapchain;
struct oxr_space;
struct oxr_action_set;
struct oxr_action;
struct oxr_handle_base;
#define XRT_MAX_HANDLE_CHILDREN 256
struct time_state;
typedef XrResult (*oxr_handle_destroyer)(struct oxr_logger *log,
struct oxr_handle_base *hb);
/*!
* State of a handle base, to reduce likelyhood of going "boom" on
* out-of-order destruction or other unsavory behavior.
*/
enum oxr_handle_state
{
/*! State during/before oxr_handle_init, or after failure */
OXR_HANDLE_STATE_UNINITIALIZED = 0,
/*! State after successful oxr_handle_init */
OXR_HANDLE_STATE_LIVE,
/*! State after successful oxr_handle_destroy */
OXR_HANDLE_STATE_DESTROYED,
};
/*
*
* oxr_handle_base.c
*
*/
/*!
* Destroy the handle's object, as well as all child handles recursively.
*
* This should be how all handle-associated objects are destroyed.
*/
XrResult
oxr_handle_destroy(struct oxr_logger *log, struct oxr_handle_base *hb);
/*!
* Returns a human-readable label for a handle state.
*/
const char *
oxr_handle_state_to_string(enum oxr_handle_state state);
/*
*
......@@ -87,9 +129,6 @@ oxr_instance_create(struct oxr_logger *log,
const XrInstanceCreateInfo *createInfo,
struct oxr_instance **out_inst);
XrResult
oxr_instance_destroy(struct oxr_logger *log, struct oxr_instance *inst);
XrResult
oxr_instance_get_properties(struct oxr_logger *log,
struct oxr_instance *inst,
......@@ -130,8 +169,13 @@ oxr_session_create(struct oxr_logger *log,
XrStructureType *next,
struct oxr_session **out_session);
/*!
* Internal destructor - not to be used directly!
*
* Use oxr_handle_destroy() to destroy a session.
*/
XrResult
oxr_session_destroy(struct oxr_logger *log, struct oxr_session *sess);
oxr_session_destroy(struct oxr_logger *log, struct oxr_handle_base *hb);
XrResult
oxr_session_enumerate_formats(struct oxr_logger *log,
......@@ -196,15 +240,17 @@ oxr_space_to_openxr(struct oxr_space *spc)
return (XrSpace)spc;
}
XrResult
oxr_space_action_create(struct oxr_logger *log,
struct oxr_action *act,
const XrActionSpaceCreateInfo *createInfo,
struct oxr_space **out_space);
XrResult
oxr_space_reference_create(struct oxr_logger *log,
struct oxr_session *sess,
const XrReferenceSpaceCreateInfo *createInfo,
struct oxr_space **out_space);
XrResult
oxr_space_destroy(struct oxr_logger *log, struct oxr_space *spc);
XrResult
oxr_space_locate(struct oxr_logger *log,
struct oxr_space *spc,
......@@ -245,6 +291,7 @@ oxr_create_swapchain(struct oxr_logger *,
/*
*
* oxr_system.c
*
*/
......@@ -399,6 +446,39 @@ oxr_swapchain_vk_create(struct oxr_logger *,
*
*/
/*!
* Used to hold diverse child handles and ensure orderly destruction.
*
* Each object referenced by an OpenXR handle should have one of these as its
* first element.
*/
struct oxr_handle_base
{
//! Magic (per-handle-type) value for debugging.
uint64_t debug;
/*!
* Pointer to this object's parent handle holder, if any.
*/
struct oxr_handle_base *parent;
/*!
* Array of children, if any.
*/
struct oxr_handle_base *children[XRT_MAX_HANDLE_CHILDREN];
/*!
* Current handle state.
*/
enum oxr_handle_state state;
/*!
* Destroy the object this handle refers to.
*/
oxr_handle_destroyer destroy;
};
/*!
* Single or multiple devices grouped together to form a system that sessions
* can be created from. Might need to open devices in order to get all
......@@ -426,7 +506,9 @@ struct oxr_system
*/
struct oxr_instance
{
uint64_t debug;
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
struct xrt_prober *prober;
// Enabled extensions
......@@ -451,7 +533,8 @@ struct oxr_instance
*/
struct oxr_session
{
uint64_t debug;
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
struct oxr_system *sys;
struct xrt_compositor *compositor;
......@@ -481,8 +564,8 @@ struct oxr_session
*/
struct oxr_space
{
//! Magic value for debugging.
uint64_t debug;
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
//! Onwer of this space.
struct oxr_session *sess;
......@@ -504,8 +587,8 @@ struct oxr_space
*/
struct oxr_swapchain
{
//! Magic value for debugging.
uint64_t debug;
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
//! Onwer of this swapchain.
struct oxr_session *sess;
......@@ -544,8 +627,8 @@ struct oxr_swapchain
*/
struct oxr_action_set
{
//! Magic value for debugging.
uint64_t debug;
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
//! Onwer of this messenger.
struct oxr_session *sess;
......@@ -558,8 +641,8 @@ struct oxr_action_set
*/
struct oxr_action
{
//! Magic value for debugging.
uint64_t debug;
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
//! Onwer of this messenger.
struct oxr_action_set *act_set;
......@@ -572,8 +655,8 @@ struct oxr_action
*/
struct oxr_debug_messenger
{
//! Magic value for debugging.
uint64_t debug;
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
//! Onwer of this messenger.
struct oxr_instance *inst;
......
......@@ -23,6 +23,7 @@
#include "oxr_objects.h"
#include "oxr_logger.h"
#include "oxr_two_call.h"
#include "oxr_handle.h"
DEBUG_GET_ONCE_BOOL_OPTION(views, "OXR_DEBUG_VIEWS", false)
......@@ -482,8 +483,9 @@ oxr_session_create(struct oxr_logger *log,
if (sys->inst->headless && next == NULL) {
ret = XR_SUCCESS;
sess = U_TYPED_CALLOC(struct oxr_session);
sess->debug = OXR_XR_DEBUG_SESSION;
OXR_ALLOCATE_HANDLE_OR_RETURN(log, sess, OXR_XR_DEBUG_SESSION,
oxr_session_destroy,
&sys->inst->handle);
sess->sys = sys;
sess->compositor = NULL;
sess->create_swapchain = NULL;
......@@ -525,8 +527,9 @@ oxr_session_create(struct oxr_logger *log,
}
XrResult
oxr_session_destroy(struct oxr_logger *log, struct oxr_session *sess)
oxr_session_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
{
struct oxr_session *sess = (struct oxr_session *)hb;
if (sess->compositor != NULL) {
sess->compositor->destroy(sess->compositor);
}
......
......@@ -17,6 +17,7 @@
#include "oxr_objects.h"
#include "oxr_logger.h"
#include "oxr_two_call.h"
#include "oxr_handle.h"
XrResult
......@@ -34,9 +35,14 @@ oxr_session_create_gl_xlib(struct oxr_logger *log,
" failed create a compositor");
}
struct oxr_session *sess = U_TYPED_CALLOC(struct oxr_session);
sess->debug = OXR_XR_DEBUG_SESSION;
struct oxr_session *sess = NULL;
XrResult result =
OXR_ALLOCATE_HANDLE(log, sess, OXR_XR_DEBUG_SESSION,
oxr_session_destroy, &sys->inst->handle);
if (result != XR_SUCCESS) {
xcgl->base.destroy(&xcgl->base);
return result;
}
sess->sys = sys;
sess->compositor = &xcgl->base;
sess->create_swapchain = oxr_swapchain_gl_create;
......
......@@ -17,6 +17,7 @@
#include "oxr_objects.h"
#include "oxr_logger.h"
#include "oxr_two_call.h"
#include "oxr_handle.h"
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
......@@ -38,8 +39,14 @@ oxr_session_create_vk(struct oxr_logger *log,
" failed create a compositor");
}
struct oxr_session *sess = U_TYPED_CALLOC(struct oxr_session);
sess->debug = OXR_XR_DEBUG_SESSION;
struct oxr_session *sess = NULL;
XrResult result =
OXR_ALLOCATE_HANDLE(log, sess, OXR_XR_DEBUG_SESSION,