Root cause of #15848 (and the long-standing macOS #6296 / Linux #3343
class): raw native texture pointers are shared across the platform
thread, the engine raster thread and the video thread, with teardown
ordered by a 100 ms sleep - or, when moving a tab to a new window, by
nothing at all. A lost race frees the texture while it is still in use:
the raster thread parks on a destroyed lock (frozen/black view, a
never-presented 'transparent' hole, every later session black) and the
video thread hangs while holding session locks (app half-dead until
restart, still reported as Responding).
- unregister textures with compare-and-clear (new session_unregister_*
FFI): a late clear can no longer wipe a new window's registration
(#8016) and Rust never keeps pushing into a freed texture; the 100 ms
sleeps are gone (the plugins now drain in-flight pushes and defer
object deletion until the raster thread is done)
- guard the async texture create path against destroy racing it (#13596)
- per-display locks: the per-frame plugin call no longer holds
session-level locks, so a stalled plugin or driver call cannot freeze
every window's UI thread
- adopt the frame size after 30 consecutive mismatches instead of
dropping frames forever (silent black screen on a live connection)
- watchdog: frames pushed but never consumed by the engine fall the
session back to software rendering live, record texture-render-health,
and flip the effective default off; toggling the option clears the
record and re-arms validation
- Dart raster-stall monitor records a hung raster thread for the next
launch (rendering cannot be rescued in-process in that state)
- startup probe: render one frame through a 1x1 texture in the main
window each launch; failure disables texture rendering before the
first session goes black, a pass self-heals a stale failure record
Platform defaults are unchanged (macOS off, Win10+ on, Linux on).
Requires flutter_texture_rgba_renderer ad4c37e and
flutter_gpu_texture_renderer 767bb9f (pinned in pubspec).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(web): zero-readback WebCodecs video path
Decoded VideoFrames from js/src/webcodecs.js are handed to Flutter via
window.onVideoFrame and imported GPU-side with createImageFromTextureSource;
any failure unregisters the hook so the JS side falls back to RGBA readback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(web): load bundled terminal font when Google CDNs are unreachable
In air-gapped deployments GoogleFonts.robotoMono() cannot download the
terminal font; when index.html signals offline mode, load the copy bundled
with the web app under the family name google_fonts registers.
Part of the fix for rustdesk/rustdesk-server-pro#996.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci: bump windows arm64 to Flutter 3.44.8, add web build patch script
apply_flutter_3.44_web_patches.sh prepares a 3.44.x web build on top of the
shared source patches: qr_code_scanner's web impl needs dart:ui_web for the
removed platformViewRegistry, and flutter/web/fonts is refreshed to the font
paths the 3.44 engine requests. The disabled build-rustdesk-web job runs it
automatically once FLUTTER_VERSION moves to 3.44.x, and version-guarded
'Patch flutter' steps no longer fail when the guard does not match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(web): prevent stale WebCodecs frames across sessions
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(web): harden WebCodecs reconnect and Flutter 3.44 patches
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(ci): harden Flutter 3.44 patch input validation
Validate required files before checking patch state,
parameterize the theme-range validator, and prevent
missing inputs from satisfying NO_MATCHES checks.
Signed-off-by: fufesou <linlong1266@gmail.com>
* Remove unused code
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(web): retry font loading and dispose stale decoded images
Signed-off-by: fufesou <linlong1266@gmail.com>
* remove unused code
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(web): Bad state: RenderBox was not laid out
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
* fix(linux): load librustdesk.so relative to the executable
The runner and the Dart FFI init loaded the core library by bare name,
relying on the runner's $ORIGIN/lib RPATH. Repackaged installs (CachyOS
repo, AUR) can lose that RPATH, making the app fail to start with
"Failed to load librustdesk.so" unless users add the lib directory to
ld.so.conf. Resolve lib/librustdesk.so next to the executable first,
then fall back to the loader search path.
https://github.com/rustdesk/rustdesk/discussions/14407
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(linux): harden bundled librustdesk.so resolution
Address review: bail out when readlink() may have truncated the
executable path, and widen the Dart try block so any failure probing
the bundled library falls back to the loader search path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Multiple dylib instances will cause some global instances to be invalid.
eg. lazy_static objects in rust side, will be created more than once.
Signed-off-by: fufesou <linlong1266@gmail.com>