Seperates out the notion of screen specific vs. "global" VBLANK callbacks

"Global" VBLANK callbacks, of course, make no conceptual sense -- it should probably fire every once in a while even if there is no screen
This commit is contained in:
Zsolt Vasvari 2008-03-07 08:18:28 +00:00
parent 5f53680e03
commit 9ad9532722
6 changed files with 97 additions and 77 deletions

View File

@ -968,27 +968,26 @@ static void cpu_inittimers(running_machine *machine)
/* VBLANK interrupts */
if (config->vblank_interrupts_per_frame > 0)
{
const char *screen_tag;
screen_state *screen;
const device_config *screen;
/* get the screen that will trigger the VBLANK */
/* new style - use screen tag directly */
if (config->vblank_interrupts_per_frame == 1)
screen_tag = config->vblank_interrupt_screen;
screen = device_list_find_by_tag(machine->config->devicelist, VIDEO_SCREEN, config->vblank_interrupt_screen);
/* old style 'hack' setup - use screen #0 */
else
{
const device_config *config = device_list_first(machine->config->devicelist, VIDEO_SCREEN);
screen_tag = config->tag;
screen = device_list_first(machine->config->devicelist, VIDEO_SCREEN);
/* allocate timer that will trigger the partial frame updates */
cpu[cpunum].partial_frame_timer = timer_alloc(trigger_partial_frame_interrupt, 0);
}
screen = devtag_get_token(machine, VIDEO_SCREEN, screen_tag);
video_screen_register_vbl_cb(machine, screen, on_vblank);
assert(screen != NULL);
video_screen_register_vbl_cb(screen, on_vblank);
}
/* periodic interrupts */

View File

@ -144,7 +144,7 @@ int mame_debug_is_active(void)
on_vblank - called when a VBLANK hits
-------------------------------------------------*/
static void on_vblank(const device_config *device, int vblank_state)
static void on_vblank(running_machine *machine, int vblank_state)
{
/* if we're configured to stop on VBLANK, break */
if (vblank_state && break_on_vblank)
@ -296,7 +296,7 @@ void debug_cpu_init(running_machine *machine)
}
/* add callback for breaking on VBLANK */
video_screen_register_vbl_cb(machine, NULL, on_vblank);
video_screen_register_global_vbl_cb(on_vblank);
add_exit_callback(machine, debug_cpu_exit);
}

View File

@ -1032,7 +1032,7 @@ static int default_ports_lookup[__ipt_max][MAX_PLAYERS];
FUNCTION PROTOTYPES
***************************************************************************/
static void on_vblank(const device_config *device, int vblank_state);
static void on_vblank(running_machine *machine, int vblank_state);
static void setup_playback(running_machine *machine);
static void setup_record(running_machine *machine);
static void input_port_exit(running_machine *machine);
@ -1142,7 +1142,7 @@ void input_port_init(running_machine *machine, const input_port_token *ipt)
void input_port_post_init(running_machine *machine)
{
/* set up callback for updating the ports */
video_screen_register_vbl_cb(machine, NULL, on_vblank);
video_screen_register_global_vbl_cb(on_vblank);
}
@ -1153,11 +1153,11 @@ void input_port_post_init(running_machine *machine)
*
*************************************/
static void on_vblank(const device_config *device, int vblank_state)
static void on_vblank(running_machine *machine, int vblank_state)
{
/* VBLANK starting - read keyboard & update the status of the input ports */
if (vblank_state)
input_port_vblank_start(device->machine);
input_port_vblank_start(machine);
/* VBLANK ending - update IPT_VBLANK input ports */
else

View File

@ -73,7 +73,6 @@ struct _internal_screen_state
UINT64 frame_number; /* the current frame number */
/* screen specific VBLANK callbacks */
int vbl_cb_count;
vblank_state_changed_func vbl_cbs[MAX_VBL_CB]; /* the array of callbacks */
/* movie recording */
@ -132,6 +131,9 @@ struct _video_global
UINT8 crosshair_animate; /* animation frame index */
UINT8 crosshair_visible; /* crosshair visible mask */
UINT8 crosshair_needed; /* crosshair needed mask */
/* global VBLANK callbacks */
vblank_state_changed_global_func vbl_cbs[MAX_VBL_CB]; /* the array of callbacks */
};
@ -218,7 +220,7 @@ INLINE screen_state *get_safe_token(const device_config *device)
{
assert(device != NULL);
assert(device->token != NULL);
assert(device->type == DEVICE_GET_INFO_NAME(video_screen));
assert(device->type == VIDEO_SCREEN);
return (screen_state *)device->token;
}
@ -1103,53 +1105,64 @@ UINT64 video_screen_get_frame_number(int scrnum)
VBLANK callback for a specific screen
-------------------------------------------------*/
void video_screen_register_vbl_cb(running_machine *machine, void *screen, vblank_state_changed_func vbl_cb)
void video_screen_register_vbl_cb(const device_config *screen, vblank_state_changed_func vbl_cb)
{
int i, found;
internal_screen_state *internal_state = NULL;
screen_state *state = get_safe_token(screen);
internal_screen_state *internal_state = (internal_screen_state *)state->private_data;
/* validate arguments */
assert(machine != NULL);
assert(machine->config != NULL);
assert(machine->config->devicelist != NULL);
assert(vbl_cb != NULL);
/* if the screen is NULL, grab the first screen -- we are installing a "global" handler */
if (screen == NULL)
{
if (video_screen_count(machine->config) > 0)
{
const char *screen_tag = video_screen_first(machine->config)->tag;
screen = devtag_get_token(machine, VIDEO_SCREEN, screen_tag);
}
else
{
/* we need to do something for screenless games */
assert(screen != NULL);
}
}
/* find the screen info structure for the given token - there should only be one */
for (i = 0; i < MAX_SCREENS; i++)
if (machine->screen[i].private_data == ((screen_state *)screen)->private_data)
internal_state = get_internal_state(machine, i);
/* make sure we still have room for the callback */
assert(internal_state != NULL);
assert(internal_state->vbl_cb_count != MAX_VBL_CB);
/* check if we already have this callback registered */
found = FALSE;
for (i = 0; i < internal_state->vbl_cb_count; i++)
for (i = 0; i < MAX_VBL_CB; i++)
{
if (internal_state->vbl_cbs[i] == NULL)
break;
if (internal_state->vbl_cbs[i] == vbl_cb)
found = TRUE;
}
/* check that there is room */
assert(i != MAX_VBL_CB);
/* if not found, register and increment count */
if (!found)
internal_state->vbl_cbs[i] = vbl_cb;
}
/*-------------------------------------------------
video_screen_register_global_vbl_cb - registers a
VBLANK callback for a specific screen
-------------------------------------------------*/
void video_screen_register_global_vbl_cb(vblank_state_changed_global_func vbl_cb)
{
int i, found;
/* validate arguments */
assert(vbl_cb != NULL);
/* check if we already have this callback registered */
found = FALSE;
for (i = 0; i < MAX_VBL_CB; i++)
{
internal_state->vbl_cbs[internal_state->vbl_cb_count] = vbl_cb;
internal_state->vbl_cb_count++;
if (global.vbl_cbs[i] == NULL)
break;
if (global.vbl_cbs[i] == vbl_cb)
found = TRUE;
}
/* check that there is room */
assert(i != MAX_VBL_CB);
/* if not found, register and increment count */
if (!found)
global.vbl_cbs[i] = vbl_cb;
}
@ -1218,23 +1231,6 @@ DEVICE_GET_INFO( video_screen )
GLOBAL RENDERING
***************************************************************************/
/*-------------------------------------------------
call_vb_callbacks - call any external VBLANK
callsbacks with the given state
-------------------------------------------------*/
static void call_vb_callbacks(internal_screen_state *scrinfo, int vblank_state)
{
int i;
/* set it in the state structure */
scrinfo->vblank_state = vblank_state;
for (i = 0; scrinfo->vbl_cbs[i] != NULL; i++)
scrinfo->vbl_cbs[i](scrinfo->device, vblank_state);
}
/*-------------------------------------------------
vblank_begin_callback - call any external
callbacks to signal the VBLANK period has begun
@ -1242,6 +1238,7 @@ static void call_vb_callbacks(internal_screen_state *scrinfo, int vblank_state)
static TIMER_CALLBACK( vblank_begin_callback )
{
int i;
attoseconds_t vblank_period;
screen_state *state = ptr;
internal_screen_state *internal_state = (internal_screen_state *)state->private_data;
@ -1249,8 +1246,17 @@ static TIMER_CALLBACK( vblank_begin_callback )
/* reset the starting VBLANK time */
internal_state->vblank_time = timer_get_time();
/* call the external callbacks */
call_vb_callbacks(internal_state, TRUE);
/* mark as being in VBLANK */
internal_state->vblank_state = TRUE;
/* call the screen specific callbacks */
for (i = 0; internal_state->vbl_cbs[i] != NULL; i++)
internal_state->vbl_cbs[i](internal_state->device, TRUE);
/* for the first screen, call the global callbacks */
if (internal_state->scrnum == 0)
for (i = 0; global.vbl_cbs[i] != NULL; i++)
global.vbl_cbs[i](machine, TRUE);
/* do we update the screen now? - only do it for the first screen */
if (!(machine->config->video_attributes & VIDEO_UPDATE_AFTER_VBLANK) && (internal_state->scrnum == 0))
@ -1276,14 +1282,24 @@ static TIMER_CALLBACK( vblank_begin_callback )
static TIMER_CALLBACK( vblank_end_callback )
{
int i;
internal_screen_state *internal_state = ptr;
/* update the first screen if we didn't before */
if ((machine->config->video_attributes & VIDEO_UPDATE_AFTER_VBLANK) && (internal_state->scrnum == 0))
video_frame_update(machine, FALSE);
/* let any external parties know that the VBLANK is over */
call_vb_callbacks(internal_state, FALSE);
/* mark as not being in VBLANK */
internal_state->vblank_state = FALSE;
/* call the screen specific callbacks */
for (i = 0; internal_state->vbl_cbs[i] != NULL; i++)
internal_state->vbl_cbs[i](internal_state->device, FALSE);
/* for the first screen, call the global callbacks */
if (internal_state->scrnum == 0)
for (i = 0; global.vbl_cbs[i] != NULL; i++)
global.vbl_cbs[i](machine, FALSE);
/* increment the frame number counter */
internal_state->frame_number++;

View File

@ -90,12 +90,14 @@ struct _screen_config
/*-------------------------------------------------
vblank_state_changed_func - callback that a
screen calls to notify of a change of
the VBLANK state
vblank_state_changed_func
vblank_state_changed_global_func -
callback that is called to notify of a change
in the VBLANK state
-------------------------------------------------*/
typedef void (*vblank_state_changed_func)(const device_config *device, int vblank_state);
typedef void (*vblank_state_changed_global_func)(running_machine *machine, int vblank_state);
@ -155,8 +157,11 @@ UINT64 video_screen_get_frame_number(int scrnum);
/* returns whether a given screen exists */
int video_screen_exists(int scrnum);
/* registers a VBLANK callback for the given screen*/
void video_screen_register_vbl_cb(running_machine *machine, void *screen, vblank_state_changed_func vbl_cb);
/* registers a VBLANK callback for the given screen */
void video_screen_register_vbl_cb(const device_config *screen, vblank_state_changed_func vbl_cb);
/* registers a VBLANK callback independent of a screen */
void video_screen_register_global_vbl_cb(vblank_state_changed_global_func vbl_cb);
/* ----- video screen device interface ----- */

View File

@ -83,18 +83,18 @@ static TIMER_CALLBACK( watchdog_callback )
timers
-------------------------------------------------*/
static void on_vblank(const device_config *device, int vblank_state)
static void on_vblank(running_machine *machine, int vblank_state)
{
/* VBLANK starting */
if (vblank_state && watchdog_enabled)
{
/* check the watchdog */
if (device->machine->config->watchdog_vblank_count != 0)
if (machine->config->watchdog_vblank_count != 0)
{
watchdog_counter = watchdog_counter - 1;
if (watchdog_counter == 0)
watchdog_callback(device->machine, NULL, 0);
watchdog_callback(machine, NULL, 0);
}
}
}
@ -116,7 +116,7 @@ void watchdog_reset(running_machine *machine)
watchdog_counter = machine->config->watchdog_vblank_count;
/* register a global VBLANK callback */
video_screen_register_vbl_cb(machine, NULL, on_vblank);
video_screen_register_global_vbl_cb(on_vblank);
}
/* timer-based watchdog? */