[GH-ISSUE #502] [AMD/VAAPI] RX 9070 XT zero-copy HEVC 4K120 produces ~70 unique fps #308

Closed
opened 2026-10-15 12:59:31 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @boiler4 on GitHub (Sep 16, 2026).
Original GitHub issue: https://github.com/games-on-whales/wolf/issues/502

Summary

On an RX 9070 XT, Wolf accepts a Moonlight HEVC session requested at 3840x2160@120, but I observed only about 70.5 unique encoded frame IDs/s on the GameStream video flow. A standalone reproduction using Wolf's zero-copy GStreamer/VA path in the same image measured 63.3 fps HEVC and 24.2 fps AV1 at 4K120/80 Mbps.

I am not claiming that Wolf core or GStreamer alone is proven defective. The minimal pipeline reproduces the throughput without Wolf networking or Moonlight, so the remaining boundary is the VA encode path shipped in the tested Wolf image: GstVA, the container's Mesa/libva stack, encoder settings/submission behavior, or their interaction.

Environment

  • GPU: ASRock Radeon RX 9070 XT 16 GB, PCI ID 1002:7550 (ASRock subsystem 1849:5417)
  • GPU presented by PCI passthrough; amdgpu in use
  • Only one DRM render node: /dev/dri/renderD128
  • Guest kernel: 7.0.0-31-generic
  • Wolf image: ghcr.io/games-on-whales/wolf:stable
  • Tested image digest: sha256:0d901e766e6ed288712ff994dd3b877aea7c9f22ff6e5b0efbb16bc7bb4ae9a4
  • Image source revision: 7f416ec0f26bb4d95218af806cd1181fe5434598
  • GStreamer/GstVA: 1.26.7
  • Wolf container Mesa VA driver: 25.0.7
  • Wolf container libva: 2.22.0

Library identities in the Wolf container:

libva.so.2.2200.0
  f306d7a76960b75f76eef6fda33b0b6a094d1e352955344fea65d098308c6923
libva-drm.so.2.2200.0
  48c66f46f6a8f881f07a3a270d968fea523ce51ffe200469ca93bb61df47fa4e
libgallium-25.0.7-0ubuntu0.25.04.2.so (radeonsi_drv_video.so target)
  bd462a81a46f2afbd8a02cb8b2189baba68f45da20275b4c8e51cdbe421ed507
/usr/local/lib/x86_64-linux-gnu/gstreamer-1.0/libgstva.so
  222402ce7517a4682a3a01c8343f77688016e233269c91b1c1fb419f29711834

The current stable source branch is newer than the tested revision, but I found no changes to the GStreamer base, GPU-driver Dockerfile, or VA encoder defaults between them.

Real Wolf/Moonlight result

  • Requested session: HEVC 3840x2160@120
  • HEVC independently confirmed from Annex-B NAL headers in the live video flow
  • Network sample: 415 unique GameStream frame IDs over 5.883 seconds = 70.54 fps
  • The frame-ID sample was collected during a 120-second telemetry window; it is not a 120-second frame-ID average
  • Moonlight on iPad reported 4 ms latency and 0 dropped frames
  • Global MediaEngine: 94.93% average / 100% max
  • Wolf VCN_Unified: 96.08% average; this ASIC/kernel does not expose separate Encode or VPE counters
  • Wolf CPU: 49.34% of one core average
  • Maximum temperatures: edge 48 C, hotspot 57 C, VRAM 72 C
  • No Wolf restart/OOM and no new kernel GPU fault/reset/timeout

Zero client drops only means that received frames were delivered; it does not mean 120 distinct frames were encoded.

Standalone reproduction inside the Wolf image

This removes Wolf networking, Moonlight and parsers from the throughput path:

docker exec \
  -e GST_GL_WINDOW=surfaceless \
  -e GST_GL_PLATFORM=egl \
  -e GST_GL_API=gles2 \
  wolf timeout --signal=TERM --kill-after=3 31 \
  gst-launch-1.0 -q \
    gltestsrc is-live=false pattern=smpte \
    ! 'video/x-raw(memory:GLMemory),width=3840,height=2160,framerate=120/1' \
    ! glcolorconvert \
    ! gldownload \
    ! 'video/x-raw(memory:DMABuf)' \
    ! vapostproc add-borders=true \
    ! 'video/x-raw(memory:VAMemory),format=NV12,width=3840,height=2160,framerate=120/1,pixel-aspect-ratio=1/1' \
    ! progressreport name=in_hevc format=buffers do-query=false update-freq=1 \
    ! vah265enc aud=false b-frames=0 ref-frames=1 num-slices=1 \
        bitrate=80000 cpb-size=8000 min-qp=20 key-int-max=1024 \
        rate-control=cbr target-usage=6 \
    ! progressreport name=out_hevc format=buffers do-query=false update-freq=1 \
    ! fakesink sync=false

Thirty-second throughput was calculated from the slope of output progressreport buffer counts after the startup interval.

Encoder 4K120 / 80 Mbps Input/output frames at final common report MediaEngine avg/max VCN_Unified avg/max
vah265enc 63.308 fps 1951 / 1950 83.0 / 96% 77.0 / 88%
vaav1enc 24.231 fps 737 / 736 86.33 / 97% 85.4 / 96%

For AV1 I replaced vah265enc with:

vaav1enc ref-frames=1 bitrate=80000 cpb-size=8000 min-qp=20
           key-int-max=1024 rate-control=cbr target-usage=6

Additional isolation:

  • HEVC stayed about 62.3-63.7 fps and AV1 24.0-24.2 fps from 60 to 150 Mbps.
  • The same GL/DMABUF/VAMemory conversion path without the encoder exceeded 700 fps.
  • Replacing filesink with fakesink did not remove the HEVC ceiling.
  • CQP, target-usage 7, plugin defaults, slice and tile variants did not remove it.
  • Changing gltestsrc from SMPTE color bars to black did not produce an obvious speedup in short follow-up runs.
  • There is no system-memory upload or videoconvert in the reproduction above.

Cross-backend evidence and important caveat

A host-linked FFmpeg 8.0.1 VAAPI build on the same VM/GPU/kernel/firmware measured:

Codec 8-bit 10-bit
HEVC 215.8 fps 111.5 fps
AV1 213.2 fps 112.6 fps

However, this is not an apples-to-apples comparison:

  • FFmpeg used host Mesa 25.2.8 and libva 2.20.0, not Wolf's Mesa 25.0.7/libva 2.22.0.
  • Input was all-zero raw NV12/P010 from /dev/zero in RAM followed by hwupload.
  • FFmpeg explicitly used -async_depth 8.
  • Rate-control settings were similar (CBR 80 Mbps, B-frames 0, GOP 1024), but not every encoder property was equivalent.

Short output files probed as hardware-produced HEVC Main / AV1 Main at 3840x2160 with 120/1 timing. I use these results only to show that a different VA userspace/submission path can exceed 120 fps on this hardware, not as proof that Wolf core or GstVA is the sole cause or as an image-quality comparison.

AMF and Vulkan tests also used different APIs and RAM upload, so I have intentionally omitted them from the primary reproduction.

  • #159: historically related AMD VAAPI throughput, but it concerned an older non-zero-copy path and was closed after frame-dropping/latency mitigation.
  • #478: >60 fps negotiation failure caused by exposing multiple GPUs/using the legacy path; this system has one GPU, negotiates 4K120 and uses zero-copy.
  • #330: outdated Mesa in GOW images on newer AMD hardware; potentially related, but that report concerns VPE errors/functional failure rather than measured encode throughput.
  • #103: older AMD grey-screen/performance regression.

I did not find an exact duplicate for negotiated zero-copy 4K120 working while unique encoded throughput remains around 70 fps on RDNA4.

Questions

  1. Is this level of vah265enc / vaav1enc throughput expected with the Mesa/GstVA versions bundled in the current Wolf image on RDNA4?
  2. Could the synchronous submission behavior or lack of an FFmpeg-like async depth in GstVA explain the gap, or are there Wolf pipeline properties worth testing?
  3. Would a controlled retest with the planned newer/Fedora Mesa image be the most useful next discriminator for #330 versus a GstVA-specific issue?

I can provide the sanitized 83-test GStreamer matrix, commands and telemetry if useful.

Originally created by @boiler4 on GitHub (Sep 16, 2026). Original GitHub issue: https://github.com/games-on-whales/wolf/issues/502 ## Summary On an RX 9070 XT, Wolf accepts a Moonlight HEVC session requested at 3840x2160@120, but I observed only about **70.5 unique encoded frame IDs/s** on the GameStream video flow. A standalone reproduction using Wolf's zero-copy GStreamer/VA path in the same image measured **63.3 fps HEVC** and **24.2 fps AV1** at 4K120/80 Mbps. I am **not** claiming that Wolf core or GStreamer alone is proven defective. The minimal pipeline reproduces the throughput without Wolf networking or Moonlight, so the remaining boundary is the VA encode path shipped in the tested Wolf image: GstVA, the container's Mesa/libva stack, encoder settings/submission behavior, or their interaction. ## Environment - GPU: ASRock Radeon RX 9070 XT 16 GB, PCI ID `1002:7550` (ASRock subsystem `1849:5417`) - GPU presented by PCI passthrough; `amdgpu` in use - Only one DRM render node: `/dev/dri/renderD128` - Guest kernel: `7.0.0-31-generic` - Wolf image: `ghcr.io/games-on-whales/wolf:stable` - Tested image digest: `sha256:0d901e766e6ed288712ff994dd3b877aea7c9f22ff6e5b0efbb16bc7bb4ae9a4` - Image source revision: `7f416ec0f26bb4d95218af806cd1181fe5434598` - GStreamer/GstVA: 1.26.7 - Wolf container Mesa VA driver: 25.0.7 - Wolf container libva: 2.22.0 Library identities in the Wolf container: ```text libva.so.2.2200.0 f306d7a76960b75f76eef6fda33b0b6a094d1e352955344fea65d098308c6923 libva-drm.so.2.2200.0 48c66f46f6a8f881f07a3a270d968fea523ce51ffe200469ca93bb61df47fa4e libgallium-25.0.7-0ubuntu0.25.04.2.so (radeonsi_drv_video.so target) bd462a81a46f2afbd8a02cb8b2189baba68f45da20275b4c8e51cdbe421ed507 /usr/local/lib/x86_64-linux-gnu/gstreamer-1.0/libgstva.so 222402ce7517a4682a3a01c8343f77688016e233269c91b1c1fb419f29711834 ``` The current `stable` source branch is newer than the tested revision, but I found no changes to the GStreamer base, GPU-driver Dockerfile, or VA encoder defaults between them. ## Real Wolf/Moonlight result - Requested session: HEVC 3840x2160@120 - HEVC independently confirmed from Annex-B NAL headers in the live video flow - Network sample: 415 unique GameStream frame IDs over 5.883 seconds = **70.54 fps** - The frame-ID sample was collected during a 120-second telemetry window; it is not a 120-second frame-ID average - Moonlight on iPad reported 4 ms latency and 0 dropped frames - Global MediaEngine: 94.93% average / 100% max - Wolf `VCN_Unified`: 96.08% average; this ASIC/kernel does not expose separate Encode or VPE counters - Wolf CPU: 49.34% of one core average - Maximum temperatures: edge 48 C, hotspot 57 C, VRAM 72 C - No Wolf restart/OOM and no new kernel GPU fault/reset/timeout Zero client drops only means that received frames were delivered; it does not mean 120 distinct frames were encoded. ## Standalone reproduction inside the Wolf image This removes Wolf networking, Moonlight and parsers from the throughput path: ```bash docker exec \ -e GST_GL_WINDOW=surfaceless \ -e GST_GL_PLATFORM=egl \ -e GST_GL_API=gles2 \ wolf timeout --signal=TERM --kill-after=3 31 \ gst-launch-1.0 -q \ gltestsrc is-live=false pattern=smpte \ ! 'video/x-raw(memory:GLMemory),width=3840,height=2160,framerate=120/1' \ ! glcolorconvert \ ! gldownload \ ! 'video/x-raw(memory:DMABuf)' \ ! vapostproc add-borders=true \ ! 'video/x-raw(memory:VAMemory),format=NV12,width=3840,height=2160,framerate=120/1,pixel-aspect-ratio=1/1' \ ! progressreport name=in_hevc format=buffers do-query=false update-freq=1 \ ! vah265enc aud=false b-frames=0 ref-frames=1 num-slices=1 \ bitrate=80000 cpb-size=8000 min-qp=20 key-int-max=1024 \ rate-control=cbr target-usage=6 \ ! progressreport name=out_hevc format=buffers do-query=false update-freq=1 \ ! fakesink sync=false ``` Thirty-second throughput was calculated from the slope of output `progressreport` buffer counts after the startup interval. | Encoder | 4K120 / 80 Mbps | Input/output frames at final common report | MediaEngine avg/max | `VCN_Unified` avg/max | |---|---:|---:|---:|---:| | `vah265enc` | 63.308 fps | 1951 / 1950 | 83.0 / 96% | 77.0 / 88% | | `vaav1enc` | 24.231 fps | 737 / 736 | 86.33 / 97% | 85.4 / 96% | For AV1 I replaced `vah265enc` with: ```text vaav1enc ref-frames=1 bitrate=80000 cpb-size=8000 min-qp=20 key-int-max=1024 rate-control=cbr target-usage=6 ``` Additional isolation: - HEVC stayed about 62.3-63.7 fps and AV1 24.0-24.2 fps from 60 to 150 Mbps. - The same GL/DMABUF/VAMemory conversion path without the encoder exceeded 700 fps. - Replacing filesink with fakesink did not remove the HEVC ceiling. - CQP, target-usage 7, plugin defaults, slice and tile variants did not remove it. - Changing `gltestsrc` from SMPTE color bars to black did not produce an obvious speedup in short follow-up runs. - There is no system-memory upload or `videoconvert` in the reproduction above. ## Cross-backend evidence and important caveat A host-linked FFmpeg 8.0.1 VAAPI build on the same VM/GPU/kernel/firmware measured: | Codec | 8-bit | 10-bit | |---|---:|---:| | HEVC | 215.8 fps | 111.5 fps | | AV1 | 213.2 fps | 112.6 fps | However, this is **not an apples-to-apples comparison**: - FFmpeg used host Mesa 25.2.8 and libva 2.20.0, not Wolf's Mesa 25.0.7/libva 2.22.0. - Input was all-zero raw NV12/P010 from `/dev/zero` in RAM followed by `hwupload`. - FFmpeg explicitly used `-async_depth 8`. - Rate-control settings were similar (CBR 80 Mbps, B-frames 0, GOP 1024), but not every encoder property was equivalent. Short output files probed as hardware-produced HEVC Main / AV1 Main at 3840x2160 with 120/1 timing. I use these results only to show that a different VA userspace/submission path can exceed 120 fps on this hardware, **not** as proof that Wolf core or GstVA is the sole cause or as an image-quality comparison. AMF and Vulkan tests also used different APIs and RAM upload, so I have intentionally omitted them from the primary reproduction. ## Related issues checked - #159: historically related AMD VAAPI throughput, but it concerned an older non-zero-copy path and was closed after frame-dropping/latency mitigation. - #478: >60 fps negotiation failure caused by exposing multiple GPUs/using the legacy path; this system has one GPU, negotiates 4K120 and uses zero-copy. - #330: outdated Mesa in GOW images on newer AMD hardware; potentially related, but that report concerns VPE errors/functional failure rather than measured encode throughput. - #103: older AMD grey-screen/performance regression. I did not find an exact duplicate for negotiated zero-copy 4K120 working while unique encoded throughput remains around 70 fps on RDNA4. ## Questions 1. Is this level of `vah265enc` / `vaav1enc` throughput expected with the Mesa/GstVA versions bundled in the current Wolf image on RDNA4? 2. Could the synchronous submission behavior or lack of an FFmpeg-like async depth in GstVA explain the gap, or are there Wolf pipeline properties worth testing? 3. Would a controlled retest with the planned newer/Fedora Mesa image be the most useful next discriminator for #330 versus a GstVA-specific issue? I can provide the sanitized 83-test GStreamer matrix, commands and telemetry if useful.
Author
Owner

@ABeltramo commented on GitHub (Sep 21, 2026):

There are quite a few tunables that you can play with in the Gstreamer pipeline, there's a good discussion about this on our Discord server here.
I think your AI answered all the other questions already, the ffmpeg comparison is definitely not an apples-to-apples comparison especially since you are encoding a static image (/dev/zero) which is by itself much faster compared to a real gaming session.

I'm going to close this because it doesn't sound like an actual issue, at best this could be a tuning discussion, which usually ends up in the usual dilemma: better image quality but with slower encoding or worse image but faster?

<!-- gh-comment-id:5762206822 --> @ABeltramo commented on GitHub (Sep 21, 2026): There are quite a few tunables that you can play with in the Gstreamer pipeline, there's a good discussion about this on our Discord server [here](https://discord.com/channels/856434175455133727/1446648398907179029). I think your AI answered all the other questions already, the ffmpeg comparison is definitely not an apples-to-apples comparison especially since you are encoding a static image (`/dev/zero`) which is by itself much faster compared to a real gaming session. I'm going to close this because it doesn't sound like an actual issue, at best this could be a tuning discussion, which usually ends up in the usual dilemma: better image quality but with slower encoding or worse image but faster?
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
games-on-whales/wolf#308
No description provided.