1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
30 #include "vogl_core.h"
38 cETC1BytesPerBlock = 8U,
39 cETC1SelectorBits = 2U,
40 cETC1SelectorValues = 1U << cETC1SelectorBits,
41 cETC1SelectorMask = cETC1SelectorValues - 1U,
43 cETC1BlockSize = 1U << cETC1BlockShift,
44 cETC1LSBSelectorIndicesBitOffset = 0,
45 cETC1MSBSelectorIndicesBitOffset = 16,
46 cETC1FlipBitOffset = 32,
47 cETC1DiffBitOffset = 33,
48 cETC1IntenModifierNumBits = 3,
49 cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
50 cETC1RightIntenModifierTableBitOffset = 34,
51 cETC1LeftIntenModifierTableBitOffset = 37,
53 // Base+Delta encoding (5 bit bases, 3 bit delta)
54 cETC1BaseColorCompNumBits = 5,
55 cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
56 cETC1DeltaColorCompNumBits = 3,
57 cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
58 cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
59 cETC1BaseColor5RBitOffset = 59,
60 cETC1BaseColor5GBitOffset = 51,
61 cETC1BaseColor5BBitOffset = 43,
62 cETC1DeltaColor3RBitOffset = 56,
63 cETC1DeltaColor3GBitOffset = 48,
64 cETC1DeltaColor3BBitOffset = 40,
66 // Absolute (non-delta) encoding (two 4-bit per component bases)
67 cETC1AbsColorCompNumBits = 4,
68 cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
69 cETC1AbsColor4R1BitOffset = 60,
70 cETC1AbsColor4G1BitOffset = 52,
71 cETC1AbsColor4B1BitOffset = 44,
72 cETC1AbsColor4R2BitOffset = 56,
73 cETC1AbsColor4G2BitOffset = 48,
74 cETC1AbsColor4B2BitOffset = 40,
75 cETC1ColorDeltaMin = -4,
76 cETC1ColorDeltaMax = 3,
80 // 000 001 010 011 100 101 110 111
81 // 0 1 2 3 -4 -3 -2 -1
84 extern const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues];
85 extern const uint8 g_etc1_to_selector_index[cETC1SelectorValues];
86 extern const uint8 g_selector_index_to_etc1[cETC1SelectorValues];
92 extern const etc1_coord2 g_etc1_pixel_coords[2][2][8]; // [flipped][subblock][subblock_pixel]
96 // big endian uint64_t:
97 // bit ofs: 56 48 40 32 24 16 8 0
98 // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7
105 uint8 m_low_color[2];
106 uint8 m_high_color[2];
110 cNumSelectorBytes = 4
112 uint8 m_selectors[cNumSelectorBytes];
116 utils::zero_this(this);
119 inline uint get_general_bits(uint ofs, uint num) const
121 VOGL_ASSERT((ofs + num) <= 64U);
122 VOGL_ASSERT(num && (num < 32U));
123 return static_cast<uint>((utils::read_be64(&m_uint64) >> ofs) & ((1UL << num) - 1UL));
126 inline void set_general_bits(uint ofs, uint num, uint bits)
128 VOGL_ASSERT((ofs + num) <= 64U);
129 VOGL_ASSERT(num && (num < 32U));
131 uint64_t x = utils::read_be64(&m_uint64);
132 uint64_t msk = ((1ULL << static_cast<uint64_t>(num)) - 1ULL) << static_cast<uint64_t>(ofs);
134 x |= (static_cast<uint64_t>(bits) << static_cast<uint64_t>(ofs));
135 utils::write_be64(&m_uint64, x);
138 inline uint get_byte_bits(uint ofs, uint num) const
140 VOGL_ASSERT((ofs + num) <= 64U);
141 VOGL_ASSERT(num && (num <= 8U));
142 VOGL_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
143 const uint byte_ofs = 7 - (ofs >> 3);
144 const uint byte_bit_ofs = ofs & 7;
145 return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);
148 inline void set_byte_bits(uint ofs, uint num, uint bits)
150 VOGL_ASSERT((ofs + num) <= 64U);
151 VOGL_ASSERT(num && (num < 32U));
152 VOGL_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
153 VOGL_ASSERT(bits < (1U << num));
154 const uint byte_ofs = 7 - (ofs >> 3);
155 const uint byte_bit_ofs = ofs & 7;
156 const uint mask = (1 << num) - 1;
157 m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);
158 m_bytes[byte_ofs] |= (bits << byte_bit_ofs);
161 // false = left/right subblocks
162 // true = upper/lower subblocks
163 inline bool get_flip_bit() const
165 return (m_bytes[3] & 1) != 0;
168 inline void set_flip_bit(bool flip)
171 m_bytes[3] |= static_cast<uint8>(flip);
174 inline bool get_diff_bit() const
176 return (m_bytes[3] & 2) != 0;
179 inline void set_diff_bit(bool diff)
182 m_bytes[3] |= (static_cast<uint>(diff) << 1);
185 // Returns intensity modifier table (0-7) used by subblock subblock_id.
186 // subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
187 inline uint get_inten_table(uint subblock_id) const
189 VOGL_ASSERT(subblock_id < 2);
190 const uint ofs = subblock_id ? 2 : 5;
191 return (m_bytes[3] >> ofs) & 7;
194 // Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
195 inline void set_inten_table(uint subblock_id, uint t)
197 VOGL_ASSERT(subblock_id < 2);
199 const uint ofs = subblock_id ? 2 : 5;
200 m_bytes[3] &= ~(7 << ofs);
201 m_bytes[3] |= (t << ofs);
204 // Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
205 inline uint get_selector(uint x, uint y) const
207 VOGL_ASSERT((x | y) < 4);
209 const uint bit_index = x * 4 + y;
210 const uint byte_bit_ofs = bit_index & 7;
211 const uint8 *p = &m_bytes[7 - (bit_index >> 3)];
212 const uint lsb = (p[0] >> byte_bit_ofs) & 1;
213 const uint msb = (p[-2] >> byte_bit_ofs) & 1;
214 const uint val = lsb | (msb << 1);
216 return g_etc1_to_selector_index[val];
219 // Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
220 inline void set_selector(uint x, uint y, uint val)
222 VOGL_ASSERT((x | y | val) < 4);
223 const uint bit_index = x * 4 + y;
225 uint8 *p = &m_bytes[7 - (bit_index >> 3)];
227 const uint byte_bit_ofs = bit_index & 7;
228 const uint mask = 1 << byte_bit_ofs;
230 const uint etc1_val = g_selector_index_to_etc1[val];
232 const uint lsb = etc1_val & 1;
233 const uint msb = etc1_val >> 1;
236 p[0] |= (lsb << byte_bit_ofs);
239 p[-2] |= (msb << byte_bit_ofs);
242 inline void set_base4_color(uint idx, uint16 c)
246 set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
247 set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
248 set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);
252 set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
253 set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
254 set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);
258 inline uint16 get_base4_color(uint idx) const
263 r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
264 g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
265 b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
269 r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
270 g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
271 b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
273 return static_cast<uint16>(b | (g << 4U) | (r << 8U));
276 inline void set_base5_color(uint16 c)
278 set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
279 set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
280 set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);
283 inline uint16 get_base5_color() const
285 const uint r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);
286 const uint g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);
287 const uint b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);
288 return static_cast<uint16>(b | (g << 5U) | (r << 10U));
291 void set_delta3_color(uint16 c)
293 set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
294 set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
295 set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);
298 inline uint16 get_delta3_color() const
300 const uint r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
301 const uint g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
302 const uint b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
303 return static_cast<uint16>(b | (g << 3U) | (r << 6U));
307 static uint16 pack_color5(const color_quad_u8 &color, bool scaled, uint bias = 127U);
308 static uint16 pack_color5(uint r, uint g, uint b, bool scaled, uint bias = 127U);
310 static color_quad_u8 unpack_color5(uint16 packed_color5, bool scaled, uint alpha = 255U);
311 static void unpack_color5(uint &r, uint &g, uint &b, uint16 packed_color, bool scaled);
313 static bool unpack_color5(color_quad_u8 &result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
314 static bool unpack_color5(uint &r, uint &g, uint &b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
317 // Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
318 static uint16 pack_delta3(const color_quad_i16 &color);
319 static uint16 pack_delta3(int r, int g, int b);
321 // Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
322 static color_quad_i16 unpack_delta3(uint16 packed_delta3);
323 static void unpack_delta3(int &r, int &g, int &b, uint16 packed_delta3);
326 static uint16 pack_color4(const color_quad_u8 &color, bool scaled, uint bias = 127U);
327 static uint16 pack_color4(uint r, uint g, uint b, bool scaled, uint bias = 127U);
329 static color_quad_u8 unpack_color4(uint16 packed_color4, bool scaled, uint alpha = 255U);
330 static void unpack_color4(uint &r, uint &g, uint &b, uint16 packed_color4, bool scaled);
333 static void get_diff_subblock_colors(color_quad_u8 *pDst, uint16 packed_color5, uint table_idx);
334 static bool get_diff_subblock_colors(color_quad_u8 *pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx);
335 static void get_abs_subblock_colors(color_quad_u8 *pDst, uint16 packed_color4, uint table_idx);
337 static inline void unscaled_to_scaled_color(color_quad_u8 &dst, const color_quad_u8 &src, bool color4)
341 dst.r = src.r | (src.r << 4);
342 dst.g = src.g | (src.g << 4);
343 dst.b = src.b | (src.b << 4);
347 dst.r = (src.r >> 2) | (src.r << 3);
348 dst.g = (src.g >> 2) | (src.g << 3);
349 dst.b = (src.b >> 2) | (src.b << 3);
355 VOGL_DEFINE_BITWISE_COPYABLE(etc1_block);
357 // Returns false if the block is invalid (it will still be unpacked with clamping).
358 bool unpack_etc1(const etc1_block &block, color_quad_u8 *pDst, bool preserve_alpha = false);
360 enum vogl_etc_quality
363 cCRNETCQualityMedium,
366 cCRNETCQualityForceDWORD = 0xFFFFFFFF
369 struct vogl_etc1_pack_params
371 vogl_etc_quality m_quality;
375 inline vogl_etc1_pack_params()
382 m_quality = cCRNETCQualitySlow;
388 struct etc1_solution_coordinates
390 inline etc1_solution_coordinates()
391 : m_unscaled_color(0, 0, 0, 0),
397 inline etc1_solution_coordinates(uint r, uint g, uint b, uint inten_table, bool color4)
398 : m_unscaled_color(r, g, b, 255),
399 m_inten_table(inten_table),
404 inline etc1_solution_coordinates(const color_quad_u8 &c, uint inten_table, bool color4)
405 : m_unscaled_color(c),
406 m_inten_table(inten_table),
411 inline etc1_solution_coordinates(const etc1_solution_coordinates &other)
416 inline etc1_solution_coordinates &operator=(const etc1_solution_coordinates &rhs)
418 m_unscaled_color = rhs.m_unscaled_color;
419 m_inten_table = rhs.m_inten_table;
420 m_color4 = rhs.m_color4;
426 m_unscaled_color.clear();
431 inline color_quad_u8 get_scaled_color() const
436 br = m_unscaled_color.r | (m_unscaled_color.r << 4);
437 bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
438 bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
442 br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
443 bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
444 bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
446 return color_quad_u8(br, bg, bb);
449 inline void get_block_colors(color_quad_u8 *pBlock_colors)
454 br = m_unscaled_color.r | (m_unscaled_color.r << 4);
455 bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
456 bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
460 br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
461 bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
462 bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
464 const int *pInten_table = g_etc1_inten_tables[m_inten_table];
465 pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0]);
466 pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1]);
467 pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2]);
468 pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3]);
471 color_quad_u8 m_unscaled_color;
478 VOGL_NO_COPY_OR_ASSIGNMENT_OP(etc1_optimizer);
490 m_pSorted_luma = NULL;
491 m_pSorted_luma_indices = NULL;
494 struct params : vogl_etc1_pack_params
501 params(const vogl_etc1_pack_params &base_params)
502 : vogl_etc1_pack_params(base_params)
504 clear_optimizer_params();
509 vogl_etc1_pack_params::clear();
510 clear_optimizer_params();
513 void clear_optimizer_params()
515 m_num_src_pixels = 0;
518 m_use_color4 = false;
519 static const int s_default_scan_delta[] = { 0 };
520 m_pScan_deltas = s_default_scan_delta;
521 m_scan_delta_size = 1;
523 m_base_color5.clear();
524 m_constrain_against_base_color5 = false;
527 uint m_num_src_pixels;
528 const color_quad_u8 *m_pSrc_pixels;
531 const int *m_pScan_deltas;
532 uint m_scan_delta_size;
534 color_quad_u8 m_base_color5;
535 bool m_constrain_against_base_color5;
541 color_quad_u8 m_block_color_unscaled;
542 uint m_block_inten_table;
547 inline results &operator=(const results &rhs)
549 m_block_color_unscaled = rhs.m_block_color_unscaled;
550 m_block_color4 = rhs.m_block_color4;
551 m_block_inten_table = rhs.m_block_inten_table;
552 m_error = rhs.m_error;
553 VOGL_ASSERT(m_n == rhs.m_n);
554 memcpy(m_pSelectors, rhs.m_pSelectors, rhs.m_n);
559 void init(const params ¶ms, results &result);
563 struct potential_solution
566 : m_coords(), m_error(cUINT64_MAX), m_valid(false)
570 etc1_solution_coordinates m_coords;
571 vogl::vector<uint8> m_selectors;
578 m_selectors.resize(0);
579 m_error = cUINT64_MAX;
583 bool are_selectors_all_equal() const
585 if (m_selectors.is_empty())
587 const uint s = m_selectors[0];
588 for (uint i = 1; i < m_selectors.size(); i++)
589 if (m_selectors[i] != s)
595 const params *m_pParams;
601 int m_br, m_bg, m_bb;
602 vogl::vector<uint16> m_luma;
603 vogl::vector<uint32> m_sorted_luma[2];
604 const uint32 *m_pSorted_luma_indices;
605 uint32 *m_pSorted_luma;
607 vogl::vector<uint8> m_selectors;
608 vogl::vector<uint8> m_best_selectors;
610 potential_solution m_best_solution;
611 potential_solution m_trial_solution;
612 vogl::vector<uint8> m_temp_selectors;
614 bool evaluate_solution(const etc1_solution_coordinates &coords, potential_solution &trial_solution, potential_solution *pBest_solution);
615 bool evaluate_solution_fast(const etc1_solution_coordinates &coords, potential_solution &trial_solution, potential_solution *pBest_solution);
618 struct pack_etc1_block_context
620 etc1_optimizer m_optimizer;
623 void pack_etc1_block_init();
625 uint64_t pack_etc1_block(etc1_block &block, const color_quad_u8 *pSrc_pixels, vogl_etc1_pack_params &pack_params, pack_etc1_block_context &context);