Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/headless/WindowsHeadlessHost.cpp
3185 views
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "ppsspp_config.h"
19
#include <cstdio>
20
21
#include "headless/WindowsHeadlessHost.h"
22
23
#include "Common/GPU/OpenGL/GLCommon.h"
24
#include "Common/GPU/OpenGL/GLFeatures.h"
25
#include "Common/File/VFS/VFS.h"
26
#include "Common/File/VFS/DirectoryReader.h"
27
28
#include "Common/CommonWindows.h"
29
#include "Common/Log.h"
30
#include "Common/File/FileUtil.h"
31
#include "Common/TimeUtil.h"
32
33
#include "Core/CoreParameter.h"
34
#include "Core/System.h"
35
#include "GPU/Common/GPUDebugInterface.h"
36
#include "GPU/GPUState.h"
37
#if PPSSPP_API(ANY_GL)
38
#include "Windows/GPU/WindowsGLContext.h"
39
#endif
40
#include "Windows/GPU/D3D11Context.h"
41
#include "Windows/GPU/WindowsVulkanContext.h"
42
43
const bool WINDOW_VISIBLE = false;
44
const int WINDOW_WIDTH = 480;
45
const int WINDOW_HEIGHT = 272;
46
47
HWND CreateHiddenWindow() {
48
static WNDCLASSEX wndClass = {
49
sizeof(WNDCLASSEX),
50
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
51
DefWindowProc,
52
0,
53
0,
54
NULL,
55
NULL,
56
LoadCursor(NULL, IDC_ARROW),
57
(HBRUSH) GetStockObject(BLACK_BRUSH),
58
NULL,
59
L"PPSSPPHeadless",
60
NULL,
61
};
62
RegisterClassEx(&wndClass);
63
64
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP;
65
return CreateWindowEx(0, L"PPSSPPHeadless", L"PPSSPPHeadless", style, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, NULL, NULL);
66
}
67
68
void WindowsHeadlessHost::SendDebugOutput(const std::string &output) {
69
if (writeDebugOutput_)
70
fwrite(output.data(), sizeof(char), output.length(), stdout);
71
OutputDebugStringUTF8(output.c_str());
72
}
73
74
bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext **ctx, GPUCore core) {
75
hWnd = CreateHiddenWindow();
76
gpuCore_ = core;
77
78
if (WINDOW_VISIBLE) {
79
ShowWindow(hWnd, TRUE);
80
SetFocus(hWnd);
81
}
82
83
WindowsGraphicsContext *graphicsContext = nullptr;
84
bool needRenderThread = false;
85
switch (gpuCore_) {
86
case GPUCORE_GLES:
87
#if PPSSPP_API(ANY_GL)
88
case GPUCORE_SOFTWARE:
89
graphicsContext = new WindowsGLContext();
90
needRenderThread = true;
91
break;
92
#endif
93
case GPUCORE_DIRECTX11:
94
graphicsContext = new D3D11Context();
95
break;
96
97
case GPUCORE_VULKAN:
98
graphicsContext = new WindowsVulkanContext();
99
break;
100
default:
101
_assert_(false);
102
break;
103
}
104
105
if (graphicsContext->Init(NULL, hWnd, error_message)) {
106
*ctx = graphicsContext;
107
gfx_ = graphicsContext;
108
} else {
109
delete graphicsContext;
110
*ctx = nullptr;
111
gfx_ = nullptr;
112
return false;
113
}
114
115
if (needRenderThread) {
116
std::thread th([&]{
117
while (threadState_ == RenderThreadState::IDLE)
118
sleep_ms(1, "render-thread-idle-poll");
119
threadState_ = RenderThreadState::STARTING;
120
121
std::string err;
122
if (!gfx_->InitFromRenderThread(&err)) {
123
threadState_ = RenderThreadState::START_FAILED;
124
return;
125
}
126
gfx_->ThreadStart();
127
threadState_ = RenderThreadState::STARTED;
128
129
while (threadState_ != RenderThreadState::STOP_REQUESTED) {
130
if (!gfx_->ThreadFrame()) {
131
break;
132
}
133
}
134
135
threadState_ = RenderThreadState::STOPPING;
136
gfx_->ThreadEnd();
137
gfx_->ShutdownFromRenderThread();
138
threadState_ = RenderThreadState::STOPPED;
139
});
140
th.detach();
141
}
142
143
if (needRenderThread) {
144
threadState_ = RenderThreadState::START_REQUESTED;
145
while (threadState_ == RenderThreadState::START_REQUESTED || threadState_ == RenderThreadState::STARTING)
146
sleep_ms(1, "render-thread-start-poll");
147
148
return threadState_ == RenderThreadState::STARTED;
149
}
150
151
return true;
152
}
153
154
void WindowsHeadlessHost::ShutdownGraphics() {
155
gfx_->StopThread();
156
while (threadState_ != RenderThreadState::STOPPED && threadState_ != RenderThreadState::IDLE)
157
sleep_ms(1, "render-thread-stop-poll");
158
159
gfx_->Shutdown();
160
delete gfx_;
161
gfx_ = nullptr;
162
DestroyWindow(hWnd);
163
hWnd = NULL;
164
}
165
166
void WindowsHeadlessHost::SwapBuffers() {}
167
168