1// Copyright 2019 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "Common.comp"
16
17precision highp int;
18
19const uint VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147;
20const uint VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148;
21const uint VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149;
22const uint VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150;
23const uint VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151;
24const uint VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152;
25const uint VK_FORMAT_EAC_R11_UNORM_BLOCK = 153;
26const uint VK_FORMAT_EAC_R11_SNORM_BLOCK = 154;
27const uint VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155;
28const uint VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156;
29
30const int kLookup[8] = {0, 1, 2, 3, -4, -3, -2, -1};
31
32const ivec4 kRGBModifierTable[] = {
33    /* 0 */ {2, 8, -2, -8},
34    /* 1 */ {5, 17, -5, -17},
35    /* 2 */ {9, 29, -9, -29},
36    /* 3 */ {13, 42, -13, -42},
37    /* 4 */ {18, 60, -18, -60},
38    /* 5 */ {24, 80, -24, -80},
39    /* 6 */ {33, 106, -33, -106},
40    /* 7 */ {47, 183, -47, -183}};
41
42const ivec4 kRGBOpaqueModifierTable[] = {
43    /* 0 */ {0, 8, 0, -8},
44    /* 1 */ {0, 17, 0, -17},
45    /* 2 */ {0, 29, 0, -29},
46    /* 3 */ {0, 42, 0, -42},
47    /* 4 */ {0, 60, 0, -60},
48    /* 5 */ {0, 80, 0, -80},
49    /* 6 */ {0, 106, 0, -106},
50    /* 7 */ {0, 183, 0, -183}};
51
52const ivec4 kAlphaModifierTable[] = {
53    /* 0 */ {-3, -6, -9, -15},  {2, 5, 8, 14},
54    /* 1 */ {-3, -7, -10, -13}, {2, 6, 9, 12},
55    /* 2 */ {-2, -5, -8, -13},  {1, 4, 7, 12},
56    /* 3 */ {-2, -4, -6, -13},  {1, 3, 5, 12},
57    /* 4 */ {-3, -6, -8, -12},  {2, 5, 7, 11},
58    /* 5 */ {-3, -7, -9, -11},  {2, 6, 8, 10},
59    /* 6 */ {-4, -7, -8, -11},  {3, 6, 7, 10},
60    /* 7 */ {-3, -5, -8, -11},  {2, 4, 7, 10},
61    /* 8 */ {-2, -6, -8, -10},  {1, 5, 7, 9},
62    /* 9 */ {-2, -5, -8, -10},  {1, 4, 7, 9},
63    /* 10 */ {-2, -4, -8, -10}, {1, 3, 7, 9},
64    /* 11 */ {-2, -5, -7, -10}, {1, 4, 6, 9},
65    /* 12 */ {-3, -4, -7, -10}, {2, 3, 6, 9},
66    /* 13 */ {-1, -2, -3, -10}, {0, 1, 2, 9},
67    /* 14 */ {-4, -6, -8, -9},  {3, 5, 7, 8},
68    /* 15 */ {-3, -5, -7, -9},  {2, 4, 6, 8}};
69
70bool isOverflowed(uint base, uint diff) {
71    int val = int(0x1f & base) + kLookup[0x7 & diff];
72    return (val < 0) || (val >= 32);
73}
74
75uint convert4To8(uint b) {
76    uint c = b & 0xf;
77    return (c << 4) | c;
78}
79
80uint convert5To8(uint b) {
81    uint c = b & 0x1f;
82    return (c << 3) | (c >> 2);
83}
84
85uint convert6To8(uint b) {
86    uint c = b & 0x3f;
87    return (c << 2) | (c >> 4);
88}
89
90uint convert7To8(uint b) {
91    uint c = b & 0x7f;
92    return (c << 1) | (c >> 6);
93}
94
95uint convertDiff(uint base, uint diff) {
96    return convert5To8(uint(int(0x1f & base) + kLookup[0x7 & diff]));
97}
98
99int _clamp(int x) { return int(clamp(x, 0, 255)); }
100
101ivec3 _clamp(ivec3 x) { return ivec3(clamp(x, 0, 255)); }
102
103ivec4[16] etc2_T_H_index(ivec3[4] clrTable, uint low, bool isPunchthroughAlpha, bool opaque) {
104    ivec4 ret[16];
105    for (uint y = 0; y < 4; y++) {
106        for (uint x = 0; x < 4; x++) {
107            uint k = y + x * 4;
108            uint msb = (low >> (k + 15)) & 2;
109            uint lsb = (low >> k) & 1;
110            if (isPunchthroughAlpha && (!opaque) && (msb != 0) && (lsb == 0)) {
111                // rgba all 0
112                ret[y * 4 + x] = ivec4(0, 0, 0, 0);
113            } else {
114                uint offset = lsb | msb;
115                ret[y * 4 + x] = ivec4(clrTable[offset], 255);
116            }
117        }
118    }
119    return ret;
120}
121
122ivec4[16] etc2_decode_block_T(uint high, uint low, bool isPunchthroughAlpha, bool opaque) {
123    const int LUT[] = {3, 6, 11, 16, 23, 32, 41, 64};
124    int r1, r2, g1, g2, b1, b2;
125    r1 = int(convert4To8((((high >> 27) & 3) << 2) | ((high >> 24) & 3)));
126    g1 = int(convert4To8(high >> 20));
127    b1 = int(convert4To8(high >> 16));
128    r2 = int(convert4To8(high >> 12));
129    g2 = int(convert4To8(high >> 8));
130    b2 = int(convert4To8(high >> 4));
131    // 3 bits intense modifier
132    int intenseIdx = int((((high >> 2) & 3) << 1) | (high & 1));
133    int intenseMod = LUT[intenseIdx];
134    ivec3 clrTable[4];
135    clrTable[0] = ivec3(r1, g1, b1);
136    clrTable[1] = ivec3(_clamp(int(r2) + intenseMod), _clamp(int(g2) + intenseMod),
137                        _clamp(int(b2) + intenseMod));
138    clrTable[2] = ivec3(r2, g2, b2);
139    clrTable[3] = ivec3(_clamp(int(r2) - intenseMod), _clamp(int(g2) - intenseMod),
140                        _clamp(int(b2) - intenseMod));
141    return etc2_T_H_index(clrTable, low, isPunchthroughAlpha, opaque);
142}
143
144ivec4[16] etc2_decode_block_H(uint high, uint low, bool isPunchthroughAlpha, bool opaque) {
145    const int LUT[] = {3, 6, 11, 16, 23, 32, 41, 64};
146    ivec3 rgb1, rgb2;
147    rgb1.r = int(convert4To8(high >> 27));
148    rgb1.g = int(convert4To8(((high >> 24) << 1) | ((high >> 20) & 1)));
149    rgb1.b = int(convert4To8(((high >> 19) << 3) | ((high >> 15) & 7)));
150    rgb2.r = int(convert4To8(high >> 11));
151    rgb2.g = int(convert4To8(high >> 7));
152    rgb2.b = int(convert4To8(high >> 3));
153    // 3 bits intense modifier
154    uint intenseIdx = high & 4;
155    intenseIdx |= (high & 1) << 1;
156    intenseIdx |= uint(((rgb1.r << 16) | (rgb1.g << 8) | rgb1.b) >=
157                       ((rgb2.r << 16) | (rgb2.g << 8) | rgb2.b));
158    int intenseMod = LUT[intenseIdx];
159    ivec3 clrTable[4];
160    clrTable[0] = _clamp(ivec3(rgb1) + intenseMod);
161    clrTable[1] = _clamp(ivec3(rgb1) - intenseMod);
162    clrTable[2] = _clamp(ivec3(rgb2) + intenseMod);
163    clrTable[3] = _clamp(ivec3(rgb2) - intenseMod);
164    return etc2_T_H_index(clrTable, low, isPunchthroughAlpha, opaque);
165}
166
167ivec4[16] etc2_decode_block_P(uint high, uint low, bool isPunchthroughAlpha) {
168    ivec3 rgbo, rgbh, rgbv;
169    rgbo.r = int(convert6To8(high >> 25));
170    rgbo.g = int(convert7To8(((high >> 24) << 6) | ((high >> 17) & 63)));
171    rgbo.b = int(convert6To8(((high >> 16) << 5) | (((high >> 11) & 3) << 3) | ((high >> 7) & 7)));
172    rgbh.r = int(convert6To8(((high >> 2) << 1) | (high & 1)));
173    rgbh.g = int(convert7To8(low >> 25));
174    rgbh.b = int(convert6To8(low >> 19));
175    rgbv.r = int(convert6To8(low >> 13));
176    rgbv.g = int(convert7To8(low >> 6));
177    rgbv.b = int(convert6To8(low));
178    ivec4 ret[16];
179    for (int i = 0; i < 16; i++) {
180        int y = i >> 2;
181        int x = i & 3;
182        ret[i] = ivec4(_clamp((x * (rgbh - rgbo) + y * (rgbv - rgbo) + 4 * rgbo + 2) >> 2), 255);
183        ret[i].a = 255;
184    }
185    return ret;
186}
187
188void decode_subblock(inout ivec4 pOut[16], int r, int g, int b, ivec4 table, uint low, bool second,
189                     bool flipped, bool isPunchthroughAlpha, bool opaque) {
190    uint baseX = 0;
191    uint baseY = 0;
192    if (second) {
193        if (flipped) {
194            baseY = 2;
195        } else {
196            baseX = 2;
197        }
198    }
199    for (int i = 0; i < 8; i++) {
200        uint x, y;
201        if (flipped) {
202            x = baseX + (i >> 1);
203            y = baseY + (i & 1);
204        } else {
205            x = baseX + (i >> 2);
206            y = baseY + (i & 3);
207        }
208        uint k = y + (x * 4);
209        uint msb = ((low >> (k + 15)) & 2);
210        uint lsb = ((low >> k) & 1);
211        uint q = x + 4 * y;
212        if (isPunchthroughAlpha && (!opaque) && (msb != 0) && (lsb == 0)) {
213            // rgba all 0
214            pOut[q] = ivec4(0, 0, 0, 0);
215        } else {
216            uint offset = lsb | msb;
217            int delta = table[offset];
218            pOut[q] =
219                ivec4(_clamp(int(r) + delta), _clamp(int(g) + delta), _clamp(int(b) + delta), 255);
220        }
221    }
222}
223
224ivec4[16] allZeros() {
225    ivec4[16] ret;
226    for (int i = 0; i < 16; i++) {
227        ret[i] = ivec4(0);
228    }
229    return ret;
230}
231
232ivec4[16] etc2_decode_rgb_block(uint high, uint low, bool isPunchthroughAlpha) {
233    bool opaque = (((high >> 1) & 1) != 0);
234    int r1, r2, g1, g2, b1, b2;
235    if (isPunchthroughAlpha || ((high & 2) != 0)) {
236        // differntial
237        uint rBase = high >> 27;
238        uint gBase = high >> 19;
239        uint bBase = high >> 11;
240        if (isOverflowed(rBase, high >> 24)) {
241            return etc2_decode_block_T(high, low, isPunchthroughAlpha, opaque);
242        }
243        if (isOverflowed(gBase, high >> 16)) {
244            return etc2_decode_block_H(high, low, isPunchthroughAlpha, opaque);
245        }
246        if (isOverflowed(bBase, high >> 8)) {
247            return etc2_decode_block_P(high, low, isPunchthroughAlpha);
248        }
249        r1 = int(convert5To8(rBase));
250        r2 = int(convertDiff(rBase, high >> 24));
251        g1 = int(convert5To8(gBase));
252        g2 = int(convertDiff(gBase, high >> 16));
253        b1 = int(convert5To8(bBase));
254        b2 = int(convertDiff(bBase, high >> 8));
255    } else {
256        // not differential
257        r1 = int(convert4To8(high >> 28));
258        r2 = int(convert4To8(high >> 24));
259        g1 = int(convert4To8(high >> 20));
260        g2 = int(convert4To8(high >> 16));
261        b1 = int(convert4To8(high >> 12));
262        b2 = int(convert4To8(high >> 8));
263    }
264    uint tableIndexA = 7 & (high >> 5);
265    uint tableIndexB = 7 & (high >> 2);
266    ivec4 tableA;
267    ivec4 tableB;
268    if (opaque || !isPunchthroughAlpha) {
269        tableA = kRGBModifierTable[tableIndexA];
270        tableB = kRGBModifierTable[tableIndexB];
271    } else {
272        tableA = kRGBOpaqueModifierTable[tableIndexA];
273        tableB = kRGBOpaqueModifierTable[tableIndexB];
274    }
275    bool flipped = ((high & 1) != 0);
276    ivec4[16] ret;
277    decode_subblock(ret, r1, g1, b1, tableA, low, false, flipped, isPunchthroughAlpha, opaque);
278    decode_subblock(ret, r2, g2, b2, tableB, low, true, flipped, isPunchthroughAlpha, opaque);
279    return ret;
280}
281
282uint[16] eac_decode_single_channel_block(uint high, uint low, bool isSigned) {
283    int base_codeword = int(high >> 24);
284    base_codeword &= 255;
285    int multiplier = int(high >> 20);
286    multiplier &= 15;
287
288    uint tblIdx = ((high >> 16) & 15);
289    const ivec4 table0 = kAlphaModifierTable[tblIdx * 2];
290    const ivec4 table1 = kAlphaModifierTable[tblIdx * 2 + 1];
291    const uint p[16] = {
292        high >> 13, high >> 10, high >> 7, high >> 4, high >> 1, (high << 2) | (low >> 30),
293        low >> 27,  low >> 24,  low >> 21, low >> 18, low >> 15, low >> 12,
294        low >> 9,   low >> 6,   low >> 3,  low};
295    uint result[16];
296    for (uint i = 0; i < 16; i++) {
297        // flip x, y in output
298        uint outIdx = (i % 4) * 4 + i / 4;
299
300        uint modifier = (p[i] & 7);
301        int modifierValue = ((modifier >= 4) ? table1[modifier - 4] : table0[modifier]);
302        int decoded = base_codeword + modifierValue * multiplier;
303        result[outIdx] = uint(_clamp(decoded));
304    }
305    return result;
306}
307
308float[16] eac_decode_single_channel_block_float(uint high, uint low, bool isSigned) {
309    int base_codeword = int(high >> 24);
310    if (isSigned) {
311        if (base_codeword >= 128) {
312            base_codeword -= 256;
313        }
314        if (base_codeword == -128) {
315            base_codeword = -127;
316        }
317    }
318    int multiplier = int(high >> 20);
319    multiplier &= 15;
320
321    uint tblIdx = ((high >> 16) & 15);
322    const ivec4 table0 = kAlphaModifierTable[tblIdx * 2];
323    const ivec4 table1 = kAlphaModifierTable[tblIdx * 2 + 1];
324    const uint p[16] = {
325        high >> 13, high >> 10, high >> 7, high >> 4, high >> 1, (high << 2) | (low >> 30),
326        low >> 27,  low >> 24,  low >> 21, low >> 18, low >> 15, low >> 12,
327        low >> 9,   low >> 6,   low >> 3,  low};
328    float result[16];
329    for (uint i = 0; i < 16; i++) {
330        // flip x, y in output
331        uint outIdx = (i % 4) * 4 + i / 4;
332
333        uint modifier = (p[i] & 7);
334        int modifierValue = ((modifier >= 4) ? table1[modifier - 4] : table0[modifier]);
335        int decoded = base_codeword + modifierValue * multiplier;
336        decoded *= 8;
337        if (multiplier == 0) {
338            decoded += modifierValue;
339        }
340        if (isSigned) {
341            decoded = clamp(decoded, -1023, 1023);
342            result[outIdx] = float(decoded) / 1023.0;
343        } else {
344            decoded += 4;
345            decoded = clamp(decoded, 0, 2047);
346            result[outIdx] = float(decoded) / 2047.0;
347        }
348    }
349    return result;
350}
351
352uint constructUint32(uint a16, uint b16) {
353    uint a2 = (a16 & 0xff) << 8;
354    a2 |= (a16 >> 8) & 0xff;
355    uint b2 = (b16 & 0xff) << 8;
356    b2 |= (b16 >> 8) & 0xff;
357    return (a2 << 16) | b2;
358}
359
360uint flip32(uint a) {
361    return ((a & 0xff) << 24) | ((a & 0xff00) << 8) | ((a & 0xff0000) >> 8) |
362           ((a & 0xff000000) >> 24);
363}
364
365#define BLOCK_Y_SIZE_1DArray 1
366#define BLOCK_Y_SIZE_2DArray 4
367#define BLOCK_Y_SIZE_3D 4
368