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) <noreply@anthropic.com>
This commit is contained in:
Henrik Rydgård
2026-09-10 10:48:32 -06:00
co-authored by Claude Opus 5
parent a52b11aa2e
commit 765d5bfbcf
2 changed files with 13 additions and 0 deletions
+1
View File
@@ -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},
+12
View File
@@ -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<u8> topaddr;
__DisplayGetFramebuf(&topaddr, &desc.stride, &desc.format, 0);
desc.data = &topaddr[0];
desc.height = 272;
SendDebugScreenshot(desc);
}
PSP_Shutdown(true);
if (!opt.bench) {