Optimize emulator frame loop

Syncronize to number of cycles performed instead of VCOUNT when
emulating a frame


Former-commit-id: 0f9afe6a95a576dbb7a15cd1bf6bfb7d7ce02fff
This commit is contained in:
Michel Heily 2020-04-10 00:28:59 +03:00
parent ff95b67ae1
commit 8f8204a52b
3 changed files with 23 additions and 10 deletions

View file

@ -24,6 +24,8 @@ pub struct GameBoyAdvance {
pub input_device: Rc<RefCell<dyn InputInterface>>, pub input_device: Rc<RefCell<dyn InputInterface>>,
pub cycles_to_next_event: usize, pub cycles_to_next_event: usize,
overshoot_cycles: usize,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -58,6 +60,7 @@ impl GameBoyAdvance {
input_device: input_device, input_device: input_device,
cycles_to_next_event: 1, cycles_to_next_event: 1,
overshoot_cycles: 0,
}; };
gba.sysbus.created(); gba.sysbus.created();
@ -93,12 +96,20 @@ impl GameBoyAdvance {
pub fn frame(&mut self) { pub fn frame(&mut self) {
self.key_poll(); self.key_poll();
while self.sysbus.io.gpu.vcount != DISPLAY_HEIGHT {
self.step(); let mut remaining_cycles = 280896 - self.overshoot_cycles;
while remaining_cycles > 0 {
let cycles = self.step();
if remaining_cycles >= cycles {
remaining_cycles -= cycles;
} else {
self.overshoot_cycles = cycles - remaining_cycles;
return;
} }
while self.sysbus.io.gpu.vcount == DISPLAY_HEIGHT {
self.step();
} }
self.overshoot_cycles = 0;
} }
pub fn add_breakpoint(&mut self, addr: u32) -> Option<usize> { pub fn add_breakpoint(&mut self, addr: u32) -> Option<usize> {
@ -137,7 +148,7 @@ impl GameBoyAdvance {
self.cpu.cycles - previous_cycles self.cpu.cycles - previous_cycles
} }
pub fn step(&mut self) { pub fn step(&mut self) -> usize {
// I hate myself for doing this, but rust left me no choice. // I hate myself for doing this, but rust left me no choice.
let io = unsafe { let io = unsafe {
let ptr = &mut *self.sysbus as *mut SysBus; let ptr = &mut *self.sysbus as *mut SysBus;
@ -162,7 +173,7 @@ impl GameBoyAdvance {
} else { } else {
io.dmac.perform_work(&mut self.sysbus, &mut irqs); io.dmac.perform_work(&mut self.sysbus, &mut irqs);
io.intc.request_irqs(irqs); io.intc.request_irqs(irqs);
return; return cycles;
}; };
cycles += _cycles; cycles += _cycles;
@ -174,7 +185,7 @@ impl GameBoyAdvance {
// update gpu & sound // update gpu & sound
io.timers.update(cycles, &mut self.sysbus, &mut irqs); io.timers.update(cycles, &mut self.sysbus, &mut irqs);
io.gpu.step( io.gpu.update(
cycles, cycles,
&mut self.sysbus, &mut self.sysbus,
&mut irqs, &mut irqs,
@ -185,6 +196,8 @@ impl GameBoyAdvance {
.update(cycles, &mut cycles_to_next_event, &self.audio_device); .update(cycles, &mut cycles_to_next_event, &self.audio_device);
self.cycles_to_next_event = cycles_to_next_event; self.cycles_to_next_event = cycles_to_next_event;
io.intc.request_irqs(irqs); io.intc.request_irqs(irqs);
cycles
} }
/// Query the emulator for the recently drawn framebuffer. /// Query the emulator for the recently drawn framebuffer.

View file

@ -451,7 +451,7 @@ impl Gpu {
} }
// Returns the new gpu state // Returns the new gpu state
pub fn step( pub fn update(
&mut self, &mut self,
cycles: usize, cycles: usize,
sb: &mut SysBus, sb: &mut SysBus,

View file

@ -42,7 +42,7 @@ impl Target for GameBoyAdvance {
if self.cycles_to_next_event <= unsafe { S_TOTAL_CYCLES } { if self.cycles_to_next_event <= unsafe { S_TOTAL_CYCLES } {
let mut cycles_to_next_event = std::usize::MAX; let mut cycles_to_next_event = std::usize::MAX;
io.gpu.step( io.gpu.update(
unsafe { S_TOTAL_CYCLES }, unsafe { S_TOTAL_CYCLES },
&mut self.sysbus, &mut self.sysbus,
&mut irqs, &mut irqs,