summaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/gui.zig30
1 files changed, 30 insertions, 0 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 8da6f933..17bdb46f 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -2096,6 +2096,12 @@ fn runNative(init: std.process.Init, opts_in: pardes.Options, attach: ?[]const u
log.err("PARDES_TEST requires PARDES_TEST_CAPTURE_DIR", .{});
return error.SdlInit;
}
+ if (test_mode) if (env.get("PARDES_TEST_LATENCY")) |path| {
+ var path_buf: [4096]u8 = undefined;
+ if (std.fmt.bufPrintSentinel(&path_buf, "{s}", .{path}, 0)) |z|
+ latency_fd = libc.open(z, .{ .ACCMODE = .WRONLY, .CREAT = true, .TRUNC = true, .CLOEXEC = true }, @as(libc.mode_t, 0o644))
+ else |_| {}
+ };
_ = c.SDL_SetHint("SDL_JOYSTICK_HIDAPI", "1"); // SDL_HINT_JOYSTICK_HIDAPI
_ = c.SDL_SetHint("SDL_JOYSTICK_HIDAPI_STEAMDECK", "1"); // ..._STEAMDECK
@@ -2105,6 +2111,8 @@ fn runNative(init: std.process.Init, opts_in: pardes.Options, attach: ?[]const u
}
var win_flags: c.SDL_WindowFlags = c.SDL_WINDOW_RESIZABLE;
if (!test_mode) win_flags |= c.SDL_WINDOW_HIGH_PIXEL_DENSITY;
+ // A latency run renders to the capture texture; keep it off the desktop.
+ if (latency_fd >= 0) win_flags |= c.SDL_WINDOW_HIDDEN;
const native_wayland = !test_mode and std.mem.eql(u8, std.mem.span(c.SDL_GetCurrentVideoDriver()), "wayland");
// Background-only opacity needs per-pixel alpha; whole-window compositor
// opacity would dim the text as well. SDL requires this flag at creation.
@@ -2769,6 +2777,7 @@ const StdinFeed = struct {
}
const rn = libc.read(0, f.buf[f.fill..].ptr, f.buf.len - f.fill);
if (rn < 0) return out;
+ if (rn > 0) latencyNote("R {d}\n", .{monoNs()});
if (rn == 0) {
out.eof = true;
return out;
@@ -3884,6 +3893,7 @@ fn present(ctx: ?*anyopaque, surface: *const pardes.Surface) void {
const s = shellOf(ctx);
const core = s.core;
const g = s.gui orelse return;
+ frame_started_ns = monoNs();
const frame = @constCast(surface);
s.surface = frame;
const scene_requested = core.settings.scene_effects.crt or
@@ -6371,6 +6381,25 @@ test "background opacity retains exact endpoints and percentage precision" {
}
}
+/// PARDES_TEST_LATENCY trace for an external driver, CLOCK_MONOTONIC ns:
+/// `R t` when stdin input is read, `F start fence` per captured frame (present
+/// entry, and the GPU fence of that frame). Nothing is written without it.
+var latency_fd: c_int = -1;
+var frame_started_ns: u64 = 0;
+
+fn monoNs() u64 {
+ var ts: libc.timespec = undefined;
+ if (libc.clock_gettime(.MONOTONIC, &ts) != 0) return 0;
+ return @as(u64, @intCast(ts.sec)) * std.time.ns_per_s + @as(u64, @intCast(ts.nsec));
+}
+
+fn latencyNote(comptime fmt: []const u8, args: anytype) void {
+ if (latency_fd < 0) return;
+ var buf: [64]u8 = undefined;
+ const line = std.fmt.bufPrint(&buf, fmt, args) catch return;
+ _ = libc.write(latency_fd, line.ptr, line.len);
+}
+
fn captureFrame(g: *Gui, gpa: std.mem.Allocator, cmd: *c.SDL_GPUCommandBuffer, target: *c.SDL_GPUTexture, sw: u32, sh: u32) !void {
const size = c.SDL_CalculateGPUTextureFormatSize(g.swapchain_format, sw, sh, 1);
if (size == 0) {
@@ -6398,6 +6427,7 @@ fn captureFrame(g: *Gui, gpa: std.mem.Allocator, cmd: *c.SDL_GPUCommandBuffer, t
defer c.SDL_ReleaseGPUFence(g.device, fence);
var fences = [_]*c.SDL_GPUFence{fence};
if (!c.SDL_WaitForGPUFences(g.device, true, &fences, 1)) return error.GpuSubmit;
+ latencyNote("F {d} {d}\n", .{ frame_started_ns, monoNs() });
const mapped = c.SDL_MapGPUTransferBuffer(g.device, xfer, false) orelse return error.GpuMap;
defer c.SDL_UnmapGPUTransferBuffer(g.device, xfer);