diff --git a/Core/CmdLine.cpp b/Core/CmdLine.cpp index 65361d2ba2..c4a6a48d09 100644 --- a/Core/CmdLine.cpp +++ b/Core/CmdLine.cpp @@ -21,6 +21,7 @@ enum class CmdParamType { Bool, BoolInverse, Int, + Double, String, }; @@ -66,6 +67,9 @@ ParseParamResult SetValue(CommandLineOptions *options, const CommandLineParam &p case CmdParamType::Int: *reinterpret_cast *>(reinterpret_cast(options) + param.offsetInStruct) = std::stoi(value); break; + case CmdParamType::Double: + *reinterpret_cast *>(reinterpret_cast(options) + param.offsetInStruct) = std::stod(value); + break; case CmdParamType::String: *reinterpret_cast *>(reinterpret_cast(options) + param.offsetInStruct) = value; break; @@ -132,21 +136,23 @@ static ParseParamResult ParseParameterStr(int argc, const char *argv[], size_t & } static const CommandLineParam g_autoParams[] = { - {POFF(fullscreen), CmdParamType::Bool, "fullscreen", 0, "Force full screen mode", CmdLineMode::Application}, - {POFF(fullscreen), CmdParamType::BoolInverse, "windowed", 0, "Force windowed mode", CmdLineMode::Application}, - {POFF(startScreen), CmdParamType::String, "start-screen", 0, "Start on a specific screen (e.g. 'gamesettings', 'touchscreentest')", CmdLineMode::Application}, - {POFF(escapeExit), CmdParamType::Bool, "escape-exit", 0, "Escape key exits the application", CmdLineMode::Application}, - {POFF(pauseMenuExit), CmdParamType::Bool, "pause-menu-exit", 0, "Change \"Exit to menu\" in pause menu to \"Exit\"", CmdLineMode::Application}, - {POFF(appendConfig), CmdParamType::String, "appendconfig", 0, "Merge config FILE into the current configuration"}, + {POFF(fullscreen), CmdParamType::Bool, "fullscreen", '\0', "Force full screen mode", CmdLineMode::Application}, + {POFF(fullscreen), CmdParamType::BoolInverse, "windowed", '\0', "Force windowed mode", CmdLineMode::Application}, + {POFF(startScreen), CmdParamType::String, "start-screen", '\0', "Start on a specific screen (e.g. 'gamesettings', 'touchscreentest')", CmdLineMode::Application}, + {POFF(escapeExit), CmdParamType::Bool, "escape-exit", '\0', "Escape key exits the application", CmdLineMode::Application}, + {POFF(pauseMenuExit), CmdParamType::Bool, "pause-menu-exit", '\0', "Change \"Exit to menu\" in pause menu to \"Exit\"", CmdLineMode::Application}, + {POFF(appendConfig), CmdParamType::String, "appendconfig", '\0', "Merge config FILE into the current configuration"}, {POFF(root), CmdParamType::String, "root", 'r', "Mount root directory"}, - {POFF(stateToLoad), CmdParamType::String, "state", 0, "Load state from specified file"}, + {POFF(stateToLoad), CmdParamType::String, "state", '\0', "Load state from specified file"}, {POFF(compare), CmdParamType::Bool, "compare", 'c', "Enable comparison mode"}, {POFF(bench), CmdParamType::Bool, "bench", 'b', "Enable benchmark mode"}, - {POFF(oldAtrac), CmdParamType::Bool, "old-atrac", 0, "Use old ATRAC decoder"}, - {POFF(log), CmdParamType::String, "log", 0, "Output log to FILE"}, - {POFF(screenshotFilename), CmdParamType::String, "screenshot", 0, "Take a screenshot and save to FILE"}, - {POFF(screenshotFilenameSave), CmdParamType::String, "screenshot-save", 0, "Save screenshot to specified path"}, - {POFF(timeout), CmdParamType::Int, "timeout", 0, "Set the timeout value"}, + {POFF(oldAtrac), CmdParamType::Bool, "old-atrac", '\0', "Use old ATRAC decoder"}, + {POFF(log), CmdParamType::String, "log", '\0', "Output log to FILE"}, + {POFF(screenshotFilename), CmdParamType::String, "screenshot", '\0', "Take a screenshot and save to FILE"}, + {POFF(screenshotFilenameSave), CmdParamType::String, "screenshot-save", '\0', "Save screenshot to specified path"}, + {POFF(timeout), CmdParamType::Double, "timeout", '\0', "Set the timeout value"}, + {POFF(resolutionScale), CmdParamType::Int, "resolution-scale", '\0', "Set the resolution scale factor"}, + // TODO: At some point we should maybe simply expose all config settings to be set directly from the command line automatically? }; // NOTE: On Windows this prints nothing unfortunately, since PPSSPP is not a "console app". @@ -405,6 +411,11 @@ void CommandLineOptions::ApplyToConfig() const { g_Config.mountRoot = Path(root.value()); } + if (resolutionScale.has_value()) { + g_Config.iInternalResolution = resolutionScale.value(); + g_Config.DoNotSaveSetting(&g_Config.iInternalResolution); + } + // Note: dpi is not applied here - it's platform-specific. // Platforms should check cmdLineOptions.dpi.has_value() and handle accordingly. } diff --git a/Core/CmdLine.h b/Core/CmdLine.h index 5eb2b3ea09..99f08822e5 100644 --- a/Core/CmdLine.h +++ b/Core/CmdLine.h @@ -64,6 +64,10 @@ struct CommandLineOptions { std::optional oldAtrac; + // Headless options that may also be mildly useful in application mode + std::optional resolutionScale; + + // Headless options std::optional compare; std::optional bench; @@ -71,5 +75,5 @@ struct CommandLineOptions { std::optional screenshotFilename; std::optional screenshotFilenameSave; - std::optional timeout; + std::optional timeout; }; diff --git a/headless/Compare.cpp b/headless/Compare.cpp index 48bba6bce1..e0f6f470d8 100644 --- a/headless/Compare.cpp +++ b/headless/Compare.cpp @@ -56,8 +56,7 @@ struct BufferedLineReader { const static int MAX_BUFFER = 5; const static int TEMP_BUFFER_SIZE = 32768; - BufferedLineReader(const std::string &data) : data_(data) { - } + BufferedLineReader(const std::string &data) : data_(data) {} void Fill() { while (valid_ < MAX_BUFFER && HasMoreLines()) { @@ -203,13 +202,11 @@ bool CompareOutput(const Path &bootFilename, const std::string &output, bool ver BufferedLineReader actual(output); bool failed = false; - while (expected.HasLines()) - { + while (expected.HasLines()) { if (expected.Compare(actual)) continue; - if (!failed) - { + if (!failed) { GitHubActionsPrint("error", "Incorrect output for %s", currentTestName.c_str()); failed = true; } @@ -217,20 +214,18 @@ bool CompareOutput(const Path &bootFilename, const std::string &output, bool ver // This is a really dirt simple comparing algorithm. // Perhaps it was an extra line? - if (expected.Peek(0) == actual.Peek(1) || !expected.HasLines()) + if (expected.Peek(0) == actual.Peek(1) || !expected.HasLines()) { printf("+ %s\n", actual.Consume().c_str()); - // A single missing line? - else if (expected.Peek(1) == actual.Peek(0) || !actual.HasLines()) + // A single missing line? + } else if (expected.Peek(1) == actual.Peek(0) || !actual.HasLines()) { printf("- %s\n", expected.Consume().c_str()); - else - { + } else { printf("O %s\n", actual.Consume().c_str()); printf("E %s\n", expected.Consume().c_str()); } } - while (actual.HasLines()) - { + while (actual.HasLines()) { // If it's a blank line, this will pass. if (actual.Compare(expected)) continue; @@ -238,16 +233,12 @@ bool CompareOutput(const Path &bootFilename, const std::string &output, bool ver printf("+ %s\n", actual.Consume().c_str()); } - if (verbose) - { - if (!failed) - { + if (verbose) { + if (!failed) { printf("++++++++++++++ The Equal Output +++++++++++++\n"); printf("%s", output.c_str()); printf("+++++++++++++++++++++++++++++++++++++++++++++\n"); - } - else - { + } else { printf("============== output from failed %s:\n", GetTestName(bootFilename).c_str()); printf("%s", output.c_str()); printf("============== expected output:\n"); diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 055b0e40bd..295a1f81f8 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -234,6 +234,7 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const // If we were rendering, this might be a nice time to do something about it. if (coreState == CORE_NEXTFRAME) { + // INFO_LOG(Log::System, "(frame)"); coreState = CORE_RUNNING_CPU; headlessHost->SwapBuffers(); } @@ -372,7 +373,7 @@ int main(int argc, const char* argv[]) { AutoTestOptions testOptions{}; testOptions.compare = cmdLineOptions.compare.value_or(false); testOptions.bench = cmdLineOptions.bench.value_or(false); - testOptions.timeout = cmdLineOptions.timeout.value_or(0); + testOptions.timeout = cmdLineOptions.timeout.value_or(std::numeric_limits::infinity()); bool fullLog = false; const char *stateToLoad = 0; @@ -477,14 +478,14 @@ int main(int argc, const char* argv[]) { coreParameter.mountRoot = mountRoot.empty() ? Path() : Path(mountRoot); coreParameter.startBreak = false; coreParameter.headLess = true; - coreParameter.renderScaleFactor = 1; - coreParameter.renderWidth = 480; - coreParameter.renderHeight = 272; - coreParameter.pixelWidth = 480; - coreParameter.pixelHeight = 272; + coreParameter.renderScaleFactor = cmdLineOptions.resolutionScale.value_or(1); + coreParameter.renderWidth = 480 * coreParameter.renderScaleFactor; + coreParameter.renderHeight = 272 * coreParameter.renderScaleFactor; + coreParameter.pixelWidth = 480 * coreParameter.renderScaleFactor; + coreParameter.pixelHeight = 272 * coreParameter.renderScaleFactor; coreParameter.fastForward = true; - g_Config.RestoreDefaults(RestoreSettingsBits::SETTINGS | RestoreSettingsBits::CONTROLS, true); + g_Config.RestoreDefaults(RestoreSettingsBits::SETTINGS | RestoreSettingsBits::CONTROLS | RestoreSettingsBits::RECENT, true); // Somehow this affects the test execution of pspautotests/tests/gpu/vertices/morph.prx, even though // we actually set the cpu core in CoreParameter above. Probably because we end up using the JIT vs non-JIT @@ -512,7 +513,7 @@ int main(int argc, const char* argv[]) { 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.iInternalResolution = coreParameter.renderScaleFactor; g_Config.bEnableLogging = (fullLog || outputDebugStringLog); g_Config.bVertexDecoderJit = true; g_Config.bSoftwareRendering = coreParameter.gpuCore == GPUCORE_SOFTWARE; @@ -589,13 +590,16 @@ int main(int argc, const char* argv[]) { StartWebServer(WebServerFlags::DEBUGGER); } - if (stateToLoad != NULL) + if (stateToLoad) { SaveState::Load(Path(stateToLoad), -1); + } + + // Run the tests (or frame dumps), one after another. std::vector failedTests; std::vector passedTests; - for (size_t i = 0; i < testFilenames.size(); ++i) - { + + for (size_t i = 0; i < testFilenames.size(); ++i) { coreParameter.fileToStart = Path(testFilenames[i]); if (testOptions.compare) printf("%s:\n", coreParameter.fileToStart.c_str()); @@ -607,9 +611,9 @@ int main(int argc, const char* argv[]) { for (int i = 0; i < 100; ++i) { RunAutoTest(headlessHost, coreParameter, testOptions); runs++; - - if (time_now_d() > deadline) + if (time_now_d() > deadline) { break; + } } double et = time_now_d(); @@ -621,9 +625,9 @@ int main(int argc, const char* argv[]) { if (passed) { passedTests.push_back(testName); printf(" %s - passed!\n", testName.c_str()); - } - else + } else { failedTests.push_back(testName); + } } }