mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
Merge pull request #2007 from laaledesiempre/fix/main-thread-jitter
fix(core): cut per-frame allocation churn and GC pressure on the main loop
This commit is contained in:
@@ -34,12 +34,21 @@ end
|
||||
|
||||
-- Global emergency quit: holding Start + Select for 5 seconds forcefully terminates LOVE.
|
||||
local emergencyQuitTimer = 0
|
||||
-- getJoysticks() allocates a fresh table every call; this runs once (twice)
|
||||
-- per frame, so cache the list and refresh it once a second instead. The 5s
|
||||
-- hold requirement makes a 1s hotplug delay irrelevant.
|
||||
local cachedJoysticks = nil
|
||||
local joystickCacheAge = 1
|
||||
|
||||
local function checkEmergencyQuit(dt)
|
||||
local held = false
|
||||
joystickCacheAge = joystickCacheAge + (dt or 0.016)
|
||||
if love.joystick and love.joystick.getJoysticks then
|
||||
local joysticks = love.joystick.getJoysticks()
|
||||
for _, j in ipairs(joysticks) do
|
||||
if not cachedJoysticks or joystickCacheAge >= 1 then
|
||||
cachedJoysticks = love.joystick.getJoysticks()
|
||||
joystickCacheAge = 0
|
||||
end
|
||||
for _, j in ipairs(cachedJoysticks) do
|
||||
if j:isGamepad() then
|
||||
local start = j:isGamepadDown("start")
|
||||
local selectBtn = j:isGamepadDown("back") or j:isGamepadDown("guide")
|
||||
|
||||
+17
-8
@@ -21,6 +21,12 @@ local function renderVisible(stack, state)
|
||||
return state and (not stack.renderVisible or stack:renderVisible(state))
|
||||
end
|
||||
|
||||
-- Vanilla defaults for ModRuntime.call, hoisted to module level: called from
|
||||
-- the 60Hz logic step / per-frame speed resolution, an inline closure here
|
||||
-- allocated a fresh function every tick for no behavioral gain.
|
||||
local function noop() end
|
||||
local function resolveLogicSpeedVanilla(g) return g:_resolveLogicSpeed() end
|
||||
|
||||
-- dev-mode gate for the F5/backtick hotkeys; false keeps every src/dev
|
||||
-- module unloaded, so a player boot never touches a byte of dev code
|
||||
local devMode = os.getenv("POKEPORT_DEV") == "1" or _G.POKEPORT_DEV_MODE == true
|
||||
@@ -304,7 +310,7 @@ function Game:step(dt)
|
||||
-- the same fixed-step boundary as a physical controller. Run them before
|
||||
-- Input:step promotes queued edges so a button chosen here is visible to
|
||||
-- this logic tick, not one tick later. With no wrapper this is a no-op.
|
||||
ModRuntime.call("input.step", function() end, self, dt)
|
||||
ModRuntime.call("input.step", noop, self, dt)
|
||||
self.input:step()
|
||||
-- A+B+SELECT+START held for 16 steps: SoftReset (home/init.asm) stops the
|
||||
-- audio, whites the palettes out and falls through into Init, i.e. the
|
||||
@@ -390,7 +396,7 @@ function Game:logicSpeed()
|
||||
-- returns a bad value, so an unclamped result would flow straight into
|
||||
-- the FixedStep accumulator math below and freeze or destabilize logic.
|
||||
return GameSpeed.clamp(ModRuntime.call("core.logic_speed",
|
||||
function(g) return g:_resolveLogicSpeed() end, self))
|
||||
resolveLogicSpeedVanilla, self))
|
||||
end
|
||||
|
||||
function Game:update(dt)
|
||||
@@ -420,12 +426,15 @@ function Game:update(dt)
|
||||
pcall(function() require("src.core.DiscordPresence").update(dt) end)
|
||||
self:updateSync(dt)
|
||||
-- Steady-state memory backstop: advance the incremental collector one
|
||||
-- small step every rendered frame. The heavy GPU objects are now freed
|
||||
-- explicitly (map eviction, battle exit, canvas/renderer swaps), so this
|
||||
-- only has to keep ordinary Lua-heap garbage (per-frame tables/closures)
|
||||
-- from drifting upward over a long session, and to spread collection out
|
||||
-- so the default lazy schedule never batches it into a visible pause.
|
||||
if collectgarbage then collectgarbage("step", 1) end
|
||||
-- small step every few rendered frames. The heavy GPU objects are now
|
||||
-- freed explicitly (map eviction, battle exit, canvas/renderer swaps), so
|
||||
-- this only has to keep ordinary Lua-heap garbage (per-frame tables) from
|
||||
-- drifting upward over a long session, and to spread collection out so the
|
||||
-- default lazy schedule never batches it into a visible pause. Every 4th
|
||||
-- frame (not every frame) so the stepping itself does not compete with
|
||||
-- the frame budget on weak single-core handhelds.
|
||||
self.gcStepFrame = (self.gcStepFrame or 0) + 1
|
||||
if collectgarbage and self.gcStepFrame % 4 == 0 then collectgarbage("step", 1) end
|
||||
end
|
||||
|
||||
-- render.zones' identity default: unhooked, the zone list reaches the blit
|
||||
|
||||
Reference in New Issue
Block a user