/src/libjxl/lib/jxl/enc_progressive_split.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #include "lib/jxl/enc_progressive_split.h" |
7 | | |
8 | | #include <string.h> |
9 | | |
10 | | #include <cstdint> |
11 | | |
12 | | #include "lib/jxl/ac_strategy.h" |
13 | | #include "lib/jxl/base/compiler_specific.h" |
14 | | #include "lib/jxl/coeff_order_fwd.h" |
15 | | #include "lib/jxl/common.h" // kMaxNumPasses |
16 | | #include "lib/jxl/frame_dimensions.h" |
17 | | |
18 | | namespace jxl { |
19 | | |
20 | | template <typename T> |
21 | | void ProgressiveSplitter::SplitACCoefficients( |
22 | | const T* JXL_RESTRICT block, const AcStrategy& acs, size_t bx, size_t by, |
23 | 725k | T* JXL_RESTRICT output[kMaxNumPasses]) { |
24 | 725k | size_t size = acs.covered_blocks_x() * acs.covered_blocks_y() * kDCTBlockSize; |
25 | 725k | auto shift_right_round0 = [&](T v, int shift) { |
26 | 0 | T one_if_negative = static_cast<uint32_t>(v) >> 31; |
27 | 0 | T add = (one_if_negative << shift) - one_if_negative; |
28 | 0 | return (v + add) >> shift; |
29 | 0 | }; Unexecuted instantiation: jxl::ProgressiveSplitter::SplitACCoefficients<int>(int const*, jxl::AcStrategy const&, unsigned long, unsigned long, int* restrict*)::{lambda(int, int)#1}::operator()(int, int) const Unexecuted instantiation: jxl::ProgressiveSplitter::SplitACCoefficients<short>(short const*, jxl::AcStrategy const&, unsigned long, unsigned long, short* restrict*)::{lambda(short, int)#1}::operator()(short, int) const |
30 | | // Early quit for the simple case of only one pass. |
31 | 725k | if (mode_.num_passes == 1) { |
32 | 725k | memcpy(output[0], block, sizeof(T) * size); |
33 | 725k | return; |
34 | 725k | } |
35 | 0 | size_t ncoeffs_all_done_from_earlier_passes = 1; |
36 | |
|
37 | 0 | int previous_pass_shift = 0; |
38 | 0 | for (size_t num_pass = 0; num_pass < mode_.num_passes; num_pass++) { // pass |
39 | | // Zero out output block. |
40 | 0 | memset(output[num_pass], 0, size * sizeof(T)); |
41 | 0 | const int pass_shift = mode_.passes[num_pass].shift; |
42 | 0 | size_t frame_ncoeffs = mode_.passes[num_pass].num_coefficients; |
43 | 0 | size_t xsize = acs.covered_blocks_x(); |
44 | 0 | size_t ysize = acs.covered_blocks_y(); |
45 | 0 | CoefficientLayout(&ysize, &xsize); |
46 | 0 | for (size_t y = 0; y < ysize * frame_ncoeffs; y++) { // superblk-y |
47 | 0 | for (size_t x = 0; x < xsize * frame_ncoeffs; x++) { // superblk-x |
48 | 0 | size_t pos = y * xsize * kBlockDim + x; |
49 | 0 | if (x < xsize * ncoeffs_all_done_from_earlier_passes && |
50 | 0 | y < ysize * ncoeffs_all_done_from_earlier_passes) { |
51 | | // This coefficient was already included in an earlier pass, |
52 | | // which included a genuinely smaller set of coefficients. |
53 | 0 | continue; |
54 | 0 | } |
55 | 0 | T v = block[pos]; |
56 | | // Previous pass discarded some bits: do not encode them again. |
57 | 0 | if (previous_pass_shift != 0) { |
58 | 0 | T previous_v = shift_right_round0(v, previous_pass_shift) * |
59 | 0 | (1 << previous_pass_shift); |
60 | 0 | v -= previous_v; |
61 | 0 | } |
62 | 0 | output[num_pass][pos] = shift_right_round0(v, pass_shift); |
63 | 0 | } // superblk-x |
64 | 0 | } // superblk-y |
65 | | // We just finished a pass. |
66 | | // Hence, we are now guaranteed to have included all coeffs up to |
67 | | // frame_ncoeffs in every block, unless the current pass is shifted. |
68 | 0 | if (mode_.passes[num_pass].shift == 0) { |
69 | 0 | ncoeffs_all_done_from_earlier_passes = frame_ncoeffs; |
70 | 0 | } |
71 | 0 | previous_pass_shift = mode_.passes[num_pass].shift; |
72 | 0 | } // num_pass |
73 | 0 | } void jxl::ProgressiveSplitter::SplitACCoefficients<int>(int const*, jxl::AcStrategy const&, unsigned long, unsigned long, int* restrict*) Line | Count | Source | 23 | 725k | T* JXL_RESTRICT output[kMaxNumPasses]) { | 24 | 725k | size_t size = acs.covered_blocks_x() * acs.covered_blocks_y() * kDCTBlockSize; | 25 | 725k | auto shift_right_round0 = [&](T v, int shift) { | 26 | 725k | T one_if_negative = static_cast<uint32_t>(v) >> 31; | 27 | 725k | T add = (one_if_negative << shift) - one_if_negative; | 28 | 725k | return (v + add) >> shift; | 29 | 725k | }; | 30 | | // Early quit for the simple case of only one pass. | 31 | 725k | if (mode_.num_passes == 1) { | 32 | 725k | memcpy(output[0], block, sizeof(T) * size); | 33 | 725k | return; | 34 | 725k | } | 35 | 0 | size_t ncoeffs_all_done_from_earlier_passes = 1; | 36 | |
| 37 | 0 | int previous_pass_shift = 0; | 38 | 0 | for (size_t num_pass = 0; num_pass < mode_.num_passes; num_pass++) { // pass | 39 | | // Zero out output block. | 40 | 0 | memset(output[num_pass], 0, size * sizeof(T)); | 41 | 0 | const int pass_shift = mode_.passes[num_pass].shift; | 42 | 0 | size_t frame_ncoeffs = mode_.passes[num_pass].num_coefficients; | 43 | 0 | size_t xsize = acs.covered_blocks_x(); | 44 | 0 | size_t ysize = acs.covered_blocks_y(); | 45 | 0 | CoefficientLayout(&ysize, &xsize); | 46 | 0 | for (size_t y = 0; y < ysize * frame_ncoeffs; y++) { // superblk-y | 47 | 0 | for (size_t x = 0; x < xsize * frame_ncoeffs; x++) { // superblk-x | 48 | 0 | size_t pos = y * xsize * kBlockDim + x; | 49 | 0 | if (x < xsize * ncoeffs_all_done_from_earlier_passes && | 50 | 0 | y < ysize * ncoeffs_all_done_from_earlier_passes) { | 51 | | // This coefficient was already included in an earlier pass, | 52 | | // which included a genuinely smaller set of coefficients. | 53 | 0 | continue; | 54 | 0 | } | 55 | 0 | T v = block[pos]; | 56 | | // Previous pass discarded some bits: do not encode them again. | 57 | 0 | if (previous_pass_shift != 0) { | 58 | 0 | T previous_v = shift_right_round0(v, previous_pass_shift) * | 59 | 0 | (1 << previous_pass_shift); | 60 | 0 | v -= previous_v; | 61 | 0 | } | 62 | 0 | output[num_pass][pos] = shift_right_round0(v, pass_shift); | 63 | 0 | } // superblk-x | 64 | 0 | } // superblk-y | 65 | | // We just finished a pass. | 66 | | // Hence, we are now guaranteed to have included all coeffs up to | 67 | | // frame_ncoeffs in every block, unless the current pass is shifted. | 68 | 0 | if (mode_.passes[num_pass].shift == 0) { | 69 | 0 | ncoeffs_all_done_from_earlier_passes = frame_ncoeffs; | 70 | 0 | } | 71 | 0 | previous_pass_shift = mode_.passes[num_pass].shift; | 72 | 0 | } // num_pass | 73 | 0 | } |
Unexecuted instantiation: void jxl::ProgressiveSplitter::SplitACCoefficients<short>(short const*, jxl::AcStrategy const&, unsigned long, unsigned long, short* restrict*) |
74 | | |
75 | | template void ProgressiveSplitter::SplitACCoefficients<int32_t>( |
76 | | const int32_t* JXL_RESTRICT, const AcStrategy&, size_t, size_t, |
77 | | int32_t* JXL_RESTRICT[kMaxNumPasses]); |
78 | | |
79 | | template void ProgressiveSplitter::SplitACCoefficients<int16_t>( |
80 | | const int16_t* JXL_RESTRICT, const AcStrategy&, size_t, size_t, |
81 | | int16_t* JXL_RESTRICT[kMaxNumPasses]); |
82 | | |
83 | | } // namespace jxl |