1 | // basisu_transcoder_uastc.h |
2 | #pragma once |
3 | #include "basisu_transcoder_internal.h" |
4 | |
5 | namespace basist |
6 | { |
7 | struct color_quad_u8 |
8 | { |
9 | uint8_t m_c[4]; |
10 | }; |
11 | |
12 | const uint32_t TOTAL_UASTC_MODES = 19; |
13 | const uint32_t UASTC_MODE_INDEX_SOLID_COLOR = 8; |
14 | |
15 | const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS2 = 30; |
16 | const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS3 = 11; |
17 | const uint32_t TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS = 19; |
18 | |
19 | extern const uint8_t g_uastc_mode_weight_bits[TOTAL_UASTC_MODES]; |
20 | extern const uint8_t g_uastc_mode_weight_ranges[TOTAL_UASTC_MODES]; |
21 | extern const uint8_t g_uastc_mode_endpoint_ranges[TOTAL_UASTC_MODES]; |
22 | extern const uint8_t g_uastc_mode_subsets[TOTAL_UASTC_MODES]; |
23 | extern const uint8_t g_uastc_mode_planes[TOTAL_UASTC_MODES]; |
24 | extern const uint8_t g_uastc_mode_comps[TOTAL_UASTC_MODES]; |
25 | extern const uint8_t g_uastc_mode_has_etc1_bias[TOTAL_UASTC_MODES]; |
26 | extern const uint8_t g_uastc_mode_has_bc1_hint0[TOTAL_UASTC_MODES]; |
27 | extern const uint8_t g_uastc_mode_has_bc1_hint1[TOTAL_UASTC_MODES]; |
28 | extern const uint8_t g_uastc_mode_has_alpha[TOTAL_UASTC_MODES]; |
29 | extern const uint8_t g_uastc_mode_is_la[TOTAL_UASTC_MODES]; |
30 | |
31 | struct astc_bc7_common_partition2_desc |
32 | { |
33 | uint8_t m_bc7; |
34 | uint16_t m_astc; |
35 | bool m_invert; |
36 | }; |
37 | |
38 | extern const astc_bc7_common_partition2_desc g_astc_bc7_common_partitions2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2]; |
39 | |
40 | struct bc73_astc2_common_partition_desc |
41 | { |
42 | uint8_t m_bc73; |
43 | uint16_t m_astc2; |
44 | uint8_t k; // 0-5 - how to modify the BC7 3-subset pattern to match the ASTC pattern (LSB=invert) |
45 | }; |
46 | |
47 | extern const bc73_astc2_common_partition_desc g_bc7_3_astc2_common_partitions[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS]; |
48 | |
49 | struct astc_bc7_common_partition3_desc |
50 | { |
51 | uint8_t m_bc7; |
52 | uint16_t m_astc; |
53 | uint8_t m_astc_to_bc7_perm; // converts ASTC to BC7 partition using g_astc_bc7_partition_index_perm_tables[][] |
54 | }; |
55 | |
56 | extern const astc_bc7_common_partition3_desc g_astc_bc7_common_partitions3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3]; |
57 | |
58 | extern const uint8_t g_astc_bc7_patterns2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][16]; |
59 | extern const uint8_t g_astc_bc7_patterns3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][16]; |
60 | extern const uint8_t g_bc7_3_astc2_patterns2[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][16]; |
61 | |
62 | extern const uint8_t g_astc_bc7_pattern2_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][3]; |
63 | extern const uint8_t g_astc_bc7_pattern3_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][3]; |
64 | extern const uint8_t g_bc7_3_astc2_patterns2_anchors[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][3]; |
65 | |
66 | extern const uint32_t g_uastc_mode_huff_codes[TOTAL_UASTC_MODES + 1][2]; |
67 | |
68 | extern const uint8_t g_astc_to_bc7_partition_index_perm_tables[6][3]; |
69 | extern const uint8_t g_bc7_to_astc_partition_index_perm_tables[6][3]; // inverse of g_astc_to_bc7_partition_index_perm_tables |
70 | |
71 | extern const uint8_t* s_uastc_to_bc1_weights[6]; |
72 | |
73 | uint32_t bc7_convert_partition_index_3_to_2(uint32_t p, uint32_t k); |
74 | |
75 | inline uint32_t astc_interpolate(uint32_t l, uint32_t h, uint32_t w, bool srgb) |
76 | { |
77 | if (srgb) |
78 | { |
79 | l = (l << 8) | 0x80; |
80 | h = (h << 8) | 0x80; |
81 | } |
82 | else |
83 | { |
84 | l = (l << 8) | l; |
85 | h = (h << 8) | h; |
86 | } |
87 | |
88 | uint32_t k = (l * (64 - w) + h * w + 32) >> 6; |
89 | |
90 | return k >> 8; |
91 | } |
92 | |
93 | struct astc_block_desc |
94 | { |
95 | int m_weight_range; // weight BISE range |
96 | |
97 | int m_subsets; // number of ASTC partitions |
98 | int m_partition_seed; // partition pattern seed |
99 | int m_cem; // color endpoint mode used by all subsets |
100 | |
101 | int m_ccs; // color component selector (dual plane only) |
102 | bool m_dual_plane; // true if dual plane |
103 | |
104 | // Weight and endpoint BISE values. |
105 | // Note these values are NOT linear, they must be BISE encoded. See Table 97 and Table 107. |
106 | uint8_t m_endpoints[18]; // endpoint values, in RR GG BB etc. order |
107 | uint8_t m_weights[64]; // weight index values, raster order, in P0 P1, P0 P1, etc. or P0, P0, P0, P0, etc. order |
108 | }; |
109 | |
110 | const uint32_t BC7ENC_TOTAL_ASTC_RANGES = 21; |
111 | |
112 | // See tables 81, 93, 18.13.Endpoint Unquantization |
113 | const uint32_t TOTAL_ASTC_RANGES = 21; |
114 | extern const int g_astc_bise_range_table[TOTAL_ASTC_RANGES][3]; |
115 | |
116 | struct astc_quant_bin |
117 | { |
118 | uint8_t m_unquant; // unquantized value |
119 | uint8_t m_index; // sorted index |
120 | }; |
121 | |
122 | extern astc_quant_bin g_astc_unquant[BC7ENC_TOTAL_ASTC_RANGES][256]; // [ASTC encoded endpoint index] |
123 | |
124 | int astc_get_levels(int range); |
125 | bool astc_is_valid_endpoint_range(uint32_t range); |
126 | uint32_t unquant_astc_endpoint(uint32_t packed_bits, uint32_t packed_trits, uint32_t packed_quints, uint32_t range); |
127 | uint32_t unquant_astc_endpoint_val(uint32_t packed_val, uint32_t range); |
128 | |
129 | const uint8_t* get_anchor_indices(uint32_t subsets, uint32_t mode, uint32_t common_pattern, const uint8_t*& pPartition_pattern); |
130 | |
131 | // BC7 |
132 | const uint32_t BC7ENC_BLOCK_SIZE = 16; |
133 | |
134 | struct bc7_block |
135 | { |
136 | uint64_t m_qwords[2]; |
137 | }; |
138 | |
139 | struct bc7_optimization_results |
140 | { |
141 | uint32_t m_mode; |
142 | uint32_t m_partition; |
143 | uint8_t m_selectors[16]; |
144 | uint8_t m_alpha_selectors[16]; |
145 | color_quad_u8 m_low[3]; |
146 | color_quad_u8 m_high[3]; |
147 | uint32_t m_pbits[3][2]; |
148 | uint32_t m_index_selector; |
149 | uint32_t m_rotation; |
150 | }; |
151 | |
152 | extern const uint32_t g_bc7_weights1[2]; |
153 | extern const uint32_t g_bc7_weights2[4]; |
154 | extern const uint32_t g_bc7_weights3[8]; |
155 | extern const uint32_t g_bc7_weights4[16]; |
156 | extern const uint32_t g_astc_weights4[16]; |
157 | extern const uint32_t g_astc_weights5[32]; |
158 | extern const uint32_t g_astc_weights_3levels[3]; |
159 | extern const uint8_t g_bc7_partition1[16]; |
160 | extern const uint8_t g_bc7_partition2[64 * 16]; |
161 | extern const uint8_t g_bc7_partition3[64 * 16]; |
162 | extern const uint8_t g_bc7_table_anchor_index_second_subset[64]; |
163 | extern const uint8_t g_bc7_table_anchor_index_third_subset_1[64]; |
164 | extern const uint8_t g_bc7_table_anchor_index_third_subset_2[64]; |
165 | extern const uint8_t g_bc7_num_subsets[8]; |
166 | extern const uint8_t g_bc7_partition_bits[8]; |
167 | extern const uint8_t g_bc7_color_index_bitcount[8]; |
168 | extern const uint8_t g_bc7_mode_has_p_bits[8]; |
169 | extern const uint8_t g_bc7_mode_has_shared_p_bits[8]; |
170 | extern const uint8_t g_bc7_color_precision_table[8]; |
171 | extern const int8_t g_bc7_alpha_precision_table[8]; |
172 | extern const uint8_t g_bc7_alpha_index_bitcount[8]; |
173 | |
174 | inline bool get_bc7_mode_has_seperate_alpha_selectors(int mode) { return (mode == 4) || (mode == 5); } |
175 | inline int get_bc7_color_index_size(int mode, int index_selection_bit) { return g_bc7_color_index_bitcount[mode] + index_selection_bit; } |
176 | inline int get_bc7_alpha_index_size(int mode, int index_selection_bit) { return g_bc7_alpha_index_bitcount[mode] - index_selection_bit; } |
177 | |
178 | struct endpoint_err |
179 | { |
180 | uint16_t m_error; uint8_t m_lo; uint8_t m_hi; |
181 | }; |
182 | |
183 | extern endpoint_err g_bc7_mode_6_optimal_endpoints[256][2]; // [c][pbit] |
184 | const uint32_t BC7ENC_MODE_6_OPTIMAL_INDEX = 5; |
185 | |
186 | extern endpoint_err g_bc7_mode_5_optimal_endpoints[256]; // [c] |
187 | const uint32_t BC7ENC_MODE_5_OPTIMAL_INDEX = 1; |
188 | |
189 | // Packs a BC7 block from a high-level description. Handles all BC7 modes. |
190 | void encode_bc7_block(void* pBlock, const bc7_optimization_results* pResults); |
191 | |
192 | // Packs an ASTC block |
193 | // Constraints: Always 4x4, all subset CEM's must be equal, only tested with LDR CEM's. |
194 | bool pack_astc_block(uint32_t* pDst, const astc_block_desc* pBlock, uint32_t mode); |
195 | |
196 | void pack_astc_solid_block(void* pDst_block, const color32& color); |
197 | |
198 | #ifdef _DEBUG |
199 | int astc_compute_texel_partition(int seed, int x, int y, int z, int partitioncount, bool small_block); |
200 | #endif |
201 | |
202 | struct uastc_block |
203 | { |
204 | union |
205 | { |
206 | uint8_t m_bytes[16]; |
207 | uint32_t m_dwords[4]; |
208 | }; |
209 | }; |
210 | |
211 | struct unpacked_uastc_block |
212 | { |
213 | astc_block_desc m_astc; |
214 | |
215 | uint32_t m_mode; |
216 | uint32_t m_common_pattern; |
217 | |
218 | color32 m_solid_color; |
219 | |
220 | bool m_bc1_hint0; |
221 | bool m_bc1_hint1; |
222 | |
223 | bool m_etc1_flip; |
224 | bool m_etc1_diff; |
225 | uint32_t m_etc1_inten0; |
226 | uint32_t m_etc1_inten1; |
227 | |
228 | uint32_t m_etc1_bias; |
229 | |
230 | uint32_t m_etc2_hints; |
231 | |
232 | uint32_t m_etc1_selector; |
233 | uint32_t m_etc1_r, m_etc1_g, m_etc1_b; |
234 | }; |
235 | |
236 | color32 apply_etc1_bias(const color32 &block_color, uint32_t bias, uint32_t limit, uint32_t subblock); |
237 | |
238 | struct decoder_etc_block; |
239 | struct eac_block; |
240 | |
241 | bool unpack_uastc(uint32_t mode, uint32_t common_pattern, const color32& solid_color, const astc_block_desc& astc, color32* pPixels, bool srgb); |
242 | bool unpack_uastc(const unpacked_uastc_block& unpacked_blk, color32* pPixels, bool srgb); |
243 | |
244 | bool unpack_uastc(const uastc_block& blk, color32* pPixels, bool srgb); |
245 | bool unpack_uastc(const uastc_block& blk, unpacked_uastc_block& unpacked, bool undo_blue_contract, bool read_hints = true); |
246 | |
247 | bool transcode_uastc_to_astc(const uastc_block& src_blk, void* pDst); |
248 | |
249 | bool transcode_uastc_to_bc7(const unpacked_uastc_block& unpacked_src_blk, bc7_optimization_results& dst_blk); |
250 | bool transcode_uastc_to_bc7(const uastc_block& src_blk, bc7_optimization_results& dst_blk); |
251 | bool transcode_uastc_to_bc7(const uastc_block& src_blk, void* pDst); |
252 | |
253 | void transcode_uastc_to_etc1(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst); |
254 | bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst); |
255 | bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst, uint32_t channel); |
256 | |
257 | void transcode_uastc_to_etc2_eac_a8(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst); |
258 | bool transcode_uastc_to_etc2_rgba(const uastc_block& src_blk, void* pDst); |
259 | |
260 | // Packs 16 scalar values to BC4. Same PSNR as stb_dxt's BC4 encoder, around 13% faster. |
261 | void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride); |
262 | |
263 | void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb); |
264 | |
265 | enum |
266 | { |
267 | cEncodeBC1HighQuality = 1, |
268 | cEncodeBC1HigherQuality = 2, |
269 | cEncodeBC1UseSelectors = 4, |
270 | }; |
271 | void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags); |
272 | |
273 | // Alternate PCA-free encoder, around 15% faster, same (or slightly higher) avg. PSNR |
274 | void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags); |
275 | |
276 | void transcode_uastc_to_bc1_hint0(const unpacked_uastc_block& unpacked_src_blk, void* pDst); |
277 | void transcode_uastc_to_bc1_hint1(const unpacked_uastc_block& unpacked_src_blk, const color32 block_pixels[4][4], void* pDst, bool high_quality); |
278 | |
279 | bool transcode_uastc_to_bc1(const uastc_block& src_blk, void* pDst, bool high_quality); |
280 | bool transcode_uastc_to_bc3(const uastc_block& src_blk, void* pDst, bool high_quality); |
281 | bool transcode_uastc_to_bc4(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0); |
282 | bool transcode_uastc_to_bc5(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1); |
283 | |
284 | bool transcode_uastc_to_etc2_eac_r11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0); |
285 | bool transcode_uastc_to_etc2_eac_rg11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1); |
286 | |
287 | bool transcode_uastc_to_pvrtc1_4_rgb(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality, bool from_alpha); |
288 | bool transcode_uastc_to_pvrtc1_4_rgba(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality); |
289 | |
290 | // uastc_init() MUST be called before using this module. |
291 | void uastc_init(); |
292 | |
293 | } // namespace basist |
294 | |