From b5e847c8144547b0057ee856e67fb31716b4609a Mon Sep 17 00:00:00 2001
From: Jakob Bornecrantz <jakob@collabora.com>
Date: Tue, 3 Nov 2020 21:39:20 +0000
Subject: [PATCH] ipc: Add support for device provided bindings

---
 src/xrt/ipc/client/ipc_client_device.c  | 26 +++++++++++
 src/xrt/ipc/server/ipc_server_process.c | 59 +++++++++++++++++++++++++
 src/xrt/ipc/shared/ipc_protocol.h       | 47 ++++++++++++++++++--
 3 files changed, 129 insertions(+), 3 deletions(-)

diff --git a/src/xrt/ipc/client/ipc_client_device.c b/src/xrt/ipc/client/ipc_client_device.c
index b07005e2a..a9dc7fc12 100644
--- a/src/xrt/ipc/client/ipc_client_device.c
+++ b/src/xrt/ipc/client/ipc_client_device.c
@@ -188,6 +188,32 @@ ipc_client_device_create(struct ipc_connection *ipc_c,
 		icd->base.outputs = NULL;
 	}
 
+	if (isdev->num_binding_profiles > 0) {
+		icd->base.binding_profiles = U_TYPED_ARRAY_CALLOC(
+		    struct xrt_binding_profile, isdev->num_binding_profiles);
+		icd->base.num_binding_profiles = isdev->num_binding_profiles;
+	}
+
+	for (size_t i = 0; i < isdev->num_binding_profiles; i++) {
+		struct xrt_binding_profile *xbp =
+		    &icd->base.binding_profiles[i];
+		struct ipc_shared_binding_profile *isbp =
+		    &ism->binding_profiles[isdev->first_binding_profile_index +
+		                           i];
+
+		xbp->name = isbp->name;
+		if (isbp->num_inputs > 0) {
+			xbp->inputs =
+			    &ism->input_pairs[isbp->first_input_index];
+			xbp->num_inputs = isbp->num_inputs;
+		}
+		if (isbp->num_outputs > 0) {
+			xbp->outputs =
+			    &ism->output_pairs[isbp->first_output_index];
+			xbp->num_outputs = isbp->num_inputs;
+		}
+	}
+
 	// Setup variable tracker.
 	u_var_add_root(icd, icd->base.str, true);
 	u_var_add_ro_u32(icd, &icd->device_id, "device_id");
diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c
index 50b15405f..e65e22a27 100644
--- a/src/xrt/ipc/server/ipc_server_process.c
+++ b/src/xrt/ipc/server/ipc_server_process.c
@@ -138,6 +138,46 @@ init_tracking_origins(struct ipc_server *s)
 	return 0;
 }
 
+static void
+handle_binding(struct ipc_shared_memory *ism,
+               struct xrt_binding_profile *xbp,
+               struct ipc_shared_binding_profile *isbp,
+               uint32_t *input_pair_index_ptr,
+               uint32_t *output_pair_index_ptr)
+{
+	uint32_t input_pair_index = *input_pair_index_ptr;
+	uint32_t output_pair_index = *output_pair_index_ptr;
+
+	isbp->name = xbp->name;
+
+	// Copy the initial state and also count the number in input_pairs.
+	size_t input_pair_start = input_pair_index;
+	for (size_t k = 0; k < xbp->num_inputs; k++) {
+		ism->input_pairs[input_pair_index++] = xbp->inputs[k];
+	}
+
+	// Setup the 'offsets' and number of input_pairs.
+	if (input_pair_start != input_pair_index) {
+		isbp->num_inputs = input_pair_index - input_pair_start;
+		isbp->first_input_index = input_pair_start;
+	}
+
+	// Copy the initial state and also count the number in outputs.
+	size_t output_pair_start = output_pair_index;
+	for (size_t k = 0; k < xbp->num_outputs; k++) {
+		ism->output_pairs[output_pair_index++] = xbp->outputs[k];
+	}
+
+	// Setup the 'offsets' and number of output_pairs.
+	if (output_pair_start != output_pair_index) {
+		isbp->num_outputs = output_pair_index - output_pair_start;
+		isbp->first_output_index = output_pair_start;
+	}
+
+	*input_pair_index_ptr = input_pair_index;
+	*output_pair_index_ptr = output_pair_index;
+}
+
 static int
 init_shm(struct ipc_server *s)
 {
@@ -185,6 +225,10 @@ init_shm(struct ipc_server *s)
 	count = 0;
 	uint32_t input_index = 0;
 	uint32_t output_index = 0;
+	uint32_t binding_index = 0;
+	uint32_t input_pair_index = 0;
+	uint32_t output_pair_index = 0;
+
 	for (size_t i = 0; i < IPC_SERVER_NUM_XDEVS; i++) {
 		struct xrt_device *xdev = s->idevs[i].xdev;
 		if (xdev == NULL) {
@@ -233,6 +277,21 @@ init_shm(struct ipc_server *s)
 		// Initial update.
 		xrt_device_update_inputs(xdev);
 
+		// Bindings
+		size_t binding_start = binding_index;
+		for (size_t k = 0; k < xdev->num_binding_profiles; k++) {
+			handle_binding(ism, &xdev->binding_profiles[k],
+			               &ism->binding_profiles[binding_index++],
+			               &input_pair_index, &output_pair_index);
+		}
+
+		// Setup the 'offsets' and number of bindings.
+		if (binding_start != binding_index) {
+			isdev->num_binding_profiles =
+			    binding_index - binding_start;
+			isdev->first_binding_profile_index = binding_start;
+		}
+
 		// Copy the initial state and also count the number in inputs.
 		size_t input_start = input_index;
 		for (size_t k = 0; k < xdev->num_inputs; k++) {
diff --git a/src/xrt/ipc/shared/ipc_protocol.h b/src/xrt/ipc/shared/ipc_protocol.h
index 592e3e007..a5559397d 100644
--- a/src/xrt/ipc/shared/ipc_protocol.h
+++ b/src/xrt/ipc/shared/ipc_protocol.h
@@ -35,6 +35,8 @@
 #define IPC_SHARED_MAX_DEVICES 8
 #define IPC_SHARED_MAX_INPUTS 1024
 #define IPC_SHARED_MAX_OUTPUTS 128
+#define IPC_SHARED_MAX_BINDINGS 64
+
 
 /*
  *
@@ -42,6 +44,11 @@
  *
  */
 
+/*!
+ * A tracking in the shared memory area.
+ *
+ * @ingroup ipc
+ */
 struct ipc_shared_tracking_origin
 {
 	//! For debugging.
@@ -54,6 +61,31 @@ struct ipc_shared_tracking_origin
 	struct xrt_pose offset;
 };
 
+/*!
+ * A binding in the shared memory area.
+ *
+ * @ingroup ipc
+ */
+struct ipc_shared_binding_profile
+{
+	enum xrt_device_name name;
+
+	//! Number of inputs.
+	uint32_t num_inputs;
+	//! Offset into the array of pairs where this input bindings starts.
+	uint32_t first_input_index;
+
+	//! Number of outputs.
+	uint32_t num_outputs;
+	//! Offset into the array of pairs where this output bindings starts.
+	uint32_t first_output_index;
+};
+
+/*!
+ * A device in the shared memory area.
+ *
+ * @ingroup ipc
+ */
 struct ipc_shared_device
 {
 	//! Enum identifier of the device.
@@ -66,15 +98,19 @@ struct ipc_shared_device
 	//! A string describing the device.
 	char str[XRT_DEVICE_NAME_LEN];
 
+	//! Number of bindings.
+	uint32_t num_binding_profiles;
+	//! 'Offset' into the array of bindings where the bindings starts.
+	uint32_t first_binding_profile_index;
+
 	//! Number of inputs.
 	uint32_t num_inputs;
-	//! 'Offset' into the array of inputs where this devices inputs starts.
+	//! 'Offset' into the array of inputs where the inputs starts.
 	uint32_t first_input_index;
 
 	//! Number of outputs.
 	uint32_t num_outputs;
-	//! 'Offset' into the array of outputs where this devices outputs
-	//! starts.
+	//! 'Offset' into the array of outputs where the outputs starts.
 	uint32_t first_output_index;
 
 	bool orientation_tracking_supported;
@@ -194,6 +230,11 @@ struct ipc_shared_memory
 
 	struct xrt_output outputs[IPC_SHARED_MAX_OUTPUTS];
 
+	struct ipc_shared_binding_profile
+	    binding_profiles[IPC_SHARED_MAX_BINDINGS];
+	struct xrt_binding_input_pair input_pairs[IPC_SHARED_MAX_INPUTS];
+	struct xrt_binding_output_pair output_pairs[IPC_SHARED_MAX_OUTPUTS];
+
 	struct ipc_layer_slot slots[IPC_MAX_SLOTS];
 };