//! The virtio-gpu control protocol — the command/response structs the driver exchanges with //! the device over its control virtqueue (virtio spec, "GPU Device"). `extern` structs, so //! the layout matches the little-endian wire format exactly. Host-tested for size. See //! docs/display-v2.md. const std = @import("std"); /// Control command / response types (virtio_gpu_ctrl_type). Commands are 0x01xx, responses /// 0x11xx (ok) / 0x12xx (error). pub const CmdType = enum(u32) { get_display_info = 0x0100, resource_create_2d = 0x0101, resource_unref = 0x0102, set_scanout = 0x0103, resource_flush = 0x0104, transfer_to_host_2d = 0x0105, resource_attach_backing = 0x0106, resource_detach_backing = 0x0107, get_edid = 0x010a, resp_ok_nodata = 0x1100, resp_ok_display_info = 0x1101, resp_ok_edid = 0x1104, resp_err_unspec = 0x1200, _, }; /// Set in a command's `flags` to request a fence; the device echoes `fence_id` in the /// response and does not report completion until the command's effects are visible. pub const flag_fence: u32 = 1 << 0; /// VIRTIO_GPU_F_EDID — device feature bit 1 (the low feature word): the device answers the /// `get_edid` command. Negotiate it only when the device offers it. pub const feature_edid: u32 = 1 << 1; /// virtio_gpu_ctrl_hdr — the header on every command and response. pub const CtrlHdr = extern struct { type: u32, flags: u32 = 0, fence_id: u64 = 0, ctx_id: u32 = 0, ring_idx: u8 = 0, padding: [3]u8 = .{ 0, 0, 0 }, }; pub const Rect = extern struct { x: u32, y: u32, width: u32, height: u32, }; /// 2D pixel formats. QEMU's virtio-gpu host default is B8G8R8X8 (matches our bgrx). pub const format_b8g8r8x8_unorm: u32 = 2; pub const format_r8g8b8x8_unorm: u32 = 134; pub const ResourceCreate2d = extern struct { hdr: CtrlHdr, resource_id: u32, format: u32, width: u32, height: u32, }; /// One scatter-gather entry of a resource's guest backing (a physical span). pub const MemEntry = extern struct { addr: u64, length: u32, padding: u32 = 0, }; /// Header for RESOURCE_ATTACH_BACKING; `nr_entries` `MemEntry` follow it inline. pub const ResourceAttachBacking = extern struct { hdr: CtrlHdr, resource_id: u32, nr_entries: u32, }; pub const SetScanout = extern struct { hdr: CtrlHdr, rect: Rect, scanout_id: u32, resource_id: u32, }; pub const ResourceFlush = extern struct { hdr: CtrlHdr, rect: Rect, resource_id: u32, padding: u32 = 0, }; /// Copy the guest backing into the host resource for `rect` (2D resources must transfer /// before a flush shows the update). pub const TransferToHost2d = extern struct { hdr: CtrlHdr, rect: Rect, offset: u64, resource_id: u32, padding: u32 = 0, }; pub const max_scanouts = 16; pub const DisplayOne = extern struct { rect: Rect, enabled: u32, flags: u32, }; pub const RespDisplayInfo = extern struct { hdr: CtrlHdr, pmodes: [max_scanouts]DisplayOne, }; pub const GetEdid = extern struct { hdr: CtrlHdr, scanout: u32, padding: u32 = 0, }; pub const RespEdid = extern struct { hdr: CtrlHdr, size: u32, padding: u32 = 0, edid: [1024]u8, }; test "virtio-gpu struct sizes match the wire layout" { try std.testing.expectEqual(@as(usize, 24), @sizeOf(CtrlHdr)); try std.testing.expectEqual(@as(usize, 16), @sizeOf(Rect)); try std.testing.expectEqual(@as(usize, 40), @sizeOf(ResourceCreate2d)); try std.testing.expectEqual(@as(usize, 16), @sizeOf(MemEntry)); try std.testing.expectEqual(@as(usize, 32), @sizeOf(ResourceAttachBacking)); try std.testing.expectEqual(@as(usize, 48), @sizeOf(SetScanout)); try std.testing.expectEqual(@as(usize, 48), @sizeOf(ResourceFlush)); try std.testing.expectEqual(@as(usize, 56), @sizeOf(TransferToHost2d)); try std.testing.expectEqual(@as(usize, 24 + 4 + 4 + 1024), @sizeOf(RespEdid)); }