Skip to content

LibGfx: Decode Mellor_ACTITC_10.pdf faster [3/N]#26250

Merged
nico merged 2 commits intoSerenityOS:masterfrom
LucasChollet:pdf_optimize_part_3
Oct 7, 2025
Merged

LibGfx: Decode Mellor_ACTITC_10.pdf faster [3/N]#26250
nico merged 2 commits intoSerenityOS:masterfrom
LucasChollet:pdf_optimize_part_3

Conversation

@LucasChollet
Copy link
Copy Markdown
Member

Related to #26082

Before:

Benchmark 1: BuildLagom/bin/pdf --render out.png PDF/Mellor_ACTITC_10.pdf --page 4
  Time (mean ± σ):     427.7 ms ±   8.4 ms    [User: 381.2 ms, System: 46.3 ms]
  Range (min … max):   410.3 ms … 438.6 ms    10 runs

After:

Benchmark 1: BuildLagom/bin/pdf --render out.png PDF/Mellor_ACTITC_10.pdf --page 4
  Time (mean ± σ):     337.2 ms ±   3.0 ms    [User: 295.2 ms, System: 41.8 ms]
  Range (min … max):   332.0 ms … 340.7 ms    10 runs

@github-actions github-actions bot added the 👀 pr-needs-review PR needs review from a maintainer or community member label Oct 6, 2025
if (!inputs.uses_huffman_encoding || inputs.uses_refinement_or_aggregate_coding) {
auto bitmap = TRY(read_symbol_bitmap(symbol_width, height_class_height));
new_symbols.append(Symbol::create(move(bitmap)));
new_symbols.append(Symbol::create(bitmap->subbitmap(IntRect(0, 0, bitmap->width(), bitmap->height()))));
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

As the two types are not compatible, it forces a few of these conversions.
These are the only non-mechanical changes in the decoder.

Copy link
Copy Markdown
Contributor

@nico nico Oct 6, 2025

Choose a reason for hiding this comment

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

Maybe BilevelImage should have a rect() method, similar to Gfx::Bitmap. That'd make this here slightly less awkward.

(No action needed.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Or a as_subbitmap method?

Copy link
Copy Markdown
Contributor

@nico nico left a comment

Choose a reason for hiding this comment

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

Very nice!

The commit message grammar-o is the only real comment.

For non-CCITT jbig2s, the additional rect bounds are a teeny tiny slowdown, but it's probably in the measurement noise. (261.0 ms ± 3.7 ms -> 258.9 ms ± 2.8 ms for big_image.jpg converted to jbig2 and then hyperfine 'Build/lagom/bin/image --no-output big_image.jbig2')

if (!inputs.uses_huffman_encoding || inputs.uses_refinement_or_aggregate_coding) {
auto bitmap = TRY(read_symbol_bitmap(symbol_width, height_class_height));
new_symbols.append(Symbol::create(move(bitmap)));
new_symbols.append(Symbol::create(bitmap->subbitmap(IntRect(0, 0, bitmap->width(), bitmap->height()))));
Copy link
Copy Markdown
Contributor

@nico nico Oct 6, 2025

Choose a reason for hiding this comment

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

Maybe BilevelImage should have a rect() method, similar to Gfx::Bitmap. That'd make this here slightly less awkward.

(No action needed.)

This type stores a pointer to an upstream `BilevelImage` and a
rectangle, corresponding to the dimensions of the sub-bitmap.

It is introduced to avoid the copies that were made in
`BilevelImage::subbitmap`. When using this test case:
```
BuildLagom/bin/pdf --render out.png PDF/Mellor_ACTITC_10.pdf --page 4
```

The number of calls to `subbitmap` is ~25000, and none of the resulting
sub-bitmaps are modified. So making shallow copies gives a nice
performance improvement: according to valgrind, this makes the time
spent in `BilevelImage::subbitmap` drop from 26% to 0.03%.
@nico nico merged commit 7d1d475 into SerenityOS:master Oct 7, 2025
13 checks passed
@github-actions github-actions bot removed the 👀 pr-needs-review PR needs review from a maintainer or community member label Oct 7, 2025
nico added a commit to nico/serenity that referenced this pull request Oct 7, 2025
Symbol was a RefCounted wrapper around BilevelImage.

As of SerenityOS#26250, BilevelImage is refcounted itself, and it moved the
loader to BilevelSubImage which can cheaply be copied. Just use
that directly.

No behavior change.
nico added a commit to nico/serenity that referenced this pull request Oct 7, 2025
Symbol was a RefCounted wrapper around BilevelImage.

As of SerenityOS#26250, BilevelImage is refcounted itself, and it moved the
loader to BilevelSubImage which can cheaply be copied. Just use
that directly.

No behavior change.
nico added a commit to nico/serenity that referenced this pull request Oct 7, 2025
Symbol was a RefCounted wrapper around BilevelImage.

As of SerenityOS#26250, BilevelImage is refcounted itself, and it moved the
loader to BilevelSubImage which can cheaply be copied. Just use
that directly.

No behavior change.
@LucasChollet LucasChollet deleted the pdf_optimize_part_3 branch October 8, 2025 08:58
LucasChollet pushed a commit to LucasChollet/serenity that referenced this pull request Oct 8, 2025
Symbol was a RefCounted wrapper around BilevelImage.

As of SerenityOS#26250, BilevelImage is refcounted itself, and it moved the
loader to BilevelSubImage which can cheaply be copied. Just use
that directly.

No behavior change.
nico added a commit that referenced this pull request Oct 8, 2025
Symbol was a RefCounted wrapper around BilevelImage.

As of #26250, BilevelImage is refcounted itself, and it moved the
loader to BilevelSubImage which can cheaply be copied. Just use
that directly.

No behavior change.
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