diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 8e61522cee..da021db024 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -357,6 +357,18 @@ u32 sceDisplaySetFramebuf() { return 0; } +bool __DisplayGetFramebuf(u8 **topaddr, u32 *linesize, u32 *pixelFormat, int mode) { + const FrameBufferState &fbState = mode == 1 ? latchedFramebuf : framebuf; + if (topaddr != NULL) + *topaddr = Memory::GetPointer(fbState.topaddr); + if (linesize != NULL) + *linesize = fbState.pspFramebufLinesize; + if (pixelFormat != NULL) + *pixelFormat = fbState.pspFramebufFormat; + + return true; +} + u32 sceDisplayGetFramebuf(u32 topaddrPtr, u32 linesizePtr, u32 pixelFormatPtr, int mode) { const FrameBufferState &fbState = mode == 1 ? latchedFramebuf : framebuf; DEBUG_LOG(HLE,"sceDisplayGetFramebuf(*%08x = %08x, *%08x = %08x, *%08x = %08x, %i)", diff --git a/Core/HLE/sceDisplay.h b/Core/HLE/sceDisplay.h index c75faf93f7..fd6de956e3 100644 --- a/Core/HLE/sceDisplay.h +++ b/Core/HLE/sceDisplay.h @@ -26,6 +26,9 @@ void Register_sceDisplay(); // will return true once after every end-of-frame. bool __DisplayFrameDone(); +// Get information about the current framebuffer. +bool __DisplayGetFramebuf(u8 **topaddr, u32 *linesize, u32 *pixelFormat, int mode); + typedef void (*VblankCallback)(); // Listen for vblank events. Only register during init. void __DisplayListenVblank(VblankCallback callback); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 15c535cf4c..19a3a5cf4c 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -38,6 +38,9 @@ #include "sceKernelMemory.h" #include "sceKernelThread.h" +// For headless screenshots. +#include "sceDisplay.h" + #define ERROR_ERRNO_FILE_NOT_FOUND 0x80010002 #define ERROR_MEMSTICK_DEVCTL_BAD_PARAMS 0x80220081 @@ -782,6 +785,15 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, SaveState::Verify(); // TODO: Maybe save/load to a file just to be sure? return 0; + + case 0x20: // EMULATOR_DEVCTL__EMIT_SCREENSHOT + u8 *topaddr; + u32 linesize, pixelFormat; + + __DisplayGetFramebuf(&topaddr, &linesize, &pixelFormat, 0); + // TODO: Convert based on pixel format / mode / something? + host->SendDebugScreenshot(topaddr, linesize, 272); + return 0; } ERROR_LOG(HLE, "sceIoDevCtl: UNKNOWN PARAMETERS"); diff --git a/Core/Host.h b/Core/Host.h index 29cc5b2fc4..d426289d14 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -63,6 +63,7 @@ public: // Used for headless. virtual void SendDebugOutput(const std::string &output) {} + virtual void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) {} }; extern Host *host; diff --git a/headless/Headless.cpp b/headless/Headless.cpp index b01338982e..e6ff10335b 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -59,7 +59,10 @@ void printUsage(const char *progname, const char *reason) HEADLESSHOST_CLASS h1; HeadlessHost h2; if (typeid(h1) != typeid(h2)) + { fprintf(stderr, " --graphics use the full gpu backend (slower)\n"); + fprintf(stderr, " --screenshot=FILE compare against a screenshot\n"); + } fprintf(stderr, " -f use the fast interpreter\n"); fprintf(stderr, " -j use jit (overrides -f)\n"); @@ -77,6 +80,7 @@ int main(int argc, const char* argv[]) const char *bootFilename = 0; const char *mountIso = 0; + const char *screenshotFilename = 0; bool readMount = false; for (int i = 1; i < argc; i++) @@ -99,6 +103,8 @@ int main(int argc, const char* argv[]) autoCompare = true; else if (!strcmp(argv[i], "--graphics")) useGraphics = true; + else if (!strncmp(argv[i], "--screenshot=", strlen("--screenshot=")) && strlen(argv[i]) > strlen("--screenshot=")) + screenshotFilename = argv[i] + strlen("--screenshot="); else if (bootFilename == 0) bootFilename = argv[i]; else @@ -174,6 +180,9 @@ int main(int argc, const char* argv[]) host->BootDone(); + if (screenshotFilename != 0) + headlessHost->SetComparisonScreenshot(screenshotFilename); + coreState = CORE_RUNNING; while (coreState == CORE_RUNNING) { diff --git a/headless/StubHost.h b/headless/StubHost.h index 9445aee06c..1533c381c3 100644 --- a/headless/StubHost.h +++ b/headless/StubHost.h @@ -50,6 +50,7 @@ public: virtual bool AttemptLoadSymbolMap() {return false;} virtual void SendDebugOutput(const std::string &output) { printf("%s", output.c_str()); } + virtual void SetComparisonScreenshot(const std::string &filename) {} virtual bool isGLWorking() { return false; } }; \ No newline at end of file diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp index 606235c26a..689afbf800 100644 --- a/headless/WindowsHeadlessHost.cpp +++ b/headless/WindowsHeadlessHost.cpp @@ -89,6 +89,16 @@ void WindowsHeadlessHost::SendDebugOutput(const std::string &output) OutputDebugString(output.c_str()); } +void WindowsHeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) +{ + fprintf_s(out, "Got a screenshot: %d/%d\n", w, h); +} + +void WindowsHeadlessHost::SetComparisonScreenshot(const std::string &filename) +{ + comparisonScreenshot = filename; +} + void WindowsHeadlessHost::InitGL() { glOkay = false; diff --git a/headless/WindowsHeadlessHost.h b/headless/WindowsHeadlessHost.h index 28e51ee543..5abc20ca05 100644 --- a/headless/WindowsHeadlessHost.h +++ b/headless/WindowsHeadlessHost.h @@ -35,6 +35,8 @@ public: virtual bool isGLWorking() { return glOkay; } virtual void SendDebugOutput(const std::string &output); + virtual void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h); + virtual void SetComparisonScreenshot(const std::string &filename); private: bool ResizeGL(); @@ -45,4 +47,5 @@ private: HDC hDC; HGLRC hRC; FILE *out; + std::string comparisonScreenshot; }; \ No newline at end of file diff --git a/test.py b/test.py index 52b2b906b1..983e47db6a 100755 --- a/test.py +++ b/test.py @@ -222,6 +222,8 @@ def run_tests(test_list, args): cmdline = [PPSSPP_EXE, elf_filename] cmdline.extend([i for i in args if i not in ['-v', '-g']]) + if os.path.exists(expected_filename + ".bmp"): + cmdline.extend(["--screenshot=" + expected_filename + ".bmp", "--graphics"]) c = Command(cmdline) c.run(TIMEOUT)