//! The display wire protocol — what a client says to the display service over its //! well-known `.display` endpoint. extern-struct messages with an `Operation` tag, the //! same shape as block/vfs/input protocols. The compositor owns the framebuffer and an //! ordered stack of **layers**; a client creates layers, draws into them with these //! operations, marks damage, and asks for a `present`. v1 surfaces are server-owned (a //! client draws by command); shared-memory surfaces are a later milestone (docs/display.md). const std = @import("std"); pub const Operation = enum(u32) { /// info() -> { width, height, pitch, format }: the display's current mode. info = 0, /// create_layer(x, y, width, height, z) -> { layer }: a new server-owned surface. create_layer = 1, /// configure_layer(layer, x, y, z, visible): move, restack, show, or hide a layer. configure_layer = 2, /// destroy_layer(layer): release a layer. destroy_layer = 3, /// fill_rect(layer, x, y, width, height, colour): fill a rectangle of a layer. fill_rect = 4, /// blit_tile(layer, x, y, width, height, ): copy a small pixel tile in. blit_tile = 5, /// damage(layer, x, y, width, height): mark a region dirty for the next present. damage = 6, /// present(): composite the dirty layers and flush to the screen. present = 7, }; /// The fixed request header. A `blit_tile`'s pixel payload (width*height 32-bit pixels) /// follows this header inline in the same message, up to `maximum_payload`. pub const Request = extern struct { operation: u32, layer: u32 = 0, // create/configure/destroy/fill/blit/damage: the target layer x: u32 = 0, y: u32 = 0, width: u32 = 0, height: u32 = 0, z: u32 = 0, // create_layer / configure_layer: stacking order (higher = in front) colour: u32 = 0, // fill_rect: the fill colour (native pixel value) visible: u32 = 1, // configure_layer: 0 hides the layer reserved: u32 = 0, }; pub const Reply = extern struct { status: i32, // 0 on success, negative on failure reserved: u32 = 0, // info(): width: u32 = 0, height: u32 = 0, pitch: u32 = 0, format: u32 = 0, // a device-abi DisplayFormat value (0 = rgbx, 1 = bgrx) // create_layer(): layer: u32 = 0, reserved2: u32 = 0, }; /// The IPC message size — the kernel caps every message at `MESSAGE_MAXIMUM` (256 bytes, /// system/kernel/ipc-synchronous.zig), so this matches it (a larger receive/reply buffer /// is rejected with -E2BIG). A `blit_tile` therefore carries only a *small* tile inline — /// `maximum_payload` bytes = up to 54 pixels, enough for a cursor or small sprite; larger /// bitmaps are the deferred shared-memory surface path (docs/display.md). pub const message_maximum: usize = 256; pub const request_size: usize = @sizeOf(Request); pub const reply_size: usize = @sizeOf(Reply); pub const maximum_payload: usize = message_maximum - request_size; /// Pack an 8-bit-per-channel colour into the display's native 32-bit pixel for `format` /// (a device-abi `DisplayFormat`: 0 = rgbx, 1 = bgrx). Shared so a `colour` in a /// `fill_rect` request means the same thing to the client that sends it and the /// compositor that paints it. Little-endian memory, reserved byte 0: rgbx puts red in /// the low byte, bgrx puts blue there. pub fn pack(format: u32, r: u8, g: u8, b: u8) u32 { const rr: u32 = r; const gg: u32 = g; const bb: u32 = b; return switch (format) { 1 => bb | (gg << 8) | (rr << 16), // bgrx else => rr | (gg << 8) | (bb << 16), // rgbx }; } test "pack encodes native byte order for rgbx and bgrx" { // rgbx: red in the low byte, blue in byte 2. try std.testing.expectEqual(@as(u32, 0x0000_00AA), pack(0, 0xAA, 0, 0)); try std.testing.expectEqual(@as(u32, 0x00AA_0000), pack(0, 0, 0, 0xAA)); // bgrx: blue in the low byte, red in byte 2. try std.testing.expectEqual(@as(u32, 0x0000_00AA), pack(1, 0, 0, 0xAA)); try std.testing.expectEqual(@as(u32, 0x00AA_0000), pack(1, 0xAA, 0, 0)); try std.testing.expectEqual(@as(u32, 0x0000_3020), pack(0, 0x20, 0x30, 0)); // green in byte 1 }