diff --git a/code2/grime/dynamic_array.odin b/code2/grime/dynamic_array.odin index 3e1c30e..da3a98b 100644 --- a/code2/grime/dynamic_array.odin +++ b/code2/grime/dynamic_array.odin @@ -6,7 +6,7 @@ Made becasue of the map issue with fonts during hot-reload. I didn't want to make the HMapZPL impl with the [dynamic] array for now to isolate the hot-reload issue (when I was diagnoising) Note 2024-5-26: -TODO(Ed): Raw_Dynamic_Array is defined within base:runtime/core.odin and exposes what we need for worst case hot-reloads. +Raw_Dynamic_Array is defined within base:runtime/core.odin and exposes what we need for worst case hot-reloads. So its best to go back to regular dynamic arrays at some point. Note 2025-5-12: I can use either... so I'll just keep both diff --git a/code2/host/host.odin b/code2/host/host.odin index be72cba..33dd5c8 100644 --- a/code2/host/host.odin +++ b/code2/host/host.odin @@ -235,7 +235,7 @@ host_job_worker_entrypoint :: proc(worker_thread: ^SysThread) when SHOULD_SETUP_PROFILERS { thread_memory.spall_buffer = spall_buffer_create(thread_memory.spall_buffer_backing[:], cast(u32) thread_memory.system_ctx.id) - host_memory.client_api.tick_lane_startup(& thread_memory) + host_memory.client_api.job_worker_startup(& thread_memory) grime_set_profiler_thread_buffer(& thread_memory.spall_buffer) } jobs_enqueued := false @@ -246,7 +246,7 @@ host_job_worker_entrypoint :: proc(worker_thread: ^SysThread) host_tick := time_tick_now() for ; jobs_enqueued || sync_load(& host_memory.job_system.running, .Relaxed); { - profile("Host Job Tick") + // profile("Host Job Tick") host_memory.client_api.jobsys_worker_tick(duration_seconds(delta_ns), delta_ns) diff --git a/code2/sectr/engine/client_api.odin b/code2/sectr/engine/client_api.odin index c205515..a155832 100644 --- a/code2/sectr/engine/client_api.odin +++ b/code2/sectr/engine/client_api.odin @@ -197,7 +197,7 @@ Host handles the loop. (We need threads to be outside of client callstack in the event of a hot-reload) */ @export -tick_lane :: proc(host_delta_time_ms: f64, host_delta_ns: Duration) -> (should_close: b64 = false) +tick_lane :: proc(host_delta_time_ms: f64, host_delta_ns: Duration) -> (should_close: bool = false) { profile(#procedure) @@ -207,53 +207,7 @@ tick_lane :: proc(host_delta_time_ms: f64, host_delta_ns: Duration) -> (should_c profile_begin("Client Tick") { - profile("Work frame") - context.logger = to_odin_logger( & memory.client_memory.logger ) - - // TODO(Ed): Setup frame alloator - - if thread.id == .Master_Prepper - { - // config := & memory.client_memory.config - // debug := & memory.client_memory.debug - - // debug.draw_ui_box_bounds_points = false - // debug.draw_ui_padding_bounds = false - // debug.draw_ui_content_bounds = false - - // config.engine_refresh_hz = 165 - - // config.color_theme = App_Thm_Light - // config.color_theme = App_Thm_Dusk - // config.color_theme = App_Thm_Dark - - // sokol_width := sokol_app.widthf() - // sokol_height := sokol_app.heightf() - - // window := & get_state().app_window - // if int(window.extent.x) != int(sokol_width) || int(window.extent.y) != int(sokol_height) { - // window.resized = true - // window.extent.x = sokol_width * 0.5 - // window.extent.y = sokol_height * 0.5 - // log("sokol_app: Event-based frame callback triggered (detected a resize") - // } - } - - // Test dispatching 64 jobs during hot_reload loop (when the above store is uncommented) - if true - { - if thread.id == .Master_Prepper { - profile("dispatching") - for job_id := 1; job_id < JOB_TEST_NUM; job_id += 1 { - memory.job_info_reload[job_id].id = job_id - memory.job_reload[job_id] = make_job_raw(& memory.job_group_reload, & memory.job_info_reload[job_id], test_job, {}, "Job Test (Hot-Reload)") - job_dispatch_single(& memory.job_reload[job_id], .Normal) - } - } - should_close = true - } - // should_close |= update( host_delta_time_ms ) - // render() + should_close = tick_lane_work_frame(host_delta_time_ms) } client_tick := tick_now() profile_end() @@ -266,10 +220,63 @@ tick_lane :: proc(host_delta_time_ms: f64, host_delta_ns: Duration) -> (should_c return sync_load(& should_close, .Acquire) } +// Note(Ed): Necessary for sokol_app_frame_callback +tick_lane_work_frame :: proc(host_delta_time_ms: f64) -> (should_close: bool) +{ + profile("Work frame") + context.logger = to_odin_logger( & memory.client_memory.logger ) + + // TODO(Ed): Setup frame alloator + + if thread.id == .Master_Prepper + { + // config := & memory.client_memory.config + // debug := & memory.client_memory.debug + + // debug.draw_ui_box_bounds_points = false + // debug.draw_ui_padding_bounds = false + // debug.draw_ui_content_bounds = false + + // config.engine_refresh_hz = 165 + + // config.color_theme = App_Thm_Light + // config.color_theme = App_Thm_Dusk + // config.color_theme = App_Thm_Dark + + // sokol_width := sokol_app.widthf() + // sokol_height := sokol_app.heightf() + + // window := & get_state().app_window + // if int(window.extent.x) != int(sokol_width) || int(window.extent.y) != int(sokol_height) { + // window.resized = true + // window.extent.x = sokol_width * 0.5 + // window.extent.y = sokol_height * 0.5 + // log("sokol_app: Event-based frame callback triggered (detected a resize") + // } + } + + // Test dispatching 64 jobs during hot_reload loop (when the above store is uncommented) + if true + { + if thread.id == .Master_Prepper { + profile("dispatching") + for job_id := 1; job_id < JOB_TEST_NUM; job_id += 1 { + memory.job_info_reload[job_id].id = job_id + memory.job_reload[job_id] = make_job_raw(& memory.job_group_reload, & memory.job_info_reload[job_id], test_job, {}, "Job Test (Hot-Reload)") + job_dispatch_single(& memory.job_reload[job_id], .Normal) + } + } + should_close = true + } + // should_close |= update( host_delta_time_ms ) + // render() + return +} + @export jobsys_worker_tick :: proc(host_delta_time_ms: f64, host_delta_ns: Duration) { - profile("Worker Tick") + // profile("Worker Tick") context.logger = to_odin_logger(& memory.client_memory.logger) ORDERED_PRIORITIES :: [len(JobPriority)]JobPriority{.High, .Normal, .Low} @@ -316,6 +323,7 @@ test_job :: proc(data: rawptr) Frametime_High_Perf_Threshold_MS :: 1 / 240.0 +// TODO(Ed): Lift this to be usable by both tick lanes and job worker threads. tick_lane_frametime :: proc(client_tick: ^Tick, host_delta_time_ms: f64, host_delta_ns: Duration, can_sleep := true) { profile(#procedure) diff --git a/code2/sectr/engine/client_api_sokol_callbacks.odin b/code2/sectr/engine/client_api_sokol_callbacks.odin new file mode 100644 index 0000000..0924da3 --- /dev/null +++ b/code2/sectr/engine/client_api_sokol_callbacks.odin @@ -0,0 +1,39 @@ +package sectr + +import sokol_app "thirdparty:sokol/app" + +sokol_app_init_callback :: proc "c" () { + context = memory.client_memory.sokol_context + log_print("sokol_app: Confirmed initialization") +} +// This is being filled in but we're directly controlling the lifetime of sokol_app's execution. +// So this will only get called during window pan or resize events (on Win32 at least) +sokol_app_frame_callback :: proc "c" () +{ + profile(#procedure) + context = memory.client_memory.sokol_context + should_close: bool + + sokol_width := sokol_app.widthf() + sokol_height := sokol_app.heightf() + + window := & memory.client_memory.app_window + // if int(window.extent.x) != int(sokol_width) || int(window.extent.y) != int(sokol_height) { + window.resized = true + window.extent.x = cast(f32) i32(sokol_width * 0.5) + window.extent.y = cast(f32) i32(sokol_height * 0.5) + // log("sokol_app: Event-based frame callback triggered (detected a resize") + // } + + // sokol_app is the only good reference for a frame-time at this point. + sokol_delta_ms := sokol_app.frame_delta() + sokol_delta_ns := transmute(Duration) sokol_delta_ms * MS_To_NS + + profile_begin("Client Tick") + client_tick := tick_now() + should_close |= tick_lane_work_frame( sokol_delta_ms ) + profile_end() + + tick_lane_frametime( & client_tick, sokol_delta_ms, sokol_delta_ns, can_sleep = false ) + window.resized = false +} diff --git a/code2/sectr/pkg_mappings.odin b/code2/sectr/pkg_mappings.odin index 057deca..ca2ab64 100644 --- a/code2/sectr/pkg_mappings.odin +++ b/code2/sectr/pkg_mappings.odin @@ -8,6 +8,9 @@ Any symbol that does must be mapped from the Grime package to properly tirage it import "base:intrinsics" debug_trap :: intrinsics.debug_trap +import "base:runtime" + Context :: runtime.Context + import "core:dynlib" // Only referenced in ModuleAPI DynLibrary :: dynlib.Library diff --git a/code2/sectr/space.odin b/code2/sectr/space.odin index 7157785..0bbd432 100644 --- a/code2/sectr/space.odin +++ b/code2/sectr/space.odin @@ -55,3 +55,5 @@ CameraZoomMode :: enum u32 { Smooth, } +Extents2_F4 :: V2_F4 +Extents2_S4 :: V2_S4 diff --git a/code2/sectr/state.odin b/code2/sectr/state.odin index 7eaf46e..70c1fc8 100644 --- a/code2/sectr/state.odin +++ b/code2/sectr/state.odin @@ -49,6 +49,13 @@ AppConfig :: struct { text_alpha_sharpen : f32, } +AppWindow :: struct { + extent: Extents2_F4, // Window half-size + dpi_scale: f32, // Dots per inch scale (provided by raylib via glfw) + ppcm: f32, // Dots per centimetre + resized: b32, // Extent changed this frame +} + FrameTime :: struct { sleep_is_granular : b32, @@ -63,12 +70,16 @@ FrameTime :: struct { } State :: struct { - config: AppConfig, + config: AppConfig, + app_window: AppWindow, // Overall frametime of the tick frame (currently main thread's) using frametime : FrameTime, logger: Logger, + + sokol_frame_count: i64, + sokol_context: Context, } ThreadState :: struct {