- a probe or raster-stall failure record now also downgrades sessions
that are already running: main_set_local_option broadcasts the
fallback for failed-* health writes, which also closes the hole where
the watchdog's idempotence guard no-oped after the probe had already
written the record
- probe success requires a frame timing newer than the first push:
'consumed' advances inside the plugin callback before the GL/Metal
upload, so a raster thread hanging in the driver no longer counts as
a pass (and cannot clear a previous failure)
- watchdog failures are tagged with the failing backend
(failed-watchdog-rgba/gpu); the rgba-only probe clears only the rgba
class, so a working pixel-buffer path can no longer re-enable a
broken D3D shared-handle path every launch
- the watchdog pauses while the session's window is hidden (new
session_set_render_visible FFI wired to the window minimize/restore
events): a display registered in a minimized window no longer records
a false global failure; observation now counts pushes within the
window rather than since registration
- probe failure verdicts additionally require a resumed lifecycle,
matching the raster-stall monitor
- linux plugin: deferred-unref grace lengthened to 10s (no raster-side
completion barrier exists; documented as heuristic), ref bumped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
flutter_texture_rgba_renderer 7932bf9: linux double-free/terminate-UAF
fixes, exported GetConsumed (was invisible to dlsym under hidden
visibility - the watchdog was silently disabled on Linux), C++14
shared_timed_mutex; macos autoreleasepool + failed-registration guard.
flutter_gpu_texture_renderer 208619e: rendering_ no longer sticks true
before the first populate; honest GetConsumed semantics (descriptor
fetches; EGL bind failure still advances it) - noted at the gpu
watchdog call site.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
The give-up log added in the white-window follow-ups declared a local
named message inside MessageHandler, shadowing its UINT message
parameter. MSVC C4457 plus /WX failed both Windows nightly jobs.
Point the lock at rustdesk_desktop_multi_window#35 which renames it.
https://github.com/rustdesk/rustdesk/actions/runs/30512756157
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(flutter/windows): heal the white window left by a resize around the first frame
If the window is resized between the creation of the Flutter surface and
the present of the first frame - which is what the PowerToys FancyZones
option "Move newly created windows to their last known zone" does - the
embedder's resize synchronization enters kResizeStarted and from then on
only presents frames that match the new size. A frame already generated
for the old size is rejected, nothing schedules a matching one, and the
window stays white until a real resize re-enters OnWindowSizeChanged,
which resets the resize target and resends the window metrics. Sciter is
unaffected: it repaints synchronously on WM_PAINT and has no such
handshake. Upstream has no fix (flutter/flutter#159630, open at P3).
Recover with a timer armed at creation and re-armed on WM_SHOWWINDOW
(covers windows created hidden and shown much later, e.g. the connection
manager): until the first frame arrives, kick the engine - first with
the cheap ForceRedraw(), which only helps when no resize is pending (it
is gated on resize_status_ == kDone), then by nudging the Flutter child
window by 1px and back, which re-enters OnWindowSizeChanged and heals
the wedge the same way minimize/restore does. Because the first-frame
callback fires on frame generation even when the present is rejected, a
resize observed before the first frame forces one final child refresh -
in practice nearly every window sees a pre-first-frame WM_SIZE, so this
acts as a cheap unconditional guarantee. Giving up after 5s is logged.
The remote session windows get the same fix in
rustdesk_desktop_multi_window.
https://github.com/rustdesk/rustdesk/issues/6756
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(flutter): bump desktop_multi_window for the white-window fix
Picks up rustdesk-org/rustdesk_desktop_multi_window#33 (340ca43), the
session-window side of the FancyZones white-window workaround. Only the
resolved-ref of this one dependency is moved; nothing else is upgraded.
https://github.com/rustdesk/rustdesk/issues/6756
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(flutter/windows): drop a dead guard and log where users can see it
Two follow-ups on the force-redraw timer.
The resized_before_first_frame_ guard never discriminated. CreateWindow()
sends a WM_SIZE before it returns, and WM_NCCREATE has already installed the
window pointer by then, so the flag was set during construction - before
OnCreate() even arms the timer - and was therefore always true when the first
frame arrived. Drop the flag and do the final child refresh unconditionally,
which is what the code already did, and say so instead of implying there is an
exceptional case.
The give-up message went to std::cerr, which lands nowhere on the machines
that hit this: main.cpp only attaches a console when the process is started
from one or runs under a debugger. Use OutputDebugString so it is actually
readable with DebugView in the field.
Also note in the comment that the "callback fires on frame generation" premise
is not load-bearing - if it only fired on a successful present, the timer would
simply keep nudging - so the redundancy is not mistaken for duplication and
removed later.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(flutter): bump desktop_multi_window to pick up the follow-ups
Moves the pin from the #33 merge (340ca43) to current master (f8c4fce),
which adds #34: the dead resized_before_first_frame_ guard is gone and the
give-up message goes to OutputDebugString instead of a stderr nobody sees.
Keeps the sub-window fix in step with the runner fix in this branch; without
it the two would ship the same logic in two different states.
Edited by hand, not via pub upgrade - that re-resolves unrelated packages.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The lock still pinned 7d9a674, the commit rustdesk-org/window_manager#8
reverted. Move it to current main (cf4aef0), which carries the reworked
guard for methods called after the toplevel window is destroyed.
Edited by hand rather than via pub upgrade: upgrading re-resolved 17
packages, downgrading some and pulling flutter_test and its leak_tracker
tree in as new entries, none of which belongs in this change.
https://github.com/rustdesk/rustdesk/issues/15703
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix qsv memory leak by updating ffmpeg
* Memory leaks occur when destroying FFmpeg QSV VRAM encoders. This issue is resolved with FFmpeg version 7.
* FFmpeg requires ffnvcodec version 12.1.14.0 or higher, and an NVIDIA driver version greater than 530. For more details, https://github.com/FFmpeg/nv-codec-headers/tree/n12.1.14.0.
* The code of NVIDIA VRAM encoder is not changed, still use Video Codec SDK version 11, which is unaffected by FFmpeg. Drivers newer than 470 can support this, but we may consider an update later, as the support check by sdk code may not be accurate for FFmpeg RAM encoders.
* The issue is related to FFmpeg, not libmfx. FFmpeg version 7 recommends using libvpl, but vcpkg currently lacks ports for libvpl. We can add these in the future.
* D3D11 Texture Rendering: The "Shared GPU Memory" in the task manager continue increasing when using D3D11 texture render, which can exceed the GPU memory limit (e.g., reaching up to 100GB). I don't know what it is and will try to find it out.
* Roughly tests on Windows, Linux, macOS, and Android for quick fix. Further testing will be performed, and I will share the results in this pr.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* update flutter_gpu_texture_render, fix shared gpu memory leak while
rendering
Signed-off-by: 21pages <sunboeasy@gmail.com>
---------
Signed-off-by: 21pages <sunboeasy@gmail.com>