/* * 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 "SystemInit.h" #if defined(AZ_RESTRICTED_PLATFORM) || defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) #undef AZ_RESTRICTED_SECTION #define SYSTEMINIT_CPP_SECTION_1 1 #define SYSTEMINIT_CPP_SECTION_2 2 #define SYSTEMINIT_CPP_SECTION_3 3 #define SYSTEMINIT_CPP_SECTION_4 4 #define SYSTEMINIT_CPP_SECTION_5 5 #define SYSTEMINIT_CPP_SECTION_6 6 #define SYSTEMINIT_CPP_SECTION_7 7 #define SYSTEMINIT_CPP_SECTION_8 8 #define SYSTEMINIT_CPP_SECTION_9 9 #define SYSTEMINIT_CPP_SECTION_10 10 #define SYSTEMINIT_CPP_SECTION_11 11 #define SYSTEMINIT_CPP_SECTION_12 12 #define SYSTEMINIT_CPP_SECTION_13 13 #define SYSTEMINIT_CPP_SECTION_14 14 #define SYSTEMINIT_CPP_SECTION_15 15 #define SYSTEMINIT_CPP_SECTION_16 16 #define SYSTEMINIT_CPP_SECTION_17 17 #endif #if defined(MAP_LOADING_SLICING) #include "SystemScheduler.h" #endif // defined(MAP_LOADING_SLICING) #include "CryLibrary.h" #include "CryPath.h" #include #include #include "CryFontBus.h" #include #include #include #include #include // for AZ_MAX_PATH_LEN #include #include #include #include #include #include #include #include #include "AZCoreLogSink.h" #include #include #include #include #include #include #include #include #include #include #include #if defined(APPLE) || defined(LINUX) #include #include #endif #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include "windows.h" #include // To enable profiling with vtune (https://software.intel.com/en-us/intel-vtune-amplifier-xe), make sure the line below is not commented out //#define PROFILE_WITH_VTUNE #endif //WIN32 #include #include #include #include #include #include #include #include #include #include #include "HMDCVars.h" #include #include #include "XConsole.h" #include "Log.h" #include "XML/xml.h" #include "StreamEngine/StreamEngine.h" #include "PhysRenderer.h" #include "LocalizedStringManager.h" #include "SystemEventDispatcher.h" #include "Statistics/LocalMemoryUsage.h" #include "ThreadConfigManager.h" #include "Validator.h" #include "ServerThrottle.h" #include "SystemCFG.h" #include "AutoDetectSpec.h" #include "ResourceManager.h" #include "VisRegTest.h" #include "MTSafeAllocator.h" #include "NotificationNetwork.h" #include "ExtensionSystem/CryFactoryRegistryImpl.h" #include "ExtensionSystem/TestCases/TestExtensions.h" #include "ProfileLogSystem.h" #include "SoftCode/SoftCodeMgr.h" #include "ZLibCompressor.h" #include "ZLibDecompressor.h" #include "ZStdDecompressor.h" #include "LZ4Decompressor.h" #include "OverloadSceneManager/OverloadSceneManager.h" #include "ServiceNetwork.h" #include "RemoteCommand.h" #include "LevelSystem/LevelSystem.h" #include "ViewSystem/ViewSystem.h" #include #include #include #include #include "PerfHUD.h" #include "MiniGUI/MiniGUI.h" #if USE_STEAM #include "Steamworks/public/steam/steam_api.h" #include "Steamworks/public/steam/isteamremotestorage.h" #endif #if defined(IOS) #include "IOSConsole.h" #endif #if defined(ANDROID) #include #include "AndroidConsole.h" #if !defined(AZ_RELEASE_BUILD) #include "ThermalInfoAndroid.h" #endif // !defined(AZ_RELEASE_BUILD) #endif #if defined(AZ_PLATFORM_ANDROID) || defined(AZ_PLATFORM_IOS) #include "MobileDetectSpec.h" #endif #include "IDebugCallStack.h" #include "WindowsConsole.h" #if defined(EXTERNAL_CRASH_REPORTING) #include #endif // select the asset processor based on cvars and defines. // uncomment the following and edit the path where it is instantiated if you'd like to use the test file client //#define USE_TEST_FILE_CLIENT #if defined(REMOTE_ASSET_PROCESSOR) // Over here, we'd put the header to the Remote Asset Processor interface (as opposed to the Local built in version below) # include #endif // if we enable the built-in local version instead of remote: #if defined(CRY_ENABLE_RC_HELPER) #include "ResourceCompilerHelper.h" #endif #ifdef WIN32 extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExceptionPointers); #endif #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_14 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif #if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER #include #include void CryEngineSignalHandler(int signal) { char resolvedPath[_MAX_PATH]; // it is assumed that @log@ points at the appropriate place (so for apple, to the user profile dir) if (AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath("@log@/crash.log", resolvedPath, _MAX_PATH)) { fprintf(stderr, "Crash Signal Handler - logged to %s\n", resolvedPath); FILE* file = fopen(resolvedPath, "a"); if (file) { char sTime[128]; time_t ltime; time(<ime); struct tm* today = localtime(<ime); strftime(sTime, 40, "<%Y-%m-%d %H:%M:%S> ", today); fprintf(file, "%s: Error: signal %s:\n", sTime, strsignal(signal)); fflush(file); void* array[100]; int s = backtrace(array, 100); backtrace_symbols_fd(array, s, fileno(file)); fclose(file); CryLogAlways("Successfully recorded crash file: '%s'", resolvedPath); abort(); } } CryLogAlways("Could not record crash file..."); abort(); } #endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER #if defined(USE_UNIXCONSOLE) #if defined(LINUX) && !defined(ANDROID) CUNIXConsole* pUnixConsole; #endif #endif // USE_UNIXCONSOLE ////////////////////////////////////////////////////////////////////////// #define DEFAULT_LOG_FILENAME "@log@/Log.txt" #define CRYENGINE_ENGINE_FOLDER "Engine" ////////////////////////////////////////////////////////////////////////// #define CRYENGINE_DEFAULT_LOCALIZATION_LANG "en-US" #define LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME "Libs/Localization/localization.xml" #define LOAD_LEGACY_RENDERER_FOR_EDITOR true // If you set this to false you must for now also set 'ed_useAtomNativeViewport' to true (see /Code/Sandbox/Editor/ViewManager.cpp) #define LOAD_LEGACY_RENDERER_FOR_LAUNCHER true ////////////////////////////////////////////////////////////////////////// // Where possible, these are defaults used to initialize cvars // System.cfg can then be used to override them // This includes the Game DLL, although it is loaded elsewhere #define DLL_FONT "CryFont" #define DLL_3DENGINE "Cry3DEngine" #define DLL_RENDERER_DX9 "CryRenderD3D9" #define DLL_RENDERER_DX11 "CryRenderD3D11" #define DLL_RENDERER_DX12 "CryRenderD3D12" #define DLL_RENDERER_METAL "CryRenderMetal" #define DLL_RENDERER_GL "CryRenderGL" #define DLL_RENDERER_NULL "CryRenderNULL" #define DLL_SHINE "LyShine" ////////////////////////////////////////////////////////////////////////// #if defined(WIN32) || defined(LINUX) || defined(APPLE) # define DLL_MODULE_INIT_ISYSTEM "ModuleInitISystem" # define DLL_MODULE_SHUTDOWN_ISYSTEM "ModuleShutdownISystem" # define DLL_INITFUNC_RENDERER "PackageRenderConstructor" # define DLL_INITFUNC_SOUND "CreateSoundSystem" # define DLL_INITFUNC_FONT "CreateCryFontInterface" # define DLL_INITFUNC_3DENGINE "CreateCry3DEngine" # define DLL_INITFUNC_UI "CreateLyShineInterface" #define AZ_RESTRICTED_SECTION_IMPLEMENTED #elif defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_1 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else # define DLL_MODULE_INIT_ISYSTEM (LPCSTR)2 # define DLL_MODULE_SHUTDOWN_ISYSTEM (LPCSTR)3 # define DLL_INITFUNC_RENDERER (LPCSTR)1 # define DLL_INITFUNC_RENDERER (LPCSTR)1 # define DLL_INITFUNC_SOUND (LPCSTR)1 # define DLL_INITFUNC_PHYSIC (LPCSTR)1 # define DLL_INITFUNC_FONT (LPCSTR)1 # define DLL_INITFUNC_3DENGINE (LPCSTR)1 # define DLL_INITFUNC_UI (LPCSTR)1 #endif #define AZ_TRACE_SYSTEM_WINDOW AZ::Debug::Trace::GetDefaultSystemWindow() extern CMTSafeHeap* g_pPakHeap; #ifdef WIN32 extern HMODULE gDLLHandle; #endif namespace { #if defined(AZ_PLATFORM_WINDOWS) // on windows, we lock our cache using a lockfile. On other platforms this is not necessary since devices like ios, android, consoles cannot // run more than one game process that uses the same folder anyway. HANDLE g_cacheLock = INVALID_HANDLE_VALUE; #endif } //static int g_sysSpecChanged = false; const char* g_szLvlResExt = "_LvlRes.txt"; struct SCVarsClientConfigSink : public ILoadConfigurationEntrySink { virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, [[maybe_unused]] const char* szGroup) { gEnv->pConsole->SetClientDataProbeString(szKey, szValue); } }; ////////////////////////////////////////////////////////////////////////// static inline void InlineInitializationProcessing([[maybe_unused]] const char* sDescription) { assert(CryMemory::IsHeapValid()); if (gEnv->pLog) { gEnv->pLog->UpdateLoadingScreen(0); } } ////////////////////////////////////////////////////////////////////////// AZ_PUSH_DISABLE_WARNING(4723, "-Wunknown-warning-option") // potential divide by 0 (needs to wrap the function) static void CmdCrashTest(IConsoleCmdArgs* pArgs) { assert(pArgs); if (pArgs->GetArgCount() == 2) { //This method intentionally crashes, a lot. int crashType = atoi(pArgs->GetArg(1)); switch (crashType) { case 1: { int* p = 0; PREFAST_SUPPRESS_WARNING(6011) * p = 0xABCD; } break; case 2: { float a = 1.0f; memset(&a, 0, sizeof(a)); float* b = &a; float c = 3; CryLog("%f", (c / *b)); } break; case 3: while (true) { char* element = new char[10240]; } break; case 4: CryFatalError("sys_crashtest 4"); break; case 5: while (true) { char* element = new char[128]; //testing the crash handler an exception in the cry memory allocation occurred } case 6: { AZ_Assert(false, "Testing assert for testing crashes"); } break; case 7: __debugbreak(); break; case 8: CrySleep(1000 * 60 * 10); break; } } } AZ_POP_DISABLE_WARNING #if USE_STEAM ////////////////////////////////////////////////////////////////////////// static void CmdWipeSteamCloud(IConsoleCmdArgs* pArgs) { if (!gEnv->pSystem->SteamInit()) { return; } int32 fileCount = SteamRemoteStorage()->GetFileCount(); for (int i = 0; i < fileCount; i++) { int32 size = 0; const char* name = SteamRemoteStorage()->GetFileNameAndSize(i, &size); bool success = SteamRemoteStorage()->FileDelete(name); CryLog("Deleting file: %s - success: %d", name, success); } } #endif ////////////////////////////////////////////////////////////////////////// struct SysSpecOverrideSink : public ILoadConfigurationEntrySink { virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup) { ICVar* pCvar = gEnv->pConsole->GetCVar(szKey); if (pCvar) { const bool wasNotInConfig = ((pCvar->GetFlags() & VF_WASINCONFIG) == 0); bool applyCvar = wasNotInConfig; if (applyCvar == false) { // Special handling for sys_spec_full if (azstricmp(szKey, "sys_spec_full") == 0) { // If it is set to 0 then ignore this request to set to something else // If it is set to 0 then the user wants to changes system spec settings in system.cfg if (pCvar->GetIVal() != 0) { applyCvar = true; } } else { // This could bypass the restricted/whitelisted cvar checks that exist elsewhere depending on // the calling code so we also need check here before setting. bool isConst = pCvar->IsConstCVar(); bool isCheat = ((pCvar->GetFlags() & (VF_CHEAT | VF_CHEAT_NOCHECK | VF_CHEAT_ALWAYS_CHECK)) != 0); bool isReadOnly = ((pCvar->GetFlags() & VF_READONLY) != 0); bool isDeprecated = ((pCvar->GetFlags() & VF_DEPRECATED) != 0); bool allowApplyCvar = true; bool whitelisted = true; #if defined CVARS_WHITELIST ICVarsWhitelist* cvarWhitelist = gEnv->pSystem->GetCVarsWhiteList(); whitelisted = cvarWhitelist ? cvarWhitelist->IsWhiteListed(szKey, true) : true; #endif if ((isConst || isCheat || isReadOnly) || isDeprecated) { allowApplyCvar = !isDeprecated && (gEnv->pSystem->IsDevMode()) || (gEnv->IsEditor()); } if ((allowApplyCvar && whitelisted) || ALLOW_CONST_CVAR_MODIFICATIONS) { applyCvar = true; } } } if (applyCvar) { pCvar->Set(szValue); } else { CryLogAlways("NOT VF_WASINCONFIG Ignoring cvar '%s' new value '%s' old value '%s' group '%s'", szKey, szValue, pCvar->GetString(), szGroup); } } else { CryLogAlways("Can't find cvar '%s' value '%s' group '%s'", szKey, szValue, szGroup); } } }; #if !defined(CONSOLE) struct SysSpecOverrideSinkConsole : public ILoadConfigurationEntrySink { virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup) { // Ignore platform-specific cvars that should just be executed on the console if (azstricmp(szGroup, "Platform") == 0) { return; } ICVar* pCvar = gEnv->pConsole->GetCVar(szKey); if (pCvar) { pCvar->Set(szValue); } else { // If the cvar doesn't exist, calling this function only saves the value in case it's registered later where // at that point it will be set from the stored value. This is required because otherwise registering the // cvar bypasses any callbacks and uses values directly from the cvar group files. gEnv->pConsole->LoadConfigVar(szKey, szValue); } } }; #endif static ESystemConfigPlatform GetDevicePlatform() { #if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX) return CONFIG_PC; #define AZ_RESTRICTED_SECTION_IMPLEMENTED #elif defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_2 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #elif defined(AZ_PLATFORM_ANDROID) return CONFIG_ANDROID; #elif defined(AZ_PLATFORM_IOS) return CONFIG_IOS; #elif defined(AZ_PLATFORM_MAC) return CONFIG_OSX_METAL; #else AZ_Assert(false, "Platform not supported"); return CONFIG_INVALID_PLATFORM; #endif } static void GetSpecConfigFileToLoad(ICVar* pVar, AZStd::string& cfgFile, ESystemConfigPlatform platform) { switch (platform) { case CONFIG_PC: cfgFile = "pc"; break; case CONFIG_ANDROID: cfgFile = "android"; break; case CONFIG_IOS: cfgFile = "ios"; break; #if defined(AZ_PLATFORM_JASPER) || defined(TOOLS_SUPPORT_JASPER) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_3 #include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, jasper) #endif #if defined(AZ_PLATFORM_PROVO) || defined(TOOLS_SUPPORT_PROVO) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_3 #include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, provo) #endif #if defined(AZ_PLATFORM_SALEM) || defined(TOOLS_SUPPORT_SALEM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_3 #include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, salem) #endif case CONFIG_OSX_METAL: cfgFile = "osx_metal"; break; case CONFIG_OSX_GL: // Spec level is hardcoded for these platforms cfgFile = ""; return; default: AZ_Assert(false, "Platform not supported"); return; } switch (pVar->GetIVal()) { case CONFIG_AUTO_SPEC: // Spec level is set for autodetection cfgFile = ""; break; case CONFIG_LOW_SPEC: cfgFile += "_low.cfg"; break; case CONFIG_MEDIUM_SPEC: cfgFile += "_medium.cfg"; break; case CONFIG_HIGH_SPEC: cfgFile += "_high.cfg"; break; case CONFIG_VERYHIGH_SPEC: #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_4 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif cfgFile += "_veryhigh.cfg"; break; default: AZ_Assert(false, "Invalid value for r_GraphicsQuality"); break; } } static void LoadDetectedSpec(ICVar* pVar) { CDebugAllowFileAccess ignoreInvalidFileAccess; SysSpecOverrideSink sysSpecOverrideSink; ILoadConfigurationEntrySink* pSysSpecOverrideSinkConsole = nullptr; #if !defined(CONSOLE) SysSpecOverrideSinkConsole sysSpecOverrideSinkConsole; pSysSpecOverrideSinkConsole = &sysSpecOverrideSinkConsole; #endif // g_sysSpecChanged = true; static int no_recursive = false; if (no_recursive) { return; } no_recursive = true; int spec = pVar->GetIVal(); ESystemConfigPlatform platform = GetDevicePlatform(); if (gEnv->IsEditor()) { ESystemConfigPlatform configPlatform = GetISystem()->GetConfigPlatform(); // Check if the config platform is set first. if (configPlatform != CONFIG_INVALID_PLATFORM) { platform = configPlatform; } } AZStd::string configFile; GetSpecConfigFileToLoad(pVar, configFile, platform); if (configFile.length()) { GetISystem()->LoadConfiguration(configFile.c_str(), platform == CONFIG_PC ? &sysSpecOverrideSink : pSysSpecOverrideSinkConsole); } else { // Automatically sets graphics quality - spec level autodetected for ios/android, hardcoded for all other platforms switch (platform) { case CONFIG_PC: { // TODO: add support for autodetection pVar->Set(CONFIG_VERYHIGH_SPEC); GetISystem()->LoadConfiguration("pc_veryhigh.cfg", &sysSpecOverrideSink); break; } case CONFIG_ANDROID: { #if defined(AZ_PLATFORM_ANDROID) AZStd::string file; if (MobileSysInspect::GetAutoDetectedSpecName(file)) { if (file == "android_low.cfg") { pVar->Set(CONFIG_LOW_SPEC); } if (file == "android_medium.cfg") { pVar->Set(CONFIG_MEDIUM_SPEC); } if (file == "android_high.cfg") { pVar->Set(CONFIG_HIGH_SPEC); } if (file == "android_veryhigh.cfg") { pVar->Set(CONFIG_VERYHIGH_SPEC); } GetISystem()->LoadConfiguration(file.c_str(), pSysSpecOverrideSinkConsole); } else { float totalRAM = MobileSysInspect::GetDeviceRamInGB(); if (totalRAM < MobileSysInspect::LOW_SPEC_RAM) { pVar->Set(CONFIG_LOW_SPEC); GetISystem()->LoadConfiguration("android_low.cfg", pSysSpecOverrideSinkConsole); } else if (totalRAM < MobileSysInspect::MEDIUM_SPEC_RAM) { pVar->Set(CONFIG_MEDIUM_SPEC); GetISystem()->LoadConfiguration("android_medium.cfg", pSysSpecOverrideSinkConsole); } else if (totalRAM < MobileSysInspect::HIGH_SPEC_RAM) { pVar->Set(CONFIG_HIGH_SPEC); GetISystem()->LoadConfiguration("android_high.cfg", pSysSpecOverrideSinkConsole); } else { pVar->Set(CONFIG_VERYHIGH_SPEC); GetISystem()->LoadConfiguration("android_veryhigh.cfg", pSysSpecOverrideSinkConsole); } } #endif break; } case CONFIG_IOS: { #if defined(AZ_PLATFORM_IOS) AZStd::string file; if (MobileSysInspect::GetAutoDetectedSpecName(file)) { if (file == "ios_low.cfg") { pVar->Set(CONFIG_LOW_SPEC); } if (file == "ios_medium.cfg") { pVar->Set(CONFIG_MEDIUM_SPEC); } if (file == "ios_high.cfg") { pVar->Set(CONFIG_HIGH_SPEC); } if (file == "ios_veryhigh.cfg") { pVar->Set(CONFIG_VERYHIGH_SPEC); } GetISystem()->LoadConfiguration(file.c_str(), pSysSpecOverrideSinkConsole); } else { pVar->Set(CONFIG_MEDIUM_SPEC); GetISystem()->LoadConfiguration("ios_medium.cfg", pSysSpecOverrideSinkConsole); } #endif break; } #if defined(AZ_PLATFORM_JASPER) || defined(TOOLS_SUPPORT_JASPER) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_5 #include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, jasper) #endif #if defined(AZ_PLATFORM_PROVO) || defined(TOOLS_SUPPORT_PROVO) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_5 #include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, provo) #endif #if defined(AZ_PLATFORM_SALEM) || defined(TOOLS_SUPPORT_SALEM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_5 #include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, salem) #endif case CONFIG_OSX_GL: { pVar->Set(CONFIG_HIGH_SPEC); GetISystem()->LoadConfiguration("osx_gl.cfg", pSysSpecOverrideSinkConsole); break; } case CONFIG_OSX_METAL: { pVar->Set(CONFIG_HIGH_SPEC); GetISystem()->LoadConfiguration("osx_metal_high.cfg", pSysSpecOverrideSinkConsole); break; } default: AZ_Assert(false, "Platform not supported"); break; } } // make sure editor specific settings are not changed if (gEnv->IsEditor()) { GetISystem()->LoadConfiguration("editor.cfg"); } bool bMultiGPUEnabled = false; if (gEnv->pRenderer) { gEnv->pRenderer->EF_Query(EFQ_MultiGPUEnabled, bMultiGPUEnabled); #if defined(AZ_PLATFORM_ANDROID) AZStd::string gpuConfigFile; const AZStd::string& adapterDesc = gEnv->pRenderer->GetAdapterDescription(); const AZStd::string& apiver = gEnv->pRenderer->GetApiVersion(); if (!adapterDesc.empty()) { MobileSysInspect::GetSpecForGPUAndAPI(adapterDesc, apiver, gpuConfigFile); GetISystem()->LoadConfiguration(gpuConfigFile.c_str(), pSysSpecOverrideSinkConsole); } #endif } if (bMultiGPUEnabled) { GetISystem()->LoadConfiguration("mgpu.cfg"); } // override cvars just loaded based on current API version/GPU GetISystem()->SetConfigSpec(static_cast(spec), platform, false); if (gEnv->p3DEngine) { gEnv->p3DEngine->GetMaterialManager()->RefreshMaterialRuntime(); } no_recursive = false; } ////////////////////////////////////////////////////////////////////////// struct SCryEngineLanguageConfigLoader : public ILoadConfigurationEntrySink { CSystem* m_pSystem; string m_language; string m_pakFile; SCryEngineLanguageConfigLoader(CSystem* pSystem) { m_pSystem = pSystem; } void Load(const char* sCfgFilename) { CSystemConfiguration cfg(sCfgFilename, m_pSystem, this); // Parse folders config file. } virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, [[maybe_unused]] const char* szGroup) { if (azstricmp(szKey, "Language") == 0) { m_language = szValue; } else if (azstricmp(szKey, "PAK") == 0) { m_pakFile = szValue; } } virtual void OnLoadConfigurationEntry_End() {} }; ////////////////////////////////////////////////////////////////////////// #if !defined(AZ_MONOLITHIC_BUILD) AZStd::unique_ptr CSystem::LoadDynamiclibrary(const char* dllName) const { AZStd::unique_ptr handle = AZ::DynamicModuleHandle::Create(dllName); bool libraryLoaded = handle->Load(false); // We need to inject the environment first thing so that allocators are available immediately InjectEnvironmentFunction injectEnv = handle->GetFunction(INJECT_ENVIRONMENT_FUNCTION); if (injectEnv) { auto env = AZ::Environment::GetInstance(); injectEnv(env); } if (!libraryLoaded) { handle.release(); } return handle; } ////////////////////////////////////////////////////////////////////////// AZStd::unique_ptr CSystem::LoadDLL(const char* dllName) { LOADING_TIME_PROFILE_SECTION(GetISystem()); AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "Loading DLL: %s", dllName); AZStd::unique_ptr handle = LoadDynamiclibrary(dllName); if (!handle) { #if defined(LINUX) || defined(APPLE) AZ_Assert(false, "Error loading dylib: %s, error : %s\n", dllName, dlerror()); #else AZ_Assert(false, "Error loading dll: %s, error code %d", dllName, GetLastError()); #endif return handle; } ////////////////////////////////////////////////////////////////////////// // After loading DLL initialize it by calling ModuleInitISystem ////////////////////////////////////////////////////////////////////////// string moduleName = PathUtil::GetFileName(dllName); typedef void*(*PtrFunc_ModuleInitISystem)(ISystem* pSystem, const char* moduleName); PtrFunc_ModuleInitISystem pfnModuleInitISystem = handle->GetFunction(DLL_MODULE_INIT_ISYSTEM); if (pfnModuleInitISystem) { pfnModuleInitISystem(this, moduleName.c_str()); } return handle; } // TODO:DLL #endif //#if defined(AZ_HAS_DLL_SUPPORT) && !defined(AZ_MONOLITHIC_BUILD) #endif //if !defined(AZ_MONOLITHIC_BUILD) ////////////////////////////////////////////////////////////////////////// bool CSystem::LoadEngineDLLs() { return true; } ////////////////////////////////////////////////////////////////////////// bool CSystem::UnloadDLL(const char* dllName) { bool isSuccess = false; CCryNameCRC key(dllName); AZStd::unique_ptr empty; AZStd::unique_ptr& hModule = stl::find_in_map_ref(m_moduleDLLHandles, key, empty); if ((hModule) && (hModule->IsLoaded())) { DetachEnvironmentFunction detachEnv = hModule->GetFunction(DETACH_ENVIRONMENT_FUNCTION); if (detachEnv) { detachEnv(); } isSuccess = hModule->Unload(); hModule.release(); } return isSuccess; } ////////////////////////////////////////////////////////////////////////// bool CSystem::InitializeEngineModule(const char* dllName, const char* moduleClassName, const SSystemInitParams& initParams) { bool bResult = false; stack_string msg; msg = "Initializing "; AZStd::string dll = dllName; // Strip off Cry if the dllname is Cry if (dll.find("Cry") == 0) { msg += dll.substr(3).c_str(); } else { msg += dllName; } msg += "..."; if (m_pUserCallback) { m_pUserCallback->OnInitProgress(msg.c_str()); } AZ_TracePrintf(moduleClassName, "%s", msg.c_str()); IMemoryManager::SProcessMemInfo memStart, memEnd; if (GetIMemoryManager()) { GetIMemoryManager()->GetProcessMemInfo(memStart); } else { ZeroStruct(memStart); } stack_string dllfile = ""; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_16 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else dllfile.append(dllName); #if defined(LINUX) dllfile = "lib" + PathUtil::ReplaceExtension(dllfile, "so"); #ifndef LINUX dllfile.MakeLower(); #endif #elif defined(AZ_PLATFORM_MAC) dllfile = "lib" + PathUtil::ReplaceExtension(dllfile, "dylib"); #elif defined(AZ_PLATFORM_IOS) PathUtil::RemoveExtension(dllfile); #else dllfile = PathUtil::ReplaceExtension(dllfile, "dll"); #endif #endif #if !defined(AZ_MONOLITHIC_BUILD) m_moduleDLLHandles.insert(std::make_pair(dllfile.c_str(), LoadDLL(dllfile.c_str()))); if (!m_moduleDLLHandles[dllfile.c_str()]) { return bResult; } #endif // #if !defined(AZ_MONOLITHIC_BUILD) AZStd::shared_ptr pModule; if (CryCreateClassInstance(moduleClassName, pModule)) { bResult = pModule->Initialize(m_env, initParams); // After initializing the module, give it a chance to register any AZ console vars // declared within the module. pModule->RegisterConsoleVars(); } if (GetIMemoryManager()) { GetIMemoryManager()->GetProcessMemInfo(memEnd); uint64 memUsed = memEnd.WorkingSetSize - memStart.WorkingSetSize; AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "Initializing %s %s, MemUsage=%uKb", dllName, pModule ? "done" : "failed", uint32(memUsed / 1024)); } return bResult; } ////////////////////////////////////////////////////////////////////////// bool CSystem::UnloadEngineModule(const char* dllName, const char* moduleClassName) { bool isSuccess = false; // Remove the factory. ICryFactoryRegistryImpl* const pReg = static_cast(GetCryFactoryRegistry()); if (pReg != nullptr) { ICryFactory* pICryFactory = pReg->GetFactory(moduleClassName); if (pICryFactory != nullptr) { pReg->UnregisterFactory(pICryFactory); } } stack_string msg; msg = "Unloading "; msg += dllName; msg += "..."; AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "%s", msg.c_str()); stack_string dllfile = dllName; #if defined(LINUX) dllfile = "lib" + PathUtil::ReplaceExtension(dllfile, "so"); #ifndef LINUX dllfile.MakeLower(); #endif #elif defined(APPLE) dllfile = "lib" + PathUtil::ReplaceExtension(dllfile, "dylib"); #else dllfile = PathUtil::ReplaceExtension(dllfile, "dll"); #endif #if !defined(AZ_MONOLITHIC_BUILD) isSuccess = UnloadDLL(dllfile.c_str()); #endif // #if !defined(AZ_MONOLITHIC_BUILD) return isSuccess; } ////////////////////////////////////////////////////////////////////////// void CSystem::ShutdownModuleLibraries() { #if !defined(AZ_MONOLITHIC_BUILD) for (auto iterator = m_moduleDLLHandles.begin(); iterator != m_moduleDLLHandles.end(); ++iterator) { typedef void*( * PtrFunc_ModuleShutdownISystem )(ISystem* pSystem); PtrFunc_ModuleShutdownISystem pfnModuleShutdownISystem = iterator->second->GetFunction(DLL_MODULE_SHUTDOWN_ISYSTEM); if (pfnModuleShutdownISystem) { pfnModuleShutdownISystem(this); } if (iterator->second->IsLoaded()) { iterator->second->Unload(); } iterator->second.release(); } m_moduleDLLHandles.clear(); #endif // !defined(AZ_MONOLITHIC_BUILD) } ////////////////////////////////////////////////////////////////////////// bool CSystem::OpenRenderLibrary([[maybe_unused]] const char* t_rend, const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION(GetISystem()); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_6 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else if (gEnv->IsDedicated()) { return OpenRenderLibrary(R_NULL_RENDERER, initParams); } if (AZ::Interface::Get()) { return OpenRenderLibrary(R_DX11_RENDERER, initParams); } else if (azstricmp(t_rend, "DX9") == 0) { return OpenRenderLibrary(R_DX9_RENDERER, initParams); } else if (azstricmp(t_rend, "DX11") == 0) { return OpenRenderLibrary(R_DX11_RENDERER, initParams); } else if (azstricmp(t_rend, "DX12") == 0) { return OpenRenderLibrary(R_DX12_RENDERER, initParams); } else if (azstricmp(t_rend, "GL") == 0) { return OpenRenderLibrary(R_GL_RENDERER, initParams); } else if (azstricmp(t_rend, "METAL") == 0) { return OpenRenderLibrary(R_METAL_RENDERER, initParams); } else if (azstricmp(t_rend, "NULL") == 0) { return OpenRenderLibrary(R_NULL_RENDERER, initParams); } AZ_Assert(false, "Unknown renderer type: %s", t_rend); return false; #endif } ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// #if defined(WIN32) || defined(WIN64) wstring GetErrorStringUnsupportedGPU(const char* gpuName, unsigned int gpuVendorId, unsigned int gpuDeviceId) { const size_t fullLangID = (size_t) GetKeyboardLayout(0); const size_t primLangID = fullLangID & 0x3FF; const wchar_t* pFmt = L"Unsupported video card detected! Continuing to run might lead to unexpected results or crashes. " L"Please check the manual for further information on hardware requirements.\n\n\"%S\" [vendor id = 0x%.4x, device id = 0x%.4x]"; switch (primLangID) { case 0x04: // Chinese { static const wchar_t fmt[] = {0x5075, 0x6E2C, 0x5230, 0x4E0D, 0x652F, 0x63F4, 0x7684, 0x986F, 0x793A, 0x5361, 0xFF01, 0x7E7C, 0x7E8C, 0x57F7, 0x884C, 0x53EF, 0x80FD, 0x5C0E, 0x81F4, 0x7121, 0x6CD5, 0x9810, 0x671F, 0x7684, 0x7D50, 0x679C, 0x6216, 0x7576, 0x6A5F, 0x3002, 0x8ACB, 0x6AA2, 0x67E5, 0x8AAA, 0x660E, 0x66F8, 0x4E0A, 0x7684, 0x786C, 0x9AD4, 0x9700, 0x6C42, 0x4EE5, 0x53D6, 0x5F97, 0x66F4, 0x591A, 0x76F8, 0x95DC, 0x8CC7, 0x8A0A, 0x3002, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x5EE0, 0x5546, 0x7DE8, 0x865F, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x88DD, 0x7F6E, 0x7DE8, 0x865F, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x05: // Czech { static const wchar_t fmt[] = {0x0042, 0x0079, 0x006C, 0x0061, 0x0020, 0x0064, 0x0065, 0x0074, 0x0065, 0x006B, 0x006F, 0x0076, 0x00E1, 0x006E, 0x0061, 0x0020, 0x0067, 0x0072, 0x0061, 0x0066, 0x0069, 0x0063, 0x006B, 0x00E1, 0x0020, 0x006B, 0x0061, 0x0072, 0x0074, 0x0061, 0x002C, 0x0020, 0x006B, 0x0074, 0x0065, 0x0072, 0x00E1, 0x0020, 0x006E, 0x0065, 0x006E, 0x00ED, 0x0020, 0x0070, 0x006F, 0x0064, 0x0070, 0x006F, 0x0072, 0x006F, 0x0076, 0x00E1, 0x006E, 0x0061, 0x002E, 0x0020, 0x0050, 0x006F, 0x006B, 0x0072, 0x0061, 0x010D, 0x006F, 0x0076, 0x00E1, 0x006E, 0x00ED, 0x0020, 0x006D, 0x016F, 0x017E, 0x0065, 0x0020, 0x0076, 0x00E9, 0x0073, 0x0074, 0x0020, 0x006B, 0x0065, 0x0020, 0x006B, 0x0072, 0x0069, 0x0074, 0x0069, 0x0063, 0x006B, 0x00FD, 0x006D, 0x0020, 0x0063, 0x0068, 0x0079, 0x0062, 0x00E1, 0x006D, 0x0020, 0x006E, 0x0065, 0x0062, 0x006F, 0x0020, 0x006E, 0x0065, 0x0073, 0x0074, 0x0061, 0x0062, 0x0069, 0x006C, 0x0069, 0x0074, 0x011B, 0x0020, 0x0073, 0x0079, 0x0073, 0x0074, 0x00E9, 0x006D, 0x0075, 0x002E, 0x0020, 0x0050, 0x0159, 0x0065, 0x010D, 0x0074, 0x011B, 0x0074, 0x0065, 0x0020, 0x0073, 0x0069, 0x0020, 0x0070, 0x0072, 0x006F, 0x0073, 0x00ED, 0x006D, 0x0020, 0x0075, 0x017E, 0x0069, 0x0076, 0x0061, 0x0074, 0x0065, 0x006C, 0x0073, 0x006B, 0x006F, 0x0075, 0x0020, 0x0070, 0x0159, 0x00ED, 0x0072, 0x0075, 0x010D, 0x006B, 0x0075, 0x0020, 0x0070, 0x0072, 0x006F, 0x0020, 0x0070, 0x006F, 0x0064, 0x0072, 0x006F, 0x0062, 0x006E, 0x00E9, 0x0020, 0x0069, 0x006E, 0x0066, 0x006F, 0x0072, 0x006D, 0x0061, 0x0063, 0x0065, 0x0020, 0x006F, 0x0020, 0x0073, 0x0079, 0x0073, 0x0074, 0x00E9, 0x006D, 0x006F, 0x0076, 0x00FD, 0x0063, 0x0068, 0x0020, 0x0070, 0x006F, 0x017E, 0x0061, 0x0064, 0x0061, 0x0076, 0x0063, 0x00ED, 0x0063, 0x0068, 0x002E, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x0076, 0x0065, 0x006E, 0x0064, 0x006F, 0x0072, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x07: // German { static const wchar_t fmt[] = {0x004E, 0x0069, 0x0063, 0x0068, 0x0074, 0x002D, 0x0075, 0x006E, 0x0074, 0x0065, 0x0072, 0x0073, 0x0074, 0x00FC, 0x0074, 0x007A, 0x0074, 0x0065, 0x0020, 0x0056, 0x0069, 0x0064, 0x0065, 0x006F, 0x006B, 0x0061, 0x0072, 0x0074, 0x0065, 0x0020, 0x0067, 0x0065, 0x0066, 0x0075, 0x006E, 0x0064, 0x0065, 0x006E, 0x0021, 0x0020, 0x0046, 0x006F, 0x0072, 0x0074, 0x0066, 0x0061, 0x0068, 0x0072, 0x0065, 0x006E, 0x0020, 0x006B, 0x0061, 0x006E, 0x006E, 0x0020, 0x007A, 0x0075, 0x0020, 0x0075, 0x006E, 0x0065, 0x0072, 0x0077, 0x0061, 0x0072, 0x0074, 0x0065, 0x0074, 0x0065, 0x006E, 0x0020, 0x0045, 0x0072, 0x0067, 0x0065, 0x0062, 0x006E, 0x0069, 0x0073, 0x0073, 0x0065, 0x006E, 0x0020, 0x006F, 0x0064, 0x0065, 0x0072, 0x0020, 0x0041, 0x0062, 0x0073, 0x0074, 0x00FC, 0x0072, 0x007A, 0x0065, 0x006E, 0x0020, 0x0066, 0x00FC, 0x0068, 0x0072, 0x0065, 0x006E, 0x002E, 0x0020, 0x0042, 0x0069, 0x0074, 0x0074, 0x0065, 0x0020, 0x006C, 0x0069, 0x0065, 0x0073, 0x0020, 0x0064, 0x0061, 0x0073, 0x0020, 0x004D, 0x0061, 0x006E, 0x0075, 0x0061, 0x006C, 0x0020, 0x0066, 0x00FC, 0x0072, 0x0020, 0x0077, 0x0065, 0x0069, 0x0074, 0x0065, 0x0072, 0x0065, 0x0020, 0x0049, 0x006E, 0x0066, 0x006F, 0x0072, 0x006D, 0x0061, 0x0074, 0x0069, 0x006F, 0x006E, 0x0065, 0x006E, 0x0020, 0x007A, 0x0075, 0x0020, 0x0048, 0x0061, 0x0072, 0x0064, 0x0077, 0x0061, 0x0072, 0x0065, 0x002D, 0x0041, 0x006E, 0x0066, 0x006F, 0x0072, 0x0064, 0x0065, 0x0072, 0x0075, 0x006E, 0x0067, 0x0065, 0x006E, 0x002E, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x0076, 0x0065, 0x006E, 0x0064, 0x006F, 0x0072, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x0a: // Spanish { static const wchar_t fmt[] = {0x0053, 0x0065, 0x0020, 0x0068, 0x0061, 0x0020, 0x0064, 0x0065, 0x0074, 0x0065, 0x0063, 0x0074, 0x0061, 0x0064, 0x006F, 0x0020, 0x0075, 0x006E, 0x0061, 0x0020, 0x0074, 0x0061, 0x0072, 0x006A, 0x0065, 0x0074, 0x0061, 0x0020, 0x0067, 0x0072, 0x00E1, 0x0066, 0x0069, 0x0063, 0x0061, 0x0020, 0x006E, 0x006F, 0x0020, 0x0063, 0x006F, 0x006D, 0x0070, 0x0061, 0x0074, 0x0069, 0x0062, 0x006C, 0x0065, 0x002E, 0x0020, 0x0053, 0x0069, 0x0020, 0x0073, 0x0069, 0x0067, 0x0075, 0x0065, 0x0073, 0x0020, 0x0065, 0x006A, 0x0065, 0x0063, 0x0075, 0x0074, 0x0061, 0x006E, 0x0064, 0x006F, 0x0020, 0x0065, 0x006C, 0x0020, 0x006A, 0x0075, 0x0065, 0x0067, 0x006F, 0x002C, 0x0020, 0x0065, 0x0073, 0x0020, 0x0070, 0x006F, 0x0073, 0x0069, 0x0062, 0x006C, 0x0065, 0x0020, 0x0071, 0x0075, 0x0065, 0x0020, 0x0073, 0x0065, 0x0020, 0x0070, 0x0072, 0x006F, 0x0064, 0x0075, 0x007A, 0x0063, 0x0061, 0x006E, 0x0020, 0x0065, 0x0066, 0x0065, 0x0063, 0x0074, 0x006F, 0x0073, 0x0020, 0x0069, 0x006E, 0x0065, 0x0073, 0x0070, 0x0065, 0x0072, 0x0061, 0x0064, 0x006F, 0x0073, 0x0020, 0x006F, 0x0020, 0x0071, 0x0075, 0x0065, 0x0020, 0x0065, 0x006C, 0x0020, 0x0070, 0x0072, 0x006F, 0x0067, 0x0072, 0x0061, 0x006D, 0x0061, 0x0020, 0x0064, 0x0065, 0x006A, 0x0065, 0x0020, 0x0064, 0x0065, 0x0020, 0x0066, 0x0075, 0x006E, 0x0063, 0x0069, 0x006F, 0x006E, 0x0061, 0x0072, 0x002E, 0x0020, 0x0050, 0x006F, 0x0072, 0x0020, 0x0066, 0x0061, 0x0076, 0x006F, 0x0072, 0x002C, 0x0020, 0x0063, 0x006F, 0x006D, 0x0070, 0x0072, 0x0075, 0x0065, 0x0062, 0x0061, 0x0020, 0x0065, 0x006C, 0x0020, 0x006D, 0x0061, 0x006E, 0x0075, 0x0061, 0x006C, 0x0020, 0x0070, 0x0061, 0x0072, 0x0061, 0x0020, 0x006F, 0x0062, 0x0074, 0x0065, 0x006E, 0x0065, 0x0072, 0x0020, 0x006D, 0x00E1, 0x0073, 0x0020, 0x0069, 0x006E, 0x0066, 0x006F, 0x0072, 0x006D, 0x0061, 0x0063, 0x0069, 0x00F3, 0x006E, 0x0020, 0x0061, 0x0063, 0x0065, 0x0072, 0x0063, 0x0061, 0x0020, 0x0064, 0x0065, 0x0020, 0x006C, 0x006F, 0x0073, 0x0020, 0x0072, 0x0065, 0x0071, 0x0075, 0x0069, 0x0073, 0x0069, 0x0074, 0x006F, 0x0073, 0x0020, 0x0064, 0x0065, 0x006C, 0x0020, 0x0073, 0x0069, 0x0073, 0x0074, 0x0065, 0x006D, 0x0061, 0x002E, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x0076, 0x0065, 0x006E, 0x0064, 0x006F, 0x0072, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x0c: // French { static const wchar_t fmt[] = {0x0041, 0x0074, 0x0074, 0x0065, 0x006E, 0x0074, 0x0069, 0x006F, 0x006E, 0x002C, 0x0020, 0x006C, 0x0061, 0x0020, 0x0063, 0x0061, 0x0072, 0x0074, 0x0065, 0x0020, 0x0076, 0x0069, 0x0064, 0x00E9, 0x006F, 0x0020, 0x0064, 0x00E9, 0x0074, 0x0065, 0x0063, 0x0074, 0x00E9, 0x0065, 0x0020, 0x006E, 0x2019, 0x0065, 0x0073, 0x0074, 0x0020, 0x0070, 0x0061, 0x0073, 0x0020, 0x0073, 0x0075, 0x0070, 0x0070, 0x006F, 0x0072, 0x0074, 0x00E9, 0x0065, 0x0020, 0x0021, 0x0020, 0x0050, 0x006F, 0x0075, 0x0072, 0x0073, 0x0075, 0x0069, 0x0076, 0x0072, 0x0065, 0x0020, 0x006C, 0x2019, 0x0061, 0x0070, 0x0070, 0x006C, 0x0069, 0x0063, 0x0061, 0x0074, 0x0069, 0x006F, 0x006E, 0x0020, 0x0070, 0x006F, 0x0075, 0x0072, 0x0072, 0x0061, 0x0069, 0x0074, 0x0020, 0x0065, 0x006E, 0x0067, 0x0065, 0x006E, 0x0064, 0x0072, 0x0065, 0x0072, 0x0020, 0x0064, 0x0065, 0x0073, 0x0020, 0x0069, 0x006E, 0x0073, 0x0074, 0x0061, 0x0062, 0x0069, 0x006C, 0x0069, 0x0074, 0x00E9, 0x0073, 0x0020, 0x006F, 0x0075, 0x0020, 0x0064, 0x0065, 0x0073, 0x0020, 0x0063, 0x0072, 0x0061, 0x0073, 0x0068, 0x0073, 0x002E, 0x0020, 0x0056, 0x0065, 0x0075, 0x0069, 0x006C, 0x006C, 0x0065, 0x007A, 0x0020, 0x0076, 0x006F, 0x0075, 0x0073, 0x0020, 0x0072, 0x0065, 0x0070, 0x006F, 0x0072, 0x0074, 0x0065, 0x0072, 0x0020, 0x0061, 0x0075, 0x0020, 0x006D, 0x0061, 0x006E, 0x0075, 0x0065, 0x006C, 0x0020, 0x0070, 0x006F, 0x0075, 0x0072, 0x0020, 0x0070, 0x006C, 0x0075, 0x0073, 0x0020, 0x0064, 0x2019, 0x0069, 0x006E, 0x0066, 0x006F, 0x0072, 0x006D, 0x0061, 0x0074, 0x0069, 0x006F, 0x006E, 0x0073, 0x0020, 0x0073, 0x0075, 0x0072, 0x0020, 0x006C, 0x0065, 0x0073, 0x0020, 0x0070, 0x0072, 0x00E9, 0x002D, 0x0072, 0x0065, 0x0071, 0x0075, 0x0069, 0x0073, 0x0020, 0x006D, 0x0061, 0x0074, 0x00E9, 0x0072, 0x0069, 0x0065, 0x006C, 0x002E, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x0076, 0x0065, 0x006E, 0x0064, 0x006F, 0x0072, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x10: // Italian { static const wchar_t fmt[] = {0x00C8, 0x0020, 0x0073, 0x0074, 0x0061, 0x0074, 0x0061, 0x0020, 0x0072, 0x0069, 0x006C, 0x0065, 0x0076, 0x0061, 0x0074, 0x0061, 0x0020, 0x0075, 0x006E, 0x0061, 0x0020, 0x0073, 0x0063, 0x0068, 0x0065, 0x0064, 0x0061, 0x0020, 0x0067, 0x0072, 0x0061, 0x0066, 0x0069, 0x0063, 0x0061, 0x0020, 0x006E, 0x006F, 0x006E, 0x0020, 0x0073, 0x0075, 0x0070, 0x0070, 0x006F, 0x0072, 0x0074, 0x0061, 0x0074, 0x0061, 0x0021, 0x0020, 0x0053, 0x0065, 0x0020, 0x0073, 0x0069, 0x0020, 0x0063, 0x006F, 0x006E, 0x0074, 0x0069, 0x006E, 0x0075, 0x0061, 0x002C, 0x0020, 0x0073, 0x0069, 0x0020, 0x0070, 0x006F, 0x0074, 0x0072, 0x0065, 0x0062, 0x0062, 0x0065, 0x0072, 0x006F, 0x0020, 0x0076, 0x0065, 0x0072, 0x0069, 0x0066, 0x0069, 0x0063, 0x0061, 0x0072, 0x0065, 0x0020, 0x0072, 0x0069, 0x0073, 0x0075, 0x006C, 0x0074, 0x0061, 0x0074, 0x0069, 0x0020, 0x0069, 0x006E, 0x0061, 0x0074, 0x0074, 0x0065, 0x0073, 0x0069, 0x0020, 0x006F, 0x0020, 0x0063, 0x0072, 0x0061, 0x0073, 0x0068, 0x002E, 0x0020, 0x0043, 0x006F, 0x006E, 0x0073, 0x0075, 0x006C, 0x0074, 0x0061, 0x0020, 0x0069, 0x006C, 0x0020, 0x006D, 0x0061, 0x006E, 0x0075, 0x0061, 0x006C, 0x0065, 0x0020, 0x0070, 0x0065, 0x0072, 0x0020, 0x0075, 0x006C, 0x0074, 0x0065, 0x0072, 0x0069, 0x006F, 0x0072, 0x0069, 0x0020, 0x0069, 0x006E, 0x0066, 0x006F, 0x0072, 0x006D, 0x0061, 0x007A, 0x0069, 0x006F, 0x006E, 0x0069, 0x0020, 0x0073, 0x0075, 0x0069, 0x0020, 0x0072, 0x0065, 0x0071, 0x0075, 0x0069, 0x0073, 0x0069, 0x0074, 0x0069, 0x0020, 0x0064, 0x0069, 0x0020, 0x0073, 0x0069, 0x0073, 0x0074, 0x0065, 0x006D, 0x0061, 0x002E, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x0076, 0x0065, 0x006E, 0x0064, 0x006F, 0x0072, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x11: // Japanese { static const wchar_t fmt[] = {0x30B5, 0x30DD, 0x30FC, 0x30C8, 0x3055, 0x308C, 0x3066, 0x3044, 0x306A, 0x3044, 0x30D3, 0x30C7, 0x30AA, 0x30AB, 0x30FC, 0x30C9, 0x304C, 0x691C, 0x51FA, 0x3055, 0x308C, 0x307E, 0x3057, 0x305F, 0xFF01, 0x0020, 0x3053, 0x306E, 0x307E, 0x307E, 0x7D9A, 0x3051, 0x308B, 0x3068, 0x4E88, 0x671F, 0x3057, 0x306A, 0x3044, 0x7D50, 0x679C, 0x3084, 0x30AF, 0x30E9, 0x30C3, 0x30B7, 0x30E5, 0x306E, 0x6050, 0x308C, 0x304C, 0x3042, 0x308A, 0x307E, 0x3059, 0x3002, 0x0020, 0x30DE, 0x30CB, 0x30E5, 0x30A2, 0x30EB, 0x306E, 0x5FC5, 0x8981, 0x52D5, 0x4F5C, 0x74B0, 0x5883, 0x3092, 0x3054, 0x78BA, 0x8A8D, 0x304F, 0x3060, 0x3055, 0x3044, 0x3002, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x30D9, 0x30F3, 0x30C0, 0x30FC, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x30C7, 0x30D0, 0x30A4, 0x30B9, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x15: // Polish { static const wchar_t fmt[] = {0x0057, 0x0079, 0x006B, 0x0072, 0x0079, 0x0074, 0x006F, 0x0020, 0x006E, 0x0069, 0x0065, 0x006F, 0x0062, 0x0073, 0x0142, 0x0075, 0x0067, 0x0069, 0x0077, 0x0061, 0x006E, 0x0105, 0x0020, 0x006B, 0x0061, 0x0072, 0x0074, 0x0119, 0x0020, 0x0067, 0x0072, 0x0061, 0x0066, 0x0069, 0x0063, 0x007A, 0x006E, 0x0105, 0x0021, 0x0020, 0x0044, 0x0061, 0x006C, 0x0073, 0x007A, 0x0065, 0x0020, 0x006B, 0x006F, 0x0072, 0x007A, 0x0079, 0x0073, 0x0074, 0x0061, 0x006E, 0x0069, 0x0065, 0x0020, 0x007A, 0x0020, 0x0070, 0x0072, 0x006F, 0x0064, 0x0075, 0x006B, 0x0074, 0x0075, 0x0020, 0x006D, 0x006F, 0x017C, 0x0065, 0x0020, 0x0073, 0x0070, 0x006F, 0x0077, 0x006F, 0x0064, 0x006F, 0x0077, 0x0061, 0x0107, 0x0020, 0x006E, 0x0069, 0x0065, 0x0070, 0x006F, 0x017C, 0x0105, 0x0064, 0x0061, 0x006E, 0x0065, 0x0020, 0x007A, 0x0061, 0x0063, 0x0068, 0x006F, 0x0077, 0x0061, 0x006E, 0x0069, 0x0065, 0x0020, 0x006C, 0x0075, 0x0062, 0x0020, 0x0077, 0x0073, 0x0074, 0x0072, 0x007A, 0x0079, 0x006D, 0x0061, 0x006E, 0x0069, 0x0065, 0x0020, 0x0070, 0x0072, 0x006F, 0x0067, 0x0072, 0x0061, 0x006D, 0x0075, 0x002E, 0x0020, 0x0041, 0x0062, 0x0079, 0x0020, 0x0075, 0x007A, 0x0079, 0x0073, 0x006B, 0x0061, 0x0107, 0x0020, 0x0077, 0x0069, 0x0119, 0x0063, 0x0065, 0x006A, 0x0020, 0x0069, 0x006E, 0x0066, 0x006F, 0x0072, 0x006D, 0x0061, 0x0063, 0x006A, 0x0069, 0x002C, 0x0020, 0x0073, 0x006B, 0x006F, 0x006E, 0x0073, 0x0075, 0x006C, 0x0074, 0x0075, 0x006A, 0x0020, 0x0073, 0x0069, 0x0119, 0x0020, 0x007A, 0x0020, 0x0069, 0x006E, 0x0073, 0x0074, 0x0072, 0x0075, 0x006B, 0x0063, 0x006A, 0x0105, 0x0020, 0x006F, 0x0062, 0x0073, 0x0142, 0x0075, 0x0067, 0x0069, 0x002E, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x0076, 0x0065, 0x006E, 0x0064, 0x006F, 0x0072, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x19: // Russian { static const wchar_t fmt[] = {0x0412, 0x0430, 0x0448, 0x0430, 0x0020, 0x0432, 0x0438, 0x0434, 0x0435, 0x043E, 0x0020, 0x043A, 0x0430, 0x0440, 0x0442, 0x0430, 0x0020, 0x043D, 0x0435, 0x0020, 0x043F, 0x043E, 0x0434, 0x0434, 0x0435, 0x0440, 0x0436, 0x0438, 0x0432, 0x0430, 0x0435, 0x0442, 0x0441, 0x044F, 0x0021, 0x0020, 0x042D, 0x0442, 0x043E, 0x0020, 0x043C, 0x043E, 0x0436, 0x0435, 0x0442, 0x0020, 0x043F, 0x0440, 0x0438, 0x0432, 0x0435, 0x0441, 0x0442, 0x0438, 0x0020, 0x043A, 0x0020, 0x043D, 0x0435, 0x043F, 0x0440, 0x0435, 0x0434, 0x0441, 0x043A, 0x0430, 0x0437, 0x0443, 0x0435, 0x043C, 0x043E, 0x043C, 0x0443, 0x0020, 0x043F, 0x043E, 0x0432, 0x0435, 0x0434, 0x0435, 0x043D, 0x0438, 0x044E, 0x0020, 0x0438, 0x0020, 0x0437, 0x0430, 0x0432, 0x0438, 0x0441, 0x0430, 0x043D, 0x0438, 0x044E, 0x0020, 0x0438, 0x0433, 0x0440, 0x044B, 0x002E, 0x0020, 0x0414, 0x043B, 0x044F, 0x0020, 0x043F, 0x043E, 0x043B, 0x0443, 0x0447, 0x0435, 0x043D, 0x0438, 0x044F, 0x0020, 0x0438, 0x043D, 0x0444, 0x043E, 0x0440, 0x043C, 0x0430, 0x0446, 0x0438, 0x0438, 0x0020, 0x043E, 0x0020, 0x0441, 0x0438, 0x0441, 0x0442, 0x0435, 0x043C, 0x043D, 0x044B, 0x0445, 0x0020, 0x0442, 0x0440, 0x0435, 0x0431, 0x043E, 0x0432, 0x0430, 0x043D, 0x0438, 0x044F, 0x0445, 0x0020, 0x043E, 0x0431, 0x0440, 0x0430, 0x0442, 0x0438, 0x0442, 0x0435, 0x0441, 0x044C, 0x0020, 0x043A, 0x0020, 0x0440, 0x0443, 0x043A, 0x043E, 0x0432, 0x043E, 0x0434, 0x0441, 0x0442, 0x0432, 0x0443, 0x0020, 0x043F, 0x043E, 0x043B, 0x044C, 0x0437, 0x043E, 0x0432, 0x0430, 0x0442, 0x0435, 0x043B, 0x044F, 0x002E, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x0076, 0x0065, 0x006E, 0x0064, 0x006F, 0x0072, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x1f: // Turkish { static const wchar_t fmt[] = {0x0044, 0x0065, 0x0073, 0x0074, 0x0065, 0x006B, 0x006C, 0x0065, 0x006E, 0x006D, 0x0065, 0x0079, 0x0065, 0x006E, 0x0020, 0x0062, 0x0069, 0x0072, 0x0020, 0x0065, 0x006B, 0x0072, 0x0061, 0x006E, 0x0020, 0x006B, 0x0061, 0x0072, 0x0074, 0x0131, 0x0020, 0x0061, 0x006C, 0x0067, 0x0131, 0x006C, 0x0061, 0x006E, 0x0064, 0x0131, 0x0021, 0x0020, 0x0044, 0x0065, 0x0076, 0x0061, 0x006D, 0x0020, 0x0065, 0x0074, 0x006D, 0x0065, 0x006B, 0x0020, 0x0062, 0x0065, 0x006B, 0x006C, 0x0065, 0x006E, 0x006D, 0x0065, 0x0064, 0x0069, 0x006B, 0x0020, 0x0073, 0x006F, 0x006E, 0x0075, 0x00E7, 0x006C, 0x0061, 0x0072, 0x0061, 0x0020, 0x0076, 0x0065, 0x0020, 0x00E7, 0x00F6, 0x006B, 0x006D, 0x0065, 0x006C, 0x0065, 0x0072, 0x0065, 0x0020, 0x0079, 0x006F, 0x006C, 0x0020, 0x0061, 0x00E7, 0x0061, 0x0062, 0x0069, 0x006C, 0x0069, 0x0072, 0x002E, 0x0020, 0x0044, 0x006F, 0x006E, 0x0061, 0x006E, 0x0131, 0x006D, 0x0020, 0x0067, 0x0065, 0x0072, 0x0065, 0x006B, 0x006C, 0x0069, 0x006C, 0x0069, 0x006B, 0x006C, 0x0065, 0x0072, 0x0069, 0x0020, 0x0069, 0x00E7, 0x0069, 0x006E, 0x0020, 0x006C, 0x00FC, 0x0074, 0x0066, 0x0065, 0x006E, 0x0020, 0x0072, 0x0065, 0x0068, 0x0062, 0x0065, 0x0072, 0x0069, 0x006E, 0x0069, 0x007A, 0x0065, 0x0020, 0x0062, 0x0061, 0x015F, 0x0076, 0x0075, 0x0072, 0x0075, 0x006E, 0x002E, 0x000A, 0x000A, 0x0022, 0x0025, 0x0053, 0x0022, 0x0020, 0x005B, 0x0076, 0x0065, 0x006E, 0x0064, 0x006F, 0x0072, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x002C, 0x0020, 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0069, 0x0064, 0x0020, 0x003D, 0x0020, 0x0030, 0x0078, 0x0025, 0x002E, 0x0034, 0x0078, 0x005D, 0}; pFmt = fmt; break; } case 0x09: // English default: break; } wchar_t msg[1024]; msg[0] = L'\0'; msg[sizeof(msg) / sizeof(msg[0]) - 1] = L'\0'; azsnwprintf(msg, sizeof(msg) / sizeof(msg[0]) - 1, pFmt, gpuName, gpuVendorId, gpuDeviceId); return msg; } #endif bool CSystem::OpenRenderLibrary(int type, const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION; #if defined(WIN32) || defined(WIN64) if (!gEnv->IsDedicated()) { unsigned int gpuVendorId = 0, gpuDeviceId = 0, totVidMem = 0; char gpuName[256]; Win32SysInspect::DXFeatureLevel featureLevel = Win32SysInspect::DXFL_Undefined; Win32SysInspect::GetGPUInfo(gpuName, sizeof(gpuName), gpuVendorId, gpuDeviceId, totVidMem, featureLevel); if (m_env.IsEditor()) { #if defined(EXTERNAL_CRASH_REPORTING) CrashHandler::CrashHandlerBase::AddAnnotation("dx.feature.level", Win32SysInspect::GetFeatureLevelAsString(featureLevel)); CrashHandler::CrashHandlerBase::AddAnnotation("gpu.name", gpuName); CrashHandler::CrashHandlerBase::AddAnnotation("gpu.vendorId", std::to_string(gpuVendorId)); CrashHandler::CrashHandlerBase::AddAnnotation("gpu.deviceId", std::to_string(gpuDeviceId)); CrashHandler::CrashHandlerBase::AddAnnotation("gpu.memory", std::to_string(totVidMem)); #endif } else { if (featureLevel < Win32SysInspect::DXFL_11_0) { const char logMsgFmt[] ("Unsupported GPU configuration!\n- %s (vendor = 0x%.4x, device = 0x%.4x)\n- Dedicated video memory: %d MB\n- Feature level: %s\n"); AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, logMsgFmt, gpuName, gpuVendorId, gpuDeviceId, totVidMem >> 20, GetFeatureLevelAsString(featureLevel)); #if !defined(_RELEASE) const bool allowPrompts = m_env.pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "noprompt") == 0; #else const bool allowPrompts = true; #endif // !defined(_RELEASE) if (allowPrompts) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Asking user if they wish to continue..."); const int mbRes = MessageBoxW(0, GetErrorStringUnsupportedGPU(gpuName, gpuVendorId, gpuDeviceId).c_str(), L"Lumberyard", MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2 | MB_DEFAULT_DESKTOP_ONLY); if (mbRes == IDCANCEL) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "User chose to cancel startup due to unsupported GPU."); return false; } } else { #if !defined(_RELEASE) const bool obeyGPUCheck = m_env.pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "anygpu") == 0; #else const bool obeyGPUCheck = true; #endif // !defined(_RELEASE) if (obeyGPUCheck) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "No prompts allowed and unsupported GPU check active. Treating unsupported GPU as error and exiting."); return false; } } AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "User chose to continue despite unsupported GPU!"); } } } #endif #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_7 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif if (gEnv->IsDedicated()) { type = R_NULL_RENDERER; } const char* libname = ""; if (AZ::Interface::Get()) { libname = "CryRenderOther"; } else if (type == R_DX9_RENDERER) { libname = DLL_RENDERER_DX9; } else if (type == R_DX11_RENDERER) { libname = DLL_RENDERER_DX11; } else if (type == R_DX12_RENDERER) { libname = DLL_RENDERER_DX12; } else if (type == R_NULL_RENDERER) { libname = DLL_RENDERER_NULL; } else if (type == R_GL_RENDERER) { libname = DLL_RENDERER_GL; } else if (type == R_METAL_RENDERER) { libname = DLL_RENDERER_METAL; } else { AZ_Assert(false, "Renderer did not initialize correctly; no valid renderer specified."); return false; } if (!InitializeEngineModule(libname, "EngineModule_CryRenderer", initParams)) { return false; } if (!m_env.pRenderer) { AZ_Assert(false, "Renderer did not initialize correctly; it could not be found in the system environment."); return false; } return true; } ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// bool CSystem::InitConsole() { LOADING_TIME_PROFILE_SECTION(GetISystem()); if (m_env.pConsole) { m_env.pConsole->Init(this); } return true; } ////////////////////////////////////////////////////////////////////////// // attaches the given variable to the given container; // recreates the variable if necessary ICVar* CSystem::attachVariable (const char* szVarName, int* pContainer, const char* szComment, int dwFlags) { IConsole* pConsole = GetIConsole(); ICVar* pOldVar = pConsole->GetCVar (szVarName); int nDefault; if (pOldVar) { nDefault = pOldVar->GetIVal(); pConsole->UnregisterVariable(szVarName, true); } // NOTE: maybe we should preserve the actual value of the variable across the registration, // because of the strange architecture of IConsole that converts int->float->int REGISTER_CVAR2(szVarName, pContainer, *pContainer, dwFlags, szComment); ICVar* pVar = pConsole->GetCVar(szVarName); #ifdef _DEBUG // test if the variable really has this container assert (*pContainer == pVar->GetIVal()); ++*pContainer; assert (*pContainer == pVar->GetIVal()); --*pContainer; #endif if (pOldVar) { // carry on the default value from the old variable anyway pVar->Set(nDefault); } return pVar; } ///////////////////////////////////////////////////////////////////////////////// bool CSystem::InitRenderer(WIN_HINSTANCE hinst, WIN_HWND hwnd, const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION(GetISystem()); if (m_pUserCallback) { m_pUserCallback->OnInitProgress("Initializing Renderer..."); } if (m_bEditor) { m_env.pConsole->GetCVar("r_Width"); // save current screen width/height/bpp, so they can be restored on shutdown m_iWidth = m_env.pConsole->GetCVar("r_Width")->GetIVal(); m_iHeight = m_env.pConsole->GetCVar("r_Height")->GetIVal(); m_iColorBits = m_env.pConsole->GetCVar("r_ColorBits")->GetIVal(); } if (!OpenRenderLibrary(m_rDriver->GetString(), initParams)) { return false; } #if defined(AZ_PLATFORM_IOS) || defined(AZ_PLATFORM_ANDROID) if (m_rWidthAndHeightAsFractionOfScreenSize->GetFlags() & VF_WASINCONFIG) { int displayWidth = 0; int displayHeight = 0; if (GetPrimaryPhysicalDisplayDimensions(displayWidth, displayHeight)) { // Ideally we would probably want to clamp this at the source, // but I don't believe cvars support specifying a valid range. float scaleFactor = 1.0f; if(IsTablet()) { scaleFactor = AZ::GetClamp(m_rTabletWidthAndHeightAsFractionOfScreenSize->GetFVal(), 0.1f, 1.0f); } else { scaleFactor = AZ::GetClamp(m_rWidthAndHeightAsFractionOfScreenSize->GetFVal(), 0.1f, 1.0f); } displayWidth *= scaleFactor; displayHeight *= scaleFactor; const int maxWidth = m_rMaxWidth->GetIVal(); if (maxWidth > 0 && maxWidth < displayWidth) { const float widthScaleFactor = static_cast(maxWidth) / static_cast(displayWidth); displayWidth *= widthScaleFactor; displayHeight *= widthScaleFactor; } const int maxHeight = m_rMaxHeight->GetIVal(); if (maxHeight > 0 && maxHeight < displayHeight) { const float heightScaleFactor = static_cast(maxHeight) / static_cast(displayHeight); displayWidth *= heightScaleFactor; displayHeight *= heightScaleFactor; } m_rWidth->Set(displayWidth); m_rHeight->Set(displayHeight); } } #endif // defined(AZ_PLATFORM_IOS) || defined(AZ_PLATFORM_ANDROID) if (m_env.pRenderer) { // This is crucial as textures suffix are hard coded to context and we need to initialize // the texture semantics to look it up. m_env.pRenderer->InitTexturesSemantics(); #ifdef WIN32 SCustomRenderInitArgs args; args.appStartedFromMediaCenter = strstr(initParams.szSystemCmdLine, "ReLaunchMediaCenter") != 0; m_hWnd = m_env.pRenderer->Init(0, 0, m_rWidth->GetIVal(), m_rHeight->GetIVal(), m_rColorBits->GetIVal(), m_rDepthBits->GetIVal(), m_rStencilBits->GetIVal(), m_rFullscreen->GetIVal() ? true : false, initParams.bEditor, hinst, hwnd, false, &args, initParams.bShaderCacheGen); //Timur, Not very clean code, we need to push new hwnd value to the system init params, so other modules can used when initializing. (const_cast(&initParams))->hWnd = m_hWnd; bool retVal = (initParams.bShaderCacheGen || m_hWnd != 0); AZ_Assert(retVal, "Renderer failed to initialize correctly."); return retVal; #else // WIN32 WIN_HWND h = m_env.pRenderer->Init(0, 0, m_rWidth->GetIVal(), m_rHeight->GetIVal(), m_rColorBits->GetIVal(), m_rDepthBits->GetIVal(), m_rStencilBits->GetIVal(), m_rFullscreen->GetIVal() ? true : false, initParams.bEditor, hinst, hwnd, false, nullptr, initParams.bShaderCacheGen); #if (defined(LINUX) && !defined(AZ_PLATFORM_ANDROID)) return true; #define AZ_RESTRICTED_SECTION_IMPLEMENTED #elif defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_8 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else bool retVal = (initParams.bShaderCacheGen || h != 0); if (retVal) { return true; } AZ_Assert(false, "Renderer failed to initialize correctly."); return false; #endif #endif } return true; } ///////////////////////////////////////////////////////////////////////////////// bool CSystem::InitFileSystem() { LOADING_TIME_PROFILE_SECTION; using namespace AzFramework::AssetSystem; if (m_pUserCallback) { m_pUserCallback->OnInitProgress("Initializing File System..."); } bool bLvlRes = false; // true: all assets since executable start are recorded, false otherwise // get the DirectInstance FileIOBase which should be the AZ::LocalFileIO m_env.pFileIO = AZ::IO::FileIOBase::GetDirectInstance(); m_env.pResourceCompilerHelper = nullptr; #if !defined(_RELEASE) const ICmdLineArg* pArg = m_pCmdLine->FindArg(eCLAT_Pre, "LvlRes"); // -LvlRes command line option if (pArg) { bLvlRes = true; } #endif // !defined(_RELEASE) m_env.pCryPak = AZ::Interface::Get(); m_env.pFileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(m_env.pCryPak, "CryPak has not been initialized on AZ::Interface"); AZ_Assert(m_env.pFileIO, "FileIOBase has not been initialized"); if (m_bEditor || bLvlRes) { m_env.pCryPak->RecordFileOpen(AZ::IO::IArchive::RFOM_EngineStartup); } //init crypak if (m_env.pCryPak->Init("")) { #if !defined(_RELEASE) const ICmdLineArg* pakalias = m_pCmdLine->FindArg(eCLAT_Pre, "pakalias"); #else const ICmdLineArg* pakalias = nullptr; #endif // !defined(_RELEASE) if (pakalias && strlen(pakalias->GetValue()) > 0) { m_env.pCryPak->ParseAliases(pakalias->GetValue()); } } else { AZ_Assert(false, "Failed to initialize CryPak."); return false; } // Now that file systems are init, we will clear any events that have arrived // during file system init, so that systems do not reload assets that were already compiled in the // critical compilation section. AzFramework::LegacyAssetEventBus::ClearQueuedEvents(); //we are good to go return true; } void CSystem::ShutdownFileSystem() { #if defined(AZ_PLATFORM_WINDOWS) if (g_cacheLock != INVALID_HANDLE_VALUE) { CloseHandle(g_cacheLock); g_cacheLock = INVALID_HANDLE_VALUE; } #endif using namespace AZ::IO; FileIOBase* directInstance = FileIOBase::GetDirectInstance(); FileIOBase* pakInstance = FileIOBase::GetInstance(); if (directInstance == m_env.pFileIO) { // we only mess with file io if we own the instance that we installed. // if we dont' own the instance, then we never configured fileIO and we should not alter it. delete directInstance; FileIOBase::SetDirectInstance(nullptr); if (pakInstance != directInstance) { delete pakInstance; FileIOBase::SetInstance(nullptr); } } m_env.pFileIO = nullptr; } ///////////////////////////////////////////////////////////////////////////////// bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION; { ILoadConfigurationEntrySink* pCVarsWhiteListConfigSink = GetCVarsWhiteListConfigSink(); LoadConfiguration(m_systemConfigName.c_str(), pCVarsWhiteListConfigSink); AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Loading system configuration from %s...", m_systemConfigName.c_str()); } #if defined(AZ_PLATFORM_ANDROID) AZ::Android::Utils::SetLoadFilesToMemory(m_sys_load_files_to_memory->GetString()); #endif GetISystem()->SetConfigPlatform(GetDevicePlatform()); #if defined(CRY_ENABLE_RC_HELPER) if (!m_env.pResourceCompilerHelper) { m_env.pResourceCompilerHelper = new CResourceCompilerHelper(); } #endif auto projectPath = AZ::Utils::GetProjectPath(); AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Path: %s\n", projectPath.empty() ? "None specified" : projectPath.c_str()); auto projectName = AZ::Utils::GetProjectName(); AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Name: %s\n", projectName.empty() ? "None specified" : projectName.c_str()); // simply open all paks if fast load pak can't be found if (!m_pResourceManager->LoadFastLoadPaks(true)) { OpenBasicPaks(); } // Load game-specific folder. LoadConfiguration("game.cfg"); // Load the client/sever-specific configuration static const char* g_additionalConfig = gEnv->IsDedicated() ? "server_cfg" : "client_cfg"; LoadConfiguration(g_additionalConfig, nullptr, false); if (initParams.bShaderCacheGen) { LoadConfiguration("shadercachegen.cfg"); } // We do not use CVar groups on the consoles AddCVarGroupDirectory("Config/CVarGroups"); return (true); } ////////////////////////////////////////////////////////////////////////// bool CSystem::InitStreamEngine() { LOADING_TIME_PROFILE_SECTION(GetISystem()); if (m_pUserCallback) { m_pUserCallback->OnInitProgress("Initializing Stream Engine..."); } m_pStreamEngine = new CStreamEngine(); return true; } ///////////////////////////////////////////////////////////////////////////////// bool CSystem::InitFont(const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION(GetISystem()); bool fontInited = false; AZ::CryFontCreationRequestBus::BroadcastResult(fontInited, &AZ::CryFontCreationRequests::CreateCryFont, m_env, initParams); if (!fontInited && !InitializeEngineModule(DLL_FONT, "EngineModule_CryFont", initParams)) { return false; } if (!m_env.pCryFont) { AZ_Assert(false, "Font System did not initialize correctly; it could not be found in the system environment"); return false; } if (gEnv->IsDedicated()) { return true; } if (!LoadFontInternal(m_pIFont, "default")) { return false; } if (!LoadFontInternal(m_pIFontUi, "default-ui")) { return false; } return true; } ////////////////////////////////////////////////////////////////////////// bool CSystem::Init3DEngine(const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION(GetISystem()); if (!InitializeEngineModule(DLL_3DENGINE, "EngineModule_Cry3DEngine", initParams)) { return false; } if (!m_env.p3DEngine) { AZ_Assert(false, "3D Engine did not initialize correctly; it could not be found in the system environment"); return false; } if (!m_env.p3DEngine->Init()) { return false; } m_pProcess = m_env.p3DEngine; m_pProcess->SetFlags(PROC_3DENGINE); return true; } ////////////////////////////////////////////////////////////////////////// bool CSystem::InitAudioSystem(const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION(GetISystem()); if (!Audio::Gem::AudioSystemGemRequestBus::HasHandlers()) { // AudioSystem Gem has not been enabled for this project. // This should not generate an error, but calling scope will warn. return false; } bool useRealAudioSystem = false; if (!initParams.bPreview && !initParams.bShaderCacheGen && !initParams.bMinimal && !m_bDedicatedServer && m_sys_audio_disable->GetIVal() == 0) { useRealAudioSystem = true; } bool result = false; if (useRealAudioSystem) { Audio::Gem::AudioSystemGemRequestBus::BroadcastResult(result, &Audio::Gem::AudioSystemGemRequestBus::Events::Initialize, &initParams); } else { Audio::Gem::AudioSystemGemRequestBus::BroadcastResult(result, &Audio::Gem::AudioSystemGemRequestBus::Events::Initialize, nullptr); } if (result) { AZ_Assert(Audio::AudioSystemRequestBus::HasHandlers(), "Initialization of the Audio System succeeded, but the Audio System EBus is not connected!\n"); } else { AZ_Error(AZ_TRACE_SYSTEM_WINDOW, result, "The Audio System did not initialize correctly!\n"); } return result; } ////////////////////////////////////////////////////////////////////////// bool CSystem::InitVTuneProfiler() { LOADING_TIME_PROFILE_SECTION(GetISystem()); #ifdef PROFILE_WITH_VTUNE WIN_HMODULE hModule = LoadDLL("VTuneApi.dll"); if (!hModule) { return false; } VTPause = (VTuneFunction) CryGetProcAddress(hModule, "VTPause"); VTResume = (VTuneFunction) CryGetProcAddress(hModule, "VTResume"); if (!VTPause || !VTResume) { AZ_Assert(false, "VTune did not initialize correctly.") return false; } else { AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "VTune API Initialized"); } #endif //PROFILE_WITH_VTUNE return true; } ///////////////////////////////////////////////////////////////////////////////// bool CSystem::InitShine([[maybe_unused]] const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION(GetISystem()); EBUS_EVENT(UiSystemBus, InitializeSystem); if (!m_env.pLyShine) { AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, "LYShine System did not initialize correctly. Please check that the LyShine gem is enabled for this project in ProjectConfigurator."); return false; } return true; } ////////////////////////////////////////////////////////////////////////// void CSystem::InitLocalization() { LOADING_TIME_PROFILE_SECTION(GetISystem()); // Set the localization folder ICVar* pCVar = m_env.pConsole != 0 ? m_env.pConsole->GetCVar("sys_localization_folder") : 0; if (pCVar) { static_cast(m_env.pCryPak)->SetLocalizationFolder(g_cvars.sys_localization_folder->GetString()); } // Removed line that assigned language based on a #define if (m_pLocalizationManager == nullptr) { m_pLocalizationManager = new CLocalizedStringsManager(this); } // Platform-specific implementation of getting the system language ILocalizationManager::EPlatformIndependentLanguageID languageID = m_pLocalizationManager->GetSystemLanguage(); if (!m_pLocalizationManager->IsLanguageSupported(languageID)) { languageID = ILocalizationManager::EPlatformIndependentLanguageID::ePILID_English_US; } string language = m_pLocalizationManager->LangNameFromPILID(languageID); m_pLocalizationManager->SetLanguage(language.c_str()); if (m_pLocalizationManager->GetLocalizationFormat() == 1) { string translationsListXML = LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME; m_pLocalizationManager->InitLocalizationData(translationsListXML); m_pLocalizationManager->LoadAllLocalizationData(); } else { // if the language value cannot be found, let's default to the english pak OpenLanguagePak(language); } pCVar = m_env.pConsole != 0 ? m_env.pConsole->GetCVar("g_languageAudio") : 0; if (pCVar) { if (strlen(pCVar->GetString()) == 0) { pCVar->Set(language); } else { language = pCVar->GetString(); } } OpenLanguageAudioPak(language); } void CSystem::OpenBasicPaks() { static bool bBasicPaksLoaded = false; if (bBasicPaksLoaded) { return; } bBasicPaksLoaded = true; LOADING_TIME_PROFILE_SECTION; // open pak files constexpr AZStd::string_view paksFolder = "@assets@/*.pak"; // (@assets@ assumed) m_env.pCryPak->OpenPacks(paksFolder); InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( paksFolder.c_str() )"); ////////////////////////////////////////////////////////////////////////// // Open engine packs ////////////////////////////////////////////////////////////////////////// const char* const assetsDir = "@assets@"; const char* shaderCachePakDir = "@assets@/shadercache.pak"; const char* shaderCacheStartupPakDir = "@assets@/shadercachestartup.pak"; // After game paks to have same search order as with files on disk m_env.pCryPak->OpenPack(assetsDir, "Engine.pak"); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_15 #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif m_env.pCryPak->OpenPack(assetsDir, shaderCachePakDir); m_env.pCryPak->OpenPack(assetsDir, shaderCacheStartupPakDir); m_env.pCryPak->OpenPack(assetsDir, "Shaders.pak"); m_env.pCryPak->OpenPack(assetsDir, "ShadersBin.pak"); #ifdef AZ_PLATFORM_ANDROID // Load Android Obb files if available const char* obbStorage = AZ::Android::Utils::GetObbStoragePath(); AZStd::string mainObbPath = AZStd::move(AZStd::string::format("%s/%s", obbStorage, AZ::Android::Utils::GetObbFileName(true))); AZStd::string patchObbPath = AZStd::move(AZStd::string::format("%s/%s", obbStorage, AZ::Android::Utils::GetObbFileName(false))); m_env.pCryPak->OpenPack(assetsDir, mainObbPath.c_str()); m_env.pCryPak->OpenPack(assetsDir, patchObbPath.c_str()); #endif //AZ_PLATFORM_ANDROID InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( Engine... )"); ////////////////////////////////////////////////////////////////////////// // Open paks in MOD subfolders. ////////////////////////////////////////////////////////////////////////// #if !defined(_RELEASE) if (const ICmdLineArg* pModArg = GetICmdLine()->FindArg(eCLAT_Pre, "MOD")) { if (IsMODValid(pModArg->GetValue())) { AZStd::string modFolder = "Mods\\"; modFolder += pModArg->GetValue(); modFolder += "\\*.pak"; GetIPak()->OpenPacks(assetsDir, modFolder, AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::INestedArchive::FLAGS_OVERRIDE_PAK); } } #endif // !defined(_RELEASE) // Load paks required for game init to mem gEnv->pCryPak->LoadPakToMemory("Engine.pak", AZ::IO::IArchive::eInMemoryPakLocale_GPU); } ////////////////////////////////////////////////////////////////////////// void CSystem::OpenLanguagePak(const char* sLanguage) { // Don't attempt to open a language PAK file if the game doesn't have a // loc folder configured. bool projUsesLocalization = false; LocalizationManagerRequestBus::BroadcastResult(projUsesLocalization, &LocalizationManagerRequestBus::Events::ProjectUsesLocalization); if (!projUsesLocalization) { return; } // Initialize languages. // Omit the trailing slash! string sLocalizationFolder = PathUtil::GetLocalizationFolder(); // load xml pak with full filenames to perform wildcard searches. string sLocalizedPath; GetLocalizedPath(sLanguage, sLocalizedPath); if (!m_env.pCryPak->OpenPacks({ sLocalizationFolder.c_str(), sLocalizationFolder.size() }, { sLocalizedPath.c_str(), sLocalizedPath.size() }, 0)) { // make sure the localized language is found - not really necessary, for TC AZ_Printf("Localization", "Localized language content(%s) not available or modified from the original installation.", sLanguage); } } ////////////////////////////////////////////////////////////////////////// void CSystem::OpenLanguageAudioPak([[maybe_unused]] const char* sLanguage) { // Don't attempt to open a language PAK file if the game doesn't have a // loc folder configured. bool projUsesLocalization = false; LocalizationManagerRequestBus::BroadcastResult(projUsesLocalization, &LocalizationManagerRequestBus::Events::ProjectUsesLocalization); if (!projUsesLocalization) { return; } // Initialize languages. int nPakFlags = 0; // Omit the trailing slash! string sLocalizationFolder(string().assign(PathUtil::GetLocalizationFolder(), 0, PathUtil::GetLocalizationFolder().size() - 1)); if (sLocalizationFolder.compareNoCase("Languages") == 0) { sLocalizationFolder = "@assets@"; } // load localized pak with crc32 filenames on consoles to save memory. string sLocalizedPath = "loc.pak"; if (!m_env.pCryPak->OpenPacks(sLocalizationFolder.c_str(), sLocalizedPath.c_str(), nPakFlags)) { // make sure the localized language is found - not really necessary, for TC AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, "Localized language content(%s) not available or modified from the original installation.", sLanguage); } } string GetUniqueLogFileName(string logFileName) { string logFileNamePrefix = logFileName; if ((logFileNamePrefix[0] != '@') && (AzFramework::StringFunc::Path::IsRelative(logFileNamePrefix))) { logFileNamePrefix = "@log@/"; logFileNamePrefix += logFileName; } char resolvedLogFilePathBuffer[AZ_MAX_PATH_LEN] = { 0 }; AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(logFileNamePrefix.c_str(), resolvedLogFilePathBuffer, AZ_MAX_PATH_LEN); int instance = gEnv->pSystem->GetApplicationLogInstance(resolvedLogFilePathBuffer); if (instance == 0) { return logFileNamePrefix; } string logFileExtension; size_t extensionIndex = logFileName.find_last_of('.'); if (extensionIndex != string::npos) { logFileExtension = logFileName.substr(extensionIndex, logFileName.length() - extensionIndex); logFileNamePrefix = logFileName.substr(0, extensionIndex); } logFileName.Format("%s(%d)%s", logFileNamePrefix.c_str(), instance, logFileExtension.c_str()); return logFileName; } #if defined(WIN32) || defined(WIN64) static wstring GetErrorStringUnsupportedCPU() { static const wchar_t s_EN[] = L"Unsupported CPU detected. CPU needs to support SSE, SSE2, SSE3 and SSE4.1."; static const wchar_t s_FR[] = { 0 }; static const wchar_t s_RU[] = { 0 }; static const wchar_t s_ES[] = { 0 }; static const wchar_t s_DE[] = { 0 }; static const wchar_t s_IT[] = { 0 }; const size_t fullLangID = (size_t) GetKeyboardLayout(0); const size_t primLangID = fullLangID & 0x3FF; const wchar_t* pFmt = s_EN; /*switch (primLangID) { case 0x07: // German pFmt = s_DE; break; case 0x0a: // Spanish pFmt = s_ES; break; case 0x0c: // French pFmt = s_FR; break; case 0x10: // Italian pFmt = s_IT; break; case 0x19: // Russian pFmt = s_RU; break; case 0x09: // English default: break; }*/ wchar_t msg[1024]; msg[0] = L'\0'; msg[sizeof(msg) / sizeof(msg[0]) - 1] = L'\0'; azsnwprintf(msg, sizeof(msg) / sizeof(msg[0]) - 1, pFmt); return msg; } #endif static bool CheckCPURequirements([[maybe_unused]] CCpuFeatures* pCpu, [[maybe_unused]] CSystem* pSystem) { #if defined(WIN32) || defined(WIN64) if (!gEnv->IsDedicated()) { if (!(pCpu->hasSSE() && pCpu->hasSSE2() && pCpu->hasSSE3() && pCpu->hasSSE41())) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Unsupported CPU! Need SSE, SSE2, SSE3 and SSE4.1 instructions to be available."); #if !defined(_RELEASE) const bool allowPrompts = pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "noprompt") == 0; #else const bool allowPrompts = true; #endif // !defined(_RELEASE) if (allowPrompts) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Asking user if they wish to continue..."); const int mbRes = MessageBoxW(0, GetErrorStringUnsupportedCPU().c_str(), L"Lumberyard", MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2 | MB_DEFAULT_DESKTOP_ONLY); if (mbRes == IDCANCEL) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "User chose to cancel startup."); return false; } } else { #if !defined(_RELEASE) const bool obeyCPUCheck = pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "anycpu") == 0; #else const bool obeyCPUCheck = true; #endif // !defined(_RELEASE) if (obeyCPUCheck) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "No prompts allowed and unsupported CPU check active. Treating unsupported CPU as error and exiting."); return false; } } AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "User chose to continue despite unsupported CPU!"); } } #endif return true; } class AzConsoleToCryConsoleBinder final { public: static void OnInvoke(IConsoleCmdArgs* args) { std::string command = args->GetCommandLine(); const size_t delim = command.find_first_of('='); if (delim != std::string::npos) { // All Cry executed cfg files will come in through this pathway in addition to regular commands // We strip out the = sign at this layer to maintain compatibility with cvars that use the '=' as a separator // Swap the '=' character for a space command[delim] = ' '; } AZ::Interface::Get()->PerformCommand(command.c_str(), AZ::ConsoleSilentMode::Silent, AZ::ConsoleInvokedFrom::CryBinding); } static void OnVarChanged(ICVar* cvar) { AZ::CVarFixedString command = AZ::CVarFixedString::format("%s %s", cvar->GetName(), cvar->GetString()); AZ::Interface::Get()->PerformCommand(command.c_str(), AZ::ConsoleSilentMode::Silent, AZ::ConsoleInvokedFrom::CryBinding); } static void Visit(AZ::ConsoleFunctorBase* functor) { if (gEnv->pConsole == nullptr) { AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Cry console was NULL while attempting to register Az CVars and CFuncs.\n"); return; } int32_t cryFlags = VF_NET_SYNCED; if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::DontReplicate) != AZ::ConsoleFunctorFlags::Null) { cryFlags = VF_NULL; } if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::ServerOnly) != AZ::ConsoleFunctorFlags::Null) { cryFlags |= VF_DEDI_ONLY; } if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::ReadOnly) != AZ::ConsoleFunctorFlags::Null) { cryFlags |= VF_READONLY; } if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsCheat) != AZ::ConsoleFunctorFlags::Null) { cryFlags |= VF_CHEAT; } if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsInvisible) != AZ::ConsoleFunctorFlags::Null) { cryFlags |= VF_INVISIBLE; } if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsDeprecated) != AZ::ConsoleFunctorFlags::Null) { cryFlags |= VF_DEPRECATED; } if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::NeedsReload) != AZ::ConsoleFunctorFlags::Null) { cryFlags |= VF_REQUIRE_APP_RESTART; } if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::AllowClientSet) != AZ::ConsoleFunctorFlags::Null) { cryFlags |= VF_DEV_ONLY; } gEnv->pConsole->RemoveCommand(functor->GetName()); if (functor->GetTypeId() != AZ::TypeId::CreateNull()) { AZ::CVarFixedString value; functor->GetValue(value); gEnv->pConsole->RegisterString(functor->GetName(), value.c_str(), cryFlags, functor->GetDesc(), AzConsoleToCryConsoleBinder::OnVarChanged); } else { gEnv->pConsole->AddCommand(functor->GetName(), AzConsoleToCryConsoleBinder::OnInvoke, cryFlags, functor->GetDesc()); } } using CommandRegisteredHandler = AZ::IConsole::ConsoleCommandRegisteredEvent::Handler; static inline CommandRegisteredHandler s_commandRegisteredHandler = CommandRegisteredHandler([](AZ::ConsoleFunctorBase* functor) { Visit(functor); }); using CommandInvokedHandler = AZ::ConsoleCommandInvokedEvent::Handler; static inline CommandInvokedHandler s_commandInvokedHandler = CommandInvokedHandler([] ( AZStd::string_view command, const AZ::ConsoleCommandContainer& args, [[maybe_unused]] AZ::ConsoleFunctorFlags flags, AZ::ConsoleInvokedFrom invokedFrom ) { if (invokedFrom == AZ::ConsoleInvokedFrom::CryBinding) { // If a command originated from the cry console, do not echo it back to the cry console return; } AZ::CVarFixedString joinedCommand = AZ::CVarFixedString(command) + " "; AZ::StringFunc::Join(joinedCommand, args.begin(), args.end(), " "); gEnv->pConsole->ExecuteString(joinedCommand.c_str(), true); }); using CommandNotFoundHandler = AZ::DispatchCommandNotFoundEvent::Handler; static inline CommandNotFoundHandler s_commandNotFoundHandler = CommandNotFoundHandler([] ( AZStd::string_view command, const AZ::ConsoleCommandContainer& args, AZ::ConsoleInvokedFrom invokedFrom ) { if (invokedFrom == AZ::ConsoleInvokedFrom::CryBinding) { // If a command originated from the cry console, do not echo it back to the cry console return; } AZ::CVarFixedString joinedCommand = AZ::CVarFixedString(command) + " "; AZ::StringFunc::Join(joinedCommand, args.begin(), args.end(), " "); gEnv->pConsole->ExecuteString(joinedCommand.c_str(), true); }); }; // System initialization ///////////////////////////////////////////////////////////////////////////////// // INIT ///////////////////////////////////////////////////////////////////////////////// bool CSystem::Init(const SSystemInitParams& startupParams) { #if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER signal(SIGSEGV, CryEngineSignalHandler); signal(SIGTRAP, CryEngineSignalHandler); signal(SIGILL, CryEngineSignalHandler); #endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER // Temporary Fix for an issue accessing gEnv from this object instance. The gEnv is not resolving to the // global gEnv, instead its resolving an some uninitialized gEnv elsewhere (NULL). Since gEnv is // initialized to this instance's SSystemGlobalEnvironment (m_env), we will force set it again here // to m_env if (!gEnv) { gEnv = &m_env; } LOADING_TIME_PROFILE_SECTION; SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_INIT); gEnv->mMainThreadId = GetCurrentThreadId(); //Set this ASAP on startup InlineInitializationProcessing("CSystem::Init start"); m_szCmdLine = startupParams.szSystemCmdLine; m_env.szCmdLine = m_szCmdLine.c_str(); m_env.bTesting = startupParams.bTesting; m_env.bNoAssertDialog = startupParams.bTesting; m_env.bNoRandomSeed = startupParams.bNoRandom; m_bShaderCacheGenMode = startupParams.bShaderCacheGen; m_bNoCrashDialog = gEnv->IsDedicated(); if (startupParams.bUnattendedMode) { m_bNoCrashDialog = true; m_env.bNoAssertDialog = true; //this also suppresses CryMessageBox g_cvars.sys_no_crash_dialog = true; } #if defined(AZ_PLATFORM_LINUX) // Linux is all console for now and so no room for dialog boxes! m_env.bNoAssertDialog = true; #endif m_pCmdLine = new CCmdLine(startupParams.szSystemCmdLine); AZCoreLogSink::Connect(); // Registers all AZ Console Variables functors specified within CrySystem if (auto azConsole = AZ::Interface::Get(); azConsole) { azConsole->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead()); } if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry) { AZ::SettingsRegistryInterface::FixedValueString assetPlatform; if (!AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, assetPlatform, AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, "assets")) { assetPlatform = AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, R"(A valid asset platform is missing in "%s/assets" key in the SettingsRegistry.)""\n" R"(This typically done by setting he "assets" field in the bootstrap.cfg for within a .setreg file)""\n" R"(A fallback of %s will be used.)", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, assetPlatform.c_str()); } m_systemConfigName = "system_" AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER "_"; m_systemConfigName += assetPlatform.c_str(); m_systemConfigName += ".cfg"; } AZ_Assert(CryMemory::IsHeapValid(), "Memory heap must be valid before continuing SystemInit."); #ifdef EXTENSION_SYSTEM_INCLUDE_TESTCASES TestExtensions(&CCryFactoryRegistryImpl::Access()); #endif //_controlfp(0, _EM_INVALID|_EM_ZERODIVIDE | _PC_64 ); #if defined(WIN32) || defined(WIN64) // check OS version - we only want to run on XP or higher - talk to Martin Mittring if you want to change this { OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option") GetVersionExA(&osvi); AZ_POP_DISABLE_WARNING bool bIsWindowsXPorLater = osvi.dwMajorVersion > 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1); if (!bIsWindowsXPorLater) { AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, "Lumberyard requires an OS version of Windows XP or later."); return false; } } #endif m_pResourceManager->Init(); // Get file version information. QueryVersionInfo(); DetectGameFolderAccessRights(); m_hInst = (WIN_HINSTANCE)startupParams.hInstance; m_hWnd = (WIN_HWND)startupParams.hWnd; m_bEditor = startupParams.bEditor; m_bPreviewMode = startupParams.bPreview; m_bTestMode = startupParams.bTestMode; m_pUserCallback = startupParams.pUserCallback; m_bMinimal = startupParams.bMinimal; #if defined(CVARS_WHITELIST) m_pCVarsWhitelist = startupParams.pCVarsWhitelist; #endif // defined(CVARS_WHITELIST) m_bDedicatedServer = startupParams.bDedicatedServer; m_currentLanguageAudio = ""; memcpy(gEnv->pProtectedFunctions, startupParams.pProtectedFunctions, sizeof(startupParams.pProtectedFunctions)); #if !defined(CONSOLE) m_env.SetIsEditor(m_bEditor); m_env.SetIsEditorGameMode(false); m_env.SetIsEditorSimulationMode(false); #endif m_env.SetToolMode(startupParams.bToolMode); m_env.bIsOutOfMemory = false; if (m_bEditor) { m_bInDevMode = true; } if (!gEnv->IsDedicated()) { const ICmdLineArg* crashdialog = m_pCmdLine->FindArg(eCLAT_Post, "sys_no_crash_dialog"); if (crashdialog) { m_bNoCrashDialog = true; } } if (!startupParams.pValidator) { m_pDefaultValidator = new SDefaultValidator(this); m_pValidator = m_pDefaultValidator; } else { m_pValidator = startupParams.pValidator; } #if !defined(_RELEASE) if (!m_bDedicatedServer) { const ICmdLineArg* dedicated = m_pCmdLine->FindArg(eCLAT_Pre, "dedicated"); if (dedicated) { m_bDedicatedServer = true; } } #endif // !defined(_RELEASE) #if !defined(CONSOLE) gEnv->SetIsDedicated(m_bDedicatedServer); #endif #if !defined(CONSOLE) #if !defined(_RELEASE) bool isDaemonMode = (m_pCmdLine->FindArg(eCLAT_Pre, "daemon") != 0); #else bool isDaemonMode = false; #endif // !defined(_RELEASE) #if defined(USE_DEDICATED_SERVER_CONSOLE) #if !defined(_RELEASE) bool isSimpleConsole = (m_pCmdLine->FindArg(eCLAT_Pre, "simple_console") != 0); if (!(isDaemonMode || isSimpleConsole)) #endif // !defined(_RELEASE) { #if defined(USE_UNIXCONSOLE) CUNIXConsole* pConsole = new CUNIXConsole(); #if defined(LINUX) pUnixConsole = pConsole; #endif #elif defined(USE_IOSCONSOLE) CIOSConsole* pConsole = new CIOSConsole(); #elif defined(USE_WINDOWSCONSOLE) CWindowsConsole* pConsole = new CWindowsConsole(); #elif defined(USE_ANDROIDCONSOLE) CAndroidConsole* pConsole = new CAndroidConsole(); #else CNULLConsole* pConsole = new CNULLConsole(false); #endif m_pTextModeConsole = static_cast(pConsole); if (m_pUserCallback == nullptr && m_bDedicatedServer) { char headerString[128]; m_pUserCallback = pConsole; pConsole->SetRequireDedicatedServer(true); azstrcpy( headerString, AZ_ARRAY_SIZE(headerString), "Lumberyard - " #if defined(LINUX) "Linux " #elif defined(MAC) "MAC " #elif defined(IOS) "iOS " #endif "Dedicated Server" " - Version "); char* str = headerString + strlen(headerString); GetProductVersion().ToString(str, sizeof(headerString) - (str - headerString)); pConsole->SetHeader(headerString); } } #if !defined(_RELEASE) else #endif #endif #if !(defined(USE_DEDICATED_SERVER_CONSOLE) && defined(_RELEASE)) { CNULLConsole* pConsole = new CNULLConsole(isDaemonMode); m_pTextModeConsole = pConsole; if (m_pUserCallback == nullptr && m_bDedicatedServer) { m_pUserCallback = pConsole; } } #endif #endif // !defined(CONSOLE) { EBUS_EVENT(CrySystemEventBus, OnCrySystemPreInitialize, *this, startupParams); ////////////////////////////////////////////////////////////////////////// // File system, must be very early ////////////////////////////////////////////////////////////////////////// if (!InitFileSystem()) { return false; } ////////////////////////////////////////////////////////////////////////// InlineInitializationProcessing("CSystem::Init InitFileSystem"); m_missingAssetLogger = AZStd::make_unique(); ////////////////////////////////////////////////////////////////////////// // Logging is only available after file system initialization. ////////////////////////////////////////////////////////////////////////// if (!startupParams.pLog) { m_env.pLog = new CLog(this); if (startupParams.pLogCallback) { m_env.pLog->AddCallback(startupParams.pLogCallback); } const ICmdLineArg* logfile = m_pCmdLine->FindArg(eCLAT_Pre, "logfile"); //see if the user specified a log name, if so use it if (logfile && strlen(logfile->GetValue()) > 0) { m_env.pLog->SetFileName(logfile->GetValue(), startupParams.autoBackupLogs); } else if (startupParams.sLogFileName) //otherwise see if the startup params has a log file name, if so use it { const string sUniqueLogFileName = GetUniqueLogFileName(startupParams.sLogFileName); m_env.pLog->SetFileName(sUniqueLogFileName.c_str(), startupParams.autoBackupLogs); } else//use the default log name { m_env.pLog->SetFileName(DEFAULT_LOG_FILENAME, startupParams.autoBackupLogs); } } else { m_env.pLog = startupParams.pLog; } // The log backup system expects the version number to be the first line of the log // so we log this immediately after setting the log filename LogVersion(); //here we should be good to ask Crypak to do something // Initialise after pLog and CPU feature initialization // AND after console creation (Editor only) // May need access to engine folder .pak files gEnv->pThreadManager->GetThreadConfigManager()->LoadConfig("config/engine_core.thread_config"); if (m_bEditor) { gEnv->pThreadManager->GetThreadConfigManager()->LoadConfig("config/engine_sandbox.thread_config"); } // Setup main thread void* pThreadHandle = 0; // Let system figure out thread handle gEnv->pThreadManager->RegisterThirdPartyThread(pThreadHandle, "Main"); m_env.pProfileLogSystem = new CProfileLogSystem(); bool devModeEnable = true; #if defined(_RELEASE) // disable devmode by default in release builds outside the editor devModeEnable = m_bEditor; #endif // disable devmode in launcher if someone really wants to (even in non release builds) if (!m_bEditor && m_pCmdLine->FindArg(eCLAT_Pre, "nodevmode")) { devModeEnable = false; } SetDevMode(devModeEnable); ////////////////////////////////////////////////////////////////////////// // CREATE NOTIFICATION NETWORK ////////////////////////////////////////////////////////////////////////// m_pNotificationNetwork = nullptr; #ifndef _RELEASE #ifndef LINUX if (!startupParams.bMinimal) { m_pNotificationNetwork = CNotificationNetwork::Create(); } #endif//LINUX #endif // _RELEASE InlineInitializationProcessing("CSystem::Init NotificationNetwork"); ////////////////////////////////////////////////////////////////////////// // CREATE CONSOLE ////////////////////////////////////////////////////////////////////////// if (!startupParams.bSkipConsole) { m_env.pConsole = new CXConsole; if (startupParams.pPrintSync) { m_env.pConsole->AddOutputPrintSink(startupParams.pPrintSync); } } ////////////////////////////////////////////////////////////////////////// if (m_pUserCallback) { m_pUserCallback->OnInit(this); } m_env.pLog->RegisterConsoleVariables(); GetIRemoteConsole()->RegisterConsoleVariables(); if (!startupParams.bSkipConsole) { // Register system console variables. CreateSystemVars(); // Register Audio-related system CVars CreateAudioVars(); // Register any AZ CVar commands created above with the AZ Console system. AZ::ConsoleFunctorBase*& deferredHead = AZ::ConsoleFunctorBase::GetDeferredHead(); AZ::Interface::Get()->LinkDeferredFunctors(deferredHead); // Callback if (m_pUserCallback && m_env.pConsole) { m_pUserCallback->OnConsoleCreated(m_env.pConsole); } // Let listeners know its safe to register cvars EBUS_EVENT(CrySystemEventBus, OnCrySystemCVarRegistry); } // Set this as soon as the system cvars got initialized. static_cast(m_env.pCryPak)->SetLocalizationFolder(g_cvars.sys_localization_folder->GetString()); InlineInitializationProcessing("CSystem::Init Create console"); if (!startupParams.bSkipRenderer) { CreateRendererVars(startupParams); } // Need to load the engine.pak that includes the config files needed during initialization m_env.pCryPak->OpenPack("@assets@", "Engine.pak"); #if defined(AZ_PLATFORM_ANDROID) || defined(AZ_PLATFORM_IOS) MobileSysInspect::LoadDeviceSpecMapping(); #endif InitFileSystem_LoadEngineFolders(startupParams); #if !defined(RELEASE) || defined(RELEASE_LOGGING) // now that the system cfgs have been loaded, we can start the remote console GetIRemoteConsole()->Update(); #endif // CPU features detection. m_pCpu = new CCpuFeatures; m_pCpu->Detect(); m_env.pi.numCoresAvailableToProcess = m_pCpu->GetCPUCount(); m_env.pi.numLogicalProcessors = m_pCpu->GetLogicalCPUCount(); // Check hard minimum CPU requirements if (!CheckCPURequirements(m_pCpu, this)) { return false; } if (!startupParams.bSkipConsole) { LogSystemInfo(); } InlineInitializationProcessing("CSystem::Init Load Engine Folders"); ////////////////////////////////////////////////////////////////////////// //Load config files ////////////////////////////////////////////////////////////////////////// int curSpecVal = 0; ICVar* pSysSpecCVar = gEnv->pConsole->GetCVar("r_GraphicsQuality"); if (gEnv->pSystem->IsDevMode()) { if (pSysSpecCVar && pSysSpecCVar->GetFlags() & VF_WASINCONFIG) { curSpecVal = pSysSpecCVar->GetIVal(); pSysSpecCVar->SetFlags(pSysSpecCVar->GetFlags() | VF_SYSSPEC_OVERWRITE); } } // tools may not interact with @user@ if (!gEnv->IsInToolMode()) { if (m_pCmdLine->FindArg(eCLAT_Pre, "ResetProfile") == 0) { LoadConfiguration("@user@/game.cfg", 0, false); } } // If sys spec variable was specified, is not 0, and we are in devmode restore the value from before loading game.cfg // This enables setting of a specific sys_spec outside menu and game.cfg if (gEnv->pSystem->IsDevMode()) { if (pSysSpecCVar && curSpecVal && curSpecVal != pSysSpecCVar->GetIVal()) { pSysSpecCVar->Set(curSpecVal); } } { ILoadConfigurationEntrySink* pCVarsWhiteListConfigSink = GetCVarsWhiteListConfigSink(); // We have to load this file again since first time we did it without devmode LoadConfiguration(m_systemConfigName.c_str(), pCVarsWhiteListConfigSink); // Optional user defined overrides LoadConfiguration("user.cfg", pCVarsWhiteListConfigSink); if (!startupParams.bSkipRenderer) { // Load the hmd.cfg if it exists. This will enable optional stereo rendering. LoadConfiguration("hmd.cfg"); } if (startupParams.bShaderCacheGen) { LoadConfiguration("shadercachegen.cfg", pCVarsWhiteListConfigSink); } #if defined(ENABLE_STATS_AGENT) if (m_pCmdLine->FindArg(eCLAT_Pre, "useamblecfg")) { LoadConfiguration("amble.cfg", pCVarsWhiteListConfigSink); } #endif } #if defined(PERFORMANCE_BUILD) LoadConfiguration("performance.cfg"); #endif ////////////////////////////////////////////////////////////////////////// if (g_cvars.sys_asserts == 0) { gEnv->bIgnoreAllAsserts = true; } if (g_cvars.sys_asserts == 2) { gEnv->bNoAssertDialog = true; } ////////////////////////////////////////////////////////////////////////// // Stream Engine ////////////////////////////////////////////////////////////////////////// AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Stream Engine Initialization"); InitStreamEngine(); InlineInitializationProcessing("CSystem::Init StreamEngine"); { if (m_pCmdLine->FindArg(eCLAT_Pre, "NullRenderer")) { m_env.pConsole->LoadConfigVar("r_Driver", "NULL"); } else if (m_pCmdLine->FindArg(eCLAT_Pre, "DX11")) { m_env.pConsole->LoadConfigVar("r_Driver", "DX11"); } else if (m_pCmdLine->FindArg(eCLAT_Pre, "GL")) { m_env.pConsole->LoadConfigVar("r_Driver", "GL"); } } LogBuildInfo(); InlineInitializationProcessing("CSystem::Init LoadConfigurations"); m_env.pOverloadSceneManager = new COverloadSceneManager; if (m_bDedicatedServer && m_rDriver) { m_sSavedRDriver = m_rDriver->GetString(); m_rDriver->Set("NULL"); } #if defined(WIN32) || defined(WIN64) if (!startupParams.bSkipRenderer) { if (azstricmp(m_rDriver->GetString(), "Auto") == 0) { m_rDriver->Set("DX11"); } } if (gEnv->IsEditor() && azstricmp(m_rDriver->GetString(), "DX12") == 0) { AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, "DX12 mode is not supported in the editor. Reverting to DX11 mode."); m_rDriver->Set("DX11"); } #endif #ifdef WIN32 if ((g_cvars.sys_WER) && (!startupParams.bMinimal)) { SetUnhandledExceptionFilter(CryEngineExceptionFilterWER); } #endif ////////////////////////////////////////////////////////////////////////// // Localization ////////////////////////////////////////////////////////////////////////// if (!startupParams.bMinimal) { InitLocalization(); } InlineInitializationProcessing("CSystem::Init InitLocalizations"); ////////////////////////////////////////////////////////////////////////// // RENDERER ////////////////////////////////////////////////////////////////////////// const bool loadLegacyRenderer = gEnv->IsEditor() ? LOAD_LEGACY_RENDERER_FOR_EDITOR : LOAD_LEGACY_RENDERER_FOR_LAUNCHER; if (loadLegacyRenderer && !startupParams.bSkipRenderer) { AZ_Assert(CryMemory::IsHeapValid(), "CryMemory must be valid before initializing renderer."); AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Renderer initialization"); if (!InitRenderer(m_hInst, m_hWnd, startupParams)) { return false; } AZ_Assert(CryMemory::IsHeapValid(), "CryMemory must be valid after initializing renderer."); if (m_env.pRenderer) { bool bMultiGPUEnabled = false; m_env.pRenderer->EF_Query(EFQ_MultiGPUEnabled, bMultiGPUEnabled); if (bMultiGPUEnabled) { LoadConfiguration("mgpu.cfg"); } } InlineInitializationProcessing("CSystem::Init InitRenderer"); if (m_env.pCryFont) { m_env.pCryFont->SetRendererProperties(m_env.pRenderer); } AZ_Assert(m_env.pRenderer || startupParams.bSkipRenderer, "The renderer did not initialize correctly."); } #if !defined(AZ_RELEASE_BUILD) && defined(AZ_PLATFORM_ANDROID) m_thermalInfoHandler = AZStd::make_unique(); #endif if (g_cvars.sys_rendersplashscreen && !startupParams.bEditor && !startupParams.bShaderCacheGen) { if (m_env.pRenderer) { LOADING_TIME_PROFILE_SECTION_NAMED("Rendering Splash Screen"); ITexture* pTex = m_env.pRenderer->EF_LoadTexture(g_cvars.sys_splashscreen, FT_DONT_STREAM | FT_NOMIPS | FT_USAGE_ALLOWREADSRGB); //check the width and height as extra verification hack. This texture is loaded before the replace me, so there is //no backup if it fails to load. if (pTex && pTex->GetWidth() && pTex->GetHeight()) { const int splashWidth = pTex->GetWidth(); const int splashHeight = pTex->GetHeight(); const int screenWidth = m_env.pRenderer->GetOverlayWidth(); const int screenHeight = m_env.pRenderer->GetOverlayHeight(); const float scaleX = (float)screenWidth / (float)splashWidth; const float scaleY = (float)screenHeight / (float)splashHeight; float scale = 1.0f; switch (g_cvars.sys_splashScreenScaleMode) { case SSystemCVars::SplashScreenScaleMode_Fit: { scale = AZStd::GetMin(scaleX, scaleY); } break; case SSystemCVars::SplashScreenScaleMode_Fill: { scale = AZStd::GetMax(scaleX, scaleY); } break; } const float w = splashWidth * scale; const float h = splashHeight * scale; const float x = (screenWidth - w) * 0.5f; const float y = (screenHeight - h) * 0.5f; const float vx = (800.0f / (float) screenWidth); const float vy = (600.0f / (float) screenHeight); m_env.pRenderer->SetViewport(0, 0, screenWidth, screenHeight); // Skip splash screen rendering if (!AZ::Interface::Get()) { // make sure it's rendered in full screen mode when triple buffering is enabled as well for (size_t n = 0; n < 3; n++) { m_env.pRenderer->BeginFrame(); m_env.pRenderer->SetCullMode(R_CULL_NONE); m_env.pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST); m_env.pRenderer->Draw2dImageStretchMode(true); m_env.pRenderer->Draw2dImage(x * vx, y * vy, w * vx, h * vy, pTex->GetTextureID(), 0.0f, 1.0f, 1.0f, 0.0f); m_env.pRenderer->Draw2dImageStretchMode(false); m_env.pRenderer->EndFrame(); } } #if defined(AZ_PLATFORM_IOS) || defined(AZ_PLATFORM_MAC) // Pump system events in order to update the screen AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::PumpSystemEventLoopUntilEmpty); #endif pTex->Release(); } #if defined(AZ_PLATFORM_ANDROID) bool engineSplashEnabled = (g_cvars.sys_rendersplashscreen != 0); if (engineSplashEnabled) { AZ::Android::Utils::DismissSplashScreen(); } #endif } else { AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, "Could not load startscreen image: %s.", g_cvars.sys_splashscreen); } } ////////////////////////////////////////////////////////////////////////// // Open basic pak files after intro movie playback started ////////////////////////////////////////////////////////////////////////// OpenBasicPaks(); ////////////////////////////////////////////////////////////////////////// // AUDIO ////////////////////////////////////////////////////////////////////////// if (!startupParams.bMinimal) { if (InitAudioSystem(startupParams)) { // Pump the Log - Audio initialization happened on a non-main thread, there may be log messages queued up. gEnv->pLog->Update(); } else { // Failure to initialize audio system is no longer a fatal or an error. A warning is sufficient. AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, "