mirror of https://github.com/xemu-project/xemu.git
contrib/vhost-user-gpu: implement get_edid feature
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>
This commit is contained in:
parent
50cbd5b4b3
commit
c06444261e
|
@ -303,6 +303,53 @@ vg_get_display_info(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd)
|
||||||
cmd->state = VG_CMD_STATE_PENDING;
|
cmd->state = VG_CMD_STATE_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_edid_cb(gint fd, GIOCondition condition, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_resp_edid resp_edid;
|
||||||
|
VuGpu *vg = user_data;
|
||||||
|
struct virtio_gpu_ctrl_command *cmd = QTAILQ_LAST(&vg->fenceq);
|
||||||
|
|
||||||
|
g_debug("get edid cb");
|
||||||
|
assert(cmd->cmd_hdr.type == VIRTIO_GPU_CMD_GET_EDID);
|
||||||
|
if (!vg_recv_msg(vg, VHOST_USER_GPU_GET_EDID,
|
||||||
|
sizeof(resp_edid), &resp_edid)) {
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTAILQ_REMOVE(&vg->fenceq, cmd, next);
|
||||||
|
vg_ctrl_response(vg, cmd, &resp_edid.hdr, sizeof(resp_edid));
|
||||||
|
|
||||||
|
vg->wait_in = 0;
|
||||||
|
vg_handle_ctrl(&vg->dev.parent, 0);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vg_get_edid(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_cmd_get_edid get_edid;
|
||||||
|
|
||||||
|
VUGPU_FILL_CMD(get_edid);
|
||||||
|
virtio_gpu_bswap_32(&get_edid, sizeof(get_edid));
|
||||||
|
|
||||||
|
VhostUserGpuMsg msg = {
|
||||||
|
.request = VHOST_USER_GPU_GET_EDID,
|
||||||
|
.size = sizeof(VhostUserGpuEdidRequest),
|
||||||
|
.payload.edid_req = {
|
||||||
|
.scanout_id = get_edid.scanout,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(vg->wait_in == 0);
|
||||||
|
|
||||||
|
vg_send_msg(vg, &msg, -1);
|
||||||
|
vg->wait_in = g_unix_fd_add(vg->sock_fd, G_IO_IN | G_IO_HUP,
|
||||||
|
get_edid_cb, vg);
|
||||||
|
cmd->state = VG_CMD_STATE_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vg_resource_create_2d(VuGpu *g,
|
vg_resource_create_2d(VuGpu *g,
|
||||||
struct virtio_gpu_ctrl_command *cmd)
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
@ -837,8 +884,9 @@ vg_process_cmd(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd)
|
||||||
case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
|
case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
|
||||||
vg_resource_detach_backing(vg, cmd);
|
vg_resource_detach_backing(vg, cmd);
|
||||||
break;
|
break;
|
||||||
/* case VIRTIO_GPU_CMD_GET_EDID: */
|
case VIRTIO_GPU_CMD_GET_EDID:
|
||||||
/* break */
|
vg_get_edid(vg, cmd);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_warning("TODO handle ctrl %x\n", cmd->cmd_hdr.type);
|
g_warning("TODO handle ctrl %x\n", cmd->cmd_hdr.type);
|
||||||
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||||
|
@ -1022,26 +1070,36 @@ vg_queue_set_started(VuDev *dev, int qidx, bool started)
|
||||||
static gboolean
|
static gboolean
|
||||||
protocol_features_cb(gint fd, GIOCondition condition, gpointer user_data)
|
protocol_features_cb(gint fd, GIOCondition condition, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
const uint64_t protocol_edid = (1 << VHOST_USER_GPU_PROTOCOL_F_EDID);
|
||||||
VuGpu *g = user_data;
|
VuGpu *g = user_data;
|
||||||
uint64_t u64;
|
uint64_t protocol_features;
|
||||||
VhostUserGpuMsg msg = {
|
VhostUserGpuMsg msg = {
|
||||||
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES
|
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!vg_recv_msg(g, msg.request, sizeof(u64), &u64)) {
|
if (!vg_recv_msg(g, msg.request,
|
||||||
|
sizeof(protocol_features), &protocol_features)) {
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protocol_features &= protocol_edid;
|
||||||
|
|
||||||
msg = (VhostUserGpuMsg) {
|
msg = (VhostUserGpuMsg) {
|
||||||
.request = VHOST_USER_GPU_SET_PROTOCOL_FEATURES,
|
.request = VHOST_USER_GPU_SET_PROTOCOL_FEATURES,
|
||||||
.size = sizeof(uint64_t),
|
.size = sizeof(uint64_t),
|
||||||
.payload.u64 = 0
|
.payload.u64 = protocol_features,
|
||||||
};
|
};
|
||||||
vg_send_msg(g, &msg, -1);
|
vg_send_msg(g, &msg, -1);
|
||||||
|
|
||||||
g->wait_in = 0;
|
g->wait_in = 0;
|
||||||
vg_handle_ctrl(&g->dev.parent, 0);
|
vg_handle_ctrl(&g->dev.parent, 0);
|
||||||
|
|
||||||
|
if (g->edid_inited && !(protocol_features & protocol_edid)) {
|
||||||
|
g_printerr("EDID feature set by the frontend but it does not support "
|
||||||
|
"the EDID vhost-user-gpu protocol.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1049,7 +1107,7 @@ static void
|
||||||
set_gpu_protocol_features(VuGpu *g)
|
set_gpu_protocol_features(VuGpu *g)
|
||||||
{
|
{
|
||||||
VhostUserGpuMsg msg = {
|
VhostUserGpuMsg msg = {
|
||||||
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES
|
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES,
|
||||||
};
|
};
|
||||||
|
|
||||||
vg_send_msg(g, &msg, -1);
|
vg_send_msg(g, &msg, -1);
|
||||||
|
@ -1086,6 +1144,7 @@ vg_get_features(VuDev *dev)
|
||||||
if (opt_virgl) {
|
if (opt_virgl) {
|
||||||
features |= 1 << VIRTIO_GPU_F_VIRGL;
|
features |= 1 << VIRTIO_GPU_F_VIRGL;
|
||||||
}
|
}
|
||||||
|
features |= 1 << VIRTIO_GPU_F_EDID;
|
||||||
|
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
|
@ -1103,6 +1162,8 @@ vg_set_features(VuDev *dev, uint64_t features)
|
||||||
g->virgl_inited = true;
|
g->virgl_inited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g->edid_inited = !!(features & (1 << VIRTIO_GPU_F_EDID));
|
||||||
|
|
||||||
g->virgl = virgl;
|
g->virgl = virgl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -495,6 +495,9 @@ void vg_virgl_process_cmd(VuGpu *g, struct virtio_gpu_ctrl_command *cmd)
|
||||||
case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
|
case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
|
||||||
vg_get_display_info(g, cmd);
|
vg_get_display_info(g, cmd);
|
||||||
break;
|
break;
|
||||||
|
case VIRTIO_GPU_CMD_GET_EDID:
|
||||||
|
vg_get_edid(g, cmd);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_debug("TODO handle ctrl %x\n", cmd->cmd_hdr.type);
|
g_debug("TODO handle ctrl %x\n", cmd->cmd_hdr.type);
|
||||||
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||||
|
|
|
@ -36,6 +36,7 @@ typedef enum VhostUserGpuRequest {
|
||||||
VHOST_USER_GPU_UPDATE,
|
VHOST_USER_GPU_UPDATE,
|
||||||
VHOST_USER_GPU_DMABUF_SCANOUT,
|
VHOST_USER_GPU_DMABUF_SCANOUT,
|
||||||
VHOST_USER_GPU_DMABUF_UPDATE,
|
VHOST_USER_GPU_DMABUF_UPDATE,
|
||||||
|
VHOST_USER_GPU_GET_EDID,
|
||||||
} VhostUserGpuRequest;
|
} VhostUserGpuRequest;
|
||||||
|
|
||||||
typedef struct VhostUserGpuDisplayInfoReply {
|
typedef struct VhostUserGpuDisplayInfoReply {
|
||||||
|
@ -83,6 +84,10 @@ typedef struct VhostUserGpuDMABUFScanout {
|
||||||
int fd_drm_fourcc;
|
int fd_drm_fourcc;
|
||||||
} QEMU_PACKED VhostUserGpuDMABUFScanout;
|
} QEMU_PACKED VhostUserGpuDMABUFScanout;
|
||||||
|
|
||||||
|
typedef struct VhostUserGpuEdidRequest {
|
||||||
|
uint32_t scanout_id;
|
||||||
|
} QEMU_PACKED VhostUserGpuEdidRequest;
|
||||||
|
|
||||||
typedef struct VhostUserGpuMsg {
|
typedef struct VhostUserGpuMsg {
|
||||||
uint32_t request; /* VhostUserGpuRequest */
|
uint32_t request; /* VhostUserGpuRequest */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
@ -93,6 +98,8 @@ typedef struct VhostUserGpuMsg {
|
||||||
VhostUserGpuScanout scanout;
|
VhostUserGpuScanout scanout;
|
||||||
VhostUserGpuUpdate update;
|
VhostUserGpuUpdate update;
|
||||||
VhostUserGpuDMABUFScanout dmabuf_scanout;
|
VhostUserGpuDMABUFScanout dmabuf_scanout;
|
||||||
|
VhostUserGpuEdidRequest edid_req;
|
||||||
|
struct virtio_gpu_resp_edid resp_edid;
|
||||||
struct virtio_gpu_resp_display_info display_info;
|
struct virtio_gpu_resp_display_info display_info;
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
} payload;
|
} payload;
|
||||||
|
@ -104,6 +111,8 @@ static VhostUserGpuMsg m __attribute__ ((unused));
|
||||||
|
|
||||||
#define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
|
#define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
|
||||||
|
|
||||||
|
#define VHOST_USER_GPU_PROTOCOL_F_EDID 0
|
||||||
|
|
||||||
struct virtio_gpu_scanout {
|
struct virtio_gpu_scanout {
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
@ -122,6 +131,7 @@ typedef struct VuGpu {
|
||||||
|
|
||||||
bool virgl;
|
bool virgl;
|
||||||
bool virgl_inited;
|
bool virgl_inited;
|
||||||
|
bool edid_inited;
|
||||||
uint32_t inflight;
|
uint32_t inflight;
|
||||||
|
|
||||||
struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
|
struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
|
||||||
|
@ -171,6 +181,7 @@ int vg_create_mapping_iov(VuGpu *g,
|
||||||
struct iovec **iov);
|
struct iovec **iov);
|
||||||
void vg_cleanup_mapping_iov(VuGpu *g, struct iovec *iov, uint32_t count);
|
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_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_wait_ok(VuGpu *g);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue