diff --git a/src/app.c b/src/app.c index 669c3400..228443a7 100644 --- a/src/app.c +++ b/src/app.c @@ -279,6 +279,8 @@ void sys_app_entry(struct string args_str) #endif /* Startup systems */ + resource_startup(); + gp_startup(); struct sock_startup_receipt sock_sr = sock_startup(); struct host_startup_receipt host_sr = host_startup(&sock_sr); struct asset_cache_startup_receipt asset_cache_sr = asset_cache_startup(); diff --git a/src/config.h b/src/config.h index 9787e1ec..bdade75e 100644 --- a/src/config.h +++ b/src/config.h @@ -42,7 +42,7 @@ #define SIM_TILES_PER_UNIT_SQRT (4) #define SIM_TILES_PER_CHUNK_SQRT (16) -#define SIM_TICKS_PER_SECOND 50 +#define SIM_TICKS_PER_SECOND 100 //#define SIM_TIMESCALE 1 /* Like USER_INTERP_RATIO, but applies to snapshots received by the local sim from the * master sim (how far back in time should the client render the server's state) */ diff --git a/src/draw.c b/src/draw.c index 2f0a6484..360ad8c1 100644 --- a/src/draw.c +++ b/src/draw.c @@ -17,7 +17,11 @@ struct draw_startup_receipt draw_startup(struct font_startup_receipt *font_sr) { (UNUSED)font_sr; u32 pixel_white = 0xFFFFFFFF; - G.solid_white_texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, V2I32(1, 1), &pixel_white); + { + struct snc_counter counter = ZI; + G.solid_white_texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, V2I32(1, 1), &pixel_white, &counter); + snc_counter_wait(&counter); + } return (struct draw_startup_receipt) { 0 }; } diff --git a/src/font.c b/src/font.c index 114cd0d5..02040a62 100644 --- a/src/font.c +++ b/src/font.c @@ -110,7 +110,12 @@ INTERNAL SYS_JOB_DEF(font_load_asset_job, job) resource_close(&res); /* Send texture to GPU */ - struct gp_resource *texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, V2I32(result.image_data.width, result.image_data.height), result.image_data.pixels); + struct gp_resource *texture = 0; + { + struct snc_counter counter = ZI; + texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, V2I32(result.image_data.width, result.image_data.height), result.image_data.pixels, &counter); + snc_counter_wait(&counter); + } /* Allocate store memory */ struct font *font = 0; diff --git a/src/gp.h b/src/gp.h index e8e4da93..81446246 100644 --- a/src/gp.h +++ b/src/gp.h @@ -2,6 +2,7 @@ #define GP_H struct sys_window; +struct snc_counter; /* ========================== * * Startup @@ -38,7 +39,7 @@ enum gp_texture_flag { GP_TEXTURE_FLAG_TARGETABLE = (1 << 0) }; -struct gp_resource *gp_texture_alloc(enum gp_texture_format format, u32 flags, struct v2i32 size, void *initial_data); +struct gp_resource *gp_texture_alloc(enum gp_texture_format format, u32 flags, struct v2i32 size, void *initial_data, struct snc_counter *counter); struct v2i32 gp_texture_get_size(struct gp_resource *texture); diff --git a/src/gp_dx12.c b/src/gp_dx12.c index 19d03c6d..03fbde1c 100644 --- a/src/gp_dx12.c +++ b/src/gp_dx12.c @@ -2194,7 +2194,26 @@ INTERNAL D3D12_INDEX_BUFFER_VIEW ibv_from_command_buffer(struct command_buffer * * Texture * ========================== */ -struct gp_resource *gp_texture_alloc(enum gp_texture_format format, u32 flags, struct v2i32 size, void *initial_data) +struct dx12_wait_fence_job_sig { + ID3D12Fence *fence; + u64 target; +}; + +INTERNAL SYS_JOB_DEF(dx12_wait_fence_job, job) +{ + __prof; + struct dx12_wait_fence_job_sig *sig = job.sig; + ID3D12Fence *fence = sig->fence; + u64 target = sig->target; + if (ID3D12Fence_GetCompletedValue(fence) < target) { + HANDLE event = CreateEvent(0, 0, 0, 0); + ID3D12Fence_SetEventOnCompletion(sig->fence, sig->target, event); + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } +} + +struct gp_resource *gp_texture_alloc(enum gp_texture_format format, u32 flags, struct v2i32 size, void *initial_data, struct snc_counter *counter) { __prof; struct dxgi_format_info { DXGI_FORMAT format; u32 size; }; @@ -2336,14 +2355,12 @@ struct gp_resource *gp_texture_alloc(enum gp_texture_format format, u32 flags, s } u64 fence_target = command_list_close(cl); - /* Wait */ - /* TODO: Return async waitable to caller */ - { - __profn("Wait for upload"); - HANDLE event = CreateEvent(0, 0, 0, 0); - ID3D12Fence_SetEventOnCompletion(cq->submit_fence, fence_target, event); - WaitForSingleObject(event, INFINITE); - CloseHandle(event); + /* Submit wait job */ + if (counter && ID3D12Fence_GetCompletedValue(cq->submit_fence) < fence_target) { + struct dx12_wait_fence_job_sig sig = ZI; + sig.fence = cq->submit_fence; + sig.target = fence_target; + sys_run(1, dx12_wait_fence_job, &sig, SYS_POOL_FLOATING, SYS_PRIORITY_LOW, counter); } } diff --git a/src/playback_wasapi.c b/src/playback_wasapi.c index 6add84d1..efc71f35 100644 --- a/src/playback_wasapi.c +++ b/src/playback_wasapi.c @@ -221,12 +221,6 @@ INTERNAL void wasapi_update_end(struct wasapi_buffer *wspbuf, struct mixed_pcm_f * Playback thread entry * ========================== */ -INTERNAL SYS_JOB_DEF(playback_wait_job, _) -{ - __prof; - WaitForSingleObject(G.event, INFINITE); -} - INTERNAL SYS_JOB_DEF(playback_job, _) { __prof; @@ -239,9 +233,7 @@ INTERNAL SYS_JOB_DEF(playback_job, _) struct arena_temp scratch = scratch_begin_no_conflict(); { __profn("Wasapi wait"); - struct snc_counter counter = ZI; - sys_run(1, playback_wait_job, 0, SYS_POOL_FLOATING, SYS_PRIORITY_INHERIT, &counter); - snc_counter_wait(&counter); + WaitForSingleObject(G.event, INFINITE); } { __profn("Fill sample buffer"); diff --git a/src/sprite.c b/src/sprite.c index 483e7177..c548bf6b 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -221,7 +221,11 @@ struct sprite_startup_receipt sprite_startup(void) { struct arena_temp scratch = scratch_begin_no_conflict(); struct image_rgba purple_black_image = generate_purple_black_image(scratch.arena, 64, 64); - G.nil_texture->gp_texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, V2I32(purple_black_image.width, purple_black_image.height), purple_black_image.pixels); + { + struct snc_counter counter = ZI; + G.nil_texture->gp_texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, V2I32(purple_black_image.width, purple_black_image.height), purple_black_image.pixels, &counter); + snc_counter_wait(&counter); + } scratch_end(scratch); } @@ -366,9 +370,13 @@ INTERNAL void cache_entry_load_texture(struct cache_ref ref, struct sprite_tag t e->texture = arena_push(e->arena, struct sprite_texture); e->texture->width = decoded.image.width; e->texture->height = decoded.image.height; - e->texture->gp_texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM_SRGB, 0, V2I32(decoded.image.width, decoded.image.height), decoded.image.pixels); e->texture->valid = 1; e->texture->loaded = 1; + { + struct snc_counter counter = ZI; + e->texture->gp_texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM_SRGB, 0, V2I32(decoded.image.width, decoded.image.height), decoded.image.pixels, &counter); + snc_counter_wait(&counter); + } /* TODO: Query gpu for more accurate texture size in VRAM */ memory_size += (decoded.image.width * decoded.image.height) * sizeof(*decoded.image.pixels); success = 1; @@ -1208,7 +1216,6 @@ INTERNAL SORT_COMPARE_FUNC_DEF(evict_sort, arg_a, arg_b, udata) return (b_cycle > a_cycle) - (a_cycle > b_cycle); } - /* NOTE: * A cache node is safe from eviction as long as: * - Its bin mutex is locked diff --git a/src/sys.h b/src/sys.h index 7d868031..6cb85008 100644 --- a/src/sys.h +++ b/src/sys.h @@ -457,14 +457,11 @@ struct sys_window_settings { i32 floating_height; }; -struct sys_window_present_job_sig { - struct sys_window *window; - struct sys_event_array events; -}; - -struct sys_window *sys_window_alloc(sys_job_func *present_job); +struct sys_window *sys_window_alloc(void); void sys_window_release(struct sys_window *sys_window); +struct sys_event_array sys_window_pop_events(struct arena *arena, struct sys_window *sys_window); + void sys_window_update_settings(struct sys_window *sys_window, struct sys_window_settings *settings); struct sys_window_settings sys_window_get_settings(struct sys_window *sys_window); @@ -482,8 +479,6 @@ void sys_window_cursor_hide(struct sys_window *sys_window); void sys_window_cursor_enable_clip(struct sys_window *sys_window, struct rect bounds); void sys_window_cursor_disable_clip(struct sys_window *sys_window); -struct gp_swapchain *sys_window_get_swapchain(struct sys_window *window); - /* ========================== * * Threads * ========================== */ diff --git a/src/sys_win32.c b/src/sys_win32.c index bd15ebd2..903cc22c 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -8,7 +8,6 @@ #include "math.h" #include "util.h" #include "uni.h" -#include "gp.h" #include "resource.h" #pragma warning(push, 0) @@ -105,16 +104,11 @@ struct win32_window { struct v2 cursor_set_position; struct rect cursor_clip_bounds; - struct gp_swapchain *swapchain; - struct snc_mutex event_arena_swp_mutex; i32 current_event_arena_index; struct arena *event_arenas[2]; - sys_job_func *present_job; - struct sys_thread *event_thread; - struct sys_thread *present_thread; struct atomic32 shutdown; struct win32_window *next_free; @@ -426,6 +420,7 @@ void sys_wait(void *addr, void *cmp, u32 size, i64 timeout_ns) /* REQUIRED: Caller must have acquired `wake_lock` for each fiber in array */ INTERNAL void wake_fibers_locked(i32 num_fibers, struct fiber **fibers) { + __prof; /* Update wait lists */ for (i32 i = 0; i < num_fibers; ++i) { struct fiber *fiber = fibers[i]; @@ -1303,7 +1298,7 @@ INTERNAL SYS_THREAD_DEF(test_entry, _) struct sys_thread *scheduler_thread = sys_thread_alloc(job_scheduler_entry, 0, LIT("Scheduler thread"), PROF_THREAD_GROUP_SCHEDULER); /* Start workers */ - /* TODO: Heuristic worker count & priorities */ + /* TODO: Heuristic worker counts & affinities */ for (enum sys_pool pool_kind = 0; pool_kind < (i32)countof(G.job_pools); ++pool_kind) { struct job_pool *pool = &G.job_pools[pool_kind]; struct string name_fmt = ZI; @@ -1348,7 +1343,7 @@ INTERNAL SYS_THREAD_DEF(test_entry, _) name_fmt = LIT("Floating worker #%F"); pool->thread_affinity_mask = 0xFFFFFFFFFFFFFFFFull; pool->thread_priority = 0; - pool->num_worker_threads = 32; + pool->num_worker_threads = 8; } break; } pool->worker_threads_arena = arena_alloc(GIBI(64)); @@ -1371,6 +1366,7 @@ INTERNAL SYS_THREAD_DEF(test_entry, _) sys_thread_wait_release(worker_thread); } } + /* Wait on scheduler */ sys_thread_wait_release(scheduler_thread); @@ -2164,13 +2160,11 @@ INTERNAL void win32_window_wake(struct win32_window *window); INTERNAL void win32_window_process_event(struct win32_window *window, struct sys_event event) { __prof; - if (window->present_job) { - struct snc_lock lock = snc_lock_e(&window->event_arena_swp_mutex); - { - *arena_push(window->event_arenas[window->current_event_arena_index], struct sys_event) = event; - } - snc_unlock(&lock); + struct snc_lock lock = snc_lock_e(&window->event_arena_swp_mutex); + { + *arena_push(window->event_arenas[window->current_event_arena_index], struct sys_event) = event; } + snc_unlock(&lock); } INTERNAL HWND win32_create_window(struct win32_window *window) @@ -2296,44 +2290,7 @@ INTERNAL SYS_THREAD_DEF(window_event_thread_entry_point, arg) DestroyWindow(window->hwnd); } -INTERNAL SYS_THREAD_DEF(window_present_thread_entry_point, arg) -{ - struct win32_window *window = (struct win32_window *)arg; - - /* Show window */ - sys_window_show((struct sys_window *)window); - - while (!atomic32_fetch(&window->shutdown)) { - { - __profn("Swapchain wait"); - gp_swapchain_wait(window->swapchain); - } - { - i32 event_arena_index = 0; - { - struct snc_lock lock = snc_lock_e(&window->event_arena_swp_mutex); - event_arena_index = window->current_event_arena_index; - 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_POOL_USER, SYS_PRIORITY_HIGH, &counter); - snc_counter_wait(&counter); - } - arena_reset(events_arena); - } - } -} - -INTERNAL struct win32_window *win32_window_alloc(sys_job_func *present_job) +INTERNAL struct win32_window *win32_window_alloc(void) { struct win32_window *window = 0; { @@ -2347,12 +2304,9 @@ INTERNAL struct win32_window *win32_window_alloc(sys_job_func *present_job) snc_unlock(&lock); } MEMZERO_STRUCT(window); - window->present_job = present_job; - if (present_job) { - window->event_arenas[0] = arena_alloc(GIBI(64)); - window->event_arenas[1] = arena_alloc(GIBI(64)); - } + window->event_arenas[0] = arena_alloc(GIBI(64)); + window->event_arenas[1] = arena_alloc(GIBI(64)); /* Start window event thread */ /* NOTE: This thread must finish building for the window to actually be @@ -2362,12 +2316,6 @@ INTERNAL struct win32_window *win32_window_alloc(sys_job_func *present_job) 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); - /* Start window present thread */ - if (present_job) { - window->swapchain = gp_swapchain_alloc((struct sys_window *)window, V2I32(100, 100)); - window->present_thread = sys_thread_alloc(&window_present_thread_entry_point, window, LIT("Window present thread"), PROF_THREAD_GROUP_WINDOW); - } - return window; } @@ -2376,12 +2324,8 @@ INTERNAL void win32_window_release(struct win32_window *window) /* Stop window threads */ atomic32_fetch_set(&window->shutdown, 1); win32_window_wake(window); - sys_thread_wait_release(window->present_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; @@ -2390,6 +2334,26 @@ INTERNAL void win32_window_release(struct win32_window *window) snc_unlock(&lock); } +struct sys_event_array sys_window_pop_events(struct arena *arena, struct sys_window *sys_window) +{ + __prof; + struct win32_window *window = (struct win32_window *)sys_window; + i32 event_arena_index = 0; + { + struct snc_lock lock = snc_lock_e(&window->event_arena_swp_mutex); + event_arena_index = window->current_event_arena_index; + 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 = arena_push_array_no_zero(arena, struct sys_event, events.count); + MEMCPY(events.events, arena_base(events_arena), events_arena->pos); + arena_reset(events_arena); + return events; +} + INTERNAL void win32_update_window_from_system(struct win32_window *window) { HWND hwnd = window->hwnd; @@ -2750,10 +2714,10 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, return result; } -struct sys_window *sys_window_alloc(sys_job_func *present_job) +struct sys_window *sys_window_alloc(void) { __prof; - return (struct sys_window *)win32_window_alloc(present_job); + return (struct sys_window *)win32_window_alloc(); } void sys_window_release(struct sys_window *sys_window) @@ -2857,12 +2821,6 @@ void sys_window_cursor_disable_clip(struct sys_window *sys_window) win32_window_wake(window); } -/* TODO: Remove this */ -struct gp_swapchain *sys_window_get_swapchain(struct sys_window *window) -{ - return ((struct win32_window *)window)->swapchain; -} - /* ========================== * * Threads * ========================== */ @@ -3348,10 +3306,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, /* Start test thread */ 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 * ========================== */ diff --git a/src/user.c b/src/user.c index 0ea96e81..0e57145b 100644 --- a/src/user.c +++ b/src/user.c @@ -51,6 +51,7 @@ GLOBAL struct { struct atomic32 shutdown; struct snc_counter shutdown_job_counters; struct sys_window *window; + struct gp_swapchain *swapchain; struct sim_ctx *local_sim_ctx; @@ -242,12 +243,15 @@ struct user_startup_receipt user_startup(struct font_startup_receipt *font_sr, //log_register_callback(debug_console_log_callback, LOG_LEVEL_SUCCESS); log_register_callback(debug_console_log_callback, LOG_LEVEL_DEBUG); - /* Start sim job */ + G.window = sys_window_alloc(); + G.swapchain = gp_swapchain_alloc(G.window, V2I32(100, 100)); + sys_window_show(G.window); + + /* Start jobs */ + sys_run(1, user_update_job, 0, SYS_POOL_USER, SYS_PRIORITY_HIGH, &G.shutdown_job_counters); sys_run(1, local_sim_job, 0, SYS_POOL_SIM, SYS_PRIORITY_HIGH, &G.shutdown_job_counters); sys_on_exit(&user_shutdown); - G.window = sys_window_alloc(user_update_job); - return (struct user_startup_receipt) { 0 }; } @@ -561,12 +565,9 @@ INTERNAL SORT_COMPARE_FUNC_DEF(ent_draw_order_cmp, arg_a, arg_b, udata) * Update * ========================== */ -SYS_JOB_DEF(user_update_job, job) +INTERNAL void user_update(struct sys_window *window) { __prof; - struct sys_window_present_job_sig *sig = job.sig; - struct sys_window *window = sig->window; - struct sys_event_array events = sig->events; struct arena_temp scratch = scratch_begin_no_conflict(); @@ -701,6 +702,8 @@ SYS_JOB_DEF(user_update_job, job) { __profn("Process sys events"); + struct sys_event_array events = sys_window_pop_events(scratch.arena, window); + /* Reset bind pressed / released states */ for (u32 i = 0; i < countof(G.bind_states); ++i) { G.bind_states[i] = (struct bind_state) { @@ -2023,7 +2026,12 @@ SYS_JOB_DEF(user_update_job, job) if (G.user_texture) { gp_resource_release(G.user_texture); } - G.user_texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, GP_TEXTURE_FLAG_TARGETABLE, user_resolution, 0); + { + /* TODO: Don't wait here */ + struct snc_counter counter = ZI; + G.user_texture = gp_texture_alloc(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, GP_TEXTURE_FLAG_TARGETABLE, user_resolution, 0, &counter); + snc_counter_wait(&counter); + } } /* Render world to user texture */ @@ -2047,9 +2055,8 @@ SYS_JOB_DEF(user_update_job, job) gp_dispatch(params); } - /* Present user texture */ - struct gp_swapchain *swapchain = sys_window_get_swapchain(window); - gp_present(swapchain, backbuffer_resolution, G.user_texture, XFORM_TRS(.t = v2_mul(G.screen_size, 0.5), .s = G.user_size), VSYNC); + /* Present */ + gp_present(G.swapchain, backbuffer_resolution, G.user_texture, XFORM_TRS(.t = v2_mul(G.screen_size, 0.5), .s = G.user_size), VSYNC); } /* ========================== * @@ -2061,6 +2068,19 @@ SYS_JOB_DEF(user_update_job, job) scratch_end(scratch); } +INTERNAL SYS_JOB_DEF(user_update_job, _) +{ + (UNUSED)_; + while (!atomic32_fetch(&G.shutdown)) { + struct sys_window *window = G.window; + { + __profn("Swapchain wait"); + gp_swapchain_wait(G.swapchain); + } + user_update(window); + } +} +