feat: pause emu when UI reads emu state
This commit is contained in:
parent
ae78588b80
commit
a8fac5f3c6
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue