chore(ui): rewrite channel implementation
This commit is contained in:
		 Submodule lib/zba-util updated: 72349459ec...77d11c9903
									
								
							@@ -5,7 +5,9 @@ const config = @import("../config.zig");
 | 
			
		||||
const Scheduler = @import("scheduler.zig").Scheduler;
 | 
			
		||||
const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
 | 
			
		||||
const Tracker = @import("../util.zig").FpsTracker;
 | 
			
		||||
const TwoWayChannel = @import("zba-util").TwoWayChannel;
 | 
			
		||||
const Channel = @import("zba-util").Channel(Message, 0x100);
 | 
			
		||||
 | 
			
		||||
pub const Message = enum { Pause, Resume, Quit };
 | 
			
		||||
 | 
			
		||||
const Timer = std.time.Timer;
 | 
			
		||||
 | 
			
		||||
@@ -35,18 +37,18 @@ const RunKind = enum {
 | 
			
		||||
    LimitedFPS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub fn run(cpu: *Arm7tdmi, scheduler: *Scheduler, tracker: *Tracker, channel: *TwoWayChannel) void {
 | 
			
		||||
pub fn run(cpu: *Arm7tdmi, scheduler: *Scheduler, tracker: *Tracker, rx: Channel.Receiver) 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, cpu, scheduler, tracker, channel);
 | 
			
		||||
        inner(.LimitedFPS, audio_sync, cpu, scheduler, tracker, rx);
 | 
			
		||||
    } else {
 | 
			
		||||
        inner(.UnlimitedFPS, audio_sync, cpu, scheduler, tracker, channel);
 | 
			
		||||
        inner(.UnlimitedFPS, audio_sync, cpu, scheduler, tracker, rx);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn inner(comptime kind: RunKind, audio_sync: bool, cpu: *Arm7tdmi, scheduler: *Scheduler, tracker: ?*Tracker, channel: *TwoWayChannel) void {
 | 
			
		||||
fn inner(comptime kind: RunKind, audio_sync: bool, cpu: *Arm7tdmi, scheduler: *Scheduler, tracker: ?*Tracker, rx: Channel.Receiver) void {
 | 
			
		||||
    if (kind == .UnlimitedFPS or kind == .LimitedFPS) {
 | 
			
		||||
        std.debug.assert(tracker != null);
 | 
			
		||||
        log.info("FPS tracking enabled", .{});
 | 
			
		||||
@@ -59,13 +61,9 @@ fn inner(comptime kind: RunKind, audio_sync: bool, cpu: *Arm7tdmi, scheduler: *S
 | 
			
		||||
            log.info("Emulation w/out video sync", .{});
 | 
			
		||||
 | 
			
		||||
            while (true) {
 | 
			
		||||
                if (channel.emu.pop()) |e| switch (e) {
 | 
			
		||||
                if (rx.recv()) |m| switch (m) {
 | 
			
		||||
                    .Quit => break,
 | 
			
		||||
                    .Resume => paused = false,
 | 
			
		||||
                    .Pause => {
 | 
			
		||||
                        paused = true;
 | 
			
		||||
                        channel.gui.push(.Paused);
 | 
			
		||||
                    },
 | 
			
		||||
                    .Resume, .Pause => paused = m == .Pause,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if (paused) continue;
 | 
			
		||||
@@ -82,13 +80,9 @@ fn inner(comptime kind: RunKind, audio_sync: bool, cpu: *Arm7tdmi, scheduler: *S
 | 
			
		||||
            var wake_time: u64 = frame_period;
 | 
			
		||||
 | 
			
		||||
            while (true) {
 | 
			
		||||
                if (channel.emu.pop()) |e| switch (e) {
 | 
			
		||||
                if (rx.recv()) |m| switch (m) {
 | 
			
		||||
                    .Quit => break,
 | 
			
		||||
                    .Resume => paused = false,
 | 
			
		||||
                    .Pause => {
 | 
			
		||||
                        paused = true;
 | 
			
		||||
                        channel.gui.push(.Paused);
 | 
			
		||||
                    },
 | 
			
		||||
                    .Resume, .Pause => paused = m == .Pause,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if (paused) continue;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								src/main.zig
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/main.zig
									
									
									
									
									
								
							@@ -6,7 +6,7 @@ const clap = @import("clap");
 | 
			
		||||
const config = @import("config.zig");
 | 
			
		||||
const emu = @import("core/emu.zig");
 | 
			
		||||
 | 
			
		||||
const TwoWayChannel = @import("zba-util").TwoWayChannel;
 | 
			
		||||
const Channel = @import("zba-util").Channel(emu.Message, 0x100);
 | 
			
		||||
const Gui = @import("platform.zig").Gui;
 | 
			
		||||
const Bus = @import("core/Bus.zig");
 | 
			
		||||
const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
 | 
			
		||||
@@ -98,8 +98,8 @@ pub fn main() void {
 | 
			
		||||
 | 
			
		||||
    var quit = std.atomic.Atomic(bool).init(false);
 | 
			
		||||
 | 
			
		||||
    var items: [0x100]u8 = undefined;
 | 
			
		||||
    var channel = TwoWayChannel.init(&items);
 | 
			
		||||
    var ch = Channel.init(allocator) catch |e| exitln("failed to initialize ui -> emu thread message channel: {}", .{e});
 | 
			
		||||
    defer ch.deinit(allocator);
 | 
			
		||||
 | 
			
		||||
    if (result.args.gdb != 0) {
 | 
			
		||||
        const Server = @import("gdbstub").Server;
 | 
			
		||||
@@ -122,22 +122,22 @@ pub fn main() void {
 | 
			
		||||
        gui.run(.Debug, .{
 | 
			
		||||
            .cpu = &cpu,
 | 
			
		||||
            .scheduler = &scheduler,
 | 
			
		||||
            .channel = &channel,
 | 
			
		||||
            .ch = ch.tx,
 | 
			
		||||
        }) catch |e| exitln("main thread panicked: {}", .{e});
 | 
			
		||||
    } else {
 | 
			
		||||
        var tracker = FpsTracker.init();
 | 
			
		||||
 | 
			
		||||
        // emu should start paused if there's no ROM to run
 | 
			
		||||
        if (paths.rom == null)
 | 
			
		||||
            channel.emu.push(.Pause);
 | 
			
		||||
            ch.tx.send(.Pause);
 | 
			
		||||
 | 
			
		||||
        const thread = std.Thread.spawn(.{}, emu.run, .{ &cpu, &scheduler, &tracker, &channel }) catch |e| exitln("emu thread panicked: {}", .{e});
 | 
			
		||||
        const thread = std.Thread.spawn(.{}, emu.run, .{ &cpu, &scheduler, &tracker, ch.rx }) catch |e| exitln("emu thread panicked: {}", .{e});
 | 
			
		||||
        defer thread.join();
 | 
			
		||||
 | 
			
		||||
        gui.run(.Standard, .{
 | 
			
		||||
            .cpu = &cpu,
 | 
			
		||||
            .scheduler = &scheduler,
 | 
			
		||||
            .channel = &channel,
 | 
			
		||||
            .ch = ch.tx,
 | 
			
		||||
            .tracker = &tracker,
 | 
			
		||||
        }) catch |e| exitln("main thread panicked: {}", .{e});
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ const Apu = @import("core/apu.zig").Apu;
 | 
			
		||||
const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
 | 
			
		||||
const Scheduler = @import("core/scheduler.zig").Scheduler;
 | 
			
		||||
const FpsTracker = @import("util.zig").FpsTracker;
 | 
			
		||||
const TwoWayChannel = @import("zba-util").TwoWayChannel;
 | 
			
		||||
const Channel = @import("zba-util").Channel(emu.Message, 0x100);
 | 
			
		||||
const KeyInput = @import("core/bus/io.zig").KeyInput;
 | 
			
		||||
 | 
			
		||||
const gba_width = @import("core/ppu.zig").width;
 | 
			
		||||
@@ -94,7 +94,7 @@ pub const Gui = struct {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const RunOptions = struct {
 | 
			
		||||
        channel: *TwoWayChannel,
 | 
			
		||||
        ch: Channel.Sender,
 | 
			
		||||
        tracker: ?*FpsTracker = null,
 | 
			
		||||
        cpu: *Arm7tdmi,
 | 
			
		||||
        scheduler: *Scheduler,
 | 
			
		||||
@@ -105,7 +105,7 @@ pub const Gui = struct {
 | 
			
		||||
    pub fn run(self: *Self, comptime mode: RunMode, opt: RunOptions) !void {
 | 
			
		||||
        const cpu = opt.cpu;
 | 
			
		||||
        const tracker = opt.tracker;
 | 
			
		||||
        const channel = opt.channel;
 | 
			
		||||
        const ch = opt.ch;
 | 
			
		||||
 | 
			
		||||
        const objects = opengl_impl.createObjects();
 | 
			
		||||
        defer gl.deleteBuffers(3, @as(*const [3]GLuint, &.{ objects.vao, objects.vbo, objects.ebo }));
 | 
			
		||||
@@ -193,54 +193,50 @@ pub const Gui = struct {
 | 
			
		||||
            switch (self.state.emulation) {
 | 
			
		||||
                .Transition => |inner| switch (inner) {
 | 
			
		||||
                    .Active => {
 | 
			
		||||
                        _ = channel.gui.pop();
 | 
			
		||||
 | 
			
		||||
                        channel.emu.push(.Resume);
 | 
			
		||||
                        ch.send(.Resume);
 | 
			
		||||
                        if (!config.config().host.mute) SDL.SDL_PauseAudioDevice(self.audio.device, 0);
 | 
			
		||||
 | 
			
		||||
                        self.state.emulation = .Active;
 | 
			
		||||
                    },
 | 
			
		||||
                    .Inactive => {
 | 
			
		||||
                        // Assert that double pausing is impossible
 | 
			
		||||
                        if (channel.gui.peek()) |value|
 | 
			
		||||
                            std.debug.assert(value != .Paused);
 | 
			
		||||
 | 
			
		||||
                        SDL.SDL_PauseAudioDevice(self.audio.device, 1);
 | 
			
		||||
                        channel.emu.push(.Pause);
 | 
			
		||||
                        ch.send(.Pause);
 | 
			
		||||
 | 
			
		||||
                        self.state.emulation = .Inactive;
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                .Active => skip_draw: {
 | 
			
		||||
                .Active => {
 | 
			
		||||
                    const is_std = mode == .Standard;
 | 
			
		||||
 | 
			
		||||
                    if (is_std) channel.emu.push(.Pause);
 | 
			
		||||
                    defer if (is_std) channel.emu.push(.Resume);
 | 
			
		||||
                    if (is_std) ch.send(.Pause);
 | 
			
		||||
                    defer if (is_std) ch.send(.Resume);
 | 
			
		||||
 | 
			
		||||
                    switch (mode) {
 | 
			
		||||
                        .Standard => blk: {
 | 
			
		||||
                            const limit = 15; // TODO: What should this be?
 | 
			
		||||
                    // switch (mode) {
 | 
			
		||||
                    //     .Standard => blk: {
 | 
			
		||||
                    //         const limit = 15; // TODO: What should this be?
 | 
			
		||||
 | 
			
		||||
                            // TODO: learn more about std.atomic.spinLoopHint();
 | 
			
		||||
                            for (0..limit) |_| {
 | 
			
		||||
                                const message = channel.gui.pop() orelse continue;
 | 
			
		||||
                    //         // TODO: learn more about std.atomic.spinLoopHint();
 | 
			
		||||
                    //         for (0..limit) |_| {
 | 
			
		||||
                    //             const message = channel.gui.pop() orelse continue;
 | 
			
		||||
 | 
			
		||||
                                switch (message) {
 | 
			
		||||
                                    .Paused => break :blk,
 | 
			
		||||
                                    .Quit => unreachable,
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                    //             switch (message) {
 | 
			
		||||
                    //                 .Paused => break :blk,
 | 
			
		||||
                    //                 .Quit => unreachable,
 | 
			
		||||
                    //             }
 | 
			
		||||
                    //         }
 | 
			
		||||
 | 
			
		||||
                            log.info("timed out waiting for emu thread to pause (limit: {})", .{limit});
 | 
			
		||||
                            break :skip_draw;
 | 
			
		||||
                        },
 | 
			
		||||
                        .Debug => blk: {
 | 
			
		||||
                            switch (channel.gui.pop() orelse break :blk) {
 | 
			
		||||
                                .Paused => unreachable, // only in standard mode
 | 
			
		||||
                                .Quit => break :emu_loop, // FIXME: gdb side of emu is seriously out-of-date...
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                    }
 | 
			
		||||
                    //         log.info("timed out waiting for emu thread to pause (limit: {})", .{limit});
 | 
			
		||||
                    //         break :skip_draw;
 | 
			
		||||
                    //     },
 | 
			
		||||
                    //     .Debug => blk: {
 | 
			
		||||
                    //         switch (channel.gui.pop() orelse break :blk) {
 | 
			
		||||
                    //             .Paused => unreachable, // only in standard mode
 | 
			
		||||
                    //             .Quit => break :emu_loop, // FIXME: gdb side of emu is seriously out-of-date...
 | 
			
		||||
                    //         }
 | 
			
		||||
                    //     },
 | 
			
		||||
                    // }
 | 
			
		||||
 | 
			
		||||
                    // Add FPS count to the histogram
 | 
			
		||||
                    if (tracker) |t| self.state.fps_hist.push(t.value()) catch {};
 | 
			
		||||
@@ -279,7 +275,7 @@ pub const Gui = struct {
 | 
			
		||||
            SDL.SDL_GL_SwapWindow(self.window);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        channel.emu.push(.Quit);
 | 
			
		||||
        ch.send(.Quit);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn glGetProcAddress(ctx: SDL.SDL_GLContext, proc: [:0]const u8) ?*anyopaque {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user