Add a GUI to ZBA #7

Merged
paoda merged 24 commits from imgui into main 2023-03-11 03:18:15 +00:00
2 changed files with 43 additions and 37 deletions
Showing only changes of commit a8fac5f3c6 - Show all commits

View File

@ -4,7 +4,7 @@ const config = @import("../config.zig");
const Scheduler = @import("scheduler.zig").Scheduler; const Scheduler = @import("scheduler.zig").Scheduler;
const Arm7tdmi = @import("cpu.zig").Arm7tdmi; const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
const FpsTracker = @import("../util.zig").FpsTracker; const Tracker = @import("../util.zig").FpsTracker;
const Timer = std.time.Timer; const Timer = std.time.Timer;
const Atomic = std.atomic.Atomic; const Atomic = std.atomic.Atomic;
@ -35,18 +35,18 @@ const RunKind = enum {
LimitedFPS, 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; const audio_sync = config.config().guest.audio_sync and !config.config().host.mute;
if (audio_sync) log.info("Audio sync enabled", .{}); if (audio_sync) log.info("Audio sync enabled", .{});
if (config.config().guest.video_sync) { if (config.config().guest.video_sync) {
inner(.LimitedFPS, audio_sync, quit, scheduler, cpu, tracker); inner(.LimitedFPS, audio_sync, quit, pause, cpu, scheduler, tracker);
} else { } 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) { if (kind == .UnlimitedFPS or kind == .LimitedFPS) {
std.debug.assert(tracker != null); std.debug.assert(tracker != null);
log.info("FPS tracking enabled", .{}); 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", .{}); log.info("Emulation w/out video sync", .{});
while (!quit.load(.Monotonic)) { while (!quit.load(.Monotonic)) {
if (pause.load(.Monotonic)) continue;
runFrame(scheduler, cpu); runFrame(scheduler, cpu);
audioSync(audio_sync, cpu.bus.apu.stream, &cpu.bus.apu.is_buffer_full); 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; var wake_time: u64 = frame_period;
while (!quit.load(.Monotonic)) { while (!quit.load(.Monotonic)) {
if (pause.load(.Monotonic)) continue;
runFrame(scheduler, cpu); runFrame(scheduler, cpu);
const new_wake_time = videoSync(&timer, wake_time); 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); const fbo_id = try Self.genFrameBufObject(out_tex);
defer gl.deleteFramebuffers(1, &fbo_id); defer gl.deleteFramebuffers(1, &fbo_id);
var quit = std.atomic.Atomic(bool).init(false);
var tracker = FpsTracker.init(); 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; var title_buf: [0x100]u8 = undefined;
@ -441,12 +442,6 @@ pub const Gui = struct {
SDL.SDLK_s => keyinput.shoulder_r.set(), SDL.SDLK_s => keyinput.shoulder_r.set(),
SDL.SDLK_RETURN => keyinput.start.set(), SDL.SDLK_RETURN => keyinput.start.set(),
SDL.SDLK_RSHIFT => keyinput.select.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 => {}, else => {},
} }
@ -456,37 +451,44 @@ pub const Gui = struct {
} }
} }
// We Access non-atomic parts of the Emulator here
{ {
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo_id); pause.store(true, .Monotonic);
defer gl.bindFramebuffer(gl.FRAMEBUFFER, 0); defer pause.store(false, .Monotonic);
const buf = cpu.bus.ppu.framebuf.get(.Renderer); self.state.fps_hist.push(tracker.value()) catch {};
gl.viewport(0, 0, gba_width, gba_height);
self.drawGbaTexture(obj_ids, emu_tex, buf); // 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); 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 { fn glGetProcAddress(ctx: SDL.SDL_GLContext, proc: [:0]const u8) ?*anyopaque {