save/restore otuput values in save states

This commit is contained in:
Vas Crabb 2019-12-13 14:41:35 +11:00
parent d2983c58a0
commit ed2992101c
6 changed files with 119 additions and 82 deletions

View File

@ -263,6 +263,11 @@ void running_machine::start()
save().register_presave(save_prepost_delegate(FUNC(running_machine::presave_all_devices), this));
start_all_devices();
save().register_postload(save_prepost_delegate(FUNC(running_machine::postload_all_devices), this));
// save outputs created before start time
output().register_save();
// load cheat files
manager().load_cheatfiles(*this);
// start recording movie if specified

View File

@ -8,8 +8,11 @@
***************************************************************************/
#include "emu.h"
#include "output.h"
#include "coreutil.h"
#include "modules/output/output_module.h"
#include <algorithm>
#define OUTPUT_VERBOSE 0
@ -67,19 +70,46 @@ void output_manager::item_proxy::resolve(device_t &device, std::string const &na
// OUTPUT MANAGER
//**************************************************************************
//-------------------------------------------------
// output_manager - constructor
//-------------------------------------------------
/*-------------------------------------------------
output_manager - constructor
-------------------------------------------------*/
output_manager::output_manager(running_machine &machine)
: m_machine(machine),
m_uniqueid(12345)
: m_machine(machine)
, m_uniqueid(12345)
{
/* add pause callback */
// add callbacks
machine.add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(&output_manager::pause, this));
machine.add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(&output_manager::resume, this));
machine.save().register_presave(save_prepost_delegate(FUNC(output_manager::presave), this));
machine.save().register_postload(save_prepost_delegate(FUNC(output_manager::postload), this));
}
/*-------------------------------------------------
register_save - register for save states
-------------------------------------------------*/
void output_manager::register_save()
{
assert(m_save_order.empty());
assert(!m_save_data);
// make space for the data
m_save_order.clear();
m_save_order.reserve(m_itemtable.size());
m_save_data = std::make_unique<s32 []>(m_itemtable.size());
// sort existing outputs by name and register for save
for (auto &item : m_itemtable)
m_save_order.emplace_back(item.second);
std::sort(m_save_order.begin(), m_save_order.end(), [] (auto const &l, auto const &r) { return l.get().name() < r.get().name(); });
// register the reserved space for saving
machine().save().save_pointer(nullptr, "output", nullptr, 0, NAME(m_save_data), m_itemtable.size());
}
/*-------------------------------------------------
find_item - find an item based on a string
-------------------------------------------------*/
@ -114,6 +144,7 @@ output_manager::output_item &output_manager::find_or_create_item(const char *out
return item ? *item : create_new_item(outname, value);
}
/*-------------------------------------------------
output_pause - send pause message
-------------------------------------------------*/
@ -129,6 +160,28 @@ void output_manager::resume()
}
/*-------------------------------------------------
presave - prepare data for save state
-------------------------------------------------*/
void output_manager::presave()
{
for (size_t i = 0; m_save_order.size() > i; ++i)
m_save_data[i] = m_save_order[i].get().get();
}
/*-------------------------------------------------
postload - restore loaded data
-------------------------------------------------*/
void output_manager::postload()
{
for (size_t i = 0; m_save_order.size() > i; ++i)
m_save_order[i].get().set(m_save_data[i]);
}
/*-------------------------------------------------
output_set_value - set the value of an output
-------------------------------------------------*/
@ -145,32 +198,6 @@ void output_manager::set_value(const char *outname, s32 value)
}
/*-------------------------------------------------
output_set_indexed_value - set the value of an
indexed output
-------------------------------------------------*/
void output_manager::set_indexed_value(const char *basename, int index, int value)
{
char buffer[100];
char *dest = buffer;
/* copy the string */
while (*basename != 0)
*dest++ = *basename++;
/* append the index */
if (index >= 1000) *dest++ = '0' + ((index / 1000) % 10);
if (index >= 100) *dest++ = '0' + ((index / 100) % 10);
if (index >= 10) *dest++ = '0' + ((index / 10) % 10);
*dest++ = '0' + (index % 10);
*dest++ = 0;
/* set the value */
set_value(buffer, value);
}
/*-------------------------------------------------
output_get_value - return the value of an
output
@ -191,7 +218,7 @@ s32 output_manager::get_value(const char *outname)
if nullptr is specified
-------------------------------------------------*/
void output_manager::set_notifier(const char *outname, output_notifier_func callback, void *param)
void output_manager::set_notifier(const char *outname, notifier_func callback, void *param)
{
// if an item is specified, find/create it
if (outname)
@ -206,18 +233,6 @@ void output_manager::set_notifier(const char *outname, output_notifier_func call
}
/*-------------------------------------------------
output_notify_all - immediately call the given
notifier for all outputs
-------------------------------------------------*/
void output_manager::notify_all(output_module *module)
{
for (auto &item : m_itemtable)
module->notify(item.second.name().c_str(), item.second.get());
}
/*-------------------------------------------------
output_name_to_id - returns a unique ID for
a given name

View File

@ -6,23 +6,25 @@
General purpose output routines.
***************************************************************************/
#ifndef MAME_EMU_OUTPUT_H
#define MAME_EMU_OUTPUT_H
#pragma once
#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif
#ifndef MAME_EMU_OUTPUT_H
#define MAME_EMU_OUTPUT_H
#include <functional>
#include <iterator>
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
typedef void (*output_notifier_func)(const char *outname, s32 value, void *param);
// ======================> output_manager
class output_manager
@ -30,10 +32,12 @@ class output_manager
private:
template <typename Input, std::make_unsigned_t<Input> DefaultMask> friend class devcb_write;
typedef void (*notifier_func)(const char *outname, s32 value, void *param);
class output_notify
{
public:
output_notify(output_notifier_func callback, void *param)
output_notify(notifier_func callback, void *param)
: m_notifier(callback)
, m_param(param)
{
@ -42,8 +46,8 @@ private:
void operator()(char const *outname, s32 value) const { m_notifier(outname, value, m_param); }
private:
output_notifier_func m_notifier; // callback to call
void * m_param; // parameter to pass the callback
notifier_func m_notifier; // callback to call
void * m_param; // parameter to pass the callback
};
using notify_vector = std::vector<output_notify>;
@ -67,7 +71,7 @@ private:
void set(s32 value) { if (m_value != value) { notify(value); } }
void notify(s32 value);
void set_notifier(output_notifier_func callback, void *param) { m_notifylist.emplace_back(callback, param); }
void set_notifier(notifier_func callback, void *param) { m_notifylist.emplace_back(callback, param); }
private:
output_manager &m_manager; // parent output manager
@ -158,6 +162,9 @@ public:
// construction/destruction
output_manager(running_machine &machine);
// register for save states
void register_save() ATTR_COLD;
// getters
running_machine &machine() const { return m_machine; }
@ -168,10 +175,14 @@ public:
s32 get_value(const char *outname);
// set a notifier on a particular output, or globally if nullptr
void set_notifier(const char *outname, output_notifier_func callback, void *param);
void set_notifier(const char *outname, notifier_func callback, void *param);
// set a notifier on a particular output, or globally if nullptr
void notify_all(output_module *module);
// immdediately call a notifier for all outputs
template <typename T> void notify_all(T &&notifier) const
{
for (auto const &item : m_itemtable)
notifier(item.second.name().c_str(), item.second.get());
}
// map a name to a unique ID
u32 name_to_id(const char *outname);
@ -179,24 +190,26 @@ public:
// map a unique ID back to a name
const char *id_to_name(u32 id);
void pause();
void resume();
private:
// set an indexed value for an output (concatenates basename + index)
void set_indexed_value(const char *basename, int index, int value);
output_item *find_item(const char *string);
output_item &create_new_item(const char *outname, s32 value);
output_item &find_or_create_item(const char *outname, s32 value);
// event handlers
void pause();
void resume();
void presave() ATTR_COLD;
void postload() ATTR_COLD;
// internal state
running_machine &m_machine; // reference to our machine
std::unordered_map<std::string, output_item> m_itemtable;
notify_vector m_global_notifylist;
std::vector<std::reference_wrapper<output_item> > m_save_order;
std::unique_ptr<s32 []> m_save_data;
u32 m_uniqueid;
};
template <unsigned... N> using output_finder = output_manager::output_finder<void, N...>;
#endif // MAME_EMU_OUTPUT_H
#endif // MAME_EMU_OUTPUT_H

View File

@ -216,9 +216,17 @@ public:
// global memory registration
template <typename ItemType>
void save_item(ItemType &value, const char *valname, int index = 0) { save_item(nullptr, "global", nullptr, index, value, valname); }
void save_item(ItemType &value, const char *valname, int index = 0)
{ save_item(nullptr, "global", nullptr, index, value, valname); }
template <typename ItemType, typename StructType, typename ElementType>
void save_item(ItemType &value, ElementType StructType::*element, const char *valname, int index = 0)
{ save_item(nullptr, "global", nullptr, index, value, element, valname); }
template <typename ItemType>
void save_pointer(ItemType *value, const char *valname, u32 count, int index = 0) { save_pointer(nullptr, "global", nullptr, index, value, valname, count); }
void save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0)
{ save_pointer(nullptr, "global", nullptr, index, std::forward<ItemType>(value), valname, count); }
template <typename ItemType, typename StructType, typename ElementType>
void save_pointer(ItemType &&value, ElementType StructType::*element, const char *valname, u32 count, int index = 0)
{ save_pointer(nullptr, "global", nullptr, index, std::forward<ItemType>(value), element, valname, count); }
// file processing
static save_error check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...));

View File

@ -240,9 +240,9 @@ void emu_timer::register_save()
int index = 0;
std::string name;
// for non-device timers, it is an index based on the callback function name
if (m_device == nullptr)
{
// for non-device timers, it is an index based on the callback function name
name = m_callback.name() ? m_callback.name() : "unnamed";
for (emu_timer *curtimer = machine().scheduler().first_timer(); curtimer != nullptr; curtimer = curtimer->next())
if (!curtimer->m_temporary && curtimer->m_device == nullptr)
@ -253,13 +253,12 @@ void emu_timer::register_save()
index++;
}
}
// for device timers, it is an index based on the device and timer ID
else
{
// for device timers, it is an index based on the device and timer ID
name = string_format("%s/%d", m_device->tag(), m_id);
for (emu_timer *curtimer = machine().scheduler().first_timer(); curtimer != nullptr; curtimer = curtimer->next())
if (!curtimer->m_temporary && curtimer->m_device != nullptr && curtimer->m_device == m_device && curtimer->m_id == m_id)
if (!curtimer->m_temporary && curtimer->m_device == m_device && curtimer->m_id == m_id)
index++;
}

View File

@ -78,7 +78,7 @@ public:
virtual void notify(const char *outname, int32_t value) override;
int create_window_class(void);
int create_window_class();
LRESULT register_client(HWND hwnd, LPARAM id);
LRESULT unregister_client(HWND hwnd, LPARAM id);
LRESULT send_id_string(HWND hwnd, LPARAM id);
@ -174,7 +174,7 @@ void output_win32::exit()
// create_window_class
//============================================================
int output_win32::create_window_class(void)
int output_win32::create_window_class()
{
static bool classes_created = false;
@ -261,7 +261,7 @@ LRESULT output_win32::register_client(HWND hwnd, LPARAM id)
if ((*client)->id == id)
{
(*client)->hwnd = hwnd;
machine().output().notify_all(this);
machine().output().notify_all([this] (const char *outname, int32_t value) { notify(outname, value); });
return 1;
}
@ -273,7 +273,7 @@ LRESULT output_win32::register_client(HWND hwnd, LPARAM id)
(*client)->machine = &machine();
// request a notification for all outputs
machine().output().notify_all(this);
machine().output().notify_all([this] (const char *outname, int32_t value) { notify(outname, value); });
return 0;
}
@ -346,12 +346,9 @@ LRESULT output_win32::send_id_string(HWND hwnd, LPARAM id)
void output_win32::notify(const char *outname, int32_t value)
{
registered_client *client;
// loop over clients and notify them
for (client = m_clientlist; client != nullptr; client = client->next)
{
for (registered_client *client = m_clientlist; client != nullptr; client = client->next)
PostMessage(client->hwnd, om_mame_update_state, client->machine->output().name_to_id(outname), value);
}
}