From fdca06d20813c8eeb15e19d03a90f104ac061a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 16 Jan 2018 18:13:31 +0100 Subject: [PATCH] More work on shutdown, still hanging though. --- Common/GraphicsContext.h | 5 +- Windows/EmuThread.cpp | 10 +++- Windows/GPU/WindowsGLContext.cpp | 21 ++++++-- Windows/GPU/WindowsGLContext.h | 5 +- android/jni/app-android.cpp | 1 - ext/native/thin3d/GLRenderManager.cpp | 74 +++++++++++++-------------- ext/native/thin3d/GLRenderManager.h | 11 ++-- 7 files changed, 73 insertions(+), 54 deletions(-) diff --git a/Common/GraphicsContext.h b/Common/GraphicsContext.h index 64a5141379..66afcd94da 100644 --- a/Common/GraphicsContext.h +++ b/Common/GraphicsContext.h @@ -11,6 +11,7 @@ public: virtual ~GraphicsContext() {} virtual bool InitFromRenderThread(std::string *errorMessage) { return true; } + virtual void ShutdownFromRenderThread() {} virtual void Shutdown() = 0; virtual void SwapInterval(int interval) = 0; @@ -28,7 +29,9 @@ public: virtual void *GetAPIContext() { return nullptr; } // Called from the render thread from threaded backends. - virtual void ThreadFrame() {} + virtual void ThreadStart() {} + virtual bool ThreadFrame() { return true; } + virtual void ThreadEnd() {} virtual Draw::DrawContext *GetDrawContext() = 0; }; diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index 7e5ed4f48f..da187068d6 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -104,7 +104,13 @@ void RenderThreadFunc() { renderThreadSucceeded = true; } - g_graphicsContext->ThreadFrame(); + g_graphicsContext->ThreadStart(); + while (emuThreadState != THREAD_SHUTDOWN) { + if (!g_graphicsContext->ThreadFrame()) + break; + } + g_graphicsContext->ThreadEnd(); + g_graphicsContext->ShutdownFromRenderThread(); } void EmuThreadFunc() { @@ -227,6 +233,8 @@ shutdown: emuThreadState = THREAD_SHUTDOWN; NativeShutdownGraphics(); + if (!useRenderThread) + g_graphicsContext->ShutdownFromRenderThread(); // NativeShutdown deletes the graphics context through host->ShutdownGraphics(). NativeShutdown(); diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index f4285d017b..ac48df35fd 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -153,6 +153,8 @@ void DebugCallbackARB(GLenum source, GLenum type, GLuint id, GLenum severity, } bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_message) { + glslang::InitializeProcess(); + hInst_ = hInst; hWnd_ = window; *error_message = "ok"; @@ -160,8 +162,6 @@ bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_mes } bool WindowsGLContext::InitFromRenderThread(std::string *error_message) { - glslang::InitializeProcess(); - *error_message = "ok"; GLuint PixelFormat; @@ -386,6 +386,10 @@ void WindowsGLContext::SwapInterval(int interval) { } void WindowsGLContext::Shutdown() { + glslang::FinalizeProcess(); +} + +void WindowsGLContext::ShutdownFromRenderThread() { delete draw_; draw_ = nullptr; CloseHandle(pauseEvent); @@ -411,12 +415,19 @@ void WindowsGLContext::Shutdown() { hDC = NULL; } hWnd_ = NULL; - glslang::FinalizeProcess(); } void WindowsGLContext::Resize() { } -void WindowsGLContext::ThreadFrame() { - renderManager_->ThreadFunc(); +void WindowsGLContext::ThreadStart() { + renderManager_->ThreadStart(); +} + +bool WindowsGLContext::ThreadFrame() { + return renderManager_->ThreadFrame(); +} + +void WindowsGLContext::ThreadEnd() { + renderManager_->ThreadEnd(); } diff --git a/Windows/GPU/WindowsGLContext.h b/Windows/GPU/WindowsGLContext.h index b628ee25d2..38c9494947 100644 --- a/Windows/GPU/WindowsGLContext.h +++ b/Windows/GPU/WindowsGLContext.h @@ -14,6 +14,7 @@ public: bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override; bool InitFromRenderThread(std::string *errorMessage) override; + void ShutdownFromRenderThread() override; void Shutdown() override; void SwapInterval(int interval) override; @@ -25,7 +26,9 @@ public: void Resume() override; void Resize() override; - void ThreadFrame() override; + void ThreadStart() override; + void ThreadEnd() override; + bool ThreadFrame() override; Draw::DrawContext *GetDrawContext() override { return draw_; } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 48fe18013c..97ce69edc4 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -470,7 +470,6 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv } } - // JavaEGL extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, jobject obj) { static bool hasSetThreadName = false; diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index d4532489c9..85cd8b5089 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -47,7 +47,7 @@ GLRenderManager::GLRenderManager() { if (!useThread_) { // The main thread is also the render thread. - ThreadStartup(); + ThreadStart(); } } @@ -62,54 +62,50 @@ GLRenderManager::~GLRenderManager() { } } -void GLRenderManager::ThreadStartup() { +void GLRenderManager::ThreadStart() { queueRunner_.CreateDeviceObjects(); threadFrame_ = threadInitFrame_; } void GLRenderManager::ThreadEnd() { queueRunner_.DestroyDeviceObjects(); + VLOG("PULL: Quitting"); } -void GLRenderManager::ThreadFunc() { - ThreadStartup(); - while (true) { - { - if (nextFrame) { - threadFrame_++; - if (threadFrame_ >= MAX_INFLIGHT_FRAMES) - threadFrame_ = 0; - } - FrameData &frameData = frameData_[threadFrame_]; - std::unique_lock lock(frameData.pull_mutex); - while (!frameData.readyForRun && run_) { - VLOG("PULL: Waiting for frame[%d].readyForRun", threadFrame_); - frameData.pull_condVar.wait(lock); - } - if (!frameData.readyForRun && !run_) { - // This means we're out of frames to render and run_ is false, so bail. - break; - } - VLOG("PULL: frame[%d].readyForRun = false", threadFrame_); - frameData.readyForRun = false; - // Previously we had a quick exit here that avoided calling Run() if run_ was suddenly false, - // but that created a race condition where frames could end up not finished properly on resize etc. +bool GLRenderManager::ThreadFrame() { + { + if (nextFrame) { + threadFrame_++; + if (threadFrame_ >= MAX_INFLIGHT_FRAMES) + threadFrame_ = 0; + } + FrameData &frameData = frameData_[threadFrame_]; + std::unique_lock lock(frameData.pull_mutex); + while (!frameData.readyForRun && run_) { + VLOG("PULL: Waiting for frame[%d].readyForRun", threadFrame_); + frameData.pull_condVar.wait(lock); + } + if (!frameData.readyForRun && !run_) { + // This means we're out of frames to render and run_ is false, so bail. + return false; + } + VLOG("PULL: frame[%d].readyForRun = false", threadFrame_); + frameData.readyForRun = false; + // Previously we had a quick exit here that avoided calling Run() if run_ was suddenly false, + // but that created a race condition where frames could end up not finished properly on resize etc. - // Only increment next time if we're done. - nextFrame = frameData.type == GLRRunType::END; - assert(frameData.type == GLRRunType::END || frameData.type == GLRRunType::SYNC); - } - VLOG("PULL: Running frame %d", threadFrame_); - if (firstFrame) { - ILOG("Running first frame (%d)", threadFrame_); - firstFrame = false; - } - Run(threadFrame_); - VLOG("PULL: Finished frame %d", threadFrame_); + // Only increment next time if we're done. + nextFrame = frameData.type == GLRRunType::END; + assert(frameData.type == GLRRunType::END || frameData.type == GLRRunType::SYNC); } - ThreadEnd(); - - VLOG("PULL: Quitting"); + VLOG("PULL: Running frame %d", threadFrame_); + if (firstFrame) { + ILOG("Running first frame (%d)", threadFrame_); + firstFrame = false; + } + Run(threadFrame_); + VLOG("PULL: Finished frame %d", threadFrame_); + return true; } void GLRenderManager::StopThread() { diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index dd8b3b29c5..0778f35339 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -199,7 +199,9 @@ public: GLRenderManager(); ~GLRenderManager(); - void ThreadFunc(); + void ThreadStart(); + void ThreadEnd(); + bool ThreadFrame(); // Returns false to request exiting the loop. // Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again. void BeginFrame(); @@ -642,10 +644,9 @@ public: } } -private: - void ThreadStartup(); - void ThreadEnd(); + void StopThread(); +private: void BeginSubmitFrame(int frame); void EndSubmitFrame(int frame); void Submit(int frame, bool triggerFence); @@ -654,8 +655,6 @@ private: void FlushSync(); void EndSyncFrame(int frame); - void StopThread(); - // Per-frame data, round-robin so we can overlap submission with execution of the previous frame. struct FrameData { std::mutex push_mutex;