Skip to content

feat(graphics): added gfxfb's calls to set and move a hardware cursor - #461

Merged
FlareCoding merged 1 commit into
masterfrom
pr/gfxfb-cursor
Oct 26, 2026
Merged

FlareCoding merged 1 commit into
masterfrom
pr/gfxfb-cursor

Conversation

@FlareCoding

@FlareCoding FlareCoding commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

gfxfb lets a program set the picture and position of an output's hardware cursor, which the display draws over what the output shows, so a mouse moves the pointer without drawing and presenting a new frame.

Changes

  • A pointer that moves without a new frame: GFXFB_SET_CURSOR gives an output's cursor a picture with straight alpha (colors not multiplied by alpha) and its hotspot (the pixel that sits at the cursor's position), or hides the cursor at a width of 0, and GFXFB_MOVE_CURSOR places the hotspot anywhere, even off the output. GFXFB_GET_OUTPUT reports each output's largest cursor picture, 0 by 0 without a hardware cursor, so gfxfb_output_info grows from 32 to 40 bytes.
  • Checked and copied before control: gfxfb_node refuses an unknown output, a set reserved field, a hotspot outside the picture or a picture past the output's largest with EINVAL, then copies the pixels onto the unprivileged heap, failing with ENOMEM or, for pixels it cannot read, EINVAL, so a refused request fails alike whoever controls the buffers. A largest picture a display reports past CURSOR_DIMENSION_MAX (256) is held to it, in GFXFB_GET_OUTPUT's reply as in the check, so a copy never passes 256 KiB.
  • Control and a failed display as presents have them: a cursor call takes control as a creation or present does, fails with EBUSY while another file controls or reserves it, and fails with EIO without handing the call to the display once the display has failed, which a cursor call's ERR_DEVICE also marks. The controlling file's close, in give_outputs_back(), hides each output's cursor before its control ends, unless the display has failed or refuses the hide.
  • One cursor call per output at a time: gfxfb::display gains set_cursor() and move_cursor(), which gfxfb calls one at a time for each output under a mutex of their own, so a mouse's moves never wait for a present's display call. The boot display and virtio-gpu report no hardware cursor, so a picture there fails with EINVAL against a maximum of 0 by 0, and a hide or a move with ENOTTY.
  • Tests: on the fake display, a picture reaches the display as a copy and a hide reads none of the picture's other fields, gfxfb's own refusals (among them values whose low 16 bits would pass) come before control, each display result returns as its errno, a cursor call's ERR_DEVICE fails every later flush, present and cursor call (another file's cursor calls with EBUSY while the controller holds control, and with EIO once it closes), cursor calls take and keep control as creations do, a closing controller hides every output's cursor before its control ends, and a move waits for a hide's display call on its output (output 1 as well as output 0) but not for a present there. On the boot display a picture fails with EINVAL and a hide or a move with ENOTTY, none taking control. Two GET_OUTPUT tests and the boot display's read_output() test check the largest picture, one reporting a fake's maximum past 256 held to CURSOR_DIMENSION_MAX.
  • Boots: in QEMU on x86_64 and aarch64, at 5fff2cc against master c00fad8, the desktop came up on virtio-gpu and on the firmware's framebuffer with no faults or forbidden log lines. No program sets a cursor, so no boot runs the cursor calls.

Note

Medium Risk
Touches kernel user-copy paths, device control lifecycle, and the gfxfb display contract; virtio-gpu and boot paths are stubs only until a driver implements hardware cursors.

Overview
Adds hardware cursor support to /dev/gfxfb so userland can set a cursor image and move it without presenting frames.

User API: New ioctls GFXFB_SET_CURSOR (ARGB picture + hotspot, or width 0 to hide) and GFXFB_MOVE_CURSOR (hotspot position, including off-screen). GFXFB_GET_OUTPUT now returns cursor_max_width / cursor_max_height (gfxfb_output_info grows to 40 bytes). Reported maxima are capped at CURSOR_DIMENSION_MAX (256) so kernel copies stay bounded (up to 256 KiB).

Kernel path: gfxfb_node validates arguments, copies pixel data from userland before taking buffer control, and forwards to new display::set_cursor() / move_cursor() under per-output cursor mutexes (serialized with each other, not with presents). Successful cursor calls participate in the same single-controller model as buffer create/present; device failure and ERR_DEVICE from cursor calls block later flush/present/cursor ioctls. On close, the controller hides cursors on all outputs via give_outputs_back().

Drivers: boot_display and virtio-gpu stub cursor support (ERR_UNSUPPORTED, 0×0 max); real hardware drivers must implement the new display methods.

Reviewed by Cursor Bugbot for commit 5fff2cc. 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
A pointer drawn into each frame costs a present for every mouse move.
gfxfb_output_info grew to 40 bytes to report each output's cursor
maximum, and the two cursor calls take control as presents do.
@FlareCoding
FlareCoding merged commit 32b330f into master Oct 26, 2026
11 checks passed
@FlareCoding
FlareCoding deleted the pr/gfxfb-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