summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/video.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/video.c')
-rw-r--r--src/emu/video.c355
1 files changed, 221 insertions, 134 deletions
diff --git a/src/emu/video.c b/src/emu/video.c
index 5beb54bb571..7aa855d14d9 100644
--- a/src/emu/video.c
+++ b/src/emu/video.c
@@ -38,7 +38,8 @@
#define SUBSECONDS_PER_SPEED_UPDATE (ATTOSECONDS_PER_SECOND / 4)
#define PAUSED_REFRESH_RATE (30)
#define MAX_VBLANK_CALLBACKS (10)
-#define DEFAULT_FRAME_PERIOD ATTOTIME_IN_HZ(60)
+#define DEFAULT_FRAME_RATE 60
+#define DEFAULT_FRAME_PERIOD ATTOTIME_IN_HZ(DEFAULT_FRAME_RATE)
@@ -78,11 +79,6 @@ struct _screen_state
/* screen specific VBLANK callbacks */
vblank_state_changed_func vblank_callback[MAX_VBLANK_CALLBACKS]; /* the array of callbacks */
-
- /* movie recording */
- mame_file * mng_file; /* handle to the open movie file */
- avi_file * avi_file; /* handle to the open movie file */
- UINT32 movie_frame; /* current movie frame number */
};
@@ -128,6 +124,16 @@ struct _video_global
/* snapshot stuff */
render_target * snap_target; /* screen shapshot target */
bitmap_t * snap_bitmap; /* screen snapshot bitmap */
+ UINT8 snap_native; /* are we using native per-screen layouts? */
+ INT32 snap_width; /* width of snapshots (0 == auto) */
+ INT32 snap_height; /* height of snapshots (0 == auto) */
+
+ /* movie recording */
+ mame_file * mng_file; /* handle to the open movie file */
+ avi_file * avi_file; /* handle to the open movie file */
+ attotime movie_frame_period; /* period of a single movie frame */
+ attotime movie_next_frame_time; /* time of next frame */
+ UINT32 movie_frame; /* current movie frame number */
};
@@ -190,8 +196,8 @@ static void create_snapshot_bitmap(const device_config *screen);
static file_error mame_fopen_next(running_machine *machine, const char *pathoption, const char *extension, mame_file **file);
/* movie recording */
-static void video_mng_record_frame(const device_config *screen);
-static void video_avi_record_frame(const device_config *screen);
+static void video_mng_record_frame(running_machine *machine);
+static void video_avi_record_frame(running_machine *machine);
/* software rendering */
static void rgb888_draw_primitives(const render_primitive *primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);
@@ -295,6 +301,7 @@ INLINE int original_speed_setting(void)
void video_init(running_machine *machine)
{
const char *filename;
+ const char *viewname;
/* validate */
assert(machine != NULL);
@@ -339,21 +346,51 @@ void video_init(running_machine *machine)
pdrawgfx_shadow_lowpri = 0;
/* create a render target for snapshots */
- if (machine->primary_screen != NULL)
- {
+ viewname = options_get_string(mame_options(), OPTION_SNAPVIEW);
+ global.snap_native = (machine->primary_screen != NULL && (viewname[0] == 0 || strcmp(viewname, "native") == 0));
+ if (global.snap_native)
global.snap_target = render_target_alloc(layout_snap, RENDER_CREATE_SINGLE_FILE | RENDER_CREATE_HIDDEN);
- assert(global.snap_target != NULL);
+ else
+ global.snap_target = render_target_alloc(NULL, RENDER_CREATE_HIDDEN);
+ assert(global.snap_target != NULL);
+
+ /* if we are using the native layout, turn off all accoutrements */
+ if (global.snap_native)
render_target_set_layer_config(global.snap_target, 0);
+
+ /* otherwise, find the requested view and select it */
+ else
+ {
+ int viewindex;
+
+ /* scan for a match or partial match */
+ for (viewindex = 0; ; viewindex++)
+ {
+ const char *name = render_target_get_view_name(global.snap_target, viewindex);
+
+ /* stop scanning when we hit NULL */
+ if (name == NULL)
+ break;
+ if (mame_strnicmp(name, viewname, strlen(viewname)) == 0)
+ {
+ render_target_set_view(global.snap_target, viewindex);
+ break;
+ }
+ }
}
+
+ /* extract snap resolution if present */
+ if (sscanf(options_get_string(mame_options(), OPTION_SNAPSIZE), "%dx%d", &global.snap_width, &global.snap_height) != 2)
+ global.snap_width = global.snap_height = 0;
/* start recording movie if specified */
filename = options_get_string(mame_options(), OPTION_MNGWRITE);
- if (filename[0] != 0 && machine->primary_screen != NULL)
- video_mng_begin_recording(machine->primary_screen, filename);
+ if (filename[0] != 0)
+ video_mng_begin_recording(machine, filename);
filename = options_get_string(mame_options(), OPTION_AVIWRITE);
- if (filename[0] != 0 && machine->primary_screen != NULL)
- video_avi_begin_recording(machine->primary_screen, filename);
+ if (filename[0] != 0)
+ video_avi_begin_recording(machine, filename);
/* if no screens, create a periodic timer to drive updates */
if (machine->primary_screen == NULL)
@@ -379,8 +416,8 @@ static void video_exit(running_machine *machine)
/* stop recording any movie */
if (machine->primary_screen != NULL)
{
- video_mng_end_recording(machine->primary_screen);
- video_avi_end_recording(machine->primary_screen);
+ video_mng_end_recording(machine);
+ video_avi_end_recording(machine);
}
/* free all the graphics elements */
@@ -1515,13 +1552,6 @@ static int finish_screen_updates(running_machine *machine)
render_container_empty(render_container_get_screen(screen));
render_screen_add_quad(screen, 0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), state->texture[state->curtexture], PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1));
}
-
- /* update our movie recording state */
- if (!mame_is_paused(machine))
- {
- video_mng_record_frame(screen);
- video_avi_record_frame(screen);
- }
}
/* reset the screen changed flags */
@@ -1530,6 +1560,13 @@ static int finish_screen_updates(running_machine *machine)
state->changed = FALSE;
}
+ /* update our movie recording state */
+ if (!mame_is_paused(machine))
+ {
+ video_mng_record_frame(machine);
+ video_avi_record_frame(machine);
+ }
+
/* draw any crosshairs */
for (screen = video_screen_first(machine->config); screen != NULL; screen = video_screen_next(screen))
crosshair_render(screen);
@@ -2089,7 +2126,7 @@ static void recompute_speed(running_machine *machine, attotime emutime)
filerr = mame_fopen(SEARCHPATH_SCREENSHOT, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
if (filerr == FILERR_NONE)
{
- video_screen_save_snapshot(machine->primary_screen, file);
+ video_screen_save_snapshot(machine, machine->primary_screen, file);
mame_fclose(file);
}
astring_free(fname);
@@ -2111,15 +2148,15 @@ static void recompute_speed(running_machine *machine, attotime emutime)
to the given file handle
-------------------------------------------------*/
-void video_screen_save_snapshot(const device_config *screen, mame_file *fp)
+void video_screen_save_snapshot(running_machine *machine, const device_config *screen, mame_file *fp)
{
- const rgb_t *palette;
png_info pnginfo = { 0 };
+ const rgb_t *palette;
png_error error;
char text[256];
/* validate */
- assert(screen != NULL);
+ assert(!global.snap_native || screen != NULL);
assert(fp != NULL);
/* create the bitmap to pass in */
@@ -2128,12 +2165,12 @@ void video_screen_save_snapshot(const device_config *screen, mame_file *fp)
/* add two text entries describing the image */
sprintf(text, APPNAME " %s", build_version);
png_add_text(&pnginfo, "Software", text);
- sprintf(text, "%s %s", screen->machine->gamedrv->manufacturer, screen->machine->gamedrv->description);
+ sprintf(text, "%s %s", machine->gamedrv->manufacturer, machine->gamedrv->description);
png_add_text(&pnginfo, "System", text);
/* now do the actual work */
- palette = (screen->machine->palette != NULL) ? palette_entry_list_adjusted(screen->machine->palette) : NULL;
- error = png_write_bitmap(mame_core_file(fp), &pnginfo, global.snap_bitmap, screen->machine->config->total_colors, palette);
+ palette = (machine->palette != NULL) ? palette_entry_list_adjusted(machine->palette) : NULL;
+ error = png_write_bitmap(mame_core_file(fp), &pnginfo, global.snap_bitmap, machine->config->total_colors, palette);
/* free any data allocated */
png_free(&pnginfo);
@@ -2153,18 +2190,33 @@ void video_save_active_screen_snapshots(running_machine *machine)
/* validate */
assert(machine != NULL);
assert(machine->config != NULL);
-
- /* write one snapshot per visible screen */
- for (screen = video_screen_first(machine->config); screen != NULL; screen = video_screen_next(screen))
- if (render_is_live_screen(screen))
- {
- file_error filerr = mame_fopen_next(machine, SEARCHPATH_SCREENSHOT, "png", &fp);
- if (filerr == FILERR_NONE)
+
+ /* if we're native, then write one snapshot per visible screen */
+ if (global.snap_native)
+ {
+ /* write one snapshot per visible screen */
+ for (screen = video_screen_first(machine->config); screen != NULL; screen = video_screen_next(screen))
+ if (render_is_live_screen(screen))
{
- video_screen_save_snapshot(screen, fp);
- mame_fclose(fp);
+ file_error filerr = mame_fopen_next(machine, SEARCHPATH_SCREENSHOT, "png", &fp);
+ if (filerr == FILERR_NONE)
+ {
+ video_screen_save_snapshot(machine, screen, fp);
+ mame_fclose(fp);
+ }
}
+ }
+
+ /* otherwise, just write a single snapshot */
+ else
+ {
+ file_error filerr = mame_fopen_next(machine, SEARCHPATH_SCREENSHOT, "png", &fp);
+ if (filerr == FILERR_NONE)
+ {
+ video_screen_save_snapshot(machine, NULL, fp);
+ mame_fclose(fp);
}
+ }
}
@@ -2181,12 +2233,18 @@ static void create_snapshot_bitmap(const device_config *screen)
int view_index;
/* select the appropriate view in our dummy target */
- view_index = device_list_index(screen->machine->config->devicelist, VIDEO_SCREEN, screen->tag);
- assert(view_index != -1);
- render_target_set_view(global.snap_target, view_index);
+ if (global.snap_native && screen != NULL)
+ {
+ view_index = device_list_index(screen->machine->config->devicelist, VIDEO_SCREEN, screen->tag);
+ assert(view_index != -1);
+ render_target_set_view(global.snap_target, view_index);
+ }
/* get the minimum width/height and set it on the target */
- render_target_get_minimum_size(global.snap_target, &width, &height);
+ width = global.snap_width;
+ height = global.snap_height;
+ if (width == 0 || height == 0)
+ render_target_get_minimum_size(global.snap_target, &width, &height);
render_target_set_bounds(global.snap_target, width, height, 0);
/* if we don't have a bitmap, or if it's not the right size, allocate a new one */
@@ -2285,10 +2343,9 @@ static file_error mame_fopen_next(running_machine *machine, const char *pathopti
MNG movie is currently being recorded
-------------------------------------------------*/
-int video_mng_is_movie_active(const device_config *screen)
+int video_mng_is_movie_active(running_machine *machine)
{
- screen_state *state = get_safe_token(screen);
- return (state->mng_file != NULL);
+ return (global.mng_file != NULL);
}
@@ -2297,21 +2354,43 @@ int video_mng_is_movie_active(const device_config *screen)
of a MNG movie
-------------------------------------------------*/
-void video_mng_begin_recording(const device_config *screen, const char *name)
+void video_mng_begin_recording(running_machine *machine, const char *name)
{
- screen_state *state = get_safe_token(screen);
+ screen_state *state = NULL;
file_error filerr;
+ png_error pngerr;
+ int rate;
/* close any existing movie file */
- if (state->mng_file != NULL)
- video_mng_end_recording(screen);
+ if (global.mng_file != NULL)
+ video_mng_end_recording(machine);
+
+ /* look up the primary screen */
+ if (machine->primary_screen != NULL)
+ state = get_safe_token(machine->primary_screen);
+
+ /* create a snapshot bitmap so we know what the target size is */
+ create_snapshot_bitmap(NULL);
/* create a new movie file and start recording */
if (name != NULL)
- filerr = mame_fopen(SEARCHPATH_MOVIE, name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &state->mng_file);
+ filerr = mame_fopen(SEARCHPATH_MOVIE, name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &global.mng_file);
else
- filerr = mame_fopen_next(screen->machine, SEARCHPATH_MOVIE, "mng", &state->mng_file);
- state->movie_frame = 0;
+ filerr = mame_fopen_next(machine, SEARCHPATH_MOVIE, "mng", &global.mng_file);
+
+ /* start the capture */
+ rate = (state != NULL) ? ATTOSECONDS_TO_HZ(state->frame_period) : DEFAULT_FRAME_RATE;
+ pngerr = mng_capture_start(mame_core_file(global.mng_file), global.snap_bitmap, rate);
+ if (pngerr != PNGERR_NONE)
+ {
+ video_mng_end_recording(machine);
+ return;
+ }
+
+ /* compute the frame time */
+ global.movie_next_frame_time = timer_get_time();
+ global.movie_frame_period = ATTOTIME_IN_HZ(rate);
+ global.movie_frame = 0;
}
@@ -2320,17 +2399,15 @@ void video_mng_begin_recording(const device_config *screen, const char *name)
a MNG movie
-------------------------------------------------*/
-void video_mng_end_recording(const device_config *screen)
+void video_mng_end_recording(running_machine *machine)
{
- screen_state *state = get_safe_token(screen);
-
/* close the file if it exists */
- if (state->mng_file != NULL)
+ if (global.mng_file != NULL)
{
- mng_capture_stop(mame_core_file(state->mng_file));
- mame_fclose(state->mng_file);
- state->mng_file = NULL;
- state->movie_frame = 0;
+ mng_capture_stop(mame_core_file(global.mng_file));
+ mame_fclose(global.mng_file);
+ global.mng_file = NULL;
+ global.movie_frame = 0;
}
}
@@ -2340,49 +2417,50 @@ void video_mng_end_recording(const device_config *screen)
movie
-------------------------------------------------*/
-static void video_mng_record_frame(const device_config *screen)
+static void video_mng_record_frame(running_machine *machine)
{
- screen_state *state = get_safe_token(screen);
- const rgb_t *palette;
-
/* only record if we have a file */
- if (state->mng_file != NULL)
+ if (global.mng_file != NULL)
{
+ attotime curtime = timer_get_time();
png_info pnginfo = { 0 };
png_error error;
profiler_mark(PROFILER_MOVIE_REC);
/* create the bitmap */
- create_snapshot_bitmap(screen);
+ create_snapshot_bitmap(NULL);
- /* track frames */
- if (state->movie_frame++ == 0)
+ /* loop until we hit the right time */
+ while (attotime_compare(global.movie_next_frame_time, curtime) <= 0)
{
- char text[256];
+ const rgb_t *palette;
/* set up the text fields in the movie info */
- sprintf(text, APPNAME " %s", build_version);
- png_add_text(&pnginfo, "Software", text);
- sprintf(text, "%s %s", screen->machine->gamedrv->manufacturer, screen->machine->gamedrv->description);
- png_add_text(&pnginfo, "System", text);
+ if (global.movie_frame == 0)
+ {
+ char text[256];
- /* start the capture */
- error = mng_capture_start(mame_core_file(state->mng_file), global.snap_bitmap, ATTOSECONDS_TO_HZ(state->frame_period));
+ sprintf(text, APPNAME " %s", build_version);
+ png_add_text(&pnginfo, "Software", text);
+ sprintf(text, "%s %s", machine->gamedrv->manufacturer, machine->gamedrv->description);
+ png_add_text(&pnginfo, "System", text);
+ }
+
+ /* write the next frame */
+ palette = (machine->palette != NULL) ? palette_entry_list_adjusted(machine->palette) : NULL;
+ error = mng_capture_frame(mame_core_file(global.mng_file), &pnginfo, global.snap_bitmap, machine->config->total_colors, palette);
+ png_free(&pnginfo);
if (error != PNGERR_NONE)
{
- png_free(&pnginfo);
- video_mng_end_recording(screen);
- return;
+ video_mng_end_recording(machine);
+ break;
}
- }
- /* write the next frame */
- palette = (screen->machine->palette != NULL) ? palette_entry_list_adjusted(screen->machine->palette) : NULL;
- error = mng_capture_frame(mame_core_file(state->mng_file), &pnginfo, global.snap_bitmap, screen->machine->config->total_colors, palette);
- png_free(&pnginfo);
- if (error != PNGERR_NONE)
- video_mng_end_recording(screen);
+ /* advance time */
+ global.movie_next_frame_time = attotime_add(global.movie_next_frame_time, global.movie_frame_period);
+ global.movie_frame++;
+ }
profiler_mark(PROFILER_END);
}
@@ -2399,24 +2477,28 @@ static void video_mng_record_frame(const device_config *screen)
of an AVI movie
-------------------------------------------------*/
-void video_avi_begin_recording(const device_config *screen, const char *name)
+void video_avi_begin_recording(running_machine *machine, const char *name)
{
- screen_state *state = get_safe_token(screen);
+ screen_state *state = NULL;
avi_movie_info info;
mame_file *tempfile;
file_error filerr;
avi_error avierr;
/* close any existing movie file */
- if (state->avi_file != NULL)
- video_avi_end_recording(screen);
+ if (global.avi_file != NULL)
+ video_avi_end_recording(machine);
+
+ /* look up the primary screen */
+ if (machine->primary_screen != NULL)
+ state = get_safe_token(machine->primary_screen);
/* create a snapshot bitmap so we know what the target size is */
- create_snapshot_bitmap(screen);
+ create_snapshot_bitmap(NULL);
/* build up information about this new movie */
info.video_format = 0;
- info.video_timescale = 1000 * ATTOSECONDS_TO_HZ(state->frame_period);
+ info.video_timescale = 1000 * ((state != NULL) ? ATTOSECONDS_TO_HZ(state->frame_period) : DEFAULT_FRAME_RATE);
info.video_sampletime = 1000;
info.video_numsamples = 0;
info.video_width = global.snap_bitmap->width;
@@ -2425,18 +2507,22 @@ void video_avi_begin_recording(const device_config *screen, const char *name)
info.audio_format = 0;
info.audio_timescale = 1;
- info.audio_sampletime = screen->machine->sample_rate;
+ info.audio_sampletime = machine->sample_rate;
info.audio_numsamples = 0;
info.audio_channels = 2;
info.audio_samplebits = 16;
- info.audio_samplerate = screen->machine->sample_rate;
+ info.audio_samplerate = machine->sample_rate;
/* create a new temporary movie file */
if (name != NULL)
filerr = mame_fopen(SEARCHPATH_MOVIE, name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &tempfile);
else
- filerr = mame_fopen_next(screen->machine, SEARCHPATH_MOVIE, "avi", &tempfile);
- state->movie_frame = 0;
+ filerr = mame_fopen_next(machine, SEARCHPATH_MOVIE, "avi", &tempfile);
+
+ /* reset our tracking */
+ global.movie_frame = 0;
+ global.movie_next_frame_time = timer_get_time();
+ global.movie_frame_period = attotime_div(ATTOTIME_IN_SEC(1000), info.video_timescale);
/* if we succeeded, make a copy of the name and create the real file over top */
if (filerr == FILERR_NONE)
@@ -2445,7 +2531,7 @@ void video_avi_begin_recording(const device_config *screen, const char *name)
mame_fclose(tempfile);
/* create the file and free the string */
- avierr = avi_create(astring_c(fullname), &info, &state->avi_file);
+ avierr = avi_create(astring_c(fullname), &info, &global.avi_file);
astring_free(fullname);
}
}
@@ -2456,16 +2542,14 @@ void video_avi_begin_recording(const device_config *screen, const char *name)
a avi movie
-------------------------------------------------*/
-void video_avi_end_recording(const device_config *screen)
+void video_avi_end_recording(running_machine *machine)
{
- screen_state *state = get_safe_token(screen);
-
/* close the file if it exists */
- if (state->avi_file != NULL)
+ if (global.avi_file != NULL)
{
- avi_close(state->avi_file);
- state->avi_file = NULL;
- state->movie_frame = 0;
+ avi_close(global.avi_file);
+ global.avi_file = NULL;
+ global.movie_frame = 0;
}
}
@@ -2475,24 +2559,34 @@ void video_avi_end_recording(const device_config *screen)
movie
-------------------------------------------------*/
-static void video_avi_record_frame(const device_config *screen)
+static void video_avi_record_frame(running_machine *machine)
{
- screen_state *state = get_safe_token(screen);
-
/* only record if we have a file */
- if (state->avi_file != NULL)
+ if (global.avi_file != NULL)
{
+ attotime curtime = timer_get_time();
avi_error avierr;
profiler_mark(PROFILER_MOVIE_REC);
-
+
/* create the bitmap */
- create_snapshot_bitmap(screen);
+ create_snapshot_bitmap(NULL);
- /* write the next frame */
- avierr = avi_append_video_frame_rgb32(state->avi_file, global.snap_bitmap);
- if (avierr != AVIERR_NONE)
- video_avi_end_recording(screen);
+ /* loop until we hit the right time */
+ while (attotime_compare(global.movie_next_frame_time, curtime) <= 0)
+ {
+ /* write the next frame */
+ avierr = avi_append_video_frame_rgb32(global.avi_file, global.snap_bitmap);
+ if (avierr != AVIERR_NONE)
+ {
+ video_avi_end_recording(machine);
+ break;
+ }
+
+ /* advance time */
+ global.movie_next_frame_time = attotime_add(global.movie_next_frame_time, global.movie_frame_period);
+ global.movie_frame++;
+ }
profiler_mark(PROFILER_END);
}
@@ -2506,29 +2600,21 @@ static void video_avi_record_frame(const device_config *screen)
void video_avi_add_sound(running_machine *machine, const INT16 *sound, int numsamples)
{
- const device_config *screen;
-
- /* loop over screens that might be recording */
- for (screen = video_screen_first(machine->config); screen != NULL; screen = video_screen_next(screen))
+ /* only record if we have a file */
+ if (global.avi_file != NULL)
{
- screen_state *state = get_safe_token(screen);
-
- /* only record if we have a file */
- if (state->avi_file != NULL)
- {
- avi_error avierr;
+ avi_error avierr;
- profiler_mark(PROFILER_MOVIE_REC);
+ profiler_mark(PROFILER_MOVIE_REC);
- /* write the next frame */
- avierr = avi_append_sound_samples(state->avi_file, 0, sound + 0, numsamples, 1);
- if (avierr == AVIERR_NONE)
- avierr = avi_append_sound_samples(state->avi_file, 1, sound + 1, numsamples, 1);
- if (avierr != AVIERR_NONE)
- video_avi_end_recording(screen);
+ /* write the next frame */
+ avierr = avi_append_sound_samples(global.avi_file, 0, sound + 0, numsamples, 1);
+ if (avierr == AVIERR_NONE)
+ avierr = avi_append_sound_samples(global.avi_file, 1, sound + 1, numsamples, 1);
+ if (avierr != AVIERR_NONE)
+ video_avi_end_recording(machine);
- profiler_mark(PROFILER_END);
- }
+ profiler_mark(PROFILER_END);
}
}
@@ -2546,5 +2632,6 @@ void video_avi_add_sound(running_machine *machine, const INT16 *sound, int numsa
#define DSTSHIFT_R 16
#define DSTSHIFT_G 8
#define DSTSHIFT_B 0
+#define BILINEAR_FILTER 1
#include "rendersw.c"