danos/library/protocol/scanout/scanout-protocol.zig

56 lines
2.3 KiB
Zig

//! The scanout wire protocol — what the compositor says to a native scanout driver (e.g.
//! virtio-gpu) over `/protocol/scanout` to put a composited frame on screen. The driver owns
//! the panel and the shared scanout surface it handed the compositor (via the display
//! service's `attach_scanout`); the compositor composites into that surface, then asks the
//! driver to present a damaged rectangle. Tiny by design — one present request. Separate from
//! the display protocol because the directions differ: clients call the compositor over
//! `/protocol/display`; the compositor calls the driver over `/protocol/scanout`. See
//! docs/display-v2.md.
//!
//! One scanout per driver instance, so `Header.target` is always 0.
const envelope = @import("envelope");
/// `present(rect)`: put the given rectangle of the shared scanout surface on the panel (on
/// virtio-gpu: transfer-to-host of the region, then a fenced resource flush).
pub const Present = extern struct {
x: u32 = 0,
y: u32 = 0,
width: u32 = 0,
height: u32 = 0,
};
/// `set_mode(width, height)`: change the scanout resolution — the shared surface is sized to
/// the largest mode, so this just re-points the scanout rectangle; the surface is unchanged.
pub const SetMode = extern struct { width: u32, height: u32 };
/// One offered display mode.
pub const Mode = extern struct { width: u32, height: u32 };
pub const max_modes = 4;
/// The answer to `get_modes`: a small fixed list of modes. The success/failure verdict is
/// the reply's `Status`, so this carries only the modes.
pub const Modes = extern struct {
count: u32 = 0,
_padding: u32 = 0,
modes: [max_modes]Mode = @splat(.{ .width = 0, .height = 0 }),
};
pub const Protocol = envelope.Define(.{
.name = "scanout",
.version = 1,
.operations = &.{
.{ .name = "present", .request = Present },
.{ .name = "get_modes", .reply = Modes },
.{ .name = "set_mode", .request = SetMode },
},
});
pub const Operation = Protocol.Operation;
/// The call floor, like every synchronous protocol. This module used to declare
/// 64 — the *push* floor — which was simply wrong: nothing here is pushed, and a
/// provider sizing its receive buffer to 64 refuses (`-E2BIG`) any caller that
/// sends up to the floor it is entitled to.
pub const message_maximum: usize = Protocol.message_maximum;