fix: decouple VBlank ISR and main loop to prevent IRQ stack overflow

- Make handle_vblank strictly increment frame counter (frame++)
- Move heavy frame logic (background updates, OAM updates, palette animations, and console stats) to update_frame() on the main thread synchronized with swiWaitForVBlank()
- Eliminate 256-byte ARM9 IRQ stack (sp_irq) overflow caused by bg_update and iprintf that was corrupting DTCM stack and causing data aborts
- Preserve all playfield entities on game over with top-screen defeat summary and smooth background deceleration

Co-authored-by: Antigravity <antigravity@google.com>
This commit is contained in:
phillipandAntigravity committed 2026-10-04 00:21:09 +02:00
1 parent 91908d1f15
commit 496de1a31f
10 files changed
+171 -81

No files matched your search

+1
View File
@@ -23,6 +23,7 @@ struct BackgroundContext {
bool hard_mode = false;
bool is_cursed = false;
bool game_over = false;
uint8_t game_over_fade = 0;
Scene scene = Scene::Menu;
};
+1
View File
@@ -42,6 +42,7 @@ void invalidate_hud(RenderAssets &assets);
void draw_game(const GameState &state, const RenderAssets &assets);
void draw_stats(const GameState &state, RenderAssets &assets, bool internals, bool musicEnabled, uint8_t frame);
void draw_menu(const GameState &state, RenderAssets &assets, bool musicEnabled);
void draw_game_over_screen(const GameState &state);
void blink_apples(const GameState &state, u16 *gfx_apple);
// Called every VBlank: owns OAM slots [0, BARRIER_OAM_SLOTS) and animates barrier palette entries
void draw_barriers(const GameState &state, const RenderAssets &assets, uint8_t frame);
+8
View File
@@ -15,6 +15,13 @@ enum class Scene {
constexpr int MENU_ITEM_COUNT = 3;
enum class GameOverReason : uint8_t {
None = 0,
SelfCollision,
BarrierCollision,
RottenAppleDepleted,
};
enum class BarrierPhase : uint8_t {
Inactive, // Slot free
Warning, // Flashing announcement, harmless
@@ -47,6 +54,7 @@ struct GameState {
volatile uint16_t applesEaten = 0;
bool gameOver = false;
GameOverReason gameOverReason = GameOverReason::None;
bool paused = false;
bool hardMode = false;