ƒƒ‚# This is a combination of 2 commits. (#139)

Updated etcpak. Added ETC2A/EAC encode and EAC/ETC2A1 decode.

.
This commit is contained in:
Branimir Karadžić
2026-06-17 21:47:27 -07:00
committed by Бранимир Караџић
parent 0d3cfc25b5
commit 41c867b0a2
19 changed files with 5058 additions and 934 deletions

View File

@@ -1,719 +0,0 @@
#include <string.h>
#include "Math.hpp"
#include "ProcessCommon.hpp"
#include "ProcessRGB.hpp"
#include "Tables.hpp"
#include "Types.hpp"
#include "Vector.hpp"
#include <bx/endian.h>
#ifdef __SSE4_1__
# ifdef _MSC_VER
# include <intrin.h>
# include <Windows.h>
# else
# include <x86intrin.h>
# endif
#endif
namespace
{
typedef uint16 v4i[4];
void Average( const uint8* data, v4i* a )
{
#ifdef __SSE4_1__
__m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
__m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
__m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
__m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
__m128i d0l = _mm_unpacklo_epi8(d0, _mm_setzero_si128());
__m128i d0h = _mm_unpackhi_epi8(d0, _mm_setzero_si128());
__m128i d1l = _mm_unpacklo_epi8(d1, _mm_setzero_si128());
__m128i d1h = _mm_unpackhi_epi8(d1, _mm_setzero_si128());
__m128i d2l = _mm_unpacklo_epi8(d2, _mm_setzero_si128());
__m128i d2h = _mm_unpackhi_epi8(d2, _mm_setzero_si128());
__m128i d3l = _mm_unpacklo_epi8(d3, _mm_setzero_si128());
__m128i d3h = _mm_unpackhi_epi8(d3, _mm_setzero_si128());
__m128i sum0 = _mm_add_epi16(d0l, d1l);
__m128i sum1 = _mm_add_epi16(d0h, d1h);
__m128i sum2 = _mm_add_epi16(d2l, d3l);
__m128i sum3 = _mm_add_epi16(d2h, d3h);
__m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128());
__m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128());
__m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128());
__m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128());
__m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128());
__m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128());
__m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128());
__m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128());
__m128i b0 = _mm_add_epi32(sum0l, sum0h);
__m128i b1 = _mm_add_epi32(sum1l, sum1h);
__m128i b2 = _mm_add_epi32(sum2l, sum2h);
__m128i b3 = _mm_add_epi32(sum3l, sum3h);
__m128i a0 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b2, b3), _mm_set1_epi32(4)), 3);
__m128i a1 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b1), _mm_set1_epi32(4)), 3);
__m128i a2 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b1, b3), _mm_set1_epi32(4)), 3);
__m128i a3 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b2), _mm_set1_epi32(4)), 3);
_mm_storeu_si128((__m128i*)&a[0], _mm_packus_epi32(_mm_shuffle_epi32(a0, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a1, _MM_SHUFFLE(3, 0, 1, 2))));
_mm_storeu_si128((__m128i*)&a[2], _mm_packus_epi32(_mm_shuffle_epi32(a2, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a3, _MM_SHUFFLE(3, 0, 1, 2))));
#else
uint32 r[4];
uint32 g[4];
uint32 b[4];
memset(r, 0, sizeof(r));
memset(g, 0, sizeof(g));
memset(b, 0, sizeof(b));
for( int j=0; j<4; j++ )
{
for( int i=0; i<4; i++ )
{
int index = (j & 2) + (i >> 1);
b[index] += *data++;
g[index] += *data++;
r[index] += *data++;
data++;
}
}
a[0][0] = uint16( (r[2] + r[3] + 4) / 8 );
a[0][1] = uint16( (g[2] + g[3] + 4) / 8 );
a[0][2] = uint16( (b[2] + b[3] + 4) / 8 );
a[0][3] = 0;
a[1][0] = uint16( (r[0] + r[1] + 4) / 8 );
a[1][1] = uint16( (g[0] + g[1] + 4) / 8 );
a[1][2] = uint16( (b[0] + b[1] + 4) / 8 );
a[1][3] = 0;
a[2][0] = uint16( (r[1] + r[3] + 4) / 8 );
a[2][1] = uint16( (g[1] + g[3] + 4) / 8 );
a[2][2] = uint16( (b[1] + b[3] + 4) / 8 );
a[2][3] = 0;
a[3][0] = uint16( (r[0] + r[2] + 4) / 8 );
a[3][1] = uint16( (g[0] + g[2] + 4) / 8 );
a[3][2] = uint16( (b[0] + b[2] + 4) / 8 );
a[3][3] = 0;
#endif
}
void CalcErrorBlock( const uint8* data, uint err[4][4] )
{
#ifdef __SSE4_1__
__m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
__m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
__m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
__m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
__m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF));
__m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF));
__m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF));
__m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF));
__m128i d0l = _mm_unpacklo_epi8(dm0, _mm_setzero_si128());
__m128i d0h = _mm_unpackhi_epi8(dm0, _mm_setzero_si128());
__m128i d1l = _mm_unpacklo_epi8(dm1, _mm_setzero_si128());
__m128i d1h = _mm_unpackhi_epi8(dm1, _mm_setzero_si128());
__m128i d2l = _mm_unpacklo_epi8(dm2, _mm_setzero_si128());
__m128i d2h = _mm_unpackhi_epi8(dm2, _mm_setzero_si128());
__m128i d3l = _mm_unpacklo_epi8(dm3, _mm_setzero_si128());
__m128i d3h = _mm_unpackhi_epi8(dm3, _mm_setzero_si128());
__m128i sum0 = _mm_add_epi16(d0l, d1l);
__m128i sum1 = _mm_add_epi16(d0h, d1h);
__m128i sum2 = _mm_add_epi16(d2l, d3l);
__m128i sum3 = _mm_add_epi16(d2h, d3h);
__m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128());
__m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128());
__m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128());
__m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128());
__m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128());
__m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128());
__m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128());
__m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128());
__m128i b0 = _mm_add_epi32(sum0l, sum0h);
__m128i b1 = _mm_add_epi32(sum1l, sum1h);
__m128i b2 = _mm_add_epi32(sum2l, sum2h);
__m128i b3 = _mm_add_epi32(sum3l, sum3h);
__m128i a0 = _mm_add_epi32(b2, b3);
__m128i a1 = _mm_add_epi32(b0, b1);
__m128i a2 = _mm_add_epi32(b1, b3);
__m128i a3 = _mm_add_epi32(b0, b2);
_mm_storeu_si128((__m128i*)&err[0], a0);
_mm_storeu_si128((__m128i*)&err[1], a1);
_mm_storeu_si128((__m128i*)&err[2], a2);
_mm_storeu_si128((__m128i*)&err[3], a3);
#else
uint terr[4][4];
memset(terr, 0, 16 * sizeof(uint));
for( int j=0; j<4; j++ )
{
for( int i=0; i<4; i++ )
{
int index = (j & 2) + (i >> 1);
uint d = *data++;
terr[index][0] += d;
d = *data++;
terr[index][1] += d;
d = *data++;
terr[index][2] += d;
data++;
}
}
for( int i=0; i<3; i++ )
{
err[0][i] = terr[2][i] + terr[3][i];
err[1][i] = terr[0][i] + terr[1][i];
err[2][i] = terr[1][i] + terr[3][i];
err[3][i] = terr[0][i] + terr[2][i];
}
for( int i=0; i<4; i++ )
{
err[i][3] = 0;
}
#endif
}
uint CalcError( const uint block[4], const v4i& average )
{
uint err = 0x3FFFFFFF; // Big value to prevent negative values, but small enough to prevent overflow
err -= block[0] * 2 * average[2];
err -= block[1] * 2 * average[1];
err -= block[2] * 2 * average[0];
err += 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) );
return err;
}
void ProcessAverages( v4i* a )
{
#ifdef __SSE4_1__
for( int i=0; i<2; i++ )
{
__m128i d = _mm_loadu_si128((__m128i*)a[i*2]);
__m128i t = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(31)), _mm_set1_epi16(128));
__m128i c = _mm_srli_epi16(_mm_add_epi16(t, _mm_srli_epi16(t, 8)), 8);
__m128i c1 = _mm_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2));
__m128i diff = _mm_sub_epi16(c, c1);
diff = _mm_max_epi16(diff, _mm_set1_epi16(-4));
diff = _mm_min_epi16(diff, _mm_set1_epi16(3));
__m128i co = _mm_add_epi16(c1, diff);
c = _mm_blend_epi16(co, c, 0xF0);
__m128i a0 = _mm_or_si128(_mm_slli_epi16(c, 3), _mm_srli_epi16(c, 2));
_mm_storeu_si128((__m128i*)a[4+i*2], a0);
}
for( int i=0; i<2; i++ )
{
__m128i d = _mm_loadu_si128((__m128i*)a[i*2]);
__m128i t0 = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(15)), _mm_set1_epi16(128));
__m128i t1 = _mm_srli_epi16(_mm_add_epi16(t0, _mm_srli_epi16(t0, 8)), 8);
__m128i t2 = _mm_or_si128(t1, _mm_slli_epi16(t1, 4));
_mm_storeu_si128((__m128i*)a[i*2], t2);
}
#else
for( int i=0; i<2; i++ )
{
for( int j=0; j<3; j++ )
{
int32 c1 = mul8bit( a[i*2+1][j], 31 );
int32 c2 = mul8bit( a[i*2][j], 31 );
int32 diff = c2 - c1;
if( diff > 3 ) diff = 3;
else if( diff < -4 ) diff = -4;
int32 co = c1 + diff;
a[5+i*2][j] = ( c1 << 3 ) | ( c1 >> 2 );
a[4+i*2][j] = ( co << 3 ) | ( co >> 2 );
}
}
for( int i=0; i<4; i++ )
{
a[i][0] = g_avg2[mul8bit( a[i][0], 15 )];
a[i][1] = g_avg2[mul8bit( a[i][1], 15 )];
a[i][2] = g_avg2[mul8bit( a[i][2], 15 )];
}
#endif
}
void EncodeAverages( uint64& _d, const v4i* a, size_t idx )
{
uint64 d = _d;
d |= ( idx << 24 );
size_t base = idx << 1;
if( ( idx & 0x2 ) == 0 )
{
for( int i=0; i<3; i++ )
{
d |= uint64( a[base+0][i] >> 4 ) << ( i*8 );
d |= uint64( a[base+1][i] >> 4 ) << ( i*8 + 4 );
}
}
else
{
for( int i=0; i<3; i++ )
{
d |= uint64( a[base+1][i] & 0xF8 ) << ( i*8 );
int32 c = ( ( a[base+0][i] & 0xF8 ) - ( a[base+1][i] & 0xF8 ) ) >> 3;
c &= ~0xFFFFFFF8;
d |= ((uint64)c) << ( i*8 );
}
}
_d = d;
}
uint64 CheckSolid( const uint8* src )
{
#ifdef __SSE4_1__
__m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0);
__m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1);
__m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2);
__m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3);
__m128i c = _mm_shuffle_epi32(d0, _MM_SHUFFLE(0, 0, 0, 0));
__m128i c0 = _mm_cmpeq_epi8(d0, c);
__m128i c1 = _mm_cmpeq_epi8(d1, c);
__m128i c2 = _mm_cmpeq_epi8(d2, c);
__m128i c3 = _mm_cmpeq_epi8(d3, c);
__m128i m0 = _mm_and_si128(c0, c1);
__m128i m1 = _mm_and_si128(c2, c3);
__m128i m = _mm_and_si128(m0, m1);
if (!_mm_testc_si128(m, _mm_set1_epi32(-1)))
{
return 0;
}
#else
const uint8* ptr = src + 4;
for( int i=1; i<16; i++ )
{
if( memcmp( src, ptr, 4 ) != 0 )
{
return 0;
}
ptr += 4;
}
#endif
return 0x02000000 |
( uint( src[0] & 0xF8 ) << 16 ) |
( uint( src[1] & 0xF8 ) << 8 ) |
( uint( src[2] & 0xF8 ) );
}
void PrepareAverages( v4i a[8], const uint8* src, uint err[4] )
{
Average( src, a );
ProcessAverages( a );
uint errblock[4][4];
CalcErrorBlock( src, errblock );
for( int i=0; i<4; i++ )
{
err[i/2] += CalcError( errblock[i], a[i] );
err[2+i/2] += CalcError( errblock[i], a[i+4] );
}
}
void FindBestFit( uint64 terr[2][8], uint16 tsel[16][8], v4i a[8], const uint32* id, const uint8* data )
{
for( size_t i=0; i<16; i++ )
{
uint16* sel = tsel[i];
uint bid = id[i];
uint64* ter = terr[bid%2];
uint8 b = *data++;
uint8 g = *data++;
uint8 r = *data++;
data++;
int dr = a[bid][0] - r;
int dg = a[bid][1] - g;
int db = a[bid][2] - b;
#ifdef __SSE4_1__
// Reference implementation
__m128i pix = _mm_set1_epi32(dr * 77 + dg * 151 + db * 28);
// Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
__m128i error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[0]));
__m128i error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[1]));
__m128i error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[0]));
__m128i error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[1]));
__m128i index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1));
__m128i minError0 = _mm_min_epi32(error0, error1);
__m128i index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2));
__m128i minError1 = _mm_min_epi32(error2, error3);
__m128i minIndex0 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0));
__m128i minError = _mm_min_epi32(minError0, minError1);
// Squaring the minimum error to produce correct values when adding
__m128i minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0));
__m128i squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow);
squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0));
_mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow);
__m128i minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2));
__m128i squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh);
squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1));
_mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh);
// Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[2]));
error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[3]));
error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[2]));
error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[3]));
index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1));
minError0 = _mm_min_epi32(error0, error1);
index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2));
minError1 = _mm_min_epi32(error2, error3);
__m128i minIndex1 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0));
minError = _mm_min_epi32(minError0, minError1);
// Squaring the minimum error to produce correct values when adding
minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0));
squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow);
squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 2));
_mm_storeu_si128(((__m128i*)ter) + 2, squareErrorLow);
minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2));
squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh);
squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 3));
_mm_storeu_si128(((__m128i*)ter) + 3, squareErrorHigh);
__m128i minIndex = _mm_packs_epi32(minIndex0, minIndex1);
_mm_storeu_si128((__m128i*)sel, minIndex);
#else
int pix = dr * 77 + dg * 151 + db * 28;
for( int t=0; t<8; t++ )
{
const int64* tab = g_table256[t];
uint idx = 0;
uint64 err = sq( tab[0] + pix );
for( int j=1; j<4; j++ )
{
uint64 local = sq( tab[j] + pix );
if( local < err )
{
err = local;
idx = j;
}
}
*sel++ = idx;
*ter++ += err;
}
#endif
}
}
#ifdef __SSE4_1__
// Non-reference implementation, but faster. Produces same results as the AVX2 version
void FindBestFit( uint32 terr[2][8], uint16 tsel[16][8], v4i a[8], const uint32* id, const uint8* data )
{
for( size_t i=0; i<16; i++ )
{
uint16* sel = tsel[i];
uint bid = id[i];
uint32* ter = terr[bid%2];
uint8 b = *data++;
uint8 g = *data++;
uint8 r = *data++;
data++;
int dr = a[bid][0] - r;
int dg = a[bid][1] - g;
int db = a[bid][2] - b;
// The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
// This produces slightly different results, but is significant faster
__m128i pixel = _mm_set1_epi16(dr * 38 + dg * 76 + db * 14);
__m128i pix = _mm_abs_epi16(pixel);
// Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
// Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
__m128i error0 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[0]));
__m128i error1 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[1]));
__m128i index = _mm_and_si128(_mm_cmplt_epi16(error1, error0), _mm_set1_epi16(1));
__m128i minError = _mm_min_epi16(error0, error1);
// Exploiting symmetry of the selector table and use the sign bit
// This produces slightly different results, but is needed to produce same results as AVX2 implementation
__m128i indexBit = _mm_andnot_si128(_mm_srli_epi16(pixel, 15), _mm_set1_epi8(-1));
__m128i minIndex = _mm_or_si128(index, _mm_add_epi16(indexBit, indexBit));
// Squaring the minimum error to produce correct values when adding
__m128i squareErrorLo = _mm_mullo_epi16(minError, minError);
__m128i squareErrorHi = _mm_mulhi_epi16(minError, minError);
__m128i squareErrorLow = _mm_unpacklo_epi16(squareErrorLo, squareErrorHi);
__m128i squareErrorHigh = _mm_unpackhi_epi16(squareErrorLo, squareErrorHi);
squareErrorLow = _mm_add_epi32(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0));
_mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow);
squareErrorHigh = _mm_add_epi32(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1));
_mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh);
_mm_storeu_si128((__m128i*)sel, minIndex);
}
}
#endif
uint8_t convert6(float f)
{
int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1;
return (i + 11 - ((i + 11) >> 7) - ((i + 4) >> 7)) >> 3;
}
uint8_t convert7(float f)
{
int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1;
return (i + 9 - ((i + 9) >> 8) - ((i + 6) >> 8)) >> 2;
}
std::pair<uint64, uint64> Planar(const uint8* src)
{
int32 r = 0;
int32 g = 0;
int32 b = 0;
for (int i = 0; i < 16; ++i)
{
b += src[i * 4 + 0];
g += src[i * 4 + 1];
r += src[i * 4 + 2];
}
int32 difRyz = 0;
int32 difGyz = 0;
int32 difByz = 0;
int32 difRxz = 0;
int32 difGxz = 0;
int32 difBxz = 0;
const int32 scaling[] = { -255, -85, 85, 255 };
for (int i = 0; i < 16; ++i)
{
int32 difB = (static_cast<int>(src[i * 4 + 0]) << 4) - b;
int32 difG = (static_cast<int>(src[i * 4 + 1]) << 4) - g;
int32 difR = (static_cast<int>(src[i * 4 + 2]) << 4) - r;
difRyz += difR * scaling[i % 4];
difGyz += difG * scaling[i % 4];
difByz += difB * scaling[i % 4];
difRxz += difR * scaling[i / 4];
difGxz += difG * scaling[i / 4];
difBxz += difB * scaling[i / 4];
}
const float scale = -4.0f / ((255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f);
float aR = difRxz * scale;
float aG = difGxz * scale;
float aB = difBxz * scale;
float bR = difRyz * scale;
float bG = difGyz * scale;
float bB = difByz * scale;
float dR = r * (4.0f / 16.0f);
float dG = g * (4.0f / 16.0f);
float dB = b * (4.0f / 16.0f);
// calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y;
float cofR = (aR * 255.0f + (bR * 255.0f + dR));
float cofG = (aG * 255.0f + (bG * 255.0f + dG));
float cofB = (aB * 255.0f + (bB * 255.0f + dB));
float chfR = (aR * -425.0f + (bR * 255.0f + dR));
float chfG = (aG * -425.0f + (bG * 255.0f + dG));
float chfB = (aB * -425.0f + (bB * 255.0f + dB));
float cvfR = (aR * 255.0f + (bR * -425.0f + dR));
float cvfG = (aG * 255.0f + (bG * -425.0f + dG));
float cvfB = (aB * 255.0f + (bB * -425.0f + dB));
// convert to r6g7b6
int32 coR = convert6(cofR);
int32 coG = convert7(cofG);
int32 coB = convert6(cofB);
int32 chR = convert6(chfR);
int32 chG = convert7(chfG);
int32 chB = convert6(chfB);
int32 cvR = convert6(cvfR);
int32 cvG = convert7(cvfG);
int32 cvB = convert6(cvfB);
// Error calculation
int32 ro0 = coR;
int32 go0 = coG;
int32 bo0 = coB;
int32 ro1 = (ro0 >> 4) | (ro0 << 2);
int32 go1 = (go0 >> 6) | (go0 << 1);
int32 bo1 = (bo0 >> 4) | (bo0 << 2);
int32 ro2 = (ro1 << 2) + 2;
int32 go2 = (go1 << 2) + 2;
int32 bo2 = (bo1 << 2) + 2;
int32 rh0 = chR;
int32 gh0 = chG;
int32 bh0 = chB;
int32 rh1 = (rh0 >> 4) | (rh0 << 2);
int32 gh1 = (gh0 >> 6) | (gh0 << 1);
int32 bh1 = (bh0 >> 4) | (bh0 << 2);
int32 rh2 = rh1 - ro1;
int32 gh2 = gh1 - go1;
int32 bh2 = bh1 - bo1;
int32 rv0 = cvR;
int32 gv0 = cvG;
int32 bv0 = cvB;
int32 rv1 = (rv0 >> 4) | (rv0 << 2);
int32 gv1 = (gv0 >> 6) | (gv0 << 1);
int32 bv1 = (bv0 >> 4) | (bv0 << 2);
int32 rv2 = rv1 - ro1;
int32 gv2 = gv1 - go1;
int32 bv2 = bv1 - bo1;
uint64 error = 0;
for (int i = 0; i < 16; ++i)
{
int32 cR = clampu8((rh2 * (i / 4) + rv2 * (i % 4) + ro2) >> 2);
int32 cG = clampu8((gh2 * (i / 4) + gv2 * (i % 4) + go2) >> 2);
int32 cB = clampu8((bh2 * (i / 4) + bv2 * (i % 4) + bo2) >> 2);
int32 difB = static_cast<int>(src[i * 4 + 0]) - cB;
int32 difG = static_cast<int>(src[i * 4 + 1]) - cG;
int32 difR = static_cast<int>(src[i * 4 + 2]) - cR;
int32 dif = difR * 38 + difG * 76 + difB * 14;
error += dif * dif;
}
/**/
uint32 rgbv = cvB | (cvG << 6) | (cvR << 13);
uint32 rgbh = chB | (chG << 6) | (chR << 13);
uint32 hi = rgbv | ((rgbh & 0x1FFF) << 19);
uint32 lo = (chR & 0x1) | 0x2 | ((chR << 1) & 0x7C);
lo |= ((coB & 0x07) << 7) | ((coB & 0x18) << 8) | ((coB & 0x20) << 11);
lo |= ((coG & 0x3F) << 17) | ((coG & 0x40) << 18);
lo |= coR << 25;
const int32 idx = (coR & 0x20) | ((coG & 0x20) >> 1) | ((coB & 0x1E) >> 1);
lo |= g_flags[idx];
uint64 result = static_cast<uint32>(bx::endianSwap(lo));
result |= static_cast<uint64>(static_cast<uint32>(bx::endianSwap(hi))) << 32;
return std::make_pair(result, error);
}
template<class T, class S>
uint64 EncodeSelectors( uint64 d, const T terr[2][8], const S tsel[16][8], const uint32* id, const uint64 value, const uint64 error)
{
size_t tidx[2];
tidx[0] = GetLeastError( terr[0], 8 );
tidx[1] = GetLeastError( terr[1], 8 );
if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error)
{
return value;
}
d |= tidx[0] << 26;
d |= tidx[1] << 29;
for( int i=0; i<16; i++ )
{
uint64 t = tsel[i][tidx[id[i]%2]];
d |= ( t & 0x1 ) << ( i + 32 );
d |= ( t & 0x2 ) << ( i + 47 );
}
return FixByteOrder(d);
}
}
uint64 ProcessRGB( const uint8* src )
{
uint64 d = CheckSolid( src );
if( d != 0 ) return d;
v4i a[8];
uint err[4] = {};
PrepareAverages( a, src, err );
size_t idx = GetLeastError( err, 4 );
EncodeAverages( d, a, idx );
#if defined __SSE4_1__ && !defined REFERENCE_IMPLEMENTATION
uint32 terr[2][8] = {};
#else
uint64 terr[2][8] = {};
#endif
uint16 tsel[16][8];
const uint32* id = g_id[idx];
FindBestFit( terr, tsel, a, id, src );
return FixByteOrder( EncodeSelectors( d, terr, tsel, id ) );
}
uint64 ProcessRGB_ETC2( const uint8* src )
{
std::pair<uint64, uint64> result = Planar( src );
uint64 d = 0;
v4i a[8];
uint err[4] = {};
PrepareAverages( a, src, err );
size_t idx = GetLeastError( err, 4 );
EncodeAverages( d, a, idx );
uint64 terr[2][8] = {};
uint16 tsel[16][8];
const uint32* id = g_id[idx];
FindBestFit( terr, tsel, a, id, src );
return EncodeSelectors( d, terr, tsel, id, result.first, result.second );
}

View File

@@ -1,9 +0,0 @@
#ifndef __PROCESSRGB_HPP__
#define __PROCESSRGB_HPP__
#include "Types.hpp"
uint64 ProcessRGB( const uint8* src );
uint64 ProcessRGB_ETC2( const uint8* src );
#endif

View File

@@ -1,109 +0,0 @@
#include "Tables.hpp"
const int32 g_table[8][4] = {
{ 2, 8, -2, -8 },
{ 5, 17, -5, -17 },
{ 9, 29, -9, -29 },
{ 13, 42, -13, -42 },
{ 18, 60, -18, -60 },
{ 24, 80, -24, -80 },
{ 33, 106, -33, -106 },
{ 47, 183, -47, -183 }
};
const int64 g_table256[8][4] = {
{ 2*256, 8*256, -2*256, -8*256 },
{ 5*256, 17*256, -5*256, -17*256 },
{ 9*256, 29*256, -9*256, -29*256 },
{ 13*256, 42*256, -13*256, -42*256 },
{ 18*256, 60*256, -18*256, -60*256 },
{ 24*256, 80*256, -24*256, -80*256 },
{ 33*256, 106*256, -33*256, -106*256 },
{ 47*256, 183*256, -47*256, -183*256 }
};
const uint32 g_id[4][16] = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2 },
{ 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6 }
};
const uint32 g_avg2[16] = {
0x00,
0x11,
0x22,
0x33,
0x44,
0x55,
0x66,
0x77,
0x88,
0x99,
0xAA,
0xBB,
0xCC,
0xDD,
0xEE,
0xFF
};
const uint32 g_flags[64] = {
0x80800402, 0x80800402, 0x80800402, 0x80800402,
0x80800402, 0x80800402, 0x80800402, 0x8080E002,
0x80800402, 0x80800402, 0x8080E002, 0x8080E002,
0x80800402, 0x8080E002, 0x8080E002, 0x8080E002,
0x80000402, 0x80000402, 0x80000402, 0x80000402,
0x80000402, 0x80000402, 0x80000402, 0x8000E002,
0x80000402, 0x80000402, 0x8000E002, 0x8000E002,
0x80000402, 0x8000E002, 0x8000E002, 0x8000E002,
0x00800402, 0x00800402, 0x00800402, 0x00800402,
0x00800402, 0x00800402, 0x00800402, 0x0080E002,
0x00800402, 0x00800402, 0x0080E002, 0x0080E002,
0x00800402, 0x0080E002, 0x0080E002, 0x0080E002,
0x00000402, 0x00000402, 0x00000402, 0x00000402,
0x00000402, 0x00000402, 0x00000402, 0x0000E002,
0x00000402, 0x00000402, 0x0000E002, 0x0000E002,
0x00000402, 0x0000E002, 0x0000E002, 0x0000E002
};
#ifdef __SSE4_1__
const uint8 g_flags_AVX2[64] =
{
0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x7D,
0x63, 0x63, 0x7D, 0x7D,
0x63, 0x7D, 0x7D, 0x7D,
0x43, 0x43, 0x43, 0x43,
0x43, 0x43, 0x43, 0x5D,
0x43, 0x43, 0x5D, 0x5D,
0x43, 0x5D, 0x5D, 0x5D,
0x23, 0x23, 0x23, 0x23,
0x23, 0x23, 0x23, 0x3D,
0x23, 0x23, 0x3D, 0x3D,
0x23, 0x3D, 0x3D, 0x3D,
0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x1D,
0x03, 0x03, 0x1D, 0x1D,
0x03, 0x1D, 0x1D, 0x1D,
};
const __m128i g_table_SIMD[2] =
{
_mm_setr_epi16( 2, 5, 9, 13, 18, 24, 33, 47),
_mm_setr_epi16( 8, 17, 29, 42, 60, 80, 106, 183)
};
const __m128i g_table128_SIMD[2] =
{
_mm_setr_epi16( 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128),
_mm_setr_epi16( 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128)
};
const __m128i g_table256_SIMD[4] =
{
_mm_setr_epi32( 2*256, 5*256, 9*256, 13*256),
_mm_setr_epi32( 8*256, 17*256, 29*256, 42*256),
_mm_setr_epi32( 18*256, 24*256, 33*256, 47*256),
_mm_setr_epi32( 60*256, 80*256, 106*256, 183*256)
};
#endif

View File

@@ -1,25 +0,0 @@
#ifndef __TABLES_HPP__
#define __TABLES_HPP__
#include "Types.hpp"
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
extern const int32 g_table[8][4];
extern const int64 g_table256[8][4];
extern const uint32 g_id[4][16];
extern const uint32 g_avg2[16];
extern const uint32 g_flags[64];
#ifdef __SSE4_1__
extern const uint8 g_flags_AVX2[64];
extern const __m128i g_table_SIMD[2];
extern const __m128i g_table128_SIMD[2];
extern const __m128i g_table256_SIMD[4];
#endif
#endif

View File

@@ -1,17 +0,0 @@
#ifndef __DARKRL__TYPES_HPP__
#define __DARKRL__TYPES_HPP__
#include <stdint.h>
typedef int8_t int8;
typedef uint8_t uint8;
typedef int16_t int16;
typedef uint16_t uint16;
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
typedef unsigned int uint;
#endif

120
3rdparty/etcpak/Dither.cpp vendored Normal file
View File

@@ -0,0 +1,120 @@
#include <algorithm>
#include <string.h>
#include "Dither.hpp"
#include "Math.hpp"
#ifdef __SSE4_1__
# ifdef _MSC_VER
# include <intrin.h>
# include <Windows.h>
# else
# include <x86intrin.h>
# endif
#endif
#ifdef __AVX2__
void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
{
static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 };
static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 };
static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 };
static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 };
const __m256i BayerAdd0 = _mm256_setr_epi8(
a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0,
a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0
);
const __m256i BayerAdd1 = _mm256_setr_epi8(
a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0,
a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0
);
const __m256i BayerSub0 = _mm256_setr_epi8(
s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0,
s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0
);
const __m256i BayerSub1 = _mm256_setr_epi8(
s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0,
s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0
);
__m256i l0 = _mm256_inserti128_si256( _mm256_castsi128_si256( px0 ), px1, 1 );
__m256i l1 = _mm256_inserti128_si256( _mm256_castsi128_si256( px2 ), px3, 1 );
__m256i a0 = _mm256_adds_epu8( l0, BayerAdd0 );
__m256i a1 = _mm256_adds_epu8( l1, BayerAdd1 );
__m256i s0 = _mm256_subs_epu8( a0, BayerSub0 );
__m256i s1 = _mm256_subs_epu8( a1, BayerSub1 );
_mm256_storeu_si256( (__m256i*)(data ), s0 );
_mm256_storeu_si256( (__m256i*)(data+32), s1 );
}
#endif
void Dither( uint8_t* data )
{
#ifdef __AVX2__
static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 };
static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 };
static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 };
static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 };
const __m256i BayerAdd0 = _mm256_setr_epi8(
a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0,
a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0
);
const __m256i BayerAdd1 = _mm256_setr_epi8(
a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0,
a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0
);
const __m256i BayerSub0 = _mm256_setr_epi8(
s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0,
s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0
);
const __m256i BayerSub1 = _mm256_setr_epi8(
s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0,
s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0
);
__m256i px0 = _mm256_loadu_si256( (__m256i*)(data ) );
__m256i px1 = _mm256_loadu_si256( (__m256i*)(data+32) );
__m256i a0 = _mm256_adds_epu8( px0, BayerAdd0 );
__m256i a1 = _mm256_adds_epu8( px1, BayerAdd1 );
__m256i s0 = _mm256_subs_epu8( a0, BayerSub0 );
__m256i s1 = _mm256_subs_epu8( a1, BayerSub1 );
_mm256_storeu_si256( (__m256i*)(data ), s0 );
_mm256_storeu_si256( (__m256i*)(data+32), s1 );
#else
static constexpr int8_t Bayer31[16] = {
( 0-8)*2/3, ( 8-8)*2/3, ( 2-8)*2/3, (10-8)*2/3,
(12-8)*2/3, ( 4-8)*2/3, (14-8)*2/3, ( 6-8)*2/3,
( 3-8)*2/3, (11-8)*2/3, ( 1-8)*2/3, ( 9-8)*2/3,
(15-8)*2/3, ( 7-8)*2/3, (13-8)*2/3, ( 5-8)*2/3
};
static constexpr int8_t Bayer63[16] = {
( 0-8)*2/6, ( 8-8)*2/6, ( 2-8)*2/6, (10-8)*2/6,
(12-8)*2/6, ( 4-8)*2/6, (14-8)*2/6, ( 6-8)*2/6,
( 3-8)*2/6, (11-8)*2/6, ( 1-8)*2/6, ( 9-8)*2/6,
(15-8)*2/6, ( 7-8)*2/6, (13-8)*2/6, ( 5-8)*2/6
};
for( int i=0; i<16; i++ )
{
uint32_t col;
memcpy( &col, data, 4 );
uint8_t r = col & 0xFF;
uint8_t g = ( col >> 8 ) & 0xFF;
uint8_t b = ( col >> 16 ) & 0xFF;
r = clampu8( r + Bayer31[i] );
g = clampu8( g + Bayer63[i] );
b = clampu8( b + Bayer31[i] );
col = r | ( g << 8 ) | ( b << 16 );
memcpy( data, &col, 4 );
data += 4;
}
#endif
}

21
3rdparty/etcpak/Dither.hpp vendored Normal file
View File

@@ -0,0 +1,21 @@
#ifndef __DITHER_HPP__
#define __DITHER_HPP__
#include <stddef.h>
#include <stdint.h>
#ifdef __AVX2__
# ifdef _MSC_VER
# include <intrin.h>
# else
# include <x86intrin.h>
# endif
#endif
void Dither( uint8_t* data );
#ifdef __AVX2__
void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 );
#endif
#endif

20
3rdparty/etcpak/ForceInline.hpp vendored Normal file
View File

@@ -0,0 +1,20 @@
#ifndef __FORCEINLINE_HPP__
#define __FORCEINLINE_HPP__
#if defined(__GNUC__)
# define etcpak_force_inline __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
# define etcpak_force_inline __forceinline
#else
# define etcpak_force_inline inline
#endif
#if defined(__GNUC__)
# define etcpak_no_inline __attribute__((noinline))
#elif defined(_MSC_VER)
# define etcpak_no_inline __declspec(noinline)
#else
# define etcpak_no_inline
#endif
#endif

View File

@@ -1,4 +1,6 @@
Copyright (c) 2013, Bartosz Taudul <wolf.pld@gmail.com>
etcpak, an extremely fast ETC compression utility (https://github.com/wolfpld/etcpak)
Copyright (c) 2013-2026, Bartosz Taudul <wolf@nereid.pl>
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -2,12 +2,13 @@
#define __DARKRL__MATH_HPP__
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stdint.h>
#include "Types.hpp"
#include "ForceInline.hpp"
template<typename T>
inline T AlignPOT( T val )
static etcpak_force_inline T AlignPOT( T val )
{
if( val == 0 ) return 1;
val--;
@@ -18,7 +19,7 @@ inline T AlignPOT( T val )
return val + 1;
}
inline int CountSetBits( uint32 val )
static etcpak_force_inline int CountSetBits( uint32_t val )
{
val -= ( val >> 1 ) & 0x55555555;
val = ( ( val >> 2 ) & 0x33333333 ) + ( val & 0x33333333 );
@@ -28,7 +29,7 @@ inline int CountSetBits( uint32 val )
return val & 0x0000003f;
}
inline int CountLeadingZeros( uint32 val )
static etcpak_force_inline int CountLeadingZeros( uint32_t val )
{
val |= val >> 1;
val |= val >> 2;
@@ -38,7 +39,7 @@ inline int CountLeadingZeros( uint32 val )
return 32 - CountSetBits( val );
}
inline float sRGB2linear( float v )
static etcpak_force_inline float sRGB2linear( float v )
{
const float a = 0.055f;
if( v <= 0.04045f )
@@ -47,11 +48,11 @@ inline float sRGB2linear( float v )
}
else
{
return powf( ( v + a ) / ( 1 + a ), 2.4f );
return pow( ( v + a ) / ( 1 + a ), 2.4f );
}
}
inline float linear2sRGB( float v )
static etcpak_force_inline float linear2sRGB( float v )
{
const float a = 0.055f;
if( v <= 0.0031308f )
@@ -65,23 +66,24 @@ inline float linear2sRGB( float v )
}
template<class T>
inline T SmoothStep( T x )
static etcpak_force_inline T SmoothStep( T x )
{
return x*x*(3-2*x);
}
inline uint8 clampu8( int32 val )
static etcpak_force_inline uint8_t clampu8( int32_t val )
{
return std::min( std::max( 0, val ), 255 );
if( ( val & ~0xFF ) == 0 ) return val;
return ( ( ~val ) >> 31 ) & 0xFF;
}
template<class T>
inline T sq( T val )
static etcpak_force_inline T sq( T val )
{
return val * val;
}
static inline int mul8bit( int a, int b )
static etcpak_force_inline int mul8bit( int a, int b )
{
int t = a*b + 128;
return ( t + ( t >> 8 ) ) >> 8;

View File

@@ -3,8 +3,7 @@
#include <assert.h>
#include <stddef.h>
#include "Types.hpp"
#include <stdint.h>
template<class T>
static size_t GetLeastError( const T* err, size_t num )
@@ -20,7 +19,7 @@ static size_t GetLeastError( const T* err, size_t num )
return idx;
}
static uint64 FixByteOrder( uint64 d )
static uint64_t FixByteOrder( uint64_t d )
{
return ( ( d & 0x00000000FFFFFFFF ) ) |
( ( d & 0xFF00000000000000 ) >> 24 ) |
@@ -30,7 +29,7 @@ static uint64 FixByteOrder( uint64 d )
}
template<class T, class S>
static uint64 EncodeSelectors( uint64 d, const T terr[2][8], const S tsel[16][8], const uint32* id )
static uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id )
{
size_t tidx[2];
tidx[0] = GetLeastError( terr[0], 8 );
@@ -40,7 +39,7 @@ static uint64 EncodeSelectors( uint64 d, const T terr[2][8], const S tsel[16][8]
d |= tidx[1] << 29;
for( int i=0; i<16; i++ )
{
uint64 t = tsel[i][tidx[id[i]%2]];
uint64_t t = tsel[i][tidx[id[i]%2]];
d |= ( t & 0x1 ) << ( i + 32 );
d |= ( t & 0x2 ) << ( i + 47 );
}

4210
3rdparty/etcpak/ProcessRGB.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

14
3rdparty/etcpak/ProcessRGB.hpp vendored Normal file
View File

@@ -0,0 +1,14 @@
#ifndef __PROCESSRGB_HPP__
#define __PROCESSRGB_HPP__
#include <stdint.h>
void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width, bool useHeuristics );
void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width, bool useHeuristics );
void CompressEacR( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
void CompressEacRg( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
#endif

223
3rdparty/etcpak/Tables.cpp vendored Normal file
View File

@@ -0,0 +1,223 @@
#include "Tables.hpp"
const int32_t g_table[8][4] = {
{ 2, 8, -2, -8 },
{ 5, 17, -5, -17 },
{ 9, 29, -9, -29 },
{ 13, 42, -13, -42 },
{ 18, 60, -18, -60 },
{ 24, 80, -24, -80 },
{ 33, 106, -33, -106 },
{ 47, 183, -47, -183 }
};
const int64_t g_table256[8][4] = {
{ 2*256, 8*256, -2*256, -8*256 },
{ 5*256, 17*256, -5*256, -17*256 },
{ 9*256, 29*256, -9*256, -29*256 },
{ 13*256, 42*256, -13*256, -42*256 },
{ 18*256, 60*256, -18*256, -60*256 },
{ 24*256, 80*256, -24*256, -80*256 },
{ 33*256, 106*256, -33*256, -106*256 },
{ 47*256, 183*256, -47*256, -183*256 }
};
const uint32_t g_id[4][16] = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2 },
{ 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4 },
{ 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6 }
};
const uint32_t g_avg2[16] = {
0x00,
0x11,
0x22,
0x33,
0x44,
0x55,
0x66,
0x77,
0x88,
0x99,
0xAA,
0xBB,
0xCC,
0xDD,
0xEE,
0xFF
};
const uint32_t g_flags[64] = {
0x80800402, 0x80800402, 0x80800402, 0x80800402,
0x80800402, 0x80800402, 0x80800402, 0x8080E002,
0x80800402, 0x80800402, 0x8080E002, 0x8080E002,
0x80800402, 0x8080E002, 0x8080E002, 0x8080E002,
0x80000402, 0x80000402, 0x80000402, 0x80000402,
0x80000402, 0x80000402, 0x80000402, 0x8000E002,
0x80000402, 0x80000402, 0x8000E002, 0x8000E002,
0x80000402, 0x8000E002, 0x8000E002, 0x8000E002,
0x00800402, 0x00800402, 0x00800402, 0x00800402,
0x00800402, 0x00800402, 0x00800402, 0x0080E002,
0x00800402, 0x00800402, 0x0080E002, 0x0080E002,
0x00800402, 0x0080E002, 0x0080E002, 0x0080E002,
0x00000402, 0x00000402, 0x00000402, 0x00000402,
0x00000402, 0x00000402, 0x00000402, 0x0000E002,
0x00000402, 0x00000402, 0x0000E002, 0x0000E002,
0x00000402, 0x0000E002, 0x0000E002, 0x0000E002
};
const int32_t g_alpha[16][8] = {
{ -3, -6, -9, -15, 2, 5, 8, 14 },
{ -3, -7, -10, -13, 2, 6, 9, 12 },
{ -2, -5, -8, -13, 1, 4, 7, 12 },
{ -2, -4, -6, -13, 1, 3, 5, 12 },
{ -3, -6, -8, -12, 2, 5, 7, 11 },
{ -3, -7, -9, -11, 2, 6, 8, 10 },
{ -4, -7, -8, -11, 3, 6, 7, 10 },
{ -3, -5, -8, -11, 2, 4, 7, 10 },
{ -2, -6, -8, -10, 1, 5, 7, 9 },
{ -2, -5, -8, -10, 1, 4, 7, 9 },
{ -2, -4, -8, -10, 1, 3, 7, 9 },
{ -2, -5, -7, -10, 1, 4, 6, 9 },
{ -3, -4, -7, -10, 2, 3, 6, 9 },
{ -1, -2, -3, -10, 0, 1, 2, 9 },
{ -4, -6, -8, -9, 3, 5, 7, 8 },
{ -3, -5, -7, -9, 2, 4, 6, 8 }
};
const int32_t g_alpha11Mul[16] = { 1, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 };
const int32_t g_alphaRange[16] = {
0x100FF / ( 1 + g_alpha[0][7] - g_alpha[0][3] ),
0x100FF / ( 1 + g_alpha[1][7] - g_alpha[1][3] ),
0x100FF / ( 1 + g_alpha[2][7] - g_alpha[2][3] ),
0x100FF / ( 1 + g_alpha[3][7] - g_alpha[3][3] ),
0x100FF / ( 1 + g_alpha[4][7] - g_alpha[4][3] ),
0x100FF / ( 1 + g_alpha[5][7] - g_alpha[5][3] ),
0x100FF / ( 1 + g_alpha[6][7] - g_alpha[6][3] ),
0x100FF / ( 1 + g_alpha[7][7] - g_alpha[7][3] ),
0x100FF / ( 1 + g_alpha[8][7] - g_alpha[8][3] ),
0x100FF / ( 1 + g_alpha[9][7] - g_alpha[9][3] ),
0x100FF / ( 1 + g_alpha[10][7] - g_alpha[10][3] ),
0x100FF / ( 1 + g_alpha[11][7] - g_alpha[11][3] ),
0x100FF / ( 1 + g_alpha[12][7] - g_alpha[12][3] ),
0x100FF / ( 1 + g_alpha[13][7] - g_alpha[13][3] ),
0x100FF / ( 1 + g_alpha[14][7] - g_alpha[14][3] ),
0x100FF / ( 1 + g_alpha[15][7] - g_alpha[15][3] ),
};
#ifdef __SSE4_1__
const __m128i g_table_SIMD[2] =
{
_mm_setr_epi16( 2, 5, 9, 13, 18, 24, 33, 47),
_mm_setr_epi16( 8, 17, 29, 42, 60, 80, 106, 183)
};
const __m128i g_table128_SIMD[2] =
{
_mm_setr_epi16( 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128),
_mm_setr_epi16( 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128)
};
const __m128i g_table256_SIMD[4] =
{
_mm_setr_epi32( 2*256, 5*256, 9*256, 13*256),
_mm_setr_epi32( 8*256, 17*256, 29*256, 42*256),
_mm_setr_epi32( 18*256, 24*256, 33*256, 47*256),
_mm_setr_epi32( 60*256, 80*256, 106*256, 183*256)
};
const __m128i g_alpha_SIMD[16] = {
_mm_setr_epi16( g_alpha[ 0][0], g_alpha[ 0][1], g_alpha[ 0][2], g_alpha[ 0][3], g_alpha[ 0][4], g_alpha[ 0][5], g_alpha[ 0][6], g_alpha[ 0][7] ),
_mm_setr_epi16( g_alpha[ 1][0], g_alpha[ 1][1], g_alpha[ 1][2], g_alpha[ 1][3], g_alpha[ 1][4], g_alpha[ 1][5], g_alpha[ 1][6], g_alpha[ 1][7] ),
_mm_setr_epi16( g_alpha[ 2][0], g_alpha[ 2][1], g_alpha[ 2][2], g_alpha[ 2][3], g_alpha[ 2][4], g_alpha[ 2][5], g_alpha[ 2][6], g_alpha[ 2][7] ),
_mm_setr_epi16( g_alpha[ 3][0], g_alpha[ 3][1], g_alpha[ 3][2], g_alpha[ 3][3], g_alpha[ 3][4], g_alpha[ 3][5], g_alpha[ 3][6], g_alpha[ 3][7] ),
_mm_setr_epi16( g_alpha[ 4][0], g_alpha[ 4][1], g_alpha[ 4][2], g_alpha[ 4][3], g_alpha[ 4][4], g_alpha[ 4][5], g_alpha[ 4][6], g_alpha[ 4][7] ),
_mm_setr_epi16( g_alpha[ 5][0], g_alpha[ 5][1], g_alpha[ 5][2], g_alpha[ 5][3], g_alpha[ 5][4], g_alpha[ 5][5], g_alpha[ 5][6], g_alpha[ 5][7] ),
_mm_setr_epi16( g_alpha[ 6][0], g_alpha[ 6][1], g_alpha[ 6][2], g_alpha[ 6][3], g_alpha[ 6][4], g_alpha[ 6][5], g_alpha[ 6][6], g_alpha[ 6][7] ),
_mm_setr_epi16( g_alpha[ 7][0], g_alpha[ 7][1], g_alpha[ 7][2], g_alpha[ 7][3], g_alpha[ 7][4], g_alpha[ 7][5], g_alpha[ 7][6], g_alpha[ 7][7] ),
_mm_setr_epi16( g_alpha[ 8][0], g_alpha[ 8][1], g_alpha[ 8][2], g_alpha[ 8][3], g_alpha[ 8][4], g_alpha[ 8][5], g_alpha[ 8][6], g_alpha[ 8][7] ),
_mm_setr_epi16( g_alpha[ 9][0], g_alpha[ 9][1], g_alpha[ 9][2], g_alpha[ 9][3], g_alpha[ 9][4], g_alpha[ 9][5], g_alpha[ 9][6], g_alpha[ 9][7] ),
_mm_setr_epi16( g_alpha[10][0], g_alpha[10][1], g_alpha[10][2], g_alpha[10][3], g_alpha[10][4], g_alpha[10][5], g_alpha[10][6], g_alpha[10][7] ),
_mm_setr_epi16( g_alpha[11][0], g_alpha[11][1], g_alpha[11][2], g_alpha[11][3], g_alpha[11][4], g_alpha[11][5], g_alpha[11][6], g_alpha[11][7] ),
_mm_setr_epi16( g_alpha[12][0], g_alpha[12][1], g_alpha[12][2], g_alpha[12][3], g_alpha[12][4], g_alpha[12][5], g_alpha[12][6], g_alpha[12][7] ),
_mm_setr_epi16( g_alpha[13][0], g_alpha[13][1], g_alpha[13][2], g_alpha[13][3], g_alpha[13][4], g_alpha[13][5], g_alpha[13][6], g_alpha[13][7] ),
_mm_setr_epi16( g_alpha[14][0], g_alpha[14][1], g_alpha[14][2], g_alpha[14][3], g_alpha[14][4], g_alpha[14][5], g_alpha[14][6], g_alpha[14][7] ),
_mm_setr_epi16( g_alpha[15][0], g_alpha[15][1], g_alpha[15][2], g_alpha[15][3], g_alpha[15][4], g_alpha[15][5], g_alpha[15][6], g_alpha[15][7] ),
};
const __m128i g_alphaRange_SIMD = _mm_setr_epi16(
g_alphaRange[0],
g_alphaRange[1],
g_alphaRange[4],
g_alphaRange[5],
g_alphaRange[8],
g_alphaRange[14],
0,
0 );
#endif
#ifdef __AVX2__
const __m256i g_alpha_AVX[8] = {
_mm256_setr_epi16( g_alpha[ 0][0], g_alpha[ 1][0], g_alpha[ 2][0], g_alpha[ 3][0], g_alpha[ 4][0], g_alpha[ 5][0], g_alpha[ 6][0], g_alpha[ 7][0], g_alpha[ 8][0], g_alpha[ 9][0], g_alpha[10][0], g_alpha[11][0], g_alpha[12][0], g_alpha[13][0], g_alpha[14][0], g_alpha[15][0] ),
_mm256_setr_epi16( g_alpha[ 0][1], g_alpha[ 1][1], g_alpha[ 2][1], g_alpha[ 3][1], g_alpha[ 4][1], g_alpha[ 5][1], g_alpha[ 6][1], g_alpha[ 7][1], g_alpha[ 8][1], g_alpha[ 9][1], g_alpha[10][1], g_alpha[11][1], g_alpha[12][1], g_alpha[13][1], g_alpha[14][1], g_alpha[15][1] ),
_mm256_setr_epi16( g_alpha[ 0][2], g_alpha[ 1][2], g_alpha[ 2][2], g_alpha[ 3][2], g_alpha[ 4][2], g_alpha[ 5][2], g_alpha[ 6][2], g_alpha[ 7][2], g_alpha[ 8][2], g_alpha[ 9][2], g_alpha[10][2], g_alpha[11][2], g_alpha[12][2], g_alpha[13][2], g_alpha[14][2], g_alpha[15][2] ),
_mm256_setr_epi16( g_alpha[ 0][3], g_alpha[ 1][3], g_alpha[ 2][3], g_alpha[ 3][3], g_alpha[ 4][3], g_alpha[ 5][3], g_alpha[ 6][3], g_alpha[ 7][3], g_alpha[ 8][3], g_alpha[ 9][3], g_alpha[10][3], g_alpha[11][3], g_alpha[12][3], g_alpha[13][3], g_alpha[14][3], g_alpha[15][3] ),
_mm256_setr_epi16( g_alpha[ 0][4], g_alpha[ 1][4], g_alpha[ 2][4], g_alpha[ 3][4], g_alpha[ 4][4], g_alpha[ 5][4], g_alpha[ 6][4], g_alpha[ 7][4], g_alpha[ 8][4], g_alpha[ 9][4], g_alpha[10][4], g_alpha[11][4], g_alpha[12][4], g_alpha[13][4], g_alpha[14][4], g_alpha[15][4] ),
_mm256_setr_epi16( g_alpha[ 0][5], g_alpha[ 1][5], g_alpha[ 2][5], g_alpha[ 3][5], g_alpha[ 4][5], g_alpha[ 5][5], g_alpha[ 6][5], g_alpha[ 7][5], g_alpha[ 8][5], g_alpha[ 9][5], g_alpha[10][5], g_alpha[11][5], g_alpha[12][5], g_alpha[13][5], g_alpha[14][5], g_alpha[15][5] ),
_mm256_setr_epi16( g_alpha[ 0][6], g_alpha[ 1][6], g_alpha[ 2][6], g_alpha[ 3][6], g_alpha[ 4][6], g_alpha[ 5][6], g_alpha[ 6][6], g_alpha[ 7][6], g_alpha[ 8][6], g_alpha[ 9][6], g_alpha[10][6], g_alpha[11][6], g_alpha[12][6], g_alpha[13][6], g_alpha[14][6], g_alpha[15][6] ),
_mm256_setr_epi16( g_alpha[ 0][7], g_alpha[ 1][7], g_alpha[ 2][7], g_alpha[ 3][7], g_alpha[ 4][7], g_alpha[ 5][7], g_alpha[ 6][7], g_alpha[ 7][7], g_alpha[ 8][7], g_alpha[ 9][7], g_alpha[10][7], g_alpha[11][7], g_alpha[12][7], g_alpha[13][7], g_alpha[14][7], g_alpha[15][7] ),
};
const __m256i g_alphaRange_AVX = _mm256_setr_epi16(
g_alphaRange[ 0], g_alphaRange[ 1], g_alphaRange[ 2], g_alphaRange[ 3], g_alphaRange[ 4], g_alphaRange[ 5], g_alphaRange[ 6], g_alphaRange[ 7],
g_alphaRange[ 8], g_alphaRange[ 9], g_alphaRange[10], g_alphaRange[11], g_alphaRange[12], g_alphaRange[13], g_alphaRange[14], g_alphaRange[15]
);
#endif
#ifdef __ARM_NEON
const int16x8_t g_table128_NEON[2] =
{
{ 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128 },
{ 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128 }
};
const int32x4_t g_table256_NEON[4] =
{
{ 2*256, 5*256, 9*256, 13*256 },
{ 8*256, 17*256, 29*256, 42*256 },
{ 18*256, 24*256, 33*256, 47*256 },
{ 60*256, 80*256, 106*256, 183*256 }
};
const int16x8_t g_alpha_NEON[16] =
{
{ -3, -6, -9, -15, 2, 5, 8, 14 },
{ -3, -7, -10, -13, 2, 6, 9, 12 },
{ -2, -5, -8, -13, 1, 4, 7, 12 },
{ -2, -4, -6, -13, 1, 3, 5, 12 },
{ -3, -6, -8, -12, 2, 5, 7, 11 },
{ -3, -7, -9, -11, 2, 6, 8, 10 },
{ -4, -7, -8, -11, 3, 6, 7, 10 },
{ -3, -5, -8, -11, 2, 4, 7, 10 },
{ -2, -6, -8, -10, 1, 5, 7, 9 },
{ -2, -5, -8, -10, 1, 4, 7, 9 },
{ -2, -4, -8, -10, 1, 3, 7, 9 },
{ -2, -5, -7, -10, 1, 4, 6, 9 },
{ -3, -4, -7, -10, 2, 3, 6, 9 },
{ -1, -2, -3, -10, 0, 1, 2, 9 },
{ -4, -6, -8, -9, 3, 5, 7, 8 },
{ -3, -5, -7, -9, 2, 4, 6, 8 }
};
const int16x8_t g_alphaRange_NEON =
{
(int16_t)g_alphaRange[0],
(int16_t)g_alphaRange[1],
(int16_t)g_alphaRange[4],
(int16_t)g_alphaRange[5],
(int16_t)g_alphaRange[8],
(int16_t)g_alphaRange[14],
0,
0
};
#endif

50
3rdparty/etcpak/Tables.hpp vendored Normal file
View File

@@ -0,0 +1,50 @@
#ifndef __TABLES_HPP__
#define __TABLES_HPP__
#include <stdint.h>
#ifdef __AVX2__
# include <immintrin.h>
#endif
#ifdef __SSE4_1__
# include <smmintrin.h>
#endif
#ifdef __ARM_NEON
# include <arm_neon.h>
#endif
extern const int32_t g_table[8][4];
extern const int64_t g_table256[8][4];
extern const uint32_t g_id[4][16];
extern const uint32_t g_avg2[16];
extern const uint32_t g_flags[64];
extern const int32_t g_alpha[16][8];
extern const int32_t g_alpha11Mul[16];
extern const int32_t g_alphaRange[16];
#ifdef __SSE4_1__
extern const __m128i g_table_SIMD[2];
extern const __m128i g_table128_SIMD[2];
extern const __m128i g_table256_SIMD[4];
extern const __m128i g_alpha_SIMD[16];
extern const __m128i g_alphaRange_SIMD;
#endif
#ifdef __AVX2__
extern const __m256i g_alpha_AVX[8];
extern const __m256i g_alphaRange_AVX;
#endif
#ifdef __ARM_NEON
extern const int16x8_t g_table128_NEON[2];
extern const int32x4_t g_table256_NEON[4];
extern const int16x8_t g_alpha_NEON[16];
extern const int16x8_t g_alphaRange_NEON;
#endif
#endif

View File

@@ -4,9 +4,9 @@
#include <assert.h>
#include <algorithm>
#include <math.h>
#include <stdint.h>
#include "Math.hpp"
#include "Types.hpp"
template<class T>
struct Vector2
@@ -65,7 +65,7 @@ Vector2<T> operator/( const Vector2<T>& lhs, const T& rhs )
}
typedef Vector2<int32> v2i;
typedef Vector2<int32_t> v2i;
typedef Vector2<float> v2f;
@@ -89,8 +89,8 @@ struct Vector3
bool operator==( const Vector3<T>& rhs ) const { return x == rhs.x && y == rhs.y && z == rhs.z; }
bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); }
T& operator[]( uint idx ) { assert( idx < 3 ); return ((T*)this)[idx]; }
const T& operator[]( uint idx ) const { assert( idx < 3 ); return ((T*)this)[idx]; }
T& operator[]( unsigned int idx ) { assert( idx < 3 ); return ((T*)this)[idx]; }
const T& operator[]( unsigned int idx ) const { assert( idx < 3 ); return ((T*)this)[idx]; }
Vector3<T> operator+=( const Vector3<T>& rhs )
{
@@ -156,14 +156,14 @@ bool operator<( const Vector3<T>& lhs, const Vector3<T>& rhs )
return lhs.Luminance() < rhs.Luminance();
}
typedef Vector3<int32> v3i;
typedef Vector3<int32_t> v3i;
typedef Vector3<float> v3f;
typedef Vector3<uint8> v3b;
typedef Vector3<uint8_t> v3b;
static inline v3b v3f_to_v3b( const v3f& v )
{
return v3b( uint8( std::min( 1.f, v.x ) * 255 ), uint8( std::min( 1.f, v.y ) * 255 ), uint8( std::min( 1.f, v.z ) * 255 ) );
return v3b( uint8_t( std::min( 1.f, v.x ) * 255 ), uint8_t( std::min( 1.f, v.y ) * 255 ), uint8_t( std::min( 1.f, v.z ) * 255 ) );
}
template<class T>

View File

@@ -25,8 +25,8 @@ project "bimg_encode"
path.join(BIMG_DIR, "3rdparty/edtaa3/**.h"),
path.join(BIMG_DIR, "3rdparty/etc1/**.cpp"),
path.join(BIMG_DIR, "3rdparty/etc1/**.h"),
path.join(BIMG_DIR, "3rdparty/etc2/**.cpp"),
path.join(BIMG_DIR, "3rdparty/etc2/**.hpp"),
path.join(BIMG_DIR, "3rdparty/etcpak/**.cpp"),
path.join(BIMG_DIR, "3rdparty/etcpak/**.hpp"),
path.join(BIMG_DIR, "3rdparty/nvtt/**.cpp"),
path.join(BIMG_DIR, "3rdparty/nvtt/**.h"),
path.join(BIMG_DIR, "3rdparty/pvrtc/**.cpp"),

View File

@@ -3094,6 +3094,148 @@ namespace bimg
}
}
static const int32_t s_etc2a1Mod[8][4] =
{
{ 0, 8, 0, -8 },
{ 0, 17, 0, -17 },
{ 0, 29, 0, -29 },
{ 0, 42, 0, -42 },
{ 0, 60, 0, -60 },
{ 0, 80, 0, -80 },
{ 0, 106, 0, -106 },
{ 0, 183, 0, -183 },
};
static void decodeBlockEtc2PunchThrough(uint8_t _dst[16*4], const uint8_t _src[8])
{
uint32_t indexMsb = (_src[4]<<8) | _src[5];
uint32_t indexLsb = (_src[6]<<8) | _src[7];
for (uint32_t ii = 0; ii < 16; ++ii)
{
const uint32_t idx = (ii&0xc) | ( (ii & 0x3)<<4);
const uint32_t pixelIndex = (indexLsb & 1) | ( (indexMsb & 1)<<1);
if (2 == pixelIndex)
{
_dst[idx + 0] = 0;
_dst[idx + 1] = 0;
_dst[idx + 2] = 0;
_dst[idx + 3] = 0;
}
indexLsb >>= 1;
indexMsb >>= 1;
}
}
static void decodeBlockEtc2Rgb8A1(uint8_t _dst[16*4], const uint8_t _src[8])
{
if (!BX_ENABLED(BIMG_CONFIG_DECODE_ETC2) )
{
return;
}
const bool flipBit = 0 != (_src[3] & 0x1);
const bool opaque = 0 != (_src[3] & 0x2);
uint8_t rgb[8];
rgb[0] = _src[0] >> 3;
rgb[1] = _src[1] >> 3;
rgb[2] = _src[2] >> 3;
int8_t diff[3];
diff[0] = int8_t( (_src[0] & 0x7)<<5)>>5;
diff[1] = int8_t( (_src[1] & 0x7)<<5)>>5;
diff[2] = int8_t( (_src[2] & 0x7)<<5)>>5;
const int8_t rr = rgb[0] + diff[0];
const int8_t gg = rgb[1] + diff[1];
const int8_t bb = rgb[2] + diff[2];
if (0 > rr
|| 31 < rr)
{
decodeBlockEtc2ModeT(_dst, _src);
if (!opaque)
{
decodeBlockEtc2PunchThrough(_dst, _src);
}
return;
}
if (0 > gg
|| 31 < gg)
{
decodeBlockEtc2ModeH(_dst, _src);
if (!opaque)
{
decodeBlockEtc2PunchThrough(_dst, _src);
}
return;
}
if (0 > bb
|| 31 < bb)
{
decodeBlockEtc2ModePlanar(_dst, _src);
return;
}
rgb[0] = bitRangeConvert(rgb[0], 5, 8);
rgb[1] = bitRangeConvert(rgb[1], 5, 8);
rgb[2] = bitRangeConvert(rgb[2], 5, 8);
rgb[4] = bitRangeConvert(rr, 5, 8);
rgb[5] = bitRangeConvert(gg, 5, 8);
rgb[6] = bitRangeConvert(bb, 5, 8);
uint32_t table[2];
table[0] = (_src[3] >> 5) & 0x7;
table[1] = (_src[3] >> 2) & 0x7;
uint32_t indexMsb = (_src[4]<<8) | _src[5];
uint32_t indexLsb = (_src[6]<<8) | _src[7];
for (uint32_t ii = 0; ii < 16; ++ii)
{
const uint32_t block = flipBit
? (ii>>1)&1
: ii>>3
;
const uint32_t color = block<<2;
const uint32_t idx = (ii&0xc) | ( (ii & 0x3)<<4);
const uint32_t pixelIndex = (indexLsb & 1) | ( (indexMsb & 1)<<1);
if (!opaque
&& 2 == pixelIndex)
{
_dst[idx + 0] = 0;
_dst[idx + 1] = 0;
_dst[idx + 2] = 0;
_dst[idx + 3] = 0;
}
else
{
const int32_t mod = opaque
? s_etc1Mod [table[block] ][pixelIndex]
: s_etc2a1Mod[table[block] ][pixelIndex]
;
_dst[idx + 0] = uint8_satadd(rgb[color+2], mod);
_dst[idx + 1] = uint8_satadd(rgb[color+1], mod);
_dst[idx + 2] = uint8_satadd(rgb[color+0], mod);
_dst[idx + 3] = 255;
}
indexLsb >>= 1;
indexMsb >>= 1;
}
}
static const int8_t s_etc2aMod[16][8] =
{
{ -3, -6, -9, -15, 2, 5, 8, 14 },
@@ -3131,7 +3273,8 @@ namespace bimg
| ((uint64_t)_src[6] << 8)
| _src[7];
for (int ii = 0; ii < 16; ii++) {
for (int ii = 0; ii < 16; ii++)
{
const uint32_t idx = (ii & 0xc) | ((ii & 0x3) << 4);
const int32_t mod = modTable[(indices >> (45 - ii * 3)) & 0x7];
@@ -3139,6 +3282,48 @@ namespace bimg
}
}
template<bool SignedT>
static void decodeBlockEac(uint8_t _dst[16*4], const uint8_t _src[8], uint32_t _byteOffset)
{
if (!BX_ENABLED(BIMG_CONFIG_DECODE_ETC2) )
{
return;
}
const int32_t base = SignedT
? int32_t(int8_t(_src[0]) )
: int32_t(_src[0])
;
const int8_t* modTable = s_etc2aMod[_src[1] & 0x0f];
const int32_t mult = (_src[1] & 0xf0) >> 4;
const uint64_t indices = ( (uint64_t)_src[2] << 40)
| ( (uint64_t)_src[3] << 32)
| ( (uint64_t)_src[4] << 24)
| ( (uint64_t)_src[5] << 16)
| ( (uint64_t)_src[6] << 8)
| _src[7]
;
for (int32_t ii = 0; ii < 16; ++ii)
{
const uint32_t idx = (ii & 0xc) | ( (ii & 0x3) << 4);
const int32_t mod = modTable[(indices >> (45 - ii*3) ) & 0x7];
if (SignedT)
{
const int32_t b = (base < -127 ? -127 : base) * 8;
const int32_t value = bx::clamp(0 != mult ? b + mod*mult*8 : b + mod, -1023, 1023);
_dst[idx + _byteOffset] = uint8_t( (value + 1023)*255/2046);
}
else
{
const int32_t b = base*8 + 4;
const int32_t value = bx::clamp(0 != mult ? b + mod*mult*8 : b + mod, 0, 2047);
_dst[idx + _byteOffset] = uint8_t(value >> 3);
}
}
}
static const uint8_t s_pvrtcFactors[16][4] =
{
@@ -6027,16 +6212,118 @@ namespace bimg
break;
case TextureFormat::ETC2A1:
BX_WARN(false, "ETC2A1 decoder is not implemented.");
imageCheckerboard(_dst, _width, _height, 16, UINT32_C(0xff000000), UINT32_C(0xffff0000) );
if (BX_ENABLED(BIMG_CONFIG_DECODE_ETC2) )
{
for (uint32_t yy = 0; yy < height; ++yy)
{
for (uint32_t xx = 0; xx < width; ++xx)
{
decodeBlockEtc2Rgb8A1(temp, src);
src += 8;
uint8_t* block = &dst[yy*_dstPitch*4 + xx*16];
bx::memCopy(&block[0*_dstPitch], &temp[ 0], 16);
bx::memCopy(&block[1*_dstPitch], &temp[16], 16);
bx::memCopy(&block[2*_dstPitch], &temp[32], 16);
bx::memCopy(&block[3*_dstPitch], &temp[48], 16);
}
}
}
else
{
BX_WARN(false, "ETC2A1 decoder is disabled (BIMG_CONFIG_DECODE_ETC2).");
imageCheckerboard(_dst, _width, _height, 16, UINT32_C(0xff000000), UINT32_C(0xffff0000) );
}
break;
case TextureFormat::EACR11:
case TextureFormat::EACR11S:
if (BX_ENABLED(BIMG_CONFIG_DECODE_ETC2) )
{
const bool sign = TextureFormat::EACR11S == _srcFormat;
for (uint32_t yy = 0; yy < height; ++yy)
{
for (uint32_t xx = 0; xx < width; ++xx)
{
for (uint32_t ii = 0; ii < 16; ++ii)
{
temp[ii*4+0] = 0;
temp[ii*4+1] = 0;
temp[ii*4+2] = 0;
temp[ii*4+3] = 255;
}
if (sign)
{
decodeBlockEac<true >(temp, src, 2);
}
else
{
decodeBlockEac<false>(temp, src, 2);
}
src += 8;
uint8_t* block = &dst[yy*_dstPitch*4 + xx*16];
bx::memCopy(&block[0*_dstPitch], &temp[ 0], 16);
bx::memCopy(&block[1*_dstPitch], &temp[16], 16);
bx::memCopy(&block[2*_dstPitch], &temp[32], 16);
bx::memCopy(&block[3*_dstPitch], &temp[48], 16);
}
}
}
else
{
BX_WARN(false, "EAC decoder is disabled (BIMG_CONFIG_DECODE_ETC2).");
imageCheckerboard(_dst, _width, _height, 16, UINT32_C(0xff000000), UINT32_C(0xff00ffff) );
}
break;
case TextureFormat::EACRG11:
case TextureFormat::EACRG11S:
BX_WARN(false, "EAC decoder is not implemented.");
imageCheckerboard(_dst, _width, _height, 16, UINT32_C(0xff000000), UINT32_C(0xff00ffff) );
if (BX_ENABLED(BIMG_CONFIG_DECODE_ETC2) )
{
const bool sign = TextureFormat::EACRG11S == _srcFormat;
for (uint32_t yy = 0; yy < height; ++yy)
{
for (uint32_t xx = 0; xx < width; ++xx)
{
for (uint32_t ii = 0; ii < 16; ++ii)
{
temp[ii*4+0] = 0;
temp[ii*4+1] = 0;
temp[ii*4+2] = 0;
temp[ii*4+3] = 255;
}
if (sign)
{
decodeBlockEac<true >(temp, src, 2);
decodeBlockEac<true >(temp, src + 8, 1);
}
else
{
decodeBlockEac<false>(temp, src, 2);
decodeBlockEac<false>(temp, src + 8, 1);
}
src += 16;
uint8_t* block = &dst[yy*_dstPitch*4 + xx*16];
bx::memCopy(&block[0*_dstPitch], &temp[ 0], 16);
bx::memCopy(&block[1*_dstPitch], &temp[16], 16);
bx::memCopy(&block[2*_dstPitch], &temp[32], 16);
bx::memCopy(&block[3*_dstPitch], &temp[48], 16);
}
}
}
else
{
BX_WARN(false, "EAC decoder is disabled (BIMG_CONFIG_DECODE_ETC2).");
imageCheckerboard(_dst, _width, _height, 16, UINT32_C(0xff000000), UINT32_C(0xff00ffff) );
}
break;
case TextureFormat::PTC12:

View File

@@ -8,7 +8,7 @@
#include <libsquish/squish.h>
#include <etc1/etc1.h>
#include <etc2/ProcessRGB.hpp>
#include <etcpak/ProcessRGB.hpp>
#include <nvtt/nvtt.h>
#include <pvrtc/PvrTcEncoder.h>
#include <edtaa3/edtaa3func.h>
@@ -54,6 +54,48 @@ namespace bimg
};
static_assert(Quality::Count == BX_COUNTOF(s_astcQuality) );
static uint32_t* etcpakAllocBgraBlocks(
bx::AllocatorI* _allocator
, const uint8_t* _src
, uint32_t _width
, uint32_t _height
, uint32_t& _outNumBlocks
, uint32_t& _outPaddedWidth
)
{
const uint32_t blockWidth = (_width + 3)/4;
const uint32_t blockHeight = (_height + 3)/4;
const uint32_t paddedWidth = blockWidth *4;
const uint32_t paddedHeight = blockHeight*4;
const uint32_t srcPitch = _width*4;
uint32_t* bgra = (uint32_t*)bx::alloc(_allocator, paddedWidth*paddedHeight*sizeof(uint32_t) );
for (uint32_t yy = 0; yy < paddedHeight; ++yy)
{
const uint32_t sy = bx::min(yy, _height-1);
const uint8_t* srcRow = &_src[sy*srcPitch];
uint32_t* dstRow = &bgra[yy*paddedWidth];
for (uint32_t xx = 0; xx < paddedWidth; ++xx)
{
const uint32_t sx = bx::min(xx, _width-1);
const uint8_t* px = &srcRow[sx*4];
dstRow[xx] = 0
| (uint32_t(px[3])<<24) // A
| (uint32_t(px[0])<<16) // R
| (uint32_t(px[1])<< 8) // G
| (uint32_t(px[2]) ) // B
;
}
}
_outNumBlocks = blockWidth*blockHeight;
_outPaddedWidth = paddedWidth;
return bgra;
}
void imageEncodeFromRgba8(bx::AllocatorI* _allocator, void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint32_t _depth, TextureFormat::Enum _format, Quality::Enum _quality, bx::Error* _err)
{
const uint8_t* src = (const uint8_t*)_src;
@@ -89,9 +131,8 @@ namespace bimg
BX_ERROR_SET(_err, BIMG_ERROR, "Unable to convert between input/output formats!");
break;
case TextureFormat::ETC2A:
case TextureFormat::ETC2A1:
BX_ERROR_SET(_err, BIMG_ERROR, "Encoding to ETC2A/ETC2A1 is not supported.");
BX_ERROR_SET(_err, BIMG_ERROR, "Encoding to ETC2A1 is not supported.");
break;
case TextureFormat::ETC1:
@@ -100,25 +141,37 @@ namespace bimg
case TextureFormat::ETC2:
{
const uint32_t blockWidth = (_width +3)/4;
const uint32_t blockHeight = (_height+3)/4;
uint64_t* dstBlock = (uint64_t*)dst;
for (uint32_t yy = 0; yy < blockHeight; ++yy)
{
for (uint32_t xx = 0; xx < blockWidth; ++xx)
{
uint8_t block[4*4*4];
const uint8_t* ptr = &src[(yy*srcPitch+xx*4)*4];
uint32_t numBlocks, paddedWidth;
uint32_t* bgra = etcpakAllocBgraBlocks(_allocator, src, _width, _height, numBlocks, paddedWidth);
CompressEtc2Rgb(bgra, (uint64_t*)dst, numBlocks, paddedWidth, true);
bx::free(_allocator, bgra);
}
break;
for (uint32_t ii = 0; ii < 16; ++ii)
{ // BGRx
bx::memCopy(&block[ii*4], &ptr[(ii%4)*srcPitch + (ii&~3)], 4);
bx::swap(block[ii*4+0], block[ii*4+2]);
}
case TextureFormat::ETC2A:
{
uint32_t numBlocks, paddedWidth;
uint32_t* bgra = etcpakAllocBgraBlocks(_allocator, src, _width, _height, numBlocks, paddedWidth);
CompressEtc2Rgba(bgra, (uint64_t*)dst, numBlocks, paddedWidth, true);
bx::free(_allocator, bgra);
}
break;
*dstBlock++ = ProcessRGB_ETC2(block);
}
}
case TextureFormat::EACR11:
{
uint32_t numBlocks, paddedWidth;
uint32_t* bgra = etcpakAllocBgraBlocks(_allocator, src, _width, _height, numBlocks, paddedWidth);
CompressEacR(bgra, (uint64_t*)dst, numBlocks, paddedWidth);
bx::free(_allocator, bgra);
}
break;
case TextureFormat::EACRG11:
{
uint32_t numBlocks, paddedWidth;
uint32_t* bgra = etcpakAllocBgraBlocks(_allocator, src, _width, _height, numBlocks, paddedWidth);
CompressEacRg(bgra, (uint64_t*)dst, numBlocks, paddedWidth);
bx::free(_allocator, bgra);
}
break;
@@ -332,6 +385,9 @@ namespace bimg
case TextureFormat::BC5:
case TextureFormat::ETC1:
case TextureFormat::ETC2:
case TextureFormat::ETC2A:
case TextureFormat::EACR11:
case TextureFormat::EACRG11:
case TextureFormat::PTC14:
case TextureFormat::PTC14A:
case TextureFormat::ASTC4x4:
@@ -366,9 +422,8 @@ namespace bimg
}
break;
case bimg::TextureFormat::ETC2A:
case bimg::TextureFormat::ETC2A1:
BX_ERROR_SET(_err, BIMG_ERROR, "Encoding to ETC2A/ETC2A1 is not supported.");
BX_ERROR_SET(_err, BIMG_ERROR, "Encoding to ETC2A1 is not supported.");
break;
default: