From 63e3f973b2de8e7a2170161e46712c924f6f67dd Mon Sep 17 00:00:00 2001 From: Kevin Trogant Date: Sat, 14 Oct 2023 00:15:05 +0200 Subject: [PATCH] feat: config variables, mutex abstraction - Mutex abstraction (create, destroy, lock, unlock) - Config variables (cvars) --- include/config.h | 43 ++++++++++++++++++ include/threading.h | 18 ++++++++ include/voyage.h | 1 + meson.build | 9 +++- src/config.c | 39 ++++++++++++++++ src/error_report.c | 56 ++++++++++++++++++++--- src/gfx_shader_loading.c | 2 +- src/threading.c | 98 ++++++++++++++++++++++++++++++++++++++++ src/voyage.c | 1 + 9 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 include/config.h create mode 100644 include/threading.h create mode 100644 src/config.c create mode 100644 src/threading.c diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..8675a66 --- /dev/null +++ b/include/config.h @@ -0,0 +1,43 @@ +#ifndef VY_CONFIG_H +#define VY_CONFIG_H + +typedef enum +{ + VY_CVAR_TYPE_INT, + VY_CVAR_TYPE_FLOAT, + VY_CVAR_TYPE_STRING, +} vy_cvar_type; + +typedef struct +{ + const char *name; + const char *description; + union { + int i; + float f; + const char *s; + }; + vy_cvar_type type; +} vy_cvar; + +#define VY_CVAR_I(n, d, v) \ + vy_cvar n = {.name = #n, \ + .description = d, \ + .i = (v), \ + .type = VY_CVAR_TYPE_INT} +#define VY_CVAR_F(n, d, v) \ + vy_cvar n = {.name = #n, \ + .description = d, \ + .f = (v), \ + .type = VY_CVAR_TYPE_FLOAT} +#define VY_CVAR_S(n, d, v) \ + vy_cvar n = {.name = #n, \ + .description = d, \ + .s = (v), \ + .type = VY_CVAR_TYPE_STRING} + +void vyRegisterCVAR(vy_cvar *cvar); + +vy_cvar *vyGetCVAR(const char *name); + +#endif \ No newline at end of file diff --git a/include/threading.h b/include/threading.h new file mode 100644 index 0000000..83a1199 --- /dev/null +++ b/include/threading.h @@ -0,0 +1,18 @@ +#ifndef VY_THREADING_H +#define VY_THREADING_H + +/* platform independent threading */ + +#include + +typedef struct vy_mutex_s vy_mutex; + +vy_mutex *vyCreateMutex(void); + +void vyDestroyMutex(vy_mutex *mutex); + +bool vyLockMutex(vy_mutex *mutex); + +bool vyUnlockMutex(vy_mutex *mutex); + +#endif diff --git a/include/voyage.h b/include/voyage.h index f66b2e9..7541080 100644 --- a/include/voyage.h +++ b/include/voyage.h @@ -6,6 +6,7 @@ #include #define VY_UNUSED(x) ((void)sizeof((x))) +#define VY_ARRAY_COUNT(x) (sizeof((x)) / sizeof((x)[0])) typedef struct { const char *start; diff --git a/meson.build b/meson.build index b31120e..6414bad 100644 --- a/meson.build +++ b/meson.build @@ -13,9 +13,12 @@ if compiler.get_argument_syntax() == 'gcc' ) elif compiler.get_argument_syntax() == 'msvc' add_project_arguments( - ['/wd4146', '/wd4245', '/wd4100', '/D_CRT_SECURE_NO_WARNINGS', '/RTCsu'], + ['/wd4146', '/wd4245', '/wd4100', '/D_CRT_SECURE_NO_WARNINGS'], language: 'c' ) + if buildtype == 'debug' + add_project_arguments(['/RTCsu'], language : 'c') + endif endif # Debug specific flags @@ -41,6 +44,8 @@ executable('voyage', 'include/gfx.h', 'include/gfx_backend.h', 'include/fio.h', + 'include/config.h', + 'include/threading.h', 'src/voyage.c', 'src/fio.c', @@ -48,6 +53,8 @@ executable('voyage', 'src/gfx_main.c', 'src/gfx_shader_loading.c', 'src/gfx_pipelines.c', + 'src/config.c', + 'src/threading.c', # Contrib Sources 'contrib/glad/glad.c', diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..90aa82e --- /dev/null +++ b/src/config.c @@ -0,0 +1,39 @@ +#include "config.h" +#include "threading.h" +#include "voyage.h" + +#include +#include + +#define VY_MAX_CVARS 1024 + +static vy_cvar *_vars[VY_MAX_CVARS]; +static unsigned int _next = 0; +static vy_mutex *_mutex = NULL; + +void vyRegisterCVAR(vy_cvar *cvar) { + if (!_mutex) + _mutex = vyCreateMutex(); + vyLockMutex(_mutex); + if (_next < VY_MAX_CVARS) { + _vars[_next++] = cvar; + } else { + vyReportError("cvar", "Ran out of space for CVars"); + } + vyUnlockMutex(_mutex); +} + +vy_cvar *vyGetCVAR(const char *name) { + if (!_mutex) + _mutex = vyCreateMutex(); + vy_cvar *var = NULL; + vyLockMutex(_mutex); + for (unsigned int i = 0; i < _next; ++i) { + if (strcmp(name, _vars[i]->name) == 0) { + var = _vars[i]; + break; + } + } + vyUnlockMutex(_mutex); + return var; +} \ No newline at end of file diff --git a/src/error_report.c b/src/error_report.c index 85f96a1..b8210e0 100644 --- a/src/error_report.c +++ b/src/error_report.c @@ -3,22 +3,66 @@ #include "voyage.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + /* TODO(Kevin): Log to file, show error message box, ... */ +static void DisplayErrorBox(const char *text) +{ +#ifdef _WIN32 + WCHAR msg[256]; + MultiByteToWideChar(CP_UTF8, + MB_PRECOMPOSED, + text, + -1, + msg, + VY_ARRAY_COUNT(msg)); + MessageBoxW(NULL, msg, L"Error", MB_ICONERROR); +#endif +} + +static void LogOut(const char *text) +{ +#ifdef _WIN32 + WCHAR msg[256]; + MultiByteToWideChar(CP_UTF8, + MB_PRECOMPOSED, + text, + -1, + msg, + VY_ARRAY_COUNT(msg)); + OutputDebugStringW(msg); +#elif defined(__linux__) + fprintf(stderr, "%s", text); +#endif +} + void vyReportError(const char *subsystem, const char *fmt, ...) { + char buf[256]; + + int at = snprintf(buf, VY_ARRAY_COUNT(buf) - 1, "[%s] ", subsystem); va_list ap; va_start(ap, fmt); - fprintf(stderr, "[%s] ", subsystem); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); + at += vsnprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, fmt, ap); va_end(ap); + at += snprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, "\n"); + + LogOut(buf); + DisplayErrorBox(buf); } void vyLog(const char *subsystem, const char *fmt, ...) { + char buf[256]; + + int at = snprintf(buf, VY_ARRAY_COUNT(buf) - 1, "[%s] ", subsystem); va_list ap; va_start(ap, fmt); - fprintf(stderr, "[%s] ", subsystem); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); + at += vsnprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, fmt, ap); va_end(ap); + at += snprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, "\n"); + + LogOut(buf); } \ No newline at end of file diff --git a/src/gfx_shader_loading.c b/src/gfx_shader_loading.c index e6eb65e..e9acf15 100644 --- a/src/gfx_shader_loading.c +++ b/src/gfx_shader_loading.c @@ -233,7 +233,7 @@ static void DbgPrintShaderFile(const vy_parse_state *state, } stmt_index = stmt->next; } - assert(stmt_index == UINT_MAX); + assert(stmt_index == UINT_MAX || stmt_index == 0); } static bool CompareSpanToString(vy_text_span span, const char *cmp) { diff --git a/src/threading.c b/src/threading.c new file mode 100644 index 0000000..4c6ba18 --- /dev/null +++ b/src/threading.c @@ -0,0 +1,98 @@ +#include "threading.h" +#include "voyage.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +struct vy_mutex_s { + HANDLE handle; + ptrdiff_t next_reusable; +}; + +#define MAX_MUTEX 1024 +static vy_mutex _mutex[MAX_MUTEX]; +static ptrdiff_t _first_reusable = MAX_MUTEX; +static ptrdiff_t _next = 0; + +vy_mutex *vyCreateMutex(void) { + if (_first_reusable < MAX_MUTEX) { + vy_mutex *mtx = &_mutex[_first_reusable]; + _first_reusable = mtx->next_reusable; + return mtx; + } else if (_next < MAX_MUTEX) { + vy_mutex *mtx = &_mutex[_next]; + mtx->handle = CreateMutexW(NULL, FALSE, NULL); + if (!mtx->handle) { + vyLog("core", "Mutex creation failed: %u", GetLastError()); + return NULL; + } + mtx->next_reusable = MAX_MUTEX; + ++_next; + return mtx; + } + vyReportError("core", "Ran out of mutex objects"); + return NULL; +} + +void vyDestroyMutex(vy_mutex *mutex) { + ptrdiff_t index = mutex - &_mutex[0]; + mutex->next_reusable = _first_reusable; + _first_reusable = index; +} + +bool vyLockMutex(vy_mutex *mutex) { + return WaitForSingleObject(mutex->handle, INFINITE) == WAIT_OBJECT_0; +} + +bool vyUnlockMutex(vy_mutex *mutex) { + return ReleaseMutex(mutex) != 0; +} + +#elif defined(__linux__) + +#include +struct vy_mutex_s { + pthread_mutex_t handle; + ptrdiff_t next_reusable; +}; + + #define MAX_MUTEX 1024 +static vy_mutex _mutex[MAX_MUTEX]; +static ptrdiff_t _first_reusable = MAX_MUTEX; +static ptrdiff_t _next = 0; + +vy_mutex *vyCreateMutex(void) { + if (_first_reusable < MAX_MUTEX) { + vy_mutex *mtx = &_mutex[_first_reusable]; + _first_reusable = mtx->next_reusable; + return mtx; + } else if (_next < MAX_MUTEX) { + vy_mutex *mtx = &_mutex[_next]; + if (pthread_mutex_init(&mtx->handle, NULL) != 0) { + vyLog("core", "Mutex creation failed: %u", GetLastError()); + return NULL; + } + mtx->next_reusable = MAX_MUTEX; + ++_next; + return mtx; + } + vyReportError("core", "Ran out of mutex objects"); + return NULL; +} + +void vyDestroyMutex(vy_mutex *mutex) { + ptrdiff_t index = mutex - &_mutex[0]; + mutex->next_reusable = _first_reusable; + _first_reusable = index; +} + +bool vyLockMutex(vy_mutex *mutex) { + return pthread_mutex_lock(&mutex->handle) == 0; +} + +bool vyUnlockMutex(vy_mutex *mutex) { + return pthread_mutex_unlock(&mutex->handle) == 0; +} + +#endif \ No newline at end of file diff --git a/src/voyage.c b/src/voyage.c index 45580b0..10536fe 100644 --- a/src/voyage.c +++ b/src/voyage.c @@ -7,6 +7,7 @@ #include "fio.h" #include "gfx.h" +#include "threading.h" static void glfw_error_cb(int err, const char *description) { fprintf(stderr, "[GLFW] %u: %s\n", err, description);