diff options
Diffstat (limited to 'ui_sdl.zig')
| -rw-r--r-- | ui_sdl.zig | 201 |
1 files changed, 132 insertions, 69 deletions
@@ -25,6 +25,7 @@ const vaxis = @import("vaxis"); const ui_sdl_config = @import("ui_sdl_config"); const posix = std.posix; const linux = std.os.linux; +const os_tag = builtin.os.tag; const is_emscripten = builtin.os.tag == .emscripten; pub const c = @cImport({ @@ -150,7 +151,7 @@ capture_xfer_size: u32 = 0, capture_frame: u64 = 0, trace_enabled: bool = false, -trace_fd: c_int = -1, +trace_fd: posix.fd_t = -1, trace_every: u32 = 1, trace_frame: u64 = 0, @@ -233,9 +234,93 @@ fn envFlag(env_map: *std.process.Environ.Map, name: []const u8) bool { fn nowNs() i128 { if (is_emscripten) return @intCast(c.SDL_GetTicksNS()); - var ts: linux.timespec = undefined; - _ = linux.clock_gettime(linux.CLOCK.MONOTONIC, &ts); - return @as(i128, ts.sec) * 1_000_000_000 + @as(i128, ts.nsec); + switch (os_tag) { + .linux => { + var ts: linux.timespec = undefined; + _ = linux.clock_gettime(linux.CLOCK.MONOTONIC, &ts); + return @as(i128, ts.sec) * 1_000_000_000 + @as(i128, ts.nsec); + }, + else => { + var ts: posix.timespec = undefined; + switch (posix.errno(posix.system.clock_gettime(posix.CLOCK.MONOTONIC, &ts))) { + .SUCCESS => return @as(i128, ts.sec) * 1_000_000_000 + @as(i128, ts.nsec), + else => return 0, + } + }, + } +} + +fn openCreateTrunc(path: [*:0]const u8) ?posix.fd_t { + switch (os_tag) { + .linux => { + const fd_rc = linux.open(path, .{ .ACCMODE = .WRONLY, .CREAT = true, .TRUNC = true }, 0o644); + const fd_s: isize = @bitCast(fd_rc); + return if (fd_s < 0) null else @intCast(fd_s); + }, + else => return posix.openatZ(posix.AT.FDCWD, path, .{ + .ACCMODE = .WRONLY, + .CREAT = true, + .TRUNC = true, + }, 0o644) catch null, + } +} + +fn closeFdBestEffort(fd: posix.fd_t) void { + switch (os_tag) { + .linux => _ = linux.close(fd), + else => switch (posix.errno(posix.system.close(fd))) { + .SUCCESS, .INTR => {}, + else => {}, + }, + } +} + +fn writeAllFd(fd: posix.fd_t, bytes: []const u8) !void { + var off: usize = 0; + while (off < bytes.len) { + switch (os_tag) { + .linux => { + const rc = linux.write(fd, bytes[off..].ptr, bytes.len - off); + const n: isize = @bitCast(rc); + if (n < 0) { + if (n == -@as(isize, @intFromEnum(linux.E.INTR))) continue; + return error.WriteFailed; + } + if (n == 0) return error.WriteFailed; + off += @intCast(n); + }, + else => { + const rc = posix.system.write(fd, bytes[off..].ptr, bytes.len - off); + switch (posix.errno(rc)) { + .SUCCESS => { + const n: usize = @intCast(rc); + if (n == 0) return error.WriteFailed; + off += n; + }, + .INTR => continue, + else => return error.WriteFailed, + } + }, + } + } +} + +fn writeAllFdIgnore(fd: posix.fd_t, bytes: []const u8) void { + writeAllFd(fd, bytes) catch {}; +} + +fn renameZ(old_path: [*:0]const u8, new_path: [*:0]const u8) !void { + switch (os_tag) { + .linux => { + const rr = linux.rename(old_path, new_path); + const rs: isize = @bitCast(rr); + if (rs < 0) return error.RenameFailed; + }, + else => switch (posix.errno(posix.system.rename(old_path, new_path))) { + .SUCCESS => {}, + else => return error.RenameFailed, + }, + } } fn nsToUs(delta: i128) u64 { @@ -302,7 +387,7 @@ pub fn init( } const trace_enabled = envFlag(env_map, "PARDES_SDL_TRACE"); const trace_every = envU32(env_map, "PARDES_SDL_TRACE_EVERY") orelse 1; - var trace_fd: c_int = -1; + var trace_fd: posix.fd_t = -1; if (!is_emscripten and trace_enabled) { if (env_map.get("PARDES_SDL_TRACE_FILE")) |path| { trace_fd = openTraceFile(path); @@ -463,7 +548,7 @@ fn initGl( test_mode: bool, capture_dir: ?[]const u8, trace_enabled: bool, - trace_fd: c_int, + trace_fd: posix.fd_t, trace_every: u32, ) !SdlBackend { _ = c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_PROFILE_MASK, c.SDL_GL_CONTEXT_PROFILE_ES); @@ -606,7 +691,7 @@ pub fn deinit(self: *SdlBackend, alloc: ?std.mem.Allocator, writer: *std.Io.Writ } if (self.capture_tex) |t| c.SDL_ReleaseGPUTexture(self.device, t); if (self.capture_xfer) |x| c.SDL_ReleaseGPUTransferBuffer(self.device, x); - if (self.trace_fd >= 0 and self.trace_fd != 2) _ = linux.close(self.trace_fd); + if (self.trace_fd >= 0 and self.trace_fd != 2) closeFdBestEffort(self.trace_fd); c.SDL_ReleaseGPUBuffer(self.device, self.vbuf); c.SDL_ReleaseGPUTransferBuffer(self.device, self.vxfer); self.alloc.free(self.cell_keys); @@ -994,17 +1079,7 @@ fn dumpGrid(self: *SdlBackend) !void { } buf.appendSlice(self.alloc, "---ENDFRAME---\n") catch return; - // write to stdout (fd 1) - var off: usize = 0; - while (off < buf.items.len) { - const rc = linux.write(1, buf.items[off..].ptr, buf.items.len - off); - const n: isize = @bitCast(rc); - if (n < 0) { - if (n == -@as(isize, @intFromEnum(linux.E.INTR))) continue; - return; - } - off += @intCast(n); - } + try writeAllFd(1, buf.items); } fn captureSwapchain(self: *SdlBackend, cmd: *c.SDL_GPUCommandBuffer, target: *c.SDL_GPUTexture, sw: u32, sh: u32) !void { @@ -1094,11 +1169,8 @@ fn writeCapturePpm(self: *SdlBackend, pixels: []const u8, width: u32, height: u3 const tmp_path = std.fmt.bufPrintZ(&tmp_buf, "{s}/latest.ppm.tmp", .{dir}) catch return error.CapturePathTooLong; const final_path = std.fmt.bufPrintZ(&final_buf, "{s}/latest.ppm", .{dir}) catch return error.CapturePathTooLong; - const fd_rc = linux.open(tmp_path.ptr, .{ .ACCMODE = .WRONLY, .CREAT = true, .TRUNC = true }, 0o644); - const fd_s: isize = @bitCast(fd_rc); - if (fd_s < 0) return error.CaptureWriteFailed; - const fd: c_int = @intCast(fd_s); - defer _ = linux.close(fd); + const fd = openCreateTrunc(tmp_path.ptr) orelse return error.CaptureWriteFailed; + defer closeFdBestEffort(fd); var header: [64]u8 = undefined; const hdr = std.fmt.bufPrint(&header, "P6\n{d} {d}\n255\n", .{ width, height }) catch return error.CaptureWriteFailed; @@ -1134,47 +1206,14 @@ fn writeCapturePpm(self: *SdlBackend, pixels: []const u8, width: u32, height: u3 try writeAllFd(fd, row_rgb); } - const rr = linux.rename(tmp_path.ptr, final_path.ptr); - const rs: isize = @bitCast(rr); - if (rs < 0) return error.CaptureWriteFailed; + renameZ(tmp_path.ptr, final_path.ptr) catch return error.CaptureWriteFailed; self.capture_frame += 1; } -fn writeAllFd(fd: c_int, bytes: []const u8) !void { - var off: usize = 0; - while (off < bytes.len) { - const rc = linux.write(fd, bytes[off..].ptr, bytes.len - off); - const n: isize = @bitCast(rc); - if (n < 0) { - if (n == -@as(isize, @intFromEnum(linux.E.INTR))) continue; - return error.CaptureWriteFailed; - } - if (n == 0) return error.CaptureWriteFailed; - off += @intCast(n); - } -} - -fn openTraceFile(path: []const u8) c_int { +fn openTraceFile(path: []const u8) posix.fd_t { var buf: [4096]u8 = undefined; const z = std.fmt.bufPrintZ(&buf, "{s}", .{path}) catch return 2; - const fd_rc = linux.open(z.ptr, .{ .ACCMODE = .WRONLY, .CREAT = true, .TRUNC = true }, 0o644); - const fd_s: isize = @bitCast(fd_rc); - if (fd_s < 0) return 2; - return @intCast(fd_s); -} - -fn writeAllFdIgnore(fd: c_int, bytes: []const u8) void { - var off: usize = 0; - while (off < bytes.len) { - const rc = linux.write(fd, bytes[off..].ptr, bytes.len - off); - const n: isize = @bitCast(rc); - if (n < 0) { - if (n == -@as(isize, @intFromEnum(linux.E.INTR))) continue; - return; - } - if (n == 0) return; - off += @intCast(n); - } + return openCreateTrunc(z.ptr) orelse 2; } fn tracef(self: *SdlBackend, comptime fmt: []const u8, args: anytype) void { @@ -1759,7 +1798,7 @@ fn SdlLoop(comptime EventType: type) type { if (!is_emscripten and self.vx.test_mode) { // read winsize from stdin (fd 0 = the pty slave) var ws: posix.winsize = std.mem.zeroes(posix.winsize); - const iorc = posix.system.ioctl(0, posix.T.IOCGWINSZ, @intFromPtr(&ws)); + const iorc = posix.system.ioctl(0, tiocgwinszReq(), @intFromPtr(&ws)); if (iorc < 0) return; // fd 0 is not a pty const cols: u16 = ws.col; const rows: u16 = ws.row; @@ -1968,14 +2007,9 @@ fn SdlLoop(comptime EventType: type) type { _ = posix.poll(&fds, 50) catch continue; if ((fds[0].revents & posix.POLL.IN) == 0) continue; - const rc = linux.read(0, buf[read_start..].ptr, buf.len - read_start); - const n: isize = @bitCast(rc); - if (n < 0) { - if (n == -@as(isize, @intFromEnum(linux.E.INTR))) continue; - break; - } + const n = readStdin(buf[read_start..]) catch break; if (n == 0) break; - const len: usize = read_start + @as(usize, @intCast(n)); + const len: usize = read_start + n; var seq_start: usize = 0; while (seq_start < len) { const result = parser.parse(buf[seq_start..len], null) catch break; @@ -2023,11 +2057,40 @@ fn setStdinRaw() !void { term.lflag.ICANON = false; term.lflag.IEXTEN = false; term.lflag.ISIG = false; - term.cc[@intFromEnum(linux.V.MIN)] = 1; - term.cc[@intFromEnum(linux.V.TIME)] = 0; + term.cc[@intFromEnum(posix.V.MIN)] = 1; + term.cc[@intFromEnum(posix.V.TIME)] = 0; try posix.tcsetattr(0, .NOW, term); } +fn ioctlReq(bits: u32) c_int { + return @bitCast(bits); +} + +fn tiocgwinszReq() c_int { + return switch (os_tag) { + .linux => @intCast(posix.T.IOCGWINSZ), + .macos, .freebsd, .openbsd, .netbsd, .dragonfly => ioctlReq(0x40087468), + else => @intCast(posix.T.IOCGWINSZ), + }; +} + +fn readStdin(buf: []u8) !usize { + switch (os_tag) { + .linux => { + while (true) { + const rc = linux.read(0, buf.ptr, buf.len); + const n: isize = @bitCast(rc); + if (n < 0) { + if (n == -@as(isize, @intFromEnum(linux.E.INTR))) continue; + return error.ReadFailed; + } + return @intCast(n); + } + }, + else => return posix.read(0, buf), + } +} + // ---- test-mode SIGWINCH handler ---- // Signal handlers can't take closures, so we just set a flag; the stdin reader // (SdlLoop.stdinRunTyped) checks it and reads + posts the new winsize. |
