mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-02 22:24:26 +00:00
LibGfx/WebPWriter: Use symbols for writing image data
No behavior change yet, but this will allow us to emit distance/length and color cache symbols in addition to literal symbols. Not super expensive perf-wise. Before: Benchmark 1: image -o sunset-retro.webp sunset-retro.bmp Time (mean ± σ): 25.3 ms ± 0.5 ms Benchmark 1: animation -o 7z7c.webp 7z7c.gif Time (mean ± σ): 13.9 ms ± 0.6 ms Benchmark 1: animation -o wow.webp wow.gif Time (mean ± σ): 105.7 ms ± 1.7 ms After: Benchmark 1: image -o sunset-retro.webp sunset-retro.bmp Time (mean ± σ): 26.1 ms ± 0.6 ms Benchmark 1: animation -o 7z7c.webp 7z7c.gif Time (mean ± σ): 14.4 ms ± 0.6 ms Benchmark 1: animation -o wow.webp wow.gif Time (mean ± σ): 106.5 ms ± 1.9 ms
This commit is contained in:
parent
7c6176f983
commit
85739def89
|
@ -36,21 +36,23 @@ struct IsOpaque {
|
|||
}
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
u16 green_or_length_or_index { 0 };
|
||||
u8 r;
|
||||
u8 b;
|
||||
u8 a;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
NEVER_INLINE static ErrorOr<void> write_image_data(LittleEndianOutputBitStream& bit_stream, Bitmap const& bitmap, PrefixCodeGroup const& prefix_code_group)
|
||||
NEVER_INLINE static ErrorOr<void> write_image_data(LittleEndianOutputBitStream& bit_stream, ReadonlySpan<Symbol> symbols, PrefixCodeGroup const& prefix_code_group)
|
||||
{
|
||||
// This is currently the hot loop. Keep performance in mind when you change it.
|
||||
for (ARGB32 pixel : bitmap) {
|
||||
u8 a = pixel >> 24;
|
||||
u8 r = pixel >> 16;
|
||||
u8 g = pixel >> 8;
|
||||
u8 b = pixel;
|
||||
|
||||
TRY(prefix_code_group[0].write_symbol(bit_stream, g));
|
||||
TRY(prefix_code_group[1].write_symbol(bit_stream, r));
|
||||
TRY(prefix_code_group[2].write_symbol(bit_stream, b));
|
||||
TRY(prefix_code_group[3].write_symbol(bit_stream, a));
|
||||
for (Symbol const& symbol : symbols) {
|
||||
TRY(prefix_code_group[0].write_symbol(bit_stream, symbol.green_or_length_or_index));
|
||||
TRY(prefix_code_group[1].write_symbol(bit_stream, symbol.r));
|
||||
TRY(prefix_code_group[2].write_symbol(bit_stream, symbol.b));
|
||||
TRY(prefix_code_group[3].write_symbol(bit_stream, symbol.a));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -280,21 +282,37 @@ static ErrorOr<void> write_VP8L_coded_image(ImageKind image_kind, LittleEndianOu
|
|||
if (alphabet_sizes[0] > 288)
|
||||
return Error::from_string_literal("Invalid alphabet size");
|
||||
|
||||
Vector<Symbol> symbols;
|
||||
TRY(symbols.try_ensure_capacity(bitmap.size().area()));
|
||||
Array<Array<u16, 256>, 4> symbol_frequencies {};
|
||||
|
||||
static constexpr auto saturating_increment = [](u16& value) {
|
||||
if (value < UINT16_MAX)
|
||||
value++;
|
||||
};
|
||||
|
||||
auto emit_literal = [&](ARGB32 pixel) {
|
||||
Symbol symbol;
|
||||
symbol.green_or_length_or_index = (pixel >> 8) & 0xff;
|
||||
symbol.r = pixel >> 16;
|
||||
symbol.b = pixel;
|
||||
symbol.a = pixel >> 24;
|
||||
symbols.append(symbol);
|
||||
|
||||
saturating_increment(symbol_frequencies[0][symbol.green_or_length_or_index]);
|
||||
saturating_increment(symbol_frequencies[1][symbol.r]);
|
||||
saturating_increment(symbol_frequencies[2][symbol.b]);
|
||||
saturating_increment(symbol_frequencies[3][symbol.a]);
|
||||
};
|
||||
|
||||
for (ARGB32 const* it = bitmap.begin(), * end = bitmap.end(); it != end; ++it) {
|
||||
ARGB32 pixel = *it;
|
||||
emit_literal(pixel);
|
||||
}
|
||||
|
||||
// We do use huffman coding by writing a single prefix-code-group for the entire image.
|
||||
// FIXME: Consider using a meta-prefix image and using one prefix-code-group per tile.
|
||||
|
||||
Array<Array<u16, 256>, 4> symbol_frequencies {};
|
||||
for (ARGB32 pixel : bitmap) {
|
||||
static constexpr auto saturating_increment = [](u16& value) {
|
||||
if (value < UINT16_MAX)
|
||||
value++;
|
||||
};
|
||||
saturating_increment(symbol_frequencies[0][(pixel >> 8) & 0xff]); // green
|
||||
saturating_increment(symbol_frequencies[1][(pixel >> 16) & 0xff]); // red
|
||||
saturating_increment(symbol_frequencies[2][pixel & 0xff]); // blue
|
||||
saturating_increment(symbol_frequencies[3][pixel >> 24]); // alpha
|
||||
}
|
||||
|
||||
Array<Array<u8, 256>, 4> code_lengths {};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// "Code [0..15] indicates literal code lengths." => the maximum bit length is 15.
|
||||
|
@ -326,7 +344,7 @@ static ErrorOr<void> write_VP8L_coded_image(ImageKind image_kind, LittleEndianOu
|
|||
prefix_code_group[4] = TRY(write_simple_code_lengths(bit_stream, {}));
|
||||
|
||||
// Image data.
|
||||
TRY(write_image_data(bit_stream, bitmap, prefix_code_group));
|
||||
TRY(write_image_data(bit_stream, symbols.span(), prefix_code_group));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue