Coverage Report

Created: 2026-11-12 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/lib/jxl/enc_fast_lossless.cc
Line
Count
Source
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/base/status.h"
7
#ifndef FJXL_SELF_INCLUDE
8
9
#include <assert.h>
10
11
#include <algorithm>
12
#include <array>
13
#include <atomic>
14
#include <cstdint>
15
#include <cstdlib>
16
#include <cstring>
17
#include <limits>
18
#include <memory>
19
#include <vector>
20
21
#include "lib/jxl/enc_fast_lossless.h"
22
23
#if !FJXL_STANDALONE
24
#include "lib/jxl/encode_internal.h"
25
#endif  // FJXL_STANDALONE
26
27
#if defined(__x86_64__) || defined(_M_X64)
28
#define FJXL_ARCH_IS_X86_64 1
29
#else
30
#define FJXL_ARCH_IS_X86_64 0
31
#endif
32
33
#if defined(__i386__) || defined(_M_IX86) || FJXL_ARCH_IS_X86_64
34
#define FJXL_ARCH_IS_X86 1
35
#else
36
#define FJXL_ARCH_IS_X86 0
37
#endif
38
39
#if FJXL_ARCH_IS_X86
40
#if defined(_MSC_VER)
41
#include <intrin.h>
42
#else  // _MSC_VER
43
#include <cpuid.h>
44
#endif  // _MSC_VER
45
#endif  // FJXL_ARCH_IS_X86
46
47
// Enable NEON and AVX2/AVX512 if not asked to do otherwise and the compilers
48
// support it.
49
#if defined(__aarch64__) || defined(_M_ARM64)  // ARCH
50
#include <arm_neon.h>
51
52
#if !defined(FJXL_ENABLE_NEON)
53
#define FJXL_ENABLE_NEON 1
54
#endif  // !defined(FJXL_ENABLE_NEON)
55
56
#elif FJXL_ARCH_IS_X86_64 && !defined(_MSC_VER)  // ARCH
57
#include <immintrin.h>
58
59
// manually add _mm512_cvtsi512_si32 definition if missing
60
// (e.g. with Xcode on macOS Mojave)
61
// copied from gcc 11.1.0 include/avx512fintrin.h line 14367-14373
62
#if defined(__clang__) &&                                           \
63
    ((!defined(__apple_build_version__) && __clang_major__ < 10) || \
64
     (defined(__apple_build_version__) && __apple_build_version__ < 12000032))
65
inline int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
66
_mm512_cvtsi512_si32(__m512i __A) {
67
  __v16si __B = (__v16si)__A;
68
  return __B[0];
69
}
70
#endif
71
72
#if !defined(FJXL_ENABLE_AVX2)
73
#define FJXL_ENABLE_AVX2 1
74
#endif  // !defined(FJXL_ENABLE_AVX2)
75
76
#if !defined(FJXL_ENABLE_AVX512)
77
// On clang-7 or earlier, and gcc-10 or earlier, AVX512 seems broken.
78
#if (defined(__clang__) &&                                             \
79
         (!defined(__apple_build_version__) && __clang_major__ > 7) || \
80
     (defined(__apple_build_version__) &&                              \
81
      __apple_build_version__ > 10010046)) ||                          \
82
    (defined(__GNUC__) && __GNUC__ > 10)
83
#define FJXL_ENABLE_AVX512 1
84
#endif
85
#endif  // !defined(FJXL_ENABLE_AVX512)
86
87
#endif  // ARCH
88
89
#ifdef __CLANGD__
90
#undef FJXL_ENABLE_NEON
91
#undef FJXL_ENABLE_AVX2
92
#undef FJXL_ENABLE_AVX512
93
#endif
94
95
#ifndef FJXL_ENABLE_NEON
96
#define FJXL_ENABLE_NEON 0
97
#endif
98
99
#ifndef FJXL_ENABLE_AVX2
100
#define FJXL_ENABLE_AVX2 0
101
#endif
102
103
#ifndef FJXL_ENABLE_AVX512
104
#define FJXL_ENABLE_AVX512 0
105
#endif
106
107
namespace {
108
109
enum class CpuFeature : uint32_t {
110
  kAVX2 = 0,
111
112
  kAVX512F,
113
  kAVX512VL,
114
  kAVX512CD,
115
  kAVX512BW,
116
117
  kVBMI,
118
  kVBMI2
119
};
120
121
0
constexpr uint32_t CpuFeatureBit(CpuFeature feature) {
122
0
  return 1u << static_cast<uint32_t>(feature);
123
0
}
124
125
#if FJXL_ARCH_IS_X86
126
#if defined(_MSC_VER)
127
void Cpuid(const uint32_t level, const uint32_t count,
128
           std::array<uint32_t, 4>& abcd) {
129
  int regs[4];
130
  __cpuidex(regs, level, count);
131
  for (int i = 0; i < 4; ++i) {
132
    abcd[i] = regs[i];
133
  }
134
}
135
uint32_t ReadXCR0() { return static_cast<uint32_t>(_xgetbv(0)); }
136
#else   // _MSC_VER
137
void Cpuid(const uint32_t level, const uint32_t count,
138
0
           std::array<uint32_t, 4>& abcd) {
139
0
  uint32_t a;
140
0
  uint32_t b;
141
0
  uint32_t c;
142
0
  uint32_t d;
143
0
  __cpuid_count(level, count, a, b, c, d);
144
0
  abcd[0] = a;
145
0
  abcd[1] = b;
146
0
  abcd[2] = c;
147
0
  abcd[3] = d;
148
0
}
149
0
uint32_t ReadXCR0() {
150
0
  uint32_t xcr0;
151
0
  uint32_t xcr0_high;
152
0
  const uint32_t index = 0;
153
0
  asm volatile(".byte 0x0F, 0x01, 0xD0"
154
0
               : "=a"(xcr0), "=d"(xcr0_high)
155
0
               : "c"(index));
156
0
  return xcr0;
157
0
}
158
#endif  // _MSC_VER
159
160
0
uint32_t DetectCpuFeatures() {
161
0
  uint32_t flags = 0;  // return value
162
0
  std::array<uint32_t, 4> abcd;
163
0
  Cpuid(0, 0, abcd);
164
0
  const uint32_t max_level = abcd[0];
165
166
0
  const auto check_bit = [](uint32_t v, uint32_t idx) -> bool {
167
0
    return (v & (1U << idx)) != 0;
168
0
  };
169
170
  // Extended features
171
0
  if (max_level >= 7) {
172
0
    Cpuid(7, 0, abcd);
173
0
    flags |= check_bit(abcd[1], 5) ? CpuFeatureBit(CpuFeature::kAVX2) : 0;
174
175
0
    flags |= check_bit(abcd[1], 16) ? CpuFeatureBit(CpuFeature::kAVX512F) : 0;
176
0
    flags |= check_bit(abcd[1], 28) ? CpuFeatureBit(CpuFeature::kAVX512CD) : 0;
177
0
    flags |= check_bit(abcd[1], 30) ? CpuFeatureBit(CpuFeature::kAVX512BW) : 0;
178
0
    flags |= check_bit(abcd[1], 31) ? CpuFeatureBit(CpuFeature::kAVX512VL) : 0;
179
180
0
    flags |= check_bit(abcd[2], 1) ? CpuFeatureBit(CpuFeature::kVBMI) : 0;
181
0
    flags |= check_bit(abcd[2], 6) ? CpuFeatureBit(CpuFeature::kVBMI2) : 0;
182
0
  }
183
184
0
  Cpuid(1, 0, abcd);
185
0
  const bool os_has_xsave = check_bit(abcd[2], 27);
186
0
  if (os_has_xsave) {
187
0
    const uint32_t xcr0 = ReadXCR0();
188
0
    if (!check_bit(xcr0, 1) || !check_bit(xcr0, 2)) {
189
0
      flags = 0;
190
0
    } else if (!check_bit(xcr0, 5) || !check_bit(xcr0, 6) ||
191
0
               !check_bit(xcr0, 7)) {
192
      // No AVX-512; disable everything but AVX2 if present
193
0
      flags &= CpuFeatureBit(CpuFeature::kAVX2);
194
0
    }
195
0
  }
196
197
0
  return flags;
198
0
}
199
#else   // FJXL_ARCH_IS_X86
200
uint32_t DetectCpuFeatures() { return 0; }
201
#endif  // FJXL_ARCH_IS_X86
202
203
#if defined(_MSC_VER) && !defined(__clang__)
204
#define FJXL_UNUSED
205
#else
206
#define FJXL_UNUSED __attribute__((unused))
207
#endif
208
209
0
FJXL_UNUSED bool HasCpuFeature(CpuFeature feature) {
210
0
  static uint32_t cpu_features = DetectCpuFeatures();
211
0
  return (cpu_features & CpuFeatureBit(feature)) != 0;
212
0
}
213
214
#if defined(_MSC_VER) && !defined(__clang__)
215
#define FJXL_INLINE __forceinline
216
FJXL_INLINE uint32_t FloorLog2(uint32_t v) {
217
  unsigned long index;
218
  _BitScanReverse(&index, v);
219
  return index;
220
}
221
FJXL_INLINE uint32_t CtzNonZero(uint64_t v) {
222
  unsigned long index;
223
  _BitScanForward(&index, v);
224
  return index;
225
}
226
#else
227
#define FJXL_INLINE inline __attribute__((always_inline))
228
0
FJXL_INLINE uint32_t FloorLog2(uint32_t v) {
229
0
  return v ? 31 - __builtin_clz(v) : 0;
230
0
}
231
0
FJXL_UNUSED FJXL_INLINE uint32_t CtzNonZero(uint64_t v) {
232
0
  return __builtin_ctzll(v);
233
0
}
234
#endif
235
236
// Compiles to a memcpy on little-endian systems.
237
0
FJXL_INLINE void StoreLE64(uint8_t* tgt, uint64_t data) {
238
#if (!defined(__BYTE_ORDER__) || (__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__))
239
  for (int i = 0; i < 8; i++) {
240
    tgt[i] = (data >> (i * 8)) & 0xFF;
241
  }
242
#else
243
0
  memcpy(tgt, &data, 8);
244
0
#endif
245
0
}
246
247
FJXL_INLINE size_t AddBits(uint32_t count, uint64_t bits, uint8_t* data_buf,
248
0
                           size_t& bits_in_buffer, uint64_t& bit_buffer) {
249
0
  bit_buffer |= bits << bits_in_buffer;
250
0
  bits_in_buffer += count;
251
0
  StoreLE64(data_buf, bit_buffer);
252
0
  size_t bytes_in_buffer = bits_in_buffer / 8;
253
0
  bits_in_buffer -= bytes_in_buffer * 8;
254
0
  bit_buffer >>= bytes_in_buffer * 8;
255
0
  return bytes_in_buffer;
256
0
}
257
258
struct BitWriter {
259
0
  bool Allocate(size_t maximum_bit_size) {
260
0
    assert(data == nullptr);
261
    // Leave some padding.
262
0
    data.reset(static_cast<uint8_t*>(malloc(maximum_bit_size / 8 + 64)));
263
0
    return data != nullptr;
264
0
  }
265
266
0
  void Write(uint32_t count, uint64_t bits) {
267
0
    bytes_written += AddBits(count, bits, data.get() + bytes_written,
268
0
                             bits_in_buffer, buffer);
269
0
  }
270
271
0
  void ZeroPadToByte() {
272
0
    if (bits_in_buffer != 0) {
273
0
      Write(8 - bits_in_buffer, 0);
274
0
    }
275
0
  }
276
277
  FJXL_INLINE void WriteMultiple(const uint64_t* nbits, const uint64_t* bits,
278
0
                                 size_t n) {
279
    // Necessary because Write() is only guaranteed to work with <=56 bits.
280
    // Trying to SIMD-fy this code results in lower speed (and definitely less
281
    // clarity).
282
0
    {
283
0
      for (size_t i = 0; i < n; i++) {
284
0
        this->buffer |= bits[i] << this->bits_in_buffer;
285
0
        memcpy(this->data.get() + this->bytes_written, &this->buffer, 8);
286
0
        uint64_t shift = 64 - this->bits_in_buffer;
287
0
        this->bits_in_buffer += nbits[i];
288
        // This `if` seems to be faster than using ternaries.
289
0
        if (this->bits_in_buffer >= 64) {
290
0
          uint64_t next_buffer = shift >= 64 ? 0 : bits[i] >> shift;
291
0
          this->buffer = next_buffer;
292
0
          this->bits_in_buffer -= 64;
293
0
          this->bytes_written += 8;
294
0
        }
295
0
      }
296
0
      memcpy(this->data.get() + this->bytes_written, &this->buffer, 8);
297
0
      size_t bytes_in_buffer = this->bits_in_buffer / 8;
298
0
      this->bits_in_buffer -= bytes_in_buffer * 8;
299
0
      this->buffer >>= bytes_in_buffer * 8;
300
0
      this->bytes_written += bytes_in_buffer;
301
0
    }
302
0
  }
303
304
  std::unique_ptr<uint8_t[], void (*)(void*)> data = {nullptr, free};
305
  size_t bytes_written = 0;
306
  size_t bits_in_buffer = 0;
307
  uint64_t buffer = 0;
308
};
309
310
0
size_t SectionSize(const std::array<BitWriter, 4>& group_data) {
311
0
  size_t sz = 0;
312
0
  for (size_t j = 0; j < 4; j++) {
313
0
    const auto& writer = group_data[j];
314
0
    sz += writer.bytes_written * 8 + writer.bits_in_buffer;
315
0
  }
316
0
  sz = (sz + 7) / 8;
317
0
  return sz;
318
0
}
319
320
constexpr size_t kMaxFrameHeaderSize = 5;
321
322
constexpr size_t kGroupSizeOffset[4] = {
323
    static_cast<size_t>(0),
324
    static_cast<size_t>(1024),
325
    static_cast<size_t>(17408),
326
    static_cast<size_t>(4211712),
327
};
328
constexpr size_t kTOCBits[4] = {12, 16, 24, 32};
329
330
0
size_t TOCBucket(size_t group_size) {
331
0
  size_t bucket = 0;
332
0
  while (bucket < 3 && group_size >= kGroupSizeOffset[bucket + 1]) ++bucket;
333
0
  return bucket;
334
0
}
335
336
#if !FJXL_STANDALONE
337
0
size_t TOCSize(const std::vector<size_t>& group_sizes) {
338
0
  size_t toc_bits = 0;
339
0
  for (size_t group_size : group_sizes) {
340
0
    toc_bits += kTOCBits[TOCBucket(group_size)];
341
0
  }
342
0
  return (toc_bits + 7) / 8;
343
0
}
344
345
0
size_t FrameHeaderSize(bool have_alpha, bool is_last) {
346
0
  size_t nbits = 28 + (have_alpha ? 4 : 0) + (is_last ? 0 : 2);
347
0
  return (nbits + 7) / 8;
348
0
}
349
#endif
350
351
void ComputeAcGroupDataOffset(size_t dc_global_size, size_t num_dc_groups,
352
                              size_t num_ac_groups, size_t& min_dc_global_size,
353
0
                              size_t& ac_group_offset) {
354
  // Max AC group size is 768 kB, so max AC group TOC bits is 24.
355
0
  size_t ac_toc_max_bits = num_ac_groups * 24;
356
0
  size_t ac_toc_min_bits = num_ac_groups * 12;
357
0
  size_t max_padding = 1 + (ac_toc_max_bits - ac_toc_min_bits + 7) / 8;
358
0
  min_dc_global_size = dc_global_size;
359
0
  size_t dc_global_bucket = TOCBucket(min_dc_global_size);
360
0
  while (TOCBucket(min_dc_global_size + max_padding) > dc_global_bucket) {
361
0
    dc_global_bucket = TOCBucket(min_dc_global_size + max_padding);
362
0
    min_dc_global_size = kGroupSizeOffset[dc_global_bucket];
363
0
  }
364
0
  assert(TOCBucket(min_dc_global_size) == dc_global_bucket);
365
0
  assert(TOCBucket(min_dc_global_size + max_padding) == dc_global_bucket);
366
0
  size_t max_toc_bits =
367
0
      kTOCBits[dc_global_bucket] + 12 * (1 + num_dc_groups) + ac_toc_max_bits;
368
0
  size_t max_toc_size = (max_toc_bits + 7) / 8;
369
0
  ac_group_offset = kMaxFrameHeaderSize + max_toc_size + min_dc_global_size;
370
0
}
371
372
#if !FJXL_STANDALONE
373
size_t ComputeDcGlobalPadding(const std::vector<size_t>& group_sizes,
374
                              size_t ac_group_data_offset,
375
                              size_t min_dc_global_size, bool have_alpha,
376
0
                              bool is_last) {
377
0
  std::vector<size_t> new_group_sizes = group_sizes;
378
0
  new_group_sizes[0] = min_dc_global_size;
379
0
  size_t toc_size = TOCSize(new_group_sizes);
380
0
  size_t actual_offset =
381
0
      FrameHeaderSize(have_alpha, is_last) + toc_size + group_sizes[0];
382
0
  return ac_group_data_offset - actual_offset;
383
0
}
384
#endif
385
386
constexpr size_t kNumRawSymbols = 19;
387
constexpr size_t kNumLZ77 = 33;
388
constexpr size_t kLZ77CacheSize = 32;
389
390
constexpr size_t kLZ77Offset = 224;
391
constexpr size_t kLZ77MinLength = 7;
392
393
void EncodeHybridUintLZ77(uint32_t value, uint32_t* token, uint32_t* nbits,
394
0
                          uint32_t* bits) {
395
  // 400 config
396
0
  uint32_t n = FloorLog2(value);
397
0
  *token = value < 16 ? value : 16 + n - 4;
398
0
  *nbits = value < 16 ? 0 : n;
399
0
  *bits = value < 16 ? 0 : value - (1 << *nbits);
400
0
}
401
402
struct PrefixCode {
403
  uint8_t raw_nbits[kNumRawSymbols] = {};
404
  uint8_t raw_bits[kNumRawSymbols] = {};
405
406
  uint8_t lz77_nbits[kNumLZ77] = {};
407
  uint16_t lz77_bits[kNumLZ77] = {};
408
409
  uint64_t lz77_cache_bits[kLZ77CacheSize] = {};
410
  uint8_t lz77_cache_nbits[kLZ77CacheSize] = {};
411
412
  size_t numraw;
413
414
0
  static uint16_t BitReverse(size_t nbits, uint16_t bits) {
415
0
    constexpr uint16_t kNibbleLookup[16] = {
416
0
        0b0000, 0b1000, 0b0100, 0b1100, 0b0010, 0b1010, 0b0110, 0b1110,
417
0
        0b0001, 0b1001, 0b0101, 0b1101, 0b0011, 0b1011, 0b0111, 0b1111,
418
0
    };
419
0
    uint16_t rev16 = (kNibbleLookup[bits & 0xF] << 12) |
420
0
                     (kNibbleLookup[(bits >> 4) & 0xF] << 8) |
421
0
                     (kNibbleLookup[(bits >> 8) & 0xF] << 4) |
422
0
                     (kNibbleLookup[bits >> 12]);
423
0
    return rev16 >> (16 - nbits);
424
0
  }
425
426
  // Create the prefix codes given the code lengths.
427
  // Supports the code lengths being split into two halves.
428
  static void ComputeCanonicalCode(const uint8_t* first_chunk_nbits,
429
                                   uint8_t* first_chunk_bits,
430
                                   size_t first_chunk_size,
431
                                   const uint8_t* second_chunk_nbits,
432
                                   uint16_t* second_chunk_bits,
433
0
                                   size_t second_chunk_size) {
434
0
    constexpr size_t kMaxCodeLength = 15;
435
0
    uint8_t code_length_counts[kMaxCodeLength + 1] = {};
436
0
    for (size_t i = 0; i < first_chunk_size; i++) {
437
0
      code_length_counts[first_chunk_nbits[i]]++;
438
0
      assert(first_chunk_nbits[i] <= kMaxCodeLength);
439
0
      assert(first_chunk_nbits[i] <= 8);
440
0
      assert(first_chunk_nbits[i] > 0);
441
0
    }
442
0
    for (size_t i = 0; i < second_chunk_size; i++) {
443
0
      code_length_counts[second_chunk_nbits[i]]++;
444
0
      assert(second_chunk_nbits[i] <= kMaxCodeLength);
445
0
    }
446
447
0
    uint16_t next_code[kMaxCodeLength + 1] = {};
448
449
0
    uint16_t code = 0;
450
0
    for (size_t i = 1; i < kMaxCodeLength + 1; i++) {
451
0
      code = (code + code_length_counts[i - 1]) << 1;
452
0
      next_code[i] = code;
453
0
    }
454
455
0
    for (size_t i = 0; i < first_chunk_size; i++) {
456
0
      first_chunk_bits[i] =
457
0
          BitReverse(first_chunk_nbits[i], next_code[first_chunk_nbits[i]]++);
458
0
    }
459
0
    for (size_t i = 0; i < second_chunk_size; i++) {
460
0
      second_chunk_bits[i] =
461
0
          BitReverse(second_chunk_nbits[i], next_code[second_chunk_nbits[i]]++);
462
0
    }
463
0
  }
464
465
  template <typename T>
466
  static void ComputeCodeLengthsNonZeroImpl(const uint64_t* freqs, size_t n,
467
                                            size_t precision, T infty,
468
                                            const uint8_t* min_limit,
469
                                            const uint8_t* max_limit,
470
0
                                            uint8_t* nbits) {
471
0
    assert(precision < 15);
472
0
    assert(n <= kMaxNumSymbols);
473
0
    std::vector<T> dynp(((1U << precision) + 1) * (n + 1), infty);
474
0
    auto d = [&](size_t sym, size_t off) -> T& {
475
0
      return dynp[sym * ((1 << precision) + 1) + off];
476
0
    };
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::ComputeCodeLengthsNonZeroImpl<unsigned int>(unsigned long const*, unsigned long, unsigned long, unsigned int, unsigned char const*, unsigned char const*, unsigned char*)::{lambda(unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::ComputeCodeLengthsNonZeroImpl<unsigned long>(unsigned long const*, unsigned long, unsigned long, unsigned long, unsigned char const*, unsigned char const*, unsigned char*)::{lambda(unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long) const
477
0
    d(0, 0) = 0;
478
0
    for (size_t sym = 0; sym < n; sym++) {
479
0
      for (T bits = min_limit[sym]; bits <= max_limit[sym]; bits++) {
480
0
        size_t off_delta = 1U << (precision - bits);
481
0
        for (size_t off = 0; off + off_delta <= (1U << precision); off++) {
482
0
          d(sym + 1, off + off_delta) =
483
0
              std::min(d(sym, off) + static_cast<T>(freqs[sym]) * bits,
484
0
                       d(sym + 1, off + off_delta));
485
0
        }
486
0
      }
487
0
    }
488
489
0
    size_t sym = n;
490
0
    size_t off = 1U << precision;
491
492
0
    assert(d(sym, off) != infty);
493
494
0
    while (sym-- > 0) {
495
0
      assert(off > 0);
496
0
      for (size_t bits = min_limit[sym]; bits <= max_limit[sym]; bits++) {
497
0
        size_t off_delta = 1U << (precision - bits);
498
0
        if (off_delta <= off &&
499
0
            d(sym + 1, off) == d(sym, off - off_delta) + freqs[sym] * bits) {
500
0
          off -= off_delta;
501
0
          nbits[sym] = bits;
502
0
          break;
503
0
        }
504
0
      }
505
0
    }
506
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:void (anonymous namespace)::PrefixCode::ComputeCodeLengthsNonZeroImpl<unsigned int>(unsigned long const*, unsigned long, unsigned long, unsigned int, unsigned char const*, unsigned char const*, unsigned char*)
Unexecuted instantiation: enc_fast_lossless.cc:void (anonymous namespace)::PrefixCode::ComputeCodeLengthsNonZeroImpl<unsigned long>(unsigned long const*, unsigned long, unsigned long, unsigned long, unsigned char const*, unsigned char const*, unsigned char*)
507
508
  // Computes nbits[i] for i <= n, subject to min_limit[i] <= nbits[i] <=
509
  // max_limit[i] and sum 2**-nbits[i] == 1, so to minimize sum(nbits[i] *
510
  // freqs[i]).
511
  static void ComputeCodeLengthsNonZero(const uint64_t* freqs, size_t n,
512
                                        uint8_t* min_limit, uint8_t* max_limit,
513
0
                                        uint8_t* nbits) {
514
0
    size_t precision = 0;
515
0
    size_t shortest_length = 255;
516
0
    uint64_t freqsum = 0;
517
0
    for (size_t i = 0; i < n; i++) {
518
0
      assert(freqs[i] != 0);
519
0
      freqsum += freqs[i];
520
0
      if (min_limit[i] < 1) min_limit[i] = 1;
521
0
      assert(min_limit[i] <= max_limit[i]);
522
0
      precision = std::max<size_t>(max_limit[i], precision);
523
0
      shortest_length = std::min<size_t>(min_limit[i], shortest_length);
524
0
    }
525
    // If all the minimum limits are greater than 1, shift precision so that we
526
    // behave as if the shortest was 1.
527
0
    precision -= shortest_length - 1;
528
0
    uint64_t infty = freqsum * precision;
529
0
    if (infty < std::numeric_limits<uint32_t>::max() / 2) {
530
0
      ComputeCodeLengthsNonZeroImpl(freqs, n, precision,
531
0
                                    static_cast<uint32_t>(infty), min_limit,
532
0
                                    max_limit, nbits);
533
0
    } else {
534
0
      ComputeCodeLengthsNonZeroImpl(freqs, n, precision, infty, min_limit,
535
0
                                    max_limit, nbits);
536
0
    }
537
0
  }
538
539
  static constexpr size_t kMaxNumSymbols =
540
      kNumRawSymbols + 1 < kNumLZ77 ? kNumLZ77 : kNumRawSymbols + 1;
541
  static void ComputeCodeLengths(const uint64_t* freqs, size_t n,
542
                                 const uint8_t* min_limit_in,
543
0
                                 const uint8_t* max_limit_in, uint8_t* nbits) {
544
0
    assert(n <= kMaxNumSymbols);
545
0
    uint64_t compact_freqs[kMaxNumSymbols];
546
0
    uint8_t min_limit[kMaxNumSymbols];
547
0
    uint8_t max_limit[kMaxNumSymbols];
548
0
    size_t ni = 0;
549
0
    for (size_t i = 0; i < n; i++) {
550
0
      if (freqs[i]) {
551
0
        compact_freqs[ni] = freqs[i];
552
0
        min_limit[ni] = min_limit_in[i];
553
0
        max_limit[ni] = max_limit_in[i];
554
0
        ni++;
555
0
      }
556
0
    }
557
0
    for (size_t i = ni; i < kMaxNumSymbols; ++i) {
558
0
      compact_freqs[i] = 0;
559
0
      min_limit[i] = 0;
560
0
      max_limit[i] = 0;
561
0
    }
562
0
    uint8_t num_bits[kMaxNumSymbols] = {};
563
0
    ComputeCodeLengthsNonZero(compact_freqs, ni, min_limit, max_limit,
564
0
                              num_bits);
565
0
    ni = 0;
566
0
    for (size_t i = 0; i < n; i++) {
567
0
      nbits[i] = 0;
568
0
      if (freqs[i]) {
569
0
        nbits[i] = num_bits[ni++];
570
0
      }
571
0
    }
572
0
  }
573
574
  // Invalid code, used to construct arrays.
575
0
  PrefixCode() = default;
576
577
  template <typename BitDepth>
578
  PrefixCode(BitDepth /* bitdepth */, uint64_t* raw_counts,
579
0
             uint64_t* lz77_counts) {
580
    // "merge" together all the lz77 counts in a single symbol for the level 1
581
    // table (containing just the raw symbols, up to length 7).
582
0
    uint64_t level1_counts[kNumRawSymbols + 1];
583
0
    memcpy(level1_counts, raw_counts, kNumRawSymbols * sizeof(uint64_t));
584
0
    numraw = kNumRawSymbols;
585
0
    while (numraw > 0 && level1_counts[numraw - 1] == 0) numraw--;
586
587
0
    level1_counts[numraw] = 0;
588
0
    for (size_t i = 0; i < kNumLZ77; i++) {
589
0
      level1_counts[numraw] += lz77_counts[i];
590
0
    }
591
0
    uint8_t level1_nbits[kNumRawSymbols + 1] = {};
592
0
    ComputeCodeLengths(level1_counts, numraw + 1, BitDepth::kMinRawLength,
593
0
                       BitDepth::kMaxRawLength, level1_nbits);
594
595
0
    uint8_t level2_nbits[kNumLZ77] = {};
596
0
    uint8_t min_lengths[kNumLZ77] = {};
597
0
    uint8_t l = 15 - level1_nbits[numraw];
598
0
    uint8_t max_lengths[kNumLZ77];
599
0
    for (uint8_t& max_length : max_lengths) {
600
0
      max_length = l;
601
0
    }
602
0
    size_t num_lz77 = kNumLZ77;
603
0
    while (num_lz77 > 0 && lz77_counts[num_lz77 - 1] == 0) num_lz77--;
604
0
    ComputeCodeLengths(lz77_counts, num_lz77, min_lengths, max_lengths,
605
0
                       level2_nbits);
606
0
    for (size_t i = 0; i < numraw; i++) {
607
0
      raw_nbits[i] = level1_nbits[i];
608
0
    }
609
0
    for (size_t i = 0; i < num_lz77; i++) {
610
0
      lz77_nbits[i] =
611
0
          level2_nbits[i] ? level1_nbits[numraw] + level2_nbits[i] : 0;
612
0
    }
613
614
0
    ComputeCanonicalCode(raw_nbits, raw_bits, numraw, lz77_nbits, lz77_bits,
615
0
                         kNumLZ77);
616
617
    // Prepare lz77 cache
618
0
    for (size_t count = 0; count < kLZ77CacheSize; count++) {
619
0
      unsigned token, nbits, bits;
620
0
      EncodeHybridUintLZ77(count, &token, &nbits, &bits);
621
0
      lz77_cache_nbits[count] = lz77_nbits[token] + nbits + raw_nbits[0];
622
0
      lz77_cache_bits[count] =
623
0
          (((bits << lz77_nbits[token]) | lz77_bits[token]) << raw_nbits[0]) |
624
0
          raw_bits[0];
625
0
    }
626
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::PrefixCode<AVX2::(anonymous namespace)::UpTo8Bits>(AVX2::(anonymous namespace)::UpTo8Bits, unsigned long*, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::PrefixCode<AVX2::(anonymous namespace)::From9To13Bits>(AVX2::(anonymous namespace)::From9To13Bits, unsigned long*, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::PrefixCode<AVX2::(anonymous namespace)::Exactly14Bits>(AVX2::(anonymous namespace)::Exactly14Bits, unsigned long*, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::PrefixCode<AVX2::(anonymous namespace)::MoreThan14Bits>(AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long*, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::PrefixCode<default_implementation::(anonymous namespace)::UpTo8Bits>(default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long*, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::PrefixCode<default_implementation::(anonymous namespace)::From9To13Bits>(default_implementation::(anonymous namespace)::From9To13Bits, unsigned long*, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::PrefixCode<default_implementation::(anonymous namespace)::Exactly14Bits>(default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long*, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:(anonymous namespace)::PrefixCode::PrefixCode<default_implementation::(anonymous namespace)::MoreThan14Bits>(default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long*, unsigned long*)
627
628
  // Max bits written: 2 + 72 + 95 + 24 + 165 = 286
629
0
  void WriteTo(BitWriter* writer) const {
630
0
    uint64_t code_length_counts[18] = {};
631
0
    code_length_counts[17] = 3 + 2 * (kNumLZ77 - 1);
632
0
    for (uint8_t raw_nbit : raw_nbits) {
633
0
      code_length_counts[raw_nbit]++;
634
0
    }
635
0
    for (uint8_t lz77_nbit : lz77_nbits) {
636
0
      code_length_counts[lz77_nbit]++;
637
0
    }
638
0
    uint8_t code_length_nbits[18] = {};
639
0
    uint8_t code_length_nbits_min[18] = {};
640
0
    uint8_t code_length_nbits_max[18] = {
641
0
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
642
0
    };
643
0
    ComputeCodeLengths(code_length_counts, 18, code_length_nbits_min,
644
0
                       code_length_nbits_max, code_length_nbits);
645
0
    writer->Write(2, 0b00);  // HSKIP = 0, i.e. don't skip code lengths.
646
647
    // As per Brotli RFC.
648
0
    uint8_t code_length_order[18] = {1, 2, 3, 4,  0,  5,  17, 6,  16,
649
0
                                     7, 8, 9, 10, 11, 12, 13, 14, 15};
650
0
    uint8_t code_length_length_nbits[] = {2, 4, 3, 2, 2, 4};
651
0
    uint8_t code_length_length_bits[] = {0, 7, 3, 2, 1, 15};
652
653
    // Encode lengths of code lengths.
654
0
    size_t num_code_lengths = 18;
655
0
    while (code_length_nbits[code_length_order[num_code_lengths - 1]] == 0) {
656
0
      num_code_lengths--;
657
0
    }
658
    // Max bits written in this loop: 18 * 4 = 72
659
0
    for (size_t i = 0; i < num_code_lengths; i++) {
660
0
      int symbol = code_length_nbits[code_length_order[i]];
661
0
      writer->Write(code_length_length_nbits[symbol],
662
0
                    code_length_length_bits[symbol]);
663
0
    }
664
665
    // Compute the canonical codes for the codes that represent the lengths of
666
    // the actual codes for data.
667
0
    uint16_t code_length_bits[18] = {};
668
0
    ComputeCanonicalCode(nullptr, nullptr, 0, code_length_nbits,
669
0
                         code_length_bits, 18);
670
    // Encode raw bit code lengths.
671
    // Max bits written in this loop: 19 * 5 = 95
672
0
    for (uint8_t raw_nbit : raw_nbits) {
673
0
      writer->Write(code_length_nbits[raw_nbit], code_length_bits[raw_nbit]);
674
0
    }
675
0
    size_t num_lz77 = kNumLZ77;
676
0
    while (lz77_nbits[num_lz77 - 1] == 0) {
677
0
      num_lz77--;
678
0
    }
679
    // Encode 0s until 224 (start of LZ77 symbols). This is in total 224-19 =
680
    // 205.
681
0
    static_assert(kLZ77Offset == 224, "kLZ77Offset should be 224");
682
0
    static_assert(kNumRawSymbols == 19, "kNumRawSymbols should be 19");
683
0
    {
684
      // Max bits in this block: 24
685
0
      writer->Write(code_length_nbits[17], code_length_bits[17]);
686
0
      writer->Write(3, 0b010);  // 5
687
0
      writer->Write(code_length_nbits[17], code_length_bits[17]);
688
0
      writer->Write(3, 0b000);  // (5-2)*8 + 3 = 27
689
0
      writer->Write(code_length_nbits[17], code_length_bits[17]);
690
0
      writer->Write(3, 0b010);  // (27-2)*8 + 5 = 205
691
0
    }
692
    // Encode LZ77 symbols, with values 224+i.
693
    // Max bits written in this loop: 33 * 5 = 165
694
0
    for (size_t i = 0; i < num_lz77; i++) {
695
0
      writer->Write(code_length_nbits[lz77_nbits[i]],
696
0
                    code_length_bits[lz77_nbits[i]]);
697
0
    }
698
0
  }
699
};
700
701
}  // namespace
702
703
extern "C" {
704
705
struct JxlFastLosslessFrameState {
706
  JxlChunkedFrameInputSource input;
707
  size_t width;
708
  size_t height;
709
  size_t num_groups_x;
710
  size_t num_groups_y;
711
  size_t num_dc_groups_x;
712
  size_t num_dc_groups_y;
713
  size_t nb_chans;
714
  size_t bitdepth;
715
  int big_endian;
716
  int effort;
717
  bool collided;
718
  PrefixCode hcode[4];
719
  std::vector<int16_t> lookup;
720
  BitWriter header;
721
  std::vector<std::array<BitWriter, 4>> group_data;
722
  std::vector<size_t> group_sizes;
723
  size_t ac_group_data_offset = 0;
724
  size_t min_dc_global_size = 0;
725
  size_t current_bit_writer = 0;
726
  size_t bit_writer_byte_pos = 0;
727
  size_t bits_in_buffer = 0;
728
  uint64_t bit_buffer = 0;
729
  bool process_done = false;
730
};
731
732
0
size_t JxlFastLosslessOutputSize(const JxlFastLosslessFrameState* frame) {
733
0
  size_t total_size_groups = 0;
734
0
  for (const auto& section : frame->group_data) {
735
0
    total_size_groups += SectionSize(section);
736
0
  }
737
0
  return frame->header.bytes_written + total_size_groups;
738
0
}
739
740
size_t JxlFastLosslessMaxRequiredOutput(
741
0
    const JxlFastLosslessFrameState* frame) {
742
0
  return JxlFastLosslessOutputSize(frame) + 32;
743
0
}
744
745
bool JxlFastLosslessPrepareHeader(JxlFastLosslessFrameState* frame,
746
0
                                  int add_image_header, int is_last) {
747
0
  BitWriter* output = &frame->header;
748
0
  if (!output->Allocate(1000 + frame->group_sizes.size() * 32)) return false;
749
750
0
  bool have_alpha = (frame->nb_chans == 2 || frame->nb_chans == 4);
751
752
#if FJXL_STANDALONE
753
  if (add_image_header) {
754
    // Signature
755
    output->Write(16, 0x0AFF);
756
757
    // Size header, hand-crafted.
758
    // Not small
759
    output->Write(1, 0);
760
761
    auto wsz = [output](size_t size) {
762
      if (size - 1 < (1 << 9)) {
763
        output->Write(2, 0b00);
764
        output->Write(9, size - 1);
765
      } else if (size - 1 < (1 << 13)) {
766
        output->Write(2, 0b01);
767
        output->Write(13, size - 1);
768
      } else if (size - 1 < (1 << 18)) {
769
        output->Write(2, 0b10);
770
        output->Write(18, size - 1);
771
      } else {
772
        output->Write(2, 0b11);
773
        output->Write(30, size - 1);
774
      }
775
    };
776
777
    wsz(frame->height);
778
779
    // No special ratio.
780
    output->Write(3, 0);
781
782
    wsz(frame->width);
783
784
    // Hand-crafted ImageMetadata.
785
    output->Write(1, 0);  // all_default
786
    output->Write(1, 0);  // extra_fields
787
    output->Write(1, 0);  // bit_depth.floating_point_sample
788
    if (frame->bitdepth == 8) {
789
      output->Write(2, 0b00);  // bit_depth.bits_per_sample = 8
790
    } else if (frame->bitdepth == 10) {
791
      output->Write(2, 0b01);  // bit_depth.bits_per_sample = 10
792
    } else if (frame->bitdepth == 12) {
793
      output->Write(2, 0b10);  // bit_depth.bits_per_sample = 12
794
    } else {
795
      output->Write(2, 0b11);  // 1 + u(6)
796
      output->Write(6, frame->bitdepth - 1);
797
    }
798
    if (frame->bitdepth <= 14) {
799
      output->Write(1, 1);  // 16-bit-buffer sufficient
800
    } else {
801
      output->Write(1, 0);  // 16-bit-buffer NOT sufficient
802
    }
803
    if (have_alpha) {
804
      output->Write(2, 0b01);  // One extra channel
805
      if (frame->bitdepth == 8) {
806
        output->Write(1, 1); // ... all_default (ie. 8-bit alpha)
807
      } else {
808
        output->Write(1, 0); // not d_alpha
809
        output->Write(2, 0); // type = kAlpha
810
        output->Write(1, 0); // not float
811
        if (frame->bitdepth == 10) {
812
          output->Write(2, 0b01); // bit_depth.bits_per_sample = 10
813
        } else if (frame->bitdepth == 12) {
814
          output->Write(2, 0b10); // bit_depth.bits_per_sample = 12
815
        } else {
816
          output->Write(2, 0b11); // 1 + u(6)
817
          output->Write(6, frame->bitdepth - 1);
818
        }
819
        output->Write(2, 0); // dim_shift = 0
820
        output->Write(2, 0); // name_len = 0
821
        output->Write(1, 0); // alpha_associated = 0
822
      }
823
    } else {
824
      output->Write(2, 0b00);  // No extra channel
825
    }
826
    output->Write(1, 0);  // Not XYB
827
    if (frame->nb_chans > 2) {
828
      output->Write(1, 1);  // color_encoding.all_default (sRGB)
829
    } else {
830
      output->Write(1, 0);     // color_encoding.all_default false
831
      output->Write(1, 0);     // color_encoding.want_icc false
832
      output->Write(2, 1);     // grayscale
833
      output->Write(2, 1);     // D65
834
      output->Write(1, 0);     // no gamma transfer function
835
      output->Write(2, 0b10);  // tf: 2 + u(4)
836
      output->Write(4, 11);    // tf of sRGB
837
      output->Write(2, 1);     // relative rendering intent
838
    }
839
    output->Write(2, 0b00);  // No extensions.
840
841
    output->Write(1, 1);  // all_default transform data
842
843
    // No ICC, no preview. Frame should start at byte boundary.
844
    output->ZeroPadToByte();
845
  }
846
#else
847
0
  assert(!add_image_header);
848
0
#endif
849
  // Handcrafted frame header.
850
0
  output->Write(1, 0);     // all_default
851
0
  output->Write(2, 0b00);  // regular frame
852
0
  output->Write(1, 1);     // modular
853
0
  output->Write(2, 0b00);  // default flags
854
0
  output->Write(1, 0);     // not YCbCr
855
0
  output->Write(2, 0b00);  // no upsampling
856
0
  if (have_alpha) {
857
0
    output->Write(2, 0b00);  // no alpha upsampling
858
0
  }
859
0
  output->Write(2, 0b01);  // default group size
860
0
  output->Write(2, 0b00);  // exactly one pass
861
0
  output->Write(1, 0);     // no custom size or origin
862
0
  output->Write(2, 0b00);  // kReplace blending mode
863
0
  if (have_alpha) {
864
0
    output->Write(2, 0b00);  // kReplace blending mode for alpha channel
865
0
  }
866
0
  output->Write(1, is_last);  // is_last
867
0
  if (!is_last) {
868
0
    output->Write(2, 0b00);  // can not be saved as reference
869
0
  }
870
0
  output->Write(2, 0b00);  // a frame has no name
871
0
  output->Write(1, 0);     // loop filter is not all_default
872
0
  output->Write(1, 0);     // no gaborish
873
0
  output->Write(2, 0);     // 0 EPF iters
874
0
  output->Write(2, 0b00);  // No LF extensions
875
0
  output->Write(2, 0b00);  // No FH extensions
876
877
0
  output->Write(1, 0);      // No TOC permutation
878
0
  output->ZeroPadToByte();  // TOC is byte-aligned.
879
0
  assert(add_image_header || output->bytes_written <= kMaxFrameHeaderSize);
880
0
  for (size_t group_size : frame->group_sizes) {
881
0
    size_t bucket = TOCBucket(group_size);
882
0
    output->Write(2, bucket);
883
0
    output->Write(kTOCBits[bucket] - 2, group_size - kGroupSizeOffset[bucket]);
884
0
  }
885
0
  output->ZeroPadToByte();  // Groups are byte-aligned.
886
0
  return true;
887
0
}
888
889
#if !FJXL_STANDALONE
890
bool JxlFastLosslessOutputAlignedSection(
891
0
    const BitWriter& bw, JxlEncoderOutputProcessorWrapper* output_processor) {
892
0
  assert(bw.bits_in_buffer == 0);
893
0
  const uint8_t* data = bw.data.get();
894
0
  size_t remaining_len = bw.bytes_written;
895
0
  while (remaining_len > 0) {
896
0
    JXL_ASSIGN_OR_RETURN(auto buffer,
897
0
                         output_processor->GetBuffer(1, remaining_len));
898
0
    size_t n = std::min(buffer.size(), remaining_len);
899
0
    if (n == 0) break;
900
0
    memcpy(buffer.data(), data, n);
901
0
    JXL_RETURN_IF_ERROR(buffer.advance(n));
902
0
    data += n;
903
0
    remaining_len -= n;
904
0
  };
905
0
  return true;
906
0
}
907
908
bool JxlFastLosslessOutputHeaders(
909
    JxlFastLosslessFrameState* frame_state,
910
0
    JxlEncoderOutputProcessorWrapper* output_processor) {
911
0
  JXL_RETURN_IF_ERROR(JxlFastLosslessOutputAlignedSection(frame_state->header,
912
0
                                                          output_processor));
913
0
  JXL_RETURN_IF_ERROR(JxlFastLosslessOutputAlignedSection(
914
0
      frame_state->group_data[0][0], output_processor));
915
0
  return true;
916
0
}
917
#endif
918
919
#if FJXL_ENABLE_AVX512
920
__attribute__((target("avx512vbmi2"))) static size_t AppendBytesWithBitOffset(
921
    const uint8_t* data, size_t n, size_t bit_buffer_nbits,
922
    unsigned char* output, uint64_t& bit_buffer) {
923
  if (n < 128) {
924
    return 0;
925
  }
926
927
  size_t i = 0;
928
  __m512i shift = _mm512_set1_epi64(64 - bit_buffer_nbits);
929
  __m512i carry = _mm512_set1_epi64(bit_buffer << (64 - bit_buffer_nbits));
930
931
  for (; i + 64 <= n; i += 64) {
932
    __m512i current = _mm512_loadu_si512(data + i);
933
    __m512i previous_u64 = _mm512_alignr_epi64(current, carry, 7);
934
    carry = current;
935
    __m512i out = _mm512_shrdv_epi64(previous_u64, current, shift);
936
    _mm512_storeu_si512(output + i, out);
937
  }
938
939
  bit_buffer = data[i - 1] >> (8 - bit_buffer_nbits);
940
941
  return i;
942
}
943
#endif
944
945
size_t JxlFastLosslessWriteOutput(JxlFastLosslessFrameState* frame,
946
0
                                  unsigned char* output, size_t output_size) {
947
0
  assert(output_size >= 32);
948
0
  unsigned char* initial_output = output;
949
0
  size_t (*append_bytes_with_bit_offset)(const uint8_t*, size_t, size_t,
950
0
                                         unsigned char*, uint64_t&) = nullptr;
951
952
#if FJXL_ENABLE_AVX512
953
  if (HasCpuFeature(CpuFeature::kVBMI2)) {
954
    append_bytes_with_bit_offset = AppendBytesWithBitOffset;
955
  }
956
#endif
957
958
0
  while (true) {
959
0
    size_t& cur = frame->current_bit_writer;
960
0
    size_t& bw_pos = frame->bit_writer_byte_pos;
961
0
    if (cur >= 1 + frame->group_data.size() * frame->nb_chans) {
962
0
      return output - initial_output;
963
0
    }
964
0
    if (output_size <= 9) {
965
0
      return output - initial_output;
966
0
    }
967
0
    size_t nbc = frame->nb_chans;
968
0
    const BitWriter& writer =
969
0
        cur == 0 ? frame->header
970
0
                 : frame->group_data[(cur - 1) / nbc][(cur - 1) % nbc];
971
0
    size_t full_byte_count =
972
0
        std::min(output_size - 9, writer.bytes_written - bw_pos);
973
0
    if (frame->bits_in_buffer == 0) {
974
0
      memcpy(output, writer.data.get() + bw_pos, full_byte_count);
975
0
    } else {
976
0
      size_t i = 0;
977
0
      if (append_bytes_with_bit_offset) {
978
0
        i += append_bytes_with_bit_offset(
979
0
            writer.data.get() + bw_pos, full_byte_count, frame->bits_in_buffer,
980
0
            output, frame->bit_buffer);
981
0
      }
982
0
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
983
      // Copy 8 bytes at a time until we reach the border.
984
0
      for (; i + 8 < full_byte_count; i += 8) {
985
0
        uint64_t chunk;
986
0
        memcpy(&chunk, writer.data.get() + bw_pos + i, 8);
987
0
        uint64_t out = frame->bit_buffer | (chunk << frame->bits_in_buffer);
988
0
        memcpy(output + i, &out, 8);
989
0
        frame->bit_buffer = chunk >> (64 - frame->bits_in_buffer);
990
0
      }
991
0
#endif
992
0
      for (; i < full_byte_count; i++) {
993
0
        AddBits(8, writer.data.get()[bw_pos + i], output + i,
994
0
                frame->bits_in_buffer, frame->bit_buffer);
995
0
      }
996
0
    }
997
0
    output += full_byte_count;
998
0
    output_size -= full_byte_count;
999
0
    bw_pos += full_byte_count;
1000
0
    if (bw_pos == writer.bytes_written) {
1001
0
      auto write = [&](size_t num, uint64_t bits) {
1002
0
        size_t n = AddBits(num, bits, output, frame->bits_in_buffer,
1003
0
                           frame->bit_buffer);
1004
0
        output += n;
1005
0
        output_size -= n;
1006
0
      };
1007
0
      if (writer.bits_in_buffer) {
1008
0
        write(writer.bits_in_buffer, writer.buffer);
1009
0
      }
1010
0
      bw_pos = 0;
1011
0
      cur++;
1012
0
      if ((cur - 1) % nbc == 0 && frame->bits_in_buffer != 0) {
1013
0
        write(8 - frame->bits_in_buffer, 0);
1014
0
      }
1015
0
    }
1016
0
  }
1017
0
}
1018
1019
0
void JxlFastLosslessFreeFrameState(JxlFastLosslessFrameState* frame) {
1020
0
  delete frame;
1021
0
}
1022
1023
}  // extern "C"
1024
1025
#endif
1026
1027
#if defined(FJXL_SELF_INCLUDE) || defined(__CLANGD__)
1028
#ifdef __CLANGD__
1029
namespace default_implementation {
1030
#endif
1031
1032
namespace {
1033
1034
template <typename T>
1035
struct VecPair {
1036
  T low;
1037
  T hi;
1038
};
1039
1040
#ifdef FJXL_GENERIC_SIMD
1041
#undef FJXL_GENERIC_SIMD
1042
#endif
1043
1044
#ifdef FJXL_AVX512
1045
#define FJXL_GENERIC_SIMD
1046
struct SIMDVec32;
1047
struct Mask32 {
1048
  __mmask16 mask;
1049
  SIMDVec32 IfThenElse(const SIMDVec32& if_true, const SIMDVec32& if_false);
1050
  size_t CountPrefix() const {
1051
    return CtzNonZero(~uint64_t{_cvtmask16_u32(mask)});
1052
  }
1053
};
1054
1055
struct SIMDVec32 {
1056
  __m512i vec;
1057
1058
  static constexpr size_t kLanes = 16;
1059
1060
  FJXL_INLINE static SIMDVec32 Load(const uint32_t* data) {
1061
    return SIMDVec32{_mm512_loadu_si512((__m512i*)data)};
1062
  }
1063
  FJXL_INLINE void Store(uint32_t* data) {
1064
    _mm512_storeu_si512((__m512i*)data, vec);
1065
  }
1066
  FJXL_INLINE static SIMDVec32 Val(uint32_t v) {
1067
    return SIMDVec32{_mm512_set1_epi32(v)};
1068
  }
1069
  FJXL_INLINE SIMDVec32 ValToToken() const {
1070
    return SIMDVec32{
1071
        _mm512_sub_epi32(_mm512_set1_epi32(32), _mm512_lzcnt_epi32(vec))};
1072
  }
1073
  FJXL_INLINE SIMDVec32 SatSubU(const SIMDVec32& to_subtract) const {
1074
    return SIMDVec32{_mm512_sub_epi32(_mm512_max_epu32(vec, to_subtract.vec),
1075
                                      to_subtract.vec)};
1076
  }
1077
  FJXL_INLINE SIMDVec32 Sub(const SIMDVec32& to_subtract) const {
1078
    return SIMDVec32{_mm512_sub_epi32(vec, to_subtract.vec)};
1079
  }
1080
  FJXL_INLINE SIMDVec32 Add(const SIMDVec32& oth) const {
1081
    return SIMDVec32{_mm512_add_epi32(vec, oth.vec)};
1082
  }
1083
  FJXL_INLINE SIMDVec32 Xor(const SIMDVec32& oth) const {
1084
    return SIMDVec32{_mm512_xor_epi32(vec, oth.vec)};
1085
  }
1086
  FJXL_INLINE Mask32 Eq(const SIMDVec32& oth) const {
1087
    return Mask32{_mm512_cmpeq_epi32_mask(vec, oth.vec)};
1088
  }
1089
  FJXL_INLINE Mask32 Gt(const SIMDVec32& oth) const {
1090
    return Mask32{_mm512_cmpgt_epi32_mask(vec, oth.vec)};
1091
  }
1092
  FJXL_INLINE SIMDVec32 Pow2() const {
1093
    return SIMDVec32{_mm512_sllv_epi32(_mm512_set1_epi32(1), vec)};
1094
  }
1095
  template <size_t i>
1096
  FJXL_INLINE SIMDVec32 SignedShiftRight() const {
1097
    return SIMDVec32{_mm512_srai_epi32(vec, i)};
1098
  }
1099
};
1100
1101
struct SIMDVec16;
1102
1103
struct Mask16 {
1104
  __mmask32 mask;
1105
  SIMDVec16 IfThenElse(const SIMDVec16& if_true, const SIMDVec16& if_false);
1106
  Mask16 And(const Mask16& oth) const {
1107
    return Mask16{_kand_mask32(mask, oth.mask)};
1108
  }
1109
  size_t CountPrefix() const {
1110
    return CtzNonZero(~uint64_t{_cvtmask32_u32(mask)});
1111
  }
1112
};
1113
1114
struct SIMDVec16 {
1115
  __m512i vec;
1116
1117
  static constexpr size_t kLanes = 32;
1118
1119
  FJXL_INLINE static SIMDVec16 Load(const uint16_t* data) {
1120
    return SIMDVec16{_mm512_loadu_si512((__m512i*)data)};
1121
  }
1122
  FJXL_INLINE void Store(uint16_t* data) {
1123
    _mm512_storeu_si512((__m512i*)data, vec);
1124
  }
1125
  FJXL_INLINE static SIMDVec16 Val(uint16_t v) {
1126
    return SIMDVec16{_mm512_set1_epi16(v)};
1127
  }
1128
  FJXL_INLINE static SIMDVec16 FromTwo32(const SIMDVec32& lo,
1129
                                         const SIMDVec32& hi) {
1130
    auto tmp = _mm512_packus_epi32(lo.vec, hi.vec);
1131
    alignas(64) uint64_t perm[8] = {0, 2, 4, 6, 1, 3, 5, 7};
1132
    return SIMDVec16{
1133
        _mm512_permutex2var_epi64(tmp, _mm512_load_si512((__m512i*)perm), tmp)};
1134
  }
1135
1136
  FJXL_INLINE SIMDVec16 ValToToken() const {
1137
    auto c16 = _mm512_set1_epi32(16);
1138
    auto c32 = _mm512_set1_epi32(32);
1139
    auto low16bit = _mm512_set1_epi32(0x0000FFFF);
1140
    auto lzhi =
1141
        _mm512_sub_epi32(c16, _mm512_min_epu32(c16, _mm512_lzcnt_epi32(vec)));
1142
    auto lzlo = _mm512_sub_epi32(
1143
        c32, _mm512_lzcnt_epi32(_mm512_and_si512(low16bit, vec)));
1144
    return SIMDVec16{_mm512_or_si512(lzlo, _mm512_slli_epi32(lzhi, 16))};
1145
  }
1146
1147
  FJXL_INLINE SIMDVec16 SatSubU(const SIMDVec16& to_subtract) const {
1148
    return SIMDVec16{_mm512_subs_epu16(vec, to_subtract.vec)};
1149
  }
1150
  FJXL_INLINE SIMDVec16 Sub(const SIMDVec16& to_subtract) const {
1151
    return SIMDVec16{_mm512_sub_epi16(vec, to_subtract.vec)};
1152
  }
1153
  FJXL_INLINE SIMDVec16 Add(const SIMDVec16& oth) const {
1154
    return SIMDVec16{_mm512_add_epi16(vec, oth.vec)};
1155
  }
1156
  FJXL_INLINE SIMDVec16 Min(const SIMDVec16& oth) const {
1157
    return SIMDVec16{_mm512_min_epu16(vec, oth.vec)};
1158
  }
1159
  FJXL_INLINE Mask16 Eq(const SIMDVec16& oth) const {
1160
    return Mask16{_mm512_cmpeq_epi16_mask(vec, oth.vec)};
1161
  }
1162
  FJXL_INLINE Mask16 Gt(const SIMDVec16& oth) const {
1163
    return Mask16{_mm512_cmpgt_epi16_mask(vec, oth.vec)};
1164
  }
1165
  FJXL_INLINE SIMDVec16 Pow2() const {
1166
    return SIMDVec16{_mm512_sllv_epi16(_mm512_set1_epi16(1), vec)};
1167
  }
1168
  FJXL_INLINE SIMDVec16 Or(const SIMDVec16& oth) const {
1169
    return SIMDVec16{_mm512_or_si512(vec, oth.vec)};
1170
  }
1171
  FJXL_INLINE SIMDVec16 Xor(const SIMDVec16& oth) const {
1172
    return SIMDVec16{_mm512_xor_si512(vec, oth.vec)};
1173
  }
1174
  FJXL_INLINE SIMDVec16 And(const SIMDVec16& oth) const {
1175
    return SIMDVec16{_mm512_and_si512(vec, oth.vec)};
1176
  }
1177
  FJXL_INLINE SIMDVec16 HAdd(const SIMDVec16& oth) const {
1178
    return SIMDVec16{_mm512_srai_epi16(_mm512_add_epi16(vec, oth.vec), 1)};
1179
  }
1180
  FJXL_INLINE SIMDVec16 PrepareForU8Lookup() const {
1181
    return SIMDVec16{_mm512_or_si512(vec, _mm512_set1_epi16(0xFF00))};
1182
  }
1183
  FJXL_INLINE SIMDVec16 U8Lookup(const uint8_t* table) const {
1184
    return SIMDVec16{_mm512_shuffle_epi8(
1185
        _mm512_broadcast_i32x4(_mm_loadu_si128((__m128i*)table)), vec)};
1186
  }
1187
  FJXL_INLINE VecPair<SIMDVec16> Interleave(const SIMDVec16& low) const {
1188
    auto lo = _mm512_unpacklo_epi16(low.vec, vec);
1189
    auto hi = _mm512_unpackhi_epi16(low.vec, vec);
1190
    alignas(64) uint64_t perm1[8] = {0, 1, 8, 9, 2, 3, 10, 11};
1191
    alignas(64) uint64_t perm2[8] = {4, 5, 12, 13, 6, 7, 14, 15};
1192
    return {SIMDVec16{_mm512_permutex2var_epi64(
1193
                lo, _mm512_load_si512((__m512i*)perm1), hi)},
1194
            SIMDVec16{_mm512_permutex2var_epi64(
1195
                lo, _mm512_load_si512((__m512i*)perm2), hi)}};
1196
  }
1197
  FJXL_INLINE VecPair<SIMDVec32> Upcast() const {
1198
    auto lo = _mm512_unpacklo_epi16(vec, _mm512_setzero_si512());
1199
    auto hi = _mm512_unpackhi_epi16(vec, _mm512_setzero_si512());
1200
    alignas(64) uint64_t perm1[8] = {0, 1, 8, 9, 2, 3, 10, 11};
1201
    alignas(64) uint64_t perm2[8] = {4, 5, 12, 13, 6, 7, 14, 15};
1202
    return {SIMDVec32{_mm512_permutex2var_epi64(
1203
                lo, _mm512_load_si512((__m512i*)perm1), hi)},
1204
            SIMDVec32{_mm512_permutex2var_epi64(
1205
                lo, _mm512_load_si512((__m512i*)perm2), hi)}};
1206
  }
1207
  template <size_t i>
1208
  FJXL_INLINE SIMDVec16 SignedShiftRight() const {
1209
    return SIMDVec16{_mm512_srai_epi16(vec, i)};
1210
  }
1211
1212
  static std::array<SIMDVec16, 1> LoadG8(const unsigned char* data) {
1213
    __m256i bytes = _mm256_loadu_si256((__m256i*)data);
1214
    return {SIMDVec16{_mm512_cvtepu8_epi16(bytes)}};
1215
  }
1216
  static std::array<SIMDVec16, 1> LoadG16(const unsigned char* data) {
1217
    return {Load((const uint16_t*)data)};
1218
  }
1219
1220
  static std::array<SIMDVec16, 2> LoadGA8(const unsigned char* data) {
1221
    __m512i bytes = _mm512_loadu_si512((__m512i*)data);
1222
    __m512i gray = _mm512_and_si512(bytes, _mm512_set1_epi16(0xFF));
1223
    __m512i alpha = _mm512_srli_epi16(bytes, 8);
1224
    return {SIMDVec16{gray}, SIMDVec16{alpha}};
1225
  }
1226
  static std::array<SIMDVec16, 2> LoadGA16(const unsigned char* data) {
1227
    __m512i bytes1 = _mm512_loadu_si512((__m512i*)data);
1228
    __m512i bytes2 = _mm512_loadu_si512((__m512i*)(data + 64));
1229
    __m512i g_mask = _mm512_set1_epi32(0xFFFF);
1230
    __m512i permuteidx = _mm512_set_epi64(7, 5, 3, 1, 6, 4, 2, 0);
1231
    __m512i g = _mm512_permutexvar_epi64(
1232
        permuteidx, _mm512_packus_epi32(_mm512_and_si512(bytes1, g_mask),
1233
                                        _mm512_and_si512(bytes2, g_mask)));
1234
    __m512i a = _mm512_permutexvar_epi64(
1235
        permuteidx, _mm512_packus_epi32(_mm512_srli_epi32(bytes1, 16),
1236
                                        _mm512_srli_epi32(bytes2, 16)));
1237
    return {SIMDVec16{g}, SIMDVec16{a}};
1238
  }
1239
1240
  static std::array<SIMDVec16, 3> LoadRGB8(const unsigned char* data) {
1241
    __m512i bytes0 = _mm512_loadu_si512((__m512i*)data);
1242
    __m512i bytes1 =
1243
        _mm512_zextsi256_si512(_mm256_loadu_si256((__m256i*)(data + 64)));
1244
1245
    // 0x7A = element of upper half of second vector = 0 after lookup; still in
1246
    // the upper half once we add 1 or 2.
1247
    uint8_t z = 0x7A;
1248
    __m512i ridx =
1249
        _mm512_set_epi8(z, 93, z, 90, z, 87, z, 84, z, 81, z, 78, z, 75, z, 72,
1250
                        z, 69, z, 66, z, 63, z, 60, z, 57, z, 54, z, 51, z, 48,
1251
                        z, 45, z, 42, z, 39, z, 36, z, 33, z, 30, z, 27, z, 24,
1252
                        z, 21, z, 18, z, 15, z, 12, z, 9, z, 6, z, 3, z, 0);
1253
    __m512i gidx = _mm512_add_epi8(ridx, _mm512_set1_epi8(1));
1254
    __m512i bidx = _mm512_add_epi8(gidx, _mm512_set1_epi8(1));
1255
    __m512i r = _mm512_permutex2var_epi8(bytes0, ridx, bytes1);
1256
    __m512i g = _mm512_permutex2var_epi8(bytes0, gidx, bytes1);
1257
    __m512i b = _mm512_permutex2var_epi8(bytes0, bidx, bytes1);
1258
    return {SIMDVec16{r}, SIMDVec16{g}, SIMDVec16{b}};
1259
  }
1260
  static std::array<SIMDVec16, 3> LoadRGB16(const unsigned char* data) {
1261
    __m512i bytes0 = _mm512_loadu_si512((__m512i*)data);
1262
    __m512i bytes1 = _mm512_loadu_si512((__m512i*)(data + 64));
1263
    __m512i bytes2 = _mm512_loadu_si512((__m512i*)(data + 128));
1264
1265
    __m512i ridx_lo = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 60, 57,
1266
                                       54, 51, 48, 45, 42, 39, 36, 33, 30, 27,
1267
                                       24, 21, 18, 15, 12, 9, 6, 3, 0);
1268
    // -1 is such that when adding 1 or 2, we get the correct index for
1269
    // green/blue.
1270
    __m512i ridx_hi =
1271
        _mm512_set_epi16(29, 26, 23, 20, 17, 14, 11, 8, 5, 2, -1, 0, 0, 0, 0, 0,
1272
                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1273
    __m512i gidx_lo = _mm512_add_epi16(ridx_lo, _mm512_set1_epi16(1));
1274
    __m512i gidx_hi = _mm512_add_epi16(ridx_hi, _mm512_set1_epi16(1));
1275
    __m512i bidx_lo = _mm512_add_epi16(gidx_lo, _mm512_set1_epi16(1));
1276
    __m512i bidx_hi = _mm512_add_epi16(gidx_hi, _mm512_set1_epi16(1));
1277
1278
    __mmask32 rmask = _cvtu32_mask32(0b11111111110000000000000000000000);
1279
    __mmask32 gbmask = _cvtu32_mask32(0b11111111111000000000000000000000);
1280
1281
    __m512i rlo = _mm512_permutex2var_epi16(bytes0, ridx_lo, bytes1);
1282
    __m512i glo = _mm512_permutex2var_epi16(bytes0, gidx_lo, bytes1);
1283
    __m512i blo = _mm512_permutex2var_epi16(bytes0, bidx_lo, bytes1);
1284
    __m512i r = _mm512_mask_permutexvar_epi16(rlo, rmask, ridx_hi, bytes2);
1285
    __m512i g = _mm512_mask_permutexvar_epi16(glo, gbmask, gidx_hi, bytes2);
1286
    __m512i b = _mm512_mask_permutexvar_epi16(blo, gbmask, bidx_hi, bytes2);
1287
    return {SIMDVec16{r}, SIMDVec16{g}, SIMDVec16{b}};
1288
  }
1289
1290
  static std::array<SIMDVec16, 4> LoadRGBA8(const unsigned char* data) {
1291
    __m512i bytes1 = _mm512_loadu_si512((__m512i*)data);
1292
    __m512i bytes2 = _mm512_loadu_si512((__m512i*)(data + 64));
1293
    __m512i rg_mask = _mm512_set1_epi32(0xFFFF);
1294
    __m512i permuteidx = _mm512_set_epi64(7, 5, 3, 1, 6, 4, 2, 0);
1295
    __m512i rg = _mm512_permutexvar_epi64(
1296
        permuteidx, _mm512_packus_epi32(_mm512_and_si512(bytes1, rg_mask),
1297
                                        _mm512_and_si512(bytes2, rg_mask)));
1298
    __m512i b_a = _mm512_permutexvar_epi64(
1299
        permuteidx, _mm512_packus_epi32(_mm512_srli_epi32(bytes1, 16),
1300
                                        _mm512_srli_epi32(bytes2, 16)));
1301
    __m512i r = _mm512_and_si512(rg, _mm512_set1_epi16(0xFF));
1302
    __m512i g = _mm512_srli_epi16(rg, 8);
1303
    __m512i b = _mm512_and_si512(b_a, _mm512_set1_epi16(0xFF));
1304
    __m512i a = _mm512_srli_epi16(b_a, 8);
1305
    return {SIMDVec16{r}, SIMDVec16{g}, SIMDVec16{b}, SIMDVec16{a}};
1306
  }
1307
  static std::array<SIMDVec16, 4> LoadRGBA16(const unsigned char* data) {
1308
    __m512i bytes0 = _mm512_loadu_si512((__m512i*)data);
1309
    __m512i bytes1 = _mm512_loadu_si512((__m512i*)(data + 64));
1310
    __m512i bytes2 = _mm512_loadu_si512((__m512i*)(data + 128));
1311
    __m512i bytes3 = _mm512_loadu_si512((__m512i*)(data + 192));
1312
1313
    auto pack32 = [](__m512i a, __m512i b) {
1314
      __m512i permuteidx = _mm512_set_epi64(7, 5, 3, 1, 6, 4, 2, 0);
1315
      return _mm512_permutexvar_epi64(permuteidx, _mm512_packus_epi32(a, b));
1316
    };
1317
    auto packlow32 = [&pack32](__m512i a, __m512i b) {
1318
      __m512i mask = _mm512_set1_epi32(0xFFFF);
1319
      return pack32(_mm512_and_si512(a, mask), _mm512_and_si512(b, mask));
1320
    };
1321
    auto packhi32 = [&pack32](__m512i a, __m512i b) {
1322
      return pack32(_mm512_srli_epi32(a, 16), _mm512_srli_epi32(b, 16));
1323
    };
1324
1325
    __m512i rb0 = packlow32(bytes0, bytes1);
1326
    __m512i rb1 = packlow32(bytes2, bytes3);
1327
    __m512i ga0 = packhi32(bytes0, bytes1);
1328
    __m512i ga1 = packhi32(bytes2, bytes3);
1329
1330
    __m512i r = packlow32(rb0, rb1);
1331
    __m512i g = packlow32(ga0, ga1);
1332
    __m512i b = packhi32(rb0, rb1);
1333
    __m512i a = packhi32(ga0, ga1);
1334
    return {SIMDVec16{r}, SIMDVec16{g}, SIMDVec16{b}, SIMDVec16{a}};
1335
  }
1336
1337
  void SwapEndian() {
1338
    auto indices = _mm512_broadcast_i32x4(
1339
        _mm_setr_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14));
1340
    vec = _mm512_shuffle_epi8(vec, indices);
1341
  }
1342
};
1343
1344
SIMDVec16 Mask16::IfThenElse(const SIMDVec16& if_true,
1345
                             const SIMDVec16& if_false) {
1346
  return SIMDVec16{_mm512_mask_blend_epi16(mask, if_false.vec, if_true.vec)};
1347
}
1348
1349
SIMDVec32 Mask32::IfThenElse(const SIMDVec32& if_true,
1350
                             const SIMDVec32& if_false) {
1351
  return SIMDVec32{_mm512_mask_blend_epi32(mask, if_false.vec, if_true.vec)};
1352
}
1353
1354
struct Bits64 {
1355
  static constexpr size_t kLanes = 8;
1356
1357
  __m512i nbits;
1358
  __m512i bits;
1359
1360
  FJXL_INLINE void Store(uint64_t* nbits_out, uint64_t* bits_out) {
1361
    _mm512_storeu_si512((__m512i*)nbits_out, nbits);
1362
    _mm512_storeu_si512((__m512i*)bits_out, bits);
1363
  }
1364
};
1365
1366
struct Bits32 {
1367
  __m512i nbits;
1368
  __m512i bits;
1369
1370
  static Bits32 FromRaw(SIMDVec32 nbits, SIMDVec32 bits) {
1371
    return Bits32{nbits.vec, bits.vec};
1372
  }
1373
1374
  Bits64 Merge() const {
1375
    auto nbits_hi32 = _mm512_srli_epi64(nbits, 32);
1376
    auto nbits_lo32 = _mm512_and_si512(nbits, _mm512_set1_epi64(0xFFFFFFFF));
1377
    auto bits_hi32 = _mm512_srli_epi64(bits, 32);
1378
    auto bits_lo32 = _mm512_and_si512(bits, _mm512_set1_epi64(0xFFFFFFFF));
1379
1380
    auto nbits64 = _mm512_add_epi64(nbits_hi32, nbits_lo32);
1381
    auto bits64 =
1382
        _mm512_or_si512(_mm512_sllv_epi64(bits_hi32, nbits_lo32), bits_lo32);
1383
    return Bits64{nbits64, bits64};
1384
  }
1385
1386
  void Interleave(const Bits32& low) {
1387
    bits = _mm512_or_si512(_mm512_sllv_epi32(bits, low.nbits), low.bits);
1388
    nbits = _mm512_add_epi32(nbits, low.nbits);
1389
  }
1390
1391
  void ClipTo(size_t n) {
1392
    n = std::min<size_t>(n, 16);
1393
    constexpr uint32_t kMask[32] = {
1394
        ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u,
1395
        ~0u, ~0u, ~0u, ~0u, ~0u, 0,   0,   0,   0,   0,   0,
1396
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
1397
    };
1398
    __m512i mask = _mm512_loadu_si512((__m512i*)(kMask + 16 - n));
1399
    nbits = _mm512_and_si512(mask, nbits);
1400
    bits = _mm512_and_si512(mask, bits);
1401
  }
1402
  void Skip(size_t n) {
1403
    n = std::min<size_t>(n, 16);
1404
    constexpr uint32_t kMask[32] = {
1405
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
1406
        0,   0,   0,   0,   0,   ~0u, ~0u, ~0u, ~0u, ~0u, ~0u,
1407
        ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u,
1408
    };
1409
    __m512i mask = _mm512_loadu_si512((__m512i*)(kMask + 16 - n));
1410
    nbits = _mm512_and_si512(mask, nbits);
1411
    bits = _mm512_and_si512(mask, bits);
1412
  }
1413
};
1414
1415
struct Bits16 {
1416
  __m512i nbits;
1417
  __m512i bits;
1418
1419
  static Bits16 FromRaw(SIMDVec16 nbits, SIMDVec16 bits) {
1420
    return Bits16{nbits.vec, bits.vec};
1421
  }
1422
1423
  Bits32 Merge() const {
1424
    auto nbits_hi16 = _mm512_srli_epi32(nbits, 16);
1425
    auto nbits_lo16 = _mm512_and_si512(nbits, _mm512_set1_epi32(0xFFFF));
1426
    auto bits_hi16 = _mm512_srli_epi32(bits, 16);
1427
    auto bits_lo16 = _mm512_and_si512(bits, _mm512_set1_epi32(0xFFFF));
1428
1429
    auto nbits32 = _mm512_add_epi32(nbits_hi16, nbits_lo16);
1430
    auto bits32 =
1431
        _mm512_or_si512(_mm512_sllv_epi32(bits_hi16, nbits_lo16), bits_lo16);
1432
    return Bits32{nbits32, bits32};
1433
  }
1434
1435
  void Interleave(const Bits16& low) {
1436
    bits = _mm512_or_si512(_mm512_sllv_epi16(bits, low.nbits), low.bits);
1437
    nbits = _mm512_add_epi16(nbits, low.nbits);
1438
  }
1439
1440
  void ClipTo(size_t n) {
1441
    n = std::min<size_t>(n, 32);
1442
    constexpr uint16_t kMask[64] = {
1443
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1444
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1445
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1446
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1447
        0,      0,      0,      0,      0,      0,      0,      0,
1448
        0,      0,      0,      0,      0,      0,      0,      0,
1449
        0,      0,      0,      0,      0,      0,      0,      0,
1450
        0,      0,      0,      0,      0,      0,      0,      0,
1451
    };
1452
    __m512i mask = _mm512_loadu_si512((__m512i*)(kMask + 32 - n));
1453
    nbits = _mm512_and_si512(mask, nbits);
1454
    bits = _mm512_and_si512(mask, bits);
1455
  }
1456
  void Skip(size_t n) {
1457
    n = std::min<size_t>(n, 32);
1458
    constexpr uint16_t kMask[64] = {
1459
        0,      0,      0,      0,      0,      0,      0,      0,
1460
        0,      0,      0,      0,      0,      0,      0,      0,
1461
        0,      0,      0,      0,      0,      0,      0,      0,
1462
        0,      0,      0,      0,      0,      0,      0,      0,
1463
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1464
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1465
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1466
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1467
    };
1468
    __m512i mask = _mm512_loadu_si512((__m512i*)(kMask + 32 - n));
1469
    nbits = _mm512_and_si512(mask, nbits);
1470
    bits = _mm512_and_si512(mask, bits);
1471
  }
1472
};
1473
1474
#endif
1475
1476
#ifdef FJXL_AVX2
1477
#define FJXL_GENERIC_SIMD
1478
1479
struct SIMDVec32;
1480
1481
struct Mask32 {
1482
  __m256i mask;
1483
  SIMDVec32 IfThenElse(const SIMDVec32& if_true, const SIMDVec32& if_false);
1484
0
  size_t CountPrefix() const {
1485
0
    return CtzNonZero(~static_cast<uint64_t>(
1486
0
        static_cast<uint8_t>(_mm256_movemask_ps(_mm256_castsi256_ps(mask)))));
1487
0
  }
1488
};
1489
1490
struct SIMDVec32 {
1491
  __m256i vec;
1492
1493
  static constexpr size_t kLanes = 8;
1494
1495
0
  FJXL_INLINE static SIMDVec32 Load(const uint32_t* data) {
1496
0
    return SIMDVec32{_mm256_loadu_si256((__m256i*)data)};
1497
0
  }
1498
0
  FJXL_INLINE void Store(uint32_t* data) {
1499
0
    _mm256_storeu_si256((__m256i*)data, vec);
1500
0
  }
1501
0
  FJXL_INLINE static SIMDVec32 Val(uint32_t v) {
1502
0
    return SIMDVec32{_mm256_set1_epi32(v)};
1503
0
  }
1504
0
  FJXL_INLINE SIMDVec32 ValToToken() const {
1505
0
    auto f32 = _mm256_castps_si256(_mm256_cvtepi32_ps(vec));
1506
0
    return SIMDVec32{_mm256_max_epi32(
1507
0
        _mm256_setzero_si256(),
1508
0
        _mm256_sub_epi32(_mm256_srli_epi32(f32, 23), _mm256_set1_epi32(126)))};
1509
0
  }
1510
0
  FJXL_INLINE SIMDVec32 SatSubU(const SIMDVec32& to_subtract) const {
1511
0
    return SIMDVec32{_mm256_sub_epi32(_mm256_max_epu32(vec, to_subtract.vec),
1512
0
                                      to_subtract.vec)};
1513
0
  }
1514
0
  FJXL_INLINE SIMDVec32 Sub(const SIMDVec32& to_subtract) const {
1515
0
    return SIMDVec32{_mm256_sub_epi32(vec, to_subtract.vec)};
1516
0
  }
1517
0
  FJXL_INLINE SIMDVec32 Add(const SIMDVec32& oth) const {
1518
0
    return SIMDVec32{_mm256_add_epi32(vec, oth.vec)};
1519
0
  }
1520
0
  FJXL_INLINE SIMDVec32 Xor(const SIMDVec32& oth) const {
1521
0
    return SIMDVec32{_mm256_xor_si256(vec, oth.vec)};
1522
0
  }
1523
0
  FJXL_INLINE SIMDVec32 Pow2() const {
1524
0
    return SIMDVec32{_mm256_sllv_epi32(_mm256_set1_epi32(1), vec)};
1525
0
  }
1526
0
  FJXL_INLINE Mask32 Eq(const SIMDVec32& oth) const {
1527
0
    return Mask32{_mm256_cmpeq_epi32(vec, oth.vec)};
1528
0
  }
1529
0
  FJXL_INLINE Mask32 Gt(const SIMDVec32& oth) const {
1530
0
    return Mask32{_mm256_cmpgt_epi32(vec, oth.vec)};
1531
0
  }
1532
  template <size_t i>
1533
0
  FJXL_INLINE SIMDVec32 SignedShiftRight() const {
1534
0
    return SIMDVec32{_mm256_srai_epi32(vec, i)};
1535
0
  }
1536
};
1537
1538
struct SIMDVec16;
1539
1540
struct Mask16 {
1541
  __m256i mask;
1542
  SIMDVec16 IfThenElse(const SIMDVec16& if_true, const SIMDVec16& if_false);
1543
0
  Mask16 And(const Mask16& oth) const {
1544
0
    return Mask16{_mm256_and_si256(mask, oth.mask)};
1545
0
  }
1546
0
  size_t CountPrefix() const {
1547
0
    return CtzNonZero(~static_cast<uint64_t>(
1548
0
               static_cast<uint32_t>(_mm256_movemask_epi8(mask)))) /
1549
0
           2;
1550
0
  }
1551
};
1552
1553
struct SIMDVec16 {
1554
  __m256i vec;
1555
1556
  static constexpr size_t kLanes = 16;
1557
1558
0
  FJXL_INLINE static SIMDVec16 Load(const uint16_t* data) {
1559
0
    return SIMDVec16{_mm256_loadu_si256((__m256i*)data)};
1560
0
  }
1561
0
  FJXL_INLINE void Store(uint16_t* data) {
1562
0
    _mm256_storeu_si256((__m256i*)data, vec);
1563
0
  }
1564
0
  FJXL_INLINE static SIMDVec16 Val(uint16_t v) {
1565
0
    return SIMDVec16{_mm256_set1_epi16(v)};
1566
0
  }
1567
  FJXL_INLINE static SIMDVec16 FromTwo32(const SIMDVec32& lo,
1568
0
                                         const SIMDVec32& hi) {
1569
0
    auto tmp = _mm256_packus_epi32(lo.vec, hi.vec);
1570
0
    return SIMDVec16{_mm256_permute4x64_epi64(tmp, 0b11011000)};
1571
0
  }
1572
1573
0
  FJXL_INLINE SIMDVec16 ValToToken() const {
1574
0
    auto nibble0 =
1575
0
        _mm256_or_si256(_mm256_and_si256(vec, _mm256_set1_epi16(0xF)),
1576
0
                        _mm256_set1_epi16(0xFF00));
1577
0
    auto nibble1 = _mm256_or_si256(
1578
0
        _mm256_and_si256(_mm256_srli_epi16(vec, 4), _mm256_set1_epi16(0xF)),
1579
0
        _mm256_set1_epi16(0xFF00));
1580
0
    auto nibble2 = _mm256_or_si256(
1581
0
        _mm256_and_si256(_mm256_srli_epi16(vec, 8), _mm256_set1_epi16(0xF)),
1582
0
        _mm256_set1_epi16(0xFF00));
1583
0
    auto nibble3 =
1584
0
        _mm256_or_si256(_mm256_srli_epi16(vec, 12), _mm256_set1_epi16(0xFF00));
1585
1586
0
    auto lut0 = _mm256_broadcastsi128_si256(
1587
0
        _mm_setr_epi8(0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4));
1588
0
    auto lut1 = _mm256_broadcastsi128_si256(
1589
0
        _mm_setr_epi8(0, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8));
1590
0
    auto lut2 = _mm256_broadcastsi128_si256(_mm_setr_epi8(
1591
0
        0, 9, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12));
1592
0
    auto lut3 = _mm256_broadcastsi128_si256(_mm_setr_epi8(
1593
0
        0, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16));
1594
1595
0
    auto token0 = _mm256_shuffle_epi8(lut0, nibble0);
1596
0
    auto token1 = _mm256_shuffle_epi8(lut1, nibble1);
1597
0
    auto token2 = _mm256_shuffle_epi8(lut2, nibble2);
1598
0
    auto token3 = _mm256_shuffle_epi8(lut3, nibble3);
1599
1600
0
    auto token = _mm256_max_epi16(_mm256_max_epi16(token0, token1),
1601
0
                                  _mm256_max_epi16(token2, token3));
1602
0
    return SIMDVec16{token};
1603
0
  }
1604
1605
0
  FJXL_INLINE SIMDVec16 SatSubU(const SIMDVec16& to_subtract) const {
1606
0
    return SIMDVec16{_mm256_subs_epu16(vec, to_subtract.vec)};
1607
0
  }
1608
0
  FJXL_INLINE SIMDVec16 Sub(const SIMDVec16& to_subtract) const {
1609
0
    return SIMDVec16{_mm256_sub_epi16(vec, to_subtract.vec)};
1610
0
  }
1611
0
  FJXL_INLINE SIMDVec16 Add(const SIMDVec16& oth) const {
1612
0
    return SIMDVec16{_mm256_add_epi16(vec, oth.vec)};
1613
0
  }
1614
0
  FJXL_INLINE SIMDVec16 Min(const SIMDVec16& oth) const {
1615
0
    return SIMDVec16{_mm256_min_epu16(vec, oth.vec)};
1616
0
  }
1617
0
  FJXL_INLINE Mask16 Eq(const SIMDVec16& oth) const {
1618
0
    return Mask16{_mm256_cmpeq_epi16(vec, oth.vec)};
1619
0
  }
1620
0
  FJXL_INLINE Mask16 Gt(const SIMDVec16& oth) const {
1621
0
    return Mask16{_mm256_cmpgt_epi16(vec, oth.vec)};
1622
0
  }
1623
0
  FJXL_INLINE SIMDVec16 Pow2() const {
1624
0
    auto pow2_lo_lut = _mm256_broadcastsi128_si256(
1625
0
        _mm_setr_epi8(1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
1626
0
                      1u << 7, 0, 0, 0, 0, 0, 0, 0, 0));
1627
0
    auto pow2_hi_lut = _mm256_broadcastsi128_si256(
1628
0
        _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1 << 0, 1 << 1, 1 << 2, 1 << 3,
1629
0
                      1 << 4, 1 << 5, 1 << 6, 1u << 7));
1630
1631
0
    auto masked = _mm256_or_si256(vec, _mm256_set1_epi16(0xFF00));
1632
1633
0
    auto pow2_lo = _mm256_shuffle_epi8(pow2_lo_lut, masked);
1634
0
    auto pow2_hi = _mm256_shuffle_epi8(pow2_hi_lut, masked);
1635
1636
0
    auto pow2 = _mm256_or_si256(_mm256_slli_epi16(pow2_hi, 8), pow2_lo);
1637
0
    return SIMDVec16{pow2};
1638
0
  }
1639
0
  FJXL_INLINE SIMDVec16 Or(const SIMDVec16& oth) const {
1640
0
    return SIMDVec16{_mm256_or_si256(vec, oth.vec)};
1641
0
  }
1642
0
  FJXL_INLINE SIMDVec16 Xor(const SIMDVec16& oth) const {
1643
0
    return SIMDVec16{_mm256_xor_si256(vec, oth.vec)};
1644
0
  }
1645
0
  FJXL_INLINE SIMDVec16 And(const SIMDVec16& oth) const {
1646
0
    return SIMDVec16{_mm256_and_si256(vec, oth.vec)};
1647
0
  }
1648
0
  FJXL_INLINE SIMDVec16 HAdd(const SIMDVec16& oth) const {
1649
0
    return SIMDVec16{_mm256_srai_epi16(_mm256_add_epi16(vec, oth.vec), 1)};
1650
0
  }
1651
0
  FJXL_INLINE SIMDVec16 PrepareForU8Lookup() const {
1652
0
    return SIMDVec16{_mm256_or_si256(vec, _mm256_set1_epi16(0xFF00))};
1653
0
  }
1654
0
  FJXL_INLINE SIMDVec16 U8Lookup(const uint8_t* table) const {
1655
0
    return SIMDVec16{_mm256_shuffle_epi8(
1656
0
        _mm256_broadcastsi128_si256(_mm_loadu_si128((__m128i*)table)), vec)};
1657
0
  }
1658
0
  FJXL_INLINE VecPair<SIMDVec16> Interleave(const SIMDVec16& low) const {
1659
0
    auto v02 = _mm256_unpacklo_epi16(low.vec, vec);
1660
0
    auto v13 = _mm256_unpackhi_epi16(low.vec, vec);
1661
0
    return {SIMDVec16{_mm256_permute2x128_si256(v02, v13, 0x20)},
1662
0
            SIMDVec16{_mm256_permute2x128_si256(v02, v13, 0x31)}};
1663
0
  }
1664
0
  FJXL_INLINE VecPair<SIMDVec32> Upcast() const {
1665
0
    auto v02 = _mm256_unpacklo_epi16(vec, _mm256_setzero_si256());
1666
0
    auto v13 = _mm256_unpackhi_epi16(vec, _mm256_setzero_si256());
1667
0
    return {SIMDVec32{_mm256_permute2x128_si256(v02, v13, 0x20)},
1668
0
            SIMDVec32{_mm256_permute2x128_si256(v02, v13, 0x31)}};
1669
0
  }
1670
  template <size_t i>
1671
0
  FJXL_INLINE SIMDVec16 SignedShiftRight() const {
1672
0
    return SIMDVec16{_mm256_srai_epi16(vec, i)};
1673
0
  }
1674
1675
0
  static std::array<SIMDVec16, 1> LoadG8(const unsigned char* data) {
1676
0
    __m128i bytes = _mm_loadu_si128((__m128i*)data);
1677
0
    return {SIMDVec16{_mm256_cvtepu8_epi16(bytes)}};
1678
0
  }
1679
0
  static std::array<SIMDVec16, 1> LoadG16(const unsigned char* data) {
1680
0
    return {Load((const uint16_t*)data)};
1681
0
  }
1682
1683
0
  static std::array<SIMDVec16, 2> LoadGA8(const unsigned char* data) {
1684
0
    __m256i bytes = _mm256_loadu_si256((__m256i*)data);
1685
0
    __m256i gray = _mm256_and_si256(bytes, _mm256_set1_epi16(0xFF));
1686
0
    __m256i alpha = _mm256_srli_epi16(bytes, 8);
1687
0
    return {SIMDVec16{gray}, SIMDVec16{alpha}};
1688
0
  }
1689
0
  static std::array<SIMDVec16, 2> LoadGA16(const unsigned char* data) {
1690
0
    __m256i bytes1 = _mm256_loadu_si256((__m256i*)data);
1691
0
    __m256i bytes2 = _mm256_loadu_si256((__m256i*)(data + 32));
1692
0
    __m256i g_mask = _mm256_set1_epi32(0xFFFF);
1693
0
    __m256i g = _mm256_permute4x64_epi64(
1694
0
        _mm256_packus_epi32(_mm256_and_si256(bytes1, g_mask),
1695
0
                            _mm256_and_si256(bytes2, g_mask)),
1696
0
        0b11011000);
1697
0
    __m256i a = _mm256_permute4x64_epi64(
1698
0
        _mm256_packus_epi32(_mm256_srli_epi32(bytes1, 16),
1699
0
                            _mm256_srli_epi32(bytes2, 16)),
1700
0
        0b11011000);
1701
0
    return {SIMDVec16{g}, SIMDVec16{a}};
1702
0
  }
1703
1704
0
  static std::array<SIMDVec16, 3> LoadRGB8(const unsigned char* data) {
1705
0
    __m128i bytes0 = _mm_loadu_si128((__m128i*)data);
1706
0
    __m128i bytes1 = _mm_loadu_si128((__m128i*)(data + 16));
1707
0
    __m128i bytes2 = _mm_loadu_si128((__m128i*)(data + 32));
1708
1709
0
    __m128i idx =
1710
0
        _mm_setr_epi8(0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13);
1711
1712
0
    __m128i r6b5g5_0 = _mm_shuffle_epi8(bytes0, idx);
1713
0
    __m128i g6r5b5_1 = _mm_shuffle_epi8(bytes1, idx);
1714
0
    __m128i b6g5r5_2 = _mm_shuffle_epi8(bytes2, idx);
1715
1716
0
    __m128i mask010 = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF,
1717
0
                                    0xFF, 0, 0, 0, 0, 0);
1718
0
    __m128i mask001 = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,
1719
0
                                    0xFF, 0xFF, 0xFF);
1720
1721
0
    __m128i b2g2b1 = _mm_blendv_epi8(b6g5r5_2, g6r5b5_1, mask001);
1722
0
    __m128i b2b0b1 = _mm_blendv_epi8(b2g2b1, r6b5g5_0, mask010);
1723
1724
0
    __m128i r0r1b1 = _mm_blendv_epi8(r6b5g5_0, g6r5b5_1, mask010);
1725
0
    __m128i r0r1r2 = _mm_blendv_epi8(r0r1b1, b6g5r5_2, mask001);
1726
1727
0
    __m128i g1r1g0 = _mm_blendv_epi8(g6r5b5_1, r6b5g5_0, mask001);
1728
0
    __m128i g1g2g0 = _mm_blendv_epi8(g1r1g0, b6g5r5_2, mask010);
1729
1730
0
    __m128i g0g1g2 = _mm_alignr_epi8(g1g2g0, g1g2g0, 11);
1731
0
    __m128i b0b1b2 = _mm_alignr_epi8(b2b0b1, b2b0b1, 6);
1732
1733
0
    return {SIMDVec16{_mm256_cvtepu8_epi16(r0r1r2)},
1734
0
            SIMDVec16{_mm256_cvtepu8_epi16(g0g1g2)},
1735
0
            SIMDVec16{_mm256_cvtepu8_epi16(b0b1b2)}};
1736
0
  }
1737
0
  static std::array<SIMDVec16, 3> LoadRGB16(const unsigned char* data) {
1738
0
    auto load_and_split_lohi = [](const unsigned char* data) {
1739
      // LHLHLH...
1740
0
      __m256i bytes = _mm256_loadu_si256((__m256i*)data);
1741
      // L0L0L0...
1742
0
      __m256i lo = _mm256_and_si256(bytes, _mm256_set1_epi16(0xFF));
1743
      // H0H0H0...
1744
0
      __m256i hi = _mm256_srli_epi16(bytes, 8);
1745
      // LLLLLLLLHHHHHHHHLLLLLLLLHHHHHHHH
1746
0
      __m256i packed = _mm256_packus_epi16(lo, hi);
1747
0
      return _mm256_permute4x64_epi64(packed, 0b11011000);
1748
0
    };
1749
0
    __m256i bytes0 = load_and_split_lohi(data);
1750
0
    __m256i bytes1 = load_and_split_lohi(data + 32);
1751
0
    __m256i bytes2 = load_and_split_lohi(data + 64);
1752
1753
0
    __m256i idx = _mm256_broadcastsi128_si256(
1754
0
        _mm_setr_epi8(0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13));
1755
1756
0
    __m256i r6b5g5_0 = _mm256_shuffle_epi8(bytes0, idx);
1757
0
    __m256i g6r5b5_1 = _mm256_shuffle_epi8(bytes1, idx);
1758
0
    __m256i b6g5r5_2 = _mm256_shuffle_epi8(bytes2, idx);
1759
1760
0
    __m256i mask010 = _mm256_broadcastsi128_si256(_mm_setr_epi8(
1761
0
        0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0));
1762
0
    __m256i mask001 = _mm256_broadcastsi128_si256(_mm_setr_epi8(
1763
0
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF));
1764
1765
0
    __m256i b2g2b1 = _mm256_blendv_epi8(b6g5r5_2, g6r5b5_1, mask001);
1766
0
    __m256i b2b0b1 = _mm256_blendv_epi8(b2g2b1, r6b5g5_0, mask010);
1767
1768
0
    __m256i r0r1b1 = _mm256_blendv_epi8(r6b5g5_0, g6r5b5_1, mask010);
1769
0
    __m256i r0r1r2 = _mm256_blendv_epi8(r0r1b1, b6g5r5_2, mask001);
1770
1771
0
    __m256i g1r1g0 = _mm256_blendv_epi8(g6r5b5_1, r6b5g5_0, mask001);
1772
0
    __m256i g1g2g0 = _mm256_blendv_epi8(g1r1g0, b6g5r5_2, mask010);
1773
1774
0
    __m256i g0g1g2 = _mm256_alignr_epi8(g1g2g0, g1g2g0, 11);
1775
0
    __m256i b0b1b2 = _mm256_alignr_epi8(b2b0b1, b2b0b1, 6);
1776
1777
    // Now r0r1r2, g0g1g2, b0b1b2 have the low bytes of the RGB pixels in their
1778
    // lower half, and the high bytes in their upper half.
1779
1780
0
    auto combine_low_hi = [](__m256i v) {
1781
0
      __m128i low = _mm256_extracti128_si256(v, 0);
1782
0
      __m128i hi = _mm256_extracti128_si256(v, 1);
1783
0
      __m256i low16 = _mm256_cvtepu8_epi16(low);
1784
0
      __m256i hi16 = _mm256_cvtepu8_epi16(hi);
1785
0
      return _mm256_or_si256(_mm256_slli_epi16(hi16, 8), low16);
1786
0
    };
1787
1788
0
    return {SIMDVec16{combine_low_hi(r0r1r2)},
1789
0
            SIMDVec16{combine_low_hi(g0g1g2)},
1790
0
            SIMDVec16{combine_low_hi(b0b1b2)}};
1791
0
  }
1792
1793
0
  static std::array<SIMDVec16, 4> LoadRGBA8(const unsigned char* data) {
1794
0
    __m256i bytes1 = _mm256_loadu_si256((__m256i*)data);
1795
0
    __m256i bytes2 = _mm256_loadu_si256((__m256i*)(data + 32));
1796
0
    __m256i rg_mask = _mm256_set1_epi32(0xFFFF);
1797
0
    __m256i rg = _mm256_permute4x64_epi64(
1798
0
        _mm256_packus_epi32(_mm256_and_si256(bytes1, rg_mask),
1799
0
                            _mm256_and_si256(bytes2, rg_mask)),
1800
0
        0b11011000);
1801
0
    __m256i b_a = _mm256_permute4x64_epi64(
1802
0
        _mm256_packus_epi32(_mm256_srli_epi32(bytes1, 16),
1803
0
                            _mm256_srli_epi32(bytes2, 16)),
1804
0
        0b11011000);
1805
0
    __m256i r = _mm256_and_si256(rg, _mm256_set1_epi16(0xFF));
1806
0
    __m256i g = _mm256_srli_epi16(rg, 8);
1807
0
    __m256i b = _mm256_and_si256(b_a, _mm256_set1_epi16(0xFF));
1808
0
    __m256i a = _mm256_srli_epi16(b_a, 8);
1809
0
    return {SIMDVec16{r}, SIMDVec16{g}, SIMDVec16{b}, SIMDVec16{a}};
1810
0
  }
1811
0
  static std::array<SIMDVec16, 4> LoadRGBA16(const unsigned char* data) {
1812
0
    __m256i bytes0 = _mm256_loadu_si256((__m256i*)data);
1813
0
    __m256i bytes1 = _mm256_loadu_si256((__m256i*)(data + 32));
1814
0
    __m256i bytes2 = _mm256_loadu_si256((__m256i*)(data + 64));
1815
0
    __m256i bytes3 = _mm256_loadu_si256((__m256i*)(data + 96));
1816
1817
0
    auto pack32 = [](__m256i a, __m256i b) {
1818
0
      return _mm256_permute4x64_epi64(_mm256_packus_epi32(a, b), 0b11011000);
1819
0
    };
1820
0
    auto packlow32 = [&pack32](__m256i a, __m256i b) {
1821
0
      __m256i mask = _mm256_set1_epi32(0xFFFF);
1822
0
      return pack32(_mm256_and_si256(a, mask), _mm256_and_si256(b, mask));
1823
0
    };
1824
0
    auto packhi32 = [&pack32](__m256i a, __m256i b) {
1825
0
      return pack32(_mm256_srli_epi32(a, 16), _mm256_srli_epi32(b, 16));
1826
0
    };
1827
1828
0
    __m256i rb0 = packlow32(bytes0, bytes1);
1829
0
    __m256i rb1 = packlow32(bytes2, bytes3);
1830
0
    __m256i ga0 = packhi32(bytes0, bytes1);
1831
0
    __m256i ga1 = packhi32(bytes2, bytes3);
1832
1833
0
    __m256i r = packlow32(rb0, rb1);
1834
0
    __m256i g = packlow32(ga0, ga1);
1835
0
    __m256i b = packhi32(rb0, rb1);
1836
0
    __m256i a = packhi32(ga0, ga1);
1837
0
    return {SIMDVec16{r}, SIMDVec16{g}, SIMDVec16{b}, SIMDVec16{a}};
1838
0
  }
1839
1840
0
  void SwapEndian() {
1841
0
    auto indices = _mm256_broadcastsi128_si256(
1842
0
        _mm_setr_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14));
1843
0
    vec = _mm256_shuffle_epi8(vec, indices);
1844
0
  }
1845
};
1846
1847
SIMDVec16 Mask16::IfThenElse(const SIMDVec16& if_true,
1848
0
                             const SIMDVec16& if_false) {
1849
0
  return SIMDVec16{_mm256_blendv_epi8(if_false.vec, if_true.vec, mask)};
1850
0
}
1851
1852
SIMDVec32 Mask32::IfThenElse(const SIMDVec32& if_true,
1853
0
                             const SIMDVec32& if_false) {
1854
0
  return SIMDVec32{_mm256_blendv_epi8(if_false.vec, if_true.vec, mask)};
1855
0
}
1856
1857
struct Bits64 {
1858
  static constexpr size_t kLanes = 4;
1859
1860
  __m256i nbits;
1861
  __m256i bits;
1862
1863
0
  FJXL_INLINE void Store(uint64_t* nbits_out, uint64_t* bits_out) {
1864
0
    _mm256_storeu_si256((__m256i*)nbits_out, nbits);
1865
0
    _mm256_storeu_si256((__m256i*)bits_out, bits);
1866
0
  }
1867
};
1868
1869
struct Bits32 {
1870
  __m256i nbits;
1871
  __m256i bits;
1872
1873
0
  static Bits32 FromRaw(SIMDVec32 nbits, SIMDVec32 bits) {
1874
0
    return Bits32{nbits.vec, bits.vec};
1875
0
  }
1876
1877
0
  Bits64 Merge() const {
1878
0
    auto nbits_hi32 = _mm256_srli_epi64(nbits, 32);
1879
0
    auto nbits_lo32 = _mm256_and_si256(nbits, _mm256_set1_epi64x(0xFFFFFFFF));
1880
0
    auto bits_hi32 = _mm256_srli_epi64(bits, 32);
1881
0
    auto bits_lo32 = _mm256_and_si256(bits, _mm256_set1_epi64x(0xFFFFFFFF));
1882
1883
0
    auto nbits64 = _mm256_add_epi64(nbits_hi32, nbits_lo32);
1884
0
    auto bits64 =
1885
0
        _mm256_or_si256(_mm256_sllv_epi64(bits_hi32, nbits_lo32), bits_lo32);
1886
0
    return Bits64{nbits64, bits64};
1887
0
  }
1888
1889
0
  void Interleave(const Bits32& low) {
1890
0
    bits = _mm256_or_si256(_mm256_sllv_epi32(bits, low.nbits), low.bits);
1891
0
    nbits = _mm256_add_epi32(nbits, low.nbits);
1892
0
  }
1893
1894
0
  void ClipTo(size_t n) {
1895
0
    n = std::min<size_t>(n, 8);
1896
0
    constexpr uint32_t kMask[16] = {
1897
0
        ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, 0, 0, 0, 0, 0, 0, 0, 0,
1898
0
    };
1899
0
    __m256i mask = _mm256_loadu_si256((__m256i*)(kMask + 8 - n));
1900
0
    nbits = _mm256_and_si256(mask, nbits);
1901
0
    bits = _mm256_and_si256(mask, bits);
1902
0
  }
1903
0
  void Skip(size_t n) {
1904
0
    n = std::min<size_t>(n, 8);
1905
0
    constexpr uint32_t kMask[16] = {
1906
0
        0, 0, 0, 0, 0, 0, 0, 0, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u, ~0u,
1907
0
    };
1908
0
    __m256i mask = _mm256_loadu_si256((__m256i*)(kMask + 8 - n));
1909
0
    nbits = _mm256_and_si256(mask, nbits);
1910
0
    bits = _mm256_and_si256(mask, bits);
1911
0
  }
1912
};
1913
1914
struct Bits16 {
1915
  __m256i nbits;
1916
  __m256i bits;
1917
1918
0
  static Bits16 FromRaw(SIMDVec16 nbits, SIMDVec16 bits) {
1919
0
    return Bits16{nbits.vec, bits.vec};
1920
0
  }
1921
1922
0
  Bits32 Merge() const {
1923
0
    auto nbits_hi16 = _mm256_srli_epi32(nbits, 16);
1924
0
    auto nbits_lo16 = _mm256_and_si256(nbits, _mm256_set1_epi32(0xFFFF));
1925
0
    auto bits_hi16 = _mm256_srli_epi32(bits, 16);
1926
0
    auto bits_lo16 = _mm256_and_si256(bits, _mm256_set1_epi32(0xFFFF));
1927
1928
0
    auto nbits32 = _mm256_add_epi32(nbits_hi16, nbits_lo16);
1929
0
    auto bits32 =
1930
0
        _mm256_or_si256(_mm256_sllv_epi32(bits_hi16, nbits_lo16), bits_lo16);
1931
0
    return Bits32{nbits32, bits32};
1932
0
  }
1933
1934
0
  void Interleave(const Bits16& low) {
1935
0
    auto pow2_lo_lut = _mm256_broadcastsi128_si256(
1936
0
        _mm_setr_epi8(1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
1937
0
                      1u << 7, 0, 0, 0, 0, 0, 0, 0, 0));
1938
0
    auto low_nbits_masked =
1939
0
        _mm256_or_si256(low.nbits, _mm256_set1_epi16(0xFF00));
1940
1941
0
    auto bits_shifted = _mm256_mullo_epi16(
1942
0
        bits, _mm256_shuffle_epi8(pow2_lo_lut, low_nbits_masked));
1943
1944
0
    nbits = _mm256_add_epi16(nbits, low.nbits);
1945
0
    bits = _mm256_or_si256(bits_shifted, low.bits);
1946
0
  }
1947
1948
0
  void ClipTo(size_t n) {
1949
0
    n = std::min<size_t>(n, 16);
1950
0
    constexpr uint16_t kMask[32] = {
1951
0
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1952
0
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1953
0
        0,      0,      0,      0,      0,      0,      0,      0,
1954
0
        0,      0,      0,      0,      0,      0,      0,      0,
1955
0
    };
1956
0
    __m256i mask = _mm256_loadu_si256((__m256i*)(kMask + 16 - n));
1957
0
    nbits = _mm256_and_si256(mask, nbits);
1958
0
    bits = _mm256_and_si256(mask, bits);
1959
0
  }
1960
1961
0
  void Skip(size_t n) {
1962
0
    n = std::min<size_t>(n, 16);
1963
0
    constexpr uint16_t kMask[32] = {
1964
0
        0,      0,      0,      0,      0,      0,      0,      0,
1965
0
        0,      0,      0,      0,      0,      0,      0,      0,
1966
0
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1967
0
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1968
0
    };
1969
0
    __m256i mask = _mm256_loadu_si256((__m256i*)(kMask + 16 - n));
1970
0
    nbits = _mm256_and_si256(mask, nbits);
1971
0
    bits = _mm256_and_si256(mask, bits);
1972
0
  }
1973
};
1974
1975
#endif
1976
1977
#ifdef FJXL_NEON
1978
#define FJXL_GENERIC_SIMD
1979
1980
struct SIMDVec32;
1981
1982
struct Mask32 {
1983
  uint32x4_t mask;
1984
  SIMDVec32 IfThenElse(const SIMDVec32& if_true, const SIMDVec32& if_false);
1985
  Mask32 And(const Mask32& oth) const {
1986
    return Mask32{vandq_u32(mask, oth.mask)};
1987
  }
1988
  size_t CountPrefix() const {
1989
    uint32_t val_unset[4] = {0, 1, 2, 3};
1990
    uint32_t val_set[4] = {4, 4, 4, 4};
1991
    uint32x4_t val = vbslq_u32(mask, vld1q_u32(val_set), vld1q_u32(val_unset));
1992
    return vminvq_u32(val);
1993
  }
1994
};
1995
1996
struct SIMDVec32 {
1997
  uint32x4_t vec;
1998
1999
  static constexpr size_t kLanes = 4;
2000
2001
  FJXL_INLINE static SIMDVec32 Load(const uint32_t* data) {
2002
    return SIMDVec32{vld1q_u32(data)};
2003
  }
2004
  FJXL_INLINE void Store(uint32_t* data) { vst1q_u32(data, vec); }
2005
  FJXL_INLINE static SIMDVec32 Val(uint32_t v) {
2006
    return SIMDVec32{vdupq_n_u32(v)};
2007
  }
2008
  FJXL_INLINE SIMDVec32 ValToToken() const {
2009
    return SIMDVec32{vsubq_u32(vdupq_n_u32(32), vclzq_u32(vec))};
2010
  }
2011
  FJXL_INLINE SIMDVec32 SatSubU(const SIMDVec32& to_subtract) const {
2012
    return SIMDVec32{vqsubq_u32(vec, to_subtract.vec)};
2013
  }
2014
  FJXL_INLINE SIMDVec32 Sub(const SIMDVec32& to_subtract) const {
2015
    return SIMDVec32{vsubq_u32(vec, to_subtract.vec)};
2016
  }
2017
  FJXL_INLINE SIMDVec32 Add(const SIMDVec32& oth) const {
2018
    return SIMDVec32{vaddq_u32(vec, oth.vec)};
2019
  }
2020
  FJXL_INLINE SIMDVec32 Xor(const SIMDVec32& oth) const {
2021
    return SIMDVec32{veorq_u32(vec, oth.vec)};
2022
  }
2023
  FJXL_INLINE SIMDVec32 Pow2() const {
2024
    return SIMDVec32{vshlq_u32(vdupq_n_u32(1), vreinterpretq_s32_u32(vec))};
2025
  }
2026
  FJXL_INLINE Mask32 Eq(const SIMDVec32& oth) const {
2027
    return Mask32{vceqq_u32(vec, oth.vec)};
2028
  }
2029
  FJXL_INLINE Mask32 Gt(const SIMDVec32& oth) const {
2030
    return Mask32{
2031
        vcgtq_s32(vreinterpretq_s32_u32(vec), vreinterpretq_s32_u32(oth.vec))};
2032
  }
2033
  template <size_t i>
2034
  FJXL_INLINE SIMDVec32 SignedShiftRight() const {
2035
    return SIMDVec32{
2036
        vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_u32(vec), i))};
2037
  }
2038
};
2039
2040
struct SIMDVec16;
2041
2042
struct Mask16 {
2043
  uint16x8_t mask;
2044
  SIMDVec16 IfThenElse(const SIMDVec16& if_true, const SIMDVec16& if_false);
2045
  Mask16 And(const Mask16& oth) const {
2046
    return Mask16{vandq_u16(mask, oth.mask)};
2047
  }
2048
  size_t CountPrefix() const {
2049
    uint16_t val_unset[8] = {0, 1, 2, 3, 4, 5, 6, 7};
2050
    uint16_t val_set[8] = {8, 8, 8, 8, 8, 8, 8, 8};
2051
    uint16x8_t val = vbslq_u16(mask, vld1q_u16(val_set), vld1q_u16(val_unset));
2052
    return vminvq_u16(val);
2053
  }
2054
};
2055
2056
struct SIMDVec16 {
2057
  uint16x8_t vec;
2058
2059
  static constexpr size_t kLanes = 8;
2060
2061
  FJXL_INLINE static SIMDVec16 Load(const uint16_t* data) {
2062
    return SIMDVec16{vld1q_u16(data)};
2063
  }
2064
  FJXL_INLINE void Store(uint16_t* data) { vst1q_u16(data, vec); }
2065
  FJXL_INLINE static SIMDVec16 Val(uint16_t v) {
2066
    return SIMDVec16{vdupq_n_u16(v)};
2067
  }
2068
  FJXL_INLINE static SIMDVec16 FromTwo32(const SIMDVec32& lo,
2069
                                         const SIMDVec32& hi) {
2070
    return SIMDVec16{vmovn_high_u32(vmovn_u32(lo.vec), hi.vec)};
2071
  }
2072
2073
  FJXL_INLINE SIMDVec16 ValToToken() const {
2074
    return SIMDVec16{vsubq_u16(vdupq_n_u16(16), vclzq_u16(vec))};
2075
  }
2076
  FJXL_INLINE SIMDVec16 SatSubU(const SIMDVec16& to_subtract) const {
2077
    return SIMDVec16{vqsubq_u16(vec, to_subtract.vec)};
2078
  }
2079
  FJXL_INLINE SIMDVec16 Sub(const SIMDVec16& to_subtract) const {
2080
    return SIMDVec16{vsubq_u16(vec, to_subtract.vec)};
2081
  }
2082
  FJXL_INLINE SIMDVec16 Add(const SIMDVec16& oth) const {
2083
    return SIMDVec16{vaddq_u16(vec, oth.vec)};
2084
  }
2085
  FJXL_INLINE SIMDVec16 Min(const SIMDVec16& oth) const {
2086
    return SIMDVec16{vminq_u16(vec, oth.vec)};
2087
  }
2088
  FJXL_INLINE Mask16 Eq(const SIMDVec16& oth) const {
2089
    return Mask16{vceqq_u16(vec, oth.vec)};
2090
  }
2091
  FJXL_INLINE Mask16 Gt(const SIMDVec16& oth) const {
2092
    return Mask16{
2093
        vcgtq_s16(vreinterpretq_s16_u16(vec), vreinterpretq_s16_u16(oth.vec))};
2094
  }
2095
  FJXL_INLINE SIMDVec16 Pow2() const {
2096
    return SIMDVec16{vshlq_u16(vdupq_n_u16(1), vreinterpretq_s16_u16(vec))};
2097
  }
2098
  FJXL_INLINE SIMDVec16 Or(const SIMDVec16& oth) const {
2099
    return SIMDVec16{vorrq_u16(vec, oth.vec)};
2100
  }
2101
  FJXL_INLINE SIMDVec16 Xor(const SIMDVec16& oth) const {
2102
    return SIMDVec16{veorq_u16(vec, oth.vec)};
2103
  }
2104
  FJXL_INLINE SIMDVec16 And(const SIMDVec16& oth) const {
2105
    return SIMDVec16{vandq_u16(vec, oth.vec)};
2106
  }
2107
  FJXL_INLINE SIMDVec16 HAdd(const SIMDVec16& oth) const {
2108
    return SIMDVec16{vhaddq_u16(vec, oth.vec)};
2109
  }
2110
  FJXL_INLINE SIMDVec16 PrepareForU8Lookup() const {
2111
    return SIMDVec16{vorrq_u16(vec, vdupq_n_u16(0xFF00))};
2112
  }
2113
  FJXL_INLINE SIMDVec16 U8Lookup(const uint8_t* table) const {
2114
    uint8x16_t tbl = vld1q_u8(table);
2115
    uint8x16_t indices = vreinterpretq_u8_u16(vec);
2116
    return SIMDVec16{vreinterpretq_u16_u8(vqtbl1q_u8(tbl, indices))};
2117
  }
2118
  FJXL_INLINE VecPair<SIMDVec16> Interleave(const SIMDVec16& low) const {
2119
    return {SIMDVec16{vzip1q_u16(low.vec, vec)},
2120
            SIMDVec16{vzip2q_u16(low.vec, vec)}};
2121
  }
2122
  FJXL_INLINE VecPair<SIMDVec32> Upcast() const {
2123
    uint32x4_t lo = vmovl_u16(vget_low_u16(vec));
2124
    uint32x4_t hi = vmovl_high_u16(vec);
2125
    return {SIMDVec32{lo}, SIMDVec32{hi}};
2126
  }
2127
  template <size_t i>
2128
  FJXL_INLINE SIMDVec16 SignedShiftRight() const {
2129
    return SIMDVec16{
2130
        vreinterpretq_u16_s16(vshrq_n_s16(vreinterpretq_s16_u16(vec), i))};
2131
  }
2132
2133
  static std::array<SIMDVec16, 1> LoadG8(const unsigned char* data) {
2134
    uint8x8_t v = vld1_u8(data);
2135
    return {SIMDVec16{vmovl_u8(v)}};
2136
  }
2137
  static std::array<SIMDVec16, 1> LoadG16(const unsigned char* data) {
2138
    return {Load((const uint16_t*)data)};
2139
  }
2140
2141
  static std::array<SIMDVec16, 2> LoadGA8(const unsigned char* data) {
2142
    uint8x8x2_t v = vld2_u8(data);
2143
    return {SIMDVec16{vmovl_u8(v.val[0])}, SIMDVec16{vmovl_u8(v.val[1])}};
2144
  }
2145
  static std::array<SIMDVec16, 2> LoadGA16(const unsigned char* data) {
2146
    uint16x8x2_t v = vld2q_u16((const uint16_t*)data);
2147
    return {SIMDVec16{v.val[0]}, SIMDVec16{v.val[1]}};
2148
  }
2149
2150
  static std::array<SIMDVec16, 3> LoadRGB8(const unsigned char* data) {
2151
    uint8x8x3_t v = vld3_u8(data);
2152
    return {SIMDVec16{vmovl_u8(v.val[0])}, SIMDVec16{vmovl_u8(v.val[1])},
2153
            SIMDVec16{vmovl_u8(v.val[2])}};
2154
  }
2155
  static std::array<SIMDVec16, 3> LoadRGB16(const unsigned char* data) {
2156
    uint16x8x3_t v = vld3q_u16((const uint16_t*)data);
2157
    return {SIMDVec16{v.val[0]}, SIMDVec16{v.val[1]}, SIMDVec16{v.val[2]}};
2158
  }
2159
2160
  static std::array<SIMDVec16, 4> LoadRGBA8(const unsigned char* data) {
2161
    uint8x8x4_t v = vld4_u8(data);
2162
    return {SIMDVec16{vmovl_u8(v.val[0])}, SIMDVec16{vmovl_u8(v.val[1])},
2163
            SIMDVec16{vmovl_u8(v.val[2])}, SIMDVec16{vmovl_u8(v.val[3])}};
2164
  }
2165
  static std::array<SIMDVec16, 4> LoadRGBA16(const unsigned char* data) {
2166
    uint16x8x4_t v = vld4q_u16((const uint16_t*)data);
2167
    return {SIMDVec16{v.val[0]}, SIMDVec16{v.val[1]}, SIMDVec16{v.val[2]},
2168
            SIMDVec16{v.val[3]}};
2169
  }
2170
2171
  void SwapEndian() {
2172
    vec = vreinterpretq_u16_u8(vrev16q_u8(vreinterpretq_u8_u16(vec)));
2173
  }
2174
};
2175
2176
SIMDVec16 Mask16::IfThenElse(const SIMDVec16& if_true,
2177
                             const SIMDVec16& if_false) {
2178
  return SIMDVec16{vbslq_u16(mask, if_true.vec, if_false.vec)};
2179
}
2180
2181
SIMDVec32 Mask32::IfThenElse(const SIMDVec32& if_true,
2182
                             const SIMDVec32& if_false) {
2183
  return SIMDVec32{vbslq_u32(mask, if_true.vec, if_false.vec)};
2184
}
2185
2186
struct Bits64 {
2187
  static constexpr size_t kLanes = 2;
2188
2189
  uint64x2_t nbits;
2190
  uint64x2_t bits;
2191
2192
  FJXL_INLINE void Store(uint64_t* nbits_out, uint64_t* bits_out) {
2193
    vst1q_u64(nbits_out, nbits);
2194
    vst1q_u64(bits_out, bits);
2195
  }
2196
};
2197
2198
struct Bits32 {
2199
  uint32x4_t nbits;
2200
  uint32x4_t bits;
2201
2202
  static Bits32 FromRaw(SIMDVec32 nbits, SIMDVec32 bits) {
2203
    return Bits32{nbits.vec, bits.vec};
2204
  }
2205
2206
  Bits64 Merge() const {
2207
    // TODO(veluca): can probably be optimized.
2208
    uint64x2_t nbits_lo32 =
2209
        vandq_u64(vreinterpretq_u64_u32(nbits), vdupq_n_u64(0xFFFFFFFF));
2210
    uint64x2_t bits_hi32 =
2211
        vshlq_u64(vshrq_n_u64(vreinterpretq_u64_u32(bits), 32),
2212
                  vreinterpretq_s64_u64(nbits_lo32));
2213
    uint64x2_t bits_lo32 =
2214
        vandq_u64(vreinterpretq_u64_u32(bits), vdupq_n_u64(0xFFFFFFFF));
2215
    uint64x2_t nbits64 =
2216
        vsraq_n_u64(nbits_lo32, vreinterpretq_u64_u32(nbits), 32);
2217
    uint64x2_t bits64 = vorrq_u64(bits_hi32, bits_lo32);
2218
    return Bits64{nbits64, bits64};
2219
  }
2220
2221
  void Interleave(const Bits32& low) {
2222
    bits =
2223
        vorrq_u32(vshlq_u32(bits, vreinterpretq_s32_u32(low.nbits)), low.bits);
2224
    nbits = vaddq_u32(nbits, low.nbits);
2225
  }
2226
2227
  void ClipTo(size_t n) {
2228
    n = std::min<size_t>(n, 4);
2229
    constexpr uint32_t kMask[8] = {
2230
        ~0u, ~0u, ~0u, ~0u, 0, 0, 0, 0,
2231
    };
2232
    uint32x4_t mask = vld1q_u32(kMask + 4 - n);
2233
    nbits = vandq_u32(mask, nbits);
2234
    bits = vandq_u32(mask, bits);
2235
  }
2236
  void Skip(size_t n) {
2237
    n = std::min<size_t>(n, 4);
2238
    constexpr uint32_t kMask[8] = {
2239
        0, 0, 0, 0, ~0u, ~0u, ~0u, ~0u,
2240
    };
2241
    uint32x4_t mask = vld1q_u32(kMask + 4 - n);
2242
    nbits = vandq_u32(mask, nbits);
2243
    bits = vandq_u32(mask, bits);
2244
  }
2245
};
2246
2247
struct Bits16 {
2248
  uint16x8_t nbits;
2249
  uint16x8_t bits;
2250
2251
  static Bits16 FromRaw(SIMDVec16 nbits, SIMDVec16 bits) {
2252
    return Bits16{nbits.vec, bits.vec};
2253
  }
2254
2255
  Bits32 Merge() const {
2256
    // TODO(veluca): can probably be optimized.
2257
    uint32x4_t nbits_lo16 =
2258
        vandq_u32(vreinterpretq_u32_u16(nbits), vdupq_n_u32(0xFFFF));
2259
    uint32x4_t bits_hi16 =
2260
        vshlq_u32(vshrq_n_u32(vreinterpretq_u32_u16(bits), 16),
2261
                  vreinterpretq_s32_u32(nbits_lo16));
2262
    uint32x4_t bits_lo16 =
2263
        vandq_u32(vreinterpretq_u32_u16(bits), vdupq_n_u32(0xFFFF));
2264
    uint32x4_t nbits32 =
2265
        vsraq_n_u32(nbits_lo16, vreinterpretq_u32_u16(nbits), 16);
2266
    uint32x4_t bits32 = vorrq_u32(bits_hi16, bits_lo16);
2267
    return Bits32{nbits32, bits32};
2268
  }
2269
2270
  void Interleave(const Bits16& low) {
2271
    bits =
2272
        vorrq_u16(vshlq_u16(bits, vreinterpretq_s16_u16(low.nbits)), low.bits);
2273
    nbits = vaddq_u16(nbits, low.nbits);
2274
  }
2275
2276
  void ClipTo(size_t n) {
2277
    n = std::min<size_t>(n, 8);
2278
    constexpr uint16_t kMask[16] = {
2279
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
2280
        0,      0,      0,      0,      0,      0,      0,      0,
2281
    };
2282
    uint16x8_t mask = vld1q_u16(kMask + 8 - n);
2283
    nbits = vandq_u16(mask, nbits);
2284
    bits = vandq_u16(mask, bits);
2285
  }
2286
  void Skip(size_t n) {
2287
    n = std::min<size_t>(n, 8);
2288
    constexpr uint16_t kMask[16] = {
2289
        0,      0,      0,      0,      0,      0,      0,      0,
2290
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
2291
    };
2292
    uint16x8_t mask = vld1q_u16(kMask + 8 - n);
2293
    nbits = vandq_u16(mask, nbits);
2294
    bits = vandq_u16(mask, bits);
2295
  }
2296
};
2297
2298
#endif
2299
2300
#ifdef FJXL_GENERIC_SIMD
2301
constexpr size_t SIMDVec32::kLanes;
2302
constexpr size_t SIMDVec16::kLanes;
2303
2304
//  Each of these functions will process SIMDVec16::kLanes worth of values.
2305
2306
FJXL_INLINE void TokenizeSIMD(const uint16_t* residuals, uint16_t* token_out,
2307
0
                              uint16_t* nbits_out, uint16_t* bits_out) {
2308
0
  SIMDVec16 res = SIMDVec16::Load(residuals);
2309
0
  SIMDVec16 token = res.ValToToken();
2310
0
  SIMDVec16 nbits = token.SatSubU(SIMDVec16::Val(1));
2311
0
  SIMDVec16 bits = res.SatSubU(nbits.Pow2());
2312
0
  token.Store(token_out);
2313
0
  nbits.Store(nbits_out);
2314
0
  bits.Store(bits_out);
2315
0
}
2316
2317
FJXL_INLINE void TokenizeSIMD(const uint32_t* residuals, uint16_t* token_out,
2318
0
                              uint32_t* nbits_out, uint32_t* bits_out) {
2319
0
  static_assert(SIMDVec16::kLanes == 2 * SIMDVec32::kLanes,
2320
0
                "There should be twice more 16-bit lanes than 32-bit lanes");
2321
0
  SIMDVec32 res_lo = SIMDVec32::Load(residuals);
2322
0
  SIMDVec32 res_hi = SIMDVec32::Load(residuals + SIMDVec32::kLanes);
2323
0
  SIMDVec32 token_lo = res_lo.ValToToken();
2324
0
  SIMDVec32 token_hi = res_hi.ValToToken();
2325
0
  SIMDVec32 nbits_lo = token_lo.SatSubU(SIMDVec32::Val(1));
2326
0
  SIMDVec32 nbits_hi = token_hi.SatSubU(SIMDVec32::Val(1));
2327
0
  SIMDVec32 bits_lo = res_lo.SatSubU(nbits_lo.Pow2());
2328
0
  SIMDVec32 bits_hi = res_hi.SatSubU(nbits_hi.Pow2());
2329
0
  SIMDVec16 token = SIMDVec16::FromTwo32(token_lo, token_hi);
2330
0
  token.Store(token_out);
2331
0
  nbits_lo.Store(nbits_out);
2332
0
  nbits_hi.Store(nbits_out + SIMDVec32::kLanes);
2333
0
  bits_lo.Store(bits_out);
2334
0
  bits_hi.Store(bits_out + SIMDVec32::kLanes);
2335
0
}
2336
2337
FJXL_INLINE void HuffmanSIMDUpTo13(const uint16_t* tokens,
2338
                                   const uint8_t* raw_nbits_simd,
2339
                                   const uint8_t* raw_bits_simd,
2340
0
                                   uint16_t* nbits_out, uint16_t* bits_out) {
2341
0
  SIMDVec16 tok = SIMDVec16::Load(tokens).PrepareForU8Lookup();
2342
0
  tok.U8Lookup(raw_nbits_simd).Store(nbits_out);
2343
0
  tok.U8Lookup(raw_bits_simd).Store(bits_out);
2344
0
}
2345
2346
FJXL_INLINE void HuffmanSIMD14(const uint16_t* tokens,
2347
                               const uint8_t* raw_nbits_simd,
2348
                               const uint8_t* raw_bits_simd,
2349
0
                               uint16_t* nbits_out, uint16_t* bits_out) {
2350
0
  SIMDVec16 token_cap = SIMDVec16::Val(15);
2351
0
  SIMDVec16 tok = SIMDVec16::Load(tokens);
2352
0
  SIMDVec16 tok_index = tok.Min(token_cap).PrepareForU8Lookup();
2353
0
  SIMDVec16 huff_bits_pre = tok_index.U8Lookup(raw_bits_simd);
2354
  // Set the highest bit when token == 16; the Huffman code is constructed in
2355
  // such a way that the code for token 15 is the same as the code for 16,
2356
  // except for the highest bit.
2357
0
  Mask16 needs_high_bit = tok.Eq(SIMDVec16::Val(16));
2358
0
  SIMDVec16 huff_bits = needs_high_bit.IfThenElse(
2359
0
      huff_bits_pre.Or(SIMDVec16::Val(128)), huff_bits_pre);
2360
0
  huff_bits.Store(bits_out);
2361
0
  tok_index.U8Lookup(raw_nbits_simd).Store(nbits_out);
2362
0
}
2363
2364
FJXL_INLINE void HuffmanSIMDAbove14(const uint16_t* tokens,
2365
                                    const uint8_t* raw_nbits_simd,
2366
                                    const uint8_t* raw_bits_simd,
2367
0
                                    uint16_t* nbits_out, uint16_t* bits_out) {
2368
0
  SIMDVec16 tok = SIMDVec16::Load(tokens);
2369
  // We assume `tok` fits in a *signed* 16-bit integer.
2370
0
  Mask16 above = tok.Gt(SIMDVec16::Val(12));
2371
  // 13, 14 -> 13
2372
  // 15, 16 -> 14
2373
  // 17, 18 -> 15
2374
0
  SIMDVec16 remap_tok = above.IfThenElse(tok.HAdd(SIMDVec16::Val(13)), tok);
2375
0
  SIMDVec16 tok_index = remap_tok.PrepareForU8Lookup();
2376
0
  SIMDVec16 huff_bits_pre = tok_index.U8Lookup(raw_bits_simd);
2377
  // Set the highest bit when token == 14, 16, 18.
2378
0
  Mask16 needs_high_bit = above.And(tok.Eq(tok.And(SIMDVec16::Val(0xFFFE))));
2379
0
  SIMDVec16 huff_bits = needs_high_bit.IfThenElse(
2380
0
      huff_bits_pre.Or(SIMDVec16::Val(128)), huff_bits_pre);
2381
0
  huff_bits.Store(bits_out);
2382
0
  tok_index.U8Lookup(raw_nbits_simd).Store(nbits_out);
2383
0
}
2384
2385
FJXL_INLINE void StoreSIMDUpTo8(const uint16_t* nbits_tok,
2386
                                const uint16_t* bits_tok,
2387
                                const uint16_t* nbits_huff,
2388
                                const uint16_t* bits_huff, size_t n,
2389
0
                                size_t skip, Bits32* bits_out) {
2390
0
  Bits16 bits =
2391
0
      Bits16::FromRaw(SIMDVec16::Load(nbits_tok), SIMDVec16::Load(bits_tok));
2392
0
  Bits16 huff_bits =
2393
0
      Bits16::FromRaw(SIMDVec16::Load(nbits_huff), SIMDVec16::Load(bits_huff));
2394
0
  bits.Interleave(huff_bits);
2395
0
  bits.ClipTo(n);
2396
0
  bits.Skip(skip);
2397
0
  bits_out[0] = bits.Merge();
2398
0
}
2399
2400
// Huffman and raw bits don't necessarily fit in a single u16 here.
2401
FJXL_INLINE void StoreSIMDUpTo14(const uint16_t* nbits_tok,
2402
                                 const uint16_t* bits_tok,
2403
                                 const uint16_t* nbits_huff,
2404
                                 const uint16_t* bits_huff, size_t n,
2405
0
                                 size_t skip, Bits32* bits_out) {
2406
0
  VecPair<SIMDVec16> bits =
2407
0
      SIMDVec16::Load(bits_tok).Interleave(SIMDVec16::Load(bits_huff));
2408
0
  VecPair<SIMDVec16> nbits =
2409
0
      SIMDVec16::Load(nbits_tok).Interleave(SIMDVec16::Load(nbits_huff));
2410
0
  Bits16 low = Bits16::FromRaw(nbits.low, bits.low);
2411
0
  Bits16 hi = Bits16::FromRaw(nbits.hi, bits.hi);
2412
0
  low.ClipTo(2 * n);
2413
0
  low.Skip(2 * skip);
2414
0
  hi.ClipTo(std::max(2 * n, SIMDVec16::kLanes) - SIMDVec16::kLanes);
2415
0
  hi.Skip(std::max(2 * skip, SIMDVec16::kLanes) - SIMDVec16::kLanes);
2416
2417
0
  bits_out[0] = low.Merge();
2418
0
  bits_out[1] = hi.Merge();
2419
0
}
2420
2421
FJXL_INLINE void StoreSIMDAbove14(const uint32_t* nbits_tok,
2422
                                  const uint32_t* bits_tok,
2423
                                  const uint16_t* nbits_huff,
2424
                                  const uint16_t* bits_huff, size_t n,
2425
0
                                  size_t skip, Bits32* bits_out) {
2426
0
  static_assert(SIMDVec16::kLanes == 2 * SIMDVec32::kLanes,
2427
0
                "There should be twice more 16-bit lanes than 32-bit lanes");
2428
0
  Bits32 bits_low =
2429
0
      Bits32::FromRaw(SIMDVec32::Load(nbits_tok), SIMDVec32::Load(bits_tok));
2430
0
  Bits32 bits_hi =
2431
0
      Bits32::FromRaw(SIMDVec32::Load(nbits_tok + SIMDVec32::kLanes),
2432
0
                      SIMDVec32::Load(bits_tok + SIMDVec32::kLanes));
2433
2434
0
  VecPair<SIMDVec32> huff_bits = SIMDVec16::Load(bits_huff).Upcast();
2435
0
  VecPair<SIMDVec32> huff_nbits = SIMDVec16::Load(nbits_huff).Upcast();
2436
2437
0
  Bits32 huff_low = Bits32::FromRaw(huff_nbits.low, huff_bits.low);
2438
0
  Bits32 huff_hi = Bits32::FromRaw(huff_nbits.hi, huff_bits.hi);
2439
2440
0
  bits_low.Interleave(huff_low);
2441
0
  bits_low.ClipTo(n);
2442
0
  bits_low.Skip(skip);
2443
0
  bits_out[0] = bits_low;
2444
0
  bits_hi.Interleave(huff_hi);
2445
0
  bits_hi.ClipTo(std::max(n, SIMDVec32::kLanes) - SIMDVec32::kLanes);
2446
0
  bits_hi.Skip(std::max(skip, SIMDVec32::kLanes) - SIMDVec32::kLanes);
2447
0
  bits_out[1] = bits_hi;
2448
0
}
2449
2450
#ifdef FJXL_AVX512
2451
FJXL_INLINE void StoreToWriterAVX512(const Bits32& bits32, BitWriter& output) {
2452
  __m512i bits = bits32.bits;
2453
  __m512i nbits = bits32.nbits;
2454
2455
  // Insert the leftover bits from the bit buffer at the bottom of the vector
2456
  // and extract the top of the vector.
2457
  uint64_t trail_bits =
2458
      _mm512_cvtsi512_si32(_mm512_alignr_epi32(bits, bits, 15));
2459
  uint64_t trail_nbits =
2460
      _mm512_cvtsi512_si32(_mm512_alignr_epi32(nbits, nbits, 15));
2461
  __m512i lead_bits = _mm512_set1_epi32(output.buffer);
2462
  __m512i lead_nbits = _mm512_set1_epi32(output.bits_in_buffer);
2463
  bits = _mm512_alignr_epi32(bits, lead_bits, 15);
2464
  nbits = _mm512_alignr_epi32(nbits, lead_nbits, 15);
2465
2466
  // Merge 32 -> 64 bits.
2467
  Bits32 b{nbits, bits};
2468
  Bits64 b64 = b.Merge();
2469
  bits = b64.bits;
2470
  nbits = b64.nbits;
2471
2472
  __m512i zero = _mm512_setzero_si512();
2473
2474
  auto sh1 = [zero](__m512i vec) { return _mm512_alignr_epi64(vec, zero, 7); };
2475
  auto sh2 = [zero](__m512i vec) { return _mm512_alignr_epi64(vec, zero, 6); };
2476
  auto sh4 = [zero](__m512i vec) { return _mm512_alignr_epi64(vec, zero, 4); };
2477
2478
  // Compute first-past-end-bit-position.
2479
  __m512i end_intermediate0 = _mm512_add_epi64(nbits, sh1(nbits));
2480
  __m512i end_intermediate1 =
2481
      _mm512_add_epi64(end_intermediate0, sh2(end_intermediate0));
2482
  __m512i end = _mm512_add_epi64(end_intermediate1, sh4(end_intermediate1));
2483
2484
  uint64_t simd_nbits = _mm512_cvtsi512_si32(_mm512_alignr_epi64(end, end, 7));
2485
2486
  // Compute begin-bit-position.
2487
  __m512i begin = _mm512_sub_epi64(end, nbits);
2488
2489
  // Index of the last bit in the chunk, or the end bit if nbits==0.
2490
  __m512i last = _mm512_mask_sub_epi64(
2491
      end, _mm512_cmpneq_epi64_mask(nbits, zero), end, _mm512_set1_epi64(1));
2492
2493
  __m512i lane_offset_mask = _mm512_set1_epi64(63);
2494
2495
  // Starting position of the chunk that each lane will ultimately belong to.
2496
  __m512i chunk_start = _mm512_andnot_si512(lane_offset_mask, last);
2497
2498
  // For all lanes that contain bits belonging to two different 64-bit chunks,
2499
  // compute the number of bits that belong to the first chunk.
2500
  // total # of bits fit in a u16, so we can satsub_u16 here.
2501
  __m512i first_chunk_nbits = _mm512_subs_epu16(chunk_start, begin);
2502
2503
  // Move all the previous-chunk-bits to the previous lane.
2504
  __m512i negnbits = _mm512_sub_epi64(_mm512_set1_epi64(64), first_chunk_nbits);
2505
  __m512i first_chunk_bits =
2506
      _mm512_srlv_epi64(_mm512_sllv_epi64(bits, negnbits), negnbits);
2507
  __m512i first_chunk_bits_down =
2508
      _mm512_alignr_epi32(zero, first_chunk_bits, 2);
2509
  bits = _mm512_srlv_epi64(bits, first_chunk_nbits);
2510
  nbits = _mm512_sub_epi64(nbits, first_chunk_nbits);
2511
  bits = _mm512_or_si512(bits, _mm512_sllv_epi64(first_chunk_bits_down, nbits));
2512
  begin = _mm512_add_epi64(begin, first_chunk_nbits);
2513
2514
  // We now know that every lane should give bits to only one chunk. We can
2515
  // shift the bits and then horizontally-or-reduce them within the same chunk.
2516
  __m512i offset = _mm512_and_si512(begin, lane_offset_mask);
2517
  __m512i aligned_bits = _mm512_sllv_epi64(bits, offset);
2518
  // h-or-reduce within same chunk
2519
  __m512i red0 = _mm512_mask_or_epi64(
2520
      aligned_bits, _mm512_cmpeq_epi64_mask(sh1(chunk_start), chunk_start),
2521
      sh1(aligned_bits), aligned_bits);
2522
  __m512i red1 = _mm512_mask_or_epi64(
2523
      red0, _mm512_cmpeq_epi64_mask(sh2(chunk_start), chunk_start), sh2(red0),
2524
      red0);
2525
  __m512i reduced = _mm512_mask_or_epi64(
2526
      red1, _mm512_cmpeq_epi64_mask(sh4(chunk_start), chunk_start), sh4(red1),
2527
      red1);
2528
  // Extract the highest lane that belongs to each chunk (the lane that ends up
2529
  // with the OR-ed value of all the other lanes of that chunk).
2530
  __m512i next_chunk_start =
2531
      _mm512_alignr_epi32(_mm512_set1_epi64(~0), chunk_start, 2);
2532
  __m512i result = _mm512_maskz_compress_epi64(
2533
      _mm512_cmpneq_epi64_mask(chunk_start, next_chunk_start), reduced);
2534
2535
  _mm512_storeu_si512((__m512i*)(output.data.get() + output.bytes_written),
2536
                      result);
2537
2538
  // Update the bit writer and add the last 32-bit lane.
2539
  // Note that since trail_nbits was at most 32 to begin with, operating on
2540
  // trail_bits does not risk overflowing.
2541
  output.bytes_written += simd_nbits / 8;
2542
  // Here we are implicitly relying on the fact that simd_nbits < 512 to know
2543
  // that the byte of bitreader data we access is initialized. This is
2544
  // guaranteed because the remaining bits in the bitreader buffer are at most
2545
  // 7, so simd_nbits <= 505 always.
2546
  trail_bits = (trail_bits << (simd_nbits % 8)) +
2547
               output.data.get()[output.bytes_written];
2548
  trail_nbits += simd_nbits % 8;
2549
  StoreLE64(output.data.get() + output.bytes_written, trail_bits);
2550
  size_t trail_bytes = trail_nbits / 8;
2551
  output.bits_in_buffer = trail_nbits % 8;
2552
  output.buffer = trail_bits >> (trail_bytes * 8);
2553
  output.bytes_written += trail_bytes;
2554
}
2555
2556
#endif
2557
2558
template <size_t n>
2559
0
FJXL_INLINE void StoreToWriter(const Bits32* bits, BitWriter& output) {
2560
#ifdef FJXL_AVX512
2561
  static_assert(n <= 2, "n should be less or 2 for AVX512");
2562
  StoreToWriterAVX512(bits[0], output);
2563
  if (n == 2) {
2564
    StoreToWriterAVX512(bits[1], output);
2565
  }
2566
  return;
2567
#endif
2568
0
  static_assert(n <= 4, "n should be less or 4");
2569
0
  alignas(64) uint64_t nbits64[Bits64::kLanes * n];
2570
0
  alignas(64) uint64_t bits64[Bits64::kLanes * n];
2571
0
  bits[0].Merge().Store(nbits64, bits64);
2572
0
  if (n > 1) {
2573
0
    bits[1].Merge().Store(nbits64 + Bits64::kLanes, bits64 + Bits64::kLanes);
2574
0
  }
2575
0
  if (n > 2) {
2576
0
    bits[2].Merge().Store(nbits64 + 2 * Bits64::kLanes,
2577
0
                          bits64 + 2 * Bits64::kLanes);
2578
0
  }
2579
0
  if (n > 3) {
2580
0
    bits[3].Merge().Store(nbits64 + 3 * Bits64::kLanes,
2581
0
                          bits64 + 3 * Bits64::kLanes);
2582
0
  }
2583
0
  output.WriteMultiple(nbits64, bits64, Bits64::kLanes * n);
2584
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::StoreToWriter<1ul>(AVX2::(anonymous namespace)::Bits32 const*, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::StoreToWriter<2ul>(AVX2::(anonymous namespace)::Bits32 const*, (anonymous namespace)::BitWriter&)
2585
2586
namespace detail {
2587
template <typename T>
2588
struct IntegerTypes;
2589
2590
template <>
2591
struct IntegerTypes<SIMDVec16> {
2592
  using signed_ = int16_t;
2593
  using unsigned_ = uint16_t;
2594
};
2595
2596
template <>
2597
struct IntegerTypes<SIMDVec32> {
2598
  using signed_ = int32_t;
2599
  using unsigned_ = uint32_t;
2600
};
2601
2602
template <typename T>
2603
struct SIMDType;
2604
2605
template <>
2606
struct SIMDType<int16_t> {
2607
  using type = SIMDVec16;
2608
};
2609
2610
template <>
2611
struct SIMDType<int32_t> {
2612
  using type = SIMDVec32;
2613
};
2614
2615
}  // namespace detail
2616
2617
template <typename T>
2618
using signed_t = typename detail::IntegerTypes<T>::signed_;
2619
2620
template <typename T>
2621
using unsigned_t = typename detail::IntegerTypes<T>::unsigned_;
2622
2623
template <typename T>
2624
using simd_t = typename detail::SIMDType<T>::type;
2625
2626
// This function will process exactly one vector worth of pixels.
2627
2628
template <typename T>
2629
size_t PredictPixels(const signed_t<T>* pixels, const signed_t<T>* pixels_left,
2630
                     const signed_t<T>* pixels_top,
2631
                     const signed_t<T>* pixels_topleft,
2632
0
                     unsigned_t<T>* residuals) {
2633
0
  T px = T::Load((unsigned_t<T>*)pixels);
2634
0
  T left = T::Load((unsigned_t<T>*)pixels_left);
2635
0
  T top = T::Load((unsigned_t<T>*)pixels_top);
2636
0
  T topleft = T::Load((unsigned_t<T>*)pixels_topleft);
2637
0
  T ac = left.Sub(topleft);
2638
0
  T ab = left.Sub(top);
2639
0
  T bc = top.Sub(topleft);
2640
0
  T grad = ac.Add(top);
2641
0
  T d = ab.Xor(bc);
2642
0
  T zero = T::Val(0);
2643
0
  T clamp = zero.Gt(d).IfThenElse(top, left);
2644
0
  T s = ac.Xor(bc);
2645
0
  T pred = zero.Gt(s).IfThenElse(grad, clamp);
2646
0
  T res = px.Sub(pred);
2647
0
  T res_times_2 = res.Add(res);
2648
0
  res = zero.Gt(res).IfThenElse(T::Val(-1).Sub(res_times_2), res_times_2);
2649
0
  res.Store(residuals);
2650
0
  return res.Eq(T::Val(0)).CountPrefix();
2651
0
}
Unexecuted instantiation: enc_fast_lossless.cc:unsigned long AVX2::(anonymous namespace)::PredictPixels<AVX2::(anonymous namespace)::SIMDVec16>(AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec16>::signed_ const*, AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec16>::signed_ const*, AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec16>::signed_ const*, AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec16>::signed_ const*, AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec16>::unsigned_*)
Unexecuted instantiation: enc_fast_lossless.cc:unsigned long AVX2::(anonymous namespace)::PredictPixels<AVX2::(anonymous namespace)::SIMDVec32>(AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec32>::signed_ const*, AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec32>::signed_ const*, AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec32>::signed_ const*, AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec32>::signed_ const*, AVX2::(anonymous namespace)::detail::IntegerTypes<AVX2::(anonymous namespace)::SIMDVec32>::unsigned_*)
2652
2653
#endif
2654
2655
void EncodeHybridUint000(uint32_t value, uint32_t* token, uint32_t* nbits,
2656
0
                         uint32_t* bits) {
2657
0
  uint32_t n = FloorLog2(value);
2658
0
  *token = value ? n + 1 : 0;
2659
0
  *nbits = value ? n : 0;
2660
0
  *bits = value ? value - (1 << n) : 0;
2661
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::EncodeHybridUint000(unsigned int, unsigned int*, unsigned int*, unsigned int*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::EncodeHybridUint000(unsigned int, unsigned int*, unsigned int*, unsigned int*)
2662
2663
#ifdef FJXL_AVX512
2664
constexpr static size_t kLogChunkSize = 5;
2665
#elif defined(FJXL_AVX2) || defined(FJXL_NEON)
2666
// Even if NEON only has 128-bit lanes, it is still significantly (~1.3x) faster
2667
// to process two vectors at a time.
2668
constexpr static size_t kLogChunkSize = 4;
2669
#else
2670
constexpr static size_t kLogChunkSize = 3;
2671
#endif
2672
2673
constexpr static size_t kChunkSize = 1 << kLogChunkSize;
2674
2675
template <typename Residual>
2676
void GenericEncodeChunk(const Residual* residuals, size_t n, size_t skip,
2677
0
                        const PrefixCode& code, BitWriter& output) {
2678
0
  for (size_t ix = skip; ix < n; ix++) {
2679
0
    unsigned token, nbits, bits;
2680
0
    EncodeHybridUint000(residuals[ix], &token, &nbits, &bits);
2681
0
    output.Write(code.raw_nbits[token] + nbits,
2682
0
                 code.raw_bits[token] | bits << code.raw_nbits[token]);
2683
0
  }
2684
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::GenericEncodeChunk<unsigned short>(unsigned short const*, unsigned long, unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::GenericEncodeChunk<unsigned int>(unsigned int const*, unsigned long, unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
2685
2686
struct UpTo8Bits {
2687
  size_t bitdepth;
2688
0
  explicit UpTo8Bits(size_t bitdepth) : bitdepth(bitdepth) {
2689
0
    assert(bitdepth <= 8);
2690
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::UpTo8Bits::UpTo8Bits(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::UpTo8Bits::UpTo8Bits(unsigned long)
2691
  // Here we can fit up to 9 extra bits + 7 Huffman bits in a u16; for all other
2692
  // symbols, we could actually go up to 8 Huffman bits as we have at most 8
2693
  // extra bits; however, the SIMD bit merging logic for AVX2 assumes that no
2694
  // Huffman length is 8 or more, so we cap at 8 anyway. Last symbol is used for
2695
  // LZ77 lengths and has no limitations except allowing to represent 32 symbols
2696
  // in total.
2697
  static constexpr uint8_t kMinRawLength[12] = {};
2698
  static constexpr uint8_t kMaxRawLength[12] = {
2699
      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10,
2700
  };
2701
0
  static size_t MaxEncodedBitsPerSample() { return 16; }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::UpTo8Bits::MaxEncodedBitsPerSample()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::UpTo8Bits::MaxEncodedBitsPerSample()
2702
  static constexpr size_t kInputBytes = 1;
2703
  using pixel_t = int16_t;
2704
  using upixel_t = uint16_t;
2705
2706
  static void PrepareForSimd(const uint8_t* nbits, const uint8_t* bits,
2707
                             size_t n, uint8_t* nbits_simd,
2708
0
                             uint8_t* bits_simd) {
2709
0
    assert(n <= 16);
2710
0
    memcpy(nbits_simd, nbits, 16);
2711
0
    memcpy(bits_simd, bits, 16);
2712
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::UpTo8Bits::PrepareForSimd(unsigned char const*, unsigned char const*, unsigned long, unsigned char*, unsigned char*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::UpTo8Bits::PrepareForSimd(unsigned char const*, unsigned char const*, unsigned long, unsigned char*, unsigned char*)
2713
2714
#ifdef FJXL_GENERIC_SIMD
2715
  static void EncodeChunkSimd(upixel_t* residuals, size_t n, size_t skip,
2716
                              const uint8_t* raw_nbits_simd,
2717
0
                              const uint8_t* raw_bits_simd, BitWriter& output) {
2718
0
    Bits32 bits32[kChunkSize / SIMDVec16::kLanes];
2719
0
    alignas(64) uint16_t bits[SIMDVec16::kLanes];
2720
0
    alignas(64) uint16_t nbits[SIMDVec16::kLanes];
2721
0
    alignas(64) uint16_t bits_huff[SIMDVec16::kLanes];
2722
0
    alignas(64) uint16_t nbits_huff[SIMDVec16::kLanes];
2723
0
    alignas(64) uint16_t token[SIMDVec16::kLanes];
2724
0
    for (size_t i = 0; i < kChunkSize; i += SIMDVec16::kLanes) {
2725
0
      TokenizeSIMD(residuals + i, token, nbits, bits);
2726
0
      HuffmanSIMDUpTo13(token, raw_nbits_simd, raw_bits_simd, nbits_huff,
2727
0
                        bits_huff);
2728
0
      StoreSIMDUpTo8(nbits, bits, nbits_huff, bits_huff, std::max(n, i) - i,
2729
0
                     std::max(skip, i) - i, bits32 + i / SIMDVec16::kLanes);
2730
0
    }
2731
0
    StoreToWriter<kChunkSize / SIMDVec16::kLanes>(bits32, output);
2732
0
  }
2733
#endif
2734
2735
0
  size_t NumSymbols(bool doing_ycocg_or_large_palette) const {
2736
    // values gain 1 bit for YCoCg, 1 bit for prediction.
2737
    // Maximum symbol is 1 + effective bit depth of residuals.
2738
0
    if (doing_ycocg_or_large_palette) {
2739
0
      return bitdepth + 3;
2740
0
    } else {
2741
0
      return bitdepth + 2;
2742
0
    }
2743
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::UpTo8Bits::NumSymbols(bool) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::UpTo8Bits::NumSymbols(bool) const
2744
};
2745
constexpr uint8_t UpTo8Bits::kMinRawLength[];
2746
constexpr uint8_t UpTo8Bits::kMaxRawLength[];
2747
2748
struct From9To13Bits {
2749
  size_t bitdepth;
2750
0
  explicit From9To13Bits(size_t bitdepth) : bitdepth(bitdepth) {
2751
0
    assert(bitdepth <= 13 && bitdepth >= 9);
2752
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::From9To13Bits::From9To13Bits(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::From9To13Bits::From9To13Bits(unsigned long)
2753
  // Last symbol is used for LZ77 lengths and has no limitations except allowing
2754
  // to represent 32 symbols in total.
2755
  // We cannot fit all the bits in a u16, so do not even try and use up to 8
2756
  // bits per raw symbol.
2757
  // There are at most 16 raw symbols, so Huffman coding can be SIMDfied without
2758
  // any special tricks.
2759
  static constexpr uint8_t kMinRawLength[17] = {};
2760
  static constexpr uint8_t kMaxRawLength[17] = {
2761
      8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10,
2762
  };
2763
0
  static size_t MaxEncodedBitsPerSample() { return 22; }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::From9To13Bits::MaxEncodedBitsPerSample()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::From9To13Bits::MaxEncodedBitsPerSample()
2764
  static constexpr size_t kInputBytes = 2;
2765
  using pixel_t = int16_t;
2766
  using upixel_t = uint16_t;
2767
2768
  static void PrepareForSimd(const uint8_t* nbits, const uint8_t* bits,
2769
                             size_t n, uint8_t* nbits_simd,
2770
0
                             uint8_t* bits_simd) {
2771
0
    assert(n <= 16);
2772
0
    memcpy(nbits_simd, nbits, 16);
2773
0
    memcpy(bits_simd, bits, 16);
2774
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::From9To13Bits::PrepareForSimd(unsigned char const*, unsigned char const*, unsigned long, unsigned char*, unsigned char*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::From9To13Bits::PrepareForSimd(unsigned char const*, unsigned char const*, unsigned long, unsigned char*, unsigned char*)
2775
2776
#ifdef FJXL_GENERIC_SIMD
2777
  static void EncodeChunkSimd(upixel_t* residuals, size_t n, size_t skip,
2778
                              const uint8_t* raw_nbits_simd,
2779
0
                              const uint8_t* raw_bits_simd, BitWriter& output) {
2780
0
    Bits32 bits32[2 * kChunkSize / SIMDVec16::kLanes];
2781
0
    alignas(64) uint16_t bits[SIMDVec16::kLanes];
2782
0
    alignas(64) uint16_t nbits[SIMDVec16::kLanes];
2783
0
    alignas(64) uint16_t bits_huff[SIMDVec16::kLanes];
2784
0
    alignas(64) uint16_t nbits_huff[SIMDVec16::kLanes];
2785
0
    alignas(64) uint16_t token[SIMDVec16::kLanes];
2786
0
    for (size_t i = 0; i < kChunkSize; i += SIMDVec16::kLanes) {
2787
0
      TokenizeSIMD(residuals + i, token, nbits, bits);
2788
0
      HuffmanSIMDUpTo13(token, raw_nbits_simd, raw_bits_simd, nbits_huff,
2789
0
                        bits_huff);
2790
0
      StoreSIMDUpTo14(nbits, bits, nbits_huff, bits_huff, std::max(n, i) - i,
2791
0
                      std::max(skip, i) - i,
2792
0
                      bits32 + 2 * i / SIMDVec16::kLanes);
2793
0
    }
2794
0
    StoreToWriter<2 * kChunkSize / SIMDVec16::kLanes>(bits32, output);
2795
0
  }
2796
#endif
2797
2798
0
  size_t NumSymbols(bool doing_ycocg_or_large_palette) const {
2799
    // values gain 1 bit for YCoCg, 1 bit for prediction.
2800
    // Maximum symbol is 1 + effective bit depth of residuals.
2801
0
    if (doing_ycocg_or_large_palette) {
2802
0
      return bitdepth + 3;
2803
0
    } else {
2804
0
      return bitdepth + 2;
2805
0
    }
2806
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::From9To13Bits::NumSymbols(bool) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::From9To13Bits::NumSymbols(bool) const
2807
};
2808
constexpr uint8_t From9To13Bits::kMinRawLength[];
2809
constexpr uint8_t From9To13Bits::kMaxRawLength[];
2810
2811
0
void CheckHuffmanBitsSIMD(int bits1, int nbits1, int bits2, int nbits2) {
2812
0
  assert(nbits1 == 8);
2813
0
  assert(nbits2 == 8);
2814
0
  assert(bits2 == (bits1 | 128));
2815
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::CheckHuffmanBitsSIMD(int, int, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::CheckHuffmanBitsSIMD(int, int, int, int)
2816
2817
struct Exactly14Bits {
2818
0
  explicit Exactly14Bits(size_t bitdepth_) { assert(bitdepth_ == 14); }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::Exactly14Bits::Exactly14Bits(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::Exactly14Bits::Exactly14Bits(unsigned long)
2819
  // Force LZ77 symbols to have at least 8 bits, and raw symbols 15 and 16 to
2820
  // have exactly 8, and no other symbol to have 8 or more. This ensures that
2821
  // the representation for 15 and 16 is identical up to one bit.
2822
  static constexpr uint8_t kMinRawLength[18] = {
2823
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 7,
2824
  };
2825
  static constexpr uint8_t kMaxRawLength[18] = {
2826
      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 10,
2827
  };
2828
  static constexpr size_t bitdepth = 14;
2829
0
  static size_t MaxEncodedBitsPerSample() { return 23; }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::Exactly14Bits::MaxEncodedBitsPerSample()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::Exactly14Bits::MaxEncodedBitsPerSample()
2830
  static constexpr size_t kInputBytes = 2;
2831
  using pixel_t = int16_t;
2832
  using upixel_t = uint16_t;
2833
2834
  static void PrepareForSimd(const uint8_t* nbits, const uint8_t* bits,
2835
                             size_t n, uint8_t* nbits_simd,
2836
0
                             uint8_t* bits_simd) {
2837
0
    assert(n == 17);
2838
0
    CheckHuffmanBitsSIMD(bits[15], nbits[15], bits[16], nbits[16]);
2839
0
    memcpy(nbits_simd, nbits, 16);
2840
0
    memcpy(bits_simd, bits, 16);
2841
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::Exactly14Bits::PrepareForSimd(unsigned char const*, unsigned char const*, unsigned long, unsigned char*, unsigned char*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::Exactly14Bits::PrepareForSimd(unsigned char const*, unsigned char const*, unsigned long, unsigned char*, unsigned char*)
2842
2843
#ifdef FJXL_GENERIC_SIMD
2844
  static void EncodeChunkSimd(upixel_t* residuals, size_t n, size_t skip,
2845
                              const uint8_t* raw_nbits_simd,
2846
0
                              const uint8_t* raw_bits_simd, BitWriter& output) {
2847
0
    Bits32 bits32[2 * kChunkSize / SIMDVec16::kLanes];
2848
0
    alignas(64) uint16_t bits[SIMDVec16::kLanes];
2849
0
    alignas(64) uint16_t nbits[SIMDVec16::kLanes];
2850
0
    alignas(64) uint16_t bits_huff[SIMDVec16::kLanes];
2851
0
    alignas(64) uint16_t nbits_huff[SIMDVec16::kLanes];
2852
0
    alignas(64) uint16_t token[SIMDVec16::kLanes];
2853
0
    for (size_t i = 0; i < kChunkSize; i += SIMDVec16::kLanes) {
2854
0
      TokenizeSIMD(residuals + i, token, nbits, bits);
2855
0
      HuffmanSIMD14(token, raw_nbits_simd, raw_bits_simd, nbits_huff,
2856
0
                    bits_huff);
2857
0
      StoreSIMDUpTo14(nbits, bits, nbits_huff, bits_huff, std::max(n, i) - i,
2858
0
                      std::max(skip, i) - i,
2859
0
                      bits32 + 2 * i / SIMDVec16::kLanes);
2860
0
    }
2861
0
    StoreToWriter<2 * kChunkSize / SIMDVec16::kLanes>(bits32, output);
2862
0
  }
2863
#endif
2864
2865
0
  size_t NumSymbols(bool) const { return 17; }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::Exactly14Bits::NumSymbols(bool) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::Exactly14Bits::NumSymbols(bool) const
2866
};
2867
constexpr uint8_t Exactly14Bits::kMinRawLength[];
2868
constexpr uint8_t Exactly14Bits::kMaxRawLength[];
2869
2870
struct MoreThan14Bits {
2871
  size_t bitdepth;
2872
0
  explicit MoreThan14Bits(size_t bitdepth) : bitdepth(bitdepth) {
2873
0
    assert(bitdepth > 14);
2874
0
    assert(bitdepth <= 16);
2875
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::MoreThan14Bits::MoreThan14Bits(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::MoreThan14Bits::MoreThan14Bits(unsigned long)
2876
  // Force LZ77 symbols to have at least 8 bits, and raw symbols 13 to 18 to
2877
  // have exactly 8, and no other symbol to have 8 or more. This ensures that
2878
  // the representation for (13, 14), (15, 16), (17, 18) is identical up to one
2879
  // bit.
2880
  static constexpr uint8_t kMinRawLength[20] = {
2881
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 7,
2882
  };
2883
  static constexpr uint8_t kMaxRawLength[20] = {
2884
      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 10,
2885
  };
2886
0
  static size_t MaxEncodedBitsPerSample() { return 25; }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::MoreThan14Bits::MaxEncodedBitsPerSample()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::MoreThan14Bits::MaxEncodedBitsPerSample()
2887
  static constexpr size_t kInputBytes = 2;
2888
  using pixel_t = int32_t;
2889
  using upixel_t = uint32_t;
2890
2891
  static void PrepareForSimd(const uint8_t* nbits, const uint8_t* bits,
2892
                             size_t n, uint8_t* nbits_simd,
2893
0
                             uint8_t* bits_simd) {
2894
0
    assert(n == 19);
2895
0
    CheckHuffmanBitsSIMD(bits[13], nbits[13], bits[14], nbits[14]);
2896
0
    CheckHuffmanBitsSIMD(bits[15], nbits[15], bits[16], nbits[16]);
2897
0
    CheckHuffmanBitsSIMD(bits[17], nbits[17], bits[18], nbits[18]);
2898
0
    for (size_t i = 0; i < 14; i++) {
2899
0
      nbits_simd[i] = nbits[i];
2900
0
      bits_simd[i] = bits[i];
2901
0
    }
2902
0
    nbits_simd[14] = nbits[15];
2903
0
    bits_simd[14] = bits[15];
2904
0
    nbits_simd[15] = nbits[17];
2905
0
    bits_simd[15] = bits[17];
2906
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::MoreThan14Bits::PrepareForSimd(unsigned char const*, unsigned char const*, unsigned long, unsigned char*, unsigned char*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::MoreThan14Bits::PrepareForSimd(unsigned char const*, unsigned char const*, unsigned long, unsigned char*, unsigned char*)
2907
2908
#ifdef FJXL_GENERIC_SIMD
2909
  static void EncodeChunkSimd(upixel_t* residuals, size_t n, size_t skip,
2910
                              const uint8_t* raw_nbits_simd,
2911
0
                              const uint8_t* raw_bits_simd, BitWriter& output) {
2912
0
    Bits32 bits32[2 * kChunkSize / SIMDVec16::kLanes];
2913
0
    alignas(64) uint32_t bits[SIMDVec16::kLanes];
2914
0
    alignas(64) uint32_t nbits[SIMDVec16::kLanes];
2915
0
    alignas(64) uint16_t bits_huff[SIMDVec16::kLanes];
2916
0
    alignas(64) uint16_t nbits_huff[SIMDVec16::kLanes];
2917
0
    alignas(64) uint16_t token[SIMDVec16::kLanes];
2918
0
    for (size_t i = 0; i < kChunkSize; i += SIMDVec16::kLanes) {
2919
0
      TokenizeSIMD(residuals + i, token, nbits, bits);
2920
0
      HuffmanSIMDAbove14(token, raw_nbits_simd, raw_bits_simd, nbits_huff,
2921
0
                         bits_huff);
2922
0
      StoreSIMDAbove14(nbits, bits, nbits_huff, bits_huff, std::max(n, i) - i,
2923
0
                       std::max(skip, i) - i,
2924
0
                       bits32 + 2 * i / SIMDVec16::kLanes);
2925
0
    }
2926
0
    StoreToWriter<2 * kChunkSize / SIMDVec16::kLanes>(bits32, output);
2927
0
  }
2928
#endif
2929
0
  size_t NumSymbols(bool) const { return 19; }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::MoreThan14Bits::NumSymbols(bool) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::MoreThan14Bits::NumSymbols(bool) const
2930
};
2931
constexpr uint8_t MoreThan14Bits::kMinRawLength[];
2932
constexpr uint8_t MoreThan14Bits::kMaxRawLength[];
2933
2934
bool PrepareDCGlobalCommon(bool is_single_group, size_t width, size_t height,
2935
                           size_t max_encoded_bits_per_sample,
2936
0
                           const PrefixCode code[4], BitWriter* output) {
2937
0
  size_t num_samples = is_single_group ? (width * height) : 0;
2938
0
  if (!output->Allocate(100000 + num_samples * max_encoded_bits_per_sample)) {
2939
0
    return false;
2940
0
  }
2941
  // No patches, spline or noise.
2942
0
  output->Write(1, 1);  // default DC dequantization factors (?)
2943
0
  output->Write(1, 1);  // use global tree / histograms
2944
0
  output->Write(1, 0);  // no lz77 for the tree
2945
2946
0
  output->Write(1, 1);         // simple code for the tree's context map
2947
0
  output->Write(2, 0);         // all contexts clustered together
2948
0
  output->Write(1, 1);         // use prefix code for tree
2949
0
  output->Write(4, 0);         // 000 hybrid uint
2950
0
  output->Write(6, 0b100011);  // Alphabet size is 4 (var16)
2951
0
  output->Write(2, 1);         // simple prefix code
2952
0
  output->Write(2, 3);         // with 4 symbols
2953
0
  output->Write(2, 0);
2954
0
  output->Write(2, 1);
2955
0
  output->Write(2, 2);
2956
0
  output->Write(2, 3);
2957
0
  output->Write(1, 0);  // First tree encoding option
2958
2959
  // Huffman table + extra bits for the tree.
2960
0
  uint8_t symbol_bits[6] = {0b00, 0b10, 0b001, 0b101, 0b0011, 0b0111};
2961
0
  uint8_t symbol_nbits[6] = {2, 2, 3, 3, 4, 4};
2962
  // Write a tree with a leaf per channel, and gradient predictor for every
2963
  // leaf.
2964
0
  for (auto v : {1, 2, 1, 4, 1, 0, 0, 5, 0, 0, 0, 0, 5,
2965
0
                 0, 0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 0}) {
2966
0
    output->Write(symbol_nbits[v], symbol_bits[v]);
2967
0
  }
2968
2969
0
  output->Write(1, 1);     // Enable lz77 for the main bitstream
2970
0
  output->Write(2, 0b00);  // lz77 offset 224
2971
0
  static_assert(kLZ77Offset == 224, "kLZ77Offset should be 224");
2972
0
  output->Write(4, 0b1010);  // lz77 min length 7
2973
  // 400 hybrid uint config for lz77
2974
0
  output->Write(4, 4);
2975
0
  output->Write(3, 0);
2976
0
  output->Write(3, 0);
2977
2978
0
  output->Write(1, 1);  // simple code for the context map
2979
0
  output->Write(2, 3);  // 3 bits per entry
2980
0
  output->Write(3, 4);  // channel 3
2981
0
  output->Write(3, 3);  // channel 2
2982
0
  output->Write(3, 2);  // channel 1
2983
0
  output->Write(3, 1);  // channel 0
2984
0
  output->Write(3, 0);  // distance histogram first
2985
2986
0
  output->Write(1, 1);  // use prefix codes
2987
0
  output->Write(4, 0);  // 000 hybrid uint config for distances (only need 0)
2988
0
  for (size_t i = 0; i < 4; i++) {
2989
0
    output->Write(4, 0);  // 000 hybrid uint config for symbols (only <= 10)
2990
0
  }
2991
2992
  // Distance alphabet size:
2993
0
  output->Write(5, 0b00001);  // 2: just need 1 for RLE (i.e. distance 1)
2994
  // Symbol + LZ77 alphabet size:
2995
0
  for (size_t i = 0; i < 4; i++) {
2996
0
    output->Write(1, 1);    // > 1
2997
0
    output->Write(4, 8);    // <= 512
2998
0
    output->Write(8, 256);  // == 512
2999
0
  }
3000
3001
  // Distance histogram:
3002
0
  output->Write(2, 1);  // simple prefix code
3003
0
  output->Write(2, 0);  // with one symbol
3004
0
  output->Write(1, 1);  // 1
3005
3006
  // Symbol + lz77 histogram:
3007
0
  for (size_t i = 0; i < 4; i++) {
3008
0
    code[i].WriteTo(output);
3009
0
  }
3010
3011
  // Group header for global modular image.
3012
0
  output->Write(1, 1);  // Global tree
3013
0
  output->Write(1, 1);  // All default wp
3014
0
  return true;
3015
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::PrepareDCGlobalCommon(bool, unsigned long, unsigned long, unsigned long, (anonymous namespace)::PrefixCode const*, (anonymous namespace)::BitWriter*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::PrepareDCGlobalCommon(bool, unsigned long, unsigned long, unsigned long, (anonymous namespace)::PrefixCode const*, (anonymous namespace)::BitWriter*)
3016
3017
bool PrepareDCGlobal(bool is_single_group, size_t width, size_t height,
3018
                     size_t max_encoded_bits_per_sample, size_t nb_chans,
3019
0
                     const PrefixCode code[4], BitWriter* output) {
3020
0
  if (!PrepareDCGlobalCommon(is_single_group, width, height,
3021
0
                             max_encoded_bits_per_sample, code, output)) {
3022
0
    return false;
3023
0
  }
3024
0
  if (nb_chans > 2) {
3025
0
    output->Write(2, 0b01);     // 1 transform
3026
0
    output->Write(2, 0b00);     // RCT
3027
0
    output->Write(5, 0b00000);  // Starting from ch 0
3028
0
    output->Write(2, 0b00);     // YCoCg
3029
0
  } else {
3030
0
    output->Write(2, 0b00);  // no transforms
3031
0
  }
3032
0
  if (!is_single_group) {
3033
0
    output->ZeroPadToByte();
3034
0
  }
3035
0
  return true;
3036
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::PrepareDCGlobal(bool, unsigned long, unsigned long, unsigned long, unsigned long, (anonymous namespace)::PrefixCode const*, (anonymous namespace)::BitWriter*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::PrepareDCGlobal(bool, unsigned long, unsigned long, unsigned long, unsigned long, (anonymous namespace)::PrefixCode const*, (anonymous namespace)::BitWriter*)
3037
3038
template <typename BitDepth>
3039
struct ChunkEncoder {
3040
0
  void PrepareForSimd() {
3041
0
    BitDepth::PrepareForSimd(code->raw_nbits, code->raw_bits, code->numraw,
3042
0
                             raw_nbits_simd, raw_bits_simd);
3043
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>::PrepareForSimd()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>::PrepareForSimd()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>::PrepareForSimd()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>::PrepareForSimd()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>::PrepareForSimd()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>::PrepareForSimd()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>::PrepareForSimd()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>::PrepareForSimd()
3044
  FJXL_INLINE static void EncodeRle(size_t count, const PrefixCode& code,
3045
0
                                    BitWriter& output) {
3046
0
    if (count == 0) return;
3047
0
    count -= kLZ77MinLength + 1;
3048
0
    if (count < kLZ77CacheSize) {
3049
0
      output.Write(code.lz77_cache_nbits[count], code.lz77_cache_bits[count]);
3050
0
    } else {
3051
0
      unsigned token, nbits, bits;
3052
0
      EncodeHybridUintLZ77(count, &token, &nbits, &bits);
3053
0
      uint64_t wbits = bits;
3054
0
      wbits = (wbits << code.lz77_nbits[token]) | code.lz77_bits[token];
3055
0
      wbits = (wbits << code.raw_nbits[0]) | code.raw_bits[0];
3056
0
      output.Write(code.lz77_nbits[token] + nbits + code.raw_nbits[0], wbits);
3057
0
    }
3058
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>::EncodeRle(unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>::EncodeRle(unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>::EncodeRle(unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>::EncodeRle(unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>::EncodeRle(unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>::EncodeRle(unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>::EncodeRle(unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>::EncodeRle(unsigned long, (anonymous namespace)::PrefixCode const&, (anonymous namespace)::BitWriter&)
3059
3060
  FJXL_INLINE void Chunk(size_t run, typename BitDepth::upixel_t* residuals,
3061
0
                         size_t skip, size_t n) {
3062
0
    EncodeRle(run, *code, *output);
3063
#ifdef FJXL_GENERIC_SIMD
3064
    BitDepth::EncodeChunkSimd(residuals, n, skip, raw_nbits_simd, raw_bits_simd,
3065
                              *output);
3066
#else
3067
    GenericEncodeChunk(residuals, n, skip, *code, *output);
3068
#endif
3069
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>::Chunk(unsigned long, unsigned int*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>::Chunk(unsigned long, unsigned int*, unsigned long, unsigned long)
3070
3071
0
  inline void Finalize(size_t run) { EncodeRle(run, *code, *output); }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>::Finalize(unsigned long)
3072
3073
  const PrefixCode* code;
3074
  BitWriter* output;
3075
  alignas(64) uint8_t raw_nbits_simd[16] = {};
3076
  alignas(64) uint8_t raw_bits_simd[16] = {};
3077
};
3078
3079
template <typename BitDepth>
3080
struct ChunkSampleCollector {
3081
0
  FJXL_INLINE void Rle(size_t count, uint64_t* lz77_counts_) {
3082
0
    if (count == 0) return;
3083
0
    raw_counts[0] += 1;
3084
0
    count -= kLZ77MinLength + 1;
3085
0
    unsigned token, nbits, bits;
3086
0
    EncodeHybridUintLZ77(count, &token, &nbits, &bits);
3087
0
    lz77_counts_[token]++;
3088
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>::Rle(unsigned long, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>::Rle(unsigned long, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>::Rle(unsigned long, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>::Rle(unsigned long, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>::Rle(unsigned long, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>::Rle(unsigned long, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>::Rle(unsigned long, unsigned long*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>::Rle(unsigned long, unsigned long*)
3089
3090
  FJXL_INLINE void Chunk(size_t run, typename BitDepth::upixel_t* residuals,
3091
0
                         size_t skip, size_t n) {
3092
    // Run is broken. Encode the run and encode the individual vector.
3093
0
    Rle(run, lz77_counts);
3094
0
    for (size_t ix = skip; ix < n; ix++) {
3095
0
      unsigned token, nbits, bits;
3096
0
      EncodeHybridUint000(residuals[ix], &token, &nbits, &bits);
3097
0
      raw_counts[token]++;
3098
0
    }
3099
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>::Chunk(unsigned long, unsigned int*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>::Chunk(unsigned long, unsigned short*, unsigned long, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>::Chunk(unsigned long, unsigned int*, unsigned long, unsigned long)
3100
3101
  // don't count final run since we don't know how long it really is
3102
0
  void Finalize(size_t run) {}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>::Finalize(unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>::Finalize(unsigned long)
3103
3104
  uint64_t* raw_counts;
3105
  uint64_t* lz77_counts;
3106
};
3107
3108
0
constexpr uint32_t PackSigned(int32_t value) {
3109
0
  return (static_cast<uint32_t>(value) << 1) ^
3110
0
         ((static_cast<uint32_t>(~value) >> 31) - 1);
3111
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::PackSigned(int)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::PackSigned(int)
3112
3113
template <typename T, typename BitDepth>
3114
struct ChannelRowProcessor {
3115
  using upixel_t = typename BitDepth::upixel_t;
3116
  using pixel_t = typename BitDepth::pixel_t;
3117
  T* t;
3118
  void ProcessChunk(const pixel_t* row, const pixel_t* row_left,
3119
                    const pixel_t* row_top, const pixel_t* row_topleft,
3120
0
                    size_t n) {
3121
0
    alignas(64) upixel_t residuals[kChunkSize] = {};
3122
0
    size_t prefix_size = 0;
3123
0
    size_t required_prefix_size = 0;
3124
#ifdef FJXL_GENERIC_SIMD
3125
    constexpr size_t kNum =
3126
0
        sizeof(pixel_t) == 2 ? SIMDVec16::kLanes : SIMDVec32::kLanes;
3127
0
    for (size_t ix = 0; ix < kChunkSize; ix += kNum) {
3128
0
      size_t c =
3129
0
          PredictPixels<simd_t<pixel_t>>(row + ix, row_left + ix, row_top + ix,
3130
0
                                         row_topleft + ix, residuals + ix);
3131
0
      prefix_size =
3132
0
          prefix_size == required_prefix_size ? prefix_size + c : prefix_size;
3133
0
      required_prefix_size += kNum;
3134
0
    }
3135
#else
3136
0
    for (size_t ix = 0; ix < kChunkSize; ix++) {
3137
0
      pixel_t px = row[ix];
3138
0
      pixel_t left = row_left[ix];
3139
0
      pixel_t top = row_top[ix];
3140
0
      pixel_t topleft = row_topleft[ix];
3141
0
      pixel_t ac = left - topleft;
3142
0
      pixel_t ab = left - top;
3143
0
      pixel_t bc = top - topleft;
3144
0
      pixel_t grad = static_cast<pixel_t>(static_cast<upixel_t>(ac) +
3145
0
                                          static_cast<upixel_t>(top));
3146
0
      pixel_t d = ab ^ bc;
3147
0
      pixel_t clamp = d < 0 ? top : left;
3148
0
      pixel_t s = ac ^ bc;
3149
0
      pixel_t pred = s < 0 ? grad : clamp;
3150
0
      residuals[ix] = PackSigned(px - pred);
3151
0
      prefix_size = prefix_size == required_prefix_size
3152
0
                        ? prefix_size + (residuals[ix] == 0)
3153
0
                        : prefix_size;
3154
0
      required_prefix_size += 1;
3155
0
    }
3156
#endif
3157
0
    prefix_size = std::min(n, prefix_size);
3158
0
    if (prefix_size == n && (run > 0 || prefix_size > kLZ77MinLength)) {
3159
      // Run continues, nothing to do.
3160
0
      run += prefix_size;
3161
0
    } else if (prefix_size + run > kLZ77MinLength) {
3162
      // Run is broken. Encode the run and encode the individual vector.
3163
0
      t->Chunk(run + prefix_size, residuals, prefix_size, n);
3164
0
      run = 0;
3165
0
    } else {
3166
      // There was no run to begin with.
3167
0
      t->Chunk(0, residuals, 0, n);
3168
0
    }
3169
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>::ProcessChunk(int const*, int const*, int const*, int const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>::ProcessChunk(int const*, int const*, int const*, int const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>::ProcessChunk(int const*, int const*, int const*, int const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>::ProcessChunk(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>::ProcessChunk(int const*, int const*, int const*, int const*, unsigned long)
3170
3171
  void ProcessRow(const pixel_t* row, const pixel_t* row_left,
3172
                  const pixel_t* row_top, const pixel_t* row_topleft,
3173
0
                  size_t xs) {
3174
0
    for (size_t x = 0; x < xs; x += kChunkSize) {
3175
0
      ProcessChunk(row + x, row_left + x, row_top + x, row_topleft + x,
3176
0
                   std::min(kChunkSize, xs - x));
3177
0
    }
3178
0
  }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>::ProcessRow(int const*, int const*, int const*, int const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>::ProcessRow(int const*, int const*, int const*, int const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>::ProcessRow(int const*, int const*, int const*, int const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>::ProcessRow(short const*, short const*, short const*, short const*, unsigned long)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>::ProcessRow(int const*, int const*, int const*, int const*, unsigned long)
3179
3180
0
  void Finalize() { t->Finalize(run); }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>::Finalize()
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>::Finalize()
3181
  // Invariant: run == 0 or run > kLZ77MinLength.
3182
  size_t run = 0;
3183
};
3184
3185
0
uint16_t LoadLE16(const unsigned char* ptr) {
3186
0
  return uint16_t{ptr[0]} | (uint16_t{ptr[1]} << 8);
3187
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LoadLE16(unsigned char const*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LoadLE16(unsigned char const*)
3188
3189
0
uint16_t SwapEndian(uint16_t in) { return (in >> 8) | (in << 8); }
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::SwapEndian(unsigned short)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::SwapEndian(unsigned short)
3190
3191
#ifdef FJXL_GENERIC_SIMD
3192
0
void StorePixels(SIMDVec16 p, int16_t* dest) { p.Store((uint16_t*)dest); }
3193
3194
0
void StorePixels(SIMDVec16 p, int32_t* dest) {
3195
0
  VecPair<SIMDVec32> p_up = p.Upcast();
3196
0
  p_up.low.Store((uint32_t*)dest);
3197
0
  p_up.hi.Store((uint32_t*)dest + SIMDVec32::kLanes);
3198
0
}
3199
#endif
3200
3201
template <typename pixel_t>
3202
0
void FillRowG8(const unsigned char* rgba, size_t oxs, pixel_t* luma) {
3203
0
  size_t x = 0;
3204
#ifdef FJXL_GENERIC_SIMD
3205
0
  for (; x + SIMDVec16::kLanes <= oxs; x += SIMDVec16::kLanes) {
3206
0
    auto rgb = SIMDVec16::LoadG8(rgba + x);
3207
0
    StorePixels(rgb[0], luma + x);
3208
0
  }
3209
#endif
3210
0
  for (; x < oxs; x++) {
3211
0
    luma[x] = rgba[x];
3212
0
  }
3213
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowG8<short>(unsigned char const*, unsigned long, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowG8<short>(unsigned char const*, unsigned long, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowG8<int>(unsigned char const*, unsigned long, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowG8<int>(unsigned char const*, unsigned long, int*)
3214
3215
template <bool big_endian, typename pixel_t>
3216
0
void FillRowG16(const unsigned char* rgba, size_t oxs, pixel_t* luma) {
3217
0
  size_t x = 0;
3218
#ifdef FJXL_GENERIC_SIMD
3219
0
  for (; x + SIMDVec16::kLanes <= oxs; x += SIMDVec16::kLanes) {
3220
0
    auto rgb = SIMDVec16::LoadG16(rgba + 2 * x);
3221
0
    if (big_endian) {
3222
0
      rgb[0].SwapEndian();
3223
0
    }
3224
0
    StorePixels(rgb[0], luma + x);
3225
0
  }
3226
#endif
3227
0
  for (; x < oxs; x++) {
3228
0
    uint16_t val = LoadLE16(rgba + 2 * x);
3229
0
    if (big_endian) {
3230
0
      val = SwapEndian(val);
3231
0
    }
3232
0
    luma[x] = val;
3233
0
  }
3234
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowG16<true, short>(unsigned char const*, unsigned long, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowG16<false, short>(unsigned char const*, unsigned long, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowG16<true, int>(unsigned char const*, unsigned long, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowG16<false, int>(unsigned char const*, unsigned long, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowG16<true, short>(unsigned char const*, unsigned long, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowG16<false, short>(unsigned char const*, unsigned long, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowG16<true, int>(unsigned char const*, unsigned long, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowG16<false, int>(unsigned char const*, unsigned long, int*)
3235
3236
template <typename pixel_t>
3237
void FillRowGA8(const unsigned char* rgba, size_t oxs, pixel_t* luma,
3238
0
                pixel_t* alpha) {
3239
0
  size_t x = 0;
3240
#ifdef FJXL_GENERIC_SIMD
3241
0
  for (; x + SIMDVec16::kLanes <= oxs; x += SIMDVec16::kLanes) {
3242
0
    auto rgb = SIMDVec16::LoadGA8(rgba + 2 * x);
3243
0
    StorePixels(rgb[0], luma + x);
3244
0
    StorePixels(rgb[1], alpha + x);
3245
0
  }
3246
#endif
3247
0
  for (; x < oxs; x++) {
3248
0
    luma[x] = rgba[2 * x];
3249
0
    alpha[x] = rgba[2 * x + 1];
3250
0
  }
3251
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowGA8<short>(unsigned char const*, unsigned long, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowGA8<short>(unsigned char const*, unsigned long, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowGA8<int>(unsigned char const*, unsigned long, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowGA8<int>(unsigned char const*, unsigned long, int*, int*)
3252
3253
template <bool big_endian, typename pixel_t>
3254
void FillRowGA16(const unsigned char* rgba, size_t oxs, pixel_t* luma,
3255
0
                 pixel_t* alpha) {
3256
0
  size_t x = 0;
3257
#ifdef FJXL_GENERIC_SIMD
3258
0
  for (; x + SIMDVec16::kLanes <= oxs; x += SIMDVec16::kLanes) {
3259
0
    auto rgb = SIMDVec16::LoadGA16(rgba + 4 * x);
3260
0
    if (big_endian) {
3261
0
      rgb[0].SwapEndian();
3262
0
      rgb[1].SwapEndian();
3263
0
    }
3264
0
    StorePixels(rgb[0], luma + x);
3265
0
    StorePixels(rgb[1], alpha + x);
3266
0
  }
3267
#endif
3268
0
  for (; x < oxs; x++) {
3269
0
    uint16_t l = LoadLE16(rgba + 4 * x);
3270
0
    uint16_t a = LoadLE16(rgba + 4 * x + 2);
3271
0
    if (big_endian) {
3272
0
      l = SwapEndian(l);
3273
0
      a = SwapEndian(a);
3274
0
    }
3275
0
    luma[x] = l;
3276
0
    alpha[x] = a;
3277
0
  }
3278
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowGA16<true, short>(unsigned char const*, unsigned long, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowGA16<false, short>(unsigned char const*, unsigned long, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowGA16<true, int>(unsigned char const*, unsigned long, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowGA16<false, int>(unsigned char const*, unsigned long, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowGA16<true, short>(unsigned char const*, unsigned long, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowGA16<false, short>(unsigned char const*, unsigned long, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowGA16<true, int>(unsigned char const*, unsigned long, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowGA16<false, int>(unsigned char const*, unsigned long, int*, int*)
3279
3280
template <typename pixel_t>
3281
void StoreYCoCg(pixel_t r, pixel_t g, pixel_t b, pixel_t* y, pixel_t* co,
3282
0
                pixel_t* cg) {
3283
0
  *co = r - b;
3284
0
  pixel_t tmp = b + (*co >> 1);
3285
0
  *cg = g - tmp;
3286
0
  *y = tmp + (*cg >> 1);
3287
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::StoreYCoCg<short>(short, short, short, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::StoreYCoCg<int>(int, int, int, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::StoreYCoCg<short>(short, short, short, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::StoreYCoCg<int>(int, int, int, int*, int*, int*)
3288
3289
#ifdef FJXL_GENERIC_SIMD
3290
void StoreYCoCg(SIMDVec16 r, SIMDVec16 g, SIMDVec16 b, int16_t* y, int16_t* co,
3291
0
                int16_t* cg) {
3292
0
  SIMDVec16 co_v = r.Sub(b);
3293
0
  SIMDVec16 tmp = b.Add(co_v.SignedShiftRight<1>());
3294
0
  SIMDVec16 cg_v = g.Sub(tmp);
3295
0
  SIMDVec16 y_v = tmp.Add(cg_v.SignedShiftRight<1>());
3296
0
  y_v.Store(reinterpret_cast<uint16_t*>(y));
3297
0
  co_v.Store(reinterpret_cast<uint16_t*>(co));
3298
0
  cg_v.Store(reinterpret_cast<uint16_t*>(cg));
3299
0
}
3300
3301
void StoreYCoCg(SIMDVec16 r, SIMDVec16 g, SIMDVec16 b, int32_t* y, int32_t* co,
3302
0
                int32_t* cg) {
3303
0
  VecPair<SIMDVec32> r_up = r.Upcast();
3304
0
  VecPair<SIMDVec32> g_up = g.Upcast();
3305
0
  VecPair<SIMDVec32> b_up = b.Upcast();
3306
0
  SIMDVec32 co_lo_v = r_up.low.Sub(b_up.low);
3307
0
  SIMDVec32 tmp_lo = b_up.low.Add(co_lo_v.SignedShiftRight<1>());
3308
0
  SIMDVec32 cg_lo_v = g_up.low.Sub(tmp_lo);
3309
0
  SIMDVec32 y_lo_v = tmp_lo.Add(cg_lo_v.SignedShiftRight<1>());
3310
0
  SIMDVec32 co_hi_v = r_up.hi.Sub(b_up.hi);
3311
0
  SIMDVec32 tmp_hi = b_up.hi.Add(co_hi_v.SignedShiftRight<1>());
3312
0
  SIMDVec32 cg_hi_v = g_up.hi.Sub(tmp_hi);
3313
0
  SIMDVec32 y_hi_v = tmp_hi.Add(cg_hi_v.SignedShiftRight<1>());
3314
0
  y_lo_v.Store(reinterpret_cast<uint32_t*>(y));
3315
0
  co_lo_v.Store(reinterpret_cast<uint32_t*>(co));
3316
0
  cg_lo_v.Store(reinterpret_cast<uint32_t*>(cg));
3317
0
  y_hi_v.Store(reinterpret_cast<uint32_t*>(y) + SIMDVec32::kLanes);
3318
0
  co_hi_v.Store(reinterpret_cast<uint32_t*>(co) + SIMDVec32::kLanes);
3319
0
  cg_hi_v.Store(reinterpret_cast<uint32_t*>(cg) + SIMDVec32::kLanes);
3320
0
}
3321
#endif
3322
3323
template <typename pixel_t>
3324
void FillRowRGB8(const unsigned char* rgba, size_t oxs, pixel_t* y, pixel_t* co,
3325
0
                 pixel_t* cg) {
3326
0
  size_t x = 0;
3327
#ifdef FJXL_GENERIC_SIMD
3328
0
  for (; x + SIMDVec16::kLanes <= oxs; x += SIMDVec16::kLanes) {
3329
0
    auto rgb = SIMDVec16::LoadRGB8(rgba + 3 * x);
3330
0
    StoreYCoCg(rgb[0], rgb[1], rgb[2], y + x, co + x, cg + x);
3331
0
  }
3332
#endif
3333
0
  for (; x < oxs; x++) {
3334
0
    uint16_t r = rgba[3 * x];
3335
0
    uint16_t g = rgba[3 * x + 1];
3336
0
    uint16_t b = rgba[3 * x + 2];
3337
0
    StoreYCoCg<pixel_t>(r, g, b, y + x, co + x, cg + x);
3338
0
  }
3339
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGB8<short>(unsigned char const*, unsigned long, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGB8<short>(unsigned char const*, unsigned long, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGB8<int>(unsigned char const*, unsigned long, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGB8<int>(unsigned char const*, unsigned long, int*, int*, int*)
3340
3341
template <bool big_endian, typename pixel_t>
3342
void FillRowRGB16(const unsigned char* rgba, size_t oxs, pixel_t* y,
3343
0
                  pixel_t* co, pixel_t* cg) {
3344
0
  size_t x = 0;
3345
#ifdef FJXL_GENERIC_SIMD
3346
0
  for (; x + SIMDVec16::kLanes <= oxs; x += SIMDVec16::kLanes) {
3347
0
    auto rgb = SIMDVec16::LoadRGB16(rgba + 6 * x);
3348
0
    if (big_endian) {
3349
0
      rgb[0].SwapEndian();
3350
0
      rgb[1].SwapEndian();
3351
0
      rgb[2].SwapEndian();
3352
0
    }
3353
0
    StoreYCoCg(rgb[0], rgb[1], rgb[2], y + x, co + x, cg + x);
3354
0
  }
3355
#endif
3356
0
  for (; x < oxs; x++) {
3357
0
    uint16_t r = LoadLE16(rgba + 6 * x);
3358
0
    uint16_t g = LoadLE16(rgba + 6 * x + 2);
3359
0
    uint16_t b = LoadLE16(rgba + 6 * x + 4);
3360
0
    if (big_endian) {
3361
0
      r = SwapEndian(r);
3362
0
      g = SwapEndian(g);
3363
0
      b = SwapEndian(b);
3364
0
    }
3365
0
    StoreYCoCg<pixel_t>(r, g, b, y + x, co + x, cg + x);
3366
0
  }
3367
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGB16<true, short>(unsigned char const*, unsigned long, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGB16<false, short>(unsigned char const*, unsigned long, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGB16<true, int>(unsigned char const*, unsigned long, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGB16<false, int>(unsigned char const*, unsigned long, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGB16<true, short>(unsigned char const*, unsigned long, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGB16<false, short>(unsigned char const*, unsigned long, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGB16<true, int>(unsigned char const*, unsigned long, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGB16<false, int>(unsigned char const*, unsigned long, int*, int*, int*)
3368
3369
template <typename pixel_t>
3370
void FillRowRGBA8(const unsigned char* rgba, size_t oxs, pixel_t* y,
3371
0
                  pixel_t* co, pixel_t* cg, pixel_t* alpha) {
3372
0
  size_t x = 0;
3373
#ifdef FJXL_GENERIC_SIMD
3374
0
  for (; x + SIMDVec16::kLanes <= oxs; x += SIMDVec16::kLanes) {
3375
0
    auto rgb = SIMDVec16::LoadRGBA8(rgba + 4 * x);
3376
0
    StoreYCoCg(rgb[0], rgb[1], rgb[2], y + x, co + x, cg + x);
3377
0
    StorePixels(rgb[3], alpha + x);
3378
0
  }
3379
#endif
3380
0
  for (; x < oxs; x++) {
3381
0
    uint16_t r = rgba[4 * x];
3382
0
    uint16_t g = rgba[4 * x + 1];
3383
0
    uint16_t b = rgba[4 * x + 2];
3384
0
    uint16_t a = rgba[4 * x + 3];
3385
0
    StoreYCoCg<pixel_t>(r, g, b, y + x, co + x, cg + x);
3386
0
    alpha[x] = a;
3387
0
  }
3388
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGBA8<short>(unsigned char const*, unsigned long, short*, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGBA8<short>(unsigned char const*, unsigned long, short*, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGBA8<int>(unsigned char const*, unsigned long, int*, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGBA8<int>(unsigned char const*, unsigned long, int*, int*, int*, int*)
3389
3390
template <bool big_endian, typename pixel_t>
3391
void FillRowRGBA16(const unsigned char* rgba, size_t oxs, pixel_t* y,
3392
0
                   pixel_t* co, pixel_t* cg, pixel_t* alpha) {
3393
0
  size_t x = 0;
3394
#ifdef FJXL_GENERIC_SIMD
3395
0
  for (; x + SIMDVec16::kLanes <= oxs; x += SIMDVec16::kLanes) {
3396
0
    auto rgb = SIMDVec16::LoadRGBA16(rgba + 8 * x);
3397
0
    if (big_endian) {
3398
0
      rgb[0].SwapEndian();
3399
0
      rgb[1].SwapEndian();
3400
0
      rgb[2].SwapEndian();
3401
0
      rgb[3].SwapEndian();
3402
0
    }
3403
0
    StoreYCoCg(rgb[0], rgb[1], rgb[2], y + x, co + x, cg + x);
3404
0
    StorePixels(rgb[3], alpha + x);
3405
0
  }
3406
#endif
3407
0
  for (; x < oxs; x++) {
3408
0
    uint16_t r = LoadLE16(rgba + 8 * x);
3409
0
    uint16_t g = LoadLE16(rgba + 8 * x + 2);
3410
0
    uint16_t b = LoadLE16(rgba + 8 * x + 4);
3411
0
    uint16_t a = LoadLE16(rgba + 8 * x + 6);
3412
0
    if (big_endian) {
3413
0
      r = SwapEndian(r);
3414
0
      g = SwapEndian(g);
3415
0
      b = SwapEndian(b);
3416
0
      a = SwapEndian(a);
3417
0
    }
3418
0
    StoreYCoCg<pixel_t>(r, g, b, y + x, co + x, cg + x);
3419
0
    alpha[x] = a;
3420
0
  }
3421
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGBA16<true, short>(unsigned char const*, unsigned long, short*, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGBA16<false, short>(unsigned char const*, unsigned long, short*, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGBA16<true, int>(unsigned char const*, unsigned long, int*, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowRGBA16<false, int>(unsigned char const*, unsigned long, int*, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGBA16<true, short>(unsigned char const*, unsigned long, short*, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGBA16<false, short>(unsigned char const*, unsigned long, short*, short*, short*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGBA16<true, int>(unsigned char const*, unsigned long, int*, int*, int*, int*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowRGBA16<false, int>(unsigned char const*, unsigned long, int*, int*, int*, int*)
3422
3423
template <typename Processor, typename BitDepth>
3424
void ProcessImageArea(const unsigned char* rgba, size_t x0, size_t y0,
3425
                      size_t xs, size_t yskip, size_t ys, size_t row_stride,
3426
                      BitDepth bitdepth, size_t nb_chans, bool big_endian,
3427
0
                      Processor* processors) {
3428
0
  constexpr size_t kPadding = 32;
3429
3430
0
  using pixel_t = typename BitDepth::pixel_t;
3431
3432
0
  constexpr size_t kAlign = 64;
3433
0
  constexpr size_t kAlignPixels = kAlign / sizeof(pixel_t);
3434
3435
0
  auto align = [=](pixel_t* ptr) {
3436
0
    size_t offset = reinterpret_cast<size_t>(ptr) % kAlign;
3437
0
    if (offset) {
3438
0
      ptr += offset / sizeof(pixel_t);
3439
0
    }
3440
0
    return ptr;
3441
0
  };
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>*)::{lambda(int*)#1}::operator()(int*) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>*)::{lambda(int*)#1}::operator()(int*) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>*)::{lambda(int*)#1}::operator()(int*) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>*)::{lambda(short*)#1}::operator()(short*) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>*)::{lambda(int*)#1}::operator()(int*) const
3442
3443
0
  constexpr size_t kNumPx =
3444
0
      (256 + kPadding * 2 + kAlignPixels + kAlignPixels - 1) / kAlignPixels *
3445
0
      kAlignPixels;
3446
3447
0
  std::vector<std::array<std::array<pixel_t, kNumPx>, 2>> group_data(nb_chans);
3448
3449
0
  for (size_t y = 0; y < ys; y++) {
3450
0
    const auto rgba_row =
3451
0
        rgba + row_stride * (y0 + y) + x0 * nb_chans * BitDepth::kInputBytes;
3452
0
    pixel_t* crow[4] = {};
3453
0
    pixel_t* prow[4] = {};
3454
0
    for (size_t i = 0; i < nb_chans; i++) {
3455
0
      crow[i] = align(&group_data[i][y & 1][kPadding]);
3456
0
      prow[i] = align(&group_data[i][(y - 1) & 1][kPadding]);
3457
0
    }
3458
3459
    // Pre-fill rows with YCoCg converted pixels.
3460
0
    if (nb_chans == 1) {
3461
0
      if (BitDepth::kInputBytes == 1) {
3462
0
        FillRowG8(rgba_row, xs, crow[0]);
3463
0
      } else if (big_endian) {
3464
0
        FillRowG16</*big_endian=*/true>(rgba_row, xs, crow[0]);
3465
0
      } else {
3466
0
        FillRowG16</*big_endian=*/false>(rgba_row, xs, crow[0]);
3467
0
      }
3468
0
    } else if (nb_chans == 2) {
3469
0
      if (BitDepth::kInputBytes == 1) {
3470
0
        FillRowGA8(rgba_row, xs, crow[0], crow[1]);
3471
0
      } else if (big_endian) {
3472
0
        FillRowGA16</*big_endian=*/true>(rgba_row, xs, crow[0], crow[1]);
3473
0
      } else {
3474
0
        FillRowGA16</*big_endian=*/false>(rgba_row, xs, crow[0], crow[1]);
3475
0
      }
3476
0
    } else if (nb_chans == 3) {
3477
0
      if (BitDepth::kInputBytes == 1) {
3478
0
        FillRowRGB8(rgba_row, xs, crow[0], crow[1], crow[2]);
3479
0
      } else if (big_endian) {
3480
0
        FillRowRGB16</*big_endian=*/true>(rgba_row, xs, crow[0], crow[1],
3481
0
                                          crow[2]);
3482
0
      } else {
3483
0
        FillRowRGB16</*big_endian=*/false>(rgba_row, xs, crow[0], crow[1],
3484
0
                                           crow[2]);
3485
0
      }
3486
0
    } else {
3487
0
      if (BitDepth::kInputBytes == 1) {
3488
0
        FillRowRGBA8(rgba_row, xs, crow[0], crow[1], crow[2], crow[3]);
3489
0
      } else if (big_endian) {
3490
0
        FillRowRGBA16</*big_endian=*/true>(rgba_row, xs, crow[0], crow[1],
3491
0
                                           crow[2], crow[3]);
3492
0
      } else {
3493
0
        FillRowRGBA16</*big_endian=*/false>(rgba_row, xs, crow[0], crow[1],
3494
0
                                            crow[2], crow[3]);
3495
0
      }
3496
0
    }
3497
    // Deal with x == 0.
3498
0
    for (size_t c = 0; c < nb_chans; c++) {
3499
0
      *(crow[c] - 1) = y > 0 ? *(prow[c]) : 0;
3500
      // Fix topleft.
3501
0
      *(prow[c] - 1) = y > 0 ? *(prow[c]) : 0;
3502
0
    }
3503
0
    if (y < yskip) continue;
3504
0
    for (size_t c = 0; c < nb_chans; c++) {
3505
      // Get pointers to px/left/top/topleft data to speedup loop.
3506
0
      const pixel_t* row = crow[c];
3507
0
      const pixel_t* row_left = crow[c] - 1;
3508
0
      const pixel_t* row_top = y == 0 ? row_left : prow[c];
3509
0
      const pixel_t* row_topleft = y == 0 ? row_left : prow[c] - 1;
3510
3511
0
      processors[c].ProcessRow(row, row_left, row_top, row_topleft, xs);
3512
0
    }
3513
0
  }
3514
0
  for (size_t c = 0; c < nb_chans; c++) {
3515
0
    processors[c].Finalize();
3516
0
  }
3517
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::From9To13Bits>, AVX2::(anonymous namespace)::From9To13Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::Exactly14Bits>, AVX2::(anonymous namespace)::Exactly14Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageArea<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::MoreThan14Bits>, AVX2::(anonymous namespace)::MoreThan14Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::From9To13Bits>, default_implementation::(anonymous namespace)::From9To13Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::Exactly14Bits>, default_implementation::(anonymous namespace)::Exactly14Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageArea<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::MoreThan14Bits>, default_implementation::(anonymous namespace)::MoreThan14Bits>*)
3518
3519
template <typename BitDepth>
3520
bool WriteACSection(const unsigned char* rgba, size_t x0, size_t y0, size_t xs,
3521
                    size_t ys, size_t row_stride, bool is_single_group,
3522
                    BitDepth bitdepth, size_t nb_chans, bool big_endian,
3523
                    const PrefixCode code[4],
3524
0
                    std::array<BitWriter, 4>& output) {
3525
0
  for (size_t i = 0; i < nb_chans; i++) {
3526
0
    if (is_single_group && i == 0) continue;
3527
0
    if (!output[i].Allocate(xs * ys * bitdepth.MaxEncodedBitsPerSample() + 4)) {
3528
0
      return false;
3529
0
    }
3530
0
  }
3531
0
  if (!is_single_group) {
3532
    // Group header for modular image.
3533
    // When the image is single-group, the global modular image is the one
3534
    // that contains the pixel data, and there is no group header.
3535
0
    output[0].Write(1, 1);     // Global tree
3536
0
    output[0].Write(1, 1);     // All default wp
3537
0
    output[0].Write(2, 0b00);  // 0 transforms
3538
0
  }
3539
3540
0
  ChunkEncoder<BitDepth> encoders[4];
3541
0
  ChannelRowProcessor<ChunkEncoder<BitDepth>, BitDepth> row_encoders[4];
3542
0
  for (size_t c = 0; c < nb_chans; c++) {
3543
0
    row_encoders[c].t = &encoders[c];
3544
0
    encoders[c].output = &output[c];
3545
0
    encoders[c].code = &code[c];
3546
0
    encoders[c].PrepareForSimd();
3547
0
  }
3548
0
  ProcessImageArea<ChannelRowProcessor<ChunkEncoder<BitDepth>, BitDepth>>(
3549
0
      rgba, x0, y0, xs, 0, ys, row_stride, bitdepth, nb_chans, big_endian,
3550
0
      row_encoders);
3551
0
  return true;
3552
0
}
Unexecuted instantiation: enc_fast_lossless.cc:bool AVX2::(anonymous namespace)::WriteACSection<AVX2::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, (anonymous namespace)::PrefixCode const*, std::__1::array<(anonymous namespace)::BitWriter, 4ul>&)
Unexecuted instantiation: enc_fast_lossless.cc:bool AVX2::(anonymous namespace)::WriteACSection<AVX2::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, (anonymous namespace)::PrefixCode const*, std::__1::array<(anonymous namespace)::BitWriter, 4ul>&)
Unexecuted instantiation: enc_fast_lossless.cc:bool AVX2::(anonymous namespace)::WriteACSection<AVX2::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, (anonymous namespace)::PrefixCode const*, std::__1::array<(anonymous namespace)::BitWriter, 4ul>&)
Unexecuted instantiation: enc_fast_lossless.cc:bool AVX2::(anonymous namespace)::WriteACSection<AVX2::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, (anonymous namespace)::PrefixCode const*, std::__1::array<(anonymous namespace)::BitWriter, 4ul>&)
Unexecuted instantiation: enc_fast_lossless.cc:bool default_implementation::(anonymous namespace)::WriteACSection<default_implementation::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, (anonymous namespace)::PrefixCode const*, std::__1::array<(anonymous namespace)::BitWriter, 4ul>&)
Unexecuted instantiation: enc_fast_lossless.cc:bool default_implementation::(anonymous namespace)::WriteACSection<default_implementation::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, (anonymous namespace)::PrefixCode const*, std::__1::array<(anonymous namespace)::BitWriter, 4ul>&)
Unexecuted instantiation: enc_fast_lossless.cc:bool default_implementation::(anonymous namespace)::WriteACSection<default_implementation::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, (anonymous namespace)::PrefixCode const*, std::__1::array<(anonymous namespace)::BitWriter, 4ul>&)
Unexecuted instantiation: enc_fast_lossless.cc:bool default_implementation::(anonymous namespace)::WriteACSection<default_implementation::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, (anonymous namespace)::PrefixCode const*, std::__1::array<(anonymous namespace)::BitWriter, 4ul>&)
3553
3554
constexpr int kHashExp = 16;
3555
constexpr uint32_t kHashSize = 1 << kHashExp;
3556
constexpr uint32_t kHashMultiplier = 2654435761;
3557
constexpr int kMaxColors = 512;
3558
3559
// can be any function that returns a value in 0 .. kHashSize-1
3560
// has to map 0 to 0
3561
0
inline uint32_t pixel_hash(uint32_t p) {
3562
0
  return (p * kHashMultiplier) >> (32 - kHashExp);
3563
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::pixel_hash(unsigned int)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::pixel_hash(unsigned int)
3564
3565
template <size_t nb_chans>
3566
void FillRowPalette(const unsigned char* inrow, size_t xs,
3567
0
                    const int16_t* lookup, int16_t* out) {
3568
0
  for (size_t x = 0; x < xs; x++) {
3569
0
    uint32_t p = 0;
3570
0
    for (size_t i = 0; i < nb_chans; ++i) {
3571
0
      p |= inrow[x * nb_chans + i] << (8 * i);
3572
0
    }
3573
0
    out[x] = lookup[pixel_hash(p)];
3574
0
  }
3575
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowPalette<1ul>(unsigned char const*, unsigned long, short const*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowPalette<2ul>(unsigned char const*, unsigned long, short const*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowPalette<3ul>(unsigned char const*, unsigned long, short const*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::FillRowPalette<4ul>(unsigned char const*, unsigned long, short const*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowPalette<1ul>(unsigned char const*, unsigned long, short const*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowPalette<2ul>(unsigned char const*, unsigned long, short const*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowPalette<3ul>(unsigned char const*, unsigned long, short const*, short*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::FillRowPalette<4ul>(unsigned char const*, unsigned long, short const*, short*)
3576
3577
template <typename Processor>
3578
void ProcessImageAreaPalette(const unsigned char* rgba, size_t x0, size_t y0,
3579
                             size_t xs, size_t yskip, size_t ys,
3580
                             size_t row_stride, const int16_t* lookup,
3581
0
                             size_t nb_chans, Processor* processors) {
3582
0
  constexpr size_t kPadding = 32;
3583
3584
0
  std::vector<std::array<int16_t, 256 + kPadding * 2>> group_data(2);
3585
0
  Processor& row_encoder = processors[0];
3586
3587
0
  for (size_t y = 0; y < ys; y++) {
3588
    // Pre-fill rows with palette converted pixels.
3589
0
    const unsigned char* inrow = rgba + row_stride * (y0 + y) + x0 * nb_chans;
3590
0
    int16_t* outrow = &group_data[y & 1][kPadding];
3591
0
    if (nb_chans == 1) {
3592
0
      FillRowPalette<1>(inrow, xs, lookup, outrow);
3593
0
    } else if (nb_chans == 2) {
3594
0
      FillRowPalette<2>(inrow, xs, lookup, outrow);
3595
0
    } else if (nb_chans == 3) {
3596
0
      FillRowPalette<3>(inrow, xs, lookup, outrow);
3597
0
    } else if (nb_chans == 4) {
3598
0
      FillRowPalette<4>(inrow, xs, lookup, outrow);
3599
0
    }
3600
    // Deal with x == 0.
3601
0
    group_data[y & 1][kPadding - 1] =
3602
0
        y > 0 ? group_data[(y - 1) & 1][kPadding] : 0;
3603
    // Fix topleft.
3604
0
    group_data[(y - 1) & 1][kPadding - 1] =
3605
0
        y > 0 ? group_data[(y - 1) & 1][kPadding] : 0;
3606
    // Get pointers to px/left/top/topleft data to speedup loop.
3607
0
    const int16_t* row = &group_data[y & 1][kPadding];
3608
0
    const int16_t* row_left = &group_data[y & 1][kPadding - 1];
3609
0
    const int16_t* row_top =
3610
0
        y == 0 ? row_left : &group_data[(y - 1) & 1][kPadding];
3611
0
    const int16_t* row_topleft =
3612
0
        y == 0 ? row_left : &group_data[(y - 1) & 1][kPadding - 1];
3613
3614
0
    row_encoder.ProcessRow(row, row_left, row_top, row_topleft, xs);
3615
0
  }
3616
0
  row_encoder.Finalize();
3617
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageAreaPalette<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits> >(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, short const*, unsigned long, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkSampleCollector<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageAreaPalette<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits> >(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, short const*, unsigned long, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkSampleCollector<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::ProcessImageAreaPalette<AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits> >(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, short const*, unsigned long, AVX2::(anonymous namespace)::ChannelRowProcessor<AVX2::(anonymous namespace)::ChunkEncoder<AVX2::(anonymous namespace)::UpTo8Bits>, AVX2::(anonymous namespace)::UpTo8Bits>*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::ProcessImageAreaPalette<default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits> >(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, short const*, unsigned long, default_implementation::(anonymous namespace)::ChannelRowProcessor<default_implementation::(anonymous namespace)::ChunkEncoder<default_implementation::(anonymous namespace)::UpTo8Bits>, default_implementation::(anonymous namespace)::UpTo8Bits>*)
3618
3619
bool WriteACSectionPalette(const unsigned char* rgba, size_t x0, size_t y0,
3620
                           size_t xs, size_t ys, size_t row_stride,
3621
                           bool is_single_group, const PrefixCode code[4],
3622
                           const int16_t* lookup, size_t nb_chans,
3623
0
                           BitWriter& output) {
3624
0
  if (!is_single_group) {
3625
0
    if (!output.Allocate(16 * xs * ys + 4)) return false;
3626
    // Group header for modular image.
3627
    // When the image is single-group, the global modular image is the one
3628
    // that contains the pixel data, and there is no group header.
3629
0
    output.Write(1, 1);     // Global tree
3630
0
    output.Write(1, 1);     // All default wp
3631
0
    output.Write(2, 0b00);  // 0 transforms
3632
0
  }
3633
3634
0
  ChunkEncoder<UpTo8Bits> encoder;
3635
0
  ChannelRowProcessor<ChunkEncoder<UpTo8Bits>, UpTo8Bits> row_encoder;
3636
3637
0
  row_encoder.t = &encoder;
3638
0
  encoder.output = &output;
3639
0
  encoder.code = &code[is_single_group ? 1 : 0];
3640
0
  encoder.PrepareForSimd();
3641
0
  ProcessImageAreaPalette<
3642
0
      ChannelRowProcessor<ChunkEncoder<UpTo8Bits>, UpTo8Bits>>(
3643
0
      rgba, x0, y0, xs, 0, ys, row_stride, lookup, nb_chans, &row_encoder);
3644
0
  return true;
3645
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::WriteACSectionPalette(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, (anonymous namespace)::PrefixCode const*, short const*, unsigned long, (anonymous namespace)::BitWriter&)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::WriteACSectionPalette(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, bool, (anonymous namespace)::PrefixCode const*, short const*, unsigned long, (anonymous namespace)::BitWriter&)
3646
3647
template <typename BitDepth>
3648
void CollectSamples(const unsigned char* rgba, size_t x0, size_t y0, size_t xs,
3649
                    size_t row_stride, size_t row_count,
3650
                    uint64_t raw_counts[4][kNumRawSymbols],
3651
                    uint64_t lz77_counts[4][kNumLZ77], bool is_single_group,
3652
                    bool palette, BitDepth bitdepth, size_t nb_chans,
3653
0
                    bool big_endian, const int16_t* lookup) {
3654
0
  if (palette) {
3655
0
    ChunkSampleCollector<UpTo8Bits> sample_collectors[4];
3656
0
    ChannelRowProcessor<ChunkSampleCollector<UpTo8Bits>, UpTo8Bits>
3657
0
        row_sample_collectors[4];
3658
0
    for (size_t c = 0; c < nb_chans; c++) {
3659
0
      row_sample_collectors[c].t = &sample_collectors[c];
3660
0
      sample_collectors[c].raw_counts = raw_counts[is_single_group ? 1 : 0];
3661
0
      sample_collectors[c].lz77_counts = lz77_counts[is_single_group ? 1 : 0];
3662
0
    }
3663
0
    ProcessImageAreaPalette<
3664
0
        ChannelRowProcessor<ChunkSampleCollector<UpTo8Bits>, UpTo8Bits>>(
3665
0
        rgba, x0, y0, xs, 1, 1 + row_count, row_stride, lookup, nb_chans,
3666
0
        row_sample_collectors);
3667
0
  } else {
3668
0
    ChunkSampleCollector<BitDepth> sample_collectors[4];
3669
0
    ChannelRowProcessor<ChunkSampleCollector<BitDepth>, BitDepth>
3670
0
        row_sample_collectors[4];
3671
0
    for (size_t c = 0; c < nb_chans; c++) {
3672
0
      row_sample_collectors[c].t = &sample_collectors[c];
3673
0
      sample_collectors[c].raw_counts = raw_counts[c];
3674
0
      sample_collectors[c].lz77_counts = lz77_counts[c];
3675
0
    }
3676
0
    ProcessImageArea<
3677
0
        ChannelRowProcessor<ChunkSampleCollector<BitDepth>, BitDepth>>(
3678
0
        rgba, x0, y0, xs, 1, 1 + row_count, row_stride, bitdepth, nb_chans,
3679
0
        big_endian, row_sample_collectors);
3680
0
  }
3681
0
}
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::CollectSamples<AVX2::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long (*) [19], unsigned long (*) [33], bool, bool, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, short const*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::CollectSamples<AVX2::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long (*) [19], unsigned long (*) [33], bool, bool, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, short const*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::CollectSamples<AVX2::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long (*) [19], unsigned long (*) [33], bool, bool, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, short const*)
Unexecuted instantiation: enc_fast_lossless.cc:void AVX2::(anonymous namespace)::CollectSamples<AVX2::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long (*) [19], unsigned long (*) [33], bool, bool, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, short const*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::CollectSamples<default_implementation::(anonymous namespace)::UpTo8Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long (*) [19], unsigned long (*) [33], bool, bool, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, short const*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::CollectSamples<default_implementation::(anonymous namespace)::From9To13Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long (*) [19], unsigned long (*) [33], bool, bool, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, short const*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::CollectSamples<default_implementation::(anonymous namespace)::Exactly14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long (*) [19], unsigned long (*) [33], bool, bool, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, short const*)
Unexecuted instantiation: enc_fast_lossless.cc:void default_implementation::(anonymous namespace)::CollectSamples<default_implementation::(anonymous namespace)::MoreThan14Bits>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long (*) [19], unsigned long (*) [33], bool, bool, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, short const*)
3682
3683
bool PrepareDCGlobalPalette(bool is_single_group, size_t width, size_t height,
3684
                            size_t max_encoded_bits_per_sample, size_t nb_chans,
3685
                            const PrefixCode code[4],
3686
                            const std::vector<uint32_t>& palette,
3687
0
                            size_t pcolors, BitWriter* output) {
3688
0
  if (!PrepareDCGlobalCommon(is_single_group, width, height,
3689
0
                             max_encoded_bits_per_sample, code, output)) {
3690
0
    return false;
3691
0
  }
3692
0
  output->Write(2, 0b01);     // 1 transform
3693
0
  output->Write(2, 0b01);     // Palette
3694
0
  output->Write(5, 0b00000);  // Starting from ch 0
3695
0
  if (nb_chans == 1) {
3696
0
    output->Write(2, 0b00);  // 1-channel palette (Gray)
3697
0
  } else if (nb_chans == 3) {
3698
0
    output->Write(2, 0b01);  // 3-channel palette (RGB)
3699
0
  } else if (nb_chans == 4) {
3700
0
    output->Write(2, 0b10);  // 4-channel palette (RGBA)
3701
0
  } else {
3702
0
    output->Write(2, 0b11);
3703
0
    output->Write(13, nb_chans - 1);
3704
0
  }
3705
  // pcolors <= kMaxColors + kChunkSize - 1
3706
0
  static_assert(kMaxColors + kChunkSize < 1281,
3707
0
                "add code to signal larger palette sizes");
3708
0
  if (pcolors < 256) {
3709
0
    output->Write(2, 0b00);
3710
0
    output->Write(8, pcolors);
3711
0
  } else {
3712
0
    output->Write(2, 0b01);
3713
0
    output->Write(10, pcolors - 256);
3714
0
  }
3715
3716
0
  output->Write(2, 0b00);  // nb_deltas == 0
3717
0
  output->Write(4, 0);     // Zero predictor for delta palette
3718
  // Encode palette
3719
0
  ChunkEncoder<UpTo8Bits> encoder;
3720
0
  ChannelRowProcessor<ChunkEncoder<UpTo8Bits>, UpTo8Bits> row_encoder;
3721
0
  row_encoder.t = &encoder;
3722
0
  encoder.output = output;
3723
0
  encoder.code = &code[0];
3724
0
  encoder.PrepareForSimd();
3725
0
  std::vector<std::array<int16_t, 32 + 1024>> p(4);
3726
0
  size_t i = 0;
3727
0
  size_t have_zero = 1;
3728
0
  for (; i < pcolors; i++) {
3729
0
    p[0][16 + i + have_zero] = palette[i] & 0xFF;
3730
0
    p[1][16 + i + have_zero] = (palette[i] >> 8) & 0xFF;
3731
0
    p[2][16 + i + have_zero] = (palette[i] >> 16) & 0xFF;
3732
0
    p[3][16 + i + have_zero] = (palette[i] >> 24) & 0xFF;
3733
0
  }
3734
0
  p[0][15] = 0;
3735
0
  row_encoder.ProcessRow(p[0].data() + 16, p[0].data() + 15, p[0].data() + 15,
3736
0
                         p[0].data() + 15, pcolors);
3737
0
  p[1][15] = p[0][16];
3738
0
  p[0][15] = p[0][16];
3739
0
  if (nb_chans > 1) {
3740
0
    row_encoder.ProcessRow(p[1].data() + 16, p[1].data() + 15, p[0].data() + 16,
3741
0
                           p[0].data() + 15, pcolors);
3742
0
  }
3743
0
  p[2][15] = p[1][16];
3744
0
  p[1][15] = p[1][16];
3745
0
  if (nb_chans > 2) {
3746
0
    row_encoder.ProcessRow(p[2].data() + 16, p[2].data() + 15, p[1].data() + 16,
3747
0
                           p[1].data() + 15, pcolors);
3748
0
  }
3749
0
  p[3][15] = p[2][16];
3750
0
  p[2][15] = p[2][16];
3751
0
  if (nb_chans > 3) {
3752
0
    row_encoder.ProcessRow(p[3].data() + 16, p[3].data() + 15, p[2].data() + 16,
3753
0
                           p[2].data() + 15, pcolors);
3754
0
  }
3755
0
  row_encoder.Finalize();
3756
3757
0
  if (!is_single_group) {
3758
0
    output->ZeroPadToByte();
3759
0
  }
3760
0
  return true;
3761
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::PrepareDCGlobalPalette(bool, unsigned long, unsigned long, unsigned long, unsigned long, (anonymous namespace)::PrefixCode const*, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&, unsigned long, (anonymous namespace)::BitWriter*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::PrepareDCGlobalPalette(bool, unsigned long, unsigned long, unsigned long, unsigned long, (anonymous namespace)::PrefixCode const*, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&, unsigned long, (anonymous namespace)::BitWriter*)
3762
3763
template <size_t nb_chans>
3764
bool detect_palette(const unsigned char* r, size_t width,
3765
0
                    std::vector<uint32_t>& palette) {
3766
0
  size_t x = 0;
3767
0
  bool collided = false;
3768
  // this is just an unrolling of the next loop
3769
0
  size_t look_ahead = 7 + ((nb_chans == 1) ? 3 : ((nb_chans < 4) ? 1 : 0));
3770
0
  for (; x + look_ahead < width; x += 8) {
3771
0
    uint32_t p[8] = {}, index[8];
3772
0
    for (int i = 0; i < 8; i++) {
3773
0
      for (int j = 0; j < 4; ++j) {
3774
0
        p[i] |= r[(x + i) * nb_chans + j] << (8 * j);
3775
0
      }
3776
0
    }
3777
0
    for (int i = 0; i < 8; i++) p[i] &= ((1llu << (8 * nb_chans)) - 1);
3778
0
    for (int i = 0; i < 8; i++) index[i] = pixel_hash(p[i]);
3779
0
    for (int i = 0; i < 8; i++) {
3780
0
      collided |= (palette[index[i]] != 0 && p[i] != palette[index[i]]);
3781
0
      palette[index[i]] = p[i];
3782
0
    }
3783
0
  }
3784
0
  for (; x < width; x++) {
3785
0
    uint32_t p = 0;
3786
0
    for (size_t i = 0; i < nb_chans; ++i) {
3787
0
      p |= r[x * nb_chans + i] << (8 * i);
3788
0
    }
3789
0
    uint32_t index = pixel_hash(p);
3790
0
    collided |= (palette[index] != 0 && p != palette[index]);
3791
0
    palette[index] = p;
3792
0
  }
3793
0
  return collided;
3794
0
}
Unexecuted instantiation: enc_fast_lossless.cc:bool AVX2::(anonymous namespace)::detect_palette<1ul>(unsigned char const*, unsigned long, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)
Unexecuted instantiation: enc_fast_lossless.cc:bool AVX2::(anonymous namespace)::detect_palette<2ul>(unsigned char const*, unsigned long, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)
Unexecuted instantiation: enc_fast_lossless.cc:bool AVX2::(anonymous namespace)::detect_palette<3ul>(unsigned char const*, unsigned long, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)
Unexecuted instantiation: enc_fast_lossless.cc:bool AVX2::(anonymous namespace)::detect_palette<4ul>(unsigned char const*, unsigned long, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)
Unexecuted instantiation: enc_fast_lossless.cc:bool default_implementation::(anonymous namespace)::detect_palette<1ul>(unsigned char const*, unsigned long, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)
Unexecuted instantiation: enc_fast_lossless.cc:bool default_implementation::(anonymous namespace)::detect_palette<2ul>(unsigned char const*, unsigned long, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)
Unexecuted instantiation: enc_fast_lossless.cc:bool default_implementation::(anonymous namespace)::detect_palette<3ul>(unsigned char const*, unsigned long, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)
Unexecuted instantiation: enc_fast_lossless.cc:bool default_implementation::(anonymous namespace)::detect_palette<4ul>(unsigned char const*, unsigned long, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&)
3795
3796
template <typename BitDepth>
3797
JxlFastLosslessFrameState* LLPrepare(JxlChunkedFrameInputSource input,
3798
                                     size_t width, size_t height,
3799
                                     BitDepth bitdepth, size_t nb_chans,
3800
0
                                     bool big_endian, int effort, int oneshot) {
3801
0
  assert(width != 0);
3802
0
  assert(height != 0);
3803
3804
  // Count colors to try palette
3805
0
  std::vector<uint32_t> palette(kHashSize);
3806
0
  std::vector<int16_t> lookup(kHashSize);
3807
0
  lookup[0] = 0;
3808
0
  int pcolors = 0;
3809
0
  bool collided = effort < 2 || bitdepth.bitdepth != 8 || !oneshot;
3810
0
  for (size_t y0 = 0; y0 < height && !collided; y0 += 256) {
3811
0
    size_t ys = std::min<size_t>(height - y0, 256);
3812
0
    for (size_t x0 = 0; x0 < width && !collided; x0 += 256) {
3813
0
      size_t xs = std::min<size_t>(width - x0, 256);
3814
0
      size_t stride;
3815
      // TODO(szabadka): Add RAII wrapper around this.
3816
0
      const void* buffer = input.get_color_channel_data_at(input.opaque, x0, y0,
3817
0
                                                           xs, ys, &stride);
3818
0
      if (buffer == nullptr) return nullptr;
3819
0
      auto rgba = reinterpret_cast<const unsigned char*>(buffer);
3820
0
      for (size_t y = 0; y < ys && !collided; y++) {
3821
0
        const unsigned char* r = rgba + stride * y;
3822
0
        if (nb_chans == 1) collided = detect_palette<1>(r, xs, palette);
3823
0
        if (nb_chans == 2) collided = detect_palette<2>(r, xs, palette);
3824
0
        if (nb_chans == 3) collided = detect_palette<3>(r, xs, palette);
3825
0
        if (nb_chans == 4) collided = detect_palette<4>(r, xs, palette);
3826
0
      }
3827
0
      input.release_buffer(input.opaque, buffer);
3828
0
    }
3829
0
  }
3830
0
  int nb_entries = 0;
3831
0
  if (!collided) {
3832
0
    pcolors = 1;  // always have all-zero as a palette color
3833
0
    bool have_color = false;
3834
0
    uint8_t minG = 255, maxG = 0;
3835
0
    for (uint32_t k = 0; k < kHashSize; k++) {
3836
0
      if (palette[k] == 0) continue;
3837
0
      uint8_t p[4];
3838
0
      for (int i = 0; i < 4; ++i) {
3839
0
        p[i] = (palette[k] >> (8 * i)) & 0xFF;
3840
0
      }
3841
      // move entries to front so sort has less work
3842
0
      palette[nb_entries] = palette[k];
3843
0
      if (p[0] != p[1] || p[0] != p[2]) have_color = true;
3844
0
      if (p[1] < minG) minG = p[1];
3845
0
      if (p[1] > maxG) maxG = p[1];
3846
0
      nb_entries++;
3847
      // don't do palette if too many colors are needed
3848
0
      if (nb_entries + pcolors > kMaxColors) {
3849
0
        collided = true;
3850
0
        break;
3851
0
      }
3852
0
    }
3853
0
    if (!have_color) {
3854
      // don't do palette if it's just grayscale without many holes
3855
0
      if (maxG - minG < nb_entries * 1.4f) collided = true;
3856
0
    }
3857
0
  }
3858
0
  if (!collided) {
3859
0
    std::sort(
3860
0
        palette.begin(), palette.begin() + nb_entries,
3861
0
        [&nb_chans](uint32_t ap, uint32_t bp) {
3862
0
          if (ap == 0) return false;
3863
0
          if (bp == 0) return true;
3864
0
          uint8_t a[4], b[4];
3865
0
          for (int i = 0; i < 4; ++i) {
3866
0
            a[i] = (ap >> (8 * i)) & 0xFF;
3867
0
            b[i] = (bp >> (8 * i)) & 0xFF;
3868
0
          }
3869
0
          float ay, by;
3870
0
          if (nb_chans == 4) {
3871
0
            ay = (0.299f * a[0] + 0.587f * a[1] + 0.114f * a[2] + 0.01f) * a[3];
3872
0
            by = (0.299f * b[0] + 0.587f * b[1] + 0.114f * b[2] + 0.01f) * b[3];
3873
0
          } else {
3874
0
            ay = (0.299f * a[0] + 0.587f * a[1] + 0.114f * a[2] + 0.01f);
3875
0
            by = (0.299f * b[0] + 0.587f * b[1] + 0.114f * b[2] + 0.01f);
3876
0
          }
3877
0
          return ay < by;  // sort on alpha*luma
3878
0
        });
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::UpTo8Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, int, int)::{lambda(unsigned int, unsigned int)#1}::operator()(unsigned int, unsigned int) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::From9To13Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, int, int)::{lambda(unsigned int, unsigned int)#1}::operator()(unsigned int, unsigned int) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::Exactly14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, int, int)::{lambda(unsigned int, unsigned int)#1}::operator()(unsigned int, unsigned int) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::MoreThan14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, int, int)::{lambda(unsigned int, unsigned int)#1}::operator()(unsigned int, unsigned int) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::UpTo8Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, int, int)::{lambda(unsigned int, unsigned int)#1}::operator()(unsigned int, unsigned int) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::From9To13Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, int, int)::{lambda(unsigned int, unsigned int)#1}::operator()(unsigned int, unsigned int) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::Exactly14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, int, int)::{lambda(unsigned int, unsigned int)#1}::operator()(unsigned int, unsigned int) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::MoreThan14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, int, int)::{lambda(unsigned int, unsigned int)#1}::operator()(unsigned int, unsigned int) const
3879
0
    for (int k = 0; k < nb_entries; k++) {
3880
0
      if (palette[k] == 0) break;
3881
0
      lookup[pixel_hash(palette[k])] = pcolors++;
3882
0
    }
3883
0
  }
3884
3885
0
  size_t num_groups_x = (width + 255) / 256;
3886
0
  size_t num_groups_y = (height + 255) / 256;
3887
0
  size_t num_dc_groups_x = (width + 2047) / 2048;
3888
0
  size_t num_dc_groups_y = (height + 2047) / 2048;
3889
3890
0
  uint64_t raw_counts[4][kNumRawSymbols] = {};
3891
0
  uint64_t lz77_counts[4][kNumLZ77] = {};
3892
3893
0
  bool onegroup = num_groups_x == 1 && num_groups_y == 1;
3894
3895
0
  auto sample_rows = [&](size_t xg, size_t yg, size_t num_rows) {
3896
0
    size_t y0 = yg * 256;
3897
0
    size_t x0 = xg * 256;
3898
0
    size_t ys = std::min<size_t>(height - y0, 256);
3899
0
    size_t xs = std::min<size_t>(width - x0, 256);
3900
0
    size_t stride;
3901
0
    const void* buffer =
3902
0
        input.get_color_channel_data_at(input.opaque, x0, y0, xs, ys, &stride);
3903
0
    if (buffer == nullptr) {
3904
0
      return false;
3905
0
    }
3906
0
    auto rgba = reinterpret_cast<const unsigned char*>(buffer);
3907
0
    int y_begin_group =
3908
0
        std::max<ptrdiff_t>(
3909
0
            0, static_cast<ptrdiff_t>(ys) - static_cast<ptrdiff_t>(num_rows)) /
3910
0
        2;
3911
0
    int y_count =
3912
0
        std::max<int>(0, std::min<int>(num_rows, ys - y_begin_group - 1));
3913
0
    int x_max = xs / kChunkSize * kChunkSize;
3914
0
    CollectSamples(rgba, 0, y_begin_group, x_max, stride, y_count, raw_counts,
3915
0
                   lz77_counts, onegroup, !collided, bitdepth, nb_chans,
3916
0
                   big_endian, lookup.data());
3917
0
    input.release_buffer(input.opaque, buffer);
3918
0
    return true;
3919
0
  };
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::UpTo8Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, int, int)::{lambda(unsigned long, unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::From9To13Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, int, int)::{lambda(unsigned long, unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::Exactly14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, int, int)::{lambda(unsigned long, unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::MoreThan14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, int, int)::{lambda(unsigned long, unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::UpTo8Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, int, int)::{lambda(unsigned long, unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::From9To13Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, int, int)::{lambda(unsigned long, unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::Exactly14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, int, int)::{lambda(unsigned long, unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::MoreThan14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, int, int)::{lambda(unsigned long, unsigned long, unsigned long)#1}::operator()(unsigned long, unsigned long, unsigned long) const
3920
3921
  // TODO(veluca): that `64` is an arbitrary constant, meant to correspond to
3922
  // the point where the number of processed rows is large enough that loading
3923
  // the entire image is cost-effective.
3924
0
  if (oneshot || effort >= 64) {
3925
0
    for (size_t g = 0; g < num_groups_y * num_groups_x; g++) {
3926
0
      size_t xg = g % num_groups_x;
3927
0
      size_t yg = g / num_groups_x;
3928
0
      size_t y0 = yg * 256;
3929
0
      size_t ys = std::min<size_t>(height - y0, 256);
3930
0
      size_t num_rows = 2 * effort * ys / 256;
3931
0
      if (!sample_rows(xg, yg, num_rows)) {
3932
0
        return nullptr;
3933
0
      }
3934
0
    }
3935
0
  } else {
3936
    // sample the middle (effort * 2 * num_groups) rows of the center group
3937
    // (possibly all of them).
3938
0
    if (!sample_rows((num_groups_x - 1) / 2, (num_groups_y - 1) / 2,
3939
0
                     2 * effort * num_groups_x * num_groups_y)) {
3940
0
      return nullptr;
3941
0
    }
3942
0
  }
3943
3944
  // TODO(veluca): can probably improve this and make it bitdepth-dependent.
3945
0
  uint64_t base_raw_counts[kNumRawSymbols] = {
3946
0
      3843, 852, 1270, 1214, 1014, 727, 481, 300, 159, 51,
3947
0
      5,    1,   1,    1,    1,    1,   1,   1,   1};
3948
3949
0
  bool doing_ycocg = nb_chans > 2 && collided;
3950
0
  bool large_palette = !collided || pcolors >= 256;
3951
0
  for (size_t i = bitdepth.NumSymbols(doing_ycocg || large_palette);
3952
0
       i < kNumRawSymbols; i++) {
3953
0
    base_raw_counts[i] = 0;
3954
0
  }
3955
3956
0
  for (size_t c = 0; c < 4; c++) {
3957
0
    for (size_t i = 0; i < kNumRawSymbols; i++) {
3958
0
      raw_counts[c][i] = (raw_counts[c][i] << 8) + base_raw_counts[i];
3959
0
    }
3960
0
  }
3961
3962
0
  if (!collided) {
3963
0
    unsigned token, nbits, bits;
3964
0
    EncodeHybridUint000(PackSigned(pcolors - 1), &token, &nbits, &bits);
3965
    // ensure all palette indices can actually be encoded
3966
0
    for (size_t i = 0; i < token + 1; i++)
3967
0
      raw_counts[0][i] = std::max<uint64_t>(raw_counts[0][i], 1);
3968
    // these tokens are only used for the palette itself so they can get a bad
3969
    // code
3970
0
    for (size_t i = token + 1; i < 10; i++) raw_counts[0][i] = 1;
3971
0
  }
3972
3973
0
  uint64_t base_lz77_counts[kNumLZ77] = {
3974
0
      29, 27, 25,  23, 21, 21, 19, 18, 21, 17, 16, 15, 15, 14,
3975
0
      13, 13, 137, 98, 61, 34, 1,  1,  1,  1,  1,  1,  1,  1,
3976
0
  };
3977
3978
0
  for (size_t c = 0; c < 4; c++) {
3979
0
    for (size_t i = 0; i < kNumLZ77; i++) {
3980
0
      lz77_counts[c][i] = (lz77_counts[c][i] << 8) + base_lz77_counts[i];
3981
0
    }
3982
0
  }
3983
3984
0
  JxlFastLosslessFrameState* frame_state = new JxlFastLosslessFrameState();
3985
0
  if (!frame_state) return nullptr;
3986
0
  for (size_t i = 0; i < 4; i++) {
3987
0
    frame_state->hcode[i] = PrefixCode(bitdepth, raw_counts[i], lz77_counts[i]);
3988
0
  }
3989
3990
0
  size_t num_dc_groups = num_dc_groups_x * num_dc_groups_y;
3991
0
  size_t num_ac_groups = num_groups_x * num_groups_y;
3992
0
  size_t num_groups = onegroup ? 1 : (2 + num_dc_groups + num_ac_groups);
3993
0
  frame_state->input = input;
3994
0
  frame_state->width = width;
3995
0
  frame_state->height = height;
3996
0
  frame_state->num_groups_x = num_groups_x;
3997
0
  frame_state->num_groups_y = num_groups_y;
3998
0
  frame_state->num_dc_groups_x = num_dc_groups_x;
3999
0
  frame_state->num_dc_groups_y = num_dc_groups_y;
4000
0
  frame_state->nb_chans = nb_chans;
4001
0
  frame_state->bitdepth = bitdepth.bitdepth;
4002
0
  frame_state->big_endian = big_endian;
4003
0
  frame_state->effort = effort;
4004
0
  frame_state->collided = collided;
4005
0
  frame_state->lookup = lookup;
4006
4007
0
  frame_state->group_data = std::vector<std::array<BitWriter, 4>>(num_groups);
4008
0
  frame_state->group_sizes.resize(num_groups);
4009
0
  if (collided) {
4010
0
    if (!PrepareDCGlobal(onegroup, width, height,
4011
0
                         bitdepth.MaxEncodedBitsPerSample(), nb_chans,
4012
0
                         frame_state->hcode, &frame_state->group_data[0][0])) {
4013
0
      delete frame_state;
4014
0
      return nullptr;
4015
0
    }
4016
0
  } else {
4017
0
    if (!PrepareDCGlobalPalette(onegroup, width, height,
4018
0
                                bitdepth.MaxEncodedBitsPerSample(), nb_chans,
4019
0
                                frame_state->hcode, palette, pcolors,
4020
0
                                &frame_state->group_data[0][0])) {
4021
0
      delete frame_state;
4022
0
      return nullptr;
4023
0
    }
4024
0
  }
4025
0
  frame_state->group_sizes[0] = SectionSize(frame_state->group_data[0]);
4026
0
  if (!onegroup) {
4027
0
    ComputeAcGroupDataOffset(frame_state->group_sizes[0], num_dc_groups,
4028
0
                             num_ac_groups, frame_state->min_dc_global_size,
4029
0
                             frame_state->ac_group_data_offset);
4030
0
  }
4031
4032
0
  return frame_state;
4033
0
}
Unexecuted instantiation: enc_fast_lossless.cc:JxlFastLosslessFrameState* AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::UpTo8Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::UpTo8Bits, unsigned long, bool, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:JxlFastLosslessFrameState* AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::From9To13Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::From9To13Bits, unsigned long, bool, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:JxlFastLosslessFrameState* AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::Exactly14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::Exactly14Bits, unsigned long, bool, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:JxlFastLosslessFrameState* AVX2::(anonymous namespace)::LLPrepare<AVX2::(anonymous namespace)::MoreThan14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, AVX2::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:JxlFastLosslessFrameState* default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::UpTo8Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::UpTo8Bits, unsigned long, bool, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:JxlFastLosslessFrameState* default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::From9To13Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::From9To13Bits, unsigned long, bool, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:JxlFastLosslessFrameState* default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::Exactly14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::Exactly14Bits, unsigned long, bool, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:JxlFastLosslessFrameState* default_implementation::(anonymous namespace)::LLPrepare<default_implementation::(anonymous namespace)::MoreThan14Bits>(JxlChunkedFrameInputSource, unsigned long, unsigned long, default_implementation::(anonymous namespace)::MoreThan14Bits, unsigned long, bool, int, int)
4034
4035
template <typename BitDepth>
4036
jxl::Status LLProcess(JxlFastLosslessFrameState* frame_state, bool is_last,
4037
                      BitDepth bitdepth, void* runner_opaque,
4038
                      FJxlParallelRunner runner,
4039
0
                      JxlEncoderOutputProcessorWrapper* output_processor) {
4040
0
#if !FJXL_STANDALONE
4041
0
  if (frame_state->process_done) {
4042
0
    if (!JxlFastLosslessPrepareHeader(frame_state, /*add_image_header=*/0,
4043
0
                                      is_last)) {
4044
0
      return JXL_FAILURE("Allocation failed");
4045
0
    };
4046
0
    if (output_processor) {
4047
0
      JXL_RETURN_IF_ERROR(
4048
0
          JxlFastLosslessOutputFrame(frame_state, output_processor));
4049
0
    }
4050
0
    return true;
4051
0
  }
4052
0
#endif
4053
  // The maximum number of groups that we process concurrently here.
4054
  // TODO(szabadka) Use the number of threads or some outside parameter for the
4055
  // maximum memory usage instead.
4056
0
  constexpr size_t kMaxLocalGroups = 16;
4057
0
  bool onegroup = frame_state->group_sizes.size() == 1;
4058
0
  bool streaming = !onegroup && output_processor;
4059
0
  size_t total_groups = frame_state->num_groups_x * frame_state->num_groups_y;
4060
0
  size_t max_groups = streaming ? kMaxLocalGroups : total_groups;
4061
0
#if !FJXL_STANDALONE
4062
0
  size_t start_pos = 0;
4063
0
  if (streaming) {
4064
0
    start_pos = output_processor->CurrentPosition();
4065
0
    JXL_RETURN_IF_ERROR(
4066
0
        output_processor->Seek(start_pos + frame_state->ac_group_data_offset));
4067
0
  }
4068
0
#endif
4069
0
  for (size_t offset = 0; offset < total_groups; offset += max_groups) {
4070
0
    size_t num_groups = std::min(max_groups, total_groups - offset);
4071
0
    JxlFastLosslessFrameState local_frame_state;
4072
0
    if (streaming) {
4073
0
      local_frame_state.group_data =
4074
0
          std::vector<std::array<BitWriter, 4>>(num_groups);
4075
0
    }
4076
0
    std::atomic<uint32_t> has_error{0};
4077
0
    auto run_one = [&](size_t i) {
4078
0
      size_t g = offset + i;
4079
0
      size_t xg = g % frame_state->num_groups_x;
4080
0
      size_t yg = g / frame_state->num_groups_x;
4081
0
      size_t num_dc_groups =
4082
0
          frame_state->num_dc_groups_x * frame_state->num_dc_groups_y;
4083
0
      size_t group_id = onegroup ? 0 : (2 + num_dc_groups + g);
4084
0
      size_t xs = std::min<size_t>(frame_state->width - xg * 256, 256);
4085
0
      size_t ys = std::min<size_t>(frame_state->height - yg * 256, 256);
4086
0
      size_t x0 = xg * 256;
4087
0
      size_t y0 = yg * 256;
4088
0
      size_t stride;
4089
0
      JxlChunkedFrameInputSource input = frame_state->input;
4090
0
      const void* buffer = input.get_color_channel_data_at(input.opaque, x0, y0,
4091
0
                                                           xs, ys, &stride);
4092
0
      if (buffer == nullptr) {
4093
0
        has_error = 1;
4094
0
        return;
4095
0
      }
4096
0
      const unsigned char* rgba =
4097
0
          reinterpret_cast<const unsigned char*>(buffer);
4098
4099
0
      auto& gd = streaming ? local_frame_state.group_data[i]
4100
0
                           : frame_state->group_data[group_id];
4101
0
      bool ok;
4102
0
      if (frame_state->collided) {
4103
0
        ok = WriteACSection(rgba, 0, 0, xs, ys, stride, onegroup, bitdepth,
4104
0
                            frame_state->nb_chans, frame_state->big_endian,
4105
0
                            frame_state->hcode, gd);
4106
0
      } else {
4107
0
        ok = WriteACSectionPalette(
4108
0
            rgba, 0, 0, xs, ys, stride, onegroup, frame_state->hcode,
4109
0
            frame_state->lookup.data(), frame_state->nb_chans, gd[0]);
4110
0
      }
4111
0
      if (ok) {
4112
0
        frame_state->group_sizes[group_id] = SectionSize(gd);
4113
0
      } else {
4114
0
        has_error = 1;
4115
0
      }
4116
0
      input.release_buffer(input.opaque, buffer);
4117
0
    };
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::UpTo8Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::UpTo8Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(unsigned long)#1}::operator()(unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::From9To13Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::From9To13Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(unsigned long)#1}::operator()(unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::Exactly14Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::Exactly14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(unsigned long)#1}::operator()(unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::MoreThan14Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::MoreThan14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(unsigned long)#1}::operator()(unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::UpTo8Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::UpTo8Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(unsigned long)#1}::operator()(unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::From9To13Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::From9To13Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(unsigned long)#1}::operator()(unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::Exactly14Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::Exactly14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(unsigned long)#1}::operator()(unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::MoreThan14Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::MoreThan14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(unsigned long)#1}::operator()(unsigned long) const
4118
0
    runner(
4119
0
        runner_opaque, &run_one,
4120
0
        +[](void* r, size_t i) {
4121
0
          (*reinterpret_cast<decltype(&run_one)>(r))(i);
4122
0
        },
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::UpTo8Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::UpTo8Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(void*, unsigned long)#1}::operator()(void*, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::From9To13Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::From9To13Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(void*, unsigned long)#1}::operator()(void*, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::Exactly14Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::Exactly14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(void*, unsigned long)#1}::operator()(void*, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::MoreThan14Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::MoreThan14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(void*, unsigned long)#1}::operator()(void*, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::UpTo8Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::UpTo8Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(void*, unsigned long)#1}::operator()(void*, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::From9To13Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::From9To13Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(void*, unsigned long)#1}::operator()(void*, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::Exactly14Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::Exactly14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(void*, unsigned long)#1}::operator()(void*, unsigned long) const
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::MoreThan14Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::MoreThan14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)::{lambda(void*, unsigned long)#1}::operator()(void*, unsigned long) const
4123
0
        num_groups);
4124
0
    if (has_error) return JXL_FAILURE("Allocation failed");
4125
0
#if !FJXL_STANDALONE
4126
0
    if (streaming) {
4127
0
      local_frame_state.nb_chans = frame_state->nb_chans;
4128
0
      local_frame_state.current_bit_writer = 1;
4129
0
      JXL_RETURN_IF_ERROR(
4130
0
          JxlFastLosslessOutputFrame(&local_frame_state, output_processor));
4131
0
    }
4132
0
#endif
4133
0
  }
4134
0
#if !FJXL_STANDALONE
4135
0
  if (streaming) {
4136
0
    size_t end_pos = output_processor->CurrentPosition();
4137
0
    JXL_RETURN_IF_ERROR(output_processor->Seek(start_pos));
4138
0
    frame_state->group_data.resize(1);
4139
0
    bool have_alpha = frame_state->nb_chans == 2 || frame_state->nb_chans == 4;
4140
0
    size_t padding = ComputeDcGlobalPadding(
4141
0
        frame_state->group_sizes, frame_state->ac_group_data_offset,
4142
0
        frame_state->min_dc_global_size, have_alpha, is_last);
4143
4144
0
    for (size_t i = 0; i < padding; ++i) {
4145
0
      frame_state->group_data[0][0].Write(8, 0);
4146
0
    }
4147
0
    frame_state->group_sizes[0] += padding;
4148
0
    if (!JxlFastLosslessPrepareHeader(frame_state, /*add_image_header=*/0,
4149
0
                                      is_last)) {
4150
0
      return JXL_FAILURE("Allocation failed");
4151
0
    }
4152
0
    assert(frame_state->ac_group_data_offset ==
4153
0
           JxlFastLosslessOutputSize(frame_state));
4154
0
    JXL_RETURN_IF_ERROR(
4155
0
        JxlFastLosslessOutputHeaders(frame_state, output_processor));
4156
0
    JXL_RETURN_IF_ERROR(output_processor->Seek(end_pos));
4157
0
  } else if (output_processor) {
4158
0
    assert(onegroup);
4159
0
    if (!JxlFastLosslessPrepareHeader(frame_state, /*add_image_header=*/0,
4160
0
                                      is_last)) {
4161
0
      return JXL_FAILURE("Allocation failed");
4162
0
    }
4163
0
    if (output_processor) {
4164
0
      JXL_RETURN_IF_ERROR(
4165
0
          JxlFastLosslessOutputFrame(frame_state, output_processor));
4166
0
    }
4167
0
  }
4168
0
  frame_state->process_done = true;
4169
0
#endif
4170
0
  return true;
4171
0
}
Unexecuted instantiation: enc_fast_lossless.cc:jxl::Status AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::UpTo8Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::UpTo8Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::Status AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::From9To13Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::From9To13Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::Status AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::Exactly14Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::Exactly14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::Status AVX2::(anonymous namespace)::LLProcess<AVX2::(anonymous namespace)::MoreThan14Bits>(JxlFastLosslessFrameState*, bool, AVX2::(anonymous namespace)::MoreThan14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::Status default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::UpTo8Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::UpTo8Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::Status default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::From9To13Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::From9To13Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::Status default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::Exactly14Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::Exactly14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::Status default_implementation::(anonymous namespace)::LLProcess<default_implementation::(anonymous namespace)::MoreThan14Bits>(JxlFastLosslessFrameState*, bool, default_implementation::(anonymous namespace)::MoreThan14Bits, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
4172
4173
JxlFastLosslessFrameState* JxlFastLosslessPrepareImpl(
4174
    JxlChunkedFrameInputSource input, size_t width, size_t height,
4175
    size_t nb_chans, size_t bitdepth, bool big_endian, int effort,
4176
0
    int oneshot) {
4177
0
  assert(bitdepth > 0);
4178
0
  assert(nb_chans <= 4);
4179
0
  assert(nb_chans != 0);
4180
0
  if (bitdepth <= 8) {
4181
0
    return LLPrepare(input, width, height, UpTo8Bits(bitdepth), nb_chans,
4182
0
                     big_endian, effort, oneshot);
4183
0
  }
4184
0
  if (bitdepth <= 13) {
4185
0
    return LLPrepare(input, width, height, From9To13Bits(bitdepth), nb_chans,
4186
0
                     big_endian, effort, oneshot);
4187
0
  }
4188
0
  if (bitdepth == 14) {
4189
0
    return LLPrepare(input, width, height, Exactly14Bits(bitdepth), nb_chans,
4190
0
                     big_endian, effort, oneshot);
4191
0
  }
4192
0
  return LLPrepare(input, width, height, MoreThan14Bits(bitdepth), nb_chans,
4193
0
                   big_endian, effort, oneshot);
4194
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::JxlFastLosslessPrepareImpl(JxlChunkedFrameInputSource, unsigned long, unsigned long, unsigned long, unsigned long, bool, int, int)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::JxlFastLosslessPrepareImpl(JxlChunkedFrameInputSource, unsigned long, unsigned long, unsigned long, unsigned long, bool, int, int)
4195
4196
jxl::Status JxlFastLosslessProcessFrameImpl(
4197
    JxlFastLosslessFrameState* frame_state, bool is_last, void* runner_opaque,
4198
    FJxlParallelRunner runner,
4199
0
    JxlEncoderOutputProcessorWrapper* output_processor) {
4200
0
  const size_t bitdepth = frame_state->bitdepth;
4201
0
  if (bitdepth <= 8) {
4202
0
    JXL_RETURN_IF_ERROR(LLProcess(frame_state, is_last, UpTo8Bits(bitdepth),
4203
0
                                  runner_opaque, runner, output_processor));
4204
0
  } else if (bitdepth <= 13) {
4205
0
    JXL_RETURN_IF_ERROR(LLProcess(frame_state, is_last, From9To13Bits(bitdepth),
4206
0
                                  runner_opaque, runner, output_processor));
4207
0
  } else if (bitdepth == 14) {
4208
0
    JXL_RETURN_IF_ERROR(LLProcess(frame_state, is_last, Exactly14Bits(bitdepth),
4209
0
                                  runner_opaque, runner, output_processor));
4210
0
  } else {
4211
0
    JXL_RETURN_IF_ERROR(LLProcess(frame_state, is_last,
4212
0
                                  MoreThan14Bits(bitdepth), runner_opaque,
4213
0
                                  runner, output_processor));
4214
0
  }
4215
0
  return true;
4216
0
}
Unexecuted instantiation: enc_fast_lossless.cc:AVX2::(anonymous namespace)::JxlFastLosslessProcessFrameImpl(JxlFastLosslessFrameState*, bool, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
Unexecuted instantiation: enc_fast_lossless.cc:default_implementation::(anonymous namespace)::JxlFastLosslessProcessFrameImpl(JxlFastLosslessFrameState*, bool, void*, void (*)(void*, void*, void (*)(void*, unsigned long), unsigned long), JxlEncoderOutputProcessorWrapper*)
4217
4218
}  // namespace
4219
4220
#ifdef __CLANGD__
4221
}  // namespace default_implementation
4222
#endif
4223
#endif  // FJXL_SELF_INCLUDE
4224
4225
#ifndef FJXL_SELF_INCLUDE
4226
#ifndef __CLANGD__
4227
4228
#define FJXL_SELF_INCLUDE
4229
4230
// If we have NEON enabled, it is the default target.
4231
#if FJXL_ENABLE_NEON
4232
4233
namespace default_implementation {
4234
#define FJXL_NEON
4235
#include "lib/jxl/enc_fast_lossless.cc"
4236
#undef FJXL_NEON
4237
}  // namespace default_implementation
4238
4239
#else                                    // FJXL_ENABLE_NEON
4240
4241
namespace default_implementation {
4242
#include "lib/jxl/enc_fast_lossless.cc"  // NOLINT
4243
}
4244
4245
#if FJXL_ENABLE_AVX2
4246
#ifdef __clang__
4247
#pragma clang attribute push(__attribute__((target("avx,avx2"))), \
4248
                             apply_to = function)
4249
// Causes spurious warnings on clang5.
4250
#pragma clang diagnostic push
4251
#pragma clang diagnostic ignored "-Wmissing-braces"
4252
#elif defined(__GNUC__)
4253
#pragma GCC push_options
4254
// Seems to cause spurious errors on GCC8.
4255
#pragma GCC diagnostic ignored "-Wpsabi"
4256
#pragma GCC target "avx,avx2"
4257
#endif
4258
4259
namespace AVX2 {
4260
#define FJXL_AVX2
4261
#include "lib/jxl/enc_fast_lossless.cc"  // NOLINT
4262
#undef FJXL_AVX2
4263
}  // namespace AVX2
4264
4265
#ifdef __clang__
4266
#pragma clang attribute pop
4267
#pragma clang diagnostic pop
4268
#elif defined(__GNUC__)
4269
#pragma GCC pop_options
4270
#endif
4271
#endif  // FJXL_ENABLE_AVX2
4272
4273
#if FJXL_ENABLE_AVX512
4274
#ifdef __clang__
4275
#pragma clang attribute push(                                                 \
4276
    __attribute__((target("avx512cd,avx512bw,avx512vl,avx512f,avx512vbmi"))), \
4277
    apply_to = function)
4278
#elif defined(__GNUC__)
4279
#pragma GCC push_options
4280
#pragma GCC target "avx512cd,avx512bw,avx512vl,avx512f,avx512vbmi"
4281
#endif
4282
4283
namespace AVX512 {
4284
#define FJXL_AVX512
4285
#include "lib/jxl/enc_fast_lossless.cc"
4286
#undef FJXL_AVX512
4287
}  // namespace AVX512
4288
4289
#ifdef __clang__
4290
#pragma clang attribute pop
4291
#elif defined(__GNUC__)
4292
#pragma GCC pop_options
4293
#endif
4294
#endif  // FJXL_ENABLE_AVX512
4295
4296
#endif
4297
#endif  // __CLANGD__
4298
4299
extern "C" {
4300
4301
#if FJXL_STANDALONE
4302
class FJxlFrameInput {
4303
 public:
4304
  FJxlFrameInput(const unsigned char* rgba, size_t row_stride, size_t nb_chans,
4305
                 size_t bitdepth)
4306
      : rgba_(rgba),
4307
        row_stride_(row_stride),
4308
        bytes_per_pixel_(bitdepth <= 8 ? nb_chans : 2 * nb_chans) {}
4309
4310
  JxlChunkedFrameInputSource GetInputSource() {
4311
    return JxlChunkedFrameInputSource{
4312
        this, GetColorChannelDataAt,
4313
        /*release_buffer=*/[](void*, const void*) {}};
4314
  }
4315
4316
 private:
4317
  static const void* GetColorChannelDataAt(void* opaque, size_t xpos,
4318
                                           size_t ypos, size_t xsize,
4319
                                           size_t ysize, size_t* row_offset) {
4320
    FJxlFrameInput* self = static_cast<FJxlFrameInput*>(opaque);
4321
    *row_offset = self->row_stride_;
4322
    return self->rgba_ + ypos * (*row_offset) + xpos * self->bytes_per_pixel_;
4323
  }
4324
4325
  const uint8_t* rgba_;
4326
  size_t row_stride_;
4327
  size_t bytes_per_pixel_;
4328
};
4329
4330
size_t JxlFastLosslessEncode(const unsigned char* rgba, size_t width,
4331
                             size_t row_stride, size_t height, size_t nb_chans,
4332
                             size_t bitdepth, bool big_endian, int effort,
4333
                             unsigned char** output, void* runner_opaque,
4334
                             FJxlParallelRunner runner) {
4335
  FJxlFrameInput input(rgba, row_stride, nb_chans, bitdepth);
4336
  auto* frame_state = JxlFastLosslessPrepareFrame(
4337
      input.GetInputSource(), width, height, nb_chans, bitdepth, big_endian,
4338
      effort, /*oneshot=*/true);
4339
  if (!frame_state) return 0;
4340
  if (!JxlFastLosslessProcessFrame(frame_state, /*is_last=*/true, runner_opaque,
4341
                                   runner, nullptr)) {
4342
    JxlFastLosslessFreeFrameState(frame_state);
4343
    return 0;
4344
  }
4345
  if (!JxlFastLosslessPrepareHeader(frame_state, /*add_image_header=*/1,
4346
                                    /*is_last=*/1)) {
4347
    JxlFastLosslessFreeFrameState(frame_state);
4348
    return 0;
4349
  }
4350
  size_t output_size = JxlFastLosslessMaxRequiredOutput(frame_state);
4351
  *output = (unsigned char*)malloc(output_size);
4352
  if (*output == NULL) {
4353
    return JXL_FAILURE("Memory allocation failed");
4354
  }
4355
  size_t written = 0;
4356
  size_t total = 0;
4357
  while ((written = JxlFastLosslessWriteOutput(frame_state, *output + total,
4358
                                               output_size - total)) != 0) {
4359
    total += written;
4360
  }
4361
  JxlFastLosslessFreeFrameState(frame_state);
4362
  return total;
4363
}
4364
#endif
4365
4366
JxlFastLosslessFrameState* JxlFastLosslessPrepareFrame(
4367
    JxlChunkedFrameInputSource input, size_t width, size_t height,
4368
    size_t nb_chans, size_t bitdepth, bool big_endian, int effort,
4369
0
    int oneshot) {
4370
#if FJXL_ENABLE_AVX512
4371
  if (HasCpuFeature(CpuFeature::kAVX512CD) &&
4372
      HasCpuFeature(CpuFeature::kVBMI) &&
4373
      HasCpuFeature(CpuFeature::kAVX512BW) &&
4374
      HasCpuFeature(CpuFeature::kAVX512F) &&
4375
      HasCpuFeature(CpuFeature::kAVX512VL)) {
4376
    return AVX512::JxlFastLosslessPrepareImpl(
4377
        input, width, height, nb_chans, bitdepth, big_endian, effort, oneshot);
4378
  }
4379
#endif
4380
0
#if FJXL_ENABLE_AVX2
4381
0
  if (HasCpuFeature(CpuFeature::kAVX2)) {
4382
0
    return AVX2::JxlFastLosslessPrepareImpl(
4383
0
        input, width, height, nb_chans, bitdepth, big_endian, effort, oneshot);
4384
0
  }
4385
0
#endif
4386
4387
0
  return default_implementation::JxlFastLosslessPrepareImpl(
4388
0
      input, width, height, nb_chans, bitdepth, big_endian, effort, oneshot);
4389
0
}
4390
4391
bool JxlFastLosslessProcessFrame(
4392
    JxlFastLosslessFrameState* frame_state, bool is_last, void* runner_opaque,
4393
    FJxlParallelRunner runner,
4394
0
    JxlEncoderOutputProcessorWrapper* output_processor) {
4395
0
  auto trivial_runner =
4396
0
      +[](void*, void* opaque, void fun(void*, size_t), size_t count) {
4397
0
        for (size_t i = 0; i < count; i++) {
4398
0
          fun(opaque, i);
4399
0
        }
4400
0
      };
4401
4402
0
  if (runner == nullptr) {
4403
0
    runner = trivial_runner;
4404
0
  }
4405
4406
#if FJXL_ENABLE_AVX512
4407
  if (HasCpuFeature(CpuFeature::kAVX512CD) &&
4408
      HasCpuFeature(CpuFeature::kVBMI) &&
4409
      HasCpuFeature(CpuFeature::kAVX512BW) &&
4410
      HasCpuFeature(CpuFeature::kAVX512F) &&
4411
      HasCpuFeature(CpuFeature::kAVX512VL)) {
4412
    JXL_RETURN_IF_ERROR(AVX512::JxlFastLosslessProcessFrameImpl(
4413
        frame_state, is_last, runner_opaque, runner, output_processor));
4414
    return true;
4415
  }
4416
#endif
4417
0
#if FJXL_ENABLE_AVX2
4418
0
  if (HasCpuFeature(CpuFeature::kAVX2)) {
4419
0
    JXL_RETURN_IF_ERROR(AVX2::JxlFastLosslessProcessFrameImpl(
4420
0
        frame_state, is_last, runner_opaque, runner, output_processor));
4421
0
    return true;
4422
0
  }
4423
0
#endif
4424
4425
0
  JXL_RETURN_IF_ERROR(default_implementation::JxlFastLosslessProcessFrameImpl(
4426
0
      frame_state, is_last, runner_opaque, runner, output_processor));
4427
0
  return true;
4428
0
}
4429
4430
}  // extern "C"
4431
4432
#if !FJXL_STANDALONE
4433
bool JxlFastLosslessOutputFrame(
4434
    JxlFastLosslessFrameState* frame_state,
4435
0
    JxlEncoderOutputProcessorWrapper* output_processor) {
4436
0
  size_t fl_size = JxlFastLosslessOutputSize(frame_state);
4437
0
  size_t written = 0;
4438
0
  while (written < fl_size) {
4439
0
    JXL_ASSIGN_OR_RETURN(auto buffer,
4440
0
                         output_processor->GetBuffer(32, fl_size - written));
4441
0
    size_t n =
4442
0
        JxlFastLosslessWriteOutput(frame_state, buffer.data(), buffer.size());
4443
0
    if (n == 0) break;
4444
0
    JXL_RETURN_IF_ERROR(buffer.advance(n));
4445
0
    written += n;
4446
0
  };
4447
0
  return true;
4448
0
}
4449
#endif
4450
4451
#endif  // FJXL_SELF_INCLUDE