diff --git a/src/core/emu.zig b/src/core/emu.zig index 1a84c11..11931d7 100644 --- a/src/core/emu.zig +++ b/src/core/emu.zig @@ -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); diff --git a/src/platform.zig b/src/platform.zig index 1b3c533..3fe8ab8 100644 --- a/src/platform.zig +++ b/src/platform.zig @@ -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 {