Skip to content

feat(graphics): drove virtio-gpu's hardware cursor - #462

Merged
FlareCoding merged 1 commit into
pr/gfxfb-cursorfrom
pr/virtio-gpu-cursor
Oct 26, 2026
Merged

FlareCoding merged 1 commit into
pr/gfxfb-cursorfrom
pr/virtio-gpu-cursor

Conversation

@FlareCoding

@FlareCoding FlareCoding commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

virtio-gpu drives the device's hardware cursor (a small picture of up to 64 by 64 pixels that the device draws over what the scanout shows) for gfxfb's GFXFB_SET_CURSOR and GFXFB_MOVE_CURSOR, so a client can move a pointer without presenting a frame.

Changes

  • Draw any picture gfxfb accepts on the device's 64 by 64 cursor: virtio_gpu_driver makes one 64 by 64 cursor resource (the device's own copy of the cursor's picture) at attach, and set_cursor() pads each picture with transparent pixels into the resource's RAM, waits for the device to confirm the copy, then sends UPDATE_CURSOR on the device's cursor queue.
  • Keep the cursor where the client put it: move_cursor() sends MOVE_CURSOR naming the cursor resource, since QEMU's device hides the cursor on a move naming none. cursor_corner() holds the picture's top-left corner to at most 64 pixels left of or above the scanout, past which nothing shows.
  • Keep a hidden cursor hidden on every display: gfxfb.h's move_cursor() doc extends the move that only records the position from before any picture to after a hide as well, and virtio-gpu's move_cursor() sends nothing while the cursor is hidden.
  • Bound gfxfb's close and a pointer's moves: a cursor call's UPDATE_CURSOR or MOVE_CURSOR is due GFXFB_PRESENT_TIMEOUT_NS after the call takes the driver's lock and the picture's copy a refresh period sooner, each given at least a refresh period after its submission (answer_deadline()), as each command batch of a present is. An UPDATE_CURSOR or MOVE_CURSOR the device has not handed back by its deadline fails the display with a log line of its own.
  • Report the cursor on every scanout: read_output() reports a 64 by 64 cursor maximum for each scanout, lit or dark, since the device has a cursor on each.
  • Wake cursor waits with the existing interrupt: attach() routes the cursor queue to the control queue's MSI-X vector, since every wait that sleeps on it holds m_batch_lock.
  • Boots: no kernel test drives virtio-gpu, so a diagnostic program, on a branch of its own over this commit with an init that starts no stlxdm, drove both calls on x86_64 and aarch64, each with MSI-X and polled, and on x86_64 also with a second, dark scanout. QEMU's trace showed each cursor command and copy in the expected order, and QEMU's VNC server returned each picture and its hotspot (the picture's pixel that sits at the cursor's position) as set.
  • Not run: no attach failed, QEMU refused no copy and handed back every UPDATE_CURSOR and MOVE_CURSOR by its deadline, and the driver never ran out of descriptors or submitted less than a refresh period before a deadline, so detach() freeing the cursor's RAM after a failed attach, ERR_REFUSED, "device stopped answering cursor commands" and answer_deadline()'s minimum are checked by reading.

Note

Medium Risk
Adds kernel display-driver paths (DMA, virtqueues, timeouts) on the lit scanout; failures can mark the device broken like unanswered present batches.

Overview
virtio-gpu now drives the device’s 64×64 hardware cursor for gfxfb’s GFXFB_SET_CURSOR / GFXFB_MOVE_CURSOR, replacing the previous ERR_UNSUPPORTED stubs.

At attach it sets up the cursor virtqueue, a dedicated B8G8R8A8 cursor resource, and MSI-X routing shared with the control queue. set_cursor() pads images into that resource, TRANSFER_TO_HOST_2D on the control queue, then UPDATE_CURSOR (hide uses resource id 0). move_cursor() issues MOVE_CURSOR only when the cursor is visible; otherwise it only updates stored coordinates. cursor_corner() clamps position for hardware limits. Completion waiting is generalized via wait_for_used() and answer_deadline() (same minimum wait as presents). read_output() advertises a 64×64 cursor on every scanout.

gfxfb docs clarify that move_cursor() while hidden—before any picture or after a hide—only records position; gfxfb_node comments note cursor calls never wait on present locks.

Reviewed by Cursor Bugbot for commit 3001327. Bugbot is set up for automated code reviews on this repo. Configure here.

@FlareCoding
FlareCoding added this pull request to stack #465 October 25, 2026 22:03
virtio-gpu reported no cursor, so moving a pointer meant presenting a
frame. Each picture is padded into one 64 by 64 resource, the only size
the device draws, and every display only records a hidden cursor's move.
@FlareCoding
FlareCoding merged commit db0bbe8 into master Oct 26, 2026
11 checks passed
@FlareCoding
FlareCoding deleted the pr/virtio-gpu-cursor branch October 26, 2026 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant