Remove all uses of first_screen() from core files, nw

This commit is contained in:
Ryan Holtz 2018-03-11 11:16:58 +01:00
parent 1a89b550fa
commit 81a35fb46e
14 changed files with 542 additions and 245 deletions

View File

@ -118,7 +118,7 @@ render_crosshair::render_crosshair(running_machine &machine, int player)
, m_time(0)
{
// for now, use the main screen
m_screen = machine.first_screen();
m_screen = screen_device_iterator(machine.root_device()).first();
}
@ -314,8 +314,9 @@ crosshair_manager::crosshair_manager(running_machine &machine)
machine.configuration().config_register("crosshairs", config_load_delegate(&crosshair_manager::config_load, this), config_save_delegate(&crosshair_manager::config_save, this));
/* register the animation callback */
if (machine.first_screen() != nullptr)
machine.first_screen()->register_vblank_callback(vblank_state_delegate(&crosshair_manager::animate, this));
screen_device *first_screen = screen_device_iterator(machine.root_device()).first();
if (first_screen != nullptr)
first_screen->register_vblank_callback(vblank_state_delegate(&crosshair_manager::animate, this));
}
/*-------------------------------------------------

View File

@ -59,8 +59,6 @@ debugger_cpu::debugger_cpu(running_machine &machine)
, m_last_periodic_update_time(0)
, m_comments_loaded(false)
{
screen_device *first_screen = m_machine.first_screen();
m_tempvar = make_unique_clear<u64[]>(NUM_TEMP_VARIABLES);
/* create a global symbol table */
@ -75,9 +73,28 @@ debugger_cpu::debugger_cpu(running_machine &machine)
using namespace std::placeholders;
m_symtable->add("cpunum", std::bind(&debugger_cpu::get_cpunum, this, _1));
m_symtable->add("beamx", std::bind(&debugger_cpu::get_beamx, this, _1, first_screen));
m_symtable->add("beamy", std::bind(&debugger_cpu::get_beamy, this, _1, first_screen));
m_symtable->add("frame", std::bind(&debugger_cpu::get_frame, this, _1, first_screen));
screen_device_iterator screen_iterator = screen_device_iterator(m_machine.root_device());
screen_device_iterator::auto_iterator iter = screen_iterator.begin();
const uint32_t count = (uint32_t)screen_iterator.count();
if (count == 1)
{
m_symtable->add("beamx", std::bind(&debugger_cpu::get_beamx, this, _1, iter.current()));
m_symtable->add("beamy", std::bind(&debugger_cpu::get_beamy, this, _1, iter.current()));
m_symtable->add("frame", std::bind(&debugger_cpu::get_frame, this, _1, iter.current()));
iter.current()->register_vblank_callback(vblank_state_delegate(&debugger_cpu::on_vblank, this));
}
else if (count > 1)
{
for (uint32_t i = 0; i < count; i++, iter++)
{
m_symtable->add(string_format("beamx%d", i).c_str(), std::bind(&debugger_cpu::get_beamx, this, _1, iter.current()));
m_symtable->add(string_format("beamy%d", i).c_str(), std::bind(&debugger_cpu::get_beamy, this, _1, iter.current()));
m_symtable->add(string_format("frame%d", i).c_str(), std::bind(&debugger_cpu::get_frame, this, _1, iter.current()));
iter.current()->register_vblank_callback(vblank_state_delegate(&debugger_cpu::on_vblank, this));
}
}
/* add the temporary variables to the global symbol table */
for (int regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++)
@ -97,10 +114,6 @@ debugger_cpu::debugger_cpu(running_machine &machine)
break;
}
}
/* add callback for breaking on VBLANK */
if (m_machine.first_screen() != nullptr)
m_machine.first_screen()->register_vblank_callback(vblank_state_delegate(&debugger_cpu::on_vblank, this));
}
void debugger_cpu::configure_memory(symbol_table &table)

View File

@ -119,14 +119,30 @@ void debug_view_state::recompute()
// add a cycles entry: cycles:99999999
m_state_list.emplace_back(REG_CYCLES, "cycles", 8);
// add a beam entry: beamx:1234
m_state_list.emplace_back(REG_BEAMX, "beamx", 4);
screen_device_iterator screen_iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = screen_iterator.begin();
const int screen_count = screen_iterator.count();
// add a beam entry: beamy:5678
m_state_list.emplace_back(REG_BEAMY, "beamy", 4);
if (screen_count == 1)
{
// add a beam entry: beamx:1234
m_state_list.emplace_back(REG_BEAMX, "beamx", 4);
// add a beam entry: frame:123456
m_state_list.emplace_back(REG_FRAME, "frame", 6);
// add a beam entry: beamy:5678
m_state_list.emplace_back(REG_BEAMY, "beamy", 4);
// add a beam entry: frame:123456
m_state_list.emplace_back(REG_FRAME, "frame", 6);
}
else if (screen_count > 1)
{
for (int i = 0; i < screen_count; i++, iter++)
{
m_state_list.emplace_back(REG_BEAMX_S0 - i, string_format("beamx%d", i).c_str(), 4);
m_state_list.emplace_back(REG_BEAMY_S0 - i, string_format("beamy%d", i).c_str(), 4);
m_state_list.emplace_back(REG_FRAME_S0 - i, string_format("frame%d", i).c_str(), 6);
}
}
// add a flags entry: flags:xxxxxxxx
m_state_list.emplace_back(STATE_GENFLAGS, "flags", source.m_stateintf->state_string_max_length(STATE_GENFLAGS));
@ -196,7 +212,6 @@ void debug_view_state::view_update()
// loop over rows
auto it(m_state_list.begin());
screen_device const *const screen(machine().first_screen());
debug_view_char *dest(&m_viewdata[0]);
for (s32 index = 0, limit = m_topleft.y + m_visible.y; (index < limit) || (it != m_state_list.end()); ++index)
{
@ -222,18 +237,21 @@ void debug_view_state::view_update()
valstr = string_format("%-8d", curitem.value());
break;
case REG_BEAMX:
curitem.update(screen ? screen->hpos() : 0, cycles_changed);
case REG_BEAMX_S0: case REG_BEAMX_S1: case REG_BEAMX_S2: case REG_BEAMX_S3:
case REG_BEAMX_S4: case REG_BEAMX_S5: case REG_BEAMX_S6: case REG_BEAMX_S7:
curitem.update(screen_device_iterator(machine().root_device()).byindex(-(curitem.index() - REG_BEAMX_S0))->hpos(), cycles_changed);
valstr = string_format("%4d", curitem.value());
break;
case REG_BEAMY:
curitem.update(screen ? screen->vpos() : 0, cycles_changed);
case REG_BEAMY_S0: case REG_BEAMY_S1: case REG_BEAMY_S2: case REG_BEAMY_S3:
case REG_BEAMY_S4: case REG_BEAMY_S5: case REG_BEAMY_S6: case REG_BEAMY_S7:
curitem.update(screen_device_iterator(machine().root_device()).byindex(-(curitem.index() - REG_BEAMY_S0))->vpos(), cycles_changed);
valstr = string_format("%4d", curitem.value());
break;
case REG_FRAME:
curitem.update(screen ? screen->frame_number() : 0, cycles_changed);
case REG_FRAME_S0: case REG_FRAME_S1: case REG_FRAME_S2: case REG_FRAME_S3:
case REG_FRAME_S4: case REG_FRAME_S5: case REG_FRAME_S6: case REG_FRAME_S7:
curitem.update(screen_device_iterator(machine().root_device()).byindex(-(curitem.index() - REG_FRAME_S0))->frame_number(), cycles_changed);
valstr = string_format("%-6d", curitem.value());
break;

View File

@ -89,8 +89,32 @@ private:
static constexpr int REG_DIVIDER = -10;
static constexpr int REG_CYCLES = -11;
static constexpr int REG_BEAMX = -12;
static constexpr int REG_BEAMY = -13;
static constexpr int REG_FRAME = -14;
static constexpr int REG_BEAMX_S0 = -12;
static constexpr int REG_BEAMX_S1 = -13;
static constexpr int REG_BEAMX_S2 = -14;
static constexpr int REG_BEAMX_S3 = -15;
static constexpr int REG_BEAMX_S4 = -16;
static constexpr int REG_BEAMX_S5 = -17;
static constexpr int REG_BEAMX_S6 = -18;
static constexpr int REG_BEAMX_S7 = -19;
static constexpr int REG_BEAMY = -20;
static constexpr int REG_BEAMY_S0 = -20;
static constexpr int REG_BEAMY_S1 = -21;
static constexpr int REG_BEAMY_S2 = -22;
static constexpr int REG_BEAMY_S3 = -23;
static constexpr int REG_BEAMY_S4 = -24;
static constexpr int REG_BEAMY_S5 = -25;
static constexpr int REG_BEAMY_S6 = -26;
static constexpr int REG_BEAMY_S7 = -27;
static constexpr int REG_FRAME = -28;
static constexpr int REG_FRAME_S0 = -28;
static constexpr int REG_FRAME_S1 = -29;
static constexpr int REG_FRAME_S2 = -30;
static constexpr int REG_FRAME_S3 = -31;
static constexpr int REG_FRAME_S4 = -32;
static constexpr int REG_FRAME_S5 = -33;
static constexpr int REG_FRAME_S6 = -34;
static constexpr int REG_FRAME_S7 = -35;
};

View File

@ -836,7 +836,8 @@ inline void construct_core_types_UI(simple_list<input_type_entry> &typelist)
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_FPS, "Show FPS", input_seq(KEYCODE_F11, input_seq::not_code, KEYCODE_LSHIFT) )
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SNAPSHOT, "Save Snapshot", input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT) )
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TIMECODE, "Write current timecode", input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT) )
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RECORD_MOVIE, "Record Movie", input_seq(KEYCODE_F12, KEYCODE_LSHIFT) )
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RECORD_MNG, "Record MNG", input_seq(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LCONTROL) )
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RECORD_AVI, "Record AVI", input_seq(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LCONTROL) )
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_CHEAT, "Toggle Cheat", input_seq(KEYCODE_F6) )
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_AUTOFIRE, "Toggle Autofire", input_seq() )
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_UP, "UI Up", input_seq(KEYCODE_UP, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(0)) )

View File

@ -333,7 +333,8 @@ enum ioport_type
IPT_UI_SHOW_FPS,
IPT_UI_SNAPSHOT,
IPT_UI_TIMECODE,
IPT_UI_RECORD_MOVIE,
IPT_UI_RECORD_MNG,
IPT_UI_RECORD_AVI,
IPT_UI_TOGGLE_CHEAT,
IPT_UI_UP,
IPT_UI_DOWN,

View File

@ -1368,7 +1368,7 @@ void screen_device::vblank_begin()
m_vblank_end_time = m_vblank_start_time + attotime(0, m_vblank_period);
// if this is the primary screen and we need to update now
if (this == machine().first_screen() && !(m_video_attributes & VIDEO_UPDATE_AFTER_VBLANK))
if (this == screen_device_iterator(machine().root_device()).first() && !(m_video_attributes & VIDEO_UPDATE_AFTER_VBLANK))
machine().video().frame_update();
// call the screen specific callbacks
@ -1400,7 +1400,7 @@ void screen_device::vblank_end()
m_screen_vblank(0);
// if this is the primary screen and we need to update now
if (this == machine().first_screen() && (m_video_attributes & VIDEO_UPDATE_AFTER_VBLANK))
if (this == screen_device_iterator(machine().root_device()).first() && (m_video_attributes & VIDEO_UPDATE_AFTER_VBLANK))
machine().video().frame_update();
// increment the frame number counter

View File

@ -43,6 +43,8 @@ enum texture_format
// screen_update callback flags
constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed
constexpr u32 MAX_NUM_SCREENS = 9;
/*!
@defgroup flags for video_attributes
@{

View File

@ -100,13 +100,6 @@ video_manager::video_manager(running_machine &machine)
m_snap_native(true),
m_snap_width(0),
m_snap_height(0),
m_mng_frame_period(attotime::zero),
m_mng_next_frame_time(attotime::zero),
m_mng_frame(0),
m_avi_file(nullptr),
m_avi_frame_period(attotime::zero),
m_avi_next_frame_time(attotime::zero),
m_avi_frame(0),
m_timecode_enabled(false),
m_timecode_write(false),
m_timecode_text(""),
@ -121,13 +114,15 @@ video_manager::video_manager(running_machine &machine)
// extract initial execution state from global configuration settings
update_refresh_speed();
const bool no_screens = screen_device_iterator(machine.root_device()).count() == 0;
// create a render target for snapshots
const char *viewname = machine.options().snap_view();
m_snap_native = (machine.first_screen() != nullptr && (viewname[0] == 0 || strcmp(viewname, "native") == 0));
m_snap_native = !no_screens && (viewname[0] == 0 || strcmp(viewname, "native") == 0);
// the native target is hard-coded to our internal layout and has all options disabled
if (m_snap_native)
{
// the native target is hard-coded to our internal layout and has all options disabled
m_snap_target = machine.render().target_alloc(&layout_snap, RENDER_CREATE_SINGLE_FILE | RENDER_CREATE_HIDDEN);
m_snap_target->set_backdrops_enabled(false);
m_snap_target->set_overlays_enabled(false);
@ -137,10 +132,9 @@ video_manager::video_manager(running_machine &machine)
m_snap_target->set_screen_overlay_enabled(false);
m_snap_target->set_zoom_to_screen(false);
}
// other targets select the specified view and turn off effects
else
{
// otherwise, non-default targets select the specified view and turn off effects
m_snap_target = machine.render().target_alloc(nullptr, RENDER_CREATE_HIDDEN);
m_snap_target->set_view(m_snap_target->configured_view(viewname, 0, 1));
m_snap_target->set_screen_overlay_enabled(false);
@ -160,7 +154,7 @@ video_manager::video_manager(running_machine &machine)
begin_recording(filename, MF_AVI);
// if no screens, create a periodic timer to drive updates
if (machine.first_screen() == nullptr)
if (no_screens)
{
m_screenless_frame_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(video_manager::screenless_update_callback), this));
m_screenless_frame_timer->adjust(screen_device::DEFAULT_FRAME_PERIOD, 0, screen_device::DEFAULT_FRAME_PERIOD);
@ -247,7 +241,7 @@ void video_manager::frame_update(bool from_debugger)
if (phase == machine_phase::RUNNING)
{
// reset partial updates if we're paused or if the debugger is active
screen_device *const screen = machine().first_screen();
screen_device *const screen = screen_device_iterator(machine().root_device()).first();
bool const debugger_enabled = machine().debug_flags & DEBUG_FLAG_ENABLED;
bool const within_instruction_hook = debugger_enabled && machine().debugger().within_instruction_hook();
if (screen && (machine().paused() || from_debugger || within_instruction_hook))
@ -396,7 +390,138 @@ std::string &video_manager::timecode_total_text(std::string &str)
return str;
}
//-------------------------------------------------
// begin_recording_mng - begin recording a MNG
//-------------------------------------------------
void video_manager::begin_recording_mng(const char *name, uint32_t index, screen_device *screen)
{
// stop any existing recording
end_recording_mng(index);
mng_info_t &info = m_mngs[index];
// reset the state
info.m_mng_frame = 0;
info.m_mng_next_frame_time = machine().time();
// create a new movie file and start recording
info.m_mng_file = std::make_unique<emu_file>(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
osd_file::error filerr;
if (name != nullptr)
{
std::string full_name(name);
if (index > 0)
{
char name_buf[256] = { 0 };
snprintf(name_buf, 256, "%s%d", name, index);
full_name = name_buf;
}
filerr = info.m_mng_file->open(full_name.c_str());
}
else
{
filerr = open_next(*info.m_mng_file, "mng");
}
if (filerr == osd_file::error::NONE)
{
// start the capture
int rate = ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds());
png_error pngerr = mng_capture_start(*info.m_mng_file, m_snap_bitmap, rate);
if (pngerr != PNGERR_NONE)
{
osd_printf_error("Error capturing MNG, png_error=%d\n", pngerr);
return end_recording_mng(index);
}
// compute the frame time
info.m_mng_frame_period = attotime::from_hz(rate);
}
else
{
osd_printf_error("Error creating MNG, osd_file::error=%d\n", int(filerr));
info.m_mng_file.reset();
}
}
//-------------------------------------------------
// begin_recording_avi - begin recording an AVI
//-------------------------------------------------
void video_manager::begin_recording_avi(const char *name, uint32_t index, screen_device *screen)
{
// stop any existing recording
end_recording_avi(index);
avi_info_t &avi_info = m_avis[index];
// reset the state
avi_info.m_avi_frame = 0;
avi_info.m_avi_next_frame_time = machine().time();
// build up information about this new movie
avi_file::movie_info info;
info.video_format = 0;
info.video_timescale = 1000 * ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds());
info.video_sampletime = 1000;
info.video_numsamples = 0;
info.video_width = m_snap_bitmap.width();
info.video_height = m_snap_bitmap.height();
info.video_depth = 24;
info.audio_format = 0;
info.audio_timescale = machine().sample_rate();
info.audio_sampletime = 1;
info.audio_numsamples = 0;
info.audio_channels = 2;
info.audio_samplebits = 16;
info.audio_samplerate = machine().sample_rate();
// create a new temporary movie file
osd_file::error filerr;
std::string fullpath;
{
emu_file tempfile(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
if (name != nullptr)
{
std::string full_name(name);
if (index > 0)
{
char name_buf[256] = { 0 };
snprintf(name_buf, 256, "%s%d", name, index);
full_name = name_buf;
}
filerr = tempfile.open(full_name.c_str());
}
else
{
filerr = open_next(tempfile, "avi");
}
// if we succeeded, make a copy of the name and create the real file over top
if (filerr == osd_file::error::NONE)
fullpath = tempfile.fullpath();
}
if (filerr == osd_file::error::NONE)
{
// compute the frame time
avi_info.m_avi_frame_period = attotime::from_seconds(1000) / info.video_timescale;
// create the file and free the string
avi_file::error avierr = avi_file::create(fullpath, info, avi_info.m_avi_file);
if (avierr != avi_file::error::NONE)
{
osd_printf_error("Error creating AVI: %s\n", avi_file::error_string(avierr));
return end_recording_avi(index);
}
}
}
//-------------------------------------------------
// begin_recording - begin recording of a movie
@ -405,141 +530,84 @@ std::string &video_manager::timecode_total_text(std::string &str)
void video_manager::begin_recording(const char *name, movie_format format)
{
// create a snapshot bitmap so we know what the target size is
create_snapshot_bitmap(nullptr);
screen_device_iterator iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = iterator.begin();
const uint32_t count = (uint32_t)iterator.count();
// start up an AVI recording
if (format == MF_AVI)
switch (format)
{
// stop any existing recording
end_recording(format);
// reset the state
m_avi_frame = 0;
m_avi_next_frame_time = machine().time();
// build up information about this new movie
screen_device *screen = machine().first_screen();
avi_file::movie_info info;
info.video_format = 0;
info.video_timescale = 1000 * ((screen != nullptr) ? ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds()) : screen_device::DEFAULT_FRAME_RATE);
info.video_sampletime = 1000;
info.video_numsamples = 0;
info.video_width = m_snap_bitmap.width();
info.video_height = m_snap_bitmap.height();
info.video_depth = 24;
info.audio_format = 0;
info.audio_timescale = machine().sample_rate();
info.audio_sampletime = 1;
info.audio_numsamples = 0;
info.audio_channels = 2;
info.audio_samplebits = 16;
info.audio_samplerate = machine().sample_rate();
// create a new temporary movie file
osd_file::error filerr;
std::string fullpath;
{
emu_file tempfile(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
if (name != nullptr)
filerr = tempfile.open(name);
case MF_AVI:
if (m_snap_native)
{
for (uint32_t index = 0; index < count; index++, iter++)
{
create_snapshot_bitmap(iter.current());
begin_recording_avi(name, index, iter.current());
}
}
else
filerr = open_next(tempfile, "avi");
// if we succeeded, make a copy of the name and create the real file over top
if (filerr == osd_file::error::NONE)
fullpath = tempfile.fullpath();
}
if (filerr == osd_file::error::NONE)
{
// compute the frame time
m_avi_frame_period = attotime::from_seconds(1000) / info.video_timescale;
// create the file and free the string
avi_file::error avierr = avi_file::create(fullpath, info, m_avi_file);
if (avierr != avi_file::error::NONE)
{
osd_printf_error("Error creating AVI: %s\n", avi_file::error_string(avierr));
return end_recording(format);
create_snapshot_bitmap(nullptr);
begin_recording_avi(name, 0, iter.current());
}
}
}
break;
// start up a MNG recording
else if (format == MF_MNG)
case MF_MNG:
if (m_snap_native)
{
for (uint32_t index = 0; index < count; index++, iter++)
{
create_snapshot_bitmap(iter.current());
begin_recording_mng(name, index, iter.current());
}
}
else
{
create_snapshot_bitmap(nullptr);
begin_recording_avi(name, 0, iter.current());
}
break;
default:
osd_printf_error("Unknown movie format: %d\n", format);
break;
}
}
//--------------------------------------------------
// end_recording_avi - stop recording an AVI movie
//--------------------------------------------------
void video_manager::end_recording_avi(uint32_t index)
{
avi_info_t &info = m_avis[index];
if (info.m_avi_file)
{
// stop any existing recording
end_recording(format);
info.m_avi_file.reset();
// reset the state
m_mng_frame = 0;
m_mng_next_frame_time = machine().time();
// create a new movie file and start recording
m_mng_file = std::make_unique<emu_file>(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
osd_file::error filerr;
if (name != nullptr)
filerr = m_mng_file->open(name);
else
filerr = open_next(*m_mng_file, "mng");
if (filerr == osd_file::error::NONE)
{
// start the capture
screen_device *screen = machine().first_screen();
int rate = (screen != nullptr) ? ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds()) : screen_device::DEFAULT_FRAME_RATE;
png_error pngerr = mng_capture_start(*m_mng_file, m_snap_bitmap, rate);
if (pngerr != PNGERR_NONE)
{
osd_printf_error("Error capturing MNG, png_error=%d\n", pngerr);
return end_recording(format);
}
// compute the frame time
m_mng_frame_period = attotime::from_hz(rate);
}
else
{
osd_printf_error("Error creating MNG, osd_file::error=%d\n", int(filerr));
m_mng_file.reset();
}
info.m_avi_frame = 0;
}
}
//--------------------------------------------------
// end_recording_mng - stop recording a MNG movie
//--------------------------------------------------
//-------------------------------------------------
// end_recording - stop recording of a movie
//-------------------------------------------------
void video_manager::end_recording(movie_format format)
void video_manager::end_recording_mng(uint32_t index)
{
if (format == MF_AVI)
mng_info_t &info = m_mngs[index];
if (info.m_mng_file != nullptr)
{
// close the file if it exists
if (m_avi_file)
{
m_avi_file.reset();
mng_capture_stop(*info.m_mng_file);
info.m_mng_file.reset();
// reset the state
m_avi_frame = 0;
}
}
else if (format == MF_MNG)
{
// close the file if it exists
if (m_mng_file != nullptr)
{
mng_capture_stop(*m_mng_file);
m_mng_file.reset();
// reset the state
m_mng_frame = 0;
}
// reset the state
info.m_mng_frame = 0;
}
}
//-------------------------------------------------
// add_sound_to_recording - add sound to a movie
// recording
@ -547,24 +615,44 @@ void video_manager::end_recording(movie_format format)
void video_manager::add_sound_to_recording(const s16 *sound, int numsamples)
{
if (m_snap_native)
{
const uint32_t count = (uint32_t)screen_device_iterator(machine().root_device()).count();
for (uint32_t index = 0; index < count; index++)
{
add_sound_to_avi_recording(sound, numsamples, index);
}
}
else
{
add_sound_to_avi_recording(sound, numsamples, 0);
}
}
//-------------------------------------------------
// add_sound_to_avi_recording - add sound to an
// AVI recording for a given screen
//-------------------------------------------------
void video_manager::add_sound_to_avi_recording(const s16 *sound, int numsamples, uint32_t index)
{
avi_info_t &info = m_avis[index];
// only record if we have a file
if (m_avi_file != nullptr)
if (info.m_avi_file != nullptr)
{
g_profiler.start(PROFILER_MOVIE_REC);
// write the next frame
avi_file::error avierr = m_avi_file->append_sound_samples(0, sound + 0, numsamples, 1);
avi_file::error avierr = info.m_avi_file->append_sound_samples(0, sound + 0, numsamples, 1);
if (avierr == avi_file::error::NONE)
avierr = m_avi_file->append_sound_samples(1, sound + 1, numsamples, 1);
avierr = info.m_avi_file->append_sound_samples(1, sound + 1, numsamples, 1);
if (avierr != avi_file::error::NONE)
end_recording(MF_AVI);
end_recording_avi(index);
g_profiler.stop();
}
}
//-------------------------------------------------
// video_exit - close down the video system
//-------------------------------------------------
@ -572,8 +660,20 @@ void video_manager::add_sound_to_recording(const s16 *sound, int numsamples)
void video_manager::exit()
{
// stop recording any movie
end_recording(MF_AVI);
end_recording(MF_MNG);
screen_device_iterator device_iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = device_iterator.begin();
const uint32_t count = (uint32_t)device_iterator.count();
for (uint32_t index = 0; index < count; index++, iter++)
{
end_recording_avi(index);
end_recording_mng(index);
if (!m_snap_native)
{
break;
}
}
// free the snapshot target
machine().render().target_free(m_snap_target);
@ -609,11 +709,48 @@ void video_manager::screenless_update_callback(void *ptr, int param)
void video_manager::postload()
{
m_avi_next_frame_time = machine().time();
m_mng_next_frame_time = machine().time();
screen_device_iterator device_iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = device_iterator.begin();
const uint32_t count = (uint32_t)device_iterator.count();
for (uint32_t index = 0; index < count; index++, iter++)
{
m_avis[index].m_avi_next_frame_time = machine().time();
m_mngs[index].m_mng_next_frame_time = machine().time();
if (!m_snap_native)
{
break;
}
}
}
//-------------------------------------------------
// is_recording - returns whether or not any
// screen is currently recording
//-------------------------------------------------
bool video_manager::is_recording() const
{
screen_device_iterator device_iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = device_iterator.begin();
const uint32_t count = (uint32_t)device_iterator.count();
for (uint32_t index = 0; index < count; index++, iter++)
{
if (m_mngs[index].m_mng_file || m_avis[index].m_avi_file)
{
return true;
}
if (!m_snap_native)
{
break;
}
}
return false;
}
//-------------------------------------------------
// effective_autoframeskip - return the effective
// autoframeskip value, accounting for fast
@ -1128,7 +1265,7 @@ void video_manager::create_snapshot_bitmap(screen_device *screen)
// scheme
//-------------------------------------------------
osd_file::error video_manager::open_next(emu_file &file, const char *extension)
osd_file::error video_manager::open_next(emu_file &file, const char *extension, uint32_t added_index)
{
u32 origflags = file.openflags();
@ -1229,7 +1366,7 @@ osd_file::error video_manager::open_next(emu_file &file, const char *extension)
else
{
// try until we succeed
file.set_openflags(OPEN_FLAG_READ);
file.set_openflags(OPEN_FLAG_WRITE);
for (int seq = 0; ; seq++)
{
// build up the filename
@ -1238,8 +1375,10 @@ osd_file::error video_manager::open_next(emu_file &file, const char *extension)
// try to open the file; stop when we fail
osd_file::error filerr = file.open(fname.c_str());
if (filerr != osd_file::error::NONE)
if (filerr == osd_file::error::NOT_FOUND)
{
break;
}
}
}
@ -1256,68 +1395,88 @@ osd_file::error video_manager::open_next(emu_file &file, const char *extension)
void video_manager::record_frame()
{
// ignore if nothing to do
if (m_mng_file == nullptr && m_avi_file == nullptr)
bool any_recording = false;
for (uint32_t index = 0; index < MAX_NUM_SCREENS && !any_recording; index++)
{
if (m_mngs[index].m_mng_file != nullptr || m_avis[index].m_avi_file != nullptr)
any_recording = true;
}
if (!any_recording)
return;
// start the profiler and get the current time
g_profiler.start(PROFILER_MOVIE_REC);
attotime curtime = machine().time();
// create the bitmap
create_snapshot_bitmap(nullptr);
screen_device_iterator device_iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = device_iterator.begin();
const uint32_t count = (uint32_t)device_iterator.count();
// handle an AVI recording
if (m_avi_file != nullptr)
for (uint32_t index = 0; index < count; index++, iter++)
{
// loop until we hit the right time
while (m_avi_next_frame_time <= curtime)
{
// write the next frame
avi_file::error avierr = m_avi_file->append_video_frame(m_snap_bitmap);
if (avierr != avi_file::error::NONE)
{
g_profiler.stop();
end_recording(MF_AVI);
break;
}
// create the bitmap
create_snapshot_bitmap(iter.current());
// advance time
m_avi_next_frame_time += m_avi_frame_period;
m_avi_frame++;
// handle an AVI recording
avi_info_t &avi_info = m_avis[index];
if (avi_info.m_avi_file != nullptr)
{
// loop until we hit the right time
while (avi_info.m_avi_next_frame_time <= curtime)
{
// write the next frame
avi_file::error avierr = avi_info.m_avi_file->append_video_frame(m_snap_bitmap);
if (avierr != avi_file::error::NONE)
{
g_profiler.stop();
end_recording_avi(index);
break;
}
// advance time
avi_info.m_avi_next_frame_time += avi_info.m_avi_frame_period;
avi_info.m_avi_frame++;
}
}
}
// handle a MNG recording
if (m_mng_file != nullptr)
{
// loop until we hit the right time
while (m_mng_next_frame_time <= curtime)
// handle a MNG recording
mng_info_t &mng_info = m_mngs[index];
if (mng_info.m_mng_file != nullptr)
{
// set up the text fields in the movie info
png_info pnginfo;
if (m_mng_frame == 0)
// loop until we hit the right time
while (mng_info.m_mng_next_frame_time <= curtime)
{
std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version());
std::string text2 = std::string(machine().system().manufacturer).append(" ").append(machine().system().type.fullname());
pnginfo.add_text("Software", text1.c_str());
pnginfo.add_text("System", text2.c_str());
}
// set up the text fields in the movie info
png_info pnginfo;
if (mng_info.m_mng_frame == 0)
{
std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version());
std::string text2 = std::string(machine().system().manufacturer).append(" ").append(machine().system().type.fullname());
pnginfo.add_text("Software", text1.c_str());
pnginfo.add_text("System", text2.c_str());
}
// write the next frame
screen_device *screen = machine().first_screen();
const rgb_t *palette = (screen != nullptr && screen->has_palette()) ? screen->palette().palette()->entry_list_adjusted() : nullptr;
int entries = (screen != nullptr && screen->has_palette()) ? screen->palette().entries() : 0;
png_error error = mng_capture_frame(*m_mng_file, pnginfo, m_snap_bitmap, entries, palette);
if (error != PNGERR_NONE)
{
g_profiler.stop();
end_recording(MF_MNG);
break;
}
// write the next frame
screen_device *screen = iter.current();
const rgb_t *palette = (screen != nullptr && screen->has_palette()) ? screen->palette().palette()->entry_list_adjusted() : nullptr;
int entries = (screen != nullptr && screen->has_palette()) ? screen->palette().entries() : 0;
png_error error = mng_capture_frame(*mng_info.m_mng_file, pnginfo, m_snap_bitmap, entries, palette);
if (error != PNGERR_NONE)
{
g_profiler.stop();
end_recording_mng(index);
break;
}
// advance time
m_mng_next_frame_time += m_mng_frame_period;
m_mng_frame++;
// advance time
mng_info.m_mng_next_frame_time += mng_info.m_mng_frame_period;
mng_info.m_mng_frame++;
}
}
if (!m_snap_native)
{
break;
}
}
@ -1338,16 +1497,52 @@ void video_manager::toggle_throttle()
// toggle_record_movie
//-------------------------------------------------
void video_manager::toggle_record_movie()
void video_manager::toggle_record_movie(movie_format format)
{
if (!is_recording())
{
begin_recording(nullptr, MF_MNG);
machine().popmessage("REC START");
begin_recording(nullptr, format);
machine().popmessage("REC START (%s)", format == MF_MNG ? "MNG" : "AVI");
}
else
{
end_recording(MF_MNG);
machine().popmessage("REC STOP");
end_recording(format);
machine().popmessage("REC STOP (%s)", format == MF_MNG ? "MNG" : "AVI");
}
}
void video_manager::end_recording(movie_format format)
{
screen_device_iterator device_iterator = screen_device_iterator(machine().root_device());
screen_device_iterator::auto_iterator iter = device_iterator.begin();
const uint32_t count = (uint32_t)device_iterator.count();
switch (format)
{
case MF_AVI:
for (uint32_t index = 0; index < count; index++, iter++)
{
end_recording_avi(index);
if (!m_snap_native)
{
break;
}
}
break;
case MF_MNG:
for (uint32_t index = 0; index < count; index++, iter++)
{
end_recording_mng(index);
if (!m_snap_native)
{
break;
}
}
break;
default:
osd_printf_error("Unknown movie format: %d\n", format);
break;
}
}

View File

@ -59,7 +59,7 @@ public:
bool throttled() const { return m_throttled; }
float throttle_rate() const { return m_throttle_rate; }
bool fastforward() const { return m_fastforward; }
bool is_recording() const { return (m_mng_file || m_avi_file); }
bool is_recording() const;
// setters
void set_frameskip(int frameskip);
@ -70,8 +70,10 @@ public:
// misc
void toggle_throttle();
void toggle_record_movie();
osd_file::error open_next(emu_file &file, const char *extension);
void toggle_record_movie(movie_format format);
void toggle_record_mng() { toggle_record_movie(MF_MNG); }
void toggle_record_avi() { toggle_record_movie(MF_AVI); }
osd_file::error open_next(emu_file &file, const char *extension, uint32_t index = 0);
// render a frame
void frame_update(bool from_debugger = false);
@ -87,8 +89,13 @@ public:
// movies
void begin_recording(const char *name, movie_format format);
void begin_recording_mng(const char *name, uint32_t index, screen_device *screen);
void begin_recording_avi(const char *name, uint32_t index, screen_device *screen);
void end_recording(movie_format format);
void end_recording_mng(uint32_t index);
void end_recording_avi(uint32_t index);
void add_sound_to_recording(const s16 *sound, int numsamples);
void add_sound_to_avi_recording(const s16 *sound, int numsamples, uint32_t index);
void set_timecode_enabled(bool value) { m_timecode_enabled = value; }
bool get_timecode_enabled() { return m_timecode_enabled; }
@ -173,16 +180,37 @@ private:
s32 m_snap_height; // height of snapshots (0 == auto)
// movie recording - MNG
std::unique_ptr<emu_file> m_mng_file; // handle to the open movie file
attotime m_mng_frame_period; // period of a single movie frame
attotime m_mng_next_frame_time; // time of next frame
u32 m_mng_frame; // current movie frame number
class mng_info_t
{
public:
mng_info_t()
: m_mng_frame_period(attotime::zero)
, m_mng_next_frame_time(attotime::zero)
, m_mng_frame(0) { }
std::unique_ptr<emu_file> m_mng_file; // handle to the open movie file
attotime m_mng_frame_period; // period of a single movie frame
attotime m_mng_next_frame_time; // time of next frame
u32 m_mng_frame; // current movie frame number
};
mng_info_t m_mngs[9];
// movie recording - AVI
avi_file::ptr m_avi_file; // handle to the open movie file
attotime m_avi_frame_period; // period of a single movie frame
attotime m_avi_next_frame_time; // time of next frame
u32 m_avi_frame; // current movie frame number
class avi_info_t
{
public:
avi_info_t()
: m_avi_file(nullptr)
, m_avi_frame_period(attotime::zero)
, m_avi_next_frame_time(attotime::zero)
, m_avi_frame(0) { }
avi_file::ptr m_avi_file; // handle to the open movie file
attotime m_avi_frame_period; // period of a single movie frame
attotime m_avi_next_frame_time; // time of next frame
u32 m_avi_frame; // current movie frame number
};
avi_info_t m_avis[9];
static const bool s_skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS];

View File

@ -176,7 +176,7 @@ menu_cheat::~menu_cheat()
menu_autofire::menu_autofire(mame_ui_manager &mui, render_container &container) : menu(mui, container), last_toggle(false)
{
const screen_device *screen = mui.machine().first_screen();
const screen_device *screen = screen_device_iterator(mui.machine().root_device()).first();
if (screen == nullptr)
{

View File

@ -1213,9 +1213,13 @@ uint32_t mame_ui_manager::handler_ingame(render_container &container)
if (machine().ui_input().pressed(IPT_UI_TOGGLE_CHEAT))
mame_machine_manager::instance()->cheat().set_enable(!mame_machine_manager::instance()->cheat().enabled());
// toggle movie recording
if (machine().ui_input().pressed(IPT_UI_RECORD_MOVIE))
machine().video().toggle_record_movie();
// toggle MNG recording
if (machine().ui_input().pressed(IPT_UI_RECORD_MNG))
machine().video().toggle_record_mng();
// toggle MNG recording
if (machine().ui_input().pressed(IPT_UI_RECORD_AVI))
machine().video().toggle_record_avi();
// toggle profiler display
if (machine().ui_input().pressed(IPT_UI_SHOW_PROFILER))
@ -1676,9 +1680,10 @@ int32_t mame_ui_manager::slider_refresh(running_machine &machine, void *arg, int
const rectangle &visarea = screen->visible_area();
screen->configure(width, height, visarea, HZ_TO_ATTOSECONDS(defrefresh + (double)newval * 0.001));
}
if (str)
*str = string_format(_("%1$.3ffps"), ATTOSECONDS_TO_HZ(machine.first_screen()->frame_period().attoseconds()));
refresh = ATTOSECONDS_TO_HZ(machine.first_screen()->frame_period().attoseconds());
*str = string_format(_("%1$.3ffps"), ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds()));
refresh = ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds());
return floor((refresh - defrefresh) * 1000.0 + 0.5);
}

View File

@ -1320,7 +1320,11 @@ static void tilemap_update_bitmap(running_machine &machine, ui_gfx_state &state,
{
state.bitmap->fill(0);
tilemap_t *tilemap = machine.tilemap().find(state.tilemap.which);
tilemap->draw_debug(*machine.first_screen(), *state.bitmap, state.tilemap.xoffs, state.tilemap.yoffs, state.tilemap.flags);
screen_device *first_screen = screen_device_iterator(machine.root_device()).first();
if (first_screen)
{
tilemap->draw_debug(*first_screen, *state.bitmap, state.tilemap.xoffs, state.tilemap.yoffs, state.tilemap.flags);
}
// reset the texture to force an update
state.texture->set_bitmap(*state.bitmap, state.bitmap->cliprect(), TEXFORMAT_RGB32);

View File

@ -137,8 +137,13 @@ void windows_osd_interface::customize_input_type_list(simple_list<input_type_ent
break;
// add a NOT-lalt to our default shift-F12
case IPT_UI_RECORD_MOVIE: // emu/input.c: input_seq(KEYCODE_F12, KEYCODE_LSHIFT)
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
case IPT_UI_RECORD_MNG: // emu/input.c: input_seq(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LCONTROL)
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LALT);
break;
// add a NOT-lalt to our default shift-ctrl-F12
case IPT_UI_RECORD_AVI: // emu/input.c: input_seq(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LCONTROL)
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LALT);
break;
// add a NOT-lalt to write timecode file