Skip to content

feat(session): render the EGFX graphics pipeline output - #1461

Open
Greg Lamberson (glamberson) wants to merge 1 commit into
Devolutions:masterfrom
lamco-admin:feat/session-egfx-render
Open

feat(session): render the EGFX graphics pipeline output#1461
Greg Lamberson (glamberson) wants to merge 1 commit into
Devolutions:masterfrom
lamco-admin:feat/session-egfx-render

Conversation

@glamberson

@glamberson Greg Lamberson (glamberson) commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • The ironrdp-egfx compositor exposes changed output regions via drain_output(), but nothing consumed them, so an EGFX session decoded frames and dropped them.
  • Drains the compositor from ActiveStage::process: composites each completed-frame OutputUpdate into the DecodedImage and emits ActiveStageOutput::GraphicsUpdate, so every session consumer renders EGFX with no new code. No-op when the graphics DVC is not registered.
  • Adds a by-type mutable DVC accessor DrdynvcClient::get_dvc_mut, mirrored on the session (the x224 processor and ActiveStage), matching the existing get_dvc.
  • All regions drained in one pass are composited first by composite_graphics_updates, then surfaced as a single GraphicsUpdate covering their union. A consumer may redraw whatever region an update names, and ironrdp-client rebuilds the whole framebuffer for each one, so emitting per region would copy the desktop once per rectangle. A single RDPGFX_SOLIDFILL_PDU or RDPGFX_CACHE_TO_SURFACE_PDU can name up to u16::MAX of them.

Validation

  • cargo xtask check fmt/lints/tests/typos/locks all pass, including the dependency guard.
  • Four tests cover the coalescing: two disjoint deltas collapsing to the rectangle spanning both, 64 deltas yielding exactly one region, a single delta passing through unwidened, and an empty drain surfacing nothing. Checked against a reverted coalescing, where the first two fail.
  • The loop lives in composite_graphics_updates rather than inline in ActiveStage::process so it can be tested without standing up an x224 processor. It takes (ExclusiveRectangle, Vec<u8>) rather than OutputUpdate, since that type is #[non_exhaustive] and cannot be constructed from ironrdp-session; this keeps the change inside the crate instead of widening an already-merged API for testability.

Notes

@glamberson
Greg Lamberson (glamberson) force-pushed the feat/session-egfx-render branch 2 times, most recently from 4a19d44 to a9d9b55 Compare July 31, 2026 14:58
@github-actions github-actions Bot added dependencies Pull requests that update a dependency file scope/core Touches the core architectural tier A-extra size/XL Size: 800 or more lines of code labels Jul 31, 2026
@github-actions github-actions Bot added size/M Size: 150-399 lines of code and removed size/XL Size: 800 or more lines of code size/M Size: 150-399 lines of code labels Jul 31, 2026
@github-actions github-actions Bot added size/M Size: 150-399 lines of code and removed size/M Size: 150-399 lines of code labels Jul 31, 2026
@github-actions github-actions Bot added size/L Size: 400-799 lines of code and removed size/M Size: 150-399 lines of code labels Jul 31, 2026
@CBenoit Benoît Cortier (CBenoit) added risk/high Substantial core public API impact, or fail-closed triage; needs maintainer-level scrutiny ai-reviewed/1 One automated review completed maintainer-required Maintainer review or intervention is required labels Aug 3, 2026
@CBenoit

Copy link
Copy Markdown
Member

This high-risk, protocol-relevant EGFX/DVC integration is additive and feature-gated, with no valid findings anchorable to changed files; the protocol review identified valuable follow-up tests but no reportable defect, so it is ready for human review.

@github-actions github-actions Bot added size/L Size: 400-799 lines of code and removed size/L Size: 400-799 lines of code labels Aug 3, 2026
@CBenoit Benoît Cortier (CBenoit) removed rust dependencies Pull requests that update a dependency file labels Aug 4, 2026
@github-actions github-actions Bot added breaking-change Includes a breaking change, and requires special scrutiny at the boundaries scope/cross-cutting Spans multiple architectural boundaries scope/ffi Affects native or .NET bindings labels Aug 4, 2026
The client-side graphics pipeline (ironrdp-egfx GraphicsPipelineClient) keeps
a surface compositor and exposes the changed output regions via drain_output(),
but nothing consumed them: an EGFX session decoded frames and dropped them.

Drain the compositor from ActiveStage after processing a frame: composite each
completed-frame OutputUpdate into the DecodedImage and surface it as an
ActiveStageOutput::GraphicsUpdate, so every session consumer renders the
graphics pipeline without new code. The drain is a no-op when the graphics
pipeline DVC is not registered, so non-EGFX sessions are unaffected.

Reaching the pipeline mutably needs a by-type mutable DVC accessor, which the
typed-accessor set did not have (only by-type immutable and by-channel-id
mutable). Add DrdynvcClient::get_dvc_mut and mirror it on the session (the x224
processor and ActiveStage), matching the existing get_dvc.

The compositor's regions are RGBA8888 in exclusive-rectangle space; the session
converts to its inclusive-rectangle convention and reuses apply_rgba32
(previously gated behind the qoi feature) to write them into the RgbA32 image.
@github-actions github-actions Bot added kind/protocol Changes how we encode/decode or interpret RDP wire packets size/M Size: 150-399 lines of code and removed scope/ffi Affects native or .NET bindings size/L Size: 400-799 lines of code breaking-change Includes a breaking change, and requires special scrutiny at the boundaries labels Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-reviewed/1 One automated review completed kind/protocol Changes how we encode/decode or interpret RDP wire packets maintainer-required Maintainer review or intervention is required risk/high Substantial core public API impact, or fail-closed triage; needs maintainer-level scrutiny scope/core Touches the core architectural tier scope/cross-cutting Spans multiple architectural boundaries size/M Size: 150-399 lines of code

Development

Successfully merging this pull request may close these issues.

2 participants