int main(int argc, const char* argv[]) { #ifdef ANDROID_NDK_PROFILER setenv("CPUPROFILE_FREQUENCY", "500", 1); setenv("CPUPROFILE", "/sdcard/gmon.out", 1); monstartup("ppsspp_headless"); #endif bool fullLog = false; bool useJit = true; bool autoCompare = false; bool verbose = false; const char *stateToLoad = 0; GPUCore gpuCore = GPU_NULL; std::vector<std::string> testFilenames; const char *mountIso = 0; const char *screenshotFilename = 0; bool readMount = false; float timeout = std::numeric_limits<float>::infinity(); for (int i = 1; i < argc; i++) { if (readMount) { mountIso = argv[i]; readMount = false; continue; } if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--mount")) readMount = true; else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--log")) fullLog = true; else if (!strcmp(argv[i], "-i")) useJit = false; else if (!strcmp(argv[i], "-j")) useJit = true; else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compare")) autoCompare = true; else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) verbose = true; else if (!strncmp(argv[i], "--graphics=", strlen("--graphics=")) && strlen(argv[i]) > strlen("--graphics=")) { const char *gpuName = argv[i] + strlen("--graphics="); if (!strcasecmp(gpuName, "gles")) gpuCore = GPU_GLES; else if (!strcasecmp(gpuName, "software")) gpuCore = GPU_SOFTWARE; else if (!strcasecmp(gpuName, "directx9")) gpuCore = GPU_DIRECTX9; else if (!strcasecmp(gpuName, "null")) gpuCore = GPU_NULL; else { printUsage(argv[0], "Unknown gpu backend specified after --graphics="); return 1; } } // Default to GLES if no value selected. else if (!strcmp(argv[i], "--graphics")) gpuCore = GPU_GLES; else if (!strncmp(argv[i], "--screenshot=", strlen("--screenshot=")) && strlen(argv[i]) > strlen("--screenshot=")) screenshotFilename = argv[i] + strlen("--screenshot="); else if (!strncmp(argv[i], "--timeout=", strlen("--timeout=")) && strlen(argv[i]) > strlen("--timeout=")) timeout = strtod(argv[i] + strlen("--timeout="), NULL); else if (!strcmp(argv[i], "--teamcity")) teamCityMode = true; else if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state=")) stateToLoad = argv[i] + strlen("--state="); else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) { printUsage(argv[0], NULL); return 1; } else testFilenames.push_back(argv[i]); } // TODO: Allow a filename here? if (testFilenames.size() == 1 && testFilenames[0] == "@-") { testFilenames.clear(); char temp[2048]; temp[2047] = '\0'; while (scanf("%2047s", temp) == 1) testFilenames.push_back(temp); } if (readMount) { printUsage(argv[0], "Missing argument after -m"); return 1; } if (testFilenames.empty()) { printUsage(argv[0], argc <= 1 ? NULL : "No executables specified"); return 1; } HeadlessHost *headlessHost = getHost(gpuCore); host = headlessHost; std::string error_string; bool glWorking = host->InitGL(&error_string); LogManager::Init(); LogManager *logman = LogManager::GetInstance(); PrintfLogger *printfLogger = new PrintfLogger(); for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) { LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i; logman->SetEnable(type, fullLog); logman->SetLogLevel(type, LogTypes::LDEBUG); logman->AddListener(type, printfLogger); } CoreParameter coreParameter; coreParameter.cpuCore = useJit ? CPU_JIT : CPU_INTERPRETER; coreParameter.gpuCore = glWorking ? gpuCore : GPU_NULL; coreParameter.enableSound = false; coreParameter.mountIso = mountIso ? mountIso : ""; coreParameter.startPaused = false; coreParameter.printfEmuLog = !autoCompare; coreParameter.headLess = true; coreParameter.renderWidth = 480; coreParameter.renderHeight = 272; coreParameter.pixelWidth = 480; coreParameter.pixelHeight = 272; coreParameter.unthrottle = true; g_Config.bEnableSound = false; g_Config.bFirstRun = false; g_Config.bIgnoreBadMemAccess = true; // Never report from tests. g_Config.sReportHost = ""; g_Config.bAutoSaveSymbolMap = false; g_Config.iRenderingMode = 0; g_Config.bHardwareTransform = true; #ifdef USING_GLES2 g_Config.iAnisotropyLevel = 0; #else g_Config.iAnisotropyLevel = 8; #endif g_Config.bVertexCache = true; g_Config.bTrueColor = true; g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH; g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR; g_Config.bEncryptSave = true; g_Config.sNickName = "shadow"; g_Config.iTimeZone = 60; g_Config.iDateFormat = PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY; g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CROSS; g_Config.iLockParentalLevel = 9; g_Config.iInternalResolution = 1; g_Config.bFrameSkipUnthrottle = false; g_Config.bEnableLogging = fullLog; g_Config.iNumWorkerThreads = 1; g_Config.iBGMVolume = MAX_CONFIG_VOLUME; g_Config.iSFXVolume = MAX_CONFIG_VOLUME; g_Config.bSoftwareSkinning = true; g_Config.bVertexDecoderJit = true; #ifdef _WIN32 InitSysDirectories(); #endif #if defined(ANDROID) #elif defined(BLACKBERRY) || defined(__SYMBIAN32__) #elif !defined(_WIN32) g_Config.memCardDirectory = std::string(getenv("HOME")) + "/.ppsspp/"; #endif // Try to find the flash0 directory. Often this is from a subdirectory. for (int i = 0; i < 3; ++i) { if (!File::Exists(g_Config.flash0Directory)) g_Config.flash0Directory += "../../flash0/"; } // Or else, maybe in the executable's dir. if (!File::Exists(g_Config.flash0Directory)) g_Config.flash0Directory = File::GetExeDirectory() + "flash0/"; if (screenshotFilename != 0) headlessHost->SetComparisonScreenshot(screenshotFilename); #ifdef ANDROID // For some reason the debugger installs it with this name? if (File::Exists("/data/app/org.ppsspp.ppsspp-2.apk")) { VFSRegister("", new ZipAssetReader("/data/app/org.ppsspp.ppsspp-2.apk", "assets/")); } if (File::Exists("/data/app/org.ppsspp.ppsspp.apk")) { VFSRegister("", new ZipAssetReader("/data/app/org.ppsspp.ppsspp.apk", "assets/")); } #endif if (stateToLoad != NULL) SaveState::Load(stateToLoad); std::vector<std::string> failedTests; std::vector<std::string> passedTests; for (size_t i = 0; i < testFilenames.size(); ++i) { coreParameter.fileToStart = testFilenames[i]; if (autoCompare) printf("%s:\n", coreParameter.fileToStart.c_str()); bool passed = RunAutoTest(headlessHost, coreParameter, autoCompare, verbose, timeout); if (autoCompare) { std::string testName = GetTestName(coreParameter.fileToStart); if (passed) { passedTests.push_back(testName); printf(" %s - passed!\n", testName.c_str()); } else failedTests.push_back(testName); } } if (autoCompare) { printf("%d tests passed, %d tests failed.\n", (int)passedTests.size(), (int)failedTests.size()); if (!failedTests.empty()) { printf("Failed tests:\n"); for (size_t i = 0; i < failedTests.size(); ++i) { printf(" %s\n", failedTests[i].c_str()); } } } host->ShutdownGL(); delete host; host = NULL; headlessHost = NULL; #ifdef ANDROID_NDK_PROFILER moncleanup(); #endif return 0; }
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) { setCurrentThreadName("Main"); // Windows Vista and above: alert Windows that PPSSPP is DPI aware, // so that we don't flicker in fullscreen on some PCs. MakePPSSPPDPIAware(); // FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. #ifdef _M_X64 _set_FMA3_enable(0); #endif EnableCrashingOnCrashes(); wchar_t modulePath[MAX_PATH]; GetModuleFileName(NULL, modulePath, MAX_PATH); for (size_t i = wcslen(modulePath) - 1; i > 0; i--) { if (modulePath[i] == '\\') { modulePath[i] = 0; break; } } SetCurrentDirectory(modulePath); // GetCurrentDirectory(MAX_PATH, modulePath); // for checking in the debugger #ifndef _DEBUG bool showLog = false; #else bool showLog = false; #endif VFSRegister("", new DirectoryAssetReader("assets/")); VFSRegister("", new DirectoryAssetReader("")); wchar_t lcCountry[256]; // LOCALE_SNAME is only available in WinVista+ // Really should find a way to do this in XP too :/ if (0 != GetLocaleInfo(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256)) { langRegion = ConvertWStringToUTF8(lcCountry); for (size_t i = 0; i < langRegion.size(); i++) { if (langRegion[i] == '-') langRegion[i] = '_'; } } else { langRegion = "en_US"; } osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture(); const char *configFilename = NULL; const char *configOption = "--config="; const char *controlsConfigFilename = NULL; const char *controlsOption = "--controlconfig="; for (int i = 1; i < __argc; ++i) { if (__argv[i][0] == '\0') continue; if (__argv[i][0] == '-') { if (!strncmp(__argv[i], configOption, strlen(configOption)) && strlen(__argv[i]) > strlen(configOption)) { configFilename = __argv[i] + strlen(configOption); } if (!strncmp(__argv[i], controlsOption, strlen(controlsOption)) && strlen(__argv[i]) > strlen(controlsOption)) { controlsConfigFilename = __argv[i] + strlen(controlsOption); } } } // On Win32 it makes more sense to initialize the system directories here // because the next place it was called was in the EmuThread, and it's too late by then. InitSysDirectories(); // Load config up here, because those changes below would be overwritten // if it's not loaded here first. g_Config.AddSearchPath(""); g_Config.AddSearchPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.SetDefaultPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.Load(configFilename, controlsConfigFilename); bool debugLogLevel = false; // The rest is handled in NativeInit(). for (int i = 1; i < __argc; ++i) { if (__argv[i][0] == '\0') continue; if (__argv[i][0] == '-') { switch (__argv[i][1]) { case 'l': showLog = true; g_Config.bEnableLogging = true; break; case 's': g_Config.bAutoRun = false; g_Config.bSaveSettings = false; break; case 'd': debugLogLevel = true; break; } if (!strncmp(__argv[i], "--fullscreen", strlen("--fullscreen"))) g_Config.bFullScreen = true; if (!strncmp(__argv[i], "--windowed", strlen("--windowed"))) g_Config.bFullScreen = false; } } #ifdef _DEBUG g_Config.bEnableLogging = true; #endif LogManager::Init(); // Consider at least the following cases before changing this code: // - By default in Release, the console should be hidden by default even if logging is enabled. // - By default in Debug, the console should be shown by default. // - The -l switch is expected to show the log console, REGARDLESS of config settings. // - It should be possible to log to a file without showing the console. LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console"); if (debugLogLevel) LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG); //Windows, API init stuff INITCOMMONCONTROLSEX comm; comm.dwSize = sizeof(comm); comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES; InitCommonControlsEx(&comm); timeBeginPeriod(1); MainWindow::Init(_hInstance); g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS); MainWindow::Show(_hInstance, iCmdShow); HWND hwndMain = MainWindow::GetHWND(); HWND hwndDisplay = MainWindow::GetDisplayHWND(); //initialize custom controls CtrlDisAsmView::init(); CtrlMemView::init(); CtrlRegisterList::init(); CGEDebugger::Init(); DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS)); host = new WindowsHost(hwndMain, hwndDisplay); host->SetWindowTitle(0); MainWindow::CreateDebugWindows(); // Emu thread is always running! EmuThread_Start(); InputDevice::BeginPolling(); HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS); HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS); //so.. we're at the message pump of the GUI thread for (MSG msg; GetMessage(&msg, NULL, 0, 0); ) // for no quit { if (msg.message == WM_KEYDOWN) { //hack to enable/disable menu command accelerate keys MainWindow::UpdateCommands(); //hack to make it possible to get to main window from floating windows with Esc if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE) BringWindowToTop(hwndMain); } //Translate accelerators and dialog messages... HWND wnd; HACCEL accel; switch (g_activeWindow) { case WINDOW_MAINWINDOW: wnd = hwndMain; accel = hAccelTable; break; case WINDOW_CPUDEBUGGER: wnd = disasmWindow[0] ? disasmWindow[0]->GetDlgHandle() : 0; accel = hDebugAccelTable; break; case WINDOW_GEDEBUGGER: default: wnd = 0; accel = 0; break; } if (!TranslateAccelerator(wnd, accel, &msg)) { if (!DialogManager::IsDialogMessage(&msg)) { //and finally translate and dispatch TranslateMessage(&msg); DispatchMessage(&msg); } } } VFSShutdown(); InputDevice::StopPolling(); EmuThread_Stop(); MainWindow::DestroyDebugWindows(); DialogManager::DestroyAll(); timeEndPeriod(1); delete host; g_Config.Save(); LogManager::Shutdown(); return 0; }
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) { setCurrentThreadName("Main"); CoInitializeEx(NULL, COINIT_MULTITHREADED); #ifdef _DEBUG _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif PROFILE_INIT(); #if defined(_M_X64) && defined(_MSC_VER) && _MSC_VER < 1900 // FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. _set_FMA3_enable(0); #endif EnableCrashingOnCrashes(); #ifndef _DEBUG bool showLog = false; #else bool showLog = true; #endif const std::string &exePath = File::GetExeDirectory(); VFSRegister("", new DirectoryAssetReader((exePath + "/assets/").c_str())); VFSRegister("", new DirectoryAssetReader(exePath.c_str())); langRegion = GetDefaultLangRegion(); osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture(); char configFilename[MAX_PATH] = { 0 }; const std::wstring configOption = L"--config="; char controlsConfigFilename[MAX_PATH] = { 0 }; const std::wstring controlsOption = L"--controlconfig="; std::vector<std::wstring> wideArgs = GetWideCmdLine(); for (size_t i = 1; i < wideArgs.size(); ++i) { if (wideArgs[i][0] == L'\0') continue; if (wideArgs[i][0] == L'-') { if (wideArgs[i].find(configOption) != std::wstring::npos && wideArgs[i].size() > configOption.size()) { const std::wstring tempWide = wideArgs[i].substr(configOption.size()); const std::string tempStr = ConvertWStringToUTF8(tempWide); std::strncpy(configFilename, tempStr.c_str(), MAX_PATH); } if (wideArgs[i].find(controlsOption) != std::wstring::npos && wideArgs[i].size() > controlsOption.size()) { const std::wstring tempWide = wideArgs[i].substr(controlsOption.size()); const std::string tempStr = ConvertWStringToUTF8(tempWide); std::strncpy(controlsConfigFilename, tempStr.c_str(), MAX_PATH); } } } // On Win32 it makes more sense to initialize the system directories here // because the next place it was called was in the EmuThread, and it's too late by then. InitSysDirectories(); // Load config up here, because those changes below would be overwritten // if it's not loaded here first. g_Config.AddSearchPath(""); g_Config.AddSearchPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.SetDefaultPath(GetSysDirectory(DIRECTORY_SYSTEM)); g_Config.Load(configFilename, controlsConfigFilename); bool debugLogLevel = false; const std::wstring gpuBackend = L"--graphics="; // The rest is handled in NativeInit(). for (size_t i = 1; i < wideArgs.size(); ++i) { if (wideArgs[i][0] == L'\0') continue; if (wideArgs[i][0] == L'-') { switch (wideArgs[i][1]) { case L'l': showLog = true; g_Config.bEnableLogging = true; break; case L's': g_Config.bAutoRun = false; g_Config.bSaveSettings = false; break; case L'd': debugLogLevel = true; break; } if (wideArgs[i] == L"--fullscreen") g_Config.bFullScreen = true; if (wideArgs[i] == L"--windowed") g_Config.bFullScreen = false; if (wideArgs[i].find(gpuBackend) != std::wstring::npos && wideArgs[i].size() > gpuBackend.size()) { const std::wstring restOfOption = wideArgs[i].substr(gpuBackend.size()); // Force software rendering off, as picking directx9 or gles implies HW acceleration. // Once software rendering supports Direct3D9/11, we can add more options for software, // such as "software-gles", "software-d3d9", and "software-d3d11", or something similar. // For now, software rendering force-activates OpenGL. if (restOfOption == L"directx9") { g_Config.iGPUBackend = GPU_BACKEND_DIRECT3D9; g_Config.bSoftwareRendering = false; } else if (restOfOption == L"gles") { g_Config.iGPUBackend = GPU_BACKEND_OPENGL; g_Config.bSoftwareRendering = false; } else if (restOfOption == L"software") { g_Config.iGPUBackend = GPU_BACKEND_OPENGL; g_Config.bSoftwareRendering = true; } } } } #ifdef _DEBUG g_Config.bEnableLogging = true; #endif if (iCmdShow == SW_MAXIMIZE) { // Consider this to mean --fullscreen. g_Config.bFullScreen = true; } LogManager::Init(); // Consider at least the following cases before changing this code: // - By default in Release, the console should be hidden by default even if logging is enabled. // - By default in Debug, the console should be shown by default. // - The -l switch is expected to show the log console, REGARDLESS of config settings. // - It should be possible to log to a file without showing the console. LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console"); if (debugLogLevel) LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG); //Windows, API init stuff INITCOMMONCONTROLSEX comm; comm.dwSize = sizeof(comm); comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES; InitCommonControlsEx(&comm); timeBeginPeriod(1); MainWindow::Init(_hInstance); g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS); MainWindow::Show(_hInstance); HWND hwndMain = MainWindow::GetHWND(); HWND hwndDisplay = MainWindow::GetDisplayHWND(); //initialize custom controls CtrlDisAsmView::init(); CtrlMemView::init(); CtrlRegisterList::init(); CGEDebugger::Init(); DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS)); host = new WindowsHost(_hInstance, hwndMain, hwndDisplay); host->SetWindowTitle(0); MainWindow::CreateDebugWindows(); const bool minimized = iCmdShow == SW_MINIMIZE || iCmdShow == SW_SHOWMINIMIZED || iCmdShow == SW_SHOWMINNOACTIVE; if (minimized) { MainWindow::Minimize(); } // Emu thread is always running! EmuThread_Start(); InputDevice::BeginPolling(); HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS); HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS); //so.. we're at the message pump of the GUI thread for (MSG msg; GetMessage(&msg, NULL, 0, 0); ) // for no quit { if (msg.message == WM_KEYDOWN) { //hack to enable/disable menu command accelerate keys MainWindow::UpdateCommands(); //hack to make it possible to get to main window from floating windows with Esc if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE) BringWindowToTop(hwndMain); } //Translate accelerators and dialog messages... HWND wnd; HACCEL accel; switch (g_activeWindow) { case WINDOW_MAINWINDOW: wnd = hwndMain; accel = hAccelTable; break; case WINDOW_CPUDEBUGGER: wnd = disasmWindow[0] ? disasmWindow[0]->GetDlgHandle() : 0; accel = hDebugAccelTable; break; case WINDOW_GEDEBUGGER: default: wnd = 0; accel = 0; break; } if (!TranslateAccelerator(wnd, accel, &msg)) { if (!DialogManager::IsDialogMessage(&msg)) { //and finally translate and dispatch TranslateMessage(&msg); DispatchMessage(&msg); } } } VFSShutdown(); InputDevice::StopPolling(); EmuThread_Stop(); MainWindow::DestroyDebugWindows(); DialogManager::DestroyAll(); timeEndPeriod(1); delete host; g_Config.Save(); LogManager::Shutdown(); if (g_Config.bRestartRequired) { W32Util::ExitAndRestart(); } CoUninitialize(); return 0; }