Coverage Report

Created: 2025-06-16 07:00

/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