mbox series

[RFC,0/6] RFC: hw/display/virtio-gpu: problems with coloured cursors

Message ID 20250123191536.142753-1-berrange@redhat.com (mailing list archive)
Headers show
Series RFC: hw/display/virtio-gpu: problems with coloured cursors | expand

Message

Daniel P. Berrangé Jan. 23, 2025, 7:15 p.m. UTC
Help needed ! This is not for merge, just demo.

I started working on a simple bug in the GTK-VNC 'alpha cursor' encoding
support and in testing that uncovered what appear to be several bugs in
QEMU related to cursor handling across different components.

The two core behaviours are seen:

 * In some display backends (SDL, GTK), areas of the cursor
   with partial alpha are less saturated than they ought to be.

   The cursor data virtio-gpu is receiving from the guest has
   had the alpha channel pre-multiplied into the RGB components.

   This is not apparent in the VNC backend, since the VNC server
   is *supposed* to pre-multiply alpha but forgot to do so. Thus
   the virtio-gpu issue is hiding the VNC server issue.

 * In some display backends (GTK, VNC), the cursor RGB components
   are reversed.

   The cursor data virtio-gpu is receiving from the guest appears
   to be in BGRA8888 format, while GTK/VNC both expect the data to
   be in RGBA8888 format.

   This is not apparent in the SDL backend, since that is telling
   SDL to use BGRA8888 format when loading the cursor.

This series has patches to virtio-gpu which reverse the RGB
components and un-multiply the alpha channel.

I am not especially confident this is correct though.

The virtio spec is light on details:

  https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-3200007

but says

   "In 2D mode the virtio-gpu device provides support
    for ARGB Hardware cursors and multiple scanouts
    (aka heads)."

I'm unclear whether its reference to "ARGB" here implies that
seeing BGRA8888 data is intentional, or a guest kernel bug ?

The spec says nothing at all about alpha pre-multiplication.
I kind of think this is more likely to be a guest kernel bug,
but its possible the spec just forgot to mention this ?

Meanwhile I've absolutely no clue what impact endianness will
have on this mess. All my testing thus far has been x86_64
host (QEMU git HEAD) with x86_64 guest (Fedora 41).

The problem isn't obvious since guests usually have monochrome
cursors by default. To aid in testing, on *both* your host and
your guest OS do:

  git clone https://gitlab.com/berrange/cursordemo
  cd cursordemo
  ./setup.sh
  gnome-tweaks

Navigate to Apperance, and select "RGB" or "Rainbow" as the
cursor theme.

Now compare the guest OS rendered cursor to what you see on
the host OS. They should obviously match 100% since they're
using the same theme.

Daniel P. Berrangé (6):
  ui: add more cursor helper methods
  hw/display/virtio-gpu.c: reverse alpha pre-multiplication
  hw/display/virtio-gpu: fix pixel ordering from BGRA8888 to RGBA8888
  ui/vnc: pre-multiply alpha with alpha cursor
  ui/sdl: load cursor in RGBA8888 format not BGRA8888
  ui: add ability to dump the raw cursor bytes

 hw/display/virtio-gpu.c |  3 ++
 include/ui/console.h    |  7 +++++
 ui/cursor.c             | 70 +++++++++++++++++++++++++++++++++++++++++
 ui/sdl2.c               |  2 +-
 ui/vnc.c                |  7 ++++-
 5 files changed, 87 insertions(+), 2 deletions(-)

Comments

Gerd Hoffmann Jan. 24, 2025, 10 a.m. UTC | #1
Hi,

>    The cursor data virtio-gpu is receiving from the guest has
>    had the alpha channel pre-multiplied into the RGB components.

The kernel driver simply passes through whatever it gets from userspace.

Not sure what userspace passes to the kernel, I suspect it is whatever
typical GPUs can use unmodified as cursor sprite.

>    The cursor data virtio-gpu is receiving from the guest appears
>    to be in BGRA8888 format, while GTK/VNC both expect the data to
>    be in RGBA8888 format.

The format used by virtio-gpu is DRM_FORMAT_ARGB8888
(VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM) on little endian guests.  Byteswapped
(DRM_FORMAT_BGRA8888 / VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM) on bigendian
guests.

> This series has patches to virtio-gpu which reverse the RGB
> components and un-multiply the alpha channel.

I'd tend to simply pass the cursor format information to the ui and
leave it to the ui to convert if needed, or just use the data as-is if
possible (like SDL does).  Same approach we are using for the
framebuffer data.

IIRC the cursor code predates the adoption of pixman in qemu, maybe it
makes sense to redesign this around pixman images.

> I'm unclear whether its reference to "ARGB" here implies that
> seeing BGRA8888 data is intentional, or a guest kernel bug ?

Intentional.

> The spec says nothing at all about alpha pre-multiplication.
> I kind of think this is more likely to be a guest kernel bug,
> but its possible the spec just forgot to mention this ?

Not sure, missing in the spec I'd guess.

> Meanwhile I've absolutely no clue what impact endianness will
> have on this mess. All my testing thus far has been x86_64
> host (QEMU git HEAD) with x86_64 guest (Fedora 41).

Looking at virtio_gpu_update_cursor_data() my guess would be it's
broken (or working by pure luck and bug compatibility).  The
function goes lookup the resource containing the cursor data,
checks size, but doesn't even look at the format.

HTH & take care,
  Gerd
Daniel P. Berrangé Jan. 24, 2025, 2:28 p.m. UTC | #2
On Fri, Jan 24, 2025 at 11:00:33AM +0100, Gerd Hoffmann wrote:
>   Hi,
> 
> >    The cursor data virtio-gpu is receiving from the guest has
> >    had the alpha channel pre-multiplied into the RGB components.
> 
> The kernel driver simply passes through whatever it gets from userspace.
> 
> Not sure what userspace passes to the kernel, I suspect it is whatever
> typical GPUs can use unmodified as cursor sprite.
> 
> >    The cursor data virtio-gpu is receiving from the guest appears
> >    to be in BGRA8888 format, while GTK/VNC both expect the data to
> >    be in RGBA8888 format.
> 
> The format used by virtio-gpu is DRM_FORMAT_ARGB8888
> (VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM) on little endian guests.  Byteswapped
> (DRM_FORMAT_BGRA8888 / VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM) on bigendian
> guests.
> 
> > This series has patches to virtio-gpu which reverse the RGB
> > components and un-multiply the alpha channel.
> 
> I'd tend to simply pass the cursor format information to the ui and
> leave it to the ui to convert if needed, or just use the data as-is if
> possible (like SDL does).  Same approach we are using for the
> framebuffer data.
> 
> IIRC the cursor code predates the adoption of pixman in qemu, maybe it
> makes sense to redesign this around pixman images.

Yeah that all makes sense, but trying it I hit something odd. The
virtio_gpu_resource_create_2d *always* seems to report the format
as VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM rather than
VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM for the cursor resources.

IOW, the guest is incorrectly telling us there's no alpha channel
data, so if I honour the guest format, the cursor is filled in
black wherever there is supposed to be 100% alpha :-(

I can see a place in linux.git virtiogpu_gem.c that has harcoded
the DRM_FORMAT_HOST_XRGB8888 format for resources, which I guess
is where its going wrong :-(

I could try to workaround this in QEMU, and blindly assume that
guests always intend to have an alpha channel with cursors, as
it makes no sense to not do so.

With regards,
Daniel