Implement the virtio-gpu feature in contrib/vhost-user-gpu, which was unsupported until now. In this implementation, the feature is enabled inconditionally to avoid creating another optional config argument. Similarly to get_display_info, vhost-user-gpu sends a message back to the frontend to have access to all the display information. In the case of get_edid, it also needs to pass which scanout we should retrieve the edid for. The VHOST_USER_GPU_PROTOCOL_F_EDID protocol feature is required if the frontend sets the VIRTIO_GPU_F_EDID virtio-gpu feature. If the frontend sets the virtio-gpu feature but does not support the protocol feature, the backend will abort with an error. Signed-off-by: Erico Nunes <ernunes@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20230626164708.1163239-4-ernunes@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
		
			
				
	
	
		
			195 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Virtio vhost-user GPU Device
 | 
						|
 *
 | 
						|
 * Copyright Red Hat, Inc. 2013-2018
 | 
						|
 *
 | 
						|
 * Authors:
 | 
						|
 *     Dave Airlie <airlied@redhat.com>
 | 
						|
 *     Gerd Hoffmann <kraxel@redhat.com>
 | 
						|
 *     Marc-André Lureau <marcandre.lureau@redhat.com>
 | 
						|
 *
 | 
						|
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | 
						|
 * See the COPYING file in the top-level directory.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef VUGPU_H
 | 
						|
#define VUGPU_H
 | 
						|
 | 
						|
 | 
						|
#include "libvhost-user-glib.h"
 | 
						|
#include "standard-headers/linux/virtio_gpu.h"
 | 
						|
 | 
						|
#include "qemu/queue.h"
 | 
						|
#include "qemu/iov.h"
 | 
						|
#include "qemu/bswap.h"
 | 
						|
#include "vugbm.h"
 | 
						|
 | 
						|
typedef enum VhostUserGpuRequest {
 | 
						|
    VHOST_USER_GPU_NONE = 0,
 | 
						|
    VHOST_USER_GPU_GET_PROTOCOL_FEATURES,
 | 
						|
    VHOST_USER_GPU_SET_PROTOCOL_FEATURES,
 | 
						|
    VHOST_USER_GPU_GET_DISPLAY_INFO,
 | 
						|
    VHOST_USER_GPU_CURSOR_POS,
 | 
						|
    VHOST_USER_GPU_CURSOR_POS_HIDE,
 | 
						|
    VHOST_USER_GPU_CURSOR_UPDATE,
 | 
						|
    VHOST_USER_GPU_SCANOUT,
 | 
						|
    VHOST_USER_GPU_UPDATE,
 | 
						|
    VHOST_USER_GPU_DMABUF_SCANOUT,
 | 
						|
    VHOST_USER_GPU_DMABUF_UPDATE,
 | 
						|
    VHOST_USER_GPU_GET_EDID,
 | 
						|
} VhostUserGpuRequest;
 | 
						|
 | 
						|
typedef struct VhostUserGpuDisplayInfoReply {
 | 
						|
    struct virtio_gpu_resp_display_info info;
 | 
						|
} VhostUserGpuDisplayInfoReply;
 | 
						|
 | 
						|
typedef struct VhostUserGpuCursorPos {
 | 
						|
    uint32_t scanout_id;
 | 
						|
    uint32_t x;
 | 
						|
    uint32_t y;
 | 
						|
} QEMU_PACKED VhostUserGpuCursorPos;
 | 
						|
 | 
						|
typedef struct VhostUserGpuCursorUpdate {
 | 
						|
    VhostUserGpuCursorPos pos;
 | 
						|
    uint32_t hot_x;
 | 
						|
    uint32_t hot_y;
 | 
						|
    uint32_t data[64 * 64];
 | 
						|
} QEMU_PACKED VhostUserGpuCursorUpdate;
 | 
						|
 | 
						|
typedef struct VhostUserGpuScanout {
 | 
						|
    uint32_t scanout_id;
 | 
						|
    uint32_t width;
 | 
						|
    uint32_t height;
 | 
						|
} QEMU_PACKED VhostUserGpuScanout;
 | 
						|
 | 
						|
typedef struct VhostUserGpuUpdate {
 | 
						|
    uint32_t scanout_id;
 | 
						|
    uint32_t x;
 | 
						|
    uint32_t y;
 | 
						|
    uint32_t width;
 | 
						|
    uint32_t height;
 | 
						|
    uint8_t data[];
 | 
						|
} QEMU_PACKED VhostUserGpuUpdate;
 | 
						|
 | 
						|
typedef struct VhostUserGpuDMABUFScanout {
 | 
						|
    uint32_t scanout_id;
 | 
						|
    uint32_t x;
 | 
						|
    uint32_t y;
 | 
						|
    uint32_t width;
 | 
						|
    uint32_t height;
 | 
						|
    uint32_t fd_width;
 | 
						|
    uint32_t fd_height;
 | 
						|
    uint32_t fd_stride;
 | 
						|
    uint32_t fd_flags;
 | 
						|
    int fd_drm_fourcc;
 | 
						|
} QEMU_PACKED VhostUserGpuDMABUFScanout;
 | 
						|
 | 
						|
typedef struct VhostUserGpuEdidRequest {
 | 
						|
    uint32_t scanout_id;
 | 
						|
} QEMU_PACKED VhostUserGpuEdidRequest;
 | 
						|
 | 
						|
typedef struct VhostUserGpuMsg {
 | 
						|
    uint32_t request; /* VhostUserGpuRequest */
 | 
						|
    uint32_t flags;
 | 
						|
    uint32_t size; /* the following payload size */
 | 
						|
    union {
 | 
						|
        VhostUserGpuCursorPos cursor_pos;
 | 
						|
        VhostUserGpuCursorUpdate cursor_update;
 | 
						|
        VhostUserGpuScanout scanout;
 | 
						|
        VhostUserGpuUpdate update;
 | 
						|
        VhostUserGpuDMABUFScanout dmabuf_scanout;
 | 
						|
        VhostUserGpuEdidRequest edid_req;
 | 
						|
        struct virtio_gpu_resp_edid resp_edid;
 | 
						|
        struct virtio_gpu_resp_display_info display_info;
 | 
						|
        uint64_t u64;
 | 
						|
    } payload;
 | 
						|
} QEMU_PACKED VhostUserGpuMsg;
 | 
						|
 | 
						|
static VhostUserGpuMsg m __attribute__ ((unused));
 | 
						|
#define VHOST_USER_GPU_HDR_SIZE \
 | 
						|
    (sizeof(m.request) + sizeof(m.flags) + sizeof(m.size))
 | 
						|
 | 
						|
#define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
 | 
						|
 | 
						|
#define VHOST_USER_GPU_PROTOCOL_F_EDID 0
 | 
						|
 | 
						|
struct virtio_gpu_scanout {
 | 
						|
    uint32_t width, height;
 | 
						|
    int x, y;
 | 
						|
    int invalidate;
 | 
						|
    uint32_t resource_id;
 | 
						|
};
 | 
						|
 | 
						|
typedef struct VuGpu {
 | 
						|
    VugDev dev;
 | 
						|
    struct virtio_gpu_config virtio_config;
 | 
						|
    struct vugbm_device gdev;
 | 
						|
    int sock_fd;
 | 
						|
    int drm_rnode_fd;
 | 
						|
    GSource *renderer_source;
 | 
						|
    guint wait_in;
 | 
						|
 | 
						|
    bool virgl;
 | 
						|
    bool virgl_inited;
 | 
						|
    bool edid_inited;
 | 
						|
    uint32_t inflight;
 | 
						|
 | 
						|
    struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
 | 
						|
    QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist;
 | 
						|
    QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
 | 
						|
} VuGpu;
 | 
						|
 | 
						|
enum {
 | 
						|
    VG_CMD_STATE_NEW,
 | 
						|
    VG_CMD_STATE_PENDING,
 | 
						|
    VG_CMD_STATE_FINISHED,
 | 
						|
};
 | 
						|
 | 
						|
struct virtio_gpu_ctrl_command {
 | 
						|
    VuVirtqElement elem;
 | 
						|
    VuVirtq *vq;
 | 
						|
    struct virtio_gpu_ctrl_hdr cmd_hdr;
 | 
						|
    uint32_t error;
 | 
						|
    int state;
 | 
						|
    QTAILQ_ENTRY(virtio_gpu_ctrl_command) next;
 | 
						|
};
 | 
						|
 | 
						|
#define VUGPU_FILL_CMD(out) do {                                \
 | 
						|
        size_t s;                                               \
 | 
						|
        s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0,  \
 | 
						|
                       &out, sizeof(out));                      \
 | 
						|
        if (s != sizeof(out)) {                                 \
 | 
						|
            g_critical("%s: command size incorrect %zu vs %zu", \
 | 
						|
                       __func__, s, sizeof(out));               \
 | 
						|
            return;                                             \
 | 
						|
        }                                                       \
 | 
						|
    } while (0)
 | 
						|
 | 
						|
 | 
						|
void    vg_ctrl_response(VuGpu *g,
 | 
						|
                         struct virtio_gpu_ctrl_command *cmd,
 | 
						|
                         struct virtio_gpu_ctrl_hdr *resp,
 | 
						|
                         size_t resp_len);
 | 
						|
 | 
						|
void    vg_ctrl_response_nodata(VuGpu *g,
 | 
						|
                                struct virtio_gpu_ctrl_command *cmd,
 | 
						|
                                enum virtio_gpu_ctrl_type type);
 | 
						|
 | 
						|
int     vg_create_mapping_iov(VuGpu *g,
 | 
						|
                              struct virtio_gpu_resource_attach_backing *ab,
 | 
						|
                              struct virtio_gpu_ctrl_command *cmd,
 | 
						|
                              struct iovec **iov);
 | 
						|
void    vg_cleanup_mapping_iov(VuGpu *g, struct iovec *iov, uint32_t count);
 | 
						|
void    vg_get_display_info(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd);
 | 
						|
void    vg_get_edid(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd);
 | 
						|
 | 
						|
void    vg_wait_ok(VuGpu *g);
 | 
						|
 | 
						|
void    vg_send_msg(VuGpu *g, const VhostUserGpuMsg *msg, int fd);
 | 
						|
 | 
						|
bool    vg_recv_msg(VuGpu *g, uint32_t expect_req, uint32_t expect_size,
 | 
						|
                    gpointer payload);
 | 
						|
 | 
						|
 | 
						|
#endif
 |