Functional hot reloading
This commit is contained in:
parent
9a4c57d4c2
commit
23bafb943f
4 changed files with 58 additions and 13 deletions
8
Makefile
8
Makefile
|
|
@ -1,8 +1,8 @@
|
||||||
INTERFACEDIR:=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
|
INTERFACEDIR:=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
|
||||||
CFLAGS=-Wall -Wextra -Og -ggdb3 -Wno-unused-but-set-variable -Wno-unused-parameter
|
CFLAGS=-Wall -Wextra -Og -ggdb3 -Wno-unused-but-set-variable -Wno-unused-parameter -Wl,--export-dynamic
|
||||||
LIBS=-lwayland-client -lwayland-egl -lEGL -lOpenGL -lxkbcommon -levdev
|
LIBS=-lwayland-client -lwayland-egl -lEGL -lOpenGL -lxkbcommon -levdev
|
||||||
wayland: wayland.c xdg-shell-protocol.c xdg-shell-client-protocol.h zwp-text-input-unstable-v3-client-protocol.c zwp-text-input-unstable-v3-protocol.h xdg-decoration-unstable-v1.c xdg-decoration-unstable-v1.h
|
wayland: wayland.c xdg-shell-protocol.c xdg-shell-client-protocol.h zwp-text-input-unstable-v3-client-protocol.c zwp-text-input-unstable-v3-protocol.h xdg-decoration-unstable-v1.c xdg-decoration-unstable-v1.h game.h
|
||||||
gcc $(CFLAGS) $(LIBS) wayland.c xdg-shell-protocol.c xdg-decoration-unstable-v1.c zwp-text-input-unstable-v3-client-protocol.c -o wayland
|
gcc $(CFLAGS) $(LIBS) $^ -o wayland
|
||||||
|
|
||||||
# TODO: Normalize these annoying names
|
# TODO: Normalize these annoying names
|
||||||
xdg-shell-protocol.c:
|
xdg-shell-protocol.c:
|
||||||
|
|
@ -18,4 +18,4 @@ xdg-decoration-unstable-v1.c:
|
||||||
xdg-decoration-unstable-v1.h:
|
xdg-decoration-unstable-v1.h:
|
||||||
wayland-scanner client-header $(INTERFACEDIR)/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml xdg-decoration-unstable-v1.h
|
wayland-scanner client-header $(INTERFACEDIR)/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml xdg-decoration-unstable-v1.h
|
||||||
game.so: game.c game.h
|
game.so: game.c game.h
|
||||||
gcc $(CFLAGS) game.c --shared -o game.so
|
gcc $(CFLAGS) game.c -shared -o game.so
|
||||||
|
|
|
||||||
2
game.c
2
game.c
|
|
@ -3,5 +3,5 @@
|
||||||
void simulate_frame(game_state_t *state)
|
void simulate_frame(game_state_t *state)
|
||||||
{
|
{
|
||||||
// TODO: Do something amazing here
|
// TODO: Do something amazing here
|
||||||
;
|
state->version = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
game.h
1
game.h
|
|
@ -11,6 +11,7 @@ typedef struct {
|
||||||
int32_t window_w;
|
int32_t window_w;
|
||||||
int64_t frame;
|
int64_t frame;
|
||||||
double dt;
|
double dt;
|
||||||
|
int32_t version;
|
||||||
} game_state_t;
|
} game_state_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
60
wayland.c
60
wayland.c
|
|
@ -18,6 +18,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
// libevdev
|
// libevdev
|
||||||
#include <libevdev-1.0/libevdev/libevdev.h>
|
#include <libevdev-1.0/libevdev/libevdev.h>
|
||||||
// generated header using wayland-scanner
|
// generated header using wayland-scanner
|
||||||
|
|
@ -70,12 +71,14 @@ error_level_t error_verbosity = { ERROR_LEVEL_DEBUG };
|
||||||
|
|
||||||
typedef void (*simulate_frame_fn)(game_state_t*);
|
typedef void (*simulate_frame_fn)(game_state_t*);
|
||||||
|
|
||||||
/* Game layer */
|
/* Game layer and hot reload */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
simulate_frame_fn simulate_frame;
|
simulate_frame_fn simulate_frame;
|
||||||
} game_api_t;
|
} game_api_t;
|
||||||
|
|
||||||
game_api_t game_api = {};
|
game_api_t game_api = {};
|
||||||
|
time_t hr_timestamp = 0;
|
||||||
|
void *dlhandle = NULL;
|
||||||
|
|
||||||
char *egl_s(int code)
|
char *egl_s(int code)
|
||||||
{
|
{
|
||||||
|
|
@ -742,16 +745,25 @@ int main()
|
||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
|
|
||||||
// Trying to link with game layer
|
// Trying to link with game layer
|
||||||
void *dlhandle = dlopen("./game.so", RTLD_NOW);
|
dlhandle = dlopen("./game.so", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
|
||||||
if (!dlhandle)
|
if (!dlhandle)
|
||||||
|
{
|
||||||
console_err_ss(MODULE_HOTRELOAD, "Could not load game layer\n");
|
console_err_ss(MODULE_HOTRELOAD, "Could not load game layer\n");
|
||||||
dlerror();
|
dlerror();
|
||||||
|
}
|
||||||
|
|
||||||
game_api.simulate_frame = (simulate_frame_fn)dlsym(dlhandle, "simulate_frame");
|
struct stat fs;
|
||||||
|
if (stat("./game.so", &fs) == -1)
|
||||||
|
console_err_ss(MODULE_HOTRELOAD, "Could not get info for game library: %s\n", strerror(errno));
|
||||||
|
|
||||||
char *dlerr = NULL;
|
{
|
||||||
if ((dlerr = dlerror()))
|
hr_timestamp = fs.st_mtime;
|
||||||
console_err_ss(MODULE_HOTRELOAD, "Could not link game layer: %s\n", dlerr);
|
game_api.simulate_frame = (simulate_frame_fn)dlsym(dlhandle, "simulate_frame");
|
||||||
|
char *dlerr = NULL;
|
||||||
|
if ((dlerr = dlerror()))
|
||||||
|
console_err_ss(MODULE_HOTRELOAD, "Could not link game layer: %s\n", dlerr);
|
||||||
|
}
|
||||||
|
|
||||||
// Main event loop
|
// Main event loop
|
||||||
int framecount = 0;
|
int framecount = 0;
|
||||||
|
|
@ -759,6 +771,37 @@ int main()
|
||||||
{
|
{
|
||||||
wl_display_dispatch_pending(display);
|
wl_display_dispatch_pending(display);
|
||||||
|
|
||||||
|
// TODO: Do not try to hot-reload every frame. Lmao
|
||||||
|
struct stat file_stats;
|
||||||
|
if (stat("./game.so", &file_stats) == -1)
|
||||||
|
{
|
||||||
|
console_err_ss(MODULE_HOTRELOAD, "Could not get info for game library: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
else if (hr_timestamp < file_stats.st_mtime)
|
||||||
|
{
|
||||||
|
console_log_ss(MODULE_HOTRELOAD, "Game library has changed: trying to hot reload\n");
|
||||||
|
|
||||||
|
// NOTE: We cannot load new symbols from the same path unless we close the currently open handle.
|
||||||
|
// However, until the linker is done with the file it will fail on dlopen.
|
||||||
|
// For now we just busywait trying to link it.
|
||||||
|
dlclose(dlhandle);
|
||||||
|
while (!(dlhandle = dlopen("./game.so", RTLD_NOW | RTLD_LOCAL)));
|
||||||
|
|
||||||
|
|
||||||
|
hr_timestamp = fs.st_mtime;
|
||||||
|
game_api.simulate_frame = (simulate_frame_fn)dlsym(dlhandle, "simulate_frame");
|
||||||
|
char *dlerr = NULL;
|
||||||
|
if ((dlerr = dlerror()))
|
||||||
|
console_err_ss(MODULE_HOTRELOAD, "Could not link game layer: %s\n", dlerr);
|
||||||
|
|
||||||
|
hr_timestamp = file_stats.st_mtime;
|
||||||
|
char *error_string = dlerror();
|
||||||
|
if (error_string)
|
||||||
|
console_err_ss(MODULE_HOTRELOAD, "Error loading game code: %s\n", error_string);
|
||||||
|
|
||||||
|
console_log_ss(MODULE_HOTRELOAD, "Successfully hot reloaded game layer\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* Controller input handling */
|
/* Controller input handling */
|
||||||
if (libevdev_get_fd(libevdev) != -1) // check if we actually found a controller to query
|
if (libevdev_get_fd(libevdev) != -1) // check if we actually found a controller to query
|
||||||
{
|
{
|
||||||
|
|
@ -848,8 +891,9 @@ int main()
|
||||||
game_state.frame = framecount;
|
game_state.frame = framecount;
|
||||||
// TODO: Get delta time since last frame
|
// TODO: Get delta time since last frame
|
||||||
game_state.dt = 0;
|
game_state.dt = 0;
|
||||||
|
|
||||||
game_api.simulate_frame(&game_state);
|
game_api.simulate_frame(&game_state);
|
||||||
|
if (game_state.version != 1)
|
||||||
|
console_debug_ss(MODULE_HOTRELOAD, "Version %d\n", game_state.version);
|
||||||
//console_debug_ss(MODULE_WAYLAND, "Frame %d\n", framecount);
|
//console_debug_ss(MODULE_WAYLAND, "Frame %d\n", framecount);
|
||||||
glClearColor(0.5, 0.3, 0.0, 1.0);
|
glClearColor(0.5, 0.3, 0.0, 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue