diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c index 64f8a6ee095fdd89f34bff07f18794b0a3ca8064..7f8c413a2ecbbbeee6d8b731005c5ac507abe82a 100644 --- a/src/xrt/compositor/client/comp_gl_client.c +++ b/src/xrt/compositor/client/comp_gl_client.c @@ -92,6 +92,16 @@ client_gl_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index) * */ +static xrt_result_t +client_gl_compositor_prepare_session(struct xrt_compositor *xc, + struct xrt_overlay_info *oi) +{ + struct client_gl_compositor *c = client_gl_compositor(xc); + // Pipe down call into fd compositor. + return xrt_comp_prepare_session(&c->xcfd->base, oi); +} + + static xrt_result_t client_gl_compositor_begin_session(struct xrt_compositor *xc, enum xrt_view_type type) @@ -308,6 +318,14 @@ client_gl_swapchain_create(struct xrt_compositor *xc, return &sc->base.base; } +static void +client_gl_compositor_poll_events(struct xrt_compositor *xc, + struct xrt_ipc_event *e) +{ + struct client_gl_compositor *c = client_gl_compositor(xc); + c->xcfd->base.poll_events(&c->xcfd->base, e); +} + static void client_gl_compositor_destroy(struct xrt_compositor *xc) { @@ -320,6 +338,7 @@ client_gl_compositor_init(struct client_gl_compositor *c, client_gl_get_procaddr get_gl_procaddr) { c->base.base.create_swapchain = client_gl_swapchain_create; + c->base.base.prepare_session = client_gl_compositor_prepare_session; c->base.base.begin_session = client_gl_compositor_begin_session; c->base.base.end_session = client_gl_compositor_end_session; c->base.base.wait_frame = client_gl_compositor_wait_frame; @@ -331,6 +350,7 @@ client_gl_compositor_init(struct client_gl_compositor *c, c->base.base.layer_quad = client_gl_compositor_layer_quad; c->base.base.layer_commit = client_gl_compositor_layer_commit; c->base.base.destroy = client_gl_compositor_destroy; + c->base.base.poll_events = client_gl_compositor_poll_events; c->xcfd = xcfd; // Passthrough our formats from the fd compositor to the client. diff --git a/src/xrt/compositor/client/comp_vk_client.c b/src/xrt/compositor/client/comp_vk_client.c index 8c4854d2891433e2ec13073cd7c508471bff174a..a54d27e5fd6faaa5beda477eed70406479517f9d 100644 --- a/src/xrt/compositor/client/comp_vk_client.c +++ b/src/xrt/compositor/client/comp_vk_client.c @@ -139,6 +139,13 @@ client_vk_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index) * Compositor functions. * */ +static void +client_vk_compositor_poll_events(struct xrt_compositor *xc, + struct xrt_ipc_event *e) +{ + struct client_vk_compositor *c = client_vk_compositor(xc); + c->xcfd->base.poll_events(&c->xcfd->base, e); +} static void client_vk_compositor_destroy(struct xrt_compositor *xc) @@ -159,6 +166,15 @@ client_vk_compositor_destroy(struct xrt_compositor *xc) free(c); } +static xrt_result_t +client_vk_compositor_prepare_session(struct xrt_compositor *xc, + struct xrt_overlay_info *oi) +{ + struct client_vk_compositor *c = client_vk_compositor(xc); + // Pipe down call into fd compositor. + return xrt_comp_prepare_session(&c->xcfd->base, oi); +} + static xrt_result_t client_vk_compositor_begin_session(struct xrt_compositor *xc, enum xrt_view_type type) @@ -436,6 +452,7 @@ client_vk_compositor_create(struct xrt_compositor_fd *xcfd, U_TYPED_CALLOC(struct client_vk_compositor); c->base.base.create_swapchain = client_vk_swapchain_create; + c->base.base.prepare_session = client_vk_compositor_prepare_session; c->base.base.begin_session = client_vk_compositor_begin_session; c->base.base.end_session = client_vk_compositor_end_session; c->base.base.wait_frame = client_vk_compositor_wait_frame; @@ -447,6 +464,8 @@ client_vk_compositor_create(struct xrt_compositor_fd *xcfd, c->base.base.layer_quad = client_vk_compositor_layer_quad; c->base.base.layer_commit = client_vk_compositor_layer_commit; c->base.base.destroy = client_vk_compositor_destroy; + c->base.base.poll_events = client_vk_compositor_poll_events; + c->xcfd = xcfd; // passthrough our formats from the fd compositor to the client for (uint32_t i = 0; i < xcfd->base.num_formats; i++) { diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index c13464501c51c42c39d1797a6592625bc03ce6f0..89c3a79234b79e488ddde2078de857a72cf5259d 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -386,12 +386,13 @@ struct xrt_compositor * * This function is very much WIP. */ - void (*poll_events)(struct xrt_compositor *xc, uint64_t *WIP); + void (*poll_events)(struct xrt_compositor *xc, struct xrt_ipc_event *e); /*! * This function is implicit in the OpenXR spec but made explicit here. */ - void (*prepare_session)(struct xrt_compositor *xc); + xrt_result_t (*prepare_session)(struct xrt_compositor *xc, + struct xrt_overlay_info *oi); /*! * See xrBeginSession. @@ -516,9 +517,9 @@ xrt_comp_create_swapchain(struct xrt_compositor *xc, * @public @memberof xrt_compositor */ static inline void -xrt_comp_poll_events(struct xrt_compositor *xc, uint64_t *WIP) +xrt_comp_poll_events(struct xrt_compositor *xc, struct xrt_ipc_event *e) { - xc->poll_events(xc, WIP); + xc->poll_events(xc, e); } /*! @@ -528,10 +529,10 @@ xrt_comp_poll_events(struct xrt_compositor *xc, uint64_t *WIP) * * @public @memberof xrt_compositor */ -static inline void -xrt_comp_prepare_session(struct xrt_compositor *xc) +static inline xrt_result_t +xrt_comp_prepare_session(struct xrt_compositor *xc, struct xrt_overlay_info *oi) { - xc->prepare_session(xc); + return xc->prepare_session(xc, oi); } /*! diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h index 121e6a5450d19da86b9e1de490625179102a2f06..7b5f33c640b13a3e0463929346a13a38236eca70 100644 --- a/src/xrt/include/xrt/xrt_defines.h +++ b/src/xrt/include/xrt/xrt_defines.h @@ -18,6 +18,7 @@ extern "C" { #endif +#define XRT_EVENT_SIZE 256 /*! * A base class for reference counted objects. @@ -29,6 +30,68 @@ struct xrt_reference uint32_t count; }; +/*! + * Overlay extension data - sent when creating an session + * + * @ingroup xrt_iface + */ +struct xrt_overlay_info +{ + bool is_overlay; + uint64_t flags; + uint32_t z_order; +}; + +#define XRT_MAX_APPLICATION_NAME_SIZE 128 + +struct xrt_instance_info +{ + char application_name[XRT_MAX_APPLICATION_NAME_SIZE]; + pid_t pid; +}; + +typedef enum xrt_ipc_event_type +{ + XRT_EVENT_OVERLAY, + XRT_EVENT_CLIENT_STATE +} xrt_event_type; + +struct xrt_client_state_event +{ + uint8_t active; + uint8_t visible; + uint8_t focused; +}; + +struct xrt_overlay_event +{ + bool visible; +}; + +struct xrt_ipc_event +{ + bool valid; + xrt_event_type type; + uint8_t data[XRT_EVENT_SIZE]; +}; + +/*! + * Client data - used to store per-client state information in the ipc + * server/compositor + * + * @ingroup xrt_iface + */ +struct xrt_client_state +{ + bool primary_application; + bool session_active; + bool session_visible; + bool session_focused; + bool session_overlay; + uint32_t z_order; + struct xrt_instance_info info; +}; + /*! * Which blend mode does the device support, used as both a bitfield and value. * diff --git a/src/xrt/include/xrt/xrt_instance.h b/src/xrt/include/xrt/xrt_instance.h index 33bd792d6159bf76c5ba7a74bf510c98992df1cb..4b9178499de26ab6fb29547c2a2d93ff7cae46ce 100644 --- a/src/xrt/include/xrt/xrt_instance.h +++ b/src/xrt/include/xrt/xrt_instance.h @@ -10,6 +10,8 @@ #pragma once #include "xrt/xrt_compiler.h" +#include "xrt/xrt_defines.h" + #ifdef __cplusplus extern "C" { @@ -20,6 +22,8 @@ struct xrt_prober; struct xrt_device; struct xrt_compositor_fd; + + /*! * @ingroup xrt_iface * @{ @@ -131,6 +135,7 @@ struct xrt_instance /*! * @} */ + struct xrt_instance_info instance_info; }; /*! @@ -220,7 +225,8 @@ xrt_instance_destroy(struct xrt_instance **xinst_ptr) * @relates xrt_instance */ int -xrt_instance_create(struct xrt_instance **out_xinst); +xrt_instance_create(struct xrt_instance **out_xinst, + struct xrt_instance_info *ii); /*! * @} diff --git a/src/xrt/ipc/CMakeLists.txt b/src/xrt/ipc/CMakeLists.txt index 1f8f3240fa6cb1b8a0e9cd0364dcb63901b9a9cc..c998822365b01e36a4f3544cf9ff1b7fcde8c6b4 100644 --- a/src/xrt/ipc/CMakeLists.txt +++ b/src/xrt/ipc/CMakeLists.txt @@ -38,6 +38,7 @@ add_library(ipc_client STATIC ) target_include_directories(ipc_client INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} ) target_include_directories(ipc_client PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} @@ -66,6 +67,7 @@ add_library(ipc_server STATIC target_include_directories(ipc_server INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} ) target_include_directories(ipc_server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../compositor diff --git a/src/xrt/ipc/ipc_client_compositor.c b/src/xrt/ipc/ipc_client_compositor.c index 79acfe98b2135104e3006ec5ec7eb90d4fe918e5..813c9ef8115c3d75c4134008896638760f8dca3f 100644 --- a/src/xrt/ipc/ipc_client_compositor.c +++ b/src/xrt/ipc/ipc_client_compositor.c @@ -224,6 +224,30 @@ ipc_compositor_swapchain_create(struct xrt_compositor *xc, return &ics->base.base; } +static xrt_result_t +ipc_compositor_prepare_session(struct xrt_compositor *xc, + struct xrt_overlay_info *oi) +{ + struct ipc_client_compositor *icc = ipc_client_compositor(xc); + + IPC_SPEW(icc->ipc_c, "IPC: compositor create session"); + + IPC_CALL_CHK(ipc_call_session_create(icc->ipc_c, oi)); + return res; +} + +static void +ipc_compositor_poll_events(struct xrt_compositor *xc, struct xrt_ipc_event *e) +{ + struct ipc_client_compositor *icc = ipc_client_compositor(xc); + + IPC_SPEW(icc->ipc_c, "IPC: polling for events"); + + struct xrt_ipc_event event; + IPC_CALL_CHK(ipc_call_compositor_poll_events(icc->ipc_c, &event)); + memcpy(e, &event, sizeof(struct xrt_ipc_event)); +} + static xrt_result_t ipc_compositor_begin_session(struct xrt_compositor *xc, enum xrt_view_type view_type) @@ -445,6 +469,7 @@ ipc_client_compositor_create(ipc_connection_t *ipc_c, U_TYPED_CALLOC(struct ipc_client_compositor); c->base.base.create_swapchain = ipc_compositor_swapchain_create; + c->base.base.prepare_session = ipc_compositor_prepare_session; c->base.base.begin_session = ipc_compositor_begin_session; c->base.base.end_session = ipc_compositor_end_session; c->base.base.wait_frame = ipc_compositor_wait_frame; @@ -456,6 +481,7 @@ ipc_client_compositor_create(ipc_connection_t *ipc_c, c->base.base.layer_quad = ipc_compositor_layer_quad; c->base.base.layer_commit = ipc_compositor_layer_commit; c->base.base.destroy = ipc_compositor_destroy; + c->base.base.poll_events = ipc_compositor_poll_events; c->ipc_c = ipc_c; // fetch our format list on client compositor construction diff --git a/src/xrt/ipc/ipc_client_instance.c b/src/xrt/ipc/ipc_client_instance.c index 98ea73b72af37065f169172f9285e695bb860ce1..7ea04c82def610a17c8ec058276fdd3f47d95be8 100644 --- a/src/xrt/ipc/ipc_client_instance.c +++ b/src/xrt/ipc/ipc_client_instance.c @@ -183,7 +183,8 @@ ipc_client_instance_destroy(struct xrt_instance *xinst) * @public @memberof ipc_instance */ int -ipc_instance_create(struct xrt_instance **out_xinst) +ipc_instance_create(struct xrt_instance **out_xinst, + struct xrt_instance_info *i_info) { struct ipc_client_instance *ii = U_TYPED_CALLOC(struct ipc_client_instance); @@ -223,6 +224,15 @@ ipc_instance_create(struct xrt_instance **out_xinst) return -1; } + struct xrt_client_state desc = {0}; + desc.info = *i_info; + r = ipc_call_system_set_client_info(&ii->ipc_c, &desc); + if (r != XRT_SUCCESS) { + IPC_ERROR(&ii->ipc_c, "Failed to set instance info"); + free(ii); + return -1; + } + const int flags = MAP_SHARED; const int access = PROT_READ | PROT_WRITE; const size_t size = sizeof(struct ipc_shared_memory); diff --git a/src/xrt/ipc/ipc_protocol.h b/src/xrt/ipc/ipc_protocol.h index 69d7b1b1325801561d7fc67fb5d90bdaeda9d784..d8374e9867ec3cb668b06ffa608be9a6e1df9488 100644 --- a/src/xrt/ipc/ipc_protocol.h +++ b/src/xrt/ipc/ipc_protocol.h @@ -4,20 +4,23 @@ * @file * @brief Common protocol definition. * @author Pete Black <pblack@collabora.com> + * @author Jakob Bornecrantz <jakob@collabora.com> * @ingroup ipc */ #pragma once -#include "xrt/xrt_tracking.h" -#include "xrt/xrt_device.h" #include "xrt/xrt_compiler.h" -#include "xrt/xrt_compositor.h" - #include "xrt/xrt_results.h" +#include "xrt/xrt_defines.h" +#include "xrt/xrt_instance.h" +#include "xrt/xrt_compositor.h" +#include "xrt/xrt_device.h" +#include "xrt/xrt_tracking.h" #include <semaphore.h> + #define IPC_MSG_SOCK_FILE "/tmp/monado_comp_ipc" #define IPC_MAX_SWAPCHAIN_FDS 8 #define IPC_CRED_SIZE 1 // auth not implemented @@ -26,7 +29,9 @@ #define IPC_MAX_FORMATS 32 // max formats our server-side compositor supports #define IPC_MAX_DEVICES 8 // max number of devices we will map via shared mem #define IPC_MAX_LAYERS 16 -#define IPC_MAX_SLOTS 3 +#define IPC_MAX_SLOTS 128 +#define IPC_MAX_CLIENTS 8 +#define IPC_EVENT_QUEUE_SIZE 32 #define IPC_SHARED_MAX_DEVICES 8 #define IPC_SHARED_MAX_INPUTS 1024 @@ -172,10 +177,15 @@ struct ipc_shared_memory } wait_frame; }; -/* - * - * Rest of protocol is generated. - * - */ +struct ipc_client_list +{ + int32_t ids[IPC_MAX_CLIENTS]; +}; -#include "ipc_protocol_generated.h" +struct ipc_compositor_state +{ + uint8_t active; + uint8_t visible; + uint8_t focused; + int32_t z_order; +}; diff --git a/src/xrt/ipc/ipc_server.h b/src/xrt/ipc/ipc_server.h index 2b4bba8c1941cbbc2c257f1921662a67cc406653..e30b1e081b605fa43f6560f73cc9fb993804b3a2 100644 --- a/src/xrt/ipc/ipc_server.h +++ b/src/xrt/ipc/ipc_server.h @@ -62,7 +62,7 @@ extern "C" { #define IPC_SERVER_NUM_XDEVS 8 #define IPC_MAX_CLIENT_SWAPCHAINS 32 -#define IPC_MAX_CLIENTS 8 +//#define IPC_MAX_CLIENTS 8 struct xrt_instance; struct xrt_compositor; @@ -85,6 +85,14 @@ struct ipc_swapchain_data bool active; }; + +struct ipc_queued_event +{ + bool pending; + uint64_t timestamp; + struct xrt_ipc_event event; +}; + /*! * Holds the state for a single client. * @@ -116,7 +124,10 @@ struct ipc_client_state //! Whether we are currently rendering @ref render_state bool rendering_state; - bool active; + struct xrt_client_state client_state; + struct ipc_queued_event queued_events[IPC_EVENT_QUEUE_SIZE]; + + int server_thread_index; }; /*! @@ -160,10 +171,16 @@ struct ipc_server // Hack for now. struct ipc_wait *iw; - struct os_thread thread; - volatile bool thread_started; - volatile bool thread_stopping; - volatile struct ipc_client_state thread_state; + struct os_thread thread[IPC_MAX_CLIENTS]; + volatile bool thread_started[IPC_MAX_CLIENTS]; + volatile bool thread_stopping[IPC_MAX_CLIENTS]; + volatile struct ipc_client_state thread_state[IPC_MAX_CLIENTS]; + + volatile uint32_t current_slot_index; + + int active_client_index; + int last_active_client_index; + pthread_mutex_t global_state_lock; }; /*! @@ -174,6 +191,14 @@ struct ipc_server int ipc_server_main(int argc, char **argv); +/*! + * Called by client threads to manage global state + * + * @ingroup ipc_server + */ +void +update_server_state(struct ipc_server *vs); + /*! * Thread function for the client side dispatching. * diff --git a/src/xrt/ipc/ipc_server_client.c b/src/xrt/ipc/ipc_server_client.c index 7fc7bd171d23db2717bf539e454bd1e568855b21..c53e3e0ba2133de6db53e643d47edf2ac0a3366c 100644 --- a/src/xrt/ipc/ipc_server_client.c +++ b/src/xrt/ipc/ipc_server_client.c @@ -48,71 +48,189 @@ ipc_handle_instance_get_shm_fd(volatile struct ipc_client_state *cs, *out_num_fds = 1; return XRT_SUCCESS; } +xrt_result_t +ipc_handle_session_create(volatile struct ipc_client_state *ics, + struct xrt_overlay_info *oi) +{ + ics->client_state.session_active = false; + ics->client_state.session_overlay = false; + ics->client_state.session_visible = false; + if (oi->is_overlay) { + ics->client_state.session_overlay = true; + ics->client_state.z_order = oi->z_order; + //@todo handle flags + } + update_server_state(ics->server); + return XRT_SUCCESS; +} xrt_result_t -ipc_handle_session_begin(volatile struct ipc_client_state *cs) +ipc_handle_session_begin(volatile struct ipc_client_state *ics) { - cs->active = true; + // ics->client_state.session_active = true; + // update_server_state(ics->server); return XRT_SUCCESS; } xrt_result_t -ipc_handle_session_end(volatile struct ipc_client_state *cs) +ipc_handle_session_end(volatile struct ipc_client_state *ics) { - cs->active = false; + ics->client_state.session_active = false; + update_server_state(ics->server); return XRT_SUCCESS; } xrt_result_t -ipc_handle_compositor_get_formats(volatile struct ipc_client_state *cs, +ipc_handle_compositor_get_formats(volatile struct ipc_client_state *ics, struct ipc_formats_info *out_info) { - out_info->num_formats = cs->xc->num_formats; - for (size_t i = 0; i < cs->xc->num_formats; i++) { - out_info->formats[i] = cs->xc->formats[i]; + out_info->num_formats = ics->xc->num_formats; + for (size_t i = 0; i < ics->xc->num_formats; i++) { + out_info->formats[i] = ics->xc->formats[i]; } return XRT_SUCCESS; } xrt_result_t -ipc_handle_compositor_wait_frame(volatile struct ipc_client_state *cs) +ipc_handle_compositor_wait_frame(volatile struct ipc_client_state *ics) { - ipc_server_wait_add_frame(cs->server->iw, cs); + ipc_server_wait_add_frame(ics->server->iw, ics); + ics->client_state.session_active = true; + update_server_state(ics->server); return XRT_SUCCESS; } xrt_result_t -ipc_handle_compositor_begin_frame(volatile struct ipc_client_state *cs) +ipc_handle_compositor_begin_frame(volatile struct ipc_client_state *ics) { + // update_server_state(ics->server); return XRT_SUCCESS; } xrt_result_t -ipc_handle_compositor_discard_frame(volatile struct ipc_client_state *cs) +ipc_handle_compositor_discard_frame(volatile struct ipc_client_state *ics) { return XRT_SUCCESS; } xrt_result_t -ipc_handle_compositor_layer_sync(volatile struct ipc_client_state *cs, +ipc_handle_compositor_layer_sync(volatile struct ipc_client_state *ics, uint32_t slot_id, uint32_t *out_free_slot_id) { - struct ipc_shared_memory *ism = cs->server->ism; + struct ipc_shared_memory *ism = ics->server->ism; struct ipc_layer_slot *slot = &ism->slots[slot_id]; // Copy current slot data to our state. - cs->render_state = *slot; - cs->rendering_state = true; + ics->render_state = *slot; + ics->rendering_state = true; + + os_mutex_lock((struct os_mutex *)&ics->server->global_state_lock); + *out_free_slot_id = + (ics->server->current_slot_index + 1) % IPC_MAX_SLOTS; + ics->server->current_slot_index = *out_free_slot_id; + os_mutex_unlock((struct os_mutex *)&ics->server->global_state_lock); + + return XRT_SUCCESS; +} - *out_free_slot_id = (slot_id + 1) % IPC_MAX_SLOTS; +xrt_result_t +ipc_handle_compositor_poll_events(volatile struct ipc_client_state *cs, + struct xrt_ipc_event *out_event) +{ + uint64_t l_timestamp = UINT64_MAX; + volatile struct ipc_queued_event *event_to_send = NULL; + for (uint32_t i = 0; i < IPC_EVENT_QUEUE_SIZE; i++) { + volatile struct ipc_queued_event *e = &cs->queued_events[i]; + if (e->pending == true && e->timestamp < l_timestamp) { + event_to_send = e; + } + } + // we always return an event in response to this call - but + // only 'real' events are marked valid + out_event->valid = false; + if (event_to_send) { + out_event->type = event_to_send->event.type; + memcpy(out_event->data, (void *)&event_to_send->event.data, + sizeof(struct xrt_ipc_event)); + out_event->valid = true; + event_to_send->pending = false; + } return XRT_SUCCESS; } xrt_result_t -ipc_handle_swapchain_create(volatile struct ipc_client_state *cs, +ipc_handle_system_get_client_info(volatile struct ipc_client_state *_ics, + uint32_t id, + struct xrt_client_state *out_client_desc) +{ + if (id >= IPC_MAX_CLIENTS) { + return XRT_ERROR_IPC_FAILURE; + } + volatile struct ipc_client_state *ics = &_ics->server->thread_state[id]; + + if (ics->ipc_socket_fd <= 0) { + return XRT_ERROR_IPC_FAILURE; + } + + *out_client_desc = ics->client_state; + + //@todo: track this data in the ipc_client_state struct + out_client_desc->primary_application = false; + if (ics->server->active_client_index == (int)id) { + out_client_desc->primary_application = true; + } + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_system_set_client_info(volatile struct ipc_client_state *ics, + struct xrt_client_state *client_desc) +{ + ics->client_state.info = client_desc->info; + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_system_get_clients(volatile struct ipc_client_state *_ics, + struct ipc_client_list *list) +{ + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + volatile struct ipc_client_state *ics = + &_ics->server->thread_state[i]; + list->ids[i] = ics->server_thread_index; + } + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_system_set_primary_client(volatile struct ipc_client_state *ics, + uint32_t client_id) +{ + + ics->server->active_client_index = client_id; + printf("system setting active client to %d\n", client_id); + update_server_state(ics->server); + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_system_set_focused_client(volatile struct ipc_client_state *ics, + uint32_t client_id) +{ + + // cs->server->active_client_index = client_id; + printf("UNIMPLEMENTED: system setting focused client to %d\n", + client_id); + // update_server_state(cs->server); + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_swapchain_create(volatile struct ipc_client_state *ics, enum xrt_swapchain_create_flags create, enum xrt_swapchain_usage_bits bits, int64_t format, @@ -132,7 +250,7 @@ ipc_handle_swapchain_create(volatile struct ipc_client_state *cs, // Our handle is just the index for now. uint32_t index = 0; for (; index < IPC_MAX_CLIENT_SWAPCHAINS; index++) { - if (!cs->swapchain_data[index].active) { + if (!ics->swapchain_data[index].active) { break; } } @@ -143,11 +261,11 @@ ipc_handle_swapchain_create(volatile struct ipc_client_state *cs, } // It's now safe to increment the number of swapchains. - cs->num_swapchains++; + ics->num_swapchains++; // create the swapchain struct xrt_swapchain *xsc = - xrt_comp_create_swapchain(cs->xc, // Compositor + xrt_comp_create_swapchain(ics->xc, // Compositor create, // Flags bits, // Usage format, // Format @@ -160,14 +278,14 @@ ipc_handle_swapchain_create(volatile struct ipc_client_state *cs, uint32_t num_images = xsc->num_images; - IPC_SPEW(cs->server, "IPC: Created swapchain %d\n", index); + IPC_SPEW(ics->server, "IPC: Created swapchain %d\n", index); - cs->xscs[index] = xsc; - cs->swapchain_data[index].active = true; - cs->swapchain_data[index].width = width; - cs->swapchain_data[index].height = height; - cs->swapchain_data[index].format = format; - cs->swapchain_data[index].num_images = num_images; + ics->xscs[index] = xsc; + ics->swapchain_data[index].active = true; + ics->swapchain_data[index].width = width; + ics->swapchain_data[index].height = height; + ics->swapchain_data[index].format = format; + ics->swapchain_data[index].num_images = num_images; // return our result to the caller. struct xrt_swapchain_fd *xcsfd = (struct xrt_swapchain_fd *)xsc; @@ -190,14 +308,14 @@ ipc_handle_swapchain_create(volatile struct ipc_client_state *cs, } xrt_result_t -ipc_handle_swapchain_wait_image(volatile struct ipc_client_state *cs, +ipc_handle_swapchain_wait_image(volatile struct ipc_client_state *ics, uint32_t id, uint64_t timeout, uint32_t index) { //! @todo Look up the index. uint32_t sc_index = id; - struct xrt_swapchain *xsc = cs->xscs[sc_index]; + struct xrt_swapchain *xsc = ics->xscs[sc_index]; xrt_swapchain_wait_image(xsc, timeout, index); @@ -205,14 +323,14 @@ ipc_handle_swapchain_wait_image(volatile struct ipc_client_state *cs, } xrt_result_t -ipc_handle_swapchain_acquire_image(volatile struct ipc_client_state *cs, +ipc_handle_swapchain_acquire_image(volatile struct ipc_client_state *ics, uint32_t id, uint32_t *out_index) { //! @todo Look up the index. uint32_t sc_index = id; - struct xrt_swapchain *xsc = cs->xscs[sc_index]; + struct xrt_swapchain *xsc = ics->xscs[sc_index]; xrt_swapchain_acquire_image(xsc, out_index); @@ -220,13 +338,13 @@ ipc_handle_swapchain_acquire_image(volatile struct ipc_client_state *cs, } xrt_result_t -ipc_handle_swapchain_release_image(volatile struct ipc_client_state *cs, +ipc_handle_swapchain_release_image(volatile struct ipc_client_state *ics, uint32_t id, uint32_t index) { //! @todo Look up the index. uint32_t sc_index = id; - struct xrt_swapchain *xsc = cs->xscs[sc_index]; + struct xrt_swapchain *xsc = ics->xscs[sc_index]; xrt_swapchain_release_image(xsc, index); @@ -234,25 +352,25 @@ ipc_handle_swapchain_release_image(volatile struct ipc_client_state *cs, } xrt_result_t -ipc_handle_swapchain_destroy(volatile struct ipc_client_state *cs, uint32_t id) +ipc_handle_swapchain_destroy(volatile struct ipc_client_state *ics, uint32_t id) { //! @todo Implement destroy swapchain. - cs->num_swapchains--; + ics->num_swapchains--; - xrt_swapchain_destroy((struct xrt_swapchain **)&cs->xscs[id]); - cs->swapchain_data[id].active = false; + xrt_swapchain_destroy((struct xrt_swapchain **)&ics->xscs[id]); + ics->swapchain_data[id].active = false; return XRT_SUCCESS; } xrt_result_t -ipc_handle_device_update_input(volatile struct ipc_client_state *cs, +ipc_handle_device_update_input(volatile struct ipc_client_state *ics, uint32_t id) { // To make the code a bit more readable. uint32_t device_id = id; - struct ipc_shared_memory *ism = cs->server->ism; - struct xrt_device *xdev = cs->server->xdevs[device_id]; + struct ipc_shared_memory *ism = ics->server->ism; + struct xrt_device *xdev = ics->server->xdevs[device_id]; struct ipc_shared_device *idev = &ism->idevs[device_id]; // Update inputs. @@ -268,7 +386,7 @@ ipc_handle_device_update_input(volatile struct ipc_client_state *cs, } xrt_result_t -ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *cs, +ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *ics, uint32_t id, enum xrt_input_name name, uint64_t at_timestamp, @@ -278,7 +396,7 @@ ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *cs, // To make the code a bit more readable. uint32_t device_id = id; - struct xrt_device *xdev = cs->server->xdevs[device_id]; + struct xrt_device *xdev = ics->server->xdevs[device_id]; // Get the pose. xrt_device_get_tracked_pose(xdev, name, at_timestamp, out_timestamp, @@ -288,7 +406,7 @@ ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *cs, } xrt_result_t -ipc_handle_device_get_view_pose(volatile struct ipc_client_state *cs, +ipc_handle_device_get_view_pose(volatile struct ipc_client_state *ics, uint32_t id, struct xrt_vec3 *eye_relation, uint32_t view_index, @@ -297,7 +415,7 @@ ipc_handle_device_get_view_pose(volatile struct ipc_client_state *cs, // To make the code a bit more readable. uint32_t device_id = id; - struct xrt_device *xdev = cs->server->xdevs[device_id]; + struct xrt_device *xdev = ics->server->xdevs[device_id]; // Get the pose. xrt_device_get_view_pose(xdev, eye_relation, view_index, out_pose); @@ -306,14 +424,14 @@ ipc_handle_device_get_view_pose(volatile struct ipc_client_state *cs, } xrt_result_t -ipc_handle_device_set_output(volatile struct ipc_client_state *cs, +ipc_handle_device_set_output(volatile struct ipc_client_state *ics, uint32_t id, enum xrt_output_name name, union xrt_output_value *value) { // To make the code a bit more readable. uint32_t device_id = id; - struct xrt_device *xdev = cs->server->xdevs[device_id]; + struct xrt_device *xdev = ics->server->xdevs[device_id]; // Set the output. xrt_device_set_output(xdev, name, value); @@ -360,19 +478,19 @@ setup_epoll(int listen_socket) */ static void -client_loop(volatile struct ipc_client_state *cs) +client_loop(volatile struct ipc_client_state *ics) { fprintf(stderr, "SERVER: Client connected\n"); // Claim the client fd. - int epoll_fd = setup_epoll(cs->ipc_socket_fd); + int epoll_fd = setup_epoll(ics->ipc_socket_fd); if (epoll_fd < 0) { return; } uint8_t buf[IPC_BUF_SIZE]; - while (cs->server->running) { + while (ics->server->running) { const int half_a_second_ms = 500; struct epoll_event event = {0}; @@ -380,7 +498,8 @@ client_loop(volatile struct ipc_client_state *cs) int ret = epoll_wait(epoll_fd, &event, 1, half_a_second_ms); if (ret < 0) { fprintf(stderr, - "ERROR: Failed epoll_wait '%i', disconnecting " + "ERROR: Failed epoll_wait '%i', " + "disconnecting " "client.\n", ret); break; @@ -398,20 +517,22 @@ client_loop(volatile struct ipc_client_state *cs) } // Finally get the data that is waiting for us. - ssize_t len = recv(cs->ipc_socket_fd, &buf, IPC_BUF_SIZE, 0); + ssize_t len = recv(ics->ipc_socket_fd, &buf, IPC_BUF_SIZE, 0); if (len < 4) { fprintf(stderr, - "ERROR: Invalid packet received, disconnecting " + "ERROR: Invalid packet received, " + "disconnecting " "client.\n"); break; } // Check the first 4 bytes of the message and dispatch. ipc_command_t *ipc_command = (uint32_t *)buf; - ret = ipc_dispatch(cs, ipc_command); + ret = ipc_dispatch(ics, ipc_command); if (ret < 0) { fprintf(stderr, - "ERROR: During packet handling, disconnecting " + "ERROR: During packet handling, " + "disconnecting " "client.\n"); break; } @@ -420,18 +541,19 @@ client_loop(volatile struct ipc_client_state *cs) close(epoll_fd); epoll_fd = -1; - close(cs->ipc_socket_fd); - cs->ipc_socket_fd = -1; - - cs->active = false; - cs->num_swapchains = 0; + close(ics->ipc_socket_fd); + ics->server->thread_stopping[ics->server_thread_index] = true; + ics->ipc_socket_fd = -1; + ics->server_thread_index = -1; + memset((void *)&ics->client_state, 0, sizeof(struct xrt_client_state)); + ics->num_swapchains = 0; // Make sure to reset the renderstate fully. - cs->rendering_state = false; - cs->render_state.num_layers = 0; - for (uint32_t i = 0; i < ARRAY_SIZE(cs->render_state.layers); ++i) { + ics->rendering_state = false; + ics->render_state.num_layers = 0; + for (uint32_t i = 0; i < ARRAY_SIZE(ics->render_state.layers); ++i) { volatile struct ipc_layer_entry *rl = - &cs->render_state.layers[i]; + &ics->render_state.layers[i]; rl->swapchain_ids[0] = 0; rl->swapchain_ids[1] = 0; @@ -449,17 +571,17 @@ client_loop(volatile struct ipc_client_state *cs) // Destroy all swapchains now. for (uint32_t j = 0; j < IPC_MAX_CLIENT_SWAPCHAINS; j++) { - xrt_swapchain_destroy((struct xrt_swapchain **)&cs->xscs[j]); - cs->swapchain_data[j].active = false; - IPC_SPEW(cs->server, "IPC: Destroyed swapchain %d\n", j); + xrt_swapchain_destroy((struct xrt_swapchain **)&ics->xscs[j]); + ics->swapchain_data[j].active = false; + IPC_SPEW(ics->server, "IPC: Destroyed swapchain %d\n", j); } // Should we stop the server when a client disconnects? - if (cs->server->exit_on_disconnect) { - cs->server->running = false; + if (ics->server->exit_on_disconnect) { + ics->server->running = false; } - ipc_server_wait_reset_client(cs->server->iw, cs); + ipc_server_wait_reset_client(ics->server->iw, ics); } @@ -470,14 +592,17 @@ client_loop(volatile struct ipc_client_state *cs) */ void * -ipc_server_client_thread(void *_cs) +ipc_server_client_thread(void *_ics) { - volatile struct ipc_client_state *cs = _cs; + volatile struct ipc_client_state *ics = _ics; + + client_loop(ics); - client_loop(cs); + // cs->session_state = XR_SESSION_STATE_STOPPING; + update_server_state(ics->server); - cs->server->thread_stopping = true; - cs->server->thread_started = false; + ics->server->thread_stopping[ics->server_thread_index] = true; + ics->server->thread_started[ics->server_thread_index] = false; return NULL; } diff --git a/src/xrt/ipc/ipc_server_process.c b/src/xrt/ipc/ipc_server_process.c index 0a44f520cd9d5c4a832ef243ced0f3cb39b8cbc2..867df4e2ad7933adaf674de26a7e2f7a3d43e109 100644 --- a/src/xrt/ipc/ipc_server_process.c +++ b/src/xrt/ipc/ipc_server_process.c @@ -14,6 +14,7 @@ #include "xrt/xrt_compositor.h" #include "xrt/xrt_config_have.h" +#include "os/os_time.h" #include "util/u_var.h" #include "util/u_misc.h" #include "util/u_debug.h" @@ -50,10 +51,14 @@ * */ -#define IPC_MAX_CLIENTS 8 - DEBUG_GET_ONCE_BOOL_OPTION(exit_on_disconnect, "IPC_EXIT_ON_DISCONNECT", false) +struct _z_sort_data +{ + int32_t index; + int32_t z_order; +}; + /* * @@ -384,7 +389,7 @@ init_all(struct ipc_server *s) s->running = true; s->exit_on_disconnect = debug_get_bool_option_exit_on_disconnect(); - int ret = xrt_instance_create(&s->xinst); + int ret = xrt_instance_create(&s->xinst, NULL); if (ret < 0) { teardown_all(s); return ret; @@ -447,6 +452,8 @@ init_all(struct ipc_server *s) u_var_add_bool(s, &s->exit_on_disconnect, "exit_on_disconnect"); u_var_add_bool(s, (void *)&s->running, "running"); + + return 0; } @@ -459,26 +466,46 @@ handle_listen(struct ipc_server *vs) vs->running = false; } - volatile struct ipc_client_state *cs = &vs->thread_state; + volatile struct ipc_client_state *cs = &vs->thread_state[0]; + int32_t cs_index = -1; // The return is the new fd; int fd = ret; - if (vs->thread_started && !vs->thread_stopping) { - fprintf(stderr, "ERROR: Client already connected!\n"); + // find the next free thread in our array (server_thread_index is -1) + // and have it handle this connection + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + volatile struct ipc_client_state *_cs = &vs->thread_state[i]; + if (_cs->server_thread_index < 0) { + cs = _cs; + cs_index = i; + break; + } + } + if (cs == NULL) { + fprintf(stderr, "ERROR: Max client count reached!\n"); + close(fd); + return; + } + + if (vs->thread_started[cs_index] && !vs->thread_stopping[cs_index]) { + // we should not get here + fprintf(stderr, "ERROR: Client state management error!\n"); close(fd); return; } - if (vs->thread_stopping) { - os_thread_join((struct os_thread *)&vs->thread); - os_thread_destroy((struct os_thread *)&vs->thread); - vs->thread_stopping = false; + if (vs->thread_stopping[cs_index]) { + os_thread_join((struct os_thread *)&vs->thread[cs_index]); + os_thread_destroy((struct os_thread *)&vs->thread[cs_index]); + vs->thread_stopping[cs_index] = false; } - vs->thread_started = true; + vs->thread_started[cs_index] = true; cs->ipc_socket_fd = fd; - os_thread_start((struct os_thread *)&vs->thread, + cs->server = vs; + cs->server_thread_index = cs_index; + os_thread_start((struct os_thread *)&vs->thread[cs_index], ipc_server_client_thread, (void *)cs); } @@ -514,6 +541,57 @@ check_epoll(struct ipc_server *vs) } } +static uint32_t +find_event_slot(volatile struct ipc_client_state *cs) +{ + uint64_t oldest_event_timestamp = UINT64_MAX; + uint32_t oldest_event_index = 0; + for (uint32_t i = 0; i < IPC_EVENT_QUEUE_SIZE; i++) { + if (cs->queued_events->timestamp < oldest_event_timestamp) { + oldest_event_index = i; + } + if (!cs->queued_events[i].pending) { + return i; + } + } + + fprintf(stderr, "ERROR! event queue full - unconsumed event lost!\n"); + return oldest_event_index; +} + +static void +transition_overlay_visibility(volatile struct ipc_client_state *cs, + bool visible) +{ + uint32_t event_slot = find_event_slot(cs); + uint64_t timestamp = os_monotonic_get_ns(); + volatile struct ipc_queued_event *qe = &cs->queued_events[event_slot]; + qe->timestamp = timestamp; + qe->pending = true; + qe->event.valid = true; + qe->event.type = XRT_EVENT_OVERLAY; + struct xrt_overlay_event oe; + oe.visible = visible; + memcpy((void *)qe->event.data, &oe, sizeof(oe)); +} + +static void +send_client_state(volatile struct ipc_client_state *ics) +{ + uint32_t event_slot = find_event_slot(ics); + uint64_t timestamp = os_monotonic_get_ns(); + volatile struct ipc_queued_event *qe = &ics->queued_events[event_slot]; + qe->timestamp = timestamp; + qe->pending = true; + qe->event.valid = true; + qe->event.type = XRT_EVENT_CLIENT_STATE; + struct xrt_client_state_event cse; + cse.active = ics->client_state.session_active; + cse.visible = ics->client_state.session_visible; + cse.focused = ics->client_state.session_focused; + memcpy((void *)qe->event.data, &cse, sizeof(cse)); +} + static bool _update_projection_layer(struct comp_compositor *c, volatile struct ipc_client_state *active_client, @@ -576,75 +654,138 @@ _update_quad_layer(struct comp_compositor *c, return true; } +static int +_overlay_sort_func(const void *a, const void *b) +{ + struct _z_sort_data *oa = (struct _z_sort_data *)a; + struct _z_sort_data *ob = (struct _z_sort_data *)b; + if (oa->z_order < ob->z_order) { + return -1; + } else if (oa->z_order > ob->z_order) { + return 1; + } + return 0; +} + static bool _update_layers(struct comp_compositor *c, - volatile struct ipc_client_state *active_client, + struct ipc_server *s, uint32_t *num_layers) { - volatile struct ipc_layer_slot *render_state = - &active_client->render_state; + struct _z_sort_data z_data[IPC_MAX_CLIENTS]; + + // initialise, and fill in overlay app data + for (int32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + volatile struct ipc_client_state *ics = &s->thread_state[i]; + z_data[i].index = -1; + z_data[i].z_order = -1; + // we need to create a list of overlay applications, sorted by z + if (ics->client_state.session_overlay) { + if (ics->client_state.session_active) { + z_data[i].index = i; + z_data[i].z_order = ics->client_state.z_order; + } + } + } - if (*num_layers != render_state->num_layers) { - //! @todo Resizing here would be faster - *num_layers = render_state->num_layers; - comp_renderer_destroy_layers(c->r); - comp_renderer_allocate_layers(c->r, render_state->num_layers); + // ensure our primary application is enabled, + // and rendered first in the stack + if (s->active_client_index >= 0) { + z_data[s->active_client_index].index = s->active_client_index; + z_data[s->active_client_index].z_order = INT32_MIN; } - for (uint32_t i = 0; i < render_state->num_layers; i++) { - volatile struct ipc_layer_entry *layer = - &render_state->layers[i]; - switch (layer->data.type) { - case XRT_LAYER_STEREO_PROJECTION: { - if (!_update_projection_layer(c, active_client, layer, - i)) - return false; - break; - } - case XRT_LAYER_QUAD: { - if (!_update_quad_layer(c, active_client, layer, i)) - return false; - break; + // sort the stack array + qsort(z_data, IPC_MAX_CLIENTS, sizeof(struct _z_sort_data), + _overlay_sort_func); + + // count the layers + uint32_t n = 0; + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + struct _z_sort_data *zd = &z_data[i]; + if (zd->index >= 0) { + volatile struct ipc_client_state *ics = + &s->thread_state[zd->index]; + n += ics->render_state.num_layers; } + } + + if (*num_layers != n) { + // TODO: Resizing here would be faster + *num_layers = n; + comp_renderer_destroy_layers(c->r); + comp_renderer_allocate_layers(c->r, n); + } + + // render the layer stack + uint32_t layer_id = 0; + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + struct _z_sort_data *zd = &z_data[i]; + if (zd->index >= 0) { + volatile struct ipc_client_state *ics = + &s->thread_state[zd->index]; + for (uint32_t j = 0; j < ics->render_state.num_layers; + j++) { + + volatile struct ipc_layer_entry *layer = + &ics->render_state.layers[j]; + switch (layer->data.type) { + case XRT_LAYER_STEREO_PROJECTION: { + _update_projection_layer(c, ics, layer, + layer_id); + layer_id++; + break; + } + case XRT_LAYER_QUAD: { + _update_quad_layer(c, ics, layer, + layer_id); + layer_id++; + break; + } + } + } } } return true; } + + static int -main_loop(struct ipc_server *vs) +main_loop(struct ipc_server *s) { - struct xrt_compositor *xc = vs->xc; + struct xrt_compositor *xc = s->xc; struct comp_compositor *c = comp_compositor(xc); - // make sure all our client connections have a handle to the compositor - // and consistent initial state - vs->thread_state.server = vs; - vs->thread_state.xc = xc; + // make sure all our client connections have a handle to the + // compositor and consistent initial state uint32_t num_layers = 0; - while (vs->running) { + while (s->running) { /* * Check polling. */ - check_epoll(vs); + check_epoll(s); /* * Update active client. */ volatile struct ipc_client_state *active_client = NULL; - if (vs->thread_state.active) { - active_client = &vs->thread_state; + if (s->active_client_index >= 0) { + active_client = + &s->thread_state[s->active_client_index]; } + + /* * Render the swapchains. */ - if (active_client == NULL || !active_client->active || + if (active_client == NULL || active_client->num_swapchains == 0) { if (num_layers != 0) { COMP_DEBUG(c, "Destroying layers."); @@ -656,17 +797,19 @@ main_loop(struct ipc_server *vs) // swapchain indices and toggle wait to false // when the client calls end_frame, signalling // us to render. + if (active_client->rendering_state) { - if (!_update_layers(c, active_client, - &num_layers)) + if (!_update_layers(c, s, &num_layers)) continue; - // set our client state back to waiting. active_client->rendering_state = false; } } comp_renderer_draw(c->r); + // we should release any slots that are not used by a + // rendering client + // Now is a good time to destroy objects. comp_compositor_garbage_collect(c); @@ -676,12 +819,188 @@ main_loop(struct ipc_server *vs) } +static void +handle_overlay_client_events(volatile struct ipc_client_state *ics, + int active_id, + int prev_active_id) +{ + // this is an overlay session. + if (ics->client_state.session_overlay) { + + // switch between main applications + if (active_id >= 0 && prev_active_id >= 0) { + transition_overlay_visibility(ics, false); + transition_overlay_visibility(ics, true); + } + + // switch from idle to active application + if (active_id >= 0 && prev_active_id < 0) { + transition_overlay_visibility(ics, true); + } + + // switch from active application to idle + if (active_id < 0 && prev_active_id >= 0) { + transition_overlay_visibility(ics, false); + } + } +} + +static void +handle_focused_client_events(volatile struct ipc_client_state *ics, + int active_id, + int prev_active_id) +{ + + // if our prev active id is -1 and our cur active id is -1, we + // can bail out early + + if (active_id == -1 && prev_active_id == -1) { + return; + } + + // set visibility/focus to false on all applications + ics->client_state.session_focused = false; + ics->client_state.session_visible = false; + + // do we have a primary application? + if (active_id >= 0) { + + // if we are an overlay, we are always visible + // if we have a primary application + if (ics->client_state.session_overlay) { + ics->client_state.session_visible = true; + } + + // set visible + focused if we are the primary + // application + if (ics->server_thread_index == active_id) { + ics->client_state.session_visible = true; + ics->client_state.session_focused = true; + } + send_client_state(ics); + return; + } + + // no primary application, set all overlays to synchronised + // state + if (ics->client_state.session_overlay) { + ics->client_state.session_focused = false; + ics->client_state.session_visible = false; + send_client_state(ics); + } +} + + +void +init_server_state(struct ipc_server *s) +{ + + // set up initial state for global vars, and each client state + + s->active_client_index = -1; // we start off with no active client. + s->last_active_client_index = -1; + s->current_slot_index = 0; + + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + volatile struct ipc_client_state *cs = &s->thread_state[i]; + cs->server = s; + cs->xc = s->xc; + cs->server_thread_index = -1; + } +} + /* * * Exported functions. * */ +void +update_server_state(struct ipc_server *s) +{ + + pthread_mutex_lock(&s->global_state_lock); // multiple threads + // could call this at + // the same time + + // if our client that is set to active is still active, + // and it is the same as our last active client, we can + // early-out, as no events need to be sent + + if (s->active_client_index >= 0) { + + volatile struct ipc_client_state *ics = + &s->thread_state[s->active_client_index]; + + if (ics->client_state.session_active && + s->active_client_index == s->last_active_client_index) { + pthread_mutex_unlock(&s->global_state_lock); + return; + } + } + + + // our active application has changed - this would typically be + // switched by the monado-ctl application or other app making a + // 'set active application' ipc call, or it could be a + // connection loss resulting in us needing to 'fall through' to + // the first active application + //, or finally to the idle 'wallpaper' images. + + + bool set_idle = true; + int fallback_active_application = -1; + + // do we have a fallback application? + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + volatile struct ipc_client_state *ics = &s->thread_state[i]; + if (ics->client_state.session_overlay == false && + ics->server_thread_index >= 0 && + ics->client_state.session_active) { + fallback_active_application = i; + set_idle = false; + } + } + + // if our currently-set active primary application is not + // actually active/displayable, use the fallback application + // instead. + volatile struct ipc_client_state *ics = + &s->thread_state[s->active_client_index]; + if (!(ics->client_state.session_overlay == false && + s->active_client_index >= 0 && + ics->client_state.session_active)) { + s->active_client_index = fallback_active_application; + } + + + // if we have no applications to fallback to, enable the idle + // wallpaper. + if (set_idle) { + s->active_client_index = -1; + } + + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + + volatile struct ipc_client_state *ics = &s->thread_state[i]; + if (ics->server_thread_index >= 0) { + + handle_focused_client_events( + ics, s->active_client_index, + s->last_active_client_index); + + handle_overlay_client_events( + ics, s->active_client_index, + s->last_active_client_index); + } + } + + s->last_active_client_index = s->active_client_index; + + pthread_mutex_unlock(&s->global_state_lock); + return; +} + int ipc_server_main(int argc, char **argv) { @@ -692,6 +1011,7 @@ ipc_server_main(int argc, char **argv) return ret; } + init_server_state(s); ret = main_loop(s); teardown_all(s); diff --git a/src/xrt/ipc/proto.json b/src/xrt/ipc/proto.json index 6b4177b8b2da5a6f22e3cd332e1b4d02b9a03a4c..0282025be9e715c8283cab519970ccbfaf402cf0 100644 --- a/src/xrt/ipc/proto.json +++ b/src/xrt/ipc/proto.json @@ -3,6 +3,45 @@ "out_fds": true }, + "system_get_client_info": { + "in": [ + {"name": "id", "type": "uint32_t"} + ], + "out": [ + {"name": "desc", "type": "struct xrt_client_state"} + ] + }, + + "system_set_client_info": { + "in": [ + {"name": "desc", "type": "struct xrt_client_state"} + ] + }, + + "system_get_clients": { + "out": [ + {"name": "clients", "type": "struct ipc_client_list"} + ] + }, + + "system_set_primary_client": { + "in": [ + {"name": "id", "type": "uint32_t"} + ] + }, + + "system_set_focused_client": { + "in": [ + {"name": "id", "type": "uint32_t"} + ] + }, + + "session_create": { + "in": [ + {"name": "overlay_info", "type": "struct xrt_overlay_info"} + ] + }, + "session_begin": {}, "session_end": {}, @@ -13,8 +52,7 @@ ] }, - "compositor_wait_frame": { - }, + "compositor_wait_frame": {}, "compositor_begin_frame": {}, @@ -29,6 +67,12 @@ ] }, + "compositor_poll_events": { + "out": [ + {"name": "event", "type": "struct xrt_ipc_event"} + ] + }, + "swapchain_create": { "in": [ {"name": "create", "type": "enum xrt_swapchain_create_flags"}, diff --git a/src/xrt/ipc/proto.py b/src/xrt/ipc/proto.py index ca669c0512c74a479d29312db97d7ff264c7987f..a5af0fffcdd1a208750a46de326a69e9c0c4c504 100755 --- a/src/xrt/ipc/proto.py +++ b/src/xrt/ipc/proto.py @@ -246,6 +246,7 @@ def generate_client_c(file, p): f.write(header.format(brief='Generated IPC client code', suffix='_client')) f.write(''' #include "ipc_client.h" +#include "ipc_protocol_generated.h" // clang-format off @@ -305,6 +306,7 @@ def generate_client_h(file, p): #pragma once #include "ipc_protocol.h" +#include "ipc_protocol_generated.h" #include "ipc_client.h" @@ -409,6 +411,7 @@ def generate_server_header(file, p): #pragma once #include "ipc_protocol.h" +#include "ipc_protocol_generated.h" #include "ipc_server.h" diff --git a/src/xrt/state_trackers/gui/gui_prober.c b/src/xrt/state_trackers/gui/gui_prober.c index bbdfbd67b4af4c82da3d57800e04e8a4cb355c70..f7636b9d6e8ff8e0c020ad3afa0d56f21dd54ff5 100644 --- a/src/xrt/state_trackers/gui/gui_prober.c +++ b/src/xrt/state_trackers/gui/gui_prober.c @@ -38,7 +38,7 @@ gui_prober_init(struct gui_program *p) int ret = 0; // Initialize the prober. - ret = xrt_instance_create(&p->instance); + ret = xrt_instance_create(&p->instance, NULL); if (ret != 0) { return do_exit(p, ret); } diff --git a/src/xrt/state_trackers/oxr/oxr_event.c b/src/xrt/state_trackers/oxr/oxr_event.c index ec906d7b4d3b4b20e68d7c3cab2cd09e9a528ec4..5c2931d1edc7657ea07058dd7a5d229ac12c807f 100644 --- a/src/xrt/state_trackers/oxr/oxr_event.c +++ b/src/xrt/state_trackers/oxr/oxr_event.c @@ -157,6 +157,26 @@ oxr_event_push_XrEventDataSessionStateChanged(struct oxr_logger *log, return XR_SUCCESS; } +XrResult +oxr_event_push_XrEventDataMainSessionVisibilityChangedEXTX( + struct oxr_logger *log, struct oxr_session *sess, bool visible) +{ + struct oxr_instance *inst = sess->sys->inst; + XrEventDataMainSessionVisibilityChangedEXTX *changed; + struct oxr_event *event = NULL; + + ALLOC(log, inst, &event, &changed); + changed->type = XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX; + changed->flags = 0; + changed->visible = visible; + event->result = XR_SUCCESS; + lock(inst); + push(inst, event); + unlock(inst); + + return XR_SUCCESS; +} + XrResult oxr_event_remove_session_events(struct oxr_logger *log, struct oxr_session *sess) @@ -202,7 +222,7 @@ oxr_poll_event(struct oxr_logger *log, { struct oxr_session *sess = inst->sessions; while (sess) { - oxr_session_poll(sess); + oxr_session_poll(log, sess); sess = sess->next; } diff --git a/src/xrt/state_trackers/oxr/oxr_extension_support.h b/src/xrt/state_trackers/oxr/oxr_extension_support.h index 3b67dd02029939f015748a1eb90287f64bd41d55..0f8cd7974776e5d595af956dc3b0f73b21e5ee4e 100644 --- a/src/xrt/state_trackers/oxr/oxr_extension_support.h +++ b/src/xrt/state_trackers/oxr/oxr_extension_support.h @@ -101,6 +101,16 @@ #define OXR_EXTENSION_SUPPORT_MND_headless(_) #endif +/* + * XR_EXTX_overlay + */ +#if defined(XR_EXTX_overlay) +#define OXR_HAVE_EXTX_overlay +#define OXR_EXTENSION_SUPPORT_EXTX_overlay(_) _(EXTX_overlay, EXTX_OVERLAY) +#else +#define OXR_EXTENSION_SUPPORT_EXTX_overlay(_) +#endif + // end of GENERATED per-extension defines - do not modify - used by scripts /*! @@ -131,5 +141,6 @@ OXR_EXTENSION_SUPPORT_KHR_opengl_es_enable(_) \ OXR_EXTENSION_SUPPORT_KHR_vulkan_enable(_) \ OXR_EXTENSION_SUPPORT_MNDX_egl_enable(_) \ - OXR_EXTENSION_SUPPORT_MND_headless(_) + OXR_EXTENSION_SUPPORT_MND_headless(_) \ + OXR_EXTENSION_SUPPORT_EXTX_overlay(_) // clang-format on diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c index f8910417b948beaa78ade77fe652761be5bc6d93..db324f8fa7f7399fa532e50dfc51879c56db2acf 100644 --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -7,11 +7,6 @@ * @ingroup oxr_main */ -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <math.h> - #include "util/u_var.h" #include "util/u_time.h" #include "util/u_misc.h" @@ -24,6 +19,13 @@ #include "oxr_handle.h" #include "oxr_extension_support.h" +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> + DEBUG_GET_ONCE_BOOL_OPTION(debug_views, "OXR_DEBUG_VIEWS", false) DEBUG_GET_ONCE_BOOL_OPTION(debug_spaces, "OXR_DEBUG_SPACES", false) @@ -167,7 +169,16 @@ oxr_instance_create(struct oxr_logger *log, cache_path(log, inst, "/interaction_profiles/mnd/ball_on_stick_controller", &inst->path_cache.mnd_ball_on_stick_controller); // clang-format on - xinst_ret = xrt_instance_create(&inst->xinst); + // fill in our application info - @todo - replicate all createInfo + // fields? + + struct xrt_instance_info i_info = {0}; + i_info.pid = (int32_t)getpid(); + snprintf(i_info.application_name, + sizeof(inst->xinst->instance_info.application_name), "%s", + createInfo->applicationInfo.applicationName); + + xinst_ret = xrt_instance_create(&inst->xinst, &i_info); if (xinst_ret != 0) { ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to create prober"); diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index a15dca7f05fba030bc3c1c25eb91d7d839f51839..89feaa7ec2b9e408397ec3c296a0e1209ffc60c9 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -615,7 +615,7 @@ XrResult oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess); void -oxr_session_poll(struct oxr_session *sess); +oxr_session_poll(struct oxr_logger *log, struct oxr_session *sess); /*! * Get the view space position at the given time in relation to the @@ -828,6 +828,10 @@ oxr_event_push_XrEventDataSessionStateChanged(struct oxr_logger *log, XrSessionState state, XrTime time); +XrResult +oxr_event_push_XrEventDataMainSessionVisibilityChangedEXTX( + struct oxr_logger *log, struct oxr_session *sess, bool visible); + /*! * This clears all pending events refers to the given session. */ diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 35b7e541996c4ba30b8591024a47f440cbab9359..42c4b2f01b777da9119da7c1cf009ec5d7d5785e 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -16,6 +16,7 @@ #include "util/u_debug.h" #include "util/u_misc.h" #include "util/u_time.h" +#include "os/os_time.h" #include "math/m_api.h" @@ -210,10 +211,49 @@ oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess) } void -oxr_session_poll(struct oxr_session *sess) +oxr_session_poll(struct oxr_logger *log, struct oxr_session *sess) { struct xrt_compositor *xc = sess->compositor; - (void)xc; // TODO: dispatch to compositor + struct xrt_ipc_event e; + while (true) { + xc->poll_events(xc, &e); + if (!e.valid) { + break; + } + + // dispatch based on event type + struct xrt_client_state_event *xcse = + (struct xrt_client_state_event *)e.data; + switch (e.type) { + case XRT_EVENT_CLIENT_STATE: { + + if (xcse->visible && sess->state) { + oxr_session_change_state( + log, sess, XR_SESSION_STATE_VISIBLE); + } + if (xcse->focused) { // @todo: this only works + // because focused always + // coincides with visible + oxr_session_change_state( + log, sess, XR_SESSION_STATE_FOCUSED); + } + if (!xcse->visible) { + oxr_session_change_state( + log, sess, XR_SESSION_STATE_SYNCHRONIZED); + } + + + } break; + case XRT_EVENT_OVERLAY: { + struct xrt_overlay_event *ove = + (struct xrt_overlay_event *)&e.data; + oxr_event_push_XrEventDataMainSessionVisibilityChangedEXTX( + log, sess, ove->visible); + } break; + + default: fprintf(stderr, "unhandled event type! %d", e.type); + } + } } XrResult @@ -452,11 +492,15 @@ oxr_session_frame_wait(struct oxr_logger *log, frameState->predictedDisplayTime); } - if (!sess->has_waited_once) { + if (!sess->has_waited_once && sess->state < XR_SESSION_STATE_VISIBLE) { oxr_session_change_state(log, sess, XR_SESSION_STATE_SYNCHRONIZED); - oxr_session_change_state(log, sess, XR_SESSION_STATE_VISIBLE); - oxr_session_change_state(log, sess, XR_SESSION_STATE_FOCUSED); + // oxr_session_change_state(log, sess, + // XR_SESSION_STATE_VISIBLE); //these states will be handled by + // messages received from the compositor + // oxr_session_change_state(log, sess, + // XR_SESSION_STATE_FOCUSED); //these states will be handled by + // messages received from the compositor sess->has_waited_once = true; } @@ -1024,9 +1068,14 @@ oxr_session_frame_end(struct oxr_logger *log, struct xrt_pose inv_offset = {0}; + + + math_pose_invert(&sess->sys->head->tracking_origin->offset, &inv_offset); + + CALL_CHK(xrt_comp_layer_begin(xc, blend_mode)); for (uint32_t i = 0; i < frameEndInfo->layerCount; i++) { @@ -1034,6 +1083,17 @@ oxr_session_frame_end(struct oxr_logger *log, frameEndInfo->layers[i]; assert(layer != NULL); + struct oxr_space *layer_space = + (struct oxr_space *)layer->space; + if (layer_space->type == XR_REFERENCE_SPACE_TYPE_VIEW) { + inv_offset.position.x = 0.0f; + inv_offset.position.y = 0.0f; + inv_offset.position.z = 0.0f; + inv_offset.orientation.x = 0.0f; + inv_offset.orientation.y = 0.0f; + inv_offset.orientation.z = 0.0f; + inv_offset.orientation.w = 1.0f; + } switch (layer->type) { case XR_TYPE_COMPOSITION_LAYER_PROJECTION: submit_projection_layer( @@ -1195,6 +1255,22 @@ oxr_session_create(struct oxr_logger *log, return ret; } + struct xrt_compositor *xc = sess->compositor; + + if (xc != NULL) { + struct xrt_overlay_info oi = {0}; + const XrSessionCreateInfoOverlayEXTX *overlay_info = + OXR_GET_INPUT_FROM_CHAIN( + createInfo, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX, + XrSessionCreateInfoOverlayEXTX); + if (overlay_info) { + oi.is_overlay = true; + oi.flags = overlay_info->createFlags; + oi.z_order = overlay_info->sessionLayersPlacement; + } + xrt_comp_prepare_session(xc, &oi); + } + sess->ipd_meters = debug_get_num_option_ipd() / 1000.0f; sess->static_prediction_s = debug_get_num_option_prediction_ms() / 1000.0f; diff --git a/src/xrt/targets/CMakeLists.txt b/src/xrt/targets/CMakeLists.txt index 1a7c98445211f401f8f5bed1e24e7a950d8781fa..5da63f6136ba4d8ce72a0b558b3ee60394ff1da4 100644 --- a/src/xrt/targets/CMakeLists.txt +++ b/src/xrt/targets/CMakeLists.txt @@ -20,4 +20,5 @@ endif() if(XRT_FEATURE_SERVICE) add_subdirectory(service) + add_subdirectory(monado-ctl) endif() diff --git a/src/xrt/targets/cli/cli_cmd_calibrate.c b/src/xrt/targets/cli/cli_cmd_calibrate.c index eaa4fd91a0425cf165afb27f54e70dd59af8376d..2f3e788293ac640522dd08f9a59684537782ff0b 100644 --- a/src/xrt/targets/cli/cli_cmd_calibrate.c +++ b/src/xrt/targets/cli/cli_cmd_calibrate.c @@ -32,7 +32,7 @@ init(struct program *p) int ret; // Fist initialize the instance. - ret = xrt_instance_create(&p->xi); + ret = xrt_instance_create(&p->xi, NULL); if (ret != 0) { fprintf(stderr, "Failed to create instance\n"); return ret; diff --git a/src/xrt/targets/cli/cli_cmd_probe.c b/src/xrt/targets/cli/cli_cmd_probe.c index 9ed1e2fa811c5c8b1bcfd43817037c0c96611e71..f59c69a3a86b644c0d45c7b6eaf8b072c823d599 100644 --- a/src/xrt/targets/cli/cli_cmd_probe.c +++ b/src/xrt/targets/cli/cli_cmd_probe.c @@ -36,7 +36,7 @@ cli_cmd_probe(int argc, const char **argv) // Initialize the prober. printf(" :: Creating instance!\n"); - ret = xrt_instance_create(&xi); + ret = xrt_instance_create(&xi, NULL); if (ret != 0) { return do_exit(&xi, 0); } diff --git a/src/xrt/targets/cli/cli_cmd_test.c b/src/xrt/targets/cli/cli_cmd_test.c index aace672721ae72053b2f31496b9f11b34764caed..fc0b62fbb365f43f0f8712da797735c7bd569dec 100644 --- a/src/xrt/targets/cli/cli_cmd_test.c +++ b/src/xrt/targets/cli/cli_cmd_test.c @@ -36,7 +36,7 @@ cli_cmd_test(int argc, const char **argv) // Initialize the prober. printf(" :: Creating instance!\n"); - ret = xrt_instance_create(&xi); + ret = xrt_instance_create(&xi, NULL); if (ret != 0) { return do_exit(&xi, 0); } diff --git a/src/xrt/targets/common/target_instance.c b/src/xrt/targets/common/target_instance.c index 60cf99a2c50a4bb96f20256c9d0e2940e924cf8b..fd6ce91655b2594c41127c12913fba5756d8090f 100644 --- a/src/xrt/targets/common/target_instance.c +++ b/src/xrt/targets/common/target_instance.c @@ -35,7 +35,8 @@ t_instance_create_fd_compositor(struct xrt_instance *xinst, */ int -xrt_instance_create(struct xrt_instance **out_xinst) +xrt_instance_create(struct xrt_instance **out_xinst, + struct xrt_instance_info *i_info) { struct xrt_prober *xp = NULL; diff --git a/src/xrt/targets/common/target_instance_no_comp.c b/src/xrt/targets/common/target_instance_no_comp.c index 48fc4899b93cc80710e2eb0a3d46e54896894ecd..927e8e26956a316c9c47d4477c46f65ba22639f6 100644 --- a/src/xrt/targets/common/target_instance_no_comp.c +++ b/src/xrt/targets/common/target_instance_no_comp.c @@ -29,7 +29,8 @@ t_instance_create_fd_compositor_stub(struct xrt_instance *xinst, */ int -xrt_instance_create(struct xrt_instance **out_xinst) +xrt_instance_create(struct xrt_instance **out_xinst, + struct xrt_instance_info *i_info) { struct xrt_prober *xp = NULL; diff --git a/src/xrt/targets/monado-ctl/CMakeLists.txt b/src/xrt/targets/monado-ctl/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6015210378e917d33eb0204e36f82202da94a0c6 --- /dev/null +++ b/src/xrt/targets/monado-ctl/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright 2020, Collabora, Ltd. +# SPDX-License-Identifier: BSL-1.0 + + +add_executable(monado-ctl + main.c + ) + + target_include_directories(monado-ctl PRIVATE + ipc + ) + +target_link_libraries(monado-ctl PRIVATE + aux_util + ipc_client + ) + +install(TARGETS monado-ctl + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + diff --git a/src/xrt/targets/monado-ctl/main.c b/src/xrt/targets/monado-ctl/main.c new file mode 100644 index 0000000000000000000000000000000000000000..8644badcbdff762b4616b11672cd29a55bc7cc06 --- /dev/null +++ b/src/xrt/targets/monado-ctl/main.c @@ -0,0 +1,161 @@ + +#include "ipc_client.h" +#include "ipc_client_generated.h" + +#include <sys/socket.h> +#include <sys/un.h> +#include <ctype.h> +#include <unistd.h> + +typedef enum op_mode +{ + MODE_GET, + MODE_SET_PRIMARY, + MODE_SET_FOCUSED, + +} op_mode_t; + + +int +main(int argc, char *argv[]) +{ + ipc_connection_t ipc_c; + os_mutex_init(&ipc_c.mutex); + + op_mode_t op_mode = MODE_GET; + + // parse arguments + int c; + int s_val = 0; + + opterr = 0; + while ((c = getopt(argc, argv, "p:f:")) != -1) { + switch (c) { + case 'p': + s_val = atoi(optarg); + if (s_val >= 0 && s_val < IPC_MAX_CLIENTS) { + op_mode = MODE_SET_PRIMARY; + } + break; + case 'f': + s_val = atoi(optarg); + if (s_val >= 0 && s_val < IPC_MAX_CLIENTS) { + op_mode = MODE_SET_FOCUSED; + } + break; + + case '?': + if (optopt == 's') { + fprintf(stderr, + "Option -s requires an id to set.\n"); + } else if (isprint(optopt)) { + fprintf(stderr, "Option `-%c' unknown.\n", + optopt); + } else { + fprintf(stderr, "Option `\\x%x' unknown.\n", + optopt); + } + exit(1); + default: exit(0); + } + } + + bool socket_created = true; + bool socket_connected = true; + + int fd; + struct sockaddr_un addr; + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + printf("Socket Create Error!\n"); + socket_created = false; + } + + if (socket_created) { + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, IPC_MSG_SOCK_FILE); + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + printf("Socket Connect error!\n"); + socket_connected = false; + } + } + + if (socket_connected) { + + ipc_c.socket_fd = fd; + + struct xrt_client_state cs; + cs.info.pid = getpid(); + snprintf(cs.info.application_name, + sizeof(cs.info.application_name), "%s", "monado-ctl"); + + xrt_result_t r = + ipc_call_system_set_client_info(&ipc_c, &cs); + + if (r != XRT_SUCCESS) { + printf("failed to set client info.\n"); + exit(1); + } + switch (op_mode) { + case MODE_GET: { + + struct ipc_client_list clients; + xrt_result_t r = + ipc_call_system_get_clients(&ipc_c, &clients); + if (r != XRT_SUCCESS) { + printf("failed to get client list.\n"); + exit(1); + } + + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + if (clients.ids[i] >= 0) { + struct xrt_client_state cs; + xrt_result_t r = + ipc_call_system_get_client_info( + &ipc_c, i, &cs); + if (r != XRT_SUCCESS) { + printf( + "failed to get client info " + "for client %d.\n", + i); + exit(1); + } + printf( + "id: %d\tact: %d\tdisp: " + "%d\tfoc: %d\tovly: %d\tz: " + "%d\tpid: " + "%d\t %s\t\n", + clients.ids[i], cs.session_active, + cs.session_visible, + cs.session_focused, + cs.session_overlay, cs.z_order, + cs.info.pid, + cs.info.application_name); + } + } + + } break; + case MODE_SET_PRIMARY: { + xrt_result_t r = + ipc_call_system_set_primary_client(&ipc_c, s_val); + if (r != XRT_SUCCESS) { + printf("failed to set active client to %d.\n", + s_val); + exit(1); + } + } break; + case MODE_SET_FOCUSED: { + xrt_result_t r = + ipc_call_system_set_focused_client(&ipc_c, s_val); + if (r != XRT_SUCCESS) { + printf("failed to set focused client to %d.\n", + s_val); + exit(1); + } + } break; + default: printf("Unrecognised operation mode.\n"); exit(1); + } + } + close(fd); +} diff --git a/src/xrt/targets/openxr/target.c b/src/xrt/targets/openxr/target.c index 16ba1aaf747b2dd0c71968c178fad3c2fa13aebe..be2f8280fb4869b98ff0049a17d80221b87469f4 100644 --- a/src/xrt/targets/openxr/target.c +++ b/src/xrt/targets/openxr/target.c @@ -14,12 +14,14 @@ // Forward declaration int -ipc_instance_create(struct xrt_instance **out_xinst); +ipc_instance_create(struct xrt_instance **out_xinst, + struct xrt_instance_info *i_info); int -xrt_instance_create(struct xrt_instance **out_xinst) +xrt_instance_create(struct xrt_instance **out_xinst, + struct xrt_instance_info *i_info) { - return ipc_instance_create(out_xinst); + return ipc_instance_create(out_xinst, i_info); } #else