Draw offscreen in headless (Windows only.)

This commit is contained in:
Unknown W. Brackets 2012-12-29 19:36:03 -08:00
parent 8f027a6282
commit 03d9157d26
8 changed files with 279 additions and 41 deletions

View File

@ -886,7 +886,7 @@ if(WIN32)
endif()
if(HEADLESS)
add_executable(PPSSPPHeadless headless/Headless.cpp)
add_executable(PPSSPPHeadless headless/Headless.cpp headless/StubHost.h)
target_link_libraries(PPSSPPHeadless ${CoreLibName}
${COCOA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
setup_target_project(PPSSPPHeadless headless)

View File

@ -182,20 +182,18 @@ bool __KernelIsRunning() {
void sceKernelExitGame()
{
INFO_LOG(HLE,"sceKernelExitGame");
if (PSP_CoreParameter().headLess)
exit(0);
else
if (!PSP_CoreParameter().headLess)
PanicAlert("Game exited");
__KernelSwitchOffThread("game exited");
Core_Stop();
}
void sceKernelExitGameWithStatus()
{
INFO_LOG(HLE,"sceKernelExitGameWithStatus");
if (PSP_CoreParameter().headLess)
exit(0);
else
if (!PSP_CoreParameter().headLess)
PanicAlert("Game exited (with status)");
__KernelSwitchOffThread("game exited");
Core_Stop();
}

View File

@ -12,35 +12,13 @@
#include "../Core/Host.h"
#include "Log.h"
#include "LogManager.h"
#include "file/vfs.h"
#include "file/zip_read.h"
// TODO: Get rid of this junk
class HeadlessHost : public Host
{
public:
// virtual void StartThread()
virtual void UpdateUI() {}
virtual void UpdateMemView() {}
virtual void UpdateDisassembly() {}
virtual void SetDebugMode(bool mode) { }
virtual void InitGL() {}
virtual void BeginFrame() {}
virtual void EndFrame() {}
virtual void ShutdownGL() {}
virtual void InitSound(PMixer *mixer) {}
virtual void UpdateSound() {}
virtual void ShutdownSound() {}
// this is sent from EMU thread! Make sure that Host handles it properly!
virtual void BootDone() {}
virtual void PrepareShutdown() {}
virtual bool IsDebuggingEnabled() {return false;}
virtual bool AttemptLoadSymbolMap() {return false;}
};
#include "StubHost.h"
#ifdef _WIN32
#include "WindowsHeadlessHost.h"
#endif
class PrintfLogger : public LogListener
{
@ -140,7 +118,12 @@ int main(int argc, const char* argv[])
return 1;
}
host = new HeadlessHost();
VFSRegister("", new DirectoryAssetReader("assets/"));
VFSRegister("", new DirectoryAssetReader(""));
HeadlessHost *headlessHost = new HEADLESSHOST_CLASS();
host = headlessHost;
host->InitGL();
LogManager::Init();
LogManager *logman = LogManager::GetInstance();
@ -160,7 +143,7 @@ int main(int argc, const char* argv[])
coreParameter.mountIso = mountIso ? mountIso : "";
coreParameter.startPaused = false;
coreParameter.cpuCore = useJit ? CPU_JIT : (fastInterpreter ? CPU_FASTINTERPRETER : CPU_INTERPRETER);
coreParameter.gpuCore = GPU_NULL;
coreParameter.gpuCore = headlessHost->isGLWorking() ? GPU_GLES : GPU_NULL;
coreParameter.enableSound = false;
coreParameter.headLess = true;
coreParameter.printfEmuLog = true;
@ -191,10 +174,13 @@ int main(int argc, const char* argv[])
coreState = CORE_RUNNING;
}
// NOTE: we won't get here until I've gotten rid of the exit(0) in sceExitProcess or whatever it's called
host->ShutdownGL();
PSP_Shutdown();
delete host;
host = NULL;
headlessHost = NULL;
if (autoCompare)
{
std::string expect_filename = std::string(bootFilename).substr(strlen(bootFilename - 4)) + ".expected";

View File

@ -81,7 +81,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../Common;..;../Core;../native/ext/glew;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../Common;..;../Core;../native/ext/glew;../native</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
</ClCompile>
<Link>
@ -112,7 +112,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../Common;..;../Core;../native/ext/glew;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../Common;..;../Core;../native/ext/glew;../native</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<FloatingPointModel>Fast</FloatingPointModel>
@ -151,6 +151,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="WindowsHeadlessHost.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="headless.txt" />
@ -175,6 +176,10 @@
<Project>{f761046e-6c38-4428-a5f1-38391a37bb34}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="StubHost.h" />
<ClInclude Include="WindowsHeadlessHost.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -3,8 +3,13 @@
<ItemGroup>
<ClCompile Include="Headless.cpp" />
<ClCompile Include="..\native\ext\glew\glew.c" />
<ClCompile Include="WindowsHeadlessHost.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="headless.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="StubHost.h" />
<ClInclude Include="WindowsHeadlessHost.h" />
</ItemGroup>
</Project>

53
headless/StubHost.h Normal file
View File

@ -0,0 +1,53 @@
// 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/.
#pragma once
#include "../Core/Host.h"
#define HEADLESSHOST_CLASS HeadlessHost
// TODO: Get rid of this junk
class HeadlessHost : public Host
{
public:
// virtual void StartThread()
virtual void UpdateUI() {}
virtual void UpdateMemView() {}
virtual void UpdateDisassembly() {}
virtual void SetDebugMode(bool mode) { }
virtual void InitGL() {}
virtual void BeginFrame() {}
virtual void EndFrame() {}
virtual void ShutdownGL() {}
virtual void InitSound(PMixer *mixer) {}
virtual void UpdateSound() {}
virtual void ShutdownSound() {}
// this is sent from EMU thread! Make sure that Host handles it properly
virtual void BootDone() {}
virtual void PrepareShutdown() {}
virtual bool IsDebuggingEnabled() {return false;}
virtual bool AttemptLoadSymbolMap() {return false;}
virtual bool isGLWorking() { return false; }
};

View File

@ -0,0 +1,147 @@
// 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/.
#include "WindowsHeadlessHost.h"
#include <stdio.h>
#include <windows.h>
#include "../native/gfx_es2/gl_state.h"
#include "../native/gfx/gl_common.h"
const bool WINDOW_VISIBLE = false;
const int WINDOW_WIDTH = 480;
const int WINDOW_HEIGHT = 272;
typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)(int value);
PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = NULL;
HWND CreateHiddenWindow()
{
static WNDCLASSEX wndClass = {
sizeof(WNDCLASSEX),
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
DefWindowProc,
0,
0,
NULL,
NULL,
LoadCursor(NULL, IDC_ARROW),
(HBRUSH) GetStockObject(BLACK_BRUSH),
NULL,
"PPSSPPHeadless",
NULL,
};
RegisterClassEx(&wndClass);
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP;
return CreateWindowEx(0, "PPSSPPHeadless", "PPSSPPHeadless", style, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, NULL, NULL);
}
void SetVSync(int value)
{
const char *extensions = (const char *) glGetString(GL_EXTENSIONS);
if (!strstr(extensions, "WGL_EXT_swap_control"))
return;
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC) wglGetProcAddress("wglSwapIntervalEXT");
if (wglSwapIntervalEXT != NULL)
wglSwapIntervalEXT(value);
}
void WindowsHeadlessHost::InitGL()
{
glOkay = false;
hWnd = CreateHiddenWindow();
if (WINDOW_VISIBLE)
{
ShowWindow(hWnd, TRUE);
SetFocus(hWnd);
}
int pixelFormat;
static PIXELFORMATDESCRIPTOR pfd = {0};
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
#define ENFORCE(x, msg) { if (!(x)) { fprintf(stderr, msg); return; } }
ENFORCE(hDC = GetDC(hWnd), "Unable to create DC.");
ENFORCE(pixelFormat = ChoosePixelFormat(hDC, &pfd), "Unable to match pixel format.");
ENFORCE(SetPixelFormat(hDC, pixelFormat, &pfd), "Unable to set pixel format.");
ENFORCE(hRC = wglCreateContext(hDC), "Unable to create GL context.");
ENFORCE(wglMakeCurrent(hDC, hRC), "Unable to activate GL context.");
SetVSync(0);
glewInit();
glstate.Initialize();
if (ResizeGL())
glOkay = true;
}
void WindowsHeadlessHost::ShutdownGL()
{
if (hRC)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hRC);
hRC = NULL;
}
if (hDC)
ReleaseDC(hWnd, hDC);
hDC = NULL;
DestroyWindow(hWnd);
hWnd = NULL;
}
bool WindowsHeadlessHost::ResizeGL()
{
if (!hWnd)
return false;
RECT rc;
GetWindowRect(hWnd, &rc);
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, WINDOW_WIDTH, WINDOW_HEIGHT, 0.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
return true;
}
void WindowsHeadlessHost::BeginFrame()
{
}
void WindowsHeadlessHost::EndFrame()
{
SwapBuffers(hDC);
}

View File

@ -0,0 +1,44 @@
// 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/.
#pragma once
#include "StubHost.h"
#undef HEADLESSHOST_CLASS
#define HEADLESSHOST_CLASS WindowsHeadlessHost
#include <windows.h>
// TODO: Get rid of this junk
class WindowsHeadlessHost : public HeadlessHost
{
public:
virtual void InitGL();
virtual void BeginFrame();
virtual void EndFrame();
virtual void ShutdownGL();
virtual bool isGLWorking() { return glOkay; }
private:
bool ResizeGL();
bool glOkay;
HWND hWnd;
HDC hDC;
HGLRC hRC;
};