From b348acaa8136baf6fd2d2fa294e76021d364b553 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 28 Mar 2023 12:57:47 -0400 Subject: [PATCH] Made coroutines make more sense, and fixed a bug. (#1381) * Made coroutines make more sense, and fixed a bug. * Fixed typo. * Additional checking for off-cycles. * Fixed issue with calling step too much. * If we have no redraw, set next step time for next frame. * Added in `now` variables to reduce calls. --- data/core/init.lua | 58 ++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/data/core/init.lua b/data/core/init.lua index 6ac63e53..5056927d 100644 --- a/data/core/init.lua +++ b/data/core/init.lua @@ -305,7 +305,7 @@ function core.add_project_directory(path) end end if project_dir_open then - coroutine.yield(changed and 0.05 or 0) + coroutine.yield(changed and 0 or 0.05) else return end @@ -1384,7 +1384,7 @@ end local run_threads = coroutine.wrap(function() while true do local max_time = 1 / config.fps - 0.004 - local need_more_work = false + local minimal_time_to_wake = math.huge for k, thread in pairs(core.threads) do -- run thread @@ -1398,48 +1398,60 @@ local run_threads = coroutine.wrap(function() end elseif wait then thread.wake = system.get_time() + wait + minimal_time_to_wake = math.min(minimal_time_to_wake, wait) else - need_more_work = true + minimal_time_to_wake = 0 end + else + minimal_time_to_wake = math.min(minimal_time_to_wake, thread.wake - system.get_time()) end -- stop running threads if we're about to hit the end of frame if system.get_time() - core.frame_start > max_time then - coroutine.yield(true) + coroutine.yield(0) end end - if not need_more_work then coroutine.yield(false) end + coroutine.yield(minimal_time_to_wake) end end) function core.run() - local idle_iterations = 0 + local next_step while true do core.frame_start = system.get_time() - local need_more_work = run_threads() - local did_redraw = core.step() + local time_to_wake = run_threads() + local did_redraw = false + if not next_step or system.get_time() >= next_step then + did_redraw = core.step() + next_step = nil + end if core.restart_request or core.quit_request then break end - if not did_redraw and not need_more_work then - idle_iterations = idle_iterations + 1 - -- do not wait of events at idle_iterations = 1 to give a chance at core.step to run - -- and set "redraw" flag. - if idle_iterations > 1 then - if system.window_has_focus() then - -- keep running even with no events to make the cursor blinks - local t = system.get_time() - core.blink_start + + if not did_redraw then + if system.window_has_focus() then + local now = system.get_time() + if not next_step then -- compute the time until the next blink + local t = now - core.blink_start local h = config.blink_period / 2 local dt = math.ceil(t / h) * h - t - system.wait_event(dt + 1 / config.fps) - else - system.wait_event() + local cursor_time_to_wake = dt + 1 / config.fps + next_step = now + cursor_time_to_wake end + if time_to_wake > 0 and system.wait_event(math.min(next_step - now, time_to_wake)) then + next_step = nil -- if we've recevied an event, perform a step + end + else + system.wait_event() + next_step = nil -- perform a step when we're not in focus if get we an event end - else - idle_iterations = 0 - local elapsed = system.get_time() - core.frame_start - system.sleep(math.max(0, 1 / config.fps - elapsed)) + else -- if we redrew, then make sure we only draw at most FPS/sec + local now = system.get_time() + local elapsed = now - core.frame_start + local next_frame = math.max(0, 1 / config.fps - elapsed) + next_step = next_step or (now + next_frame) + system.sleep(math.min(next_frame, time_to_wake)) end end end