Files
Jungfraujoch/viewer/RemoteDisplayMode.h
T
leonarski_fandClaude Fable 5 7b868fb9f5 viewer: raster window composition and remote-display repaint throttling
Over "ssh -X" the viewer was near unusable, and the July finding that every
repaint uploads the whole window (5.3 MiB at the default size) regardless of
how small the damage is turns out to have a single cause: the reciprocal-space
window constructed a QOpenGLWidget at startup, and one dormant QOpenGLWidget -
unmapped, in a window nobody ever opened - switches Qt's window composition
onto the OpenGL swapchain path. That path re-presents the entire window on
every flush (and is also the llvmpipe CPU burn seen on headless boxes). The
reciprocal-space window was a placeholder feature and is removed; with it gone
Qt flushes through the raster backing store, which sends only the damaged
region.

On top of that, interactions that repainted once per input event are held to
the hover cadence (15 Hz) on remote sessions only: panning accumulates its
pixel delta, wheel zoom its steps, a recolour burst its final value, live
playback keeps only the newest frame (the worker ack stays per-frame), and the
toolbar counter/slider readbacks coalesce the same way. Each throttle applies
inline with a single-shot tail, the same shape as the existing hover limiter,
so the view always lands exactly where the gesture put it. Local sessions are
unchanged - every event still applies inline.

Remote sessions are detected once at startup (xcb platform and a DISPLAY with
a host part, i.e. "localhost:10.0" from SSH forwarding or "host:0"); the
JFJOCH_VIEWER_REMOTE environment variable and a View-menu toggle override the
detection in either direction.

Measured through a byte-counting X relay against Xvfb with MIT-SHM disabled
(client-to-server bytes are what the SSH link carries), same scripted
interaction sequence, 1200x1100 window, KiB:

                     rc169    removal only   removal+throttles
  hover, 50 motions  82088    2040           2040
  pan, 50 motions    290046   12087          4778
  wheel zoom x10     71143    12603          7649
  ctrl-wheel x6      65672    7194           4797
  frame step x10     284572   21454          21454

Removing the reciprocal-space window from the source measured byte-identical
to only deferring its GL view to first show, confirming the cost is the live
QOpenGLWidget, not the code being compiled in. The image panel renders
pixel-identically (AE=0) to rc169 after identical zoom+pan gestures, with the
throttles on and off.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WbjnQhutnboy4qbxwmgDAX
2026-09-12 22:38:45 +02:00

17 lines
867 B
C++

// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
// Whether the viewer talks to its display server across a network link (ssh -X and the like).
// On such a link every repaint is shipped as pixels, so interactions that repaint per input
// event are throttled to the hover cadence instead. Detected once from the session; the
// JFJOCH_VIEWER_REMOTE environment variable (0/1) and the View-menu toggle override it.
// Only call after QApplication exists - detection reads the platform name.
bool RemoteDisplayMode();
void SetRemoteDisplayMode(bool active);
// The cadence remote-throttled updates run at, chosen to match JFJochImage's hover rate limit:
// far below the input event rate, above what the eye follows.
constexpr int kRemoteRepaintIntervalMs = 66;