qt: schedule a paintEvent when the placeholder → real-frame swap happens

drainVulkan set m_subsurfaceHasFrame=true after attaching a
matching-size dmabuf, but didn't schedule a repaint. The parent
backing store still held the OPAQUE bg-color placeholder painted
in the previous paintEvent; the wl_subsurface is stacked BELOW
the parent surface, so the parent's opaque pixels obscured the
subsurface even though the buffer was attached and committed.
Until some unrelated event triggered a repaint (mouse move,
chrome update), the user saw the placeholder persist with the
real terminal content sitting invisibly below — visible as a
"tab opens, sits at bg color for a moment, suddenly snaps to
real content" jank.

Call update() on the false → true transition so Qt re-runs
paintEvent (which now sees m_subsurfaceHasFrame=true and fills
the terminal area transparent), letting the subsurface show
through.

exchange(true) with acq_rel ordering also serves as the single-
shot guard — subsequent drains on the steady state (atomic
already true) don't re-trigger update().

Co-Authored-By: claude-flow <ruv@ruv.net>
pull/12846/head
Nathan 2026-05-26 16:09:05 -05:00
parent e13189217b
commit 24158f3439
1 changed files with 16 additions and 1 deletions

View File

@ -2174,7 +2174,22 @@ void GhosttySurface::drainVulkan() {
// show through. Release-ordering: paint may be on a different
// thread (Qt event loop is single-threaded but the atomic
// contract is cheap to honor).
m_subsurfaceHasFrame.store(true, std::memory_order_release);
const bool placeholder_to_real =
!m_subsurfaceHasFrame.exchange(true, std::memory_order_acq_rel);
if (placeholder_to_real) {
// First real frame after the placeholder paint. The
// placeholder painted an OPAQUE bg color over the terminal
// area; the subsurface is stacked BELOW the parent surface,
// so the parent's opaque pixels obscure the subsurface.
// Without forcing a fresh paintEvent here, the placeholder
// visibly persists in the parent backing store until some
// unrelated event triggers a repaint — that's the "tab
// opens, sits at bg color, suddenly snaps to real content"
// jank. update() schedules a paintEvent which (now that
// m_subsurfaceHasFrame is true) will fill the terminal
// area transparent and let the subsurface show through.
update();
}
// Close OUR dup of the dmabuf fd now that presentDmabuf has
// handed it to create_immed (which SCM_RIGHTS-dup'd it again
// for the compositor's view, or did a cache hit and didn't