From 765d5bfbcf66a438cd2267fdd6fffd97972fd539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 10 Sep 2026 10:48:32 -0600 Subject: [PATCH] headless: make --nand and --screenshot-save work --nand had a field and an ApplyToConfig branch but nothing ever parsed it, so it was silently ignored. --screenshot-save only fired when a GE replay finished or a test used the EMIT_SCREENSHOT devctl, and even then only under --compare. Anything else - a game, or --vsh - ran to the timeout and wrote nothing. Capture the display at the end of the run when nothing else did, which is what makes it usable for looking at what a booting system actually has on screen. Co-Authored-By: Claude Opus 5 (1M context) --- Core/CmdLine.cpp | 1 + headless/Headless.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/Core/CmdLine.cpp b/Core/CmdLine.cpp index f29a2f0528..419b0a1858 100644 --- a/Core/CmdLine.cpp +++ b/Core/CmdLine.cpp @@ -194,6 +194,7 @@ static const CommandLineParam g_autoParams[] = { {POFF(appendConfig), CmdParamType::String, "appendconfig", '\0', "Merge config FILE into the current configuration"}, {POFF(root), CmdParamType::String, "root", 'r', "Mount directory as the root of host0:/."}, {POFF(memStick), CmdParamType::String, "memstick", '\0', "Memory stick root directory (contains PSP/GAME etc)"}, + {POFF(nand), CmdParamType::String, "nand", '\0', "Root NAND directory, one level above flash0 (default: the memstick's PSP/NAND)"}, {POFF(stateToLoad), CmdParamType::String, "state", '\0', "Load state from specified file"}, {POFF(stateToSave), CmdParamType::String, "save-state", '\0', "Save a state to FILE partway through the run", CmdLineMode::Headless}, {POFF(compare), CmdParamType::Bool, "compare", 'c', "Enable comparison mode", CmdLineMode::Headless}, diff --git a/headless/Headless.cpp b/headless/Headless.cpp index fcb61f6604..c3c04bbecf 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -61,6 +61,7 @@ #include "Core/Util/PkgUnpack.h" #include "headless/ReverseEngineer.h" #include "Core/WebServer.h" +#include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceUtility.h" #include "Core/SaveState.h" #include "GPU/GPUCommon.h" @@ -79,6 +80,7 @@ static Path g_comparisonScreenshot; static Path g_screenshotSavePath; static Path g_screenshotDiffPath; static bool g_screenshotSaveKeepAlpha = false; +static bool g_screenshotSaved = false; static double g_maxScreenshotError = 0.0; static bool g_screenshotFailed = false; static std::string g_debugOutputBuffer; @@ -207,6 +209,7 @@ void SendDebugScreenshot(const DebugScreenshotDesc &desc) { if (!g_screenshotSavePath.empty()) { ScreenshotComparer saver(pixels, FRAME_STRIDE, FRAME_WIDTH, FRAME_HEIGHT); bool saved = g_screenshotSavePath.GetFileExtension() == ".png" ? saver.SaveActualPNG(g_screenshotSavePath, g_screenshotSaveKeepAlpha) : saver.SaveActualBitmap(g_screenshotSavePath); + g_screenshotSaved = g_screenshotSaved || saved; if (saved) SendAndCollectOutput("Screenshot saved to: " + g_screenshotSavePath.ToVisualString() + "\n"); } @@ -406,6 +409,15 @@ static bool RunAutoTest(GraphicsContext *graphicsContext, CoreParameter &corePar draw->EndFrame(); } + if (!g_screenshotSavePath.empty() && !g_screenshotSaved) { + DebugScreenshotDesc desc; + PSPPointer topaddr; + __DisplayGetFramebuf(&topaddr, &desc.stride, &desc.format, 0); + desc.data = &topaddr[0]; + desc.height = 272; + SendDebugScreenshot(desc); + } + PSP_Shutdown(true); if (!opt.bench) {