140 lines
3.9 KiB
Zig
140 lines
3.9 KiB
Zig
//! 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));
|
|
}
|