diff --git a/build_scripts/build.py b/build_scripts/build.py index 14067efce..1785eee59 100644 --- a/build_scripts/build.py +++ b/build_scripts/build.py @@ -1141,7 +1141,7 @@ def download_addon(name,addonName,url,commitId=None): curDir = os.getcwd() if not skip_repository_updates: if with_pfm: - download_addon("PFM","filmmaker","https://github.com/Silverlan/pfm.git","183eaf445f648b7c055b2ba1f5ff4f7681c3ae36") + download_addon("PFM","filmmaker","https://github.com/Silverlan/pfm.git","66f6c05d0fa36272c5caba1dcc8e15a34386cc50") download_addon("model editor","tool_model_editor","https://github.com/Silverlan/pragma_model_editor.git","a9ea4820f03be250bdf1e6951dad313561b75b17") if with_vr: diff --git a/core/client/src/c_engine.cpp b/core/client/src/c_engine.cpp index dd90cfa19..8212545e4 100644 --- a/core/client/src/c_engine.cpp +++ b/core/client/src/c_engine.cpp @@ -762,6 +762,7 @@ bool CEngine::Initialize(int argc, char *argv[]) contextCreateInfo.width = 1280; contextCreateInfo.height = 1024; contextCreateInfo.windowless = g_windowless; + contextCreateInfo.enableDiagnostics = IsGfxDiagnosticsModeEnabled(); std::shared_ptr renderApiData {}; try { diff --git a/core/pragma/include/pragma/pragma_executable.hpp b/core/pragma/include/pragma/pragma_executable.hpp index 811274cf1..6d5bcb492 100644 --- a/core/pragma/include/pragma/pragma_executable.hpp +++ b/core/pragma/include/pragma/pragma_executable.hpp @@ -89,6 +89,12 @@ namespace pragma { ~ModuleWrapper() { #ifdef _WIN32 + if(std::uncaught_exceptions() > 0) { + // If we're stack unwinding due to an uncaught exception, + // we DON'T want to release the library, since we'll need + // the library to collect information for our crashdump! + return; + } FreeLibrary(handle); #else dlclose(handle); @@ -103,9 +109,9 @@ namespace pragma { static std::unique_ptr launch_pragma(int argc, char *argv[], bool server = false) { #ifdef __linux__ - const char *library = server ? "libshared.so" : "libclient.so"; + const char *library = server ? "libshared.so" : "libclient.so"; #else - const char *library = server ? "shared.dll" : "client.dll"; + const char *library = server ? "shared.dll" : "client.dll"; #endif const char *runEngineSymbol = server ? "RunEngine" : "RunCEngine"; @@ -149,7 +155,7 @@ namespace pragma { #if 0 std::thread t([]() { std::cout << "Linux Thread Test"; }); #endif - void (*runEngine)(int, char *[]) = (void (*)(int, char *[]))dlsym(hEngine, runEngineSymbol); + void (*runEngine)(int, char *[]) = (void (*)(int, char *[]))dlsym(hEngine, runEngineSymbol); if(runEngine != nullptr) { runEngine(argc, argv); return wrapper; diff --git a/core/shared/include/pragma/debug/mdump.h b/core/shared/include/pragma/debug/mdump.h index af5aceaea..ffd03838d 100644 --- a/core/shared/include/pragma/debug/mdump.h +++ b/core/shared/include/pragma/debug/mdump.h @@ -27,8 +27,10 @@ typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFi namespace pragma::debug { class DLLNETWORK CrashHandler { public: - CrashHandler(const std::string &appName); + static CrashHandler &Get(); + CrashHandler(); ~CrashHandler(); + void SetAppName(const std::string &appName); private: bool GenerateCrashDump() const; std::string m_appName; diff --git a/core/shared/include/pragma/engine_init.hpp b/core/shared/include/pragma/engine_init.hpp index b79a86916..f4c888d8e 100644 --- a/core/shared/include/pragma/engine_init.hpp +++ b/core/shared/include/pragma/engine_init.hpp @@ -15,7 +15,7 @@ template std::shared_ptr InitializeEngine(int argc, char *argv[]) { auto exe = engine_info::get_executable_name(); - pragma::debug::CrashHandler dmp(exe); + pragma::debug::CrashHandler::Get().SetAppName(exe); auto en = std::shared_ptr {new T {argc, argv}, [](T *p) { #ifdef _WIN32 if(std::uncaught_exceptions() > 0) { @@ -40,7 +40,7 @@ std::shared_ptr InitializeEngine(int argc, char *argv[]) inline DLLNETWORK std::shared_ptr InitializeServer(int argc, char *argv[]) { auto exe = engine_info::get_executable_name(); - pragma::debug::CrashHandler dmp(exe); + pragma::debug::CrashHandler::Get().SetAppName(exe); auto en = std::shared_ptr {new Engine {argc, argv}, [](Engine *p) { if(std::uncaught_exceptions() > 0) { // If we're stack unwinding due to an uncaught exception, diff --git a/core/shared/src/debug/mdump.cpp b/core/shared/src/debug/mdump.cpp index 6ac18b373..fd761aefc 100644 --- a/core/shared/src/debug/mdump.cpp +++ b/core/shared/src/debug/mdump.cpp @@ -31,22 +31,17 @@ extern DLLNETWORK Engine *engine; using namespace pragma::debug; std::string g_crashExceptionMessage = {}; -static CrashHandler *g_crashHandler = nullptr; -CrashHandler::CrashHandler(const std::string &appName) : m_appName {appName} +static CrashHandler g_crashHandler {}; +CrashHandler &CrashHandler::Get() { return g_crashHandler; } +CrashHandler::CrashHandler() { - assert(!g_crashHandler); - g_crashHandler = this; #ifdef _WIN32 ::SetUnhandledExceptionFilter(TopLevelFilter); #else signal( SIGSEGV, +[](int sig) { - if(!g_crashHandler) { - exit(1); - return; - } - g_crashHandler->m_sig = sig; - g_crashHandler->GenerateCrashDump(); + g_crashHandler.m_sig = sig; + g_crashHandler.GenerateCrashDump(); exit(1); }); #endif @@ -72,7 +67,9 @@ CrashHandler::CrashHandler(const std::string &appName) : m_appName {appName} }); } -CrashHandler::~CrashHandler() { g_crashHandler = nullptr; } +void CrashHandler::SetAppName(const std::string &appName) { m_appName = appName; } + +CrashHandler::~CrashHandler() {} #ifdef _WIN32 BOOL CALLBACK MyMiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput); @@ -343,12 +340,21 @@ bool CrashHandler::GenerateCrashDump() const } #ifdef _WIN32 +static auto g_crashDumpGenerated = false; +static std::mutex g_crashMutex; LONG CrashHandler::TopLevelFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) { - if(!g_crashHandler) + // When a crash occurs, there's a good chance that other threads will also crash. + // This can cause the entire application to die before the crash dump has been fully generated. + // Since we probably only care about the first crash anyway, we'll simply make all other threads wait + // until the crash dump has been generated. + std::unique_lock lock {g_crashMutex}; + if(g_crashDumpGenerated) return EXCEPTION_CONTINUE_SEARCH; - g_crashHandler->m_pExceptionInfo = pExceptionInfo; - g_crashHandler->GenerateCrashDump(); + + g_crashDumpGenerated = true; + g_crashHandler.m_pExceptionInfo = pExceptionInfo; + g_crashHandler.GenerateCrashDump(); return EXCEPTION_EXECUTE_HANDLER; } #endif diff --git a/core/shared/src/engine.cpp b/core/shared/src/engine.cpp index ffc5df81c..67bf4e3fa 100644 --- a/core/shared/src/engine.cpp +++ b/core/shared/src/engine.cpp @@ -1042,6 +1042,8 @@ void Engine::DumpDebugInformation(uzip::ZIPFile &zip) const fWriteConvars(GetServerNetworkState()->GetConVars(), "cvars_sv.txt"); fWriteLuaTraceback(GetServerNetworkState()->GetLuaState(), "sv"); } + + const_cast(this)->CallCallbacks>("DumpDebugInformation", zip); } const long long &Engine::GetLastTick() const { return m_lastTick; }