1a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Copyright 2012 Google Inc. All Rights Reserved.
2a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//
30406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Use of this source code is governed by a BSD-style license
40406ce1417f76f2034833414dcecc9f56253640cVikas Arora// that can be found in the COPYING file in the root of the source
50406ce1417f76f2034833414dcecc9f56253640cVikas Arora// tree. An additional intellectual property rights grant can be found
60406ce1417f76f2034833414dcecc9f56253640cVikas Arora// in the file PATENTS. All contributing project authors may
70406ce1417f76f2034833414dcecc9f56253640cVikas Arora// be found in the AUTHORS file in the root of the source tree.
8a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
9a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//
10a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Author: Jyrki Alakuijala (jyrki@google.com)
11a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//
12a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
13a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include <assert.h>
14a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include <math.h>
15a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
16fa39824bb690c5806358871f46940d0450973d8aJames Zern#include "./backward_references_enc.h"
17fa39824bb690c5806358871f46940d0450973d8aJames Zern#include "./histogram_enc.h"
18a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "../dsp/lossless.h"
19fa39824bb690c5806358871f46940d0450973d8aJames Zern#include "../dsp/lossless_common.h"
207c8da7ce66017295a65ec028084b90800be377f8James Zern#include "../dsp/dsp.h"
21fa39824bb690c5806358871f46940d0450973d8aJames Zern#include "../utils/color_cache_utils.h"
22a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "../utils/utils.h"
23a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
24a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#define VALUES_IN_BYTE 256
25a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
2633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define MIN_BLOCK_SIZE 256  // minimum block size for backward references
2733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define MAX_ENTROPY    (1e30f)
2933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
30a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// 1M window (4M bytes) minus 120 special codes for short distances.
310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#define WINDOW_SIZE_BITS 20
320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#define WINDOW_SIZE ((1 << WINDOW_SIZE_BITS) - 120)
33a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
34fa39824bb690c5806358871f46940d0450973d8aJames Zern// Minimum number of pixels for which it is cheaper to encode a
35fa39824bb690c5806358871f46940d0450973d8aJames Zern// distance + length instead of each pixel as a literal.
36fa39824bb690c5806358871f46940d0450973d8aJames Zern#define MIN_LENGTH 4
370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// If you change this, you need MAX_LENGTH_BITS + WINDOW_SIZE_BITS <= 32 as it
380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// is used in VP8LHashChain.
390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#define MAX_LENGTH_BITS 12
400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// We want the max value to be attainable and stored in MAX_LENGTH_BITS bits.
410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#define MAX_LENGTH ((1 << MAX_LENGTH_BITS) - 1)
420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#if MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32
430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#error "MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32"
440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#endif
45a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
46a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
47a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
48a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic const uint8_t plane_to_code_lut[128] = {
49a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 96,   73,  55,  39,  23,  13,   5,  1,  255, 255, 255, 255, 255, 255, 255, 255,
50a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 101,  78,  58,  42,  26,  16,   8,  2,    0,   3,  9,   17,  27,  43,  59,  79,
51a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 102,  86,  62,  46,  32,  20,  10,  6,    4,   7,  11,  21,  33,  47,  63,  87,
52a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 105,  90,  70,  52,  37,  28,  18,  14,  12,  15,  19,  29,  38,  53,  71,  91,
53a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 110,  99,  82,  66,  48,  35,  30,  24,  22,  25,  31,  36,  49,  67,  83, 100,
54a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 115, 108,  94,  76,  64,  50,  44,  40,  34,  41,  45,  51,  65,  77,  95, 109,
55a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 118, 113, 103,  92,  80,  68,  60,  56,  54,  57,  61,  69,  81,  93, 104, 114,
56a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 119, 116, 111, 106,  97,  88,  84,  74,  72,  75,  85,  89,  98, 107, 112, 117
57a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora};
58a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
59a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int DistanceToPlaneCode(int xsize, int dist) {
60a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int yoffset = dist / xsize;
61a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int xoffset = dist - yoffset * xsize;
62a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (xoffset <= 8 && yoffset < 8) {
63a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    return plane_to_code_lut[yoffset * 16 + 8 - xoffset] + 1;
64a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  } else if (xoffset > xsize - 8 && yoffset < 7) {
65a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    return plane_to_code_lut[(yoffset + 1) * 16 + 8 + (xsize - xoffset)] + 1;
66a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
67a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return dist + 120;
68a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
69a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
700912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Returns the exact index where array1 and array2 are different. For an index
710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// inferior or equal to best_len_match, the return value just has to be strictly
720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// inferior to best_len_match. The current behavior is to return 0 if this index
730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// is best_len_match, and the index itself otherwise.
747c8da7ce66017295a65ec028084b90800be377f8James Zern// If no two elements are the same, it returns max_limit.
75a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE int FindMatchLength(const uint32_t* const array1,
76a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                       const uint32_t* const array2,
770912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                       int best_len_match, int max_limit) {
787c8da7ce66017295a65ec028084b90800be377f8James Zern  // Before 'expensive' linear match, check if the two arrays match at the
797c8da7ce66017295a65ec028084b90800be377f8James Zern  // current best length index.
807c8da7ce66017295a65ec028084b90800be377f8James Zern  if (array1[best_len_match] != array2[best_len_match]) return 0;
817c8da7ce66017295a65ec028084b90800be377f8James Zern
820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return VP8LVectorMismatch(array1, array2, max_limit);
83a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
84a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
85a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
86a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//  VP8LBackwardRefs
87a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
8833f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastruct PixOrCopyBlock {
8933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopyBlock* next_;   // next block (or NULL)
9033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopy* start_;       // data start
9133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int size_;               // currently used size
9233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora};
9333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9433f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void ClearBackwardRefs(VP8LBackwardRefs* const refs) {
9533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(refs != NULL);
9633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (refs->tail_ != NULL) {
9733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    *refs->tail_ = refs->free_blocks_;  // recycle all blocks at once
98a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
9933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->free_blocks_ = refs->refs_;
10033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->tail_ = &refs->refs_;
10133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->last_block_ = NULL;
10233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->refs_ = NULL;
103a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
104a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
10533f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) {
10633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(refs != NULL);
10733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
10833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (refs->free_blocks_ != NULL) {
10933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    PixOrCopyBlock* const next = refs->free_blocks_->next_;
11033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    WebPSafeFree(refs->free_blocks_);
11133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    refs->free_blocks_ = next;
112a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
113a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
114a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
11533f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size) {
116a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  assert(refs != NULL);
11733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  memset(refs, 0, sizeof(*refs));
11833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->tail_ = &refs->refs_;
11933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->block_size_ =
12033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      (block_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : block_size;
12133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
12233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
12333f74dabbc7920a65ed435d7417987589febdc16Vikas AroraVP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs) {
12433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LRefsCursor c;
12533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  c.cur_block_ = refs->refs_;
12633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (refs->refs_ != NULL) {
12733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    c.cur_pos = c.cur_block_->start_;
12833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    c.last_pos_ = c.cur_pos + c.cur_block_->size_;
12933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
13033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    c.cur_pos = NULL;
13133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    c.last_pos_ = NULL;
13233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
13333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return c;
13433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
13533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
13633f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid VP8LRefsCursorNextBlock(VP8LRefsCursor* const c) {
13733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopyBlock* const b = c->cur_block_->next_;
13833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  c->cur_pos = (b == NULL) ? NULL : b->start_;
13933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  c->last_pos_ = (b == NULL) ? NULL : b->start_ + b->size_;
14033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  c->cur_block_ = b;
14133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
14233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
14333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Create a new block, either from the free list or allocated
14433f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic PixOrCopyBlock* BackwardRefsNewBlock(VP8LBackwardRefs* const refs) {
14533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopyBlock* b = refs->free_blocks_;
14633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (b == NULL) {   // allocate new memory chunk
14733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const size_t total_size =
14833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        sizeof(*b) + refs->block_size_ * sizeof(*b->start_);
14933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    b = (PixOrCopyBlock*)WebPSafeMalloc(1ULL, total_size);
15033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (b == NULL) {
15133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      refs->error_ |= 1;
15233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      return NULL;
15333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
15433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    b->start_ = (PixOrCopy*)((uint8_t*)b + sizeof(*b));  // not always aligned
15533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {  // recycle from free-list
15633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    refs->free_blocks_ = b->next_;
15733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
15833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  *refs->tail_ = b;
15933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->tail_ = &b->next_;
16033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->last_block_ = b;
16133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  b->next_ = NULL;
16233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  b->size_ = 0;
16333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return b;
16433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
16533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
16633f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE void BackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
16733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                              const PixOrCopy v) {
16833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopyBlock* b = refs->last_block_;
16933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (b == NULL || b->size_ == refs->block_size_) {
17033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    b = BackwardRefsNewBlock(refs);
17133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (b == NULL) return;   // refs->error_ is set
17233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
17333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  b->start_[b->size_++] = v;
17433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
17533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
17633f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint VP8LBackwardRefsCopy(const VP8LBackwardRefs* const src,
17733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         VP8LBackwardRefs* const dst) {
17833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const PixOrCopyBlock* b = src->refs_;
17933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(dst);
18033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(src->block_size_ == dst->block_size_);
18133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (b != NULL) {
18233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    PixOrCopyBlock* const new_b = BackwardRefsNewBlock(dst);
18333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (new_b == NULL) return 0;   // dst->error_ is set
18433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    memcpy(new_b->start_, b->start_, b->size_ * sizeof(*b->start_));
18533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    new_b->size_ = b->size_;
18633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    b = b->next_;
18733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
188a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return 1;
189a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
190a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
191a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
192a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Hash chains
193a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
19433f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint VP8LHashChainInit(VP8LHashChain* const p, int size) {
19533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(p->size_ == 0);
1960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  assert(p->offset_length_ == NULL);
19733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(size > 0);
1980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  p->offset_length_ =
1990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      (uint32_t*)WebPSafeMalloc(size, sizeof(*p->offset_length_));
2000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (p->offset_length_ == NULL) return 0;
20133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  p->size_ = size;
2020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
203a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return 1;
204a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
205a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
20633f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid VP8LHashChainClear(VP8LHashChain* const p) {
20733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(p != NULL);
2080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  WebPSafeFree(p->offset_length_);
2090912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
21033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  p->size_ = 0;
2110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  p->offset_length_ = NULL;
21233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
21333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
21433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// -----------------------------------------------------------------------------
21533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
216fa39824bb690c5806358871f46940d0450973d8aJames Zern#define HASH_MULTIPLIER_HI (0xc6a4a793ULL)
217fa39824bb690c5806358871f46940d0450973d8aJames Zern#define HASH_MULTIPLIER_LO (0x5bd1e996ULL)
2187c8da7ce66017295a65ec028084b90800be377f8James Zern
2197c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE uint32_t GetPixPairHash64(const uint32_t* const argb) {
2207c8da7ce66017295a65ec028084b90800be377f8James Zern  uint32_t key;
221fa39824bb690c5806358871f46940d0450973d8aJames Zern  key  = (argb[1] * HASH_MULTIPLIER_HI) & 0xffffffffu;
222fa39824bb690c5806358871f46940d0450973d8aJames Zern  key += (argb[0] * HASH_MULTIPLIER_LO) & 0xffffffffu;
2237c8da7ce66017295a65ec028084b90800be377f8James Zern  key = key >> (32 - HASH_BITS);
22433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return key;
225a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
226a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
2277c8da7ce66017295a65ec028084b90800be377f8James Zern// Returns the maximum number of hash chain lookups to do for a
2280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// given compression quality. Return value in range [8, 86].
2290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic int GetMaxItersForQuality(int quality) {
2300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return 8 + (quality * quality) / 128;
2317c8da7ce66017295a65ec028084b90800be377f8James Zern}
2327c8da7ce66017295a65ec028084b90800be377f8James Zern
2337c8da7ce66017295a65ec028084b90800be377f8James Zernstatic int GetWindowSizeForHashChain(int quality, int xsize) {
2347c8da7ce66017295a65ec028084b90800be377f8James Zern  const int max_window_size = (quality > 75) ? WINDOW_SIZE
2357c8da7ce66017295a65ec028084b90800be377f8James Zern                            : (quality > 50) ? (xsize << 8)
2367c8da7ce66017295a65ec028084b90800be377f8James Zern                            : (quality > 25) ? (xsize << 6)
2371e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                            : (xsize << 4);
2381e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  assert(xsize > 0);
2397c8da7ce66017295a65ec028084b90800be377f8James Zern  return (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE : max_window_size;
2407c8da7ce66017295a65ec028084b90800be377f8James Zern}
2417c8da7ce66017295a65ec028084b90800be377f8James Zern
2427c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE int MaxFindCopyLength(int len) {
2437c8da7ce66017295a65ec028084b90800be377f8James Zern  return (len < MAX_LENGTH) ? len : MAX_LENGTH;
2447c8da7ce66017295a65ec028084b90800be377f8James Zern}
2457c8da7ce66017295a65ec028084b90800be377f8James Zern
2460912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernint VP8LHashChainFill(VP8LHashChain* const p, int quality,
247fa39824bb690c5806358871f46940d0450973d8aJames Zern                      const uint32_t* const argb, int xsize, int ysize,
248fa39824bb690c5806358871f46940d0450973d8aJames Zern                      int low_effort) {
2490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  const int size = xsize * ysize;
2500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  const int iter_max = GetMaxItersForQuality(quality);
2510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize);
2527c8da7ce66017295a65ec028084b90800be377f8James Zern  int pos;
253fa39824bb690c5806358871f46940d0450973d8aJames Zern  int argb_comp;
2540912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  uint32_t base_position;
2550912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int32_t* hash_to_first_index;
2560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Temporarily use the p->offset_length_ as a hash chain.
2570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int32_t* chain = (int32_t*)p->offset_length_;
258fa39824bb690c5806358871f46940d0450973d8aJames Zern  assert(size > 0);
2590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  assert(p->size_ != 0);
2600912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  assert(p->offset_length_ != NULL);
2610912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
262fa39824bb690c5806358871f46940d0450973d8aJames Zern  if (size <= 2) {
263fa39824bb690c5806358871f46940d0450973d8aJames Zern    p->offset_length_[0] = p->offset_length_[size - 1] = 0;
264fa39824bb690c5806358871f46940d0450973d8aJames Zern    return 1;
265fa39824bb690c5806358871f46940d0450973d8aJames Zern  }
266fa39824bb690c5806358871f46940d0450973d8aJames Zern
2670912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  hash_to_first_index =
2680912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      (int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index));
2690912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (hash_to_first_index == NULL) return 0;
2700912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
2710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Set the int32_t array to -1.
2720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index));
2730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Fill the chain linking pixels with the same hash.
274fa39824bb690c5806358871f46940d0450973d8aJames Zern  argb_comp = (argb[0] == argb[1]);
275fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (pos = 0; pos < size - 2;) {
276fa39824bb690c5806358871f46940d0450973d8aJames Zern    uint32_t hash_code;
277fa39824bb690c5806358871f46940d0450973d8aJames Zern    const int argb_comp_next = (argb[pos + 1] == argb[pos + 2]);
278fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (argb_comp && argb_comp_next) {
279fa39824bb690c5806358871f46940d0450973d8aJames Zern      // Consecutive pixels with the same color will share the same hash.
280fa39824bb690c5806358871f46940d0450973d8aJames Zern      // We therefore use a different hash: the color and its repetition
281fa39824bb690c5806358871f46940d0450973d8aJames Zern      // length.
282fa39824bb690c5806358871f46940d0450973d8aJames Zern      uint32_t tmp[2];
283fa39824bb690c5806358871f46940d0450973d8aJames Zern      uint32_t len = 1;
284fa39824bb690c5806358871f46940d0450973d8aJames Zern      tmp[0] = argb[pos];
285fa39824bb690c5806358871f46940d0450973d8aJames Zern      // Figure out how far the pixels are the same.
286fa39824bb690c5806358871f46940d0450973d8aJames Zern      // The last pixel has a different 64 bit hash, as its next pixel does
287fa39824bb690c5806358871f46940d0450973d8aJames Zern      // not have the same color, so we just need to get to the last pixel equal
288fa39824bb690c5806358871f46940d0450973d8aJames Zern      // to its follower.
289fa39824bb690c5806358871f46940d0450973d8aJames Zern      while (pos + (int)len + 2 < size && argb[pos + len + 2] == argb[pos]) {
290fa39824bb690c5806358871f46940d0450973d8aJames Zern        ++len;
291fa39824bb690c5806358871f46940d0450973d8aJames Zern      }
292fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (len > MAX_LENGTH) {
293fa39824bb690c5806358871f46940d0450973d8aJames Zern        // Skip the pixels that match for distance=1 and length>MAX_LENGTH
294fa39824bb690c5806358871f46940d0450973d8aJames Zern        // because they are linked to their predecessor and we automatically
295fa39824bb690c5806358871f46940d0450973d8aJames Zern        // check that in the main for loop below. Skipping means setting no
296fa39824bb690c5806358871f46940d0450973d8aJames Zern        // predecessor in the chain, hence -1.
297fa39824bb690c5806358871f46940d0450973d8aJames Zern        memset(chain + pos, 0xff, (len - MAX_LENGTH) * sizeof(*chain));
298fa39824bb690c5806358871f46940d0450973d8aJames Zern        pos += len - MAX_LENGTH;
299fa39824bb690c5806358871f46940d0450973d8aJames Zern        len = MAX_LENGTH;
300fa39824bb690c5806358871f46940d0450973d8aJames Zern      }
301fa39824bb690c5806358871f46940d0450973d8aJames Zern      // Process the rest of the hash chain.
302fa39824bb690c5806358871f46940d0450973d8aJames Zern      while (len) {
303fa39824bb690c5806358871f46940d0450973d8aJames Zern        tmp[1] = len--;
304fa39824bb690c5806358871f46940d0450973d8aJames Zern        hash_code = GetPixPairHash64(tmp);
305fa39824bb690c5806358871f46940d0450973d8aJames Zern        chain[pos] = hash_to_first_index[hash_code];
306fa39824bb690c5806358871f46940d0450973d8aJames Zern        hash_to_first_index[hash_code] = pos++;
307fa39824bb690c5806358871f46940d0450973d8aJames Zern      }
308fa39824bb690c5806358871f46940d0450973d8aJames Zern      argb_comp = 0;
309fa39824bb690c5806358871f46940d0450973d8aJames Zern    } else {
310fa39824bb690c5806358871f46940d0450973d8aJames Zern      // Just move one pixel forward.
311fa39824bb690c5806358871f46940d0450973d8aJames Zern      hash_code = GetPixPairHash64(argb + pos);
312fa39824bb690c5806358871f46940d0450973d8aJames Zern      chain[pos] = hash_to_first_index[hash_code];
313fa39824bb690c5806358871f46940d0450973d8aJames Zern      hash_to_first_index[hash_code] = pos++;
314fa39824bb690c5806358871f46940d0450973d8aJames Zern      argb_comp = argb_comp_next;
315fa39824bb690c5806358871f46940d0450973d8aJames Zern    }
3167c8da7ce66017295a65ec028084b90800be377f8James Zern  }
317fa39824bb690c5806358871f46940d0450973d8aJames Zern  // Process the penultimate pixel.
318fa39824bb690c5806358871f46940d0450973d8aJames Zern  chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)];
319fa39824bb690c5806358871f46940d0450973d8aJames Zern
3200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  WebPSafeFree(hash_to_first_index);
3210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
3220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Find the best match interval at each pixel, defined by an offset to the
3230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // pixel and a length. The right-most pixel cannot match anything to the right
3240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // (hence a best length of 0) and the left-most pixel nothing to the left
3250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // (hence an offset of 0).
326fa39824bb690c5806358871f46940d0450973d8aJames Zern  assert(size > 2);
3270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  p->offset_length_[0] = p->offset_length_[size - 1] = 0;
328fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (base_position = size - 2; base_position > 0;) {
3290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const int max_len = MaxFindCopyLength(size - 1 - base_position);
3300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const uint32_t* const argb_start = argb + base_position;
3310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int iter = iter_max;
3320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int best_length = 0;
3330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    uint32_t best_distance = 0;
334fa39824bb690c5806358871f46940d0450973d8aJames Zern    uint32_t best_argb;
3350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const int min_pos =
3360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        (base_position > window_size) ? base_position - window_size : 0;
3370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const int length_max = (max_len < 256) ? max_len : 256;
3380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    uint32_t max_base_position;
3390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
340fa39824bb690c5806358871f46940d0450973d8aJames Zern    pos = chain[base_position];
341fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (!low_effort) {
3420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      int curr_length;
343fa39824bb690c5806358871f46940d0450973d8aJames Zern      // Heuristic: use the comparison with the above line as an initialization.
344fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (base_position >= (uint32_t)xsize) {
345fa39824bb690c5806358871f46940d0450973d8aJames Zern        curr_length = FindMatchLength(argb_start - xsize, argb_start,
346fa39824bb690c5806358871f46940d0450973d8aJames Zern                                      best_length, max_len);
347fa39824bb690c5806358871f46940d0450973d8aJames Zern        if (curr_length > best_length) {
348fa39824bb690c5806358871f46940d0450973d8aJames Zern          best_length = curr_length;
349fa39824bb690c5806358871f46940d0450973d8aJames Zern          best_distance = xsize;
350fa39824bb690c5806358871f46940d0450973d8aJames Zern        }
351fa39824bb690c5806358871f46940d0450973d8aJames Zern        --iter;
352fa39824bb690c5806358871f46940d0450973d8aJames Zern      }
353fa39824bb690c5806358871f46940d0450973d8aJames Zern      // Heuristic: compare to the previous pixel.
354fa39824bb690c5806358871f46940d0450973d8aJames Zern      curr_length =
355fa39824bb690c5806358871f46940d0450973d8aJames Zern          FindMatchLength(argb_start - 1, argb_start, best_length, max_len);
356fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (curr_length > best_length) {
357fa39824bb690c5806358871f46940d0450973d8aJames Zern        best_length = curr_length;
358fa39824bb690c5806358871f46940d0450973d8aJames Zern        best_distance = 1;
3590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }
360fa39824bb690c5806358871f46940d0450973d8aJames Zern      --iter;
361fa39824bb690c5806358871f46940d0450973d8aJames Zern      // Skip the for loop if we already have the maximum.
362fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (best_length == MAX_LENGTH) pos = min_pos - 1;
363fa39824bb690c5806358871f46940d0450973d8aJames Zern    }
364fa39824bb690c5806358871f46940d0450973d8aJames Zern    best_argb = argb_start[best_length];
365fa39824bb690c5806358871f46940d0450973d8aJames Zern
366fa39824bb690c5806358871f46940d0450973d8aJames Zern    for (; pos >= min_pos && --iter; pos = chain[pos]) {
367fa39824bb690c5806358871f46940d0450973d8aJames Zern      int curr_length;
3680912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      assert(base_position > (uint32_t)pos);
3690912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
370fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (argb[pos + best_length] != best_argb) continue;
371fa39824bb690c5806358871f46940d0450973d8aJames Zern
372fa39824bb690c5806358871f46940d0450973d8aJames Zern      curr_length = VP8LVectorMismatch(argb + pos, argb_start, max_len);
3730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (best_length < curr_length) {
3740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        best_length = curr_length;
3750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        best_distance = base_position - pos;
376fa39824bb690c5806358871f46940d0450973d8aJames Zern        best_argb = argb_start[best_length];
377fa39824bb690c5806358871f46940d0450973d8aJames Zern        // Stop if we have reached a good enough length.
378fa39824bb690c5806358871f46940d0450973d8aJames Zern        if (best_length >= length_max) break;
3790912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }
380a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
3810912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // We have the best match but in case the two intervals continue matching
3820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // to the left, we have the best matches for the left-extended pixels.
3830912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    max_base_position = base_position;
3840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    while (1) {
3850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      assert(best_length <= MAX_LENGTH);
3860912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      assert(best_distance <= WINDOW_SIZE);
3870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      p->offset_length_[base_position] =
3880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          (best_distance << MAX_LENGTH_BITS) | (uint32_t)best_length;
3890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      --base_position;
3900912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // Stop if we don't have a match or if we are out of bounds.
3910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (best_distance == 0 || base_position == 0) break;
3920912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // Stop if we cannot extend the matching intervals to the left.
3930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (base_position < best_distance ||
3940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          argb[base_position - best_distance] != argb[base_position]) {
395a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        break;
396a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
3970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // Stop if we are matching at its limit because there could be a closer
3980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // matching interval with the same maximum length. Then again, if the
3990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // matching interval is as close as possible (best_distance == 1), we will
4000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // never find anything better so let's continue.
4010912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (best_length == MAX_LENGTH && best_distance != 1 &&
4020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          base_position + MAX_LENGTH < max_base_position) {
4030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        break;
4040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }
4050912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (best_length < MAX_LENGTH) {
4060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        ++best_length;
4070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        max_base_position = base_position;
4080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }
409a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
410a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
4110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return 1;
4120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
4130912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
4140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE int HashChainFindOffset(const VP8LHashChain* const p,
4150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                           const int base_position) {
4160912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return p->offset_length_[base_position] >> MAX_LENGTH_BITS;
4170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
4180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
4190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE int HashChainFindLength(const VP8LHashChain* const p,
4200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                           const int base_position) {
4210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return p->offset_length_[base_position] & ((1U << MAX_LENGTH_BITS) - 1);
4220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
4230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
4240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void HashChainFindCopy(const VP8LHashChain* const p,
4250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          int base_position,
4260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          int* const offset_ptr,
4270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          int* const length_ptr) {
4280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  *offset_ptr = HashChainFindOffset(p, base_position);
4290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  *length_ptr = HashChainFindLength(p, base_position);
430a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
431a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
4327c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache,
4337c8da7ce66017295a65ec028084b90800be377f8James Zern                                         VP8LColorCache* const hashers,
4347c8da7ce66017295a65ec028084b90800be377f8James Zern                                         VP8LBackwardRefs* const refs) {
4357c8da7ce66017295a65ec028084b90800be377f8James Zern  PixOrCopy v;
4367c8da7ce66017295a65ec028084b90800be377f8James Zern  if (use_color_cache) {
4377c8da7ce66017295a65ec028084b90800be377f8James Zern    const uint32_t key = VP8LColorCacheGetIndex(hashers, pixel);
4387c8da7ce66017295a65ec028084b90800be377f8James Zern    if (VP8LColorCacheLookup(hashers, key) == pixel) {
4397c8da7ce66017295a65ec028084b90800be377f8James Zern      v = PixOrCopyCreateCacheIdx(key);
4407c8da7ce66017295a65ec028084b90800be377f8James Zern    } else {
4417c8da7ce66017295a65ec028084b90800be377f8James Zern      v = PixOrCopyCreateLiteral(pixel);
4427c8da7ce66017295a65ec028084b90800be377f8James Zern      VP8LColorCacheSet(hashers, key, pixel);
4437c8da7ce66017295a65ec028084b90800be377f8James Zern    }
4447c8da7ce66017295a65ec028084b90800be377f8James Zern  } else {
4457c8da7ce66017295a65ec028084b90800be377f8James Zern    v = PixOrCopyCreateLiteral(pixel);
446a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
4477c8da7ce66017295a65ec028084b90800be377f8James Zern  BackwardRefsCursorAdd(refs, v);
448a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
449a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
45033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int BackwardReferencesRle(int xsize, int ysize,
45133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                 const uint32_t* const argb,
4527c8da7ce66017295a65ec028084b90800be377f8James Zern                                 int cache_bits, VP8LBackwardRefs* const refs) {
453a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int pix_count = xsize * ysize;
4547c8da7ce66017295a65ec028084b90800be377f8James Zern  int i, k;
4557c8da7ce66017295a65ec028084b90800be377f8James Zern  const int use_color_cache = (cache_bits > 0);
4567c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LColorCache hashers;
4577c8da7ce66017295a65ec028084b90800be377f8James Zern
4587c8da7ce66017295a65ec028084b90800be377f8James Zern  if (use_color_cache && !VP8LColorCacheInit(&hashers, cache_bits)) {
4597c8da7ce66017295a65ec028084b90800be377f8James Zern    return 0;
4607c8da7ce66017295a65ec028084b90800be377f8James Zern  }
46133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
4627c8da7ce66017295a65ec028084b90800be377f8James Zern  // Add first pixel as literal.
4637c8da7ce66017295a65ec028084b90800be377f8James Zern  AddSingleLiteral(argb[0], use_color_cache, &hashers, refs);
4647c8da7ce66017295a65ec028084b90800be377f8James Zern  i = 1;
4657c8da7ce66017295a65ec028084b90800be377f8James Zern  while (i < pix_count) {
4667c8da7ce66017295a65ec028084b90800be377f8James Zern    const int max_len = MaxFindCopyLength(pix_count - i);
4677c8da7ce66017295a65ec028084b90800be377f8James Zern    const int rle_len = FindMatchLength(argb + i, argb + i - 1, 0, max_len);
4687c8da7ce66017295a65ec028084b90800be377f8James Zern    const int prev_row_len = (i < xsize) ? 0 :
4697c8da7ce66017295a65ec028084b90800be377f8James Zern        FindMatchLength(argb + i, argb + i - xsize, 0, max_len);
470fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (rle_len >= prev_row_len && rle_len >= MIN_LENGTH) {
4717c8da7ce66017295a65ec028084b90800be377f8James Zern      BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, rle_len));
4727c8da7ce66017295a65ec028084b90800be377f8James Zern      // We don't need to update the color cache here since it is always the
4737c8da7ce66017295a65ec028084b90800be377f8James Zern      // same pixel being copied, and that does not change the color cache
4747c8da7ce66017295a65ec028084b90800be377f8James Zern      // state.
4757c8da7ce66017295a65ec028084b90800be377f8James Zern      i += rle_len;
476fa39824bb690c5806358871f46940d0450973d8aJames Zern    } else if (prev_row_len >= MIN_LENGTH) {
4777c8da7ce66017295a65ec028084b90800be377f8James Zern      BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(xsize, prev_row_len));
4787c8da7ce66017295a65ec028084b90800be377f8James Zern      if (use_color_cache) {
4797c8da7ce66017295a65ec028084b90800be377f8James Zern        for (k = 0; k < prev_row_len; ++k) {
4807c8da7ce66017295a65ec028084b90800be377f8James Zern          VP8LColorCacheInsert(&hashers, argb[i + k]);
4817c8da7ce66017295a65ec028084b90800be377f8James Zern        }
4827c8da7ce66017295a65ec028084b90800be377f8James Zern      }
4837c8da7ce66017295a65ec028084b90800be377f8James Zern      i += prev_row_len;
484a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    } else {
4857c8da7ce66017295a65ec028084b90800be377f8James Zern      AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
4867c8da7ce66017295a65ec028084b90800be377f8James Zern      i++;
487a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
488a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
4897c8da7ce66017295a65ec028084b90800be377f8James Zern  if (use_color_cache) VP8LColorCacheClear(&hashers);
49033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return !refs->error_;
491a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
492a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
4937c8da7ce66017295a65ec028084b90800be377f8James Zernstatic int BackwardReferencesLz77(int xsize, int ysize,
4947c8da7ce66017295a65ec028084b90800be377f8James Zern                                  const uint32_t* const argb, int cache_bits,
4950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                  const VP8LHashChain* const hash_chain,
4967c8da7ce66017295a65ec028084b90800be377f8James Zern                                  VP8LBackwardRefs* const refs) {
497a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i;
4980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int i_last_check = -1;
499a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
500a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int cc_init = 0;
501a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int use_color_cache = (cache_bits > 0);
502a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int pix_count = xsize * ysize;
503a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  VP8LColorCache hashers;
504a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
505a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (use_color_cache) {
506a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    cc_init = VP8LColorCacheInit(&hashers, cache_bits);
507a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!cc_init) goto Error;
508a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
50933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
5100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  for (i = 0; i < pix_count;) {
511a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    // Alternative#1: Code the pixels starting at 'i' using backward reference.
512a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int offset = 0;
513a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int len = 0;
5140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int j;
5150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    HashChainFindCopy(hash_chain, i, &offset, &len);
516fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (len >= MIN_LENGTH) {
5170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      const int len_ini = len;
5180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      int max_reach = 0;
5190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      assert(i + len < pix_count);
5200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // Only start from what we have not checked already.
5210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      i_last_check = (i > i_last_check) ? i : i_last_check;
5220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // We know the best match for the current pixel but we try to find the
5230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // best matches for the current pixel AND the next one combined.
5240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // The naive method would use the intervals:
5250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // [i,i+len) + [i+len, length of best match at i+len)
5260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // while we check if we can use:
5270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // [i,j) (where j<=i+len) + [j, length of best match at j)
5280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      for (j = i_last_check + 1; j <= i + len_ini; ++j) {
5290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        const int len_j = HashChainFindLength(hash_chain, j);
5300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        const int reach =
531fa39824bb690c5806358871f46940d0450973d8aJames Zern            j + (len_j >= MIN_LENGTH ? len_j : 1);  // 1 for single literal.
5320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (reach > max_reach) {
5330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          len = j - i;
5340912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          max_reach = reach;
535a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
536a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
537a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    } else {
5380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      len = 1;
5390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
5400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Go with literal or backward reference.
5410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    assert(len > 0);
5420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (len == 1) {
5437c8da7ce66017295a65ec028084b90800be377f8James Zern      AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
5440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    } else {
5450912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len));
5460912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (use_color_cache) {
5470912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        for (j = i; j < i + len; ++j) VP8LColorCacheInsert(&hashers, argb[j]);
548a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
549a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
5500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    i += len;
5517c8da7ce66017295a65ec028084b90800be377f8James Zern  }
5527c8da7ce66017295a65ec028084b90800be377f8James Zern
55333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ok = !refs->error_;
5547c8da7ce66017295a65ec028084b90800be377f8James Zern Error:
555a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (cc_init) VP8LColorCacheClear(&hashers);
556a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
557a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
558a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
559a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
560a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
561a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroratypedef struct {
562a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double alpha_[VALUES_IN_BYTE];
563a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double red_[VALUES_IN_BYTE];
564a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double blue_[VALUES_IN_BYTE];
565a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double distance_[NUM_DISTANCE_CODES];
5667c8da7ce66017295a65ec028084b90800be377f8James Zern  double* literal_;
567a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora} CostModel;
568a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
569a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int BackwardReferencesTraceBackwards(
5707c8da7ce66017295a65ec028084b90800be377f8James Zern    int xsize, int ysize, const uint32_t* const argb, int quality,
5710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int cache_bits, const VP8LHashChain* const hash_chain,
5721e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    VP8LBackwardRefs* const refs);
573a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
574a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic void ConvertPopulationCountTableToBitEstimates(
57533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int num_symbols, const uint32_t population_counts[], double output[]) {
57633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint32_t sum = 0;
577a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int nonzeros = 0;
578a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i;
579a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  for (i = 0; i < num_symbols; ++i) {
580a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    sum += population_counts[i];
581a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (population_counts[i] > 0) {
582a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      ++nonzeros;
583a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
584a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
585a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (nonzeros <= 1) {
586a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    memset(output, 0, num_symbols * sizeof(*output));
587a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  } else {
588a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    const double logsum = VP8LFastLog2(sum);
589a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    for (i = 0; i < num_symbols; ++i) {
590a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      output[i] = logsum - VP8LFastLog2(population_counts[i]);
591a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
592a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
593a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
594a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
5957c8da7ce66017295a65ec028084b90800be377f8James Zernstatic int CostModelBuild(CostModel* const m, int cache_bits,
59633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          VP8LBackwardRefs* const refs) {
597a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
5987c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LHistogram* const histo = VP8LAllocateHistogram(cache_bits);
59933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (histo == NULL) goto Error;
60033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
60133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LHistogramCreate(histo, refs, cache_bits);
60233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
603a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
60433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VP8LHistogramNumCodes(histo->palette_code_bits_),
60533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      histo->literal_, m->literal_);
606a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
60733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VALUES_IN_BYTE, histo->red_, m->red_);
608a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
60933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VALUES_IN_BYTE, histo->blue_, m->blue_);
610a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
61133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VALUES_IN_BYTE, histo->alpha_, m->alpha_);
612a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
61333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      NUM_DISTANCE_CODES, histo->distance_, m->distance_);
614a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ok = 1;
615a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
616a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora Error:
61733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LFreeHistogram(histo);
618a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
619a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
620a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
621a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) {
622a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return m->alpha_[v >> 24] +
623a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora         m->red_[(v >> 16) & 0xff] +
624a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora         m->literal_[(v >> 8) & 0xff] +
625a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora         m->blue_[v & 0xff];
626a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
627a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
628a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
629a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx;
630a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return m->literal_[literal_idx];
631a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
632a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
633a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE double GetLengthCost(const CostModel* const m,
634a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                        uint32_t length) {
6358b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int code, extra_bits;
6368b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  VP8LPrefixEncodeBits(length, &code, &extra_bits);
6378b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return m->literal_[VALUES_IN_BYTE + code] + extra_bits;
638a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
639a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
640a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE double GetDistanceCost(const CostModel* const m,
641a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                          uint32_t distance) {
6428b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int code, extra_bits;
6438b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  VP8LPrefixEncodeBits(distance, &code, &extra_bits);
6448b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return m->distance_[code] + extra_bits;
645a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
646a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
6470912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic void AddSingleLiteralWithCostModel(const uint32_t* const argb,
6480912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          VP8LColorCache* const hashers,
6490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          const CostModel* const cost_model,
6500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          int idx, int use_color_cache,
6510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          double prev_cost, float* const cost,
6520912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          uint16_t* const dist_array) {
6537c8da7ce66017295a65ec028084b90800be377f8James Zern  double cost_val = prev_cost;
6547c8da7ce66017295a65ec028084b90800be377f8James Zern  const uint32_t color = argb[0];
655fa39824bb690c5806358871f46940d0450973d8aJames Zern  const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1;
656fa39824bb690c5806358871f46940d0450973d8aJames Zern  if (ix >= 0) {
657fa39824bb690c5806358871f46940d0450973d8aJames Zern    // use_color_cache is true and hashers contains color
6587c8da7ce66017295a65ec028084b90800be377f8James Zern    const double mul0 = 0.68;
6597c8da7ce66017295a65ec028084b90800be377f8James Zern    cost_val += GetCacheCost(cost_model, ix) * mul0;
6607c8da7ce66017295a65ec028084b90800be377f8James Zern  } else {
6617c8da7ce66017295a65ec028084b90800be377f8James Zern    const double mul1 = 0.82;
6627c8da7ce66017295a65ec028084b90800be377f8James Zern    if (use_color_cache) VP8LColorCacheInsert(hashers, color);
6637c8da7ce66017295a65ec028084b90800be377f8James Zern    cost_val += GetLiteralCost(cost_model, color) * mul1;
6647c8da7ce66017295a65ec028084b90800be377f8James Zern  }
6657c8da7ce66017295a65ec028084b90800be377f8James Zern  if (cost[idx] > cost_val) {
6667c8da7ce66017295a65ec028084b90800be377f8James Zern    cost[idx] = (float)cost_val;
6677c8da7ce66017295a65ec028084b90800be377f8James Zern    dist_array[idx] = 1;  // only one is inserted.
6687c8da7ce66017295a65ec028084b90800be377f8James Zern  }
6697c8da7ce66017295a65ec028084b90800be377f8James Zern}
6707c8da7ce66017295a65ec028084b90800be377f8James Zern
6710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// -----------------------------------------------------------------------------
6720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// CostManager and interval handling
6730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
6740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Empirical value to avoid high memory consumption but good for performance.
6750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#define COST_CACHE_INTERVAL_SIZE_MAX 100
6760912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
6770912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// To perform backward reference every pixel at index index_ is considered and
6780912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// the cost for the MAX_LENGTH following pixels computed. Those following pixels
6790912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// at index index_ + k (k from 0 to MAX_LENGTH) have a cost of:
6800912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern//     distance_cost_ at index_ + GetLengthCost(cost_model, k)
6810912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern//            (named cost)            (named cached cost)
6820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// and the minimum value is kept. GetLengthCost(cost_model, k) is cached in an
6830912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// array of size MAX_LENGTH.
6840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Instead of performing MAX_LENGTH comparisons per pixel, we keep track of the
6850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// minimal values using intervals, for which lower_ and upper_ bounds are kept.
6860912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// An interval is defined by the index_ of the pixel that generated it and
6870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// is only useful in a range of indices from start_ to end_ (exclusive), i.e.
6880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// it contains the minimum value for pixels between start_ and end_.
6890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Intervals are stored in a linked list and ordered by start_. When a new
6900912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// interval has a better minimum, old intervals are split or removed.
6910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zerntypedef struct CostInterval CostInterval;
6920912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstruct CostInterval {
6930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double lower_;
6940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double upper_;
6950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int start_;
6960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int end_;
6970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double distance_cost_;
6980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int index_;
6990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* previous_;
7000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* next_;
7010912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern};
7020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// The GetLengthCost(cost_model, k) part of the costs is also bounded for
7040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// efficiency in a set of intervals of a different type.
7050912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// If those intervals are small enough, they are not used for comparison and
7060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// written into the costs right away.
7070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zerntypedef struct {
7080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double lower_;  // Lower bound of the interval.
7090912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double upper_;  // Upper bound of the interval.
7100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int start_;
7110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int end_;       // Exclusive.
7120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int do_write_;  // If !=0, the interval is saved to cost instead of being kept
7130912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                  // for comparison.
7140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern} CostCacheInterval;
7150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7160912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// This structure is in charge of managing intervals and costs.
7170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// It caches the different CostCacheInterval, caches the different
7180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// GetLengthCost(cost_model, k) in cost_cache_ and the CostInterval's (whose
7190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// count_ is limited by COST_CACHE_INTERVAL_SIZE_MAX).
7200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern#define COST_MANAGER_MAX_FREE_LIST 10
7210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zerntypedef struct {
7220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* head_;
7230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int count_;  // The number of stored intervals.
7240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostCacheInterval* cache_intervals_;
7250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  size_t cache_intervals_size_;
7260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double cost_cache_[MAX_LENGTH];  // Contains the GetLengthCost(cost_model, k).
7270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double min_cost_cache_;          // The minimum value in cost_cache_[1:].
7280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double max_cost_cache_;          // The maximum value in cost_cache_[1:].
7290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  float* costs_;
7300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  uint16_t* dist_array_;
7310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Most of the time, we only need few intervals -> use a free-list, to avoid
7320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // fragmentation with small allocs in most common cases.
7330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval intervals_[COST_MANAGER_MAX_FREE_LIST];
7340912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* free_intervals_;
7350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // These are regularly malloc'd remains. This list can't grow larger than than
7360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // size COST_CACHE_INTERVAL_SIZE_MAX - COST_MANAGER_MAX_FREE_LIST, note.
7370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* recycled_intervals_;
7380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Buffer used in BackwardReferencesHashChainDistanceOnly to store the ends
7390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // of the intervals that can have impacted the cost at a pixel.
7400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int* interval_ends_;
7410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int interval_ends_size_;
7420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern} CostManager;
7430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic int IsCostCacheIntervalWritable(int start, int end) {
7450912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // 100 is the length for which we consider an interval for comparison, and not
7460912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // for writing.
7470912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // The first intervals are very small and go in increasing size. This constant
7480912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // helps merging them into one big interval (up to index 150/200 usually from
7490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // which intervals start getting much bigger).
7500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // This value is empirical.
7510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (end - start + 1 < 100);
7520912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
7530912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7540912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic void CostIntervalAddToFreeList(CostManager* const manager,
7550912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                      CostInterval* const interval) {
7560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  interval->next_ = manager->free_intervals_;
7570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->free_intervals_ = interval;
7580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
7590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7600912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic int CostIntervalIsInFreeList(const CostManager* const manager,
7610912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                    const CostInterval* const interval) {
7620912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (interval >= &manager->intervals_[0] &&
7630912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          interval <= &manager->intervals_[COST_MANAGER_MAX_FREE_LIST - 1]);
7640912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
7650912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7660912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic void CostManagerInitFreeList(CostManager* const manager) {
7670912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int i;
7680912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->free_intervals_ = NULL;
7690912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  for (i = 0; i < COST_MANAGER_MAX_FREE_LIST; ++i) {
7700912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    CostIntervalAddToFreeList(manager, &manager->intervals_[i]);
7710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
7720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
7730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic void DeleteIntervalList(CostManager* const manager,
7750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                               const CostInterval* interval) {
7760912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  while (interval != NULL) {
7770912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const CostInterval* const next = interval->next_;
7780912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (!CostIntervalIsInFreeList(manager, interval)) {
7790912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      WebPSafeFree((void*)interval);
7800912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }  // else: do nothing
7810912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    interval = next;
7820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
7830912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
7840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic void CostManagerClear(CostManager* const manager) {
7860912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (manager == NULL) return;
7870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  WebPSafeFree(manager->costs_);
7890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  WebPSafeFree(manager->cache_intervals_);
7900912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  WebPSafeFree(manager->interval_ends_);
7910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7920912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Clear the interval lists.
7930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  DeleteIntervalList(manager, manager->head_);
7940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->head_ = NULL;
7950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  DeleteIntervalList(manager, manager->recycled_intervals_);
7960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->recycled_intervals_ = NULL;
7970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
7980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Reset pointers, count_ and cache_intervals_size_.
7990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  memset(manager, 0, sizeof(*manager));
8000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostManagerInitFreeList(manager);
8010912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
8020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
8030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic int CostManagerInit(CostManager* const manager,
8040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                           uint16_t* const dist_array, int pix_count,
8050912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                           const CostModel* const cost_model) {
8060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int i;
8070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  const int cost_cache_size = (pix_count > MAX_LENGTH) ? MAX_LENGTH : pix_count;
8080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // This constant is tied to the cost_model we use.
8090912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Empirically, differences between intervals is usually of more than 1.
8100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  const double min_cost_diff = 0.1;
8110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
8120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->costs_ = NULL;
8130912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->cache_intervals_ = NULL;
8140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->interval_ends_ = NULL;
8150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->head_ = NULL;
8160912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->recycled_intervals_ = NULL;
8170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->count_ = 0;
8180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->dist_array_ = dist_array;
8190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostManagerInitFreeList(manager);
8200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
8210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Fill in the cost_cache_.
8220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->cache_intervals_size_ = 1;
8230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->cost_cache_[0] = 0;
8240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  for (i = 1; i < cost_cache_size; ++i) {
8250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->cost_cache_[i] = GetLengthCost(cost_model, i);
8260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Get an approximation of the number of bound intervals.
8270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (fabs(manager->cost_cache_[i] - manager->cost_cache_[i - 1]) >
8280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        min_cost_diff) {
8290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      ++manager->cache_intervals_size_;
8300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
8310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Compute the minimum of cost_cache_.
8320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (i == 1) {
8330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      manager->min_cost_cache_ = manager->cost_cache_[1];
8340912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      manager->max_cost_cache_ = manager->cost_cache_[1];
8350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    } else if (manager->cost_cache_[i] < manager->min_cost_cache_) {
8360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      manager->min_cost_cache_ = manager->cost_cache_[i];
8370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    } else if (manager->cost_cache_[i] > manager->max_cost_cache_) {
8380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      manager->max_cost_cache_ = manager->cost_cache_[i];
8390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
8400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
8410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
8420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // With the current cost models, we have 15 intervals, so we are safe by
8430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // setting a maximum of COST_CACHE_INTERVAL_SIZE_MAX.
8440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (manager->cache_intervals_size_ > COST_CACHE_INTERVAL_SIZE_MAX) {
8450912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->cache_intervals_size_ = COST_CACHE_INTERVAL_SIZE_MAX;
8460912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
8470912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->cache_intervals_ = (CostCacheInterval*)WebPSafeMalloc(
8480912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      manager->cache_intervals_size_, sizeof(*manager->cache_intervals_));
8490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (manager->cache_intervals_ == NULL) {
8500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    CostManagerClear(manager);
8510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    return 0;
8520912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
8530912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
8540912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Fill in the cache_intervals_.
8550912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  {
8560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    double cost_prev = -1e38f;  // unprobably low initial value
8570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    CostCacheInterval* prev = NULL;
8580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    CostCacheInterval* cur = manager->cache_intervals_;
8590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const CostCacheInterval* const end =
8600912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        manager->cache_intervals_ + manager->cache_intervals_size_;
8610912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
8620912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Consecutive values in cost_cache_ are compared and if a big enough
8630912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // difference is found, a new interval is created and bounded.
8640912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    for (i = 0; i < cost_cache_size; ++i) {
8650912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      const double cost_val = manager->cost_cache_[i];
8660912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (i == 0 ||
8670912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          (fabs(cost_val - cost_prev) > min_cost_diff && cur + 1 < end)) {
8680912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (i > 1) {
8690912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          const int is_writable =
8700912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern              IsCostCacheIntervalWritable(cur->start_, cur->end_);
8710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // Merge with the previous interval if both are writable.
8720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          if (is_writable && cur != manager->cache_intervals_ &&
8730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern              prev->do_write_) {
8740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            // Update the previous interval.
8750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            prev->end_ = cur->end_;
8760912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            if (cur->lower_ < prev->lower_) {
8770912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern              prev->lower_ = cur->lower_;
8780912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            } else if (cur->upper_ > prev->upper_) {
8790912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern              prev->upper_ = cur->upper_;
8800912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            }
8810912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          } else {
8820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            cur->do_write_ = is_writable;
8830912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            prev = cur;
8840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            ++cur;
8850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          }
8860912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        }
8870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // Initialize an interval.
8880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        cur->start_ = i;
8890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        cur->do_write_ = 0;
8900912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        cur->lower_ = cost_val;
8910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        cur->upper_ = cost_val;
8920912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      } else {
8930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // Update the current interval bounds.
8940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (cost_val < cur->lower_) {
8950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          cur->lower_ = cost_val;
8960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        } else if (cost_val > cur->upper_) {
8970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          cur->upper_ = cost_val;
8980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        }
8990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }
9000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      cur->end_ = i + 1;
9010912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      cost_prev = cost_val;
9020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
9030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->cache_intervals_size_ = cur + 1 - manager->cache_intervals_;
9040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
9050912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  manager->costs_ = (float*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_));
9070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (manager->costs_ == NULL) {
9080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    CostManagerClear(manager);
9090912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    return 0;
9100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
9110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Set the initial costs_ high for every pixel as we will keep the minimum.
9120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  for (i = 0; i < pix_count; ++i) manager->costs_[i] = 1e38f;
9130912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // The cost at pixel is influenced by the cost intervals from previous pixels.
9150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Let us take the specific case where the offset is the same (which actually
9160912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // happens a lot in case of uniform regions).
9170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // pixel i contributes to j>i a cost of: offset cost + cost_cache_[j-i]
9180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // pixel i+1 contributes to j>i a cost of: 2*offset cost + cost_cache_[j-i-1]
9190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // pixel i+2 contributes to j>i a cost of: 3*offset cost + cost_cache_[j-i-2]
9200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // and so on.
9210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // A pixel i influences the following length(j) < MAX_LENGTH pixels. What is
9220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // the value of j such that pixel i + j cannot influence any of those pixels?
9230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // This value is such that:
9240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  //               max of cost_cache_ < j*offset cost + min of cost_cache_
9250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // (pixel i + j 's cost cannot beat the worst cost given by pixel i).
9260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // This value will be used to optimize the cost computation in
9270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // BackwardReferencesHashChainDistanceOnly.
9280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  {
9290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // The offset cost is computed in GetDistanceCost and has a minimum value of
9300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // the minimum in cost_model->distance_. The case where the offset cost is 0
9310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // will be dealt with differently later so we are only interested in the
9320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // minimum non-zero offset cost.
9330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    double offset_cost_min = 0.;
9340912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int size;
9350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
9360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (cost_model->distance_[i] != 0) {
9370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (offset_cost_min == 0.) {
9380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          offset_cost_min = cost_model->distance_[i];
9390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        } else if (cost_model->distance_[i] < offset_cost_min) {
9400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          offset_cost_min = cost_model->distance_[i];
9410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        }
9420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }
9430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
9440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // In case all the cost_model->distance_ is 0, the next non-zero cost we
9450912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // can have is from the extra bit in GetDistanceCost, hence 1.
9460912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (offset_cost_min < 1.) offset_cost_min = 1.;
9470912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9480912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    size = 1 + (int)ceil((manager->max_cost_cache_ - manager->min_cost_cache_) /
9490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                         offset_cost_min);
9500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Empirically, we usually end up with a value below 100.
9510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (size > MAX_LENGTH) size = MAX_LENGTH;
9520912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9530912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->interval_ends_ =
9540912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        (int*)WebPSafeMalloc(size, sizeof(*manager->interval_ends_));
9550912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (manager->interval_ends_ == NULL) {
9560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      CostManagerClear(manager);
9570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      return 0;
9580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
9590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->interval_ends_size_ = size;
9600912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
9610912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9620912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return 1;
9630912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
9640912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9650912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Given the distance_cost for pixel 'index', update the cost at pixel 'i' if it
9660912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// is smaller than the previously computed value.
9670912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void UpdateCost(CostManager* const manager, int i, int index,
9680912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                   double distance_cost) {
9690912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int k = i - index;
9700912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  double cost_tmp;
9710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  assert(k >= 0 && k < MAX_LENGTH);
9720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  cost_tmp = distance_cost + manager->cost_cache_[k];
9730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (manager->costs_[i] > cost_tmp) {
9750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->costs_[i] = (float)cost_tmp;
9760912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->dist_array_[i] = k + 1;
9770912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
9780912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
9790912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9800912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Given the distance_cost for pixel 'index', update the cost for all the pixels
9810912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// between 'start' and 'end' excluded.
9820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void UpdateCostPerInterval(CostManager* const manager,
9830912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                              int start, int end, int index,
9840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                              double distance_cost) {
9850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  int i;
9860912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  for (i = start; i < end; ++i) UpdateCost(manager, i, index, distance_cost);
9870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
9880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Given two intervals, make 'prev' be the previous one of 'next' in 'manager'.
9900912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void ConnectIntervals(CostManager* const manager,
9910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                         CostInterval* const prev,
9920912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                         CostInterval* const next) {
9930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (prev != NULL) {
9940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    prev->next_ = next;
9950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  } else {
9960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->head_ = next;
9970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
9980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
9990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (next != NULL) next->previous_ = prev;
10000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
10010912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Pop an interval in the manager.
10030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void PopInterval(CostManager* const manager,
10040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                    CostInterval* const interval) {
10050912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* const next = interval->next_;
10060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (interval == NULL) return;
10080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10090912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  ConnectIntervals(manager, interval->previous_, next);
10100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (CostIntervalIsInFreeList(manager, interval)) {
10110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    CostIntervalAddToFreeList(manager, interval);
10120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  } else {  // recycle regularly malloc'd intervals too
10130912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    interval->next_ = manager->recycled_intervals_;
10140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->recycled_intervals_ = interval;
10150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
10160912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  --manager->count_;
10170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  assert(manager->count_ >= 0);
10180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
10190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Update the cost at index i by going over all the stored intervals that
10210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// overlap with i.
10220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void UpdateCostPerIndex(CostManager* const manager, int i) {
10230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* current = manager->head_;
10240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  while (current != NULL && current->start_ <= i) {
10260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (current->end_ <= i) {
10270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // We have an outdated interval, remove it.
10280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      CostInterval* next = current->next_;
10290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      PopInterval(manager, current);
10300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      current = next;
10310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    } else {
10320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      UpdateCost(manager, i, current->index_, current->distance_cost_);
10330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      current = current->next_;
10340912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
10350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
10360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
10370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Given a current orphan interval and its previous interval, before
10390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// it was orphaned (which can be NULL), set it at the right place in the list
10400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// of intervals using the start_ ordering and the previous interval as a hint.
10410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void PositionOrphanInterval(CostManager* const manager,
10420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                               CostInterval* const current,
10430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                               CostInterval* previous) {
10440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  assert(current != NULL);
10450912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10460912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (previous == NULL) previous = manager->head_;
10470912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  while (previous != NULL && current->start_ < previous->start_) {
10480912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    previous = previous->previous_;
10490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
10500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  while (previous != NULL && previous->next_ != NULL &&
10510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern         previous->next_->start_ < current->start_) {
10520912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    previous = previous->next_;
10530912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
10540912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10550912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (previous != NULL) {
10560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    ConnectIntervals(manager, current, previous->next_);
10570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  } else {
10580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    ConnectIntervals(manager, current, manager->head_);
10590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
10600912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  ConnectIntervals(manager, previous, current);
10610912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
10620912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10630912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Insert an interval in the list contained in the manager by starting at
10640912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// interval_in as a hint. The intervals are sorted by start_ value.
10650912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void InsertInterval(CostManager* const manager,
10660912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                       CostInterval* const interval_in,
10670912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                       double distance_cost, double lower,
10680912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                       double upper, int index, int start,
10690912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                       int end) {
10700912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* interval_new;
10710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (IsCostCacheIntervalWritable(start, end) ||
10730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      manager->count_ >= COST_CACHE_INTERVAL_SIZE_MAX) {
10740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Write down the interval if it is too small.
10750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    UpdateCostPerInterval(manager, start, end, index, distance_cost);
10760912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    return;
10770912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
10780912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (manager->free_intervals_ != NULL) {
10790912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    interval_new = manager->free_intervals_;
10800912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->free_intervals_ = interval_new->next_;
10810912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  } else if (manager->recycled_intervals_ != NULL) {
10820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    interval_new = manager->recycled_intervals_;
10830912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    manager->recycled_intervals_ = interval_new->next_;
10840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  } else {   // malloc for good
10850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    interval_new = (CostInterval*)WebPSafeMalloc(1, sizeof(*interval_new));
10860912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (interval_new == NULL) {
10870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // Write down the interval if we cannot create it.
10880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      UpdateCostPerInterval(manager, start, end, index, distance_cost);
10890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      return;
10900912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
10910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
10920912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
10930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  interval_new->distance_cost_ = distance_cost;
10940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  interval_new->lower_ = lower;
10950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  interval_new->upper_ = upper;
10960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  interval_new->index_ = index;
10970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  interval_new->start_ = start;
10980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  interval_new->end_ = end;
10990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  PositionOrphanInterval(manager, interval_new, interval_in);
11000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11010912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  ++manager->count_;
11020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
11030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// When an interval has its start_ or end_ modified, it needs to be
11050912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// repositioned in the linked list.
11060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void RepositionInterval(CostManager* const manager,
11070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                           CostInterval* const interval) {
11080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (IsCostCacheIntervalWritable(interval->start_, interval->end_)) {
11090912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Maybe interval has been resized and is small enough to be removed.
11100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    UpdateCostPerInterval(manager, interval->start_, interval->end_,
11110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                          interval->index_, interval->distance_cost_);
11120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    PopInterval(manager, interval);
11130912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    return;
11140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
11150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11160912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  // Early exit if interval is at the right spot.
11170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if ((interval->previous_ == NULL ||
11180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern       interval->previous_->start_ <= interval->start_) &&
11190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      (interval->next_ == NULL ||
11200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern       interval->start_ <= interval->next_->start_)) {
11210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    return;
11220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
11230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  ConnectIntervals(manager, interval->previous_, interval->next_);
11250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  PositionOrphanInterval(manager, interval, interval->previous_);
11260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
11270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// Given a new cost interval defined by its start at index, its last value and
11290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// distance_cost, add its contributions to the previous intervals and costs.
11300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// If handling the interval or one of its subintervals becomes to heavy, its
11310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern// contribution is added to the costs right away.
11320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic WEBP_INLINE void PushInterval(CostManager* const manager,
11330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                     double distance_cost, int index,
11340912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                     int last) {
11350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  size_t i;
11360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* interval = manager->head_;
11370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostInterval* interval_next;
11380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  const CostCacheInterval* const cost_cache_intervals =
11390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      manager->cache_intervals_;
11400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  for (i = 0; i < manager->cache_intervals_size_ &&
11420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern              cost_cache_intervals[i].start_ < last;
11430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern       ++i) {
11440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Define the intersection of the ith interval with the new one.
11450912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int start = index + cost_cache_intervals[i].start_;
11460912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const int end = index + (cost_cache_intervals[i].end_ > last
11470912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                 ? last
11480912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                 : cost_cache_intervals[i].end_);
11490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const double lower_in = cost_cache_intervals[i].lower_;
11500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const double upper_in = cost_cache_intervals[i].upper_;
11510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const double lower_full_in = distance_cost + lower_in;
11520912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const double upper_full_in = distance_cost + upper_in;
11530912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11540912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (cost_cache_intervals[i].do_write_) {
11550912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      UpdateCostPerInterval(manager, start, end, index, distance_cost);
11560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      continue;
11570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
11580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    for (; interval != NULL && interval->start_ < end && start < end;
11600912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern         interval = interval_next) {
11610912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      const double lower_full_interval =
11620912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          interval->distance_cost_ + interval->lower_;
11630912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      const double upper_full_interval =
11640912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          interval->distance_cost_ + interval->upper_;
11650912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11660912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      interval_next = interval->next_;
11670912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11680912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // Make sure we have some overlap
11690912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (start >= interval->end_) continue;
11700912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (lower_full_in >= upper_full_interval) {
11720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // When intervals are represented, the lower, the better.
11730912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // [**********************************************************]
11740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // start                                                    end
11750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        //                   [----------------------------------]
11760912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        //                   interval->start_       interval->end_
11770912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // If we are worse than what we already have, add whatever we have so
11780912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // far up to interval.
11790912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        const int start_new = interval->end_;
11800912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        InsertInterval(manager, interval, distance_cost, lower_in, upper_in,
11810912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                       index, start, interval->start_);
11820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        start = start_new;
11830912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        continue;
11840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }
11850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
11860912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // We know the two intervals intersect.
11870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (upper_full_in >= lower_full_interval) {
11880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // There is no clear cut on which is best, so let's keep both.
11890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // [*********[*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*]***********]
11900912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // start     interval->start_     interval->end_         end
11910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // OR
11920912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // [*********[*-*-*-*-*-*-*-*-*-*-*-]----------------------]
11930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // start     interval->start_     end          interval->end_
11940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        const int end_new = (interval->end_ <= end) ? interval->end_ : end;
11950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        InsertInterval(manager, interval, distance_cost, lower_in, upper_in,
11960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                       index, start, end_new);
11970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        start = end_new;
11980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      } else if (start <= interval->start_ && interval->end_ <= end) {
11990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        //                   [----------------------------------]
12000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        //                   interval->start_       interval->end_
12010912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // [**************************************************************]
12020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // start                                                        end
12030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // We can safely remove the old interval as it is fully included.
12040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        PopInterval(manager, interval);
12050912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      } else {
12060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (interval->start_ <= start && end <= interval->end_) {
12070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // [--------------------------------------------------------------]
12080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // interval->start_                                  interval->end_
12090912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          //                     [*****************************]
12100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          //                     start                       end
12110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // We have to split the old interval as it fully contains the new one.
12120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          const int end_original = interval->end_;
12130912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          interval->end_ = start;
12140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          InsertInterval(manager, interval, interval->distance_cost_,
12150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                         interval->lower_, interval->upper_, interval->index_,
12160912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                         end, end_original);
12170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        } else if (interval->start_ < start) {
12180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // [------------------------------------]
12190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // interval->start_        interval->end_
12200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          //                     [*****************************]
12210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          //                     start                       end
12220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          interval->end_ = start;
12230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        } else {
12240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          //              [------------------------------------]
12250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          //              interval->start_        interval->end_
12260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // [*****************************]
12270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // start                       end
12280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          interval->start_ = end;
12290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        }
12300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
12310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // The interval has been modified, we need to reposition it or write it.
12320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        RepositionInterval(manager, interval);
12330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }
12340912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    }
12350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    // Insert the remaining interval from start to end.
12360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    InsertInterval(manager, interval, distance_cost, lower_in, upper_in, index,
12370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                   start, end);
12380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
12390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern}
12400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
1241a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int BackwardReferencesHashChainDistanceOnly(
12420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int xsize, int ysize, const uint32_t* const argb, int quality,
12430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int cache_bits, const VP8LHashChain* const hash_chain,
12447c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8LBackwardRefs* const refs, uint16_t* const dist_array) {
1245a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i;
1246a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
1247a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int cc_init = 0;
1248a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int pix_count = xsize * ysize;
1249a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int use_color_cache = (cache_bits > 0);
12507c8da7ce66017295a65ec028084b90800be377f8James Zern  const size_t literal_array_size = sizeof(double) *
12517c8da7ce66017295a65ec028084b90800be377f8James Zern      (NUM_LITERAL_CODES + NUM_LENGTH_CODES +
12527c8da7ce66017295a65ec028084b90800be377f8James Zern       ((cache_bits > 0) ? (1 << cache_bits) : 0));
12537c8da7ce66017295a65ec028084b90800be377f8James Zern  const size_t cost_model_size = sizeof(CostModel) + literal_array_size;
12547c8da7ce66017295a65ec028084b90800be377f8James Zern  CostModel* const cost_model =
12550912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      (CostModel*)WebPSafeCalloc(1ULL, cost_model_size);
1256a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  VP8LColorCache hashers;
12577c8da7ce66017295a65ec028084b90800be377f8James Zern  const int skip_length = 32 + quality;
12587c8da7ce66017295a65ec028084b90800be377f8James Zern  const int skip_min_distance_code = 2;
12590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostManager* cost_manager =
12600912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      (CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager));
1261a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
12620912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (cost_model == NULL || cost_manager == NULL) goto Error;
1263a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
12647c8da7ce66017295a65ec028084b90800be377f8James Zern  cost_model->literal_ = (double*)(cost_model + 1);
1265a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (use_color_cache) {
1266a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    cc_init = VP8LColorCacheInit(&hashers, cache_bits);
1267a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!cc_init) goto Error;
1268a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
1269a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
12707c8da7ce66017295a65ec028084b90800be377f8James Zern  if (!CostModelBuild(cost_model, cache_bits, refs)) {
1271a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    goto Error;
1272a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
1273a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
12740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (!CostManagerInit(cost_manager, dist_array, pix_count, cost_model)) {
12750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    goto Error;
12760912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  }
1277a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1278a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  // We loop one pixel at a time, but store all currently best points to
1279a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  // non-processed locations from this point.
1280a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  dist_array[0] = 0;
12817c8da7ce66017295a65ec028084b90800be377f8James Zern  // Add first pixel as literal.
12820912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  AddSingleLiteralWithCostModel(argb + 0, &hashers, cost_model, 0,
12830912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                use_color_cache, 0.0, cost_manager->costs_,
12840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                dist_array);
12850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
12867c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 1; i < pix_count - 1; ++i) {
12870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int offset = 0, len = 0;
12880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    double prev_cost = cost_manager->costs_[i - 1];
12890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    HashChainFindCopy(hash_chain, i, &offset, &len);
1290fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (len >= 2) {
1291fa39824bb690c5806358871f46940d0450973d8aJames Zern      // If we are dealing with a non-literal.
12927c8da7ce66017295a65ec028084b90800be377f8James Zern      const int code = DistanceToPlaneCode(xsize, offset);
12930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      const double offset_cost = GetDistanceCost(cost_model, code);
12940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      const int first_i = i;
12950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      int j_max = 0, interval_ends_index = 0;
12960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      const int is_offset_zero = (offset_cost == 0.);
12970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
12980912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      if (!is_offset_zero) {
12990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        j_max = (int)ceil(
13000912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            (cost_manager->max_cost_cache_ - cost_manager->min_cost_cache_) /
13010912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            offset_cost);
13020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (j_max < 1) {
13030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          j_max = 1;
13040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        } else if (j_max > cost_manager->interval_ends_size_ - 1) {
13050912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // This could only happen in the case of MAX_LENGTH.
13060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          j_max = cost_manager->interval_ends_size_ - 1;
13070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        }
13080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      }  // else j_max is unused anyway.
13090912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
13100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // Instead of considering all contributions from a pixel i by calling:
13110912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      //         PushInterval(cost_manager, prev_cost + offset_cost, i, len);
13120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // we optimize these contributions in case offset_cost stays the same for
13130912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // consecutive pixels. This describes a set of pixels similar to a
13140912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // previous set (e.g. constant color regions).
13150912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      for (; i < pix_count - 1; ++i) {
13160912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        int offset_next, len_next;
13170912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        prev_cost = cost_manager->costs_[i - 1];
13180912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
13190912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (is_offset_zero) {
13200912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // No optimization can be made so we just push all of the
13210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // contributions from i.
13220912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          PushInterval(cost_manager, prev_cost, i, len);
13230912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        } else {
13240912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // j_max is chosen as the smallest j such that:
13250912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          //       max of cost_cache_ < j*offset cost + min of cost_cache_
13260912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // Therefore, the pixel influenced by i-j_max, cannot be influenced
13270912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // by i. Only the costs after the end of what i contributed need to be
13280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // updated. cost_manager->interval_ends_ is a circular buffer that
13290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // stores those ends.
13300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          const double distance_cost = prev_cost + offset_cost;
13310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          int j = cost_manager->interval_ends_[interval_ends_index];
13320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          if (i - first_i <= j_max ||
13330912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern              !IsCostCacheIntervalWritable(j, i + len)) {
13340912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            PushInterval(cost_manager, distance_cost, i, len);
13350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          } else {
13360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            for (; j < i + len; ++j) {
13370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern              UpdateCost(cost_manager, j, i, distance_cost);
13380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern            }
13390912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          }
13400912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          // Store the new end in the circular buffer.
13410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          assert(interval_ends_index < cost_manager->interval_ends_size_);
13420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          cost_manager->interval_ends_[interval_ends_index] = i + len;
13430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          if (++interval_ends_index > j_max) interval_ends_index = 0;
13447c8da7ce66017295a65ec028084b90800be377f8James Zern        }
13450912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
13460912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // Check whether i is the last pixel to consider, as it is handled
13470912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // differently.
13480912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (i + 1 >= pix_count - 1) break;
13490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        HashChainFindCopy(hash_chain, i + 1, &offset_next, &len_next);
13500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (offset_next != offset) break;
13510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        len = len_next;
13520912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        UpdateCostPerIndex(cost_manager, i);
13530912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        AddSingleLiteralWithCostModel(argb + i, &hashers, cost_model, i,
13540912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                      use_color_cache, prev_cost,
13550912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                      cost_manager->costs_, dist_array);
1356a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
13570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      // Submit the last pixel.
13580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      UpdateCostPerIndex(cost_manager, i + 1);
13590912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
13607c8da7ce66017295a65ec028084b90800be377f8James Zern      // This if is for speedup only. It roughly doubles the speed, and
13617c8da7ce66017295a65ec028084b90800be377f8James Zern      // makes compression worse by .1 %.
13627c8da7ce66017295a65ec028084b90800be377f8James Zern      if (len >= skip_length && code <= skip_min_distance_code) {
13637c8da7ce66017295a65ec028084b90800be377f8James Zern        // Long copy for short distances, let's skip the middle
13647c8da7ce66017295a65ec028084b90800be377f8James Zern        // lookups for better copies.
13657c8da7ce66017295a65ec028084b90800be377f8James Zern        // 1) insert the hashes.
13667c8da7ce66017295a65ec028084b90800be377f8James Zern        if (use_color_cache) {
13670912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          int k;
13687c8da7ce66017295a65ec028084b90800be377f8James Zern          for (k = 0; k < len; ++k) {
13697c8da7ce66017295a65ec028084b90800be377f8James Zern            VP8LColorCacheInsert(&hashers, argb[i + k]);
1370a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          }
1371a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
13720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        // 2) jump.
13737c8da7ce66017295a65ec028084b90800be377f8James Zern        {
13740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          const int i_next = i + len - 1;  // for loop does ++i, thus -1 here.
13750912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          for (; i <= i_next; ++i) UpdateCostPerIndex(cost_manager, i + 1);
13760912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          i = i_next;
1377a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
13787c8da7ce66017295a65ec028084b90800be377f8James Zern        goto next_symbol;
1379a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
1380fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (len > 2) {
1381fa39824bb690c5806358871f46940d0450973d8aJames Zern        // Also try the smallest interval possible (size 2).
1382fa39824bb690c5806358871f46940d0450973d8aJames Zern        double cost_total =
1383fa39824bb690c5806358871f46940d0450973d8aJames Zern            prev_cost + offset_cost + GetLengthCost(cost_model, 1);
13840912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        if (cost_manager->costs_[i + 1] > cost_total) {
13850912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          cost_manager->costs_[i + 1] = (float)cost_total;
13867c8da7ce66017295a65ec028084b90800be377f8James Zern          dist_array[i + 1] = 2;
13877c8da7ce66017295a65ec028084b90800be377f8James Zern        }
1388a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
1389fa39824bb690c5806358871f46940d0450973d8aJames Zern    } else {
1390fa39824bb690c5806358871f46940d0450973d8aJames Zern      // The pixel is added as a single literal so just update the costs.
13910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      UpdateCostPerIndex(cost_manager, i + 1);
1392a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
13930912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
13940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    AddSingleLiteralWithCostModel(argb + i, &hashers, cost_model, i,
13950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                  use_color_cache, prev_cost,
13960912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                  cost_manager->costs_, dist_array);
13970912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
1398a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora next_symbol: ;
1399a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
14007c8da7ce66017295a65ec028084b90800be377f8James Zern  // Handle the last pixel.
14017c8da7ce66017295a65ec028084b90800be377f8James Zern  if (i == (pix_count - 1)) {
14020912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    AddSingleLiteralWithCostModel(
14030912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        argb + i, &hashers, cost_model, i, use_color_cache,
14040912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern        cost_manager->costs_[pix_count - 2], cost_manager->costs_, dist_array);
14057c8da7ce66017295a65ec028084b90800be377f8James Zern  }
14060912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern
140733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ok = !refs->error_;
14087c8da7ce66017295a65ec028084b90800be377f8James Zern Error:
1409a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (cc_init) VP8LColorCacheClear(&hashers);
14100912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  CostManagerClear(cost_manager);
141133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPSafeFree(cost_model);
14120912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  WebPSafeFree(cost_manager);
1413a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
1414a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
1415a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
14161e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// We pack the path at the end of *dist_array and return
14171e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// a pointer to this part of the array. Example:
14181e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// dist_array = [1x2xx3x2] => packed [1x2x1232], chosen_path = [1232]
14197c8da7ce66017295a65ec028084b90800be377f8James Zernstatic void TraceBackwards(uint16_t* const dist_array,
14201e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                           int dist_array_size,
14217c8da7ce66017295a65ec028084b90800be377f8James Zern                           uint16_t** const chosen_path,
14221e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                           int* const chosen_path_size) {
14237c8da7ce66017295a65ec028084b90800be377f8James Zern  uint16_t* path = dist_array + dist_array_size;
14247c8da7ce66017295a65ec028084b90800be377f8James Zern  uint16_t* cur = dist_array + dist_array_size - 1;
14251e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  while (cur >= dist_array) {
14261e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    const int k = *cur;
14271e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    --path;
14281e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    *path = k;
14291e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    cur -= k;
14301e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  }
14311e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  *chosen_path = path;
14321e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  *chosen_path_size = (int)(dist_array + dist_array_size - path);
1433a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
1434a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1435a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int BackwardReferencesHashChainFollowChosenPath(
14360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const uint32_t* const argb, int cache_bits,
14377c8da7ce66017295a65ec028084b90800be377f8James Zern    const uint16_t* const chosen_path, int chosen_path_size,
14380912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs) {
1439a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int use_color_cache = (cache_bits > 0);
1440a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ix;
14417c8da7ce66017295a65ec028084b90800be377f8James Zern  int i = 0;
1442a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
1443a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int cc_init = 0;
1444a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  VP8LColorCache hashers;
1445a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1446a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (use_color_cache) {
1447a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    cc_init = VP8LColorCacheInit(&hashers, cache_bits);
1448a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!cc_init) goto Error;
1449a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
1450a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
145133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
14527c8da7ce66017295a65ec028084b90800be377f8James Zern  for (ix = 0; ix < chosen_path_size; ++ix) {
14537c8da7ce66017295a65ec028084b90800be377f8James Zern    const int len = chosen_path[ix];
14547c8da7ce66017295a65ec028084b90800be377f8James Zern    if (len != 1) {
14557c8da7ce66017295a65ec028084b90800be377f8James Zern      int k;
14560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern      const int offset = HashChainFindOffset(hash_chain, i);
145733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len));
1458a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (use_color_cache) {
1459a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        for (k = 0; k < len; ++k) {
1460a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          VP8LColorCacheInsert(&hashers, argb[i + k]);
1461a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
1462a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
1463a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      i += len;
1464a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    } else {
146533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      PixOrCopy v;
1466fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int idx =
1467fa39824bb690c5806358871f46940d0450973d8aJames Zern          use_color_cache ? VP8LColorCacheContains(&hashers, argb[i]) : -1;
1468fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (idx >= 0) {
1469fa39824bb690c5806358871f46940d0450973d8aJames Zern        // use_color_cache is true and hashers contains argb[i]
1470a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        // push pixel as a color cache index
147133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        v = PixOrCopyCreateCacheIdx(idx);
1472a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      } else {
14738b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
147433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        v = PixOrCopyCreateLiteral(argb[i]);
1475a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
147633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      BackwardRefsCursorAdd(refs, v);
1477a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      ++i;
1478a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
1479a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
148033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ok = !refs->error_;
14817c8da7ce66017295a65ec028084b90800be377f8James Zern Error:
1482a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (cc_init) VP8LColorCacheClear(&hashers);
1483a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
1484a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
1485a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1486a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Returns 1 on success.
14870912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zernstatic int BackwardReferencesTraceBackwards(
14880912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int xsize, int ysize, const uint32_t* const argb, int quality,
14890912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int cache_bits, const VP8LHashChain* const hash_chain,
14900912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    VP8LBackwardRefs* const refs) {
1491a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
1492a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int dist_array_size = xsize * ysize;
14937c8da7ce66017295a65ec028084b90800be377f8James Zern  uint16_t* chosen_path = NULL;
1494a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int chosen_path_size = 0;
14957c8da7ce66017295a65ec028084b90800be377f8James Zern  uint16_t* dist_array =
14967c8da7ce66017295a65ec028084b90800be377f8James Zern      (uint16_t*)WebPSafeMalloc(dist_array_size, sizeof(*dist_array));
1497a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1498a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (dist_array == NULL) goto Error;
1499a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1500a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (!BackwardReferencesHashChainDistanceOnly(
15017c8da7ce66017295a65ec028084b90800be377f8James Zern      xsize, ysize, argb, quality, cache_bits, hash_chain,
150233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      refs, dist_array)) {
1503a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    goto Error;
1504a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
15051e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  TraceBackwards(dist_array, dist_array_size, &chosen_path, &chosen_path_size);
1506a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (!BackwardReferencesHashChainFollowChosenPath(
15070912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern          argb, cache_bits, chosen_path, chosen_path_size, hash_chain, refs)) {
1508a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    goto Error;
1509a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
1510a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ok = 1;
1511a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora Error:
151233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPSafeFree(dist_array);
1513a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
1514a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
1515a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1516a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic void BackwardReferences2DLocality(int xsize,
151733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                         const VP8LBackwardRefs* const refs) {
151833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LRefsCursor c = VP8LRefsCursorInit(refs);
151933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (VP8LRefsCursorOk(&c)) {
152033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (PixOrCopyIsCopy(c.cur_pos)) {
152133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const int dist = c.cur_pos->argb_or_distance;
1522a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      const int transformed_dist = DistanceToPlaneCode(xsize, dist);
152333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      c.cur_pos->argb_or_distance = transformed_dist;
1524a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
152533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LRefsCursorNext(&c);
1526a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
1527a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
1528a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1529fa39824bb690c5806358871f46940d0450973d8aJames Zern// Computes the entropies for a color cache size (in bits) between 0 (unused)
1530fa39824bb690c5806358871f46940d0450973d8aJames Zern// and cache_bits_max (inclusive).
1531fa39824bb690c5806358871f46940d0450973d8aJames Zern// Returns 1 on success, 0 in case of allocation error.
1532fa39824bb690c5806358871f46940d0450973d8aJames Zernstatic int ComputeCacheEntropies(const uint32_t* argb,
1533fa39824bb690c5806358871f46940d0450973d8aJames Zern                                 const VP8LBackwardRefs* const refs,
1534fa39824bb690c5806358871f46940d0450973d8aJames Zern                                 int cache_bits_max, double entropies[]) {
1535fa39824bb690c5806358871f46940d0450973d8aJames Zern  int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 };
1536fa39824bb690c5806358871f46940d0450973d8aJames Zern  VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1];
153733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LRefsCursor c = VP8LRefsCursorInit(refs);
1538fa39824bb690c5806358871f46940d0450973d8aJames Zern  VP8LHistogram* histos[MAX_COLOR_CACHE_BITS + 1] = { NULL };
1539fa39824bb690c5806358871f46940d0450973d8aJames Zern  int ok = 0;
1540fa39824bb690c5806358871f46940d0450973d8aJames Zern  int i;
1541a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
1542fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (i = 0; i <= cache_bits_max; ++i) {
1543fa39824bb690c5806358871f46940d0450973d8aJames Zern    histos[i] = VP8LAllocateHistogram(i);
1544fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (histos[i] == NULL) goto Error;
1545fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (i == 0) continue;
1546fa39824bb690c5806358871f46940d0450973d8aJames Zern    cc_init[i] = VP8LColorCacheInit(&hashers[i], i);
1547fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (!cc_init[i]) goto Error;
1548a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
1549fa39824bb690c5806358871f46940d0450973d8aJames Zern
1550fa39824bb690c5806358871f46940d0450973d8aJames Zern  assert(cache_bits_max >= 0);
1551fa39824bb690c5806358871f46940d0450973d8aJames Zern  // Do not use the color cache for cache_bits=0.
1552fa39824bb690c5806358871f46940d0450973d8aJames Zern  while (VP8LRefsCursorOk(&c)) {
1553fa39824bb690c5806358871f46940d0450973d8aJames Zern    VP8LHistogramAddSinglePixOrCopy(histos[0], c.cur_pos);
1554fa39824bb690c5806358871f46940d0450973d8aJames Zern    VP8LRefsCursorNext(&c);
1555fa39824bb690c5806358871f46940d0450973d8aJames Zern  }
1556fa39824bb690c5806358871f46940d0450973d8aJames Zern  if (cache_bits_max > 0) {
1557fa39824bb690c5806358871f46940d0450973d8aJames Zern    c = VP8LRefsCursorInit(refs);
15587c8da7ce66017295a65ec028084b90800be377f8James Zern    while (VP8LRefsCursorOk(&c)) {
15597c8da7ce66017295a65ec028084b90800be377f8James Zern      const PixOrCopy* const v = c.cur_pos;
15607c8da7ce66017295a65ec028084b90800be377f8James Zern      if (PixOrCopyIsLiteral(v)) {
15617c8da7ce66017295a65ec028084b90800be377f8James Zern        const uint32_t pix = *argb++;
1562fa39824bb690c5806358871f46940d0450973d8aJames Zern        // The keys of the caches can be derived from the longest one.
1563fa39824bb690c5806358871f46940d0450973d8aJames Zern        int key = HashPix(pix, 32 - cache_bits_max);
1564fa39824bb690c5806358871f46940d0450973d8aJames Zern        for (i = cache_bits_max; i >= 1; --i, key >>= 1) {
1565fa39824bb690c5806358871f46940d0450973d8aJames Zern          if (VP8LColorCacheLookup(&hashers[i], key) == pix) {
1566fa39824bb690c5806358871f46940d0450973d8aJames Zern            ++histos[i]->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key];
1567fa39824bb690c5806358871f46940d0450973d8aJames Zern          } else {
1568fa39824bb690c5806358871f46940d0450973d8aJames Zern            VP8LColorCacheSet(&hashers[i], key, pix);
1569fa39824bb690c5806358871f46940d0450973d8aJames Zern            ++histos[i]->blue_[pix & 0xff];
1570fa39824bb690c5806358871f46940d0450973d8aJames Zern            ++histos[i]->literal_[(pix >> 8) & 0xff];
1571fa39824bb690c5806358871f46940d0450973d8aJames Zern            ++histos[i]->red_[(pix >> 16) & 0xff];
1572fa39824bb690c5806358871f46940d0450973d8aJames Zern            ++histos[i]->alpha_[pix >> 24];
1573fa39824bb690c5806358871f46940d0450973d8aJames Zern          }
15747c8da7ce66017295a65ec028084b90800be377f8James Zern        }
15757c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
1576fa39824bb690c5806358871f46940d0450973d8aJames Zern        // Update the histograms for distance/length.
15777c8da7ce66017295a65ec028084b90800be377f8James Zern        int len = PixOrCopyLength(v);
1578fa39824bb690c5806358871f46940d0450973d8aJames Zern        int code_dist, code_len, extra_bits;
1579fa39824bb690c5806358871f46940d0450973d8aJames Zern        uint32_t argb_prev = *argb ^ 0xffffffffu;
1580fa39824bb690c5806358871f46940d0450973d8aJames Zern        VP8LPrefixEncodeBits(len, &code_len, &extra_bits);
1581fa39824bb690c5806358871f46940d0450973d8aJames Zern        VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code_dist, &extra_bits);
1582fa39824bb690c5806358871f46940d0450973d8aJames Zern        for (i = 1; i <= cache_bits_max; ++i) {
1583fa39824bb690c5806358871f46940d0450973d8aJames Zern          ++histos[i]->literal_[NUM_LITERAL_CODES + code_len];
1584fa39824bb690c5806358871f46940d0450973d8aJames Zern          ++histos[i]->distance_[code_dist];
1585fa39824bb690c5806358871f46940d0450973d8aJames Zern        }
1586fa39824bb690c5806358871f46940d0450973d8aJames Zern        // Update the colors caches.
15877c8da7ce66017295a65ec028084b90800be377f8James Zern        do {
1588fa39824bb690c5806358871f46940d0450973d8aJames Zern          if (*argb != argb_prev) {
1589fa39824bb690c5806358871f46940d0450973d8aJames Zern            // Efficiency: insert only if the color changes.
1590fa39824bb690c5806358871f46940d0450973d8aJames Zern            int key = HashPix(*argb, 32 - cache_bits_max);
1591fa39824bb690c5806358871f46940d0450973d8aJames Zern            for (i = cache_bits_max; i >= 1; --i, key >>= 1) {
1592fa39824bb690c5806358871f46940d0450973d8aJames Zern              hashers[i].colors_[key] = *argb;
1593fa39824bb690c5806358871f46940d0450973d8aJames Zern            }
1594fa39824bb690c5806358871f46940d0450973d8aJames Zern            argb_prev = *argb;
1595fa39824bb690c5806358871f46940d0450973d8aJames Zern          }
1596fa39824bb690c5806358871f46940d0450973d8aJames Zern          argb++;
1597fa39824bb690c5806358871f46940d0450973d8aJames Zern        } while (--len != 0);
1598a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
15997c8da7ce66017295a65ec028084b90800be377f8James Zern      VP8LRefsCursorNext(&c);
1600a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
1601a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
1602fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (i = 0; i <= cache_bits_max; ++i) {
1603fa39824bb690c5806358871f46940d0450973d8aJames Zern    entropies[i] = VP8LHistogramEstimateBits(histos[i]);
1604fa39824bb690c5806358871f46940d0450973d8aJames Zern  }
1605fa39824bb690c5806358871f46940d0450973d8aJames Zern  ok = 1;
1606fa39824bb690c5806358871f46940d0450973d8aJames ZernError:
1607fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (i = 0; i <= cache_bits_max; ++i) {
1608fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (cc_init[i]) VP8LColorCacheClear(&hashers[i]);
1609fa39824bb690c5806358871f46940d0450973d8aJames Zern    VP8LFreeHistogram(histos[i]);
1610fa39824bb690c5806358871f46940d0450973d8aJames Zern  }
1611fa39824bb690c5806358871f46940d0450973d8aJames Zern  return ok;
1612a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
1613a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
16147c8da7ce66017295a65ec028084b90800be377f8James Zern// Evaluate optimal cache bits for the local color cache.
16157c8da7ce66017295a65ec028084b90800be377f8James Zern// The input *best_cache_bits sets the maximum cache bits to use (passing 0
16167c8da7ce66017295a65ec028084b90800be377f8James Zern// implies disabling the local color cache). The local color cache is also
16177c8da7ce66017295a65ec028084b90800be377f8James Zern// disabled for the lower (<= 25) quality.
161833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Returns 0 in case of memory error.
16197c8da7ce66017295a65ec028084b90800be377f8James Zernstatic int CalculateBestCacheSize(const uint32_t* const argb,
16207c8da7ce66017295a65ec028084b90800be377f8James Zern                                  int xsize, int ysize, int quality,
16210912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                  const VP8LHashChain* const hash_chain,
16227c8da7ce66017295a65ec028084b90800be377f8James Zern                                  VP8LBackwardRefs* const refs,
16237c8da7ce66017295a65ec028084b90800be377f8James Zern                                  int* const lz77_computed,
16247c8da7ce66017295a65ec028084b90800be377f8James Zern                                  int* const best_cache_bits) {
1625fa39824bb690c5806358871f46940d0450973d8aJames Zern  int i;
16267c8da7ce66017295a65ec028084b90800be377f8James Zern  int cache_bits_high = (quality <= 25) ? 0 : *best_cache_bits;
1627fa39824bb690c5806358871f46940d0450973d8aJames Zern  double entropy_min = MAX_ENTROPY;
1628fa39824bb690c5806358871f46940d0450973d8aJames Zern  double entropies[MAX_COLOR_CACHE_BITS + 1];
162933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
16307c8da7ce66017295a65ec028084b90800be377f8James Zern  assert(cache_bits_high <= MAX_COLOR_CACHE_BITS);
16317c8da7ce66017295a65ec028084b90800be377f8James Zern
16327c8da7ce66017295a65ec028084b90800be377f8James Zern  *lz77_computed = 0;
16337c8da7ce66017295a65ec028084b90800be377f8James Zern  if (cache_bits_high == 0) {
16347c8da7ce66017295a65ec028084b90800be377f8James Zern    *best_cache_bits = 0;
16357c8da7ce66017295a65ec028084b90800be377f8James Zern    // Local color cache is disabled.
16367c8da7ce66017295a65ec028084b90800be377f8James Zern    return 1;
16377c8da7ce66017295a65ec028084b90800be377f8James Zern  }
1638fa39824bb690c5806358871f46940d0450973d8aJames Zern  // Compute LZ77 with no cache (0 bits), as the ideal LZ77 with a color cache
1639fa39824bb690c5806358871f46940d0450973d8aJames Zern  // is not that different in practice.
1640fa39824bb690c5806358871f46940d0450973d8aJames Zern  if (!BackwardReferencesLz77(xsize, ysize, argb, 0, hash_chain, refs)) {
164133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return 0;
1642a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
1643fa39824bb690c5806358871f46940d0450973d8aJames Zern  // Find the cache_bits giving the lowest entropy. The search is done in a
1644fa39824bb690c5806358871f46940d0450973d8aJames Zern  // brute-force way as the function (entropy w.r.t cache_bits) can be
1645fa39824bb690c5806358871f46940d0450973d8aJames Zern  // anything in practice.
1646fa39824bb690c5806358871f46940d0450973d8aJames Zern  if (!ComputeCacheEntropies(argb, refs, cache_bits_high, entropies)) {
1647fa39824bb690c5806358871f46940d0450973d8aJames Zern    return 0;
1648fa39824bb690c5806358871f46940d0450973d8aJames Zern  }
1649fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (i = 0; i <= cache_bits_high; ++i) {
1650fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (i == 0 || entropies[i] < entropy_min) {
1651fa39824bb690c5806358871f46940d0450973d8aJames Zern      entropy_min = entropies[i];
1652fa39824bb690c5806358871f46940d0450973d8aJames Zern      *best_cache_bits = i;
1653a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
1654a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
165533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
1656a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
16577c8da7ce66017295a65ec028084b90800be377f8James Zern
16587c8da7ce66017295a65ec028084b90800be377f8James Zern// Update (in-place) backward references for specified cache_bits.
16597c8da7ce66017295a65ec028084b90800be377f8James Zernstatic int BackwardRefsWithLocalCache(const uint32_t* const argb,
16607c8da7ce66017295a65ec028084b90800be377f8James Zern                                      int cache_bits,
16617c8da7ce66017295a65ec028084b90800be377f8James Zern                                      VP8LBackwardRefs* const refs) {
16627c8da7ce66017295a65ec028084b90800be377f8James Zern  int pixel_index = 0;
16637c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LColorCache hashers;
16647c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LRefsCursor c = VP8LRefsCursorInit(refs);
16657c8da7ce66017295a65ec028084b90800be377f8James Zern  if (!VP8LColorCacheInit(&hashers, cache_bits)) return 0;
16667c8da7ce66017295a65ec028084b90800be377f8James Zern
16677c8da7ce66017295a65ec028084b90800be377f8James Zern  while (VP8LRefsCursorOk(&c)) {
16687c8da7ce66017295a65ec028084b90800be377f8James Zern    PixOrCopy* const v = c.cur_pos;
16697c8da7ce66017295a65ec028084b90800be377f8James Zern    if (PixOrCopyIsLiteral(v)) {
16707c8da7ce66017295a65ec028084b90800be377f8James Zern      const uint32_t argb_literal = v->argb_or_distance;
1671fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int ix = VP8LColorCacheContains(&hashers, argb_literal);
1672fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (ix >= 0) {
1673fa39824bb690c5806358871f46940d0450973d8aJames Zern        // hashers contains argb_literal
16747c8da7ce66017295a65ec028084b90800be377f8James Zern        *v = PixOrCopyCreateCacheIdx(ix);
16757c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
16767c8da7ce66017295a65ec028084b90800be377f8James Zern        VP8LColorCacheInsert(&hashers, argb_literal);
16777c8da7ce66017295a65ec028084b90800be377f8James Zern      }
16787c8da7ce66017295a65ec028084b90800be377f8James Zern      ++pixel_index;
16797c8da7ce66017295a65ec028084b90800be377f8James Zern    } else {
16807c8da7ce66017295a65ec028084b90800be377f8James Zern      // refs was created without local cache, so it can not have cache indexes.
16817c8da7ce66017295a65ec028084b90800be377f8James Zern      int k;
16827c8da7ce66017295a65ec028084b90800be377f8James Zern      assert(PixOrCopyIsCopy(v));
16837c8da7ce66017295a65ec028084b90800be377f8James Zern      for (k = 0; k < v->len; ++k) {
16847c8da7ce66017295a65ec028084b90800be377f8James Zern        VP8LColorCacheInsert(&hashers, argb[pixel_index++]);
16857c8da7ce66017295a65ec028084b90800be377f8James Zern      }
16867c8da7ce66017295a65ec028084b90800be377f8James Zern    }
16877c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8LRefsCursorNext(&c);
16887c8da7ce66017295a65ec028084b90800be377f8James Zern  }
16897c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LColorCacheClear(&hashers);
16907c8da7ce66017295a65ec028084b90800be377f8James Zern  return 1;
16917c8da7ce66017295a65ec028084b90800be377f8James Zern}
16927c8da7ce66017295a65ec028084b90800be377f8James Zern
16937c8da7ce66017295a65ec028084b90800be377f8James Zernstatic VP8LBackwardRefs* GetBackwardReferencesLowEffort(
16940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int width, int height, const uint32_t* const argb,
16950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int* const cache_bits, const VP8LHashChain* const hash_chain,
16967c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8LBackwardRefs refs_array[2]) {
16977c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LBackwardRefs* refs_lz77 = &refs_array[0];
16987c8da7ce66017295a65ec028084b90800be377f8James Zern  *cache_bits = 0;
16990912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  if (!BackwardReferencesLz77(width, height, argb, 0, hash_chain, refs_lz77)) {
17007c8da7ce66017295a65ec028084b90800be377f8James Zern    return NULL;
17017c8da7ce66017295a65ec028084b90800be377f8James Zern  }
17027c8da7ce66017295a65ec028084b90800be377f8James Zern  BackwardReferences2DLocality(width, refs_lz77);
17037c8da7ce66017295a65ec028084b90800be377f8James Zern  return refs_lz77;
17047c8da7ce66017295a65ec028084b90800be377f8James Zern}
17057c8da7ce66017295a65ec028084b90800be377f8James Zern
17067c8da7ce66017295a65ec028084b90800be377f8James Zernstatic VP8LBackwardRefs* GetBackwardReferences(
17077c8da7ce66017295a65ec028084b90800be377f8James Zern    int width, int height, const uint32_t* const argb, int quality,
17080912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int* const cache_bits, const VP8LHashChain* const hash_chain,
17097c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8LBackwardRefs refs_array[2]) {
17107c8da7ce66017295a65ec028084b90800be377f8James Zern  int lz77_is_useful;
17117c8da7ce66017295a65ec028084b90800be377f8James Zern  int lz77_computed;
17127c8da7ce66017295a65ec028084b90800be377f8James Zern  double bit_cost_lz77, bit_cost_rle;
17137c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LBackwardRefs* best = NULL;
17147c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LBackwardRefs* refs_lz77 = &refs_array[0];
17157c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LBackwardRefs* refs_rle = &refs_array[1];
17167c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LHistogram* histo = NULL;
17177c8da7ce66017295a65ec028084b90800be377f8James Zern
17187c8da7ce66017295a65ec028084b90800be377f8James Zern  if (!CalculateBestCacheSize(argb, width, height, quality, hash_chain,
17197c8da7ce66017295a65ec028084b90800be377f8James Zern                              refs_lz77, &lz77_computed, cache_bits)) {
17207c8da7ce66017295a65ec028084b90800be377f8James Zern    goto Error;
17217c8da7ce66017295a65ec028084b90800be377f8James Zern  }
17227c8da7ce66017295a65ec028084b90800be377f8James Zern
17237c8da7ce66017295a65ec028084b90800be377f8James Zern  if (lz77_computed) {
17247c8da7ce66017295a65ec028084b90800be377f8James Zern    // Transform refs_lz77 for the optimized cache_bits.
17257c8da7ce66017295a65ec028084b90800be377f8James Zern    if (*cache_bits > 0) {
17267c8da7ce66017295a65ec028084b90800be377f8James Zern      if (!BackwardRefsWithLocalCache(argb, *cache_bits, refs_lz77)) {
17277c8da7ce66017295a65ec028084b90800be377f8James Zern        goto Error;
17287c8da7ce66017295a65ec028084b90800be377f8James Zern      }
17297c8da7ce66017295a65ec028084b90800be377f8James Zern    }
17307c8da7ce66017295a65ec028084b90800be377f8James Zern  } else {
17310912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    if (!BackwardReferencesLz77(width, height, argb, *cache_bits, hash_chain,
17320912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                refs_lz77)) {
17337c8da7ce66017295a65ec028084b90800be377f8James Zern      goto Error;
17347c8da7ce66017295a65ec028084b90800be377f8James Zern    }
17357c8da7ce66017295a65ec028084b90800be377f8James Zern  }
17367c8da7ce66017295a65ec028084b90800be377f8James Zern
17377c8da7ce66017295a65ec028084b90800be377f8James Zern  if (!BackwardReferencesRle(width, height, argb, *cache_bits, refs_rle)) {
17387c8da7ce66017295a65ec028084b90800be377f8James Zern    goto Error;
17397c8da7ce66017295a65ec028084b90800be377f8James Zern  }
17407c8da7ce66017295a65ec028084b90800be377f8James Zern
17417c8da7ce66017295a65ec028084b90800be377f8James Zern  histo = VP8LAllocateHistogram(*cache_bits);
17427c8da7ce66017295a65ec028084b90800be377f8James Zern  if (histo == NULL) goto Error;
17437c8da7ce66017295a65ec028084b90800be377f8James Zern
17447c8da7ce66017295a65ec028084b90800be377f8James Zern  {
17457c8da7ce66017295a65ec028084b90800be377f8James Zern    // Evaluate LZ77 coding.
17467c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8LHistogramCreate(histo, refs_lz77, *cache_bits);
17477c8da7ce66017295a65ec028084b90800be377f8James Zern    bit_cost_lz77 = VP8LHistogramEstimateBits(histo);
17487c8da7ce66017295a65ec028084b90800be377f8James Zern    // Evaluate RLE coding.
17497c8da7ce66017295a65ec028084b90800be377f8James Zern    VP8LHistogramCreate(histo, refs_rle, *cache_bits);
17507c8da7ce66017295a65ec028084b90800be377f8James Zern    bit_cost_rle = VP8LHistogramEstimateBits(histo);
17517c8da7ce66017295a65ec028084b90800be377f8James Zern    // Decide if LZ77 is useful.
17527c8da7ce66017295a65ec028084b90800be377f8James Zern    lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
17537c8da7ce66017295a65ec028084b90800be377f8James Zern  }
17547c8da7ce66017295a65ec028084b90800be377f8James Zern
17557c8da7ce66017295a65ec028084b90800be377f8James Zern  // Choose appropriate backward reference.
17567c8da7ce66017295a65ec028084b90800be377f8James Zern  if (lz77_is_useful) {
17577c8da7ce66017295a65ec028084b90800be377f8James Zern    // TraceBackwards is costly. Don't execute it at lower quality.
17587c8da7ce66017295a65ec028084b90800be377f8James Zern    const int try_lz77_trace_backwards = (quality >= 25);
17597c8da7ce66017295a65ec028084b90800be377f8James Zern    best = refs_lz77;   // default guess: lz77 is better
17607c8da7ce66017295a65ec028084b90800be377f8James Zern    if (try_lz77_trace_backwards) {
17617c8da7ce66017295a65ec028084b90800be377f8James Zern      VP8LBackwardRefs* const refs_trace = refs_rle;
17627c8da7ce66017295a65ec028084b90800be377f8James Zern      if (!VP8LBackwardRefsCopy(refs_lz77, refs_trace)) {
17637c8da7ce66017295a65ec028084b90800be377f8James Zern        best = NULL;
17647c8da7ce66017295a65ec028084b90800be377f8James Zern        goto Error;
17657c8da7ce66017295a65ec028084b90800be377f8James Zern      }
17667c8da7ce66017295a65ec028084b90800be377f8James Zern      if (BackwardReferencesTraceBackwards(width, height, argb, quality,
17677c8da7ce66017295a65ec028084b90800be377f8James Zern                                           *cache_bits, hash_chain,
17687c8da7ce66017295a65ec028084b90800be377f8James Zern                                           refs_trace)) {
17697c8da7ce66017295a65ec028084b90800be377f8James Zern        double bit_cost_trace;
17707c8da7ce66017295a65ec028084b90800be377f8James Zern        // Evaluate LZ77 coding.
17717c8da7ce66017295a65ec028084b90800be377f8James Zern        VP8LHistogramCreate(histo, refs_trace, *cache_bits);
17727c8da7ce66017295a65ec028084b90800be377f8James Zern        bit_cost_trace = VP8LHistogramEstimateBits(histo);
17737c8da7ce66017295a65ec028084b90800be377f8James Zern        if (bit_cost_trace < bit_cost_lz77) {
17747c8da7ce66017295a65ec028084b90800be377f8James Zern          best = refs_trace;
17757c8da7ce66017295a65ec028084b90800be377f8James Zern        }
17767c8da7ce66017295a65ec028084b90800be377f8James Zern      }
17777c8da7ce66017295a65ec028084b90800be377f8James Zern    }
17787c8da7ce66017295a65ec028084b90800be377f8James Zern  } else {
17797c8da7ce66017295a65ec028084b90800be377f8James Zern    best = refs_rle;
17807c8da7ce66017295a65ec028084b90800be377f8James Zern  }
17817c8da7ce66017295a65ec028084b90800be377f8James Zern
17827c8da7ce66017295a65ec028084b90800be377f8James Zern  BackwardReferences2DLocality(width, best);
17837c8da7ce66017295a65ec028084b90800be377f8James Zern
17847c8da7ce66017295a65ec028084b90800be377f8James Zern Error:
17857c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8LFreeHistogram(histo);
17867c8da7ce66017295a65ec028084b90800be377f8James Zern  return best;
17877c8da7ce66017295a65ec028084b90800be377f8James Zern}
17887c8da7ce66017295a65ec028084b90800be377f8James Zern
17897c8da7ce66017295a65ec028084b90800be377f8James ZernVP8LBackwardRefs* VP8LGetBackwardReferences(
17907c8da7ce66017295a65ec028084b90800be377f8James Zern    int width, int height, const uint32_t* const argb, int quality,
17910912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    int low_effort, int* const cache_bits,
17920912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    const VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[2]) {
17937c8da7ce66017295a65ec028084b90800be377f8James Zern  if (low_effort) {
17940912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern    return GetBackwardReferencesLowEffort(width, height, argb, cache_bits,
17950912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern                                          hash_chain, refs_array);
17967c8da7ce66017295a65ec028084b90800be377f8James Zern  } else {
17977c8da7ce66017295a65ec028084b90800be377f8James Zern    return GetBackwardReferences(width, height, argb, quality, cache_bits,
17987c8da7ce66017295a65ec028084b90800be377f8James Zern                                 hash_chain, refs_array);
17997c8da7ce66017295a65ec028084b90800be377f8James Zern  }
18007c8da7ce66017295a65ec028084b90800be377f8James Zern}
1801