diff --git a/CMakeLists.txt b/CMakeLists.txt
index de75f76c41..084d798d19 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -962,6 +962,7 @@ endif()
set(NativeAppSource
android/jni/NativeApp.cpp
android/jni/EmuScreen.cpp
+ android/jni/TestRunner.cpp
android/jni/MenuScreens.cpp
android/jni/GamepadEmu.cpp
android/jni/UIShader.cpp
diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h
index 3357fc027d..1cd6e08f3f 100644
--- a/Core/CoreParameter.h
+++ b/Core/CoreParameter.h
@@ -33,6 +33,7 @@ enum GPUCore {
struct CoreParameter
{
+ CoreParameter() : collectEmuLog(0) {}
// 0 = Interpreter
// 1 = Jit
// 2 = JitIL
@@ -47,6 +48,7 @@ struct CoreParameter
bool disableG3Dlog;
bool enableDebugging; // enables breakpoints and other time-consuming debugger features
bool printfEmuLog; // writes "emulator:" logging to stdout
+ std::string *collectEmuLog;
bool headLess; // Try to avoid messageboxes etc
bool useMediaEngine;
diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp
index 9ea49f0056..e8eb65d0ea 100644
--- a/Core/HLE/sceIo.cpp
+++ b/Core/HLE/sceIo.cpp
@@ -864,9 +864,9 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr,
{
host->SendDebugOutput(data.c_str());
}
- else
+ if (PSP_CoreParameter().collectEmuLog)
{
- DEBUG_LOG(HLE, "%s", data.c_str());
+ *PSP_CoreParameter().collectEmuLog += data;
}
return 0;
}
diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj
index 04c498d664..3a63f5c8af 100644
--- a/Windows/PPSSPP.vcxproj
+++ b/Windows/PPSSPP.vcxproj
@@ -249,6 +249,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
@@ -307,6 +313,7 @@
+
diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters
index 7456a22f8a..82eccdf3f8 100644
--- a/Windows/PPSSPP.vcxproj.filters
+++ b/Windows/PPSSPP.vcxproj.filters
@@ -107,6 +107,9 @@
Android
+
+ Android
+
@@ -188,6 +191,9 @@
Android
+
+ Android
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 2ee383b6d7..ce06c8af63 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -50,6 +50,7 @@ LOCAL_SRC_FILES := \
UIShader.cpp \
GamepadEmu.cpp \
ArmEmitterTest.cpp \
+ TestRunner.cpp \
ui_atlas.cpp \
$(SRC)/native/android/app-android.cpp \
$(SRC)/ext/disarm.cpp \
diff --git a/android/jni/EmuScreen.cpp b/android/jni/EmuScreen.cpp
index 8a0d13f84e..9e13b20590 100644
--- a/android/jni/EmuScreen.cpp
+++ b/android/jni/EmuScreen.cpp
@@ -15,6 +15,8 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+#include "base/logging.h"
+
#include "gfx_es2/glsl_program.h"
#include "gfx_es2/gl_state.h"
#include "gfx_es2/fbo.h"
@@ -167,8 +169,14 @@ void EmuScreen::render()
if (coreState == CORE_NEXTFRAME) {
// set back to running for the next frame
coreState = CORE_RUNNING;
+ } else if (coreState == CORE_POWERDOWN) {
+ ILOG("SELF-POWERDOWN!");
+ screenManager()->switchScreen(new MenuScreen());
}
+ if (invalid_)
+ return;
+
if (g_Config.bBufferedRendering)
fbo_unbind();
@@ -202,5 +210,6 @@ void EmuScreen::render()
void EmuScreen::deviceLost()
{
+ ILOG("EmuScreen::deviceLost()");
gpu->DeviceLost();
}
diff --git a/android/jni/MenuScreens.cpp b/android/jni/MenuScreens.cpp
index a69a5b88ec..cfbd6d8f20 100644
--- a/android/jni/MenuScreens.cpp
+++ b/android/jni/MenuScreens.cpp
@@ -42,6 +42,7 @@
#include "MenuScreens.h"
#include "EmuScreen.h"
+#include "TestRunner.h"
#ifdef USING_QT_UI
#include
@@ -344,6 +345,44 @@ void SettingsScreen::render() {
if (UIButton(GEN_ID, Pos(dp_xres - 10, dp_yres-10), LARGE_BUTTON_WIDTH, "Back", ALIGN_RIGHT | ALIGN_BOTTOM)) {
screenManager()->finishDialog(this, DR_OK);
}
+ if (UIButton(GEN_ID, Pos(10, dp_yres-10), LARGE_BUTTON_WIDTH, "Developer Menu", ALIGN_BOTTOMLEFT)) {
+ screenManager()->push(new DeveloperScreen());
+ }
+
+ UIEnd();
+
+ glsl_bind(UIShader_Get());
+ ui_draw2d.Flush(UIShader_Get());
+}
+
+void DeveloperScreen::update(InputState &input) {
+ if (input.pad_buttons_down & PAD_BUTTON_BACK) {
+ g_Config.Save();
+ screenManager()->finishDialog(this, DR_OK);
+ }
+}
+
+void DeveloperScreen::render() {
+ UIShader_Prepare();
+ UIBegin();
+ DrawBackground(1.0f);
+
+ ui_draw2d.DrawText(UBUNTU48, "Developer Tools", dp_xres / 2, 20, 0xFFFFFFFF, ALIGN_HCENTER);
+
+ if (UIButton(GEN_ID, Pos(dp_xres - 10, dp_yres-10), LARGE_BUTTON_WIDTH, "Back", ALIGN_RIGHT | ALIGN_BOTTOM)) {
+ screenManager()->finishDialog(this, DR_OK);
+ }
+
+ if (UIButton(GEN_ID, Pos(dp_xres / 2, 100), LARGE_BUTTON_WIDTH, "Run CPU tests", ALIGN_CENTER | ALIGN_TOP)) {
+ // TODO: Run tests
+ RunTests();
+ // screenManager()->push(new EmuScreen())
+ }
+
+
+ if (UIButton(GEN_ID, Pos(10, dp_yres-10), LARGE_BUTTON_WIDTH, "Dump frame to log", ALIGN_BOTTOMLEFT)) {
+ gpu->DumpNextFrame();
+ }
UIEnd();
diff --git a/android/jni/MenuScreens.h b/android/jni/MenuScreens.h
index d5858f4892..9652a79bf5 100644
--- a/android/jni/MenuScreens.h
+++ b/android/jni/MenuScreens.h
@@ -67,6 +67,14 @@ public:
};
+class DeveloperScreen : public Screen
+{
+public:
+ void update(InputState &input);
+ void render();
+};
+
+
struct FileSelectScreenOptions {
const char* filter; // Enforced extension filter. Case insensitive, extensions separated by ":".
bool allowChooseDirectory;
diff --git a/android/jni/TestRunner.cpp b/android/jni/TestRunner.cpp
new file mode 100644
index 0000000000..57629f64c7
--- /dev/null
+++ b/android/jni/TestRunner.cpp
@@ -0,0 +1,129 @@
+// Copyright (c) 2012- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+
+// TO USE:
+// Simply copy pspautotests to the root of the USB memory / SD card of your android device.
+// Then go to Settings / Developer Menu / Run CPU tests.
+// It currently just runs one test but that can be easily changed.
+
+#include
+#include
+#include
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+#include "Core/Core.h"
+#include "Core/System.h"
+#include "Core/Config.h"
+#include "Core/CoreTiming.h"
+#include "Core/MIPS/MIPS.h"
+#include "TestRunner.h"
+
+
+const char *testsToRun[] = {
+ "cpu/cpu_alu/cpu_alu",
+ "cpu/fpu/fpu",
+ "cpu/icache/icache",
+ "cpu/lsu/lsu",
+ "cpu/vfpu/base/vfpu",
+ "cpu/vfpu/colors/vfpu_colors",
+ "cpu/vfpu/convert/vfpu_convert",
+ "cpu/vfpu/prefixes/vfpu_prefixes",
+};
+
+void RunTests()
+{
+ std::string output;
+
+ CoreParameter coreParam;
+ coreParam.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER;
+ coreParam.gpuCore = GPU_GLES;
+ coreParam.enableSound = g_Config.bEnableSound;
+ coreParam.mountIso = "";
+ coreParam.startPaused = false;
+ coreParam.enableDebugging = false;
+ coreParam.printfEmuLog = false;
+ coreParam.headLess = false;
+ coreParam.renderWidth = 480;
+ coreParam.renderHeight = 272;
+ coreParam.outputWidth = 480;
+ coreParam.outputHeight = 272;
+ coreParam.pixelWidth = 480;
+ coreParam.pixelHeight = 272;
+ coreParam.useMediaEngine = false;
+ coreParam.collectEmuLog = &output;
+
+ for (int i = 0; i < ARRAY_SIZE(testsToRun); i++) {
+ const char *testName = testsToRun[i];
+ coreParam.fileToStart = g_Config.memCardDirectory + "/pspautotests/tests/" + testName + ".prx";
+ std::string expectedFile = g_Config.memCardDirectory + "/pspautotests/tests/" + testName + ".expected";
+
+ ILOG("Preparing to execute %s", testName)
+ std::string error_string;
+ output = "";
+ if (!PSP_Init(coreParam, &error_string)) {
+ ELOG("Failed to init unittest %s : %s", testsToRun[i], error_string.c_str());
+ return;
+ }
+
+ // Run the emu until the test exits
+ while (true) {
+ int blockTicks = usToCycles(1000000 / 10);
+ while (coreState == CORE_RUNNING) {
+ u64 nowTicks = CoreTiming::GetTicks();
+ mipsr4k.RunLoopUntil(nowTicks + blockTicks);
+ }
+ // Hopefully coreState is now CORE_NEXTFRAME
+ if (coreState == CORE_NEXTFRAME) {
+ // set back to running for the next frame
+ coreState = CORE_RUNNING;
+ } else if (coreState == CORE_POWERDOWN) {
+ ILOG("Finished running test %s", testName);
+ break;
+ }
+ }
+
+ std::ifstream expected(expectedFile.c_str(), std::ios_base::in);
+ if (!expected) {
+ ELOG("Error opening expectedFile %s", expectedFile.c_str());
+ return;
+ }
+
+ std::istringstream logoutput(output);
+
+ while (true) {
+ std::string e, o;
+ std::getline(expected, e);
+ std::getline(logoutput, o);
+ e = e.substr(0, e.size() - 1); // For some reason we get some extra character
+ if (e != o) {
+ ELOG("DIFF! %i vs %i, %s vs %s", (int)e.size(), (int)o.size(), e.c_str(), o.c_str());
+ }
+ if (expected.eof()) {
+ break;
+ }
+ if (logoutput.eof()) {
+ break;
+ }
+ }
+
+ ILOG("Test executed.");
+ return;
+ }
+}
\ No newline at end of file
diff --git a/android/jni/TestRunner.h b/android/jni/TestRunner.h
new file mode 100644
index 0000000000..b7b0c08a11
--- /dev/null
+++ b/android/jni/TestRunner.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+void RunTests();