61 lines
2.4 KiB
Zig
61 lines
2.4 KiB
Zig
//! 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);
|
|
}
|