fix: enclose rounded preferred timings in EDID ranges
This commit is contained in:
+3
-1
@@ -77,6 +77,8 @@ with tempfile.TemporaryDirectory(prefix='qemu-edid-probe-') as temporary:
|
|||||||
(144000, 60000, 1920, 1080, 144),
|
(144000, 60000, 1920, 1080, 144),
|
||||||
(144000, 0, 1600, 900, 144),
|
(144000, 0, 1600, 900, 144),
|
||||||
(0, 144000, 1920, 1080, 144),
|
(0, 144000, 1920, 1080, 144),
|
||||||
|
(50000, 0, 1920, 1080, 50),
|
||||||
|
(255000, 0, 1280, 800, 255),
|
||||||
]:
|
]:
|
||||||
data = subprocess.check_output([str(directory / 'probe'), *map(str, (configured, frontend, width, height))])
|
data = subprocess.check_output([str(directory / 'probe'), *map(str, (configured, frontend, width, height))])
|
||||||
assert all(sum(data[offset:offset + 128]) % 256 == 0 for offset in range(0, len(data), 128)), 'invalid EDID checksum'
|
assert all(sum(data[offset:offset + 128]) % 256 == 0 for offset in range(0, len(data), 128)), 'invalid EDID checksum'
|
||||||
@@ -93,6 +95,6 @@ with tempfile.TemporaryDirectory(prefix='qemu-edid-probe-') as temporary:
|
|||||||
assert ranges[5] <= actual <= ranges[6], f'vertical range {ranges[5:7]} excludes {actual}'
|
assert ranges[5] <= actual <= ranges[6], f'vertical range {ranges[5:7]} excludes {actual}'
|
||||||
horizontal_khz = clock / (horizontal + hblank) / 1000
|
horizontal_khz = clock / (horizontal + hblank) / 1000
|
||||||
assert ranges[7] <= horizontal_khz <= ranges[8], f'horizontal range {ranges[7:9]} excludes {horizontal_khz}'
|
assert ranges[7] <= horizontal_khz <= ranges[8], f'horizontal range {ranges[7:9]} excludes {horizontal_khz}'
|
||||||
if expected <= 75:
|
if configured == 0 and expected <= 75:
|
||||||
assert ranges[5:9] == bytes((50, 125, 30, 160)), 'legacy monitor range changed'
|
assert ranges[5:9] == bytes((50, 125, 30, 160)), 'legacy monitor range changed'
|
||||||
print(f'PASS configured={configured}, frontend={frontend}: {width}x{height}@{actual:.6f}, ranges={list(ranges[5:9])}')
|
print(f'PASS configured={configured}, frontend={frontend}: {width}x{height}@{actual:.6f}, ranges={list(ranges[5:9])}')
|
||||||
|
|||||||
@@ -112,7 +112,11 @@ The probe applies the tracked patch to four relevant source files in a temporary
|
|||||||
directory, compiles the actual EDID and virtio GPU generator functions with a
|
directory, compiles the actual EDID and virtio GPU generator functions with a
|
||||||
small dependency harness, and decodes the result. It checks 60/75 Hz fallback,
|
small dependency harness, and decodes the result. It checks 60/75 Hz fallback,
|
||||||
144 Hz configuration, a conflicting 60 Hz frontend request, resized dimensions,
|
144 Hz configuration, a conflicting 60 Hz frontend request, resized dimensions,
|
||||||
checksums and monitor ranges. At 1920×1080/144000 mHz the preferred timing is
|
checksums and monitor ranges. It also checks the supported vertical-refresh
|
||||||
|
boundaries: 1920×1080/50000 mHz and 1280×800/255000 mHz. Range endpoints
|
||||||
|
use floor/ceiling of the encoded timing after pixel-clock rounding, so the
|
||||||
|
49.998895 Hz lower-boundary timing is included by a 49 Hz minimum. Normal
|
||||||
|
automatic 60/75 Hz cases retain the legacy 50–125 Hz range. At 1920×1080/144000 mHz the preferred timing is
|
||||||
143.997231 Hz after EDID clock rounding. This is an advertised guest mode,
|
143.997231 Hz after EDID clock rounding. This is an advertised guest mode,
|
||||||
not measured frame delivery or proof of a 144 Hz physical output.
|
not measured frame delivery or proof of a 144 Hz physical output.
|
||||||
|
|
||||||
|
|||||||
@@ -33,13 +33,13 @@
|
|||||||
for (output_idx = 0, node = g->conf.outputs;
|
for (output_idx = 0, node = g->conf.outputs;
|
||||||
--- a/hw/display/edid-generate.c
|
--- a/hw/display/edid-generate.c
|
||||||
+++ b/hw/display/edid-generate.c
|
+++ b/hw/display/edid-generate.c
|
||||||
@@ -220,17 +220,17 @@
|
@@ -220,17 +220,20 @@
|
||||||
desc[5 + len] = '\n';
|
desc[5 + len] = '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
-static void edid_desc_ranges(uint8_t *desc)
|
-static void edid_desc_ranges(uint8_t *desc)
|
||||||
+static void edid_desc_ranges(uint8_t *desc, uint32_t refresh_rate,
|
+static void edid_desc_ranges(uint8_t *desc, uint64_t clock,
|
||||||
+ uint32_t horizontal_rate)
|
+ uint32_t htotal, uint32_t vtotal)
|
||||||
{
|
{
|
||||||
edid_desc_type(desc, 0xfd);
|
edid_desc_type(desc, 0xfd);
|
||||||
|
|
||||||
@@ -50,22 +50,25 @@
|
|||||||
- /* horizontal (30 -> 160 kHz) */
|
- /* horizontal (30 -> 160 kHz) */
|
||||||
- desc[7] = 30;
|
- desc[7] = 30;
|
||||||
- desc[8] = 160;
|
- desc[8] = 160;
|
||||||
+ /* Preserve the legacy ranges and include the preferred mode. */
|
+ /* Enclose the encoded timing after its 10 kHz pixel-clock rounding,
|
||||||
+ desc[5] = 50;
|
+ * while retaining legacy ranges whenever they already contain it. */
|
||||||
+ desc[6] = MIN(255, MAX(125, DIV_ROUND_UP(refresh_rate, 1000)));
|
+ 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] = 30;
|
+ desc[7] = MIN(30, clock / hperiod);
|
||||||
+ desc[8] = MIN(255, MAX(160, DIV_ROUND_UP(horizontal_rate, 1000)));
|
+ desc[8] = MIN(255, MAX(160, DIV_ROUND_UP(clock, hperiod)));
|
||||||
|
|
||||||
/* max dot clock (2550 MHz) */
|
/* max dot clock (2550 MHz) */
|
||||||
desc[9] = 2550 / 10;
|
desc[9] = 2550 / 10;
|
||||||
@@ -513,7 +513,8 @@
|
@@ -513,7 +516,8 @@
|
||||||
* so dta descriptor offsets don't move any more.
|
* so dta descriptor offsets don't move any more.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
- edid_desc_ranges(desc);
|
- edid_desc_ranges(desc);
|
||||||
+ edid_desc_ranges(desc, refresh_rate,
|
+ edid_desc_ranges(desc, (uint64_t)timings.clock * 10000,
|
||||||
+ timings.clock * 10000 / (info->prefx + timings.xblank));
|
+ info->prefx + timings.xblank, info->prefy + timings.yblank);
|
||||||
desc = edid_desc_next(edid, dta, desc);
|
desc = edid_desc_next(edid, dta, desc);
|
||||||
|
|
||||||
if (desc && info->name) {
|
if (desc && info->name) {
|
||||||
|
|||||||
Reference in New Issue
Block a user