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
16a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "./backward_references.h"
17a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "./histogram.h"
18a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "../dsp/lossless.h"
19a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "../utils/color_cache.h"
20a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "../utils/utils.h"
21a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
22a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#define VALUES_IN_BYTE 256
23a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
24a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#define HASH_MULTIPLIER (0xc6a4a7935bd1e995ULL)
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.
31a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#define WINDOW_SIZE ((1 << 20) - 120)
32a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
33a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Bounds for the match length.
34a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#define MIN_LENGTH 2
35a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#define MAX_LENGTH 4096
36a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
37a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
38a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
39a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic const uint8_t plane_to_code_lut[128] = {
40a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 96,   73,  55,  39,  23,  13,   5,  1,  255, 255, 255, 255, 255, 255, 255, 255,
41a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 101,  78,  58,  42,  26,  16,   8,  2,    0,   3,  9,   17,  27,  43,  59,  79,
42a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 102,  86,  62,  46,  32,  20,  10,  6,    4,   7,  11,  21,  33,  47,  63,  87,
43a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 105,  90,  70,  52,  37,  28,  18,  14,  12,  15,  19,  29,  38,  53,  71,  91,
44a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 110,  99,  82,  66,  48,  35,  30,  24,  22,  25,  31,  36,  49,  67,  83, 100,
45a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 115, 108,  94,  76,  64,  50,  44,  40,  34,  41,  45,  51,  65,  77,  95, 109,
46a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 118, 113, 103,  92,  80,  68,  60,  56,  54,  57,  61,  69,  81,  93, 104, 114,
47a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 119, 116, 111, 106,  97,  88,  84,  74,  72,  75,  85,  89,  98, 107, 112, 117
48a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora};
49a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
50a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int DistanceToPlaneCode(int xsize, int dist) {
51a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int yoffset = dist / xsize;
52a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int xoffset = dist - yoffset * xsize;
53a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (xoffset <= 8 && yoffset < 8) {
54a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    return plane_to_code_lut[yoffset * 16 + 8 - xoffset] + 1;
55a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  } else if (xoffset > xsize - 8 && yoffset < 7) {
56a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    return plane_to_code_lut[(yoffset + 1) * 16 + 8 + (xsize - xoffset)] + 1;
57a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
58a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return dist + 120;
59a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
60a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
61a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE int FindMatchLength(const uint32_t* const array1,
62a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                       const uint32_t* const array2,
63a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                       const int max_limit) {
64a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int match_len = 0;
65a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  while (match_len < max_limit && array1[match_len] == array2[match_len]) {
66a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    ++match_len;
67a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
68a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return match_len;
69a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
70a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
71a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
72a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//  VP8LBackwardRefs
73a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
7433f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastruct PixOrCopyBlock {
7533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopyBlock* next_;   // next block (or NULL)
7633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopy* start_;       // data start
7733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int size_;               // currently used size
7833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora};
7933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void ClearBackwardRefs(VP8LBackwardRefs* const refs) {
8133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(refs != NULL);
8233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (refs->tail_ != NULL) {
8333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    *refs->tail_ = refs->free_blocks_;  // recycle all blocks at once
84a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
8533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->free_blocks_ = refs->refs_;
8633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->tail_ = &refs->refs_;
8733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->last_block_ = NULL;
8833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->refs_ = NULL;
89a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
90a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
9133f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) {
9233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(refs != NULL);
9333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
9433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (refs->free_blocks_ != NULL) {
9533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    PixOrCopyBlock* const next = refs->free_blocks_->next_;
9633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    WebPSafeFree(refs->free_blocks_);
9733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    refs->free_blocks_ = next;
98a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
99a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
100a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
10133f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size) {
102a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  assert(refs != NULL);
10333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  memset(refs, 0, sizeof(*refs));
10433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->tail_ = &refs->refs_;
10533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->block_size_ =
10633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      (block_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : block_size;
10733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
10833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
10933f74dabbc7920a65ed435d7417987589febdc16Vikas AroraVP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs) {
11033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LRefsCursor c;
11133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  c.cur_block_ = refs->refs_;
11233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (refs->refs_ != NULL) {
11333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    c.cur_pos = c.cur_block_->start_;
11433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    c.last_pos_ = c.cur_pos + c.cur_block_->size_;
11533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
11633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    c.cur_pos = NULL;
11733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    c.last_pos_ = NULL;
11833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
11933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return c;
12033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
12133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
12233f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid VP8LRefsCursorNextBlock(VP8LRefsCursor* const c) {
12333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopyBlock* const b = c->cur_block_->next_;
12433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  c->cur_pos = (b == NULL) ? NULL : b->start_;
12533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  c->last_pos_ = (b == NULL) ? NULL : b->start_ + b->size_;
12633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  c->cur_block_ = b;
12733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
12833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
12933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Create a new block, either from the free list or allocated
13033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic PixOrCopyBlock* BackwardRefsNewBlock(VP8LBackwardRefs* const refs) {
13133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopyBlock* b = refs->free_blocks_;
13233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (b == NULL) {   // allocate new memory chunk
13333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const size_t total_size =
13433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        sizeof(*b) + refs->block_size_ * sizeof(*b->start_);
13533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    b = (PixOrCopyBlock*)WebPSafeMalloc(1ULL, total_size);
13633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (b == NULL) {
13733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      refs->error_ |= 1;
13833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      return NULL;
13933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
14033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    b->start_ = (PixOrCopy*)((uint8_t*)b + sizeof(*b));  // not always aligned
14133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {  // recycle from free-list
14233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    refs->free_blocks_ = b->next_;
14333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
14433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  *refs->tail_ = b;
14533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->tail_ = &b->next_;
14633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  refs->last_block_ = b;
14733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  b->next_ = NULL;
14833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  b->size_ = 0;
14933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return b;
15033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
15133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
15233f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE void BackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
15333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                              const PixOrCopy v) {
15433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  PixOrCopyBlock* b = refs->last_block_;
15533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (b == NULL || b->size_ == refs->block_size_) {
15633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    b = BackwardRefsNewBlock(refs);
15733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (b == NULL) return;   // refs->error_ is set
15833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
15933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  b->start_[b->size_++] = v;
16033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
16133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
16233f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint VP8LBackwardRefsCopy(const VP8LBackwardRefs* const src,
16333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         VP8LBackwardRefs* const dst) {
16433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const PixOrCopyBlock* b = src->refs_;
16533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(dst);
16633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(src->block_size_ == dst->block_size_);
16733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (b != NULL) {
16833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    PixOrCopyBlock* const new_b = BackwardRefsNewBlock(dst);
16933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (new_b == NULL) return 0;   // dst->error_ is set
17033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    memcpy(new_b->start_, b->start_, b->size_ * sizeof(*b->start_));
17133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    new_b->size_ = b->size_;
17233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    b = b->next_;
17333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
174a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return 1;
175a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
176a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
177a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
178a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Hash chains
179a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
18033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// initialize as empty
18133f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void HashChainInit(VP8LHashChain* const p) {
182a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i;
18333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(p != NULL);
18433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  for (i = 0; i < p->size_; ++i) {
185a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    p->chain_[i] = -1;
186a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
187a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  for (i = 0; i < HASH_SIZE; ++i) {
188a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    p->hash_to_first_index_[i] = -1;
189a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
19033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
19133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
19233f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint VP8LHashChainInit(VP8LHashChain* const p, int size) {
19333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(p->size_ == 0);
19433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(p->chain_ == NULL);
19533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(size > 0);
19633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  p->chain_ = (int*)WebPSafeMalloc(size, sizeof(*p->chain_));
19733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (p->chain_ == NULL) return 0;
19833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  p->size_ = size;
19933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  HashChainInit(p);
200a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return 1;
201a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
202a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
20333f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid VP8LHashChainClear(VP8LHashChain* const p) {
20433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(p != NULL);
20533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPSafeFree(p->chain_);
20633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  p->size_ = 0;
20733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  p->chain_ = NULL;
20833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
20933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
21033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// -----------------------------------------------------------------------------
21133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
21233f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint64_t GetPixPairHash64(const uint32_t* const argb) {
21333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint64_t key = ((uint64_t)argb[1] << 32) | argb[0];
21433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  key = (key * HASH_MULTIPLIER) >> (64 - HASH_BITS);
21533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return key;
216a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
217a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
218a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Insertion of two pixels at a time.
21933f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void HashChainInsert(VP8LHashChain* const p,
220a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                            const uint32_t* const argb, int pos) {
221a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const uint64_t hash_code = GetPixPairHash64(argb);
222a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  p->chain_[pos] = p->hash_to_first_index_[hash_code];
223a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  p->hash_to_first_index_[hash_code] = pos;
224a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
225a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
2261e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic void GetParamsForHashChainFindCopy(int quality, int xsize,
2270406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                          int cache_bits, int* window_size,
2280406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                          int* iter_pos, int* iter_limit) {
2291e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int iter_mult = (quality < 27) ? 1 : 1 + ((quality - 27) >> 4);
2300406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int iter_neg = -iter_mult * (quality >> 1);
2311e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  // Limit the backward-ref window size for lower qualities.
2321e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int max_window_size = (quality > 50) ? WINDOW_SIZE
2331e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                            : (quality > 25) ? (xsize << 8)
2341e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                            : (xsize << 4);
2351e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  assert(xsize > 0);
2361e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  *window_size = (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE
2371e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora               : max_window_size;
2380406ce1417f76f2034833414dcecc9f56253640cVikas Arora  *iter_pos = 8 + (quality >> 3);
2398b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  // For lower entropy images, the rigorous search loop in HashChainFindCopy
2400406ce1417f76f2034833414dcecc9f56253640cVikas Arora  // can be relaxed.
2410406ce1417f76f2034833414dcecc9f56253640cVikas Arora  *iter_limit = (cache_bits > 0) ? iter_neg : iter_neg / 2;
2421e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
2431e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
24433f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int HashChainFindCopy(const VP8LHashChain* const p,
2450406ce1417f76f2034833414dcecc9f56253640cVikas Arora                             int base_position, int xsize_signed,
2468b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                             const uint32_t* const argb, int max_len,
2471e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                             int window_size, int iter_pos, int iter_limit,
248a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                             int* const distance_ptr,
249a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                             int* const length_ptr) {
2501e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const uint32_t* const argb_start = argb + base_position;
2510406ce1417f76f2034833414dcecc9f56253640cVikas Arora  uint64_t best_val = 0;
2520406ce1417f76f2034833414dcecc9f56253640cVikas Arora  uint32_t best_length = 1;
2530406ce1417f76f2034833414dcecc9f56253640cVikas Arora  uint32_t best_distance = 0;
2540406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t xsize = (uint32_t)xsize_signed;
2551e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int min_pos =
2561e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      (base_position > window_size) ? base_position - window_size : 0;
257a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int pos;
258a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  assert(xsize > 0);
2598b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  if (max_len > MAX_LENGTH) {
2608b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    max_len = MAX_LENGTH;
2618b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  }
2620406ce1417f76f2034833414dcecc9f56253640cVikas Arora  for (pos = p->hash_to_first_index_[GetPixPairHash64(argb_start)];
263a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora       pos >= min_pos;
264a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora       pos = p->chain_[pos]) {
2650406ce1417f76f2034833414dcecc9f56253640cVikas Arora    uint64_t val;
2660406ce1417f76f2034833414dcecc9f56253640cVikas Arora    uint32_t curr_length;
2670406ce1417f76f2034833414dcecc9f56253640cVikas Arora    uint32_t distance;
26833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint32_t* const ptr1 = (argb + pos + best_length - 1);
26933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint32_t* const ptr2 = (argb_start + best_length - 1);
2708b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
2711e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    if (iter_pos < 0) {
2721e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      if (iter_pos < iter_limit || best_val >= 0xff0000) {
273a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        break;
274a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
275a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
2761e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    --iter_pos;
2778b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
2788b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    // Before 'expensive' linear match, check if the two arrays match at the
2798b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    // current best length index and also for the succeeding elements.
28033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (ptr1[0] != ptr2[0] || ptr1[1] != ptr2[1]) continue;
2818b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
2828b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    curr_length = FindMatchLength(argb + pos, argb_start, max_len);
2838b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    if (curr_length < best_length) continue;
2848b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
2850406ce1417f76f2034833414dcecc9f56253640cVikas Arora    distance = (uint32_t)(base_position - pos);
2860406ce1417f76f2034833414dcecc9f56253640cVikas Arora    val = curr_length << 16;
287a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    // Favoring 2d locality here gives savings for certain images.
2880406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (distance < 9 * xsize) {
2890406ce1417f76f2034833414dcecc9f56253640cVikas Arora      const uint32_t y = distance / xsize;
2900406ce1417f76f2034833414dcecc9f56253640cVikas Arora      uint32_t x = distance % xsize;
2910406ce1417f76f2034833414dcecc9f56253640cVikas Arora      if (x > (xsize >> 1)) {
292a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        x = xsize - x;
293a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
2940406ce1417f76f2034833414dcecc9f56253640cVikas Arora      if (x <= 7) {
2950406ce1417f76f2034833414dcecc9f56253640cVikas Arora        val += 9 * 9 + 9 * 9;
296a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        val -= y * y + x * x;
297a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
298a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
299a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (best_val < val) {
300a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      best_val = val;
301a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      best_length = curr_length;
3020406ce1417f76f2034833414dcecc9f56253640cVikas Arora      best_distance = distance;
3038b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      if (curr_length >= (uint32_t)max_len) {
304a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        break;
305a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
3060406ce1417f76f2034833414dcecc9f56253640cVikas Arora      if ((best_distance == 1 || distance == xsize) &&
307a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          best_length >= 128) {
308a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        break;
309a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
310a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
311a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
3120406ce1417f76f2034833414dcecc9f56253640cVikas Arora  *distance_ptr = (int)best_distance;
313a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  *length_ptr = best_length;
314a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return (best_length >= MIN_LENGTH);
315a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
316a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
317a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE void PushBackCopy(VP8LBackwardRefs* const refs, int length) {
318a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  while (length >= MAX_LENGTH) {
31933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, MAX_LENGTH));
320a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    length -= MAX_LENGTH;
321a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
322a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (length > 0) {
32333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, length));
324a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
325a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
326a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
32733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int BackwardReferencesRle(int xsize, int ysize,
32833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                 const uint32_t* const argb,
32933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                 VP8LBackwardRefs* const refs) {
330a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int pix_count = xsize * ysize;
331a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int match_len = 0;
332a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i;
33333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
334a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  PushBackCopy(refs, match_len);    // i=0 case
33533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  BackwardRefsCursorAdd(refs, PixOrCopyCreateLiteral(argb[0]));
336a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  for (i = 1; i < pix_count; ++i) {
337a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (argb[i] == argb[i - 1]) {
338a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      ++match_len;
339a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    } else {
340a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      PushBackCopy(refs, match_len);
341a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      match_len = 0;
34233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      BackwardRefsCursorAdd(refs, PixOrCopyCreateLiteral(argb[i]));
343a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
344a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
345a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  PushBackCopy(refs, match_len);
34633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return !refs->error_;
347a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
348a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
349a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int BackwardReferencesHashChain(int xsize, int ysize,
350a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                       const uint32_t* const argb,
351a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                       int cache_bits, int quality,
35233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                       VP8LHashChain* const hash_chain,
353a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                       VP8LBackwardRefs* const refs) {
354a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i;
355a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
356a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int cc_init = 0;
357a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int use_color_cache = (cache_bits > 0);
358a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int pix_count = xsize * ysize;
359a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  VP8LColorCache hashers;
3601e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int window_size = WINDOW_SIZE;
3611e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int iter_pos = 1;
3621e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int iter_limit = -1;
363a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
364a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (use_color_cache) {
365a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    cc_init = VP8LColorCacheInit(&hashers, cache_bits);
366a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!cc_init) goto Error;
367a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
368a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
36933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
3700406ce1417f76f2034833414dcecc9f56253640cVikas Arora  GetParamsForHashChainFindCopy(quality, xsize, cache_bits,
3710406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                &window_size, &iter_pos, &iter_limit);
37233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  HashChainInit(hash_chain);
373a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  for (i = 0; i < pix_count; ) {
374a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    // Alternative#1: Code the pixels starting at 'i' using backward reference.
375a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int offset = 0;
376a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int len = 0;
377a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (i < pix_count - 1) {  // FindCopy(i,..) reads pixels at [i] and [i + 1].
3788b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      int max_len = pix_count - i;
3798b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      HashChainFindCopy(hash_chain, i, xsize, argb, max_len,
3801e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                        window_size, iter_pos, iter_limit,
381a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                        &offset, &len);
382a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
383a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (len >= MIN_LENGTH) {
384a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      // Alternative#2: Insert the pixel at 'i' as literal, and code the
385a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      // pixels starting at 'i + 1' using backward reference.
386a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      int offset2 = 0;
387a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      int len2 = 0;
388a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      int k;
389a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      HashChainInsert(hash_chain, &argb[i], i);
390a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (i < pix_count - 2) {  // FindCopy(i+1,..) reads [i + 1] and [i + 2].
3918b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        int max_len = pix_count - (i + 1);
3928b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        HashChainFindCopy(hash_chain, i + 1, xsize, argb, max_len,
3931e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                          window_size, iter_pos, iter_limit,
3941e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                          &offset2, &len2);
395a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        if (len2 > len + 1) {
396a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          const uint32_t pixel = argb[i];
397a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          // Alternative#2 is a better match. So push pixel at 'i' as literal.
39833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora          PixOrCopy v;
399a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
400a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora            const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
40133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora            v = PixOrCopyCreateCacheIdx(ix);
402a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          } else {
4038b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora            if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel);
40433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora            v = PixOrCopyCreateLiteral(pixel);
405a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          }
40633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora          BackwardRefsCursorAdd(refs, v);
407a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          i++;  // Backward reference to be done for next pixel.
408a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          len = len2;
409a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          offset = offset2;
410a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
411a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
412a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (len >= MAX_LENGTH) {
413a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        len = MAX_LENGTH - 1;
414a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
41533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len));
416a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (use_color_cache) {
417a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        for (k = 0; k < len; ++k) {
418a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          VP8LColorCacheInsert(&hashers, argb[i + k]);
419a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
420a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
421a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      // Add to the hash_chain (but cannot add the last pixel).
422a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      {
423a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i;
424a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        for (k = 1; k < last; ++k) {
425a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          HashChainInsert(hash_chain, &argb[i + k], i + k);
426a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
427a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
428a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      i += len;
429a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    } else {
430a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      const uint32_t pixel = argb[i];
43133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      PixOrCopy v;
432a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
433a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        // push pixel as a PixOrCopyCreateCacheIdx pixel
434a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
43533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        v = PixOrCopyCreateCacheIdx(ix);
436a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      } else {
4378b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel);
43833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        v = PixOrCopyCreateLiteral(pixel);
439a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
44033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      BackwardRefsCursorAdd(refs, v);
441a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (i + 1 < pix_count) {
442a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        HashChainInsert(hash_chain, &argb[i], i);
443a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
444a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      ++i;
445a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
446a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
44733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ok = !refs->error_;
448a2415724fb3466168b2af5b08bd94ba732c0e753Vikas AroraError:
449a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (cc_init) VP8LColorCacheClear(&hashers);
450a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
451a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
452a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
453a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// -----------------------------------------------------------------------------
454a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
455a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroratypedef struct {
456a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double alpha_[VALUES_IN_BYTE];
457a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double red_[VALUES_IN_BYTE];
458a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double literal_[PIX_OR_COPY_CODES_MAX];
459a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double blue_[VALUES_IN_BYTE];
460a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  double distance_[NUM_DISTANCE_CODES];
461a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora} CostModel;
462a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
463a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int BackwardReferencesTraceBackwards(
464a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int xsize, int ysize, int recursive_cost_model,
4651e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    const uint32_t* const argb, int quality, int cache_bits,
46633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LHashChain* const hash_chain,
4671e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    VP8LBackwardRefs* const refs);
468a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
469a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic void ConvertPopulationCountTableToBitEstimates(
47033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int num_symbols, const uint32_t population_counts[], double output[]) {
47133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint32_t sum = 0;
472a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int nonzeros = 0;
473a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i;
474a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  for (i = 0; i < num_symbols; ++i) {
475a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    sum += population_counts[i];
476a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (population_counts[i] > 0) {
477a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      ++nonzeros;
478a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
479a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
480a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (nonzeros <= 1) {
481a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    memset(output, 0, num_symbols * sizeof(*output));
482a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  } else {
483a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    const double logsum = VP8LFastLog2(sum);
484a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    for (i = 0; i < num_symbols; ++i) {
485a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      output[i] = logsum - VP8LFastLog2(population_counts[i]);
486a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
487a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
488a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
489a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
490a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int CostModelBuild(CostModel* const m, int xsize, int ysize,
491a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                          int recursion_level, const uint32_t* const argb,
49233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          int quality, int cache_bits,
49333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          VP8LHashChain* const hash_chain,
49433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          VP8LBackwardRefs* const refs) {
495a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
49633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LHistogram* histo = NULL;
497a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
49833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
499a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (recursion_level > 0) {
500a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!BackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1,
50133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                          argb, quality, cache_bits, hash_chain,
50233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                          refs)) {
503a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      goto Error;
504a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
505a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  } else {
506a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!BackwardReferencesHashChain(xsize, ysize, argb, cache_bits, quality,
50733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                     hash_chain, refs)) {
508a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      goto Error;
509a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
510a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
51133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  histo = VP8LAllocateHistogram(cache_bits);
51233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (histo == NULL) goto Error;
51333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
51433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LHistogramCreate(histo, refs, cache_bits);
51533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
516a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
51733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VP8LHistogramNumCodes(histo->palette_code_bits_),
51833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      histo->literal_, m->literal_);
519a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
52033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VALUES_IN_BYTE, histo->red_, m->red_);
521a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
52233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VALUES_IN_BYTE, histo->blue_, m->blue_);
523a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
52433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VALUES_IN_BYTE, histo->alpha_, m->alpha_);
525a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ConvertPopulationCountTableToBitEstimates(
52633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      NUM_DISTANCE_CODES, histo->distance_, m->distance_);
527a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ok = 1;
528a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
529a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora Error:
53033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LFreeHistogram(histo);
531a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
532a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
533a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
534a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) {
535a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return m->alpha_[v >> 24] +
536a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora         m->red_[(v >> 16) & 0xff] +
537a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora         m->literal_[(v >> 8) & 0xff] +
538a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora         m->blue_[v & 0xff];
539a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
540a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
541a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
542a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx;
543a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return m->literal_[literal_idx];
544a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
545a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
546a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE double GetLengthCost(const CostModel* const m,
547a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                        uint32_t length) {
5488b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int code, extra_bits;
5498b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  VP8LPrefixEncodeBits(length, &code, &extra_bits);
5508b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return m->literal_[VALUES_IN_BYTE + code] + extra_bits;
551a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
552a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
553a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE double GetDistanceCost(const CostModel* const m,
554a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                          uint32_t distance) {
5558b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int code, extra_bits;
5568b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  VP8LPrefixEncodeBits(distance, &code, &extra_bits);
5578b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return m->distance_[code] + extra_bits;
558a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
559a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
560a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int BackwardReferencesHashChainDistanceOnly(
561a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb,
56233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int quality, int cache_bits, VP8LHashChain* const hash_chain,
56333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LBackwardRefs* const refs, uint32_t* const dist_array) {
564a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i;
565a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
566a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int cc_init = 0;
567a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int pix_count = xsize * ysize;
568a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int use_color_cache = (cache_bits > 0);
5691e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  float* const cost =
57033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      (float*)WebPSafeMalloc(pix_count, sizeof(*cost));
57133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  CostModel* cost_model = (CostModel*)WebPSafeMalloc(1ULL, sizeof(*cost_model));
572a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  VP8LColorCache hashers;
573a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68;
574a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const double mul1 = (recursive_cost_model != 0) ? 1.0 : 0.82;
5751e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int min_distance_code = 2;  // TODO(vikasa): tune as function of quality
5761e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int window_size = WINDOW_SIZE;
5771e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int iter_pos = 1;
5781e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int iter_limit = -1;
579a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
58033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (cost == NULL || cost_model == NULL) goto Error;
581a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
582a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (use_color_cache) {
583a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    cc_init = VP8LColorCacheInit(&hashers, cache_bits);
584a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!cc_init) goto Error;
585a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
586a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
587a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (!CostModelBuild(cost_model, xsize, ysize, recursive_cost_model, argb,
58833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                      quality, cache_bits, hash_chain, refs)) {
589a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    goto Error;
590a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
591a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
5921e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  for (i = 0; i < pix_count; ++i) cost[i] = 1e38f;
593a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
594a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  // We loop one pixel at a time, but store all currently best points to
595a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  // non-processed locations from this point.
596a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  dist_array[0] = 0;
5970406ce1417f76f2034833414dcecc9f56253640cVikas Arora  GetParamsForHashChainFindCopy(quality, xsize, cache_bits,
5980406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                &window_size, &iter_pos, &iter_limit);
59933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  HashChainInit(hash_chain);
600a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  for (i = 0; i < pix_count; ++i) {
601a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    double prev_cost = 0.0;
602a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int shortmax;
603a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (i > 0) {
604a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      prev_cost = cost[i - 1];
605a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
606a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    for (shortmax = 0; shortmax < 2; ++shortmax) {
607a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      int offset = 0;
608a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      int len = 0;
609a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (i < pix_count - 1) {  // FindCopy reads pixels at [i] and [i + 1].
6108b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        int max_len = shortmax ? 2 : pix_count - i;
6118b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        HashChainFindCopy(hash_chain, i, xsize, argb, max_len,
6121e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                          window_size, iter_pos, iter_limit,
613a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                          &offset, &len);
614a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
615a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (len >= MIN_LENGTH) {
616a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const int code = DistanceToPlaneCode(xsize, offset);
617a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const double distance_cost =
618a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora            prev_cost + GetDistanceCost(cost_model, code);
619a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        int k;
620a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        for (k = 1; k < len; ++k) {
6211e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora          const double cost_val = distance_cost + GetLengthCost(cost_model, k);
622a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          if (cost[i + k] > cost_val) {
6231e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora            cost[i + k] = (float)cost_val;
624a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora            dist_array[i + k] = k + 1;
625a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          }
626a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
627a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        // This if is for speedup only. It roughly doubles the speed, and
628a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        // makes compression worse by .1 %.
6291e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora        if (len >= 128 && code <= min_distance_code) {
630a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          // Long copy for short distances, let's skip the middle
631a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          // lookups for better copies.
632a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          // 1) insert the hashes.
633a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          if (use_color_cache) {
634a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora            for (k = 0; k < len; ++k) {
635a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora              VP8LColorCacheInsert(&hashers, argb[i + k]);
636a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora            }
637a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          }
638a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          // 2) Add to the hash_chain (but cannot add the last pixel)
639a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          {
6401e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora            const int last = (len + i < pix_count - 1) ? len + i
6411e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                                                       : pix_count - 1;
6421e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora            for (k = i; k < last; ++k) {
6431e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora              HashChainInsert(hash_chain, &argb[k], k);
644a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora            }
645a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          }
646a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          // 3) jump.
647a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          i += len - 1;  // for loop does ++i, thus -1 here.
648a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          goto next_symbol;
649a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
650a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
651a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
652a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (i < pix_count - 1) {
653a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      HashChainInsert(hash_chain, &argb[i], i);
654a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
655a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    {
656a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      // inserting a literal pixel
657a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      double cost_val = prev_cost;
658a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
659a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]);
660a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        cost_val += GetCacheCost(cost_model, ix) * mul0;
661a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      } else {
6628b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
663a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        cost_val += GetLiteralCost(cost_model, argb[i]) * mul1;
664a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
665a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (cost[i] > cost_val) {
6661e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora        cost[i] = (float)cost_val;
667a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        dist_array[i] = 1;  // only one is inserted.
668a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
669a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
670a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora next_symbol: ;
671a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
672a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  // Last pixel still to do, it can only be a single step if not reached
673a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  // through cheaper means already.
67433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ok = !refs->error_;
675a2415724fb3466168b2af5b08bd94ba732c0e753Vikas AroraError:
676a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (cc_init) VP8LColorCacheClear(&hashers);
67733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPSafeFree(cost_model);
67833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPSafeFree(cost);
679a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
680a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
681a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
6821e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// We pack the path at the end of *dist_array and return
6831e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// a pointer to this part of the array. Example:
6841e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// dist_array = [1x2xx3x2] => packed [1x2x1232], chosen_path = [1232]
6851e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic void TraceBackwards(uint32_t* const dist_array,
6861e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                           int dist_array_size,
6871e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                           uint32_t** const chosen_path,
6881e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                           int* const chosen_path_size) {
6891e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  uint32_t* path = dist_array + dist_array_size;
6901e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  uint32_t* cur = dist_array + dist_array_size - 1;
6911e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  while (cur >= dist_array) {
6921e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    const int k = *cur;
6931e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    --path;
6941e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    *path = k;
6951e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    cur -= k;
6961e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  }
6971e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  *chosen_path = path;
6981e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  *chosen_path_size = (int)(dist_array + dist_array_size - path);
699a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
700a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
701a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int BackwardReferencesHashChainFollowChosenPath(
7021e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    int xsize, int ysize, const uint32_t* const argb,
7031e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    int quality, int cache_bits,
704a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    const uint32_t* const chosen_path, int chosen_path_size,
70533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LHashChain* const hash_chain,
706a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    VP8LBackwardRefs* const refs) {
707a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int pix_count = xsize * ysize;
708a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int use_color_cache = (cache_bits > 0);
709a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int size = 0;
710a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int i = 0;
711a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int k;
712a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ix;
713a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
714a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int cc_init = 0;
7151e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int window_size = WINDOW_SIZE;
7161e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int iter_pos = 1;
7171e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int iter_limit = -1;
718a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  VP8LColorCache hashers;
719a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
720a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (use_color_cache) {
721a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    cc_init = VP8LColorCacheInit(&hashers, cache_bits);
722a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!cc_init) goto Error;
723a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
724a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
72533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ClearBackwardRefs(refs);
7260406ce1417f76f2034833414dcecc9f56253640cVikas Arora  GetParamsForHashChainFindCopy(quality, xsize, cache_bits,
7270406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                &window_size, &iter_pos, &iter_limit);
72833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  HashChainInit(hash_chain);
729a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  for (ix = 0; ix < chosen_path_size; ++ix, ++size) {
730a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int offset = 0;
731a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    int len = 0;
7328b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    int max_len = chosen_path[ix];
7338b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    if (max_len != 1) {
7348b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      HashChainFindCopy(hash_chain, i, xsize, argb, max_len,
7351e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                        window_size, iter_pos, iter_limit,
7361e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                        &offset, &len);
7378b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      assert(len == max_len);
73833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len));
739a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (use_color_cache) {
740a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        for (k = 0; k < len; ++k) {
741a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          VP8LColorCacheInsert(&hashers, argb[i + k]);
742a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
743a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
744a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      {
745a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i;
746a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        for (k = 0; k < last; ++k) {
747a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          HashChainInsert(hash_chain, &argb[i + k], i + k);
748a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        }
749a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
750a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      i += len;
751a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    } else {
75233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      PixOrCopy v;
753a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
754a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        // push pixel as a color cache index
755a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]);
75633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        v = PixOrCopyCreateCacheIdx(idx);
757a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      } else {
7588b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
75933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        v = PixOrCopyCreateLiteral(argb[i]);
760a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
76133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      BackwardRefsCursorAdd(refs, v);
762a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (i + 1 < pix_count) {
763a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        HashChainInsert(hash_chain, &argb[i], i);
764a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
765a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      ++i;
766a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
767a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
76833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ok = !refs->error_;
769a2415724fb3466168b2af5b08bd94ba732c0e753Vikas AroraError:
770a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (cc_init) VP8LColorCacheClear(&hashers);
771a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
772a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
773a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
774a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Returns 1 on success.
775a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic int BackwardReferencesTraceBackwards(int xsize, int ysize,
776a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                            int recursive_cost_model,
777a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                            const uint32_t* const argb,
7781e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                                            int quality, int cache_bits,
77933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                            VP8LHashChain* const hash_chain,
780a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                            VP8LBackwardRefs* const refs) {
781a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int ok = 0;
782a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int dist_array_size = xsize * ysize;
783a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  uint32_t* chosen_path = NULL;
784a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int chosen_path_size = 0;
785a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  uint32_t* dist_array =
78633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      (uint32_t*)WebPSafeMalloc(dist_array_size, sizeof(*dist_array));
787a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
788a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (dist_array == NULL) goto Error;
789a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
790a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (!BackwardReferencesHashChainDistanceOnly(
79133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      xsize, ysize, recursive_cost_model, argb, quality, cache_bits, hash_chain,
79233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      refs, dist_array)) {
793a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    goto Error;
794a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
7951e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  TraceBackwards(dist_array, dist_array_size, &chosen_path, &chosen_path_size);
796a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (!BackwardReferencesHashChainFollowChosenPath(
7971e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      xsize, ysize, argb, quality, cache_bits, chosen_path, chosen_path_size,
79833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      hash_chain, refs)) {
799a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    goto Error;
800a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
801a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ok = 1;
802a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora Error:
80333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPSafeFree(dist_array);
804a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return ok;
805a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
806a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
807a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic void BackwardReferences2DLocality(int xsize,
80833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                         const VP8LBackwardRefs* const refs) {
80933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LRefsCursor c = VP8LRefsCursorInit(refs);
81033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (VP8LRefsCursorOk(&c)) {
81133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (PixOrCopyIsCopy(c.cur_pos)) {
81233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const int dist = c.cur_pos->argb_or_distance;
813a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      const int transformed_dist = DistanceToPlaneCode(xsize, dist);
81433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      c.cur_pos->argb_or_distance = transformed_dist;
815a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
81633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LRefsCursorNext(&c);
817a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
818a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
819a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
82033f74dabbc7920a65ed435d7417987589febdc16Vikas AroraVP8LBackwardRefs* VP8LGetBackwardReferences(
82133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int width, int height, const uint32_t* const argb, int quality,
82233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int cache_bits, int use_2d_locality, VP8LHashChain* const hash_chain,
82333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LBackwardRefs refs_array[2]) {
824a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int lz77_is_useful;
825a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int num_pix = width * height;
82633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LBackwardRefs* best = NULL;
82733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LBackwardRefs* const refs_lz77 = &refs_array[0];
82833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LBackwardRefs* const refs_rle = &refs_array[1];
829a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
830a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (!BackwardReferencesHashChain(width, height, argb, cache_bits, quality,
83133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                   hash_chain, refs_lz77)) {
83233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return NULL;
83333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
83433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!BackwardReferencesRle(width, height, argb, refs_rle)) {
83533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return NULL;
836a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
837a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
838a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  {
839a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    double bit_cost_lz77, bit_cost_rle;
84033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LHistogram* const histo = VP8LAllocateHistogram(cache_bits);
84133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (histo == NULL) return NULL;
84233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Evaluate LZ77 coding.
84333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LHistogramCreate(histo, refs_lz77, cache_bits);
844a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    bit_cost_lz77 = VP8LHistogramEstimateBits(histo);
84533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Evaluate RLE coding.
84633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LHistogramCreate(histo, refs_rle, cache_bits);
847a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    bit_cost_rle = VP8LHistogramEstimateBits(histo);
848a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    // Decide if LZ77 is useful.
849a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
85033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LFreeHistogram(histo);
851a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
852a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
853a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  // Choose appropriate backward reference.
854a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (lz77_is_useful) {
8558b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    // TraceBackwards is costly. Don't execute it at lower quality.
8568b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const int try_lz77_trace_backwards = (quality >= 25);
85733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    best = refs_lz77;   // default guess: lz77 is better
858a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (try_lz77_trace_backwards) {
8590406ce1417f76f2034833414dcecc9f56253640cVikas Arora      // Set recursion level for large images using a color cache.
8600406ce1417f76f2034833414dcecc9f56253640cVikas Arora      const int recursion_level =
8610406ce1417f76f2034833414dcecc9f56253640cVikas Arora          (num_pix < 320 * 200) && (cache_bits > 0) ? 1 : 0;
86233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      VP8LBackwardRefs* const refs_trace = &refs_array[1];
86333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      ClearBackwardRefs(refs_trace);
8641e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      if (BackwardReferencesTraceBackwards(width, height, recursion_level, argb,
86533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                           quality, cache_bits, hash_chain,
86633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                           refs_trace)) {
86733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        best = refs_trace;
868a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
869a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
870a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  } else {
87133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    best = refs_rle;
872a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
873a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
874a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (use_2d_locality) BackwardReferences2DLocality(width, best);
875a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
87633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return best;
877a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
878a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
87933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Returns entropy for the given cache bits.
88033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic double ComputeCacheEntropy(const uint32_t* const argb,
88133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                  int xsize, int ysize,
88233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                  const VP8LBackwardRefs* const refs,
88333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                  int cache_bits) {
884a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int pixel_index = 0;
885a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  uint32_t k;
886a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int use_color_cache = (cache_bits > 0);
887a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  int cc_init = 0;
88833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  double entropy = MAX_ENTROPY;
88933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const double kSmallPenaltyForLargeCache = 4.0;
89033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LColorCache hashers;
89133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LRefsCursor c = VP8LRefsCursorInit(refs);
89233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LHistogram* histo = VP8LAllocateHistogram(cache_bits);
89333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (histo == NULL) goto Error;
894a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
895a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (use_color_cache) {
896a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    cc_init = VP8LColorCacheInit(&hashers, cache_bits);
89733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (!cc_init) goto Error;
898a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
899a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
90033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (VP8LRefsCursorOk(&c)) {
90133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const PixOrCopy* const v = c.cur_pos;
902a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (PixOrCopyIsLiteral(v)) {
903a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      if (use_color_cache &&
904a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora          VP8LColorCacheContains(&hashers, argb[pixel_index])) {
905a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        // push pixel as a cache index
906a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]);
907a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        const PixOrCopy token = PixOrCopyCreateCacheIdx(ix);
908a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        VP8LHistogramAddSinglePixOrCopy(histo, &token);
909a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      } else {
910a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        VP8LHistogramAddSinglePixOrCopy(histo, v);
911a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
912a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    } else {
913a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      VP8LHistogramAddSinglePixOrCopy(histo, v);
914a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
915a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (use_color_cache) {
916a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      for (k = 0; k < PixOrCopyLength(v); ++k) {
917a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora        VP8LColorCacheInsert(&hashers, argb[pixel_index + k]);
918a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      }
919a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
920a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    pixel_index += PixOrCopyLength(v);
92133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    VP8LRefsCursorNext(&c);
922a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
923a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  assert(pixel_index == xsize * ysize);
924a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  (void)xsize;  // xsize is not used in non-debug compilations otherwise.
925a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  (void)ysize;  // ysize is not used in non-debug compilations otherwise.
92633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  entropy = VP8LHistogramEstimateBits(histo) +
92733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      kSmallPenaltyForLargeCache * cache_bits;
92833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora Error:
929a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (cc_init) VP8LColorCacheClear(&hashers);
93033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  VP8LFreeHistogram(histo);
93133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return entropy;
932a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
933a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
93433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// *best_cache_bits will contain how many bits are to be used for a color cache.
93533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Returns 0 in case of memory error.
936a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
93733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                      int xsize, int ysize, int quality,
93833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                      VP8LHashChain* const hash_chain,
93933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                      VP8LBackwardRefs* const refs,
940a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                      int* const best_cache_bits) {
94133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int eval_low = 1;
94233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int eval_high = 1;
94333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  double entropy_low = MAX_ENTROPY;
94433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  double entropy_high = MAX_ENTROPY;
94533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int cache_bits_low = 0;
94633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int cache_bits_high = MAX_COLOR_CACHE_BITS;
94733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
94833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!BackwardReferencesHashChain(xsize, ysize, argb, 0, quality, hash_chain,
94933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                   refs)) {
95033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return 0;
951a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
95233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Do a binary search to find the optimal entropy for cache_bits.
95333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (cache_bits_high - cache_bits_low > 1) {
95433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (eval_low) {
95533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      entropy_low =
95633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora          ComputeCacheEntropy(argb, xsize, ysize, refs, cache_bits_low);
95733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      eval_low = 0;
95833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
95933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (eval_high) {
96033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      entropy_high =
96133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora          ComputeCacheEntropy(argb, xsize, ysize, refs, cache_bits_high);
96233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      eval_high = 0;
96333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
96433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (entropy_high < entropy_low) {
96533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      *best_cache_bits = cache_bits_high;
96633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cache_bits_low = (cache_bits_low + cache_bits_high) / 2;
96733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      eval_low = 1;
96833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    } else {
96933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      *best_cache_bits = cache_bits_low;
97033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cache_bits_high = (cache_bits_low + cache_bits_high) / 2;
97133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      eval_high = 1;
972a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
973a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
97433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
975a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
976