From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- .../lib/jxl/modular/encoding/context_predict.h | 4 +- .../jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc | 8 +-- .../jpeg-xl/lib/jxl/modular/encoding/encoding.cc | 12 ++-- .../lib/jxl/modular/transform/enc_palette.cc | 80 +++++++++++++++++----- .../lib/jxl/modular/transform/enc_squeeze.cc | 12 ++-- .../jpeg-xl/lib/jxl/modular/transform/palette.h | 2 + .../jpeg-xl/lib/jxl/modular/transform/squeeze.cc | 22 +++--- .../jpeg-xl/lib/jxl/modular/transform/squeeze.h | 4 +- .../jpeg-xl/lib/jxl/modular/transform/transform.cc | 2 +- .../jpeg-xl/lib/jxl/modular/transform/transform.h | 2 +- 10 files changed, 97 insertions(+), 51 deletions(-) (limited to 'third_party/jpeg-xl/lib/jxl/modular') diff --git a/third_party/jpeg-xl/lib/jxl/modular/encoding/context_predict.h b/third_party/jpeg-xl/lib/jxl/modular/encoding/context_predict.h index 7bec5128fc..df54a9425e 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/encoding/context_predict.h +++ b/third_party/jpeg-xl/lib/jxl/modular/encoding/context_predict.h @@ -63,7 +63,7 @@ struct State { pixel_type_w pred = 0; // *before* removing the added bits. std::vector pred_errors[kNumPredictors]; std::vector error; - const Header header; + const Header &header; // Allows to approximate division by a number from 1 to 64. // for (int i = 0; i < 64; i++) divlookup[i] = (1 << 24) / (i + 1); @@ -82,7 +82,7 @@ struct State { return static_cast(x) << kPredExtraBits; } - State(Header header, size_t xsize, size_t ysize) : header(header) { + State(const Header &header, size_t xsize, size_t ysize) : header(header) { // Extra margin to avoid out-of-bounds writes. // All have space for two rows of data. for (auto &pred_error : pred_errors) { diff --git a/third_party/jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc b/third_party/jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc index de629ad038..23100bba8b 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc @@ -197,7 +197,7 @@ void FindBestSplit(TreeSamples &tree_samples, float threshold, float rcost = std::numeric_limits::max(); Predictor lpred = Predictor::Zero; Predictor rpred = Predictor::Zero; - float Cost() { return lcost + rcost; } + float Cost() const { return lcost + rcost; } }; SplitInfo best_split_static_constant; @@ -242,14 +242,14 @@ void FindBestSplit(TreeSamples &tree_samples, float threshold, // The multiplier ranges cut halfway through the current ranges of static // properties. We do this even if the current node is not a leaf, to // minimize the number of nodes in the resulting tree. - for (size_t i = 0; i < mul_info.size(); i++) { + for (const auto &mmi : mul_info) { uint32_t axis; uint32_t val; IntersectionType t = - BoxIntersects(static_prop_range, mul_info[i].range, axis, val); + BoxIntersects(static_prop_range, mmi.range, axis, val); if (t == IntersectionType::kNone) continue; if (t == IntersectionType::kInside) { - (*tree)[pos].multiplier = mul_info[i].multiplier; + (*tree)[pos].multiplier = mmi.multiplier; break; } if (t == IntersectionType::kPartial) { diff --git a/third_party/jpeg-xl/lib/jxl/modular/encoding/encoding.cc b/third_party/jpeg-xl/lib/jxl/modular/encoding/encoding.cc index bb690b74ba..7e7aa019e3 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/encoding/encoding.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/encoding/encoding.cc @@ -113,7 +113,7 @@ FlatTree FilterTree(const Tree &global_tree, } } - for (size_t j = 0; j < 2; j++) mark_property(flat.properties[j]); + for (int16_t property : flat.properties) mark_property(property); mark_property(flat.property0); output.push_back(flat); } @@ -159,9 +159,9 @@ Status DecodeModularChannelMAANS(BitReader *br, ANSSymbolReader *reader, // From here on, tree lookup returns a *clustered* context ID. // This avoids an extra memory lookup after tree traversal. - for (size_t i = 0; i < tree.size(); i++) { - if (tree[i].property0 == -1) { - tree[i].childID = context_map[tree[i].childID]; + for (auto &node : tree) { + if (node.property0 == -1) { + node.childID = context_map[node.childID]; } } @@ -538,8 +538,8 @@ Status ModularDecode(BitReader *br, Image &image, GroupHeader &header, // Don't do/undo transforms if header is incomplete. header.transforms.clear(); image.transform = header.transforms; - for (size_t c = 0; c < image.channel.size(); c++) { - ZeroFillImage(&image.channel[c].plane); + for (auto &ch : image.channel) { + ZeroFillImage(&ch.plane); } return Status(StatusCode::kNotEnoughBytes); } diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/enc_palette.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/enc_palette.cc index 24c64f5aad..7f9399d3c4 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/enc_palette.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/enc_palette.cc @@ -68,8 +68,8 @@ static int QuantizeColorToImplicitPaletteIndex( int index = 0; if (high_quality) { int multiplier = 1; - for (size_t c = 0; c < color.size(); c++) { - int quantized = ((kLargeCube - 1) * color[c] + (1 << (bit_depth - 1))) / + for (int value : color) { + int quantized = ((kLargeCube - 1) * value + (1 << (bit_depth - 1))) / ((1 << bit_depth) - 1); JXL_ASSERT((quantized % kLargeCube) == quantized); index += quantized * multiplier; @@ -78,8 +78,7 @@ static int QuantizeColorToImplicitPaletteIndex( return index + palette_size + kLargeCubeOffset; } else { int multiplier = 1; - for (size_t c = 0; c < color.size(); c++) { - int value = color[c]; + for (int value : color) { value -= 1 << (std::max(0, bit_depth - 3)); value = std::max(0, value); int quantized = ((kLargeCube - 1) * value + (1 << (bit_depth - 1))) / @@ -171,6 +170,7 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, size_t w = input.channel[begin_c].w; size_t h = input.channel[begin_c].h; + if (!lossy && nb_colors < 2) return false; if (!lossy && nb == 1) { // Channel palette special case @@ -321,6 +321,20 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, } } + std::map, bool> implicit_color; + std::vector> implicit_colors; + implicit_colors.reserve(palette_internal::kImplicitPaletteSize); + for (size_t k = 0; k < palette_internal::kImplicitPaletteSize; k++) { + for (size_t i = 0; i < nb; i++) { + color[i] = palette_internal::GetPaletteValue(nullptr, k, i, 0, 0, + input.bitdepth); + } + implicit_color[color] = true; + implicit_colors.push_back(color); + } + + std::map, size_t> color_freq_map; + uint32_t implicit_colors_used = 0; for (size_t y = 0; y < h; y++) { for (uint32_t c = 0; c < nb; c++) { p_in[c] = input.channel[begin_c + c].Row(y); @@ -332,15 +346,39 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, } const bool new_color = candidate_palette.insert(color).second; if (new_color) { - candidate_palette_imageorder.push_back(color); - } - if (candidate_palette.size() > nb_colors) { - return false; // too many colors + if (implicit_color[color]) { + implicit_colors_used++; + } else { + candidate_palette_imageorder.push_back(color); + if (candidate_palette_imageorder.size() > nb_colors) { + return false; // too many colors + } + } } + color_freq_map[color] += 1; } } - nb_colors = nb_deltas + candidate_palette.size(); + nb_colors = nb_deltas + candidate_palette_imageorder.size(); + + // not useful to make a single-color palette + if (!lossy && nb_colors + implicit_colors_used == 1) return false; + // TODO(jon): if this happens (e.g. solid white group), special-case it for + // faster encode + + for (size_t k = 0; k < palette_internal::kImplicitPaletteSize; k++) { + color = implicit_colors[k]; + // still add the color to the explicit palette if it is frequent enough + if (color_freq_map[color] > 10) { + nb_colors++; + candidate_palette_imageorder.push_back(color); + } + } + for (size_t k = 0; k < palette_internal::kImplicitPaletteSize; k++) { + color = implicit_colors[k]; + inv_palette[color] = nb_colors + k; + } + JXL_DEBUG_V(6, "Channels %i-%i can be represented using a %i-color palette.", begin_c, end_c, nb_colors); @@ -360,25 +398,33 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, } } } - + // Separate the palette in two buckets, first the common colors, then the + // rare colors. + // Within each bucket, the colors are sorted on luma (times alpha). + float freq_threshold = 4; // arbitrary threshold int x = 0; if (ordered && nb >= 3) { JXL_DEBUG_V(7, "Palette of %i colors, using luma order", nb_colors); // sort on luma (multiplied by alpha if available) std::sort(candidate_palette_imageorder.begin(), candidate_palette_imageorder.end(), - [](std::vector ap, std::vector bp) { + [&](std::vector ap, std::vector bp) { float ay; float by; ay = (0.299f * ap[0] + 0.587f * ap[1] + 0.114f * ap[2] + 0.1f); if (ap.size() > 3) ay *= 1.f + ap[3]; by = (0.299f * bp[0] + 0.587f * bp[1] + 0.114f * bp[2] + 0.1f); if (bp.size() > 3) by *= 1.f + bp[3]; + // put common colors first, transparent dark to opaque bright, + // then rare colors, bright to dark + ay = color_freq_map[ap] > freq_threshold ? -ay : ay; + by = color_freq_map[bp] > freq_threshold ? -by : by; return ay < by; }); } else { JXL_DEBUG_V(7, "Palette of %i colors, using image order", nb_colors); } + for (auto pcol : candidate_palette_imageorder) { JXL_DEBUG_V(9, " Color %i : ", x); for (size_t i = 0; i < nb; i++) { @@ -398,10 +444,10 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, // beneficial for both precision and encoding speed. std::vector> error_row[3]; if (lossy) { - for (int i = 0; i < 3; ++i) { - error_row[i].resize(nb); + for (auto &row : error_row) { + row.resize(nb); for (size_t c = 0; c < nb; ++c) { - error_row[i][c].resize(w + 4); + row[c].resize(w + 4); } } } @@ -424,13 +470,11 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, std::vector ideal_residual(nb, 0); std::vector quantized_val(nb); std::vector predictions(nb); - static const double kDiffusionMultiplier[] = {0.55, 0.75}; - for (int diffusion_index = 0; diffusion_index < 2; ++diffusion_index) { + for (double diffusion_multiplier : {0.55, 0.75}) { for (size_t c = 0; c < nb; c++) { color_with_error[c] = p_in[c][x] + (palette_iteration_data.final_run ? 1 : 0) * - kDiffusionMultiplier[diffusion_index] * - error_row[0][c][x + 2]; + diffusion_multiplier * error_row[0][c][x + 2]; color[c] = Clamp1(lroundf(color_with_error[c]), 0l, (1l << input.bitdepth) - 1); } diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/enc_squeeze.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/enc_squeeze.cc index 0d924c0ace..7371830743 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/enc_squeeze.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/enc_squeeze.cc @@ -124,13 +124,13 @@ Status FwdSqueeze(Image &input, std::vector parameters, } // if nothing to do, don't do squeeze if (parameters.empty()) return false; - for (size_t i = 0; i < parameters.size(); i++) { + for (auto ¶meter : parameters) { JXL_RETURN_IF_ERROR( - CheckMetaSqueezeParams(parameters[i], input.channel.size())); - bool horizontal = parameters[i].horizontal; - bool in_place = parameters[i].in_place; - uint32_t beginc = parameters[i].begin_c; - uint32_t endc = parameters[i].begin_c + parameters[i].num_c - 1; + CheckMetaSqueezeParams(parameter, input.channel.size())); + bool horizontal = parameter.horizontal; + bool in_place = parameter.in_place; + uint32_t beginc = parameter.begin_c; + uint32_t endc = parameter.begin_c + parameter.num_c - 1; uint32_t offset; if (in_place) { offset = endc + 1; diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h b/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h index e0405a2162..2a9e5c71f4 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h @@ -30,6 +30,8 @@ static constexpr int kSmallCube = 4; static constexpr int kSmallCubeBits = 2; // kSmallCube ** 3 static constexpr int kLargeCubeOffset = kSmallCube * kSmallCube * kSmallCube; +static constexpr int kImplicitPaletteSize = + kLargeCubeOffset + kLargeCube * kLargeCube * kLargeCube; static inline pixel_type Scale(uint64_t value, uint64_t bit_depth, uint64_t denom) { diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.cc index 580829741a..b71c8dc248 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.cc @@ -385,21 +385,21 @@ void DefaultSqueezeParameters(std::vector *parameters, params.in_place = true; if (!wide) { - if (h > JXL_MAX_FIRST_PREVIEW_SIZE) { + if (h > kMaxFirstPreviewSize) { params.horizontal = false; parameters->push_back(params); h = (h + 1) / 2; JXL_DEBUG_V(7, "Vertical (%" PRIuS "x%" PRIuS "), ", w, h); } } - while (w > JXL_MAX_FIRST_PREVIEW_SIZE || h > JXL_MAX_FIRST_PREVIEW_SIZE) { - if (w > JXL_MAX_FIRST_PREVIEW_SIZE) { + while (w > kMaxFirstPreviewSize || h > kMaxFirstPreviewSize) { + if (w > kMaxFirstPreviewSize) { params.horizontal = true; parameters->push_back(params); w = (w + 1) / 2; JXL_DEBUG_V(7, "Horizontal (%" PRIuS "x%" PRIuS "), ", w, h); } - if (h > JXL_MAX_FIRST_PREVIEW_SIZE) { + if (h > kMaxFirstPreviewSize) { params.horizontal = false; parameters->push_back(params); h = (h + 1) / 2; @@ -424,13 +424,13 @@ Status MetaSqueeze(Image &image, std::vector *parameters) { DefaultSqueezeParameters(parameters, image); } - for (size_t i = 0; i < parameters->size(); i++) { + for (auto ¶meter : *parameters) { JXL_RETURN_IF_ERROR( - CheckMetaSqueezeParams((*parameters)[i], image.channel.size())); - bool horizontal = (*parameters)[i].horizontal; - bool in_place = (*parameters)[i].in_place; - uint32_t beginc = (*parameters)[i].begin_c; - uint32_t endc = (*parameters)[i].begin_c + (*parameters)[i].num_c - 1; + CheckMetaSqueezeParams(parameter, image.channel.size())); + bool horizontal = parameter.horizontal; + bool in_place = parameter.in_place; + uint32_t beginc = parameter.begin_c; + uint32_t endc = parameter.begin_c + parameter.num_c - 1; uint32_t offset; if (beginc < image.nb_meta_channels) { @@ -441,7 +441,7 @@ Status MetaSqueeze(Image &image, std::vector *parameters) { return JXL_FAILURE( "Invalid squeeze: meta channels require in-place residuals"); } - image.nb_meta_channels += (*parameters)[i].num_c; + image.nb_meta_channels += parameter.num_c; } if (in_place) { offset = endc + 1; diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.h b/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.h index bbd16c59c0..f0333da6fd 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.h +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.h @@ -29,10 +29,10 @@ #include "lib/jxl/modular/modular_image.h" #include "lib/jxl/modular/transform/transform.h" -#define JXL_MAX_FIRST_PREVIEW_SIZE 8 - namespace jxl { +constexpr size_t kMaxFirstPreviewSize = 8; + /* int avg=(A+B)>>1; int diff=(A-B); diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc index 33f7a10cc9..a609cfb3fb 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc @@ -23,7 +23,7 @@ Transform::Transform(TransformId id) { } Status Transform::Inverse(Image &input, const weighted::Header &wp_header, - ThreadPool *pool) { + ThreadPool *pool) const { JXL_DEBUG_V(6, "Input channels (%" PRIuS ", %" PRIuS " meta): ", input.channel.size(), input.nb_meta_channels); switch (id) { diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/transform.h b/third_party/jpeg-xl/lib/jxl/modular/transform/transform.h index b68861706f..70c383834a 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/transform.h +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/transform.h @@ -134,7 +134,7 @@ class Transform : public Fields { JXL_FIELDS_NAME(Transform) Status Inverse(Image &input, const weighted::Header &wp_header, - ThreadPool *pool = nullptr); + ThreadPool *pool = nullptr) const; Status MetaApply(Image &input); }; -- cgit v1.2.3