perf(graphics): optionally decode large progressive regions in parallel - #2036
Willie Abrams (willie) wants to merge 8 commits into
Conversation
RLGR decoding read bits through bitvec's BitSlice, which made it about three quarters of a progressive tile's decode time. A small MSB-first reader over the tile's bytes, with leading_zeros/leading_ones for runs, decodes identically (compared against the old decoder on random tiles in both RLGR modes) and takes a full-screen 1080p update from 35.8 to 29.2 ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A region's tile blocks each touch only their own tile state and sub-band-diffing reference, so a region of at least 8 distinct, in-bounds tiles is decoded on rayon's pool: each tile's state and reference are taken out, decoded, and put back, and results come back in block order with the first error in block order. Smaller regions (hover changes, cursor-sized updates) and regions that repeat a tile decode in order as before. After an error the parallel path still decodes the region's other tiles. rayon is a default feature of ironrdp-graphics. A full-screen 1080p update drops from 29.2 to 10.0 ms, and full-screen 3D reaches a client at 60 frames a second instead of 27. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Check unaligned reads, reads across the 64-bit window, refused reads past the end, and zero and one runs that reach the end of the data. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Before the tile decode was split out, a difference tile without a sub-band reference failed before its tile state was created. Both region decode paths now drop a tile state they created for such a tile, so the surface matches what it was before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A 12-tile region, first as original then as a mix of difference and original tiles, must produce the same pixels, tile states and sub-band references whether decoded as one region (the parallel path with the rayon feature) or one tile at a time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ironrdp-graphics is a core-tier crate, where ARCHITECTURE.md allows no non-essential dependency. Without the feature, regions decode one tile at a time as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Measurements: release builds on an Apple M4 Pro (10 performance + 4 efficiency cores) with the
Verification:
Open question: would you accept rayon as an opt-in feature of Note LLM-assisted content (no human feedback). |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
CI does not execute the new feature-gated parallel path or its documented mixed-result behavior.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Optimizes RemoteFX Progressive decoding through faster bit reads and optional tile-level parallelism.
Changes:
- Replaces bit-slice decoding with a 64-bit bit reader.
- Adds optional Rayon-based parallel tile decoding.
- Adds decoder equivalence and edge-case tests.
| File | Description |
|---|---|
crates/ironrdp-graphics/src/rlgr.rs |
Optimizes RLGR bit reading. |
crates/ironrdp-graphics/src/progressive.rs |
Adds parallel region decoding and tests. |
crates/ironrdp-graphics/Cargo.toml |
Adds the optional Rayon feature. |
Cargo.lock |
Records the Rayon dependency. |
|
This pull request may overlap with #2010. Both PRs modify RFX Progressive decoding in crates/ironrdp-graphics/src/progressive.rs: this PR restructures region tile-block decoding for optional parallelism, while This notice is advisory only. Automated review continues as usual, and how these pull requests relate is for maintainers and authors to decide. Note LLM-assisted content (no human feedback). |
Decode a 12-tile region in which tile 3 lacks a reference and tile 7 has a truncated payload. Both paths return tile 3's error. The sequential path stops there; the parallel path still decodes the other tiles, advancing their state and references. The test asserts the tile states and references each path leaves behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parallel tile decoding path only builds with the rayon feature, which no workspace crate enables, so the workspace test run never executed it. Add a feature-enabled run of the crate's unit tests to `check tests`, next to the existing per-crate feature runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

With the new opt-in
rayonfeature, a Progressive region of 8 or more distinct, in-bounds tiles decodes its tiles on rayon's global pool. Each tile block touches only its ownTileStateand sub-band-diffing reference, so these are taken out, decoded in parallel, and put back, and the decoded tiles come back in block order. Smaller regions, regions that name a tile twice, and builds without the feature decode one tile at a time as before.A full-screen 1920x1080 update takes 10.0 ms to decode instead of 29.2 ms with the new RLGR reader (mean, release build, Apple M4 Pro).
The feature is off by default because
ironrdp-graphicsis a core-tier crate, and ARCHITECTURE.md allows no non-essential dependency there.cargo xtask check testsalso runs the crate's tests with the feature, so CI covers the parallel path.On an error, both paths return the first failing block's error, but they leave different state. The sequential path stops at that block. The parallel path has already decoded the region's other tiles, so their state and references have advanced.
This builds on #2038 and will be rebased once that merges; until then, its diff also contains the reader commits.