Skip to content

Commit

Permalink
SSE2 optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
elasota committed Feb 14, 2021
1 parent cacfbb3 commit 173443e
Showing 1 changed file with 120 additions and 3 deletions.
123 changes: 120 additions & 3 deletions bc7decomp.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
// File: bc7decomp.c - Richard Geldreich, Jr. 3/31/2020 - MIT license or public domain (see end of file)
#include "bc7decomp.h"

namespace bc7decomp
#if (defined(_M_AMD64) || defined(_M_X64) || defined(__SSE2__))
# define BC7DECOMP_USE_SSE2
#endif

#ifdef BC7DECOMP_USE_SSE2
#include <immintrin.h>
#include <emmintrin.h>
#endif

namespace bc7decomp
{

#ifdef BC7DECOMP_USE_SSE2
const __m128i g_bc7_weights4_sse2[8] =
{
_mm_set_epi16(4, 4, 4, 4, 0, 0, 0, 0),
_mm_set_epi16(13, 13, 13, 13, 9, 9, 9, 9),
_mm_set_epi16(21, 21, 21, 21, 17, 17, 17, 17),
_mm_set_epi16(30, 30, 30, 30, 26, 26, 26, 26),
_mm_set_epi16(38, 38, 38, 38, 34, 34, 34, 34),
_mm_set_epi16(47, 47, 47, 47, 43, 43, 43, 43),
_mm_set_epi16(55, 55, 55, 55, 51, 51, 51, 51),
_mm_set_epi16(64, 64, 64, 64, 60, 60, 60, 60),
};
#endif

const uint32_t g_bc7_weights2[4] = { 0, 21, 43, 64 };
const uint32_t g_bc7_weights3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 };
const uint32_t g_bc7_weights4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
Expand Down Expand Up @@ -95,6 +118,52 @@ static inline uint32_t bc7_interp(uint32_t l, uint32_t h, uint32_t w, uint32_t b
return 0;
}


#ifdef BC7DECOMP_USE_SSE2
static inline __m128i bc7_interp_sse2(__m128i l, __m128i h, __m128i w, __m128i iw)
{
return _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(l, iw), _mm_mullo_epi16(h, w)), _mm_set1_epi16(32)), 6);
}

static inline void bc7_interp2_sse2(const color_rgba* endpoint_pair, color_rgba* out_colors)
{
__m128i endpoints = _mm_loadu_si64(endpoint_pair);
__m128i endpoints_16 = _mm_unpacklo_epi8(endpoints, _mm_setzero_si128());

__m128i endpoints_16_swapped = _mm_shuffle_epi32(endpoints_16, _MM_SHUFFLE(1, 0, 3, 2));

// Interpolated colors will be color 1 and 2
__m128i interpolated_colors = bc7_interp_sse2(endpoints_16, endpoints_16_swapped, _mm_set1_epi16(21), _mm_set1_epi16(43));

// all_colors will be 1, 2, 0, 3
__m128i all_colors = _mm_packus_epi16(interpolated_colors, endpoints_16);

all_colors = _mm_shuffle_epi32(all_colors, _MM_SHUFFLE(3, 1, 0, 2));

_mm_storeu_si128(reinterpret_cast<__m128i*>(out_colors), all_colors);
}

static inline void bc7_interp3_sse2(const color_rgba* endpoint_pair, color_rgba* out_colors)
{
__m128i endpoints = _mm_loadu_si64(endpoint_pair);
__m128i endpoints_16bit = _mm_unpacklo_epi8(endpoints, _mm_setzero_si128());
__m128i endpoints_16bit_swapped = _mm_shuffle_epi32(endpoints_16bit, _MM_SHUFFLE(1, 0, 3, 2));

__m128i interpolated_16 = bc7_interp_sse2(endpoints_16bit, endpoints_16bit_swapped, _mm_set1_epi16(9), _mm_set1_epi16(55));
__m128i interpolated_23 = bc7_interp_sse2(endpoints_16bit, endpoints_16bit_swapped, _mm_set_epi16(37, 37, 37, 37, 18, 18, 18, 18), _mm_set_epi16(27, 27, 27, 27, 46, 46, 46, 46));
__m128i interpolated_45 = bc7_interp_sse2(endpoints_16bit, endpoints_16bit_swapped, _mm_set_epi16(18, 18, 18, 18, 37, 37, 37, 37), _mm_set_epi16(46, 46, 46, 46, 27, 27, 27, 27));

__m128i interpolated_01 = _mm_unpacklo_epi64(endpoints_16bit, interpolated_16);
__m128i interpolated_67 = _mm_unpackhi_epi64(interpolated_16, endpoints_16bit);

__m128i all_colors_0 = _mm_packus_epi16(interpolated_01, interpolated_23);
__m128i all_colors_1 = _mm_packus_epi16(interpolated_45, interpolated_67);

_mm_storeu_si128(reinterpret_cast<__m128i*>(out_colors), all_colors_0);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out_colors + 4), all_colors_1);
}
#endif

bool unpack_bc7_mode0_2(uint32_t mode, const uint64_t* data_chunks, color_rgba* pPixels)
{
//const uint32_t SUBSETS = 3;
Expand Down Expand Up @@ -166,13 +235,24 @@ bool unpack_bc7_mode0_2(uint32_t mode, const uint64_t* data_chunks, color_rgba*
endpoints[e][c] = static_cast<uint8_t>((c == 3) ? 255 : (PBITS ? bc7_dequant(endpoints[e][c], pbits[e], ENDPOINT_BITS) : bc7_dequant(endpoints[e][c], ENDPOINT_BITS)));

color_rgba block_colors[3][8];

#ifdef BC7DECOMP_USE_SSE2
for (uint32_t s = 0; s < 3; s++)
{
if (WEIGHT_BITS == 2)
bc7_interp2_sse2(endpoints + s * 2, block_colors[s]);
else
bc7_interp3_sse2(endpoints + s * 2, block_colors[s]);
}
#else
for (uint32_t s = 0; s < 3; s++)
for (uint32_t i = 0; i < WEIGHT_VALS; i++)
{
for (uint32_t c = 0; c < 3; c++)
block_colors[s][i][c] = static_cast<uint8_t>(bc7_interp(endpoints[s * 2 + 0][c], endpoints[s * 2 + 1][c], i, WEIGHT_BITS));
block_colors[s][i][3] = 255;
}
#endif

for (uint32_t i = 0; i < 16; i++)
pPixels[i] = block_colors[g_bc7_partition3[part * 16 + i]][weights[i]];
Expand Down Expand Up @@ -256,16 +336,26 @@ bool unpack_bc7_mode1_3_7(uint32_t mode, const uint64_t* data_chunks, color_rgba

for (uint32_t e = 0; e < ENDPOINTS; e++)
for (uint32_t c = 0; c < 4; c++)
endpoints[e][c] = static_cast<uint8_t>((c == ((mode == 7U) ? 4U : 3U)) ? 255 : bc7_dequant(endpoints[e][c], pbits[SHARED_PBITS ? (e >> 1) : e], ENDPOINT_BITS));
endpoints[e][c] = static_cast<uint8_t>((mode != 7U && c == 3U) ? 255 : bc7_dequant(endpoints[e][c], pbits[SHARED_PBITS ? (e >> 1) : e], ENDPOINT_BITS));

color_rgba block_colors[2][8];
#ifdef BC7DECOMP_USE_SSE2
for (uint32_t s = 0; s < 2; s++)
{
if (WEIGHT_BITS == 2)
bc7_interp2_sse2(endpoints + s * 2, block_colors[s]);
else
bc7_interp3_sse2(endpoints + s * 2, block_colors[s]);
}
#else
for (uint32_t s = 0; s < 2; s++)
for (uint32_t i = 0; i < WEIGHT_VALS; i++)
{
for (uint32_t c = 0; c < COMPS; c++)
block_colors[s][i][c] = static_cast<uint8_t>(bc7_interp(endpoints[s * 2 + 0][c], endpoints[s * 2 + 1][c], i, WEIGHT_BITS));
block_colors[s][i][3] = (COMPS == 3) ? 255 : block_colors[s][i][3];
}
#endif

for (uint32_t i = 0; i < 16; i++)
pPixels[i] = block_colors[g_bc7_partition2[part * 16 + i]][weights[i]];
Expand Down Expand Up @@ -355,9 +445,16 @@ bool unpack_bc7_mode4_5(uint32_t mode, const uint64_t* data_chunks, color_rgba*
endpoints[e][c] = static_cast<uint8_t>(bc7_dequant(endpoints[e][c], (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS));

color_rgba block_colors[8];
#ifdef BC7DECOMP_USE_SSE2
if (weight_bits[0] == 3)
bc7_interp3_sse2(endpoints, block_colors);
else
bc7_interp2_sse2(endpoints, block_colors);
#else
for (uint32_t i = 0; i < (1U << weight_bits[0]); i++)
for (uint32_t c = 0; c < 3; c++)
block_colors[i][c] = static_cast<uint8_t>(bc7_interp(endpoints[0][c], endpoints[1][c], i, weight_bits[0]));
#endif

for (uint32_t i = 0; i < (1U << weight_bits[1]); i++)
block_colors[i][3] = static_cast<uint8_t>(bc7_interp(endpoints[0][3], endpoints[1][3], i, weight_bits[1]));
Expand Down Expand Up @@ -439,6 +536,25 @@ bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels)
const uint32_t a1 = static_cast<uint32_t>((block.m_lo.m_a1 << 1) | block.m_hi.m_p1);

color_rgba vals[16];
#ifdef BC7DECOMP_USE_SSE2
__m128i vep0 = _mm_set_epi16(a0, b0, g0, r0, a0, b0, g0, r0);
__m128i vep1 = _mm_set_epi16(a1, b1, g1, r1, a1, b1, g1, r1);

for (uint32_t i = 0; i < 16; i += 4)
{
const __m128i w0 = g_bc7_weights4_sse2[i / 4 * 2 + 0];
const __m128i w1 = g_bc7_weights4_sse2[i / 4 * 2 + 1];

const __m128i iw0 = _mm_sub_epi16(_mm_set1_epi16(64), w0);
const __m128i iw1 = _mm_sub_epi16(_mm_set1_epi16(64), w1);

__m128i first_half = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(vep0, iw0), _mm_mullo_epi16(vep1, w0)), _mm_set1_epi16(32)), 6);
__m128i second_half = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(vep0, iw1), _mm_mullo_epi16(vep1, w1)), _mm_set1_epi16(32)), 6);
__m128i combined = _mm_packus_epi16(first_half, second_half);

_mm_storeu_si128(reinterpret_cast<__m128i*>(vals + i), combined);
}
#else
for (uint32_t i = 0; i < 16; i++)
{
const uint32_t w = g_bc7_weights4[i];
Expand All @@ -449,6 +565,7 @@ bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels)
(b0 * iw + b1 * w + 32) >> 6,
(a0 * iw + a1 * w + 32) >> 6);
}
#endif

pPixels[0] = vals[block.m_hi.m_s00];
pPixels[1] = vals[block.m_hi.m_s10];
Expand Down Expand Up @@ -481,7 +598,7 @@ bool unpack_bc7(const void *pBlock, color_rgba *pPixels)
uint64_t data_chunks[2];

uint64_t endian_check = 1;
if (*reinterpret_cast<const uint8_t*>(&endian_check) != 1)
if (*reinterpret_cast<const uint8_t*>(&endian_check) == 1)
memcpy(data_chunks, pBlock, 16);
else
{
Expand Down

0 comments on commit 173443e

Please sign in to comment.