qt/vulkan: tag dmabuf QImage with the renderer's DPR

`drawImage(0, 0, m_image)` paints in *logical* coordinates by
default. The framebuffer the renderer produces is already in *device*
pixels (logical × DPR — `syncSurfaceSize` rounds up that way and
sends those dimensions to libghostty). On a HiDPI display the
QImage's pixels were treated as logical units, so QPainter scaled
them up by the DPR — glyphs came out 2× too big.

`setDevicePixelRatio(m_fbDpr)` tells QPainter the image is already
in device pixels at that ratio, so each image pixel maps 1:1 to a
framebuffer pixel and glyphs render at their real size. `m_fbDpr`
is set by `syncSurfaceSize` and is the same ratio libghostty was
told the framebuffer was sized at, so the values match exactly.

Mirrors what the OpenGL path does at line 373 for its own readback
QImage. With this in place the Vulkan terminal renders visually
correctly end-to-end on the user's display.

Co-Authored-By: claude-flow <ruv@ruv.net>
pull/12846/head
Nathan 2026-05-24 15:49:53 -05:00
parent 38acf103d4
commit ab14f8f214
1 changed files with 9 additions and 0 deletions

View File

@ -1355,6 +1355,15 @@ void GhosttySurface::presentVulkanDmabuf(
QImage owned = stamped.copy();
::munmap(mapped, bytes);
// Tell QPainter the image's pixels are device pixels at the same
// DPR the framebuffer was sized at. Without this, `drawImage` would
// treat the image as logical pixels and re-scale to framebuffer
// pixels on a HiDPI display (DPR>1) — glyphs come out 2× too big.
// `m_fbDpr` is the DPR `syncSurfaceSize` used when telling
// libghostty the framebuffer size, so it matches what the renderer
// actually drew.
if (m_fbDpr > 0) owned.setDevicePixelRatio(m_fbDpr);
// Stash for the GUI-thread polling timer to pick up.
{
QMutexLocker lock(&m_pendingMutex);