:p
atchew
Login
The purpose of this patch is customize refresh rate and resolution for the guest VM instead of being limited by the actual resolution of the host. Although it is possible to configure the VM kernel cmdline to set the EDID, such as with drm.edid_firmware=edid/1920x1080.bin, this approach is very inconvenient for three reasons: 1.Some systems, like Android, cannot dynamically set the kernel cmdline and require recompiling the Android image. 2.If the guest VM's DRM driver is built-in, the EDID file also needs to be built-in. If it is placed in the filesystem, the DRM driver will fail to load the firmware because the filesystem is not yet mounted when the driver starts. 3.Some tools for generating EDID files like:https://github.com/akatrevorjay/edid-generator.git have a limitation where the maximum main clock can only be 655 MHz, making it impossible to generate an EDID file for resolutions like 3840x2160@120Hz. The following patches are included in this series: 1. [PATCH 1/1] virtio-gpu: customize EDID for vms Thank you for reviewing these patches. Best regards, Lei Huang Lei.Huang@amd.com Lei Huang (1): virtio-gpu: customize EDID for vms hw/display/virtio-gpu-base.c | 41 ++++++++++++++++++++++++++++------ hw/display/virtio-gpu.c | 1 + include/hw/virtio/virtio-gpu.h | 26 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) -- 2.45.2
customize refresh rate and resolution for the guest VM instead of being limited by the actual resolution of the host. add edid info and modify conf like: "-device", "virtio-vga-gl,edid=on,max_outputs=2, refresh_rate0=120000,maxx0=7680,maxy0=1080,refresh_rate1=75000, maxx1=3840,maxy1=960" Change-Id: I5d5742d280186ffd5dee9eba7697f06a2b09b123 Signed-off-by: Lei Huang <Lei.Huang@amd.com> --- hw/display/virtio-gpu-base.c | 41 ++++++++++++++++++++++++++++------ hw/display/virtio-gpu.c | 1 + include/hw/virtio/virtio-gpu.h | 26 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index XXXXXXX..XXXXXXX 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -XXX,XX +XXX,XX @@ virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, for (i = 0; i < g->conf.max_outputs; i++) { if (g->enabled_output_bitmask & (1 << i)) { dpy_info->pmodes[i].enabled = 1; - dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); - dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); + if (g->edid_info[i].maxx && g->edid_info[i].maxy && + virtio_gpu_edid_enabled(g->conf)) { + dpy_info->pmodes[i].r.width = + cpu_to_le32(g->edid_info[i].maxx); + dpy_info->pmodes[i].r.height = + cpu_to_le32(g->edid_info[i].maxy); + } else { + dpy_info->pmodes[i].r.width = + cpu_to_le32(g->req_state[i].width); + dpy_info->pmodes[i].r.height = + cpu_to_le32(g->req_state[i].height); + } } } } @@ -XXX,XX +XXX,XX @@ virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout, .prefx = g->req_state[scanout].width, .prefy = g->req_state[scanout].height, .refresh_rate = g->req_state[scanout].refresh_rate, + .maxx = g->req_state[scanout].width, + .maxy = g->req_state[scanout].height, }; edid->size = cpu_to_le32(sizeof(edid->edid)); @@ -XXX,XX +XXX,XX @@ static void virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) g->req_state[idx].x = info->xoff; g->req_state[idx].y = info->yoff; - g->req_state[idx].refresh_rate = info->refresh_rate; - g->req_state[idx].width = info->width; - g->req_state[idx].height = info->height; + if (!g->edid_info[idx].refresh_rate) { + g->req_state[idx].refresh_rate = info->refresh_rate; + } + if (!g->edid_info[idx].maxx) { + g->req_state[idx].width = info->width; + } + if (!g->edid_info[idx].maxy) { + g->req_state[idx].height = info->height; + } + g->req_state[idx].width_mm = info->width_mm; g->req_state[idx].height_mm = info->height_mm; @@ -XXX,XX +XXX,XX @@ virtio_gpu_base_device_realize(DeviceState *qdev, g->enabled_output_bitmask = 1; - g->req_state[0].width = g->conf.xres; - g->req_state[0].height = g->conf.yres; g->hw_ops = &virtio_gpu_ops; for (i = 0; i < g->conf.max_outputs; i++) { + if (g->edid_info[i].maxx && g->edid_info[i].maxy && + virtio_gpu_edid_enabled(g->conf) && + g->edid_info[i].refresh_rate) { + g->req_state[i].refresh_rate = g->edid_info[i].refresh_rate; + g->req_state[i].width = g->edid_info[i].maxx; + g->req_state[i].height = g->edid_info[i].maxy; + } else { + g->req_state[i].width = g->conf.xres; + g->req_state[i].height = g->conf.yres; + } g->scanout[i].con = graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_virtio_gpu = { static Property virtio_gpu_properties[] = { VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf), + VIRTIO_GPU_EDID_PROPERTIES_MULTI_DISPLAY(VirtIOGPU, parent_obj.edid_info), DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem, 256 * MiB), DEFINE_PROP_BIT("blob", VirtIOGPU, parent_obj.conf.flags, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -XXX,XX +XXX,XX @@ #include "ui/qemu-pixman.h" #include "ui/console.h" #include "hw/virtio/virtio.h" +#include "hw/display/edid.h" #include "qemu/log.h" #include "sysemu/vhost-user-backend.h" @@ -XXX,XX +XXX,XX @@ struct VirtIOGPUBase { MemoryRegion hostmem; struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS]; + struct qemu_edid_info edid_info[VIRTIO_GPU_MAX_SCANOUTS]; int enabled_output_bitmask; struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUTS]; @@ -XXX,XX +XXX,XX @@ struct VirtIOGPUBaseClass { DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1280), \ DEFINE_PROP_UINT32("yres", _state, _conf.yres, 800) +#define VIRTIO_GPU_EDID_PROPERTIES_MULTI_DISPLAY(_state, _edid_info) \ + (VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 0), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 1), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 2), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 3), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 4), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 5), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 6), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 7), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 8), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 9), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 10), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 11), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 12), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 13), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 14), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 15)) \ + +#define VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, id) \ + (DEFINE_PROP_UINT32("maxx" #id, _state, _edid_info[id].maxx, 0), \ + DEFINE_PROP_UINT32("maxy" #id, _state, _edid_info[id].maxy, 0), \ + DEFINE_PROP_UINT32("refresh_rate" #id, _state, \ + _edid_info[id].refresh_rate, 0)) + typedef struct VGPUDMABuf { QemuDmaBuf *buf; uint32_t scanout_id; -- 2.45.2
The purpose of this patch is customize refresh rate and resolution for the guest VM instead of being limited by the actual resolution of the host. Although it is possible to configure the VM kernel cmdline to set the EDID, such as with drm.edid_firmware=edid/1920x1080.bin, this approach is very inconvenient for three reasons: 1.Some systems, like Android, cannot dynamically set the kernel cmdline and require recompiling the Android image. 2.If the guest VM's DRM driver is built-in, the EDID file also needs to be built-in. If it is placed in the filesystem, the DRM driver will fail to load the firmware because the filesystem is not yet mounted when the driver starts. 3.Some tools for generating EDID files like:https://github.com/akatrevorjay/edid-generator.git have a limitation where the maximum main clock can only be 655 MHz, making it impossible to generate an EDID file for resolutions like 3840x2160@120Hz. The following patches are included in this series: 1. [PATCH 1/1] virtio-gpu: customize EDID for vms Thank you for reviewing these patches. Best regards, Lei Huang Lei.Huang@amd.com Lei Huang (1): virtio-gpu: customize EDID for vms hw/display/virtio-gpu-base.c | 41 ++++++++++++++++++++++++++++------ hw/display/virtio-gpu.c | 1 + include/hw/virtio/virtio-gpu.h | 26 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) -- 2.45.2
customize refresh rate and resolution for the guest VM instead of being limited by the actual resolution of the host. add edid info and modify conf like: "-device", "virtio-vga-gl,edid=on,max_outputs=2, refresh_rate0=120000,maxx0=7680,maxy0=1080,refresh_rate1=75000, maxx1=3840,maxy1=960" Change-Id: I5d5742d280186ffd5dee9eba7697f06a2b09b123 Signed-off-by: Lei Huang <Lei.Huang@amd.com> --- hw/display/virtio-gpu-base.c | 41 ++++++++++++++++++++++++++++------ hw/display/virtio-gpu.c | 1 + include/hw/virtio/virtio-gpu.h | 26 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index XXXXXXX..XXXXXXX 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -XXX,XX +XXX,XX @@ virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, for (i = 0; i < g->conf.max_outputs; i++) { if (g->enabled_output_bitmask & (1 << i)) { dpy_info->pmodes[i].enabled = 1; - dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); - dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); + if (g->edid_info[i].maxx && g->edid_info[i].maxy && + virtio_gpu_edid_enabled(g->conf)) { + dpy_info->pmodes[i].r.width = + cpu_to_le32(g->edid_info[i].maxx); + dpy_info->pmodes[i].r.height = + cpu_to_le32(g->edid_info[i].maxy); + } else { + dpy_info->pmodes[i].r.width = + cpu_to_le32(g->req_state[i].width); + dpy_info->pmodes[i].r.height = + cpu_to_le32(g->req_state[i].height); + } } } } @@ -XXX,XX +XXX,XX @@ virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout, .prefx = g->req_state[scanout].width, .prefy = g->req_state[scanout].height, .refresh_rate = g->req_state[scanout].refresh_rate, + .maxx = g->req_state[scanout].width, + .maxy = g->req_state[scanout].height, }; edid->size = cpu_to_le32(sizeof(edid->edid)); @@ -XXX,XX +XXX,XX @@ static void virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) g->req_state[idx].x = info->xoff; g->req_state[idx].y = info->yoff; - g->req_state[idx].refresh_rate = info->refresh_rate; - g->req_state[idx].width = info->width; - g->req_state[idx].height = info->height; + if (!g->edid_info[idx].refresh_rate) { + g->req_state[idx].refresh_rate = info->refresh_rate; + } + if (!g->edid_info[idx].maxx) { + g->req_state[idx].width = info->width; + } + if (!g->edid_info[idx].maxy) { + g->req_state[idx].height = info->height; + } + g->req_state[idx].width_mm = info->width_mm; g->req_state[idx].height_mm = info->height_mm; @@ -XXX,XX +XXX,XX @@ virtio_gpu_base_device_realize(DeviceState *qdev, g->enabled_output_bitmask = 1; - g->req_state[0].width = g->conf.xres; - g->req_state[0].height = g->conf.yres; g->hw_ops = &virtio_gpu_ops; for (i = 0; i < g->conf.max_outputs; i++) { + if (g->edid_info[i].maxx && g->edid_info[i].maxy && + virtio_gpu_edid_enabled(g->conf) && + g->edid_info[i].refresh_rate) { + g->req_state[i].refresh_rate = g->edid_info[i].refresh_rate; + g->req_state[i].width = g->edid_info[i].maxx; + g->req_state[i].height = g->edid_info[i].maxy; + } else { + g->req_state[i].width = g->conf.xres; + g->req_state[i].height = g->conf.yres; + } g->scanout[i].con = graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_virtio_gpu = { static Property virtio_gpu_properties[] = { VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf), + VIRTIO_GPU_EDID_PROPERTIES_MULTI_DISPLAY(VirtIOGPU, parent_obj.edid_info), DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem, 256 * MiB), DEFINE_PROP_BIT("blob", VirtIOGPU, parent_obj.conf.flags, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -XXX,XX +XXX,XX @@ #include "ui/qemu-pixman.h" #include "ui/console.h" #include "hw/virtio/virtio.h" +#include "hw/display/edid.h" #include "qemu/log.h" #include "sysemu/vhost-user-backend.h" @@ -XXX,XX +XXX,XX @@ struct VirtIOGPUBase { MemoryRegion hostmem; struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS]; + struct qemu_edid_info edid_info[VIRTIO_GPU_MAX_SCANOUTS]; int enabled_output_bitmask; struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUTS]; @@ -XXX,XX +XXX,XX @@ struct VirtIOGPUBaseClass { DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1280), \ DEFINE_PROP_UINT32("yres", _state, _conf.yres, 800) +#define VIRTIO_GPU_EDID_PROPERTIES_MULTI_DISPLAY(_state, _edid_info) \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 0), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 1), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 2), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 3), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 4), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 5), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 6), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 7), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 8), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 9), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 10), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 11), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 12), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 13), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 14), \ + VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, 15) \ + +#define VIRTIO_GPU_EDID_PROPERTIES(_state, _edid_info, id) \ + DEFINE_PROP_UINT32("maxx" #id, _state, _edid_info[id].maxx, 0), \ + DEFINE_PROP_UINT32("maxy" #id, _state, _edid_info[id].maxy, 0), \ + DEFINE_PROP_UINT32("refresh_rate" #id, _state, \ + _edid_info[id].refresh_rate, 0) + typedef struct VGPUDMABuf { QemuDmaBuf *buf; uint32_t scanout_id; -- 2.45.2