r5sdk/r5dev/core/dllmain.cpp
Kawe Mazidjatari 165d80c541 Fix rare ImGui crash on shutdown
The 'DirectX_Init()' call was performed late in code, shortly after the window has been created (at this point all device objects and window handles are valid), but the 'DirectX_Shutdown()' call was performed on DLL_DETACH, which was way too late, as the objects were already destroyed at this point. This wasn't an issue before, as we created our own objects in the old DX code. But due to optimizations, we were using the same pointers as the game (noticeable performance boost), but did not adjust the shutdown to accommodate the changes. The shutdown is now performed while the device objects and window handles are valid. Code has been tested on Nvidia and AMD systems, and has confirmed to fix the aforementioned issues.
2023-06-18 22:16:43 +02:00

190 lines
4.9 KiB
C++

#include "core/stdafx.h"
#include "core/r5dev.h"
#include "core/init.h"
#include "core/logdef.h"
#include "core/logger.h"
#include "tier0/basetypes.h"
#include "tier0/crashhandler.h"
/*****************************************************************************/
#ifndef DEDICATED
#include "windows/id3dx.h"
#include "windows/input.h"
#endif // !DEDICATED
#include "windows/console.h"
#include "windows/system.h"
#include "mathlib/mathlib.h"
#include "launcher/launcher.h"
#ifndef DEDICATED
#define SDK_DEFAULT_CFG "cfg/startup_default.cfg"
#else
#define SDK_DEFAULT_CFG "cfg/startup_dedi_default.cfg"
#endif
//#############################################################################
// INITIALIZATION
//#############################################################################
void Crash_Callback()
{
// Shutdown SpdLog to flush all buffers.
SpdLog_Shutdown();
// TODO[ AMOS ]: This is where we want to call backtrace from.
}
void Tier0_Init()
{
#if !defined (DEDICATED)
g_GameDll = CModule("r5apex.exe");
g_RadVideoToolsDll = CModule("bink2w64.dll");
g_RadAudioDecoderDll = CModule("binkawin64.dll");
g_RadAudioSystemDll = CModule("mileswin64.dll");
#if !defined (CLIENT_DLL)
g_SDKDll = CModule("gamesdk.dll");
#else // This dll is loaded from 'bin/x64_retail//'
g_SDKDll = CModule("client.dll");
#endif // !CLIENT_DLL
#else // No DirectX and Miles imports.
g_GameDll = CModule("r5apex_ds.exe");
g_SDKDll = CModule("dedicated.dll");
#endif // !DEDICATED
// Setup logger callback sink.
g_CoreMsgVCallback = &EngineLoggerSink;
// Setup crash callback.
g_CrashHandler->SetCrashCallback(&Crash_Callback);
}
void SDK_Init()
{
if (strstr(GetCommandLineA(), "-launcher"))
{
g_svCmdLine = GetCommandLineA();
}
else
{
g_svCmdLine = LoadConfigFile(SDK_DEFAULT_CFG);
}
#ifndef DEDICATED
if (g_svCmdLine.find("-wconsole") != std::string::npos)
{
Console_Init();
}
#else
Console_Init();
#endif // !DEDICATED
SpdLog_Init();
Winsock_Init(); // Initialize Winsock.
for (size_t i = 0; i < SDK_ARRAYSIZE(R5R_EMBLEM); i++)
{
std::string svEscaped = StringEscape(R5R_EMBLEM[i]);
spdlog::info("{:s}{:s}{:s}\n", g_svRedF, svEscaped, g_svReset);
}
spdlog::info("\n");
Systems_Init();
WinSys_Init();
#ifndef DEDICATED
Input_Init();
#endif // !DEDICATED
// Initialize cURL with rebuilt memory callbacks
// featuring the game's memalloc implementation.
// this is required in order to hook cURL code
// in-game, as we otherwise would manage memory
// memory created by the game's implementation,
// using the standard one.
curl_global_init_mem(CURL_GLOBAL_ALL,
&R_malloc,
&R_free,
&R_realloc,
&R_strdup,
&R_calloc);
lzham_enable_fail_exceptions(true);
}
//#############################################################################
// SHUTDOWN
//#############################################################################
void SDK_Shutdown()
{
static bool bShutDown = false;
assert(!bShutDown);
if (bShutDown)
{
spdlog::error("Recursive shutdown!\n");
return;
}
bShutDown = true;
spdlog::info("Shutdown GameSDK\n");
curl_global_cleanup();
Winsock_Shutdown();
Systems_Shutdown();
WinSys_Shutdown();
#ifndef DEDICATED
Input_Shutdown();
#endif // !DEDICATED
Console_Shutdown();
SpdLog_Shutdown();
}
//#############################################################################
// ENTRYPOINT
//#############################################################################
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
CheckCPU(); // Check CPU as early as possible; error out if CPU isn't supported.
MathLib_Init(); // Initialize Mathlib.
NOTE_UNUSED(hModule);
NOTE_UNUSED(lpReserved);
#if !defined (DEDICATED) && !defined (CLIENT_DLL)
// This dll is imported by the game executable, we cannot circumvent it.
// To solve the recursive init problem, we check if -noworkerdll is passed.
// If this is passed, the worker dll will not be initialized, which allows
// us to load the client dll (or any other dll) instead, or load the game
// without the SDK.
s_bNoWorkerDll = !!strstr(GetCommandLineA(), "-noworkerdll");
#endif // !DEDICATED && CLIENT_DLL
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
if (!s_bNoWorkerDll)
{
Tier0_Init();
SDK_Init();
}
else // Destroy crash handler.
{
g_CrashHandler->~CCrashHandler();
g_CrashHandler = nullptr;
}
break;
}
case DLL_PROCESS_DETACH:
{
if (!s_bNoWorkerDll)
{
SDK_Shutdown();
}
break;
}
}
return TRUE;
}