// Copyright 2019 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "Common.comp" precision highp int; const uint VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147; const uint VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148; const uint VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149; const uint VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150; const uint VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151; const uint VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152; const uint VK_FORMAT_EAC_R11_UNORM_BLOCK = 153; const uint VK_FORMAT_EAC_R11_SNORM_BLOCK = 154; const uint VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155; const uint VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156; const int kLookup[8] = {0, 1, 2, 3, -4, -3, -2, -1}; const ivec4 kRGBModifierTable[] = { /* 0 */ {2, 8, -2, -8}, /* 1 */ {5, 17, -5, -17}, /* 2 */ {9, 29, -9, -29}, /* 3 */ {13, 42, -13, -42}, /* 4 */ {18, 60, -18, -60}, /* 5 */ {24, 80, -24, -80}, /* 6 */ {33, 106, -33, -106}, /* 7 */ {47, 183, -47, -183}}; const ivec4 kRGBOpaqueModifierTable[] = { /* 0 */ {0, 8, 0, -8}, /* 1 */ {0, 17, 0, -17}, /* 2 */ {0, 29, 0, -29}, /* 3 */ {0, 42, 0, -42}, /* 4 */ {0, 60, 0, -60}, /* 5 */ {0, 80, 0, -80}, /* 6 */ {0, 106, 0, -106}, /* 7 */ {0, 183, 0, -183}}; const ivec4 kAlphaModifierTable[] = { /* 0 */ {-3, -6, -9, -15}, {2, 5, 8, 14}, /* 1 */ {-3, -7, -10, -13}, {2, 6, 9, 12}, /* 2 */ {-2, -5, -8, -13}, {1, 4, 7, 12}, /* 3 */ {-2, -4, -6, -13}, {1, 3, 5, 12}, /* 4 */ {-3, -6, -8, -12}, {2, 5, 7, 11}, /* 5 */ {-3, -7, -9, -11}, {2, 6, 8, 10}, /* 6 */ {-4, -7, -8, -11}, {3, 6, 7, 10}, /* 7 */ {-3, -5, -8, -11}, {2, 4, 7, 10}, /* 8 */ {-2, -6, -8, -10}, {1, 5, 7, 9}, /* 9 */ {-2, -5, -8, -10}, {1, 4, 7, 9}, /* 10 */ {-2, -4, -8, -10}, {1, 3, 7, 9}, /* 11 */ {-2, -5, -7, -10}, {1, 4, 6, 9}, /* 12 */ {-3, -4, -7, -10}, {2, 3, 6, 9}, /* 13 */ {-1, -2, -3, -10}, {0, 1, 2, 9}, /* 14 */ {-4, -6, -8, -9}, {3, 5, 7, 8}, /* 15 */ {-3, -5, -7, -9}, {2, 4, 6, 8}}; bool isOverflowed(uint base, uint diff) { int val = int(0x1f & base) + kLookup[0x7 & diff]; return (val < 0) || (val >= 32); } uint convert4To8(uint b) { uint c = b & 0xf; return (c << 4) | c; } uint convert5To8(uint b) { uint c = b & 0x1f; return (c << 3) | (c >> 2); } uint convert6To8(uint b) { uint c = b & 0x3f; return (c << 2) | (c >> 4); } uint convert7To8(uint b) { uint c = b & 0x7f; return (c << 1) | (c >> 6); } uint convertDiff(uint base, uint diff) { return convert5To8(uint(int(0x1f & base) + kLookup[0x7 & diff])); } int _clamp(int x) { return int(clamp(x, 0, 255)); } ivec3 _clamp(ivec3 x) { return ivec3(clamp(x, 0, 255)); } ivec4[16] etc2_T_H_index(ivec3[4] clrTable, uint low, bool isPunchthroughAlpha, bool opaque) { ivec4 ret[16]; for (uint y = 0; y < 4; y++) { for (uint x = 0; x < 4; x++) { uint k = y + x * 4; uint msb = (low >> (k + 15)) & 2; uint lsb = (low >> k) & 1; if (isPunchthroughAlpha && (!opaque) && (msb != 0) && (lsb == 0)) { // rgba all 0 ret[y * 4 + x] = ivec4(0, 0, 0, 0); } else { uint offset = lsb | msb; ret[y * 4 + x] = ivec4(clrTable[offset], 255); } } } return ret; } ivec4[16] etc2_decode_block_T(uint high, uint low, bool isPunchthroughAlpha, bool opaque) { const int LUT[] = {3, 6, 11, 16, 23, 32, 41, 64}; int r1, r2, g1, g2, b1, b2; r1 = int(convert4To8((((high >> 27) & 3) << 2) | ((high >> 24) & 3))); g1 = int(convert4To8(high >> 20)); b1 = int(convert4To8(high >> 16)); r2 = int(convert4To8(high >> 12)); g2 = int(convert4To8(high >> 8)); b2 = int(convert4To8(high >> 4)); // 3 bits intense modifier int intenseIdx = int((((high >> 2) & 3) << 1) | (high & 1)); int intenseMod = LUT[intenseIdx]; ivec3 clrTable[4]; clrTable[0] = ivec3(r1, g1, b1); clrTable[1] = ivec3(_clamp(int(r2) + intenseMod), _clamp(int(g2) + intenseMod), _clamp(int(b2) + intenseMod)); clrTable[2] = ivec3(r2, g2, b2); clrTable[3] = ivec3(_clamp(int(r2) - intenseMod), _clamp(int(g2) - intenseMod), _clamp(int(b2) - intenseMod)); return etc2_T_H_index(clrTable, low, isPunchthroughAlpha, opaque); } ivec4[16] etc2_decode_block_H(uint high, uint low, bool isPunchthroughAlpha, bool opaque) { const int LUT[] = {3, 6, 11, 16, 23, 32, 41, 64}; ivec3 rgb1, rgb2; rgb1.r = int(convert4To8(high >> 27)); rgb1.g = int(convert4To8(((high >> 24) << 1) | ((high >> 20) & 1))); rgb1.b = int(convert4To8(((high >> 19) << 3) | ((high >> 15) & 7))); rgb2.r = int(convert4To8(high >> 11)); rgb2.g = int(convert4To8(high >> 7)); rgb2.b = int(convert4To8(high >> 3)); // 3 bits intense modifier uint intenseIdx = high & 4; intenseIdx |= (high & 1) << 1; intenseIdx |= uint(((rgb1.r << 16) | (rgb1.g << 8) | rgb1.b) >= ((rgb2.r << 16) | (rgb2.g << 8) | rgb2.b)); int intenseMod = LUT[intenseIdx]; ivec3 clrTable[4]; clrTable[0] = _clamp(ivec3(rgb1) + intenseMod); clrTable[1] = _clamp(ivec3(rgb1) - intenseMod); clrTable[2] = _clamp(ivec3(rgb2) + intenseMod); clrTable[3] = _clamp(ivec3(rgb2) - intenseMod); return etc2_T_H_index(clrTable, low, isPunchthroughAlpha, opaque); } ivec4[16] etc2_decode_block_P(uint high, uint low, bool isPunchthroughAlpha) { ivec3 rgbo, rgbh, rgbv; rgbo.r = int(convert6To8(high >> 25)); rgbo.g = int(convert7To8(((high >> 24) << 6) | ((high >> 17) & 63))); rgbo.b = int(convert6To8(((high >> 16) << 5) | (((high >> 11) & 3) << 3) | ((high >> 7) & 7))); rgbh.r = int(convert6To8(((high >> 2) << 1) | (high & 1))); rgbh.g = int(convert7To8(low >> 25)); rgbh.b = int(convert6To8(low >> 19)); rgbv.r = int(convert6To8(low >> 13)); rgbv.g = int(convert7To8(low >> 6)); rgbv.b = int(convert6To8(low)); ivec4 ret[16]; for (int i = 0; i < 16; i++) { int y = i >> 2; int x = i & 3; ret[i] = ivec4(_clamp((x * (rgbh - rgbo) + y * (rgbv - rgbo) + 4 * rgbo + 2) >> 2), 255); ret[i].a = 255; } return ret; } void decode_subblock(inout ivec4 pOut[16], int r, int g, int b, ivec4 table, uint low, bool second, bool flipped, bool isPunchthroughAlpha, bool opaque) { uint baseX = 0; uint baseY = 0; if (second) { if (flipped) { baseY = 2; } else { baseX = 2; } } for (int i = 0; i < 8; i++) { uint x, y; if (flipped) { x = baseX + (i >> 1); y = baseY + (i & 1); } else { x = baseX + (i >> 2); y = baseY + (i & 3); } uint k = y + (x * 4); uint msb = ((low >> (k + 15)) & 2); uint lsb = ((low >> k) & 1); uint q = x + 4 * y; if (isPunchthroughAlpha && (!opaque) && (msb != 0) && (lsb == 0)) { // rgba all 0 pOut[q] = ivec4(0, 0, 0, 0); } else { uint offset = lsb | msb; int delta = table[offset]; pOut[q] = ivec4(_clamp(int(r) + delta), _clamp(int(g) + delta), _clamp(int(b) + delta), 255); } } } ivec4[16] allZeros() { ivec4[16] ret; for (int i = 0; i < 16; i++) { ret[i] = ivec4(0); } return ret; } ivec4[16] etc2_decode_rgb_block(uint high, uint low, bool isPunchthroughAlpha) { bool opaque = (((high >> 1) & 1) != 0); int r1, r2, g1, g2, b1, b2; if (isPunchthroughAlpha || ((high & 2) != 0)) { // differntial uint rBase = high >> 27; uint gBase = high >> 19; uint bBase = high >> 11; if (isOverflowed(rBase, high >> 24)) { return etc2_decode_block_T(high, low, isPunchthroughAlpha, opaque); } if (isOverflowed(gBase, high >> 16)) { return etc2_decode_block_H(high, low, isPunchthroughAlpha, opaque); } if (isOverflowed(bBase, high >> 8)) { return etc2_decode_block_P(high, low, isPunchthroughAlpha); } r1 = int(convert5To8(rBase)); r2 = int(convertDiff(rBase, high >> 24)); g1 = int(convert5To8(gBase)); g2 = int(convertDiff(gBase, high >> 16)); b1 = int(convert5To8(bBase)); b2 = int(convertDiff(bBase, high >> 8)); } else { // not differential r1 = int(convert4To8(high >> 28)); r2 = int(convert4To8(high >> 24)); g1 = int(convert4To8(high >> 20)); g2 = int(convert4To8(high >> 16)); b1 = int(convert4To8(high >> 12)); b2 = int(convert4To8(high >> 8)); } uint tableIndexA = 7 & (high >> 5); uint tableIndexB = 7 & (high >> 2); ivec4 tableA; ivec4 tableB; if (opaque || !isPunchthroughAlpha) { tableA = kRGBModifierTable[tableIndexA]; tableB = kRGBModifierTable[tableIndexB]; } else { tableA = kRGBOpaqueModifierTable[tableIndexA]; tableB = kRGBOpaqueModifierTable[tableIndexB]; } bool flipped = ((high & 1) != 0); ivec4[16] ret; decode_subblock(ret, r1, g1, b1, tableA, low, false, flipped, isPunchthroughAlpha, opaque); decode_subblock(ret, r2, g2, b2, tableB, low, true, flipped, isPunchthroughAlpha, opaque); return ret; } uint[16] eac_decode_single_channel_block(uint high, uint low, bool isSigned) { int base_codeword = int(high >> 24); base_codeword &= 255; int multiplier = int(high >> 20); multiplier &= 15; uint tblIdx = ((high >> 16) & 15); const ivec4 table0 = kAlphaModifierTable[tblIdx * 2]; const ivec4 table1 = kAlphaModifierTable[tblIdx * 2 + 1]; const uint p[16] = { high >> 13, high >> 10, high >> 7, high >> 4, high >> 1, (high << 2) | (low >> 30), low >> 27, low >> 24, low >> 21, low >> 18, low >> 15, low >> 12, low >> 9, low >> 6, low >> 3, low}; uint result[16]; for (uint i = 0; i < 16; i++) { // flip x, y in output uint outIdx = (i % 4) * 4 + i / 4; uint modifier = (p[i] & 7); int modifierValue = ((modifier >= 4) ? table1[modifier - 4] : table0[modifier]); int decoded = base_codeword + modifierValue * multiplier; result[outIdx] = uint(_clamp(decoded)); } return result; } float[16] eac_decode_single_channel_block_float(uint high, uint low, bool isSigned) { int base_codeword = int(high >> 24); if (isSigned) { if (base_codeword >= 128) { base_codeword -= 256; } if (base_codeword == -128) { base_codeword = -127; } } int multiplier = int(high >> 20); multiplier &= 15; uint tblIdx = ((high >> 16) & 15); const ivec4 table0 = kAlphaModifierTable[tblIdx * 2]; const ivec4 table1 = kAlphaModifierTable[tblIdx * 2 + 1]; const uint p[16] = { high >> 13, high >> 10, high >> 7, high >> 4, high >> 1, (high << 2) | (low >> 30), low >> 27, low >> 24, low >> 21, low >> 18, low >> 15, low >> 12, low >> 9, low >> 6, low >> 3, low}; float result[16]; for (uint i = 0; i < 16; i++) { // flip x, y in output uint outIdx = (i % 4) * 4 + i / 4; uint modifier = (p[i] & 7); int modifierValue = ((modifier >= 4) ? table1[modifier - 4] : table0[modifier]); int decoded = base_codeword + modifierValue * multiplier; decoded *= 8; if (multiplier == 0) { decoded += modifierValue; } if (isSigned) { decoded = clamp(decoded, -1023, 1023); result[outIdx] = float(decoded) / 1023.0; } else { decoded += 4; decoded = clamp(decoded, 0, 2047); result[outIdx] = float(decoded) / 2047.0; } } return result; } uint constructUint32(uint a16, uint b16) { uint a2 = (a16 & 0xff) << 8; a2 |= (a16 >> 8) & 0xff; uint b2 = (b16 & 0xff) << 8; b2 |= (b16 >> 8) & 0xff; return (a2 << 16) | b2; } uint flip32(uint a) { return ((a & 0xff) << 24) | ((a & 0xff00) << 8) | ((a & 0xff0000) >> 8) | ((a & 0xff000000) >> 24); } #define BLOCK_Y_SIZE_1DArray 1 #define BLOCK_Y_SIZE_2DArray 4 #define BLOCK_Y_SIZE_3D 4