Преглед на файлове

Run updates in background threads.

Fredrik Hultin преди 9 години
родител
ревизия
028cb435e9
променени са 7 файла, в които са добавени 331 реда и са изтрити 20 реда
  1. 49 0
      include/openhmd.h
  2. 3 3
      src/drv_external/external.c
  3. 110 16
      src/openhmd.c
  4. 14 1
      src/openhmdi.h
  5. 79 0
      src/platform-posix.c
  6. 61 0
      src/platform-win32.c
  7. 15 0
      src/platform.h

+ 49 - 0
include/openhmd.h

@@ -140,12 +140,21 @@ typedef enum {
 	OHMD_DRIVER_PROPERTIES	= 1,
 } ohmd_data_value;
 
+typedef enum {
+	/** int[1] (set, default: 1): Set this to 0 to prevent OpenHMD from creating background threads to do automatic device updating.
+	    Note that you have to manually call ohmd_update(); at least once per frame if you disable the threads. */
+	OHMD_IDS_AUTOMATIC_UPDATE = 0,
+} ohmd_int_settings;
+
 /** An opaque pointer to a context structure. */
 typedef struct ohmd_context ohmd_context;
 
 /** An opaque pointer to a structure representing a device, such as an HMD. */
 typedef struct ohmd_device ohmd_device;
 
+/** An opaque pointer to a structure representing arguments for a device. */
+typedef struct ohmd_device_settings ohmd_device_settings;
+
 /**
  * Create an OpenHMD context.
  *
@@ -231,6 +240,46 @@ OHMD_APIENTRYDLL const char* OHMD_APIENTRY ohmd_list_gets(ohmd_context* ctx, int
 OHMD_APIENTRYDLL ohmd_device* OHMD_APIENTRY ohmd_list_open_device(ohmd_context* ctx, int index);
 
 /**
+ * Open a device with additional settings provided.
+ *
+ * Opens a device from a zero indexed enumeration index between 0 and (max - 1)
+ * where max is the number ohmd_ctx_probe returned (i.e. if ohmd_ctx_probe returns 3,
+ * valid indices are 0, 1 and 2).
+ *
+ * ohmd_ctx_probe must be called before calling ohmd_list_open_device.
+ *
+ * @param ctx A (probed) context.
+ * @param index An index, between 0 and the value returned from ohmd_ctx_probe.
+ * @param settings A pointer to a device settings struct.
+ * @return a pointer to an ohmd_device, which represents a hardware device, such as an HMD.
+ **/
+OHMD_APIENTRYDLL ohmd_device* OHMD_APIENTRY ohmd_list_open_device_s(ohmd_context* ctx, int index, ohmd_device_settings* settings);
+
+/**
+ * Specify int settings in a device settings struct.
+ *
+ * @param settings The device settings struct to set values to.
+ * @param key The specefic setting you wish to set.
+ * @param value A pointer to an int or int array (containing the expected number of elements) with the value(s) you wish to set.
+ **/
+OHMD_APIENTRYDLL void OHMD_APIENTRY ohmd_device_settings_seti(ohmd_device_settings* settings, ohmd_int_settings key, const int* val);
+
+/**
+ * Create a device settings instance.
+ *
+ * @param ctx A pointer to a valid ohmd_context.
+ * @return a pointer to an allocated ohmd_context on success or NULL if it fails.
+ **/
+OHMD_APIENTRYDLL ohmd_device_settings* OHMD_APIENTRY ohmd_device_settings_create(ohmd_context* ctx);
+
+/**
+ * Destroy a device settings instance.
+ *
+ * @param ctx The device settings instance to destroy.
+ **/
+OHMD_APIENTRYDLL void OHMD_APIENTRY ohmd_device_settings_destroy(ohmd_device_settings* settings);
+
+/**
  * Close a device.
  *
  * Closes a device opened by ohmd_list_open_device. Note that ohmd_ctx_destroy automatically closes any open devices

+ 3 - 3
src/drv_external/external.c

@@ -138,9 +138,9 @@ ohmd_driver* ohmd_create_external_drv(ohmd_context* ctx)
 }
 
 /* external specific functions */
-static void set_external_properties(ohmd_device* device, ohmd_device_properties* props)
+/*static void set_external_properties(ohmd_device* device, ohmd_device_properties* props)
 {
-    external_priv* priv = (external_priv*)device;
+	external_priv* priv = (external_priv*)device;
 
 	priv->base.properties.hsize = props->hsize;
 	priv->base.properties.vsize = props->vsize;
@@ -150,4 +150,4 @@ static void set_external_properties(ohmd_device* device, ohmd_device_properties*
 	priv->base.properties.lens_vpos = props->lens_vpos;
 	priv->base.properties.fov = DEG_TO_RAD(props->fov);
 	priv->base.properties.ratio = props->ratio;
-}
+}*/

+ 110 - 16
src/openhmd.c

@@ -12,6 +12,9 @@
 #include <string.h>
 #include <stdio.h>
 
+// Running automatic updates at 144 Hz
+#define AUTOMATIC_UPDATE_SLEEP (1.0 / 144.0)
+
 ohmd_context* OHMD_APIENTRY ohmd_ctx_create(void)
 {
 	ohmd_context* ctx = calloc(1, sizeof(ohmd_context));
@@ -34,6 +37,8 @@ ohmd_context* OHMD_APIENTRY ohmd_ctx_create(void)
 	// add dummy driver last to make it the lowest priority
 	ctx->drivers[ctx->num_drivers++] = ohmd_create_dummy_drv(ctx);
 
+	ctx->update_request_quit = false;
+
 	return ctx;
 }
 
@@ -46,14 +51,23 @@ void OHMD_APIENTRY ohmd_ctx_destroy(ohmd_context* ctx)
 	for(int i = 0; i < ctx->num_drivers; i++){
 		ctx->drivers[i]->destroy(ctx->drivers[i]);
 	}
+		
+	ctx->update_request_quit = true;
+
+	if(ctx->update_thread){
+		ohmd_destroy_thread(ctx->update_thread);
+		ohmd_destroy_mutex(ctx->update_mutex);
+	}
 
 	free(ctx);
 }
 
 void OHMD_APIENTRY ohmd_ctx_update(ohmd_context* ctx)
 {
-	for(int i = 0; i < ctx->num_active_devices; i++)
-		ctx->active_devices[i]->update(ctx->active_devices[i]);
+	for(int i = 0; i < ctx->num_active_devices; i++){
+		if(!ctx->active_devices[i]->settings.automatic_update && ctx->active_devices[i]->update)
+			ctx->active_devices[i]->update(ctx->active_devices[i]);
+	}
 }
 
 const char* OHMD_APIENTRY ohmd_ctx_get_error(ohmd_context* ctx)
@@ -88,8 +102,39 @@ const char* OHMD_APIENTRY ohmd_list_gets(ohmd_context* ctx, int index, ohmd_stri
 	}
 }
 
-ohmd_device* OHMD_APIENTRY ohmd_list_open_device(ohmd_context* ctx, int index)
+static unsigned int ohmd_update_thread(void* arg)
+{
+	ohmd_context* ctx = (ohmd_context*)arg;
+	
+	while(!ctx->update_request_quit)
+	{
+		ohmd_lock_mutex(ctx->update_mutex);
+
+		for(int i = 0; i < ctx->num_active_devices; i++){
+			if(ctx->active_devices[i]->settings.automatic_update && ctx->active_devices[i]->update)
+				ctx->active_devices[i]->update(ctx->active_devices[i]);
+		}
+		
+		ohmd_unlock_mutex(ctx->update_mutex);
+
+		ohmd_sleep(AUTOMATIC_UPDATE_SLEEP);
+	}
+
+	return 0;
+}
+
+static void ohmd_set_up_update_thread(ohmd_context* ctx)
+{
+	if(!ctx->update_thread){
+		ctx->update_mutex = ohmd_create_mutex(ctx);
+		ctx->update_thread = ohmd_create_thread(ctx, ohmd_update_thread, ctx);
+	}
+}
+
+ohmd_device* OHMD_APIENTRY ohmd_list_open_device_s(ohmd_context* ctx, int index, ohmd_device_settings* settings)
 {
+	ohmd_lock_mutex(ctx->update_mutex);
+
 	if(index >= 0 && index < ctx->list.num_devices){
 
 		ohmd_device_desc* desc = &ctx->list.devices[index];
@@ -101,18 +146,38 @@ ohmd_device* OHMD_APIENTRY ohmd_list_open_device(ohmd_context* ctx, int index)
 
 		device->rotation_correction.w = 1;
 
+		device->settings = *settings;
+
 		device->ctx = ctx;
 		device->active_device_idx = ctx->num_active_devices;
 		ctx->active_devices[ctx->num_active_devices++] = device;
+
+		if(device->settings.automatic_update)
+			ohmd_set_up_update_thread(ctx);
+
+		ohmd_unlock_mutex(ctx->update_mutex);
 		return device;
 	}
 
+	ohmd_unlock_mutex(ctx->update_mutex);
+
 	ohmd_set_error(ctx, "no device with index: %d", index);
 	return NULL;
 }
 
+ohmd_device* OHMD_APIENTRY ohmd_list_open_device(ohmd_context* ctx, int index)
+{
+	ohmd_device_settings settings;
+
+	settings.automatic_update = true;
+
+	return ohmd_list_open_device_s(ctx, index, &settings);
+}
+
 OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_close_device(ohmd_device* device)
 {
+	ohmd_lock_mutex(device->ctx->update_mutex);
+
 	ohmd_context* ctx = device->ctx;
 	int idx = device->active_device_idx;
 
@@ -125,11 +190,13 @@ OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_close_device(ohmd_device* device)
 
 	for(int i = idx; i < ctx->num_active_devices; i++)
 		ctx->active_devices[i]->active_device_idx--;
+	
+	ohmd_unlock_mutex(device->ctx->update_mutex);
 
 	return OHMD_S_OK;
 }
 
-int OHMD_APIENTRY ohmd_device_getf(ohmd_device* device, ohmd_float_value type, float* out)
+static int ohmd_device_getf_unp(ohmd_device* device, ohmd_float_value type, float* out)
 {
 	switch(type){
 	case OHMD_LEFT_EYE_GL_MODELVIEW_MATRIX: {
@@ -230,7 +297,16 @@ int OHMD_APIENTRY ohmd_device_getf(ohmd_device* device, ohmd_float_value type, f
 	}
 }
 
-int OHMD_APIENTRY ohmd_device_setf(ohmd_device* device, ohmd_float_value type, const float* in)
+int OHMD_APIENTRY ohmd_device_getf(ohmd_device* device, ohmd_float_value type, float* out)
+{
+	ohmd_lock_mutex(device->ctx->update_mutex);
+	int ret = ohmd_device_getf_unp(device, type, out);
+	ohmd_unlock_mutex(device->ctx->update_mutex);
+
+	return ret;
+}
+
+int ohmd_device_setf_unp(ohmd_device* device, ohmd_float_value type, const float* in)
 {
 	switch(type){
 	case OHMD_EYE_IPD:
@@ -282,6 +358,15 @@ int OHMD_APIENTRY ohmd_device_setf(ohmd_device* device, ohmd_float_value type, c
 	}
 }
 
+int OHMD_APIENTRY ohmd_device_setf(ohmd_device* device, ohmd_float_value type, const float* in)
+{
+	ohmd_lock_mutex(device->ctx->update_mutex);
+	int ret = ohmd_device_setf_unp(device, type, in);
+	ohmd_unlock_mutex(device->ctx->update_mutex);
+
+	return ret;
+}
+
 int OHMD_APIENTRY ohmd_device_geti(ohmd_device* device, ohmd_int_value type, int* out)
 {
 	switch(type){
@@ -304,23 +389,32 @@ int OHMD_APIENTRY ohmd_device_seti(ohmd_device* device, ohmd_int_value type, con
 	}
 }
 
-int OHMD_APIENTRY ohmd_device_set_data(ohmd_device* device, ohmd_data_value type, const void* in)
+
+int ohmd_device_set_data_unp(ohmd_device* device, ohmd_data_value type, const void* in)
 {
     switch(type){
-    case OHMD_DRIVER_DATA:{
-        device->set_data(device, OHMD_DRIVER_DATA, in);
-        return OHMD_S_OK;
-    }
-    case OHMD_DRIVER_PROPERTIES:{
-        device->set_data(device, OHMD_DRIVER_PROPERTIES, in);
-        return OHMD_S_OK;
-    }
-    break;
+    case OHMD_DRIVER_DATA:
+			device->set_data(device, OHMD_DRIVER_DATA, in);
+			return OHMD_S_OK;
+
+    case OHMD_DRIVER_PROPERTIES:
+			device->set_data(device, OHMD_DRIVER_PROPERTIES, in);
+			return OHMD_S_OK;
+
     default:
-        return OHMD_S_INVALID_PARAMETER;
+      return OHMD_S_INVALID_PARAMETER;
     }
 }
 
+int OHMD_APIENTRY ohmd_device_set_data(ohmd_device* device, ohmd_data_value type, const void* in)
+{
+	ohmd_lock_mutex(device->ctx->update_mutex);
+	int ret = ohmd_device_set_data_unp(device, type, in);
+	ohmd_unlock_mutex(device->ctx->update_mutex);
+
+	return ret;
+}
+
 void* ohmd_allocfn(ohmd_context* ctx, const char* e_msg, size_t size)
 {
 	void* ret = calloc(1, size);

+ 14 - 1
src/openhmdi.h

@@ -12,6 +12,7 @@
 
 #include "openhmd.h"
 #include "omath.h"
+#include "platform.h"
 
 #include <stdbool.h>
 #include <stdint.h>
@@ -71,6 +72,11 @@ typedef struct {
 		mat4x4f proj_right; // adjusted projection matrix for right screen
 } ohmd_device_properties;
 
+struct ohmd_device_settings
+{
+	bool automatic_update;
+};
+
 struct ohmd_device {
 	ohmd_device_properties properties;
 
@@ -86,6 +92,9 @@ struct ohmd_device {
 	void (*close)(ohmd_device* device);
 
 	ohmd_context* ctx;
+
+	ohmd_device_settings settings;
+
 	int active_device_idx; // index into ohmd_device->active_devices[]
 };
 
@@ -98,6 +107,11 @@ struct ohmd_context {
 	ohmd_device* active_devices[256];
 	int num_active_devices;
 
+	ohmd_thread* update_thread;
+	ohmd_mutex* update_mutex;
+
+	bool update_request_quit;
+
 	char error_msg[OHMD_STR_SIZE];
 };
 
@@ -112,7 +126,6 @@ ohmd_driver* ohmd_create_external_drv(ohmd_context* ctx);
 ohmd_driver* ohmd_create_android_drv(ohmd_context* ctx);
 
 #include "log.h"
-#include "platform.h"
 #include "omath.h"
 #include "fusion.h"
 

+ 79 - 0
src/platform-posix.c

@@ -18,6 +18,10 @@
 #include <time.h>
 #include <sys/time.h>
 #include <stdio.h>
+#include <pthread.h>
+
+#include "platform.h"
+#include "openhmdi.h"
 
 // Use clock_gettime if the system implements posix realtime timers
 #ifndef CLOCK_MONOTONIC
@@ -46,4 +50,79 @@ void ohmd_sleep(double seconds)
 	nanosleep(&sleepfor, NULL);
 }
 
+// threads
+
+struct ohmd_thread
+{
+	pthread_t thread;
+	unsigned int (*routine)(void* arg);
+	void* arg;
+};
+
+static void* pthread_wrapper(void* arg)
+{
+	ohmd_thread* my_thread = (ohmd_thread*)arg;
+	my_thread->routine(my_thread->arg);
+	return NULL;
+}
+
+ohmd_thread* ohmd_create_thread(ohmd_context* ctx, unsigned int (*routine)(void* arg), void* arg)
+{
+	ohmd_thread* thread = ohmd_alloc(ctx, sizeof(ohmd_thread));
+	if(thread == NULL)
+		return NULL;
+
+	thread->arg = arg;
+	thread->routine = routine;
+
+	int ret = pthread_create(&thread->thread, NULL, pthread_wrapper, thread);
+
+	if(ret != 0){
+		free(thread);
+		thread = NULL;
+	}
+
+	return thread;
+}
+
+ohmd_mutex* ohmd_create_mutex(ohmd_context* ctx)
+{
+	pthread_mutex_t* mutex = ohmd_alloc(ctx, sizeof(pthread_mutex_t));
+	if(mutex == NULL)
+		return NULL;
+
+	int ret = pthread_mutex_init(mutex, NULL);
+
+	if(ret != 0){
+		free(mutex);
+		mutex = NULL;
+	}
+
+	return (ohmd_mutex*)mutex;
+}
+
+void ohmd_destroy_thread(ohmd_thread* thread)
+{
+	pthread_join(thread->thread, NULL);
+	free(thread);
+}
+
+void ohmd_destroy_mutex(ohmd_mutex* mutex)
+{
+	pthread_mutex_destroy((pthread_mutex_t*)mutex);
+	free(mutex);
+}
+
+void ohmd_lock_mutex(ohmd_mutex* mutex)
+{
+	if(mutex)
+		pthread_mutex_lock((pthread_mutex_t*)mutex);
+}
+
+void ohmd_unlock_mutex(ohmd_mutex* mutex)
+{
+	if(mutex)
+		pthread_mutex_unlock((pthread_mutex_t*)mutex);
+}
+
 #endif

+ 61 - 0
src/platform-win32.c

@@ -33,4 +33,65 @@ void ohmd_sleep(double seconds)
         Sleep((DWORD)(seconds * 1000));
 }
 
+// threads
+
+struct ohmd_thread {
+	HANDLE handle;
+	void* arg;
+	unsigned int (*routine)(void* arg);
+};
+
+struct ohmd_mutex {
+	HANDLE handle;
+};
+
+__stdcall DWORD ohmd_thread_wrapper(void* t)
+{
+	ohmd_thread* thread = (ohmd_thread*)t;
+	return thread->routine(thread->arg);
+}
+
+ohmd_thread* ohmd_create_thread(ohmd_ctx* ctx, unsigned int (*routine)(void* arg), void* arg)
+{
+	ohmd_thread* thread = ohmd_alloc(ctx, sizeof(ohmd_thread));
+	if(!thread)
+		return NULL;
+
+	thread->routine = routine;
+	thread->arg = arg;
+
+	thread->handle = CreateThread(NULL, 0, ohmd_thread_wrapper, thread, 0, NULL);
+
+	return thread;
+}
+
+ohmd_mutex* ohmd_create_mutex(ohmd_ctx* ctx)
+{
+	ohmd_mutex* mutex = ohmd_alloc(ctx, sizeof(ohmd_mutex));
+	if(!mutex)
+		return NULL;
+	
+	mutex->handle = CreateMutex(NULL, FALSE, NULL);
+
+	return mutex;
+}
+
+void ohmd_destroy_mutex(ohmd_mutex* mutex)
+{
+	CloseHandle(mutex->handle);
+	free(mutex);
+}
+
+void ohmd_lock_mutex(ohmd_mutex* mutex)
+{
+	if(mutex)
+		WaitForSingleObject(mutex->handle, INFINITE);
+}
+
+void ohmd_unlock_mutex(ohmd_mutex* mutex)
+{
+	if(mutex)
+		ReleaseMutex(mutex->handle);
+}
+
 #endif

+ 15 - 0
src/platform.h

@@ -10,7 +10,22 @@
 #ifndef PLATFORM_H
 #define PLATFORM_H
 
+#include "openhmd.h"
+
 double ohmd_get_tick();
 void ohmd_sleep(double seconds);
 
+typedef struct ohmd_thread ohmd_thread;
+typedef struct ohmd_mutex ohmd_mutex;
+
+ohmd_mutex* ohmd_create_mutex(ohmd_context* ctx);
+void ohmd_destroy_mutex(ohmd_mutex* mutex);
+
+void ohmd_lock_mutex(ohmd_mutex* mutex);
+void ohmd_unlock_mutex(ohmd_mutex* mutex);
+
+ohmd_thread* ohmd_create_thread(ohmd_context* ctx, unsigned int (*routine)(void* arg), void* arg);
+void ohmd_destroy_thread(ohmd_thread* thread);
+
+
 #endif