91 lines
4.1 KiB
Zig
91 lines
4.1 KiB
Zig
//! 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, <inline pixels>): 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
|
|
}
|