1b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski/*
2b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski * Copyright 2014 Google Inc.
3b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski *
4b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski * Use of this source code is governed by a BSD-style license that can be
5b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski * found in the LICENSE file.
6b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski */
7b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
8b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski#include "SkTextureCompressor_ASTC.h"
910a350c32826d10349bc3647e83d623259805b62krajcevski#include "SkTextureCompressor_Blitter.h"
10b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
11b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski#include "SkBlitter.h"
12b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski#include "SkEndian.h"
133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#include "SkMath.h"
14b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
15b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// This table contains the weight values for each texel. This is used in determining
16b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// how to convert a 12x12 grid of alpha values into a 6x5 grid of index values. Since
17b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// we have a 6x5 grid, that gives 30 values that we have to compute. For each index,
18b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// we store up to 20 different triplets of values. In order the triplets are:
19b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// weight, texel-x, texel-y
20b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// The weight value corresponds to the amount that this index contributes to the final
21b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// index value of the given texel. Hence, we need to reconstruct the 6x5 index grid
22b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// from their relative contribution to the 12x12 texel grid.
23b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//
24b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// The algorithm is something like this:
25b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// foreach index i:
26b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//    total-weight = 0;
27b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//    total-alpha = 0;
28b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//    for w = 1 to 20:
29b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//       weight = table[i][w*3];
30b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//       texel-x = table[i][w*3 + 1];
31b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//       texel-y = table[i][w*3 + 2];
32b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//       if weight >= 0:
33b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//           total-weight += weight;
34b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//           total-alpha += weight * alphas[texel-x][texel-y];
35b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//
36b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//    total-alpha /= total-weight;
37b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//    index = top three bits of total-alpha
38b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski//
39b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// If the associated index does not contribute to 20 different texels (e.g. it's in
40b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// a corner), then the extra texels are stored with -1's in the table.
41b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
424881a4d932832c407cc6624460415f624836d7d8krajcevskistatic const int8_t k6x5To12x12Table[30][60] = {
43b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 16, 0, 0, 9, 1, 0, 1, 2, 0, 10, 0, 1, 6, 1, 1, 1, 2, 1, 4, 0, 2, 2,
44b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  1, 2, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
45b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
46b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 7, 1, 0, 15, 2, 0, 10, 3, 0, 3, 4, 0, 4, 1, 1, 9, 2, 1, 6, 3, 1, 2,
47b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 1, 2, 1, 2, 4, 2, 2, 3, 3, 2, 1, 4, 2, -1, 0, 0, -1, 0, 0, -1, 0,
48b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
49b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 6, 3, 0, 13, 4, 0, 12, 5, 0, 4, 6, 0, 4, 3, 1, 8, 4, 1, 8, 5, 1, 3,
50b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  6, 1, 1, 3, 2, 3, 4, 2, 3, 5, 2, 1, 6, 2, -1, 0, 0, -1, 0, 0, -1, 0,
51b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
52b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 4, 5, 0, 12, 6, 0, 13, 7, 0, 6, 8, 0, 2, 5, 1, 7, 6, 1, 8, 7, 1, 4,
53b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  8, 1, 1, 5, 2, 3, 6, 2, 3, 7, 2, 2, 8, 2, -1, 0, 0, -1, 0, 0, -1, 0,
54b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
55b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 3, 7, 0, 10, 8, 0, 15, 9, 0, 7, 10, 0, 2, 7, 1, 6, 8, 1, 9, 9, 1, 4,
56b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  10, 1, 1, 7, 2, 2, 8, 2, 4, 9, 2, 2, 10, 2, -1, 0, 0, -1, 0, 0, -1, 0,
57b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
58b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 9, 0, 9, 10, 0, 16, 11, 0, 1, 9, 1, 6, 10, 1, 10, 11, 1, 2, 10, 2, 4,
59b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  11, 2, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
60b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
61b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 6, 0, 1, 3, 1, 1, 12, 0, 2, 7, 1, 2, 1, 2, 2, 15, 0, 3, 8, 1, 3, 1,
62b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  2, 3, 9, 0, 4, 5, 1, 4, 1, 2, 4, 3, 0, 5, 2, 1, 5, -1, 0, 0, -1, 0,
63b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
64b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 3, 1, 1, 6, 2, 1, 4, 3, 1, 1, 4, 1, 5, 1, 2, 11, 2, 2, 7, 3, 2, 2,
65b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 2, 7, 1, 3, 14, 2, 3, 9, 3, 3, 3, 4, 3, 4, 1, 4, 8, 2, 4, 6, 3,
66b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 2, 4, 4, 1, 1, 5, 3, 2, 5, 2, 3, 5, 1, 4, 5}, // n = 20
67b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 2, 3, 1, 5, 4, 1, 4, 5, 1, 1, 6, 1, 5, 3, 2, 10, 4, 2, 9, 5, 2, 3,
68b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  6, 2, 6, 3, 3, 12, 4, 3, 11, 5, 3, 4, 6, 3, 3, 3, 4, 7, 4, 4, 7, 5,
69b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 2, 6, 4, 1, 3, 5, 2, 4, 5, 2, 5, 5, 1, 6, 5}, // n = 20
70b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 2, 5, 1, 5, 6, 1, 5, 7, 1, 2, 8, 1, 3, 5, 2, 9, 6, 2, 10, 7, 2, 4,
71b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  8, 2, 4, 5, 3, 11, 6, 3, 12, 7, 3, 6, 8, 3, 2, 5, 4, 7, 6, 4, 7, 7,
72b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 3, 8, 4, 1, 5, 5, 2, 6, 5, 2, 7, 5, 1, 8, 5}, // n = 20
73b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 7, 1, 4, 8, 1, 6, 9, 1, 3, 10, 1, 2, 7, 2, 8, 8, 2, 11, 9, 2, 5,
74b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  10, 2, 3, 7, 3, 9, 8, 3, 14, 9, 3, 7, 10, 3, 2, 7, 4, 6, 8, 4, 8, 9,
75b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 4, 10, 4, 1, 7, 5, 2, 8, 5, 3, 9, 5, 1, 10, 5}, // n = 20
76b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 3, 10, 1, 6, 11, 1, 1, 9, 2, 7, 10, 2, 12, 11, 2, 1, 9, 3, 8, 10, 3, 15,
77b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  11, 3, 1, 9, 4, 5, 10, 4, 9, 11, 4, 2, 10, 5, 3, 11, 5, -1, 0, 0, -1, 0,
78b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
79b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 0, 3, 1, 1, 3, 7, 0, 4, 4, 1, 4, 13, 0, 5, 7, 1, 5, 1, 2, 5, 13,
80b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, 6, 7, 1, 6, 1, 2, 6, 7, 0, 7, 4, 1, 7, 1, 0, 8, 1, 1, 8, -1, 0,
81b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
82b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 2, 3, 1, 3, 3, 3, 1, 4, 7, 2, 4, 4, 3, 4, 1, 4, 4, 6, 1, 5, 12,
83b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  2, 5, 8, 3, 5, 2, 4, 5, 6, 1, 6, 12, 2, 6, 8, 3, 6, 2, 4, 6, 3, 1,
84b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  7, 7, 2, 7, 4, 3, 7, 1, 4, 7, 1, 2, 8, 1, 3, 8}, // n = 20
85b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 4, 3, 1, 5, 3, 3, 3, 4, 6, 4, 4, 5, 5, 4, 2, 6, 4, 5, 3, 5, 11,
86b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 5, 10, 5, 5, 3, 6, 5, 5, 3, 6, 11, 4, 6, 10, 5, 6, 3, 6, 6, 3, 3,
87b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  7, 6, 4, 7, 5, 5, 7, 2, 6, 7, 1, 4, 8, 1, 5, 8}, // n = 20
88b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 6, 3, 1, 7, 3, 2, 5, 4, 5, 6, 4, 6, 7, 4, 3, 8, 4, 3, 5, 5, 10,
89b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  6, 5, 11, 7, 5, 5, 8, 5, 3, 5, 6, 10, 6, 6, 11, 7, 6, 5, 8, 6, 2, 5,
90b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  7, 5, 6, 7, 6, 7, 7, 3, 8, 7, 1, 6, 8, 1, 7, 8}, // n = 20
91b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 8, 3, 1, 9, 3, 1, 7, 4, 4, 8, 4, 7, 9, 4, 3, 10, 4, 2, 7, 5, 8,
92b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  8, 5, 12, 9, 5, 6, 10, 5, 2, 7, 6, 8, 8, 6, 12, 9, 6, 6, 10, 6, 1, 7,
93b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  7, 4, 8, 7, 7, 9, 7, 3, 10, 7, 1, 8, 8, 1, 9, 8}, // n = 20
94b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 10, 3, 1, 11, 3, 4, 10, 4, 7, 11, 4, 1, 9, 5, 7, 10, 5, 13, 11, 5, 1,
95b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  9, 6, 7, 10, 6, 13, 11, 6, 4, 10, 7, 7, 11, 7, 1, 10, 8, 1, 11, 8, -1, 0,
96b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
97b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 3, 0, 6, 2, 1, 6, 9, 0, 7, 5, 1, 7, 1, 2, 7, 15, 0, 8, 8, 1, 8, 1,
98b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  2, 8, 12, 0, 9, 7, 1, 9, 1, 2, 9, 6, 0, 10, 3, 1, 10, -1, 0, 0, -1, 0,
99b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
100b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 1, 6, 3, 2, 6, 2, 3, 6, 1, 4, 6, 4, 1, 7, 8, 2, 7, 6, 3, 7, 2,
101b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 7, 7, 1, 8, 14, 2, 8, 9, 3, 8, 3, 4, 8, 5, 1, 9, 11, 2, 9, 8, 3,
102b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  9, 2, 4, 9, 3, 1, 10, 6, 2, 10, 4, 3, 10, 1, 4, 10}, // n = 20
103b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 3, 6, 2, 4, 6, 2, 5, 6, 1, 6, 6, 3, 3, 7, 7, 4, 7, 7, 5, 7, 2,
104b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  6, 7, 6, 3, 8, 12, 4, 8, 11, 5, 8, 4, 6, 8, 4, 3, 9, 10, 4, 9, 9, 5,
105b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  9, 3, 6, 9, 2, 3, 10, 5, 4, 10, 5, 5, 10, 2, 6, 10}, // n = 20
106b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 5, 6, 2, 6, 6, 2, 7, 6, 1, 8, 6, 2, 5, 7, 7, 6, 7, 7, 7, 7, 3,
107b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  8, 7, 4, 5, 8, 11, 6, 8, 12, 7, 8, 6, 8, 8, 3, 5, 9, 9, 6, 9, 10, 7,
108b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  9, 5, 8, 9, 1, 5, 10, 4, 6, 10, 5, 7, 10, 2, 8, 10}, // n = 20
109b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 7, 6, 2, 8, 6, 3, 9, 6, 1, 10, 6, 2, 7, 7, 6, 8, 7, 8, 9, 7, 4,
110b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  10, 7, 3, 7, 8, 9, 8, 8, 14, 9, 8, 7, 10, 8, 2, 7, 9, 7, 8, 9, 11, 9,
111b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  9, 5, 10, 9, 1, 7, 10, 4, 8, 10, 6, 9, 10, 3, 10, 10}, // n = 20
112b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 2, 10, 6, 3, 11, 6, 1, 9, 7, 5, 10, 7, 9, 11, 7, 1, 9, 8, 8, 10, 8, 15,
113b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  11, 8, 1, 9, 9, 7, 10, 9, 12, 11, 9, 3, 10, 10, 6, 11, 10, -1, 0, 0, -1, 0,
114b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
115b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 4, 0, 9, 2, 1, 9, 10, 0, 10, 6, 1, 10, 1, 2, 10, 16, 0, 11, 9, 1, 11, 1,
116b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  2, 11, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
117b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
118b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 2, 1, 9, 4, 2, 9, 2, 3, 9, 1, 4, 9, 4, 1, 10, 9, 2, 10, 6, 3, 10, 2,
119b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  4, 10, 7, 1, 11, 15, 2, 11, 10, 3, 11, 3, 4, 11, -1, 0, 0, -1, 0, 0, -1, 0,
120b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
121b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 2, 3, 9, 3, 4, 9, 3, 5, 9, 1, 6, 9, 4, 3, 10, 8, 4, 10, 7, 5, 10, 2,
122b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  6, 10, 6, 3, 11, 13, 4, 11, 12, 5, 11, 4, 6, 11, -1, 0, 0, -1, 0, 0, -1, 0,
123b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
124b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 5, 9, 3, 6, 9, 3, 7, 9, 1, 8, 9, 3, 5, 10, 8, 6, 10, 8, 7, 10, 4,
125b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  8, 10, 4, 5, 11, 12, 6, 11, 13, 7, 11, 6, 8, 11, -1, 0, 0, -1, 0, 0, -1, 0,
126b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
127b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 1, 7, 9, 3, 8, 9, 4, 9, 9, 2, 10, 9, 2, 7, 10, 6, 8, 10, 9, 9, 10, 4,
128b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  10, 10, 3, 7, 11, 10, 8, 11, 15, 9, 11, 7, 10, 11, -1, 0, 0, -1, 0, 0, -1, 0,
129b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0}, // n = 20
130b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski{ 2, 10, 9, 4, 11, 9, 1, 9, 10, 6, 10, 10, 10, 11, 10, 1, 9, 11, 9, 10, 11, 16,
131b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  11, 11, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
132b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski  0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0} // n = 20
133b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski};
134b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
135b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// Returns the alpha value of a texel at position (x, y) from src.
136b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// (x, y) are assumed to be in the range [0, 12).
13710a350c32826d10349bc3647e83d623259805b62krajcevskiinline uint8_t GetAlpha(const uint8_t *src, int rowBytes, int x, int y) {
138b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    SkASSERT(x >= 0 && x < 12);
139b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    SkASSERT(y >= 0 && y < 12);
140b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    SkASSERT(rowBytes >= 12);
141b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    return *(src + y*rowBytes + x);
142b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski}
143b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
14410a350c32826d10349bc3647e83d623259805b62krajcevskiinline uint8_t GetAlphaTranspose(const uint8_t *src, int rowBytes, int x, int y) {
14510a350c32826d10349bc3647e83d623259805b62krajcevski    return GetAlpha(src, rowBytes, y, x);
14610a350c32826d10349bc3647e83d623259805b62krajcevski}
14710a350c32826d10349bc3647e83d623259805b62krajcevski
148b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// Output the 16 bytes stored in top and bottom and advance the pointer. The bytes
149b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// are stored as the integers are represented in memory, so they should be swapped
150b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// if necessary.
151b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevskistatic inline void send_packing(uint8_t** dst, const uint64_t top, const uint64_t bottom) {
152b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    uint64_t* dst64 = reinterpret_cast<uint64_t*>(*dst);
153b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    dst64[0] = top;
154b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    dst64[1] = bottom;
155b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    *dst += 16;
156b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski}
157b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
158b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// Compresses an ASTC block, by looking up the proper contributions from
159b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski// k6x5To12x12Table and computing an index from the associated values.
16010a350c32826d10349bc3647e83d623259805b62krajcevskitypedef uint8_t (*GetAlphaProc)(const uint8_t* src, int rowBytes, int x, int y);
16110a350c32826d10349bc3647e83d623259805b62krajcevski
16210a350c32826d10349bc3647e83d623259805b62krajcevskitemplate<GetAlphaProc getAlphaProc>
163b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevskistatic void compress_a8_astc_block(uint8_t** dst, const uint8_t* src, int rowBytes) {
164b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // Check for single color
165b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    bool constant = true;
166b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    const uint32_t firstInt = *(reinterpret_cast<const uint32_t*>(src));
167b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    for (int i = 0; i < 12; ++i) {
168b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        const uint32_t *rowInt = reinterpret_cast<const uint32_t *>(src + i*rowBytes);
169b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        constant = constant && (rowInt[0] == firstInt);
170b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        constant = constant && (rowInt[1] == firstInt);
171b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        constant = constant && (rowInt[2] == firstInt);
172b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    }
173b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
174b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    if (constant) {
175b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        if (0 == firstInt) {
176b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            // All of the indices are set to zero, and the colors are
177b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            // v0 = 0, v1 = 255, so everything will be transparent.
178b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            send_packing(dst, SkTEndian_SwapLE64(0x0000000001FE000173ULL), 0);
179b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            return;
180b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        } else if (0xFFFFFFFF == firstInt) {
181b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            // All of the indices are set to zero, and the colors are
182b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            // v0 = 255, v1 = 0, so everything will be opaque.
183b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            send_packing(dst, SkTEndian_SwapLE64(0x000000000001FE0173ULL), 0);
184b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            return;
185b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        }
186b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    }
187b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
188b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    uint8_t indices[30]; // 6x5 index grid
189b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    for (int idx = 0; idx < 30; ++idx) {
190b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        int weightTot = 0;
191b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        int alphaTot = 0;
192b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        for (int w = 0; w < 20; ++w) {
1934881a4d932832c407cc6624460415f624836d7d8krajcevski            const int8_t weight = k6x5To12x12Table[idx][w*3];
194b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            if (weight > 0) {
195b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski                const int x = k6x5To12x12Table[idx][w*3 + 1];
196b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski                const int y = k6x5To12x12Table[idx][w*3 + 2];
197b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski                weightTot += weight;
19810a350c32826d10349bc3647e83d623259805b62krajcevski                alphaTot += weight * getAlphaProc(src, rowBytes, x, y);
1994881a4d932832c407cc6624460415f624836d7d8krajcevski            } else {
2004881a4d932832c407cc6624460415f624836d7d8krajcevski                // In our table, not every entry has 20 weights, and all
2014881a4d932832c407cc6624460415f624836d7d8krajcevski                // of them are nonzero. Once we hit a negative weight, we
2024881a4d932832c407cc6624460415f624836d7d8krajcevski                // know that all of the other weights are not valid either.
2034881a4d932832c407cc6624460415f624836d7d8krajcevski                break;
204b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski            }
205b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        }
206b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
2074881a4d932832c407cc6624460415f624836d7d8krajcevski        indices[idx] = (alphaTot / weightTot) >> 5;
208b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    }
209b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
210b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // Pack indices... The ASTC block layout is fairly complicated. An extensive
211b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // description can be found here:
212b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // https://www.opengl.org/registry/specs/KHR/texture_compression_astc_hdr.txt
213b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //
214b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // Here is a summary of the options that we've chosen:
215b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // 1. Block mode: 0b00101110011
216b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //     - 6x5 texel grid
217b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //     - Single plane
218b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //     - Low-precision index values
219b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //     - Index range 0-7 (three bits per index)
220b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // 2. Partitions: 0b00
221b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //     - One partition
222b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // 3. Color Endpoint Mode: 0b0000
223b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //     - Direct luminance -- e0=(v0,v0,v0,0xFF); e1=(v1,v1,v1,0xFF);
224b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // 4. 8-bit endpoints:
225b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //     v0 = 0, v1 = 255
226b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    //
227b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // The rest of the block contains the 30 index values from before, which
228b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // are currently stored in the indices variable.
229b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
230b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    uint64_t top = 0x0000000001FE000173ULL;
231b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    uint64_t bottom = 0;
232b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
233b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    for (int idx = 0; idx <= 20; ++idx) {
2344881a4d932832c407cc6624460415f624836d7d8krajcevski        const uint8_t index = indices[idx];
235b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        bottom |= static_cast<uint64_t>(index) << (61-(idx*3));
236b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    }
237b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
238b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // index 21 straddles top and bottom
239b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    {
2404881a4d932832c407cc6624460415f624836d7d8krajcevski        const uint8_t index = indices[21];
241b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        bottom |= index & 1;
242b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        top |= static_cast<uint64_t>((index >> 2) | (index & 2)) << 62;
243b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    }
244b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
245b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    for (int idx = 22; idx < 30; ++idx) {
2464881a4d932832c407cc6624460415f624836d7d8krajcevski        const uint8_t index = indices[idx];
247b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        top |= static_cast<uint64_t>(index) << (59-(idx-22)*3);
248b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    }
249b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
250b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    // Reverse each 3-bit index since indices are read in reverse order...
251b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    uint64_t t = (bottom ^ (bottom >> 2)) & 0x2492492492492492ULL;
252b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    bottom = bottom ^ t ^ (t << 2);
253b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
254b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    t = (top ^ (top >> 2)) & 0x0924924000000000ULL;
255b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    top = top ^ t ^ (t << 2);
256b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
257b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    send_packing(dst, SkEndian_SwapLE64(top), SkEndian_SwapLE64(bottom));
258b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski}
259b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
260b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevskiinline void CompressA8ASTCBlockVertical(uint8_t* dst, const uint8_t* src) {
26110a350c32826d10349bc3647e83d623259805b62krajcevski    compress_a8_astc_block<GetAlphaTranspose>(&dst, src, 12);
26210a350c32826d10349bc3647e83d623259805b62krajcevski}
26310a350c32826d10349bc3647e83d623259805b62krajcevski
264b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski////////////////////////////////////////////////////////////////////////////////
2653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//
2663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// ASTC Decoder
2673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//
2683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Full details available in the spec:
2693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// http://www.khronos.org/registry/gles/extensions/OES/OES_texture_compression_astc.txt
2703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//
2713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski////////////////////////////////////////////////////////////////////////////////
2723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
2733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Enable this to assert whenever a decoded block has invalid ASTC values. Otherwise,
2743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// each invalid block will result in a disgusting magenta color.
2753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#define ASSERT_ASTC_DECODE_ERROR 0
2763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
2773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Reverse 64-bit integer taken from TAOCP 4a, although it's better
2783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// documented at this site:
2793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// http://matthewarcus.wordpress.com/2012/11/18/reversing-a-64-bit-word/
2803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
2813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskitemplate <typename T, T m, int k>
2823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline T swap_bits(T p) {
2833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    T q = ((p>>k)^p) & m;
2843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return p^q^(q<<k);
2853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
2863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
2873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline uint64_t reverse64(uint64_t n) {
288dea60f6db3b454b5f6db35032c82163c3b00ad46halcanary    static const uint64_t m0 = 0x5555555555555555ULL;
289dea60f6db3b454b5f6db35032c82163c3b00ad46halcanary    static const uint64_t m1 = 0x0300c0303030c303ULL;
290dea60f6db3b454b5f6db35032c82163c3b00ad46halcanary    static const uint64_t m2 = 0x00c0300c03f0003fULL;
291dea60f6db3b454b5f6db35032c82163c3b00ad46halcanary    static const uint64_t m3 = 0x00000ffc00003fffULL;
2923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    n = ((n>>1)&m0) | (n&m0)<<1;
2933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    n = swap_bits<uint64_t, m1, 4>(n);
2943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    n = swap_bits<uint64_t, m2, 8>(n);
2953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    n = swap_bits<uint64_t, m3, 20>(n);
2963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    n = (n >> 34) | (n << 30);
2973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return n;
2983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
2993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// An ASTC block is 128 bits. We represent it as two 64-bit integers in order
3013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// to efficiently operate on the block using bitwise operations.
3023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistruct ASTCBlock {
3033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    uint64_t fLow;
3043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    uint64_t fHigh;
3053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Reverses the bits of an ASTC block, making the LSB of the
3073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // 128 bit block the MSB.
3083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    inline void reverse() {
3093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const uint64_t newLow = reverse64(this->fHigh);
3103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        this->fHigh = reverse64(this->fLow);
3113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        this->fLow = newLow;
3123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
3133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski};
3143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Writes the given color to every pixel in the block. This is used by void-extent
3163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// blocks (a special constant-color encoding of a block) and by the error function.
3173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline void write_constant_color(uint8_t* dst, int blockDimX, int blockDimY,
3183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                        int dstRowBytes, SkColor color) {
3193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    for (int y = 0; y < blockDimY; ++y) {
3203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkColor *dstColors = reinterpret_cast<SkColor*>(dst);
3213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int x = 0; x < blockDimX; ++x) {
3223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            dstColors[x] = color;
3233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
3243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        dst += dstRowBytes;
3253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
3263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
3273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Sets the entire block to the ASTC "error" color, a disgusting magenta
3293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// that's not supposed to appear in natural images.
3303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline void write_error_color(uint8_t* dst, int blockDimX, int blockDimY,
3313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                     int dstRowBytes) {
3323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    static const SkColor kASTCErrorColor = SkColorSetRGB(0xFF, 0, 0xFF);
3333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#if ASSERT_ASTC_DECODE_ERROR
3353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkDEBUGFAIL("ASTC decoding error!\n");
3363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#endif
3373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    write_constant_color(dst, blockDimX, blockDimY, dstRowBytes, kASTCErrorColor);
3393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
3403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Reads up to 64 bits of the ASTC block starting from bit
3423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 'from' and going up to but not including bit 'to'. 'from' starts
3433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// counting from the LSB, counting up to the MSB. Returns -1 on
3443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// error.
3453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic uint64_t read_astc_bits(const ASTCBlock &block, int from, int to) {
3463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(0 <= from && from <= 128);
3473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(0 <= to && to <= 128);
3483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int nBits = to - from;
3503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (0 == nBits) {
3513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return 0;
3523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
3533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (nBits < 0 || 64 <= nBits) {
3553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkDEBUGFAIL("ASTC -- shouldn't read more than 64 bits");
3563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return -1;
3573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
3583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Remember, the 'to' bit isn't read.
3603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    uint64_t result = 0;
3613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (to <= 64) {
3623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // All desired bits are in the low 64-bits.
3633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        result = (block.fLow >> from) & ((1ULL << nBits) - 1);
3643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else if (from >= 64) {
3653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // All desired bits are in the high 64-bits.
3663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        result = (block.fHigh >> (from - 64)) & ((1ULL << nBits) - 1);
3673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else {
3683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // from < 64 && to > 64
3693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(nBits > (64 - from));
3703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int nLow = 64 - from;
3713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int nHigh = nBits - nLow;
3723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        result =
3733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            ((block.fLow >> from) & ((1ULL << nLow) - 1)) |
3743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            ((block.fHigh & ((1ULL << nHigh) - 1)) << nLow);
3753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
3763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return result;
3783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
3793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Returns the number of bits needed to represent a number
3813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// in the given power-of-two range (excluding the power of two itself).
3823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline int bits_for_range(int x) {
3833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(SkIsPow2(x));
3843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(0 != x);
3853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Since we know it's a power of two, there should only be one bit set,
3863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // meaning the number of trailing zeros is 31 minus the number of leading
3873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // zeros.
3883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return 31 - SkCLZ(x);
3893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
3903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Clamps an integer to the range [0, 255]
3923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline int clamp_byte(int x) {
3933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return SkClampMax(x, 255);
3943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
3953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
3963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Helper function defined in the ASTC spec, section C.2.14
3973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// It transfers a few bits of precision from one value to another.
3983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline void bit_transfer_signed(int *a, int *b) {
3993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    *b >>= 1;
4003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    *b |= *a & 0x80;
4013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    *a >>= 1;
4023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    *a &= 0x3F;
4033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if ( (*a & 0x20) != 0 ) {
4043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        *a -= 0x40;
4053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
4063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
4073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Helper function defined in the ASTC spec, section C.2.14
4093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// It uses the value in the blue channel to tint the red and green
4103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline SkColor blue_contract(int a, int r, int g, int b) {
4113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return SkColorSetARGB(a, (r + b) >> 1, (g + b) >> 1, b);
4123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
4133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Helper function that decodes two colors from eight values. If isRGB is true,
4153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// then the pointer 'v' contains six values and the last two are considered to be
4163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 0xFF. If isRGB is false, then all eight values come from the pointer 'v'. This
4173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// corresponds to the decode procedure for the following endpoint modes:
4183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   kLDR_RGB_Direct_ColorEndpointMode
4193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   kLDR_RGBA_Direct_ColorEndpointMode
4203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline void decode_rgba_direct(const int *v, SkColor *endpoints, bool isRGB) {
4213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v6 = 0xFF;
4233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v7 = 0xFF;
4243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (!isRGB) {
4253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        v6 = v[6];
4263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        v7 = v[7];
4273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
4283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int s0 = v[0] + v[2] + v[4];
4303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int s1 = v[1] + v[3] + v[5];
4313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (s1 >= s0) {
4333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        endpoints[0] = SkColorSetARGB(v6, v[0], v[2], v[4]);
4343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        endpoints[1] = SkColorSetARGB(v7, v[1], v[3], v[5]);
4353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else {
4363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        endpoints[0] = blue_contract(v7, v[1], v[3], v[5]);
4373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        endpoints[1] = blue_contract(v6, v[0], v[2], v[4]);
4383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
4393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
4403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Helper function that decodes two colors from six values. If isRGB is true,
4423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// then the pointer 'v' contains four values and the last two are considered to be
4433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 0xFF. If isRGB is false, then all six values come from the pointer 'v'. This
4443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// corresponds to the decode procedure for the following endpoint modes:
4453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   kLDR_RGB_BaseScale_ColorEndpointMode
4463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode
4473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline void decode_rgba_basescale(const int *v, SkColor *endpoints, bool isRGB) {
4483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v4 = 0xFF;
4503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v5 = 0xFF;
4513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (!isRGB) {
4523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        v4 = v[4];
4533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        v5 = v[5];
4543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
4553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    endpoints[0] = SkColorSetARGB(v4,
4573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  (v[0]*v[3]) >> 8,
4583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  (v[1]*v[3]) >> 8,
4593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  (v[2]*v[3]) >> 8);
4603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    endpoints[1] = SkColorSetARGB(v5, v[0], v[1], v[2]);
4613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
4623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Helper function that decodes two colors from eight values. If isRGB is true,
4643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// then the pointer 'v' contains six values and the last two are considered to be
4653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 0xFF. If isRGB is false, then all eight values come from the pointer 'v'. This
4663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// corresponds to the decode procedure for the following endpoint modes:
4673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   kLDR_RGB_BaseOffset_ColorEndpointMode
4683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   kLDR_RGBA_BaseOffset_ColorEndpointMode
4693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//
4703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// If isRGB is true, then treat this as if v6 and v7 are meant to encode full alpha values.
4713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline void decode_rgba_baseoffset(const int *v, SkColor *endpoints, bool isRGB) {
4723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v0 = v[0];
4733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v1 = v[1];
4743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v2 = v[2];
4753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v3 = v[3];
4763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v4 = v[4];
4773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v5 = v[5];
4783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v6 = isRGB ? 0xFF : v[6];
4793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // The 0 is here because this is an offset, not a direct value
4803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int v7 = isRGB ? 0 : v[7];
4813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bit_transfer_signed(&v1, &v0);
4833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bit_transfer_signed(&v3, &v2);
4843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bit_transfer_signed(&v5, &v4);
4853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (!isRGB) {
4863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        bit_transfer_signed(&v7, &v6);
4873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
4883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int c[2][4];
4903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if ((v1 + v3 + v5) >= 0) {
4913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[0][0] = v6;
4923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[0][1] = v0;
4933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[0][2] = v2;
4943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[0][3] = v4;
4953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
4963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[1][0] = v6 + v7;
4973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[1][1] = v0 + v1;
4983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[1][2] = v2 + v3;
4993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[1][3] = v4 + v5;
5003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else {
5013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[0][0] = v6 + v7;
5023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[0][1] = (v0 + v1 + v4 + v5) >> 1;
5033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[0][2] = (v2 + v3 + v4 + v5) >> 1;
5043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[0][3] = v4 + v5;
5053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[1][0] = v6;
5073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[1][1] = (v0 + v4) >> 1;
5083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[1][2] = (v2 + v4) >> 1;
5093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c[1][3] = v4;
5103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
5113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    endpoints[0] = SkColorSetARGB(clamp_byte(c[0][0]),
5133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  clamp_byte(c[0][1]),
5143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  clamp_byte(c[0][2]),
5153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  clamp_byte(c[0][3]));
5163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    endpoints[1] = SkColorSetARGB(clamp_byte(c[1][0]),
5183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  clamp_byte(c[1][1]),
5193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  clamp_byte(c[1][2]),
5203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  clamp_byte(c[1][3]));
5213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
5223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// A helper class used to decode bit values from standard integer values.
5253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// We can't use this class with ASTCBlock because then it would need to
5263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// handle multi-value ranges, and it's non-trivial to lookup a range of bits
5273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// that splits across two different ints.
5283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskitemplate <typename T>
5293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskiclass SkTBits {
5303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskipublic:
5313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkTBits(const T val) : fVal(val) { }
5323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Returns the bit at the given position
5343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    T operator [](const int idx) const {
5353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return (fVal >> idx) & 1;
5363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
5373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Returns the bits in the given range, inclusive
5393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    T operator ()(const int end, const int start) const {
5403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(end >= start);
5413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return (fVal >> start) & ((1ULL << ((end - start) + 1)) - 1);
5423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
5433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskiprivate:
5453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const T fVal;
5463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski};
5473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// This algorithm matches the trit block decoding in the spec (Table C.2.14)
5493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic void decode_trit_block(int* dst, int nBits, const uint64_t &block) {
5503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkTBits<uint64_t> blockBits(block);
5523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // According to the spec, a trit block, which contains five values,
5543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // has the following layout:
5553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
5563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // 27  26  25  24  23  22  21  20  19  18  17  16
5573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //  -----------------------------------------------
5583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // |T7 |     m4        |T6  T5 |     m3        |T4 |
5593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //  -----------------------------------------------
5603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
5613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // 15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0
5623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //  --------------------------------------------------------------
5633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // |    m2        |T3  T2 |      m1       |T1  T0 |      m0       |
5643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //  --------------------------------------------------------------
5653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
5663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Where the m's are variable width depending on the number of bits used
5673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // to encode the values (anywhere from 0 to 6). Since 3^5 = 243, the extra
5683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // byte labeled T (whose bits are interleaved where 0 is the LSB and 7 is
5693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // the MSB), contains five trit values. To decode the trit values, the spec
5703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // says that we need to follow the following algorithm:
5713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
5723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // if T[4:2] = 111
5733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     C = { T[7:5], T[1:0] }; t4 = t3 = 2
5743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // else
5753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     C = T[4:0]
5763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
5773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // if T[6:5] = 11
5783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     t4 = 2; t3 = T[7]
5793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // else
5803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     t4 = T[7]; t3 = T[6:5]
5813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
5823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // if C[1:0] = 11
5833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     t2 = 2; t1 = C[4]; t0 = { C[3], C[2]&~C[3] }
5843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // else if C[3:2] = 11
5853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     t2 = 2; t1 = 2; t0 = C[1:0]
5863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // else
5873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     t2 = C[4]; t1 = C[3:2]; t0 = { C[1], C[0]&~C[1] }
5883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
5893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // The following C++ code is meant to mirror this layout and algorithm as
5903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // closely as possible.
5913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
5923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int m[5];
5933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (0 == nBits) {
5943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        memset(m, 0, sizeof(m));
5953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else {
5963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(nBits < 8);
5973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        m[0] = static_cast<int>(blockBits(nBits - 1, 0));
5983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        m[1] = static_cast<int>(blockBits(2*nBits - 1 + 2, nBits + 2));
5993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        m[2] = static_cast<int>(blockBits(3*nBits - 1 + 4, 2*nBits + 4));
6003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        m[3] = static_cast<int>(blockBits(4*nBits - 1 + 5, 3*nBits + 5));
6013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        m[4] = static_cast<int>(blockBits(5*nBits - 1 + 7, 4*nBits + 7));
6023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
6033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int T =
6053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        static_cast<int>(blockBits(nBits + 1, nBits)) |
6063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        (static_cast<int>(blockBits(2*nBits + 2 + 1, 2*nBits + 2)) << 2) |
6073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        (static_cast<int>(blockBits[3*nBits + 4] << 4)) |
6083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        (static_cast<int>(blockBits(4*nBits + 5 + 1, 4*nBits + 5)) << 5) |
6093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        (static_cast<int>(blockBits[5*nBits + 7] << 7));
6103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int t[5];
6123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int C;
6143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkTBits<int> Tbits(T);
6153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (0x7 == Tbits(4, 2)) {
6163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        C = (Tbits(7, 5) << 2) | Tbits(1, 0);
6173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[3] = t[4] = 2;
6183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else {
6193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        C = Tbits(4, 0);
6203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (Tbits(6, 5) == 0x3) {
6213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            t[4] = 2; t[3] = Tbits[7];
6223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
6233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            t[4] = Tbits[7]; t[3] = Tbits(6, 5);
6243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
6253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
6263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkTBits<int> Cbits(C);
6283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (Cbits(1, 0) == 0x3) {
6293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[2] = 2;
6303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[1] = Cbits[4];
6313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[0] = (Cbits[3] << 1) | (Cbits[2] & (0x1 & ~(Cbits[3])));
6323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else if (Cbits(3, 2) == 0x3) {
6333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[2] = 2;
6343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[1] = 2;
6353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[0] = Cbits(1, 0);
6363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else {
6373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[2] = Cbits[4];
6383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[1] = Cbits(3, 2);
6393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        t[0] = (Cbits[1] << 1) | (Cbits[0] & (0x1 & ~(Cbits[1])));
6403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
6413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#ifdef SK_DEBUG
6433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Make sure all of the decoded values have a trit less than three
6443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // and a bit value within the range of the allocated bits.
6453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    for (int i = 0; i < 5; ++i) {
6463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(t[i] < 3);
6473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(m[i] < (1 << nBits));
6483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
6493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#endif
6503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    for (int i = 0; i < 5; ++i) {
6523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        *dst = (t[i] << nBits) + m[i];
6533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        ++dst;
6543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
6553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
6563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// This algorithm matches the quint block decoding in the spec (Table C.2.15)
6583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic void decode_quint_block(int* dst, int nBits, const uint64_t &block) {
6593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkTBits<uint64_t> blockBits(block);
6603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // According to the spec, a quint block, which contains three values,
6623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // has the following layout:
6633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
6643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
6653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // 18  17  16  15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0
6663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //  --------------------------------------------------------------------------
6673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // |Q6  Q5 |     m2       |Q4  Q3 |     m1        |Q2  Q1  Q0 |      m0       |
6683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //  --------------------------------------------------------------------------
6693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
6703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Where the m's are variable width depending on the number of bits used
6713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // to encode the values (anywhere from 0 to 4). Since 5^3 = 125, the extra
6723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // 7-bit value labeled Q (whose bits are interleaved where 0 is the LSB and 6 is
6733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // the MSB), contains three quint values. To decode the quint values, the spec
6743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // says that we need to follow the following algorithm:
6753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
6763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // if Q[2:1] = 11 and Q[6:5] = 00
6773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     q2 = { Q[0], Q[4]&~Q[0], Q[3]&~Q[0] }; q1 = q0 = 4
6783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // else
6793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     if Q[2:1] = 11
6803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //         q2 = 4; C = { Q[4:3], ~Q[6:5], Q[0] }
6813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     else
6823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //         q2 = T[6:5]; C = Q[4:0]
6833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
6843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     if C[2:0] = 101
6853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //         q1 = 4; q0 = C[4:3]
6863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //     else
6873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //         q1 = C[4:3]; q0 = C[2:0]
6883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
6893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // The following C++ code is meant to mirror this layout and algorithm as
6903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // closely as possible.
6913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
6923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int m[3];
6933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (0 == nBits) {
6943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        memset(m, 0, sizeof(m));
6953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else {
6963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(nBits < 8);
6973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        m[0] = static_cast<int>(blockBits(nBits - 1, 0));
6983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        m[1] = static_cast<int>(blockBits(2*nBits - 1 + 3, nBits + 3));
6993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        m[2] = static_cast<int>(blockBits(3*nBits - 1 + 5, 2*nBits + 5));
7003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
7013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int Q =
7033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        static_cast<int>(blockBits(nBits + 2, nBits)) |
7043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        (static_cast<int>(blockBits(2*nBits + 3 + 1, 2*nBits + 3)) << 3) |
7053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        (static_cast<int>(blockBits(3*nBits + 5 + 1, 3*nBits + 5)) << 5);
7063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int q[3];
7083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkTBits<int> Qbits(Q); // quantum?
7093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (Qbits(2, 1) == 0x3 && Qbits(6, 5) == 0) {
7113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int notBitZero = (0x1 & ~(Qbits[0]));
7123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        q[2] = (Qbits[0] << 2) | ((Qbits[4] & notBitZero) << 1) | (Qbits[3] & notBitZero);
7133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        q[1] = 4;
7143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        q[0] = 4;
7153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    } else {
7163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int C;
7173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (Qbits(2, 1) == 0x3) {
7183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            q[2] = 4;
7193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            C = (Qbits(4, 3) << 3) | ((0x3 & ~(Qbits(6, 5))) << 1) | Qbits[0];
7203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
7213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            q[2] = Qbits(6, 5);
7223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            C = Qbits(4, 0);
7233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
7243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkTBits<int> Cbits(C);
7263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (Cbits(2, 0) == 0x5) {
7273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            q[1] = 4;
7283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            q[0] = Cbits(4, 3);
7293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
7303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            q[1] = Cbits(4, 3);
7313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            q[0] = Cbits(2, 0);
7323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
7333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
7343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#ifdef SK_DEBUG
7363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    for (int i = 0; i < 3; ++i) {
7373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(q[i] < 5);
7383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(m[i] < (1 << nBits));
7393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
7403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#endif
7413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    for (int i = 0; i < 3; ++i) {
7433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        *dst = (q[i] << nBits) + m[i];
7443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        ++dst;
7453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
7463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
7473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Function that decodes a sequence of integers stored as an ISE (Integer
7493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Sequence Encoding) bit stream. The full details of this function are outlined
7503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// in section C.2.12 of the ASTC spec. A brief overview is as follows:
7513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//
7523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// - Each integer in the sequence is bounded by a specific range r.
7533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// - The range of each value determines the way the bit stream is interpreted,
7543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// - If the range is a power of two, then the sequence is a sequence of bits
7553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// - If the range is of the form 3*2^n, then the sequence is stored as a
7563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   sequence of blocks, each block contains 5 trits and 5 bit sequences, which
7573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   decodes into 5 values.
7583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// - Similarly, if the range is of the form 5*2^n, then the sequence is stored as a
7593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   sequence of blocks, each block contains 3 quints and 3 bit sequences, which
7603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   decodes into 3 values.
7613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic bool decode_integer_sequence(
7623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int* dst,                 // The array holding the destination bits
7633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int dstSize,              // The maximum size of the array
7643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int nVals,                // The number of values that we'd like to decode
7653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const ASTCBlock &block,   // The block that we're decoding from
7663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int startBit,             // The bit from which we're going to do the reading
7673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int endBit,               // The bit at which we stop reading (not inclusive)
7683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bool bReadForward,        // If true, then read LSB -> MSB, else read MSB -> LSB
7693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int nBits,                // The number of bits representing this encoding
7703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int nTrits,               // The number of trits representing this encoding
7713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int nQuints               // The number of quints representing this encoding
7723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski) {
7733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // If we want more values than we have, then fail.
7743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (nVals > dstSize) {
7753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return false;
7763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
7773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    ASTCBlock src = block;
7793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (!bReadForward) {
7813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        src.reverse();
7823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        startBit = 128 - startBit;
7833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        endBit = 128 - endBit;
7843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
7853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    while (nVals > 0) {
7873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (nTrits > 0) {
7893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 == nQuints);
7903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
7913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            int endBlockBit = startBit + 8 + 5*nBits;
7923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            if (endBlockBit > endBit) {
7933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                endBlockBit = endBit;
7943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
7953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
79695b1b3d82d227141647777d83324aa570b530096krajcevski            // Trit blocks are three values large.
79795b1b3d82d227141647777d83324aa570b530096krajcevski            int trits[5];
79895b1b3d82d227141647777d83324aa570b530096krajcevski            decode_trit_block(trits, nBits, read_astc_bits(src, startBit, endBlockBit));
79995b1b3d82d227141647777d83324aa570b530096krajcevski            memcpy(dst, trits, SkMin32(nVals, 5)*sizeof(int));
80095b1b3d82d227141647777d83324aa570b530096krajcevski
8013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            dst += 5;
8023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            nVals -= 5;
8033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            startBit = endBlockBit;
8043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else if (nQuints > 0) {
8063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 == nTrits);
8073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            int endBlockBit = startBit + 7 + 3*nBits;
8093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            if (endBlockBit > endBit) {
8103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                endBlockBit = endBit;
8113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
8123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
81395b1b3d82d227141647777d83324aa570b530096krajcevski            // Quint blocks are three values large
81495b1b3d82d227141647777d83324aa570b530096krajcevski            int quints[3];
81595b1b3d82d227141647777d83324aa570b530096krajcevski            decode_quint_block(quints, nBits, read_astc_bits(src, startBit, endBlockBit));
81695b1b3d82d227141647777d83324aa570b530096krajcevski            memcpy(dst, quints, SkMin32(nVals, 3)*sizeof(int));
81795b1b3d82d227141647777d83324aa570b530096krajcevski
8183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            dst += 3;
8193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            nVals -= 3;
8203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            startBit = endBlockBit;
8213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
8233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            // Just read the bits, but don't read more than we have...
8243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            int endValBit = startBit + nBits;
8253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            if (endValBit > endBit) {
8263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                endValBit = endBit;
8273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
8283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(endValBit - startBit < 31);
8303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            *dst = static_cast<int>(read_astc_bits(src, startBit, endValBit));
8313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            ++dst;
8323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            --nVals;
8333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            startBit = endValBit;
8343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
8353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
8363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return true;
8383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
8393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Helper function that unquantizes some (seemingly random) generated
8413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// numbers... meant to match the ASTC hardware. This function is used
8423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// to unquantize both colors (Table C.2.16) and weights (Table C.2.26)
8433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline int unquantize_value(unsigned mask, int A, int B, int C, int D) {
8443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int T = D * C + B;
8453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    T = T ^ A;
8463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    T = (A & mask) | (T >> 2);
8473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(T < 256);
8483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return T;
8493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
8503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Helper function to replicate the bits in x that represents an oldPrec
8523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// precision integer into a prec precision integer. For example:
8533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//   255 == replicate_bits(7, 3, 8);
8543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline int replicate_bits(int x, int oldPrec, int prec) {
8553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    while (oldPrec < prec) {
8563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int toShift = SkMin32(prec-oldPrec, oldPrec);
8573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        x = (x << toShift) | (x >> (oldPrec - toShift));
8583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        oldPrec += toShift;
8593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
8603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Make sure that no bits are set outside the desired precision.
8623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT((-(1 << prec) & x) == 0);
8633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return x;
8643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
8653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Returns the unquantized value of a color that's represented only as
8673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// a set of bits.
8683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline int unquantize_bits_color(int val, int nBits) {
8693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return replicate_bits(val, nBits, 8);
8703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
8713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Returns the unquantized value of a color that's represented as a
8733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// trit followed by nBits bits. This algorithm follows the sequence
8743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// defined in section C.2.13 of the ASTC spec.
8753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline int unquantize_trit_color(int val, int nBits) {
8763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(nBits > 0);
8773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(nBits < 7);
8783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int D = (val >> nBits) & 0x3;
8803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(D < 3);
8813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int A = -(val & 0x1) & 0x1FF;
8833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    static const int Cvals[6] = { 204, 93, 44, 22, 11, 5 };
8853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int C = Cvals[nBits - 1];
8863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int B = 0;
8883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const SkTBits<int> valBits(val);
8893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    switch (nBits) {
8903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 1:
8913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = 0;
8923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            break;
8933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
8943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 2: {
8953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int b = valBits[1];
8963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = (b << 1) | (b << 2) | (b << 4) | (b << 8);
8973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
8983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
8993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 3: {
9013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int cb = valBits(2, 1);
9023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = cb | (cb << 2) | (cb << 7);
9033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
9053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 4: {
9073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int dcb = valBits(3, 1);
9083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = dcb | (dcb << 6);
9093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
9113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 5: {
9133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int edcb = valBits(4, 1);
9143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = (edcb << 5) | (edcb >> 2);
9153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
9173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 6: {
9193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int fedcb = valBits(5, 1);
9203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = (fedcb << 4) | (fedcb >> 4);
9213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
9233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
9243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return unquantize_value(0x80, A, B, C, D);
9263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
9273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Returns the unquantized value of a color that's represented as a
9293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// quint followed by nBits bits. This algorithm follows the sequence
9303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// defined in section C.2.13 of the ASTC spec.
9313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline int unquantize_quint_color(int val, int nBits) {
9323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int D = (val >> nBits) & 0x7;
9333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(D < 5);
9343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int A = -(val & 0x1) & 0x1FF;
9363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    static const int Cvals[5] = { 113, 54, 26, 13, 6 };
9383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(nBits > 0);
9393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(nBits < 6);
9403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int C = Cvals[nBits - 1];
9423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int B = 0;
9443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const SkTBits<int> valBits(val);
9453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    switch (nBits) {
9463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 1:
9473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = 0;
9483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            break;
9493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 2: {
9513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int b = valBits[1];
9523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = (b << 2) | (b << 3) | (b << 8);
9533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
9553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 3: {
9573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int cb = valBits(2, 1);
9583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = (cb >> 1) | (cb << 1) | (cb << 7);
9593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
9613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 4: {
9633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int dcb = valBits(3, 1);
9643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = (dcb >> 1) | (dcb << 6);
9653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
9673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 5: {
9693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int edcb = valBits(4, 1);
9703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            B = (edcb << 5) | (edcb >> 3);
9713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        break;
9733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
9743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return unquantize_value(0x80, A, B, C, D);
9763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
9773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// This algorithm takes a list of integers, stored in vals, and unquantizes them
9793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// in place. This follows the algorithm laid out in section C.2.13 of the ASTC spec.
9803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic void unquantize_colors(int *vals, int nVals, int nBits, int nTrits, int nQuints) {
9813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    for (int i = 0; i < nVals; ++i) {
9823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (nTrits > 0) {
9833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(nQuints == 0);
9843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            vals[i] = unquantize_trit_color(vals[i], nBits);
9853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else if (nQuints > 0) {
9863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(nTrits == 0);
9873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            vals[i] = unquantize_quint_color(vals[i], nBits);
9883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
9893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(nQuints == 0 && nTrits == 0);
9903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            vals[i] = unquantize_bits_color(vals[i], nBits);
9913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
9923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
9933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
9943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
9953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Returns an interpolated value between c0 and c1 based on the weight. This
9963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// follows the algorithm laid out in section C.2.19 of the ASTC spec.
9973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic int interpolate_channel(int c0, int c1, int weight) {
9983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(0 <= c0 && c0 < 256);
9993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(0 <= c1 && c1 < 256);
10003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    c0 = (c0 << 8) | c0;
10023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    c1 = (c1 << 8) | c1;
10033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int result = ((c0*(64 - weight) + c1*weight + 32) / 64) >> 8;
10053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (result > 255) {
10073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return 255;
10083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
10093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkASSERT(result >= 0);
10113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return result;
10123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
10133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Returns an interpolated color between the two endpoints based on the weight.
10153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic SkColor interpolate_endpoints(const SkColor endpoints[2], int weight) {
10163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return SkColorSetARGB(
10173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        interpolate_channel(SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight),
10183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        interpolate_channel(SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight),
10193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        interpolate_channel(SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight),
10203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        interpolate_channel(SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight));
10213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
10223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Returns an interpolated color between the two endpoints based on the weight.
10243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// It uses separate weights for the channel depending on the value of the 'plane'
10253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// variable. By default, all channels will use weight 0, and the value of plane
10263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// means that weight1 will be used for:
10273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 0: red
10283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 1: green
10293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 2: blue
10303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 3: alpha
10313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic SkColor interpolate_dual_endpoints(
10323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const SkColor endpoints[2], int weight0, int weight1, int plane) {
10333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int a = interpolate_channel(SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight0);
10343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int r = interpolate_channel(SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight0);
10353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int g = interpolate_channel(SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight0);
10363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int b = interpolate_channel(SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight0);
10373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    switch (plane) {
10393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 0:
10413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            r = interpolate_channel(
10423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight1);
10433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            break;
10443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 1:
10463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            g = interpolate_channel(
10473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight1);
10483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            break;
10493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 2:
10513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            b = interpolate_channel(
10523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight1);
10533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            break;
10543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        case 3:
10563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            a = interpolate_channel(
10573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight1);
10583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            break;
10593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        default:
10613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkDEBUGFAIL("Plane should be 0-3");
10623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            break;
10633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
10643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    return SkColorSetARGB(a, r, g, b);
10663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
10673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// A struct of decoded values that we use to carry around information
10693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// about the block. dimX and dimY are the dimension in texels of the block,
10703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// for which there is only a limited subset of valid values:
10713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski//
10723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// 4x4, 5x4, 5x5, 6x5, 6x6, 8x5, 8x6, 8x8, 10x5, 10x6, 10x8, 10x10, 12x10, 12x12
10733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistruct ASTCDecompressionData {
10753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    ASTCDecompressionData(int dimX, int dimY) : fDimX(dimX), fDimY(dimY) { }
10763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int   fDimX;      // the X dimension of the decompressed block
10773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const int   fDimY;      // the Y dimension of the decompressed block
10783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    ASTCBlock   fBlock;     // the block data
10793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int         fBlockMode; // the block header that contains the block mode.
10803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bool fDualPlaneEnabled; // is this block compressing dual weight planes?
10823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fDualPlane;        // the independent plane in dual plane mode.
10833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bool fVoidExtent;       // is this block a single color?
10853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bool fError;            // does this block have an error encoding?
10863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fWeightDimX;       // the x dimension of the weight grid
10883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fWeightDimY;       // the y dimension of the weight grid
10893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fWeightBits;       // the number of bits used for each weight value
10913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fWeightTrits;      // the number of trits used for each weight value
10923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fWeightQuints;     // the number of quints used for each weight value
10933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fPartCount;        // the number of partitions in this block
10953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fPartIndex;        // the partition index: only relevant if fPartCount > 0
10963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
10973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // CEM values can be anything in the range 0-15, and each corresponds to a different
10983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // mode that represents the color data. We only support LDR modes.
10993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    enum ColorEndpointMode {
11003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_Luminance_Direct_ColorEndpointMode          = 0,
11013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_Luminance_BaseOffset_ColorEndpointMode      = 1,
11023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kHDR_Luminance_LargeRange_ColorEndpointMode      = 2,
11033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kHDR_Luminance_SmallRange_ColorEndpointMode      = 3,
11043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_LuminanceAlpha_Direct_ColorEndpointMode     = 4,
11053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_LuminanceAlpha_BaseOffset_ColorEndpointMode = 5,
11063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_RGB_BaseScale_ColorEndpointMode             = 6,
11073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kHDR_RGB_BaseScale_ColorEndpointMode             = 7,
11083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_RGB_Direct_ColorEndpointMode                = 8,
11093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_RGB_BaseOffset_ColorEndpointMode            = 9,
11103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode    = 10,
11113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kHDR_RGB_ColorEndpointMode                       = 11,
11123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_RGBA_Direct_ColorEndpointMode               = 12,
11133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kLDR_RGBA_BaseOffset_ColorEndpointMode           = 13,
11143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kHDR_RGB_LDRAlpha_ColorEndpointMode              = 14,
11153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        kHDR_RGB_HDRAlpha_ColorEndpointMode              = 15
11163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    };
11173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    static const int kMaxColorEndpointModes = 16;
11183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // the color endpoint modes for this block.
11203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    static const int kMaxPartitions = 4;
11213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    ColorEndpointMode fCEM[kMaxPartitions];
11223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fColorStartBit;    // The bit position of the first bit of the color data
11243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int  fColorEndBit;      // The bit position of the last *possible* bit of the color data
11253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Returns the number of partitions for this block.
11273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int numPartitions() const {
11283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return fPartCount;
11293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
11303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Returns the total number of weight values that are stored in this block
11323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int numWeights() const {
11333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return fWeightDimX * fWeightDimY * (fDualPlaneEnabled ? 2 : 1);
11343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
11353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#ifdef SK_DEBUG
11373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Returns the maximum value that any weight can take. We really only use
11383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // this function for debugging.
11393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int maxWeightValue() const {
11403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int maxVal = (1 << fWeightBits);
11413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (fWeightTrits > 0) {
11423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 == fWeightQuints);
11433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            maxVal *= 3;
11443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else if (fWeightQuints > 0) {
11453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 == fWeightTrits);
11463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            maxVal *= 5;
11473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
11483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return maxVal - 1;
11493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
11503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#endif
11513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // The number of bits needed to represent the texel weight data. This
11533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // comes from the 'data size determination' section of the ASTC spec (C.2.22)
11543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int numWeightBits() const {
11553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int nWeights = this->numWeights();
11563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return
11573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            ((nWeights*8*fWeightTrits + 4) / 5) +
11583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            ((nWeights*7*fWeightQuints + 2) / 3) +
11593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            (nWeights*fWeightBits);
11603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
11613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Returns the number of color values stored in this block. The number of
11633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // values stored is directly a function of the color endpoint modes.
11643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int numColorValues() const {
11653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int numValues = 0;
11663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int i = 0; i < this->numPartitions(); ++i) {
11673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            int cemInt = static_cast<int>(fCEM[i]);
11683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            numValues += ((cemInt >> 2) + 1) * 2;
11693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
11703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return numValues;
11723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
11733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Figures out the number of bits available for color values, and fills
11753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // in the maximum encoding that will fit the number of color values that
11763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // we need. Returns false on error. (See section C.2.22 of the spec)
11773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bool getColorValueEncoding(int *nBits, int *nTrits, int *nQuints) const {
11783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (NULL == nBits || NULL == nTrits || NULL == nQuints) {
11793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return false;
11803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
11813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int nColorVals = this->numColorValues();
11833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (nColorVals <= 0) {
11843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return false;
11853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
11863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int colorBits = fColorEndBit - fColorStartBit;
11883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(colorBits > 0);
11893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // This is the minimum amount of accuracy required by the spec.
11913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (colorBits < ((13 * nColorVals + 4) / 5)) {
11923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return false;
11933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
11943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
11953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Values can be represented as at most 8-bit values.
11963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // !SPEED! place this in a lookup table based on colorBits and nColorVals
11973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int i = 255; i > 0; --i) {
11983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            int range = i + 1;
11993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            int bits = 0, trits = 0, quints = 0;
12003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            bool valid = false;
12013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            if (SkIsPow2(range)) {
12023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                bits = bits_for_range(range);
12033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                valid = true;
12043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            } else if ((range % 3) == 0 && SkIsPow2(range/3)) {
12053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                trits = 1;
12063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                bits = bits_for_range(range/3);
12073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                valid = true;
12083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            } else if ((range % 5) == 0 && SkIsPow2(range/5)) {
12093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                quints = 1;
12103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                bits = bits_for_range(range/5);
12113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                valid = true;
12123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
12133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            if (valid) {
12153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                const int actualColorBits =
12163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    ((nColorVals*8*trits + 4) / 5) +
12173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    ((nColorVals*7*quints + 2) / 3) +
12183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    (nColorVals*bits);
12193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                if (actualColorBits <= colorBits) {
12203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    *nTrits = trits;
12213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    *nQuints = quints;
12223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    *nBits = bits;
12233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    return true;
12243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
12253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
12263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
12273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return false;
12293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
12303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Converts the sequence of color values into endpoints. The algorithm here
12323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // corresponds to the values determined by section C.2.14 of the ASTC spec
12333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    void colorEndpoints(SkColor endpoints[4][2], const int* colorValues) const {
12343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int i = 0; i < this->numPartitions(); ++i) {
12353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            switch (fCEM[i]) {
12363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_Luminance_Direct_ColorEndpointMode: {
12373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int* v = colorValues;
12383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    endpoints[i][0] = SkColorSetARGB(0xFF, v[0], v[0], v[0]);
12393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    endpoints[i][1] = SkColorSetARGB(0xFF, v[1], v[1], v[1]);
12403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 2;
12423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
12433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
12443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_Luminance_BaseOffset_ColorEndpointMode: {
12463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int* v = colorValues;
12473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int L0 = (v[0] >> 2) | (v[1] & 0xC0);
12483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int L1 = clamp_byte(L0 + (v[1] & 0x3F));
12493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    endpoints[i][0] = SkColorSetARGB(0xFF, L0, L0, L0);
12513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    endpoints[i][1] = SkColorSetARGB(0xFF, L1, L1, L1);
12523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 2;
12543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
12553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
12563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_LuminanceAlpha_Direct_ColorEndpointMode: {
12583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int* v = colorValues;
12593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    endpoints[i][0] = SkColorSetARGB(v[2], v[0], v[0], v[0]);
12613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    endpoints[i][1] = SkColorSetARGB(v[3], v[1], v[1], v[1]);
12623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 4;
12643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
12653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
12663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_LuminanceAlpha_BaseOffset_ColorEndpointMode: {
12683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    int v0 = colorValues[0];
12693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    int v1 = colorValues[1];
12703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    int v2 = colorValues[2];
12713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    int v3 = colorValues[3];
12723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    bit_transfer_signed(&v1, &v0);
12743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    bit_transfer_signed(&v3, &v2);
12753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    endpoints[i][0] = SkColorSetARGB(v2, v0, v0, v0);
12773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    endpoints[i][1] = SkColorSetARGB(
12783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        clamp_byte(v3+v2),
12793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        clamp_byte(v1+v0),
12803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        clamp_byte(v1+v0),
12813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        clamp_byte(v1+v0));
12823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 4;
12843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
12853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
12863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_RGB_BaseScale_ColorEndpointMode: {
12883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    decode_rgba_basescale(colorValues, endpoints[i], true);
12893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 4;
12903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
12913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
12923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_RGB_Direct_ColorEndpointMode: {
12943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    decode_rgba_direct(colorValues, endpoints[i], true);
12953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 6;
12963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
12973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
12983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
12993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_RGB_BaseOffset_ColorEndpointMode: {
13003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    decode_rgba_baseoffset(colorValues, endpoints[i], true);
13013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 6;
13023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode: {
13063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    decode_rgba_basescale(colorValues, endpoints[i], false);
13073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 6;
13083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_RGBA_Direct_ColorEndpointMode: {
13123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    decode_rgba_direct(colorValues, endpoints[i], false);
13133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 8;
13143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case kLDR_RGBA_BaseOffset_ColorEndpointMode: {
13183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    decode_rgba_baseoffset(colorValues, endpoints[i], false);
13193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    colorValues += 8;
13203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                default:
13243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    SkDEBUGFAIL("HDR mode unsupported! This should be caught sooner.");
13253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
13263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
13273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
13283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
13293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Follows the procedure from section C.2.17 of the ASTC specification
13313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int unquantizeWeight(int x) const {
13323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(x <= this->maxWeightValue());
13333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int D = (x >> fWeightBits) & 0x7;
13353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int A = -(x & 0x1) & 0x7F;
13363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkTBits<int> xbits(x);
13383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int T = 0;
13403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (fWeightTrits > 0) {
13413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 == fWeightQuints);
13423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            switch (fWeightBits) {
13433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 0: {
13443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    // x is a single trit
13453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    SkASSERT(x < 3);
13463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    static const int kUnquantizationTable[3] = { 0, 32, 63 };
13483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    T = kUnquantizationTable[x];
13493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 1: {
13533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int B = 0;
13543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int C = 50;
13553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    T = unquantize_value(0x20, A, B, C, D);
13563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 2: {
13603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int b = xbits[1];
13613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int B = b | (b << 2) | (b << 6);
13623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int C = 23;
13633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    T = unquantize_value(0x20, A, B, C, D);
13643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 3: {
13683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int cb = xbits(2, 1);
13693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int B = cb | (cb << 5);
13703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int C = 11;
13713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    T = unquantize_value(0x20, A, B, C, D);
13723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                default:
13763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    SkDEBUGFAIL("Too many bits for trit encoding");
13773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
13783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
13793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else if (fWeightQuints > 0) {
13813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 == fWeightTrits);
13823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            switch (fWeightBits) {
13833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 0: {
13843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    // x is a single quint
13853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    SkASSERT(x < 5);
13863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    static const int kUnquantizationTable[5] = { 0, 16, 32, 47, 63 };
13883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    T = kUnquantizationTable[x];
13893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 1: {
13933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int B = 0;
13943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int C = 28;
13953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    T = unquantize_value(0x20, A, B, C, D);
13963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
13973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
13983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
13993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 2: {
14003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int b = xbits[1];
14013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int B = (b << 1) | (b << 6);
14023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    const int C = 13;
14033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    T = unquantize_value(0x20, A, B, C, D);
14043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
14053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
14063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                default:
14083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    SkDEBUGFAIL("Too many bits for quint encoding");
14093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
14103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
14113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
14123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 == fWeightTrits);
14133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 == fWeightQuints);
14143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            T = replicate_bits(x, fWeightBits, 6);
14163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
14173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // This should bring the value within [0, 63]..
14193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(T <= 63);
14203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (T > 32) {
14223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            T += 1;
14233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
14243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(T <= 64);
14263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return T;
14283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
14293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Returns the weight at the associated index. If the index is out of bounds, it
14313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // returns zero. It also chooses the weight appropriately based on the given dual
14323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // plane.
14333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int getWeight(const int* unquantizedWeights, int idx, bool dualPlane) const {
14343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int maxIdx = (fDualPlaneEnabled ? 2 : 1) * fWeightDimX * fWeightDimY - 1;
14353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (fDualPlaneEnabled) {
14363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int effectiveIdx = 2*idx + (dualPlane ? 1 : 0);
14373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            if (effectiveIdx > maxIdx) {
14383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                return 0;
14393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
14403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return unquantizedWeights[effectiveIdx];
14413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
14423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(!dualPlane);
14443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (idx > maxIdx) {
14463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return 0;
14473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
14483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return unquantizedWeights[idx];
14493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
14503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
14513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // This computes the effective weight at location (s, t) of the block. This
14533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // weight is computed by sampling the texel weight grid (it's usually not 1-1), and
14543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // then applying a bilerp. The algorithm outlined here follows the algorithm
14553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // defined in section C.2.18 of the ASTC spec.
14563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int infillWeight(const int* unquantizedValues, int s, int t, bool dualPlane) const {
14573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int Ds = (1024 + fDimX/2) / (fDimX - 1);
14583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int Dt = (1024 + fDimY/2) / (fDimY - 1);
14593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int cs = Ds * s;
14613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int ct = Dt * t;
14623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int gs = (cs*(fWeightDimX - 1) + 32) >> 6;
14643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int gt = (ct*(fWeightDimY - 1) + 32) >> 6;
14653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int js = gs >> 4;
14673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int jt = gt >> 4;
14683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int fs = gs & 0xF;
14703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int ft = gt & 0xF;
14713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int idx = js + jt*fWeightDimX;
14733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int p00 = this->getWeight(unquantizedValues, idx, dualPlane);
14743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int p01 = this->getWeight(unquantizedValues, idx + 1, dualPlane);
14753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int p10 = this->getWeight(unquantizedValues, idx + fWeightDimX, dualPlane);
14763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int p11 = this->getWeight(unquantizedValues, idx + fWeightDimX + 1, dualPlane);
14773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int w11 = (fs*ft + 8) >> 4;
14793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int w10 = ft - w11;
14803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int w01 = fs - w11;
14813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int w00 = 16 - fs - ft + w11;
14823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int weight = (p00*w00 + p01*w01 + p10*w10 + p11*w11 + 8) >> 4;
14843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(weight <= 64);
14853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return weight;
14863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
14873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Unquantizes the decoded texel weights as described in section C.2.17 of
14893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // the ASTC specification. Additionally, it populates texelWeights with
14903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // the expanded weight grid, which is computed according to section C.2.18
14913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    void texelWeights(int texelWeights[2][12][12], const int* texelValues) const {
14923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Unquantized texel weights...
14933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int unquantizedValues[144*2]; // 12x12 blocks with dual plane decoding...
14943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(this->numWeights() <= 144*2);
14953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
14963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Unquantize the weights and cache them
14973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int j = 0; j < this->numWeights(); ++j) {
14983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            unquantizedValues[j] = this->unquantizeWeight(texelValues[j]);
14993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
15003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Do weight infill...
15023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int y = 0; y < fDimY; ++y) {
15033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            for (int x = 0; x < fDimX; ++x) {
15043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                texelWeights[0][x][y] = this->infillWeight(unquantizedValues, x, y, false);
15053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                if (fDualPlaneEnabled) {
15063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    texelWeights[1][x][y] = this->infillWeight(unquantizedValues, x, y, true);
15073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
15083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
15093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
15103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
15113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Returns the partition for the texel located at position (x, y).
15133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Adapted from C.2.21 of the ASTC specification
15143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int getPartition(int x, int y) const {
15153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int partitionCount = this->numPartitions();
15163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int seed = fPartIndex;
15173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if ((fDimX * fDimY) < 31) {
15183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            x <<= 1;
15193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            y <<= 1;
15203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
15213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed += (partitionCount - 1) * 1024;
15233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint32_t p = seed;
15253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        p ^= p >> 15;  p -= p << 17;  p += p << 7; p += p <<  4;
15263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        p ^= p >>  5;  p += p << 16;  p ^= p >> 7; p ^= p >> 3;
15273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        p ^= p <<  6;  p ^= p >> 17;
15283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint32_t rnum = p;
15303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed1  =  rnum        & 0xF;
15313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed2  = (rnum >>  4) & 0xF;
15323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed3  = (rnum >>  8) & 0xF;
15333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed4  = (rnum >> 12) & 0xF;
15343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed5  = (rnum >> 16) & 0xF;
15353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed6  = (rnum >> 20) & 0xF;
15363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed7  = (rnum >> 24) & 0xF;
15373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed8  = (rnum >> 28) & 0xF;
15383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed9  = (rnum >> 18) & 0xF;
15393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed10 = (rnum >> 22) & 0xF;
15403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed11 = (rnum >> 26) & 0xF;
15413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF;
15423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed1 *= seed1;     seed2 *= seed2;
15443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed3 *= seed3;     seed4 *= seed4;
15453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed5 *= seed5;     seed6 *= seed6;
15463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed7 *= seed7;     seed8 *= seed8;
15473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed9 *= seed9;     seed10 *= seed10;
15483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed11 *= seed11;   seed12 *= seed12;
15493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int sh1, sh2, sh3;
15513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (0 != (seed & 1)) {
15523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            sh1 = (0 != (seed & 2))? 4 : 5;
15533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            sh2 = (partitionCount == 3)? 6 : 5;
15543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
15553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            sh1 = (partitionCount==3)? 6 : 5;
15563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            sh2 = (0 != (seed & 2))? 4 : 5;
15573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
15583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        sh3 = (0 != (seed & 0x10))? sh1 : sh2;
15593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed1 >>= sh1; seed2  >>= sh2; seed3  >>= sh1; seed4  >>= sh2;
15613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed5 >>= sh1; seed6  >>= sh2; seed7  >>= sh1; seed8  >>= sh2;
15623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3;
15633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int z = 0;
15653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int a = seed1*x + seed2*y + seed11*z + (rnum >> 14);
15663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int b = seed3*x + seed4*y + seed12*z + (rnum >> 10);
15673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int c = seed5*x + seed6*y + seed9 *z + (rnum >>  6);
15683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int d = seed7*x + seed8*y + seed10*z + (rnum >>  2);
15693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        a &= 0x3F;
15713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        b &= 0x3F;
15723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        c &= 0x3F;
15733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        d &= 0x3F;
15743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (partitionCount < 4) {
15763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            d = 0;
15773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
15783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (partitionCount < 3) {
15803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            c = 0;
15813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
15823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (a >= b && a >= c && a >= d) {
15843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return 0;
15853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else if (b >= c && b >= d) {
15863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return 1;
15873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else if (c >= d) {
15883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return 2;
15893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
15903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return 3;
15913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
15923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
15933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
15943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Performs the proper interpolation of the texel based on the
15953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // endpoints and weights.
15963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkColor getTexel(const SkColor endpoints[4][2],
15973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                     const int weights[2][12][12],
15983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                     int x, int y) const {
15993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int part = 0;
16003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (this->numPartitions() > 1) {
16013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            part = this->getPartition(x, y);
16023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
16033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkColor result;
16053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (fDualPlaneEnabled) {
16063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            result = interpolate_dual_endpoints(
16073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                endpoints[part], weights[0][x][y], weights[1][x][y], fDualPlane);
16083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
16093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            result = interpolate_endpoints(endpoints[part], weights[0][x][y]);
16103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
16113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#if 1
16133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // !FIXME! if we're writing directly to a bitmap, then we don't need
16143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // to swap the red and blue channels, but since we're usually being used
16153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // by the SkImageDecoder_astc module, the results are expected to be in RGBA.
16163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        result = SkColorSetARGB(
16173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkColorGetA(result), SkColorGetB(result), SkColorGetG(result), SkColorGetR(result));
16183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski#endif
16193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return result;
16213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
16223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    void decode() {
16243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // First decode the block mode.
16253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        this->decodeBlockMode();
16263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Now we can decode the partition information.
16283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        fPartIndex = static_cast<int>(read_astc_bits(fBlock, 11, 23));
16293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        fPartCount = (fPartIndex & 0x3) + 1;
16303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        fPartIndex >>= 2;
16313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // This is illegal
16333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (fDualPlaneEnabled && this->numPartitions() == 4) {
16343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fError = true;
16353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return;
16363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
16373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Based on the partition info, we can decode the color information.
16393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        this->decodeColorData();
16403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
16413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Decodes the dual plane based on the given bit location. The final
16433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // location, if the dual plane is enabled, is also the end of our color data.
16443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // This function is only meant to be used from this->decodeColorData()
16453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    void decodeDualPlane(int bitLoc) {
16463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (fDualPlaneEnabled) {
16473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fDualPlane = static_cast<int>(read_astc_bits(fBlock, bitLoc - 2, bitLoc));
16483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fColorEndBit = bitLoc - 2;
16493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
16503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fColorEndBit = bitLoc;
16513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
16523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
16533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Decodes the color information based on the ASTC spec.
16553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    void decodeColorData() {
16563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // By default, the last color bit is at the end of the texel weights
16583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int lastWeight = 128 - this->numWeightBits();
16593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // If we have a dual plane then it will be at this location, too.
16613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int dualPlaneBitLoc = lastWeight;
16623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // If there's only one partition, then our job is (relatively) easy.
16643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (this->numPartitions() == 1) {
16653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fCEM[0] = static_cast<ColorEndpointMode>(read_astc_bits(fBlock, 13, 17));
16663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fColorStartBit = 17;
16673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            // Handle dual plane mode...
16693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            this->decodeDualPlane(dualPlaneBitLoc);
16703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return;
16723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
16733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // If we have more than one partition, then we need to make
16753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // room for the partition index.
16763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        fColorStartBit = 29;
16773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Read the base CEM. If it's zero, then we have no additional
16793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // CEM data and the endpoints for each partition share the same CEM.
16803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int baseCEM = static_cast<int>(read_astc_bits(fBlock, 23, 25));
16813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if (0 == baseCEM) {
16823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const ColorEndpointMode sameCEM =
16843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                static_cast<ColorEndpointMode>(read_astc_bits(fBlock, 25, 29));
16853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            for (int i = 0; i < kMaxPartitions; ++i) {
16873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                fCEM[i] = sameCEM;
16883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
16893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            // Handle dual plane mode...
16913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            this->decodeDualPlane(dualPlaneBitLoc);
16923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            return;
16943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
16953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
16963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Move the dual plane selector bits down based on how many
16973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // partitions the block contains.
16983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        switch (this->numPartitions()) {
16993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            case 2:
17003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                dualPlaneBitLoc -= 2;
17013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
17023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            case 3:
17043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                dualPlaneBitLoc -= 5;
17053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
17063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            case 4:
17083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                dualPlaneBitLoc -= 8;
17093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
17103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            default:
17123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                SkDEBUGFAIL("Internal ASTC decoding error.");
17133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                break;
17143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
17153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // The rest of the CEM config will be between the dual plane bit selector
17173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // and the texel weight grid.
17183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int lowCEM = static_cast<int>(read_astc_bits(fBlock, 23, 29));
171995b1b3d82d227141647777d83324aa570b530096krajcevski        SkASSERT(lastWeight >= dualPlaneBitLoc);
172095b1b3d82d227141647777d83324aa570b530096krajcevski        SkASSERT(lastWeight - dualPlaneBitLoc < 31);
17213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int fullCEM = static_cast<int>(read_astc_bits(fBlock, dualPlaneBitLoc, lastWeight));
17223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Attach the config at the end of the weight grid to the CEM values
17243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // in the beginning of the block.
17253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        fullCEM = (fullCEM << 6) | lowCEM;
17263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Ignore the two least significant bits, since those are our baseCEM above.
17283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        fullCEM = fullCEM >> 2;
17293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int C[kMaxPartitions]; // Next, decode C and M from the spec (Table C.2.12)
17313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int i = 0; i < this->numPartitions(); ++i) {
17323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            C[i] = fullCEM & 1;
17333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fullCEM = fullCEM >> 1;
17343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
17353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int M[kMaxPartitions];
17373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int i = 0; i < this->numPartitions(); ++i) {
17383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            M[i] = fullCEM & 0x3;
17393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fullCEM = fullCEM >> 2;
17403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
17413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Construct our CEMs..
17433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkASSERT(baseCEM > 0);
17443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int i = 0; i < this->numPartitions(); ++i) {
17453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            int cem = (baseCEM - 1) * 4;
17463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            cem += (0 == C[i])? 0 : 4;
17473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            cem += M[i];
17483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(cem < 16);
17503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fCEM[i] = static_cast<ColorEndpointMode>(cem);
17513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
17523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Finally, if we have dual plane mode, then read the plane selector.
17543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        this->decodeDualPlane(dualPlaneBitLoc);
17553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
17563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Decodes the block mode. This function determines whether or not we use
17583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // dual plane encoding, the size of the texel weight grid, and the number of
17593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // bits, trits and quints that are used to encode it. For more information,
17603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // see section C.2.10 of the ASTC spec.
17613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
17623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // For 2D blocks, the Block Mode field is laid out as follows:
17633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
17643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // -------------------------------------------------------------------------
17653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // 10  9   8   7   6   5   4   3   2   1   0   Width Height Notes
17663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // -------------------------------------------------------------------------
17673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H     B       A     R0  0   0   R2  R1  B+4   A+2
17683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H     B       A     R0  0   1   R2  R1  B+8   A+2
17693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H     B       A     R0  1   0   R2  R1  A+2   B+8
17703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H   0   B     A     R0  1   1   R2  R1  A+2   B+6
17713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H   1   B     A     R0  1   1   R2  R1  B+2   A+2
17723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H   0   0     A     R0  R2  R1  0   0   12    A+2
17733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H   0   1     A     R0  R2  R1  0   0   A+2   12
17743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H   1   1   0   0   R0  R2  R1  0   0   6     10
17753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D   H   1   1   0   1   R0  R2  R1  0   0   10    6
17763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //   B     1   0     A     R0  R2  R1  0   0   A+6   B+6   D=0, H=0
17773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // x   x   1   1   1   1   1   1   1   0   0   -     -     Void-extent
17783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // x   x   1   1   1   x   x   x   x   0   0   -     -     Reserved*
17793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // x   x   x   x   x   x   x   0   0   0   0   -     -     Reserved
17803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // -------------------------------------------------------------------------
17813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //
17823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // D - dual plane enabled
17833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // H, R - used to determine the number of bits/trits/quints in texel weight encoding
17843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    //        R is a three bit value whose LSB is R0 and MSB is R1
17853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Width, Height - dimensions of the texel weight grid (determined by A and B)
17863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    void decodeBlockMode() {
17883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        const int blockMode = static_cast<int>(read_astc_bits(fBlock, 0, 11));
17893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Check for special void extent encoding
17913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        fVoidExtent = (blockMode & 0x1FF) == 0x1FC;
17923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Check for reserved block modes
17943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        fError = ((blockMode & 0x1C3) == 0x1C0) || ((blockMode & 0xF) == 0);
17953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
17963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // Neither reserved nor void-extent, decode as usual
17973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // This code corresponds to table C.2.8 of the ASTC spec
17983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        bool highPrecision = false;
17993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        int R = 0;
18003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if ((blockMode & 0x3) == 0) {
18013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            R = ((0xC & blockMode) >> 1) | ((0x10 & blockMode) >> 4);
18023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int bitsSevenAndEight = (blockMode & 0x180) >> 7;
18033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 <= bitsSevenAndEight && bitsSevenAndEight < 4);
18043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int A = (blockMode >> 5) & 0x3;
18063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int B = (blockMode >> 9) & 0x3;
18073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fDualPlaneEnabled = (blockMode >> 10) & 0x1;
18093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            highPrecision = (blockMode >> 9) & 0x1;
18103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            switch (bitsSevenAndEight) {
18123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                default:
18133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 0:
18143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimX = 12;
18153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimY = A + 2;
18163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
18173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 1:
18193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimX = A + 2;
18203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimY = 12;
18213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
18223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 2:
18243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimX = A + 6;
18253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimY = B + 6;
18263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fDualPlaneEnabled = false;
18273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    highPrecision = false;
18283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
18293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 3:
18313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    if (0 == A) {
18323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        fWeightDimX = 6;
18333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        fWeightDimY = 10;
18343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    } else {
18353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        fWeightDimX = 10;
18363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        fWeightDimY = 6;
18373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    }
18383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
18393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
18403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else { // (blockMode & 0x3) != 0
18413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            R = ((blockMode & 0x3) << 1) | ((blockMode & 0x10) >> 4);
18423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int bitsTwoAndThree = (blockMode >> 2) & 0x3;
18443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            SkASSERT(0 <= bitsTwoAndThree && bitsTwoAndThree < 4);
18453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int A = (blockMode >> 5) & 0x3;
18473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            const int B = (blockMode >> 7) & 0x3;
18483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fDualPlaneEnabled = (blockMode >> 10) & 0x1;
18503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            highPrecision = (blockMode >> 9) & 0x1;
18513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            switch (bitsTwoAndThree) {
18533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 0:
18543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimX = B + 4;
18553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimY = A + 2;
18563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
18573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 1:
18583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimX = B + 8;
18593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimY = A + 2;
18603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
18613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 2:
18623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimX = A + 2;
18633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    fWeightDimY = B + 8;
18643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
18653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                case 3:
18663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    if ((B & 0x2) == 0) {
18673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        fWeightDimX = A + 2;
18683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        fWeightDimY = (B & 1) + 6;
18693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    } else {
18703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        fWeightDimX = (B & 1) + 2;
18713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                        fWeightDimY = A + 2;
18723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    }
18733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    break;
18743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            }
18753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
18763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
18773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // We should have set the values of R and highPrecision
18783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // from decoding the block mode, these are used to determine
18793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // the proper dimensions of our weight grid.
18803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        if ((R & 0x6) == 0) {
18813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fError = true;
18823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        } else {
18833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            static const int kBitAllocationTable[2][6][3] = {
18843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                {
18853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  1, 0, 0 },
18863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  0, 1, 0 },
18873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  2, 0, 0 },
18883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  0, 0, 1 },
18893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  1, 1, 0 },
18903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  3, 0, 0 }
18913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                },
18923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                {
18933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  1, 0, 1 },
18943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  2, 1, 0 },
18953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  4, 0, 0 },
18963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  2, 0, 1 },
18973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  3, 1, 0 },
18983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    {  5, 0, 0 }
18993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                }
19003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            };
19013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fWeightBits = kBitAllocationTable[highPrecision][R - 2][0];
19033c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fWeightTrits = kBitAllocationTable[highPrecision][R - 2][1];
19043c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            fWeightQuints = kBitAllocationTable[highPrecision][R - 2][2];
19053c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
19063c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
19073c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski};
19083c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19093c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Reads an ASTC block from the given pointer.
19103c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic inline void read_astc_block(ASTCDecompressionData *dst, const uint8_t* src) {
19113c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    const uint64_t* qword = reinterpret_cast<const uint64_t*>(src);
19123c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    dst->fBlock.fLow = SkEndian_SwapLE64(qword[0]);
19133c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    dst->fBlock.fHigh = SkEndian_SwapLE64(qword[1]);
19143c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    dst->decode();
19153c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
19163c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19173c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Take a known void-extent block, and write out the values as a constant color.
19183c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic void decompress_void_extent(uint8_t* dst, int dstRowBytes,
19193c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                   const ASTCDecompressionData &data) {
19203c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // The top 64 bits contain 4 16-bit RGBA values.
19213c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int a = (static_cast<int>(read_astc_bits(data.fBlock, 112, 128)) + 255) >> 8;
19223c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int b = (static_cast<int>(read_astc_bits(data.fBlock, 96, 112)) + 255) >> 8;
19233c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int g = (static_cast<int>(read_astc_bits(data.fBlock, 80, 96)) + 255) >> 8;
19243c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int r = (static_cast<int>(read_astc_bits(data.fBlock, 64, 80)) + 255) >> 8;
19253c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19263c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    write_constant_color(dst, data.fDimX, data.fDimY, dstRowBytes, SkColorSetARGB(a, r, g, b));
19273c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
19283c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19293c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// Decompresses a single ASTC block. It's assumed that data.fDimX and data.fDimY are
19303c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski// set and that the block has already been decoded (i.e. data.decode() has been called)
19313c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskistatic void decompress_astc_block(uint8_t* dst, int dstRowBytes,
19323c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                                  const ASTCDecompressionData &data) {
19333c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (data.fError) {
19343c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes);
19353c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return;
19363c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
19373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19383c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (data.fVoidExtent) {
19393c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        decompress_void_extent(dst, dstRowBytes, data);
19403c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return;
19413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
19423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19433c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // According to the spec, any more than 64 values is illegal. (C.2.24)
19443c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    static const int kMaxTexelValues = 64;
19453c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19463c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Decode the texel weights.
19473c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int texelValues[kMaxTexelValues];
19483c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    bool success = decode_integer_sequence(
19493c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        texelValues, kMaxTexelValues, data.numWeights(),
19503c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        // texel data goes to the end of the 128 bit block.
19513c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        data.fBlock, 128, 128 - data.numWeightBits(), false,
19523c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        data.fWeightBits, data.fWeightTrits, data.fWeightQuints);
19533c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19543c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (!success) {
19553c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes);
19563c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return;
19573c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
19583c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19593c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Decode the color endpoints
19603c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int colorBits, colorTrits, colorQuints;
19613c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (!data.getColorValueEncoding(&colorBits, &colorTrits, &colorQuints)) {
19623c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes);
19633c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return;
19643c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
19653c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19663c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // According to the spec, any more than 18 color values is illegal. (C.2.24)
19673c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    static const int kMaxColorValues = 18;
19683c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19693c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int colorValues[kMaxColorValues];
19703c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    success = decode_integer_sequence(
19713c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        colorValues, kMaxColorValues, data.numColorValues(),
19723c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        data.fBlock, data.fColorStartBit, data.fColorEndBit, true,
19733c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        colorBits, colorTrits, colorQuints);
19743c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19753c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    if (!success) {
19763c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes);
19773c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        return;
19783c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
19793c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Unquantize the color values after they've been decoded.
19813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    unquantize_colors(colorValues, data.numColorValues(), colorBits, colorTrits, colorQuints);
19823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Decode the colors into the appropriate endpoints.
19843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    SkColor endpoints[4][2];
19853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    data.colorEndpoints(endpoints, colorValues);
19863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Do texel infill and decode the texel values.
19883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    int texelWeights[2][12][12];
19893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    data.texelWeights(texelWeights, texelValues);
19903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
19913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // Write the texels by interpolating them based on the information
19923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // stored in the block.
19933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    dst += data.fDimY * dstRowBytes;
19943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    for (int y = 0; y < data.fDimY; ++y) {
19953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        dst -= dstRowBytes;
19963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkColor* colorPtr = reinterpret_cast<SkColor*>(dst);
19973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int x = 0; x < data.fDimX; ++x) {
19983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            colorPtr[x] = data.getTexel(endpoints, texelWeights, x, y);
19993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
20003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
20013c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
20023c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
2003a10555a354cf294bde217044472d33c3161df249krajcevski////////////////////////////////////////////////////////////////////////////////
2004a10555a354cf294bde217044472d33c3161df249krajcevski//
2005a10555a354cf294bde217044472d33c3161df249krajcevski// ASTC Comrpession Struct
2006a10555a354cf294bde217044472d33c3161df249krajcevski//
2007a10555a354cf294bde217044472d33c3161df249krajcevski////////////////////////////////////////////////////////////////////////////////
2008a10555a354cf294bde217044472d33c3161df249krajcevski
200945a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// This is the type passed as the CompressorType argument of the compressed
201045a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// blitter for the ASTC format. The static functions required to be in this
201145a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// struct are documented in SkTextureCompressor_Blitter.h
201245a0bf505914adf0ee8c69e2647230618bbb3a63krajcevskistruct CompressorASTC {
201345a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski    static inline void CompressA8Vertical(uint8_t* dst, const uint8_t* src) {
201445a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski        compress_a8_astc_block<GetAlphaTranspose>(&dst, src, 12);
201545a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski    }
201645a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski
201745a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski    static inline void CompressA8Horizontal(uint8_t* dst, const uint8_t* src,
201845a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski                                            int srcRowBytes) {
201945a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski        compress_a8_astc_block<GetAlpha>(&dst, src, srcRowBytes);
202045a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski    }
202145a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski
2022a10555a354cf294bde217044472d33c3161df249krajcevski#if PEDANTIC_BLIT_RECT
2023a10555a354cf294bde217044472d33c3161df249krajcevski    static inline void UpdateBlock(uint8_t* dst, const uint8_t* src, int srcRowBytes,
2024a10555a354cf294bde217044472d33c3161df249krajcevski                                   const uint8_t* mask) {
2025a10555a354cf294bde217044472d33c3161df249krajcevski        // TODO: krajcevski
2026a10555a354cf294bde217044472d33c3161df249krajcevski        // This is kind of difficult for ASTC because the weight values are calculated
2027a10555a354cf294bde217044472d33c3161df249krajcevski        // as an average of the actual weights. The best we can do is decompress the
2028a10555a354cf294bde217044472d33c3161df249krajcevski        // weights and recalculate them based on the new texel values. This should
2029a10555a354cf294bde217044472d33c3161df249krajcevski        // be "not too bad" since we know that anytime we hit this function, we're
2030a10555a354cf294bde217044472d33c3161df249krajcevski        // compressing 12x12 block dimension alpha-only, and we know the layout
2031a10555a354cf294bde217044472d33c3161df249krajcevski        // of the block
2032a10555a354cf294bde217044472d33c3161df249krajcevski        SkFAIL("Implement me!");
203345a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski    }
2034a10555a354cf294bde217044472d33c3161df249krajcevski#endif
203545a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski};
203645a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski
20373c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski////////////////////////////////////////////////////////////////////////////////
2038b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
2039b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevskinamespace SkTextureCompressor {
2040b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
20413c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskibool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src,
20423c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                           int width, int height, int rowBytes) {
2043b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    if (width < 0 || ((width % 12) != 0) || height < 0 || ((height % 12) != 0)) {
2044b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        return false;
2045b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    }
2046b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
2047b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    uint8_t** dstPtr = &dst;
2048b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski    for (int y = 0; y < height; y += 12) {
2049b5294e8d453866ae0dc5a0304c1ca969ef3c7670krajcevski        for (int x = 0; x < width; x += 12) {
205010a350c32826d10349bc3647e83d623259805b62krajcevski            compress_a8_astc_block<GetAlpha>(dstPtr, src + y*rowBytes + x, rowBytes);
2051b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski        }
2052b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    }
2053b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
2054b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski    return true;
2055b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski}
2056b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
2057b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevskiSkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer,
2058b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski                             SkTBlitterAllocator* allocator) {
2059b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    if ((width % 12) != 0 || (height % 12) != 0) {
2060b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        return NULL;
2061b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    }
2062b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
2063b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // Memset the output buffer to an encoding that decodes to zero. We must do this
2064b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // in order to avoid having uninitialized values in the buffer if the blitter
2065b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // decides not to write certain scanlines (and skip entire rows of blocks).
2066b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // In the case of ASTC, if everything index is zero, then the interpolated value
2067b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // will decode to zero provided we have the right header. We use the encoding
2068b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // from recognizing all zero blocks from above.
2069b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    const int nBlocks = (width * height / 144);
2070b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    uint8_t *dst = reinterpret_cast<uint8_t *>(outputBuffer);
2071b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    for (int i = 0; i < nBlocks; ++i) {
2072b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        send_packing(&dst, SkTEndian_SwapLE64(0x0000000001FE000173ULL), 0);
2073b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    }
2074b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
2075b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    return allocator->createT<
207645a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski        SkTCompressedAlphaBlitter<12, 16, CompressorASTC>, int, int, void* >
207710a350c32826d10349bc3647e83d623259805b62krajcevski        (width, height, outputBuffer);
2078b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski}
2079b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski
20803c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevskivoid DecompressASTC(uint8_t* dst, int dstRowBytes, const uint8_t* src,
20813c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski                    int width, int height, int blockDimX, int blockDimY) {
20823c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // ASTC is encoded in what they call "raster order", so that the first
20833c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // block is the bottom-left block in the image, and the first pixel
20843c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    // is the bottom-left pixel of the image
20853c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    dst += height * dstRowBytes;
20863c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
20873c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    ASTCDecompressionData data(blockDimX, blockDimY);
20883c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    for (int y = 0; y < height; y += blockDimY) {
20893c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        dst -= blockDimY * dstRowBytes;
20903c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        SkColor *colorPtr = reinterpret_cast<SkColor*>(dst);
20913c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        for (int x = 0; x < width; x += blockDimX) {
20923c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            read_astc_block(&data, src);
20933c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            decompress_astc_block(reinterpret_cast<uint8_t*>(colorPtr + x), dstRowBytes, data);
20943c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
20953c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            // ASTC encoded blocks are 16 bytes (128 bits) large.
20963c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski            src += 16;
20973c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski        }
20983c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski    }
20993c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski}
21003c7edda88e275bcdaeb5d3afd0428a21f1635d13krajcevski
2101b2ef181ed614d1a5772367a8cd7ab77aa015ae29krajcevski}  // SkTextureCompressor
2102