1
// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003.
3
#include "base/timeutil.h"
4
#include "base/NativeApp.h"
5
#include "base/mutex.h"
7
#include "input/input_state.h"
8
#include "util/text/utf8.h"
10
#include "Common/Log.h"
11
#include "Common/StringUtils.h"
12
#include "../Globals.h"
13
#include "Windows/EmuThread.h"
14
#include "Windows/W32Util/Misc.h"
15
#include "Windows/MainWindow.h"
16
#include "Windows/resource.h"
17
#include "Core/Reporting.h"
18
#include "Core/MemMap.h"
19
#include "Core/Core.h"
20
#include "Core/Host.h"
21
#include "Core/System.h"
22
#include "Core/Config.h"
23
#include "thread/threadutil.h"
28
#pragma intrinsic(_InterlockedExchange)
30
static recursive_mutex emuThreadLock;
31
static HANDLE emuThread;
32
static volatile long emuThreadReady;
34
InputState input_state;
36
extern std::vector<std::wstring> GetWideCmdLine();
38
enum EmuThreadStatus : long
47
HANDLE EmuThread_GetThreadHandle()
49
lock_guard guard(emuThreadLock);
53
unsigned int WINAPI TheThread(void *);
55
void EmuThread_Start()
57
lock_guard guard(emuThreadLock);
58
emuThread = (HANDLE)_beginthreadex(0, 0, &TheThread, 0, 0, 0);
65
lock_guard guard(emuThreadLock);
66
if (emuThread == NULL || emuThreadReady == THREAD_END)
70
UpdateUIState(UISTATE_EXIT);
72
Core_WaitInactive(800);
73
if (WAIT_TIMEOUT == WaitForSingleObject(emuThread, 800))
75
_dbg_assert_msg_(COMMON, false, "Wait for EmuThread timed out.");
78
lock_guard guard(emuThreadLock);
79
CloseHandle(emuThread);
85
bool EmuThread_Ready()
87
return emuThreadReady == THREAD_CORE_LOOP;
90
unsigned int WINAPI TheThread(void *)
92
_InterlockedExchange(&emuThreadReady, THREAD_INIT);
94
setCurrentThreadName("Emu"); // And graphics...
96
// Native overwrites host. Can't allow that.
100
// Convert the command-line arguments to Unicode, then to proper UTF-8
101
// (the benefit being that we don't have to pollute the UI project with win32 ifdefs and lots of Convert<whatever>To<whatever>).
102
// This avoids issues with PPSSPP inadvertently destroying paths with Unicode glyphs
103
// (using the ANSI args resulted in Japanese/Chinese glyphs being turned into question marks, at least for me..).
105
std::vector<std::wstring> wideArgs = GetWideCmdLine();
106
std::vector<std::string> argsUTF8;
107
for (auto& string : wideArgs) {
108
argsUTF8.push_back(ConvertWStringToUTF8(string));
111
std::vector<const char *> args;
113
for (auto& string : argsUTF8) {
114
args.push_back(string.c_str());
117
NativeInit(static_cast<int>(args.size()), &args[0], "1234", "1234", nullptr);
119
Host *nativeHost = host;
124
GraphicsContext *graphicsContext;
126
std::string error_string;
127
if (!host->InitGraphics(&error_string, &graphicsContext)) {
128
I18NCategory *err = GetI18NCategory("Error");
129
Reporting::ReportMessage("Graphics init error: %s", error_string.c_str());
131
const char *defaultErrorVulkan = "Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to OpenGL?\n\nError message:";
132
const char *defaultErrorOpenGL = "Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to DirectX 9?\n\nError message:";
133
const char *defaultErrorDirect3D9 = "Failed initializing graphics. Try upgrading your graphics drivers and directx 9 runtime.\n\nWould you like to try switching to OpenGL?\n\nError message:";
134
const char *genericError;
135
int nextBackend = GPU_BACKEND_DIRECT3D9;
136
switch (g_Config.iGPUBackend) {
137
case GPU_BACKEND_DIRECT3D9:
138
nextBackend = GPU_BACKEND_OPENGL;
139
genericError = err->T("GenericDirect3D9Error", defaultErrorDirect3D9);
141
case GPU_BACKEND_VULKAN:
142
nextBackend = GPU_BACKEND_OPENGL;
143
genericError = err->T("GenericVulkanError", defaultErrorVulkan);
145
case GPU_BACKEND_OPENGL:
147
nextBackend = GPU_BACKEND_DIRECT3D9;
148
genericError = err->T("GenericOpenGLError", defaultErrorOpenGL);
151
std::string full_error = StringFromFormat("%s\n\n%s", genericError, error_string.c_str());
152
std::wstring title = ConvertUTF8ToWString(err->T("GenericGraphicsError", "Graphics Error"));
153
bool yes = IDYES == MessageBox(0, ConvertUTF8ToWString(full_error).c_str(), title.c_str(), MB_ICONERROR | MB_YESNO);
154
ERROR_LOG(BOOT, full_error.c_str());
157
// Change the config to the alternative and restart.
158
g_Config.iGPUBackend = nextBackend;
161
W32Util::ExitAndRestart();
164
// No safe way out without graphics.
168
PSP_CoreParameter().graphicsContext = graphicsContext;
170
NativeInitGraphics(graphicsContext);
173
INFO_LOG(BOOT, "Done.");
176
if (coreState == CORE_POWERDOWN) {
177
INFO_LOG(BOOT, "Exit before core loop.");
181
_InterlockedExchange(&emuThreadReady, THREAD_CORE_LOOP);
183
if (g_Config.bBrowse)
184
PostMessage(MainWindow::GetHWND(), WM_COMMAND, ID_FILE_LOAD, 0);
186
Core_EnableStepping(FALSE);
188
while (GetUIState() != UISTATE_EXIT)
190
// We're here again, so the game quit. Restart Core_Run() which controls the UI.
191
// This way they can load a new game.
192
if (!Core_IsActive())
193
UpdateUIState(UISTATE_MENU);
195
Core_Run(graphicsContext, &input_state);
199
_InterlockedExchange(&emuThreadReady, THREAD_SHUTDOWN);
201
NativeShutdownGraphics();
203
host->ShutdownSound();
207
host->ShutdownGraphics();
209
_InterlockedExchange(&emuThreadReady, THREAD_END);