Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
|
59e563723d | ||
|
14ad539f9b | ||
|
238b9f0909 |
31 changed files with 655 additions and 256 deletions
|
@ -52,6 +52,8 @@ struct _lsnes_status
|
|||
bool rtc_valid; //RTC time valid?
|
||||
std::u32string rtc; //RTC time.
|
||||
std::vector<std::u32string> inputs; //Input display.
|
||||
bool vi_valid; //VI count valid?
|
||||
uint64_t vi_counter; //VI counter.
|
||||
std::map<std::string, std::u32string> mvars; //Memory watches.
|
||||
std::map<std::string, std::u32string> lvars; //Lua variables.
|
||||
};
|
||||
|
|
|
@ -129,6 +129,7 @@ struct emulator_instance
|
|||
status_updater* supdater;
|
||||
threads::id emu_thread;
|
||||
time_t random_seed_value;
|
||||
bool vi_prev_frame;
|
||||
dtor_list D;
|
||||
private:
|
||||
emulator_instance(const emulator_instance&);
|
||||
|
|
|
@ -45,13 +45,14 @@ std::string translate_name_mprefix(std::string original, int& binary, int save);
|
|||
extern std::string last_save;
|
||||
|
||||
/**
|
||||
* Restore the actual core state from quicksave. Only call in rewind callback.
|
||||
*
|
||||
* Parameter state: The state to restore.
|
||||
* Parameter secs: The seconds counter.
|
||||
* Parameter ssecs: The subsecond counter.
|
||||
* Quicksave state.
|
||||
*/
|
||||
void mainloop_restore_state(const std::vector<char>& state, uint64_t secs, uint64_t ssecs);
|
||||
void do_quicksave(moviefile::dynamic_state& dstate, struct movie& mov);
|
||||
/**
|
||||
* Quickload state.
|
||||
*/
|
||||
void do_quickload(moviefile::dynamic_state& dstate, struct movie& mov);
|
||||
|
||||
|
||||
std::string get_mprefix_for_project();
|
||||
void set_mprefix_for_project(const std::string& pfx);
|
||||
|
|
|
@ -25,7 +25,8 @@ enum lsnes_movie_tags
|
|||
TAG_RAMCONTENT = 0xd3ec3770,
|
||||
TAG_ROMHINT = 0x6f715830,
|
||||
TAG_BRANCH = 0xf2e60707,
|
||||
TAG_BRANCH_NAME = 0x6dcb2155
|
||||
TAG_BRANCH_NAME = 0x6dcb2155,
|
||||
TAG_VICOUNTER = 0x55758e30,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -52,6 +52,84 @@ struct moviefile
|
|||
private:
|
||||
branch_extractor* real;
|
||||
};
|
||||
/**
|
||||
* Dynamic information (savestate).
|
||||
*/
|
||||
struct dynamic_state
|
||||
{
|
||||
/**
|
||||
* Initialize dynamic state to load defaults.
|
||||
*/
|
||||
dynamic_state();
|
||||
/**
|
||||
* Clear the state.
|
||||
*/
|
||||
void clear_state(int64_t sec, int64_t ssec);
|
||||
/**
|
||||
* Swap state with another.
|
||||
*/
|
||||
void swap_with(dynamic_state& d);
|
||||
/**
|
||||
* Contents of SRAM.
|
||||
*/
|
||||
std::map<std::string, std::vector<char>> sram;
|
||||
/**
|
||||
* Core savestate (if is_savestate is true).
|
||||
*/
|
||||
std::vector<char> savestate; //Savestate to load (if is_savestate is true).
|
||||
/**
|
||||
* Host memory (if is_savestate is true).
|
||||
*/
|
||||
std::vector<char> host_memory;
|
||||
/**
|
||||
* Screenshot (if is_savestate is true).
|
||||
*/
|
||||
std::vector<char> screenshot;
|
||||
/**
|
||||
* Current frame (if is_savestate is true).
|
||||
*/
|
||||
uint64_t save_frame;
|
||||
/**
|
||||
* Number of lagged frames (if is_savestate is true).
|
||||
*/
|
||||
uint64_t lagged_frames;
|
||||
/**
|
||||
* Poll counters (if is_savestate is true).
|
||||
*/
|
||||
std::vector<uint32_t> pollcounters;
|
||||
/**
|
||||
* Poll flag.
|
||||
*/
|
||||
unsigned poll_flag;
|
||||
/**
|
||||
* Current RTC second.
|
||||
*/
|
||||
int64_t rtc_second;
|
||||
/**
|
||||
* Current RTC subsecond.
|
||||
*/
|
||||
int64_t rtc_subsecond;
|
||||
/**
|
||||
* Active macros at savestate.
|
||||
*/
|
||||
std::map<std::string, uint64_t> active_macros;
|
||||
/**
|
||||
* VI counters valid.
|
||||
*/
|
||||
bool vi_valid;
|
||||
/**
|
||||
* VI counter.
|
||||
*/
|
||||
uint64_t vi_counter;
|
||||
/**
|
||||
* VI counter for this frame.
|
||||
*/
|
||||
uint32_t vi_this_frame;
|
||||
/**
|
||||
* Movie pointer. Only used for quicksave/quickload.
|
||||
*/
|
||||
uint64_t movie_ptr;
|
||||
};
|
||||
/**
|
||||
* This constructor construct movie structure with default settings.
|
||||
*
|
||||
|
@ -157,41 +235,13 @@ struct moviefile
|
|||
*/
|
||||
bool is_savestate;
|
||||
/**
|
||||
* Contents of SRAM on time of savestate (if is_savestate is true).
|
||||
* The dynamic state.
|
||||
*/
|
||||
std::map<std::string, std::vector<char>> sram;
|
||||
/**
|
||||
* Core savestate (if is_savestate is true).
|
||||
*/
|
||||
std::vector<char> savestate; //Savestate to load (if is_savestate is true).
|
||||
dynamic_state dynamic;
|
||||
/**
|
||||
* Anchoring core savestate (if not empty).
|
||||
*/
|
||||
std::vector<char> anchor_savestate;
|
||||
/**
|
||||
* Host memory (if is_savestate is true).
|
||||
*/
|
||||
std::vector<char> host_memory;
|
||||
/**
|
||||
* Screenshot (if is_savestate is true).
|
||||
*/
|
||||
std::vector<char> screenshot;
|
||||
/**
|
||||
* Current frame (if is_savestate is true).
|
||||
*/
|
||||
uint64_t save_frame;
|
||||
/**
|
||||
* Number of lagged frames (if is_savestate is true).
|
||||
*/
|
||||
uint64_t lagged_frames;
|
||||
/**
|
||||
* Poll counters (if is_savestate is true).
|
||||
*/
|
||||
std::vector<uint32_t> pollcounters;
|
||||
/**
|
||||
* Poll flag.
|
||||
*/
|
||||
unsigned poll_flag;
|
||||
/**
|
||||
* Compressed rrdata.
|
||||
*/
|
||||
|
@ -204,14 +254,6 @@ struct moviefile
|
|||
* Branches.
|
||||
*/
|
||||
std::map<std::string, portctrl::frame_vector> branches;
|
||||
/**
|
||||
* Current RTC second.
|
||||
*/
|
||||
int64_t rtc_second;
|
||||
/**
|
||||
* Current RTC subsecond.
|
||||
*/
|
||||
int64_t rtc_subsecond;
|
||||
/**
|
||||
* Movie starting RTC second.
|
||||
*/
|
||||
|
@ -232,10 +274,6 @@ struct moviefile
|
|||
* Subtitles.
|
||||
*/
|
||||
std::map<moviefile_subtiming, std::string> subtitles;
|
||||
/**
|
||||
* Active macros at savestate.
|
||||
*/
|
||||
std::map<std::string, uint64_t> active_macros;
|
||||
/**
|
||||
* Get number of frames in movie.
|
||||
*
|
||||
|
|
|
@ -109,8 +109,9 @@ extern "C" {
|
|||
#define LSNES_CORE_CAP1_MEMWATCH 0x00010000U
|
||||
//Core supports lightguns (By setting lightgun_height/lightgun_width in LSNES_CORE_GET_AV_STATE).
|
||||
#define LSNES_CORE_CAP1_LIGHTGUN 0x00020000U
|
||||
//Core signals type extensions #1 (VFR flag). Only supported if emu_flags1 >= 3
|
||||
#define LSNES_CORE_CAP1_TYPEEXT1 0x00040000U
|
||||
//Reserved capabilities.
|
||||
#define LSNES_CORE_CAP1_RESERVED18 0x00040000U
|
||||
#define LSNES_CORE_CAP1_RESERVED19 0x00080000U
|
||||
#define LSNES_CORE_CAP1_RESERVED20 0x00100000U
|
||||
#define LSNES_CORE_CAP1_RESERVED21 0x00200000U
|
||||
|
@ -379,6 +380,9 @@ struct lsnes_core_get_type_info
|
|||
struct lsnes_core_get_type_info_romimage* images;
|
||||
//Output: List of settings. Terminated by setting with NULL iname.
|
||||
struct lsnes_core_get_type_info_param* settings;
|
||||
//Output: Nonzero if input and output framerates should be decoupled.
|
||||
//Present only if LSNES_CORE_CAP1_TYPEEXT1 is set.
|
||||
int is_vfr;
|
||||
};
|
||||
|
||||
//Request 3: Request information about region.
|
||||
|
|
|
@ -619,6 +619,7 @@ public:
|
|||
void debug_reset() { core->debug_reset(); }
|
||||
bool isnull() { return core->isnull(); }
|
||||
bool safe_to_unload(loadlib::module& mod) { return core->safe_to_unload(mod); }
|
||||
bool is_vfr() { return t_is_vfr(); }
|
||||
protected:
|
||||
/**
|
||||
* Load a ROM slot set. Changes the ROM currently loaded for core.
|
||||
|
@ -638,6 +639,10 @@ protected:
|
|||
* Returns: The controller configuration.
|
||||
*/
|
||||
virtual controller_set t_controllerconfig(std::map<std::string, std::string>& settings) = 0;
|
||||
/**
|
||||
* Is VFR (defaults to false).
|
||||
*/
|
||||
virtual bool t_is_vfr();
|
||||
private:
|
||||
core_type(const core_type&);
|
||||
core_type& operator=(const core_type&);
|
||||
|
|
|
@ -73,8 +73,7 @@ struct lua_state
|
|||
void callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw();
|
||||
void callback_quit() throw();
|
||||
void callback_keyhook(const std::string& key, keyboard::key& p) throw();
|
||||
void callback_do_unsafe_rewind(const std::vector<char>& save, uint64_t secs, uint64_t ssecs, movie& mov,
|
||||
void* u);
|
||||
void callback_do_unsafe_rewind(movie& mov, void* u);
|
||||
bool callback_do_button(uint32_t port, uint32_t controller, uint32_t index, const char* type);
|
||||
void callback_movie_lost(const char* what);
|
||||
void callback_do_latch(std::list<std::string>& args);
|
||||
|
|
|
@ -3,22 +3,16 @@
|
|||
|
||||
#include "library/lua-base.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "core/moviefile.hpp"
|
||||
|
||||
struct lua_unsaferewind
|
||||
{
|
||||
lua_unsaferewind(lua::state& L);
|
||||
static size_t overcommit() { return 0; }
|
||||
std::vector<char> state;
|
||||
uint64_t frame;
|
||||
uint64_t lag;
|
||||
uint64_t ptr;
|
||||
uint64_t secs;
|
||||
uint64_t ssecs;
|
||||
std::vector<uint32_t> pollcounters;
|
||||
std::vector<char> hostmemory;
|
||||
moviefile::dynamic_state dstate;
|
||||
std::string print()
|
||||
{
|
||||
return (stringfmt() << "to frame " << frame).str();
|
||||
return (stringfmt() << "to frame " << dstate.save_frame).str();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
12
lua.lyx
12
lua.lyx
|
@ -6264,6 +6264,18 @@ Syntax: number movie.currentframe()
|
|||
Return number of current frame.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
movie.currentvi: Get current VI number
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Syntax: number movie.currentvi()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Return number of current VI.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
movie.framecount: Get move frame count
|
||||
\end_layout
|
||||
|
|
|
@ -147,7 +147,7 @@ void status_updater::update()
|
|||
_status.speed = (unsigned)(100 * framerate.get_realized_multiplier() + 0.5);
|
||||
|
||||
if(mlogic && !runmode.is_corrupt()) {
|
||||
time_t timevalue = static_cast<time_t>(mlogic.get_mfile().rtc_second);
|
||||
time_t timevalue = static_cast<time_t>(mlogic.get_mfile().dynamic.rtc_second);
|
||||
struct tm* time_decompose = gmtime(&timevalue);
|
||||
char datebuffer[512];
|
||||
strftime(datebuffer, 511, "%Y%m%d(%a)T%H%M%S", time_decompose);
|
||||
|
@ -195,6 +195,9 @@ void status_updater::update()
|
|||
}
|
||||
_status.inputs.push_back(_buffer);
|
||||
}
|
||||
//VI counts. Only display if type is VFR.
|
||||
_status.vi_valid = mlogic.get_mfile().gametype->get_type().is_vfr();
|
||||
_status.vi_counter = mlogic.get_mfile().dynamic.vi_counter;
|
||||
//Lua variables.
|
||||
_status.lvars = lua2.get_watch_vars();
|
||||
//Memory watches.
|
||||
|
|
|
@ -122,6 +122,7 @@ emulator_instance::emulator_instance()
|
|||
settings->add_set(lsnes_setgrp);
|
||||
dispatch->set_error_streams(&messages.getstream());
|
||||
random_seed_value = 0;
|
||||
vi_prev_frame = false;
|
||||
}
|
||||
|
||||
emulator_instance::~emulator_instance()
|
||||
|
|
|
@ -97,7 +97,8 @@ portctrl::frame movie_logic::update_controls(bool subframe, bool forced) throw(s
|
|||
if(core.lua2->requests_subframe_paint)
|
||||
core.fbuf->redraw_framebuffer();
|
||||
|
||||
if(subframe) {
|
||||
//If VI did not occur last frame, do subframe anyway.
|
||||
if(subframe || !core.vi_prev_frame) {
|
||||
if(core.runmode->is_advance_subframe()) {
|
||||
//Note that platform::wait() may change value of cancel flag.
|
||||
if(!core.runmode->test_cancel()) {
|
||||
|
@ -163,6 +164,8 @@ portctrl::frame movie_logic::update_controls(bool subframe, bool forced) throw(s
|
|||
}
|
||||
core.runmode->set_point(emulator_runmode::P_START);
|
||||
core.supdater->update();
|
||||
//Clear the previous VI flag, so next poll will be subframe.
|
||||
core.vi_prev_frame = false;
|
||||
}
|
||||
platform::flush_command_queue();
|
||||
portctrl::frame tmp = core.controls->get(core.mlogic->get_movie().get_current_frame());
|
||||
|
@ -249,10 +252,10 @@ public:
|
|||
if(!*core.mlogic)
|
||||
return;
|
||||
auto& m = core.mlogic->get_mfile();
|
||||
m.rtc_subsecond += increment;
|
||||
while(m.rtc_subsecond >= per_second) {
|
||||
m.rtc_second++;
|
||||
m.rtc_subsecond -= per_second;
|
||||
m.dynamic.rtc_subsecond += increment;
|
||||
while(m.dynamic.rtc_subsecond >= per_second) {
|
||||
m.dynamic.rtc_second++;
|
||||
m.dynamic.rtc_subsecond -= per_second;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,7 +272,7 @@ public:
|
|||
time_t get_time()
|
||||
{
|
||||
auto& core = CORE();
|
||||
return *core.mlogic ? core.mlogic->get_mfile().rtc_second : 0;
|
||||
return *core.mlogic ? core.mlogic->get_mfile().dynamic.rtc_second : 0;
|
||||
}
|
||||
|
||||
time_t get_randomseed()
|
||||
|
@ -280,7 +283,14 @@ public:
|
|||
void output_frame(framebuffer::raw& screen, uint32_t fps_n, uint32_t fps_d)
|
||||
{
|
||||
auto& core = CORE();
|
||||
core.lua2->callback_do_frame_emulated();
|
||||
//VI occured.
|
||||
auto& mfile = core.mlogic->get_mfile();
|
||||
mfile.dynamic.vi_this_frame++;
|
||||
mfile.dynamic.vi_counter++;
|
||||
|
||||
//This is done elsewhere for VFR.
|
||||
if(!mfile.gametype->get_type().is_vfr())
|
||||
core.lua2->callback_do_frame_emulated();
|
||||
core.runmode->set_point(emulator_runmode::P_VIDEO);
|
||||
core.fbuf->redraw_framebuffer(screen, false, true);
|
||||
auto rate = core.rom->get_audio_rate();
|
||||
|
@ -686,7 +696,7 @@ namespace
|
|||
|
||||
//If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
|
||||
//failing.
|
||||
int handle_load()
|
||||
int _handle_load()
|
||||
{
|
||||
auto& core = CORE();
|
||||
std::string old_project = *core.mlogic ? core.mlogic->get_mfile().projectid : "";
|
||||
|
@ -695,8 +705,7 @@ jumpback:
|
|||
if(!*core.mlogic)
|
||||
return 0;
|
||||
uint64_t t = framerate_regulator::get_utime();
|
||||
std::vector<char> s;
|
||||
core.lua2->callback_do_unsafe_rewind(s, 0, 0, core.mlogic->get_movie(), unsafe_rewind_obj);
|
||||
core.lua2->callback_do_unsafe_rewind(core.mlogic->get_movie(), unsafe_rewind_obj);
|
||||
core.dispatch->mode_change(false);
|
||||
do_unsafe_rewind = false;
|
||||
core.mlogic->get_mfile().is_savestate = true;
|
||||
|
@ -772,6 +781,17 @@ nothing_to_do:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int handle_load()
|
||||
{
|
||||
auto& core = CORE();
|
||||
int r = _handle_load();
|
||||
if(r > 0) {
|
||||
//Set the vi prev frame flag, as not to mess up frame advance at first oppurtunity.
|
||||
core.vi_prev_frame = true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
//If there are pending saves, perform them.
|
||||
void handle_saves()
|
||||
{
|
||||
|
@ -787,11 +807,7 @@ nothing_to_do:
|
|||
}
|
||||
if(do_unsafe_rewind && !unsafe_rewind_obj) {
|
||||
uint64_t t = framerate_regulator::get_utime();
|
||||
std::vector<char> s = core.rom->save_core_state(true);
|
||||
uint64_t secs = core.mlogic->get_mfile().rtc_second;
|
||||
uint64_t ssecs = core.mlogic->get_mfile().rtc_subsecond;
|
||||
core.lua2->callback_do_unsafe_rewind(s, secs, ssecs, core.mlogic->get_movie(),
|
||||
NULL);
|
||||
core.lua2->callback_do_unsafe_rewind(core.mlogic->get_movie(), NULL);
|
||||
do_unsafe_rewind = false;
|
||||
messages << "Rewind point set in " << (framerate_regulator::get_utime() - t)
|
||||
<< " usec." << std::endl;
|
||||
|
@ -865,6 +881,10 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
|
|||
core.runmode->set_pause_cond(initial.start_paused);
|
||||
platform::set_paused(core.runmode->is_paused());
|
||||
stop_at_frame_active = false;
|
||||
//Always set VI last frame flag when loading any savestate or movie, as not to distrupt frame advance at
|
||||
//first oppurtunity. And since we loadstated above, VI count this frame is set apporiately.
|
||||
core.vi_prev_frame = true;
|
||||
|
||||
|
||||
core.lua2->run_startup_scripts();
|
||||
|
||||
|
@ -874,7 +894,9 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
|
|||
just_did_loadstate = first_round;
|
||||
continue;
|
||||
}
|
||||
core.framerate->ack_frame_tick(framerate_regulator::get_utime());
|
||||
//Only consider frames with VI real frames.
|
||||
if(core.vi_prev_frame)
|
||||
core.framerate->ack_frame_tick(framerate_regulator::get_utime());
|
||||
core.runmode->decay_skiplag();
|
||||
|
||||
if(!first_round) {
|
||||
|
@ -921,9 +943,20 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
|
|||
just_did_loadstate = false;
|
||||
}
|
||||
core.dbg->do_callback_frame(core.mlogic->get_movie().get_current_frame(), false);
|
||||
//VI count this frame should be 0 here.
|
||||
core.rom->emulate();
|
||||
//This is done elsewhere for non-VFR.
|
||||
if(core.mlogic->get_mfile().gametype->get_type().is_vfr())
|
||||
core.lua2->callback_do_frame_emulated();
|
||||
//Reset the vi this frame count to 0, as it is only meaningful inside emulate.
|
||||
//Also, if VIs occured, set flag informing that so frame advance can stop only on output frames.
|
||||
auto& VIs = core.mlogic->get_mfile().dynamic.vi_this_frame;
|
||||
if(VIs > 0)
|
||||
core.vi_prev_frame = true;
|
||||
VIs = 0;
|
||||
random_mix_timing_entropy();
|
||||
if(core.runmode->is_freerunning())
|
||||
//Only wait if VI, to get about proper framerate.
|
||||
if(core.runmode->is_freerunning() && core.vi_prev_frame)
|
||||
platform::wait(core.framerate->to_wait_frame(framerate_regulator::get_utime()));
|
||||
first_round = false;
|
||||
core.lua2->callback_do_frame();
|
||||
|
|
|
@ -230,23 +230,23 @@ void do_save_state(const std::string& filename, int binary) throw(std::bad_alloc
|
|||
try {
|
||||
uint64_t origtime = framerate_regulator::get_utime();
|
||||
target.is_savestate = true;
|
||||
target.sram = core.rom->save_sram();
|
||||
target.dynamic.sram = core.rom->save_sram();
|
||||
for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
|
||||
target.romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
||||
target.romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
||||
target.namehint[i] = core.rom->romimg[i].namehint;
|
||||
}
|
||||
target.savestate = core.rom->save_core_state();
|
||||
core.fbuf->get_framebuffer().save(target.screenshot);
|
||||
core.mlogic->get_movie().save_state(target.projectid, target.save_frame,
|
||||
target.lagged_frames, target.pollcounters);
|
||||
target.poll_flag = core.rom->get_pflag();
|
||||
target.dynamic.savestate = core.rom->save_core_state();
|
||||
core.fbuf->get_framebuffer().save(target.dynamic.screenshot);
|
||||
core.mlogic->get_movie().save_state(target.projectid, target.dynamic.save_frame,
|
||||
target.dynamic.lagged_frames, target.dynamic.pollcounters);
|
||||
target.dynamic.poll_flag = core.rom->get_pflag();
|
||||
auto prj = core.project->get();
|
||||
if(prj) {
|
||||
target.gamename = prj->gamename;
|
||||
target.authors = prj->authors;
|
||||
}
|
||||
target.active_macros = core.controls->get_macro_frames();
|
||||
target.dynamic.active_macros = core.controls->get_macro_frames();
|
||||
target.save(filename2, SET_savecompression(*core.settings), binary > 0,
|
||||
core.mlogic->get_rrdata());
|
||||
uint64_t took = framerate_regulator::get_utime() - origtime;
|
||||
|
@ -289,7 +289,6 @@ void do_save_movie(const std::string& filename, int binary) throw(std::bad_alloc
|
|||
target.gamename = prj->gamename;
|
||||
target.authors = prj->authors;
|
||||
}
|
||||
target.active_macros.clear();
|
||||
target.save(filename2, SET_savecompression(*core.settings), binary > 0,
|
||||
core.mlogic->get_rrdata());
|
||||
uint64_t took = framerate_regulator::get_utime() - origtime;
|
||||
|
@ -422,16 +421,17 @@ namespace
|
|||
//Load the savestate and movie state.
|
||||
//Set the core ports in order to avoid port state being reinitialized when loading.
|
||||
core.controls->set_ports(portset);
|
||||
core.rom->load_core_state(_movie.savestate);
|
||||
core.rom->set_pflag(_movie.poll_flag);
|
||||
core.controls->set_macro_frames(_movie.active_macros);
|
||||
core.rom->load_core_state(_movie.dynamic.savestate);
|
||||
core.rom->set_pflag(_movie.dynamic.poll_flag);
|
||||
core.controls->set_macro_frames(_movie.dynamic.active_macros);
|
||||
} else {
|
||||
//Reload the ROM in order to rewind to the beginning.
|
||||
core.rom->load(_movie.settings, _movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
||||
//Reset things to beginning.
|
||||
_movie.is_savestate = false;
|
||||
_movie.dynamic.clear_state(_movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
||||
//Load the SRAM and volatile RAM. Or anchor savestate if any.
|
||||
core.controls->set_ports(portset);
|
||||
_movie.rtc_second = _movie.movie_rtc_second;
|
||||
_movie.rtc_subsecond = _movie.movie_rtc_subsecond;
|
||||
if(!_movie.anchor_savestate.empty()) {
|
||||
core.rom->load_core_state(_movie.anchor_savestate);
|
||||
} else {
|
||||
|
@ -443,6 +443,16 @@ namespace
|
|||
core.controls->set_macro_frames(std::map<std::string, uint64_t>());
|
||||
}
|
||||
}
|
||||
|
||||
//Clear the data that should be cleared when movie is at beginning.
|
||||
void clear_runtime_movie_data(emulator_instance& core)
|
||||
{
|
||||
auto& mf = core.mlogic->get_mfile();
|
||||
mf.is_savestate = false;
|
||||
mf.dynamic.clear_state(mf.movie_rtc_second, mf.movie_rtc_subsecond);
|
||||
core.mlogic->get_movie().reset_state();
|
||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||
}
|
||||
}
|
||||
|
||||
void do_load_rom() throw(std::bad_alloc, std::runtime_error)
|
||||
|
@ -474,10 +484,7 @@ void do_load_rom() throw(std::bad_alloc, std::runtime_error)
|
|||
core.mlogic->get_mfile().romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
||||
core.mlogic->get_mfile().romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
||||
}
|
||||
core.mlogic->get_mfile().is_savestate = false;
|
||||
core.mlogic->get_mfile().host_memory.clear();
|
||||
core.mlogic->get_movie().reset_state();
|
||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||
clear_runtime_movie_data(core);
|
||||
core.lua2->callback_do_rewind();
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
|
@ -490,23 +497,15 @@ void do_load_rom() throw(std::bad_alloc, std::runtime_error)
|
|||
//The more complicated Read-Write case.
|
||||
//We need to create a new movie and movie file.
|
||||
temporary_handle<moviefile> _movie;
|
||||
_movie.get()->force_corrupt = false;
|
||||
_movie.get()->gametype = NULL; //Not yet known.
|
||||
_movie.get()->coreversion = core.rom->get_core_identifier();
|
||||
_movie.get()->projectid = get_random_hexstring(40);
|
||||
_movie.get()->rerecords = "0";
|
||||
_movie.get()->rerecords_mem = 0;
|
||||
for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
|
||||
_movie.get()->namehint[i] = core.rom->romimg[i].namehint;
|
||||
_movie.get()->romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
||||
_movie.get()->romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
||||
}
|
||||
_movie.get()->is_savestate = false;
|
||||
_movie.get()->save_frame = 0;
|
||||
_movie.get()->lagged_frames = 0;
|
||||
_movie.get()->poll_flag = false;
|
||||
_movie.get()->movie_rtc_second = _movie.get()->rtc_second = 1000000000ULL;
|
||||
_movie.get()->movie_rtc_subsecond = _movie.get()->rtc_subsecond = 0;
|
||||
_movie.get()->movie_rtc_second = _movie.get()->dynamic.rtc_second;
|
||||
_movie.get()->movie_rtc_subsecond = _movie.get()->dynamic.rtc_subsecond;
|
||||
_movie.get()->start_paused = false;
|
||||
_movie.get()->lazy_project_create = true;
|
||||
portctrl::type_set& portset2 = construct_movie_portset(*_movie.get(), *core.rom);
|
||||
|
@ -570,10 +569,7 @@ void do_load_rewind() throw(std::bad_alloc, std::runtime_error)
|
|||
core.dispatch->mode_change(true);
|
||||
try {
|
||||
handle_load_core(core.mlogic->get_mfile(), portset, false);
|
||||
core.mlogic->get_mfile().is_savestate = false;
|
||||
core.mlogic->get_mfile().host_memory.clear();
|
||||
core.mlogic->get_movie().reset_state();
|
||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||
clear_runtime_movie_data(core);
|
||||
core.lua2->callback_do_rewind();
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
|
@ -605,8 +601,8 @@ void do_load_state_preserve(struct moviefile& _movie)
|
|||
|
||||
newmovie.get()->load(_movie.rerecords, _movie.projectid, *_movie.input);
|
||||
if(will_load_state)
|
||||
newmovie.get()->restore_state(_movie.save_frame, _movie.lagged_frames, _movie.pollcounters, true,
|
||||
_movie.input, _movie.projectid);
|
||||
newmovie.get()->restore_state(_movie.dynamic.save_frame, _movie.dynamic.lagged_frames,
|
||||
_movie.dynamic.pollcounters, true, _movie.input, _movie.projectid);
|
||||
|
||||
//Count a rerecord.
|
||||
if(core.mlogic->get_rrdata().is_lazy() && !_movie.lazy_project_create)
|
||||
|
@ -627,19 +623,15 @@ void do_load_state_preserve(struct moviefile& _movie)
|
|||
//Set new movie.
|
||||
core.mlogic->set_movie(*(newmovie()), true);
|
||||
|
||||
//Some fields MUST be taken from movie or one gets desyncs.
|
||||
//Take dynamic state from new file (to avoid desyncs). If loading movie, it has been cleared.
|
||||
core.mlogic->get_mfile().is_savestate = _movie.is_savestate;
|
||||
core.mlogic->get_mfile().rtc_second = _movie.rtc_second;
|
||||
core.mlogic->get_mfile().rtc_subsecond = _movie.rtc_subsecond;
|
||||
std::swap(core.mlogic->get_mfile().host_memory, _movie.host_memory);
|
||||
if(!will_load_state)
|
||||
core.mlogic->get_mfile().host_memory.clear();
|
||||
core.mlogic->get_mfile().dynamic.swap_with(_movie.dynamic);
|
||||
|
||||
try {
|
||||
//Paint the screen.
|
||||
framebuffer::raw tmp;
|
||||
if(will_load_state) {
|
||||
tmp.load(_movie.screenshot);
|
||||
tmp.load(_movie.dynamic.screenshot);
|
||||
core.fbuf->redraw_framebuffer(tmp);
|
||||
} else
|
||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||
|
@ -691,8 +683,8 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
|||
newmovie.get()->load(_movie.rerecords, _movie.projectid, *_movie.input);
|
||||
newmovie.get()->set_pflag_handler(&lsnes_pflag_handler);
|
||||
if(will_load_state)
|
||||
newmovie.get()->restore_state(_movie.save_frame, _movie.lagged_frames, _movie.pollcounters, true,
|
||||
NULL, _movie.projectid);
|
||||
newmovie.get()->restore_state(_movie.dynamic.save_frame, _movie.dynamic.lagged_frames,
|
||||
_movie.dynamic.pollcounters, true, NULL, _movie.projectid);
|
||||
|
||||
//Copy the other branches.
|
||||
if(lmode != LOAD_STATE_INITIAL && core.mlogic->get_mfile().projectid == _movie.projectid) {
|
||||
|
@ -752,12 +744,6 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
|||
throw;
|
||||
}
|
||||
|
||||
//If loaded a movie, clear the is savestate and rrdata.
|
||||
if(!will_load_state) {
|
||||
_movie.is_savestate = false;
|
||||
_movie.host_memory.clear();
|
||||
}
|
||||
|
||||
core.lua2->callback_movie_lost("load");
|
||||
|
||||
//Copy the data.
|
||||
|
@ -766,6 +752,15 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
|||
core.mlogic->set_mfile(_movie, true);
|
||||
used = true;
|
||||
|
||||
//Set up VI counter if none is available.
|
||||
if(!_movie.dynamic.vi_valid) {
|
||||
//If no VI counter available, set it to frame-1 and there have been 0 this frame.
|
||||
uint64_t f = core.mlogic->get_movie().get_current_frame();
|
||||
_movie.dynamic.vi_counter = (f > 0) ? (f - 1) : 0;
|
||||
_movie.dynamic.vi_this_frame = 0;
|
||||
_movie.dynamic.vi_valid = true;
|
||||
}
|
||||
|
||||
set_mprefix(get_mprefix_for_project(core.mlogic->get_mfile().projectid));
|
||||
|
||||
//Activate RW mode if needed.
|
||||
|
@ -783,7 +778,7 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
|||
{
|
||||
framebuffer::raw tmp;
|
||||
if(will_load_state) {
|
||||
tmp.load(_movie.screenshot);
|
||||
tmp.load(_movie.dynamic.screenshot);
|
||||
core.fbuf->redraw_framebuffer(tmp);
|
||||
} else
|
||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||
|
@ -879,18 +874,30 @@ bool do_load_state(const std::string& filename, int lmode)
|
|||
return true;
|
||||
}
|
||||
|
||||
void mainloop_restore_state(const std::vector<char>& state, uint64_t secs, uint64_t ssecs)
|
||||
void do_quicksave(moviefile::dynamic_state& dstate, struct movie& mov)
|
||||
{
|
||||
auto& core = CORE();
|
||||
//Force unlazy rrdata.
|
||||
core.mlogic->get_rrdata().read_base(rrdata::filename(core.mlogic->get_mfile().projectid),
|
||||
false);
|
||||
core.mlogic->get_rrdata().add((*core.nrrdata)());
|
||||
core.mlogic->get_mfile().rtc_second = secs;
|
||||
core.mlogic->get_mfile().rtc_subsecond = ssecs;
|
||||
core.rom->load_core_state(state, true);
|
||||
auto& mf = core.mlogic->get_mfile();
|
||||
dstate = mf.dynamic;
|
||||
dstate.savestate = core.rom->save_core_state(true);
|
||||
mov.fast_save(dstate.save_frame, dstate.movie_ptr, dstate.lagged_frames, dstate.pollcounters);
|
||||
}
|
||||
|
||||
void do_quickload(moviefile::dynamic_state& dstate, struct movie& mov)
|
||||
{
|
||||
auto& core = CORE();
|
||||
auto& mf = core.mlogic->get_mfile();
|
||||
|
||||
//Force unlazy rrdata.
|
||||
core.mlogic->get_rrdata().read_base(rrdata::filename(core.mlogic->get_mfile().projectid), false);
|
||||
core.mlogic->get_rrdata().add((*core.nrrdata)());
|
||||
|
||||
core.rom->load_core_state(dstate.savestate, true);
|
||||
mov.fast_load(dstate.save_frame, dstate.movie_ptr, dstate.lagged_frames, dstate.pollcounters);
|
||||
mf.dynamic = dstate;
|
||||
}
|
||||
|
||||
|
||||
rrdata::rrdata()
|
||||
: init(false)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
void moviefile::brief_info::binary_io(int _stream)
|
||||
{
|
||||
bool vi_override = false;
|
||||
|
||||
binarystream::input in(_stream);
|
||||
sysregion = in.string();
|
||||
//Discard the settings.
|
||||
|
@ -32,8 +34,14 @@ void moviefile::brief_info::binary_io(int _stream)
|
|||
this->corename = s.string_implicit();
|
||||
}},{TAG_PROJECT_ID, [this](binarystream::input& s) {
|
||||
this->projectid = s.string_implicit();
|
||||
}},{TAG_SAVESTATE, [this](binarystream::input& s) {
|
||||
}},{TAG_SAVESTATE, [this, &vi_override](binarystream::input& s) {
|
||||
//TAG_VICOUNTER overrides this.
|
||||
if(!vi_override)
|
||||
this->current_frame = s.number();
|
||||
}},{TAG_VICOUNTER, [this, &vi_override](binarystream::input& s) {
|
||||
//TAG_VICOUNTER overrides TAG_SAVESTATE.
|
||||
this->current_frame = s.number();
|
||||
vi_override = true;
|
||||
}},{TAG_RRDATA, [this](binarystream::input& s) {
|
||||
std::vector<char> c_rrdata;
|
||||
s.blob_implicit(c_rrdata);
|
||||
|
@ -118,28 +126,29 @@ void moviefile::binary_io(int _stream, rrdata_set& rrd) throw(std::bad_alloc, st
|
|||
});
|
||||
if(is_savestate) {
|
||||
out.extension(TAG_SAVESTATE, [this](binarystream::output& s) {
|
||||
s.number(this->save_frame);
|
||||
s.number(this->lagged_frames);
|
||||
s.number(this->rtc_second);
|
||||
s.number(this->rtc_subsecond);
|
||||
s.number(this->pollcounters.size());
|
||||
for(auto i : this->pollcounters)
|
||||
s.number(this->dynamic.save_frame);
|
||||
s.number(this->dynamic.lagged_frames);
|
||||
s.number(this->dynamic.rtc_second);
|
||||
s.number(this->dynamic.rtc_subsecond);
|
||||
s.number(this->dynamic.pollcounters.size());
|
||||
for(auto i : this->dynamic.pollcounters)
|
||||
s.number32(i);
|
||||
s.byte(this->poll_flag ? 0x01 : 0x00);
|
||||
s.blob_implicit(this->savestate);
|
||||
}, true, out.numberbytes(save_frame) + out.numberbytes(lagged_frames) + out.numberbytes(rtc_second) +
|
||||
out.numberbytes(rtc_subsecond) + out.numberbytes(pollcounters.size()) +
|
||||
4 * pollcounters.size() + 1 + savestate.size());
|
||||
s.byte(this->dynamic.poll_flag ? 0x01 : 0x00);
|
||||
s.blob_implicit(this->dynamic.savestate);
|
||||
}, true, out.numberbytes(dynamic.save_frame) + out.numberbytes(dynamic.lagged_frames) +
|
||||
out.numberbytes(dynamic.rtc_second) + out.numberbytes(dynamic.rtc_subsecond) +
|
||||
out.numberbytes(dynamic.pollcounters.size()) +
|
||||
4 * dynamic.pollcounters.size() + 1 + dynamic.savestate.size());
|
||||
|
||||
out.extension(TAG_HOSTMEMORY, [this](binarystream::output& s) {
|
||||
s.blob_implicit(this->host_memory);
|
||||
s.blob_implicit(this->dynamic.host_memory);
|
||||
});
|
||||
|
||||
out.extension(TAG_SCREENSHOT, [this](binarystream::output& s) {
|
||||
s.blob_implicit(this->screenshot);
|
||||
}, true, screenshot.size());
|
||||
s.blob_implicit(this->dynamic.screenshot);
|
||||
}, true, dynamic.screenshot.size());
|
||||
|
||||
for(auto i : sram) {
|
||||
for(auto i : dynamic.sram) {
|
||||
out.extension(TAG_SAVE_SRAM, [&i](binarystream::output& s) {
|
||||
s.string(i.first);
|
||||
s.blob_implicit(i.second);
|
||||
|
@ -164,7 +173,7 @@ void moviefile::binary_io(int _stream, rrdata_set& rrd) throw(std::bad_alloc, st
|
|||
s.string_implicit(i.second);
|
||||
});
|
||||
|
||||
for(auto i : active_macros)
|
||||
for(auto i : dynamic.active_macros)
|
||||
out.extension(TAG_MACRO, [&i](binarystream::output& s) {
|
||||
s.number(i.second);
|
||||
s.string_implicit(i.first);
|
||||
|
@ -177,6 +186,11 @@ void moviefile::binary_io(int _stream, rrdata_set& rrd) throw(std::bad_alloc, st
|
|||
});
|
||||
}
|
||||
|
||||
out.extension(TAG_VICOUNTER, [this](binarystream::output& s) {
|
||||
s.number(dynamic.vi_counter);
|
||||
s.number(dynamic.vi_this_frame);
|
||||
});
|
||||
|
||||
int64_t next_bnum = 0;
|
||||
std::map<std::string, uint64_t> branch_table;
|
||||
for(auto& i : branches) {
|
||||
|
@ -212,6 +226,7 @@ void moviefile::binary_io(int _stream, core_type& romtype) throw(std::bad_alloc,
|
|||
auto ctrldata = gametype->get_type().controllerconfig(settings);
|
||||
portctrl::type_set& ports = portctrl::type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||
input = NULL;
|
||||
dynamic.vi_valid = false;
|
||||
|
||||
in.extension({
|
||||
{TAG_ANCHOR_SAVE, [this](binarystream::input& s) {
|
||||
|
@ -225,10 +240,10 @@ void moviefile::binary_io(int _stream, core_type& romtype) throw(std::bad_alloc,
|
|||
}},{TAG_GAMENAME, [this](binarystream::input& s) {
|
||||
this->gamename = s.string_implicit();
|
||||
}},{TAG_HOSTMEMORY, [this](binarystream::input& s) {
|
||||
s.blob_implicit(this->host_memory);
|
||||
s.blob_implicit(this->dynamic.host_memory);
|
||||
}},{TAG_MACRO, [this](binarystream::input& s) {
|
||||
uint64_t n = s.number();
|
||||
this->active_macros[s.string_implicit()] = n;
|
||||
this->dynamic.active_macros[s.string_implicit()] = n;
|
||||
}},{TAG_BRANCH_NAME, [this, &branch_table, &next_bnum, &next_branch](binarystream::input& s) {
|
||||
branch_table[next_bnum++] = next_branch = s.string_implicit();
|
||||
}},{TAG_MOVIE, [this, &ports, &next_branch](binarystream::input& s) {
|
||||
|
@ -269,25 +284,29 @@ void moviefile::binary_io(int _stream, core_type& romtype) throw(std::bad_alloc,
|
|||
this->rerecords = (stringfmt() << rrdata_set::count(c_rrdata)).str();
|
||||
}},{TAG_SAVE_SRAM, [this](binarystream::input& s) {
|
||||
std::string a = s.string();
|
||||
s.blob_implicit(this->sram[a]);
|
||||
s.blob_implicit(this->dynamic.sram[a]);
|
||||
}},{TAG_SAVESTATE, [this](binarystream::input& s) {
|
||||
this->is_savestate = true;
|
||||
this->save_frame = s.number();
|
||||
this->lagged_frames = s.number();
|
||||
this->rtc_second = s.number();
|
||||
this->rtc_subsecond = s.number();
|
||||
this->pollcounters.resize(s.number());
|
||||
for(auto& i : this->pollcounters)
|
||||
this->dynamic.save_frame = s.number();
|
||||
this->dynamic.lagged_frames = s.number();
|
||||
this->dynamic.rtc_second = s.number();
|
||||
this->dynamic.rtc_subsecond = s.number();
|
||||
this->dynamic.pollcounters.resize(s.number());
|
||||
for(auto& i : this->dynamic.pollcounters)
|
||||
i = s.number32();
|
||||
this->poll_flag = (s.byte() != 0);
|
||||
s.blob_implicit(this->savestate);
|
||||
this->dynamic.poll_flag = (s.byte() != 0);
|
||||
s.blob_implicit(this->dynamic.savestate);
|
||||
}},{TAG_SCREENSHOT, [this](binarystream::input& s) {
|
||||
s.blob_implicit(this->screenshot);
|
||||
s.blob_implicit(this->dynamic.screenshot);
|
||||
}},{TAG_SUBTITLE, [this](binarystream::input& s) {
|
||||
uint64_t f = s.number();
|
||||
uint64_t l = s.number();
|
||||
std::string x = s.string_implicit();
|
||||
this->subtitles[moviefile_subtiming(f, l)] = x;
|
||||
}},{TAG_VICOUNTER, [this](binarystream::input& s) {
|
||||
dynamic.vi_counter = s.number();
|
||||
dynamic.vi_this_frame = s.number();
|
||||
dynamic.vi_valid = true;
|
||||
}}
|
||||
}, binarystream::null_default);
|
||||
|
||||
|
|
|
@ -200,9 +200,12 @@ void moviefile::brief_info::load(zip::reader& r)
|
|||
r.read_linefile("gametype", sysregion);
|
||||
r.read_linefile("coreversion", corename);
|
||||
r.read_linefile("projectid", projectid);
|
||||
if(r.has_member("savestate"))
|
||||
r.read_numeric_file("saveframe", current_frame);
|
||||
else
|
||||
if(r.has_member("savestate")) {
|
||||
if(r.has_member("vicount"))
|
||||
r.read_numeric_file("vicount", current_frame);
|
||||
else
|
||||
r.read_numeric_file("saveframe", current_frame);
|
||||
} else
|
||||
current_frame = 0;
|
||||
r.read_numeric_file("rerecords", rerecords);
|
||||
r.read_linefile("rom.sha256", hash[0], true);
|
||||
|
@ -242,6 +245,10 @@ void moviefile::load(zip::reader& r, core_type& romtype) throw(std::bad_alloc, s
|
|||
auto ctrldata = gametype->get_type().controllerconfig(settings);
|
||||
portctrl::type_set& ports = portctrl::type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||
|
||||
dynamic.vi_valid = true;
|
||||
dynamic.vi_counter = 0;
|
||||
dynamic.vi_this_frame = 0;
|
||||
|
||||
branches.clear();
|
||||
r.read_linefile("gamename", gamename, true);
|
||||
r.read_linefile("projectid", projectid);
|
||||
|
@ -266,34 +273,42 @@ void moviefile::load(zip::reader& r, core_type& romtype) throw(std::bad_alloc, s
|
|||
movie_rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||
r.read_numeric_file("starttime.second", movie_rtc_second, true);
|
||||
r.read_numeric_file("starttime.subsecond", movie_rtc_subsecond, true);
|
||||
rtc_second = movie_rtc_second;
|
||||
rtc_subsecond = movie_rtc_subsecond;
|
||||
dynamic.rtc_second = movie_rtc_second;
|
||||
dynamic.rtc_subsecond = movie_rtc_subsecond;
|
||||
if(r.has_member("savestate.anchor"))
|
||||
r.read_raw_file("savestate.anchor", anchor_savestate);
|
||||
if(r.has_member("savestate")) {
|
||||
dynamic.vi_valid = false;
|
||||
if(r.has_member("vicounter")) {
|
||||
r.read_numeric_file("vicounter", dynamic.vi_counter);
|
||||
r.read_numeric_file("vithisframe", dynamic.vi_this_frame);
|
||||
dynamic.vi_valid = true;
|
||||
}
|
||||
is_savestate = true;
|
||||
r.read_numeric_file("saveframe", save_frame, true);
|
||||
r.read_numeric_file("lagcounter", lagged_frames, true);
|
||||
read_pollcounters(r, "pollcounters", pollcounters);
|
||||
r.read_numeric_file("saveframe", dynamic.save_frame, true);
|
||||
r.read_numeric_file("lagcounter", dynamic.lagged_frames, true);
|
||||
read_pollcounters(r, "pollcounters", dynamic.pollcounters);
|
||||
if(r.has_member("hostmemory"))
|
||||
r.read_raw_file("hostmemory", host_memory);
|
||||
r.read_raw_file("savestate", savestate);
|
||||
r.read_raw_file("hostmemory", dynamic.host_memory);
|
||||
else
|
||||
dynamic.host_memory.clear();
|
||||
r.read_raw_file("savestate", dynamic.savestate);
|
||||
for(auto name : r)
|
||||
if(name.length() >= 5 && name.substr(0, 5) == "sram.")
|
||||
r.read_raw_file(name, sram[name.substr(5)]);
|
||||
r.read_raw_file("screenshot", screenshot);
|
||||
r.read_raw_file(name, dynamic.sram[name.substr(5)]);
|
||||
r.read_raw_file("screenshot", dynamic.screenshot);
|
||||
//If these can't be read, just use some (wrong) values.
|
||||
r.read_numeric_file("savetime.second", rtc_second, true);
|
||||
r.read_numeric_file("savetime.subsecond", rtc_subsecond, true);
|
||||
r.read_numeric_file("savetime.second", dynamic.rtc_second, true);
|
||||
r.read_numeric_file("savetime.subsecond", dynamic.rtc_subsecond, true);
|
||||
uint64_t _poll_flag = 2; //Legacy behaviour is the default.
|
||||
r.read_numeric_file("pollflag", _poll_flag, true);
|
||||
poll_flag = _poll_flag;
|
||||
active_macros = read_active_macros(r, "macros");
|
||||
dynamic.poll_flag = _poll_flag;
|
||||
dynamic.active_macros = read_active_macros(r, "macros");
|
||||
}
|
||||
for(auto name : r)
|
||||
if(name.length() >= 8 && name.substr(0, 8) == "initram.")
|
||||
r.read_raw_file(name, ramcontent[name.substr(8)]);
|
||||
if(rtc_subsecond < 0 || movie_rtc_subsecond < 0)
|
||||
if(dynamic.rtc_subsecond < 0 || movie_rtc_subsecond < 0)
|
||||
throw std::runtime_error("Invalid RTC subsecond value");
|
||||
std::string name = r.find_first();
|
||||
for(auto name : r)
|
||||
|
|
|
@ -173,20 +173,22 @@ void moviefile::save(zip::writer& w, rrdata_set& rrd) throw(std::bad_alloc, std:
|
|||
w.write_numeric_file("starttime.second", movie_rtc_second);
|
||||
w.write_numeric_file("starttime.subsecond", movie_rtc_subsecond);
|
||||
if(!anchor_savestate.empty())
|
||||
w.write_raw_file("savestate.anchor", anchor_savestate);
|
||||
w.write_raw_file("savestate.anchor", anchor_savestate);
|
||||
if(is_savestate) {
|
||||
w.write_numeric_file("saveframe", save_frame);
|
||||
w.write_numeric_file("lagcounter", lagged_frames);
|
||||
write_pollcounters(w, "pollcounters", pollcounters);
|
||||
w.write_raw_file("hostmemory", host_memory);
|
||||
w.write_raw_file("savestate", savestate);
|
||||
w.write_raw_file("screenshot", screenshot);
|
||||
for(auto i : sram)
|
||||
w.write_numeric_file("vicounter", dynamic.vi_counter);
|
||||
w.write_numeric_file("vithisframe", dynamic.vi_this_frame);
|
||||
w.write_numeric_file("saveframe", dynamic.save_frame);
|
||||
w.write_numeric_file("lagcounter", dynamic.lagged_frames);
|
||||
write_pollcounters(w, "pollcounters", dynamic.pollcounters);
|
||||
w.write_raw_file("hostmemory", dynamic.host_memory);
|
||||
w.write_raw_file("savestate", dynamic.savestate);
|
||||
w.write_raw_file("screenshot", dynamic.screenshot);
|
||||
for(auto i : dynamic.sram)
|
||||
w.write_raw_file("sram." + i.first, i.second);
|
||||
w.write_numeric_file("savetime.second", rtc_second);
|
||||
w.write_numeric_file("savetime.subsecond", rtc_subsecond);
|
||||
w.write_numeric_file("pollflag", poll_flag);
|
||||
write_active_macros(w, "macros", active_macros);
|
||||
w.write_numeric_file("savetime.second", dynamic.rtc_second);
|
||||
w.write_numeric_file("savetime.subsecond", dynamic.rtc_subsecond);
|
||||
w.write_numeric_file("pollflag", dynamic.poll_flag);
|
||||
write_active_macros(w, "macros", dynamic.active_macros);
|
||||
}
|
||||
for(auto i : ramcontent)
|
||||
w.write_raw_file("initram." + i.first, i.second);
|
||||
|
|
|
@ -75,7 +75,7 @@ moviefile::brief_info::brief_info(const std::string& filename)
|
|||
sysregion = mv.gametype->get_name();
|
||||
corename = mv.coreversion;
|
||||
projectid = mv.projectid;
|
||||
current_frame = mv.is_savestate ? mv.save_frame : 0;
|
||||
current_frame = mv.is_savestate ? mv.dynamic.save_frame : 0;
|
||||
rerecords = mv.rerecords_mem;
|
||||
for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
|
||||
hash[i] = mv.romimg_sha256[i];
|
||||
|
@ -101,6 +101,55 @@ moviefile::brief_info::brief_info(const std::string& filename)
|
|||
load(r);
|
||||
}
|
||||
|
||||
moviefile::dynamic_state::dynamic_state()
|
||||
{
|
||||
save_frame = 0;
|
||||
lagged_frames = 0;
|
||||
rtc_second = DEFAULT_RTC_SECOND;
|
||||
rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||
poll_flag = 0;
|
||||
vi_valid = true;
|
||||
vi_counter = 0;
|
||||
vi_this_frame = 0;
|
||||
}
|
||||
|
||||
void moviefile::dynamic_state::clear_state(int64_t sec, int64_t ssec)
|
||||
{
|
||||
sram.clear();
|
||||
savestate.clear();
|
||||
host_memory.clear();
|
||||
screenshot.clear();
|
||||
save_frame = 0;
|
||||
lagged_frames = 0;
|
||||
for(auto& i : pollcounters)
|
||||
i = 0;
|
||||
poll_flag = 0;
|
||||
rtc_second = sec;
|
||||
rtc_subsecond = ssec;
|
||||
active_macros.clear();
|
||||
vi_valid = true;
|
||||
vi_counter = 0;
|
||||
vi_this_frame = 0;
|
||||
}
|
||||
|
||||
void moviefile::dynamic_state::swap_with(dynamic_state& d)
|
||||
{
|
||||
std::swap(sram, d.sram);
|
||||
std::swap(savestate, d.savestate);
|
||||
std::swap(host_memory, d.host_memory);
|
||||
std::swap(screenshot, d.screenshot);
|
||||
std::swap(save_frame, d.save_frame);
|
||||
std::swap(lagged_frames, d.lagged_frames);
|
||||
std::swap(pollcounters, d.pollcounters);
|
||||
std::swap(poll_flag, d.poll_flag);
|
||||
std::swap(rtc_second, d.rtc_second);
|
||||
std::swap(rtc_subsecond, d.rtc_subsecond);
|
||||
std::swap(active_macros, d.active_macros);
|
||||
std::swap(vi_valid, d.vi_valid);
|
||||
std::swap(vi_counter, d.vi_counter);
|
||||
std::swap(vi_this_frame, d.vi_this_frame);
|
||||
}
|
||||
|
||||
moviefile::moviefile() throw(std::bad_alloc)
|
||||
{
|
||||
force_corrupt = false;
|
||||
|
@ -109,12 +158,12 @@ moviefile::moviefile() throw(std::bad_alloc)
|
|||
coreversion = "";
|
||||
projectid = "";
|
||||
rerecords = "0";
|
||||
rerecords_mem = 0;
|
||||
is_savestate = false;
|
||||
movie_rtc_second = rtc_second = DEFAULT_RTC_SECOND;
|
||||
movie_rtc_subsecond = rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||
movie_rtc_second = DEFAULT_RTC_SECOND;
|
||||
movie_rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||
start_paused = false;
|
||||
lazy_project_create = true;
|
||||
poll_flag = 0;
|
||||
}
|
||||
|
||||
moviefile::moviefile(loaded_rom& rom, std::map<std::string, std::string>& c_settings, uint64_t rtc_sec,
|
||||
|
@ -125,12 +174,12 @@ moviefile::moviefile(loaded_rom& rom, std::map<std::string, std::string>& c_sett
|
|||
coreversion = rom.get_core_identifier();
|
||||
projectid = get_random_hexstring(40);
|
||||
rerecords = "0";
|
||||
rerecords_mem = 0;
|
||||
is_savestate = false;
|
||||
movie_rtc_second = rtc_second = rtc_sec;
|
||||
movie_rtc_subsecond = rtc_subsecond = rtc_subsec;
|
||||
movie_rtc_second = dynamic.rtc_second = rtc_sec;
|
||||
movie_rtc_subsecond = dynamic.rtc_subsecond = rtc_subsec;
|
||||
start_paused = false;
|
||||
lazy_project_create = true;
|
||||
poll_flag = 0;
|
||||
settings = c_settings;
|
||||
input = NULL;
|
||||
auto ctrldata = rom.controllerconfig(settings);
|
||||
|
@ -158,7 +207,6 @@ moviefile::moviefile(const std::string& movie, core_type& romtype) throw(std::ba
|
|||
return;
|
||||
}
|
||||
input = NULL;
|
||||
poll_flag = false;
|
||||
start_paused = false;
|
||||
force_corrupt = false;
|
||||
is_savestate = false;
|
||||
|
@ -303,15 +351,8 @@ void moviefile::copy_fields(const moviefile& mv)
|
|||
movie_sram = mv.movie_sram;
|
||||
ramcontent = mv.ramcontent;
|
||||
is_savestate = mv.is_savestate;
|
||||
sram = mv.sram;
|
||||
savestate = mv.savestate;
|
||||
dynamic = mv.dynamic;
|
||||
anchor_savestate = mv.anchor_savestate;
|
||||
host_memory = mv.host_memory;
|
||||
screenshot = mv.screenshot;
|
||||
save_frame = mv.save_frame;
|
||||
lagged_frames = mv.lagged_frames;
|
||||
pollcounters = mv.pollcounters;
|
||||
poll_flag = mv.poll_flag;
|
||||
c_rrdata = mv.c_rrdata;
|
||||
branches = mv.branches;
|
||||
|
||||
|
@ -321,14 +362,11 @@ void moviefile::copy_fields(const moviefile& mv)
|
|||
if(mv.branches.count(i.first) && &mv.branches.find(i.first)->second == mv.input)
|
||||
input = &i.second;
|
||||
|
||||
rtc_second = mv.rtc_second;
|
||||
rtc_subsecond = mv.rtc_subsecond;
|
||||
movie_rtc_second = mv.movie_rtc_second;
|
||||
movie_rtc_subsecond = mv.movie_rtc_subsecond;
|
||||
start_paused = mv.start_paused;
|
||||
lazy_project_create = mv.lazy_project_create;
|
||||
subtitles = mv.subtitles;
|
||||
active_macros = mv.active_macros;
|
||||
}
|
||||
|
||||
void moviefile::fork_branch(const std::string& oldname, const std::string& newname)
|
||||
|
|
|
@ -151,8 +151,7 @@ namespace
|
|||
m.start_paused = true;
|
||||
m.movie_rtc_second = p.movie_rtc_second;
|
||||
m.movie_rtc_subsecond = p.movie_rtc_subsecond;
|
||||
m.save_frame = 0;
|
||||
m.lagged_frames = 0;
|
||||
m.dynamic = moviefile::dynamic_state();
|
||||
m.anchor_savestate = p.anchor_savestate;
|
||||
m.movie_sram = p.movie_sram;
|
||||
m.authors = p.authors;
|
||||
|
|
|
@ -234,7 +234,6 @@ void UI_save_movie(emulator_instance& inst, std::ostringstream& stream)
|
|||
inst.mlogic->get_mfile().gamename = prj->gamename;
|
||||
inst.mlogic->get_mfile().authors = prj->authors;
|
||||
}
|
||||
inst.mlogic->get_mfile().active_macros.clear();
|
||||
inst.mlogic->get_mfile().save(stream, inst.mlogic->get_rrdata());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
OBJECTS=test.$(OBJECT_SUFFIX)
|
||||
OBJECTS=test.$(OBJECT_SUFFIX) test2.$(OBJECT_SUFFIX)
|
||||
|
||||
.PRECIOUS: %.$(OBJECT_SUFFIX) %.files
|
||||
|
||||
|
|
212
src/emulation/test/test2.cpp
Normal file
212
src/emulation/test/test2.cpp
Normal file
|
@ -0,0 +1,212 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2012-2013 by Ilari Liusvaara *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "lsnes.hpp"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "core/audioapi.hpp"
|
||||
#include "core/misc.hpp"
|
||||
#include "core/command.hpp"
|
||||
#include "core/controllerframe.hpp"
|
||||
#include "core/dispatch.hpp"
|
||||
#include "core/framebuffer.hpp"
|
||||
#include "core/instance.hpp"
|
||||
#include "core/messages.hpp"
|
||||
#include "interface/callbacks.hpp"
|
||||
#include "interface/cover.hpp"
|
||||
#include "interface/romtype.hpp"
|
||||
#include "library/framebuffer-pixfmt-rgb32.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/portctrl-data.hpp"
|
||||
#include "library/serialization.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
#include "library/framebuffer.hpp"
|
||||
#include "library/hex.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
uint32_t cover_fbmem[480 * 432];
|
||||
bool pflag = false;
|
||||
|
||||
//Framebuffer.
|
||||
struct framebuffer::info cover_fbinfo = {
|
||||
&framebuffer::pixfmt_rgb32, //Format.
|
||||
(char*)cover_fbmem, //Memory.
|
||||
480, 432, 1920, //Physical size.
|
||||
480, 432, 1920, //Logical size.
|
||||
0, 0 //Offset.
|
||||
};
|
||||
|
||||
struct interface_device_reg test_registers[] = {
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
#include "ports.inc"
|
||||
|
||||
controller_set test_controllerconfig(std::map<std::string, std::string>& settings)
|
||||
{
|
||||
std::map<std::string, std::string> _settings = settings;
|
||||
controller_set r;
|
||||
r.ports.push_back(&psystem);
|
||||
r.ports.push_back(&ptype1);
|
||||
r.ports.push_back(&ptype2);
|
||||
r.logical_map.push_back(std::make_pair(1, 0));
|
||||
r.logical_map.push_back(std::make_pair(2, 0));
|
||||
return r;
|
||||
}
|
||||
|
||||
void redraw_cover_fbinfo()
|
||||
{
|
||||
for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
|
||||
cover_fbmem[i] = 0x00000000;
|
||||
cover_render_string(cover_fbmem, 0, 0, "TEST MODE", 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
|
||||
}
|
||||
|
||||
void redraw_screen()
|
||||
{
|
||||
for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
|
||||
cover_fbmem[i] = 0x00000000;
|
||||
{
|
||||
std::ostringstream str;
|
||||
unsigned k = 0;
|
||||
for(unsigned i = 0; i < 6; i++)
|
||||
str << ecore_callbacks->get_input(1, 0, i) << " ";
|
||||
for(unsigned i = 0; i < 15; i++)
|
||||
if(ecore_callbacks->get_input(1, 0, i + 6)) k |= (1 << i);
|
||||
str << hex::to16(k);
|
||||
cover_render_string(cover_fbmem, 0, 0, str.str(), 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
|
||||
}
|
||||
{
|
||||
std::ostringstream str;
|
||||
unsigned k = 0;
|
||||
for(unsigned i = 0; i < 6; i++)
|
||||
str << ecore_callbacks->get_input(2, 0, i) << " ";
|
||||
for(unsigned i = 0; i < 15; i++)
|
||||
if(ecore_callbacks->get_input(2, 0, i + 6)) k |= (1 << i);
|
||||
str << hex::to16(k);
|
||||
cover_render_string(cover_fbmem, 0, 16, str.str(), 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
|
||||
}
|
||||
}
|
||||
|
||||
struct _test_core2 : public core_core, public core_type, public core_region, public core_sysregion
|
||||
{
|
||||
_test_core2()
|
||||
: core_core({&psystem, &ptype1, &ptype2}, {
|
||||
{0, "xyzzy", "xyzzy", {
|
||||
{"Magic", "enum:[\"foo\",\"bar\",\"baz\",[\"qux\",\"zot\"]]"}
|
||||
}}
|
||||
}),
|
||||
core_type({{
|
||||
.iname = "test2",
|
||||
.hname = "test2",
|
||||
.id = 0,
|
||||
.sysname = "Test2",
|
||||
.bios = NULL,
|
||||
.regions = {this},
|
||||
.images = {{"rom", "Cartridge ROM", 1, 0, 0, "test2"}},
|
||||
.settings = {},
|
||||
.core = this,
|
||||
}}),
|
||||
core_region({{"world", "World", 0, 0, false, {1, 1000}, {0}}}),
|
||||
core_sysregion("test2", *this, *this) { hide(); }
|
||||
|
||||
std::string c_core_identifier() { return "TEST2"; }
|
||||
bool c_set_region(core_region& region) { return (®ion == this); }
|
||||
std::pair<uint32_t, uint32_t> c_video_rate() { return std::make_pair(60, 1); }
|
||||
double c_get_PAR() { return 1.0; }
|
||||
std::pair<uint32_t, uint32_t> c_audio_rate() { return std::make_pair(48000, 1); }
|
||||
std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
|
||||
std::map<std::string, std::vector<char>> s;
|
||||
return s;
|
||||
}
|
||||
void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {}
|
||||
void c_serialize(std::vector<char>& out) { out.resize(1); out[0] = fmod; }
|
||||
void c_unserialize(const char* in, size_t insize) { fmod = in[0]; }
|
||||
core_region& c_get_region() { return *this; }
|
||||
void c_power() {}
|
||||
void c_unload_cartridge() {}
|
||||
std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
|
||||
return std::make_pair(max(512 / width, (uint32_t)1), max(448 / height, (uint32_t)1));
|
||||
}
|
||||
void c_install_handler() {}
|
||||
void c_uninstall_handler() {}
|
||||
void c_emulate() {
|
||||
int16_t audio[800] = {0};
|
||||
pflag = false;
|
||||
redraw_screen();
|
||||
framebuffer::info inf;
|
||||
inf.type = &framebuffer::pixfmt_rgb32;
|
||||
inf.mem = const_cast<char*>(reinterpret_cast<const char*>(cover_fbmem));
|
||||
inf.physwidth = 480;
|
||||
inf.physheight = 432;
|
||||
inf.physstride = 1920;
|
||||
inf.width = 480;
|
||||
inf.height = 432;
|
||||
inf.stride = 1920;
|
||||
inf.offset_x = 0;
|
||||
inf.offset_y = 0;
|
||||
framebuffer::raw ls(inf);
|
||||
fmod++;
|
||||
if(fmod == 50) fmod = 0;
|
||||
if(fmod == 0 || fmod == 16 || fmod == 33)
|
||||
ecore_callbacks->output_frame(ls, 60,1);
|
||||
CORE().audio->submit_buffer(audio, 48, false, 48000);
|
||||
}
|
||||
void c_runtosave() {}
|
||||
bool c_get_pflag() { return pflag; }
|
||||
void c_set_pflag(bool _pflag) { pflag = _pflag; }
|
||||
framebuffer::raw& c_draw_cover() {
|
||||
static framebuffer::raw x(cover_fbinfo);
|
||||
redraw_cover_fbinfo();
|
||||
return x;
|
||||
}
|
||||
std::string c_get_core_shortname() { return "test"; }
|
||||
void c_pre_emulate_frame(portctrl::frame& cf) {}
|
||||
void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
|
||||
{
|
||||
if(id == 0)
|
||||
messages << "ID #0, choice: " << p[0].i << std::endl;
|
||||
}
|
||||
const interface_device_reg* c_get_registers() { return test_registers; }
|
||||
int t_load_rom(core_romimage* images, std::map<std::string, std::string>& settings,
|
||||
uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
|
||||
{
|
||||
return test_controllerconfig(settings);
|
||||
}
|
||||
bool t_is_vfr() { return true; }
|
||||
std::pair<uint64_t, uint64_t> c_get_bus_map() { return std::make_pair(0, 0); }
|
||||
std::list<core_vma_info> c_vma_list() { return std::list<core_vma_info>(); }
|
||||
std::set<std::string> c_srams() { return std::set<std::string>(); }
|
||||
unsigned c_action_flags(unsigned id) { return 1; }
|
||||
int c_reset_action(bool hard) { return -1; }
|
||||
void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags) {}
|
||||
void c_set_cheat(uint64_t addr, uint64_t value, bool set) {}
|
||||
void c_debug_reset() {}
|
||||
std::vector<std::string> c_get_trace_cpus()
|
||||
{
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
unsigned char fmod;
|
||||
} test2_core;
|
||||
}
|
|
@ -668,6 +668,10 @@ failed:
|
|||
{
|
||||
internal_pflag = true;
|
||||
}
|
||||
bool supports_vfr_sel()
|
||||
{
|
||||
return (caps1 & LSNES_CORE_CAP1_TYPEEXT1);
|
||||
}
|
||||
private:
|
||||
std::string fullname;
|
||||
std::string shortname;
|
||||
|
@ -691,8 +695,9 @@ failed:
|
|||
struct c_core_type : public core_type
|
||||
{
|
||||
c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, portctrl::type*> _ports,
|
||||
unsigned _rcount, unsigned _id)
|
||||
: core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id)
|
||||
unsigned _rcount, unsigned _id, bool _vfr)
|
||||
: core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id),
|
||||
vfr(_vfr)
|
||||
{
|
||||
}
|
||||
~c_core_type() throw()
|
||||
|
@ -749,6 +754,10 @@ failed:
|
|||
}
|
||||
return cset;
|
||||
}
|
||||
bool t_is_vfr()
|
||||
{
|
||||
return vfr;
|
||||
}
|
||||
private:
|
||||
void copy_settings(std::vector<char>& tmpmem, std::vector<lsnes_core_system_setting>& tmpmem2,
|
||||
std::map<std::string, std::string>& settings)
|
||||
|
@ -779,6 +788,7 @@ failed:
|
|||
entrypoint_fn entrypoint;
|
||||
unsigned rcount;
|
||||
unsigned id;
|
||||
bool vfr;
|
||||
};
|
||||
|
||||
std::vector<char> msgbuf;
|
||||
|
@ -1141,12 +1151,13 @@ no_parameters:
|
|||
if(!cores.count(_core))
|
||||
throw std::runtime_error("create_type: Unknown core");
|
||||
p.core = cores[_core];
|
||||
bool is_vfr = dynamic_cast<c_core_core*>(p.core)->supports_vfr_sel() && r.is_vfr;
|
||||
for(unsigned* reg = r.regions; *reg != 0xFFFFFFFFU; reg++) {
|
||||
if(!regions.count(*reg))
|
||||
throw std::runtime_error("create_type: Unknown region");
|
||||
p.regions.push_back(regions[*reg]);
|
||||
}
|
||||
return new c_core_type(lib, p, cores[_core]->get_ports(), rcount, type);
|
||||
return new c_core_type(lib, p, cores[_core]->get_ports(), rcount, type, is_vfr);
|
||||
}
|
||||
|
||||
std::map<const void*, std::list<core_sysregion*>> bylib_sysregion;
|
||||
|
@ -1184,7 +1195,7 @@ no_parameters:
|
|||
//Enumerate what the thing supports.
|
||||
entrypoint_fn entrypoint(fn);
|
||||
lsnes_core_enumerate_cores r;
|
||||
r.emu_flags1 = 2;
|
||||
r.emu_flags1 = 3;
|
||||
r.message = callback_message;
|
||||
r.get_input = callback_get_input;
|
||||
r.notify_action_update = callback_notify_action_update;
|
||||
|
|
|
@ -582,6 +582,11 @@ std::vector<std::string> core_core::get_trace_cpus()
|
|||
return c_get_trace_cpus();
|
||||
}
|
||||
|
||||
bool core_type::t_is_vfr()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
emucore_callbacks::~emucore_callbacks() throw()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace
|
|||
|
||||
P(address);
|
||||
|
||||
auto& h = CORE().mlogic->get_mfile().host_memory;
|
||||
auto& h = CORE().mlogic->get_mfile().dynamic.host_memory;
|
||||
if(address + sizeof(S) > h.size()) {
|
||||
L.pushboolean(0);
|
||||
return 1;
|
||||
|
@ -30,7 +30,7 @@ namespace
|
|||
|
||||
P(address, value);
|
||||
|
||||
auto& h = CORE().mlogic->get_mfile().host_memory;
|
||||
auto& h = CORE().mlogic->get_mfile().dynamic.host_memory;
|
||||
if(address + sizeof(S) > h.size())
|
||||
h.resize(address + sizeof(S));
|
||||
serialization::write_endian<S>(&h[address], value, 1);
|
||||
|
|
|
@ -418,8 +418,7 @@ uint64_t lua_state::timed_hook(int timer) throw()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_t secs, uint64_t ssecs, movie& mov,
|
||||
void* u)
|
||||
void lua_state::callback_do_unsafe_rewind(movie& mov, void* u)
|
||||
{
|
||||
auto& core = CORE();
|
||||
if(u) {
|
||||
|
@ -428,9 +427,7 @@ void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_
|
|||
try {
|
||||
run_callback(*on_pre_rewind);
|
||||
run_callback(*on_movie_lost, "unsaferewind");
|
||||
mainloop_restore_state(u2->state, u2->secs, u2->ssecs);
|
||||
mov.fast_load(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
|
||||
try { core.mlogic->get_mfile().host_memory = u2->hostmemory; } catch(...) {}
|
||||
do_quickload(u2->dstate, mov);
|
||||
run_callback(*on_post_rewind);
|
||||
delete reinterpret_cast<lua::objpin<lua_unsaferewind>*>(u);
|
||||
} catch(...) {
|
||||
|
@ -438,14 +435,9 @@ void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_
|
|||
}
|
||||
} else {
|
||||
//Save
|
||||
run_callback(*on_set_rewind, lua::state::fn_tag([&core, save, secs, ssecs, &mov](lua::state& L) ->
|
||||
int {
|
||||
run_callback(*on_set_rewind, lua::state::fn_tag([&core, &mov](lua::state& L) -> int {
|
||||
lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(*core.lua);
|
||||
u2->state = save;
|
||||
u2->secs = secs,
|
||||
u2->ssecs = ssecs;
|
||||
u2->hostmemory = core.mlogic->get_mfile().host_memory;
|
||||
mov.fast_save(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
|
||||
do_quicksave(u2->dstate, mov);
|
||||
return 1;
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -760,7 +760,7 @@ namespace
|
|||
if((size_t)(daddr + rows * size) < daddr)
|
||||
throw std::runtime_error("Size to copy too large");
|
||||
|
||||
auto& h = core.mlogic->get_mfile().host_memory;
|
||||
auto& h = core.mlogic->get_mfile().dynamic.host_memory;
|
||||
if(daddr + rows * size > h.size()) {
|
||||
equals = false;
|
||||
h.resize(daddr + rows * size);
|
||||
|
|
|
@ -380,7 +380,7 @@ namespace
|
|||
throw std::runtime_error("Source out of range");
|
||||
|
||||
//Calculate new size of target.
|
||||
auto& h = core.mlogic->get_mfile().host_memory;
|
||||
auto& h = core.mlogic->get_mfile().dynamic.host_memory;
|
||||
size_t rsize = size * rows;
|
||||
if(size && rsize / size != rows)
|
||||
throw std::runtime_error("Copy size out of range");
|
||||
|
|
|
@ -13,6 +13,13 @@ namespace
|
|||
return 1;
|
||||
}
|
||||
|
||||
int currentvi(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
auto& m = CORE().mlogic->get_mfile();
|
||||
L.pushnumber(m.dynamic.vi_counter);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lagcounter(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
auto& m = CORE().mlogic->get_movie();
|
||||
|
@ -79,8 +86,8 @@ namespace
|
|||
int read_rtc(lua::state& L, lua::parameters& P)
|
||||
{
|
||||
auto& core = CORE();
|
||||
L.pushnumber(core.mlogic->get_mfile().rtc_second);
|
||||
L.pushnumber(core.mlogic->get_mfile().rtc_subsecond);
|
||||
L.pushnumber(core.mlogic->get_mfile().dynamic.rtc_second);
|
||||
L.pushnumber(core.mlogic->get_mfile().dynamic.rtc_subsecond);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -112,30 +119,25 @@ namespace
|
|||
if(!mfile.is_savestate)
|
||||
throw std::runtime_error("movie.to_rewind only allows savestates");
|
||||
lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(L);
|
||||
u2->state = mfile.savestate;
|
||||
if(u2->state.size() >= 32)
|
||||
u2->state.resize(u2->state.size() - 32);
|
||||
u2->secs = mfile.rtc_second;
|
||||
u2->ssecs = mfile.rtc_subsecond;
|
||||
u2->pollcounters = mfile.pollcounters;
|
||||
u2->lag = mfile.lagged_frames;
|
||||
u2->frame = mfile.save_frame;
|
||||
u2->hostmemory = mfile.host_memory;
|
||||
u2->dstate = mfile.dynamic;
|
||||
if(u2->dstate.savestate.size() >= 32)
|
||||
u2->dstate.savestate.resize(u2->dstate.savestate.size() - 32);
|
||||
//Now the remaining field ptr is somewhat nastier.
|
||||
uint64_t f = 0;
|
||||
uint64_t s = mfile.input->size();
|
||||
u2->ptr = 0;
|
||||
while(++f < u2->frame) {
|
||||
if(u2->ptr < s)
|
||||
u2->ptr++;
|
||||
while(u2->ptr < s && !(*mfile.input)[u2->ptr].sync())
|
||||
u2->ptr++;
|
||||
u2->dstate.movie_ptr = 0;
|
||||
while(++f < u2->dstate.save_frame) {
|
||||
if(u2->dstate.movie_ptr < s)
|
||||
u2->dstate.movie_ptr++;
|
||||
while(u2->dstate.movie_ptr < s && !(*mfile.input)[u2->dstate.movie_ptr].sync())
|
||||
u2->dstate.movie_ptr++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua::functions LUA_movie_fns(lua_func_misc, "movie", {
|
||||
{"currentframe", currentframe},
|
||||
{"currentvi", currentvi},
|
||||
{"lagcount", lagcounter},
|
||||
{"framecount", framecount},
|
||||
{"rerecords", rerecords},
|
||||
|
|
|
@ -1310,6 +1310,8 @@ void wxwin_mainwindow::update_statusbar()
|
|||
s << "Frame: " << vars.curframe;
|
||||
else
|
||||
s << "Frame: " << vars.curframe << "/" << vars.length;
|
||||
if(vars.vi_valid)
|
||||
s << " VI: " << vars.vi_counter;
|
||||
s << " Lag: " << vars.lag;
|
||||
if(vars.subframe == _lsnes_status::subframe_savepoint)
|
||||
s << " Subframe: S";
|
||||
|
|
|
@ -698,8 +698,10 @@ struct moviefile& wxwin_project::make_movie()
|
|||
}
|
||||
}
|
||||
f.is_savestate = false;
|
||||
f.movie_rtc_second = f.rtc_second = boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
|
||||
f.movie_rtc_subsecond = f.rtc_subsecond = boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue()));
|
||||
f.movie_rtc_second = boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
|
||||
f.movie_rtc_subsecond = boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue()));
|
||||
f.dynamic.rtc_second = f.movie_rtc_second;
|
||||
f.dynamic.rtc_subsecond = f.movie_rtc_subsecond;
|
||||
if(f.movie_rtc_subsecond < 0)
|
||||
throw std::runtime_error("RTC subsecond must be positive");
|
||||
auto ctrldata = inst.rom->controllerconfig(f.settings);
|
||||
|
|
Loading…
Add table
Reference in a new issue