From 1532f555fe1805663cbf79c1ac9385d0d3957cb3 Mon Sep 17 00:00:00 2001 From: retro-wertz Date: Tue, 23 Jul 2019 00:40:28 +0800 Subject: [PATCH] GB: Reduce input lag by 1 frame, video and audio timing updates... Similar update to GBA which does the following: - reduces input lag by 1 frame by reading user input at beginning of cpu loop - audio and video timing update, which sends audio and video at every frame possible - add missing sound state variable, soundTicks for gb and gba --- src/gb/GB.cpp | 115 +++++++++++++++++++-------------------------- src/gb/gbSound.cpp | 79 +++++++++++++++---------------- src/gb/gbSound.h | 6 +-- src/gba/Sound.cpp | 8 ++-- 4 files changed, 93 insertions(+), 115 deletions(-) diff --git a/src/gb/GB.cpp b/src/gb/GB.cpp index 909024bce..1ae775821 100644 --- a/src/gb/GB.cpp +++ b/src/gb/GB.cpp @@ -1232,7 +1232,7 @@ void gbWriteMemory(uint16_t address, uint8_t value) case 0x3e: case 0x3f: // Sound registers handled by blargg - gbSoundEvent(address, value); + gbSoundEvent(soundTicks, address, value); //gbMemory[address] = value; return; @@ -1967,7 +1967,7 @@ uint8_t gbReadMemory(uint16_t address) case 0x3e: case 0x3f: // Sound registers read - return gbSoundRead(address); + return gbSoundRead(soundTicks, address); case 0x40: return register_LCDC; case 0x41: @@ -4535,12 +4535,37 @@ void gbDrawLine() } } +static void gbUpdateJoypads(bool readSensors) +{ + if (systemReadJoypads()) { + // read joystick + if (gbSgbMode && gbSgbMultiplayer) { + if (gbSgbFourPlayers) { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + gbJoymask[2] = systemReadJoypad(2); + gbJoymask[3] = systemReadJoypad(3); + } else { + gbJoymask[0] = systemReadJoypad(0); + gbJoymask[1] = systemReadJoypad(1); + } + } else { + gbJoymask[0] = systemReadJoypad(-1); + } + } + + if (readSensors && gbRomType == 0x22) { + systemUpdateMotionSensor(); + } +} + void gbEmulate(int ticksToStop) { gbRegister tempRegister; uint8_t tempValue; int8_t offset; + clockTicks = 0; gbDmaTicks = 0; @@ -4549,6 +4574,9 @@ void gbEmulate(int ticksToStop) int opcode1 = 0; int opcode2 = 0; bool execute = false; + bool frameDone = false; + + gbUpdateJoypads(true); while (1) { uint16_t oldPCW = PC.W; @@ -4661,6 +4689,8 @@ void gbEmulate(int ticksToStop) } ticksToStop -= clockTicks; + soundTicks += clockTicks; + if (!gbSpeed) soundTicks += clockTicks; // DIV register emulation gbDivTicks -= clockTicks; @@ -4930,6 +4960,7 @@ void gbEmulate(int ticksToStop) gbFrameCount++; systemFrame(); + gbSoundTick(soundTicks); if ((gbFrameCount % 10) == 0) system10Frames(60); @@ -4944,28 +4975,8 @@ void gbEmulate(int ticksToStop) gbFrameCount = 0; } - if (systemReadJoypads()) { - // read joystick - if (gbSgbMode && gbSgbMultiplayer) { - if (gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } - } int newmask = gbJoymask[0] & 255; - if (gbRomType == 0x22) { - systemUpdateMotionSensor(); - } - if (newmask) { gbMemory[0xff0f] = register_IF |= 16; } @@ -5003,6 +5014,8 @@ void gbEmulate(int ticksToStop) } else gbFrameSkipCount++; + frameDone = true; + } else { // go the the OAM being accessed mode gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS; @@ -5151,25 +5164,11 @@ void gbEmulate(int ticksToStop) ticksToStop = 0; } } - if (systemReadJoypads()) { - // read joystick - if (gbSgbMode && gbSgbMultiplayer) { - if (gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } - } + gbFrameCount++; systemFrame(); + gbSoundTick(soundTicks); if ((gbFrameCount % 10) == 0) system10Frames(60); @@ -5183,6 +5182,7 @@ void gbEmulate(int ticksToStop) gbLastTime = currentTime; gbFrameCount = 0; } + frameDone = true; } } } @@ -5279,15 +5279,14 @@ void gbEmulate(int ticksToStop) #endif } #endif - - soundTicks -= clockTicks; - if (!gbSpeed) - soundTicks -= clockTicks; - - while (soundTicks < 0) { - soundTicks += SOUND_CLOCK_TICKS; - - gbSoundTick(); + // TODO: evaluate and fix this + // On VBA-M (gb core running twice as fast?), each vblank is uses 35112 cycles. + // on some cases no vblank is generated causing sound ticks to keep accumulating causing core to crash. + // This forces core to flush sound buffers when expected sound ticks has passed and no frame is done yet.which then ends cpuloop + if ((soundTicks > SOUND_CLOCK_TICKS) && !frameDone) { + int last_st = soundTicks; + gbSoundTick(soundTicks); + soundTicks = (last_st - SOUND_CLOCK_TICKS); } // timer emulation @@ -5413,25 +5412,7 @@ void gbEmulate(int ticksToStop) gbBlackScreen = false; - if ((ticksToStop <= 0)) { - if (!(register_LCDC & 0x80)) { - if (systemReadJoypads()) { - // read joystick - if (gbSgbMode && gbSgbMultiplayer) { - if (gbSgbFourPlayers) { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - gbJoymask[2] = systemReadJoypad(2); - gbJoymask[3] = systemReadJoypad(3); - } else { - gbJoymask[0] = systemReadJoypad(0); - gbJoymask[1] = systemReadJoypad(1); - } - } else { - gbJoymask[0] = systemReadJoypad(-1); - } - } - } + if (ticksToStop <= 0 || frameDone) { // Stop loop return; } } @@ -5821,7 +5802,7 @@ struct EmulatedSystem GBSystem = { false, // emuCount #ifdef FINAL_VERSION - 70000 / 4, + 72000, #else 1000, #endif diff --git a/src/gb/gbSound.cpp b/src/gb/gbSound.cpp index 186ca61e8..2420f3466 100644 --- a/src/gb/gbSound.cpp +++ b/src/gb/gbSound.cpp @@ -24,25 +24,20 @@ static bool declicking = false; int const chan_count = 4; int const ticks_to_time = 2 * GB_APU_OVERCLOCK; -static inline blip_time_t blip_time() -{ - return (SOUND_CLOCK_TICKS - soundTicks) * ticks_to_time; -} - -uint8_t gbSoundRead(uint16_t address) +uint8_t gbSoundRead(int st, uint16_t address) { if (gb_apu && address >= NR10 && address <= 0xFF3F) - return gb_apu->read_register(blip_time(), address); + return gb_apu->read_register((blip_time_t)(st * ticks_to_time), address); return gbMemory[address]; } -void gbSoundEvent(uint16_t address, int data) +void gbSoundEvent(int st, uint16_t address, int data) { gbMemory[address] = data; if (gb_apu && address >= NR10 && address <= 0xFF3F) - gb_apu->write_register(blip_time(), address, data); + gb_apu->write_register((blip_time_t)(st * ticks_to_time), address, data); } static void end_frame(blip_time_t time) @@ -83,11 +78,11 @@ static void apply_volume() gb_apu->volume(soundVolume_); } -void gbSoundTick() +void gbSoundTick(int st) { if (gb_apu && stereo_buffer) { // Run sound hardware to present - end_frame(SOUND_CLOCK_TICKS * ticks_to_time); + end_frame((blip_time_t)(st * ticks_to_time)); flush_samples(stereo_buffer); @@ -100,6 +95,8 @@ void gbSoundTick() if (soundVolume_ != soundGetVolume()) apply_volume(); } + + soundTicks = 0; } static void reset_apu() @@ -115,7 +112,7 @@ static void reset_apu() if (stereo_buffer) stereo_buffer->clear(); - soundTicks = SOUND_CLOCK_TICKS; + soundTicks = 0; } static void remake_stereo_buffer() @@ -171,42 +168,42 @@ bool gbSoundGetDeclicking() void gbSoundReset() { - SOUND_CLOCK_TICKS = 20000; // 1/100 second + SOUND_CLOCK_TICKS = 35112; remake_stereo_buffer(); reset_apu(); soundPaused = 1; - gbSoundEvent(0xff10, 0x80); - gbSoundEvent(0xff11, 0xbf); - gbSoundEvent(0xff12, 0xf3); - gbSoundEvent(0xff14, 0xbf); - gbSoundEvent(0xff16, 0x3f); - gbSoundEvent(0xff17, 0x00); - gbSoundEvent(0xff19, 0xbf); - - gbSoundEvent(0xff1a, 0x7f); - gbSoundEvent(0xff1b, 0xff); - gbSoundEvent(0xff1c, 0xbf); - gbSoundEvent(0xff1e, 0xbf); - - gbSoundEvent(0xff20, 0xff); - gbSoundEvent(0xff21, 0x00); - gbSoundEvent(0xff22, 0x00); - gbSoundEvent(0xff23, 0xbf); - gbSoundEvent(0xff24, 0x77); - gbSoundEvent(0xff25, 0xf3); + gbSoundEvent(0, 0xff10, 0x80); + gbSoundEvent(0, 0xff11, 0xbf); + gbSoundEvent(0, 0xff12, 0xf3); + gbSoundEvent(0, 0xff14, 0xbf); + gbSoundEvent(0, 0xff16, 0x3f); + gbSoundEvent(0, 0xff17, 0x00); + gbSoundEvent(0, 0xff19, 0xbf); + + gbSoundEvent(0, 0xff1a, 0x7f); + gbSoundEvent(0, 0xff1b, 0xff); + gbSoundEvent(0, 0xff1c, 0xbf); + gbSoundEvent(0, 0xff1e, 0xbf); + + gbSoundEvent(0, 0xff20, 0xff); + gbSoundEvent(0, 0xff21, 0x00); + gbSoundEvent(0, 0xff22, 0x00); + gbSoundEvent(0, 0xff23, 0xbf); + gbSoundEvent(0, 0xff24, 0x77); + gbSoundEvent(0, 0xff25, 0xf3); if (gbHardware & 0x4) - gbSoundEvent(0xff26, 0xf0); + gbSoundEvent(0, 0xff26, 0xf0); else - gbSoundEvent(0xff26, 0xf1); + gbSoundEvent(0, 0xff26, 0xf1); /* workaround for game Beetlejuice */ if (gbHardware & 0x1) { - gbSoundEvent(0xff24, 0x77); - gbSoundEvent(0xff25, 0xf3); + gbSoundEvent(0, 0xff24, 0x77); + gbSoundEvent(0, 0xff25, 0xf3); } int addr = 0xff30; @@ -399,7 +396,6 @@ static void gbSoundReadGameOld(int version, gzFile gzFile) #endif // New state format - static variable_desc gb_state[] = { LOAD(int, state.version), // room_for_expansion will be used by later versions @@ -427,7 +423,8 @@ static variable_desc gb_state[] = { SKIP(int[13], room_for_expansion), // Emulator - SKIP(int[16], room_for_expansion), + LOAD(int, soundTicks), + SKIP(int[15], room_for_expansion), { NULL, 0 } }; @@ -445,7 +442,7 @@ void gbSoundSaveGame(gzFile out) state.version = 1; #ifdef __LIBRETRO__ - utilWriteDataMem(out, gb_state); + utilWriteDataMem(out, gb_state); #else utilWriteData(out, gb_state); #endif @@ -461,10 +458,10 @@ void gbSoundReadGame(int version, gzFile in) reset_apu(); gb_apu->save_state(&state.apu); - if (version > 11) #ifdef __LIBRETRO__ - utilReadDataMem(in, gb_state); + utilReadDataMem(in, gb_state); #else + if (version > 11) utilReadData(in, gb_state); else gbSoundReadGameOld(version, in); diff --git a/src/gb/gbSound.h b/src/gb/gbSound.h index 12a87a181..7c95bfa1e 100644 --- a/src/gb/gbSound.h +++ b/src/gb/gbSound.h @@ -56,14 +56,14 @@ extern gb_effects_config_t gb_effects_config; // current configuration void gbSoundReset(); // Emulates write to sound hardware -void gbSoundEvent(uint16_t address, int data); +void gbSoundEvent(int st, uint16_t address, int data); #define SOUND_EVENT gbSoundEvent // Emulates read from sound hardware -uint8_t gbSoundRead(uint16_t address); +uint8_t gbSoundRead(int st, uint16_t address); // Notifies emulator that SOUND_CLOCK_TICKS clocks have passed -void gbSoundTick(); +void gbSoundTick(int st); extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to gbSoundTick() extern int soundTicks; // Number of 16.8 MHz clocks until gbSoundTick() will be called diff --git a/src/gba/Sound.cpp b/src/gba/Sound.cpp index 1f37de72c..dba4ce01a 100644 --- a/src/gba/Sound.cpp +++ b/src/gba/Sound.cpp @@ -718,8 +718,8 @@ static variable_desc gba_state[] = { // Emulator LOAD(int, soundEnableFlag), - - SKIP(int[15], room_for_expansion), + LOAD(int, soundTicks), + SKIP(int[14], room_for_expansion), { NULL, 0 } }; @@ -806,10 +806,10 @@ void soundReadGame(gzFile in, int version) reset_apu(); gb_apu->save_state(&state.apu); - if (version > SAVE_GAME_VERSION_9) #ifdef __LIBRETRO__ - utilReadDataMem(in, gba_state); + utilReadDataMem(in, gba_state); #else + if (version > SAVE_GAME_VERSION_9) utilReadData(in, gba_state); else soundReadGameOld(in, version);