diff --git a/src/servers/render_context/opengl_13/sdl3/render_context_opengl_13_sdl3.c b/src/servers/render_context/opengl_13/sdl3/render_context_opengl_13_sdl3.c index 79d5564..d294cc9 100644 --- a/src/servers/render_context/opengl_13/sdl3/render_context_opengl_13_sdl3.c +++ b/src/servers/render_context/opengl_13/sdl3/render_context_opengl_13_sdl3.c @@ -9,6 +9,7 @@ #include "servers/render_context/render_context.h" #include "servers/window_server/sdl3/window_server_sdl3.h" #include "servers/window_server/window_server.h" +#include "types/signal.h" #include "types/types.h" /*struct RenderContextSurface { @@ -25,7 +26,8 @@ do { \ if (!SDL_IsMainThread()) { \ LOG_ERROR( \ - "WindowServer(SDL3)::" #function " must be called only from main thread or " \ + "RenderContext(OpenGL 1.3, SDL3)::" #function \ + " must be called only from main thread or " \ "via call_deferred/call_deferred_async" \ ) \ set_error(NOT_MAIN_THREAD_ERROR); \ @@ -37,6 +39,21 @@ const static u32 INIT_FLAGS = SDL_INIT_VIDEO | SDL_INIT_EVENTS; static u8 g_isInit = 0; +struct ServerSignal { + Signal* signal; + c_str name; + c_str description; +}; + +// clang-format off +static Signal g_signalGlContextCreated; + +#define SERVER_SIGNAL(_signal, _name, _description) (struct ServerSignal) {.signal = _signal, .name = _name, .description = _description} +static struct ServerSignal g_signals[] = { + SERVER_SIGNAL(&g_signalGlContextCreated, "gl_context_created", "") +}; +// clang-format on + static boolean _init(void) { if (!SDL_WasInit(INIT_FLAGS)) { if (!SDL_Init(INIT_FLAGS)) { @@ -46,6 +63,13 @@ static boolean _init(void) { g_isInit = 1; } + for (usize i = 0; i < (sizeof(g_signals) / sizeof(g_signals[0])); ++i) { + if (!signal_constructor(g_signals[i].signal)) { + LOG_ERROR("RenderContext::_init: Signal initializaito failed"); + return false; + } + } + return true; } @@ -53,10 +77,69 @@ static boolean _quit(void) { if (g_isInit) { SDL_QuitSubSystem(INIT_FLAGS); } + + for (usize i = 0; i < (sizeof(g_signals) / sizeof(g_signals[0])); ++i) { + signal_destructor(g_signals[i].signal); + } return true; } +static SignalCallbackHandler impl_signal_connect(c_str name, SignalCallbackFunc func, void* ctx) { + ERROR_ARGS_CHECK_2(name, func, { return 0; }); + + for (usize i = 0; i < (sizeof(g_signals) / sizeof(g_signals[0])); ++i) { + if (strcmp(name, g_signals[i].name) == 0) { + return signal_connect(g_signals[i].signal, func, ctx); + } + } + + LOG_WARN("RenderContext(OpenGL 1.3, SDL3)::signal_connect: Signal '%s' not found", name); + set_error(ERROR_NOT_FOUND); + return 0; +} + +static boolean impl_signal_disconnect(c_str name, SignalCallbackHandler handler) { + ERROR_ARGS_CHECK_2(name, handler, { return false; }); + + for (usize i = 0; i < (sizeof(g_signals) / sizeof(g_signals[0])); ++i) { + if (strcmp(name, g_signals[i].name) == 0) { + return signal_disconnect(g_signals[i].signal, handler); + } + } + + LOG_WARN("RenderContext.signal_disconnect: Signal '%s' not found", name); + set_error(ERROR_NOT_FOUND); + return false; +} + +static i32 get_available_signals(c_str* names_buff, c_str* descriptions_buff) { + const usize signals_count = sizeof(g_signals) / sizeof(g_signals[0]); + + if (names_buff) { + names_buff = tmalloc(sizeof(c_str) * signals_count); + ERROR_ALLOC_CHECK(names_buff, { return 0; }); + } + + if (descriptions_buff) { + descriptions_buff = tmalloc(sizeof(c_str) * signals_count); + ERROR_ALLOC_CHECK(descriptions_buff, { + tfree(names_buff); + return 0; + }); + } + + for (usize i = 0; i < (sizeof(g_signals) / sizeof(g_signals[0])); ++i) { + if (names_buff) + names_buff[i] = g_signals[i].name; + if (descriptions_buff) + descriptions_buff[i] = g_signals[i].description; + } + + return signals_count; +} + + static SDL_GLContext g_openglSharedContext = NULL; static RenderContextSurface* create_surface(WindowServerWindow* window) { ERROR_ARGS_CHECK_1(window, { return NULL; }); @@ -66,10 +149,16 @@ static RenderContextSurface* create_surface(WindowServerWindow* window) { g_openglSharedContext = SDL_GL_CreateContext((SDL_Window*) window); if (!g_openglSharedContext) { - LOG_FATAL("Failed to create shared OpenGL context. SDL Error: %s", SDL_GetError()); + LOG_FATAL( + "RenderContext.create_surface: Failed to create shared OpenGL context. SDL Error: " + "%s", + SDL_GetError() + ); set_error(ANY_ERROR); return NULL; } + + signal_emit(&g_signalGlContextCreated, NULL); } return (RenderContextSurface*) window; @@ -92,7 +181,10 @@ static boolean surface_make_current(RenderContextSurface* surface) { } if (!SDL_GL_MakeCurrent((SDL_Window*) surface, g_openglSharedContext)) { - LOG_FATAL("Failed to change OpenGL context. SDL Error: %s", SDL_GetError()); + LOG_FATAL( + "RenderContext.surface_make_current: Failed to change OpenGL context. SDL Error: %s", + SDL_GetError() + ); set_error(ANY_ERROR); return false; } @@ -111,27 +203,35 @@ static boolean surface_present(RenderContextSurface* surface) { return false; } if (!SDL_GL_SwapWindow((SDL_Window*) surface)) { - LOG_FATAL("Failed to swap window's buffers. SDL Error: %s", SDL_GetError()); + LOG_FATAL( + "RenderContext.surface_present: Failed to swap window's buffers. SDL Error: %s", + SDL_GetError() + ); set_error(ANY_ERROR); return false; } return true; } - -#define REGISTER(fn) render_context_backend_set_function(backend, #fn, (fptr) fn) +#define REGISTER_WITH_NAME(name, fn) render_context_backend_set_function(backend, name, (fptr) fn) +#define REGISTER(fn) REGISTER_WITH_NAME(#fn, fn) void render_context_opengl_13_sdl3_backend_register(void) { RenderContextBackend* backend = render_context_backend_new(); REGISTER(_init); REGISTER(_quit); + + REGISTER_WITH_NAME("signal_connect", impl_signal_connect); + REGISTER_WITH_NAME("signal_disconnect", impl_signal_disconnect); + REGISTER(get_available_signals); + REGISTER(create_surface); REGISTER(destroy_surface); REGISTER(surface_make_current); REGISTER(surface_present); - render_context_backend_set_function(backend, "get_proc_addr", (fptr) SDL_GL_GetProcAddress); + REGISTER_WITH_NAME("get_proc_addr", SDL_GL_GetProcAddress); render_context_register_backend("OpenGL 1.3", "SDL3", backend); } diff --git a/src/servers/render_context/render_context.h b/src/servers/render_context/render_context.h index 0e2ba05..db18003 100644 --- a/src/servers/render_context/render_context.h +++ b/src/servers/render_context/render_context.h @@ -2,6 +2,7 @@ #include #include +#include #include @@ -23,6 +24,12 @@ typedef struct { boolean (*_init)(void); boolean (*_quit)(void); + // TODO: change to StringSlice when fix/string PR is will be allowed + SignalCallbackHandler (*signal_connect)(c_str name, SignalCallbackFunc func, void* ctx); + boolean (*signal_disconnect)(c_str name, SignalCallbackHandler); + i32 (*get_available_signals)(c_str* names_buff, c_str* descriptions_buff); + + RenderContextSurface* (*create_surface)(WindowServerWindow* window); boolean (*destroy_surface)(RenderContextSurface* surface);