Skip to content

feat(egfx): composite client surface commands into pixel buffers#1460

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

feat(egfx): composite client surface commands into pixel buffers#1460
Greg Lamberson (glamberson) wants to merge 1 commit into
Devolutions:masterfrom
lamco-admin:feat/egfx-client-compositor

Conversation

@glamberson

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

Copy link
Copy Markdown
Contributor

Summary

  • GraphicsPipelineClient decoded WireToSurface1 bitmaps but forwarded SolidFill, SurfaceToSurface, the bitmap cache, and MapSurfaceToOutput to no-op handler callbacks, so it never held the pixel state those commands operate on. Any server that uses them (grd, Windows) renders wrong.
  • Adds a surface compositor to ironrdp-egfx: persistent RGBA8888 per-surface buffers plus a bitmap cache, applies every surface command, maps surfaces to the output, and accumulates the changed output regions.
  • Regions are committed per EndFrame and drained via a new GraphicsPipelineClient::drain_output() -> Vec<OutputUpdate>.
  • Additive: existing GraphicsPipelineHandler callbacks are retained as notifications, so current consumers are unaffected.

Validation

  • cargo xtask check fmt/lints/tests/typos/locks all pass.
  • 8 compositor unit tests (solid fill, frame atomicity, cache round-trip, oversized-destination clipping, source-rect clamping, reset).

Notes

The client GraphicsPipelineClient decoded WireToSurface1 bitmaps and
forwarded every other surface command (SolidFill, SurfaceToSurface, the
bitmap cache, MapSurfaceToOutput) to no-op handler callbacks, so it never
maintained the pixel state those commands operate on. Against any server
that uses them (GNOME Remote Desktop, Windows) the rendered result was
wrong.

Add a surface compositor that keeps persistent RGBA8888 surfaces and a
bitmap cache, applies each command into them, maps surfaces onto the
graphics output, and accumulates the changed output regions per frame.
The regions are exposed through GraphicsPipelineClient::drain_output(),
committed on EndFrame so a partial frame is never observed. Reads and
writes are clipped to their buffers, so a malformed server rectangle
shrinks the update to empty rather than reading or writing out of range.

The existing handler callbacks are kept as secondary notifications, so
current consumers are unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant