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();