mirror of
https://github.com/holub/mame
synced 2025-07-05 09:57:47 +03:00
- Moves all video timing logic from cpuexec.c to video.c
- Added a video_screen_register_vbl_cb() function for registering VBLANK callbanks - Changed inptport.c and debugcpu.c to make use the VBLANK callbacks - Added video_screen_get_time_until_vblank_start() - CCPU and anything using cpu_scalebyfcount() are currently broken - I did some fairly extensive testing, but this is a very signficant internal change, so some things may have broke
This commit is contained in:
parent
e90a92697c
commit
7198a00e65
@ -549,13 +549,13 @@ static int ccpu_execute(int cycles)
|
||||
remove section in brackets and uncomment line below.
|
||||
Speed Freak should run nice and smooth, with no flickering. */
|
||||
{
|
||||
attotime scantime, abstime;
|
||||
extern emu_timer *refresh_timer;
|
||||
scantime = timer_starttime(refresh_timer);
|
||||
abstime = timer_get_time();
|
||||
while (attotime_compare(abstime, scantime) >= 0)
|
||||
scantime = attotime_add(scantime, video_screen_get_frame_period(ccpu.scrnum));
|
||||
cpu_spinuntil_time(attotime_sub(scantime, abstime));
|
||||
// attotime scantime, abstime;
|
||||
// extern emu_timer *refresh_timer;
|
||||
// scantime = timer_starttime(refresh_timer);
|
||||
// abstime = timer_get_time();
|
||||
// while (attotime_compare(abstime, scantime) >= 0)
|
||||
// scantime = attotime_add(scantime, video_screen_get_frame_period(ccpu.scrnum));
|
||||
// cpu_spinuntil_time(attotime_sub(scantime, abstime));
|
||||
}
|
||||
/* cpu_spinuntil_time(video_screen_get_time_until_pos(ccpu.scrnum, Machine->screen[ccpu.scrnum].visarea.max_y + 1, 0)); */
|
||||
NEXT_ACC_A(); CYCLES(1);
|
||||
|
@ -77,18 +77,17 @@ struct _cpuexec_data
|
||||
UINT8 nexteatcycles; /* pending value */
|
||||
INT32 trigger; /* pending trigger to release a trigger suspension */
|
||||
|
||||
INT32 iloops; /* number of interrupts remaining this frame */
|
||||
|
||||
UINT64 totalcycles; /* total CPU cycles executed */
|
||||
attotime localtime; /* local time, relative to the timer system's global time */
|
||||
INT32 clock; /* current active clock */
|
||||
double clockscale; /* current active clock scale factor */
|
||||
|
||||
INT32 vblankint_countdown; /* number of vblank callbacks left until we interrupt */
|
||||
INT32 vblankint_multiplier; /* number of vblank callbacks per interrupt */
|
||||
emu_timer * vblankint_timer; /* reference to elapsed time counter */
|
||||
|
||||
emu_timer * timedint_timer; /* reference to this CPU's periodic interrupt timer */
|
||||
|
||||
/* these below are hacks to support multiple interrupts per frame */
|
||||
INT32 iloops; /* number of interrupts remaining this frame */
|
||||
emu_timer * partial_frame_timer; /* the timer that triggers partial frame interrupts */
|
||||
attotime partial_frame_period; /* the length of one partial frame for interrupt purposes */
|
||||
};
|
||||
|
||||
|
||||
@ -100,7 +99,6 @@ struct _cpuexec_data
|
||||
/* general CPU variables */
|
||||
static cpuexec_data cpu[MAX_CPU];
|
||||
|
||||
static UINT8 vblank;
|
||||
static UINT32 current_frame;
|
||||
|
||||
static int cycles_running;
|
||||
@ -108,16 +106,6 @@ static int cycles_stolen;
|
||||
|
||||
|
||||
/* timer variables */
|
||||
static emu_timer *vblank_timer;
|
||||
static INT32 vblank_countdown;
|
||||
static INT32 vblank_multiplier;
|
||||
static attotime vblank_period;
|
||||
|
||||
static emu_timer *update_timer;
|
||||
|
||||
emu_timer *refresh_timer; /* temporarily made non-static (for ccpu) */
|
||||
static attotime refresh_period;
|
||||
|
||||
static emu_timer *timeslice_timer;
|
||||
static attotime timeslice_period;
|
||||
|
||||
@ -139,14 +127,10 @@ static emu_timer *watchdog_timer;
|
||||
static void cpuexec_exit(running_machine *machine);
|
||||
static void cpuexec_reset(running_machine *machine);
|
||||
static void cpu_inittimers(running_machine *machine);
|
||||
static void cpu_vblankreset(running_machine *machine);
|
||||
static TIMER_CALLBACK( cpu_vblankcallback );
|
||||
static TIMER_CALLBACK( cpu_updatecallback );
|
||||
static TIMER_CALLBACK( end_interleave_boost );
|
||||
static TIMER_CALLBACK( trigger_partial_frame_interrupt );
|
||||
static void compute_perfect_interleave(running_machine *machine);
|
||||
|
||||
void cpu_compute_vblank_timing(running_machine *machine);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
@ -160,19 +144,8 @@ void cpu_compute_vblank_timing(running_machine *machine);
|
||||
|
||||
void cpuexec_init(running_machine *machine)
|
||||
{
|
||||
int numscreens = video_screen_count(machine->config);
|
||||
int cpunum;
|
||||
|
||||
/* if there has been no VBLANK time specified in the MACHINE_DRIVER, compute it now
|
||||
from the visible area */
|
||||
if (numscreens > 0 && machine->screen[0].vblank == 0 && !machine->screen[0].oldstyle_vblank_supplied)
|
||||
machine->screen[0].vblank = (machine->screen[0].refresh / machine->screen[0].height) * (machine->screen[0].height - (machine->screen[0].visarea.max_y + 1 - machine->screen[0].visarea.min_y));
|
||||
|
||||
/* allocate vblank and refresh timers, and compute the initial timing */
|
||||
vblank_timer = timer_alloc(cpu_vblankcallback, NULL);
|
||||
refresh_timer = timer_alloc(NULL, NULL);
|
||||
cpu_compute_vblank_timing(machine);
|
||||
|
||||
/* loop over all our CPUs */
|
||||
for (cpunum = 0; cpunum < MAX_CPU; cpunum++)
|
||||
{
|
||||
@ -209,8 +182,6 @@ void cpuexec_init(running_machine *machine)
|
||||
state_save_register_item("cpu", cpunum, cpu[cpunum].clock);
|
||||
state_save_register_item("cpu", cpunum, cpu[cpunum].clockscale);
|
||||
|
||||
state_save_register_item("cpu", cpunum, cpu[cpunum].vblankint_countdown);
|
||||
|
||||
/* initialize this CPU */
|
||||
state_save_push_tag(cpunum + 1);
|
||||
num_regs = state_save_get_reg_count();
|
||||
@ -235,11 +206,9 @@ void cpuexec_init(running_machine *machine)
|
||||
|
||||
/* save some stuff in the default tag */
|
||||
state_save_push_tag(0);
|
||||
state_save_register_item("cpu", 0, vblank);
|
||||
state_save_register_item("cpu", 0, current_frame);
|
||||
state_save_register_item("cpu", 0, watchdog_enabled);
|
||||
state_save_register_item("cpu", 0, watchdog_counter);
|
||||
state_save_register_item("cpu", 0, vblank_countdown);
|
||||
state_save_pop_tag();
|
||||
}
|
||||
|
||||
@ -278,8 +247,6 @@ static void cpuexec_reset(running_machine *machine)
|
||||
}
|
||||
|
||||
/* reset the globals */
|
||||
cpu_vblankreset(machine);
|
||||
vblank = 0;
|
||||
current_frame = 0;
|
||||
}
|
||||
|
||||
@ -857,33 +824,6 @@ void watchdog_enable(running_machine *machine, int enable)
|
||||
CHEESY FAKE VIDEO TIMING
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
cpu_compute_vblank_timing - recompute cheesy
|
||||
VBLANK timing after a video change
|
||||
-------------------------------------------------*/
|
||||
|
||||
void cpu_compute_vblank_timing(running_machine *machine)
|
||||
{
|
||||
int numscreens = video_screen_count(machine->config);
|
||||
attoseconds_t refresh_attosecs;
|
||||
|
||||
refresh_attosecs = (numscreens == 0) ? HZ_TO_ATTOSECONDS(60) : machine->screen[0].refresh;
|
||||
refresh_period = attotime_make(0, refresh_attosecs);
|
||||
|
||||
/* recompute the vblank period */
|
||||
vblank_period = attotime_make(0, refresh_attosecs / (vblank_multiplier ? vblank_multiplier : 1));
|
||||
if (vblank_timer != NULL && timer_enable(vblank_timer, FALSE))
|
||||
{
|
||||
attotime remaining = timer_timeleft(vblank_timer);
|
||||
if (remaining.seconds == 0 && remaining.attoseconds == 0)
|
||||
remaining = vblank_period;
|
||||
timer_adjust_periodic(vblank_timer, remaining, 0, vblank_period);
|
||||
}
|
||||
|
||||
LOG(("cpu_compute_vblank_timing: refresh=%s vblank=%s\n", attotime_string(refresh_period, 9), attotime_string(vblank_period, 9)));
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cpu_scalebyfcount - scale by time between
|
||||
refresh timers
|
||||
@ -891,18 +831,19 @@ void cpu_compute_vblank_timing(running_machine *machine)
|
||||
|
||||
int cpu_scalebyfcount(int value)
|
||||
{
|
||||
attotime refresh_elapsed = timer_timeelapsed(refresh_timer);
|
||||
int result;
|
||||
// attotime refresh_elapsed = timer_timeelapsed(refresh_timer);
|
||||
// int result;
|
||||
|
||||
/* shift off some bits to ensure no overflow */
|
||||
if (value < 65536)
|
||||
result = value * (refresh_elapsed.attoseconds >> 16) / (refresh_period.attoseconds >> 16);
|
||||
else
|
||||
result = value * (refresh_elapsed.attoseconds >> 32) / (refresh_period.attoseconds >> 32);
|
||||
if (value >= 0)
|
||||
return (result < value) ? result : value;
|
||||
else
|
||||
return (result > value) ? result : value;
|
||||
// if (value < 65536)
|
||||
// result = value * (refresh_elapsed.attoseconds >> 16) / (refresh_period.attoseconds >> 16);
|
||||
// else
|
||||
// result = value * (refresh_elapsed.attoseconds >> 32) / (refresh_period.attoseconds >> 32);
|
||||
// if (value >= 0)
|
||||
// return (result < value) ? result : value;
|
||||
// else
|
||||
// return (result > value) ? result : value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -918,17 +859,6 @@ int cpu_getiloops(void)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cpu_getvblank - return the cheesy VBLANK
|
||||
state (deprecated)
|
||||
-------------------------------------------------*/
|
||||
|
||||
int cpu_getvblank(void)
|
||||
{
|
||||
return vblank;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cpu_getcurrentframe - return the current
|
||||
frame count (deprecated)
|
||||
@ -940,147 +870,121 @@ int cpu_getcurrentframe(void)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INTERNAL TIMING
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
cpu_vblankreset - hook for updating things on
|
||||
cheesy fake VBLANK (once per frame)
|
||||
on_global_vblank - performs VBLANK related
|
||||
housekeeping
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void cpu_vblankreset(running_machine *machine)
|
||||
static void on_global_vblank(running_machine *machine, screen_state *screen, int vblank_state)
|
||||
{
|
||||
int cpunum;
|
||||
|
||||
/* notify the video system of a VBLANK start */
|
||||
video_vblank_start(machine);
|
||||
|
||||
/* read keyboard & update the status of the input ports */
|
||||
input_port_vblank_start();
|
||||
|
||||
/* check the watchdog */
|
||||
if (machine->config->watchdog_vblank_count != 0 && --watchdog_counter == 0)
|
||||
watchdog_callback(machine, NULL, 0);
|
||||
|
||||
/* reset the cycle counters */
|
||||
for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
|
||||
/* VBLANK starting */
|
||||
if (vblank_state)
|
||||
{
|
||||
if (!(cpu[cpunum].suspend & SUSPEND_REASON_DISABLE))
|
||||
cpu[cpunum].iloops = machine->config->cpu[cpunum].vblank_interrupts_per_frame - 1;
|
||||
else
|
||||
cpu[cpunum].iloops = -1;
|
||||
/* check the watchdog */
|
||||
if (machine->config->watchdog_vblank_count != 0 && --watchdog_counter == 0)
|
||||
watchdog_callback(machine, NULL, 0);
|
||||
}
|
||||
|
||||
/* VBLANK ending - increment total frames */
|
||||
else
|
||||
current_frame++;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cpu_firstvblankcallback - timer callback for
|
||||
the first fake VBLANK
|
||||
on_per_screen_vblank - calls any external
|
||||
callbacks for this screen
|
||||
-------------------------------------------------*/
|
||||
|
||||
static TIMER_CALLBACK( cpu_firstvblankcallback )
|
||||
static void on_per_screen_vblank(running_machine *machine, screen_state *screen, int vblank_state)
|
||||
{
|
||||
/* now that we're synced up, pulse from here on out */
|
||||
timer_adjust_periodic(vblank_timer, vblank_period, param, vblank_period);
|
||||
|
||||
/* but we need to call the standard routine as well */
|
||||
cpu_vblankcallback(machine, NULL, param);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cpu_vblankcallback - timer callback for
|
||||
subsequent fake VBLANKs
|
||||
-------------------------------------------------*/
|
||||
|
||||
static TIMER_CALLBACK( cpu_vblankcallback )
|
||||
{
|
||||
int cpunum;
|
||||
|
||||
if (vblank_countdown == 1)
|
||||
vblank = 1;
|
||||
|
||||
/* loop over CPUs */
|
||||
for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
|
||||
/* VBLANK starting */
|
||||
if (vblank_state)
|
||||
{
|
||||
/* if the interrupt multiplier is valid */
|
||||
if (cpu[cpunum].vblankint_multiplier != -1)
|
||||
{
|
||||
/* decrement; if we hit zero, generate the interrupt and reset the countdown */
|
||||
if (!--cpu[cpunum].vblankint_countdown)
|
||||
{
|
||||
/* a param of -1 means don't call any callbacks */
|
||||
if (param != -1)
|
||||
{
|
||||
/* if the CPU has a VBLANK handler, call it */
|
||||
if (machine->config->cpu[cpunum].vblank_interrupt && !cpunum_is_suspended(cpunum, SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
|
||||
{
|
||||
cpuintrf_push_context(cpunum);
|
||||
(*machine->config->cpu[cpunum].vblank_interrupt)(machine, cpunum);
|
||||
cpuintrf_pop_context();
|
||||
}
|
||||
int cpunum;
|
||||
const char *screen_tag = NULL;
|
||||
const device_config *device;
|
||||
|
||||
/* update the counters */
|
||||
cpu[cpunum].iloops--;
|
||||
/* get the screen's tag */
|
||||
for (device = video_screen_first(machine->config); device != NULL; device = video_screen_next(device))
|
||||
if (device->token == screen)
|
||||
screen_tag = device->tag;
|
||||
|
||||
assert(screen_tag != NULL);
|
||||
|
||||
/* find any CPUs that have this screen as their VBLANK interrupt source */
|
||||
for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
|
||||
{
|
||||
int cpu_interested;
|
||||
const cpu_config *config = machine->config->cpu + cpunum;
|
||||
|
||||
/* start the interrupt counter */
|
||||
if (!(cpu[cpunum].suspend & SUSPEND_REASON_DISABLE))
|
||||
cpu[cpunum].iloops = config->vblank_interrupts_per_frame - 1;
|
||||
else
|
||||
cpu[cpunum].iloops = -1;
|
||||
|
||||
/* the hack style VBLANK decleration uses the first screen always */
|
||||
if (config->vblank_interrupts_per_frame > 1)
|
||||
cpu_interested = TRUE;
|
||||
|
||||
/* for new style decleration, we need to compare the tags */
|
||||
else if (config->vblank_interrupts_per_frame == 1)
|
||||
cpu_interested = (strcmp(config->vblank_interrupt_screen, screen_tag) == 0);
|
||||
|
||||
/* no VBLANK interrupt, not interested */
|
||||
else
|
||||
cpu_interested = FALSE;
|
||||
|
||||
/* if interested, call the interrupt handler */
|
||||
if (cpu_interested)
|
||||
{
|
||||
if (!cpunum_is_suspended(cpunum, SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
|
||||
{
|
||||
cpuintrf_push_context(cpunum);
|
||||
(*machine->config->cpu[cpunum].vblank_interrupt)(machine, cpunum);
|
||||
cpuintrf_pop_context();
|
||||
}
|
||||
|
||||
/* reset the countdown and timer */
|
||||
cpu[cpunum].vblankint_countdown = cpu[cpunum].vblankint_multiplier;
|
||||
timer_adjust_oneshot(cpu[cpunum].vblankint_timer, attotime_never, 0);
|
||||
/* if we have more than one interrupt per frame, start the timer now to trigger the rest of them */
|
||||
if ((config->vblank_interrupts_per_frame > 1) &&
|
||||
!(cpu[cpunum].suspend & SUSPEND_REASON_DISABLE))
|
||||
{
|
||||
cpu[cpunum].partial_frame_period = attotime_div(video_screen_get_frame_period(0), config->vblank_interrupts_per_frame);
|
||||
timer_adjust_oneshot(cpu[cpunum].partial_frame_timer, cpu[cpunum].partial_frame_period, cpunum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* else reset the VBLANK timer if this is going to be a real VBLANK */
|
||||
else if (vblank_countdown == 1)
|
||||
timer_adjust_oneshot(cpu[cpunum].vblankint_timer, attotime_never, 0);
|
||||
}
|
||||
|
||||
/* is it a real VBLANK? */
|
||||
if (!--vblank_countdown)
|
||||
{
|
||||
/* do we update the screen now? */
|
||||
if (!(machine->config->video_attributes & VIDEO_UPDATE_AFTER_VBLANK))
|
||||
video_frame_update(machine, FALSE);
|
||||
|
||||
/* Set the timer to update the screen */
|
||||
timer_adjust_oneshot(update_timer, attotime_make(0, machine->screen[0].vblank), 0);
|
||||
|
||||
/* reset the globals */
|
||||
cpu_vblankreset(machine);
|
||||
|
||||
/* reset the counter */
|
||||
vblank_countdown = vblank_multiplier;
|
||||
|
||||
#ifdef ENABLE_DEBUGGER
|
||||
/* notify the debugger */
|
||||
debug_vblank_hook();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cpu_updatecallback - timer callback for
|
||||
the fake end of VBLANK
|
||||
trigger_partial_frame_interrupt - called to
|
||||
trigger a partial frame interrupt
|
||||
-------------------------------------------------*/
|
||||
|
||||
static TIMER_CALLBACK( cpu_updatecallback )
|
||||
static TIMER_CALLBACK( trigger_partial_frame_interrupt )
|
||||
{
|
||||
/* update the screen if we didn't before */
|
||||
if (machine->config->video_attributes & VIDEO_UPDATE_AFTER_VBLANK)
|
||||
video_frame_update(machine, FALSE);
|
||||
vblank = 0;
|
||||
int cpunum = param;
|
||||
|
||||
/* update IPT_VBLANK input ports */
|
||||
input_port_vblank_end();
|
||||
cpu[cpunum].iloops--;
|
||||
|
||||
/* track total frames */
|
||||
current_frame++;
|
||||
/* call the interrupt handler */
|
||||
if (!cpunum_is_suspended(cpunum, SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
|
||||
{
|
||||
cpuintrf_push_context(cpunum);
|
||||
(*machine->config->cpu[cpunum].vblank_interrupt)(machine, cpunum);
|
||||
cpuintrf_pop_context();
|
||||
}
|
||||
|
||||
/* reset the refresh timer */
|
||||
timer_adjust_oneshot(refresh_timer, attotime_never, 0);
|
||||
/* more? */
|
||||
if (cpu[cpunum].iloops > 0)
|
||||
timer_adjust_oneshot(cpu[cpunum].partial_frame_timer, cpu[cpunum].partial_frame_period, cpunum);
|
||||
}
|
||||
|
||||
|
||||
@ -1165,8 +1069,7 @@ static void cpu_inittimers(running_machine *machine)
|
||||
{
|
||||
int numscreens = video_screen_count(machine->config);
|
||||
attoseconds_t refresh_attosecs;
|
||||
attotime first_time;
|
||||
int cpunum, max, ipf;
|
||||
int cpunum, ipf;
|
||||
|
||||
/* allocate a timer for the watchdog */
|
||||
watchdog_timer = timer_alloc(watchdog_callback, NULL);
|
||||
@ -1184,68 +1087,44 @@ static void cpu_inittimers(running_machine *machine)
|
||||
interleave_boost_timer = timer_alloc(NULL, NULL);
|
||||
interleave_boost_timer_end = timer_alloc(end_interleave_boost, NULL);
|
||||
|
||||
/*
|
||||
* The following code finds all the CPUs that are interrupting in sync with the VBLANK
|
||||
* and sets up the VBLANK timer to run at the minimum number of cycles per frame in
|
||||
* order to service all the synced interrupts
|
||||
*/
|
||||
|
||||
/* find the CPU with the maximum interrupts per frame */
|
||||
max = 1;
|
||||
/* register the screen specific VBLANK callbacks */
|
||||
for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
|
||||
{
|
||||
ipf = machine->config->cpu[cpunum].vblank_interrupts_per_frame;
|
||||
if (ipf > max)
|
||||
max = ipf;
|
||||
}
|
||||
const cpu_config *config = machine->config->cpu + cpunum;
|
||||
|
||||
/* now find the LCD with the rest of the CPUs (brute force - these numbers aren't huge) */
|
||||
vblank_multiplier = max;
|
||||
while (1)
|
||||
{
|
||||
for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
|
||||
if (config->vblank_interrupts_per_frame > 0)
|
||||
{
|
||||
ipf = machine->config->cpu[cpunum].vblank_interrupts_per_frame;
|
||||
if (ipf > 0 && (vblank_multiplier % ipf) != 0)
|
||||
break;
|
||||
const char *screen_tag;
|
||||
screen_state *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;
|
||||
|
||||
/* old style 'hack' setup - use screen #0 */
|
||||
else
|
||||
{
|
||||
const device_config *config = device_list_first(machine->config->devicelist, VIDEO_SCREEN);
|
||||
screen_tag = config->tag;
|
||||
|
||||
/* 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_per_screen_vblank);
|
||||
}
|
||||
if (cpunum == cpu_gettotalcpu())
|
||||
break;
|
||||
vblank_multiplier += max;
|
||||
}
|
||||
|
||||
/* initialize the countdown timers and intervals */
|
||||
/* register the global VBLANK callback -- it's important to do it after the
|
||||
screen specific ones */
|
||||
video_screen_register_vbl_cb(machine, NULL, on_global_vblank);
|
||||
|
||||
/* start the CPU periodic interrupt timers */
|
||||
for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
|
||||
{
|
||||
ipf = machine->config->cpu[cpunum].vblank_interrupts_per_frame;
|
||||
if (ipf > 0)
|
||||
cpu[cpunum].vblankint_countdown = cpu[cpunum].vblankint_multiplier = vblank_multiplier / ipf;
|
||||
else
|
||||
cpu[cpunum].vblankint_countdown = cpu[cpunum].vblankint_multiplier = -1;
|
||||
}
|
||||
|
||||
/* allocate a vblank timer at the frame rate * the LCD number of interrupts per frame */
|
||||
vblank_period = attotime_make(0, refresh_attosecs / vblank_multiplier);
|
||||
vblank_countdown = vblank_multiplier;
|
||||
|
||||
/* allocate an update timer that will be used to time the actual screen updates */
|
||||
update_timer = timer_alloc(cpu_updatecallback, NULL);
|
||||
|
||||
/*
|
||||
* The following code creates individual timers for each CPU whose interrupts are not
|
||||
* synced to the VBLANK, and computes the typical number of cycles per interrupt
|
||||
*/
|
||||
|
||||
/* start the CPU interrupt timers */
|
||||
for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++)
|
||||
{
|
||||
ipf = machine->config->cpu[cpunum].vblank_interrupts_per_frame;
|
||||
|
||||
/* compute the average number of cycles per interrupt */
|
||||
if (ipf <= 0)
|
||||
ipf = 1;
|
||||
cpu[cpunum].vblankint_timer = timer_alloc(NULL, NULL);
|
||||
|
||||
/* see if we need to allocate a CPU timer */
|
||||
if (machine->config->cpu[cpunum].timed_interrupt_period != 0)
|
||||
{
|
||||
@ -1254,18 +1133,4 @@ static void cpu_inittimers(running_machine *machine)
|
||||
timer_adjust_periodic(cpu[cpunum].timedint_timer, timedint_period, cpunum, timedint_period);
|
||||
}
|
||||
}
|
||||
|
||||
/* note that since we start the first frame on the refresh, we can't pulse starting
|
||||
immediately; instead, we back up one VBLANK period, and inch forward until we hit
|
||||
positive time. That time will be the time of the first VBLANK timer callback */
|
||||
first_time = attotime_sub_attoseconds(vblank_period, machine->screen[0].vblank);
|
||||
while (attotime_compare(first_time, attotime_zero) < 0)
|
||||
{
|
||||
cpu_vblankcallback(machine, NULL, -1);
|
||||
first_time = attotime_add(first_time, vblank_period);
|
||||
}
|
||||
timer_set(first_time, NULL, 0, cpu_firstvblankcallback);
|
||||
|
||||
/* reset the refresh timer to get ourself back in sync */
|
||||
timer_adjust_oneshot(refresh_timer, attotime_never, 0);
|
||||
}
|
||||
|
@ -140,6 +140,22 @@ int mame_debug_is_active(void)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
on_vblank - called when a VBLANK hits
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void on_vblank(running_machine *machine, screen_state *screen, int vblank_state)
|
||||
{
|
||||
/* if we're configured to stop on VBLANK, break */
|
||||
if (vblank_state && break_on_vblank)
|
||||
{
|
||||
execution_state = EXECUTION_STATE_STOPPED;
|
||||
debug_console_printf("Stopped at VBLANK\n");
|
||||
break_on_vblank = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INITIALIZATION
|
||||
***************************************************************************/
|
||||
@ -279,6 +295,10 @@ void debug_cpu_init(running_machine *machine)
|
||||
}
|
||||
}
|
||||
|
||||
/* add callback for breaking on VBLANK */
|
||||
fprintf(stderr,"Debug 1\n");
|
||||
video_screen_register_vbl_cb(machine, NULL, on_vblank);
|
||||
|
||||
add_exit_callback(machine, debug_cpu_exit);
|
||||
}
|
||||
|
||||
@ -1027,23 +1047,6 @@ static void process_source_file(void)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
debug_vblank_hook - called when the real
|
||||
VBLANK hits
|
||||
-------------------------------------------------*/
|
||||
|
||||
void debug_vblank_hook(void)
|
||||
{
|
||||
/* if we're configured to stop on VBLANK, break */
|
||||
if (break_on_vblank)
|
||||
{
|
||||
execution_state = EXECUTION_STATE_STOPPED;
|
||||
debug_console_printf("Stopped at VBLANK\n");
|
||||
break_on_vblank = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
debug_vblank_hook - called when an interrupt
|
||||
is acknowledged
|
||||
|
@ -182,7 +182,6 @@ void debug_source_script(const char *file);
|
||||
void debug_flush_traces(void);
|
||||
|
||||
/* debugging hooks */
|
||||
void debug_vblank_hook(void);
|
||||
void debug_interrupt_hook(int cpunum, int irqline);
|
||||
void debug_get_memory_hooks(int cpunum, debug_hook_read_ptr *read, debug_hook_write_ptr *write);
|
||||
void debug_set_instruction_hook(int cpunum, int (*hook)(offs_t pc));
|
||||
|
@ -1034,11 +1034,14 @@ static int default_ports_lookup[__ipt_max][MAX_PLAYERS];
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
static void on_vblank(running_machine *machine, screen_state *screen, 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);
|
||||
static void input_port_load(int config_type, xml_data_node *parentnode);
|
||||
static void input_port_save(int config_type, xml_data_node *parentnode);
|
||||
static void input_port_vblank_start(void);
|
||||
static void input_port_vblank_end(void);
|
||||
static void update_digital_joysticks(void);
|
||||
static void update_analog_port(int port);
|
||||
static void interpolate_analog_port(int port);
|
||||
@ -1138,6 +1141,33 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* VBLANK handler
|
||||
*
|
||||
*************************************/
|
||||
|
||||
static void on_vblank(running_machine *machine, screen_state *screen, int vblank_state)
|
||||
{
|
||||
/* VBLANK starting - read keyboard & update the status of the input ports */
|
||||
if (vblank_state)
|
||||
input_port_vblank_start();
|
||||
|
||||
/* VBLANK ending - update IPT_VBLANK input ports */
|
||||
else
|
||||
input_port_vblank_end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Set up for playback
|
||||
@ -2827,7 +2857,7 @@ void input_port_update_defaults(void)
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void input_port_vblank_start(void)
|
||||
static void input_port_vblank_start(void)
|
||||
{
|
||||
int ui_visible = ui_is_menu_active() || ui_is_slider_active();
|
||||
int portnum, bitnum;
|
||||
@ -2997,7 +3027,7 @@ profiler_mark(PROFILER_END);
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void input_port_vblank_end(void)
|
||||
static void input_port_vblank_end(void)
|
||||
{
|
||||
int ui_visible = ui_is_menu_active() || ui_is_slider_active();
|
||||
int port;
|
||||
@ -3417,18 +3447,8 @@ UINT32 readinputport(int port)
|
||||
result = (result & ~portinfo->vblank) | (portinfo->defvalue & portinfo->vblank);
|
||||
|
||||
/* toggle VBLANK if we're in a VBLANK state */
|
||||
if (Machine->screen[0].oldstyle_vblank_supplied)
|
||||
{
|
||||
int cpu_getvblank(void);
|
||||
|
||||
if (cpu_getvblank())
|
||||
result ^= portinfo->vblank;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (video_screen_get_vblank(0))
|
||||
result ^= portinfo->vblank;
|
||||
}
|
||||
if (video_screen_get_vblank(0))
|
||||
result ^= portinfo->vblank;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -893,6 +893,7 @@ struct _ext_inp_header
|
||||
***************************************************************************/
|
||||
|
||||
void input_port_init(running_machine *machine, const input_port_token *ipt);
|
||||
void input_port_post_init(running_machine *machine);
|
||||
const char *input_port_string_from_token(const input_port_token token);
|
||||
|
||||
input_port_entry *input_port_initialize(input_port_init_params *params, UINT32 type, const char *tag, UINT32 mask, UINT32 defval);
|
||||
@ -926,8 +927,6 @@ int input_ui_pressed(int code);
|
||||
int input_ui_pressed_repeat(int code, int speed);
|
||||
|
||||
void input_port_update_defaults(void);
|
||||
void input_port_vblank_start(void); /* called by cpuintrf.c - not for external use */
|
||||
void input_port_vblank_end(void); /* called by cpuintrf.c - not for external use */
|
||||
|
||||
void input_port_set_digital_value(int port, UINT32 value, UINT32 mask);
|
||||
|
||||
|
@ -1573,12 +1573,6 @@ static void init_machine(running_machine *machine)
|
||||
devices_init(machine);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DEBUGGER
|
||||
/* initialize the debugger */
|
||||
if (machine->debug_mode)
|
||||
mame_debug_init(machine);
|
||||
#endif
|
||||
|
||||
/* call the game driver's init function */
|
||||
/* this is where decryption is done and memory maps are altered */
|
||||
/* so this location in the init order is important */
|
||||
@ -1593,6 +1587,13 @@ static void init_machine(running_machine *machine)
|
||||
device_list_start(machine);
|
||||
|
||||
sound_init(machine);
|
||||
input_port_post_init(machine);
|
||||
|
||||
#ifdef ENABLE_DEBUGGER
|
||||
/* initialize the debugger */
|
||||
if (machine->debug_mode)
|
||||
mame_debug_init(machine);
|
||||
#endif
|
||||
|
||||
/* call the driver's _START callbacks */
|
||||
if (machine->config->machine_start != NULL) (*machine->config->machine_start)(machine);
|
||||
|
@ -780,24 +780,10 @@ static int validate_cpu(int drivnum, const machine_config *config, const UINT32
|
||||
mame_printf_error("%s: %s cpu #%d has a valid VBLANK interrupt handler with no screen tag supplied!\n", driver->source_file, driver->name, cpunum);
|
||||
error = TRUE;
|
||||
}
|
||||
else
|
||||
else if (device_list_index(config->devicelist, VIDEO_SCREEN, cpu->vblank_interrupt_screen) == -1)
|
||||
{
|
||||
int screen_tag_found = FALSE;
|
||||
const device_config *device;
|
||||
|
||||
/* loop over screens looking for the tag */
|
||||
for (device = video_screen_first(config); device != NULL; device = video_screen_next(device))
|
||||
if (strcmp(device->tag, cpu->vblank_interrupt_screen) == 0)
|
||||
{
|
||||
screen_tag_found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!screen_tag_found)
|
||||
{
|
||||
mame_printf_error("%s: %s cpu #%d VBLANK interrupt with a non-existant screen tag (%s)!\n", driver->source_file, driver->name, cpunum, cpu->vblank_interrupt_screen);
|
||||
error = TRUE;
|
||||
}
|
||||
mame_printf_error("%s: %s cpu #%d VBLANK interrupt with a non-existant screen tag (%s)!\n", driver->source_file, driver->name, cpunum, cpu->vblank_interrupt_screen);
|
||||
error = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
248
src/emu/video.c
248
src/emu/video.c
@ -39,7 +39,8 @@
|
||||
***************************************************************************/
|
||||
|
||||
#define SUBSECONDS_PER_SPEED_UPDATE (ATTOSECONDS_PER_SECOND / 4)
|
||||
#define PAUSED_REFRESH_RATE 30
|
||||
#define PAUSED_REFRESH_RATE (30)
|
||||
#define MAX_VBL_CB (10)
|
||||
|
||||
|
||||
|
||||
@ -51,35 +52,43 @@ typedef struct _internal_screen_info internal_screen_info;
|
||||
struct _internal_screen_info
|
||||
{
|
||||
/* pointers to screen configuration and state */
|
||||
const screen_config * config; /* pointer to the configuration in the Machine->config */
|
||||
screen_state * state; /* pointer to visible state in Machine structure */
|
||||
int scrnum; /* the screen index */
|
||||
const screen_config * config; /* pointer to the configuration in the Machine->config */
|
||||
screen_state * state; /* pointer to visible state in Machine structure */
|
||||
|
||||
/* textures and bitmaps */
|
||||
render_texture * texture[2]; /* 2x textures for the screen bitmap */
|
||||
bitmap_t * bitmap[2]; /* 2x bitmaps for rendering */
|
||||
UINT8 curbitmap; /* current bitmap index */
|
||||
UINT8 curtexture; /* current texture index */
|
||||
bitmap_format format; /* format of bitmap for this screen */
|
||||
UINT8 changed; /* has this bitmap changed? */
|
||||
INT32 last_partial_scan; /* scanline of last partial update */
|
||||
render_texture * texture[2]; /* 2x textures for the screen bitmap */
|
||||
bitmap_t * bitmap[2]; /* 2x bitmaps for rendering */
|
||||
UINT8 curbitmap; /* current bitmap index */
|
||||
UINT8 curtexture; /* current texture index */
|
||||
bitmap_format format; /* format of bitmap for this screen */
|
||||
UINT8 changed; /* has this bitmap changed? */
|
||||
INT32 last_partial_scan; /* scanline of last partial update */
|
||||
UINT8 vblank_state; /* 1 = in VBLANK region, 0 = outside */
|
||||
|
||||
/* screen timing */
|
||||
attoseconds_t scantime; /* attoseconds per scanline */
|
||||
attoseconds_t pixeltime; /* attoseconds per pixel */
|
||||
attotime vblank_time; /* time of last VBLANK start */
|
||||
emu_timer * scanline0_timer; /* scanline 0 timer */
|
||||
emu_timer * scanline_timer; /* scanline timer */
|
||||
attoseconds_t scantime; /* attoseconds per scanline */
|
||||
attoseconds_t pixeltime; /* attoseconds per pixel */
|
||||
attotime vblank_time; /* time of last VBLANK start */
|
||||
emu_timer * vblank_begin_timer; /* timer to signal VBLANK start */
|
||||
emu_timer * vblank_end_timer; /* timer to signal VBLANK end */
|
||||
emu_timer * scanline0_timer; /* scanline 0 timer */
|
||||
emu_timer * scanline_timer; /* scanline timer */
|
||||
|
||||
/* VBLANK callbacks */
|
||||
int vbl_cb_count; /* # of callbacks installed */
|
||||
video_screen_on_vbl vbl_cbs[MAX_VBL_CB]; /* the array of callbacks */
|
||||
|
||||
/* movie recording */
|
||||
mame_file * movie_file; /* handle to the open movie file */
|
||||
UINT32 movie_frame; /* current movie frame number */
|
||||
mame_file * movie_file; /* handle to the open movie file */
|
||||
UINT32 movie_frame; /* current movie frame number */
|
||||
};
|
||||
|
||||
|
||||
struct _video_private
|
||||
{
|
||||
/* per-screen information */
|
||||
internal_screen_info scrinfo[MAX_SCREENS]; /* per-screen infomration */
|
||||
internal_screen_info scrinfo[MAX_SCREENS]; /* per-screen information */
|
||||
|
||||
/* snapshot stuff */
|
||||
render_target * snap_target; /* screen shapshot target */
|
||||
@ -176,6 +185,8 @@ static void allocate_graphics(running_machine *machine, const gfx_decode_entry *
|
||||
static void decode_graphics(running_machine *machine, const gfx_decode_entry *gfxdecodeinfo);
|
||||
|
||||
/* global rendering */
|
||||
static TIMER_CALLBACK( vblank_begin_callback );
|
||||
static TIMER_CALLBACK( vblank_end_callback );
|
||||
static TIMER_CALLBACK( scanline0_callback );
|
||||
static TIMER_CALLBACK( scanline_update_callback );
|
||||
static int finish_screen_updates(running_machine *machine);
|
||||
@ -305,10 +316,15 @@ void video_init(running_machine *machine)
|
||||
render_container *container = render_container_get_screen(scrnum);
|
||||
internal_screen_info *info = &viddata->scrinfo[scrnum];
|
||||
|
||||
/* allocate the VBLANK timers */
|
||||
info->vblank_begin_timer = timer_alloc(vblank_begin_callback, info);
|
||||
info->vblank_end_timer = timer_alloc(vblank_end_callback, info);
|
||||
|
||||
/* allocate a timer to reset partial updates */
|
||||
info->scanline0_timer = timer_alloc(scanline0_callback, NULL);
|
||||
|
||||
/* make pointers back to the config and state */
|
||||
info->scrnum = scrnum;
|
||||
info->config = device->inline_config;
|
||||
info->state = &machine->screen[scrnum];
|
||||
|
||||
@ -326,7 +342,7 @@ void video_init(running_machine *machine)
|
||||
render_container_set_yscale(container, info->config->yscale);
|
||||
|
||||
/* reset VBLANK timing */
|
||||
info->vblank_time = attotime_sub_attoseconds(attotime_zero, machine->screen[0].vblank);
|
||||
info->vblank_time = attotime_zero;
|
||||
|
||||
/* allocate a timer to generate per-scanline updates */
|
||||
if (machine->config->video_attributes & VIDEO_UPDATE_SCANLINE)
|
||||
@ -433,28 +449,6 @@ static void video_exit(running_machine *machine)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
video_vblank_start - called at the start of
|
||||
VBLANK, which is driven by the CPU scheduler
|
||||
-------------------------------------------------*/
|
||||
|
||||
void video_vblank_start(running_machine *machine)
|
||||
{
|
||||
video_private *viddata = machine->video_data;
|
||||
attotime curtime = timer_get_time();
|
||||
int scrnum;
|
||||
|
||||
/* kludge: we get called at time 0 to reset, but at that point,
|
||||
the time of last VBLANK is actually -vblank_duration */
|
||||
if (curtime.seconds == 0 && curtime.attoseconds == 0)
|
||||
curtime = attotime_sub_attoseconds(attotime_zero, machine->screen[0].vblank);
|
||||
|
||||
/* reset VBLANK timers for each screen -- fix me */
|
||||
for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++)
|
||||
viddata->scrinfo[scrnum].vblank_time = curtime;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
init_buffered_spriteram - initialize the
|
||||
double-buffered spriteram
|
||||
@ -765,18 +759,15 @@ void video_screen_configure(int scrnum, int width, int height, const rectangle *
|
||||
}
|
||||
}
|
||||
|
||||
/* recompute the VBLANK timing */
|
||||
{
|
||||
extern void cpu_compute_vblank_timing(running_machine *machine);
|
||||
cpu_compute_vblank_timing(Machine);
|
||||
}
|
||||
|
||||
/* if we are on scanline 0 already, reset the update timer immediately */
|
||||
/* otherwise, defer until the next scanline 0 */
|
||||
if (video_screen_get_vpos(scrnum) == 0)
|
||||
timer_adjust_oneshot(info->scanline0_timer, attotime_zero, scrnum);
|
||||
else
|
||||
timer_adjust_oneshot(info->scanline0_timer, video_screen_get_time_until_pos(scrnum, 0, 0), scrnum);
|
||||
|
||||
/* start the VBLANK timer */
|
||||
timer_adjust_oneshot(info->vblank_begin_timer, video_screen_get_time_until_vblank_start(scrnum), 0);
|
||||
}
|
||||
|
||||
|
||||
@ -973,8 +964,7 @@ int video_screen_get_hpos(int scrnum)
|
||||
int video_screen_get_vblank(int scrnum)
|
||||
{
|
||||
internal_screen_info *info = get_screen_info(Machine, scrnum);
|
||||
int vpos = video_screen_get_vpos(scrnum);
|
||||
return (vpos < info->state->visarea.min_y || vpos > info->state->visarea.max_y);
|
||||
return info->vblank_state;
|
||||
}
|
||||
|
||||
|
||||
@ -1021,6 +1011,18 @@ attotime video_screen_get_time_until_pos(int scrnum, int vpos, int hpos)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
video_screen_get_time_until_vblank_start -
|
||||
returns the amount of time remaining until
|
||||
the next VBLANK period start
|
||||
-------------------------------------------------*/
|
||||
|
||||
attotime video_screen_get_time_until_vblank_start(int scrnum)
|
||||
{
|
||||
return video_screen_get_time_until_pos(scrnum, Machine->screen[scrnum].visarea.max_y + 1, 0);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
video_screen_get_scan_period - return the
|
||||
amount of time the beam takes to draw one
|
||||
@ -1047,6 +1049,64 @@ attotime video_screen_get_frame_period(int scrnum)
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
video_screen_register_vbl_cb - registers a
|
||||
VBLANK callback
|
||||
-------------------------------------------------*/
|
||||
|
||||
void video_screen_register_vbl_cb(running_machine *machine, void *screen, video_screen_on_vbl vbl_cb)
|
||||
{
|
||||
int i, found;
|
||||
internal_screen_info *scrinfo = NULL;
|
||||
|
||||
/* validate arguments */
|
||||
assert(machine != NULL);
|
||||
assert(machine->config != NULL);
|
||||
assert(machine->config->devicelist != NULL);
|
||||
assert(machine->video_data != NULL);
|
||||
assert(machine->video_data->scrinfo != 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->video_data->scrinfo[i].state == screen)
|
||||
scrinfo = machine->video_data->scrinfo + i;
|
||||
|
||||
/* make sure we still have room for the callback */
|
||||
assert(scrinfo != NULL);
|
||||
assert(scrinfo->vbl_cb_count != MAX_VBL_CB);
|
||||
|
||||
/* check if we already have this callback registered */
|
||||
found = FALSE;
|
||||
for (i = 0; i < scrinfo->vbl_cb_count; i++)
|
||||
if (scrinfo->vbl_cbs[i] == vbl_cb)
|
||||
found = TRUE;
|
||||
|
||||
/* if not found, register and increment count */
|
||||
if (!found)
|
||||
{
|
||||
scrinfo->vbl_cbs[scrinfo->vbl_cb_count] = vbl_cb;
|
||||
scrinfo->vbl_cb_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
VIDEO SCREEN DEVICE INTERFACE
|
||||
***************************************************************************/
|
||||
@ -1087,21 +1147,21 @@ DEVICE_GET_INFO( video_screen )
|
||||
switch (state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(screen_config); break;
|
||||
case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_VIDEO; break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(screen_config); break;
|
||||
case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_VIDEO; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case DEVINFO_FCT_SET_INFO: info->set_info = DEVICE_SET_INFO_NAME(video_screen); break;
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(video_screen); break;
|
||||
case DEVINFO_FCT_STOP: /* Nothing */ break;
|
||||
case DEVINFO_FCT_RESET: /* Nothing */ break;
|
||||
case DEVINFO_FCT_SET_INFO: info->set_info = DEVICE_SET_INFO_NAME(video_screen); break;
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(video_screen); break;
|
||||
case DEVINFO_FCT_STOP: /* Nothing */ break;
|
||||
case DEVINFO_FCT_RESET: /* Nothing */ break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: info->s = "Raster"; break;
|
||||
case DEVINFO_STR_FAMILY: info->s = "Video Screen"; break;
|
||||
case DEVINFO_STR_VERSION: info->s = "1.0"; break;
|
||||
case DEVINFO_STR_SOURCE_FILE: info->s = __FILE__; break;
|
||||
case DEVINFO_STR_CREDITS: info->s = "Copyright Nicola Salmoria and the MAME Team"; break;
|
||||
case DEVINFO_STR_NAME: info->s = "Raster"; break;
|
||||
case DEVINFO_STR_FAMILY: info->s = "Video Screen"; break;
|
||||
case DEVINFO_STR_VERSION: info->s = "1.0"; break;
|
||||
case DEVINFO_STR_SOURCE_FILE: info->s = __FILE__; break;
|
||||
case DEVINFO_STR_CREDITS: info->s = "Copyright Nicola Salmoria and the MAME Team"; break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1111,6 +1171,74 @@ DEVICE_GET_INFO( video_screen )
|
||||
GLOBAL RENDERING
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
call_vb_callbacks - call any external VBLANK
|
||||
callsbacks with the given state
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void call_vb_callbacks(running_machine *machine, internal_screen_info *scrinfo, int vblank_state)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set it in the state structure */
|
||||
scrinfo->vblank_state = vblank_state;
|
||||
|
||||
for (i = 0; i < scrinfo->vbl_cb_count; i++)
|
||||
scrinfo->vbl_cbs[i](machine, scrinfo->state, vblank_state);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
vblank_begin_callback - call any external
|
||||
callbacks to signal the VBLANK period has begun
|
||||
-------------------------------------------------*/
|
||||
|
||||
static TIMER_CALLBACK( vblank_begin_callback )
|
||||
{
|
||||
attoseconds_t vblank_period;
|
||||
internal_screen_info *scrinfo = ptr;
|
||||
|
||||
/* reset the starting VBLANK time */
|
||||
scrinfo->vblank_time = timer_get_time();
|
||||
|
||||
/* call the external callbacks */
|
||||
call_vb_callbacks(machine, scrinfo, TRUE);
|
||||
|
||||
/* do we update the screen now? - only do it for the first screen */
|
||||
if (!(machine->config->video_attributes & VIDEO_UPDATE_AFTER_VBLANK) && (scrinfo->scrnum == 0))
|
||||
video_frame_update(machine, FALSE);
|
||||
|
||||
/* if there has been no VBLANK time specified in the MACHINE_DRIVER, compute it now
|
||||
from the visible area, otherwise just used the supplied value */
|
||||
if ((scrinfo->state->vblank == 0) && !scrinfo->state->oldstyle_vblank_supplied)
|
||||
vblank_period = (scrinfo->state->refresh / scrinfo->state->height) * (scrinfo->state->height - (scrinfo->state->visarea.max_y + 1 - scrinfo->state->visarea.min_y));
|
||||
else
|
||||
vblank_period = scrinfo->state->vblank;
|
||||
|
||||
/* reset the timers */
|
||||
timer_adjust_oneshot(scrinfo->vblank_begin_timer, attotime_make(0, scrinfo->state->refresh), 0);
|
||||
timer_adjust_oneshot(scrinfo->vblank_end_timer, attotime_make(0, vblank_period), 0);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
vblank_end_callback - call any external
|
||||
callbacks to signal the VBLANK period has ended
|
||||
-------------------------------------------------*/
|
||||
|
||||
static TIMER_CALLBACK( vblank_end_callback )
|
||||
{
|
||||
internal_screen_info *scrinfo = ptr;
|
||||
|
||||
/* update the first screen if we didn't before */
|
||||
if ((machine->config->video_attributes & VIDEO_UPDATE_AFTER_VBLANK) && (scrinfo->scrnum == 0))
|
||||
video_frame_update(machine, FALSE);
|
||||
|
||||
/* let any external parties know that the VBLANK is over */
|
||||
call_vb_callbacks(machine, scrinfo, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
scanline0_callback - reset partial updates
|
||||
for a screen
|
||||
|
@ -88,6 +88,15 @@ struct _screen_config
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
video_screen_on_vblank - callback that a
|
||||
screen calls to notify of a change of
|
||||
the VBLANK state
|
||||
-------------------------------------------------*/
|
||||
|
||||
typedef void (*video_screen_on_vbl)(running_machine *machine, screen_state *screen, int vblank_state);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
@ -98,9 +107,6 @@ struct _screen_config
|
||||
/* core initialization */
|
||||
void video_init(running_machine *machine);
|
||||
|
||||
/* core VBLANK callback */
|
||||
void video_vblank_start(running_machine *machine);
|
||||
|
||||
|
||||
/* ----- screen management ----- */
|
||||
|
||||
@ -127,6 +133,9 @@ int video_screen_get_hblank(int scrnum);
|
||||
/* return the time when the beam will reach a particular H,V position */
|
||||
attotime video_screen_get_time_until_pos(int scrnum, int vpos, int hpos);
|
||||
|
||||
/* return the time when the beam will reach the start of VBLANK */
|
||||
attotime video_screen_get_time_until_vblank_start(int scrnum);
|
||||
|
||||
/* return the amount of time the beam takes to draw one scan line */
|
||||
attotime video_screen_get_scan_period(int scrnum);
|
||||
|
||||
@ -136,6 +145,8 @@ attotime video_screen_get_frame_period(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, video_screen_on_vbl vbl_cb);
|
||||
|
||||
|
||||
/* ----- video screen device interface ----- */
|
||||
|
Loading…
Reference in New Issue
Block a user