encodetxb.c 71.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/*
 * Copyright (c) 2017, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

#include "av1/common/scan.h"
Angie Chiang's avatar
Angie Chiang committed
13
#include "av1/common/blockd.h"
14
#include "av1/common/idct.h"
Angie Chiang's avatar
Angie Chiang committed
15
#include "av1/common/pred_common.h"
16
17
#include "av1/encoder/bitstream.h"
#include "av1/encoder/encodeframe.h"
18
#include "av1/encoder/cost.h"
19
#include "av1/encoder/encodetxb.h"
Angie Chiang's avatar
Angie Chiang committed
20
#include "av1/encoder/rdopt.h"
21
#include "av1/encoder/subexp.h"
Angie Chiang's avatar
Angie Chiang committed
22
#include "av1/encoder/tokenize.h"
23

Angie Chiang's avatar
Angie Chiang committed
24
25
#define TEST_OPTIMIZE_TXB 0

26
void av1_alloc_txb_buf(AV1_COMP *cpi) {
27
#if 0
28
29
30
31
32
33
34
35
36
37
38
39
  AV1_COMMON *cm = &cpi->common;
  int mi_block_size = 1 << MI_SIZE_LOG2;
  // TODO(angiebird): Make sure cm->subsampling_x/y is set correctly, and then
  // use precise buffer size according to cm->subsampling_x/y
  int pixel_stride = mi_block_size * cm->mi_cols;
  int pixel_height = mi_block_size * cm->mi_rows;
  int i;
  for (i = 0; i < MAX_MB_PLANE; ++i) {
    CHECK_MEM_ERROR(
        cm, cpi->tcoeff_buf[i],
        aom_malloc(sizeof(*cpi->tcoeff_buf[i]) * pixel_stride * pixel_height));
  }
40
#else
41
42
43
44
45
46
47
  AV1_COMMON *cm = &cpi->common;
  int size = ((cm->mi_rows >> MAX_MIB_SIZE_LOG2) + 1) *
             ((cm->mi_cols >> MAX_MIB_SIZE_LOG2) + 1);

  // TODO(jingning): This should be further reduced.
  CHECK_MEM_ERROR(cm, cpi->coeff_buffer_base,
                  aom_malloc(sizeof(*cpi->coeff_buffer_base) * size));
48
#endif
49
50
51
}

void av1_free_txb_buf(AV1_COMP *cpi) {
52
#if 0
53
54
55
56
  int i;
  for (i = 0; i < MAX_MB_PLANE; ++i) {
    aom_free(cpi->tcoeff_buf[i]);
  }
57
#else
58
  aom_free(cpi->coeff_buffer_base);
59
#endif
60
61
}

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
void av1_set_coeff_buffer(const AV1_COMP *const cpi, MACROBLOCK *const x,
                          int mi_row, int mi_col) {
  int stride = (cpi->common.mi_cols >> MAX_MIB_SIZE_LOG2) + 1;
  int offset =
      (mi_row >> MAX_MIB_SIZE_LOG2) * stride + (mi_col >> MAX_MIB_SIZE_LOG2);
  CB_COEFF_BUFFER *coeff_buf = &cpi->coeff_buffer_base[offset];
  const int txb_offset = x->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
  for (int plane = 0; plane < MAX_MB_PLANE; ++plane) {
    x->mbmi_ext->tcoeff[plane] = coeff_buf->tcoeff[plane] + x->cb_offset;
    x->mbmi_ext->eobs[plane] = coeff_buf->eobs[plane] + txb_offset;
    x->mbmi_ext->txb_skip_ctx[plane] =
        coeff_buf->txb_skip_ctx[plane] + txb_offset;
    x->mbmi_ext->dc_sign_ctx[plane] =
        coeff_buf->dc_sign_ctx[plane] + txb_offset;
  }
}

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
static void write_golomb(aom_writer *w, int level) {
  int x = level + 1;
  int i = x;
  int length = 0;

  while (i) {
    i >>= 1;
    ++length;
  }
  assert(length > 0);

  for (i = 0; i < length - 1; ++i) aom_write_bit(w, 0);

  for (i = length - 1; i >= 0; --i) aom_write_bit(w, (x >> i) & 0x01);
}

void av1_write_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCKD *xd,
Jingning Han's avatar
Jingning Han committed
96
97
98
                          aom_writer *w, int blk_row, int blk_col, int block,
                          int plane, TX_SIZE tx_size, const tran_low_t *tcoeff,
                          uint16_t eob, TXB_CTX *txb_ctx) {
99
#if !LV_MAP_PROB
100
101
  aom_prob *nz_map;
  aom_prob *eob_flag;
102
#endif
103
  MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
104
  const PLANE_TYPE plane_type = get_plane_type(plane);
105
  const TX_SIZE txs_ctx = get_txsize_context(tx_size);
106
107
  const TX_TYPE tx_type =
      av1_get_tx_type(plane_type, xd, blk_row, blk_col, block, tx_size);
Angie Chiang's avatar
Angie Chiang committed
108
  const SCAN_ORDER *const scan_order = get_scan(cm, tx_size, tx_type, mbmi);
109
110
111
112
  const int16_t *scan = scan_order->scan;
  int c;
  int is_nz;
  const int bwl = b_width_log2_lookup[txsize_to_bsize[tx_size]] + 2;
113
  const int height = tx_size_high[tx_size];
114
  const int seg_eob = tx_size_2d[tx_size];
115
  uint16_t update_eob = 0;
116
  FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
117

Jingning Han's avatar
Jingning Han committed
118
119
120
  (void)blk_row;
  (void)blk_col;

121
122
#if LV_MAP_PROB
  aom_write_symbol(w, eob == 0,
123
                   ec_ctx->txb_skip_cdf[txs_ctx][txb_ctx->txb_skip_ctx], 2);
124
#else
125
  aom_write(w, eob == 0, ec_ctx->txb_skip[txs_ctx][txb_ctx->txb_skip_ctx]);
126
#endif
127
128

  if (eob == 0) return;
Angie Chiang's avatar
Angie Chiang committed
129
#if CONFIG_TXK_SEL
130
131
  av1_write_tx_type(cm, xd, blk_row, blk_col, block, plane,
                    get_min_tx_size(tx_size), w);
Angie Chiang's avatar
Angie Chiang committed
132
#endif
133

134
#if !LV_MAP_PROB
135
136
  nz_map = ec_ctx->nz_map[txs_ctx][plane_type];
  eob_flag = ec_ctx->eob_flag[txs_ctx][plane_type];
137
#endif
138
139

  for (c = 0; c < eob; ++c) {
Angie Chiang's avatar
Angie Chiang committed
140
    int coeff_ctx = get_nz_map_ctx(tcoeff, scan[c], bwl, height, tx_type);
141
    int eob_ctx = get_eob_ctx(tcoeff, scan[c], txs_ctx);
142
143
144
145
146
147

    tran_low_t v = tcoeff[scan[c]];
    is_nz = (v != 0);

    if (c == seg_eob - 1) break;

148
149
#if LV_MAP_PROB
    aom_write_symbol(w, is_nz,
150
                     ec_ctx->nz_map_cdf[txs_ctx][plane_type][coeff_ctx], 2);
151
#else
152
    aom_write(w, is_nz, nz_map[coeff_ctx]);
153
#endif
154
155

    if (is_nz) {
156
157
#if LV_MAP_PROB
      aom_write_symbol(w, c == (eob - 1),
158
                       ec_ctx->eob_flag_cdf[txs_ctx][plane_type][eob_ctx], 2);
159
#else
160
      aom_write(w, c == (eob - 1), eob_flag[eob_ctx]);
161
#endif
162
163
164
165
166
    }
  }

  int i;
  for (i = 0; i < NUM_BASE_LEVELS; ++i) {
167
#if !LV_MAP_PROB
168
    aom_prob *coeff_base = ec_ctx->coeff_base[txs_ctx][plane_type][i];
169
#endif
170
171
172
173
174
175
176
177
178
    update_eob = 0;
    for (c = eob - 1; c >= 0; --c) {
      tran_low_t v = tcoeff[scan[c]];
      tran_low_t level = abs(v);
      int sign = (v < 0) ? 1 : 0;
      int ctx;

      if (level <= i) continue;

179
      ctx = get_base_ctx(tcoeff, scan[c], bwl, height, i + 1);
180
181

      if (level == i + 1) {
182
183
#if LV_MAP_PROB
        aom_write_symbol(
184
            w, 1, ec_ctx->coeff_base_cdf[txs_ctx][plane_type][i][ctx], 2);
185
#else
186
        aom_write(w, 1, coeff_base[ctx]);
187
#endif
188
        if (c == 0) {
189
190
#if LV_MAP_PROB
          aom_write_symbol(
191
              w, sign, ec_ctx->dc_sign_cdf[plane_type][txb_ctx->dc_sign_ctx],
192
193
              2);
#else
194
          aom_write(w, sign, ec_ctx->dc_sign[plane_type][txb_ctx->dc_sign_ctx]);
195
#endif
196
197
198
199
200
        } else {
          aom_write_bit(w, sign);
        }
        continue;
      }
201
202
203

#if LV_MAP_PROB
      aom_write_symbol(w, 0,
204
                       ec_ctx->coeff_base_cdf[txs_ctx][plane_type][i][ctx], 2);
205
#else
206
      aom_write(w, 0, coeff_base[ctx]);
207
#endif
208
209
210
211
212
213
214
215
216
217
218
219
220
221
      update_eob = AOMMAX(update_eob, c);
    }
  }

  for (c = update_eob; c >= 0; --c) {
    tran_low_t v = tcoeff[scan[c]];
    tran_low_t level = abs(v);
    int sign = (v < 0) ? 1 : 0;
    int idx;
    int ctx;

    if (level <= NUM_BASE_LEVELS) continue;

    if (c == 0) {
222
223
#if LV_MAP_PROB
      aom_write_symbol(
224
          w, sign, ec_ctx->dc_sign_cdf[plane_type][txb_ctx->dc_sign_ctx], 2);
225
#else
226
      aom_write(w, sign, ec_ctx->dc_sign[plane_type][txb_ctx->dc_sign_ctx]);
227
#endif
228
229
230
231
232
    } else {
      aom_write_bit(w, sign);
    }

    // level is above 1.
233
    ctx = get_br_ctx(tcoeff, scan[c], bwl, height);
234
235
236
237
238
239
240
241
242
243
244
245
246
247

#if BR_NODE
    int base_range = level - 1 - NUM_BASE_LEVELS;
    int br_set_idx = 0;
    int br_base = 0;
    int br_offset = 0;

    if (base_range >= COEFF_BASE_RANGE)
      br_set_idx = BASE_RANGE_SETS;
    else
      br_set_idx = coeff_to_br_index[base_range];

    for (idx = 0; idx < BASE_RANGE_SETS; ++idx) {
      aom_write_symbol(w, idx == br_set_idx,
248
                       ec_ctx->coeff_br_cdf[txs_ctx][plane_type][idx][ctx], 2);
249
250
251
252
253
254
255
      if (idx == br_set_idx) {
        br_base = br_index_to_coeff[br_set_idx];
        br_offset = base_range - br_base;
        int extra_bits = (1 << br_extra_bits[idx]) - 1;
        for (int tok = 0; tok < extra_bits; ++tok) {
          if (tok == br_offset) {
            aom_write_symbol(
256
                w, 1, ec_ctx->coeff_lps_cdf[txs_ctx][plane_type][ctx], 2);
257
258
259
            break;
          }
          aom_write_symbol(w, 0,
260
                           ec_ctx->coeff_lps_cdf[txs_ctx][plane_type][ctx], 2);
261
262
263
264
265
266
267
268
        }
        //        aom_write_literal(w, br_offset, br_extra_bits[idx]);
        break;
      }
    }

    if (br_set_idx < BASE_RANGE_SETS) continue;
#else  // BR_NODE
269
270
    for (idx = 0; idx < COEFF_BASE_RANGE; ++idx) {
      if (level == (idx + 1 + NUM_BASE_LEVELS)) {
271
#if LV_MAP_PROB
272
        aom_write_symbol(w, 1, ec_ctx->coeff_lps_cdf[txs_ctx][plane_type][ctx],
273
274
                         2);
#else
275
        aom_write(w, 1, ec_ctx->coeff_lps[txs_ctx][plane_type][ctx]);
276
#endif
277
278
        break;
      }
279
#if LV_MAP_PROB
280
      aom_write_symbol(w, 0, ec_ctx->coeff_lps_cdf[txs_ctx][plane_type][ctx],
281
282
                       2);
#else
283
      aom_write(w, 0, ec_ctx->coeff_lps[txs_ctx][plane_type][ctx]);
284
#endif
285
286
    }
    if (idx < COEFF_BASE_RANGE) continue;
287
#endif  // BR_NODE
288
289
290
291
292

    // use 0-th order Golomb code to handle the residual level.
    write_golomb(w, level - COEFF_BASE_RANGE - 1 - NUM_BASE_LEVELS);
  }
}
293

Angie Chiang's avatar
Angie Chiang committed
294
295
296
297
298
299
300
void av1_write_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x,
                         aom_writer *w, int plane) {
  MACROBLOCKD *xd = &x->e_mbd;
  MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
  BLOCK_SIZE bsize = mbmi->sb_type;
  struct macroblockd_plane *pd = &xd->plane[plane];

301
#if CONFIG_CHROMA_SUB8X8
302
303
  const BLOCK_SIZE plane_bsize =
      AOMMAX(BLOCK_4X4, get_plane_block_size(bsize, pd));
304
305
#elif CONFIG_CB4X4
  const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
Angie Chiang's avatar
Angie Chiang committed
306
307
308
309
#else
  const BLOCK_SIZE plane_bsize =
      get_plane_block_size(AOMMAX(bsize, BLOCK_8X8), pd);
#endif
310
311
  const int max_blocks_wide = max_block_wide(xd, plane_bsize, plane);
  const int max_blocks_high = max_block_high(xd, plane_bsize, plane);
312
  const TX_SIZE tx_size = av1_get_tx_size(plane, xd);
Angie Chiang's avatar
Angie Chiang committed
313
314
315
316
317
  const int bkw = tx_size_wide_unit[tx_size];
  const int bkh = tx_size_high_unit[tx_size];
  const int step = tx_size_wide_unit[tx_size] * tx_size_high_unit[tx_size];
  int row, col;
  int block = 0;
318
319
  for (row = 0; row < max_blocks_high; row += bkh) {
    for (col = 0; col < max_blocks_wide; col += bkw) {
Angie Chiang's avatar
Angie Chiang committed
320
321
322
323
      tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block);
      uint16_t eob = x->mbmi_ext->eobs[plane][block];
      TXB_CTX txb_ctx = { x->mbmi_ext->txb_skip_ctx[plane][block],
                          x->mbmi_ext->dc_sign_ctx[plane][block] };
Jingning Han's avatar
Jingning Han committed
324
325
      av1_write_coeffs_txb(cm, xd, w, row, col, block, plane, tx_size, tcoeff,
                           eob, &txb_ctx);
Angie Chiang's avatar
Angie Chiang committed
326
327
328
329
330
      block += step;
    }
  }
}

331
332
static INLINE void get_base_ctx_set(const tran_low_t *tcoeffs,
                                    int c,  // raster order
333
                                    const int bwl, const int height,
334
335
336
337
338
339
340
341
342
343
344
345
346
347
                                    int ctx_set[NUM_BASE_LEVELS]) {
  const int row = c >> bwl;
  const int col = c - (row << bwl);
  const int stride = 1 << bwl;
  int mag[NUM_BASE_LEVELS] = { 0 };
  int idx;
  tran_low_t abs_coeff;
  int i;

  for (idx = 0; idx < BASE_CONTEXT_POSITION_NUM; ++idx) {
    int ref_row = row + base_ref_offset[idx][0];
    int ref_col = col + base_ref_offset[idx][1];
    int pos = (ref_row << bwl) + ref_col;

348
    if (ref_row < 0 || ref_col < 0 || ref_row >= height || ref_col >= stride)
349
350
351
352
353
354
355
356
357
358
359
360
      continue;

    abs_coeff = abs(tcoeffs[pos]);

    for (i = 0; i < NUM_BASE_LEVELS; ++i) {
      ctx_set[i] += abs_coeff > i;
      if (base_ref_offset[idx][0] >= 0 && base_ref_offset[idx][1] >= 0)
        mag[i] |= abs_coeff > (i + 1);
    }
  }

  for (i = 0; i < NUM_BASE_LEVELS; ++i) {
361
    ctx_set[i] = get_base_ctx_from_count_mag(row, col, ctx_set[i], mag[i]);
362
363
364
365
  }
  return;
}

366
static INLINE int get_br_cost(tran_low_t abs_qc, int ctx,
367
                              const int coeff_lps[2]) {
368
369
  const tran_low_t min_level = 1 + NUM_BASE_LEVELS;
  const tran_low_t max_level = 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE;
370
  (void)ctx;
371
  if (abs_qc >= min_level) {
372
373
    const int cost0 = coeff_lps[0];
    const int cost1 = coeff_lps[1];
374
375
376
377
378
379
380
381
382
383
    if (abs_qc >= max_level)
      return COEFF_BASE_RANGE * cost0;
    else
      return (abs_qc - min_level) * cost0 + cost1;
  } else {
    return 0;
  }
}

static INLINE int get_base_cost(tran_low_t abs_qc, int ctx,
384
                                const int coeff_base[2], int base_idx) {
385
  const int level = base_idx + 1;
386
  (void)ctx;
387
388
389
  if (abs_qc < level)
    return 0;
  else
390
    return coeff_base[abs_qc == level];
391
392
}

393
int av1_cost_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCK *x, int plane,
Jingning Han's avatar
Jingning Han committed
394
395
                        int blk_row, int blk_col, int block, TX_SIZE tx_size,
                        TXB_CTX *txb_ctx) {
396
  MACROBLOCKD *const xd = &x->e_mbd;
397
  TX_SIZE txs_ctx = get_txsize_context(tx_size);
398
  const PLANE_TYPE plane_type = get_plane_type(plane);
399
400
  const TX_TYPE tx_type =
      av1_get_tx_type(plane_type, xd, blk_row, blk_col, block, tx_size);
401
402
403
404
405
  MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
  const struct macroblock_plane *p = &x->plane[plane];
  const int eob = p->eobs[block];
  const tran_low_t *const qcoeff = BLOCK_OFFSET(p->qcoeff, block);
  int c, cost;
406
  const int seg_eob = AOMMIN(eob, tx_size_2d[tx_size] - 1);
407
408
409
  int txb_skip_ctx = txb_ctx->txb_skip_ctx;

  const int bwl = b_width_log2_lookup[txsize_to_bsize[tx_size]] + 2;
410
411
  const int height = tx_size_high[tx_size];

Angie Chiang's avatar
Angie Chiang committed
412
  const SCAN_ORDER *const scan_order = get_scan(cm, tx_size, tx_type, mbmi);
413
414
  const int16_t *scan = scan_order->scan;

415
416
  LV_MAP_COEFF_COST *coeff_costs = &x->coeff_costs[txs_ctx][plane_type];

417
418
419
  cost = 0;

  if (eob == 0) {
420
    cost = coeff_costs->txb_skip_cost[txb_skip_ctx][1];
421
422
    return cost;
  }
423
  cost = coeff_costs->txb_skip_cost[txb_skip_ctx][0];
424

Angie Chiang's avatar
Angie Chiang committed
425
#if CONFIG_TXK_SEL
426
  cost += av1_tx_type_cost(cm, x, xd, mbmi->sb_type, plane, tx_size, tx_type);
Angie Chiang's avatar
Angie Chiang committed
427
#endif
428

429
430
431
432
433
434
  for (c = 0; c < eob; ++c) {
    tran_low_t v = qcoeff[scan[c]];
    int is_nz = (v != 0);
    int level = abs(v);

    if (c < seg_eob) {
Angie Chiang's avatar
Angie Chiang committed
435
      int coeff_ctx = get_nz_map_ctx(qcoeff, scan[c], bwl, height, tx_type);
436
      cost += coeff_costs->nz_map_cost[coeff_ctx][is_nz];
437
438
439
440
441
442
443
444
445
    }

    if (is_nz) {
      int ctx_ls[NUM_BASE_LEVELS] = { 0 };
      int sign = (v < 0) ? 1 : 0;

      // sign bit cost
      if (c == 0) {
        int dc_sign_ctx = txb_ctx->dc_sign_ctx;
446
        cost += coeff_costs->dc_sign_cost[dc_sign_ctx][sign];
447
448
449
450
      } else {
        cost += av1_cost_bit(128, sign);
      }

451
      get_base_ctx_set(qcoeff, scan[c], bwl, height, ctx_ls);
452
453
454
455
456
457

      int i;
      for (i = 0; i < NUM_BASE_LEVELS; ++i) {
        if (level <= i) continue;

        if (level == i + 1) {
458
          cost += coeff_costs->base_cost[i][ctx_ls[i]][1];
459
460
          continue;
        }
461
        cost += coeff_costs->base_cost[i][ctx_ls[i]][0];
462
463
464
465
466
      }

      if (level > NUM_BASE_LEVELS) {
        int idx;
        int ctx;
467
        ctx = get_br_ctx(qcoeff, scan[c], bwl, height);
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
#if BR_NODE
        int base_range = level - 1 - NUM_BASE_LEVELS;
        int br_set_idx = base_range < COEFF_BASE_RANGE
                             ? coeff_to_br_index[base_range]
                             : BASE_RANGE_SETS;

        for (idx = 0; idx < BASE_RANGE_SETS; ++idx) {
          if (br_set_idx == idx) {
            int br_base = br_index_to_coeff[br_set_idx];
            int br_offset = base_range - br_base;
            int extra_bits = (1 << br_extra_bits[idx]) - 1;
            cost += coeff_costs->br_cost[idx][ctx][1];
            for (int tok = 0; tok < extra_bits; ++tok) {
              if (tok == br_offset) {
                cost += coeff_costs->lps_cost[ctx][1];
                break;
              }
              cost += coeff_costs->lps_cost[ctx][0];
            }
            //            cost += extra_bits * av1_cost_bit(128, 1);
            break;
          }
          cost += coeff_costs->br_cost[idx][ctx][0];
        }
        if (idx < BASE_RANGE_SETS) continue;
493

494
495
        idx = COEFF_BASE_RANGE;
#else
496
497
        for (idx = 0; idx < COEFF_BASE_RANGE; ++idx) {
          if (level == (idx + 1 + NUM_BASE_LEVELS)) {
498
            cost += coeff_costs->lps_cost[ctx][1];
499
500
            break;
          }
501
          cost += coeff_costs->lps_cost[ctx][0];
502
        }
503
#endif
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
        if (idx >= COEFF_BASE_RANGE) {
          // residual cost
          int r = level - COEFF_BASE_RANGE - NUM_BASE_LEVELS;
          int ri = r;
          int length = 0;

          while (ri) {
            ri >>= 1;
            ++length;
          }

          for (ri = 0; ri < length - 1; ++ri) cost += av1_cost_bit(128, 0);

          for (ri = length - 1; ri >= 0; --ri)
            cost += av1_cost_bit(128, (r >> ri) & 0x01);
        }
      }

      if (c < seg_eob) {
523
        int eob_ctx = get_eob_ctx(qcoeff, scan[c], txs_ctx);
524
        cost += coeff_costs->eob_cost[eob_ctx][c == (eob - 1)];
525
526
527
528
529
530
      }
    }
  }

  return cost;
}
Angie Chiang's avatar
Angie Chiang committed
531

532
533
534
535
536
537
538
539
540
static INLINE int has_base(tran_low_t qc, int base_idx) {
  const int level = base_idx + 1;
  return abs(qc) >= level;
}

static INLINE int has_br(tran_low_t qc) {
  return abs(qc) >= 1 + NUM_BASE_LEVELS;
}

541
static INLINE int get_sign_bit_cost(tran_low_t qc, int coeff_idx,
542
                                    const int (*dc_sign_cost)[2],
543
544
545
546
                                    int dc_sign_ctx) {
  const int sign = (qc < 0) ? 1 : 0;
  // sign bit cost
  if (coeff_idx == 0) {
547
    return dc_sign_cost[dc_sign_ctx][sign];
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  } else {
    return av1_cost_bit(128, sign);
  }
}
static INLINE int get_golomb_cost(int abs_qc) {
  if (abs_qc >= 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
    // residual cost
    int r = abs_qc - COEFF_BASE_RANGE - NUM_BASE_LEVELS;
    int ri = r;
    int length = 0;

    while (ri) {
      ri >>= 1;
      ++length;
    }

    return av1_cost_literal(2 * length - 1);
  } else {
    return 0;
  }
}

570
void gen_txb_cache(TxbCache *txb_cache, TxbInfo *txb_info) {
Angie Chiang's avatar
Angie Chiang committed
571
  // gen_nz_count_arr
572
  const int16_t *scan = txb_info->scan_order->scan;
Angie Chiang's avatar
Angie Chiang committed
573
574
575
  const int bwl = txb_info->bwl;
  const int height = txb_info->height;
  tran_low_t *qcoeff = txb_info->qcoeff;
576
577
  const BASE_CTX_TABLE *base_ctx_table =
      txb_info->coeff_ctx_table->base_ctx_table;
Angie Chiang's avatar
Angie Chiang committed
578
579
580
581
582
  for (int c = 0; c < txb_info->eob; ++c) {
    const int coeff_idx = scan[c];  // raster order
    const int row = coeff_idx >> bwl;
    const int col = coeff_idx - (row << bwl);
    txb_cache->nz_count_arr[coeff_idx] =
Angie Chiang's avatar
Angie Chiang committed
583
        get_nz_count(qcoeff, bwl, height, row, col);
Angie Chiang's avatar
Angie Chiang committed
584
    const int nz_count = txb_cache->nz_count_arr[coeff_idx];
Angie Chiang's avatar
Angie Chiang committed
585
586
    txb_cache->nz_ctx_arr[coeff_idx] =
        get_nz_map_ctx_from_count(nz_count, coeff_idx, bwl, txb_info->tx_type);
Angie Chiang's avatar
Angie Chiang committed
587
588
589
590

    // gen_base_count_mag_arr
    if (!has_base(qcoeff[coeff_idx], 0)) continue;
    int *base_mag = txb_cache->base_mag_arr[coeff_idx];
Angie Chiang's avatar
Angie Chiang committed
591
592
    int count[NUM_BASE_LEVELS];
    get_base_count_mag(base_mag, count, qcoeff, bwl, height, row, col);
Angie Chiang's avatar
Angie Chiang committed
593
594

    for (int i = 0; i < NUM_BASE_LEVELS; ++i) {
Angie Chiang's avatar
Angie Chiang committed
595
596
      if (!has_base(qcoeff[coeff_idx], i)) break;
      txb_cache->base_count_arr[i][coeff_idx] = count[i];
Angie Chiang's avatar
Angie Chiang committed
597
      const int level = i + 1;
Angie Chiang's avatar
Angie Chiang committed
598
      txb_cache->base_ctx_arr[i][coeff_idx] =
599
          base_ctx_table[row != 0][col != 0][base_mag[0] > level][count[i]];
Angie Chiang's avatar
Angie Chiang committed
600
601
602
603
604
605
    }

    // gen_br_count_mag_arr
    if (!has_br(qcoeff[coeff_idx])) continue;
    int *br_count = txb_cache->br_count_arr + coeff_idx;
    int *br_mag = txb_cache->br_mag_arr[coeff_idx];
Angie Chiang's avatar
Angie Chiang committed
606
607
    *br_count = get_br_count_mag(br_mag, qcoeff, bwl, height, row, col,
                                 NUM_BASE_LEVELS);
Angie Chiang's avatar
Angie Chiang committed
608
609
610
    txb_cache->br_ctx_arr[coeff_idx] =
        get_br_ctx_from_count_mag(row, col, *br_count, br_mag[0]);
  }
611
612
}

613
614
615
static INLINE const int *get_level_prob(int level, int coeff_idx,
                                        const TxbCache *txb_cache,
                                        const LV_MAP_COEFF_COST *txb_costs) {
616
  if (level == 0) {
617
    const int ctx = txb_cache->nz_ctx_arr[coeff_idx];
618
    return txb_costs->nz_map_cost[ctx];
619
620
  } else if (level >= 1 && level < 1 + NUM_BASE_LEVELS) {
    const int idx = level - 1;
621
    const int ctx = txb_cache->base_ctx_arr[idx][coeff_idx];
622
    return txb_costs->base_cost[idx][ctx];
623
624
  } else if (level >= 1 + NUM_BASE_LEVELS &&
             level < 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
625
    const int ctx = txb_cache->br_ctx_arr[coeff_idx];
626
    return txb_costs->lps_cost[ctx];
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
  } else if (level >= 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
    printf("get_level_prob does not support golomb\n");
    assert(0);
    return 0;
  } else {
    assert(0);
    return 0;
  }
}

static INLINE tran_low_t get_lower_coeff(tran_low_t qc) {
  if (qc == 0) {
    return 0;
  }
  return qc > 0 ? qc - 1 : qc + 1;
}

Angie Chiang's avatar
Angie Chiang committed
644
645
646
647
648
649
650
static INLINE void update_mag_arr(int *mag_arr, int abs_qc) {
  if (mag_arr[0] == abs_qc) {
    mag_arr[1] -= 1;
    assert(mag_arr[1] >= 0);
  }
}

Angie Chiang's avatar
Angie Chiang committed
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
static INLINE int get_mag_from_mag_arr(const int *mag_arr) {
  int mag;
  if (mag_arr[1] > 0) {
    mag = mag_arr[0];
  } else if (mag_arr[0] > 0) {
    mag = mag_arr[0] - 1;
  } else {
    // no neighbor
    assert(mag_arr[0] == 0 && mag_arr[1] == 0);
    mag = 0;
  }
  return mag;
}

static int neighbor_level_down_update(int *new_count, int *new_mag, int count,
                                      const int *mag, int coeff_idx,
                                      tran_low_t abs_nb_coeff, int nb_coeff_idx,
                                      int level, const TxbInfo *txb_info) {
  *new_count = count;
  *new_mag = get_mag_from_mag_arr(mag);

  int update = 0;
  // check if br_count changes
  if (abs_nb_coeff == level) {
    update = 1;
    *new_count -= 1;
    assert(*new_count >= 0);
  }
  const int row = coeff_idx >> txb_info->bwl;
  const int col = coeff_idx - (row << txb_info->bwl);
  const int nb_row = nb_coeff_idx >> txb_info->bwl;
  const int nb_col = nb_coeff_idx - (nb_row << txb_info->bwl);

  // check if mag changes
  if (nb_row >= row && nb_col >= col) {
    if (abs_nb_coeff == mag[0]) {
      assert(mag[1] > 0);
      if (mag[1] == 1) {
        // the nb is the only qc with max mag
        *new_mag -= 1;
        assert(*new_mag >= 0);
        update = 1;
      }
    }
  }
  return update;
}

static int try_neighbor_level_down_br(int coeff_idx, int nb_coeff_idx,
                                      const TxbCache *txb_cache,
701
                                      const LV_MAP_COEFF_COST *txb_costs,
Angie Chiang's avatar
Angie Chiang committed
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
                                      const TxbInfo *txb_info) {
  const tran_low_t qc = txb_info->qcoeff[coeff_idx];
  const tran_low_t abs_qc = abs(qc);
  const int level = NUM_BASE_LEVELS + 1;
  if (abs_qc < level) return 0;

  const tran_low_t nb_coeff = txb_info->qcoeff[nb_coeff_idx];
  const tran_low_t abs_nb_coeff = abs(nb_coeff);
  const int count = txb_cache->br_count_arr[coeff_idx];
  const int *mag = txb_cache->br_mag_arr[coeff_idx];
  int new_count;
  int new_mag;
  const int update =
      neighbor_level_down_update(&new_count, &new_mag, count, mag, coeff_idx,
                                 abs_nb_coeff, nb_coeff_idx, level, txb_info);
  if (update) {
    const int row = coeff_idx >> txb_info->bwl;
    const int col = coeff_idx - (row << txb_info->bwl);
720
    const int ctx = txb_cache->br_ctx_arr[coeff_idx];
721
    const int org_cost = get_br_cost(abs_qc, ctx, txb_costs->lps_cost[ctx]);
Angie Chiang's avatar
Angie Chiang committed
722
723

    const int new_ctx = get_br_ctx_from_count_mag(row, col, new_count, new_mag);
724
725
    const int new_cost =
        get_br_cost(abs_qc, new_ctx, txb_costs->lps_cost[new_ctx]);
Angie Chiang's avatar
Angie Chiang committed
726
727
728
729
730
731
732
733
734
    const int cost_diff = -org_cost + new_cost;
    return cost_diff;
  } else {
    return 0;
  }
}

static int try_neighbor_level_down_base(int coeff_idx, int nb_coeff_idx,
                                        const TxbCache *txb_cache,
735
                                        const LV_MAP_COEFF_COST *txb_costs,
Angie Chiang's avatar
Angie Chiang committed
736
737
738
                                        const TxbInfo *txb_info) {
  const tran_low_t qc = txb_info->qcoeff[coeff_idx];
  const tran_low_t abs_qc = abs(qc);
739
740
  const BASE_CTX_TABLE *base_ctx_table =
      txb_info->coeff_ctx_table->base_ctx_table;
Angie Chiang's avatar
Angie Chiang committed
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759

  int cost_diff = 0;
  for (int base_idx = 0; base_idx < NUM_BASE_LEVELS; ++base_idx) {
    const int level = base_idx + 1;
    if (abs_qc < level) continue;

    const tran_low_t nb_coeff = txb_info->qcoeff[nb_coeff_idx];
    const tran_low_t abs_nb_coeff = abs(nb_coeff);

    const int count = txb_cache->base_count_arr[base_idx][coeff_idx];
    const int *mag = txb_cache->base_mag_arr[coeff_idx];
    int new_count;
    int new_mag;
    const int update =
        neighbor_level_down_update(&new_count, &new_mag, count, mag, coeff_idx,
                                   abs_nb_coeff, nb_coeff_idx, level, txb_info);
    if (update) {
      const int row = coeff_idx >> txb_info->bwl;
      const int col = coeff_idx - (row << txb_info->bwl);
760
      const int ctx = txb_cache->base_ctx_arr[base_idx][coeff_idx];
761
762
      const int org_cost = get_base_cost(
          abs_qc, ctx, txb_costs->base_cost[base_idx][ctx], base_idx);
Angie Chiang's avatar
Angie Chiang committed
763
764

      const int new_ctx =
765
          base_ctx_table[row != 0][col != 0][new_mag > level][new_count];
766
767
      const int new_cost = get_base_cost(
          abs_qc, new_ctx, txb_costs->base_cost[base_idx][new_ctx], base_idx);
Angie Chiang's avatar
Angie Chiang committed
768
769
770
771
772
773
774
775
      cost_diff += -org_cost + new_cost;
    }
  }
  return cost_diff;
}

static int try_neighbor_level_down_nz(int coeff_idx, int nb_coeff_idx,
                                      const TxbCache *txb_cache,
776
                                      const LV_MAP_COEFF_COST *txb_costs,
Angie Chiang's avatar
Angie Chiang committed
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
                                      TxbInfo *txb_info) {
  // assume eob doesn't change
  const tran_low_t qc = txb_info->qcoeff[coeff_idx];
  const tran_low_t abs_qc = abs(qc);
  const tran_low_t nb_coeff = txb_info->qcoeff[nb_coeff_idx];
  const tran_low_t abs_nb_coeff = abs(nb_coeff);
  if (abs_nb_coeff != 1) return 0;
  const int16_t *iscan = txb_info->scan_order->iscan;
  const int scan_idx = iscan[coeff_idx];
  if (scan_idx == txb_info->seg_eob) return 0;
  const int nb_scan_idx = iscan[nb_coeff_idx];
  if (nb_scan_idx < scan_idx) {
    const int count = txb_cache->nz_count_arr[coeff_idx];
    assert(count > 0);
    txb_info->qcoeff[nb_coeff_idx] = get_lower_coeff(nb_coeff);
Angie Chiang's avatar
Angie Chiang committed
792
793
    const int new_ctx = get_nz_map_ctx_from_count(
        count - 1, coeff_idx, txb_info->bwl, txb_info->tx_type);
Angie Chiang's avatar
Angie Chiang committed
794
    txb_info->qcoeff[nb_coeff_idx] = nb_coeff;
795
    const int ctx = txb_cache->nz_ctx_arr[coeff_idx];
Angie Chiang's avatar
Angie Chiang committed
796
    const int is_nz = abs_qc > 0;
797
798
    const int org_cost = txb_costs->nz_map_cost[ctx][is_nz];
    const int new_cost = txb_costs->nz_map_cost[new_ctx][is_nz];
Angie Chiang's avatar
Angie Chiang committed
799
800
801
802
803
804
805
806
807
    const int cost_diff = new_cost - org_cost;
    return cost_diff;
  } else {
    return 0;
  }
}

static int try_self_level_down(tran_low_t *low_coeff, int coeff_idx,
                               const TxbCache *txb_cache,
808
809
                               const LV_MAP_COEFF_COST *txb_costs,
                               TxbInfo *txb_info) {
810
811
812
813
814
815
816
817
818
819
  const tran_low_t qc = txb_info->qcoeff[coeff_idx];
  if (qc == 0) {
    *low_coeff = 0;
    return 0;
  }
  const tran_low_t abs_qc = abs(qc);
  *low_coeff = get_lower_coeff(qc);
  int cost_diff;
  if (*low_coeff == 0) {
    const int scan_idx = txb_info->scan_order->iscan[coeff_idx];
820
821
822
823
    const int *level_cost =
        get_level_prob(abs_qc, coeff_idx, txb_cache, txb_costs);
    const int *low_level_cost =
        get_level_prob(abs(*low_coeff), coeff_idx, txb_cache, txb_costs);
824
825
826
827
828
    if (scan_idx < txb_info->seg_eob) {
      // When level-0, we code the binary of abs_qc > level
      // but when level-k k > 0 we code the binary of abs_qc == level
      // That's why wee need this special treatment for level-0 map
      // TODO(angiebird): make leve-0 consistent to other levels
829
      cost_diff = -level_cost[1] + low_level_cost[0] - low_level_cost[1];
830
    } else {
831
      cost_diff = -level_cost[1];
832
833
834
835
    }

    if (scan_idx < txb_info->seg_eob) {
      const int eob_ctx =
836
          get_eob_ctx(txb_info->qcoeff, coeff_idx, txb_info->txs_ctx);
837
838
      cost_diff -=
          txb_costs->eob_cost[eob_ctx][scan_idx == (txb_info->eob - 1)];
839
840
841
    }

    const int sign_cost = get_sign_bit_cost(
842
        qc, coeff_idx, txb_costs->dc_sign_cost, txb_info->txb_ctx->dc_sign_ctx);
843
844
    cost_diff -= sign_cost;
  } else if (abs_qc < 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
845
846
847
848
849
850
    const int *level_cost =
        get_level_prob(abs_qc, coeff_idx, txb_cache, txb_costs);
    const int *low_level_cost =
        get_level_prob(abs(*low_coeff), coeff_idx, txb_cache, txb_costs);

    cost_diff = -level_cost[1] + low_level_cost[1] - low_level_cost[0];
851
  } else if (abs_qc == 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE) {
852
853
854
855
    const int *low_level_cost =
        get_level_prob(abs(*low_coeff), coeff_idx, txb_cache, txb_costs);
    cost_diff =
        -get_golomb_cost(abs_qc) + low_level_cost[1] - low_level_cost[0];
856
857
858
859
860
861
862
863
  } else {
    assert(abs_qc > 1 + NUM_BASE_LEVELS + COEFF_BASE_RANGE);
    const tran_low_t abs_low_coeff = abs(*low_coeff);
    cost_diff = -get_golomb_cost(abs_qc) + get_golomb_cost(abs_low_coeff);
  }
  return cost_diff;
}

Angie Chiang's avatar
Angie Chiang committed
864
865
866
867
868
869
870
871
872
873
874
875
876
#define COST_MAP_SIZE 5
#define COST_MAP_OFFSET 2

static INLINE int check_nz_neighbor(tran_low_t qc) { return abs(qc) == 1; }

static INLINE int check_base_neighbor(tran_low_t qc) {
  return abs(qc) <= 1 + NUM_BASE_LEVELS;
}

static INLINE int check_br_neighbor(tran_low_t qc) {
  return abs(qc) > BR_MAG_OFFSET;
}

877
878
879
880
881
882
883
884
885
886
887
888
889
#define FAST_OPTIMIZE_TXB 1

#if FAST_OPTIMIZE_TXB
#define ALNB_REF_OFFSET_NUM 2
static int alnb_ref_offset[ALNB_REF_OFFSET_NUM][2] = {
  { -1, 0 }, { 0, -1 },
};
#define NB_REF_OFFSET_NUM 4
static int nb_ref_offset[NB_REF_OFFSET_NUM][2] = {
  { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 },
};
#endif  // FAST_OPTIMIZE_TXB

Angie Chiang's avatar
Angie Chiang committed
890
891
// TODO(angiebird): add static to this function once it's called
int try_level_down(int coeff_idx, const TxbCache *txb_cache,
892
                   const LV_MAP_COEFF_COST *txb_costs, TxbInfo *txb_info,
Angie Chiang's avatar
Angie Chiang committed
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
                   int (*cost_map)[COST_MAP_SIZE]) {
  if (cost_map) {
    for (int i = 0; i < COST_MAP_SIZE; ++i) av1_zero(cost_map[i]);
  }

  tran_low_t qc = txb_info->qcoeff[coeff_idx];
  tran_low_t low_coeff;
  if (qc == 0) return 0;
  int accu_cost_diff = 0;

  const int16_t *iscan = txb_info->scan_order->iscan;
  const int eob = txb_info->eob;
  const int scan_idx = iscan[coeff_idx];
  if (scan_idx < eob) {
    const int cost_diff = try_self_level_down(&low_coeff, coeff_idx, txb_cache,
908
                                              txb_costs, txb_info);
Angie Chiang's avatar
Angie Chiang committed
909
910
911
912
913
914
915
916
    if (cost_map)
      cost_map[0 + COST_MAP_OFFSET][0 + COST_MAP_OFFSET] = cost_diff;
    accu_cost_diff += cost_diff;
  }

  const int row = coeff_idx >> txb_info->bwl;
  const int col = coeff_idx - (row << txb_info->bwl);
  if (check_nz_neighbor(qc)) {
917
918
919
920
921
922
923
924
925
926
#if FAST_OPTIMIZE_TXB
    int(*ref_offset)[2] = alnb_ref_offset;
    const int ref_num = ALNB_REF_OFFSET_NUM;
#else
    int(*ref_offset)[2] = sig_ref_offset;
    const int ref_num = SIG_REF_OFFSET_NUM;
#endif
    for (int i = 0; i < ref_num; ++i) {
      const int nb_row = row - ref_offset[i][0];
      const int nb_col = col - ref_offset[i][1];
Angie Chiang's avatar
Angie Chiang committed
927
      const int nb_coeff_idx = nb_row * txb_info->stride + nb_col;
928

929
930
      if (nb_row < 0 || nb_col < 0 || nb_row >= txb_info->height ||
          nb_col >= txb_info->stride)
931
932
        continue;

Angie Chiang's avatar
Angie Chiang committed
933
      const int nb_scan_idx = iscan[nb_coeff_idx];
934
      if (nb_scan_idx < eob) {
Angie Chiang's avatar
Angie Chiang committed
935
        const int cost_diff = try_neighbor_level_down_nz(
936
            nb_coeff_idx, coeff_idx, txb_cache, txb_costs, txb_info);
Angie Chiang's avatar
Angie Chiang committed
937
938
939
940
941
942
943
944
945
        if (cost_map)
          cost_map[nb_row - row + COST_MAP_OFFSET]
                  [nb_col - col + COST_MAP_OFFSET] += cost_diff;
        accu_cost_diff += cost_diff;
      }
    }
  }

  if (check_base_neighbor(qc)) {
946
947
948
949
950
951
952
953
954
955
#if FAST_OPTIMIZE_TXB
    int(*ref_offset)[2] = nb_ref_offset;
    const int ref_num = NB_REF_OFFSET_NUM;
#else
    int(*ref_offset)[2] = base_ref_offset;
    const int ref_num = BASE_CONTEXT_POSITION_NUM;
#endif
    for (int i = 0; i < ref_num; ++i) {
      const int nb_row = row - ref_offset[i][0];
      const int nb_col = col - ref_offset[i][1];
Angie Chiang's avatar
Angie Chiang committed
956
      const int nb_coeff_idx = nb_row * txb_info->stride + nb_col;
957

958
959
      if (nb_row < 0 || nb_col < 0 || nb_row >= txb_info->height ||
          nb_col >= txb_info->stride)
960
961
        continue;

Angie Chiang's avatar
Angie Chiang committed
962
      const int nb_scan_idx = iscan[nb_coeff_idx];
963
      if (nb_scan_idx < eob) {
Angie Chiang's avatar
Angie Chiang committed
964
        const int cost_diff = try_neighbor_level_down_base(
965
            nb_coeff_idx, coeff_idx, txb_cache, txb_costs, txb_info);
Angie Chiang's avatar
Angie Chiang committed
966
967
968
969
970
971
972
973
974
        if (cost_map)
          cost_map[nb_row - row + COST_MAP_OFFSET]
                  [nb_col - col + COST_MAP_OFFSET] += cost_diff;
        accu_cost_diff += cost_diff;
      }
    }
  }

  if (check_br_neighbor(qc)) {
975
976
977
978
979
980
981
982
983
984
#if FAST_OPTIMIZE_TXB
    int(*ref_offset)[2] = nb_ref_offset;
    const int ref_num = NB_REF_OFFSET_NUM;
#else
    int(*ref_offset)[2] = br_ref_offset;
    const int ref_num = BR_CONTEXT_POSITION_NUM;
#endif
    for (int i = 0; i < ref_num; ++i) {
      const int nb_row = row - ref_offset[i][0];
      const int nb_col = col - ref_offset[i][1];
Angie Chiang's avatar
Angie Chiang committed
985
      const int nb_coeff_idx = nb_row * txb_info->stride + nb_col;
986

987
988
      if (nb_row < 0 || nb_col < 0 || nb_row >= txb_info->height ||
          nb_col >= txb_info->stride)
989
990
        continue;

Angie Chiang's avatar
Angie Chiang committed
991
      const int nb_scan_idx = iscan[nb_coeff_idx];
992
      if (nb_scan_idx < eob) {
Angie Chiang's avatar
Angie Chiang committed
993
        const int cost_diff = try_neighbor_level_down_br(
994
            nb_coeff_idx, coeff_idx, txb_cache, txb_costs, txb_info);
Angie Chiang's avatar
Angie Chiang committed
995
996
997
998
999
1000
        if (cost_map)
          cost_map[nb_row - row + COST_MAP_OFFSET]
                  [nb_col - col + COST_MAP_OFFSET] += cost_diff;
        accu_cost_diff += cost_diff;
      }
    }
For faster browsing, not all history is shown. View entire blame