Skip to content

Activate AMF intra refresh (GDR) - fixing xbox moonlight artefacts - #257

Open
Eftimin70 wants to merge 9 commits into
Nonary:vibefrom
Eftimin70:patch-1
Open

Activate AMF intra refresh (GDR) - fixing xbox moonlight artefacts #257
Eftimin70 wants to merge 9 commits into
Nonary:vibefrom
Eftimin70:patch-1

Conversation

@Eftimin70

@Eftimin70 Eftimin70 commented Aug 7, 2026

Copy link
Copy Markdown

In the latest versions of Vibeshine/Vibepollo AMD Intra Refresh (GDR) for HEVC does not work, even though the log reads otherwise. It looks like die AMF encoder is not configured correctly for that purpose and the infamous artefacts on Xbox in still/slow moving scenes still occur.

This code now works perfectly for me, 4k HDR 60fps, real AMF GDR intra refresh is at work and no additional stutters have been introduced. The dreaded Xbox artefacts are gone.

Keep in mind that this code has intra refresh hard coded and fixed values for GOP and CTU size.

@Eftimin70 Eftimin70 changed the title Update amf_d3d11.cpp to activate AMF Intra Refresh (GDR) Activate AMF intra refresh (GDR) - fixing xbox moonlight artefacts Aug 7, 2026
@Nonary

Nonary commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Thanks for digging into this, and for the clear write-up. Your core observation is correct: on the current builds, HEVC intra refresh (GDR) really is a silent no-op on AMD, even though the host log says it was enabled. That part is a genuine bug and it is now being tracked as such.

I can't take this patch as written, though, for a few reasons:

  • The new property block runs for every session, not only when a client actually asks for intra refresh, and it writes HEVC-specific properties even when the negotiated codec is H.264 or AV1.
  • It sets a 120-frame GOP. The infinite GOP (GOP_SIZE=0) above it is deliberate: periodic IDRs at high bitrate produce keyframes that overflow the stream's FEC block limit and ship unprotected, which is what caused the earlier freezes on RDNA cards. A tester log showed 319 over-FEC frames with a periodic GOP versus 0 without it.
  • The CTB-per-slot value is computed from the encoder's stored frame height, which is still zero at that point in setup, so the value always ends up as 1. At 4K that is roughly a 34-second refresh cycle, which means the rolling refresh is not really doing the work. What is most likely clearing your artifacts is the full keyframe every 120 frames.
  • None of the new property results are checked, and the "GDR mode activated" line is printed before any of them run, so the log would claim success even if the driver rejected everything.

The last two points matter because they suggest the patch fixes the symptom by a different mechanism than intended, at the cost of reintroducing the FEC problem.

Your report did point at the real cause. AMF documents the intra-refresh controls as dynamic properties, and dynamic properties are meant to be applied after Component::Init(). Vibeshine was setting them during static configuration, before init, which is exactly the kind of failure where the driver stores the value, reports it back correctly, and never acts on it. That matches what you saw: correct-looking logs, no actual refresh.

I've built an experimental host to test that theory:

https://github.com/Nonary/vibeshine/releases/tag/amf-intra-refresh-experimental-7bb77154b

This build applies and verifies the intra-refresh properties after encoder init, keeps GOP_SIZE=0 so no periodic IDR cadence is introduced, writes only the property for the negotiated codec, computes the CTB count from the real frame size (2 at 1080p, 7 at 4K), and fails encoder creation instead of logging a false success if a property does not take. It also has bounded diagnostics that record whether any full refreshes happen that nobody requested, which is how we can tell real rolling refresh apart from periodic keyframes.

If you're willing to test it, the procedure is in the release notes. In short: run a normal Xbox HEVC session for at least 75 seconds doing whatever usually triggers the artifacts, then disconnect, reconnect, and repeat once. A 1080p run and a 4K run would both be useful. No client-side changes or client logs are needed. The host log is the important part, and the first minute is left on the normal submission path so what you see visually is not measured under a different code path.

The main thing I want to know is simply whether the artifacts are gone, and whether the log shows the intra-refresh property being applied after init.

Two notes before you install: it is an unsigned local build, not a signed release, so Windows will warn about it. And it should be treated as a test host only, not a general upgrade.

@j-scrizz, you reported the same symptom on an RX 7900 XT in #256 — if you have time to try this build as well, a second data point on different hardware would help a lot.

If this turns out not to fix it on real hardware, the next thing to test is whether AMF's GDR engine requires a finite GOP after all, in which case we would need to work out how to reconcile that with the FEC limit rather than just accepting periodic keyframes.


This comment was AI generated, but has been peer reviewed by the repository owner.

@Eftimin70

Copy link
Copy Markdown
Author

Hi @Nonary , thank you for looking into this issue.

The reason I used GOP = 120 is the following explanation from Google AI:

In video encoding, int64_t gop_size = 120; defines the length of a Group of Pictures (GOP). However, its actual behavior changes completely depending on whether you are using traditional keyframes or your current Intra-Refresh (GDR) setup. [1, 2]
Here is exactly what it means in both contexts:
1. Traditional Encoding (Without Intra-Refresh)
In a standard setup, gop_size = 120 dictates the distance between two I-Frames (Keyframes). [1, 2]
  • Every 120 frames, the encoder inserts a massive, fully independent picture (IDR/I-Frame) that clears the decoder's memory and starts fresh.
  • At 60 FPS, a GOP of 120 means a keyframe is sent exactly every 2 seconds. [1, 2, 3]
2. Your Setup (With Intra-Refresh / GDR)
Because you set AMF_VIDEO_ENCODER_IDR_PERIOD to 0, traditional keyframes are entirely deactivated. There are no massive I-Frames.
Instead, gop_size = 120 acts as the "Sweep Duration" or "Refresh Cycle Length." This means:
  • Time to Full Recovery: It takes exactly 120 frames for the encoder to refresh 100% of the screen.
  • The Wave Speed: The encoder slices your screen into 120 parts. In every single frame, it forces 1/120th of the blocks to be encoded as "Intra" (cleanly encoded without referencing past frames). This clean wave moves down the screen over 120 frames. [1]
  • Maximum Distortion Duration: If a network packet drops or a new viewer joins the stream, the maximum amount of time they will see visual artifacts is 120 frames. By frame 121, the wave has touched every pixel, and the image is completely repaired.

@Eftimin70

Copy link
Copy Markdown
Author

Hi @Nonary , I tested your experimental release "amf-intra-refresh-experimental-7bb77154b", it does not fix the xbox artefacts issue. Please also see my latest comment concerning GOP size.

The following problems have been addressed:

The new property block runs for every session, not only when a client actually asks for intra refresh, and it writes HEVC-specific properties even when the negotiated codec is H.264 or AV1.

The CTB-per-slot value is computed from the encoder's stored frame height, which is still zero at that point in setup, so the value always ends up as 1. At 4K that is roughly a 34-second refresh cycle, which means the rolling refresh is not really doing the work. What is most likely clearing your artifacts is the full keyframe every 120 frames.

None of the new property results are checked, and the "GDR mode activated" line is printed before any of them run, so the log would claim success even if the driver rejected everything.
@Eftimin70

Copy link
Copy Markdown
Author

PR updated

The following problems have been addressed:

  • The new property block runs for every session, not only when a client actually asks for intra refresh, and it writes HEVC-specific properties even when the negotiated codec is H.264 or AV1.

  • The CTB-per-slot value is computed from the encoder's stored frame height, which is still zero at that point in setup, so the value always ends up as 1. At 4K that is roughly a 34-second refresh cycle, which means the rolling refresh is not really doing the work. What is most likely clearing your artifacts is the full keyframe every 120 frames.

  • None of the new property results are checked, and the "GDR mode activated" line is printed before any of them run, so the log would claim success even if the driver rejected everything.

Google code summary

Your code tells the encoder to do a "rolling refresh" of 60 blocks per frame. Because GDR mode is natively understood by the AMD driver, the huge 120-frame I-frame spike is totally destroyed, resulting in a completely flat bitrate line and zero network stutters.

Clean up and added check if the connected client explicitly requested Intra-Refresh
added INSERT2 part again
Final optimization and code cleanup
@Eftimin70

Copy link
Copy Markdown
Author

Update: Final optimization and code cleanup

@Eftimin70 Eftimin70 closed this Aug 23, 2026
added AMF_VIDEO_ENCODER_HEVC_NUM_GOPS_PER_IDR = 0
@Eftimin70 Eftimin70 reopened this Aug 26, 2026
replaced AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_NONE with AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I in case IDR frame was requested by client
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.

2 participants