display: layer stack + damage-driven compositor (D3)
Turn the service into a real compositor. A layer is a server-owned surface (its own mmap'd cacheable buffer) with a screen position, z-order, and visibility. Clients create layers, draw into them by command, mark damage, and present; the compositor repaints only the damaged region — clear to the wallpaper, paint the visible layers bottom-to-top (z-sorted), flush that rectangle back -> front (WC). - compositor.zig: the pure, host-tested core — Rect (intersect/unite), Surface, fillRect, composite (opaque, clipped to a damage rect), blitTile (unaligned- safe read of a client tile). No syscall/runtime dependency. - protocol.zig: pack(format, r, g, b) — native pixel encoding for rgbx/bgrx, the shared colour vocabulary of client and server. Host-tested. - display.zig: the layer table + create/configure/destroy/fill_rect/blit_tile/ damage/present ops wired onto the compositor, plus a damage-accumulating present. - Startup self-check: two overlapping layers composited on the real framebuffer, read back to confirm the overlap shows the top layer and outside shows the bottom — logs `display: compositor self-check ok`. Gate: `zig build test` green (compositor + pack), and the display-service case's self-check passes on hardware. Both new pure modules added to the test loop.
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
//! 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,
|
||||
@@ -59,3 +61,28 @@ pub const message_maximum: usize = 4096;
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user