mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-23 23:52:30 +00:00
Android: Fix emuthread management to exit cleanly without hanging. Helps with task switching on Android.
This commit is contained in:
parent
b3a09791b1
commit
7f30037e45
@ -54,6 +54,9 @@ enum EmuThreadStatus : int {
|
||||
void EmuThreadFunc();
|
||||
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
|
||||
// to make it the same on all platforms.
|
||||
void EmuThread_Start(bool separateRenderThread) {
|
||||
std::lock_guard<std::mutex> guard(emuThreadLock);
|
||||
emuThread = std::thread(&EmuThreadFunc);
|
||||
@ -218,7 +221,7 @@ void EmuThreadFunc() {
|
||||
if (g_Config.bBrowse)
|
||||
PostMessage(MainWindow::GetHWND(), WM_COMMAND, ID_FILE_LOAD, 0);
|
||||
|
||||
Core_EnableStepping(FALSE);
|
||||
Core_EnableStepping(false);
|
||||
|
||||
while (GetUIState() != UISTATE_EXIT) {
|
||||
// We're here again, so the game quit. Restart Core_Run() which controls the UI.
|
||||
|
@ -14,6 +14,9 @@ public:
|
||||
Draw::DrawContext *GetDrawContext() override {
|
||||
return draw_;
|
||||
}
|
||||
bool Initialized() override {
|
||||
return draw_ != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
Draw::DrawContext *draw_;
|
||||
|
@ -22,4 +22,5 @@ public:
|
||||
// This is different than the base class function since on
|
||||
// Android (EGL, Vulkan) we do have all this info on the render thread.
|
||||
virtual bool InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) = 0;
|
||||
virtual bool Initialized() = 0;
|
||||
};
|
||||
|
@ -20,6 +20,7 @@ bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int
|
||||
|
||||
void AndroidJavaEGLGraphicsContext::ShutdownFromRenderThread() {
|
||||
ILOG("AndroidJavaEGLGraphicsContext::Shutdown");
|
||||
renderManager_->WaitUntilQueueIdle();
|
||||
renderManager_ = nullptr; // owned by draw_.
|
||||
delete draw_;
|
||||
draw_ = nullptr;
|
||||
|
@ -15,6 +15,10 @@ public:
|
||||
delete draw_;
|
||||
}
|
||||
|
||||
bool Initialized() override {
|
||||
return draw_ != nullptr;
|
||||
}
|
||||
|
||||
// This performs the actual initialization,
|
||||
bool InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) override;
|
||||
|
||||
|
@ -22,6 +22,10 @@ public:
|
||||
Draw::DrawContext *GetDrawContext() override {
|
||||
return draw_;
|
||||
}
|
||||
bool Initialized() override {
|
||||
return draw_ != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
VulkanContext *g_Vulkan = nullptr;
|
||||
Draw::DrawContext *draw_ = nullptr;
|
||||
|
@ -171,6 +171,20 @@ static void EmuThreadFunc() {
|
||||
gJvm->AttachCurrentThread(&env, nullptr);
|
||||
|
||||
setCurrentThreadName("Emu");
|
||||
ILOG("Entering emu thread");
|
||||
|
||||
// Wait for render loop to get started.
|
||||
if (!graphicsContext || !graphicsContext->Initialized()) {
|
||||
ILOG("Runloop: Waiting for displayInit...");
|
||||
while (!graphicsContext || !graphicsContext->Initialized()) {
|
||||
sleep_ms(20);
|
||||
}
|
||||
} else {
|
||||
ILOG("Runloop: Graphics context available! %p", graphicsContext);
|
||||
}
|
||||
NativeInitGraphics(graphicsContext);
|
||||
|
||||
ILOG("Graphics initialized. Entering loop.");
|
||||
|
||||
// There's no real requirement that NativeInit happen on this thread.
|
||||
// We just call the update/render loop here.
|
||||
@ -179,18 +193,31 @@ static void EmuThreadFunc() {
|
||||
UpdateRunLoopAndroid(env);
|
||||
}
|
||||
emuThreadState = (int)EmuThreadState::STOPPED;
|
||||
|
||||
NativeShutdownGraphics();
|
||||
|
||||
gJvm->DetachCurrentThread();
|
||||
ILOG("Leaving emu thread");
|
||||
}
|
||||
|
||||
static void EmuThreadStart(JNIEnv *env) {
|
||||
static void EmuThreadStart() {
|
||||
ILOG("EmuThreadStart");
|
||||
emuThreadState = (int)EmuThreadState::START_REQUESTED;
|
||||
emuThread = std::thread(&EmuThreadFunc);
|
||||
}
|
||||
|
||||
// Call EmuThreadStop first, then keep running the GPU (or eat commands)
|
||||
// as long as emuThreadState isn't STOPPED and/or there are still things queued up.
|
||||
// Only after that, call EmuThreadJoin.
|
||||
static void EmuThreadStop() {
|
||||
ILOG("EmuThreadStop - stopping...");
|
||||
emuThreadState = (int)EmuThreadState::QUIT_REQUESTED;
|
||||
}
|
||||
|
||||
static void EmuThreadJoin() {
|
||||
emuThread.join();
|
||||
emuThread = std::thread();
|
||||
ILOG("EmuThreadStop - joined.");
|
||||
}
|
||||
|
||||
static void ProcessFrameCommands(JNIEnv *env);
|
||||
@ -429,9 +456,8 @@ retry:
|
||||
|
||||
if (useCPUThread) {
|
||||
ILOG("NativeApp.init() - launching emu thread");
|
||||
EmuThreadStart(env);
|
||||
EmuThreadStart();
|
||||
}
|
||||
ILOG("NativeApp.init() -- end");
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_audioInit(JNIEnv *, jclass) {
|
||||
@ -480,8 +506,13 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_pause(JNIEnv *, jclass) {
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
|
||||
if (useCPUThread)
|
||||
if (useCPUThread && graphicsContext) {
|
||||
EmuThreadStop();
|
||||
while (emuThreadState != (int)EmuThreadState::STOPPED) {
|
||||
graphicsContext->ThreadFrame();
|
||||
}
|
||||
EmuThreadJoin();
|
||||
}
|
||||
|
||||
ILOG("NativeApp.shutdown() -- begin");
|
||||
if (renderer_inited) {
|
||||
@ -507,11 +538,28 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env,
|
||||
// We should be running on the render thread here.
|
||||
std::string errorMessage;
|
||||
if (renderer_inited) {
|
||||
// Would be really nice if we could get something on the GL thread immediately when shutting down...
|
||||
ILOG("NativeApp.displayInit() restoring");
|
||||
graphicsContext->ThreadEnd();
|
||||
if (useCPUThread) {
|
||||
EmuThreadStop();
|
||||
while (emuThreadState != (int)EmuThreadState::STOPPED) {
|
||||
graphicsContext->ThreadFrame();
|
||||
}
|
||||
EmuThreadJoin();
|
||||
} else {
|
||||
NativeShutdownGraphics();
|
||||
}
|
||||
graphicsContext->ShutdownFromRenderThread();
|
||||
|
||||
ILOG("Shut down both threads. Now let's bring it up again!");
|
||||
|
||||
graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0);
|
||||
if (useCPUThread) {
|
||||
EmuThreadStart();
|
||||
} else {
|
||||
NativeInitGraphics(graphicsContext);
|
||||
}
|
||||
graphicsContext->ThreadStart();
|
||||
ILOG("Restored.");
|
||||
} else {
|
||||
@ -564,15 +612,6 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv
|
||||
}
|
||||
|
||||
void UpdateRunLoopAndroid(JNIEnv *env) {
|
||||
// Wait for render loop to get started.
|
||||
if (!renderer_inited) {
|
||||
ILOG("Runloop: Waiting for displayInit");
|
||||
while (!renderer_inited) {
|
||||
sleep_ms(20);
|
||||
}
|
||||
NativeInitGraphics(graphicsContext);
|
||||
}
|
||||
|
||||
NativeUpdate();
|
||||
|
||||
NativeRender(graphicsContext);
|
||||
|
@ -112,7 +112,7 @@ PrioritizedWorkQueueItem *PrioritizedWorkQueue::Pop() {
|
||||
static std::thread *workThread;
|
||||
|
||||
static void threadfunc(PrioritizedWorkQueue *wq) {
|
||||
setCurrentThreadName("PrioritizedWorkQueue");
|
||||
setCurrentThreadName("PrioQueue");
|
||||
while (true) {
|
||||
PrioritizedWorkQueueItem *item = wq->Pop();
|
||||
if (!item) {
|
||||
@ -126,7 +126,7 @@ static void threadfunc(PrioritizedWorkQueue *wq) {
|
||||
}
|
||||
|
||||
void ProcessWorkQueueOnThreadWhile(PrioritizedWorkQueue *wq) {
|
||||
workThread = new std::thread(std::bind(&threadfunc, wq));
|
||||
workThread = new std::thread([=](){threadfunc(wq);});
|
||||
}
|
||||
|
||||
void StopProcessingWorkQueue(PrioritizedWorkQueue *wq) {
|
||||
@ -135,5 +135,5 @@ void StopProcessingWorkQueue(PrioritizedWorkQueue *wq) {
|
||||
workThread->join();
|
||||
delete workThread;
|
||||
}
|
||||
workThread = 0;
|
||||
workThread = nullptr;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user