diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f4674d1da..558517394e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1769,6 +1769,7 @@ set(NativeAssets if(HEADLESS) add_executable(PPSSPPHeadless headless/Headless.cpp + headless/StubHost.cpp headless/StubHost.h headless/Compare.cpp headless/Compare.h diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 775f4100c6..8cd5ba7603 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -444,6 +444,7 @@ ifeq ($(HEADLESS),1) LOCAL_MODULE := ppsspp_headless LOCAL_SRC_FILES := \ $(SRC)/headless/Headless.cpp \ + $(SRC)/headless/StubHost.cpp \ $(SRC)/headless/Compare.cpp include $(BUILD_EXECUTABLE) diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index 17d3f2fee8..4018293068 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -237,6 +237,13 @@ NotUsing NotUsing + + true + true + true + true + + @@ -268,6 +275,7 @@ + diff --git a/headless/Headless.vcxproj.filters b/headless/Headless.vcxproj.filters index 3f7bc674de..962db7ee84 100644 --- a/headless/Headless.vcxproj.filters +++ b/headless/Headless.vcxproj.filters @@ -22,6 +22,10 @@ Windows + + + Other Platforms + @@ -33,10 +37,16 @@ Windows + + Other Platforms + {28215e85-3e11-4a8a-8b4d-3e355b85a542} + + {d34ba935-dcca-4f21-a869-5d0b3bba7478} + - + \ No newline at end of file diff --git a/headless/SDLHeadlessHost.cpp b/headless/SDLHeadlessHost.cpp index 8bf7ba8015..42ad38c949 100644 --- a/headless/SDLHeadlessHost.cpp +++ b/headless/SDLHeadlessHost.cpp @@ -15,12 +15,13 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#ifdef SDL + #include #include #include "gfx/gl_lost_manager.h" -#include "SDLHeadlessHost.h" -#include "Compare.h" +#include "headless/SDLHeadlessHost.h" #include "Common/FileUtil.h" #include "Common/GraphicsContext.h" @@ -70,70 +71,6 @@ void SDLHeadlessHost::LoadNativeAssets() { VFSRegister("", new DirectoryAssetReader("../")); } -void SDLHeadlessHost::SendDebugOutput(const std::string &output) { - fwrite(output.data(), sizeof(char), output.length(), stdout); - OutputDebugStringUTF8(output.c_str()); -} - -void SDLHeadlessHost::SendOrCollectDebugOutput(const std::string &data) { - if (PSP_CoreParameter().printfEmuLog) - SendDebugOutput(data); - else if (PSP_CoreParameter().collectEmuLog) - *PSP_CoreParameter().collectEmuLog += data; - else - DEBUG_LOG(COMMON, "%s", data.c_str()); -} - -void SDLHeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) { - // Only if we're actually comparing. - if (comparisonScreenshot.empty()) { - return; - } - - // We ignore the current framebuffer parameters and just grab the full screen. - const static u32 FRAME_STRIDE = 512; - const static u32 FRAME_WIDTH = 480; - const static u32 FRAME_HEIGHT = 272; - - GPUDebugBuffer buffer; - gpuDebug->GetCurrentFramebuffer(buffer, GPU_DBG_FRAMEBUF_RENDER); - const std::vector pixels = TranslateDebugBufferToCompare(&buffer, 512, 272); - - std::string error; - double errors = CompareScreenshot(pixels, FRAME_STRIDE, FRAME_WIDTH, FRAME_HEIGHT, comparisonScreenshot, error); - if (errors < 0) - SendOrCollectDebugOutput(error); - - if (errors > 0) { - char temp[256]; - snprintf(temp, 256, "Screenshot error: %f%%\n", errors * 100.0f); - SendOrCollectDebugOutput(temp); - } - - if (errors > 0 && !teamCityMode) { - // Lazy, just read in the original header to output the failed screenshot. - u8 header[14 + 40] = {0}; - FILE *bmp = File::OpenCFile(comparisonScreenshot, "rb"); - if (bmp) { - fread(&header, sizeof(header), 1, bmp); - fclose(bmp); - } - - FILE *saved = File::OpenCFile("__testfailure.bmp", "wb"); - if (saved) { - fwrite(&header, sizeof(header), 1, saved); - fwrite(pixels.data(), sizeof(u32), FRAME_STRIDE * FRAME_HEIGHT, saved); - fclose(saved); - - SendOrCollectDebugOutput("Actual output written to: __testfailure.bmp\n"); - } - } -} - -void SDLHeadlessHost::SetComparisonScreenshot(const std::string &filename) { - comparisonScreenshot = filename; -} - bool SDLHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext **ctx) { // TODO //SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); @@ -200,3 +137,5 @@ void SDLHeadlessHost::SwapBuffers() { gfx_->SwapBuffers(); SDL_GL_SwapWindow(screen_); } + +#endif diff --git a/headless/SDLHeadlessHost.h b/headless/SDLHeadlessHost.h index 72bfd7630a..9f50c8931f 100644 --- a/headless/SDLHeadlessHost.h +++ b/headless/SDLHeadlessHost.h @@ -17,7 +17,9 @@ #pragma once -#include "StubHost.h" +#ifdef SDL + +#include "headless/StubHost.h" #undef HEADLESSHOST_CLASS #define HEADLESSHOST_CLASS SDLHeadlessHost @@ -28,21 +30,17 @@ typedef void *SDL_GLContext; class SDLHeadlessHost : public HeadlessHost { public: - virtual bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override; - virtual void ShutdownGraphics() override; + bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override; + void ShutdownGraphics() override; - virtual void SwapBuffers() override; - - virtual void SendDebugOutput(const std::string &output) override; - virtual void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) override; - virtual void SetComparisonScreenshot(const std::string &filename) override; + void SwapBuffers() override; protected: void LoadNativeAssets(); - void SendOrCollectDebugOutput(const std::string &output); SDL_Window *screen_; SDL_GLContext glContext_; GraphicsContext *gfx_; - std::string comparisonScreenshot; }; + +#endif diff --git a/headless/StubHost.cpp b/headless/StubHost.cpp new file mode 100644 index 0000000000..82698770da --- /dev/null +++ b/headless/StubHost.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2017- 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/. + +#include "Common/FileUtil.h" +#include "Core/CoreParameter.h" +#include "Core/System.h" +#include "GPU/Common/GPUDebugInterface.h" +#include "headless/Compare.h" +#include "headless/StubHost.h" + +void HeadlessHost::SendOrCollectDebugOutput(const std::string &data) +{ + if (PSP_CoreParameter().printfEmuLog) + SendDebugOutput(data); + else if (PSP_CoreParameter().collectEmuLog) + *PSP_CoreParameter().collectEmuLog += data; + else + DEBUG_LOG(COMMON, "%s", data.c_str()); +} + +void HeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) +{ + if (!gfx_) { + return; + } + + // Only if we're actually comparing. + if (comparisonScreenshot_.empty()) { + return; + } + + // We ignore the current framebuffer parameters and just grab the full screen. + const static u32 FRAME_STRIDE = 512; + const static u32 FRAME_WIDTH = 480; + const static u32 FRAME_HEIGHT = 272; + + GPUDebugBuffer buffer; + gpuDebug->GetCurrentFramebuffer(buffer, GPU_DBG_FRAMEBUF_RENDER); + const std::vector pixels = TranslateDebugBufferToCompare(&buffer, 512, 272); + + std::string error; + double errors = CompareScreenshot(pixels, FRAME_STRIDE, FRAME_WIDTH, FRAME_HEIGHT, comparisonScreenshot_, error); + if (errors < 0) + SendOrCollectDebugOutput(error); + + if (errors > 0) + { + char temp[256]; + snprintf(temp, sizeof(temp), "Screenshot error: %f%%\n", errors * 100.0f); + SendOrCollectDebugOutput(temp); + } + + if (errors > 0 && !teamCityMode) + { + // Lazy, just read in the original header to output the failed screenshot. + u8 header[14 + 40] = {0}; + FILE *bmp = File::OpenCFile(comparisonScreenshot_, "rb"); + if (bmp) + { + fread(&header, sizeof(header), 1, bmp); + fclose(bmp); + } + + FILE *saved = File::OpenCFile("__testfailure.bmp", "wb"); + if (saved) + { + fwrite(&header, sizeof(header), 1, saved); + fwrite(pixels.data(), sizeof(u32), FRAME_STRIDE * FRAME_HEIGHT, saved); + fclose(saved); + + SendOrCollectDebugOutput("Actual output written to: __testfailure.bmp\n"); + } + } +} diff --git a/headless/StubHost.h b/headless/StubHost.h index 0a4be899c5..d6498e2b0f 100644 --- a/headless/StubHost.h +++ b/headless/StubHost.h @@ -64,13 +64,21 @@ public: debugOutputBuffer_.clear(); } } - virtual void SetComparisonScreenshot(const std::string &filename) {} + virtual void SetComparisonScreenshot(const std::string &filename) { + comparisonScreenshot_ = filename; + } + + void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) override; // Unique for HeadlessHost virtual void SwapBuffers() {} protected: + void SendOrCollectDebugOutput(const std::string &output); + + std::string comparisonScreenshot_; std::string debugOutputBuffer_; GPUCore gpuCore_; + GraphicsContext *gfx_ = nullptr; }; diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp index 4ad37bd219..490ae92e8e 100644 --- a/headless/WindowsHeadlessHost.cpp +++ b/headless/WindowsHeadlessHost.cpp @@ -17,8 +17,7 @@ #include -#include "WindowsHeadlessHost.h" -#include "Compare.h" +#include "headless/WindowsHeadlessHost.h" #include "Common/FileUtil.h" #include "Common/CommonWindows.h" @@ -78,72 +77,6 @@ void WindowsHeadlessHost::SendDebugOutput(const std::string &output) OutputDebugStringUTF8(output.c_str()); } -void WindowsHeadlessHost::SendOrCollectDebugOutput(const std::string &data) -{ - if (PSP_CoreParameter().printfEmuLog) - SendDebugOutput(data); - else if (PSP_CoreParameter().collectEmuLog) - *PSP_CoreParameter().collectEmuLog += data; - else - DEBUG_LOG(COMMON, "%s", data.c_str()); -} - -void WindowsHeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) -{ - // Only if we're actually comparing. - if (comparisonScreenshot.empty()) { - return; - } - - // We ignore the current framebuffer parameters and just grab the full screen. - const static u32 FRAME_STRIDE = 512; - const static u32 FRAME_WIDTH = 480; - const static u32 FRAME_HEIGHT = 272; - - GPUDebugBuffer buffer; - gpuDebug->GetCurrentFramebuffer(buffer, GPU_DBG_FRAMEBUF_RENDER); - const std::vector pixels = TranslateDebugBufferToCompare(&buffer, 512, 272); - - std::string error; - double errors = CompareScreenshot(pixels, FRAME_STRIDE, FRAME_WIDTH, FRAME_HEIGHT, comparisonScreenshot, error); - if (errors < 0) - SendOrCollectDebugOutput(error); - - if (errors > 0) - { - char temp[256]; - sprintf_s(temp, "Screenshot error: %f%%\n", errors * 100.0f); - SendOrCollectDebugOutput(temp); - } - - if (errors > 0 && !teamCityMode) - { - // Lazy, just read in the original header to output the failed screenshot. - u8 header[14 + 40] = {0}; - FILE *bmp = File::OpenCFile(comparisonScreenshot, "rb"); - if (bmp) - { - fread(&header, sizeof(header), 1, bmp); - fclose(bmp); - } - - FILE *saved = File::OpenCFile("__testfailure.bmp", "wb"); - if (saved) - { - fwrite(&header, sizeof(header), 1, saved); - fwrite(pixels.data(), sizeof(u32), FRAME_STRIDE * FRAME_HEIGHT, saved); - fclose(saved); - - SendOrCollectDebugOutput("Actual output written to: __testfailure.bmp\n"); - } - } -} - -void WindowsHeadlessHost::SetComparisonScreenshot(const std::string &filename) -{ - comparisonScreenshot = filename; -} - bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext **ctx) { hWnd = CreateHiddenWindow(); diff --git a/headless/WindowsHeadlessHost.h b/headless/WindowsHeadlessHost.h index 088e7935da..8a361ef41f 100644 --- a/headless/WindowsHeadlessHost.h +++ b/headless/WindowsHeadlessHost.h @@ -17,7 +17,7 @@ #pragma once -#include "StubHost.h" +#include "headless/StubHost.h" #undef HEADLESSHOST_CLASS #define HEADLESSHOST_CLASS WindowsHeadlessHost @@ -28,22 +28,18 @@ class WindowsHeadlessHost : public HeadlessHost { public: - virtual bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override; - virtual void ShutdownGraphics() override; + bool InitGraphics(std::string *error_message, GraphicsContext **ctx) override; + void ShutdownGraphics() override; - virtual void SwapBuffers() override; + void SwapBuffers() override; - virtual void SendDebugOutput(const std::string &output) override; - virtual void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) override; - virtual void SetComparisonScreenshot(const std::string &filename) override; + void SendDebugOutput(const std::string &output) override; protected: void LoadNativeAssets(); - void SendOrCollectDebugOutput(const std::string &output); HWND hWnd; HDC hDC; HGLRC hRC; GraphicsContext *gfx_; - std::string comparisonScreenshot; -}; \ No newline at end of file +};