]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_etc.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_etc.h
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
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
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 // File: vogl_etc.h
28 #pragma once
29
30 #include "vogl_core.h"
31 #include "vogl.h"
32 #include "vogl_dxt.h"
33
34 namespace vogl
35 {
36     enum etc_constants
37     {
38         cETC1BytesPerBlock = 8U,
39         cETC1SelectorBits = 2U,
40         cETC1SelectorValues = 1U << cETC1SelectorBits,
41         cETC1SelectorMask = cETC1SelectorValues - 1U,
42         cETC1BlockShift = 2U,
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,
52
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,
65
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,
77
78         // Delta3:
79         // 0   1   2   3   4   5   6   7
80         // 000 001 010 011 100 101 110 111
81         // 0   1   2   3   -4  -3  -2  -1
82     };
83
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];
87
88     struct etc1_coord2
89     {
90         uint8 m_x, m_y;
91     };
92     extern const etc1_coord2 g_etc1_pixel_coords[2][2][8]; // [flipped][subblock][subblock_pixel]
93
94     struct etc1_block
95     {
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
99         union
100         {
101             uint64_t m_uint64;
102             uint8 m_bytes[8];
103         };
104
105         uint8 m_low_color[2];
106         uint8 m_high_color[2];
107
108         enum
109         {
110             cNumSelectorBytes = 4
111         };
112         uint8 m_selectors[cNumSelectorBytes];
113
114         inline void clear()
115         {
116             utils::zero_this(this);
117         }
118
119         inline uint get_general_bits(uint ofs, uint num) const
120         {
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));
124         }
125
126         inline void set_general_bits(uint ofs, uint num, uint bits)
127         {
128             VOGL_ASSERT((ofs + num) <= 64U);
129             VOGL_ASSERT(num && (num < 32U));
130
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);
133             x &= ~msk;
134             x |= (static_cast<uint64_t>(bits) << static_cast<uint64_t>(ofs));
135             utils::write_be64(&m_uint64, x);
136         }
137
138         inline uint get_byte_bits(uint ofs, uint num) const
139         {
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);
146         }
147
148         inline void set_byte_bits(uint ofs, uint num, uint bits)
149         {
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);
159         }
160
161         // false = left/right subblocks
162         // true = upper/lower subblocks
163         inline bool get_flip_bit() const
164         {
165             return (m_bytes[3] & 1) != 0;
166         }
167
168         inline void set_flip_bit(bool flip)
169         {
170             m_bytes[3] &= ~1;
171             m_bytes[3] |= static_cast<uint8>(flip);
172         }
173
174         inline bool get_diff_bit() const
175         {
176             return (m_bytes[3] & 2) != 0;
177         }
178
179         inline void set_diff_bit(bool diff)
180         {
181             m_bytes[3] &= ~2;
182             m_bytes[3] |= (static_cast<uint>(diff) << 1);
183         }
184
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
188         {
189             VOGL_ASSERT(subblock_id < 2);
190             const uint ofs = subblock_id ? 2 : 5;
191             return (m_bytes[3] >> ofs) & 7;
192         }
193
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)
196         {
197             VOGL_ASSERT(subblock_id < 2);
198             VOGL_ASSERT(t < 8);
199             const uint ofs = subblock_id ? 2 : 5;
200             m_bytes[3] &= ~(7 << ofs);
201             m_bytes[3] |= (t << ofs);
202         }
203
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
206         {
207             VOGL_ASSERT((x | y) < 4);
208
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);
215
216             return g_etc1_to_selector_index[val];
217         }
218
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)
221         {
222             VOGL_ASSERT((x | y | val) < 4);
223             const uint bit_index = x * 4 + y;
224
225             uint8 *p = &m_bytes[7 - (bit_index >> 3)];
226
227             const uint byte_bit_ofs = bit_index & 7;
228             const uint mask = 1 << byte_bit_ofs;
229
230             const uint etc1_val = g_selector_index_to_etc1[val];
231
232             const uint lsb = etc1_val & 1;
233             const uint msb = etc1_val >> 1;
234
235             p[0] &= ~mask;
236             p[0] |= (lsb << byte_bit_ofs);
237
238             p[-2] &= ~mask;
239             p[-2] |= (msb << byte_bit_ofs);
240         }
241
242         inline void set_base4_color(uint idx, uint16 c)
243         {
244             if (idx)
245             {
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);
249             }
250             else
251             {
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);
255             }
256         }
257
258         inline uint16 get_base4_color(uint idx) const
259         {
260             uint r, g, b;
261             if (idx)
262             {
263                 r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
264                 g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
265                 b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
266             }
267             else
268             {
269                 r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
270                 g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
271                 b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
272             }
273             return static_cast<uint16>(b | (g << 4U) | (r << 8U));
274         }
275
276         inline void set_base5_color(uint16 c)
277         {
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);
281         }
282
283         inline uint16 get_base5_color() const
284         {
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));
289         }
290
291         void set_delta3_color(uint16 c)
292         {
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);
296         }
297
298         inline uint16 get_delta3_color() const
299         {
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));
304         }
305
306         // Base color 5
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);
309
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);
312
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);
315
316         // Delta color 3
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);
320
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);
324
325         // Abs color 4
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);
328
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);
331
332         // subblock colors
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);
336
337         static inline void unscaled_to_scaled_color(color_quad_u8 &dst, const color_quad_u8 &src, bool color4)
338         {
339             if (color4)
340             {
341                 dst.r = src.r | (src.r << 4);
342                 dst.g = src.g | (src.g << 4);
343                 dst.b = src.b | (src.b << 4);
344             }
345             else
346             {
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);
350             }
351             dst.a = src.a;
352         }
353     };
354
355     VOGL_DEFINE_BITWISE_COPYABLE(etc1_block);
356
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);
359
360     enum vogl_etc_quality
361     {
362         cCRNETCQualityFast,
363         cCRNETCQualityMedium,
364         cCRNETCQualitySlow,
365         cCRNETCQualityTotal,
366         cCRNETCQualityForceDWORD = 0xFFFFFFFF
367     };
368
369     struct vogl_etc1_pack_params
370     {
371         vogl_etc_quality m_quality;
372         bool m_perceptual;
373         bool m_dithering;
374
375         inline vogl_etc1_pack_params()
376         {
377             clear();
378         }
379
380         void clear()
381         {
382             m_quality = cCRNETCQualitySlow;
383             m_perceptual = true;
384             m_dithering = false;
385         }
386     };
387
388     struct etc1_solution_coordinates
389     {
390         inline etc1_solution_coordinates()
391             : m_unscaled_color(0, 0, 0, 0),
392               m_inten_table(0),
393               m_color4(false)
394         {
395         }
396
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),
400               m_color4(color4)
401         {
402         }
403
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),
407               m_color4(color4)
408         {
409         }
410
411         inline etc1_solution_coordinates(const etc1_solution_coordinates &other)
412         {
413             *this = other;
414         }
415
416         inline etc1_solution_coordinates &operator=(const etc1_solution_coordinates &rhs)
417         {
418             m_unscaled_color = rhs.m_unscaled_color;
419             m_inten_table = rhs.m_inten_table;
420             m_color4 = rhs.m_color4;
421             return *this;
422         }
423
424         inline void clear()
425         {
426             m_unscaled_color.clear();
427             m_inten_table = 0;
428             m_color4 = false;
429         }
430
431         inline color_quad_u8 get_scaled_color() const
432         {
433             int br, bg, bb;
434             if (m_color4)
435             {
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);
439             }
440             else
441             {
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);
445             }
446             return color_quad_u8(br, bg, bb);
447         }
448
449         inline void get_block_colors(color_quad_u8 *pBlock_colors)
450         {
451             int br, bg, bb;
452             if (m_color4)
453             {
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);
457             }
458             else
459             {
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);
463             }
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]);
469         }
470
471         color_quad_u8 m_unscaled_color;
472         uint m_inten_table;
473         bool m_color4;
474     };
475
476     class etc1_optimizer
477     {
478         VOGL_NO_COPY_OR_ASSIGNMENT_OP(etc1_optimizer);
479
480     public:
481         etc1_optimizer()
482         {
483             clear();
484         }
485
486         void clear()
487         {
488             m_pParams = NULL;
489             m_pResult = NULL;
490             m_pSorted_luma = NULL;
491             m_pSorted_luma_indices = NULL;
492         }
493
494         struct params : vogl_etc1_pack_params
495         {
496             params()
497             {
498                 clear();
499             }
500
501             params(const vogl_etc1_pack_params &base_params)
502                 : vogl_etc1_pack_params(base_params)
503             {
504                 clear_optimizer_params();
505             }
506
507             void clear()
508             {
509                 vogl_etc1_pack_params::clear();
510                 clear_optimizer_params();
511             }
512
513             void clear_optimizer_params()
514             {
515                 m_num_src_pixels = 0;
516                 m_pSrc_pixels = 0;
517
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;
522
523                 m_base_color5.clear();
524                 m_constrain_against_base_color5 = false;
525             }
526
527             uint m_num_src_pixels;
528             const color_quad_u8 *m_pSrc_pixels;
529
530             bool m_use_color4;
531             const int *m_pScan_deltas;
532             uint m_scan_delta_size;
533
534             color_quad_u8 m_base_color5;
535             bool m_constrain_against_base_color5;
536         };
537
538         struct results
539         {
540             uint64_t m_error;
541             color_quad_u8 m_block_color_unscaled;
542             uint m_block_inten_table;
543             uint m_n;
544             uint8 *m_pSelectors;
545             bool m_block_color4;
546
547             inline results &operator=(const results &rhs)
548             {
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);
555                 return *this;
556             }
557         };
558
559         void init(const params &params, results &result);
560         bool compute();
561
562     private:
563         struct potential_solution
564         {
565             potential_solution()
566                 : m_coords(), m_error(cUINT64_MAX), m_valid(false)
567             {
568             }
569
570             etc1_solution_coordinates m_coords;
571             vogl::vector<uint8> m_selectors;
572             uint64_t m_error;
573             bool m_valid;
574
575             void clear()
576             {
577                 m_coords.clear();
578                 m_selectors.resize(0);
579                 m_error = cUINT64_MAX;
580                 m_valid = false;
581             }
582
583             bool are_selectors_all_equal() const
584             {
585                 if (m_selectors.is_empty())
586                     return false;
587                 const uint s = m_selectors[0];
588                 for (uint i = 1; i < m_selectors.size(); i++)
589                     if (m_selectors[i] != s)
590                         return false;
591                 return true;
592             }
593         };
594
595         const params *m_pParams;
596         results *m_pResult;
597
598         int m_limit;
599
600         vec3F m_avg_color;
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;
606
607         vogl::vector<uint8> m_selectors;
608         vogl::vector<uint8> m_best_selectors;
609
610         potential_solution m_best_solution;
611         potential_solution m_trial_solution;
612         vogl::vector<uint8> m_temp_selectors;
613
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);
616     };
617
618     struct pack_etc1_block_context
619     {
620         etc1_optimizer m_optimizer;
621     };
622
623     void pack_etc1_block_init();
624
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);
626
627 } // namespace vogl