tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ac_strategy_test.cc (10467B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include "lib/jxl/ac_strategy.h"
      7 
      8 #include <jxl/memory_manager.h>
      9 
     10 #include <algorithm>
     11 #include <cstring>
     12 #include <hwy/base.h>  // HWY_ALIGN_MAX
     13 #include <hwy/tests/hwy_gtest.h>
     14 
     15 #include "lib/jxl/base/random.h"
     16 #include "lib/jxl/coeff_order_fwd.h"
     17 #include "lib/jxl/dec_transforms_testonly.h"
     18 #include "lib/jxl/enc_transforms.h"
     19 #include "lib/jxl/memory_manager_internal.h"
     20 #include "lib/jxl/simd_util.h"
     21 #include "lib/jxl/test_memory_manager.h"
     22 #include "lib/jxl/test_utils.h"
     23 #include "lib/jxl/testing.h"
     24 
     25 namespace jxl {
     26 namespace {
     27 
     28 // Test that DCT -> IDCT is a noop.
     29 class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT<int> {
     30 protected:
     31  void Run() {
     32    JxlMemoryManager* memory_manager = test::MemoryManager();
     33    const AcStrategyType type = static_cast<AcStrategyType>(GetParam());
     34    const AcStrategy acs = AcStrategy::FromRawStrategy(type);
     35    const size_t dct_scratch_size =
     36        3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim;
     37 
     38    size_t mem_bytes =
     39        (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float);
     40    JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem,
     41                           AlignedMemory::Create(memory_manager, mem_bytes));
     42    float* coeffs = mem.address<float>();
     43    float* idct = coeffs + AcStrategy::kMaxCoeffArea;
     44    float* input = idct + AcStrategy::kMaxCoeffArea;
     45    float* scratch_space = input + AcStrategy::kMaxCoeffArea;
     46 
     47    Rng rng(static_cast<uint64_t>(type) * 65537 + 13);
     48 
     49    for (size_t j = 0; j < 64; j++) {
     50      size_t i = (acs.log2_covered_blocks()
     51                      ? rng.UniformU(0, 64u << acs.log2_covered_blocks())
     52                      : j);
     53      std::fill_n(input, AcStrategy::kMaxCoeffArea, 0);
     54      input[i] = 0.2f;
     55      TransformFromPixels(type, input, acs.covered_blocks_x() * 8, coeffs,
     56                          scratch_space);
     57      ASSERT_NEAR(coeffs[0], 0.2 / (64 << acs.log2_covered_blocks()), 1e-6)
     58          << " i = " << i;
     59      TransformToPixels(type, coeffs, idct, acs.covered_blocks_x() * 8,
     60                        scratch_space);
     61      for (size_t j = 0; j < 64u << acs.log2_covered_blocks(); j++) {
     62        ASSERT_NEAR(idct[j], j == i ? 0.2f : 0, 2e-6)
     63            << "j = " << j << " i = " << i << " acs " << static_cast<int>(type);
     64      }
     65    }
     66    // Test DC.
     67    std::fill_n(idct, AcStrategy::kMaxCoeffArea, 0);
     68    for (size_t y = 0; y < acs.covered_blocks_y(); y++) {
     69      for (size_t x = 0; x < acs.covered_blocks_x(); x++) {
     70        float* dc = idct + AcStrategy::kMaxCoeffArea;
     71        std::fill_n(dc, AcStrategy::kMaxCoeffArea, 0);
     72        dc[y * acs.covered_blocks_x() * 8 + x] = 0.2;
     73        LowestFrequenciesFromDC(type, dc, acs.covered_blocks_x() * 8, coeffs,
     74                                scratch_space);
     75        DCFromLowestFrequencies(type, coeffs, idct, acs.covered_blocks_x() * 8);
     76        std::fill_n(dc, AcStrategy::kMaxCoeffArea, 0);
     77        dc[y * acs.covered_blocks_x() * 8 + x] = 0.2;
     78        for (size_t j = 0; j < 64u << acs.log2_covered_blocks(); j++) {
     79          ASSERT_NEAR(idct[j], dc[j], 1e-6)
     80              << "j = " << j << " x = " << x << " y = " << y << " acs "
     81              << static_cast<int>(type);
     82        }
     83      }
     84    }
     85  }
     86 };
     87 
     88 HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T(
     89    AcStrategyRoundtrip,
     90    ::testing::Range(0, static_cast<int>(AcStrategy::kNumValidStrategies)));
     91 
     92 TEST_P(AcStrategyRoundtrip, Test) { Run(); }
     93 
     94 // Test that DC(2x2) -> DCT coefficients -> IDCT -> downsampled IDCT is a noop.
     95 class AcStrategyRoundtripDownsample
     96    : public ::hwy::TestWithParamTargetAndT<int> {
     97 protected:
     98  void Run() {
     99    JxlMemoryManager* memory_manager = test::MemoryManager();
    100    const AcStrategyType type = static_cast<AcStrategyType>(GetParam());
    101    const AcStrategy acs = AcStrategy::FromRawStrategy(type);
    102    const size_t dct_scratch_size =
    103        3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim;
    104 
    105    size_t mem_bytes =
    106        (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float);
    107    JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem,
    108                           AlignedMemory::Create(memory_manager, mem_bytes));
    109    float* coeffs = mem.address<float>();
    110    float* idct = coeffs + AcStrategy::kMaxCoeffArea;
    111    float* dc = idct + AcStrategy::kMaxCoeffArea;
    112    float* scratch_space = dc + AcStrategy::kMaxCoeffArea;
    113 
    114    std::fill_n(coeffs, AcStrategy::kMaxCoeffArea, 0.0f);
    115    Rng rng(static_cast<uint64_t>(type) * 65537 + 13);
    116 
    117    for (size_t y = 0; y < acs.covered_blocks_y(); y++) {
    118      for (size_t x = 0; x < acs.covered_blocks_x(); x++) {
    119        if (x > 4 || y > 4) {
    120          if (rng.Bernoulli(0.9f)) continue;
    121        }
    122        std::fill_n(dc, AcStrategy::kMaxCoeffArea, 0);
    123        dc[y * acs.covered_blocks_x() * 8 + x] = 0.2f;
    124        LowestFrequenciesFromDC(type, dc, acs.covered_blocks_x() * 8, coeffs,
    125                                scratch_space);
    126        TransformToPixels(type, coeffs, idct, acs.covered_blocks_x() * 8,
    127                          scratch_space);
    128        std::fill_n(coeffs, AcStrategy::kMaxCoeffArea, 0.0f);
    129        std::fill_n(dc, AcStrategy::kMaxCoeffArea, 0);
    130        dc[y * acs.covered_blocks_x() * 8 + x] = 0.2f;
    131        // Downsample
    132        for (size_t dy = 0; dy < acs.covered_blocks_y(); dy++) {
    133          for (size_t dx = 0; dx < acs.covered_blocks_x(); dx++) {
    134            float sum = 0;
    135            for (size_t iy = 0; iy < 8; iy++) {
    136              for (size_t ix = 0; ix < 8; ix++) {
    137                sum += idct[(dy * 8 + iy) * 8 * acs.covered_blocks_x() +
    138                            dx * 8 + ix];
    139              }
    140            }
    141            sum /= 64.0f;
    142            ASSERT_NEAR(sum, dc[dy * 8 * acs.covered_blocks_x() + dx], 1e-6)
    143                << "acs " << static_cast<int>(type);
    144          }
    145        }
    146      }
    147    }
    148  }
    149 };
    150 
    151 HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T(
    152    AcStrategyRoundtripDownsample,
    153    ::testing::Range(0, static_cast<int>(AcStrategy::kNumValidStrategies)));
    154 
    155 TEST_P(AcStrategyRoundtripDownsample, Test) { Run(); }
    156 
    157 // Test that IDCT(block with zeros in the non-topleft corner) -> downsampled
    158 // IDCT is the same as IDCT -> DC(2x2) of the same block.
    159 class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT<int> {
    160 protected:
    161  void Run() {
    162    JxlMemoryManager* memory_manager = test::MemoryManager();
    163    const AcStrategyType type = static_cast<AcStrategyType>(GetParam());
    164    const AcStrategy acs = AcStrategy::FromRawStrategy(type);
    165    const size_t dct_scratch_size =
    166        3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim;
    167    size_t cx = acs.covered_blocks_y();
    168    size_t cy = acs.covered_blocks_x();
    169    CoefficientLayout(&cy, &cx);
    170 
    171    size_t mem_bytes =
    172        (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float);
    173    JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem,
    174                           AlignedMemory::Create(memory_manager, mem_bytes));
    175    float* idct = mem.address<float>();
    176    float* idct_acs_downsampled = idct + AcStrategy::kMaxCoeffArea;
    177    float* coeffs = idct + AcStrategy::kMaxCoeffArea;
    178    float* scratch_space = coeffs + AcStrategy::kMaxCoeffArea;
    179 
    180    Rng rng(static_cast<uint64_t>(type) * 65537 + 13);
    181 
    182    for (size_t y = 0; y < cy; y++) {
    183      for (size_t x = 0; x < cx; x++) {
    184        if (x > 4 || y > 4) {
    185          if (rng.Bernoulli(0.9f)) continue;
    186        }
    187        float* coeffs = idct + AcStrategy::kMaxCoeffArea;
    188        std::fill_n(coeffs, AcStrategy::kMaxCoeffArea, 0);
    189        coeffs[y * cx * 8 + x] = 0.2f;
    190        TransformToPixels(type, coeffs, idct, acs.covered_blocks_x() * 8,
    191                          scratch_space);
    192        std::fill_n(coeffs, AcStrategy::kMaxCoeffArea, 0);
    193        coeffs[y * cx * 8 + x] = 0.2f;
    194        DCFromLowestFrequencies(type, coeffs, idct_acs_downsampled,
    195                                acs.covered_blocks_x() * 8);
    196        // Downsample
    197        for (size_t dy = 0; dy < acs.covered_blocks_y(); dy++) {
    198          for (size_t dx = 0; dx < acs.covered_blocks_x(); dx++) {
    199            float sum = 0;
    200            for (size_t iy = 0; iy < 8; iy++) {
    201              for (size_t ix = 0; ix < 8; ix++) {
    202                sum += idct[(dy * 8 + iy) * 8 * acs.covered_blocks_x() +
    203                            dx * 8 + ix];
    204              }
    205            }
    206            sum /= 64;
    207            ASSERT_NEAR(
    208                sum, idct_acs_downsampled[dy * 8 * acs.covered_blocks_x() + dx],
    209                1e-6)
    210                << " acs " << static_cast<int>(type);
    211          }
    212        }
    213      }
    214    }
    215  }
    216 };
    217 
    218 HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T(
    219    AcStrategyDownsample,
    220    ::testing::Range(0, static_cast<int>(AcStrategy::kNumValidStrategies)));
    221 
    222 TEST_P(AcStrategyDownsample, Test) { Run(); }
    223 
    224 class AcStrategyTargetTest : public ::hwy::TestWithParamTarget {};
    225 HWY_TARGET_INSTANTIATE_TEST_SUITE_P(AcStrategyTargetTest);
    226 
    227 TEST_P(AcStrategyTargetTest, RoundtripAFVDCT) {
    228  HWY_ALIGN_MAX float idct[16];
    229  for (size_t i = 0; i < 16; i++) {
    230    HWY_ALIGN_MAX float pixels[16] = {};
    231    pixels[i] = 1;
    232    HWY_ALIGN_MAX float coeffs[16] = {};
    233 
    234    AFVDCT4x4(pixels, coeffs);
    235    AFVIDCT4x4(coeffs, idct);
    236    for (size_t j = 0; j < 16; j++) {
    237      EXPECT_NEAR(idct[j], pixels[j], 1e-6);
    238    }
    239  }
    240 }
    241 
    242 TEST_P(AcStrategyTargetTest, BenchmarkAFV) {
    243  JxlMemoryManager* memory_manager = test::MemoryManager();
    244  const AcStrategyType type = AcStrategyType::AFV0;
    245  HWY_ALIGN_MAX float pixels[64] = {1};
    246  HWY_ALIGN_MAX float coeffs[64] = {};
    247  const size_t dct_scratch_size =
    248      3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim;
    249  size_t mem_bytes = (64 + dct_scratch_size) * sizeof(float);
    250  JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem,
    251                         AlignedMemory::Create(memory_manager, mem_bytes));
    252  float* scratch_space = mem.address<float>();
    253  for (size_t i = 0; i < 1 << 14; i++) {
    254    TransformToPixels(type, coeffs, pixels, 8, scratch_space);
    255    TransformFromPixels(type, pixels, 8, coeffs, scratch_space);
    256  }
    257  EXPECT_NEAR(pixels[0], 0.0, 1E-6);
    258 }
    259 
    260 TEST_P(AcStrategyTargetTest, BenchmarkAFVDCT) {
    261  HWY_ALIGN_MAX float pixels[64] = {1};
    262  HWY_ALIGN_MAX float coeffs[64] = {};
    263  for (size_t i = 0; i < 1 << 14; i++) {
    264    AFVDCT4x4(pixels, coeffs);
    265    AFVIDCT4x4(coeffs, pixels);
    266  }
    267  EXPECT_NEAR(pixels[0], 1.0, 1E-6);
    268 }
    269 
    270 }  // namespace
    271 }  // namespace jxl