diff --git a/Cocoa/Document.m b/Cocoa/Document.m index ad723ad..4fcfb08 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -288,6 +288,7 @@ static void debuggerReloadCallback(GB_gameboy_t *gb) GB_set_user_data(&_gb, (__bridge void *)(self)); GB_set_boot_rom_load_callback(&_gb, (GB_boot_rom_load_callback_t)boot_rom_load); GB_set_vblank_callback(&_gb, (GB_vblank_callback_t) vblank); + GB_set_enable_skipped_frame_vblank_callbacks(&_gb, true); GB_set_log_callback(&_gb, (GB_log_callback_t) consoleLog); GB_set_input_callback(&_gb, (GB_input_callback_t) consoleInput); GB_set_async_input_callback(&_gb, (GB_input_callback_t) asyncConsoleInput); @@ -359,6 +360,12 @@ static void debuggerReloadCallback(GB_gameboy_t *gb) - (void)vblankWithType:(GB_vblank_type_t)type { + if (type == GB_VBLANK_TYPE_SKIPPED_FRAME) { + double frameUsage = GB_debugger_get_frame_cpu_usage(&_gb); + [_cpuView addSample:frameUsage]; + return; + } + if (_gbsVisualizer) { dispatch_async(dispatch_get_main_queue(), ^{ [_gbsVisualizer setNeedsDisplay:true]; diff --git a/Core/display.c b/Core/display.c index 2a94a03..a9c530e 100644 --- a/Core/display.c +++ b/Core/display.c @@ -197,7 +197,13 @@ void GB_display_vblank(GB_gameboy_t *gb, GB_vblank_type_t type) } if (gb->turbo) { +#ifndef GB_DISABLE_DEBUGGER + if (unlikely(gb->backstep_instructions)) return; +#endif if (GB_timing_sync_turbo(gb)) { + if (gb->vblank_callback && gb->enable_skipped_frame_vblank_callbacks) { + gb->vblank_callback(gb, GB_VBLANK_TYPE_SKIPPED_FRAME); + } return; } } @@ -2485,3 +2491,8 @@ double GB_get_usual_frame_rate(GB_gameboy_t *gb) { return GB_get_clock_rate(gb) / (double)LCDC_PERIOD; } + +void GB_set_enable_skipped_frame_vblank_callbacks(GB_gameboy_t *gb, bool enable) +{ + gb->enable_skipped_frame_vblank_callbacks = enable; +} diff --git a/Core/display.h b/Core/display.h index 34110dc..b333df0 100644 --- a/Core/display.h +++ b/Core/display.h @@ -20,6 +20,7 @@ typedef enum { GB_VBLANK_TYPE_LCD_OFF, // An artificial frame pushed while the LCD was off GB_VBLANK_TYPE_ARTIFICIAL, // An artificial frame pushed for some other reason GB_VBLANK_TYPE_REPEAT, // A frame that would not render on actual hardware, but the screen should retain the previous frame + GB_VBLANK_TYPE_SKIPPED_FRAME, // If enabled via GB_set_enable_skipped_frame_vblank_callbacks, called on skipped frames during turbo mode } GB_vblank_type_t; typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb, GB_vblank_type_t type); @@ -95,6 +96,7 @@ static const GB_color_correction_mode_t __attribute__((deprecated("Use GB_COLOR_ static const GB_color_correction_mode_t __attribute__((deprecated("Use GB_COLOR_CORRECTION_MODERN_BOOST_CONTRAST instead"))) GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS = GB_COLOR_CORRECTION_MODERN_BOOST_CONTRAST; void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback); +void GB_set_enable_skipped_frame_vblank_callbacks(GB_gameboy_t *gb, bool enable); void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback); void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette); const GB_palette_t *GB_get_palette(GB_gameboy_t *gb); diff --git a/Core/gb.h b/Core/gb.h index 859dbad..0f52822 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -833,6 +833,7 @@ struct GB_gameboy_internal_s { /* Misc */ bool turbo; bool turbo_dont_skip; + bool enable_skipped_frame_vblank_callbacks; bool disable_rendering; uint8_t boot_rom[0x900]; bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank