2012-11-01 15:19:01 +00:00
|
|
|
// Headless version of PPSSPP, for testing using http://code.google.com/p/pspautotests/ .
|
|
|
|
// See headless.txt.
|
|
|
|
// To build on non-windows systems, just run CMake in the SDL directory, it will build both a normal ppsspp and the headless version.
|
|
|
|
|
2013-09-16 15:36:10 +00:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <limits>
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2014-03-25 07:49:03 +00:00
|
|
|
#include "file/zip_read.h"
|
2015-05-30 19:53:57 +00:00
|
|
|
#include "profiler/profiler.h"
|
2013-11-17 18:15:49 +00:00
|
|
|
#include "Common/FileUtil.h"
|
2017-04-21 04:10:59 +00:00
|
|
|
#include "Common/GraphicsContext.h"
|
2013-02-18 22:25:06 +00:00
|
|
|
#include "Core/Config.h"
|
2018-06-17 01:42:31 +00:00
|
|
|
#include "Core/ConfigValues.h"
|
2013-02-18 22:25:06 +00:00
|
|
|
#include "Core/Core.h"
|
|
|
|
#include "Core/CoreTiming.h"
|
|
|
|
#include "Core/System.h"
|
2013-04-11 05:17:43 +00:00
|
|
|
#include "Core/HLE/sceUtility.h"
|
2013-02-18 22:25:06 +00:00
|
|
|
#include "Core/Host.h"
|
2014-03-25 07:46:21 +00:00
|
|
|
#include "Core/SaveState.h"
|
2018-06-17 02:20:23 +00:00
|
|
|
#include "GPU/Common/FramebufferCommon.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
#include "Log.h"
|
|
|
|
#include "LogManager.h"
|
2013-09-04 10:07:42 +00:00
|
|
|
#include "base/NativeApp.h"
|
2013-09-16 15:36:10 +00:00
|
|
|
#include "base/timeutil.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-02-08 08:22:37 +00:00
|
|
|
#include "Compare.h"
|
2012-12-30 03:36:03 +00:00
|
|
|
#include "StubHost.h"
|
2017-06-18 19:15:59 +00:00
|
|
|
#if defined(_WIN32)
|
2012-12-30 03:36:03 +00:00
|
|
|
#include "WindowsHeadlessHost.h"
|
2017-06-18 19:15:59 +00:00
|
|
|
#elif defined(SDL)
|
|
|
|
#include "SDLHeadlessHost.h"
|
2012-12-30 03:36:03 +00:00
|
|
|
#endif
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-11-03 00:13:17 +00:00
|
|
|
// https://github.com/richq/android-ndk-profiler
|
|
|
|
#ifdef ANDROID_NDK_PROFILER
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "android/android-ndk-profiler/prof.h"
|
|
|
|
#endif
|
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
class PrintfLogger : public LogListener {
|
2012-11-09 12:40:09 +00:00
|
|
|
public:
|
2017-03-18 09:47:10 +00:00
|
|
|
void Log(const LogMessage &message) {
|
|
|
|
switch (message.level) {
|
2013-03-11 05:31:47 +00:00
|
|
|
case LogTypes::LVERBOSE:
|
2017-03-18 09:47:10 +00:00
|
|
|
fprintf(stderr, "V %s", message.msg.c_str());
|
2013-03-11 05:31:47 +00:00
|
|
|
break;
|
2012-11-09 12:40:09 +00:00
|
|
|
case LogTypes::LDEBUG:
|
2017-03-18 09:47:10 +00:00
|
|
|
fprintf(stderr, "D %s", message.msg.c_str());
|
2012-11-09 12:40:09 +00:00
|
|
|
break;
|
|
|
|
case LogTypes::LINFO:
|
2017-03-18 09:47:10 +00:00
|
|
|
fprintf(stderr, "I %s", message.msg.c_str());
|
2012-11-09 12:40:09 +00:00
|
|
|
break;
|
|
|
|
case LogTypes::LERROR:
|
2017-03-18 09:47:10 +00:00
|
|
|
fprintf(stderr, "E %s", message.msg.c_str());
|
2012-11-09 12:40:09 +00:00
|
|
|
break;
|
|
|
|
case LogTypes::LWARNING:
|
2017-03-18 09:47:10 +00:00
|
|
|
fprintf(stderr, "W %s", message.msg.c_str());
|
2012-11-09 12:40:09 +00:00
|
|
|
break;
|
|
|
|
case LogTypes::LNOTICE:
|
|
|
|
default:
|
2017-03-18 09:47:10 +00:00
|
|
|
fprintf(stderr, "N %s", message.msg.c_str());
|
2012-11-09 12:40:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-08-17 14:07:14 +00:00
|
|
|
// Temporary hacks around annoying linking errors.
|
2017-03-15 05:01:18 +00:00
|
|
|
void NativeUpdate() { }
|
2015-12-31 15:59:40 +00:00
|
|
|
void NativeRender(GraphicsContext *graphicsContext) { }
|
2014-02-10 14:14:45 +00:00
|
|
|
void NativeResized() { }
|
2013-03-30 05:39:37 +00:00
|
|
|
|
2013-09-04 10:07:42 +00:00
|
|
|
std::string System_GetProperty(SystemProperty prop) { return ""; }
|
2017-04-05 14:21:08 +00:00
|
|
|
int System_GetPropertyInt(SystemProperty prop) {
|
|
|
|
return -1;
|
|
|
|
}
|
2017-04-30 00:35:12 +00:00
|
|
|
bool System_GetPropertyBool(SystemProperty prop) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-12-04 16:41:59 +00:00
|
|
|
void System_SendMessage(const char *command, const char *parameter) {}
|
2013-12-08 11:12:45 +00:00
|
|
|
bool System_InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) { return false; }
|
2015-12-17 21:41:50 +00:00
|
|
|
void System_AskForPermission(SystemPermission permission) {}
|
|
|
|
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
|
2013-09-04 10:07:42 +00:00
|
|
|
|
2014-04-19 19:52:43 +00:00
|
|
|
int printUsage(const char *progname, const char *reason)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-25 05:45:32 +00:00
|
|
|
if (reason != NULL)
|
|
|
|
fprintf(stderr, "Error: %s\n\n", reason);
|
2012-11-01 15:19:01 +00:00
|
|
|
fprintf(stderr, "PPSSPP Headless\n");
|
2012-12-06 07:47:09 +00:00
|
|
|
fprintf(stderr, "This is primarily meant as a non-interactive test tool.\n\n");
|
2013-09-17 06:58:42 +00:00
|
|
|
fprintf(stderr, "Usage: %s file.elf... [options]\n\n", progname);
|
2012-11-25 05:45:32 +00:00
|
|
|
fprintf(stderr, "Options:\n");
|
2014-04-19 19:52:43 +00:00
|
|
|
fprintf(stderr, " -m, --mount umd.cso mount iso on umd1:\n");
|
|
|
|
fprintf(stderr, " -r, --root some/path mount path on host0: (elfs must be in here)\n");
|
2012-11-25 05:45:32 +00:00
|
|
|
fprintf(stderr, " -l, --log full log output, not just emulated printfs\n");
|
2012-12-30 05:01:13 +00:00
|
|
|
|
2014-08-30 16:57:56 +00:00
|
|
|
#if defined(HEADLESSHOST_CLASS)
|
2013-01-14 00:35:34 +00:00
|
|
|
{
|
2013-09-12 04:40:25 +00:00
|
|
|
fprintf(stderr, " --graphics=BACKEND use the full gpu backend (slower)\n");
|
2017-04-23 01:17:03 +00:00
|
|
|
fprintf(stderr, " options: gles, software, directx9, etc.\n");
|
2013-01-14 00:35:34 +00:00
|
|
|
fprintf(stderr, " --screenshot=FILE compare against a screenshot\n");
|
|
|
|
}
|
2013-10-14 09:35:29 +00:00
|
|
|
#endif
|
2013-09-16 15:36:10 +00:00
|
|
|
fprintf(stderr, " --timeout=SECONDS abort test it if takes longer than SECONDS\n");
|
2012-12-30 05:01:13 +00:00
|
|
|
|
2013-09-17 07:15:19 +00:00
|
|
|
fprintf(stderr, " -v, --verbose show the full passed/failed result\n");
|
2013-02-09 09:14:39 +00:00
|
|
|
fprintf(stderr, " -i use the interpreter\n");
|
2016-05-15 02:21:52 +00:00
|
|
|
fprintf(stderr, " --ir use ir interpreter\n");
|
2013-02-09 09:14:39 +00:00
|
|
|
fprintf(stderr, " -j use jit (default)\n");
|
2012-11-25 05:45:32 +00:00
|
|
|
fprintf(stderr, " -c, --compare compare with output in file.expected\n");
|
|
|
|
fprintf(stderr, "\nSee headless.txt for details.\n");
|
2014-04-19 19:52:43 +00:00
|
|
|
|
|
|
|
return 1;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2014-08-30 16:57:56 +00:00
|
|
|
static HeadlessHost *getHost(GPUCore gpuCore) {
|
|
|
|
switch (gpuCore) {
|
2016-04-10 08:21:48 +00:00
|
|
|
case GPUCORE_NULL:
|
2013-09-16 07:42:30 +00:00
|
|
|
return new HeadlessHost();
|
2014-08-30 16:57:56 +00:00
|
|
|
#ifdef HEADLESSHOST_CLASS
|
2013-09-16 07:42:30 +00:00
|
|
|
default:
|
|
|
|
return new HEADLESSHOST_CLASS();
|
2014-08-30 16:57:56 +00:00
|
|
|
#else
|
|
|
|
default:
|
|
|
|
return new HeadlessHost();
|
|
|
|
#endif
|
2013-09-16 07:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-17 07:15:19 +00:00
|
|
|
bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool autoCompare, bool verbose, double timeout)
|
2013-09-17 06:49:41 +00:00
|
|
|
{
|
|
|
|
if (teamCityMode) {
|
|
|
|
// Kinda ugly, trying to guesstimate the test name from filename...
|
2013-09-17 07:15:19 +00:00
|
|
|
teamCityName = GetTestName(coreParameter.fileToStart);
|
2013-09-17 06:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string output;
|
|
|
|
if (autoCompare)
|
|
|
|
coreParameter.collectEmuLog = &output;
|
|
|
|
|
|
|
|
std::string error_string;
|
|
|
|
if (!PSP_Init(coreParameter, &error_string)) {
|
|
|
|
fprintf(stderr, "Failed to start %s. Error: %s\n", coreParameter.fileToStart.c_str(), error_string.c_str());
|
|
|
|
printf("TESTERROR\n");
|
|
|
|
TeamCityPrint("##teamcity[testIgnored name='%s' message='PRX/ELF missing']\n", teamCityName.c_str());
|
2013-09-18 07:17:30 +00:00
|
|
|
return false;
|
2013-09-17 06:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TeamCityPrint("##teamcity[testStarted name='%s' captureStandardOutput='true']\n", teamCityName.c_str());
|
|
|
|
|
|
|
|
host->BootDone();
|
|
|
|
|
|
|
|
if (autoCompare)
|
|
|
|
headlessHost->SetComparisonScreenshot(ExpectedScreenshotFromFilename(coreParameter.fileToStart));
|
|
|
|
|
|
|
|
time_update();
|
|
|
|
bool passed = true;
|
2013-11-23 18:42:28 +00:00
|
|
|
// TODO: We must have some kind of stack overflow or we're not following the ABI right.
|
|
|
|
// This gets trashed if it's not static.
|
2013-12-07 05:18:26 +00:00
|
|
|
static double deadline;
|
|
|
|
deadline = time_now() + timeout;
|
2013-09-17 06:49:41 +00:00
|
|
|
|
2017-11-08 10:57:53 +00:00
|
|
|
Core_UpdateDebugStats(g_Config.bShowDebugStats || g_Config.bLogFrameDrops);
|
|
|
|
|
2017-04-23 01:17:03 +00:00
|
|
|
PSP_BeginHostFrame();
|
2017-11-15 06:34:18 +00:00
|
|
|
if (coreParameter.thin3d)
|
|
|
|
coreParameter.thin3d->BeginFrame();
|
2017-04-23 01:17:03 +00:00
|
|
|
|
2013-09-17 06:49:41 +00:00
|
|
|
coreState = CORE_RUNNING;
|
|
|
|
while (coreState == CORE_RUNNING)
|
|
|
|
{
|
|
|
|
int blockTicks = usToCycles(1000000 / 10);
|
|
|
|
PSP_RunLoopFor(blockTicks);
|
|
|
|
|
|
|
|
// If we were rendering, this might be a nice time to do something about it.
|
|
|
|
if (coreState == CORE_NEXTFRAME) {
|
|
|
|
coreState = CORE_RUNNING;
|
|
|
|
headlessHost->SwapBuffers();
|
|
|
|
}
|
|
|
|
time_update();
|
|
|
|
if (time_now_d() > deadline) {
|
|
|
|
// Don't compare, print the output at least up to this point, and bail.
|
|
|
|
printf("%s", output.c_str());
|
|
|
|
passed = false;
|
|
|
|
|
|
|
|
host->SendDebugOutput("TIMEOUT\n");
|
|
|
|
TeamCityPrint("##teamcity[testFailed name='%s' message='Test timeout']\n", teamCityName.c_str());
|
|
|
|
Core_Stop();
|
|
|
|
}
|
|
|
|
}
|
2017-11-15 14:35:15 +00:00
|
|
|
PSP_EndHostFrame();
|
2013-09-17 06:49:41 +00:00
|
|
|
|
2017-11-15 06:34:18 +00:00
|
|
|
if (coreParameter.thin3d)
|
|
|
|
coreParameter.thin3d->EndFrame();
|
2017-04-23 01:17:03 +00:00
|
|
|
|
2013-09-17 06:49:41 +00:00
|
|
|
PSP_Shutdown();
|
|
|
|
|
|
|
|
headlessHost->FlushDebugOutput();
|
|
|
|
|
|
|
|
if (autoCompare && passed)
|
2013-09-17 07:15:19 +00:00
|
|
|
passed = CompareOutput(coreParameter.fileToStart, output, verbose);
|
2013-09-17 06:49:41 +00:00
|
|
|
|
|
|
|
TeamCityPrint("##teamcity[testFinished name='%s']\n", teamCityName.c_str());
|
|
|
|
|
|
|
|
return passed;
|
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
int main(int argc, const char* argv[])
|
|
|
|
{
|
2015-05-30 19:53:57 +00:00
|
|
|
PROFILE_INIT();
|
|
|
|
|
2017-06-18 19:15:59 +00:00
|
|
|
#if defined(_DEBUG) && defined(_MSC_VER)
|
2017-04-29 19:02:07 +00:00
|
|
|
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
|
|
|
#endif
|
|
|
|
|
2013-11-03 00:13:17 +00:00
|
|
|
#ifdef ANDROID_NDK_PROFILER
|
|
|
|
setenv("CPUPROFILE_FREQUENCY", "500", 1);
|
|
|
|
setenv("CPUPROFILE", "/sdcard/gmon.out", 1);
|
|
|
|
monstartup("ppsspp_headless");
|
|
|
|
#endif
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
bool fullLog = false;
|
|
|
|
bool autoCompare = false;
|
2013-09-17 07:15:19 +00:00
|
|
|
bool verbose = false;
|
2014-03-25 07:46:21 +00:00
|
|
|
const char *stateToLoad = 0;
|
2016-04-10 08:21:48 +00:00
|
|
|
GPUCore gpuCore = GPUCORE_NULL;
|
2017-03-02 11:36:54 +00:00
|
|
|
CPUCore cpuCore = CPUCore::JIT;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-09-17 06:58:42 +00:00
|
|
|
std::vector<std::string> testFilenames;
|
2012-11-01 15:19:01 +00:00
|
|
|
const char *mountIso = 0;
|
2014-04-19 19:52:43 +00:00
|
|
|
const char *mountRoot = 0;
|
2013-01-14 00:35:34 +00:00
|
|
|
const char *screenshotFilename = 0;
|
2013-09-17 06:17:34 +00:00
|
|
|
float timeout = std::numeric_limits<float>::infinity();
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2012-11-25 05:45:32 +00:00
|
|
|
for (int i = 1; i < argc; i++)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2014-04-19 19:52:43 +00:00
|
|
|
if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--mount"))
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2014-04-19 19:52:43 +00:00
|
|
|
if (++i >= argc)
|
|
|
|
return printUsage(argv[0], "Missing argument after -m");
|
2012-11-01 15:19:01 +00:00
|
|
|
mountIso = argv[i];
|
|
|
|
}
|
2014-04-19 19:52:43 +00:00
|
|
|
else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--root"))
|
|
|
|
{
|
|
|
|
if (++i >= argc)
|
|
|
|
return printUsage(argv[0], "Missing argument after -r");
|
|
|
|
mountRoot = argv[i];
|
|
|
|
}
|
2012-11-25 05:45:32 +00:00
|
|
|
else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--log"))
|
2012-11-01 15:19:01 +00:00
|
|
|
fullLog = true;
|
2013-02-09 09:14:39 +00:00
|
|
|
else if (!strcmp(argv[i], "-i"))
|
2017-03-02 11:36:54 +00:00
|
|
|
cpuCore = CPUCore::INTERPRETER;
|
2012-11-01 15:19:01 +00:00
|
|
|
else if (!strcmp(argv[i], "-j"))
|
2017-03-02 11:36:54 +00:00
|
|
|
cpuCore = CPUCore::JIT;
|
2016-05-15 02:21:52 +00:00
|
|
|
else if (!strcmp(argv[i], "--ir"))
|
2017-03-02 11:36:54 +00:00
|
|
|
cpuCore = CPUCore::IR_JIT;
|
2012-11-25 05:45:32 +00:00
|
|
|
else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compare"))
|
2012-11-01 15:19:01 +00:00
|
|
|
autoCompare = true;
|
2013-09-17 07:15:19 +00:00
|
|
|
else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose"))
|
|
|
|
verbose = true;
|
2013-09-12 04:40:25 +00:00
|
|
|
else if (!strncmp(argv[i], "--graphics=", strlen("--graphics=")) && strlen(argv[i]) > strlen("--graphics="))
|
|
|
|
{
|
|
|
|
const char *gpuName = argv[i] + strlen("--graphics=");
|
|
|
|
if (!strcasecmp(gpuName, "gles"))
|
2016-04-10 08:21:48 +00:00
|
|
|
gpuCore = GPUCORE_GLES;
|
2013-09-12 04:40:25 +00:00
|
|
|
else if (!strcasecmp(gpuName, "software"))
|
2016-04-10 08:21:48 +00:00
|
|
|
gpuCore = GPUCORE_SOFTWARE;
|
2013-09-12 04:40:25 +00:00
|
|
|
else if (!strcasecmp(gpuName, "directx9"))
|
2016-04-10 08:21:48 +00:00
|
|
|
gpuCore = GPUCORE_DIRECTX9;
|
2017-04-23 01:17:03 +00:00
|
|
|
else if (!strcasecmp(gpuName, "directx11"))
|
|
|
|
gpuCore = GPUCORE_DIRECTX11;
|
2016-03-13 18:23:46 +00:00
|
|
|
else if (!strcasecmp(gpuName, "vulkan"))
|
2016-04-10 08:21:48 +00:00
|
|
|
gpuCore = GPUCORE_VULKAN;
|
2013-09-12 04:40:25 +00:00
|
|
|
else if (!strcasecmp(gpuName, "null"))
|
2016-04-10 08:21:48 +00:00
|
|
|
gpuCore = GPUCORE_NULL;
|
2013-09-12 04:40:25 +00:00
|
|
|
else
|
2017-11-15 14:35:15 +00:00
|
|
|
return printUsage(argv[0], "Unknown gpu backend specified after --graphics=. Allowed: software, directx9, directx11, vulkan, gles, null.");
|
2013-09-12 04:40:25 +00:00
|
|
|
}
|
|
|
|
// Default to GLES if no value selected.
|
2019-05-10 21:25:57 +00:00
|
|
|
else if (!strcmp(argv[i], "--graphics")) {
|
|
|
|
#if PPSSPP_API(ANY_GL)
|
2016-04-10 08:21:48 +00:00
|
|
|
gpuCore = GPUCORE_GLES;
|
2019-05-10 21:25:57 +00:00
|
|
|
#else
|
|
|
|
gpuCore = GPUCORE_DIRECTX11;
|
|
|
|
#endif
|
2019-05-11 04:41:45 +00:00
|
|
|
} else if (!strncmp(argv[i], "--screenshot=", strlen("--screenshot=")) && strlen(argv[i]) > strlen("--screenshot="))
|
2013-01-14 00:35:34 +00:00
|
|
|
screenshotFilename = argv[i] + strlen("--screenshot=");
|
2013-09-16 15:36:10 +00:00
|
|
|
else if (!strncmp(argv[i], "--timeout=", strlen("--timeout=")) && strlen(argv[i]) > strlen("--timeout="))
|
|
|
|
timeout = strtod(argv[i] + strlen("--timeout="), NULL);
|
2013-09-16 15:15:59 +00:00
|
|
|
else if (!strcmp(argv[i], "--teamcity"))
|
|
|
|
teamCityMode = true;
|
2014-03-25 07:46:21 +00:00
|
|
|
else if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
|
|
|
|
stateToLoad = argv[i] + strlen("--state=");
|
2013-09-17 06:58:42 +00:00
|
|
|
else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h"))
|
2014-04-19 19:52:43 +00:00
|
|
|
return printUsage(argv[0], NULL);
|
2013-09-17 06:58:42 +00:00
|
|
|
else
|
|
|
|
testFilenames.push_back(argv[i]);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2013-09-18 07:17:30 +00:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2013-09-17 06:58:42 +00:00
|
|
|
if (testFilenames.empty())
|
2014-04-19 19:52:43 +00:00
|
|
|
return printUsage(argv[0], argc <= 1 ? NULL : "No executables specified");
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-09-16 07:42:30 +00:00
|
|
|
HeadlessHost *headlessHost = getHost(gpuCore);
|
2016-03-13 18:23:46 +00:00
|
|
|
headlessHost->SetGraphicsCore(gpuCore);
|
2012-12-30 03:36:03 +00:00
|
|
|
host = headlessHost;
|
2013-03-10 22:08:57 +00:00
|
|
|
|
|
|
|
std::string error_string;
|
2017-04-21 04:10:59 +00:00
|
|
|
GraphicsContext *graphicsContext = nullptr;
|
2015-12-31 15:59:40 +00:00
|
|
|
bool glWorking = host->InitGraphics(&error_string, &graphicsContext);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
LogManager::Init();
|
|
|
|
LogManager *logman = LogManager::GetInstance();
|
|
|
|
|
2012-11-09 12:40:09 +00:00
|
|
|
PrintfLogger *printfLogger = new PrintfLogger();
|
|
|
|
|
2015-12-31 15:59:40 +00:00
|
|
|
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) {
|
2012-11-01 15:19:01 +00:00
|
|
|
LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
|
2017-03-18 09:47:10 +00:00
|
|
|
logman->SetEnabled(type, fullLog);
|
2012-11-01 15:19:01 +00:00
|
|
|
logman->SetLogLevel(type, LogTypes::LDEBUG);
|
|
|
|
}
|
2017-03-17 16:57:32 +00:00
|
|
|
logman->AddListener(printfLogger);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
CoreParameter coreParameter;
|
2016-05-07 23:43:27 +00:00
|
|
|
coreParameter.cpuCore = cpuCore;
|
2016-04-10 08:21:48 +00:00
|
|
|
coreParameter.gpuCore = glWorking ? gpuCore : GPUCORE_NULL;
|
2016-01-03 19:05:36 +00:00
|
|
|
coreParameter.graphicsContext = graphicsContext;
|
2017-04-21 04:10:59 +00:00
|
|
|
coreParameter.thin3d = graphicsContext ? graphicsContext->GetDrawContext() : nullptr;
|
2012-11-01 15:19:01 +00:00
|
|
|
coreParameter.enableSound = false;
|
2013-04-11 05:17:43 +00:00
|
|
|
coreParameter.mountIso = mountIso ? mountIso : "";
|
2014-04-19 19:52:43 +00:00
|
|
|
coreParameter.mountRoot = mountRoot ? mountRoot : "";
|
2018-06-23 17:14:36 +00:00
|
|
|
coreParameter.startBreak = false;
|
2013-09-16 15:15:59 +00:00
|
|
|
coreParameter.printfEmuLog = !autoCompare;
|
2013-04-11 05:17:43 +00:00
|
|
|
coreParameter.headLess = true;
|
|
|
|
coreParameter.renderWidth = 480;
|
|
|
|
coreParameter.renderHeight = 272;
|
|
|
|
coreParameter.pixelWidth = 480;
|
|
|
|
coreParameter.pixelHeight = 272;
|
2013-05-20 15:28:07 +00:00
|
|
|
coreParameter.unthrottle = true;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2012-11-17 17:08:10 +00:00
|
|
|
g_Config.bEnableSound = false;
|
2012-11-05 12:36:12 +00:00
|
|
|
g_Config.bFirstRun = false;
|
|
|
|
g_Config.bIgnoreBadMemAccess = true;
|
2013-03-09 20:53:53 +00:00
|
|
|
// Never report from tests.
|
|
|
|
g_Config.sReportHost = "";
|
2013-04-11 05:17:43 +00:00
|
|
|
g_Config.bAutoSaveSymbolMap = false;
|
2018-06-17 02:20:23 +00:00
|
|
|
g_Config.iRenderingMode = FB_BUFFERED_MODE;
|
2013-04-11 05:17:43 +00:00
|
|
|
g_Config.bHardwareTransform = true;
|
2017-11-15 17:14:04 +00:00
|
|
|
g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this.
|
2013-04-11 05:17:43 +00:00
|
|
|
g_Config.bVertexCache = true;
|
2013-09-16 22:08:09 +00:00
|
|
|
g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH;
|
2013-06-19 05:08:29 +00:00
|
|
|
g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR;
|
2013-04-11 05:17:43 +00:00
|
|
|
g_Config.bEncryptSave = true;
|
2013-04-20 16:30:46 +00:00
|
|
|
g_Config.sNickName = "shadow";
|
|
|
|
g_Config.iTimeZone = 60;
|
|
|
|
g_Config.iDateFormat = PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY;
|
2013-06-19 05:08:29 +00:00
|
|
|
g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CROSS;
|
2013-04-20 16:30:46 +00:00
|
|
|
g_Config.iLockParentalLevel = 9;
|
2013-09-12 04:40:25 +00:00
|
|
|
g_Config.iInternalResolution = 1;
|
2013-09-19 07:29:19 +00:00
|
|
|
g_Config.bFrameSkipUnthrottle = false;
|
2013-11-17 18:15:13 +00:00
|
|
|
g_Config.bEnableLogging = fullLog;
|
2013-12-15 17:36:41 +00:00
|
|
|
g_Config.iNumWorkerThreads = 1;
|
2018-04-10 10:22:02 +00:00
|
|
|
g_Config.bSoftwareSkinning = true;
|
2014-03-25 07:46:21 +00:00
|
|
|
g_Config.bVertexDecoderJit = true;
|
2014-06-14 15:44:14 +00:00
|
|
|
g_Config.bBlockTransferGPU = true;
|
2016-04-10 04:10:41 +00:00
|
|
|
g_Config.iSplineBezierQuality = 2;
|
2017-12-27 00:19:11 +00:00
|
|
|
g_Config.bHighQualityDepth = true;
|
2018-05-29 00:24:40 +00:00
|
|
|
g_Config.bMemStickInserted = true;
|
2018-09-10 03:09:48 +00:00
|
|
|
g_Config.bFragmentTestCache = true;
|
2019-06-30 23:39:14 +00:00
|
|
|
g_Config.iAudioLatency = 1;
|
2012-11-05 12:36:12 +00:00
|
|
|
|
2013-10-25 09:45:41 +00:00
|
|
|
#ifdef _WIN32
|
2013-10-25 04:29:48 +00:00
|
|
|
InitSysDirectories();
|
2013-10-25 09:45:41 +00:00
|
|
|
#endif
|
|
|
|
|
2016-10-12 09:13:16 +00:00
|
|
|
#if !defined(__ANDROID__) && !defined(_WIN32)
|
2014-10-19 21:20:51 +00:00
|
|
|
g_Config.memStickDirectory = std::string(getenv("HOME")) + "/.ppsspp/";
|
2013-01-21 00:50:42 +00:00
|
|
|
#endif
|
|
|
|
|
2013-11-17 18:15:49 +00:00
|
|
|
// 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))
|
2017-03-31 21:50:17 +00:00
|
|
|
g_Config.flash0Directory = File::GetExeDirectory() + "assets/flash0/";
|
2013-11-17 18:15:49 +00:00
|
|
|
|
2013-01-14 00:35:34 +00:00
|
|
|
if (screenshotFilename != 0)
|
|
|
|
headlessHost->SetComparisonScreenshot(screenshotFilename);
|
|
|
|
|
2016-10-12 09:13:16 +00:00
|
|
|
#ifdef __ANDROID__
|
2014-03-25 07:49:03 +00:00
|
|
|
// 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
|
|
|
|
|
2014-03-25 07:46:21 +00:00
|
|
|
if (stateToLoad != NULL)
|
|
|
|
SaveState::Load(stateToLoad);
|
|
|
|
|
2013-09-17 07:02:53 +00:00
|
|
|
std::vector<std::string> failedTests;
|
|
|
|
std::vector<std::string> passedTests;
|
2013-09-17 06:58:42 +00:00
|
|
|
for (size_t i = 0; i < testFilenames.size(); ++i)
|
|
|
|
{
|
|
|
|
coreParameter.fileToStart = testFilenames[i];
|
|
|
|
if (autoCompare)
|
|
|
|
printf("%s:\n", coreParameter.fileToStart.c_str());
|
2013-09-17 07:15:19 +00:00
|
|
|
bool passed = RunAutoTest(headlessHost, coreParameter, autoCompare, verbose, timeout);
|
2013-09-17 07:02:53 +00:00
|
|
|
if (autoCompare)
|
|
|
|
{
|
2013-09-17 07:15:19 +00:00
|
|
|
std::string testName = GetTestName(coreParameter.fileToStart);
|
2013-09-17 07:02:53 +00:00
|
|
|
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");
|
2013-09-19 07:29:19 +00:00
|
|
|
for (size_t i = 0; i < failedTests.size(); ++i) {
|
2013-09-17 15:12:39 +00:00
|
|
|
printf(" %s\n", failedTests[i].c_str());
|
2013-09-17 07:02:53 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-17 06:58:42 +00:00
|
|
|
}
|
|
|
|
|
2014-09-20 19:55:58 +00:00
|
|
|
host->ShutdownGraphics();
|
2013-09-17 06:58:42 +00:00
|
|
|
delete host;
|
2017-04-29 19:02:07 +00:00
|
|
|
host = nullptr;
|
|
|
|
headlessHost = nullptr;
|
|
|
|
|
|
|
|
VFSShutdown();
|
|
|
|
LogManager::Shutdown();
|
|
|
|
delete printfLogger;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-11-03 00:13:17 +00:00
|
|
|
#ifdef ANDROID_NDK_PROFILER
|
|
|
|
moncleanup();
|
|
|
|
#endif
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
return 0;
|
|
|
|
}
|