Experimental AVC420/VAAPI/XShm path for xfreerdp to reduce CPU usage during hardware-decoded sessions
Experimental AVC420/VAAPI/XShm path for xfreerdp to reduce CPU usage during hardware-decoded sessions
Is your feature request related to a problem? Please describe.
Yes.
When using xfreerdp with AVC420 and hardware decoding, the system can still be heavily loaded on the client side, even though hardware decoding is active.
In my test setup, xfreerdp was used at a resolution of 3440x1600 pixels on an Intel N100 system.
Command line arguments used for testing:
/f +clipboard +grab-keyboard +async-channels +compression /compression-level:5 /multitransport /bpp:32 /gfx:avc420 /gdi:hw /sound:sys:pulse,format:0x704F,rate:48000CPU usage comparison based on pidstat:
Before optimization: 137.69%
After optimization: 34.02%The optimization reduced CPU usage from 137.69% to 34.02%. This corresponds to a reduction of approximately 75%, or roughly 4× lower CPU usage.
In practice, this frees up around three quarters of the CPU capacity that was previously required for the same workload.
Describe the solution you'd like
I would like to propose an optimized AVC420/VAAPI/X11 output path for xfreerdp.
The current optimized path is:
H.264/AVC420 -> VAAPI Decode -> VAAPI VPP -> USER_PTR RGB32 -> GDI/XShm -> XShmPutImagexfreerdp must be built with the new CMake option:
-DWITH_XSHM=ONRecommended graphics options:
/gfx:avc420 /gdi:hw /bpp:32These options are relevant for the optimized AVC420/VAAPI/X11 path.
The optimized path can be detected with log messages like:
[xf_shm_create_surface_image]: XShm runtime: enabled version=1.2 sharedPixmaps=yesThis confirms that MIT-SHM/XShm is active for X11 output.
[xf_vaapi_vpp_prepare]: VAAPI VPP v41: ready source NV12/VAAPI -> USER_PTR RGB32This confirms that the optimized VAAPI-VPP path is active.
If messages such as the following appear instead, the optimized path is not active:
not suitable for custom path
falling back
USER_PTR RGB32 target not availableThe following features must not be enabled for this optimized path:
SmartSizing
MultiTouchGestures
RemoteAppIf SmartSizing or MultiTouchGestures are active, the client deliberately falls back to the normal FreeRDP path. Display output still works, but not through the optimized VAAPI/XShm path.
Describe alternatives you've considered
A direct vaPutSurface / EGL / DMABUF render path into the window would theoretically be another possible optimization.
However, this only partially fits the current FreeRDP architecture, because FreeRDP normally controls the image flow through:
SurfaceCommand
Dirty regions
OutputUpdate
SmartSizing
RemoteApp
X11 window logicThe proposed approach deliberately remains within the existing FreeRDP output model:
VAAPI Decode -> VAAPI VPP -> USER_PTR RGB32 -> GDI/XShm -> XShmPutImageThis is not fully GPU-direct, but it avoids the expensive old hwdownload/color-conversion path and remains more compatible with the FreeRDP graphics pipeline.
Additional context
Test system:
lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 39 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Vendor ID: GenuineIntel
Model name: Intel(R) N100The resolution used during the test was 3440x1600 pixels.
Note: The following pidstat output was generated on a system using a German locale. Durchschn. means average.
Optimized version:
pidstat -u -t -p 5334 1 30
Durchschn.: 999 5334 - 28,76 5,26 0,00 0,00 34,02 - xfreerdp_111
Durchschn.: 999 - 5334 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp_111
Durchschn.: 999 - 5335 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp_111
Durchschn.: 999 - 5336 4,60 3,27 0,00 0,23 7,86 - |__xfreerdp_111
Durchschn.: 999 - 5337 1,30 0,23 0,00 0,07 1,53 - |__xfreerdp_111
Durchschn.: 999 - 5338 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp_111
Durchschn.: 999 - 5342 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp_111
Durchschn.: 999 - 5343 0,27 0,60 0,00 0,13 0,87 - |__threaded-ml
Durchschn.: 999 - 5344 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp_111
Durchschn.: 999 - 5345 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp_111
Durchschn.: 999 - 5346 22,36 1,43 0,00 0,13 23,79 - |__xfreerdp_111Original version:
pidstat -u -t -p 6463 1 30
Durchschn.: 999 6463 - 101,63 36,05 0,00 0,00 137,69 - xfreerdp
Durchschn.: 999 - 6463 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp
Durchschn.: 999 - 6464 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp
Durchschn.: 999 - 6465 3,10 1,73 0,00 1,77 4,83 - |__xfreerdp
Durchschn.: 999 - 6466 0,93 0,13 0,00 0,37 1,07 - |__xfreerdp
Durchschn.: 999 - 6467 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp
Durchschn.: 999 - 6471 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp
Durchschn.: 999 - 6472 0,20 0,33 0,00 0,70 0,53 - |__threaded-ml
Durchschn.: 999 - 6473 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp
Durchschn.: 999 - 6474 0,00 0,00 0,00 0,00 0,00 - |__xfreerdp
Durchschn.: 999 - 6475 19,49 21,39 0,00 6,13 40,89 - |__xfreerdp
Durchschn.: 999 - 6476 19,29 3,20 0,00 5,26 22,49 - |__xfreerdp
Durchschn.: 999 - 6477 19,46 3,20 0,00 5,16 22,66 - |__xfreerdp
Durchschn.: 999 - 6478 19,23 3,30 0,00 5,26 22,53 - |__xfreerdp
Durchschn.: 999 - 6479 19,46 3,23 0,00 5,06 22,69 - |__xfreerdpAudio sync was also optimized to prevent gradual drift between audio and video.
Synchronization adjustments are now applied dynamically during quiet periods or pauses in the audio stream, helping maintain stable A/V sync without introducing unnecessary artifacts.
Recommended audio option:
/sound:sys:pulse,format:0x704F,rate:480000x704F is OPUS.
For this, xrdp had to be patched, because the OPUS codec otherwise works incorrectly there.
Alternative audio option:
/sound:sys:pulse,format:0xA1060xA106 is AAC_MS.
This works here without modifications.
I started adding VA-API hardware encoding to xrdp/xorg-xrdp about one year ago. After that was working reasonably well, I realized how heavily xfreerdp loads the system despite hardware decoding.
Over the last few months, I have invested some time from time to time, and it now works continuously without problems during daily work for 14 hours.
Debian 13 static test build:
https://datiscum.de/MyPubDownload/xfreerdp_111
If all dependencies are installed, it can be tested directly.
Source: FreeRDP/FreeRDP