Skip to content

feat: AV1 encoder support, codec discovery improvements#1

Closed
porkloin wants to merge 4 commits intohgaiser:mainfrom
porkloin:av1-support
Closed

feat: AV1 encoder support, codec discovery improvements#1
porkloin wants to merge 4 commits intohgaiser:mainfrom
porkloin:av1-support

Conversation

@porkloin
Copy link
Contributor

@porkloin porkloin commented Feb 13, 2026

👋 I reached out on the moonlight discord about this work - here's the cleaned up version.

This adds AV1 support for pixelforge - the work was done in conjunction with some partner moonshine PRs which I will link here as soon as they're open:

ash has begun adding av1 encode support in the update branch - so this is mostly work implementing that. Note that this does involve changing the source for ash from the previously pinned main branch commit to a feature branch commit hash from the update branch.

A lot of this was put together using ffmpeg's av1 vulkan encoding as a reference implementation, and with a good bit of help from an LLM for questions that I had along the way. I'm hardly a graphics programmer, so this is definitely outside of my are of expertise. I also to a lesser extent consulted Khronos Group Vulkan-Headers repo and nvpro-samples vk_video_samples repo.

It should align with all the rate control and zero copy DMA-BUF, and color profile stuff other encoders in pixelforge currently support.

There's a bunch of av1 stuff here that isn't really working (bframe, tiling) which I barely understand the usecase for but seem not relevant for streaming video like moonshine is doing, and don't seem implemented in the other encoders.

I've tested using moonshine as a client on a 9070XT GPU on a fedora 43 (atomic) system with mesa 25.3.3. Additional testing on more hardware would be great, but is probably easier to do through Moonshine when the AV1 PR on that repo is posted, probably tomorrow night.

Copy link
Owner

@hgaiser hgaiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all thanks for your contribution! Happy to see others are picking up on this.

I can't really judge the Vulkan / AV1 parts properly since I'm no expert either.. but could you update the example(s) and add a encode_av1.rs example? Specifically the verify_all.rs example helps me to quickly check the results are as expected. Also, please run cargo fmt :).

Regarding B frames: they are needed if you want to use both older and newer frames for better compression. This means if a frame comes in and is intended to be a B frame, it needs to be buffered because it needs to know the next frame (or even multiple frames) before it can be encoded. This is obviously not what you want for low latency streaming, so I opted not to implement this yet.

@porkloin
Copy link
Contributor Author

@hgaiser if you have a min to review this again 🙏

@hgaiser
Copy link
Owner

hgaiser commented Feb 19, 2026

Thanks for the ping, this flew under my radar :)

Does the encode_av1 example work for you? I get an error from here.

In the verify_all example I get this:

------------------------------------------------
Testing AV1 Eight Yuv420...
  FAIL: Invalid input: Unsupported codec
------------------------------------------------
Testing AV1 Eight Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for AV1: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------
Testing AV1 Ten Yuv420...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for AV1: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------
Testing AV1 Ten Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for AV1: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------

I have a RTX 5080 and used AV1 in the past. Not through Vulkan though, but I thought AV1 was already supported for NVidia GPUs.

@porkloin
Copy link
Contributor Author

porkloin commented Feb 20, 2026

@hgaiser just pushed some more work, I had missed adding av1 in the image.rs match and a few other things still needed sprucing up like implementing the upload_<format>_to pattern that is present elsewhere and some totally unnecessary intermediate formatting.

re: nvidia, I'm not 100% sure since I don't have any nvidia hardware on hand to test with, so I don't know what the support level for av1 vulkan encode headers is beyond some cursory googling. It looks like you should expect to see at least av1 8bit and 10bit 4:2:0 pass, but 4:4:4 is unsupported?

I'm on an AMD 9070XT and the current state of the mesa RADV driver I'm on (version 25.3.5) doesn't have any 4:4:4 support across h264, hevc or av1, and on top of that doesn't have h264 10 bit support at all. My understanding from the mesa source code is that those limitations are truly stuff that the RADV vulkan encoders aren't able to do atm.

Anyway, with all that context, here's my output from verify_all as of the latest push, which I think lines up with expected hardware limitations for my hardware and driver:

$ cargo run --example verify_all
   Compiling pixelforge v0.1.0 (/home/porkloin/Projects/pixelforge)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.28s
     Running `target/debug/examples/verify_all`
WARNING: radv is not a conformant Vulkan implementation, testing use only.
Testing H264 Eight Yuv420...
  PASS: PSNR = 56.93 dB
------------------------------------------------
Testing H264 Eight Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for requested H.264 profile: ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR
------------------------------------------------
Testing H264 Ten Yuv420...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for requested H.264 profile: ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR
------------------------------------------------
Testing H264 Ten Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for requested H.264 profile: ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR
------------------------------------------------
Testing H265 Eight Yuv420...
  PASS: PSNR = 56.56 dB
------------------------------------------------
Testing H265 Eight Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query H.265 capabilities: ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR
------------------------------------------------
Testing H265 Ten Yuv420...
  PASS: PSNR = 54.33 dB
------------------------------------------------
Testing H265 Ten Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query H.265 capabilities: ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR
------------------------------------------------
Testing AV1 Eight Yuv420...
  PASS: PSNR = 53.10 dB
------------------------------------------------
Testing AV1 Eight Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for AV1: ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR
------------------------------------------------
Testing AV1 Ten Yuv420...
  PASS: PSNR = 50.06 dB
------------------------------------------------
Testing AV1 Ten Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for AV1: ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR
------------------------------------------------

We might need to figure out what your hardware is capable of with regard to vulkan av1 encoding and make sure the results are lining up, but you should see at least more passes now.

Overall what I've learned is that both AMD and nvidia seem to have pretty poor support for 4:4:4 in vulkan across all h264/hevc/av1. I wasn't sure initially how much of that was just poor support for RDNA4 cards like mine, but it looks like it's not great on nvidia.

If you let me know what graphics driver you're on for your 5080 I can do some spelunking on the driver code to see what seems reasonable.

@hgaiser
Copy link
Owner

hgaiser commented Feb 20, 2026

I don't have time to dive into this deeper at the moment, but your branch gives me these results:

Testing H264 Eight Yuv420...
  PASS: PSNR = 54.89 dB
------------------------------------------------
Testing H264 Eight Yuv444...
  PASS: PSNR = 9.87 dB
------------------------------------------------
Testing H264 Ten Yuv420...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for requested H.264 profile: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------
Testing H264 Ten Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for requested H.264 profile: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------
Testing H265 Eight Yuv420...
  PASS: PSNR = 56.43 dB
------------------------------------------------
Testing H265 Eight Yuv444...
  PASS: PSNR = 9.87 dB
------------------------------------------------
Testing H265 Ten Yuv420...
  PASS: PSNR = 54.52 dB
------------------------------------------------
Testing H265 Ten Yuv444...
  PASS: PSNR = 55.81 dB
------------------------------------------------
Testing AV1 Eight Yuv420...
  FAIL: Command buffer error: Initialization of an object has failed
------------------------------------------------
Testing AV1 Eight Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for AV1: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------
Testing AV1 Ten Yuv420...
  FAIL: Command buffer error: Initialization of an object has failed
------------------------------------------------
Testing AV1 Ten Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for AV1: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------

While main gives:

Testing H264 Eight Yuv420...
  PASS: PSNR = 61.12 dB
------------------------------------------------
Testing H264 Eight Yuv444...
  PASS: PSNR = 51.42 dB
------------------------------------------------
Testing H264 Ten Yuv420...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for requested H.264 profile: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------
Testing H264 Ten Yuv444...
  FAIL: Failed to create encoder: No suitable Vulkan physical device found: Failed to query Vulkan Video encode capabilities for requested H.264 profile: ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR
------------------------------------------------
Testing H265 Eight Yuv420...
  PASS: PSNR = 62.39 dB
------------------------------------------------
Testing H265 Eight Yuv444...
  PASS: PSNR = 64.04 dB
------------------------------------------------
Testing H265 Ten Yuv420...
  PASS: PSNR = 59.94 dB
------------------------------------------------
Testing H265 Ten Yuv444...
  PASS: PSNR = 61.29 dB
------------------------------------------------

The PSNR for YUV444 dropped to < 10 dB in both H264 and H265. Any idea why that is?

I didn't check why the command buffer for AV1 failed, that's a separate issue. For what it's worth, I'm using version 590.48.01-9 of the nvidia-open driver.

@porkloin
Copy link
Contributor Author

That's very helpful output, I'll look into it more later today.

@porkloin
Copy link
Contributor Author

porkloin commented Feb 21, 2026

OK, I finally had some time to poke at this a bit more.

For the db drop stuff: the original verify_all test produced tests at 320x240 dimensions, which failed entirely for me on a few formats because the RADV driver has minimum extent of 384 for width for h265 encode specifically. Kinda weird, but as a result I bumped the test dimensions to 480x320, so that's the cause for the db output differences. On my end the main branch tests for h265 encode fail if I have smaller test dimensions.

Anyway, if you re-run verify_all on your end but change the dimensions on the WIDTH and HEIGHT constants for the main branch to match my branch (480x320) then the results should align. One note though, when I was bouncing back and forth I got weird results so you might need to manually delete the testdata dir when switching between branches otherwise test_frames yuv files won't be recreated with new dimensions.
I included some changes in my most recent commit that make the test data distinct by dimension to catch some of that in the future if dimensions on testdata change again.

I also looked into the av1 encoder status for the nvidia drivers, and I really can't find anything definitive. 550.40.xx included support for VK_KHR_video_encode_av1, that was in late 2024. It's possible that the driver support for it isn't really there, or something in ash's implementation is working fine with RADV but not with nvidia driver. If you have time to test it out more with your hardware and trace down exactly where the command buffer thing originates from, that would be great.

@hgaiser
Copy link
Owner

hgaiser commented Feb 23, 2026

Indeed the H264/H265 issue was because of the resolution. I'm still looking into why the AV1 encoding fails on my device.. I'll let you know :).

@hgaiser
Copy link
Owner

hgaiser commented Feb 26, 2026

I've had some time to try and figure this out. It appears that, at least on Nvidia, if you use a P frame as reference to create another P frame, it will mess up. The vk_video_samples repository does work, but they seem to work around the "issue" by only referencing I frames. That means if you generate IPPPP.. sequences that the P frames become increasingly bigger.

On H264/H265 you can successfully reference a P frame to create a P frame.. so it feels like a bug in the Nvidia driver or in the configuration of vk_video_samples.

I'm not yet sure how to proceed. I want to try some more things and probably make an issue on the vk_video_samples to discuss it further.

TLDR: I didn't forget this, but it's not yet in a state where I feel comfortable merging this :)

@porkloin
Copy link
Contributor Author

porkloin commented Feb 27, 2026

TLDR: I didn't forget this, but it's not yet in a state where I feel comfortable merging this :)

All good! I saw you have some recent work merged into main so I'll rebase on that to at least keep things up to date.

In the meantime if there's anything I can do to help feel free to shout! I don't have any nvidia hardware at the moment but I am actually considering getting an nvidia card for another system I have that has been running exclusively on iGPU, so if I get hands on that I'll let you know.

@hgaiser
Copy link
Owner

hgaiser commented Feb 27, 2026

TLDR: I didn't forget this, but it's not yet in a state where I feel comfortable merging this :)

All good! I saw you have some recent work merged into main so I'll rebase on that to at least keep things up to date.

In the meantime if there's anything I can do to help feel free to shout! I don't have any nvidia hardware at the moment but I am actually considering getting an nvidia card for another system I have that has been running exclusively on iGPU, so if I get hands on that I'll let you know.

Ah no need! I've got an uncommitted branch that's rebased and contains some fixes to at least make it run on my GPU. If you want I can push those commits to this branch, but I think you have that option disabled :)

@hgaiser hgaiser mentioned this pull request Feb 28, 2026
@hgaiser
Copy link
Owner

hgaiser commented Feb 28, 2026

Thanks again for the PR! I made some fixes and merged this in #3 , though I couldn't yet get proper IPPPP.. sequences to work without letting the I frame be the reference frame.. I can't recommend using AV1 yet, as I made clear in the documentation too. I'm not sure if this is an nvidia driver issue or something else, I'll need to spend some more time on it. I wanted to get it merged to have at least some form of AV1 encoding functioning, even if it's far from ideal.

@hgaiser hgaiser closed this Feb 28, 2026
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