mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
rdeflate: CRC hash key read with one load, not three
Every position the encoder inserts into a hash chain - on screenshot content, nearly every position - first builds the 24-bit key for the CRC32 hash from three byte loads, two shifts and two ors. That was the single most expensive line in the encoder: 522 million instructions for three 4K captures, on smooth and noisy images alike. On little-endian targets the key is now one 32-bit load with the top byte masked off, which is the same value. The fourth byte it reads is always inside win[]: a key is only taken where three bytes remain before win_len, and win[] already carries an 8-byte margin past its largest win_len for the word compares in rd_longest_match(). Big-endian targets keep the byte-wise form, and builds without a CRC hash (shift-xor only) are untouched. Compressed output is byte-identical to before over the level 0-9 x input chunking x six-input matrix, zlib-wrapped and raw, for each hash build: runtime-detected SSE4.2, -msse4.2, and aarch64 +crc under qemu; valgrind memcheck clean over the same matrix. rzip, rpng, archive and encodings sample tests pass; builds C89 without new warnings, for aarch64 with and without +crc, armv7, and big-endian PowerPC. screenshot_io_bench, 3840x2160 BGR24 PNG: gradient instructions -11.3% (3.29 G -> 2.92 G), median about -10%; noise -4.0%, best 368 -> 351 ms.
This commit is contained in:
1 parent
7b44ddac58
commit
0ca986d2d4
1 file changed
+25
-4
@@ -2455,13 +2455,34 @@ static void rd_fixed_lit_lengths(uint8_t *ll)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(RD_CRC32_HASH_DIRECT) || defined(RD_CRC32_HASH_RUNTIME)
|
||||
/* The three bytes at p as the CRC hash key, p[0] lowest. On a
|
||||
* little-endian target that is one 32-bit load with the top byte
|
||||
* dropped, in place of three byte loads, two shifts and two ors - the
|
||||
* key is built at every position inserted, which on the content
|
||||
* screenshots hold is nearly every position. The fourth byte read
|
||||
* always lies inside win[]: a key is only taken where three bytes
|
||||
* remain before win_len, and win[] carries an 8-byte margin past its
|
||||
* largest win_len for the word compares in rd_longest_match(). */
|
||||
static INLINE uint32_t rd_key3(const uint8_t *p)
|
||||
{
|
||||
#if RETRO_IS_BIG_ENDIAN
|
||||
return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16);
|
||||
#else
|
||||
uint32_t k;
|
||||
memcpy(&k, p, 4);
|
||||
return k & 0x00FFFFFFu;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RD_CRC32_HASH_RUNTIME)
|
||||
#include <features/features_cpu.h>
|
||||
#if defined(_MSC_VER)
|
||||
#include <nmmintrin.h>
|
||||
static uint32_t rd_hash_crc(const uint8_t *p)
|
||||
{
|
||||
uint32_t k = (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16);
|
||||
uint32_t k = rd_key3(p);
|
||||
return _mm_crc32_u32(0, k) & RD_HASH_MASK;
|
||||
}
|
||||
#else
|
||||
@@ -2473,7 +2494,7 @@ static uint32_t rd_hash_crc(const uint8_t *p)
|
||||
* selects this path when cpu_features_get() reports SSE4.2. */
|
||||
static uint32_t rd_hash_crc(const uint8_t *p)
|
||||
{
|
||||
uint32_t k = (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16);
|
||||
uint32_t k = rd_key3(p);
|
||||
uint32_t r = 0;
|
||||
__asm__("crc32l %1, %0" : "+r"(r) : "rm"(k));
|
||||
return r & RD_HASH_MASK;
|
||||
@@ -2493,11 +2514,11 @@ static uint32_t rd_hash_soft(const uint8_t *p)
|
||||
static uint32_t rd_hash(struct rdeflate *s, const uint8_t *p)
|
||||
{
|
||||
#if defined(__SSE4_2__)
|
||||
uint32_t k = (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16);
|
||||
uint32_t k = rd_key3(p);
|
||||
(void)s;
|
||||
return _mm_crc32_u32(0, k) & RD_HASH_MASK;
|
||||
#elif defined(__ARM_FEATURE_CRC32)
|
||||
uint32_t k = (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16);
|
||||
uint32_t k = rd_key3(p);
|
||||
(void)s;
|
||||
return __crc32w(0, k) & RD_HASH_MASK;
|
||||
#elif defined(RD_CRC32_HASH_RUNTIME)
|
||||
|
||||
Reference in new issue
Block a user