Skip to content

Faster lossless WebP: predictors per mode, cost table, hashes once - #73

Merged
matmen merged 1 commit into
masterfrom
faster-webp-lossless
Oct 16, 2026
Merged

matmen merged 1 commit into
masterfrom
faster-webp-lossless

Conversation

@matmen

@matmen matmen commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

This makes lossless WebP faster without changing the output. On a 1920×1080 photo:

master this PR
encode 1220 ms 735 ms
decode 95 ms 82 ms

Both builds ran alternately in the same run, because the local machine is noisy. On the runner, encoding took 621 ms in the 3.2.1 benchmark.

Changes (src/codecs/vp8l.ts)

  • predictRun: Predictions now run with one loop per predictor mode, not through predict() with a switch for every pixel. When encoding it writes a block row's predictions into a buffer; when decoding it restores the pixels in place.
    • Encoding uses it to choose a mode per 16×16 block (14 modes per block), decoding uses it in inversePredictor.
    • predict() has no callers left and is removed.
    • A copy specialised for decoding (no restore check in the loop) measured no faster, so there is only the one function.
  • Residual cost: looked up in a 256-entry table instead of four branches.
  • tokenize: each pixel pair is hashed once into an array, instead of once for the search and again for the insert.
    • A larger hash table or a shorter chain made no measurable difference in speed or size.
    • Most of the remaining time is random memory access along the hash chains (about 17 candidates per search).

Verified

  • The VP8L data is byte-identical to master for all 1298 corpus images that were encoded. The rest of the container can differ only by the EXIF timestamp.
  • Decoded pixels are identical for all 153 WebP files in the corpus. Both builds reject the same 3 broken files.
  • npm test passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YJgRK5qpwJEbHPuFv6kgAQ

- predictRun predicts (encoding) or restores (decoding) a run of pixels
  with one loop per mode, instead of predict() with a switch per pixel.
  The encoder's mode search and the decoder's inverse predictor use it.
- residual costs come from a 256-entry table instead of branches.
- tokenize hashes every pixel pair once instead of on search and insert.

Output is identical (VP8L data of 1298 corpus encodes, pixels of 153
WebP decodes). 1920x1080 photo: encoding 1220 -> 735 ms, decoding
95 -> 82 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJgRK5qpwJEbHPuFv6kgAQ
@matmen
matmen merged commit 1a56e22 into master Oct 16, 2026
13 checks passed
@matmen
matmen deleted the faster-webp-lossless branch October 16, 2026 19:36
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.

1 participant