using skip frames properly (no audio)
This commit is contained in:
parent
040d7f3939
commit
57c43b6d98
|
@ -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
|
||||
=========
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -128,70 +128,59 @@ 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);
|
||||
|
||||
if ( sound_buf_changed_count != changed_count || sound_enabled != new_enabled )
|
||||
{
|
||||
unsigned changed_count = sound_buf->channels_changed_count();
|
||||
bool new_enabled = (frame_ != NULL);
|
||||
|
||||
if ( sound_buf_changed_count != changed_count || sound_enabled != new_enabled )
|
||||
{
|
||||
sound_buf_changed_count = changed_count;
|
||||
sound_enabled = new_enabled;
|
||||
enable_sound( sound_enabled );
|
||||
}
|
||||
sound_buf_changed_count = changed_count;
|
||||
sound_enabled = new_enabled;
|
||||
enable_sound( sound_enabled );
|
||||
}
|
||||
|
||||
frame_t* f = frame_;
|
||||
if ( f )
|
||||
{
|
||||
emu.ppu.max_palette_size = host_palette_size;
|
||||
emu.ppu.host_palette = f->palette + emu.ppu.palette_begin;
|
||||
// add black and white for emulator to use (unless emulator uses entire
|
||||
// palette for frame)
|
||||
f->palette [252] = 0x0F;
|
||||
f->palette [254] = 0x30;
|
||||
f->palette [255] = 0x0F;
|
||||
if ( host_pixels )
|
||||
emu.ppu.host_pixels = (uint8_t*) host_pixels +
|
||||
emu.ppu.host_row_bytes * f->top;
|
||||
frame_t* f = frame_;
|
||||
if ( f )
|
||||
{
|
||||
emu.ppu.max_palette_size = host_palette_size;
|
||||
emu.ppu.host_palette = f->palette + emu.ppu.palette_begin;
|
||||
// add black and white for emulator to use (unless emulator uses entire
|
||||
// palette for frame)
|
||||
f->palette [252] = 0x0F;
|
||||
f->palette [254] = 0x30;
|
||||
f->palette [255] = 0x0F;
|
||||
if ( host_pixels )
|
||||
emu.ppu.host_pixels = (uint8_t*) host_pixels +
|
||||
emu.ppu.host_row_bytes * f->top;
|
||||
|
||||
if ( sound_buf->samples_avail() )
|
||||
clear_sound_buf();
|
||||
if ( sound_buf->samples_avail() )
|
||||
clear_sound_buf();
|
||||
|
||||
nes_time_t frame_len = emu.emulate_frame();
|
||||
sound_buf->end_frame( frame_len, false );
|
||||
nes_time_t frame_len = emu.emulate_frame(joypad1, joypad2);
|
||||
sound_buf->end_frame( frame_len, false );
|
||||
|
||||
f = frame_;
|
||||
f->sample_count = sound_buf->samples_avail();
|
||||
f->chan_count = sound_buf->samples_per_frame();
|
||||
f->palette_begin = emu.ppu.palette_begin;
|
||||
f->palette_size = emu.ppu.palette_size;
|
||||
f->joypad_read_count = emu.joypad_read_count;
|
||||
f->burst_phase = emu.ppu.burst_phase;
|
||||
f->pitch = emu.ppu.host_row_bytes;
|
||||
f->pixels = emu.ppu.host_pixels + f->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
emu.ppu.max_palette_size = 0;
|
||||
emu.emulate_frame();
|
||||
}
|
||||
f = frame_;
|
||||
f->sample_count = sound_buf->samples_avail();
|
||||
f->chan_count = sound_buf->samples_per_frame();
|
||||
f->palette_begin = emu.ppu.palette_begin;
|
||||
f->palette_size = emu.ppu.palette_size;
|
||||
f->joypad_read_count = emu.joypad_read_count;
|
||||
f->burst_phase = emu.ppu.burst_phase;
|
||||
f->pitch = emu.ppu.host_row_bytes;
|
||||
f->pixels = emu.ppu.host_pixels + f->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
emu.ppu.max_palette_size = 0;
|
||||
emu.emulate_frame();
|
||||
emu.emulate_frame(joypad1, joypad2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -40,11 +40,8 @@ public:
|
|||
static const uint16_t image_width = 256;
|
||||
static const uint16_t image_height = 240;
|
||||
|
||||
const uint8_t* getHostPixels () const { return emu.ppu.host_pixels; }
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue