From 209f8340165a567b8a72bbb4501cc986d5a4afee Mon Sep 17 00:00:00 2001 From: Death Killer <884052+deathkiller@users.noreply.github.com> Date: Sun, 5 Nov 2023 01:30:43 +0100 Subject: [PATCH] Replaced `FNV1a`/`fasthash` with `CityHash`, reworked `BinaryShaderCache`, fixed `RenderBatcher`, use `static_cast` --- Sources/Jazz2.vcxproj | 1 + Sources/Jazz2.vcxproj.filters | 12 + Sources/Jazz2/Multiplayer/NetworkManager.cpp | 4 +- .../Jazz2/Scripting/JJ2PlusDefinitions.cpp | 70 ++-- Sources/Jazz2/Scripting/LevelScriptLoader.cpp | 42 +- .../Jazz2/Scripting/ScriptActorWrapper.cpp | 4 +- Sources/Jazz2/Scripting/ScriptLoader.cpp | 4 +- .../Jazz2/Scripting/ScriptPlayerWrapper.cpp | 2 +- Sources/Jazz2/UI/DiscordRpcClient.cpp | 2 +- Sources/Jazz2/UI/Menu/ImportSection.cpp | 4 +- Sources/Jazz2/UI/Menu/RefreshCacheSection.cpp | 13 +- Sources/Jazz2/UI/RgbLights.cpp | 6 +- Sources/Shared/Base/Unaligned.h | 62 +++ Sources/nCine/Audio/AudioReaderMpt.cpp | 6 +- Sources/nCine/Backends/GlfwInputManager.cpp | 2 +- Sources/nCine/Base/Clock.cpp | 5 +- Sources/nCine/Base/HashFunctions.cpp | 368 ++++++++++++++++++ Sources/nCine/Base/HashFunctions.h | 80 +++- Sources/nCine/Base/HashMap.h | 8 +- Sources/nCine/Graphics/BinaryShaderCache.cpp | 79 ++-- Sources/nCine/Graphics/BinaryShaderCache.h | 2 +- Sources/nCine/Graphics/IGfxDevice.cpp | 4 +- Sources/nCine/Graphics/RenderBatcher.cpp | 4 +- Sources/nCine/Graphics/RenderCommand.cpp | 2 +- Sources/nCine/MainApplication.cpp | 2 +- cmake/ncine_headers.cmake | 1 + 26 files changed, 634 insertions(+), 155 deletions(-) create mode 100644 Sources/Shared/Base/Unaligned.h diff --git a/Sources/Jazz2.vcxproj b/Sources/Jazz2.vcxproj index fa08e09e..37c8a5c2 100644 --- a/Sources/Jazz2.vcxproj +++ b/Sources/Jazz2.vcxproj @@ -228,6 +228,7 @@ + diff --git a/Sources/Jazz2.vcxproj.filters b/Sources/Jazz2.vcxproj.filters index e7ba2d21..adf2bf91 100644 --- a/Sources/Jazz2.vcxproj.filters +++ b/Sources/Jazz2.vcxproj.filters @@ -211,6 +211,9 @@ {8e8a53f2-8324-4eaa-ab44-82141d569c85} + + {0fd6dab6-c92b-45ba-a620-98604d239e84} + @@ -1383,6 +1386,12 @@ Header Files\Jazz2\Multiplayer + + Header Files + + + Header Files\Shared\Base + @@ -2291,6 +2300,9 @@ Source Files\Jazz2 + + Source Files + diff --git a/Sources/Jazz2/Multiplayer/NetworkManager.cpp b/Sources/Jazz2/Multiplayer/NetworkManager.cpp index 20766700..83364126 100644 --- a/Sources/Jazz2/Multiplayer/NetworkManager.cpp +++ b/Sources/Jazz2/Multiplayer/NetworkManager.cpp @@ -174,7 +174,7 @@ namespace Jazz2::Multiplayer void NetworkManager::OnClientThread(void* param) { - NetworkManager* _this = reinterpret_cast(param); + NetworkManager* _this = static_cast(param); INetworkHandler* handler = _this->_handler; ENetHost* host = _this->_host; @@ -252,7 +252,7 @@ namespace Jazz2::Multiplayer void NetworkManager::OnServerThread(void* param) { - NetworkManager* _this = reinterpret_cast(param); + NetworkManager* _this = static_cast(param); INetworkHandler* handler = _this->_handler; ENetHost* host = _this->_host; diff --git a/Sources/Jazz2/Scripting/JJ2PlusDefinitions.cpp b/Sources/Jazz2/Scripting/JJ2PlusDefinitions.cpp index 74bd8b44..84d5864e 100644 --- a/Sources/Jazz2/Scripting/JJ2PlusDefinitions.cpp +++ b/Sources/Jazz2/Scripting/JJ2PlusDefinitions.cpp @@ -167,7 +167,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjSTREAM)); return new(mem) jjSTREAM(); @@ -176,7 +176,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjSTREAM)); return new(mem) jjSTREAM(); @@ -438,7 +438,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjANIMFRAME)); return new(mem) jjANIMFRAME(); @@ -498,7 +498,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjANIMATION)); return new(mem) jjANIMATION(index); @@ -542,7 +542,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjANIMSET)); return new(mem) jjANIMSET(index); @@ -839,7 +839,7 @@ namespace Jazz2::Scripting { noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjOBJ)); return new(mem) jjOBJ(); @@ -849,7 +849,7 @@ namespace Jazz2::Scripting { noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjOBJ)); return new(mem) jjOBJ(); @@ -1415,14 +1415,14 @@ namespace Jazz2::Scripting int32_t get_jjPlayerCount() { auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPLAYER)); return owner->GetPlayers().size(); } int32_t get_jjLocalPlayerCount() { auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPLAYER)); return owner->GetPlayers().size(); @@ -1432,7 +1432,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPLAYER)); return new(mem) jjPLAYER(owner, 0); @@ -1441,7 +1441,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPLAYER)); return new(mem) jjPLAYER(owner, index); @@ -1450,7 +1450,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPLAYER)); return new(mem) jjPLAYER(owner, index); @@ -1467,7 +1467,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPIXELMAP)); return new(mem) jjPIXELMAP(); @@ -1476,7 +1476,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPIXELMAP)); return new(mem) jjPIXELMAP(); @@ -1485,7 +1485,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPIXELMAP)); return new(mem) jjPIXELMAP(); @@ -1494,7 +1494,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPIXELMAP)); return new(mem) jjPIXELMAP(); @@ -1503,7 +1503,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPIXELMAP)); return new(mem) jjPIXELMAP(); @@ -1512,7 +1512,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPIXELMAP)); return new(mem) jjPIXELMAP(); @@ -1521,7 +1521,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjPIXELMAP)); return new(mem) jjPIXELMAP(); @@ -1578,7 +1578,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjMASKMAP)); return new(mem) jjMASKMAP(); @@ -1587,7 +1587,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjMASKMAP)); return new(mem) jjMASKMAP(); @@ -1664,7 +1664,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(jjLAYER)); return new(mem) jjLAYER(); @@ -1776,7 +1776,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return _this->_levelHandler->_musicCurrentPath; } String get_jjTilesetFileName() { @@ -1787,14 +1787,14 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return _this->_levelHandler->GetLevelText(index); } void LevelScriptLoader::set_jjHelpStrings(uint32_t index, const String& text) { noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->OverrideLevelText(index, text); } @@ -1807,7 +1807,7 @@ namespace Jazz2::Scripting void LevelScriptLoader::jjAlert(const String& text, bool sendToAll, uint32_t size) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->ShowLevelText(text); } void jjPrint(const String& text, bool timestamp) { @@ -1993,14 +1993,14 @@ namespace Jazz2::Scripting //noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return _this->_levelHandler->GetTrigger(id); } bool LevelScriptLoader::set_jjTriggers(uint8_t id, bool value) { //noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->SetTrigger(id, value); return value; } @@ -2008,7 +2008,7 @@ namespace Jazz2::Scripting //noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->SetTrigger(id, !_this->_levelHandler->GetTrigger(id)); return _this->_levelHandler->GetTrigger(id); } @@ -2070,7 +2070,7 @@ namespace Jazz2::Scripting } auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->BeginLevelChange(exitType, { }); } @@ -2092,7 +2092,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->BeginPlayMusic(filename, !temporary, forceReload); return false; @@ -2101,7 +2101,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); if (_this->_levelHandler->_music != nullptr) { _this->_levelHandler->_music->stop(); } @@ -2110,7 +2110,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); if (_this->_levelHandler->_music != nullptr) { _this->_levelHandler->_music->play(); } @@ -2119,7 +2119,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); if (_this->_levelHandler->_music != nullptr) { _this->_levelHandler->_music->stop(); } @@ -2128,7 +2128,7 @@ namespace Jazz2::Scripting noop(); auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); if (_this->_levelHandler->_music != nullptr && _this->_levelHandler->_music->isPaused()) { _this->_levelHandler->_music->play(); } diff --git a/Sources/Jazz2/Scripting/LevelScriptLoader.cpp b/Sources/Jazz2/Scripting/LevelScriptLoader.cpp index b0f67f80..750049d2 100644 --- a/Sources/Jazz2/Scripting/LevelScriptLoader.cpp +++ b/Sources/Jazz2/Scripting/LevelScriptLoader.cpp @@ -3292,10 +3292,10 @@ namespace Jazz2::Scripting return nullptr; } - asIScriptObject* obj = reinterpret_cast(_engine->CreateScriptObject(typeInfo)); + asIScriptObject* obj = static_cast(_engine->CreateScriptObject(typeInfo)); // Get the pointer to the C++ side of the ActorBase class - ScriptActorWrapper* obj2 = *reinterpret_cast(obj->GetAddressOfProperty(0)); + ScriptActorWrapper* obj2 = *static_cast(obj->GetAddressOfProperty(0)); // Increase the reference count to the C++ object, as this is what will be used to control the life time of the object from the application side obj2->AddRef(); @@ -3314,63 +3314,63 @@ namespace Jazz2::Scripting uint8_t LevelScriptLoader::asGetDifficulty() { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return (uint8_t)_this->_levelHandler->_difficulty; } bool LevelScriptLoader::asIsReforged() { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return (uint8_t)_this->_levelHandler->_isReforged; } int LevelScriptLoader::asGetLevelWidth() { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return _this->_levelHandler->_tileMap->GetLevelBounds().X; } int LevelScriptLoader::asGetLevelHeight() { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return _this->_levelHandler->_tileMap->GetLevelBounds().Y; } float LevelScriptLoader::asGetElapsedFrames() { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return _this->_levelHandler->_elapsedFrames; } float LevelScriptLoader::asGetAmbientLight() { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return _this->_levelHandler->_ambientLightTarget; } void LevelScriptLoader::asSetAmbientLight(float value) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->_ambientLightTarget = value; } float LevelScriptLoader::asGetWaterLevel() { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); return _this->_levelHandler->_waterLevel; } void LevelScriptLoader::asSetWaterLevel(float value) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->_waterLevel = value; } @@ -3382,7 +3382,7 @@ namespace Jazz2::Scripting void LevelScriptLoader::asRegisterSpawnable(int eventType, const String& typeName) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); asITypeInfo* typeInfo = _this->_module->GetTypeInfoByName(typeName.data()); if (typeInfo == nullptr) { @@ -3403,8 +3403,8 @@ namespace Jazz2::Scripting if (_this != nullptr) { auto it = _this->_eventTypeToTypeInfo.find((int)details.Type); if (it != _this->_eventTypeToTypeInfo.end()) { - asIScriptObject* obj = reinterpret_cast(_this->_engine->CreateScriptObject(it->second)); - ScriptActorWrapper* obj2 = *reinterpret_cast(obj->GetAddressOfProperty(0)); + asIScriptObject* obj = static_cast(_this->_engine->CreateScriptObject(it->second)); + ScriptActorWrapper* obj2 = *static_cast(obj->GetAddressOfProperty(0)); obj2->AddRef(); obj->Release(); obj2->OnActivated(details); @@ -3418,7 +3418,7 @@ namespace Jazz2::Scripting void LevelScriptLoader::asSpawnEvent(int eventType, int x, int y) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); uint8_t spawnParams[Events::EventSpawner::SpawnParamsSize] { }; auto actor = _this->_levelHandler->EventSpawner()->SpawnEvent((EventType)eventType, spawnParams, Actors::ActorState::None, Vector3i(x, y, ILevelHandler::MainPlaneZ)); @@ -3430,7 +3430,7 @@ namespace Jazz2::Scripting void LevelScriptLoader::asSpawnEventParams(int eventType, int x, int y, const CScriptArray& eventParams) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); uint8_t spawnParams[Events::EventSpawner::SpawnParamsSize] { }; int size = eventParams.GetSize(); @@ -3445,7 +3445,7 @@ namespace Jazz2::Scripting void LevelScriptLoader::asSpawnType(const String& typeName, int x, int y) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); auto actor = _this->CreateActorInstance(typeName); if (actor == nullptr) { @@ -3464,7 +3464,7 @@ namespace Jazz2::Scripting void LevelScriptLoader::asSpawnTypeParams(const String& typeName, int x, int y, const CScriptArray& eventParams) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); auto actor = _this->CreateActorInstance(typeName); if (actor == nullptr) { @@ -3486,21 +3486,21 @@ namespace Jazz2::Scripting void LevelScriptLoader::asChangeLevel(int exitType, const String& path) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->BeginLevelChange((ExitType)exitType, path); } void LevelScriptLoader::asShowLevelText(const String& text) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->ShowLevelText(text); } void LevelScriptLoader::asSetWeather(uint8_t weatherType, uint8_t intensity) { auto ctx = asGetActiveContext(); - auto _this = reinterpret_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); + auto _this = static_cast(ctx->GetEngine()->GetUserData(EngineToOwner)); _this->_levelHandler->SetWeather((WeatherType)weatherType, intensity); } } diff --git a/Sources/Jazz2/Scripting/ScriptActorWrapper.cpp b/Sources/Jazz2/Scripting/ScriptActorWrapper.cpp index 51a42c25..ee01b491 100644 --- a/Sources/Jazz2/Scripting/ScriptActorWrapper.cpp +++ b/Sources/Jazz2/Scripting/ScriptActorWrapper.cpp @@ -179,7 +179,7 @@ shared abstract class CollectibleBase : )" AsClassName R"( ScriptActorWrapper* ScriptActorWrapper::Factory(int actorType) { auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); // Get the function that is calling the factory, so we can be certain it is the our internal script class asIScriptFunction* func = ctx->GetFunction(0); @@ -188,7 +188,7 @@ shared abstract class CollectibleBase : )" AsClassName R"( return nullptr; } - asIScriptObject* obj = reinterpret_cast(ctx->GetThisPointer()); + asIScriptObject* obj = static_cast(ctx->GetThisPointer()); switch (actorType) { default: case 0: { diff --git a/Sources/Jazz2/Scripting/ScriptLoader.cpp b/Sources/Jazz2/Scripting/ScriptLoader.cpp index 79f68450..9ab2df89 100644 --- a/Sources/Jazz2/Scripting/ScriptLoader.cpp +++ b/Sources/Jazz2/Scripting/ScriptLoader.cpp @@ -920,7 +920,7 @@ namespace Jazz2::Scripting asIScriptContext* ScriptLoader::RequestContextCallback(asIScriptEngine* engine, void* param) { // Check if there is a free context available in the pool - auto _this = reinterpret_cast(param); + auto _this = static_cast(param); if (!_this->_contextPool.empty()) { return _this->_contextPool.pop_back_val(); } else { @@ -937,7 +937,7 @@ namespace Jazz2::Scripting ctx->Unprepare(); // Place the context into the pool for when it will be needed again - auto _this = reinterpret_cast(param); + auto _this = static_cast(param); _this->_contextPool.push_back(ctx); } diff --git a/Sources/Jazz2/Scripting/ScriptPlayerWrapper.cpp b/Sources/Jazz2/Scripting/ScriptPlayerWrapper.cpp index 1f8f5c2b..2c7e4a69 100644 --- a/Sources/Jazz2/Scripting/ScriptPlayerWrapper.cpp +++ b/Sources/Jazz2/Scripting/ScriptPlayerWrapper.cpp @@ -74,7 +74,7 @@ namespace Jazz2::Scripting ScriptPlayerWrapper* ScriptPlayerWrapper::Factory(int playerIndex) { auto ctx = asGetActiveContext(); - auto owner = reinterpret_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); + auto owner = static_cast(ctx->GetEngine()->GetUserData(ScriptLoader::EngineToOwner)); void* mem = asAllocMem(sizeof(ScriptPlayerWrapper)); return new(mem) ScriptPlayerWrapper(owner, playerIndex); diff --git a/Sources/Jazz2/UI/DiscordRpcClient.cpp b/Sources/Jazz2/UI/DiscordRpcClient.cpp index c55f22a2..e1c80481 100644 --- a/Sources/Jazz2/UI/DiscordRpcClient.cpp +++ b/Sources/Jazz2/UI/DiscordRpcClient.cpp @@ -260,7 +260,7 @@ namespace Jazz2::UI void DiscordRpcClient::OnBackgroundThread(void* args) { - DiscordRpcClient* client = reinterpret_cast(args); + DiscordRpcClient* client = static_cast(args); // Handshake char buffer[2048]; diff --git a/Sources/Jazz2/UI/Menu/ImportSection.cpp b/Sources/Jazz2/UI/Menu/ImportSection.cpp index c8bab67a..b0ca3697 100644 --- a/Sources/Jazz2/UI/Menu/ImportSection.cpp +++ b/Sources/Jazz2/UI/Menu/ImportSection.cpp @@ -112,7 +112,7 @@ namespace Jazz2::UI::Menu void ImportSection::FileDataCallback(void* context, std::unique_ptr data, size_t length, const StringView& name) { - auto* _this = reinterpret_cast(context); + auto* _this = static_cast(context); _this->_fileCount--; int32_t offset = 180; // Skip header @@ -133,7 +133,7 @@ namespace Jazz2::UI::Menu void ImportSection::FileCountCallback(void* context, int32_t fileCount) { - auto* _this = reinterpret_cast(context); + auto* _this = static_cast(context); _this->_fileCount = fileCount; if (fileCount <= 0) { _this->_state = State::NothingSelected; diff --git a/Sources/Jazz2/UI/Menu/RefreshCacheSection.cpp b/Sources/Jazz2/UI/Menu/RefreshCacheSection.cpp index baf99442..806a34f1 100644 --- a/Sources/Jazz2/UI/Menu/RefreshCacheSection.cpp +++ b/Sources/Jazz2/UI/Menu/RefreshCacheSection.cpp @@ -7,8 +7,11 @@ #include "../../PreferencesCache.h" #include "../../../nCine/Base/Algorithms.h" +#include "../../../nCine/Graphics/BinaryShaderCache.h" +#include "../../../nCine/Graphics/RenderResources.h" using namespace Jazz2::UI::Menu::Resources; +using namespace nCine; namespace Jazz2::UI::Menu { @@ -23,16 +26,24 @@ namespace Jazz2::UI::Menu #if defined(WITH_THREADS) _thread.Run([](void* arg) { - auto _this = reinterpret_cast(arg); + auto _this = static_cast(arg); if (auto mainMenu = dynamic_cast(_this->_root)) { mainMenu->_root->RefreshCacheLevels(); } + + std::uint32_t filesRemoved = RenderResources::binaryShaderCache().prune(); + LOGI("Pruning binary shader cache (removed %u files)...", filesRemoved); + _this->_done = true; }, this); #else if (auto mainMenu = dynamic_cast(_root)) { mainMenu->_root->RefreshCacheLevels(); } + + std::uint32_t filesRemoved = RenderResources::binaryShaderCache().prune(); + LOGI("Pruning binary shader cache (removed %u files)...", filesRemoved); + _done = true; #endif } diff --git a/Sources/Jazz2/UI/RgbLights.cpp b/Sources/Jazz2/UI/RgbLights.cpp index e4f0b742..555fd51a 100644 --- a/Sources/Jazz2/UI/RgbLights.cpp +++ b/Sources/Jazz2/UI/RgbLights.cpp @@ -242,7 +242,7 @@ namespace Jazz2::UI if (result) { LOGE("Response failed: %i", result); } else { - RgbLights* _this = reinterpret_cast(userData); + RgbLights* _this = static_cast(userData); _this->_isConnected = true; } return EM_TRUE; @@ -250,7 +250,7 @@ namespace Jazz2::UI EM_BOOL RgbLights::emscriptenOnError(std::int32_t eventType, const EmscriptenWebSocketErrorEvent* websocketEvent, void* userData) { - RgbLights* _this = reinterpret_cast(userData); + RgbLights* _this = static_cast(userData); _this->_isConnected = false; if (_this->_ws != NULL) { @@ -263,7 +263,7 @@ namespace Jazz2::UI EM_BOOL RgbLights::emscriptenOnClose(std::int32_t eventType, const EmscriptenWebSocketCloseEvent* websocketEvent, void* userData) { - RgbLights* _this = reinterpret_cast(userData); + RgbLights* _this = static_cast(userData); _this->_isConnected = false; if (_this->_ws != NULL) { diff --git a/Sources/Shared/Base/Unaligned.h b/Sources/Shared/Base/Unaligned.h new file mode 100644 index 00000000..1c5e8986 --- /dev/null +++ b/Sources/Shared/Base/Unaligned.h @@ -0,0 +1,62 @@ +#pragma once + +#include "../Common.h" + +#include + +namespace Death +{ + /** + @brief Provides unaligned operations for pointers + */ + class Unaligned + { + public: + static std::uint16_t Load16(const void* p); + static std::uint32_t Load32(const void* p); + static std::uint64_t Load64(const void* p); + + static void Store16(void* p, std::uint16_t v); + static void Store32(void* p, std::uint32_t v); + static void Store64(void* p, std::uint64_t v); + + private: + Unaligned() = delete; + }; + + DEATH_ALWAYS_INLINE std::uint16_t Unaligned::Load16(const void* p) + { + std::uint16_t v; + std::memcpy(&v, p, sizeof(v)); + return v; + } + + DEATH_ALWAYS_INLINE std::uint32_t Unaligned::Load32(const void* p) + { + std::uint32_t v; + std::memcpy(&v, p, sizeof(v)); + return v; + } + + DEATH_ALWAYS_INLINE std::uint64_t Unaligned::Load64(const void* p) + { + std::uint64_t v; + std::memcpy(&v, p, sizeof(v)); + return v; + } + + DEATH_ALWAYS_INLINE void Unaligned::Store16(void* p, std::uint16_t v) + { + std::memcpy(p, &v, sizeof(v)); + } + + DEATH_ALWAYS_INLINE void Unaligned::Store32(void* p, std::uint32_t v) + { + std::memcpy(p, &v, sizeof(v)); + } + + DEATH_ALWAYS_INLINE void Unaligned::Store64(void* p, std::uint64_t v) + { + std::memcpy(p, &v, sizeof(v)); + } +} \ No newline at end of file diff --git a/Sources/nCine/Audio/AudioReaderMpt.cpp b/Sources/nCine/Audio/AudioReaderMpt.cpp index e70afcf3..54831aea 100644 --- a/Sources/nCine/Audio/AudioReaderMpt.cpp +++ b/Sources/nCine/Audio/AudioReaderMpt.cpp @@ -144,7 +144,7 @@ namespace nCine size_t AudioReaderMpt::stream_read_func(void* stream, void* dst, size_t bytes) { - AudioReaderMpt* _this = reinterpret_cast(stream); + AudioReaderMpt* _this = static_cast(stream); return _this->_fileHandle->Read(dst, (unsigned long)bytes); } @@ -158,14 +158,14 @@ namespace nCine case OPENMPT_STREAM_SEEK_END: origin = SeekOrigin::End; break; } - AudioReaderMpt* _this = reinterpret_cast(stream); + AudioReaderMpt* _this = static_cast(stream); _this->_fileHandle->Seek((int32_t)offset, origin); return 0; } int64_t AudioReaderMpt::stream_tell_func(void* stream) { - AudioReaderMpt* _this = reinterpret_cast(stream); + AudioReaderMpt* _this = static_cast(stream); return _this->_fileHandle->GetPosition(); } diff --git a/Sources/nCine/Backends/GlfwInputManager.cpp b/Sources/nCine/Backends/GlfwInputManager.cpp index 18086812..75845d02 100644 --- a/Sources/nCine/Backends/GlfwInputManager.cpp +++ b/Sources/nCine/Backends/GlfwInputManager.cpp @@ -416,7 +416,7 @@ namespace nCine #ifdef DEATH_TARGET_EMSCRIPTEN EM_BOOL GlfwInputManager::emscriptenHandleTouch(int eventType, const EmscriptenTouchEvent* event, void* userData) { - GlfwInputManager* inputManager = reinterpret_cast(userData); + GlfwInputManager* inputManager = static_cast(userData); double cssWidth = 0.0; double cssHeight = 0.0; diff --git a/Sources/nCine/Base/Clock.cpp b/Sources/nCine/Base/Clock.cpp index 6d4ba822..43b88df7 100644 --- a/Sources/nCine/Base/Clock.cpp +++ b/Sources/nCine/Base/Clock.cpp @@ -27,7 +27,9 @@ namespace nCine : frequency_(0UL), baseCount_(0ULL) { #if defined(DEATH_TARGET_WINDOWS) - if (::QueryPerformanceFrequency(reinterpret_cast(&frequency_))) { + LARGE_INTEGER li; + if (::QueryPerformanceFrequency(&li)) { + frequency_ = li.LowPart; hasPerfCounter_ = true; } else { frequency_ = 1000L; @@ -38,7 +40,6 @@ namespace nCine # else mach_timebase_info_data_t info; mach_timebase_info(&info); - frequency_ = (info.denom * 1.0e9L) / info.numer; # endif #else diff --git a/Sources/nCine/Base/HashFunctions.cpp b/Sources/nCine/Base/HashFunctions.cpp index dddbbca0..db09b017 100644 --- a/Sources/nCine/Base/HashFunctions.cpp +++ b/Sources/nCine/Base/HashFunctions.cpp @@ -1,5 +1,11 @@ #include "HashFunctions.h" +#include + +#if defined(DEATH_TARGET_APPLE) +# ínclude +#endif + namespace nCine { // Compression function for Merkle-Damgard construction. @@ -50,4 +56,366 @@ namespace nCine uint64_t h = fasthash64(buf, len, seed); return static_cast(h - (h >> 32)); } + + // CityHash + inline std::uint32_t ByteSwap32(std::uint32_t value) + { +#if defined(DEATH_TARGET_MSVC) + return _byteswap_ulong(value); +#elif defined(DEATH_TARGET_APPLE) + return OSSwapInt32(value); +#elif __has_builtin(__builtin_bswap32) || defined(DEATH_TARGET_GCC) + return __builtin_bswap32(value); +#else + return (((value & std::uint32_t{0xFF}) << 24) | + ((value & std::uint32_t{0xFF00}) << 8) | + ((value & std::uint32_t{0xFF0000}) >> 8) | + ((value & std::uint32_t{0xFF000000}) >> 24)); +#endif + } + + inline std::uint64_t ByteSwap64(std::uint64_t value) + { +#if defined(DEATH_TARGET_MSVC) + return _byteswap_uint64(value); +#elif defined(DEATH_TARGET_APPLE) + return OSSwapInt64(value); +#elif __has_builtin(__builtin_bswap64) || defined(DEATH_TARGET_GCC) + return __builtin_bswap64(value); +#else + return (((value & std::uint64_t{0xFF}) << 56) | + ((value & std::uint64_t{0xFF00}) << 40) | + ((value & std::uint64_t{0xFF0000}) << 24) | + ((value & std::uint64_t{0xFF000000}) << 8) | + ((value & std::uint64_t{0xFF00000000}) >> 8) | + ((value & std::uint64_t{0xFF0000000000}) >> 24) | + ((value & std::uint64_t{0xFF000000000000}) >> 40) | + ((value & std::uint64_t{0xFF00000000000000}) >> 56)); +#endif + } + +#if defined(DEATH_TARGET_BIG_ENDIAN) +# define uint32_in_expected_order(x) (ByteSwap32(x)) +# define uint64_in_expected_order(x) (ByteSwap64(x)) +#else +# define uint32_in_expected_order(x) (x) +# define uint64_in_expected_order(x) (x) +#endif + + static std::uint64_t Fetch64(const char* p) + { + using Death::Unaligned; + return uint64_in_expected_order(Unaligned::Load64(p)); + } + + static std::uint32_t Fetch32(const char* p) + { + using Death::Unaligned; + return uint32_in_expected_order(Unaligned::Load32(p)); + } + + // Some primes between 2^63 and 2^64 for various uses. + static const std::uint64_t k0 = 0xc3a5c85c97cb3127ULL; + static const std::uint64_t k1 = 0xb492b66fbe98f273ULL; + static const std::uint64_t k2 = 0x9ae16a3b2f90404fULL; + + // Magic numbers for 32-bit hashing. Copied from Murmur3. + static const std::uint32_t c1 = 0xcc9e2d51; + static const std::uint32_t c2 = 0x1b873593; + + // A 32-bit to 32-bit integer hash copied from Murmur3. + static std::uint32_t fmix(std::uint32_t h) + { + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + return h; + } + + static std::uint32_t Rotate32(std::uint32_t val, std::int32_t shift) + { + // Avoid shifting by 32: doing so yields an undefined result. + return (shift == 0 ? val : ((val >> shift) | (val << (32 - shift)))); + } + +#undef PERMUTE3 +#define PERMUTE3(a, b, c) \ + do { \ + std::swap(a, b); \ + std::swap(a, c); \ + } while (0) + + static std::uint32_t Mur(std::uint32_t a, std::uint32_t h) + { + // Helper from Murmur3 for combining two 32-bit values. + a *= c1; + a = Rotate32(a, 17); + a *= c2; + h ^= a; + h = Rotate32(h, 19); + return h * 5 + 0xe6546b64; + } + + static std::uint32_t Hash32Len13to24(const char* s, std::size_t len) + { + std::uint32_t a = Fetch32(s - 4 + (len >> 1)); + std::uint32_t b = Fetch32(s + 4); + std::uint32_t c = Fetch32(s + len - 8); + std::uint32_t d = Fetch32(s + (len >> 1)); + std::uint32_t e = Fetch32(s); + std::uint32_t f = Fetch32(s + len - 4); + std::uint32_t h = static_cast(len); + return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h))))))); + } + + static std::uint32_t Hash32Len0to4(const char* s, std::size_t len) + { + std::uint32_t b = 0; + std::uint32_t c = 9; + for (std::size_t i = 0; i < len; i++) { + signed char v = static_cast(s[i]); + b = b * c1 + static_cast(v); + c ^= b; + } + return fmix(Mur(b, Mur(static_cast(len), c))); + } + + static std::uint32_t Hash32Len5to12(const char* s, std::size_t len) + { + std::uint32_t a = static_cast(len), b = a * 5, c = 9, d = b; + a += Fetch32(s); + b += Fetch32(s + len - 4); + c += Fetch32(s + ((len >> 1) & 4)); + return fmix(Mur(c, Mur(b, Mur(a, d)))); + } + + std::uint32_t CityHash32(const char* s, std::size_t len) + { + if (len <= 24) { + return len <= 12 + ? (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) + : Hash32Len13to24(s, len); + } + + // len > 24 + std::uint32_t h = static_cast(len), g = c1 * h, f = g; + + std::uint32_t a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2; + std::uint32_t a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2; + std::uint32_t a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2; + std::uint32_t a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2; + std::uint32_t a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2; + h ^= a0; + h = Rotate32(h, 19); + h = h * 5 + 0xe6546b64; + h ^= a2; + h = Rotate32(h, 19); + h = h * 5 + 0xe6546b64; + g ^= a1; + g = Rotate32(g, 19); + g = g * 5 + 0xe6546b64; + g ^= a3; + g = Rotate32(g, 19); + g = g * 5 + 0xe6546b64; + f += a4; + f = Rotate32(f, 19); + f = f * 5 + 0xe6546b64; + std::size_t iters = (len - 1) / 20; + do { + std::uint32_t b0 = Rotate32(Fetch32(s) * c1, 17) * c2; + std::uint32_t b1 = Fetch32(s + 4); + std::uint32_t b2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2; + std::uint32_t b3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2; + std::uint32_t b4 = Fetch32(s + 16); + h ^= b0; + h = Rotate32(h, 18); + h = h * 5 + 0xe6546b64; + f += b1; + f = Rotate32(f, 19); + f = f * c1; + g += b2; + g = Rotate32(g, 18); + g = g * 5 + 0xe6546b64; + h ^= b3 + b1; + h = Rotate32(h, 19); + h = h * 5 + 0xe6546b64; + g ^= b4; + g = ByteSwap32(g) * 5; + h += b4 * 5; + h = ByteSwap32(h); + f += b0; + PERMUTE3(f, h, g); + s += 20; + } while (--iters != 0); + g = Rotate32(g, 11) * c1; + g = Rotate32(g, 17) * c1; + f = Rotate32(f, 11) * c1; + f = Rotate32(f, 17) * c1; + h = Rotate32(h + g, 19); + h = h * 5 + 0xe6546b64; + h = Rotate32(h, 17) * c1; + h = Rotate32(h + f, 19); + h = h * 5 + 0xe6546b64; + h = Rotate32(h, 17) * c1; + return h; + } + + // Bitwise right rotate. Normally this will compile to a single + // instruction, especially if the shift is a manifest constant. + static std::uint64_t Rotate(std::uint64_t val, std::int32_t shift) + { + // Avoid shifting by 64: doing so yields an undefined result. + return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); + } + + static std::uint64_t ShiftMix(std::uint64_t val) + { + return val ^ (val >> 47); + } + + static std::uint64_t HashLen16(std::uint64_t u, std::uint64_t v, std::uint64_t mul) + { + // Murmur-inspired hashing. + std::uint64_t a = (u ^ v) * mul; + a ^= (a >> 47); + std::uint64_t b = (v ^ a) * mul; + b ^= (b >> 47); + b *= mul; + return b; + } + + static std::uint64_t HashLen16(std::uint64_t u, std::uint64_t v) + { + const std::uint64_t kMul = 0x9ddfea08eb382d69ULL; + return HashLen16(u, v, kMul); + } + + static std::uint64_t HashLen0to16(const char* s, std::size_t len) + { + if (len >= 8) { + std::uint64_t mul = k2 + len * 2; + std::uint64_t a = Fetch64(s) + k2; + std::uint64_t b = Fetch64(s + len - 8); + std::uint64_t c = Rotate(b, 37) * mul + a; + std::uint64_t d = (Rotate(a, 25) + b) * mul; + return HashLen16(c, d, mul); + } + if (len >= 4) { + std::uint64_t mul = k2 + len * 2; + std::uint64_t a = Fetch32(s); + return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul); + } + if (len > 0) { + std::uint8_t a = static_cast(s[0]); + std::uint8_t b = static_cast(s[len >> 1]); + std::uint8_t c = static_cast(s[len - 1]); + std::uint32_t y = static_cast(a) + (static_cast(b) << 8); + std::uint32_t z = static_cast(len) + (static_cast(c) << 2); + return ShiftMix(y * k2 ^ z * k0) * k2; + } + return k2; + } + + // This probably works well for 16-byte strings as well, but it may be overkill in that case. + static std::uint64_t HashLen17to32(const char* s, std::size_t len) + { + std::uint64_t mul = k2 + len * 2; + std::uint64_t a = Fetch64(s) * k1; + std::uint64_t b = Fetch64(s + 8); + std::uint64_t c = Fetch64(s + len - 8) * mul; + std::uint64_t d = Fetch64(s + len - 16) * k2; + return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, a + Rotate(b + k2, 18) + c, mul); + } + + // Return a 16-byte hash for 48 bytes. Quick and dirty. + // Callers do best to use "random-looking" values for a and b. + static std::pair WeakHashLen32WithSeeds(std::uint64_t w, std::uint64_t x, std::uint64_t y, std::uint64_t z, std::uint64_t a, std::uint64_t b) + { + a += w; + b = Rotate(b + a + z, 21); + std::uint64_t c = a; + a += x; + a += y; + b += Rotate(a, 44); + return std::make_pair(a + z, b + c); + } + + // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. + static std::pair WeakHashLen32WithSeeds(const char* s, std::uint64_t a, std::uint64_t b) + { + return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a, b); + } + + // Return an 8-byte hash for 33 to 64 bytes. + static std::uint64_t HashLen33to64(const char* s, std::size_t len) + { + std::uint64_t mul = k2 + len * 2; + std::uint64_t a = Fetch64(s) * k2; + std::uint64_t b = Fetch64(s + 8); + std::uint64_t c = Fetch64(s + len - 24); + std::uint64_t d = Fetch64(s + len - 32); + std::uint64_t e = Fetch64(s + 16) * k2; + std::uint64_t f = Fetch64(s + 24) * 9; + std::uint64_t g = Fetch64(s + len - 8); + std::uint64_t h = Fetch64(s + len - 16) * mul; + std::uint64_t u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9; + std::uint64_t v = ((a + g) ^ d) + f + 1; + std::uint64_t w = ByteSwap64((u + v) * mul) + h; + std::uint64_t x = Rotate(e + f, 42) + c; + std::uint64_t y = (ByteSwap64((v + w) * mul) + g) * mul; + std::uint64_t z = e + f + c; + a = ByteSwap64((x + z) * mul + y) + b; + b = ShiftMix((z + a) * mul + d + h) * mul; + return b + x; + } + + std::uint64_t CityHash64(const char* s, std::size_t len) + { + if (len <= 32) { + if (len <= 16) { + return HashLen0to16(s, len); + } else { + return HashLen17to32(s, len); + } + } else if (len <= 64) { + return HashLen33to64(s, len); + } + + // For strings over 64 bytes we hash the end first, and then as we + // loop we keep 56 bytes of state: v, w, x, y, and z. + std::uint64_t x = Fetch64(s + len - 40); + std::uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56); + std::uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); + std::pair v = WeakHashLen32WithSeeds(s + len - 64, len, z); + std::pair w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); + x = x * k1 + Fetch64(s); + + // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. + len = (len - 1) & ~static_cast(63); + do { + x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; + y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; + x ^= w.second; + y += v.first + Fetch64(s + 40); + z = Rotate(z + w.first, 33) * k1; + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); + std::swap(z, x); + s += 64; + len -= 64; + } while (len != 0); + return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z, HashLen16(v.second, w.second) + x); + } + + std::uint64_t CityHash64WithSeeds(const char* s, std::size_t len, std::uint64_t seed0, uint64_t seed1) + { + return HashLen16(CityHash64(s, len) - seed0, seed1); + } + + std::uint64_t CityHash64WithSeed(const char* s, std::size_t len, std::uint64_t seed) + { + return CityHash64WithSeeds(s, len, k2, seed); + } } \ No newline at end of file diff --git a/Sources/nCine/Base/HashFunctions.h b/Sources/nCine/Base/HashFunctions.h index 263a1fce..b4999b56 100644 --- a/Sources/nCine/Base/HashFunctions.h +++ b/Sources/nCine/Base/HashFunctions.h @@ -11,10 +11,11 @@ using namespace Death::Containers; namespace nCine { using hash_t = uint32_t; + using hash64_t = uint64_t; const hash_t NullHash = static_cast(~0); /// Hash function returning always the first hashmap bucket, for debug purposes - template + template class FixedHashFunc { public: @@ -24,7 +25,7 @@ namespace nCine }; /// Hash function returning the modulo of the key, for debug purposes - template + template class ModuloHashFunc { public: @@ -35,7 +36,7 @@ namespace nCine /// Hash function returning the key unchanged /*! The key type should be convertible to `hash_t.` */ - template + template class IdentityHashFunc { public: @@ -45,7 +46,7 @@ namespace nCine }; /// Shift-Add-XOR hash function - template + template class SaxHashFunc { public: @@ -64,7 +65,7 @@ namespace nCine /*! * \note Specialized version of the function for C-style strings */ - template <> + template<> class SaxHashFunc { public: @@ -83,7 +84,7 @@ namespace nCine /*! * \note Specialized version of the function for String objects */ - template <> + template<> class SaxHashFunc { public: @@ -102,7 +103,7 @@ namespace nCine /*! * For more information: http://en.wikipedia.org/wiki/Jenkins_hash_function */ - template + template class JenkinsHashFunc { public: @@ -129,7 +130,7 @@ namespace nCine * * For more information: http://en.wikipedia.org/wiki/Jenkins_hash_function */ - template <> + template<> class JenkinsHashFunc { public: @@ -156,7 +157,7 @@ namespace nCine * * For more information: http://en.wikipedia.org/wiki/Jenkins_hash_function */ - template <> + template<> class JenkinsHashFunc { public: @@ -181,7 +182,7 @@ namespace nCine /*! * For more information: http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function */ - template + template class FNV1aHashFunc { public: @@ -210,7 +211,7 @@ namespace nCine * * For more information: http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function */ - template <> + template<> class FNV1aHashFunc { public: @@ -240,7 +241,7 @@ namespace nCine * * For more information: http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function */ - template <> + template<> class FNV1aHashFunc { public: @@ -281,7 +282,7 @@ namespace nCine /*! * For more information: https://github.com/ztanml/fast-hash */ - template + template class FastHashFunc { public: @@ -303,7 +304,7 @@ namespace nCine * * For more information: https://github.com/ztanml/fast-hash */ - template <> + template<> class FastHashFunc { public: @@ -322,7 +323,7 @@ namespace nCine * * For more information: https://github.com/ztanml/fast-hash */ - template <> + template<> class FastHashFunc { public: @@ -334,4 +335,53 @@ namespace nCine private: static const uint32_t Seed = 0x811C9DC5; }; + + /// CityHash + std::uint64_t CityHash64(const char* s, std::size_t len); + + std::uint64_t CityHash64WithSeed(const char* s, std::size_t len, std::uint64_t seed); + + std::uint64_t CityHash64WithSeeds(const char* s, std::size_t len, std::uint64_t seed0, std::uint64_t seed1); + + std::uint32_t CityHash32(const char* s, std::size_t len); + + template + class CityHash32Func + { + public: + hash_t operator()(const K& key) const + { + return CityHash32(reinterpret_cast(&key), sizeof(K)); + } + }; + + template<> + class CityHash32Func + { + public: + hash_t operator()(const String& string) const + { + return CityHash32(string.data(), string.size()); + } + }; + + template + class CityHash64Func + { + public: + hash64_t operator()(const K& key) const + { + return CityHash64(reinterpret_cast(&key), sizeof(K)); + } + }; + + template<> + class CityHash64Func + { + public: + hash64_t operator()(const String& string) const + { + return CityHash64(string.data(), string.size()); + } + }; } \ No newline at end of file diff --git a/Sources/nCine/Base/HashMap.h b/Sources/nCine/Base/HashMap.h index eee06285..7c9c1df3 100644 --- a/Sources/nCine/Base/HashMap.h +++ b/Sources/nCine/Base/HashMap.h @@ -5,9 +5,13 @@ namespace nCine { - // Use flat_hash_map from Parallel Hashmap library + // Use `flat_hash_map` from Parallel Hashmap library template , +#if defined(DEATH_TARGET_32BIT) + class Hash = CityHash32Func, +#else + class Hash = CityHash64Func, +#endif class Eq = phmap::priv::hash_default_eq> using HashMap = phmap::flat_hash_map; } diff --git a/Sources/nCine/Graphics/BinaryShaderCache.cpp b/Sources/nCine/Graphics/BinaryShaderCache.cpp index ce7b6447..25cb2548 100644 --- a/Sources/nCine/Graphics/BinaryShaderCache.cpp +++ b/Sources/nCine/Graphics/BinaryShaderCache.cpp @@ -15,8 +15,6 @@ namespace nCine { namespace { - constexpr uint64_t HashSeed = 0x01000193811C9DC5; - std::int32_t bufferSize = 0; std::unique_ptr bufferPtr; } @@ -56,17 +54,12 @@ namespace nCine const IGfxCapabilities::GlInfoStrings& infoStrings = gfxCaps.glInfoStrings(); - // For a stable hash, the OpenGL strings need to be copied so that padding bytes can be set to zero - char platformString[512]; - std::memset(platformString, 0, sizeof(platformString)); - int platformStringLength = copyStringFirst(platformString, infoStrings.renderer); - platformHash_ += fasthash64(platformString, platformStringLength, HashSeed); - - std::memset(platformString, 0, sizeof(platformString)); - platformStringLength = copyStringFirst(platformString, infoStrings.glVersion); - platformHash_ += fasthash64(platformString, platformStringLength, HashSeed); + platformHash_ += CityHash64(infoStrings.renderer, strlen(infoStrings.renderer)); + platformHash_ += CityHash64(infoStrings.glVersion, strlen(infoStrings.glVersion)); - path_ = path; + char platformHashString[24]; + std::int32_t platformHashLength = formatString(platformHashString, sizeof(platformHashString), "%016llx", platformHash_); + path_ = fs::CombinePath(path, { platformHashString, (std::size_t)platformHashLength }); fs::CreateDirectories(path_); bufferSize = 64 * 1024; @@ -78,20 +71,15 @@ namespace nCine String BinaryShaderCache::getCachedShaderPath(const char* shaderName) { - if (!isAvailable_ || shaderName == nullptr) { - return { }; - } - - std::size_t shaderNameLength = strlen(shaderName); - if (shaderNameLength == 0) { + if (!isAvailable_ || shaderName == nullptr || shaderName[0] == '\0') { return { }; } - std::uint64_t shaderNameHash = fasthash64(shaderName, shaderNameLength, 0x01000193811C9DC5); + std::uint64_t shaderNameHash = CityHash64(shaderName, strlen(shaderName)); - char outputBuffer[48]; - formatString(outputBuffer, sizeof(outputBuffer), "%016llx%016llx.shader", shaderNameHash, platformHash_); - return fs::CombinePath(path_, outputBuffer); + char filename[32]; + std::int32_t filenameLength = formatString(filename, sizeof(filename), "%016llx.shader", shaderNameHash); + return fs::CombinePath(path_, { filename, (std::size_t)filenameLength }); } bool BinaryShaderCache::loadFromCache(const char* shaderName, std::uint64_t shaderVersion, GLShaderProgram* program, GLShaderProgram::Introspection introspection) @@ -179,28 +167,18 @@ namespace nCine std::uint32_t BinaryShaderCache::prune() { + auto platformHashString = fs::GetFileName(path_); + std::uint32_t filesRemoved = 0; - fs::Directory dir(path_); + fs::Directory dir(fs::GetDirectoryName(path_)); while (const StringView shaderPath = dir.GetNext()) { - if (fs::GetExtension(shaderPath) != "shader"_s) { - continue; - } - - StringView filename = fs::GetFileNameWithoutExtension(shaderPath); - - bool shouldRemove; - if (filename.size() != 32) { - shouldRemove = true; - } else { - char componentString[17]; - std::memcpy(componentString, &filename[16], 16); - componentString[16] = '\0'; - - std::uint64_t platformHash = strtoull(componentString, nullptr, 16); - shouldRemove = (platformHash != platformHash_); - } - - if (shouldRemove) { + if (fs::DirectoryExists(shaderPath)) { + StringView filename = fs::GetFileName(shaderPath); + if (filename != platformHashString) { + fs::RemoveDirectoryRecursive(shaderPath); + filesRemoved++; + } + } else if (fs::GetExtension(shaderPath) == "shader"_s) { fs::RemoveFile(shaderPath); filesRemoved++; } @@ -209,20 +187,11 @@ namespace nCine return filesRemoved; } - std::uint32_t BinaryShaderCache::clear() + bool BinaryShaderCache::clear() { - std::uint32_t filesRemoved = 0; - fs::Directory dir(path_); - while (const StringView shaderPath = dir.GetNext()) { - if (fs::GetExtension(shaderPath) != "shader"_s) { - continue; - } - - fs::RemoveFile(shaderPath); - filesRemoved++; - } - - return filesRemoved; + bool success = fs::RemoveDirectoryRecursive(path_); + fs::CreateDirectories(path_); + return success; } bool BinaryShaderCache::setPath(const StringView& path) diff --git a/Sources/nCine/Graphics/BinaryShaderCache.h b/Sources/nCine/Graphics/BinaryShaderCache.h index f22bb84d..77c13bcc 100644 --- a/Sources/nCine/Graphics/BinaryShaderCache.h +++ b/Sources/nCine/Graphics/BinaryShaderCache.h @@ -37,7 +37,7 @@ namespace nCine /// Deletes all binary shaders that not belong to this platform from the cache directory std::uint32_t prune(); /// Deletes all binary shaders from the cache directory - std::uint32_t clear(); + bool clear(); /// Returns the current cache directory for binary shaders inline const StringView path() { diff --git a/Sources/nCine/Graphics/IGfxDevice.cpp b/Sources/nCine/Graphics/IGfxDevice.cpp index 664a7fd2..f4579c6d 100644 --- a/Sources/nCine/Graphics/IGfxDevice.cpp +++ b/Sources/nCine/Graphics/IGfxDevice.cpp @@ -28,7 +28,7 @@ namespace nCine # endif if (event->windowInnerWidth > 0 && event->windowInnerHeight > 0) { float pixelRatio = emscripten_get_device_pixel_ratio(); - IGfxDevice* gfxDevice = reinterpret_cast(userData); + IGfxDevice* gfxDevice = static_cast(userData); gfxDevice->setResolutionInternal(static_cast(event->windowInnerWidth * pixelRatio), static_cast(event->windowInnerHeight * pixelRatio)); } return 1; @@ -43,7 +43,7 @@ namespace nCine float pixelRatio2 = emscripten_get_device_pixel_ratio(); LOGI("Canvas was resized to %ix%i (canvas size is %ix%i; ratio is %f)", (int)(event->elementWidth * pixelRatio2), (int)(event->elementHeight * pixelRatio2), (int)cssWidth, (int)cssHeight, pixelRatio2); # endif - IGfxDevice* gfxDevice = reinterpret_cast(userData); + IGfxDevice* gfxDevice = static_cast(userData); gfxDevice->isFullscreen_ = event->isFullscreen; if (event->elementWidth > 0 && event->elementHeight > 0) { diff --git a/Sources/nCine/Graphics/RenderBatcher.cpp b/Sources/nCine/Graphics/RenderBatcher.cpp index c17d87d6..f4f6da40 100644 --- a/Sources/nCine/Graphics/RenderBatcher.cpp +++ b/Sources/nCine/Graphics/RenderBatcher.cpp @@ -170,9 +170,9 @@ namespace nCine batchingWithIndices = true; } - // Don't request more bytes than a UBO can hold + // Don't request more bytes than an instances block can hold (also protects against big `RenderingSettings::maxBatchSize` values) const unsigned long currentSize = nonBlockUniformsSize + nonInstancesBlocksSize + instancesBlockSize; - if (currentSize + singleInstanceBlockSize > UboMaxSize) { + if (currentSize + singleInstanceBlockSize > instancesBlock->size()) { break; } diff --git a/Sources/nCine/Graphics/RenderCommand.cpp b/Sources/nCine/Graphics/RenderCommand.cpp index 3e577307..d51de153 100644 --- a/Sources/nCine/Graphics/RenderCommand.cpp +++ b/Sources/nCine/Graphics/RenderCommand.cpp @@ -23,7 +23,7 @@ namespace nCine { const uint64_t upper = static_cast(layerSortKey()) << 32; const uint32_t lower = material_.sortKey(); - materialSortKey_ = upper + lower; + materialSortKey_ = upper | lower; } void RenderCommand::issue() diff --git a/Sources/nCine/MainApplication.cpp b/Sources/nCine/MainApplication.cpp index 29fd4c55..e2669d06 100644 --- a/Sources/nCine/MainApplication.cpp +++ b/Sources/nCine/MainApplication.cpp @@ -447,7 +447,7 @@ namespace nCine #if defined(DEATH_TARGET_EMSCRIPTEN) void MainApplication::emscriptenStep() { - reinterpret_cast(theApplication()).run(); + static_cast(theApplication()).run(); } #endif } diff --git a/cmake/ncine_headers.cmake b/cmake/ncine_headers.cmake index ba4b7401..a5a6bd56 100644 --- a/cmake/ncine_headers.cmake +++ b/cmake/ncine_headers.cmake @@ -11,6 +11,7 @@ set(HEADERS ${NCINE_SOURCE_DIR}/Shared/IntrinsicsSse4.h ${NCINE_SOURCE_DIR}/Shared/IntrinsicsSsse3.h ${NCINE_SOURCE_DIR}/Shared/Utf8.h + ${NCINE_SOURCE_DIR}/Shared/Base/Unaligned.h ${NCINE_SOURCE_DIR}/Shared/Containers/Array.h ${NCINE_SOURCE_DIR}/Shared/Containers/ArrayView.h ${NCINE_SOURCE_DIR}/Shared/Containers/DateTime.h