mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Cleanup the Windows thread stuff to work like the other platforms. Not quite perfect yet.
This commit is contained in:
parent
7f30037e45
commit
ae19c48138
8 changed files with 130 additions and 123 deletions
|
@ -189,10 +189,7 @@ void UpdateRunLoop() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NativeUpdate();
|
NativeUpdate();
|
||||||
|
NativeRender(graphicsContext);
|
||||||
if (GetUIState() != UISTATE_EXIT) {
|
|
||||||
NativeRender(graphicsContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeepScreenAwake() {
|
void KeepScreenAwake() {
|
||||||
|
@ -268,6 +265,7 @@ reswitch:
|
||||||
if (GetUIState() != UISTATE_INGAME) {
|
if (GetUIState() != UISTATE_INGAME) {
|
||||||
CoreStateProcessed();
|
CoreStateProcessed();
|
||||||
if (GetUIState() == UISTATE_EXIT) {
|
if (GetUIState() == UISTATE_EXIT) {
|
||||||
|
UpdateRunLoop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Core_RunLoop(ctx);
|
Core_RunLoop(ctx);
|
||||||
|
|
|
@ -641,13 +641,13 @@ int main(int argc, char *argv[]) {
|
||||||
useEmuThread = false;
|
useEmuThread = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str());
|
||||||
|
|
||||||
// Since we render from the main thread, there's nothing done here, but we call it to avoid confusion.
|
// Since we render from the main thread, there's nothing done here, but we call it to avoid confusion.
|
||||||
if (!graphicsContext->InitFromRenderThread(&error_message)) {
|
if (!graphicsContext->InitFromRenderThread(&error_message)) {
|
||||||
printf("Init from thread error: '%s'\n", error_message.c_str());
|
printf("Init from thread error: '%s'\n", error_message.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str());
|
|
||||||
|
|
||||||
#ifdef MOBILE_DEVICE
|
#ifdef MOBILE_DEVICE
|
||||||
SDL_ShowCursor(SDL_DISABLE);
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,102 +24,94 @@
|
||||||
#include "Core/Config.h"
|
#include "Core/Config.h"
|
||||||
#include "thread/threadutil.h"
|
#include "thread/threadutil.h"
|
||||||
|
|
||||||
static std::mutex emuThreadLock;
|
enum class EmuThreadState {
|
||||||
|
DISABLED,
|
||||||
|
START_REQUESTED,
|
||||||
|
RUNNING,
|
||||||
|
QUIT_REQUESTED,
|
||||||
|
STOPPED,
|
||||||
|
};
|
||||||
|
|
||||||
static std::thread emuThread;
|
static std::thread emuThread;
|
||||||
static std::atomic<int> emuThreadState;
|
static std::atomic<int> emuThreadState((int)EmuThreadState::DISABLED);
|
||||||
|
|
||||||
static std::mutex renderThreadLock;
|
static std::thread mainThread;
|
||||||
static std::thread renderThread;
|
static bool useEmuThread;
|
||||||
static std::atomic<int> renderThreadReady;
|
|
||||||
|
|
||||||
static bool useRenderThread;
|
|
||||||
static bool renderThreadFailed;
|
|
||||||
static bool renderThreadSucceeded;
|
|
||||||
static std::string g_error_message;
|
static std::string g_error_message;
|
||||||
|
static bool g_inLoop;
|
||||||
|
|
||||||
extern std::vector<std::wstring> GetWideCmdLine();
|
extern std::vector<std::wstring> GetWideCmdLine();
|
||||||
|
|
||||||
class GraphicsContext;
|
class GraphicsContext;
|
||||||
|
|
||||||
static GraphicsContext *g_graphicsContext;
|
static GraphicsContext *g_graphicsContext;
|
||||||
|
|
||||||
enum EmuThreadStatus : int {
|
void EmuThreadFunc(GraphicsContext *graphicsContext);
|
||||||
THREAD_NONE = 0,
|
void MainThreadFunc();
|
||||||
THREAD_INIT,
|
|
||||||
THREAD_CORE_LOOP,
|
|
||||||
THREAD_SHUTDOWN,
|
|
||||||
THREAD_END,
|
|
||||||
};
|
|
||||||
|
|
||||||
void EmuThreadFunc();
|
// On most other platforms, we let the "main" thread become the render thread and
|
||||||
void RenderThreadFunc();
|
|
||||||
|
|
||||||
// On most other platforms, we let the main thread become the render thread and
|
|
||||||
// start a separate emu thread from that, if needed. Should probably switch to that
|
// start a separate emu thread from that, if needed. Should probably switch to that
|
||||||
// to make it the same on all platforms.
|
// to make it the same on all platforms.
|
||||||
void EmuThread_Start(bool separateRenderThread) {
|
void MainThread_Start(bool separateEmuThread) {
|
||||||
std::lock_guard<std::mutex> guard(emuThreadLock);
|
useEmuThread = separateEmuThread;
|
||||||
emuThread = std::thread(&EmuThreadFunc);
|
mainThread = std::thread(&MainThreadFunc);
|
||||||
useRenderThread = separateRenderThread;
|
|
||||||
if (useRenderThread) {
|
|
||||||
renderThread = std::thread(&RenderThreadFunc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread_Stop() {
|
void MainThread_Stop() {
|
||||||
// Already stopped?
|
// Already stopped?
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(emuThreadLock);
|
|
||||||
if (emuThreadState == THREAD_END)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateUIState(UISTATE_EXIT);
|
UpdateUIState(UISTATE_EXIT);
|
||||||
Core_Stop();
|
mainThread.join();
|
||||||
Core_WaitInactive(800);
|
|
||||||
emuThread.join();
|
|
||||||
if (useRenderThread) {
|
|
||||||
renderThread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_UPDATE_UI, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuThread_Ready() {
|
bool MainThread_Ready() {
|
||||||
return emuThreadState == THREAD_CORE_LOOP;
|
return g_inLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderThreadFunc() {
|
static void EmuThreadFunc(GraphicsContext *graphicsContext) {
|
||||||
setCurrentThreadName("Render");
|
|
||||||
renderThreadFailed = false;
|
|
||||||
renderThreadSucceeded = false;
|
|
||||||
while (!g_graphicsContext) {
|
|
||||||
sleep_ms(10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string error_message;
|
|
||||||
if (!g_graphicsContext->InitFromRenderThread(&error_message)) {
|
|
||||||
g_error_message = error_message;
|
|
||||||
renderThreadFailed = true;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
renderThreadSucceeded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_graphicsContext->ThreadStart();
|
|
||||||
while (g_graphicsContext->ThreadFrame()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
g_graphicsContext->ThreadEnd();
|
|
||||||
g_graphicsContext->ShutdownFromRenderThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuThreadFunc() {
|
|
||||||
emuThreadState = THREAD_INIT;
|
|
||||||
|
|
||||||
setCurrentThreadName("Emu");
|
setCurrentThreadName("Emu");
|
||||||
|
|
||||||
|
// There's no real requirement that NativeInit happen on this thread.
|
||||||
|
// We just call the update/render loop here.
|
||||||
|
emuThreadState = (int)EmuThreadState::RUNNING;
|
||||||
|
|
||||||
|
NativeInitGraphics(graphicsContext);
|
||||||
|
|
||||||
|
while (emuThreadState != (int)EmuThreadState::QUIT_REQUESTED) {
|
||||||
|
// We're here again, so the game quit. Restart Core_Run() which controls the UI.
|
||||||
|
// This way they can load a new game.
|
||||||
|
if (!Core_IsActive())
|
||||||
|
UpdateUIState(UISTATE_MENU);
|
||||||
|
Core_Run(g_graphicsContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
emuThreadState = (int)EmuThreadState::STOPPED;
|
||||||
|
|
||||||
|
NativeShutdownGraphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EmuThreadStart(GraphicsContext *graphicsContext) {
|
||||||
|
emuThreadState = (int)EmuThreadState::START_REQUESTED;
|
||||||
|
emuThread = std::thread(&EmuThreadFunc, graphicsContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EmuThreadStop() {
|
||||||
|
emuThreadState = (int)EmuThreadState::QUIT_REQUESTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EmuThreadJoin() {
|
||||||
|
emuThread.join();
|
||||||
|
emuThread = std::thread();
|
||||||
|
ILOG("EmuThreadJoin - joined");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainThreadFunc() {
|
||||||
|
if (useEmuThread) {
|
||||||
|
// We'll start up a separate thread we'll call Emu
|
||||||
|
setCurrentThreadName("Render");
|
||||||
|
} else {
|
||||||
|
// This is both Emu and Render.
|
||||||
|
setCurrentThreadName("Emu");
|
||||||
|
}
|
||||||
|
|
||||||
host = new WindowsHost(MainWindow::GetHInstance(), MainWindow::GetHWND(), MainWindow::GetDisplayHWND());
|
host = new WindowsHost(MainWindow::GetHInstance(), MainWindow::GetHWND(), MainWindow::GetDisplayHWND());
|
||||||
host->SetWindowTitle(nullptr);
|
host->SetWindowTitle(nullptr);
|
||||||
|
|
||||||
|
@ -142,18 +134,8 @@ void EmuThreadFunc() {
|
||||||
bool success = host->InitGraphics(&error_string, &g_graphicsContext);
|
bool success = host->InitGraphics(&error_string, &g_graphicsContext);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (!useRenderThread) {
|
// Main thread is the render thread.
|
||||||
// This is also the render thread.
|
success = g_graphicsContext->InitFromRenderThread(&error_string);
|
||||||
success = g_graphicsContext->InitFromRenderThread(&error_string);
|
|
||||||
} else {
|
|
||||||
while (!renderThreadFailed && !renderThreadSucceeded) {
|
|
||||||
sleep_ms(10);
|
|
||||||
}
|
|
||||||
success = renderThreadSucceeded;
|
|
||||||
if (!success) {
|
|
||||||
error_string = g_error_message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -205,8 +187,12 @@ void EmuThreadFunc() {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeInitGraphics(g_graphicsContext);
|
GraphicsContext *graphicsContext = g_graphicsContext;
|
||||||
NativeResized();
|
|
||||||
|
if (!useEmuThread) {
|
||||||
|
NativeInitGraphics(graphicsContext);
|
||||||
|
NativeResized();
|
||||||
|
}
|
||||||
|
|
||||||
INFO_LOG(BOOT, "Done.");
|
INFO_LOG(BOOT, "Done.");
|
||||||
_dbg_update_();
|
_dbg_update_();
|
||||||
|
@ -216,30 +202,59 @@ void EmuThreadFunc() {
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
emuThreadState = THREAD_CORE_LOOP;
|
g_inLoop = true;
|
||||||
|
|
||||||
|
if (useEmuThread) {
|
||||||
|
EmuThreadStart(graphicsContext);
|
||||||
|
}
|
||||||
|
graphicsContext->ThreadStart();
|
||||||
|
|
||||||
if (g_Config.bBrowse)
|
if (g_Config.bBrowse)
|
||||||
PostMessage(MainWindow::GetHWND(), WM_COMMAND, ID_FILE_LOAD, 0);
|
PostMessage(MainWindow::GetHWND(), WM_COMMAND, ID_FILE_LOAD, 0);
|
||||||
|
|
||||||
Core_EnableStepping(false);
|
Core_EnableStepping(false);
|
||||||
|
|
||||||
while (GetUIState() != UISTATE_EXIT) {
|
if (useEmuThread) {
|
||||||
// We're here again, so the game quit. Restart Core_Run() which controls the UI.
|
while (emuThreadState != (int)EmuThreadState::DISABLED) {
|
||||||
// This way they can load a new game.
|
graphicsContext->ThreadFrame();
|
||||||
if (!Core_IsActive())
|
if (GetUIState() == UISTATE_EXIT) {
|
||||||
UpdateUIState(UISTATE_MENU);
|
break;
|
||||||
Core_Run(g_graphicsContext);
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (GetUIState() != UISTATE_EXIT) {
|
||||||
|
// We're here again, so the game quit. Restart Core_Run() which controls the UI.
|
||||||
|
// This way they can load a new game.
|
||||||
|
if (!Core_IsActive())
|
||||||
|
UpdateUIState(UISTATE_MENU);
|
||||||
|
Core_Run(g_graphicsContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Core_Stop();
|
||||||
|
Core_WaitInactive(800);
|
||||||
|
|
||||||
|
g_inLoop = false;
|
||||||
|
|
||||||
|
if (useEmuThread) {
|
||||||
|
EmuThreadStop();
|
||||||
|
while (emuThreadState != (int)EmuThreadState::STOPPED) {
|
||||||
|
// Need to keep eating frames to allow the EmuThread to exit correctly.
|
||||||
|
graphicsContext->ThreadFrame();
|
||||||
|
}
|
||||||
|
EmuThreadJoin();
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown:
|
shutdown:
|
||||||
emuThreadState = THREAD_SHUTDOWN;
|
|
||||||
|
|
||||||
NativeShutdownGraphics();
|
if (!useEmuThread) {
|
||||||
if (!useRenderThread)
|
NativeShutdownGraphics();
|
||||||
g_graphicsContext->ShutdownFromRenderThread();
|
}
|
||||||
|
|
||||||
|
g_graphicsContext->ThreadEnd();
|
||||||
|
g_graphicsContext->ShutdownFromRenderThread();
|
||||||
|
|
||||||
// NativeShutdown deletes the graphics context through host->ShutdownGraphics().
|
// NativeShutdown deletes the graphics context through host->ShutdownGraphics().
|
||||||
NativeShutdown();
|
NativeShutdown();
|
||||||
emuThreadState = THREAD_END;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_UPDATE_UI, 0, 0);
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void EmuThread_Start(bool separateRenderThread);
|
void MainThread_Start(bool separateRenderThread);
|
||||||
void EmuThread_Stop();
|
void MainThread_Stop();
|
||||||
bool EmuThread_Ready();
|
bool MainThread_Ready();
|
||||||
|
|
|
@ -386,8 +386,6 @@ void WindowsGLContext::SwapInterval(int interval) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowsGLContext::Shutdown() {
|
void WindowsGLContext::Shutdown() {
|
||||||
if (renderManager_)
|
|
||||||
renderManager_->StopThread();
|
|
||||||
glslang::FinalizeProcess();
|
glslang::FinalizeProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -795,7 +795,7 @@ namespace MainWindow
|
||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
{
|
{
|
||||||
if (!EmuThread_Ready())
|
if (!MainThread_Ready())
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
|
||||||
MainWindowMenu_Process(hWnd, wParam);
|
MainWindowMenu_Process(hWnd, wParam);
|
||||||
|
@ -844,7 +844,7 @@ namespace MainWindow
|
||||||
|
|
||||||
case WM_DROPFILES:
|
case WM_DROPFILES:
|
||||||
{
|
{
|
||||||
if (!EmuThread_Ready())
|
if (!MainThread_Ready())
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
|
|
||||||
HDROP hdrop = (HDROP)wParam;
|
HDROP hdrop = (HDROP)wParam;
|
||||||
|
@ -866,9 +866,8 @@ namespace MainWindow
|
||||||
|
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
InputDevice::StopPolling();
|
InputDevice::StopPolling();
|
||||||
EmuThread_Stop();
|
MainThread_Stop();
|
||||||
WindowsRawInput::Shutdown();
|
WindowsRawInput::Shutdown();
|
||||||
|
|
||||||
return DefWindowProc(hWnd,message,wParam,lParam);
|
return DefWindowProc(hWnd,message,wParam,lParam);
|
||||||
|
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
|
@ -914,10 +913,10 @@ namespace MainWindow
|
||||||
case WM_USER_RESTART_EMUTHREAD:
|
case WM_USER_RESTART_EMUTHREAD:
|
||||||
NativeSetRestarting();
|
NativeSetRestarting();
|
||||||
InputDevice::StopPolling();
|
InputDevice::StopPolling();
|
||||||
EmuThread_Stop();
|
MainThread_Stop();
|
||||||
coreState = CORE_POWERUP;
|
coreState = CORE_POWERUP;
|
||||||
ResetUIState();
|
ResetUIState();
|
||||||
EmuThread_Start(false);
|
MainThread_Start(false);
|
||||||
InputDevice::BeginPolling();
|
InputDevice::BeginPolling();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -532,7 +532,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||||
// Emu thread (and render thread, if any) is always running!
|
// Emu thread (and render thread, if any) is always running!
|
||||||
// Only OpenGL uses an externally managed render thread (due to GL's single-threaded context design). Vulkan
|
// Only OpenGL uses an externally managed render thread (due to GL's single-threaded context design). Vulkan
|
||||||
// manages its own render thread.
|
// manages its own render thread.
|
||||||
EmuThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL);
|
MainThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL);
|
||||||
InputDevice::BeginPolling();
|
InputDevice::BeginPolling();
|
||||||
|
|
||||||
HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
|
HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
|
||||||
|
@ -586,9 +586,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||||
|
|
||||||
InputDevice::StopPolling();
|
InputDevice::StopPolling();
|
||||||
|
|
||||||
// The emuthread calls NativeShutdown when shutting down.
|
|
||||||
EmuThread_Stop();
|
|
||||||
|
|
||||||
MainWindow::DestroyDebugWindows();
|
MainWindow::DestroyDebugWindows();
|
||||||
DialogManager::DestroyAll();
|
DialogManager::DestroyAll();
|
||||||
timeEndPeriod(1);
|
timeEndPeriod(1);
|
||||||
|
|
|
@ -217,7 +217,7 @@ static void EmuThreadStop() {
|
||||||
static void EmuThreadJoin() {
|
static void EmuThreadJoin() {
|
||||||
emuThread.join();
|
emuThread.join();
|
||||||
emuThread = std::thread();
|
emuThread = std::thread();
|
||||||
ILOG("EmuThreadStop - joined.");
|
ILOG("EmuThreadJoin - joined");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ProcessFrameCommands(JNIEnv *env);
|
static void ProcessFrameCommands(JNIEnv *env);
|
||||||
|
|
Loading…
Add table
Reference in a new issue