using skip frames properly (no audio)

This commit is contained in:
Sergio Martin 2024-01-14 06:12:32 +01:00
parent 040d7f3939
commit 57c43b6d98
7 changed files with 61 additions and 63 deletions

View File

@ -8,7 +8,13 @@ quickerNES is an attempt to modernizing and improving the performance of quickNE
- Add support for more mappers, controllers, and features supported by other emulators
- Improve accuracy, if possible
The main aim is to improve the exploration performance of my TASing bot, [JaffarPlus](https://github.com/SergioMartin86/jaffarPlus). However, if this work might help with homebrew emulation and other people having more fun, then much better!
The main aim is to improve the performance of skip (non-rendering, no-audio) frame advances for brute force botting. (See: [JaffarPlus](https://github.com/SergioMartin86/jaffarPlus)). However, if this work might help with homebrew emulation and other people having more fun, then much better!
Changes
=========
- Optimizations made in the CPU emulation core
- Sound is no longer emulated during skip frames
Credits
=========

View File

@ -38,7 +38,6 @@ Nes_Core::Nes_Core() : ppu( this )
mapper = NULL;
memset( &nes, 0, sizeof nes );
memset( &joypad, 0, sizeof joypad );
_doRendering = true;
}
const char * Nes_Core::init()
@ -498,8 +497,11 @@ nes_time_t Nes_Core::emulate_frame_()
}
}
nes_time_t Nes_Core::emulate_frame()
nes_time_t Nes_Core::emulate_frame(int joypad1, int joypad2)
{
current_joypad [0] = (joypad1 |= ~0xFF);
current_joypad [1] = (joypad2 |= ~0xFF);
joypad_read_count = 0;
cpu_time_offset = ppu.begin_frame( nes.timestamp ) - 1;
@ -508,10 +510,10 @@ nes_time_t Nes_Core::emulate_frame()
// TODO: clean this fucking mess up
auto t0 = emulate_frame_();
if (_doRendering == true) impl->apu.run_until_( t0 );
impl->apu.run_until_( t0 );
clock_ = cpu_time_offset;
auto t1 = cpu_time();
if (_doRendering == true) impl->apu.run_until_( t1 );
impl->apu.run_until_( t1 );
nes_time_t ppu_frame_length = ppu.frame_length();
nes_time_t length = cpu_time();

View File

@ -20,13 +20,10 @@ public:
Nes_Core();
~Nes_Core();
// Flag to enable/disable rendering
bool _doRendering;
const char * init();
const char * open( Nes_Cart const* );
void reset( bool full_reset = true, bool erase_battery_ram = false );
blip_time_t emulate_frame();
blip_time_t emulate_frame(int joypad1, int joypad2);
void close();
void save_state( Nes_State* ) const;

View File

@ -128,20 +128,15 @@ const char * Nes_Emu::emulate_skip_frame( int joypad1, int joypad2 )
{
char *old_host_pixels = host_pixels;
host_pixels = NULL;
const char *result = emulate_frame(joypad1, joypad2);
emu.emulate_frame(joypad1, joypad2);
host_pixels = old_host_pixels;
return result;
return 0;
}
const char * Nes_Emu::emulate_frame( int joypad1, int joypad2 )
{
emu.current_joypad [0] = (joypad1 |= ~0xFF);
emu.current_joypad [1] = (joypad2 |= ~0xFF);
emu.ppu.host_pixels = NULL;
if (emu._doRendering == true)
{
unsigned changed_count = sound_buf->channels_changed_count();
bool new_enabled = (frame_ != NULL);
@ -169,7 +164,7 @@ const char * Nes_Emu::emulate_frame( int joypad1, int joypad2 )
if ( sound_buf->samples_avail() )
clear_sound_buf();
nes_time_t frame_len = emu.emulate_frame();
nes_time_t frame_len = emu.emulate_frame(joypad1, joypad2);
sound_buf->end_frame( frame_len, false );
f = frame_;
@ -185,13 +180,7 @@ const char * Nes_Emu::emulate_frame( int joypad1, int joypad2 )
else
{
emu.ppu.max_palette_size = 0;
emu.emulate_frame();
}
}
else
{
emu.ppu.max_palette_size = 0;
emu.emulate_frame();
emu.emulate_frame(joypad1, joypad2);
}
return 0;

View File

@ -42,9 +42,6 @@ public:
const uint8_t* getHostPixels () const { return emu.ppu.host_pixels; }
void enableRendering() { emu._doRendering = true; }
void disableRendering() { emu._doRendering = false; }
// Basic emulation
// Emulate one video frame using joypad1 and joypad2 as input. Afterwards, image

View File

@ -171,6 +171,9 @@ class EmuInstance
return moveString;
}
void enableRendering() { _doRendering = true; }
void disableRendering() { _doRendering = false; }
void advanceState(const std::string& move)
{
if (move.find("r") != std::string::npos) _nes->reset(false);
@ -180,13 +183,17 @@ class EmuInstance
void advanceState(const inputType controller1, const inputType controller2)
{
_nes->emulate_frame(controller1, controller2);
if (_doRendering == true) _nes->emulate_frame(controller1, controller2);
if (_doRendering == false) _nes->emulate_skip_frame(controller1, controller2);
}
Nes_Emu* getInternalEmulator() const { return _nes; }
private:
// Flag to determine whether to enable/disable rendering
bool _doRendering = true;
inline size_t getStateSizeImpl() const
{
// Using dry writer to just obtain the state size

View File

@ -58,7 +58,7 @@ int main(int argc, char *argv[])
auto e = EmuInstance(romFilePath, initialStateFilePath);
// Disable rendering
e.getInternalEmulator()->disableRendering();
e.disableRendering();
// Getting initial hash
auto initialHash = e.getStateHash();