75 lines
2.5 KiB
Diff
75 lines
2.5 KiB
Diff
--- a/include/hw/virtio/virtio-gpu.h
|
|
+++ b/include/hw/virtio/virtio-gpu.h
|
|
@@ -128,6 +128,7 @@
|
|
uint32_t flags;
|
|
uint32_t xres;
|
|
uint32_t yres;
|
|
+ uint32_t refresh_rate;
|
|
uint64_t hostmem;
|
|
VirtIOGPUOutputList *outputs;
|
|
};
|
|
@@ -173,7 +174,8 @@
|
|
DEFINE_PROP_BIT("edid", _state, _conf.flags, \
|
|
VIRTIO_GPU_FLAG_EDID_ENABLED, true), \
|
|
DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1280), \
|
|
- DEFINE_PROP_UINT32("yres", _state, _conf.yres, 800)
|
|
+ DEFINE_PROP_UINT32("yres", _state, _conf.yres, 800), \
|
|
+ DEFINE_PROP_UINT32("refresh_rate", _state, _conf.refresh_rate, 0)
|
|
|
|
typedef struct VGPUDMABuf {
|
|
QemuDmaBuf *buf;
|
|
--- a/hw/display/virtio-gpu-base.c
|
|
+++ b/hw/display/virtio-gpu-base.c
|
|
@@ -64,7 +64,9 @@
|
|
.height_mm = g->req_state[scanout].height_mm,
|
|
.prefx = g->req_state[scanout].width,
|
|
.prefy = g->req_state[scanout].height,
|
|
- .refresh_rate = g->req_state[scanout].refresh_rate,
|
|
+ /* An explicit monitor refresh rate, in mHz, survives UI resizes. */
|
|
+ .refresh_rate = g->conf.refresh_rate ? g->conf.refresh_rate :
|
|
+ g->req_state[scanout].refresh_rate,
|
|
};
|
|
|
|
for (output_idx = 0, node = g->conf.outputs;
|
|
--- a/hw/display/edid-generate.c
|
|
+++ b/hw/display/edid-generate.c
|
|
@@ -220,17 +220,20 @@
|
|
desc[5 + len] = '\n';
|
|
}
|
|
|
|
-static void edid_desc_ranges(uint8_t *desc)
|
|
+static void edid_desc_ranges(uint8_t *desc, uint64_t clock,
|
|
+ uint32_t htotal, uint32_t vtotal)
|
|
{
|
|
edid_desc_type(desc, 0xfd);
|
|
|
|
- /* vertical (50 -> 125 Hz) */
|
|
- desc[5] = 50;
|
|
- desc[6] = 125;
|
|
-
|
|
- /* horizontal (30 -> 160 kHz) */
|
|
- desc[7] = 30;
|
|
- desc[8] = 160;
|
|
+ /* Enclose the encoded timing after its 10 kHz pixel-clock rounding,
|
|
+ * while retaining legacy ranges whenever they already contain it. */
|
|
+ uint64_t vperiod = (uint64_t)htotal * vtotal;
|
|
+ uint64_t hperiod = (uint64_t)htotal * 1000;
|
|
+ desc[5] = MIN(50, clock / vperiod);
|
|
+ desc[6] = MIN(255, MAX(125, DIV_ROUND_UP(clock, vperiod)));
|
|
+
|
|
+ desc[7] = MIN(30, clock / hperiod);
|
|
+ desc[8] = MIN(255, MAX(160, DIV_ROUND_UP(clock, hperiod)));
|
|
|
|
/* max dot clock (2550 MHz) */
|
|
desc[9] = 2550 / 10;
|
|
@@ -513,7 +516,8 @@
|
|
* so dta descriptor offsets don't move any more.
|
|
*/
|
|
|
|
- edid_desc_ranges(desc);
|
|
+ edid_desc_ranges(desc, (uint64_t)timings.clock * 10000,
|
|
+ info->prefx + timings.xblank, info->prefy + timings.yblank);
|
|
desc = edid_desc_next(edid, dta, desc);
|
|
|
|
if (desc && info->name) {
|