mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2024-12-29 11:06:18 +00:00
u/[session|system]: Add default and optional implementation for system and session
This commit is contained in:
parent
76c630d2bd
commit
f0dbb46cd9
|
@ -75,11 +75,15 @@ add_library(
|
|||
u_pretty_print.h
|
||||
u_prober.c
|
||||
u_prober.h
|
||||
u_session.c
|
||||
u_session.h
|
||||
u_space_overseer.c
|
||||
u_space_overseer.h
|
||||
u_string_list.cpp
|
||||
u_string_list.h
|
||||
u_string_list.hpp
|
||||
u_system.c
|
||||
u_system.h
|
||||
u_system_helpers.c
|
||||
u_system_helpers.h
|
||||
u_template_historybuf.hpp
|
||||
|
|
133
src/xrt/auxiliary/util/u_session.c
Normal file
133
src/xrt/auxiliary/util/u_session.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
// Copyright 2023, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Helper to implement @ref xrt_session.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
|
||||
#include "util/u_system.h"
|
||||
#include "util/u_session.h"
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Helpers.
|
||||
*
|
||||
*/
|
||||
|
||||
static inline struct u_session *
|
||||
u_session(struct xrt_session *xs)
|
||||
{
|
||||
return (struct u_session *)xs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Member functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static xrt_result_t
|
||||
push_event(struct xrt_session_event_sink *xses, const union xrt_session_event *xse)
|
||||
{
|
||||
struct u_session *us = container_of(xses, struct u_session, sink);
|
||||
|
||||
u_session_event_push(us, xse);
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
poll_events(struct xrt_session *xs, union xrt_session_event *out_xse)
|
||||
{
|
||||
struct u_session *us = u_session(xs);
|
||||
|
||||
u_session_event_pop(us, out_xse);
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(struct xrt_session *xs)
|
||||
{
|
||||
struct u_session *us = u_session(xs);
|
||||
|
||||
if (us->usys != NULL) {
|
||||
u_system_remove_session(us->usys, &us->base, &us->sink);
|
||||
}
|
||||
|
||||
free(xs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* 'Exported' functions.
|
||||
*
|
||||
*/
|
||||
|
||||
struct u_session *
|
||||
u_session_create(struct u_system *usys)
|
||||
{
|
||||
struct u_session *us = U_TYPED_CALLOC(struct u_session);
|
||||
|
||||
// xrt_session fields.
|
||||
us->base.poll_events = poll_events;
|
||||
us->base.destroy = destroy;
|
||||
|
||||
// xrt_session_event_sink fields.
|
||||
us->sink.push_event = push_event;
|
||||
|
||||
// u_session fields.
|
||||
XRT_MAYBE_UNUSED int ret = os_mutex_init(&us->events.mutex);
|
||||
assert(ret == 0);
|
||||
us->usys = usys;
|
||||
|
||||
// If we got a u_system.
|
||||
if (usys != NULL) {
|
||||
u_system_add_session(usys, &us->base, &us->sink);
|
||||
}
|
||||
|
||||
return us;
|
||||
}
|
||||
|
||||
void
|
||||
u_session_event_push(struct u_session *us, const union xrt_session_event *xse)
|
||||
{
|
||||
struct u_session_event *use = U_TYPED_CALLOC(struct u_session_event);
|
||||
use->xse = *xse;
|
||||
|
||||
os_mutex_lock(&us->events.mutex);
|
||||
|
||||
// Find the last slot.
|
||||
struct u_session_event **slot = &us->events.ptr;
|
||||
while (*slot != NULL) {
|
||||
slot = &(*slot)->next;
|
||||
}
|
||||
|
||||
*slot = use;
|
||||
|
||||
os_mutex_unlock(&us->events.mutex);
|
||||
}
|
||||
|
||||
void
|
||||
u_session_event_pop(struct u_session *us, union xrt_session_event *out_xse)
|
||||
{
|
||||
U_ZERO(out_xse);
|
||||
out_xse->type = XRT_SESSION_EVENT_NONE;
|
||||
|
||||
os_mutex_lock(&us->events.mutex);
|
||||
|
||||
if (us->events.ptr != NULL) {
|
||||
struct u_session_event *use = us->events.ptr;
|
||||
|
||||
*out_xse = use->xse;
|
||||
us->events.ptr = use->next;
|
||||
free(use);
|
||||
}
|
||||
|
||||
os_mutex_unlock(&us->events.mutex);
|
||||
}
|
91
src/xrt/auxiliary/util/u_session.h
Normal file
91
src/xrt/auxiliary/util/u_session.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2023, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Helper to implement @ref xrt_session.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_session.h"
|
||||
#include "os/os_threading.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
* Struct used by @ref u_session to queue up events.
|
||||
*
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
struct u_session_event
|
||||
{
|
||||
union xrt_session_event xse;
|
||||
struct u_session_event *next;
|
||||
};
|
||||
|
||||
/*!
|
||||
* This is a helper struct that fully implements @ref xrt_session object.
|
||||
*
|
||||
* The use of @ref u_system is optional, but if not used you will need to track
|
||||
* the session and signal it's destruction yourself.
|
||||
*
|
||||
* @ingroup aux_util
|
||||
* @implements xrt_session
|
||||
*/
|
||||
struct u_session
|
||||
{
|
||||
struct xrt_session base;
|
||||
|
||||
//! Pushes events to this session, used to share to other components.
|
||||
struct xrt_session_event_sink sink;
|
||||
|
||||
//! Owning system, optional.
|
||||
struct u_system *usys;
|
||||
|
||||
struct
|
||||
{
|
||||
struct os_mutex mutex;
|
||||
struct u_session_event *ptr;
|
||||
} events;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Create a session, optionally pass in a @ref u_system. If @p usys is not NULL
|
||||
* the call register this session on that system. This function is exposed so
|
||||
* that code can re-use @ref u_session as a base class.
|
||||
*
|
||||
* @public @memberof u_session
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
struct u_session *
|
||||
u_session_create(struct u_system *usys);
|
||||
|
||||
/*!
|
||||
* Push an event to this session. This function is exposed so that code can
|
||||
* re-use @ref u_session as a base class.
|
||||
*
|
||||
*
|
||||
* @public @memberof u_session
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
void
|
||||
u_session_event_push(struct u_session *us, const union xrt_session_event *xse);
|
||||
|
||||
/*!
|
||||
* Pop a single event from this session, if no event is available
|
||||
* then the type of the event will be @ref XRT_SESSION_EVENT_NONE.
|
||||
*
|
||||
* @public @memberof u_session
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
void
|
||||
u_session_event_pop(struct u_session *us, union xrt_session_event *out_xse);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
214
src/xrt/auxiliary/util/u_system.c
Normal file
214
src/xrt/auxiliary/util/u_system.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
// Copyright 2023, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Helper to implement @ref xrt_system.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_compositor.h"
|
||||
|
||||
#include "os/os_threading.h"
|
||||
|
||||
#include "util/u_system.h"
|
||||
#include "util/u_session.h"
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_logging.h"
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Helpers.
|
||||
*
|
||||
*/
|
||||
|
||||
static inline struct u_system *
|
||||
u_system(struct xrt_system *xsys)
|
||||
{
|
||||
return (struct u_system *)xsys;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Member functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static xrt_result_t
|
||||
push_event(struct xrt_session_event_sink *xses, const union xrt_session_event *xse)
|
||||
{
|
||||
struct u_system *usys = container_of(xses, struct u_system, broadcast);
|
||||
|
||||
u_system_broadcast_event(usys, xse);
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
create_session(struct xrt_system *xsys,
|
||||
const struct xrt_session_info *xsi,
|
||||
struct xrt_session **out_xs,
|
||||
struct xrt_compositor_native **out_xcn)
|
||||
{
|
||||
struct u_system *usys = u_system(xsys);
|
||||
xrt_result_t xret = XRT_SUCCESS;
|
||||
|
||||
if (out_xcn != NULL && usys->xsysc == NULL) {
|
||||
U_LOG_E("No system compositor in system, can't create native compositor.");
|
||||
return XRT_ERROR_COMPOSITOR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
struct u_session *us = u_session_create(usys);
|
||||
|
||||
// Skip making a native compositor if not asked for.
|
||||
if (out_xcn == NULL) {
|
||||
goto out_session;
|
||||
}
|
||||
|
||||
xret = xrt_syscomp_create_native_compositor( //
|
||||
usys->xsysc, //
|
||||
xsi, //
|
||||
out_xcn); //
|
||||
if (xret != XRT_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
out_session:
|
||||
*out_xs = &us->base;
|
||||
|
||||
return XRT_SUCCESS;
|
||||
|
||||
err:
|
||||
return xret;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(struct xrt_system *xsys)
|
||||
{
|
||||
struct u_system *usys = u_system(xsys);
|
||||
|
||||
if (usys->sessions.count > 0) {
|
||||
U_LOG_E("Number of sessions not zero, things will crash!");
|
||||
free(usys->sessions.pairs);
|
||||
usys->sessions.pairs = NULL;
|
||||
usys->sessions.count = 0;
|
||||
}
|
||||
|
||||
free(usys);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* 'Exported' functions.
|
||||
*
|
||||
*/
|
||||
|
||||
struct u_system *
|
||||
u_system_create(void)
|
||||
{
|
||||
struct u_system *usys = U_TYPED_CALLOC(struct u_system);
|
||||
|
||||
// xrt_system fields.
|
||||
usys->base.create_session = create_session;
|
||||
usys->base.destroy = destroy;
|
||||
|
||||
// xrt_session_event_sink fields.
|
||||
usys->broadcast.push_event = push_event;
|
||||
|
||||
// u_system fields.
|
||||
XRT_MAYBE_UNUSED int ret = os_mutex_init(&usys->sessions.mutex);
|
||||
assert(ret == 0);
|
||||
|
||||
return usys;
|
||||
}
|
||||
|
||||
void
|
||||
u_system_add_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses)
|
||||
{
|
||||
assert(xs != NULL);
|
||||
assert(xses != NULL);
|
||||
|
||||
os_mutex_lock(&usys->sessions.mutex);
|
||||
|
||||
uint32_t count = usys->sessions.count;
|
||||
|
||||
U_ARRAY_REALLOC_OR_FREE(usys->sessions.pairs, struct u_system_session_pair, count + 1);
|
||||
|
||||
usys->sessions.pairs[count] = (struct u_system_session_pair){xs, xses};
|
||||
usys->sessions.count++;
|
||||
|
||||
os_mutex_unlock(&usys->sessions.mutex);
|
||||
}
|
||||
|
||||
void
|
||||
u_system_remove_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses)
|
||||
{
|
||||
os_mutex_lock(&usys->sessions.mutex);
|
||||
|
||||
uint32_t count = usys->sessions.count;
|
||||
uint32_t dst = 0;
|
||||
|
||||
// Find where the session we are removing is.
|
||||
while (dst < count) {
|
||||
if (usys->sessions.pairs[dst].xs == xs) {
|
||||
break;
|
||||
} else {
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
// Guards against empty array as well as not finding the session.
|
||||
if (dst >= count) {
|
||||
U_LOG_E("Could not find session to remove!");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
// Should not be true with above check.
|
||||
assert(count > 0);
|
||||
|
||||
/*
|
||||
* Do copies if we are not removing the last session,
|
||||
* this also guards against uint32_t::max.
|
||||
*/
|
||||
if (dst < count - 1) {
|
||||
// Copy from every follow down one.
|
||||
for (uint32_t src = dst + 1; src < count; src++, dst++) {
|
||||
usys->sessions.pairs[dst] = usys->sessions.pairs[src];
|
||||
}
|
||||
}
|
||||
|
||||
count--;
|
||||
U_ARRAY_REALLOC_OR_FREE(usys->sessions.pairs, struct u_system_session_pair, count);
|
||||
usys->sessions.count = count;
|
||||
|
||||
unlock:
|
||||
os_mutex_unlock(&usys->sessions.mutex);
|
||||
}
|
||||
|
||||
void
|
||||
u_system_broadcast_event(struct u_system *usys, const union xrt_session_event *xse)
|
||||
{
|
||||
xrt_result_t xret;
|
||||
|
||||
os_mutex_lock(&usys->sessions.mutex);
|
||||
|
||||
for (uint32_t i = 0; i < usys->sessions.count; i++) {
|
||||
xret = xrt_session_event_sink_push(usys->sessions.pairs[i].xses, xse);
|
||||
if (xret != XRT_SUCCESS) {
|
||||
U_LOG_W("Failed to push event to session, dropping.");
|
||||
}
|
||||
}
|
||||
|
||||
os_mutex_unlock(&usys->sessions.mutex);
|
||||
}
|
||||
|
||||
void
|
||||
u_system_set_system_compositor(struct u_system *usys, struct xrt_system_compositor *xsysc)
|
||||
{
|
||||
assert(usys->xsysc == NULL);
|
||||
|
||||
usys->xsysc = xsysc;
|
||||
}
|
138
src/xrt/auxiliary/util/u_system.h
Normal file
138
src/xrt/auxiliary/util/u_system.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Copyright 2023, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Helper to implement @ref xrt_system.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_system.h"
|
||||
#include "xrt/xrt_session.h"
|
||||
#include "os/os_threading.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct xrt_session;
|
||||
struct xrt_session_event_sink;
|
||||
union xrt_session_event;
|
||||
|
||||
/*!
|
||||
* A pair of @ref xrt_session and @ref xrt_session_event_sink that has been
|
||||
* registered to this system, used to multiplex events to all sessions.
|
||||
*
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
struct u_system_session_pair
|
||||
{
|
||||
struct xrt_session *xs;
|
||||
struct xrt_session_event_sink *xses;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A helper to implement a @ref xrt_system, takes care of multiplexing events
|
||||
* to sessions.
|
||||
*
|
||||
* @ingroup aux_util
|
||||
* @implements xrt_system
|
||||
*/
|
||||
struct u_system
|
||||
{
|
||||
struct xrt_system base;
|
||||
|
||||
//! Pushes events to all sessions created from this system.
|
||||
struct xrt_session_event_sink broadcast;
|
||||
|
||||
struct
|
||||
{
|
||||
struct os_mutex mutex;
|
||||
|
||||
//! Number of session and event sink pairs.
|
||||
uint32_t count;
|
||||
//! Array of session and event sink pairs.
|
||||
struct u_system_session_pair *pairs;
|
||||
} sessions;
|
||||
|
||||
/*!
|
||||
* Used to implement @ref xrt_system::create_session, can be NULL. This
|
||||
* field should be set with @ref u_system_set_system_compositor.
|
||||
*/
|
||||
struct xrt_system_compositor *xsysc;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Create a @ref u_system.
|
||||
*
|
||||
* @public @memberof u_system
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
struct u_system *
|
||||
u_system_create(void);
|
||||
|
||||
/*!
|
||||
* Add a @ref xrt_session to be tracked and to receive multiplexed events.
|
||||
*
|
||||
* @public @memberof u_system
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
void
|
||||
u_system_add_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses);
|
||||
|
||||
/*!
|
||||
* Remove a @ref xrt_session from tracking, it will no longer receive events,
|
||||
* the given @p xses needs to match when it was added.
|
||||
*
|
||||
* @public @memberof u_system
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
void
|
||||
u_system_remove_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses);
|
||||
|
||||
/*!
|
||||
* Broadcast event to all sessions under this system.
|
||||
*
|
||||
* @public @memberof u_system
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
void
|
||||
u_system_broadcast_event(struct u_system *usys, const union xrt_session_event *xse);
|
||||
|
||||
/*!
|
||||
* Set the system compositor, used in the @ref xrt_system_create_session call.
|
||||
*
|
||||
* @public @memberof u_system
|
||||
* @ingroup aux_util
|
||||
*/
|
||||
void
|
||||
u_system_set_system_compositor(struct u_system *usys, struct xrt_system_compositor *xsysc);
|
||||
|
||||
/*!
|
||||
* Destroy an @ref u_system_create allocated @ref u_system - helper function.
|
||||
*
|
||||
* @param[in,out] usys_ptr A pointer to the @ref u_system_create allocated
|
||||
* struct pointer.
|
||||
*
|
||||
* Will destroy the system devices if @p *usys_ptr is not NULL. Will then set
|
||||
* @p *usys_ptr to NULL.
|
||||
*
|
||||
* @public @memberof u_system
|
||||
*/
|
||||
static inline void
|
||||
u_system_destroy(struct u_system **usys_ptr)
|
||||
{
|
||||
struct u_system *usys = *usys_ptr;
|
||||
if (usys == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
*usys_ptr = NULL;
|
||||
usys->base.destroy(&usys->base);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in a new issue