Commit Graph
38 Commits
Author SHA1 Message Date
RustDeskandClaude Opus 5.5 9997b7a3b8 test: remove tests that do not pin user-visible behavior (#16539)
* test: remove tests that do not pin user-visible behavior

Apply the AGENTS.md test rules to the existing Rust and Flutter suites.
A test is kept when it is the only coverage of user- or API-visible
behavior, the regression test of a reported or fixed bug, a security
boundary (one test per rejection class), or a check against an external
reference. Tests that assert private state or the order of internal
steps, pin review-round corner cases, or repeat what a kept test already
covers are removed.

Rust: 679 -> 298 tests. Dart: 118 -> 45 tests.

Test-only helpers left without callers go with them
(applyLastOnlineStateForTesting, terminalKeyboardRowWidth,
debugBufferedInputCount, tokio's test-util dev feature), and cfg gates
and visibility that existed only for the deleted tests are narrowed.
Runtime behavior is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WS1HTjp6UQuG43KEcQPq1R

* test: keep tests that pin security and user-visible behavior

Restore six tests that review showed are the only coverage of their
behavior:

- update metadata rejects an artifact file name with path components;
- ICE candidates from another session are dropped;
- KCP delivers every multi-segment frame queued before a close;
- set_files rejects an empty name in a multi-file transfer;
- a lopsided elongated cursor keeps its centre hotspot (#16242);
- toggling Show hidden during a pending same-path read issues a new read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WS1HTjp6UQuG43KEcQPq1R

* test: keep offline update and key-exchange downgrade rejections

Restore three tests that are the only coverage of their rejection class:

- offline update metadata rejects a signed artifact with an http or
  credential-bearing URL;
- offline verification rejects a renamed local file and a version that
  does not match the release;
- a key-exchange pick lowered in transit leaves both sides unable to
  decrypt, so a v0 fallback after a failed v1 decrypt cannot pass
  unnoticed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WS1HTjp6UQuG43KEcQPq1R

* test: keep the decomposed-grapheme and reconnect-cancel tests

Each catches a plausible wrong change that passes every kept test:
mapping the first scalar under a locked Ctrl turns é into \x05,
and a reconnect that does not fail pending reads leaves them hanging
until the 30 s timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WS1HTjp6UQuG43KEcQPq1R

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:45:22 +08:00
58ff78a823 Hdr tonemap (#16033)
* scrap: tone-map HDR desktops to SDR in the Windows capturer

With HDR enabled, Windows composes the desktop as linear scRGB in
R16G16B16A16_FLOAT and places SDR white at the user's "SDR content
brightness" (DISPLAYCONFIG_SDR_WHITE_LEVEL / 1000, e.g. 2.5 for 200
nits) rather than at 1.0. The legacy IDXGIOutput1::DuplicateOutput we
used always converts that surface to BGRA8, and it does so by clipping,
so everything above ~40% linear brightness lands on white. That is the
washed-out / overexposed / high-contrast picture reported for HDR hosts
in #5368, #9951, #12707 and discussion #7652.

Ask for the desktop with IDXGIOutput5::DuplicateOutput1 and the format
list [R16G16B16A16_FLOAT, B8G8R8A8_UNORM]. An SDR desktop still yields
BGRA8 and takes the unchanged path. A float frame is converted on the
GPU by a small pixel shader: divide by the SDR white level, clamp, apply
the sRGB transfer. SDR content round-trips exactly, HDR highlights clip
at white, the same result the local user sees. The white level is read
per output through DisplayConfigGetDeviceInfo and refreshed once a
second, so dragging the Windows slider tracks remotely. The converted
BGRA8 texture feeds both the staging-copy (CPU) path and the vram
(hwcodec texture) path; rotation is unchanged. Toggling HDR mid-session
invalidates the duplication as before, and the recreated capturer
re-detects the format.

The shaders are compiled at runtime from a dynamically loaded
d3dcompiler_47.dll so no new import is added to the binary. If the DLL,
the compile or any D3D object creation fails, a process-wide flag makes
later capturers fall back to the legacy DuplicateOutput, i.e. today's
behaviour.

This deliberately stops at SDR on the controlled side, with no option
and no protocol change, which is how OBS, Sunshine (client without HDR)
and macOS screen capture handle it. Real HDR pass-through would need
10-bit capture, Main10/AV1-10 encoders in the hwcodec fork, colour
metadata on the wire and, decisively, an HDR output path on the
controller: Flutter's desktop external textures are BGRA8888/RGBA8888
only on every platform, so nothing would be visible. When that changes
it should follow the Sunshine/Moonlight pattern: an hdr capability bit
advertised by the controller behind an explicit user toggle, negotiated
like i444.

Type-checked against x86_64-pc-windows-msvc (with and without the vram
feature); not yet run on an HDR machine, which needs Windows 10 1703+
with HDR on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLb1dNdhFqUQExJPANjo1F
(cherry picked from commit ca3c2f8ac7d1549a40855411b0539a69c82d7223)

* scrap: stay on DXGI when the HDR conversion fails, load the compiler once

Review follow-up:

- A tone-map failure surfaced as a capture error, and the capture loop
  answers any DXGI error by switching the capturer to GDI for the rest
  of its life. The capturer now drops the tone-map, re-creates the
  duplication with the legacy DuplicateOutput (DXGI's clipped BGRA8,
  the pre-HDR behaviour) and returns WouldBlock, so the session stays
  on DXGI and simply fetches the next frame.

- Only failures that cannot succeed anywhere in the process (no
  d3dcompiler_47.dll, shaders that do not compile) set the global
  UNAVAILABLE flag; D3D object creation failures stay with the capturer
  that hit them, so another adapter or a recreated capturer tries again.

- D3DCompile is resolved once through a OnceLock instead of a
  LoadLibrary per capturer that was never freed.

- The module doc now states what this pass is: normalization of an HDR
  desktop to SDR, with everything above SDR white clipping, not a tone
  map, and why a roll-off is deliberately not applied. The earlier
  claim that clipping matches what the local user sees was wrong for
  HDR content on an HDR display.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLb1dNdhFqUQExJPANjo1F

* scrap: only apply the SDR white level to outputs DXGI reports as HDR

Review follow-up:

- An FP16 desktop is not necessarily HDR. Since Windows 11 22H2 an
  Advanced Color (WCG) SDR display is composed in FP16 scRGB too, and
  there 1.0 is the display's reference white, not 80 nits, so the
  SDRWhiteLevel scaling does not apply (Microsoft: "Reference white
  applies only to HDR displays"). Query IDXGIOutput6::GetDesc1 and treat
  the output as HDR only for DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020,
  the documented Win32 check; a non-HDR FP16 frame now gets just the
  scRGB -> sRGB transfer. Without IDXGIOutput6 (before Windows 10 1803)
  FP16 can only mean HDR.

- The SDR white level is now Option: a failed query or a reported 0 is
  "unknown" on both the initial and the refresh path, an HDR output with
  an unknown level logs a warning and keeps the 80-nit assumption until
  the periodic re-query succeeds. DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL
  needs Windows 10 1709, not 1703 as an earlier message said.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLb1dNdhFqUQExJPANjo1F

* scrap: re-read the Advanced Color state while capturing, gate FP16 on IDXGIOutput6

Review follow-up:

- The HDR/WCG decision was taken once when the conversion was created.
  HDR can be switched on or off, and a WCG desktop can turn into an HDR
  one, without the duplication being invalidated, so the choice between
  "divide by the SDR white level" and "no scaling" could go stale. The
  once-a-second refresh now re-reads it: it keeps an IDXGIFactory1,
  and when IsCurrent reports FALSE it creates a fresh factory and
  re-finds the output by GDI name, since a stale factory's outputs keep
  stale descriptions (this is the procedure the GetDesc1 docs require).
  On a change it switches modes, re-reads the white level and updates
  the shader constant; an unreadable level keeps the last known one.

- Float frames are only requested when IDXGIOutput6 exists, as
  Microsoft's duplication sample does. That interface is also what tells
  HDR from WCG, so there is no longer a state where FP16 is requested
  without being able to interpret it. IDXGIOutput6 dates from Windows 10
  1703, not 1803 as the previous commit said; 1803 added IDXGIFactory6.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLb1dNdhFqUQExJPANjo1F

* scrap: replace the DXGI factory and output together when re-reading HDR state

Review follow-up: when the fresh factory did not find the output by name,
the refresh kept the new, current factory next to the old output, and
because IsCurrent then reported TRUE it never enumerated again, so the
stale output could stay forever. enumerate_output6 now returns both or
neither, and the refresh only replaces the pair together; a null factory
forces another enumeration on the next refresh while the old output is
still read in the meantime. The constructor gets the same guarantee for
free, since a failed lookup leaves the factory null there too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLb1dNdhFqUQExJPANjo1F

* scrap: keep enumerate_output6's both-or-neither promise when IDXGIOutput6 is missing

Review nit: a matched output whose IDXGIOutput6 query fails returned the
fresh factory next to a null output, which let the constructor pair a
current factory with the capturer's fallback output. Return neither in
that case so the next refresh enumerates again.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLb1dNdhFqUQExJPANjo1F

* scrap: log DuplicateOutput1 failures before fallback

Signed-off-by: 21pages <sunboeasy@gmail.com>

* scrap: avoid null duplication after HDR fallback failure

Signed-off-by: 21pages <sunboeasy@gmail.com>

* scrap: load the D3D compiler securely from System32

Signed-off-by: 21pages <sunboeasy@gmail.com>

* scrap: release the frame through the state machine when abandoning the tone-map

master's FrameState machine is left at Acquired by the raw ReleaseFrame(),
so the next release_frame() hits DXGI_ERROR_INVALID_CALL on the fresh
duplication and the capture loop falls back to GDI -- the outcome the
fallback exists to avoid.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
2026-09-23 18:40:49 +08:00
Joss Gray f9c2f16857 fix: recover DXGI capture after access loss (#16024)
* fix: recover DXGI capture after access loss

* fix: track DXGI frame ownership

* fix: only recover DXGI access loss

* fix: stabilize DXGI recovery after mode switches

* fix: preserve DXGI recovery budget

* refactor: model DXGI frame lifecycle as enum

* docs: clarify DXGI frame cleanup order

* fix: scope DXGI frame grace to access loss recovery

* fix: preserve DXGI recovery across display changes

* chore: log DXGI recovery attempts at debug level
2026-09-16 13:18:44 +08:00
fufesou 0797ebb695 Refact/privacy mode 1 multi monitors (#15321)
* refact: privacy mdoe 1, multi-monitors

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix: harden privacy mode overlay & capture cleanup

Signed-off-by: fufesou <linlong1266@gmail.com>

* Fix privacy mode edge cases after multi-monitor overlay changes

Signed-off-by: fufesou <linlong1266@gmail.com>

* Add missing changes

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-18 21:27:44 +08:00
RustDesk 6665242edf Revert "refact: privacy mdoe 1, multi-monitors (#15318)" (#15320)
This reverts commit 3cdf1cce54.
2026-06-17 21:46:40 +08:00
fufesou 3cdf1cce54 refact: privacy mdoe 1, multi-monitors (#15318)
* refact: privacy mdoe 1, multi-monitors

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix: harden privacy mode overlay & capture cleanup

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-17 21:43:57 +08:00
a903f710ea Eliminate build warnings from the Scrap crate (#13383)
* Updated build.rs to tell RustC that dxgi, quartz and x11 are expected configurations.
Added lifetime annotations to various methods in common/aom.rs and common/vpxcodec.rs.
Updated common/vpx.rs to allow unused_imports in the generated bindings.
Updated dxgi/mag.rs to allow non_snake_case identifiers like "dwFilterMode".

* Added lifetime annotations to methods in common/hwcodec.rs and common/vram.rs.

* Switched syntax for the rustc-check-cfg directive emitted by build.rs in the scrap crate to use syntax compatible with Rust toolchain version 1.75. The double-colon syntax requires 1.77 or newer, but the older single-colon syntax works fine on newer versions for this directive.

* Update libs/scrap/build.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Revert apparently-erroneous AI suggestion. It's usually pretty good, but not always right it seems. :-)

This reverts commit bf862b13f6.

* Removed redundant configuration directives from libs/scrap/build.rs.

---------

Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-04 10:19:13 +08:00
f0f999dc27 view camera (#11040)
* view camera

Signed-off-by: 21pages <sunboeasy@gmail.com>

* `No cameras` prompt if no cameras available,  `peerGetSessionsCount` use
connType as parameter

Signed-off-by: 21pages <sunboeasy@gmail.com>

* fix, use video_service_name rather than display_idx as key in qos,etc

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: Adwin White <adwinw01@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2025-03-10 21:06:53 +08:00
zuiyu 561bc18f49 Fix unused import with dxgiformat (#11032) 2025-03-06 09:49:04 +08:00
fufesou f08cb0412d fix: windows, dll, pre-loading attack (#10608)
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-01-26 19:39:38 +08:00
21pages 740c5358ab rotate ID3D11Texture2D (#9772)
* Rotate ID3D11Texture2D after duplication with d3d11 video processor.
* If display is not rotated, nothing will be created; If the rotation
  fails, it will use the old fallback logic

TODO:
* If changing from Landscape to Landscape(flipped) during capture, the resolution is
  not changed, video service fallback to gdi directly.

Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-11-08 12:12:10 +08:00
fufesou 8c8a643cce fix: workaround physical display rotation (#9696)
Signed-off-by: fufesou <linlong1266@gmail.com>
2024-10-19 10:57:42 +08:00
21pages 98df2b111e hwcodec uses one repository (#7701)
* update hwcodec, gpucodec repo is merged to hwcodec

Signed-off-by: 21pages <pages21@163.com>

* rename gpucodec.rs to vram.rs

Signed-off-by: 21pages <pages21@163.com>

* rename all gpucodec to vram, because vram is a feature of hwcodec

Signed-off-by: 21pages <pages21@163.com>

* use one check process and one config file

* set check encode image size to 720p

Signed-off-by: 21pages <pages21@163.com>

---------

Signed-off-by: 21pages <pages21@163.com>
2024-04-12 17:26:24 +08:00
21pages 89150317e1 add zero copy mode hareware codec for windows (#6778)
Signed-off-by: 21pages <pages21@163.com>
2024-01-02 16:58:10 +08:00
fufesou 3e8c5d3b79 trivial changes
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-11-20 17:42:34 +08:00
fufesou 2aaca0c54a Remove get_error() in windows.rs
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-11-20 17:38:53 +08:00
fufesou c6d587f0c7 Refact, use std::io::Error::from_raw_os_error() to format message
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-11-20 17:22:14 +08:00
fufesou c85682de8d Refact, replace GetLastError() by std::io::Error::last_os_error()
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-11-20 17:15:15 +08:00
21pages f05f86dc80 444
Signed-off-by: 21pages <pages21@163.com>
2023-10-30 18:46:56 +08:00
21pages aa740f4263 remove many unwrap and enum_value_or_default
Signed-off-by: 21pages <pages21@163.com>
2023-07-23 20:00:58 +08:00
fufesou 37d21d8db0 remove unused logic
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-03-06 17:31:38 +08:00
fufesou c751ebee4e fix build
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-03-06 17:31:38 +08:00
fufesou 507472e87e show one display when privacy mode is on
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-03-06 17:31:37 +08:00
fufesou c0d367f7b1 fix some incorrect capture magnifier logic
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-03-03 21:04:52 +08:00
21pages 176847c51e fix warning
Signed-off-by: 21pages <pages21@163.com>
2023-01-29 14:28:10 +08:00
Josh Soref 3949e3162c spelling: rotation
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-01-09 12:59:08 -05:00
rustdesk 0d0957cea5 remove u128 compare 2022-12-26 17:44:29 +08:00
KG7x 71103886e6 Fix typo 2022-12-25 20:21:13 +03:00
fufesou aae6e2b16b linux_wayland_support: init merge, windows build
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-07-20 09:16:13 -07:00
21pages 847c4acb07 Merge branch 'hwcodec' into master 2022-06-14 13:08:39 +08:00
fufesou 62cb9eb51e privacy_mode_win_magnifier: more check on privacy mode
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-05-31 15:54:21 +08:00
fufesou 18ba55056f privacy_mode_win_magnifier: fix crash when resolution changed
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-05-30 18:16:04 +08:00
fufesou c269d1c831 privacy_mode: win10 magnifier
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-05-30 12:08:28 +08:00
rustdesk 4d5d0a4c62 improve video, ignore same image 2022-04-24 02:50:28 +08:00
open-trade a30aaebc72 fix clipboard crash and https://github.com/rustdesk/rustdesk/issues/302 2021-12-23 17:44:44 +08:00
rustdesk 49dff161dd enable dxgi https://github.com/rustdesk/rustdesk/issues/79, may fix https://github.com/rustdesk/rustdesk/issues/169 2021-07-31 03:00:07 +08:00
rustdesk f760e56f79 better support for win7 2021-05-17 20:46:02 +08:00
rustdesk d1013487e2 source code 2021-03-29 15:59:14 +08:00