diff mbox

[1/8] virtio-gpu/2d: add hardware spec include file

Message ID 1411478887-15183-2-git-send-email-kraxel@redhat.com
State New
Headers show

Commit Message

Gerd Hoffmann Sept. 23, 2014, 1:28 p.m. UTC
This patch adds the header file with structs and defines for
the virtio based gpu device.  Covers 2d operations only.

Written by Dave Airlie and Gerd Hoffmann.

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/hw/virtio/virtgpu_hw.h | 207 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 207 insertions(+)
 create mode 100644 include/hw/virtio/virtgpu_hw.h

Comments

Gerd Hoffmann Sept. 25, 2014, 3:02 p.m. UTC | #1
Hi Dave,

Triggered by the framebuffer endian issues we have with stdvga I've
started to check where we stand with virtio-gpu and whenever we have to
fix something in the virtio protocol before setting in stone with the
upstream merge.

Fixed the protocol.  Basically s/uint32_t/__le32/g.  No changes on
x86_64 obviously.

Fixed the kernel driver to byteswap values when needed.  See
https://www.kraxel.org/cgit/linux/log/?h=virtio-gpu-rebase

Result is bigendian guest on little endian host boots fine (without
virgl).  Colors are wrong though.  Other way around still needs a bunch
of fixes in qemu so virtio-gpu works correctly on bigendian hosts.  To
be done.

So, on the color issue:  How are these defined exactly?

> +    VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM  = 1,
> +    VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM  = 2,
> +    VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM  = 3,
> +    VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM  = 4,

Looking at the code it seems the name defines the byte ordering in
memory, i.e. "B8G8R8A8" means blue first, then red, then green, then
alpha.  Or DRM_FORMAT_ARGB8888 on little endian / DRM_FORMAT_BGRX8888 on
big endian.  Correct?  Easy fix in the guest driver then ...

> +    VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM  = 5,
> +    VIRTIO_GPU_FORMAT_B5G6R5_UNORM    = 7,

Do we really wanna go down this route?  I'm inclined to just zap 16bpp
support.

> +    VIRTIO_GPU_FORMAT_R8_UNORM        = 64,

What is this btw?  Looks like gray or alpha, but why "R8" not "G8" or
"A8" then?  Why the gap in the enumeration?

With the formats being clarified fixed we are settled for 2d mode I
think.

What about 3d mode?  We are passing blobs between virglrenderer and
guest driver:  capabilities and gallium 3d command stream.  What happens
to them in case host and guest endianness don't match?  I think at least
the capabilities have 32bit values which need to be swapped.  Dunno
about the gallium commands ...

cheers,
  Gerd
Dave Airlie Sept. 30, 2014, 12:27 a.m. UTC | #2
> Triggered by the framebuffer endian issues we have with stdvga I've
> started to check where we stand with virtio-gpu and whenever we have to
> fix something in the virtio protocol before setting in stone with the
> upstream merge.

Let me start by saying its not that I don't care about endianness, but
its a mess I had hoped to avoid until someone else care more about it.

We haven't even managed to get endianness fixed for real 3D gpu hardware yet,

We sort of have decent endianness support for the llvmpipe sw driver now, after
I spent a week trawling patches and fixing up the results.

So before we try fixing things, we probably need to design something
that defines
where all the swapping happens, and what formats the virgl "hw" device supports.
The main problem is getting an efficient solution that avoids double swapping
of the major items like texture and vertex data if we can in some scenarios.

Currently the virgl "hw" supports little endian defined formats, as
per the gallium
interface, i.e. B8G8R8A8 means blue/red/green/alpha,

http://gallium.readthedocs.org/en/latest/format.html
is the documentation.

>
>> +    VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM  = 5,
>> +    VIRTIO_GPU_FORMAT_B5G6R5_UNORM    = 7,
>
> Do we really wanna go down this route?  I'm inclined to just zap 16bpp
> support.

We have to support 16bpp as an OpenGL format no matter what, and this
is why endianness sucks, we have lots of strange ass formats we need
to send over the wire, that have no nicely defined endianness, like Z24S8.

>
>> +    VIRTIO_GPU_FORMAT_R8_UNORM        = 64,
>
> What is this btw?  Looks like gray or alpha, but why "R8" not "G8" or
> "A8" then?  Why the gap in the enumeration?

Red 8, the enumeration is taken from the gallium formats list, rather than
reinventing our own. Most modern GPU hardware doesn't really have
A8 texture support, as it was deprecated in newer OpenGL.

>
> What about 3d mode?  We are passing blobs between virglrenderer and
> guest driver:  capabilities and gallium 3d command stream.  What happens
> to them in case host and guest endianness don't match?  I think at least
> the capabilities have 32bit values which need to be swapped.  Dunno
> about the gallium commands ...

For 3D we probably need to define the gallium command streams to be
little endian, however the big problem is the data that is stored
inside objects.
Texture and vertex, constants, indices etc. How do we decide to swap these,
when do we swap things, on the DMA transfers to the host, do we just
swap the formats on the host side etc.

I probably need to spend some time working this out with BenH, but
I'm not really sure how we can avoid backing ourselves into a large inefficent
hole at some point.

Dave.
Gerd Hoffmann Sept. 30, 2014, 7:54 a.m. UTC | #3
On Di, 2014-09-30 at 10:27 +1000, Dave Airlie wrote:
> > Triggered by the framebuffer endian issues we have with stdvga I've
> > started to check where we stand with virtio-gpu and whenever we have to
> > fix something in the virtio protocol before setting in stone with the
> > upstream merge.
> 
> Let me start by saying its not that I don't care about endianness, but
> its a mess I had hoped to avoid until someone else care more about it.

Understood.  It's a big mess indeed.

> So before we try fixing things, we probably need to design something
> that defines
> where all the swapping happens, and what formats the virgl "hw" device supports.

2D case is easy.  Everything is little endian.  kernel driver / qemu are
doing the byteswaps for the structs sent over the control pipe.

Problem with 3D is that both qemu and kernel driver passing through data
where they don't even know what is inside, so they can't do the
byteswapping.

> The main problem is getting an efficient solution that avoids double swapping
> of the major items like texture and vertex data if we can in some scenarios.

Yes.

> 
> Currently the virgl "hw" supports little endian defined formats, as
> per the gallium
> interface, i.e. B8G8R8A8 means blue/red/green/alpha,
> 
> http://gallium.readthedocs.org/en/latest/format.html
> is the documentation.

Thanks.

> >> +    VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM  = 5,
> >> +    VIRTIO_GPU_FORMAT_B5G6R5_UNORM    = 7,
> >
> > Do we really wanna go down this route?  I'm inclined to just zap 16bpp
> > support.
> 
> We have to support 16bpp as an OpenGL format no matter what, and this
> is why endianness sucks, we have lots of strange ass formats we need
> to send over the wire, that have no nicely defined endianness, like Z24S8.

Ok.  But for 2D we can just not support it, right?

> > What about 3d mode?  We are passing blobs between virglrenderer and
> > guest driver:  capabilities and gallium 3d command stream.  What happens
> > to them in case host and guest endianness don't match?  I think at least
> > the capabilities have 32bit values which need to be swapped.  Dunno
> > about the gallium commands ...
> 
> For 3D we probably need to define the gallium command streams to be
> little endian, however the big problem is the data that is stored
> inside objects.
> Texture and vertex, constants, indices etc. How do we decide to swap these,
> when do we swap things, on the DMA transfers to the host, do we just
> swap the formats on the host side etc.
> 
> I probably need to spend some time working this out with BenH, but
> I'm not really sure how we can avoid backing ourselves into a large inefficent
> hole at some point.

I surely don't wanna go down that route, and I think it is reasonable to
just not support 3D/virgl mode if we would have to swap data.


So, we could define *two* virgl feature bits.  One for little endian,
one for bigendian.  endianness applies to the gallium command stream and
to gallium formats using integers in host endianess.

On the host side we'll go set the feature bit matching host endianness.
qemu handles the virtqueue command struct swapping, and virglrenderer
should only see native endian.

On the guest side we'll look for the feature bit matching guest
endianness, and if it isn't set due to guest + host having different
byte order you'll get 2D support only.

The endianness negotiation is a bit iffy, but that way it is possible to
have virgl on bigendian without swapping everything twice.


The other reasonable way would be to simply define virgl being little
endian.  Bigendian guests / hosts would either simply not support 3D
then, or implement swapping.  But in the bigendian-guest on
bigendian-host case we'll swap everything twice then ...

cheers,
  Gerd
Gerd Hoffmann Sept. 30, 2014, 7:55 a.m. UTC | #4
On Di, 2014-09-30 at 10:27 +1000, Dave Airlie wrote:
> > Triggered by the framebuffer endian issues we have with stdvga I've
> > started to check where we stand with virtio-gpu and whenever we have to
> > fix something in the virtio protocol before setting in stone with the
> > upstream merge.
> 
> Let me start by saying its not that I don't care about endianness, but
> its a mess I had hoped to avoid until someone else care more about it.

Understood.  It's a big mess indeed.

> So before we try fixing things, we probably need to design something
> that defines
> where all the swapping happens, and what formats the virgl "hw" device supports.

2D case is easy.  Everything is little endian.  kernel driver / qemu are
doing the byteswaps for the structs sent over the control pipe.

Problem with 3D is that both qemu and kernel driver passing through data
where they don't even know what is inside, so they can't do the
byteswapping.

> The main problem is getting an efficient solution that avoids double swapping
> of the major items like texture and vertex data if we can in some scenarios.

Yes.

> 
> Currently the virgl "hw" supports little endian defined formats, as
> per the gallium
> interface, i.e. B8G8R8A8 means blue/red/green/alpha,
> 
> http://gallium.readthedocs.org/en/latest/format.html
> is the documentation.

Thanks.

> >> +    VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM  = 5,
> >> +    VIRTIO_GPU_FORMAT_B5G6R5_UNORM    = 7,
> >
> > Do we really wanna go down this route?  I'm inclined to just zap 16bpp
> > support.
> 
> We have to support 16bpp as an OpenGL format no matter what, and this
> is why endianness sucks, we have lots of strange ass formats we need
> to send over the wire, that have no nicely defined endianness, like Z24S8.

Ok.  But for 2D we can just not support it, right?

> > What about 3d mode?  We are passing blobs between virglrenderer and
> > guest driver:  capabilities and gallium 3d command stream.  What happens
> > to them in case host and guest endianness don't match?  I think at least
> > the capabilities have 32bit values which need to be swapped.  Dunno
> > about the gallium commands ...
> 
> For 3D we probably need to define the gallium command streams to be
> little endian, however the big problem is the data that is stored
> inside objects.
> Texture and vertex, constants, indices etc. How do we decide to swap these,
> when do we swap things, on the DMA transfers to the host, do we just
> swap the formats on the host side etc.
> 
> I probably need to spend some time working this out with BenH, but
> I'm not really sure how we can avoid backing ourselves into a large inefficent
> hole at some point.

I surely don't wanna go down that route, and I think it is reasonable to
just not support 3D/virgl mode if we would have to swap data.


So, we could define *two* virgl feature bits.  One for little endian,
one for bigendian.  endianness applies to the gallium command stream and
to gallium formats using integers in host endianess.

On the host side we'll go set the feature bit matching host endianness.
qemu handles the virtqueue command struct swapping, and virglrenderer
should only see native endian.

On the guest side we'll look for the feature bit matching guest
endianness, and if it isn't set due to guest + host having different
byte order you'll get 2D support only.

The endianness negotiation is a bit iffy, but that way it is possible to
have virgl on bigendian without swapping everything twice.


The other reasonable way would be to simply define virgl being little
endian.  Bigendian guests / hosts would either simply not support 3D
then, or implement swapping.  But in the bigendian-guest on
bigendian-host case we'll swap everything twice then ...

cheers,
  Gerd
Dave Airlie Oct. 3, 2014, 4:38 a.m. UTC | #5
On 30 September 2014 17:55, Gerd Hoffmann <kraxel@redhat.com> wrote:
>
> On Di, 2014-09-30 at 10:27 +1000, Dave Airlie wrote:
>> > Triggered by the framebuffer endian issues we have with stdvga I've
>> > started to check where we stand with virtio-gpu and whenever we have to
>> > fix something in the virtio protocol before setting in stone with the
>> > upstream merge.
>>
>> Let me start by saying its not that I don't care about endianness, but
>> its a mess I had hoped to avoid until someone else care more about it.
>
> Understood.  It's a big mess indeed.
>
>> So before we try fixing things, we probably need to design something
>> that defines
>> where all the swapping happens, and what formats the virgl "hw" device supports.
>
> 2D case is easy.  Everything is little endian.  kernel driver / qemu are
> doing the byteswaps for the structs sent over the control pipe.
>
> Problem with 3D is that both qemu and kernel driver passing through data
> where they don't even know what is inside, so they can't do the
> byteswapping.
>
>> The main problem is getting an efficient solution that avoids double swapping
>> of the major items like texture and vertex data if we can in some scenarios.
>
> Yes.
>
>>
>> Currently the virgl "hw" supports little endian defined formats, as
>> per the gallium
>> interface, i.e. B8G8R8A8 means blue/red/green/alpha,
>>
>> http://gallium.readthedocs.org/en/latest/format.html
>> is the documentation.
>
> Thanks.
>
>> >> +    VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM  = 5,
>> >> +    VIRTIO_GPU_FORMAT_B5G6R5_UNORM    = 7,
>> >
>> > Do we really wanna go down this route?  I'm inclined to just zap 16bpp
>> > support.
>>
>> We have to support 16bpp as an OpenGL format no matter what, and this
>> is why endianness sucks, we have lots of strange ass formats we need
>> to send over the wire, that have no nicely defined endianness, like Z24S8.
>
> Ok.  But for 2D we can just not support it, right?

We can, I expect some pushback at some point, people still want to
test with 16bpp
for other areas, and it would be nice to know they can. But I don't really care
about it personally. I just though we should provide at least a basic
number of working
bpps (8,16,32).


>> > What about 3d mode?  We are passing blobs between virglrenderer and
>> > guest driver:  capabilities and gallium 3d command stream.  What happens
>> > to them in case host and guest endianness don't match?  I think at least
>> > the capabilities have 32bit values which need to be swapped.  Dunno
>> > about the gallium commands ...
>>
>> For 3D we probably need to define the gallium command streams to be
>> little endian, however the big problem is the data that is stored
>> inside objects.
>> Texture and vertex, constants, indices etc. How do we decide to swap these,
>> when do we swap things, on the DMA transfers to the host, do we just
>> swap the formats on the host side etc.
>>
>> I probably need to spend some time working this out with BenH, but
>> I'm not really sure how we can avoid backing ourselves into a large inefficent
>> hole at some point.
>
> I surely don't wanna go down that route, and I think it is reasonable to
> just not support 3D/virgl mode if we would have to swap data.

I think initially not support 3D mode is the way to go until we can work it out.

>
>
> So, we could define *two* virgl feature bits.  One for little endian,
> one for bigendian.  endianness applies to the gallium command stream and
> to gallium formats using integers in host endianess.
>
> On the host side we'll go set the feature bit matching host endianness.
> qemu handles the virtqueue command struct swapping, and virglrenderer
> should only see native endian.
>
> On the guest side we'll look for the feature bit matching guest
> endianness, and if it isn't set due to guest + host having different
> byte order you'll get 2D support only.
>
> The endianness negotiation is a bit iffy, but that way it is possible to
> have virgl on bigendian without swapping everything twice.
>
>
> The other reasonable way would be to simply define virgl being little
> endian.  Bigendian guests / hosts would either simply not support 3D
> then, or implement swapping.  But in the bigendian-guest on
> bigendian-host case we'll swap everything twice then ...
>

I think we should probably move a few more formats from the 3D side
into the 2D side, so we can have the guests just pick the LE format
it requires

http://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/include/pipe/p_format.h#n354

is what gallium currently does, and we could just provide XRGB, XBGR
formats in both endianness
and have the guest pick the one it wants to use.

The 2D pixman code would need updating to provide 2D support for these
formats as well.

I suspect I could add an endian cap for the 3D bits that I could pass
through from guest to host.

How do you test guests with big endian? Isn't it really slow?

Dave.
Gerd Hoffmann Oct. 6, 2014, 9:20 a.m. UTC | #6
Hi,

> >> >> +    VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM  = 5,
> >> >> +    VIRTIO_GPU_FORMAT_B5G6R5_UNORM    = 7,
> >> >
> > Ok.  But for 2D we can just not support it, right?
> 
> We can, I expect some pushback at some point, people still want to
> test with 16bpp for other areas, and it would be nice to know they
> can. But I don't really care about it personally. I just though we
> should provide at least a basic number of working bpps (8,16,32).

Lets try to get away with 32bpp only in 2d mode then.

bochsdrm likewise supports 32bpp only and I yet have to see a request
for 16bpp or even 8bpp support.

> I think we should probably move a few more formats from the 3D side
> into the 2D side, so we can have the guests just pick the LE format
> it requires
> 
> http://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/include/pipe/p_format.h#n354
> 
> is what gallium currently does, and we could just provide XRGB, XBGR
> formats in both endianness
> and have the guest pick the one it wants to use.

   PIPE_FORMAT_R8G8B8A8_UNORM          = 67,
   PIPE_FORMAT_X8B8G8R8_UNORM          = 68,

   PIPE_FORMAT_A8B8G8R8_UNORM          = 121,
   PIPE_FORMAT_R8G8B8X8_UNORM          = 134,

With the last two ones being in a /* TODO: re-order these */ block.
How stable are these numbers?

> The 2D pixman code would need updating to provide 2D support for these
> formats as well.

Yep.  Mapping the 32bpp formats to pixmap formats is easy.

> I suspect I could add an endian cap for the 3D bits that I could pass
> through from guest to host.

I was thinking about using virtio feature bit.  Advantage is that the
guest will tell the host which features it'll use.

Initially this doesn't matter much as the host will support only one
endianness anyway. 

But in case we get the byteswapping work reasonable well some day and
the host supports both be and le virgl we'll know that way which
endianness the guest is using.

> How do you test guests with big endian? Isn't it really slow?

emulated pseries machine with fedora ppc64.  Yes, it is slow.  Building
a kernel with virtio-gpu driver takes a day or so.

cheers,
  Gerd
Gerd Hoffmann Oct. 15, 2014, 10:05 a.m. UTC | #7
Hi,

> +/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
> +#define VIRTIO_GPU_MAX_SCANOUTS 16
> +struct virtio_gpu_resp_display_info {
> +    struct virtio_gpu_ctrl_hdr hdr;
> +    struct virtio_gpu_display_one {
> +        uint32_t enabled;
> +        uint32_t width;
> +        uint32_t height;
> +        uint32_t x;
> +        uint32_t y;
> +        uint32_t flags;
> +    } pmodes[VIRTIO_GPU_MAX_SCANOUTS];

One more thing: I think it would be a good idea to add the display
resolution here.  We start seeing highres displays on desktops, and the
guest should know whenever the host display runs at 100 or 300 dpi ...

What do you think?

cheers,
  Gerd
Dave Airlie Oct. 16, 2014, 3:53 a.m. UTC | #8
>
> Lets try to get away with 32bpp only in 2d mode then.
>
> bochsdrm likewise supports 32bpp only and I yet have to see a request
> for 16bpp or even 8bpp support.
>
>> I think we should probably move a few more formats from the 3D side
>> into the 2D side, so we can have the guests just pick the LE format
>> it requires
>>
>> http://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/include/pipe/p_format.h#n354
>>
>> is what gallium currently does, and we could just provide XRGB, XBGR
>> formats in both endianness
>> and have the guest pick the one it wants to use.
>
>    PIPE_FORMAT_R8G8B8A8_UNORM          = 67,
>    PIPE_FORMAT_X8B8G8R8_UNORM          = 68,
>
>    PIPE_FORMAT_A8B8G8R8_UNORM          = 121,
>    PIPE_FORMAT_R8G8B8X8_UNORM          = 134,
>
> With the last two ones being in a /* TODO: re-order these */ block.
> How stable are these numbers?

In theory the mesa/gallium numbers aren't stable, though I've never
seen them change yet,

If they diverge in the future I'll just provide a remapping table
inside the guest driver.

So it should be fine to expose these formats for 2D use.

> Initially this doesn't matter much as the host will support only one
> endianness anyway.
>
> But in case we get the byteswapping work reasonable well some day and
> the host supports both be and le virgl we'll know that way which
> endianness the guest is using.
>
>> How do you test guests with big endian? Isn't it really slow?
>
> emulated pseries machine with fedora ppc64.  Yes, it is slow.  Building
> a kernel with virtio-gpu driver takes a day or so.

I spent a little while trying to get a ppc64 f20 install to complete, just
using the F20 qemu ppc64 system package but hit a bug I
think is related to missing SIMD instructions, so I'm not sure how best
to move forward with getting a test platform here.

Dave.
Dave Airlie Oct. 16, 2014, 3:55 a.m. UTC | #9
On 15 October 2014 20:05, Gerd Hoffmann <kraxel@redhat.com> wrote:
>   Hi,
>
>> +/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
>> +#define VIRTIO_GPU_MAX_SCANOUTS 16
>> +struct virtio_gpu_resp_display_info {
>> +    struct virtio_gpu_ctrl_hdr hdr;
>> +    struct virtio_gpu_display_one {
>> +        uint32_t enabled;
>> +        uint32_t width;
>> +        uint32_t height;
>> +        uint32_t x;
>> +        uint32_t y;
>> +        uint32_t flags;
>> +    } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
>
> One more thing: I think it would be a good idea to add the display
> resolution here.  We start seeing highres displays on desktops, and the
> guest should know whenever the host display runs at 100 or 300 dpi ...
>
> What do you think?

Passing host display side into the guest isn't going to help, unless
you are running in full screen,

I suppose the guest could adjust the numbers, but what happens with
viewers, if I connect on a hidpi and move to a lodpi screen.

I think this would require a lot more thought in how it would work in
some use-cases.

That said reserving 2 32 bit fields for possible screen measurements
might future proof things a little, though most OSes use EDID to detect
this sort of thing, so we might not find a great use for it later.

Dave.
Gerd Hoffmann Oct. 16, 2014, 12:18 p.m. UTC | #10
Hi,

> > How stable are these numbers?
> 
> In theory the mesa/gallium numbers aren't stable, though I've never
> seen them change yet,
> 
> If they diverge in the future I'll just provide a remapping table
> inside the guest driver.
> 
> So it should be fine to expose these formats for 2D use.

Good.

> >> How do you test guests with big endian? Isn't it really slow?
> >
> > emulated pseries machine with fedora ppc64.  Yes, it is slow.  Building
> > a kernel with virtio-gpu driver takes a day or so.
> 
> I spent a little while trying to get a ppc64 f20 install to complete, just
> using the F20 qemu ppc64 system package but hit a bug I
> think is related to missing SIMD instructions, so I'm not sure how best
> to move forward with getting a test platform here.

I'm using self-compiled qemu 2.1 which works fine, so it looks like this
issue has been fixed meanwhile.

If you want something newer without manually building it you can try the
virt-preview repo (see
https://fedoraproject.org/wiki/Virtualization_Preview_Repository).

cheers,
  Gerd
diff mbox

Patch

diff --git a/include/hw/virtio/virtgpu_hw.h b/include/hw/virtio/virtgpu_hw.h
new file mode 100644
index 0000000..b421a4e
--- /dev/null
+++ b/include/hw/virtio/virtgpu_hw.h
@@ -0,0 +1,207 @@ 
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ *     Dave Airlie <airlied@redhat.com>
+ *     Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This header is BSD licensed so anyone can use the definitions
+ * to implement compatible drivers/servers:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef VIRTIO_GPU_HW_H
+#define VIRTIO_GPU_HW_H
+
+enum virtio_gpu_ctrl_type {
+    VIRTIO_GPU_UNDEFINED = 0,
+
+    /* 2d commands */
+    VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
+    VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
+    VIRTIO_GPU_CMD_RESOURCE_UNREF,
+    VIRTIO_GPU_CMD_SET_SCANOUT,
+    VIRTIO_GPU_CMD_RESOURCE_FLUSH,
+    VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
+    VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
+    VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
+
+    /* cursor commands */
+    VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
+    VIRTIO_GPU_CMD_MOVE_CURSOR,
+
+    /* success responses */
+    VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
+    VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+
+    /* error responses */
+    VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
+    VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
+    VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
+    VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
+    VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
+    VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
+};
+
+#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
+
+struct virtio_gpu_ctrl_hdr {
+    uint32_t type;
+    uint32_t flags;
+    uint64_t fence_id;
+    uint32_t ctx_id;
+    uint32_t padding;
+};
+
+/* data passed in the cursor vq */
+
+struct virtio_gpu_cursor_pos {
+    uint32_t scanout_id;
+    uint32_t x;
+    uint32_t y;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */
+struct virtio_gpu_update_cursor {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_cursor_pos pos;  /* update & move */
+    uint32_t resource_id;           /* update only */
+    uint32_t hot_x;                 /* update only */
+    uint32_t hot_y;                 /* update only */
+    uint32_t padding;
+};
+
+/* data passed in the control vq, 2d related */
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNREF */
+struct virtio_gpu_resource_unref {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */
+struct virtio_gpu_resource_create_2d {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t format;
+    uint32_t width;
+    uint32_t height;
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT */
+struct virtio_gpu_set_scanout {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t scanout_id;
+    uint32_t resource_id;
+    uint32_t width;
+    uint32_t height;
+    uint32_t x;
+    uint32_t y;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */
+struct virtio_gpu_resource_flush {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t width;
+    uint32_t height;
+    uint32_t x;
+    uint32_t y;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */
+struct virtio_gpu_transfer_to_host_2d {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t offset;
+    uint32_t width;
+    uint32_t height;
+    uint32_t x;
+    uint32_t y;
+};
+
+struct virtio_gpu_mem_entry {
+    uint64_t addr;
+    uint32_t length;
+    uint32_t pad;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */
+struct virtio_gpu_resource_attach_backing {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t nr_entries;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */
+struct virtio_gpu_resource_detach_backing {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
+#define VIRTIO_GPU_MAX_SCANOUTS 16
+struct virtio_gpu_resp_display_info {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_display_one {
+        uint32_t enabled;
+        uint32_t width;
+        uint32_t height;
+        uint32_t x;
+        uint32_t y;
+        uint32_t flags;
+    } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
+};
+
+#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
+
+struct virtio_gpu_config {
+    uint32_t events_read;
+    uint32_t events_clear;
+    uint32_t num_scanouts;
+    uint32_t reserved;
+};
+
+/* simple formats for fbcon/X use */
+enum virtio_gpu_formats {
+    VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM  = 1,
+    VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM  = 2,
+    VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM  = 3,
+    VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM  = 4,
+
+    VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM  = 5,
+    VIRTIO_GPU_FORMAT_B5G6R5_UNORM    = 7,
+
+    VIRTIO_GPU_FORMAT_R8_UNORM        = 64,
+};
+
+#endif