Shane McGovern 7e2307f58c Use spare CPU cores to remove in-game hitches on low-power devices (#2872)
* Use spare CPU cores to remove in-game hitches on low-power devices

Per-frame game logic and drawing are cheap; the remaining stalls on
low-power handhelds are one-off main-thread hitches from chip SFX/cry
synthesis, RED++ atlas recolouring, image decodes and the require shim.
Move those onto background threads, each with a synchronous fallback so
behaviour is identical when threads are unavailable (POKEPORT_NO_THREAD=1,
no love.thread, worker failure).

Also adds an F3 frame-time overlay and POKEPORT_GAME_PROF headless
profiling to measure these costs.

* Address code review: shared WorkerLane, F3 gating, decode/epoch fixes

- Extract src/core/WorkerLane.lua (worker lifecycle, prioritised lanes,
  per-lane epochs, bounded LRU) and rebuild the SFX and atlas/decode
  prefetchers on it
- Keep decoded sprite sheets in every colour mode (the OBJ palette bake
  re-reads them), skip oversized decodes, and let palette changes drop
  only atlas bakes
- Only bump the SFX render epoch when the channel mix actually changes
- F3 overlay toggle no longer steals the key from rebinding screens or
  player bindings; profilers stop only when a quit really proceeds
- Require fast path: test hook instead of a hot-path counter
- Shared tests/drivers/perf_util.lua; drivers restore their patches

* WorkerLane: no budget leak on duplicate sends, keep priority on requeue

- Lane:pump only counts a job against the in-flight budget once per key
- requeueInflight puts entries back at the head of their own queue, so
  background hints no longer overtake front requests after a bump
- shutdown() keeps a fatally failed worker off
- Hiding the F3 overlay logs one summary line instead of a full block

* F3 overlay: last-120-frame stats, font-sized box, scale on large screens

* Prefetch: skip useless hints, no main-thread fallback, mix check vs worker config

- Don't queue decodes for sprite sheets whose Image and OBJ bake are cached
- Atlas hint is dropped (sync bake at build time) when the worker can't
  decode the tileset itself, instead of decoding on the main thread
- SFX epoch bump compares the live mix with what the worker was last
  configured with, replacing the load-time snapshot

* Sprite decode skip: raw-path cache check, never under RED++

* Gen 2 battles prefetch both parties' cries; sprite skip keyed by raw path

* Prefetch: skip cached tilesets outside RED++, log hint failures once

* Profiler: bench survives F3 hide, frame total excludes vsync; safer SFX pump, ordered requeue, tileset skip respects pending variants

* Profiler counts GPU stalls in present; water void-fill keeps tileset hint; README + test coverage

* Profiler vsync cap: measured cadence via RefreshRate, no per-frame allocation

* Use upstream's chip-worker prewarm for SFX/cries; drop our separate SFX worker

Our extra coverage (Gen 1 common SFX + party cries, both parties' battle
cries, lead move sounds, hit and battle SFX, Gen 2 bench cries) now goes
through ChipAudio.prewarmSfx/prewarmCry and a new Sound.prewarmMove.

* Skip decode hints for composed assets; share move cache key; drop dead demoteAll

* Drop dev-only profiling extras: POKEPORT_JITP hook and perf drivers

* README: name the worker threads POKEPORT_JIT leaves alone

* Profiler: count the pre-present vblank wait as present, log on NX quit

- time PresentSync.waitBeforePresent as "present" (the X11 GLX vblank wait
  lands there), so it is excluded like the wait inside present
- NX quit now emits the PROF summary / overlay line too
- love.quit's scripted check reads FrameProfiler.benchRequested, so
  POKEPORT_GAME_PROF=0 no longer counts as a bench run
- prefetchAtlas skips composed tileset sheets (Assets.isComposed)
- hit sounds defined once in EffectRegistry.HIT_SOUNDS, shared with the
  battle prewarm (each hit still gets its own copy)
- drop redundant obpPaths, dead FrameProfiler.visible and the unused
  Lane:bump requeue mode; restore applyOptions' doc comment
2026-10-12 08:38:45 +01:00
2026-10-07 19:07:05 -04:00
2026-10-11 09:48:16 -04:00
2026-10-08 05:46:19 -04:00
2026-10-01 21:31:40 -04:00
2026-08-17 13:06:09 -04:00

G1R Deluxe aka Gen1Recomp

A native LÖVE2D recreation of Poke Red, Blue, Yellow, Gold, Silver, Crystal, FireRed, LeafGreen, Ruby, Sapphire, and Emerald. The engine and map behavior are hand-written Lua; game data and graphics are decoded from a ROM supplied by the player.

And before you say, "that's not a recomp", you're wrong. Recomp is an acronym. Reverse Engineering Causes Obsessive Mental Problems

Click Here for the AI Use Disclosure!

Caution

We are NOT affiliated with the website gen1recomp[.]com That website is not run by this project, was not authorized by us, and we have no idea who operates it. It is impersonating this project; do not download anything from it, and treat anything it hosts or claims as untrustworthy. Even if the site currently links back to this repository, the people behind it can change its content at any time, so nothing on it should ever be trusted. This GitHub repository, the Discord, and https://gen1re.com are the only official sources for this project. Also, as I assumed would eventually happen, the idiot that made that website now pumped it full of adware. Please stay away from that website.

SUPPORT / ANNOUNCEMENTS / MODS ALL FOUND ON THE DISCORD

YouTube TikTok X Bluesky Instagram

As seen on Polygon As seen on KOTAKU As seen on Digital Foundry As seen on Android Authority As seen on XDA Developers

Watch the latest update video

Watch the latest update video

What this is

G1R Deluxe aka Gen1Recomp is a native LÖVE2D recreation of Pokemon Red, Blue, Yellow, Gold, Silver, Crystal, FireRed, LeafGreen, Ruby, Sapphire, and Emerald. The engine and map behavior are hand-written Lua, ported from the pret disassemblies & C. Game data, graphics, and audio programs are decoded on first launch from a ROM you supply.

The project does not include a ROM, emulate the Game Boy, transpile assembly, or download a disassembly. Your ROM is verified, used during import, and released from memory. It is never copied into the cache, and later launches load the private generated cache without asking for it again. Music, sound effects, and cries are synthesized while the game runs. All eleven games can be imported side by side. Gen 2 support is still under construction.

Quick Start

  1. Download the build for your platform from the latest release.
  2. Launch it. The packaged app contains no ROM and no game data, so the launcher will ask for one.
  3. Choose your legally obtained .gb / .gbc / .gba file, a .zip / .7z that holds one (offered only where your platform's build supports archives), or drop it onto the window. Import takes a few seconds and the game starts automatically.
  4. Repeat for any other game you own. Each one gets its own tab in the launcher.

Only the canonical US English ROMs below are accepted. The importer checks the SHA-1 before creating any game data. FireRed, LeafGreen, Ruby, Sapphire, and Emerald support is in beta.

Game Revision ROM size SHA-1
Red - 1 MiB ea9bcae617fdf159b045185467ae58b2e4a48b9a
Blue - 1 MiB d7037c83e1ae5b39bde3c30787637ba1d4c48ce2
Yellow - 1 MiB cc7d03262ebfaf2f06772c1a480c7d9d5f4a38e1
Gold - 2 MiB d8b8a3600a465308c9953dfa04f0081c05bdcb94
Silver - 2 MiB 49b163f7e57702bc939d642a18f591de55d92dae
Crystal 1.0 2 MiB f4cd194bdee0d04ca4eac29e09b8e4e9d818c133
Crystal 1.1 2 MiB f2f52230b536214ef7c9924f483392993e226cfb
FireRed 1.0 16 MiB 41cb23d8dccc8ebd7c649cd8fbb58eeace6e2fdc
FireRed 1.1 16 MiB dd5945db9b930750cb39d00c84da8571feebf417
LeafGreen 1.0 16 MiB 574fa542ffebb14be69902d1d36f1ec0a4afd71e
LeafGreen 1.1 16 MiB 7862c67bdecbe21d1d69ce082ce34327e1c6ed5e
Emerald 1.0 16 MiB f3ae088181bf583e55daf962a92bb46f4f1d07b7
Ruby 1.0 16 MiB f28b6ffc97847e94a6c21a63cacf633ee5c8df1e
Ruby 1.1 16 MiB 610b96a9c9a7d03d2bafb655e7560ccff1a6d894
Ruby 1.2 16 MiB 5b64eacf892920518db4ec664e62a086dd5f5bc8
Sapphire 1.0 16 MiB 3ccbbd45f8553c36463f13b938e833f652b793e4
Sapphire 1.1 16 MiB 4722efb8cd45772ca32555b98fd3b9719f8e60a9
Sapphire 1.2 16 MiB 89b45fb172e6b55d51fc0e61989775187f6fe63c

Platform notes: Linux, iOS, Xbox Dev Mode, handhelds, Nintendo Switch, and PlayStation 4 each have their own install steps.

Windows Defender: it sometimes flags the Windows build with a generic detection such as Trojan:Win32/Wacatac!ml (#621). This is a known false positive: the exe is the official LÖVE runtime with the game archive appended, and Defender distrusts unsigned executables with appended data. Every release publishes sha256sums.txt so you can verify your download, and you can check a flagged file on VirusTotal.

Controls

Action Keyboard Controller
Move Arrow keys / WASD D-pad / left stick
A Z / Enter / Space A
B X / Backspace B
Start Escape Start
Select Tab / Shift Back / Select

Rebind any of these in-game under OPTIONS > CONTROLS.

Key What it does
- / = Zoom out / in (overworld; also mouse wheel)
1 / 0 GAME SPEED up / down (controller: R2 faster, L2 slower)
2 Cycle COLORS
3 Cycle TILT (free-roam overworld)
4 Cycle ZOOM through every level (free-roam overworld)
F1 Save
F2 Load
F10 Open / close the mod manager

COLORS, TILT, ZOOM, SHADER FX, GAME SPEED, and VOID FILL are also in the Options menu and persist in options.lua.

Low-end devices: OPTIONS > PERFORMANCE scales the optional extras for weaker hardware (HIGH, BALANCED, LOW, or AUTO, the default). It only changes presentation; game logic is identical on every tier. Details in docs/new-features.md.

Documentation

Everything else lives in the docs folder or on the project wiki, which has the modding book, link play, save editor, and developer setup guides:

Measuring frame time

Press F3 in a running game to toggle a small frame-time overlay (FPS, per-section update/draw/present timings, Lua heap, draw calls, texture memory). It is off by default and costs nothing when hidden. Set POKEPORT_GAME_PROF_OVERLAY=1 to start with it shown. For a headless measurement set POKEPORT_GAME_PROF=<frames>: after a 60-frame warmup and <frames> recorded frames it prints a PROF ... summary to stderr and quits. POKEPORT_GAME_PROF=all records until the game quits and then prints the summary, which also lists the worst spikes (over 16.7 ms) with the per-section cost and the screen/map they happened on. The frame figure and the spike threshold are work time: the vsync wait in or just before present (up to one display refresh) is excluded, so an idle frame reads well under a millisecond while a GPU stall in present still counts. The launcher is never profiled.

POKEPORT_JIT=0 turns the LuaJIT compiler off (prints [info] jit off), to approximate low-power devices that run Lua without it. It affects only the main Lua state; worker threads (music/SFX and the atlas/decode worker) keep their JIT.

Bugs

Found a bug? A warp dropping you somewhere it shouldn't, a battle doing math that looks wrong, text in the wrong box, anything that does not match the original game. Open a bug report. Attach a screenshot if you can. It saves a lot of back and forth, and if you can't get one, the form asks you to describe what you saw instead.

License

See LICENSE.MD.

Special Thanks

This project would not be possible without pret > the pret band of decompiling maniacs > and their pokered disassembly.

S
Description
No description provided
Readme 212 MiB
Languages
Lua 56.8%
C 26.1%
C++ 10.7%
Shell 1.5%
Python 1.1%
Other 3.5%