123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554 |
- /*
- * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
- * its licensors.
- *
- * For complete copyright and license terms please see the LICENSE at the root of this
- * distribution (the "License"). All use of this software is governed by the License,
- * or, if provided, by the license below or the license accompanying this file. Do not
- * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *
- */
- // Original file Copyright Crytek GMBH or its affiliates, used under license.
- #include "CrySystem_precompiled.h"
- #include "System.h"
- #include <time.h>
- #include <I3DEngine.h>
- #include <IRenderer.h>
- #include <IMovieSystem.h>
- #include <ILog.h>
- #include <CryLibrary.h>
- #include <StringUtils.h>
- #include <AzCore/Debug/StackTracer.h>
- #include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
- #include <AzCore/std/allocator_stack.h>
- #if defined(AZ_RESTRICTED_PLATFORM)
- #undef AZ_RESTRICTED_SECTION
- #define SYSTEMWIN32_CPP_SECTION_1 1
- #define SYSTEMWIN32_CPP_SECTION_2 2
- #define SYSTEMWIN32_CPP_SECTION_3 3
- #endif
- #if defined(LINUX) || defined(APPLE)
- #include <unistd.h>
- #endif
- #ifdef WIN32
- #define WIN32_LEAN_AND_MEAN
- #include "windows.h"
- #include <float.h>
- #include <shellapi.h> // Needed for ShellExecute.
- #include <Psapi.h>
- #include <Aclapi.h>
- #include <shlobj.h>
- #endif
- #include "IDebugCallStack.h"
- #if defined(APPLE) || defined(LINUX)
- #include <pwd.h>
- #endif
- #include "XConsole.h"
- #include "CrySizerStats.h"
- #include "CrySizerImpl.h"
- #include "StreamEngine/StreamEngine.h"
- #include "LocalizedStringManager.h"
- #include "XML/XmlUtils.h"
- #include "AutoDetectSpec.h"
- #if defined(WIN32)
- __pragma(comment(lib, "wininet.lib"))
- __pragma(comment(lib, "Winmm.lib"))
- #endif
- #if defined(APPLE)
- #include "SystemUtilsApple.h"
- #endif
- static AZStd::vector<AZStd::string> GetModuleNames()
- {
- AZStd::vector<AZStd::string> moduleNames;
- if (moduleNames.empty())
- {
- # ifdef MODULE_EXTENSION
- # error MODULE_EXTENSION already defined!
- # endif
- # if defined(LINUX)
- # define MODULE_EXTENSION ".so"
- # elif defined(APPLE)
- # define MODULE_EXTENSION ".dylib"
- # else
- # define MODULE_EXTENSION ".dll"
- # endif
- moduleNames.push_back("Cry3DEngine" MODULE_EXTENSION);
- moduleNames.push_back("CryFont" MODULE_EXTENSION);
- moduleNames.push_back("CrySystem" MODULE_EXTENSION);
- #undef MODULE_EXTENSION
- # if defined(LINUX)
- moduleNames.push_back("CryRenderNULL.so");
- # elif defined(APPLE)
- moduleNames.push_back("CryRenderNULL.dylib");
- # else
- moduleNames.push_back("Editor.exe");
- moduleNames.push_back("CryRenderD3D9.dll");
- moduleNames.push_back("CryRenderD3D10.dll");
- moduleNames.push_back("CryRenderNULL.dll");
- //TODO: launcher?
- # endif
- }
- return moduleNames;
- }
- static bool QueryModuleMemoryInfo([[maybe_unused]] SCryEngineStatsModuleInfo& moduleInfo, [[maybe_unused]] int index)
- {
- return false;
- }
- // this is the list of modules that can be loaded into the game process
- // Each array element contains 2 strings: the name of the module (case-insensitive)
- // and the name of the group the module belongs to
- //////////////////////////////////////////////////////////////////////////
- const char g_szGroupCore[] = "CryEngine";
- const char* g_szModuleGroups[][2] = {
- {"Editor.exe", g_szGroupCore},
- {"CrySystem.dll", g_szGroupCore},
- {"CryFont.dll", g_szGroupCore},
- };
- //////////////////////////////////////////////////////////////////////////
- void CSystem::SetAffinity()
- {
- // the following code is only for Windows
- #ifdef WIN32
- // set the process affinity
- ICVar* pcvAffinityMask = GetIConsole()->GetCVar("sys_affinity");
- if (!pcvAffinityMask)
- {
- pcvAffinityMask = REGISTER_INT("sys_affinity", 0, VF_NULL, "");
- }
- if (pcvAffinityMask)
- {
- unsigned nAffinity = pcvAffinityMask->GetIVal();
- if (nAffinity)
- {
- typedef BOOL (WINAPI * FnSetProcessAffinityMask)(IN HANDLE hProcess, IN DWORD_PTR dwProcessAffinityMask);
- HMODULE hKernel = CryLoadLibrary ("kernel32.dll");
- if (hKernel)
- {
- FnSetProcessAffinityMask SetProcessAffinityMask = (FnSetProcessAffinityMask)GetProcAddress(hKernel, "SetProcessAffinityMask");
- if (SetProcessAffinityMask && !SetProcessAffinityMask(GetCurrentProcess(), nAffinity))
- {
- GetILog()->LogError("Error: Cannot set affinity mask %d, error code %d", nAffinity, GetLastError());
- }
- FreeLibrary (hKernel);
- }
- }
- }
- #endif
- }
- //! dumps the memory usage statistics to the log
- //////////////////////////////////////////////////////////////////////////
- void CSystem::DumpMemoryUsageStatistics(bool bUseKB)
- {
- // CResourceCollector ResourceCollector;
- // TickMemStats(nMSP_ForDump,&ResourceCollector);
- TickMemStats(nMSP_ForDump);
- CrySizerStatsRenderer StatsRenderer (this, m_pMemStats, 10, 0);
- StatsRenderer.dump(bUseKB);
- // since we've recalculated this mem stats for dumping, we'll want to calculate it anew the next time it's rendered
- SAFE_DELETE(m_pMemStats);
- }
- // collects the whole memory statistics into the given sizer object
- //////////////////////////////////////////////////////////////////////////
- #if defined(WIN32)
- #pragma pack(push,1)
- struct PEHeader_DLL
- {
- DWORD signature;
- IMAGE_FILE_HEADER _head;
- IMAGE_OPTIONAL_HEADER opt_head;
- IMAGE_SECTION_HEADER* section_header; // actual number in NumberOfSections
- };
- #pragma pack(pop)
- #endif
- const SmallModuleInfo* FindModuleInfo(std::vector<SmallModuleInfo>& vec, const char* name)
- {
- for (size_t i = 0; i < vec.size(); ++i)
- {
- if (!vec[i].name.compareNoCase(name))
- {
- return &vec[i];
- }
- }
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- void CSystem::CollectMemInfo(SCryEngineStatsGlobalMemInfo& m_stats)
- {
- m_stats.totalUsedInModules = 0;
- m_stats.totalCodeAndStatic = 0;
- m_stats.countedMemoryModules = 0;
- m_stats.totalAllocatedInModules = 0;
- m_stats.totalNumAllocsInModules = 0;
- AZStd::vector<AZStd::string> szModules = GetModuleNames();
- const int numModules = szModules.size();
- //////////////////////////////////////////////////////////////////////////
- // Hardcoded value for the OS memory allocation.
- //////////////////////////////////////////////////////////////////////////
- for (int i = 0; i < numModules; i++)
- {
- const char* szModule = szModules[i].c_str();
- SCryEngineStatsModuleInfo moduleInfo;
- ZeroStruct(moduleInfo.memInfo);
- moduleInfo.moduleStaticSize = moduleInfo.SizeOfCode = moduleInfo.SizeOfInitializedData = moduleInfo.SizeOfUninitializedData = moduleInfo.usedInModule = 0;
- moduleInfo.name = szModule;
- if (!QueryModuleMemoryInfo(moduleInfo, i))
- {
- continue;
- }
- m_stats.totalNumAllocsInModules += moduleInfo.memInfo.num_allocations;
- m_stats.totalAllocatedInModules += moduleInfo.memInfo.allocated;
- m_stats.totalUsedInModules += moduleInfo.usedInModule;
- m_stats.countedMemoryModules++;
- m_stats.totalCodeAndStatic += moduleInfo.moduleStaticSize;
- m_stats.modules.push_back(moduleInfo);
- }
- }
- void CSystem::CollectMemStats (ICrySizer* pSizer, MemStatsPurposeEnum nPurpose, std::vector<SmallModuleInfo>* pStats)
- {
- std::vector<SmallModuleInfo> stats;
- if (pStats)
- {
- pStats->assign(stats.begin(), stats.end());
- }
- if (nMSP_ForCrashLog == nPurpose || nMSP_ForBudget == nPurpose)
- {
- return;
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "CrySystem");
- {
- pSizer->AddObject(this, sizeof(*this));
- {
- //SIZER_COMPONENT_NAME (pSizer, "$Allocations waste");
- //const SmallModuleInfo* info = FindModuleInfo(stats, "CrySystem.dll");
- //if (info)
- //pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested );
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "VFS");
- if (m_pStreamEngine)
- {
- SIZER_COMPONENT_NAME(pSizer, "Stream Engine");
- m_pStreamEngine->GetMemoryStatistics(pSizer);
- }
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "Localization Data");
- m_pLocalizationManager->GetMemoryUsage(pSizer);
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "XML");
- m_pXMLUtils->GetMemoryUsage(pSizer);
- }
- if (m_env.pConsole)
- {
- SIZER_COMPONENT_NAME (pSizer, "Console");
- m_env.pConsole->GetMemoryUsage (pSizer);
- }
- if (m_env.pLog)
- {
- SIZER_COMPONENT_NAME (pSizer, "Log");
- m_env.pLog->GetMemoryUsage(pSizer);
- }
- }
- }
- if (m_env.p3DEngine)
- {
- SIZER_COMPONENT_NAME(pSizer, "Cry3DEngine");
- {
- m_env.p3DEngine->GetMemoryUsage (pSizer);
- {
- SIZER_COMPONENT_NAME (pSizer, "$Allocations waste");
- const SmallModuleInfo* info = FindModuleInfo(stats, "Cry3DEngine.dll");
- if (info)
- {
- pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested);
- }
- }
- }
- }
- if (m_env.pRenderer)
- {
- SIZER_COMPONENT_NAME(pSizer, "CryRenderer");
- {
- {
- SIZER_COMPONENT_NAME (pSizer, "$Allocations waste D3D9");
- const SmallModuleInfo* info = FindModuleInfo(stats, "CryRenderD3D9.dll");
- if (info)
- {
- pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested);
- }
- }
- {
- SIZER_COMPONENT_NAME (pSizer, "$Allocations waste D3D10");
- const SmallModuleInfo* info = FindModuleInfo(stats, "CryRenderD3D10.dll");
- if (info)
- {
- pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested);
- }
- }
- m_env.pRenderer->GetMemoryUsage(pSizer);
- }
- }
- if (m_env.pCryFont)
- {
- SIZER_COMPONENT_NAME(pSizer, "CryFont");
- {
- {
- SIZER_COMPONENT_NAME (pSizer, "$Allocations waste");
- const SmallModuleInfo* info = FindModuleInfo(stats, "CryFont.dll");
- if (info)
- {
- pSizer->AddObject(info, info->memInfo.allocated - info->memInfo.requested);
- }
- }
- m_env.pCryFont->GetMemoryUsage(pSizer);
- // m_pIFont and m_pIFontUi are both counted in pCryFont sizing if they exist.
- // no need to manually add them here.
- }
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "UserData");
- if (m_pUserCallback)
- {
- m_pUserCallback->GetMemoryUsage(pSizer);
- }
- }
- #ifdef WIN32
- {
- SIZER_COMPONENT_NAME(pSizer, "Code");
- GetExeSizes (pSizer, nPurpose);
- }
- #endif
- pSizer->End();
- }
- //////////////////////////////////////////////////////////////////////////
- const char* CSystem::GetUserName()
- {
- #if defined(WIN32) || defined(WIN64)
- static const int iNameBufferSize = 1024;
- static char szNameBuffer[iNameBufferSize];
- memset(szNameBuffer, 0, iNameBufferSize);
- DWORD dwSize = iNameBufferSize;
- wchar_t nameW[iNameBufferSize];
- ::GetUserNameW(nameW, &dwSize);
- cry_strcpy(szNameBuffer, CryStringUtils::WStrToUTF8(nameW));
- return szNameBuffer;
- #else
- #if defined(LINUX)
- static uid_t uid = geteuid ();
- static struct passwd* pw = getpwuid (uid);
- if (pw)
- {
- return (pw->pw_name);
- }
- else
- {
- return NULL;
- }
- #elif defined(APPLE)
- static const int iNameBufferSize = 1024;
- static char szNameBuffer[iNameBufferSize];
- if(SystemUtilsApple::GetUserName(szNameBuffer, iNameBufferSize))
- {
- return szNameBuffer;
- }
- else
- {
- return "";
- }
- #else
- return "";
- #endif
- #endif
- }
- //////////////////////////////////////////////////////////////////////////
- int CSystem::GetApplicationInstance()
- {
- #ifdef WIN32
- // tools that declare themselves as in "tool mode" may not access @user@ and may also not lock it
- if (gEnv->IsInToolMode())
- {
- return 0;
- }
- // this code below essentially "locks" an instance of the USER folder to a specific running application
- if (m_iApplicationInstance == -1)
- {
- string suffix;
- for (int instance = 0;; ++instance)
- {
- suffix.Format("(%d)", instance);
- HANDLE instanceMutex = CreateMutex(NULL, TRUE, "LumberyardApplication" + suffix);
- // search for duplicates
- if (GetLastError() != ERROR_ALREADY_EXISTS)
- {
- m_iApplicationInstance = instance;
- break;
- }
- }
- }
- return m_iApplicationInstance;
- #else
- return 0;
- #endif
- }
- int CSystem::GetApplicationLogInstance([[maybe_unused]] const char* logFilePath)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_MUTEX
- string suffix;
- int instance = 0;
- for (;; ++instance)
- {
- suffix.Format("(%d)", instance);
- HANDLE instanceMutex = CreateMutex(NULL, TRUE, logFilePath + suffix);
- if (GetLastError() != ERROR_ALREADY_EXISTS)
- {
- break;
- }
- }
- return instance;
- #else
- return 0;
- #endif
- }
- // refreshes the m_pMemStats if necessary; creates it if it's not created
- //////////////////////////////////////////////////////////////////////////
- void CSystem::TickMemStats(MemStatsPurposeEnum nPurpose, IResourceCollector* pResourceCollector)
- {
- // gather the statistics, if required
- // if there's no object, or if it's time to recalculate, or if it's for dump, then recalculate it
- if (!m_pMemStats || (m_env.pRenderer->GetFrameID(false) % m_cvMemStats->GetIVal()) == 0 || nPurpose == nMSP_ForDump)
- {
- if (!m_pMemStats)
- {
- if (m_cvMemStats->GetIVal() < 4 && m_cvMemStats->GetIVal())
- {
- GetILog()->LogToConsole("memstats is too small (%d). Performance impact can be significant. Please set to a greater value.", m_cvMemStats->GetIVal());
- }
- m_pMemStats = new CrySizerStats();
- }
- if (!m_pSizer)
- {
- m_pSizer = new CrySizerImpl();
- }
- m_pSizer->SetResourceCollector(pResourceCollector);
- m_pMemStats->startTimer(0, GetITimer());
- CollectMemStats (m_pSizer, nPurpose);
- m_pMemStats->stopTimer(0, GetITimer());
- m_pMemStats->startTimer(1, GetITimer());
- CrySizerStatsBuilder builder (m_pSizer);
- builder.build (m_pMemStats);
- m_pMemStats->stopTimer(1, GetITimer());
- m_pMemStats->startTimer(2, GetITimer());
- m_pSizer->clear();
- m_pMemStats->stopTimer(2, GetITimer());
- }
- else
- {
- m_pMemStats->incAgeFrames();
- }
- }
- //#define __HASXP
- // these 2 functions are duplicated in System.cpp in editor
- //////////////////////////////////////////////////////////////////////////
- #if !defined(LINUX)
- extern int CryStats(char* buf);
- #endif
- int CSystem::DumpMMStats(bool log)
- {
- #if defined(LINUX)
- return 0;
- #else
- if (log)
- {
- char buf[1024];
- int n = CryStats(buf);
- GetILog()->Log(buf);
- return n;
- }
- else
- {
- return CryStats(NULL);
- };
- #endif
- };
- //////////////////////////////////////////////////////////////////////////
- struct CryDbgModule
- {
- HANDLE heap;
- WIN_HMODULE handle;
- string name;
- DWORD dwSize;
- };
- //////////////////////////////////////////////////////////////////////////
- void CSystem::DebugStats([[maybe_unused]] bool checkpoint, [[maybe_unused]] bool leaks)
- {
- #ifdef WIN32
- std::vector<CryDbgModule> dbgmodules;
- //////////////////////////////////////////////////////////////////////////
- // Use windows Performance Monitoring API to enumerate all modules of current process.
- //////////////////////////////////////////////////////////////////////////
- HANDLE hSnapshot;
- hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
- if (hSnapshot != INVALID_HANDLE_VALUE)
- {
- MODULEENTRY32 me;
- memset (&me, 0, sizeof(me));
- me.dwSize = sizeof(me);
- if (Module32First (hSnapshot, &me))
- {
- // the sizes of each module group
- do
- {
- CryDbgModule module;
- module.handle = me.hModule;
- module.name = me.szModule;
- module.dwSize = me.modBaseSize;
- dbgmodules.push_back(module);
- } while (Module32Next(hSnapshot, &me));
- }
- CloseHandle (hSnapshot);
- }
- //////////////////////////////////////////////////////////////////////////
- ILog* log = GetILog();
- int totalal = 0, totalbl = 0, nolib = 0;
- #ifdef _DEBUG
- int extrastats[10];
- #endif
- int totalUsedInModules = 0;
- int countedMemoryModules = 0;
- for (int i = 0; i < (int)(dbgmodules.size()); i++)
- {
- if (!dbgmodules[i].handle)
- {
- CryLogAlways("WARNING: <CrySystem> CSystem::DebugStats: NULL handle for %s", dbgmodules[i].name.c_str());
- nolib++;
- continue;
- }
- ;
- typedef int (* PFN_MODULEMEMORY)();
- PFN_MODULEMEMORY fpCryModuleGetAllocatedMemory = (PFN_MODULEMEMORY)::GetProcAddress((HMODULE)dbgmodules[i].handle, "CryModuleGetAllocatedMemory");
- if (fpCryModuleGetAllocatedMemory)
- {
- int allocatedMemory = fpCryModuleGetAllocatedMemory();
- totalUsedInModules += allocatedMemory;
- countedMemoryModules++;
- CryLogAlways("%8d K used in Module %s: ", allocatedMemory / 1024, dbgmodules[i].name.c_str());
- }
- #ifdef _DEBUG
- typedef void (* PFNUSAGESUMMARY)(ILog* log, const char*, int*);
- typedef void (* PFNCHECKPOINT)();
- PFNUSAGESUMMARY fpu = (PFNUSAGESUMMARY)::GetProcAddress((HMODULE)dbgmodules[i].handle, "UsageSummary");
- PFNCHECKPOINT fpc = (PFNCHECKPOINT)::GetProcAddress((HMODULE)dbgmodules[i].handle, "CheckPoint");
- if (fpu && fpc)
- {
- if (checkpoint)
- {
- fpc();
- }
- else
- {
- extrastats[2] = (int)leaks;
- fpu(log, dbgmodules[i].name.c_str(), extrastats);
- totalal += extrastats[0];
- totalbl += extrastats[1];
- };
- }
- else
- {
- CryLogAlways("WARNING: <CrySystem> CSystem::DebugStats: could not retrieve function from DLL %s", dbgmodules[i].name.c_str());
- nolib++;
- };
- #endif
- typedef HANDLE(* PFNGETDLLHEAP)();
- PFNGETDLLHEAP fpg = (PFNGETDLLHEAP)::GetProcAddress((HMODULE)dbgmodules[i].handle, "GetDLLHeap");
- if (fpg)
- {
- dbgmodules[i].heap = fpg();
- }
- ;
- }
- ;
- CryLogAlways("-------------------------------------------------------");
- CryLogAlways("%8d K Total Memory Allocated in %d Modules", totalUsedInModules / 1024, countedMemoryModules);
- #ifdef _DEBUG
- CryLogAlways("$8GRAND TOTAL: %d k, %d blocks (%d dlls not included)", totalal / 1024, totalbl, nolib);
- CryLogAlways("estimated debugalloc overhead: between %d k and %d k", totalbl * 36 / 1024, totalbl * 72 / 1024);
- #endif
- //////////////////////////////////////////////////////////////////////////
- // Get HeapQueryInformation pointer if on windows XP.
- //////////////////////////////////////////////////////////////////////////
- typedef BOOL (WINAPI * FUNC_HeapQueryInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
- FUNC_HeapQueryInformation pFnHeapQueryInformation = NULL;
- HMODULE hKernelInstance = CryLoadLibrary("Kernel32.dll");
- if (hKernelInstance)
- {
- pFnHeapQueryInformation = (FUNC_HeapQueryInformation)(::GetProcAddress(hKernelInstance, "HeapQueryInformation"));
- }
- //////////////////////////////////////////////////////////////////////////
- const int MAXHANDLES = 100;
- HANDLE handles[MAXHANDLES];
- int realnumh = GetProcessHeaps(MAXHANDLES, handles);
- char hinfo[1024];
- PROCESS_HEAP_ENTRY phe;
- CryLogAlways("$6--------------------- dump of windows heaps ---------------------");
- int nTotalC = 0, nTotalCP = 0, nTotalUC = 0, nTotalUCP = 0, totalo = 0;
- for (int i = 0; i < realnumh; i++)
- {
- HANDLE hHeap = handles[i];
- HeapCompact(hHeap, 0);
- hinfo[0] = 0;
- if (pFnHeapQueryInformation)
- {
- pFnHeapQueryInformation(hHeap, HeapCompatibilityInformation, hinfo, 1024, NULL);
- }
- else
- {
- for (int m = 0; m < (int)(dbgmodules.size()); m++)
- {
- if (dbgmodules[m].heap == handles[i])
- {
- azstrcpy(hinfo, AZ_ARRAY_SIZE(hinfo), dbgmodules[m].name.c_str());
- }
- }
- }
- phe.lpData = NULL;
- int nCommitted = 0, nUncommitted = 0, nOverhead = 0;
- int nCommittedPieces = 0, nUncommittedPieces = 0;
- int nPrevRegionIndex = -1;
- while (HeapWalk(hHeap, &phe))
- {
- if (phe.wFlags & PROCESS_HEAP_REGION)
- {
- assert (++nPrevRegionIndex == phe.iRegionIndex);
- nCommitted += phe.Region.dwCommittedSize;
- nUncommitted += phe.Region.dwUnCommittedSize;
- assert (phe.cbData == 0 || (phe.wFlags & PROCESS_HEAP_ENTRY_BUSY));
- }
- else
- if (phe.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE)
- {
- nUncommittedPieces += phe.cbData;
- }
- else
- {
- //if (phe.wFlags & PROCESS_HEAP_ENTRY_BUSY)
- nCommittedPieces += phe.cbData;
- }
- {
- /*
- MEMORY_BASIC_INFORMATION mbi;
- if (VirtualQuery(phe.lpData, &mbi,sizeof(mbi)) == sizeof(mbi))
- {
- if (mbi.State == MEM_COMMIT)
- nCommittedPieces += phe.cbData;//mbi.RegionSize;
- //else
- // nUncommitted += mbi.RegionSize;
- }
- else
- nCommittedPieces += phe.cbData;
- */
- }
- nOverhead += phe.cbOverhead;
- }
- ;
- int nCommittedMin = min(nCommitted, nCommittedPieces);
- int nCommittedMax = max(nCommitted, nCommittedPieces);
- CryLogAlways("* heap %8x: %6d (or ~%6d) K in use, %6d..%6d K uncommitted, %6d K overhead (%s)\n",
- handles[i], nCommittedPieces / 1024, nCommitted / 1024, nUncommittedPieces / 1024, nUncommitted / 1024, nOverhead / 1024, hinfo);
- nTotalC += nCommitted;
- nTotalCP += nCommittedPieces;
- nTotalUC += nUncommitted;
- nTotalUCP += nUncommittedPieces;
- totalo += nOverhead;
- }
- ;
- CryLogAlways("$6----------------- total in heaps: %d megs committed (win stats shows ~%d) (%d..%d uncommitted, %d k overhead) ---------------------", nTotalCP / 1024 / 1024, nTotalC / 1024 / 1024, nTotalUCP / 1024 / 1024, nTotalUC / 1024 / 1024, totalo / 1024);
- #endif //WIN32
- };
- #ifdef WIN32
- struct DumpHeap32Stats
- {
- DumpHeap32Stats()
- : dwFree(0)
- , dwMoveable(0)
- , dwFixed(0)
- , dwUnknown(0)
- {
- }
- void operator += (const DumpHeap32Stats& right)
- {
- dwFree += right.dwFree;
- dwMoveable += right.dwMoveable;
- dwFixed += right.dwFixed;
- dwUnknown += right.dwUnknown;
- }
- DWORD dwFree;
- DWORD dwMoveable;
- DWORD dwFixed;
- DWORD dwUnknown;
- };
- static void DumpHeap32 (const HEAPLIST32& hl, DumpHeap32Stats& stats)
- {
- HEAPENTRY32 he;
- memset (&he, 0, sizeof(he));
- he.dwSize = sizeof(he);
- if (Heap32First (&he, hl.th32ProcessID, hl.th32HeapID))
- {
- DumpHeap32Stats heap;
- do
- {
- if (he.dwFlags & LF32_FREE)
- {
- heap.dwFree += he.dwBlockSize;
- }
- else
- if (he.dwFlags & LF32_MOVEABLE)
- {
- heap.dwMoveable += he.dwBlockSize;
- }
- else
- if (he.dwFlags & LF32_FIXED)
- {
- heap.dwFixed += he.dwBlockSize;
- }
- else
- {
- heap.dwUnknown += he.dwBlockSize;
- }
- } while (Heap32Next (&he));
- CryLogAlways ("%08X %6d %6d %6d (%d)", hl.th32HeapID, heap.dwFixed / 0x400, heap.dwFree / 0x400, heap.dwMoveable / 0x400, heap.dwUnknown / 0x400);
- stats += heap;
- }
- else
- {
- CryLogAlways ("%08X empty or invalid");
- }
- }
- //////////////////////////////////////////////////////////////////////////
- class CStringOrder
- {
- public:
- bool operator () (const char* szLeft, const char* szRight) const {return azstricmp(szLeft, szRight) < 0; }
- };
- typedef std::map<const char*, unsigned, CStringOrder> StringToSizeMap;
- void AddSize (StringToSizeMap& mapSS, const char* szString, unsigned nSize)
- {
- StringToSizeMap::iterator it = mapSS.find (szString);
- if (it == mapSS.end())
- {
- mapSS.insert (StringToSizeMap::value_type(szString, nSize));
- }
- else
- {
- it->second += nSize;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- const char* GetModuleGroup (const char* szString)
- {
- for (unsigned i = 0; i < sizeof(g_szModuleGroups) / sizeof(g_szModuleGroups[0]); ++i)
- {
- if (azstricmp(szString, g_szModuleGroups[i][0]) == 0)
- {
- return g_szModuleGroups[i][1];
- }
- }
- return "Other";
- }
- //////////////////////////////////////////////////////////////////////////
- void CSystem::GetExeSizes (ICrySizer* pSizer, MemStatsPurposeEnum nPurpose)
- {
- HANDLE hSnapshot;
- hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
- if (hSnapshot == INVALID_HANDLE_VALUE)
- {
- CryLogAlways ("Cannot get the module snapshot, error code %d", GetLastError());
- return;
- }
- DWORD dwProcessID = GetCurrentProcessId();
- MODULEENTRY32 me;
- memset (&me, 0, sizeof(me));
- me.dwSize = sizeof(me);
- if (Module32First (hSnapshot, &me))
- {
- // the sizes of each module group
- StringToSizeMap mapGroupSize;
- DWORD dwTotalModuleSize = 0;
- do
- {
- dwProcessID = me.th32ProcessID;
- const char* szGroup = GetModuleGroup (me.szModule);
- SIZER_COMPONENT_NAME(pSizer, szGroup);
- if (nPurpose == nMSP_ForDump)
- {
- SIZER_COMPONENT_NAME(pSizer, me.szModule);
- pSizer->AddObject(me.modBaseAddr, me.modBaseSize);
- }
- else
- {
- pSizer->AddObject(me.modBaseAddr, me.modBaseSize);
- }
- } while (Module32Next(hSnapshot, &me));
- }
- else
- {
- CryLogAlways ("No modules to dump");
- }
- CloseHandle (hSnapshot);
- }
- #endif
- //////////////////////////////////////////////////////////////////////////
- void CSystem::DumpWinHeaps()
- {
- #ifdef WIN32
- //
- // Retrieve modules and log them; remember the process id
- HANDLE hSnapshot;
- hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
- if (hSnapshot == INVALID_HANDLE_VALUE)
- {
- CryLogAlways ("Cannot get the module snapshot, error code %d", GetLastError());
- return;
- }
- DWORD dwProcessID = GetCurrentProcessId();
- MODULEENTRY32 me;
- memset (&me, 0, sizeof(me));
- me.dwSize = sizeof(me);
- if (Module32First (hSnapshot, &me))
- {
- // the sizes of each module group
- StringToSizeMap mapGroupSize;
- DWORD dwTotalModuleSize = 0;
- CryLogAlways ("base size module");
- do
- {
- dwProcessID = me.th32ProcessID;
- const char* szGroup = GetModuleGroup (me.szModule);
- CryLogAlways ("%08X %8X %25s - %s", me.modBaseAddr, me.modBaseSize, me.szModule, azstricmp(szGroup, "Other") ? szGroup : "");
- dwTotalModuleSize += me.modBaseSize;
- AddSize (mapGroupSize, szGroup, me.modBaseSize);
- } while (Module32Next(hSnapshot, &me));
- CryLogAlways ("------------------------------------");
- for (StringToSizeMap::iterator it = mapGroupSize.begin(); it != mapGroupSize.end(); ++it)
- {
- CryLogAlways (" %6.3f Mbytes - %s", double(it->second) / 0x100000, it->first);
- }
- CryLogAlways ("------------------------------------");
- CryLogAlways (" %6.3f Mbytes - TOTAL", double(dwTotalModuleSize) / 0x100000);
- CryLogAlways ("------------------------------------");
- }
- else
- {
- CryLogAlways ("No modules to dump");
- }
- CloseHandle (hSnapshot);
- //
- // Retrieve the heaps and dump each of them with a special function
- hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, 0);
- if (hSnapshot == INVALID_HANDLE_VALUE)
- {
- CryLogAlways ("Cannot get the heap LIST snapshot, error code %d", GetLastError());
- return;
- }
- HEAPLIST32 hl;
- memset (&hl, 0, sizeof(hl));
- hl.dwSize = sizeof(hl);
- CryLogAlways ("__Heap__ fixed free move (unknown)");
- if (Heap32ListFirst (hSnapshot, &hl))
- {
- DumpHeap32Stats stats;
- do
- {
- DumpHeap32 (hl, stats);
- } while (Heap32ListNext (hSnapshot, &hl));
- CryLogAlways ("-------------------------------------------------");
- CryLogAlways ("$6 %6.3f %6.3f %6.3f (%.3f) Mbytes", double(stats.dwFixed) / 0x100000, double(stats.dwFree) / 0x100000, double(stats.dwMoveable) / 0x100000, double(stats.dwUnknown) / 0x100000);
- CryLogAlways ("-------------------------------------------------");
- }
- else
- {
- CryLogAlways ("No heaps to dump");
- }
- CloseHandle(hSnapshot);
- #endif
- }
- // Make system error message string
- //////////////////////////////////////////////////////////////////////////
- //! \return pointer to the null terminated error string or 0
- static const char* GetLastSystemErrorMessage()
- {
- #ifdef WIN32
- DWORD dwError = GetLastError();
- static char szBuffer[512]; // function will return pointer to this buffer
- if (dwError)
- {
- LPVOID lpMsgBuf = 0;
- if (FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL))
- {
- cry_strcpy(szBuffer, (char*)lpMsgBuf);
- LocalFree(lpMsgBuf);
- }
- else
- {
- return 0;
- }
- return szBuffer;
- }
- #else
- return 0;
- #endif //WIN32
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- void CSystem::FatalError(const char* format, ...)
- {
- // Guard against reentrancy - out of memory fatal errors can become reentrant since logging can try to alloc.
- static bool currentlyReportingError = false;
- if (currentlyReportingError == true)
- {
- return;
- }
- currentlyReportingError = true;
- // format message
- va_list ArgList;
- char szBuffer[MAX_WARNING_LENGTH];
- const char* sPrefix = "";
- azstrcpy(szBuffer, MAX_WARNING_LENGTH, sPrefix);
- va_start(ArgList, format);
- azvsnprintf(szBuffer + strlen(sPrefix), MAX_WARNING_LENGTH - strlen(sPrefix), format, ArgList);
- va_end(ArgList);
- // get system error message before any attempt to write into log
- const char* szSysErrorMessage = GetLastSystemErrorMessage();
- CryLogAlways("=============================================================================");
- CryLogAlways("*ERROR");
- CryLogAlways("=============================================================================");
- // write both messages into log
- CryLogAlways("%s", szBuffer);
- if (szSysErrorMessage)
- {
- CryLogAlways("<CrySystem> Last System Error: %s", szSysErrorMessage);
- }
- if (GetUserCallback())
- {
- GetUserCallback()->OnError(szBuffer);
- }
- assert(szBuffer[0] >= ' ');
- // strcpy(szBuffer,szBuffer+1); // remove verbosity tag since it is not supported by ::MessageBox
- LogSystemInfo();
- CollectMemStats(0, nMSP_ForCrashLog);
- OutputDebugString(szBuffer);
- #ifdef WIN32
- OnFatalError(szBuffer);
- if (!g_cvars.sys_no_crash_dialog)
- {
- ICVar* pFullscreen = (gEnv && gEnv->pConsole) ? gEnv->pConsole->GetCVar("r_Fullscreen") : 0;
- if (pFullscreen && pFullscreen->GetIVal() != 0 && gEnv->pRenderer && gEnv->pRenderer->GetHWND())
- {
- ::ShowWindow((HWND)gEnv->pRenderer->GetHWND(), SW_MINIMIZE);
- }
- ::MessageBox(NULL, szBuffer, "Lumberyard Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
- }
- // Dump callstack.
- #endif
- #if defined (WIN32)
- //Triggers a fatal error, so the DebugCallstack can create the error.log and terminate the application
- IDebugCallStack::instance()->FatalError(szBuffer);
- #elif defined(AZ_RESTRICTED_PLATFORM)
- #define AZ_RESTRICTED_SECTION SYSTEMWIN32_CPP_SECTION_1
- #include AZ_RESTRICTED_FILE(SystemWin32_cpp)
- #endif
- CryDebugBreak();
- // app can not continue
- #ifdef _DEBUG
- #if defined(WIN32) && !defined(WIN64)
- DEBUG_BREAK;
- #endif
- #else
- #if defined(WIN32) || defined(WIN64)
- _flushall();
- // on windows, _exit does all sorts of things which can cause cleanup to fail during a crash, we need to terminate instead.
- TerminateProcess(GetCurrentProcess(), 1);
- #endif
- #if defined(AZ_RESTRICTED_PLATFORM)
- #define AZ_RESTRICTED_SECTION SYSTEMWIN32_CPP_SECTION_2
- #include AZ_RESTRICTED_FILE(SystemWin32_cpp)
- #endif
- #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
- #undef AZ_RESTRICTED_SECTION_IMPLEMENTED
- #else
- _exit(1);
- #endif
- #endif
- }
- void CSystem::ReportBug([[maybe_unused]] const char* format, ...)
- {
- #if defined (WIN32)
- va_list ArgList;
- char szBuffer[MAX_WARNING_LENGTH];
- const char* sPrefix = "";
- azstrcpy(szBuffer, MAX_WARNING_LENGTH, sPrefix);
- va_start(ArgList, format);
- azvsnprintf(szBuffer + strlen(sPrefix), MAX_WARNING_LENGTH - strlen(sPrefix), format, ArgList);
- va_end(ArgList);
- IDebugCallStack::instance()->ReportBug(szBuffer);
- #endif
- }
- //////////////////////////////////////////////////////////////////////////
- void CSystem::debug_GetCallStack(const char** pFunctions, int& nCount)
- {
- #if defined(WIN32)
- using namespace AZ::Debug;
- int nMaxCount = nCount;
- StackFrame* frames = (StackFrame*)AZ_ALLOCA(sizeof(StackFrame)*nMaxCount);
- unsigned int numFrames = StackRecorder::Record(frames, nMaxCount, 1);
- SymbolStorage::StackLine* textLines = (SymbolStorage::StackLine*)AZ_ALLOCA(sizeof(SymbolStorage::StackLine)*nMaxCount);
- SymbolStorage::DecodeFrames(frames, numFrames, textLines);
- for (int i = 0; i < numFrames; i++)
- {
- pFunctions[i] = textLines[i];
- }
- nCount = numFrames;
- #define AZ_RESTRICTED_SECTION_IMPLEMENTED
- #elif defined(AZ_RESTRICTED_PLATFORM)
- #define AZ_RESTRICTED_SECTION SYSTEMWIN32_CPP_SECTION_3
- #include AZ_RESTRICTED_FILE(SystemWin32_cpp)
- #endif
- #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
- #undef AZ_RESTRICTED_SECTION_IMPLEMENTED
- #else
- AZ_UNUSED(pFunctions);
- nCount = 0;
- #endif
- }
- //////////////////////////////////////////////////////////////////////////
- void CSystem::debug_LogCallStack(int nMaxFuncs, [[maybe_unused]] int nFlags)
- {
- if (nMaxFuncs > 32)
- {
- nMaxFuncs = 32;
- }
- // Print call stack for each find.
- const char* funcs[32];
- int nCount = nMaxFuncs;
- int nCurFrame = 0;
- if (m_env.pRenderer)
- {
- nCurFrame = (int)m_env.pRenderer->GetFrameID(false);
- }
- CryLogAlways(" ----- CallStack (Frame: %d) -----", nCurFrame);
- GetISystem()->debug_GetCallStack(funcs, nCount);
- for (int i = 1; i < nCount; i++) // start from 1 to skip this function.
- {
- CryLogAlways(" %02d) %s", i, funcs[i]);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // Support relaunching for windows media center edition.
- //////////////////////////////////////////////////////////////////////////
- #if defined(WIN32)
- #if (_WIN32_WINNT < 0x0501)
- #define SM_MEDIACENTER 87
- #endif
- bool CSystem::ReLaunchMediaCenter()
- {
- // Skip if not running on a Media Center
- if (GetSystemMetrics(SM_MEDIACENTER) == 0)
- {
- return false;
- }
- // Get the path to Media Center
- char szExpandedPath[AZ_MAX_PATH_LEN];
- if (!ExpandEnvironmentStrings("%SystemRoot%\\ehome\\ehshell.exe", szExpandedPath, AZ_MAX_PATH_LEN))
- {
- return false;
- }
- // Skip if ehshell.exe doesn't exist
- if (GetFileAttributes(szExpandedPath) == 0xFFFFFFFF)
- {
- return false;
- }
- // Launch ehshell.exe
- INT_PTR result = (INT_PTR)ShellExecute(NULL, TEXT("open"), szExpandedPath, NULL, NULL, SW_SHOWNORMAL);
- return (result > 32);
- }
- #else
- bool CSystem::ReLaunchMediaCenter()
- {
- return false;
- }
- #endif //defined(WIN32)
- //////////////////////////////////////////////////////////////////////////
- #if defined(WIN32)
- void CSystem::LogSystemInfo()
- {
- //////////////////////////////////////////////////////////////////////
- // Write the system informations to the log
- //////////////////////////////////////////////////////////////////////
- char szBuffer[1024];
- char szProfileBuffer[128];
- char szLanguageBuffer[64];
- //char szCPUModel[64];
- char* pChar = 0;
- MEMORYSTATUSEX MemoryStatus;
- MemoryStatus.dwLength = sizeof(MemoryStatus);
- DEVMODE DisplayConfig;
- OSVERSIONINFO OSVerInfo;
- OSVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- // log Windows type
- Win32SysInspect::GetOS(m_env.pi.winVer, m_env.pi.win64Bit, szBuffer, sizeof(szBuffer));
- CryLogAlways(szBuffer);
- // log system language
- GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, szLanguageBuffer, sizeof(szLanguageBuffer));
- azsprintf(szBuffer, "System language: %s", szLanguageBuffer);
- CryLogAlways(szBuffer);
- // log Windows directory
- GetWindowsDirectory(szBuffer, sizeof(szBuffer));
- string str = "Windows Directory: \"";
- str += szBuffer;
- str += "\"";
- CryLogAlways(str);
- //////////////////////////////////////////////////////////////////////
- // Send system time & date
- //////////////////////////////////////////////////////////////////////
- str = "Local time is ";
- azstrtime(szBuffer);
- str += szBuffer;
- str += " ";
- _strdate_s(szBuffer);
- str += szBuffer;
- azsprintf(szBuffer, ", system running for %lu minutes", GetTickCount() / 60000);
- str += szBuffer;
- CryLogAlways(str);
- //////////////////////////////////////////////////////////////////////
- // Send system memory status
- //////////////////////////////////////////////////////////////////////
- GlobalMemoryStatusEx(&MemoryStatus);
- azsprintf(szBuffer, "%I64dMB physical memory installed, %I64dMB available, %I64dMB virtual memory installed, %ld percent of memory in use",
- MemoryStatus.ullTotalPhys / 1048576 + 1,
- MemoryStatus.ullAvailPhys / 1048576,
- MemoryStatus.ullTotalVirtual / 1048576,
- MemoryStatus.dwMemoryLoad);
- CryLogAlways(szBuffer);
- if (GetISystem()->GetIMemoryManager())
- {
- IMemoryManager::SProcessMemInfo memCounters;
- GetISystem()->GetIMemoryManager()->GetProcessMemInfo(memCounters);
- uint64 PagefileUsage = memCounters.PagefileUsage;
- uint64 PeakPagefileUsage = memCounters.PeakPagefileUsage;
- uint64 WorkingSetSize = memCounters.WorkingSetSize;
- azsprintf(szBuffer, "PageFile usage: %I64dMB, Working Set: %I64dMB, Peak PageFile usage: %I64dMB,",
- (uint64)PagefileUsage / (1024 * 1024),
- (uint64)WorkingSetSize / (1024 * 1024),
- (uint64)PeakPagefileUsage / (1024 * 1024));
- CryLogAlways(szBuffer);
- }
- //////////////////////////////////////////////////////////////////////
- // Send display settings
- //////////////////////////////////////////////////////////////////////
- EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DisplayConfig);
- GetPrivateProfileString("boot.description", "display.drv",
- "(Unknown graphics card)", szProfileBuffer, sizeof(szProfileBuffer),
- "system.ini");
- azsprintf(szBuffer, "Current display mode is %lux%lux%lu, %s",
- DisplayConfig.dmPelsWidth, DisplayConfig.dmPelsHeight,
- DisplayConfig.dmBitsPerPel, szProfileBuffer);
- CryLogAlways(szBuffer);
- //////////////////////////////////////////////////////////////////////
- // Send input device configuration
- //////////////////////////////////////////////////////////////////////
- str = "";
- // Detect the keyboard type
- switch (GetKeyboardType(0))
- {
- case 1:
- str = "IBM PC/XT (83-key)";
- break;
- case 2:
- str = "ICO (102-key)";
- break;
- case 3:
- str = "IBM PC/AT (84-key)";
- break;
- case 4:
- str = "IBM enhanced (101/102-key)";
- break;
- case 5:
- str = "Nokia 1050";
- break;
- case 6:
- str = "Nokia 9140";
- break;
- case 7:
- str = "Japanese";
- break;
- default:
- str = "Unknown";
- break;
- }
- // Any mouse attached ?
- if (!GetSystemMetrics(SM_MOUSEPRESENT))
- {
- CryLogAlways(str + " keyboard and no mouse installed");
- }
- else
- {
- azsprintf(szBuffer, " keyboard and %i+ button mouse installed",
- GetSystemMetrics(SM_CMOUSEBUTTONS));
- CryLogAlways(str + szBuffer);
- }
- CryLogAlways("--------------------------------------------------------------------------------");
- }
- #else
- void CSystem::LogSystemInfo()
- {
- }
- #endif
- #if (defined(WIN32) || defined(WIN64))
- //////////////////////////////////////////////////////////////////////////
- bool CSystem::GetWinGameFolder(char* szMyDocumentsPath, int maxPathSize)
- {
- bool bSucceeded = false;
- // check Vista and later OS first
- HMODULE shell32 = LoadLibraryA("Shell32.dll");
- if (shell32)
- {
- typedef long (__stdcall * T_SHGetKnownFolderPath)(REFKNOWNFOLDERID rfid, unsigned long dwFlags, void* hToken, wchar_t** ppszPath);
- T_SHGetKnownFolderPath SHGetKnownFolderPath = (T_SHGetKnownFolderPath)GetProcAddress(shell32, "SHGetKnownFolderPath");
- if (SHGetKnownFolderPath)
- {
- // We must be running Vista or newer
- wchar_t* wMyDocumentsPath;
- HRESULT hr = SHGetKnownFolderPath(FOLDERID_SavedGames, KF_FLAG_CREATE | KF_FLAG_DONT_UNEXPAND, NULL, &wMyDocumentsPath);
- bSucceeded = SUCCEEDED(hr);
- if (bSucceeded)
- {
- // Convert from UNICODE to UTF-8
- cry_strcpy(szMyDocumentsPath, maxPathSize, CryStringUtils::WStrToUTF8(wMyDocumentsPath));
- CoTaskMemFree(wMyDocumentsPath);
- }
- }
- FreeLibrary(shell32);
- }
- if (!bSucceeded)
- {
- // check pre-vista OS if not succeeded before
- wchar_t wMyDocumentsPath[AZ_MAX_PATH_LEN];
- bSucceeded = SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, wMyDocumentsPath));
- if (bSucceeded)
- {
- cry_strcpy(szMyDocumentsPath, maxPathSize, CryStringUtils::WStrToUTF8(wMyDocumentsPath));
- }
- }
- return bSucceeded;
- }
- #endif
- //////////////////////////////////////////////////////////////////////////
- void CSystem::DetectGameFolderAccessRights()
- {
- // This code is trying to figure out if the current folder we are now running under have write access.
- // By default assume folder is not writable.
- // If folder is writable game.log is saved there, otherwise it is saved in user documents folder.
- #if defined(WIN32)
- DWORD DesiredAccess = FILE_GENERIC_WRITE;
- DWORD GrantedAccess = 0;
- DWORD dwRes = 0;
- PACL pDACL = NULL;
- PSECURITY_DESCRIPTOR pSD = NULL;
- HANDLE hClientToken = 0;
- PRIVILEGE_SET PrivilegeSet;
- DWORD PrivilegeSetLength = sizeof(PrivilegeSet);
- BOOL bAccessStatus = FALSE;
- // Get a pointer to the existing DACL.
- dwRes = GetNamedSecurityInfo(".", SE_FILE_OBJECT,
- DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
- NULL, NULL, &pDACL, NULL, &pSD);
- if (ERROR_SUCCESS != dwRes)
- {
- //
- assert(0);
- }
- if (!ImpersonateSelf(SecurityIdentification))
- {
- return;
- }
- if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hClientToken) && hClientToken != 0)
- {
- return;
- }
- GENERIC_MAPPING GenMap;
- GenMap.GenericRead = FILE_GENERIC_READ;
- GenMap.GenericWrite = FILE_GENERIC_WRITE;
- GenMap.GenericExecute = FILE_GENERIC_EXECUTE;
- GenMap.GenericAll = FILE_ALL_ACCESS;
- MapGenericMask(&DesiredAccess, &GenMap);
- if (!AccessCheck(pSD, hClientToken, DesiredAccess, &GenMap, &PrivilegeSet, &PrivilegeSetLength, &GrantedAccess, &bAccessStatus))
- {
- RevertToSelf();
- CloseHandle(hClientToken);
- return;
- }
- CloseHandle(hClientToken);
- RevertToSelf();
- if (bAccessStatus)
- {
- m_bGameFolderWritable = true;
- }
- #elif defined(MOBILE)
- char cwd[AZ_MAX_PATH_LEN];
- if (getcwd(cwd, AZ_MAX_PATH_LEN) != NULL)
- {
- if (0 == access(cwd, W_OK))
- {
- m_bGameFolderWritable = true;
- }
- }
- #endif //WIN32
- }
- /////////////////////////////////`/////////////////////////////////////////
- void CSystem::EnableFloatExceptions([[maybe_unused]] int type)
- {
- #ifndef _RELEASE
- #if defined(WIN32)
- #if defined(WIN32) && !defined(WIN64)
- // Optimization
- // Enable DAZ/FZ
- // Denormals Are Zeros
- // Flush-to-Zero
- _controlfp(_DN_FLUSH, _MCW_DN);
- #endif //#if defined(WIN32) && !defined(WIN64)
- AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option")
- _controlfp(_DN_FLUSH, _MCW_DN);
- if (type == 0)
- {
- // mask all floating exceptions off.
- _controlfp(_EM_INEXACT | _EM_UNDERFLOW | _EM_OVERFLOW | _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE, _MCW_EM);
- }
- else
- {
- // Clear pending exceptions
- _fpreset();
- if (type == 1)
- {
- // enable just the most important fp-exceptions.
- _controlfp(_EM_INEXACT | _EM_UNDERFLOW | _EM_OVERFLOW, _MCW_EM); // Enable floating point exceptions.
- }
- if (type == 2)
- {
- // enable ALL floating point exceptions.
- _controlfp(_EM_INEXACT, _MCW_EM);
- }
- }
- AZ_POP_DISABLE_WARNING
- #endif //#if defined(WIN32) && !defined(WIN64)
- #ifdef WIN32
- _mm_setcsr(_mm_getcsr() & ~0x280 | (type > 0 ? 0 : 0x280));
- #endif
- #endif //_RELEASE
- }
|