Skip to content

Commit 3a40b14

Browse files
ryanbreenclaude
andcommitted
feat: enforce 1280x960 minimum resolution for proper Retina display sizing
With --high-resolution on, Parallels uses 2x Retina scaling, making a 1280x960 guest appear as a tiny 640x480-point window. Switching to --high-resolution off maps 1 guest pixel to 1 Mac screen point, but GET_DISPLAY_INFO then only reports 1024x768. The kernel now enforces a 1280x960 minimum resolution floor, picking the largest valid resolution from GET_DISPLAY_INFO, GOP, and the minimum. Both run.sh and quick-test.sh updated with --high-resolution off and 256MB VRAM. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 27184e2 commit 3a40b14

3 files changed

Lines changed: 34 additions & 22 deletions

File tree

kernel/src/drivers/virtio/gpu_pci.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,11 @@ static mut PCI_3D_CMD_BUF: Pci3dCmdBuffer = Pci3dCmdBuffer { data: [0; 16384] };
406406
// 1728x1080 matches the QEMU resolution for consistent performance comparison.
407407
const DEFAULT_FB_WIDTH: u32 = 1728;
408408
const DEFAULT_FB_HEIGHT: u32 = 1080;
409+
// Minimum resolution floor — ensures the VM window is large enough on Retina Macs.
410+
// With --high-resolution off, 1 guest pixel = 1 Mac screen point, so 1280x960
411+
// gives a ~74% screen-width window on a 1728-point-wide display.
412+
const MIN_FB_WIDTH: u32 = 1280;
413+
const MIN_FB_HEIGHT: u32 = 960;
409414
// Max supported resolution: 2560x1600 @ 32bpp = ~16.4MB
410415
const FB_MAX_WIDTH: u32 = 2560;
411416
const FB_MAX_HEIGHT: u32 = 1600;
@@ -1085,28 +1090,31 @@ pub fn init() -> Result<(), &'static str> {
10851090
Err(e) => crate::serial_println!("[virtio-gpu-pci] GET_DISPLAY_INFO failed: {}", e),
10861091
}
10871092

1088-
// Use the display-reported resolution. Linux always matches its resources
1089-
// to the display mode — gl_display.c uses drmModeGetConnector to get the
1090-
// native mode and creates all resources at that resolution. SET_SCANOUT
1091-
// with dimensions exceeding the display mode is silently ignored by Parallels.
1092-
// DIAG: Force GOP resolution to test if resolution mismatch causes corruption.
1093-
// GOP reports 1024x768, GET_DISPLAY_INFO reports 1728x1080. If 2D resource
1094-
// must match the GOP physical display mode, using 1728x1080 would cause
1095-
// stride mismatch in the hypervisor's display pipeline.
1096-
// Use GOP resolution for the 2D resource + BAR0 display path.
1097-
// VirGL will use its own resolution (from GET_DISPLAY_INFO) for 3D resources.
1093+
// Pick the largest resolution from: GET_DISPLAY_INFO, GOP, or the minimum.
1094+
// On Retina Macs with --high-resolution off, Parallels maps 1 guest pixel to
1095+
// 1 Mac screen point. GET_DISPLAY_INFO may report only 1024x768 in this mode,
1096+
// but SET_SCANOUT at a larger resolution works fine (Linux does arbitrary mode
1097+
// changes via drmModeSetCrtc → SET_SCANOUT). We enforce a 1280x960 minimum
1098+
// so the VM window is reasonably large on modern displays.
10981099
let gop_w = crate::platform_config::fb_width();
10991100
let gop_h = crate::platform_config::fb_height();
1100-
let (use_width, use_height) = if gop_w > 0 && gop_h > 0 {
1101-
crate::serial_println!("[virtio-gpu-pci] Using GOP resolution {}x{} (display reported {:?})",
1102-
gop_w, gop_h, display_dims);
1103-
(gop_w, gop_h)
1104-
} else {
1105-
match display_dims {
1106-
Ok((dw, dh)) if dw > 0 && dh > 0 && dw <= FB_MAX_WIDTH && dh <= FB_MAX_HEIGHT => (dw, dh),
1107-
_ => (DEFAULT_FB_WIDTH, DEFAULT_FB_HEIGHT),
1108-
}
1109-
};
1101+
let (disp_w, disp_h) = display_dims.unwrap_or((0, 0));
1102+
// Pick the widest valid resolution, with 1280x960 as floor
1103+
let candidates: [(u32, u32); 3] = [
1104+
(disp_w, disp_h),
1105+
(gop_w, gop_h),
1106+
(MIN_FB_WIDTH, MIN_FB_HEIGHT),
1107+
];
1108+
let (use_width, use_height) = candidates
1109+
.iter()
1110+
.filter(|&&(w, h)| w >= MIN_FB_WIDTH && h > 0 && w <= FB_MAX_WIDTH && h <= FB_MAX_HEIGHT)
1111+
.max_by_key(|&&(w, _)| w)
1112+
.copied()
1113+
.unwrap_or((MIN_FB_WIDTH, MIN_FB_HEIGHT));
1114+
crate::serial_println!(
1115+
"[virtio-gpu-pci] Resolution: {}x{} (display={}x{}, GOP={}x{}, min={}x{})",
1116+
use_width, use_height, disp_w, disp_h, gop_w, gop_h, MIN_FB_WIDTH, MIN_FB_HEIGHT
1117+
);
11101118

11111119
// Update state with actual dimensions
11121120
unsafe {

run.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,10 @@ if [ "$PARALLELS" = true ]; then
331331

332332
# VirtIO GPU with 3D acceleration (required for VirGL)
333333
prlctl set "$PARALLELS_VM" --3d-accelerate highest 2>/dev/null || true
334-
prlctl set "$PARALLELS_VM" --videosize 128 2>/dev/null || true
334+
prlctl set "$PARALLELS_VM" --videosize 256 2>/dev/null || true
335+
# high-resolution OFF so the VM window maps 1:1 pixels-to-points on Retina Macs.
336+
# With high-resolution ON, a 1280x960 guest appears as a tiny 640x480 point window.
337+
prlctl set "$PARALLELS_VM" --high-resolution off 2>/dev/null || true
335338

336339
# Remove any default devices Parallels created (cdrom, hdd, serial) to avoid conflicts
337340
for dev in hdd0 hdd1 hdd2 cdrom0 cdrom1 serial0 serial1; do

scripts/parallels/quick-test.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ prlctl set "$VM_NAME" --memsize 2048 >/dev/null 2>&1
5454
prlctl set "$VM_NAME" --cpus 4 >/dev/null 2>&1
5555
prlctl set "$VM_NAME" --efi-boot on >/dev/null 2>&1 || true
5656
prlctl set "$VM_NAME" --3d-accelerate highest >/dev/null 2>&1 || true
57-
prlctl set "$VM_NAME" --videosize 128 >/dev/null 2>&1 || true
57+
prlctl set "$VM_NAME" --videosize 256 >/dev/null 2>&1 || true
58+
prlctl set "$VM_NAME" --high-resolution off >/dev/null 2>&1 || true
5859
for dev in hdd0 hdd1 hdd2 cdrom0 cdrom1 serial0 serial1; do
5960
prlctl set "$VM_NAME" --device-del "$dev" >/dev/null 2>&1 || true
6061
done

0 commit comments

Comments
 (0)