summaryrefslogtreecommitdiff
path: root/src/static_libs/rg_etc
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2014-05-27 15:02:23 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2014-06-10 14:58:27 +0900
commit6fc4c1da749f66286ddb51a3c0c08c8154be246f (patch)
tree0268b6da621d75eae661e0f7613469cae02e06bf /src/static_libs/rg_etc
parent188ffd412ce3ea184b220956d460a3e2a949cb6b (diff)
Evas ETC2: Add ETC2 encoder skeletton
Implement Alpha encoding, brute force way, but doesn't scan all possibilities either (only based on average alpha). RGB encoding is still entirely left to the rg-etc1 encoder. T, H and Planar mode will come in the next commits. @feature: Implement an ETC2 encoder from scratch for RGB8 and RGBA8
Diffstat (limited to 'src/static_libs/rg_etc')
-rw-r--r--src/static_libs/rg_etc/etc2_encoder.c274
-rw-r--r--src/static_libs/rg_etc/rg_etc1.h6
2 files changed, 280 insertions, 0 deletions
diff --git a/src/static_libs/rg_etc/etc2_encoder.c b/src/static_libs/rg_etc/etc2_encoder.c
new file mode 100644
index 0000000000..f70385c745
--- /dev/null
+++ b/src/static_libs/rg_etc/etc2_encoder.c
@@ -0,0 +1,274 @@
1/*
2Copyright (C) 2014 Jean-Philippe ANDRE
3
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
17INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
18FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include <Eina.h>
29#include "rg_etc1.h"
30
31// For alpha support
32static const int kAlphaModifiers[16][8] = {
33 { -3, -6, -9, -15, 2, 5, 8, 14},
34 { -3, -7, -10, -13, 2, 6, 9, 12},
35 { -2, -5, -8, -13, 1, 4, 7, 12},
36 { -2, -4, -6, -13, 1, 3, 5, 12},
37 { -3, -6, -8, -12, 2, 5, 7, 11},
38 { -3, -7, -9, -11, 2, 6, 8, 10},
39 { -4, -7, -8, -11, 3, 6, 7, 10},
40 { -3, -5, -8, -11, 2, 4, 7, 10},
41 { -2, -6, -8, -10, 1, 5, 7, 9},
42 { -2, -5, -8, -10, 1, 4, 7, 9},
43 { -2, -4, -8, -10, 1, 3, 7, 9},
44 { -2, -5, -7, -10, 1, 4, 6, 9},
45 { -3, -4, -7, -10, 2, 3, 6, 9},
46 { -1, -2, -3, -10, 0, 1, 2, 9},
47 { -4, -6, -8, -9, 3, 5, 7, 8},
48 { -3, -5, -7, -9, 2, 4, 6, 8}
49};
50
51// Damn OpenGL people, why don't you just pack data as on a CPU???
52static const int kBlockWalk[16] = {
53 0, 4, 8, 12,
54 1, 5, 9, 13,
55 2, 6, 10, 14,
56 3, 7, 11, 15
57};
58
59// Use with static constants so the compiler can optimize everything
60#define BITS(byteval, lowbit, highbit) \
61 (((byteval) >> (lowbit)) & ((1 << ((highbit) - (lowbit) + 1)) - 1))
62
63#define BIT(byteval, bit) \
64 (((byteval) >> (bit)) & 0x1)
65
66// Clamps only if value is > 255
67#define CLAMPDOWN(a) ({ int _z = (a); ((_z <= 255) ? _z : 255); })
68
69// Clamps only if value is < 0
70#define CLAMPUP(a) ({ int _z = (a); ((_z >= 0) ? _z : 0); })
71
72// Real clamp
73#define CLAMP(a) ({ int _b = (a); (((_b) >= 0) ? (((_b) < 256) ? (_b) : 255) : 0); })
74
75// Simple min
76#define MIN(a,b) ({ int _z = (a), _y = (b); ((_z <= _y) ? _z : _y); })
77
78// Simple abs
79#define ABS(a) ({ int _a = (a); ((_a >= 0) ? _a : (-_a)); })
80
81#ifndef WORDS_BIGENDIAN
82/* x86 */
83#define A_VAL(p) (((uint8_t *)(p))[3])
84#define R_VAL(p) (((uint8_t *)(p))[2])
85#define G_VAL(p) (((uint8_t *)(p))[1])
86#define B_VAL(p) (((uint8_t *)(p))[0])
87#else
88/* ppc */
89#define A_VAL(p) (((uint8_t *)(p))[0])
90#define R_VAL(p) (((uint8_t *)(p))[1])
91#define G_VAL(p) (((uint8_t *)(p))[2])
92#define B_VAL(p) (((uint8_t *)(p))[3])
93#endif
94
95#ifndef DBG
96# define DBG(fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__)
97#endif
98
99/** Pack alpha block given a modifier table and a multiplier
100 * @returns Squared error
101 */
102static int
103_etc2_alpha_block_pack(uint8_t *etc2_alpha,
104 const int base_codeword,
105 const int multiplier,
106 const int modifierIdx,
107 const uint32_t *bgra,
108 const Eina_Bool write)
109{
110 const int *alphaModifiers = kAlphaModifiers[modifierIdx];
111 uint8_t alphaIndexes[16];
112 int errAcc2 = 0;
113
114 // Header
115 if (write)
116 {
117 etc2_alpha[0] = base_codeword & 0xFF;
118 etc2_alpha[1] = ((multiplier << 4) & 0xF0) | (modifierIdx & 0x0F);
119 }
120
121 // Compute alphas now
122 for (int i = 0; i < 16; i++)
123 {
124 const int realA = A_VAL(bgra + kBlockWalk[i]);
125 int minErr = INT_MAX, idx = 0;
126
127 // Brute force -- find modifier index
128 for (int k = 0; (k < 8) && minErr; k++)
129 {
130 int tryA = CLAMP(base_codeword + alphaModifiers[k] * multiplier);
131 int err = ABS(realA - tryA);
132 if (err < minErr)
133 {
134 minErr = err;
135 idx = k;
136 if (!minErr) break;
137 }
138 }
139
140 alphaIndexes[i] = idx;
141
142 // Keep some stats
143 errAcc2 += minErr * minErr;
144 }
145
146 if (write)
147 for (int k = 0; k < 2; k++)
148 {
149 etc2_alpha[2 + 3 * k] = alphaIndexes[0 + 8 * k] << 5; // A
150 etc2_alpha[2 + 3 * k] |= alphaIndexes[1 + 8 * k] << 2; // B
151 etc2_alpha[2 + 3 * k] |= (alphaIndexes[2 + 8 * k] >> 1) & 0x3; // C01
152 etc2_alpha[3 + 3 * k] = (alphaIndexes[2 + 8 * k] & 0x1) << 7; // C2
153 etc2_alpha[3 + 3 * k] |= alphaIndexes[3 + 8 * k] << 4; // D
154 etc2_alpha[3 + 3 * k] |= alphaIndexes[4 + 8 * k] << 1; // E
155 etc2_alpha[3 + 3 * k] |= (alphaIndexes[5 + 8 * k] >> 2) & 0x1; // F0
156 etc2_alpha[4 + 3 * k] = (alphaIndexes[5 + 8 * k] & 0x3) << 6; // F12
157 etc2_alpha[4 + 3 * k] |= alphaIndexes[6 + 8 * k] << 3; // G
158 etc2_alpha[4 + 3 * k] |= alphaIndexes[7 + 8 * k]; // H
159 }
160
161 return errAcc2;
162}
163
164static int
165_etc2_alpha_encode(uint8_t *etc2_alpha, const uint32_t *bgra,
166 rg_etc1_pack_params *params EINA_UNUSED)
167{
168 int alphas[16], avg = 0, diff = 0, maxDiff = INT_MAX, minErr = INT_MAX;
169 int base_codeword;
170 int multiplier, bestMult = 0;
171 int modifierIdx, bestIdx = 0;
172 int err, base_range, base_step = 1, max_error = 0;
173
174 // Try to select the best alpha value (avg)
175 for (int i = 0; i < 16; i++)
176 {
177 alphas[i] = A_VAL(bgra + kBlockWalk[i]);
178 avg += alphas[i];
179 }
180 avg /= 16;
181
182 for (int i = 0; i < 16; i++)
183 {
184 int thisDiff = ABS(alphas[i] - avg);
185 maxDiff = MIN(thisDiff, maxDiff);
186 diff += thisDiff;
187 }
188
189 base_codeword = alphas[0];
190 if (!diff)
191 {
192 // All same alphas
193 etc2_alpha[0] = base_codeword;
194 memset(etc2_alpha + 1, 0, 7);
195 return 0;
196 }
197
198 // Bruteforce -- try all tables and all multipliers, oh my god this will be slow.
199
200 switch (params->m_quality)
201 {
202 // The follow parameters are completely arbitrary.
203 // Need some real testing.
204 case rg_etc1_high_quality:
205 base_range = 15;
206 base_step = 0;
207 max_error = 0;
208 break;
209 case rg_etc1_medium_quality:
210 base_range = 6;
211 base_step = 2;
212 max_error = 2 * 2 * 16; // 42dB
213 break;
214 case rg_etc1_low_quality:
215 base_range = 0;
216 max_error = 5 * 5 * 16; // 34dB
217 break;
218 }
219
220 // for loop avg, avg-1, avg+1, avg-2, avg+2, ...
221 for (int step = 0; step < base_range; step += base_step)
222 for (base_codeword = avg - step; base_codeword <= avg + step; base_codeword += 2 * step)
223 {
224 for (modifierIdx = 0; modifierIdx < 16; modifierIdx++)
225 for (multiplier = 0; multiplier < 16; multiplier++)
226 {
227 if ((ABS(multiplier * kAlphaModifiers[modifierIdx][3])) < maxDiff)
228 continue;
229
230 err = _etc2_alpha_block_pack(etc2_alpha, base_codeword,
231 multiplier, modifierIdx, bgra, EINA_FALSE);
232 if (err < minErr)
233 {
234 minErr = err;
235 bestMult = multiplier;
236 bestIdx = modifierIdx;
237 if (err < max_error)
238 goto pack_now;
239
240 }
241 }
242 if (step <= 0) break;
243 }
244
245pack_now:
246 err = _etc2_alpha_block_pack(etc2_alpha, base_codeword,
247 bestMult, bestIdx, bgra, EINA_TRUE);
248 return err;
249}
250
251unsigned int
252etc2_rgba8_block_pack(unsigned char *etc2, const unsigned int *bgra,
253 rg_etc1_pack_params *params)
254{
255 unsigned int error;
256
257 // FIXME/TODO: For now, encode use rg_etc1 only!
258 error = rg_etc1_pack_block(etc2 + 8, bgra, params);
259 error += _etc2_alpha_encode(etc2, bgra, params);
260
261 return error;
262}
263
264unsigned int
265etc2_rgb8_block_pack(unsigned char *etc2, const unsigned int *bgra,
266 rg_etc1_pack_params *params)
267{
268 unsigned int error;
269
270 // FIXME/TODO: For now, encode use rg_etc1 only!
271 error = rg_etc1_pack_block(etc2, bgra, params);
272
273 return error;
274}
diff --git a/src/static_libs/rg_etc/rg_etc1.h b/src/static_libs/rg_etc/rg_etc1.h
index 275b0dbb3d..6f4b94449b 100644
--- a/src/static_libs/rg_etc/rg_etc1.h
+++ b/src/static_libs/rg_etc/rg_etc1.h
@@ -37,6 +37,12 @@ void rg_etc1_pack_block_init();
37// pack_etc1_block() does not currently support "perceptual" colorspace metrics - it primarily optimizes for RGB RMSE. 37// pack_etc1_block() does not currently support "perceptual" colorspace metrics - it primarily optimizes for RGB RMSE.
38unsigned int rg_etc1_pack_block(void* pETC1_block, const unsigned int* pSrc_pixels_BGRA, rg_etc1_pack_params *pack_params); 38unsigned int rg_etc1_pack_block(void* pETC1_block, const unsigned int* pSrc_pixels_BGRA, rg_etc1_pack_params *pack_params);
39 39
40// Pack a 4x4 block of 32bpp BGRA pixels to a 16-byte RGBA8_ETC2_EAC block (supports alpha).
41unsigned int etc2_rgba8_block_pack(unsigned char *etc2, const unsigned int *bgra, rg_etc1_pack_params *params);
42
43// Pack a 4x4 block of 32bpp BGRA pixels to a 8-byte RGB8_ETC2 block (opaque).
44unsigned int etc2_rgb8_block_pack(unsigned char *etc2, const unsigned int *bgra, rg_etc1_pack_params *params);
45
40// ETC2 support: RGB8_ETC2 46// ETC2 support: RGB8_ETC2
41void rg_etc2_rgb8_decode_block(const unsigned char *etc_block, unsigned int *bgra); 47void rg_etc2_rgb8_decode_block(const unsigned char *etc_block, unsigned int *bgra);
42 48