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). 1379880607151ca7c2dc6b1a4b9756938bd71913ab5bsalomoninline uint8_t GetAlpha(const uint8_t *src, size_t 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 1449880607151ca7c2dc6b1a4b9756938bd71913ab5bsalomoninline uint8_t GetAlphaTranspose(const uint8_t *src, size_t 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. 1609880607151ca7c2dc6b1a4b9756938bd71913ab5bsalomontypedef uint8_t (*GetAlphaProc)(const uint8_t* src, size_t rowBytes, int x, int y); 16110a350c32826d10349bc3647e83d623259805b62krajcevski 16210a350c32826d10349bc3647e83d623259805b62krajcevskitemplate<GetAlphaProc getAlphaProc> 1639880607151ca7c2dc6b1a4b9756938bd71913ab5bsalomonstatic void compress_a8_astc_block(uint8_t** dst, const uint8_t* src, size_t 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, 20429880607151ca7c2dc6b1a4b9756938bd71913ab5bsalomon int width, int height, size_t 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