//! User-space display client: talk to the display service (query the mode, and — from D3 //! — create layers, draw, and present) without hand-rolling the IPC. The `runtime.block` //! shape: a cached `.display` lookup with a boot-race retry, then extern-struct request/ //! reply marshalling. See system/services/display/ and docs/display.md. const std = @import("std"); const ipc = @import("ipc.zig"); const system = @import("system.zig"); const protocol = @import("display-protocol"); /// The display's current mode, as `info()` reports it. pub const Info = struct { width: u32, height: u32, pitch: u32, // bytes per row (may exceed width*4; see docs/framebuffer.md) format: u32, // a device-abi DisplayFormat value (0 = rgbx, 1 = bgrx) }; /// The service endpoint, looked up once and cached. var handle: ?ipc.Handle = null; /// Look up the display service, retrying while it comes up (a client races its /// registration at boot). Returns the endpoint, or null if it never appears. fn service() ?ipc.Handle { if (handle) |h| return h; var attempts: usize = 0; while (attempts < 100) : (attempts += 1) { if (ipc.lookup(.display)) |h| { handle = h; return h; } system.sleep(50); } return null; } /// Send one request, receive its reply; true on a zero status. `out` receives the reply /// so callers can read `info`/`layer` fields on success. fn transact(request: protocol.Request, out: *protocol.Reply) bool { const h = service() orelse return false; var req = request; var reply: [protocol.reply_size]u8 = undefined; const len = ipc.call(h, std.mem.asBytes(&req), &reply) catch return false; if (len < protocol.reply_size) return false; out.* = std.mem.bytesToValue(protocol.Reply, reply[0..protocol.reply_size]); return out.status == 0; } /// The display's current mode, or null if the service never came up. pub fn info() ?Info { var reply: protocol.Reply = undefined; if (!transact(.{ .operation = @intFromEnum(protocol.Operation.info) }, &reply)) return null; return .{ .width = reply.width, .height = reply.height, .pitch = reply.pitch, .format = reply.format }; } /// Composite the dirty layers and flush the frame to the screen. pub fn present() bool { var reply: protocol.Reply = undefined; return transact(.{ .operation = @intFromEnum(protocol.Operation.present) }, &reply); }