feat: pause emu when UI reads emu state

This commit is contained in:
Rekai Nyangadzayi Musuka 2023-01-08 19:26:48 -06:00
parent ae78588b80
commit a8fac5f3c6
2 changed files with 43 additions and 37 deletions

View File

@ -4,7 +4,7 @@ const config = @import("../config.zig");
const Scheduler = @import("scheduler.zig").Scheduler;
const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
const FpsTracker = @import("../util.zig").FpsTracker;
const Tracker = @import("../util.zig").FpsTracker;
const Timer = std.time.Timer;
const Atomic = std.atomic.Atomic;
@ -35,18 +35,18 @@ const RunKind = enum {
LimitedFPS,
};
pub fn run(quit: *Atomic(bool), scheduler: *Scheduler, cpu: *Arm7tdmi, tracker: *FpsTracker) void {
pub fn run(quit: *Atomic(bool), pause: *Atomic(bool), cpu: *Arm7tdmi, scheduler: *Scheduler, tracker: *Tracker) void {
const audio_sync = config.config().guest.audio_sync and !config.config().host.mute;
if (audio_sync) log.info("Audio sync enabled", .{});
if (config.config().guest.video_sync) {
inner(.LimitedFPS, audio_sync, quit, scheduler, cpu, tracker);
inner(.LimitedFPS, audio_sync, quit, pause, cpu, scheduler, tracker);
} else {
inner(.UnlimitedFPS, audio_sync, quit, scheduler, cpu, tracker);
inner(.UnlimitedFPS, audio_sync, quit, pause, cpu, scheduler, tracker);
}
}
fn inner(comptime kind: RunKind, audio_sync: bool, quit: *Atomic(bool), scheduler: *Scheduler, cpu: *Arm7tdmi, tracker: ?*FpsTracker) void {
fn inner(comptime kind: RunKind, audio_sync: bool, quit: *Atomic(bool), pause: *Atomic(bool), cpu: *Arm7tdmi, scheduler: *Scheduler, tracker: ?*Tracker) void {
if (kind == .UnlimitedFPS or kind == .LimitedFPS) {
std.debug.assert(tracker != null);
log.info("FPS tracking enabled", .{});
@ -57,6 +57,8 @@ fn inner(comptime kind: RunKind, audio_sync: bool, quit: *Atomic(bool), schedule
log.info("Emulation w/out video sync", .{});
while (!quit.load(.Monotonic)) {
if (pause.load(.Monotonic)) continue;
runFrame(scheduler, cpu);
audioSync(audio_sync, cpu.bus.apu.stream, &cpu.bus.apu.is_buffer_full);
@ -69,6 +71,8 @@ fn inner(comptime kind: RunKind, audio_sync: bool, quit: *Atomic(bool), schedule
var wake_time: u64 = frame_period;
while (!quit.load(.Monotonic)) {
if (pause.load(.Monotonic)) continue;
runFrame(scheduler, cpu);
const new_wake_time = videoSync(&timer, wake_time);

View File

@ -389,8 +389,9 @@ pub const Gui = struct {
const fbo_id = try Self.genFrameBufObject(out_tex);
defer gl.deleteFramebuffers(1, &fbo_id);
var quit = std.atomic.Atomic(bool).init(false);
var tracker = FpsTracker.init();
var quit = std.atomic.Atomic(bool).init(false);
var pause = std.atomic.Atomic(bool).init(false);
var title_buf: [0x100]u8 = undefined;
@ -441,12 +442,6 @@ pub const Gui = struct {
SDL.SDLK_s => keyinput.shoulder_r.set(),
SDL.SDLK_RETURN => keyinput.start.set(),
SDL.SDLK_RSHIFT => keyinput.select.set(),
SDL.SDLK_i => {
comptime std.debug.assert(sample_format == SDL.AUDIO_U16);
log.err("Sample Count: {}", .{@intCast(u32, SDL.SDL_AudioStreamAvailable(cpu.bus.apu.stream)) / (2 * @sizeOf(u16))});
},
// SDL.SDLK_j => log.err("Scheduler Capacity: {} | Scheduler Event Count: {}", .{ scheduler.queue.capacity(), scheduler.queue.count() }),
SDL.SDLK_k => {},
else => {},
}
@ -456,37 +451,44 @@ pub const Gui = struct {
}
}
// We Access non-atomic parts of the Emulator here
{
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo_id);
defer gl.bindFramebuffer(gl.FRAMEBUFFER, 0);
pause.store(true, .Monotonic);
defer pause.store(false, .Monotonic);
const buf = cpu.bus.ppu.framebuf.get(.Renderer);
gl.viewport(0, 0, gba_width, gba_height);
self.drawGbaTexture(obj_ids, emu_tex, buf);
self.state.fps_hist.push(tracker.value()) catch {};
// Draw GBA Screen to Texture
{
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo_id);
defer gl.bindFramebuffer(gl.FRAMEBUFFER, 0);
const buf = cpu.bus.ppu.framebuf.get(.Renderer);
gl.viewport(0, 0, gba_width, gba_height);
self.drawGbaTexture(obj_ids, emu_tex, buf);
}
// Background Colour
const size = zgui.io.getDisplaySize();
gl.viewport(0, 0, @floatToInt(c_int, size[0]), @floatToInt(c_int, size[1]));
gl.clearColor(0, 0, 0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
if (tracker) |t| {
const emu_fps = t.value();
self.state.fps_hist.push(emu_fps) catch {};
const dyn_title = std.fmt.bufPrintZ(&title_buf, "ZBA | {s} [Emu: {}fps] ", .{ self.title, emu_fps }) catch unreachable;
SDL.SDL_SetWindowTitle(self.window, dyn_title.ptr);
}
zgui.backend.newFrame(width, height);
self.draw(out_tex, cpu);
zgui.backend.draw();
}
// Background
const size = zgui.io.getDisplaySize();
gl.viewport(0, 0, @floatToInt(c_int, size[0]), @floatToInt(c_int, size[1]));
gl.clearColor(0, 0, 0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
zgui.backend.newFrame(width, height);
self.draw(out_tex, cpu);
zgui.backend.draw();
SDL.SDL_GL_SwapWindow(self.window);
if (tracker) |t| {
const emu_fps = t.value();
self.state.fps_hist.push(emu_fps) catch {};
const dyn_title = std.fmt.bufPrintZ(&title_buf, "ZBA | {s} [Emu: {}fps] ", .{ self.title, emu_fps }) catch unreachable;
SDL.SDL_SetWindowTitle(self.window, dyn_title.ptr);
}
}
quit.store(true, .Monotonic); // Terminate Emulator Thread
}
fn glGetProcAddress(ctx: SDL.SDL_GLContext, proc: [:0]const u8) ?*anyopaque {