move opengl library loading to a thread that starts as soon as possible and is awaited as late as we can allow

This commit is contained in:
veclavtalica 2025-01-15 07:54:45 +03:00
parent 8233f31269
commit 449d4d3c32
2 changed files with 116 additions and 95 deletions

View File

@ -28,6 +28,7 @@ typedef struct EngineContext {
char **argv;
/* where the app was run from, used as the root for packs */
char *base_dir;
char *title;
Vec2 window_dims;
Rect viewport_rect;

View File

@ -4,7 +4,6 @@
#include "twn_util.h"
#include "twn_util_c.h"
#include "twn_game_object_c.h"
#include "twn_audio_c.h"
#include "twn_textures_c.h"
#include <SDL2/SDL.h>
@ -20,6 +19,9 @@
#define PACKAGE_EXTENSION "btw"
static SDL_Thread *opengl_load_thread;
static int event_callback(void *userdata, SDL_Event *event) {
(void)userdata;
@ -342,14 +344,16 @@ ERR_PACK_MANIFEST_PATH_ALLOC_FAIL:
}
static bool initialize(void) {
profile_start("SDL initialization");
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS) == -1) {
CRY_SDL("SDL initialization failed.");
return false;
}
profile_end("SDL initialization");
static int opengl_load_thread_fn(void *data) {
(void)data;
SDL_GL_LoadLibrary(NULL);
return 0;
}
static bool initialize(void) {
/* first things first, most things here will be loaded from the config file */
/* it's expected to be present in the data directory, no matter what */
/* that is why PhysicsFS is initialized before anything else */
@ -446,11 +450,11 @@ static bool initialize(void) {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
/* init got far enough to create a window */
{
toml_datum_t datum_title = toml_string_in(about, "title");
if (!datum_title.ok)
datum_title.u.s = "townengine project";
datum_title.u.s = SDL_strdup("townengine project");
ctx.title = datum_title.u.s;
/* not yet used
toml_datum_t datum_developer = toml_string_in(about, "developer");
@ -485,52 +489,7 @@ static bool initialize(void) {
ctx.game.resolution.x = (float)ctx.base_render_width;
ctx.game.resolution.y = (float)ctx.base_render_height;
/* TODO: investigate viability of detached thread driver and window creation, as it's the worst load time offender */
profile_start("window creation");
ctx.window = SDL_CreateWindow(datum_title.u.s,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
(int)ctx.base_render_width,
(int)ctx.base_render_height,
//SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_RESIZABLE |
SDL_WINDOW_OPENGL);
profile_end("window creation");
if (datum_title.ok)
SDL_free(datum_title.u.s);
//SDL_free(datum_developer.u.s);
}
if (ctx.window == NULL) {
CRY_SDL("Window creation failed.");
goto fail;
}
profile_start("opengl context creation");
ctx.gl_context = SDL_GL_CreateContext(ctx.window);
if (!ctx.gl_context) {
CRY_SDL("GL context creation failed.");
goto fail;
}
if (SDL_GL_MakeCurrent(ctx.window, ctx.gl_context)) {
CRY_SDL("GL context binding failed.");
goto fail;
}
/* TODO: figure out what we ultimately prefer */
SDL_GL_SetSwapInterval(0);
if (!render_init())
goto fail;
setup_viewport(0, 0, (int)ctx.base_render_width, (int)ctx.base_render_height);
profile_end("opengl context creation");
/* might need this to have multiple windows */
ctx.window_id = SDL_GetWindowID(ctx.window);
/* TODO: */
// SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h);
@ -628,11 +587,6 @@ static bool initialize(void) {
ctx.render_queue_2d = NULL;
ctx.uncolored_mesh_batches = NULL;
profile_start("texture and text cache initialization");
textures_cache_init(&ctx.texture_cache, ctx.window);
text_cache_init(&ctx.text_cache);
profile_end("texture and text cache initialization");
/* input */
toml_datum_t datum_keybind_slots = toml_int_in(engine, "keybind_slots");
if (!datum_keybind_slots.ok) {
@ -652,6 +606,63 @@ static bool initialize(void) {
ctx.game.fog_color = (Color){ 255, 255, 255, 255 }; /* TODO: pick some grey? */
ctx.game.fog_end = 1.0f;
update_viewport();
profile_start("game object load");
/* now we can actually start doing stuff */
game_object_load();
profile_end("game object load");
/* delayed as further as possible so that more work is done before we have to wait */
SDL_WaitThread(opengl_load_thread, NULL);
profile_end("opengl loading");
/* TODO: investigate viability of detached thread driver and window creation, as it's the worst load time offender */
profile_start("window creation");
ctx.window = SDL_CreateWindow(ctx.title,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
(int)ctx.base_render_width,
(int)ctx.base_render_height,
//SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_RESIZABLE |
SDL_WINDOW_OPENGL);
profile_end("window creation");
if (ctx.window == NULL) {
CRY_SDL("Window creation failed.");
goto fail;
}
profile_start("opengl context creation");
ctx.gl_context = SDL_GL_CreateContext(ctx.window);
if (!ctx.gl_context) {
CRY_SDL("GL context creation failed.");
goto fail;
}
if (SDL_GL_MakeCurrent(ctx.window, ctx.gl_context)) {
CRY_SDL("GL context binding failed.");
goto fail;
}
/* TODO: figure out what we ultimately prefer */
SDL_GL_SetSwapInterval(0);
if (!render_init())
goto fail;
setup_viewport(0, 0, (int)ctx.base_render_width, (int)ctx.base_render_height);
profile_end("opengl context creation");
/* might need this to have multiple windows */
ctx.window_id = SDL_GetWindowID(ctx.window);
profile_start("texture and text cache initialization");
textures_cache_init(&ctx.texture_cache, ctx.window);
text_cache_init(&ctx.text_cache);
profile_end("texture and text cache initialization");
return true;
fail:
@ -674,7 +685,9 @@ static void clean_up(void) {
PHYSFS_deinit();
SDL_free(ctx.base_dir);
SDL_free(ctx.title);
SDL_GL_DeleteContext(ctx.gl_context);
SDL_GL_UnloadLibrary();
SDL_Quit();
}
@ -688,6 +701,20 @@ static void reset_state(void) {
int enter_loop(int argc, char **argv) {
profile_start("startup");
profile_start("SDL initialization");
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS) == -1) {
CRY_SDL("SDL initialization failed.");
return EXIT_FAILURE;
}
profile_end("SDL initialization");
profile_start("opengl loading");
opengl_load_thread = SDL_CreateThread(opengl_load_thread_fn, "opengl loader", NULL);
if (!opengl_load_thread) {
CRY_SDL("Cannot create opengl loading thread: ");
return EXIT_FAILURE;
}
ctx.argc = argc;
ctx.argv = argv;
ctx.base_dir = SDL_GetBasePath();
@ -763,13 +790,6 @@ int enter_loop(int argc, char **argv) {
ctx.game.debug = false;
}
update_viewport();
profile_start("game object load");
/* now we can actually start doing stuff */
game_object_load();
profile_end("game object load");
ctx.was_successful = true;
ctx.game.initialization_needed = true;