CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/headless/WindowsHeadlessHost.cpp
Views: 1401
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/D3D9Context.h"
41
#include "Windows/GPU/D3D11Context.h"
42
#include "Windows/GPU/WindowsVulkanContext.h"
43
44
const bool WINDOW_VISIBLE = false;
45
const int WINDOW_WIDTH = 480;
46
const int WINDOW_HEIGHT = 272;
47
48
HWND CreateHiddenWindow() {
49
static WNDCLASSEX wndClass = {
50
sizeof(WNDCLASSEX),
51
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
52
DefWindowProc,
53
0,
54
0,
55
NULL,
56
NULL,
57
LoadCursor(NULL, IDC_ARROW),
58
(HBRUSH) GetStockObject(BLACK_BRUSH),
59
NULL,
60
L"PPSSPPHeadless",
61
NULL,
62
};
63
RegisterClassEx(&wndClass);
64
65
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP;
66
return CreateWindowEx(0, L"PPSSPPHeadless", L"PPSSPPHeadless", style, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, NULL, NULL);
67
}
68
69
void WindowsHeadlessHost::SendDebugOutput(const std::string &output) {
70
if (writeDebugOutput_)
71
fwrite(output.data(), sizeof(char), output.length(), stdout);
72
OutputDebugStringUTF8(output.c_str());
73
}
74
75
bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext **ctx, GPUCore core) {
76
hWnd = CreateHiddenWindow();
77
gpuCore_ = core;
78
79
if (WINDOW_VISIBLE) {
80
ShowWindow(hWnd, TRUE);
81
SetFocus(hWnd);
82
}
83
84
WindowsGraphicsContext *graphicsContext = nullptr;
85
bool needRenderThread = false;
86
switch (gpuCore_) {
87
case GPUCORE_GLES:
88
#if PPSSPP_API(ANY_GL)
89
case GPUCORE_SOFTWARE:
90
graphicsContext = new WindowsGLContext();
91
needRenderThread = true;
92
break;
93
#endif
94
case GPUCORE_DIRECTX9:
95
graphicsContext = new D3D9Context();
96
break;
97
98
case GPUCORE_DIRECTX11:
99
graphicsContext = new D3D11Context();
100
break;
101
102
case GPUCORE_VULKAN:
103
graphicsContext = new WindowsVulkanContext();
104
break;
105
}
106
107
if (graphicsContext->Init(NULL, hWnd, error_message)) {
108
*ctx = graphicsContext;
109
gfx_ = graphicsContext;
110
} else {
111
delete graphicsContext;
112
*ctx = nullptr;
113
gfx_ = nullptr;
114
return false;
115
}
116
117
if (needRenderThread) {
118
std::thread th([&]{
119
while (threadState_ == RenderThreadState::IDLE)
120
sleep_ms(1);
121
threadState_ = RenderThreadState::STARTING;
122
123
std::string err;
124
if (!gfx_->InitFromRenderThread(&err)) {
125
threadState_ = RenderThreadState::START_FAILED;
126
return;
127
}
128
gfx_->ThreadStart();
129
threadState_ = RenderThreadState::STARTED;
130
131
while (threadState_ != RenderThreadState::STOP_REQUESTED) {
132
if (!gfx_->ThreadFrame()) {
133
break;
134
}
135
}
136
137
threadState_ = RenderThreadState::STOPPING;
138
gfx_->ThreadEnd();
139
gfx_->ShutdownFromRenderThread();
140
threadState_ = RenderThreadState::STOPPED;
141
});
142
th.detach();
143
}
144
145
if (needRenderThread) {
146
threadState_ = RenderThreadState::START_REQUESTED;
147
while (threadState_ == RenderThreadState::START_REQUESTED || threadState_ == RenderThreadState::STARTING)
148
sleep_ms(1);
149
150
return threadState_ == RenderThreadState::STARTED;
151
}
152
153
return true;
154
}
155
156
void WindowsHeadlessHost::ShutdownGraphics() {
157
gfx_->StopThread();
158
while (threadState_ != RenderThreadState::STOPPED && threadState_ != RenderThreadState::IDLE)
159
sleep_ms(1);
160
161
gfx_->Shutdown();
162
delete gfx_;
163
gfx_ = nullptr;
164
DestroyWindow(hWnd);
165
hWnd = NULL;
166
}
167
168
void WindowsHeadlessHost::SwapBuffers() {
169
if (gpuCore_ == GPUCORE_DIRECTX9) {
170
MSG msg;
171
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
172
TranslateMessage(&msg);
173
DispatchMessage(&msg);
174
}
175
}
176
177