The vblank callback now reports the vblank type

This commit is contained in:
Lior Halphon 2022-06-25 01:59:51 +03:00
parent 58df8144ec
commit aaf9a76b67
9 changed files with 28 additions and 30 deletions

View File

@ -131,7 +131,7 @@ static void boot_rom_load(GB_gameboy_t *gb, GB_boot_rom_t type)
[self loadBootROM: type]; [self loadBootROM: type];
} }
static void vblank(GB_gameboy_t *gb) static void vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
{ {
Document *self = (__bridge Document *)GB_get_user_data(gb); Document *self = (__bridge Document *)GB_get_user_data(gb);
[self vblank]; [self vblank];

View File

@ -106,7 +106,7 @@ typedef struct __attribute__((packed)) {
uint8_t flags; uint8_t flags;
} object_t; } object_t;
void GB_display_vblank(GB_gameboy_t *gb) void GB_display_vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
{ {
gb->vblank_just_occured = true; gb->vblank_just_occured = true;
gb->cycles_since_vblank_callback = 0; gb->cycles_since_vblank_callback = 0;
@ -211,7 +211,7 @@ void GB_display_vblank(GB_gameboy_t *gb)
GB_handle_rumble(gb); GB_handle_rumble(gb);
if (gb->vblank_callback) { if (gb->vblank_callback) {
gb->vblank_callback(gb); gb->vblank_callback(gb, type);
} }
GB_timing_sync(gb); GB_timing_sync(gb);
} }
@ -1348,7 +1348,7 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
/* The PPU does not advance while in STOP mode on the DMG */ /* The PPU does not advance while in STOP mode on the DMG */
if (gb->stopped && !GB_is_cgb(gb)) { if (gb->stopped && !GB_is_cgb(gb)) {
if (gb->cycles_since_vblank_callback >= LCDC_PERIOD) { if (gb->cycles_since_vblank_callback >= LCDC_PERIOD) {
GB_display_vblank(gb); GB_display_vblank(gb, GB_VBLANK_TYPE_ARTIFICIAL);
} }
return; return;
} }
@ -1402,7 +1402,7 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
if (gb->cycles_since_vblank_callback < LCDC_PERIOD) { if (gb->cycles_since_vblank_callback < LCDC_PERIOD) {
GB_SLEEP(gb, display, 1, LCDC_PERIOD - gb->cycles_since_vblank_callback); GB_SLEEP(gb, display, 1, LCDC_PERIOD - gb->cycles_since_vblank_callback);
} }
GB_display_vblank(gb); GB_display_vblank(gb, GB_VBLANK_TYPE_LCD_OFF);
gb->cgb_repeated_a_frame = true; gb->cgb_repeated_a_frame = true;
} }
return; return;
@ -1889,7 +1889,7 @@ skip_slow_mode_3:
// Todo: unverified timing // Todo: unverified timing
gb->current_lcd_line++; gb->current_lcd_line++;
if (gb->current_lcd_line == LINES && GB_is_sgb(gb)) { if (gb->current_lcd_line == LINES && GB_is_sgb(gb)) {
GB_display_vblank(gb); GB_display_vblank(gb, GB_VBLANK_TYPE_NORMAL_FRAME);
} }
if (gb->icd_hreset_callback) { if (gb->icd_hreset_callback) {
@ -1931,13 +1931,13 @@ skip_slow_mode_3:
if (gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON) { if (gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON) {
if (GB_is_cgb(gb)) { if (GB_is_cgb(gb)) {
GB_display_vblank(gb); GB_display_vblank(gb, GB_VBLANK_TYPE_NORMAL_FRAME);
gb->frame_skip_state = GB_FRAMESKIP_FIRST_FRAME_SKIPPED; gb->frame_skip_state = GB_FRAMESKIP_FIRST_FRAME_SKIPPED;
} }
else { else {
if (!GB_is_sgb(gb) || gb->current_lcd_line < LINES) { if (!GB_is_sgb(gb) || gb->current_lcd_line < LINES) {
gb->is_odd_frame ^= true; gb->is_odd_frame ^= true;
GB_display_vblank(gb); GB_display_vblank(gb, GB_VBLANK_TYPE_NORMAL_FRAME);
} }
gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED; gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED;
} }
@ -1945,7 +1945,7 @@ skip_slow_mode_3:
else { else {
if (!GB_is_sgb(gb) || gb->current_lcd_line < LINES) { if (!GB_is_sgb(gb) || gb->current_lcd_line < LINES) {
gb->is_odd_frame ^= true; gb->is_odd_frame ^= true;
GB_display_vblank(gb); GB_display_vblank(gb, GB_VBLANK_TYPE_NORMAL_FRAME);
} }
if (gb->frame_skip_state == GB_FRAMESKIP_FIRST_FRAME_SKIPPED) { if (gb->frame_skip_state == GB_FRAMESKIP_FIRST_FRAME_SKIPPED) {
gb->cgb_repeated_a_frame = true; gb->cgb_repeated_a_frame = true;

View File

@ -5,12 +5,18 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
typedef enum {
GB_VBLANK_TYPE_NORMAL_FRAME, // An actual Vblank-triggered frame
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_t;
#ifdef GB_INTERNAL #ifdef GB_INTERNAL
internal void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force); internal void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force);
internal void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index); internal void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index);
internal void GB_STAT_update(GB_gameboy_t *gb); internal void GB_STAT_update(GB_gameboy_t *gb);
internal void GB_lcd_off(GB_gameboy_t *gb); internal void GB_lcd_off(GB_gameboy_t *gb);
internal void GB_display_vblank(GB_gameboy_t *gb); internal void GB_display_vblank(GB_gameboy_t *gb, GB_vblank_type_t type);
#define GB_display_sync(gb) GB_display_run(gb, 0, true) #define GB_display_sync(gb) GB_display_run(gb, 0, true)
enum { enum {

View File

@ -283,7 +283,7 @@ typedef enum {
#endif #endif
#endif #endif
typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb); typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb, GB_vblank_type_t type);
typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes); typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes);
typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb); typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb);
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b); typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);

View File

@ -1422,21 +1422,13 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case GB_IO_LCDC: case GB_IO_LCDC:
if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) { if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) {
if (value & 0x80) { // LCD turned on
// LCD turned on if (!gb->lcd_disabled_outside_of_vblank &&
if (!gb->lcd_disabled_outside_of_vblank && (gb->cycles_since_vblank_callback > 10 * 456 || GB_is_sgb(gb))) {
(gb->cycles_since_vblank_callback > 10 * 456 || GB_is_sgb(gb))) { // Trigger a vblank here so we don't exceed LCDC_PERIOD
// Trigger a vblank here so we don't exceed LCDC_PERIOD GB_display_vblank(gb, GB_VBLANK_TYPE_ARTIFICIAL);
GB_display_vblank(gb);
}
}
else {
// LCD turned off
if (gb->current_line < 144) {
// ROM might be repeatedly disabling LCDC outside of vblank, avoid callback spam
gb->lcd_disabled_outside_of_vblank = true;
}
} }
gb->display_cycles = 0; gb->display_cycles = 0;
gb->display_state = 0; gb->display_state = 0;
gb->double_speed_alignment = 0; gb->double_speed_alignment = 0;

View File

@ -25,7 +25,7 @@ static void log_callback(GB_gameboy_t *gb, const char *string, GB_log_attributes
} }
static void vblank(GB_gameboy_t *gb) static void vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
{ {
struct local_data *local_data = (struct local_data *)GB_get_user_data(gb); struct local_data *local_data = (struct local_data *)GB_get_user_data(gb);

View File

@ -462,7 +462,7 @@ static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
return SDL_MapRGB(pixel_format, r, g, b); return SDL_MapRGB(pixel_format, r, g, b);
} }
static void vblank(GB_gameboy_t *gb) static void vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
{ {
if (underclock_down && clock_mutliplier > 0.5) { if (underclock_down && clock_mutliplier > 0.5) {
clock_mutliplier -= 1.0/16; clock_mutliplier -= 1.0/16;

View File

@ -123,7 +123,7 @@ static void handle_buttons(GB_gameboy_t *gb)
} }
static void vblank(GB_gameboy_t *gb) static void vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
{ {
/* Detect common crashes and stop the test early */ /* Detect common crashes and stop the test early */
if (frames < test_length - 1) { if (frames < test_length - 1) {

View File

@ -248,12 +248,12 @@ static void audio_callback(GB_gameboy_t *gb, GB_sample_t *sample)
output_audio_buffer.data[output_audio_buffer.size++] = sample->right; output_audio_buffer.data[output_audio_buffer.size++] = sample->right;
} }
static void vblank1(GB_gameboy_t *gb) static void vblank1(GB_gameboy_t *gb, GB_vblank_type_t type)
{ {
vblank1_occurred = true; vblank1_occurred = true;
} }
static void vblank2(GB_gameboy_t *gb) static void vblank2(GB_gameboy_t *gb, GB_vblank_type_t type)
{ {
vblank2_occurred = true; vblank2_occurred = true;
} }