Skip to content

Add opt-in portal resize for fractional Wayland scaling - #42

Open
espentveit wants to merge 1 commit into
omarroth:mainfrom
espentveit:main
Open

Add opt-in portal resize for fractional Wayland scaling#42
espentveit wants to merge 1 commit into
omarroth:mainfrom
espentveit:main

Conversation

@espentveit

@espentveit espentveit commented Sep 5, 2026

Copy link
Copy Markdown

Summary

This fixes cropped screen mirroring on fractionally scaled Wayland
outputs.

The ScreenCast portal reports the output's logical size, while PipeWire
delivers a physical-size buffer. For example, a 2560x1600 panel at 166%
scale is reported as 1536x960, but the stream carries 3072x1920 frames.
The pipeline pins the compositor output to 1536x960, and the compositor
places its input at 0,0 without scaling it. The result is the top-left
1536x960 portion of the frame rather than the full desktop.

The new -portal-resize option adds a caps filter after vapostproc,
fitting the frame to the portal-reported canvas on the GPU before it
reaches the compositor.

The portal does not provide the physical buffer size, so the target caps
are requested unconditionally when the option is enabled. This is safe
when the dimensions already match because vapostproc negotiates
passthrough.

Performance

These measurements processed 600 buffers, with two runs per case:

Pipeline Run 1 Run 2
1536x960 to fakesink, no vapostproc 1.79 s 1.76 s
1536x960 through vapostproc to 1536x960 1.72 s 1.73 s
3072x1920 to fakesink, no vapostproc 7.39 s 7.36 s
3072x1920 through vapostproc to 1536x960 6.97 s 6.96 s

The matching-size case confirms that vapostproc passes the frame
through. The cost of the real resize is below the measurement noise.

Only the vapostproc path is fitted. Adding the same operation to the
software path would impose another scale on the systems least able to
absorb it. If vapostproc is unavailable, the option logs that it is
inactive and preserves the existing cropped behavior.

I also tried removing the compositor caps pin and allowing the physical
frame to reach the existing software videoconvert and videoscale.
That fixed the crop, but the 10-bit pipeline could not sustain 30 fps at
the physical resolution. Source age passed 1.7 seconds and continued to
rise while presentation slack became steadily more negative.

Verification

I tested against an Apple TV 4K (AppleTV14,1) running tvOS 26.6. The
full desktop was visible with the correct aspect ratio, source age
remained between 35 and 50 ms with positive presentation slack, and the
stream stayed stable for several minutes.

The sender was running GNOME 50.1 on Wayland at 166% scaling, GStreamer
1.28.2, Mesa radeonsi on a Radeon 860M, and NVENC HEVC on an RTX 5070.

go test ./... passes.

The option is off by default. I am happy to make it the default if you
prefer.

@espentveit espentveit changed the title Fix cropped Wayland capture on fractionally scaled outputs Add -portal-resize for fractionally scaled outputs Sep 5, 2026
@espentveit
espentveit force-pushed the main branch 2 times, most recently from b017fad to a9990b5 Compare September 5, 2026 10:30
@espentveit espentveit changed the title Add -portal-resize for fractionally scaled outputs Add opt-in portal resize for fractional Wayland scaling Sep 5, 2026
On fractionally scaled Wayland outputs, xdg-desktop-portal reports the
logical output size while PipeWire delivers a physical-size buffer. The
compositor output is pinned to the reported size, but its sink pad does
not scale, so it crops the larger frame to the top-left corner.

Add -portal-resize to fit the captured frame to the reported canvas with
vapostproc before compositing. Since the portal does not expose the
physical size, request the caps whenever the option is enabled and rely
on vapostproc to negotiate passthrough when the sizes already match.

Limit the resize to the GPU path. Systems without vapostproc retain the
existing behavior instead of paying for an additional software scale.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant