Documentation
¶
Overview ¶
Package gpu is a pure-Go virtio-gpu (2D framebuffer) driver. It drives a modern (Virtio 1.0+) PCI virtio-gpu device through the transport interfaces defined in github.com/go-virtio/common; the same code drives a UEFI-backed device, a bare-metal device, or a virtio-mmio device depending on which common.Transport implementation the caller supplies.
Scope — two paths. The 2D framebuffer path (OpenVirtioGPU) negotiates exactly VIRTIO_F_VERSION_1 and drives the device in plain 2D mode (Virtio 1.1 §5.7). The 3D path (OpenVirtioGPU3D + ClearScreen, in gpu3d.go) additionally negotiates VIRTIO_GPU_F_VIRGL (bit 0) and offloads a host-GPU scanout clear to virglrenderer via a hand-encoded virgl command stream — still pure Go, CGO=0. What remains out of scope is a FULL OpenGL/Vulkan implementation in Go (the Mesa-class GL→TGSI stack needed to generate arbitrary command streams from an application API); the 3D path hand-authors only the fixed command streams it needs.
The driver owns device bring-up, the control virtqueue (controlq), the cursor virtqueue (cursorq, set up but unused), and the on-the-wire virtio-gpu control protocol (every command is a 2-descriptor chain: a read-only request followed by a device-writable response). It exposes a scanout-enumeration + framebuffer API:
- DisplayInfo lists the device's scanouts (GET_DISPLAY_INFO).
- SetupFramebuffer creates a host resource, attaches guest backing, and binds it to a scanout (RESOURCE_CREATE_2D + RESOURCE_ATTACH_BACKING + SET_SCANOUT). The returned Framebuffer's Pix is a BGRA byte buffer the caller draws into.
- Framebuffer.Flush pushes the drawn pixels to the host and refreshes the scanout (TRANSFER_TO_HOST_2D + RESOURCE_FLUSH).
References:
- Virtio 1.1 §5.7 "GPU Device" — device-type 16 binding.
- Virtio 1.1 §5.7.4 "Device configuration layout" — virtio_gpu_config.
- Virtio 1.1 §5.7.6 "Device Operation" — control + cursor queues, struct virtio_gpu_ctrl_hdr and the 2D command structs.
- Virtio 1.1 §3.1.1 "Device Initialization".
3D / virgl extension of the virtio-gpu driver (Milestone 1). This file is purely additive: it does NOT touch the 2D OpenVirtioGPU / SetupFramebuffer / Flush / DisplayInfo path. It adds a second constructor, OpenVirtioGPU3D, that negotiates VIRTIO_GPU_F_VIRGL in addition to VERSION_1, and a single high-level operation, ClearScreen, that clears a scanout to a solid colour using the HOST GPU via virglrenderer.
M1 scope is deliberately tiny: stand up a virgl context, create a 3D render-target resource, submit a 3-command virgl buffer (CREATE SURFACE + SET_FRAMEBUFFER_STATE + CLEAR), pull the result back into the guest backing, and bind+flush it to a scanout. No Mesa is needed because the virgl command buffer for a flat clear is short enough to hand-encode.
References:
- Linux uapi linux/virtio_gpu.h — the 3D control structs and command codes (VIRTIO_GPU_CMD_*_3D, VIRTIO_GPU_F_VIRGL).
- virgl_protocol.h — VIRGL_CMD0 header layout, VIRGL_OBJECT_SURFACE, VIRGL_CCMD_* opcodes, VIRGL_OBJ_SURFACE_* / clear field order.
- virgl_encode.c — the canonical encoders this hand-encoding mirrors.
Index ¶
Constants ¶
const ( ControlQueueIdx uint16 = 0 CursorQueueIdx uint16 = 1 )
Queue indices (Virtio 1.1 §5.7.2). The control queue carries every 2D command; the cursor queue carries cursor updates and is set up for spec-completeness but otherwise unused by this driver.
const ( ControlQueueSize uint16 = 16 CursorQueueSize uint16 = 16 )
ControlQueueSize / CursorQueueSize are the desired ring sizes (clamped + rounded during setup). Commands are issued one at a time, so a small ring is plenty.
const ( CmdCtxCreate uint32 = 0x0200 CmdCtxDestroy uint32 = 0x0201 CmdCtxAttachResource uint32 = 0x0202 CmdCtxDetachResource uint32 = 0x0203 CmdResourceCreate3D uint32 = 0x0204 CmdTransferToHost3D uint32 = 0x0205 CmdTransferFromHost3D uint32 = 0x0206 CmdSubmit3D uint32 = 0x0207 )
3D control-command request type codes (Linux uapi virtio_gpu.h, sequential from 0x0200). Success responses are OK_NODATA (0x1100), same as the 2D commands.
const AcceptedFeatures uint64 = common.FeatureVersion1
AcceptedFeatures is the feature mask the driver negotiates ON — only the non-negotiable VIRTIO_F_VERSION_1. VIRTIO_GPU_F_VIRGL (bit 0) is deliberately NOT accepted, keeping the device in 2D mode.
const AcceptedFeatures3D uint64 = common.FeatureVersion1 | FeatureVirgl
AcceptedFeatures3D is the feature mask the 3D constructor negotiates ON: VERSION_1 (non-negotiable) plus VIRGL (bit 0).
const CommandPollIterations = 200000
CommandPollIterations is the busy-poll budget spent waiting for the device to complete one control command.
const DeviceType uint16 = 16
DeviceType is the virtio device-type encoding for virtio-gpu (Virtio 1.1 §5.7.1). Retained for callers enumerating PCI devices that want a stable name.
const FeatureVirgl uint64 = 1 << 0
VIRTIO_GPU_F_VIRGL is feature bit index 0 (Virtio 1.1 §5.7.3): the host advertises it when virglrenderer-backed 3D is available.
Variables ¶
var ( ErrNotModernDevice = commonGPUError("go-virtio/gpu: device doesn't offer VIRTIO_F_VERSION_1 (legacy-only)") ErrFeaturesNotOK = commonGPUError("go-virtio/gpu: FEATURES_OK status bit didn't stick after DriverFeature write") ErrInitWrongDeviceID = commonGPUError("go-virtio/gpu: PCI device ID is not 0x1050 (modern GPU device)") ErrQueueNotAvailable = commonGPUError("go-virtio/gpu: device reports QueueSize=0 for a required queue") ErrRequestTimeout = commonGPUError("go-virtio/gpu: command poll timeout (device did not complete the command)") ErrGPUCommandFailed = commonGPUError("go-virtio/gpu: device returned an error response to a control command") ErrNoScanout = commonGPUError("go-virtio/gpu: no usable scanout (none enabled, or scanout id out of range)") ErrFramebufferTooLarge = commonGPUError("go-virtio/gpu: framebuffer dimensions are zero or exceed the supported bound") )
Sentinel errors for the virtio-gpu path.
ErrVirglUnavailable is returned by OpenVirtioGPU3D when the host does not support VIRTIO_GPU_F_VIRGL (no virglrenderer): the FEATURES_OK bit does not latch after the VIRGL driver-feature write, or the negotiated mask comes back without the VIRGL bit.
Functions ¶
func AcceptFeatures ¶
AcceptFeatures returns the negotiated mask (requires VERSION_1).
Types ¶
type Framebuffer ¶
type Framebuffer struct {
// Pix is the BGRA pixel buffer, width*height*4 bytes. The caller
// writes pixels here, then calls Flush to display them.
Pix []byte
Width, Height uint32
ResourceID uint32
// contains filtered or unexported fields
}
Framebuffer is a host 2D resource bound to a scanout, backed by a guest BGRA pixel buffer the caller draws into and then pushes via Flush.
func (*Framebuffer) Flush ¶
func (fb *Framebuffer) Flush() error
Flush pushes the drawn pixels to the host resource and refreshes the scanout: TRANSFER_TO_HOST_2D(rect{0,0,W,H}, offset=0) then RESOURCE_FLUSH(rect{0,0,W,H}).
type VirtioGPU ¶
type VirtioGPU struct {
// Cfg is the modern-transport handle.
Cfg *common.ModernConfig
// NumScanouts is the device's advertised scanout count, read from
// virtio_gpu_config.num_scanouts at Open.
NumScanouts uint32
// NegotiatedFeatures records the driver-feature handshake result.
NegotiatedFeatures uint64
// contains filtered or unexported fields
}
VirtioGPU wraps one initialised virtio-gpu device in 2D mode.
func OpenVirtioGPU ¶
OpenVirtioGPU drives the full bring-up of one virtio-gpu device:
- Verify the PCI device ID is 0x1050 (modern GPU).
- InitModernConfig walks PCI caps + populates the BAR locators.
- Reset → ACK → DRIVER status progression.
- Read DeviceFeature, require VERSION_1, mask to VERSION_1 (NOT VIRGL), write DriverFeature.
- Set FEATURES_OK, verify it stuck.
- Allocate + publish controlq (queue 0) and cursorq (queue 1).
- DRIVER_OK status.
- Read num_scanouts (le32) from DeviceCfg offset 8.
func OpenVirtioGPU3D ¶ added in v0.3.0
OpenVirtioGPU3D drives the same bring-up as OpenVirtioGPU but additionally negotiates VIRTIO_GPU_F_VIRGL. If the host does not advertise virgl, the driver-feature write masks the bit off and FEATURES_OK still latches — but the resulting device has no 3D, so callers must check the negotiated mask. More importantly, if FEATURES_OK fails to latch after writing the driver features, the host has rejected the requested set: this is read as "no virglrenderer" and surfaced as ErrVirglUnavailable.
func (*VirtioGPU) ClearScreen ¶ added in v0.3.0
ClearScreen clears scanout scanoutID to the solid RGBA colour (r,g,b,a) using the host GPU, executing the full M1 virgl sequence:
(a) DisplayInfo to resolve the scanout's width/height (and reject a
disabled or out-of-range scanout with ErrNoScanout).
(b) CTX_CREATE(ctx=1).
(c) RESOURCE_CREATE_3D(res=1, w, h) — a BGRA render target.
(d) RESOURCE_ATTACH_BACKING(res=1, one mem_entry{phys, w*h*4}).
(e) CTX_ATTACH_RESOURCE(ctx=1, res=1).
(f) SUBMIT_3D(ctx=1, <CREATE SURFACE + SET_FRAMEBUFFER_STATE + CLEAR>).
(g) TRANSFER_TO_HOST_3D(ctx=1, box{0,0,0,w,h,1}, res=1).
(h) SET_SCANOUT(scanoutID, res=1, rect{0,0,w,h}).
(i) RESOURCE_FLUSH(res=1, rect{0,0,w,h}).
Every step checks its response is OK_NODATA; any other response type is ErrGPUCommandFailed.
func (*VirtioGPU) ControlQueue ¶
ControlQueue exposes the control virtqueue handle for diagnostics.
func (*VirtioGPU) DisplayInfo ¶
DisplayInfo issues GET_DISPLAY_INFO and parses the fixed array of 16 virtio_gpu_display_one entries into one Display per scanout index.
func (*VirtioGPU) SetupFramebuffer ¶
func (g *VirtioGPU) SetupFramebuffer(scanoutID, width, height uint32) (*Framebuffer, error)
SetupFramebuffer creates a 2D BGRA resource, attaches a guest-allocated backing store, and binds it to scanoutID:
- RESOURCE_CREATE_2D(resource_id=1, format=BGRA, width, height).
- Allocate ceil(width*height*4 / PageSize) contiguous pages; hold the []byte as Pix (sliced to width*height*4).
- RESOURCE_ATTACH_BACKING(resource_id=1, one mem_entry = {phys, size}).
- SET_SCANOUT(scanout_id, resource_id=1, rect{0,0,width,height}).