Page MenuHomePhabricator

Bug 1986393 - Add Rust-based JXL decoder. r=tnikkel,saschanaz
ClosedPublic

Authored by zondolfin on Dec 19 2025, 7:43 AM.
Referenced Files
F68584173: D277142.1777261747.diff
Sun, Apr 26, 3:49 AM
Unknown Object (File)
Sat, Apr 18, 10:59 AM
Unknown Object (File)
Thu, Apr 16, 2:47 PM
Unknown Object (File)
Thu, Apr 16, 8:34 AM
Unknown Object (File)
Tue, Apr 14, 11:28 AM
Unknown Object (File)
Tue, Apr 14, 9:48 AM
Unknown Object (File)
Fri, Apr 10, 11:46 AM
Unknown Object (File)
Thu, Apr 9, 10:46 PM

Diff Detail

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
This revision now requires changes to proceed.Jan 19 2026, 2:23 PM
zondolfin updated this revision to Diff 1187125.
zondolfin marked 6 inline comments as done.
image/decoders/nsJXLDecoder.cpp
74

Yes, since the jxl_decoder_process_data consumes the buffer by incrementing the pointer and decrementing the length, it will become 0 when this buffer is used up.

115

jxl_decoder_process_data will repeatedly populate the buffer until it's done. This call is only called once - after this we other fail out or return TerminateSuccess, right?

I'll add a comment.

122

When the buffer is empty we will ask for more data to continue decoding?

image/rust/jxl/Cargo.toml
9

Yes, but first we need to land some changes in jxl-rs, so that I can test without having it referring to my local checkout :P

image/decoders/nsJXLDecoder.cpp
115

So this means that after jxl_decoder_process_data returns Ok and there is a valid basic info struct it can only return Error or NeedsMoreData until it has the complete image? Is that an api constraint we want? Seems a little limiting.

image/rust/jxl/src/decoder.rs
84

This mult could overflow?

image/decoders/nsJXLDecoder.cpp
115

What else would we need to do?

It's easy to update the code if we need to (like I do in the next two patches, for animation and CMS support).

image/decoders/nsJXLDecoder.cpp
115

Okay, just something I noticed that felt a little unexpected.

image/decoders/nsJXLDecoder.cpp
31

This is not called anywhere, and why do we need a separate init function instead of doing it in the constructor? This doesn't seem to ever fail, or is the intention to make it fallible? Still jxl_decoder_new is infallible...

image/decoders/nsJXLDecoder.cpp
31

InitInternal is the virtual version of the non-virtual Decoder::Init, which it gets called from.

image/decoders/nsJXLDecoder.cpp
31

Ah. I missed override. Sorry and thanks.

image/rust/jxl/src/decoder.rs
84

I think I'd prefer to error in case of overflow, to prevent mismatches of size expectations potentially causing bugs/security issues.

image/decoders/nsJXLDecoder.cpp
115

"repeatedly populate buffer" meaning the buffer will be written with intermediate decoding result multiple times?

image/decoders/nsJXLDecoder.cpp
115

I'm actually not certain if jxl-rs will wait until it can populate it all, or will populate a bit at a time. I _think_ it's the former.

The important point is that when we have received the frame header we don't know how much data jxl-rs needs to produce a frame - we just know it will happen at some point, and how big the buffer needs to be - so from then on we need to have the buffer available.

And storing a C++ buffer on the Rust side seemed like an unnecessary amount of hassle, so sending it each call across the FFI seemed simpler.

image/decoders/nsJXLDecoder.cpp
115

Sending it sounds good to me, I just have concern that writing it repeatedly may negatively affect the performance.

Say,

  1. The browser gets 1 MB of binary data immediately
  2. Somehow the first rendering is available at 200 kB (random chosen number by me)
  3. The decoder writes that to the buffer
  4. The decoder does the same on 400 kB, 800 kB and then on 1 MB
  5. In the end there was three full buffer write even though it could happen just once, as the user would never even notice the intermediate results
115

(but yeah dealing with that doesn't have to happen in this patch IMO)

image/decoders/nsJXLDecoder.cpp
115

I have now talked with Luca about it - and current jxl-rs will render a group once neighboring groups are available. Future render pipelines will render the internal of a group once the group is available, and the rest once neighboring groups are.

It's not a full buffer write - jxl-rs only renders to the sections of memory where we get new pixels.

@sylvestre This is getting pretty close. Are you going to have some time to look at this soon? Thanks!

I think @sylvestre was automatically added when this patch had license changes. Now such changes are moved to the vendor patch, I think he can be removed here. (Note that he's not added in the child patches.)

This revision is now accepted and ready to land.Jan 23 2026, 11:54 AM
This revision now requires review to proceed.Jan 23 2026, 11:54 AM
This revision is now accepted and ready to land.Jan 26 2026, 11:04 AM

Code analysis found 1 defect in diff 1191025:

  • 1 defect found by license (Mozlint)
IMPORTANT: Found 1 defect (error level) that must be fixed before landing.

You can run this analysis locally with:

  • ./mach lint --warnings --outgoing

If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1191025.

This crashes locally and needs investigation.

image/rust/jxl/src/decoder.rs
76

This is not being used, mostly probably we want to use this...

This revision now requires changes to proceed.Jan 26 2026, 5:14 PM
zondolfin updated this revision to Diff 1191751.
zondolfin added inline comments.
image/rust/jxl/src/decoder.rs
76

It was used in a later patch - moved it to that patch now.

The analysis task source-test-mozlint-cargo-audit failed, but we could not detect any defect.
Please check this task manually.


If you see a problem in this automated review, please report it here.

zondolfin marked an inline comment as done.

Code analysis found 16 defects in diff 1191821:

  • 16 defects found by source-test-vendor-rust
IMPORTANT: Found 16 defects (error level) that must be fixed before landing.

If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1191821.

Code analysis found 16 defects in diff 1191856:

  • 16 defects found by source-test-vendor-rust
IMPORTANT: Found 16 defects (error level) that must be fixed before landing.

If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1191856.

Code analysis found 16 defects in diff 1192491:

  • 16 defects found by source-test-vendor-rust
IMPORTANT: Found 16 defects (error level) that must be fixed before landing.

If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1192491.

image/rust/jxl/src/decoder.rs
128

It seems like we wouldn't expect to get here with has_output_buffer == true? Then we would return Ok(false) below which seems wrong. I think it works because we never get here with has_output_buffer == true because the cpp code will pass an output buffer after we hit this and the subsequent process call above will fill the pixel buffer and then we'll toggle frame_ready and return Ok(true)? Is my understaning correct?

saschanaz added inline comments.
image/rust/jxl/src/decoder.rs
128

(should we assert earlier that if it's not metadata only then it should have output buffer?)

This revision is now accepted and ready to land.Jan 28 2026, 1:37 PM

Code analysis found 18 defects in diff 1192535:

  • 2 defects found by rustfmt (Mozlint)
  • 16 defects found by source-test-vendor-rust
WARNING: Found 2 defects (warning level) that can be dismissed.
IMPORTANT: Found 16 defects (error level) that must be fixed before landing.

You can run this analysis locally with:

  • ./mach lint --warnings --outgoing

If you see a problem in this automated review, please report it here.

You can view these defects in the Diff Detail section of Phabricator diff 1192535.

zondolfin added inline comments.
image/rust/jxl/src/decoder.rs
128

This isn't about guarding against metadata decodes having buffers, this is about the interaction between decoder.rs and jxl-rs - we must not have a buffer when we get frame metadata, because we are allocating based on the frame metadata, so if we already have a buffer something is wrong.

This revision was landed with ongoing or failed builds.Jan 28 2026, 3:59 PM
This revision was automatically updated to reflect the committed changes.