From: Gerd Hoffmann <kraxel@xxxxxxxxxx> Resuming the effort to get the gpu device specs merged. Support for 2d mode (3d/virgl mode is not covered by this patch) has been added to the linux kernel version 4.2 and to qemu version 2.4. git branch: https://www.kraxel.org/cgit/virtio-spec/commit/?h=virtio-gpu Rendered versions are available here: https://www.kraxel.org/virtio/virtio-v1.0-cs03-virtio-gpu.pdf https://www.kraxel.org/virtio/virtio-v1.0-cs03-virtio-gpu.html#x1-2800007 Signed-off-by: Gerd Hoffmann <kraxel@xxxxxxxxxx> --- content.tex | 2 + virtio-gpu.tex | 481 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 483 insertions(+) create mode 100644 virtio-gpu.tex diff --git a/content.tex b/content.tex index be1823431dd1..d41c2f8d7627 100644 --- a/content.tex +++ b/content.tex @@ -5325,6 +5325,8 @@ descriptor for the \field{sense_len}, \field{residual}, \field{status_qualifier}, \field{status}, \field{response} and \field{sense} fields. +\input{virtio-gpu.tex} + \chapter{Reserved Feature Bits}\label{sec:Reserved Feature Bits} Currently these device-independent feature bits defined: diff --git a/virtio-gpu.tex b/virtio-gpu.tex new file mode 100644 index 000000000000..34cf493bbcd1 --- /dev/null +++ b/virtio-gpu.tex @@ -0,0 +1,481 @@ +\section{GPU Device}\label{sec:Device Types / GPU Device} + +virtio-gpu is a virtio based graphics adapter. It can operate in 2D +mode and in 3D (virgl) mode. 3D mode will offload rendering ops to +the host gpu and therefore requires a gpu with 3D support on the host +machine. + +3D mode is not covered (yet) in this specification, even though it is +mentioned here and there due to some details of the virtual hardware +being designed with 3D mode in mind. + +In 2D mode the virtio-gpu device provides support for ARGB Hardware +cursors and multiple scanouts (aka heads). + +\subsection{Device ID}\label{sec:Device Types / GPU Device / Device ID} + +16 + +\subsection{Virtqueues}\label{sec:Device Types / GPU Device / Virtqueues} + +\begin{description} +\item[0] controlq - queue for sending control commands +\item[1] cursorq - queue for sending cursor updates +\end{description} + +Both queues have the same format. Each request and each response have +a fixed header, followed by command specific data fields. The +separate cursor queue is the "fast track" for cursor commands +(VIRTIO_GPU_CMD_UPDATE_CURSOR and VIRTIO_GPU_CMD_MOVE_CURSOR), so they +go though without being delayed by time-consuming commands in the +control queue. + +\subsection{Feature bits}\label{sec:Device Types / GPU Device / Feature bits} + +\begin{description} +\item[VIRTIO_GPU_F_VIRGL (0)] virgl 3D mode is supported. +\end{description} + +\subsection{Device configuration layout}\label{sec:Device Types / GPU Device / Device configuration layout} + +\begin{lstlisting} +#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) + +struct virtio_gpu_config { + le32 events_read; + le32 events_clear; + le32 num_scanouts; + le32 reserved; +} +\end{lstlisting} + +\subsubsection{Device configuration fields} + +\begin{description} +\item[\field{events_read}] signals pending events to the driver. The + driver MUST NOT write to this field. +\item[\field{events_clear}] clears pending events in the device. + Writing a '1' into a bit will clear the corresponding bit in + \field{events_read}, mimicking write-to-clear behavior. +\item[\field{num_scanouts}] specifies the maximum number of scanouts + supported by the device. Minimum value is 1, maximum value is 16. +\end{description} + +\subsubsection{Events} + +\begin{description} +\item[VIRTIO_GPU_EVENT_DISPLAY] Display configuration has changed. + The driver SHOULD use the VIRTIO_GPU_CMD_GET_DISPLAY_INFO command to + fetch the information from the device. +\end{description} + +\devicenormative{\subsection}{Device Initialization}{Device Types / GPU Device / Device Initialization} + +The driver SHOULD query the display information from the device using +the VIRTIO_GPU_CMD_GET_DISPLAY_INFO command and use that information +for the initial scanout setup. In case no information is available or +all displays are disabled the driver MAY choose to use a fallback, +such as 1024x768 at display 0. + +\subsection{Device Operation}\label{sec:Device Types / GPU Device / Device Operation} + +The virtio-gpu is based around the concept of resources private to the +host, the guest must DMA transfer into these resources. This is a +design requirement in order to interface with future 3D rendering. In +the unaccelerated 2D mode there is no support for DMA transfers from +resources, just to them. + +Resources are initially simple 2D resources, consisting of a width, +height and format along with an identifier. The guest must then attach +backing store to the resources in order for DMA transfers to +work. This is like a GART in a real GPU. + +\subsubsection{Device Operation: Create a framebuffer and configure scanout} + +\begin{itemize*} +\item Create a host resource using VIRTIO_GPU_CMD_RESOURCE_CREATE_2D. +\item Allocate a framebuffer from guest ram, and attach it as backing + storage to the resource just created, using + VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING. Scatter lists are + supported, so the framebuffer doesn't need to be contignous in guest + physical memory. +\item Use VIRTIO_GPU_CMD_SET_SCANOUT to link the framebuffer to + a display scanout. +\end{itemize*} + +\subsubsection{Device Operation: Update a framebuffer and scanout} + +\begin{itemize*} +\item Render to your framebuffer memory. +\item Use VIRTIO_GPU_CMD_TRANSFER_SEND_2D to update the host resource + from guest memory. +\item Use VIRTIO_GPU_CMD_RESOURCE_FLUSH to flush the updated resource + to the display. +\end{itemize*} + +\subsubsection{Device Operation: Using pageflip} + +It is possible to create multiple framebuffers, flip between them +using VIRTIO_GPU_CMD_SET_SCANOUT and VIRTIO_GPU_CMD_RESOURCE_FLUSH, +and update the invisible framebuffer using +VIRTIO_GPU_CMD_TRANSFER_SEND_2D. + +\subsubsection{Device Operation: Multihead setup} + +In case two or more displays are present there are different ways to +configure things: + +\begin{itemize*} +\item Create a single framebuffer, link it to all displays + (mirroring). +\item Create an framebuffer for each display. +\item Create one big framebuffer, configure scanouts to display a + different rectangle of that framebuffer each. +\end{itemize*} + +\devicenormative{\subsubsection}{Device Operation: Command lifecycle and fencing}{Device Types / GPU Device / Device Operation / Device Operation: Command lifecycle and fencing} + +The device MAY process controlq commands asyncronously and return them +to the driver before the processing is complete. If the driver needs +to know when the processing is finished it can set the +VIRTIO_GPU_FLAG_FENCE flag in the request. The device MUST finish the +processing before returning the command then. + +Note: current qemu implementation does asyncrounous processing only in +3d mode, when offloading the processing to the host gpu. + +\subsubsection{Device Operation: Configure mouse cursor} + +The mouse cursor image is a normal resource, except that it must be +64x64 in size. The driver MUST create and populate the resource +(using the usual VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, +VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING and +VIRTIO_GPU_CMD_TRANSFER_SEND_2D controlq commands) and make sure they +are completed (using VIRTIO_GPU_FLAG_FENCE). + +Then VIRTIO_GPU_CMD_UPDATE_CURSOR can be sent to the cursorq to set +the pointer shape and position. To move the pointer without updating +the shape use VIRTIO_GPU_CMD_MOVE_CURSOR instead. + +\subsubsection{Device Operation: Request header}\label{sec:Device Types / GPU Device / Device Operation / Device Operation: Request header} + +\begin{lstlisting} +enum virtio_gpu_ctrl_type { + + /* 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 { + le32 type; + le32 flags; + le64 fence_id; + le32 ctx_id; + le32 padding; +}; +\end{lstlisting} + +All requests and responses on the virt queues have the fixed header +\field{struct virtio_gpu_ctrl_hdr}. + +\begin{description} +\item[\field{type}] specifies the type of the driver request + (VIRTIO_GPU_CMD_*) or device response (VIRTIO_GPU_RESP_*). +\item[\field{flags}] request / response flags. +\item[\field{fence_id}] If the driver sets the VIRTIO_GPU_FLAG_FENCE + bit in the request \field{flags} field the device MUST: + \begin{itemize*} + \item set VIRTIO_GPU_FLAG_FENCE bit in the response, + \item copy the content of the \field{fence_id} field from the + request to the response, and + \item send the response only after command processing is complete. + \end{itemize*} +\item[\field{ctx_id}] Rendering context (used in 3D mode only). +\end{description} + +On success the device will return VIRTIO_GPU_RESP_OK_NODATA in +case there is no payload. Otherwise the \field{type} field will +indicate the kind of payload. + +On error the device will return one of the +VIRTIO_GPU_RESP_ERR_* error codes. + +\subsubsection{Device Operation: controlq}\label{sec:Device Types / GPU Device / Device Operation / Device Operation: controlq} + +For any coordinates given 0,0 is top left, larger x moves right, +larger y moves down. + +\begin{description} + +\item[VIRTIO_GPU_CMD_GET_DISPLAY_INFO] Retrieve the current output + configuration. No request data (just bare \field{struct + virtio_gpu_ctrl_hdr}). Response type is + VIRTIO_GPU_RESP_OK_DISPLAY_INFO, response data is \field{struct + virtio_gpu_resp_display_info}. + +\begin{lstlisting} +#define VIRTIO_GPU_MAX_SCANOUTS 16 + +struct virtio_gpu_rect { + le32 x; + le32 y; + le32 width; + le32 height; +}; + +struct virtio_gpu_resp_display_info { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_display_one { + struct virtio_gpu_rect r; + le32 enabled; + le32 flags; + } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; +}; +\end{lstlisting} + +The response contains a list of per-scanout information. The info +contains whether the scanout is enabled and what its preferred +position and size is. + +The size (fields \field{width} and \field{height}) is similar to the +native panel resolution in EDID display information, except that in +the virtual machine case the size can change when the host window +representing the guest display is gets resized. + +The position (fields \field{x} and \field{y}) describe how the +displays are arranged (i.e. which is -- for example -- the left +display). + +The \field{enabled} field is set when the user enabled the display. +It is roughly the same as the connected state of a phyiscal display +connector. + +\item[VIRTIO_GPU_CMD_RESOURCE_CREATE_2D] Create a 2D resource on the + host. Request data is \field{struct virtio_gpu_resource_create_2d}. + Response type is VIRTIO_GPU_RESP_OK_NODATA. + +\begin{lstlisting} +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_R8G8B8A8_UNORM = 67, + VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68, + + VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121, + VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, +}; + +struct virtio_gpu_resource_create_2d { + struct virtio_gpu_ctrl_hdr hdr; + le32 resource_id; + le32 format; + le32 width; + le32 height; +}; +\end{lstlisting} + +This creates a 2D resource on the host with the specified width, +height and format. The resource ids are generated by the guest. + +\item[VIRTIO_GPU_CMD_RESOURCE_UNREF] Destroy a resource. Request data + is \field{struct virtio_gpu_resource_unref}. Response type is + VIRTIO_GPU_RESP_OK_NODATA. + +\begin{lstlisting} +struct virtio_gpu_resource_unref { + struct virtio_gpu_ctrl_hdr hdr; + le32 resource_id; + le32 padding; +}; +\end{lstlisting} + +This informs the host that a resource is no longer required by the +guest. + +\item[VIRTIO_GPU_CMD_SET_SCANOUT] Set the scanout parameters for a + single output. Request data is \field{struct + virtio_gpu_set_scanout}. Response type is + VIRTIO_GPU_RESP_OK_NODATA. + +\begin{lstlisting} +struct virtio_gpu_set_scanout { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + le32 scanout_id; + le32 resource_id; +}; +\end{lstlisting} + +This sets the scanout parameters for a single scanout. The resource_id +is the resource to be scanned out from, along with a rectangle. + +Scanout rectangles must be completely covered by the underlying +resource. Overlapping (or identical) scanouts are allowed, typical +use case is screen mirroring. + +The driver can use resource_id = 0 to disable a scanout. + +\item[VIRTIO_GPU_CMD_RESOURCE_FLUSH] Flush a scanout resource Request + data is \field{struct virtio_gpu_resource_flush}. Response type is + VIRTIO_GPU_RESP_OK_NODATA. + +\begin{lstlisting} +struct virtio_gpu_resource_flush { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + le32 resource_id; + le32 padding; +}; +\end{lstlisting} + +This flushes a resource to screen. It takes a rectangle and a +resource id, and flushes any scanouts the resource is being used on. + +\item[VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D] Transfer from guest memory + to host resource. Request data is \field{struct + virtio_gpu_transfer_to_host_2d}. Response type is + VIRTIO_GPU_RESP_OK_NODATA. + +\begin{lstlisting} +struct virtio_gpu_transfer_to_host_2d { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + le64 offset; + le32 resource_id; + le32 padding; +}; +\end{lstlisting} + +This takes a resource id along with an destination offset into the +resource, and a box to transfer to the host backing for the resource. + +\item[VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING] Assign backing pages to + a resource. Request data is \field{struct + virtio_gpu_resource_attach_backing}, followed by \field{struct + virtio_gpu_mem_entry} entries. Response type is + VIRTIO_GPU_RESP_OK_NODATA. + +\begin{lstlisting} +struct virtio_gpu_resource_attach_backing { + struct virtio_gpu_ctrl_hdr hdr; + le32 resource_id; + le32 nr_entries; +}; + +struct virtio_gpu_mem_entry { + le64 addr; + le32 length; + le32 padding; +}; +\end{lstlisting} + +This assign an array of guest pages as the backing store for a +resource. These pages are then used for the transfer operations for +that resource from that point on. + +\item[VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING] Detach backing pages + from a resource. Request data is \field{struct + virtio_gpu_resource_detach_backing}. Response type is + VIRTIO_GPU_RESP_OK_NODATA. + +\begin{lstlisting} +struct virtio_gpu_resource_detach_backing { + struct virtio_gpu_ctrl_hdr hdr; + le32 resource_id; + le32 padding; +}; +\end{lstlisting} + +This detaches any backing pages from a resource, to be used in case of +guest swapping or object destruction. + +\end{description} + +\subsubsection{Device Operation: cursorq}\label{sec:Device Types / GPU Device / Device Operation / Device Operation: cursorq} + +Both cursorq commands use the same command struct. + +\begin{lstlisting} +struct virtio_gpu_cursor_pos { + le32 scanout_id; + le32 x; + le32 y; + le32 padding; +}; + +struct virtio_gpu_update_cursor { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_cursor_pos pos; + le32 resource_id; + le32 hot_x; + le32 hot_y; + le32 padding; +}; +\end{lstlisting} + +\begin{description} + +\item[VIRTIO_GPU_CMD_UPDATE_CURSOR] +Update cursor. +Request data is \field{struct virtio_gpu_update_cursor}. +Response type is VIRTIO_GPU_RESP_OK_NODATA. + +Full cursor update. Cursor will be loaded from the specified +\field{resource_id} and will be moved to \field{pos}. The driver must +transfer the cursor into the resource beforehand (using control queue +commands) and make sure the commands to fill the resource are actually +processed (using fencing). + +\item[VIRTIO_GPU_CMD_MOVE_CURSOR] +Move cursor. +Request data is \field{struct virtio_gpu_update_cursor}. +Response type is VIRTIO_GPU_RESP_OK_NODATA. + +Move cursor to the place specified in \field{pos}. The other fields +are not used and will be ignored by the device. + +\end{description} + +\subsection{VGA Compatibility}\label{sec:Device Types / GPU Device / VGA Compatibility} + +Applies to Virtio Over PCI only. The GPU device can come with and +without VGA compatibility. The PCI class should be DISPLAY_VGA if VGA +compatibility is present and DISPLAY_OTHER otherwise. + +VGA compatibility: PCI region 0 has the linear framebuffer, standard +vga registers are present. Configuring a scanout +(VIRTIO_GPU_CMD_SET_SCANOUT) switches the device from vga +compatibility mode into native virtio mode. A reset switches it back +into vga compatibility mode. + +Note: qemu implementation also provides bochs dispi interface io ports +and mmio bar at pci region 1 and is therefore fully compatible with +the qemu stdvga (see \href{http://git.qemu-project.org/?p=qemu.git;a=blob;f=docs/specs/standard-vga.txt;hb=HEAD}{docs/specs/standard-vga.txt} in the qemu source tree). -- Regards, Laurent Pinchart