Skip to content

Commit 7d992a6

Browse files
committed
Switch ImGui's ImHash function to use Special K's SSE4.2 implementation of crc32c
1 parent ca05018 commit 7d992a6

6 files changed

Lines changed: 75 additions & 45 deletions

File tree

include/SpecialK/crc32.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/**
22
* This file is part of Special K.
33
*
44
* Special K is free software : you can redistribute it
@@ -37,13 +37,13 @@ SK_File_GetCRC32C ( const wchar_t* wszFile,
3737

3838
uint32_t
3939
__cdecl
40-
crc32 (uint32_t crc, _Notnull_ const void *buf, size_t size) ;
40+
crc32 (uint32_t crc, _Notnull_ const void *buf, size_t size) noexcept;
4141

4242
// Returns the value of crc if attempting to checksum this memory throws an
4343
// access violation exception
4444
uint32_t
4545
__cdecl
46-
safe_crc32c (uint32_t crc, _Notnull_ const void *buf, size_t size);
46+
safe_crc32c (uint32_t crc, _Notnull_ const void *buf, size_t size) noexcept;
4747

4848
/*
4949
Computes CRC-32C (Castagnoli) checksum. Uses Intel's CRC32 instruction if it is available.
@@ -52,37 +52,37 @@ safe_crc32c (uint32_t crc, _Notnull_ const void *buf, size_t size);
5252
uint32_t
5353
__cdecl
5454
crc32c (
55-
uint32_t crc, // Initial CRC value. Typically it's 0.
56-
// You can supply non-trivial initial value here.
57-
// Initial value can be used to chain CRC from multiple buffers.
55+
uint32_t crc, // Initial CRC value. Typically it's 0.
56+
// You can supply non-trivial initial value here.
57+
// Initial value can be used to chain CRC from multiple buffers.
5858

5959
_Notnull_
60-
const void *input, // Data to be put through the CRC algorithm.
61-
size_t length); // Length of the data in the input buffer.
60+
const void *input, // Data to be put through the CRC algorithm.
61+
size_t length) noexcept; // Length of the data in the input buffer.
6262

6363

64-
void __cdecl __crc32_init (void);
64+
void __cdecl __crc32_init (void) noexcept;
6565

6666
/*
6767
Software fallback version of CRC-32C (Castagnoli) checksum.
6868
*/
6969
uint32_t
7070
__cdecl
71-
crc32c_append_sw (uint32_t crc, const void *input, size_t length) ;
71+
crc32c_append_sw (uint32_t crc, const void *input, size_t length) noexcept;
7272

7373
/*
7474
Hardware version of CRC-32C (Castagnoli) checksum. Will fail, if CPU does
7575
not support related instructions. Use a crc32c_append version instead of.
7676
*/
7777
uint32_t
7878
__cdecl
79-
crc32c_append_hw (uint32_t crc, const void *input, size_t length) ;
79+
crc32c_append_hw (uint32_t crc, const void *input, size_t length) noexcept;
8080

8181
/*
8282
Checks is hardware version of CRC-32C is available.
8383
*/
8484
int
8585
__cdecl
86-
crc32c_hw_available (void) ;
86+
crc32c_hw_available (void) noexcept;
8787

8888
SK_INCLUDE_END (CRC32)

include/imgui/imgui_internal.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// dear imgui, v1.90 WIP
1+
// dear imgui, v1.90 WIP
22
// (internal structures/api)
33

44
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@@ -350,8 +350,8 @@ namespace ImStb
350350
//-----------------------------------------------------------------------------
351351

352352
// Helpers: Hashing
353-
IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImGuiID seed = 0);
354-
IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImGuiID seed = 0);
353+
IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImGuiID seed = 0) noexcept;
354+
IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImGuiID seed = 0) noexcept;
355355

356356
// Helpers: Sorting
357357
#ifndef ImQsort

src/SpecialK.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,8 @@ SK_Attach (DLL_ROLE role)
16951695

16961696
if (SK_DLL_IsAttached ())
16971697
{
1698+
__crc32_init ();
1699+
16981700
SK_MinHook_Init ();
16991701

17001702
return TRUE;

src/crc32.cpp

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ std::unique_ptr <InstructionSet::InstructionSet_Internal> InstructionSet::CPU_Re
9797
extern "C"
9898
uint32_t
9999
__cdecl
100-
crc32 (uint32_t crc, _Notnull_ const void *buf, size_t size)
100+
crc32 (uint32_t crc, _Notnull_ const void *buf, size_t size) noexcept
101101
{
102102
const auto *p =
103103
static_cast <const uint8_t *> (buf);
@@ -155,15 +155,15 @@ static uint32_t short_shifts [ 4][256];
155155

156156
static bool _tableInitialized = false;
157157

158-
extern "C" void __cdecl calculate_table (void) ;
158+
extern "C" void __cdecl calculate_table (void) noexcept;
159159

160160
/* Table-driven software version as a fall-back. This is about 15 times slower
161161
than using the hardware instructions. This assumes little-endian integers,
162162
as is the case on Intel processors that the assembler code here is for. */
163163
extern "C"
164164
uint32_t
165165
__cdecl
166-
crc32c_append_sw (uint32_t crci, const void *input, size_t length)
166+
crc32c_append_sw (uint32_t crci, const void *input, size_t length) noexcept
167167
{
168168
auto next =
169169
static_cast <buffer> (input);
@@ -247,7 +247,7 @@ crc32c_append_sw (uint32_t crci, const void *input, size_t length)
247247
static
248248
inline
249249
uint32_t
250-
shift_crc ( const uint32_t shift_table[][256], uint32_t crc )
250+
shift_crc ( const uint32_t shift_table[][256], uint32_t crc ) noexcept
251251
{
252252
return shift_table [0][ crc & 0xff]
253253
^ shift_table [1][(crc >> 8) & 0xff]
@@ -259,7 +259,7 @@ shift_crc ( const uint32_t shift_table[][256], uint32_t crc )
259259
extern "C"
260260
uint32_t
261261
__cdecl
262-
crc32c_append_hw (uint32_t crc, const void *buf, size_t len)
262+
crc32c_append_hw (uint32_t crc, const void *buf, size_t len) noexcept
263263
{
264264
if (buf == nullptr || len < 1)
265265
return crc;
@@ -432,7 +432,7 @@ crc32c_append_hw (uint32_t crc, const void *buf, size_t len)
432432
extern "C"
433433
int
434434
__cdecl
435-
crc32c_hw_available (void)
435+
crc32c_hw_available (void) noexcept
436436
{
437437
int info [4] = { 0 };
438438
#ifndef SK_BUILT_BY_CLANG
@@ -447,7 +447,7 @@ crc32c_hw_available (void)
447447
extern "C"
448448
void
449449
__cdecl
450-
calculate_table (void)
450+
calculate_table (void) noexcept
451451
{
452452
for (int i = 0; i < 256; i++)
453453
{
@@ -469,7 +469,7 @@ calculate_table (void)
469469
extern "C"
470470
void
471471
__cdecl
472-
calculate_table_hw (void)
472+
calculate_table_hw (void) noexcept
473473
{
474474
for (unsigned int i = 0; i < 256UL; i++)
475475
{
@@ -520,7 +520,7 @@ volatile LONG
520520

521521
extern "C"
522522
void __cdecl
523-
__crc32_init (void)
523+
__crc32_init (void) noexcept
524524
{
525525
typedef
526526
uint32_t (__cdecl *appendfunc_pfn)( uint32_t,
@@ -565,25 +565,8 @@ extern "C"
565565
uint32_t __cdecl
566566
crc32c ( uint32_t crc,
567567
_Notnull_ const void *input,
568-
size_t length )
568+
size_t length ) noexcept
569569
{
570-
if (append_func == nullptr)
571-
{
572-
static volatile LONG __init = 0;
573-
574-
if (InterlockedCompareExchange (&__init, 1, 0) == 0)
575-
{
576-
__crc32_init ();
577-
578-
InterlockedIncrement (&__init);
579-
}
580-
581-
else
582-
{
583-
SK_Thread_SpinUntilAtomicMin (&__init, 2);
584-
}
585-
}
586-
587570
if ( input != nullptr &&
588571
length > 0 &&
589572
append_func != nullptr )

src/imgui/imgui.cpp

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,17 +2022,28 @@ static const ImU32 GCrc32LookupTable[256] =
20222022
0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
20232023
};
20242024

2025+
extern "C"
2026+
uint32_t __cdecl
2027+
crc32c ( uint32_t crc,
2028+
_Notnull_ const void *input,
2029+
size_t length ) noexcept;
2030+
20252031
// Known size hash
20262032
// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
20272033
// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
2028-
ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed)
2034+
ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) noexcept
20292035
{
20302036
ImU32 crc = ~seed;
20312037
const unsigned char* data = (const unsigned char*)data_p;
2038+
#ifdef USE_ORIGINAL_IMHASH
20322039
const ImU32* crc32_lut = GCrc32LookupTable;
20332040
while (data_size-- != 0)
20342041
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
20352042
return ~crc;
2043+
#else
2044+
crc32c (crc, data, static_cast <unsigned int> (data_size));
2045+
return ~crc;
2046+
#endif
20362047
}
20372048

20382049
// Zero-terminated string hash, with support for ### to reset back to seed value
@@ -2041,11 +2052,12 @@ ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed)
20412052
// - If we reach ### in the string we discard the hash so far and reset to the seed.
20422053
// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
20432054
// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
2044-
ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed)
2055+
ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) noexcept
20452056
{
20462057
seed = ~seed;
20472058
ImU32 crc = seed;
20482059
const unsigned char* data = (const unsigned char*)data_p;
2060+
#ifdef USE_ORIGINAL_IMHASH
20492061
const ImU32* crc32_lut = GCrc32LookupTable;
20502062
if (data_size != 0)
20512063
{
@@ -2066,6 +2078,39 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed)
20662078
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
20672079
}
20682080
}
2081+
#else
2082+
size_t unparsed_size = data_size;
2083+
const unsigned char* start_of_data = data;
2084+
2085+
if (data_size != 0)
2086+
{
2087+
while (data_size-- != 0)
2088+
{
2089+
if (*data++ == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
2090+
start_of_data = &data[2]; // Skip "###" in the hash
2091+
}
2092+
}
2093+
else
2094+
{
2095+
size_t str_size = 0;
2096+
while (unsigned char c = *data++)
2097+
{
2098+
str_size++;
2099+
2100+
if (c == '#' && data[0] == '#' && data[1] == '#') {
2101+
start_of_data = &data[2]; // Skip "###" in the hash
2102+
str_size = 0;
2103+
}
2104+
}
2105+
unparsed_size = str_size;
2106+
}
2107+
2108+
if (start_of_data <= data + unparsed_size)
2109+
{
2110+
crc =
2111+
crc32c (crc, start_of_data, static_cast <unsigned int> (data + unparsed_size - start_of_data));
2112+
}
2113+
#endif
20692114
return ~crc;
20702115
}
20712116

src/render/d3d9/d3d9_texmgr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,7 @@ SK::D3D9::TextureManager::loadQueuedTextures (void)
16031603

16041604
uint32_t
16051605
__cdecl
1606-
safe_crc32c (uint32_t seed, _Notnull_ const void *buf, size_t size)
1606+
safe_crc32c (uint32_t seed, _Notnull_ const void *buf, size_t size) noexcept
16071607
{
16081608
// Current limit == 2 GiB
16091609
if (size > (1024ULL * 1024ULL * 1024ULL * 2) || buf == nullptr)

0 commit comments

Comments
 (0)