Prepare EmuThread for other users

This commit is contained in:
Henrik Rydgård committed 2026-07-24 15:31:41 +02:00
1 parent 5763a0d731
commit 86c98c2d23
4 files changed
+46 -25

No files matched your search

+34 -23
View File
@@ -40,7 +40,7 @@ bool MainThread_Ready() {
return g_inLoop;
}
static void EmuThreadFunc(GraphicsContext *graphicsContext) {
static void EmuThreadFunc(GraphicsContext *graphicsContext, std::function<void()> postFrame) {
SetCurrentThreadName("EmuThread");
// There's no real requirement that NativeInit happen on this thread.
@@ -52,12 +52,10 @@ static void EmuThreadFunc(GraphicsContext *graphicsContext) {
while (g_emuThreadState != EmuThreadState::QUIT_REQUESTED) {
// We're here again, so the game quit. Restart Run() which controls the UI.
// This way they can load a new game.
if (!Core_IsActive()) {
UpdateUIState(UISTATE_MENU);
}
Core_StateProcessed();
NativeFrame(graphicsContext);
if (postFrame) {
postFrame();
}
if (GetUIState() == UISTATE_EXIT) {
g_emuThreadState = EmuThreadState::QUIT_REQUESTED;
@@ -69,7 +67,28 @@ static void EmuThreadFunc(GraphicsContext *graphicsContext) {
NativeShutdownGraphics();
}
void MainThreadFunc(GraphicsContext *graphicsContext) {
std::thread EmuThread_Start(GraphicsContext *graphicsContext, std::function<void()> postFrame) {
g_emuThreadState = EmuThreadState::START_REQUESTED;
std::thread emuThread = std::thread(&EmuThreadFunc, graphicsContext, postFrame);
return emuThread;
}
void EmuThread_Join(GraphicsContext *graphicsContext, std::thread &emuThread) {
_dbg_assert_(emuThread.joinable());
const EmuThreadState state = g_emuThreadState;
if (state != EmuThreadState::QUIT_REQUESTED &&
state != EmuThreadState::STOPPED) {
g_emuThreadState = EmuThreadState::QUIT_REQUESTED;
}
graphicsContext->ThreadFrameUntilCondition([] {
// Need to keep eating frames to allow the EmuThread to exit correctly.
return g_emuThreadState == EmuThreadState::STOPPED;
});
emuThread.join();
emuThread = std::thread();
}
void MainThreadFunc(GraphicsContext *graphicsContext, std::function<void()> postFrame) {
const bool useEmuThread = g_Config.iGPUBackend == (int)GPUBackend::OPENGL;
if (useEmuThread) {
SetCurrentThreadName("RenderThread");
@@ -82,8 +101,7 @@ void MainThreadFunc(GraphicsContext *graphicsContext) {
g_inLoop = true;
g_emuThreadState = EmuThreadState::START_REQUESTED;
std::thread emuThread = std::thread(&EmuThreadFunc, graphicsContext);
std::thread emuThread = EmuThread_Start(graphicsContext, postFrame);
graphicsContext->ThreadStart();
// This thread becomes the render thread.
@@ -99,19 +117,13 @@ void MainThreadFunc(GraphicsContext *graphicsContext) {
Core_Stop();
g_inLoop = false;
const EmuThreadState state = g_emuThreadState;
if (state != EmuThreadState::QUIT_REQUESTED &&
state != EmuThreadState::STOPPED) {
g_emuThreadState = EmuThreadState::QUIT_REQUESTED;
}
graphicsContext->ThreadFrameUntilCondition([] {
// Need to keep eating frames to allow the EmuThread to exit correctly.
return g_emuThreadState == EmuThreadState::STOPPED;
});
emuThread.join();
INFO_LOG(Log::System, "EmuThreadJoin - joined");
EmuThread_Join(graphicsContext, emuThread);
graphicsContext->ThreadEnd();
graphicsContext->ShutdownFromRenderThread();
INFO_LOG(Log::System, "EmuThreadJoin - joined");
} else {
SetCurrentThreadName("EmuThread");
// This is the emu thread. the graphics contexts will spawn and handle its own threads if needed.
@@ -131,10 +143,8 @@ void MainThreadFunc(GraphicsContext *graphicsContext) {
while (GetUIState() != UISTATE_EXIT) {
// We're here again, so the game quit. Restart Run() which controls the UI.
// This way they can load a new game.
if (!(Core_IsActive() || Core_IsStepping()))
UpdateUIState(UISTATE_MENU);
Core_StateProcessed();
NativeFrame(graphicsContext);
postFrame();
}
Core_Stop();
@@ -148,6 +158,7 @@ void MainThreadFunc(GraphicsContext *graphicsContext) {
graphicsContext->ThreadEnd();
graphicsContext->ShutdownFromRenderThread();
}
graphicsContext->Shutdown();