double buffer sys events and pass into present job

This commit is contained in:
jacob 2025-07-10 21:59:41 -05:00
parent 66bae61b1a
commit 7e81231639
12 changed files with 72 additions and 104 deletions

View File

@ -279,16 +279,14 @@ void sys_app_entry(struct string args_str)
#endif #endif
/* Startup systems */ /* Startup systems */
struct resource_startup_receipt resource_sr = resource_startup();
gp_startup();
struct sock_startup_receipt sock_sr = sock_startup(); struct sock_startup_receipt sock_sr = sock_startup();
struct host_startup_receipt host_sr = host_startup(&sock_sr); struct host_startup_receipt host_sr = host_startup(&sock_sr);
struct asset_cache_startup_receipt asset_cache_sr = asset_cache_startup(); struct asset_cache_startup_receipt asset_cache_sr = asset_cache_startup();
struct ttf_startup_receipt ttf_sr = ttf_startup(); struct ttf_startup_receipt ttf_sr = ttf_startup();
struct font_startup_receipt font_sr = font_startup(&asset_cache_sr, &ttf_sr, &resource_sr); struct font_startup_receipt font_sr = font_startup(&asset_cache_sr, &ttf_sr);
struct sprite_startup_receipt sprite_sr = sprite_startup(&resource_sr); struct sprite_startup_receipt sprite_sr = sprite_startup();
struct mixer_startup_receipt mixer_sr = mixer_startup(); struct mixer_startup_receipt mixer_sr = mixer_startup();
struct sound_startup_receipt sound_sr = sound_startup(&asset_cache_sr, &resource_sr); struct sound_startup_receipt sound_sr = sound_startup(&asset_cache_sr);
struct draw_startup_receipt draw_sr = draw_startup(&font_sr); struct draw_startup_receipt draw_sr = draw_startup(&font_sr);
struct sim_startup_receipt sim_sr = sim_startup(); struct sim_startup_receipt sim_sr = sim_startup();
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr); struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);

View File

@ -1,14 +1,6 @@
#ifndef APP_H #ifndef APP_H
#define APP_H #define APP_H
enum app_dedicated_worker_id {
APP_DEDICATED_WORKER_ID_USER = 0,
APP_DEDICATED_WORKER_ID_SIM = 1,
APP_DEDICATED_WORKER_ID_AUDIO = 2,
NUM_APP_DEDICATED_WORKERS
};
struct string app_write_path_cat(struct arena *arena, struct string filename); struct string app_write_path_cat(struct arena *arena, struct string filename);
void app_exit(void); void app_exit(void);

View File

@ -40,12 +40,10 @@ GLOBAL struct {
* ========================== */ * ========================== */
struct font_startup_receipt font_startup(struct asset_cache_startup_receipt *asset_cache_sr, struct font_startup_receipt font_startup(struct asset_cache_startup_receipt *asset_cache_sr,
struct ttf_startup_receipt *ttf_sr, struct ttf_startup_receipt *ttf_sr)
struct resource_startup_receipt *resource_sr)
{ {
(UNUSED)asset_cache_sr; (UNUSED)asset_cache_sr;
(UNUSED)ttf_sr; (UNUSED)ttf_sr;
(UNUSED)resource_sr;
G.params.arena = arena_alloc(GIBI(64)); G.params.arena = arena_alloc(GIBI(64));

View File

@ -6,7 +6,6 @@
struct asset; struct asset;
struct asset_cache_startup_receipt; struct asset_cache_startup_receipt;
struct ttf_startup_receipt; struct ttf_startup_receipt;
struct resource_startup_receipt;
struct font_glyph { struct font_glyph {
f32 off_x; f32 off_x;
@ -29,8 +28,7 @@ struct font {
struct font_startup_receipt { i32 _; }; struct font_startup_receipt { i32 _; };
struct font_startup_receipt font_startup(struct asset_cache_startup_receipt *asset_cache_sr, struct font_startup_receipt font_startup(struct asset_cache_startup_receipt *asset_cache_sr,
struct ttf_startup_receipt *ttf_sr, struct ttf_startup_receipt *ttf_sr);
struct resource_startup_receipt *resource_sr);
struct asset *font_load_asset(struct string path, f32 point_size, b32 wait); struct asset *font_load_asset(struct string path, f32 point_size, b32 wait);
struct font *font_load_async(struct string path, f32 point_size); struct font *font_load_async(struct string path, f32 point_size);

View File

@ -33,11 +33,9 @@ GLOBAL struct {
* Startup * Startup
* ========================== */ * ========================== */
struct sound_startup_receipt sound_startup(struct asset_cache_startup_receipt *asset_cache_sr, struct sound_startup_receipt sound_startup(struct asset_cache_startup_receipt *asset_cache_sr)
struct resource_startup_receipt *resource_sr)
{ {
(UNUSED)asset_cache_sr; (UNUSED)asset_cache_sr;
(UNUSED)resource_sr;
G.params.arena = arena_alloc(GIBI(64)); G.params.arena = arena_alloc(GIBI(64));

View File

@ -6,7 +6,6 @@
struct asset; struct asset;
struct asset_cache_startup_receipt; struct asset_cache_startup_receipt;
struct resource_startup_receipt;
struct sound { struct sound {
u32 flags; u32 flags;
@ -14,8 +13,7 @@ struct sound {
}; };
struct sound_startup_receipt { i32 _; }; struct sound_startup_receipt { i32 _; };
struct sound_startup_receipt sound_startup(struct asset_cache_startup_receipt *asset_cache_sr, struct sound_startup_receipt sound_startup(struct asset_cache_startup_receipt *asset_cache_sr);
struct resource_startup_receipt *resource_sr);
struct asset *sound_load_asset(struct string path, u32 flags, b32 wait); struct asset *sound_load_asset(struct string path, u32 flags, b32 wait);
struct sound *sound_load_async(struct string path, u32 flags); struct sound *sound_load_async(struct string path, u32 flags);

View File

@ -208,10 +208,8 @@ INTERNAL SYS_JOB_DEF(sprite_evictor_job, _);
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info); INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info);
#endif #endif
struct sprite_startup_receipt sprite_startup(struct resource_startup_receipt *resource_sr) struct sprite_startup_receipt sprite_startup(void)
{ {
(UNUSED)resource_sr;
G.perm_arena = arena_alloc(MEBI(1)); G.perm_arena = arena_alloc(MEBI(1));
{ {
/* Init loading texture */ /* Init loading texture */

View File

@ -3,7 +3,6 @@
#include "util.h" #include "util.h"
struct resource_startup_receipt;
struct sprite_sheet_span; struct sprite_sheet_span;
struct sprite_sheet_slice_group; struct sprite_sheet_slice_group;
@ -12,7 +11,7 @@ struct sprite_sheet_slice_group;
* ========================== */ * ========================== */
struct sprite_startup_receipt { i32 _; }; struct sprite_startup_receipt { i32 _; };
struct sprite_startup_receipt sprite_startup(struct resource_startup_receipt *resource_sr); struct sprite_startup_receipt sprite_startup(void);
/* ========================== * /* ========================== *
* Tag * Tag

View File

@ -434,16 +434,12 @@ struct sys_window_settings {
i32 floating_height; i32 floating_height;
}; };
struct sys_window_event_job_sig {
struct sys_window *window;
struct sys_event event;
};
struct sys_window_present_job_sig { struct sys_window_present_job_sig {
struct sys_window *window; struct sys_window *window;
struct sys_event_array events;
}; };
struct sys_window *sys_window_alloc(sys_job_func *event_job, sys_job_func *present_job); struct sys_window *sys_window_alloc(sys_job_func *present_job);
void sys_window_release(struct sys_window *sys_window); void sys_window_release(struct sys_window *sys_window);
void sys_window_update_settings(struct sys_window *sys_window, struct sys_window_settings *settings); void sys_window_update_settings(struct sys_window *sys_window, struct sys_window_settings *settings);

View File

@ -9,6 +9,7 @@
#include "util.h" #include "util.h"
#include "uni.h" #include "uni.h"
#include "gp.h" #include "gp.h"
#include "resource.h"
#pragma warning(push, 0) #pragma warning(push, 0)
# define UNICODE # define UNICODE
@ -48,7 +49,6 @@
#define MAX_EXIT_FUNCS 1024 #define MAX_EXIT_FUNCS 1024
/* Arbitrary threshold for determining when to fall back from a looped WakeByAddressSingle to WakeByAddressAll */ /* Arbitrary threshold for determining when to fall back from a looped WakeByAddressSingle to WakeByAddressAll */
#define WAKE_ALL_THRESHOLD 8 #define WAKE_ALL_THRESHOLD 8
@ -105,7 +105,10 @@ struct win32_window {
struct gp_swapchain *swapchain; struct gp_swapchain *swapchain;
sys_job_func *event_job; struct snc_mutex event_arena_swp_mutex;
i32 current_event_arena_index;
struct arena *event_arenas[2];
sys_job_func *present_job; sys_job_func *present_job;
struct sys_thread *event_thread; struct sys_thread *event_thread;
@ -887,7 +890,7 @@ INTERNAL SYS_THREAD_DEF(job_worker_entry, worker_ctx_arg)
void *job_sig = 0; void *job_sig = 0;
struct snc_counter *job_counter = 0; struct snc_counter *job_counter = 0;
{ {
__profnc("Pull job", RGB32_F(0.75, 0.75, 0)); //__profnc("Pull job", RGB32_F(0.75, 0.75, 0));
for (u32 queue_index = 0; queue_index < countof(queues) && !job_func; ++queue_index) { for (u32 queue_index = 0; queue_index < countof(queues) && !job_func; ++queue_index) {
struct job_queue *queue = queues[queue_index]; struct job_queue *queue = queues[queue_index];
if (queue) { if (queue) {
@ -1121,7 +1124,7 @@ INTERNAL SYS_THREAD_DEF(job_worker_entry, worker_ctx_arg)
{ {
shutdown = atomic_i32_fetch(&G.workers_shutdown.v); shutdown = atomic_i32_fetch(&G.workers_shutdown.v);
while (atomic_i64_fetch(&G.num_jobs_in_queue.v) <= 0 && !shutdown) { while (atomic_i64_fetch(&G.num_jobs_in_queue.v) <= 0 && !shutdown) {
__profnc("Wait for job", RGB32_F(0.75, 0.75, 0)); //__profnc("Wait for job", RGB32_F(0.75, 0.75, 0));
snc_cv_wait(&G.workers_wake_cv, &wake_lock); snc_cv_wait(&G.workers_wake_cv, &wake_lock);
shutdown = atomic_i32_fetch(&G.workers_shutdown.v); shutdown = atomic_i32_fetch(&G.workers_shutdown.v);
} }
@ -2203,14 +2206,13 @@ INTERNAL void win32_window_wake(struct win32_window *window);
INTERNAL void win32_window_process_event(struct win32_window *window, struct sys_event event) INTERNAL void win32_window_process_event(struct win32_window *window, struct sys_event event)
{ {
if (window->event_job) { __prof;
__prof; if (window->present_job) {
struct snc_counter counter = ZI; struct snc_lock lock = snc_lock_e(&window->event_arena_swp_mutex);
struct sys_window_event_job_sig sig = ZI; {
sig.window = (struct sys_window *)window; *arena_push(window->event_arenas[window->current_event_arena_index], struct sys_event) = event;
sig.event = event; }
sys_run(1, window->event_job, &sig, SYS_PRIORITY_NORMAL, &counter); snc_unlock(&lock);
snc_counter_wait(&counter);
} }
} }
@ -2350,16 +2352,31 @@ INTERNAL SYS_THREAD_DEF(window_present_thread_entry_point, arg)
gp_swapchain_wait(window->swapchain); gp_swapchain_wait(window->swapchain);
} }
{ {
struct snc_counter counter = ZI; i32 event_arena_index = 0;
struct sys_window_present_job_sig sig = ZI; {
sig.window = (struct sys_window *)window; struct snc_lock lock = snc_lock_e(&window->event_arena_swp_mutex);
sys_run(1, window->present_job, &sig, SYS_PRIORITY_HIGH, &counter); event_arena_index = window->current_event_arena_index;
snc_counter_wait(&counter); window->current_event_arena_index = 1 - window->current_event_arena_index;
snc_unlock(&lock);
}
struct arena *events_arena = window->event_arenas[event_arena_index];
struct sys_event_array events = ZI;
events.count = events_arena->pos / sizeof(struct sys_event);
events.events = (struct sys_event *)arena_base(events_arena);
{
struct snc_counter counter = ZI;
struct sys_window_present_job_sig sig = ZI;
sig.window = (struct sys_window *)window;
sig.events = events;
sys_run(1, window->present_job, &sig, SYS_PRIORITY_HIGH, &counter);
snc_counter_wait(&counter);
}
arena_reset(events_arena);
} }
} }
} }
INTERNAL struct win32_window *win32_window_alloc(sys_job_func *event_job, sys_job_func *present_job) INTERNAL struct win32_window *win32_window_alloc(sys_job_func *present_job)
{ {
struct win32_window *window = 0; struct win32_window *window = 0;
{ {
@ -2373,10 +2390,17 @@ INTERNAL struct win32_window *win32_window_alloc(sys_job_func *event_job, sys_jo
snc_unlock(&lock); snc_unlock(&lock);
} }
MEMZERO_STRUCT(window); MEMZERO_STRUCT(window);
window->event_job = event_job;
window->present_job = present_job; window->present_job = present_job;
if (present_job) {
window->event_arenas[0] = arena_alloc(GIBI(64));
window->event_arenas[1] = arena_alloc(GIBI(64));
}
/* Start window event thread */ /* Start window event thread */
/* NOTE: This thread must finish building for the window to actually be
* created and receive a HWND, because on Windows a the event proc must run on
* the same thread that created the window. */
snc_counter_add(&window->ready_fence, 1); snc_counter_add(&window->ready_fence, 1);
window->event_thread = sys_thread_alloc(&window_event_thread_entry_point, window, LIT("Window event thread"), PROF_THREAD_GROUP_WINDOW); window->event_thread = sys_thread_alloc(&window_event_thread_entry_point, window, LIT("Window event thread"), PROF_THREAD_GROUP_WINDOW);
snc_counter_wait(&window->ready_fence); snc_counter_wait(&window->ready_fence);
@ -2387,25 +2411,25 @@ INTERNAL struct win32_window *win32_window_alloc(sys_job_func *event_job, sys_jo
window->present_thread = sys_thread_alloc(&window_present_thread_entry_point, window, LIT("Window present thread"), PROF_THREAD_GROUP_WINDOW); window->present_thread = sys_thread_alloc(&window_present_thread_entry_point, window, LIT("Window present thread"), PROF_THREAD_GROUP_WINDOW);
} }
/* Release swapchain */
gp_swapchain_release(window->swapchain);
return window; return window;
} }
INTERNAL void win32_window_release(struct win32_window *window) INTERNAL void win32_window_release(struct win32_window *window)
{ {
struct snc_lock lock = snc_lock_e(&G.windows_mutex);
window->next_free = G.first_free_window;
G.first_free_window = window;
/* Stop window threads */ /* Stop window threads */
atomic_i32_fetch_set(&window->shutdown, 1); atomic_i32_fetch_set(&window->shutdown, 1);
win32_window_wake(window); win32_window_wake(window);
sys_thread_wait_release(window->present_thread); sys_thread_wait_release(window->present_thread);
sys_thread_wait_release(window->event_thread); sys_thread_wait_release(window->event_thread);
/* Release swapchain */
gp_swapchain_release(window->swapchain);
struct snc_lock lock = snc_lock_e(&G.windows_mutex);
{
window->next_free = G.first_free_window;
G.first_free_window = window;
}
snc_unlock(&lock); snc_unlock(&lock);
} }
@ -2769,10 +2793,10 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
return result; return result;
} }
struct sys_window *sys_window_alloc(sys_job_func *event_job, sys_job_func *present_job) struct sys_window *sys_window_alloc(sys_job_func *present_job)
{ {
__prof; __prof;
return (struct sys_window *)win32_window_alloc(event_job, present_job); return (struct sys_window *)win32_window_alloc(present_job);
} }
void sys_window_release(struct sys_window *sys_window) void sys_window_release(struct sys_window *sys_window)
@ -3364,6 +3388,10 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
/* Start test thread */ /* Start test thread */
struct sys_thread *test_thread = sys_thread_alloc(test_entry, 0, LIT("Test thread"), PROF_THREAD_GROUP_APP); struct sys_thread *test_thread = sys_thread_alloc(test_entry, 0, LIT("Test thread"), PROF_THREAD_GROUP_APP);
/* Startup systems */
resource_startup();
gp_startup();
/* ========================== * /* ========================== *
* App thread setup * App thread setup
* ========================== */ * ========================== */

View File

@ -192,6 +192,7 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = {
INTERNAL SYS_EXIT_FUNC(user_shutdown); INTERNAL SYS_EXIT_FUNC(user_shutdown);
INTERNAL LOG_EVENT_CALLBACK_FUNC_DEF(debug_console_log_callback, log); INTERNAL LOG_EVENT_CALLBACK_FUNC_DEF(debug_console_log_callback, log);
INTERNAL SYS_JOB_DEF(user_update_job, _);
INTERNAL SYS_JOB_DEF(local_sim_job , _); INTERNAL SYS_JOB_DEF(local_sim_job , _);
struct user_startup_receipt user_startup(struct font_startup_receipt *font_sr, struct user_startup_receipt user_startup(struct font_startup_receipt *font_sr,
@ -222,9 +223,6 @@ struct user_startup_receipt user_startup(struct font_startup_receipt *font_sr,
/* Initialize average dt to a reasonable value */ /* Initialize average dt to a reasonable value */
G.average_local_to_user_snapshot_publish_dt_ns = NS_FROM_SECONDS(1) / SIM_TICKS_PER_SECOND; G.average_local_to_user_snapshot_publish_dt_ns = NS_FROM_SECONDS(1) / SIM_TICKS_PER_SECOND;
/* Sys events */
G.sys_events_arena = arena_alloc(GIBI(64));
/* User blend clients */ /* User blend clients */
G.user_client_store = sim_client_store_alloc(); G.user_client_store = sim_client_store_alloc();
G.user_unblended_client = sim_client_alloc(G.user_client_store); G.user_unblended_client = sim_client_alloc(G.user_client_store);
@ -248,7 +246,7 @@ struct user_startup_receipt user_startup(struct font_startup_receipt *font_sr,
sys_run(1, local_sim_job, 0, SYS_PRIORITY_HIGH, &G.shutdown_job_counters); sys_run(1, local_sim_job, 0, SYS_PRIORITY_HIGH, &G.shutdown_job_counters);
sys_on_exit(&user_shutdown); sys_on_exit(&user_shutdown);
G.window = sys_window_alloc(user_event_job, user_present_job); G.window = sys_window_alloc(user_update_job);
return (struct user_startup_receipt) { 0 }; return (struct user_startup_receipt) { 0 };
} }
@ -263,36 +261,6 @@ INTERNAL SYS_EXIT_FUNC(user_shutdown)
snc_counter_wait(&G.shutdown_job_counters); snc_counter_wait(&G.shutdown_job_counters);
} }
/* ========================== *
* Window -> user communication
* ========================== */
INTERNAL struct sys_event_array pop_sys_events(struct arena *arena)
{
struct sys_event_array array = ZI;
struct snc_lock lock = snc_lock_e(&G.sys_events_mutex);
{
struct sys_event *src_events = (struct sys_event *)arena_base(G.sys_events_arena);
array.count = G.sys_events_arena->pos / sizeof(*src_events);
array.events = arena_push_array_no_zero(arena, struct sys_event, array.count);
MEMCPY(array.events, src_events, array.count * sizeof(*src_events));
arena_reset(G.sys_events_arena);
}
snc_unlock(&lock);
return array;
}
SYS_JOB_DEF(user_event_job, job)
{
__prof;
struct sys_window_event_job_sig *sig = job.sig;
struct snc_lock lock = snc_lock_e(&G.sys_events_mutex);
{
*arena_push_no_zero(G.sys_events_arena, struct sys_event) = sig->event;
}
snc_unlock(&lock);
}
/* ========================== * /* ========================== *
* Debug draw * Debug draw
* ========================== */ * ========================== */
@ -593,11 +561,12 @@ INTERNAL SORT_COMPARE_FUNC_DEF(ent_draw_order_cmp, arg_a, arg_b, udata)
* Update * Update
* ========================== */ * ========================== */
SYS_JOB_DEF(user_present_job, job) SYS_JOB_DEF(user_update_job, job)
{ {
__prof; __prof;
struct sys_window_present_job_sig *sig = job.sig; struct sys_window_present_job_sig *sig = job.sig;
struct sys_window *window = sig->window; struct sys_window *window = sig->window;
struct sys_event_array events = sig->events;
struct arena_temp scratch = scratch_begin_no_conflict(); struct arena_temp scratch = scratch_begin_no_conflict();
@ -731,7 +700,6 @@ SYS_JOB_DEF(user_present_job, job)
{ {
__profn("Process sys events"); __profn("Process sys events");
struct sys_event_array events = pop_sys_events(scratch.arena);
/* Reset bind pressed / released states */ /* Reset bind pressed / released states */
for (u32 i = 0; i < countof(G.bind_states); ++i) { for (u32 i = 0; i < countof(G.bind_states); ++i) {

View File

@ -70,7 +70,4 @@ struct user_startup_receipt user_startup(struct font_startup_receipt *font_sr,
struct sim_startup_receipt *sim_sr, struct sim_startup_receipt *sim_sr,
struct string connect_address_str); struct string connect_address_str);
SYS_JOB_DEF(user_event_job, job);
SYS_JOB_DEF(user_present_job, job);
#endif #endif