/src/libjxl/lib/jxl/ac_strategy.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/ac_strategy.h" |
7 | | |
8 | | #include <jxl/memory_manager.h> |
9 | | |
10 | | #include <algorithm> |
11 | | #include <cstdint> |
12 | | #include <cstring> |
13 | | #include <utility> |
14 | | |
15 | | #include "lib/jxl/base/bits.h" |
16 | | #include "lib/jxl/base/compiler_specific.h" |
17 | | #include "lib/jxl/base/status.h" |
18 | | #include "lib/jxl/coeff_order_fwd.h" |
19 | | #include "lib/jxl/frame_dimensions.h" |
20 | | #include "lib/jxl/image.h" |
21 | | |
22 | | namespace jxl { |
23 | | |
24 | | // Tries to generalize zig-zag order to non-square blocks. Surprisingly, in |
25 | | // square block frequency along the (i + j == const) diagonals is roughly the |
26 | | // same. For historical reasons, consecutive diagonals are traversed |
27 | | // in alternating directions - so called "zig-zag" (or "snake") order. |
28 | | template <bool is_lut> |
29 | 4.69k | static void CoeffOrderAndLut(AcStrategy acs, coeff_order_t* out) { |
30 | 4.69k | size_t cx = acs.covered_blocks_x(); |
31 | 4.69k | size_t cy = acs.covered_blocks_y(); |
32 | 4.69k | CoefficientLayout(&cy, &cx); |
33 | | |
34 | | // CoefficientLayout ensures cx >= cy. |
35 | | // We compute the zigzag order for a cx x cx block, then discard all the |
36 | | // lines that are not multiple of the ratio between cx and cy. |
37 | 4.69k | size_t xs = cx / cy; |
38 | 4.69k | size_t xsm = xs - 1; |
39 | 4.69k | size_t xss = CeilLog2Nonzero(xs); |
40 | | // First half of the block |
41 | 4.69k | size_t cur = cx * cy; |
42 | 110k | for (size_t i = 0; i < cx * kBlockDim; i++) { |
43 | 4.89M | for (size_t j = 0; j <= i; j++) { |
44 | 4.79M | size_t x = j; |
45 | 4.79M | size_t y = i - j; |
46 | 4.79M | if (i % 2) std::swap(x, y); |
47 | 4.79M | if ((y & xsm) != 0) continue; |
48 | 3.59M | y >>= xss; |
49 | 3.59M | size_t val = 0; |
50 | 3.59M | if (x < cx && y < cy) { |
51 | 110k | val = y * cx + x; |
52 | 3.48M | } else { |
53 | 3.48M | val = cur++; |
54 | 3.48M | } |
55 | 3.59M | if (is_lut) { |
56 | 56.0k | out[y * cx * kBlockDim + x] = val; |
57 | 3.53M | } else { |
58 | 3.53M | out[val] = y * cx * kBlockDim + x; |
59 | 3.53M | } |
60 | 3.59M | } |
61 | 105k | } |
62 | | // Second half |
63 | 105k | for (size_t ip = cx * kBlockDim - 1; ip > 0; ip--) { |
64 | 101k | size_t i = ip - 1; |
65 | 4.78M | for (size_t j = 0; j <= i; j++) { |
66 | 4.68M | size_t x = cx * kBlockDim - 1 - (i - j); |
67 | 4.68M | size_t y = cx * kBlockDim - 1 - j; |
68 | 4.68M | if (i % 2) std::swap(x, y); |
69 | 4.68M | if ((y & xsm) != 0) continue; |
70 | 3.48M | y >>= xss; |
71 | 3.48M | size_t val = cur++; |
72 | 3.48M | if (is_lut) { |
73 | 48.9k | out[y * cx * kBlockDim + x] = val; |
74 | 3.43M | } else { |
75 | 3.43M | out[val] = y * cx * kBlockDim + x; |
76 | 3.43M | } |
77 | 3.48M | } |
78 | 101k | } |
79 | 4.69k | } ac_strategy.cc:void jxl::CoeffOrderAndLut<false>(jxl::AcStrategy, unsigned int*) Line | Count | Source | 29 | 4.19k | static void CoeffOrderAndLut(AcStrategy acs, coeff_order_t* out) { | 30 | 4.19k | size_t cx = acs.covered_blocks_x(); | 31 | 4.19k | size_t cy = acs.covered_blocks_y(); | 32 | 4.19k | CoefficientLayout(&cy, &cx); | 33 | | | 34 | | // CoefficientLayout ensures cx >= cy. | 35 | | // We compute the zigzag order for a cx x cx block, then discard all the | 36 | | // lines that are not multiple of the ratio between cx and cy. | 37 | 4.19k | size_t xs = cx / cy; | 38 | 4.19k | size_t xsm = xs - 1; | 39 | 4.19k | size_t xss = CeilLog2Nonzero(xs); | 40 | | // First half of the block | 41 | 4.19k | size_t cur = cx * cy; | 42 | 103k | for (size_t i = 0; i < cx * kBlockDim; i++) { | 43 | 4.81M | for (size_t j = 0; j <= i; j++) { | 44 | 4.72M | size_t x = j; | 45 | 4.72M | size_t y = i - j; | 46 | 4.72M | if (i % 2) std::swap(x, y); | 47 | 4.72M | if ((y & xsm) != 0) continue; | 48 | 3.53M | y >>= xss; | 49 | 3.53M | size_t val = 0; | 50 | 3.53M | if (x < cx && y < cy) { | 51 | 108k | val = y * cx + x; | 52 | 3.42M | } else { | 53 | 3.42M | val = cur++; | 54 | 3.42M | } | 55 | 3.53M | if (is_lut) { | 56 | 0 | out[y * cx * kBlockDim + x] = val; | 57 | 3.53M | } else { | 58 | 3.53M | out[val] = y * cx * kBlockDim + x; | 59 | 3.53M | } | 60 | 3.53M | } | 61 | 98.8k | } | 62 | | // Second half | 63 | 98.8k | for (size_t ip = cx * kBlockDim - 1; ip > 0; ip--) { | 64 | 94.6k | size_t i = ip - 1; | 65 | 4.71M | for (size_t j = 0; j <= i; j++) { | 66 | 4.62M | size_t x = cx * kBlockDim - 1 - (i - j); | 67 | 4.62M | size_t y = cx * kBlockDim - 1 - j; | 68 | 4.62M | if (i % 2) std::swap(x, y); | 69 | 4.62M | if ((y & xsm) != 0) continue; | 70 | 3.43M | y >>= xss; | 71 | 3.43M | size_t val = cur++; | 72 | 3.43M | if (is_lut) { | 73 | 0 | out[y * cx * kBlockDim + x] = val; | 74 | 3.43M | } else { | 75 | 3.43M | out[val] = y * cx * kBlockDim + x; | 76 | 3.43M | } | 77 | 3.43M | } | 78 | 94.6k | } | 79 | 4.19k | } |
ac_strategy.cc:void jxl::CoeffOrderAndLut<true>(jxl::AcStrategy, unsigned int*) Line | Count | Source | 29 | 501 | static void CoeffOrderAndLut(AcStrategy acs, coeff_order_t* out) { | 30 | 501 | size_t cx = acs.covered_blocks_x(); | 31 | 501 | size_t cy = acs.covered_blocks_y(); | 32 | 501 | CoefficientLayout(&cy, &cx); | 33 | | | 34 | | // CoefficientLayout ensures cx >= cy. | 35 | | // We compute the zigzag order for a cx x cx block, then discard all the | 36 | | // lines that are not multiple of the ratio between cx and cy. | 37 | 501 | size_t xs = cx / cy; | 38 | 501 | size_t xsm = xs - 1; | 39 | 501 | size_t xss = CeilLog2Nonzero(xs); | 40 | | // First half of the block | 41 | 501 | size_t cur = cx * cy; | 42 | 7.64k | for (size_t i = 0; i < cx * kBlockDim; i++) { | 43 | 79.5k | for (size_t j = 0; j <= i; j++) { | 44 | 72.4k | size_t x = j; | 45 | 72.4k | size_t y = i - j; | 46 | 72.4k | if (i % 2) std::swap(x, y); | 47 | 72.4k | if ((y & xsm) != 0) continue; | 48 | 56.0k | y >>= xss; | 49 | 56.0k | size_t val = 0; | 50 | 56.0k | if (x < cx && y < cy) { | 51 | 1.64k | val = y * cx + x; | 52 | 54.4k | } else { | 53 | 54.4k | val = cur++; | 54 | 54.4k | } | 55 | 56.0k | if (is_lut) { | 56 | 56.0k | out[y * cx * kBlockDim + x] = val; | 57 | 56.0k | } else { | 58 | 0 | out[val] = y * cx * kBlockDim + x; | 59 | 0 | } | 60 | 56.0k | } | 61 | 7.14k | } | 62 | | // Second half | 63 | 7.14k | for (size_t ip = cx * kBlockDim - 1; ip > 0; ip--) { | 64 | 6.64k | size_t i = ip - 1; | 65 | 71.9k | for (size_t j = 0; j <= i; j++) { | 66 | 65.2k | size_t x = cx * kBlockDim - 1 - (i - j); | 67 | 65.2k | size_t y = cx * kBlockDim - 1 - j; | 68 | 65.2k | if (i % 2) std::swap(x, y); | 69 | 65.2k | if ((y & xsm) != 0) continue; | 70 | 48.9k | y >>= xss; | 71 | 48.9k | size_t val = cur++; | 72 | 48.9k | if (is_lut) { | 73 | 48.9k | out[y * cx * kBlockDim + x] = val; | 74 | 48.9k | } else { | 75 | 0 | out[val] = y * cx * kBlockDim + x; | 76 | 0 | } | 77 | 48.9k | } | 78 | 6.64k | } | 79 | 501 | } |
|
80 | | |
81 | 4.19k | void AcStrategy::ComputeNaturalCoeffOrder(coeff_order_t* order) const { |
82 | 4.19k | CoeffOrderAndLut</*is_lut=*/false>(*this, order); |
83 | 4.19k | } |
84 | 501 | void AcStrategy::ComputeNaturalCoeffOrderLut(coeff_order_t* lut) const { |
85 | 501 | CoeffOrderAndLut</*is_lut=*/true>(*this, lut); |
86 | 501 | } |
87 | | |
88 | | #if JXL_CXX_LANG < JXL_CXX_17 |
89 | | constexpr size_t AcStrategy::kMaxCoeffBlocks; |
90 | | constexpr size_t AcStrategy::kMaxBlockDim; |
91 | | constexpr size_t AcStrategy::kMaxCoeffArea; |
92 | | #endif |
93 | | |
94 | | StatusOr<AcStrategyImage> AcStrategyImage::Create( |
95 | 26.2k | JxlMemoryManager* memory_manager, size_t xsize, size_t ysize) { |
96 | 26.2k | AcStrategyImage img; |
97 | 26.2k | JXL_ASSIGN_OR_RETURN(img.layers_, |
98 | 26.2k | ImageB::Create(memory_manager, xsize, ysize)); |
99 | 26.2k | img.row_ = img.layers_.Row(0); |
100 | 26.2k | img.stride_ = img.layers_.PixelsPerRow(); |
101 | 26.2k | return img; |
102 | 26.2k | } |
103 | | |
104 | 0 | size_t AcStrategyImage::CountBlocks(AcStrategyType type) const { |
105 | 0 | size_t ret = 0; |
106 | 0 | for (size_t y = 0; y < layers_.ysize(); y++) { |
107 | 0 | const uint8_t* JXL_RESTRICT row = layers_.ConstRow(y); |
108 | 0 | for (size_t x = 0; x < layers_.xsize(); x++) { |
109 | 0 | if (row[x] == ((static_cast<uint8_t>(type) << 1) | 1)) ret++; |
110 | 0 | } |
111 | 0 | } |
112 | 0 | return ret; |
113 | 0 | } |
114 | | |
115 | | } // namespace jxl |