More work on shutdown, still hanging though.

This commit is contained in:
Henrik Rydgård 2018-01-16 18:13:31 +01:00
parent 57615344e4
commit fdca06d208
7 changed files with 73 additions and 54 deletions

View file

@ -11,6 +11,7 @@ public:
virtual ~GraphicsContext() {} virtual ~GraphicsContext() {}
virtual bool InitFromRenderThread(std::string *errorMessage) { return true; } virtual bool InitFromRenderThread(std::string *errorMessage) { return true; }
virtual void ShutdownFromRenderThread() {}
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
virtual void SwapInterval(int interval) = 0; virtual void SwapInterval(int interval) = 0;
@ -28,7 +29,9 @@ public:
virtual void *GetAPIContext() { return nullptr; } virtual void *GetAPIContext() { return nullptr; }
// Called from the render thread from threaded backends. // 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; virtual Draw::DrawContext *GetDrawContext() = 0;
}; };

View file

@ -104,7 +104,13 @@ void RenderThreadFunc() {
renderThreadSucceeded = true; 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() { void EmuThreadFunc() {
@ -227,6 +233,8 @@ shutdown:
emuThreadState = THREAD_SHUTDOWN; emuThreadState = THREAD_SHUTDOWN;
NativeShutdownGraphics(); NativeShutdownGraphics();
if (!useRenderThread)
g_graphicsContext->ShutdownFromRenderThread();
// NativeShutdown deletes the graphics context through host->ShutdownGraphics(). // NativeShutdown deletes the graphics context through host->ShutdownGraphics().
NativeShutdown(); NativeShutdown();

View file

@ -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) { bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_message) {
glslang::InitializeProcess();
hInst_ = hInst; hInst_ = hInst;
hWnd_ = window; hWnd_ = window;
*error_message = "ok"; *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) { bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
glslang::InitializeProcess();
*error_message = "ok"; *error_message = "ok";
GLuint PixelFormat; GLuint PixelFormat;
@ -386,6 +386,10 @@ void WindowsGLContext::SwapInterval(int interval) {
} }
void WindowsGLContext::Shutdown() { void WindowsGLContext::Shutdown() {
glslang::FinalizeProcess();
}
void WindowsGLContext::ShutdownFromRenderThread() {
delete draw_; delete draw_;
draw_ = nullptr; draw_ = nullptr;
CloseHandle(pauseEvent); CloseHandle(pauseEvent);
@ -411,12 +415,19 @@ void WindowsGLContext::Shutdown() {
hDC = NULL; hDC = NULL;
} }
hWnd_ = NULL; hWnd_ = NULL;
glslang::FinalizeProcess();
} }
void WindowsGLContext::Resize() { void WindowsGLContext::Resize() {
} }
void WindowsGLContext::ThreadFrame() { void WindowsGLContext::ThreadStart() {
renderManager_->ThreadFunc(); renderManager_->ThreadStart();
}
bool WindowsGLContext::ThreadFrame() {
return renderManager_->ThreadFrame();
}
void WindowsGLContext::ThreadEnd() {
renderManager_->ThreadEnd();
} }

View file

@ -14,6 +14,7 @@ public:
bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override; bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override;
bool InitFromRenderThread(std::string *errorMessage) override; bool InitFromRenderThread(std::string *errorMessage) override;
void ShutdownFromRenderThread() override;
void Shutdown() override; void Shutdown() override;
void SwapInterval(int interval) override; void SwapInterval(int interval) override;
@ -25,7 +26,9 @@ public:
void Resume() override; void Resume() override;
void Resize() override; void Resize() override;
void ThreadFrame() override; void ThreadStart() override;
void ThreadEnd() override;
bool ThreadFrame() override;
Draw::DrawContext *GetDrawContext() override { return draw_; } Draw::DrawContext *GetDrawContext() override { return draw_; }

View file

@ -470,7 +470,6 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv
} }
} }
// JavaEGL // JavaEGL
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, jobject obj) { extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, jobject obj) {
static bool hasSetThreadName = false; static bool hasSetThreadName = false;

View file

@ -47,7 +47,7 @@ GLRenderManager::GLRenderManager() {
if (!useThread_) { if (!useThread_) {
// The main thread is also the render thread. // The main thread is also the render thread.
ThreadStartup(); ThreadStart();
} }
} }
@ -62,54 +62,50 @@ GLRenderManager::~GLRenderManager() {
} }
} }
void GLRenderManager::ThreadStartup() { void GLRenderManager::ThreadStart() {
queueRunner_.CreateDeviceObjects(); queueRunner_.CreateDeviceObjects();
threadFrame_ = threadInitFrame_; threadFrame_ = threadInitFrame_;
} }
void GLRenderManager::ThreadEnd() { void GLRenderManager::ThreadEnd() {
queueRunner_.DestroyDeviceObjects(); queueRunner_.DestroyDeviceObjects();
VLOG("PULL: Quitting");
} }
void GLRenderManager::ThreadFunc() { bool GLRenderManager::ThreadFrame() {
ThreadStartup(); {
while (true) { if (nextFrame) {
{ threadFrame_++;
if (nextFrame) { if (threadFrame_ >= MAX_INFLIGHT_FRAMES)
threadFrame_++; threadFrame_ = 0;
if (threadFrame_ >= MAX_INFLIGHT_FRAMES) }
threadFrame_ = 0; FrameData &frameData = frameData_[threadFrame_];
} std::unique_lock<std::mutex> lock(frameData.pull_mutex);
FrameData &frameData = frameData_[threadFrame_]; while (!frameData.readyForRun && run_) {
std::unique_lock<std::mutex> lock(frameData.pull_mutex); VLOG("PULL: Waiting for frame[%d].readyForRun", threadFrame_);
while (!frameData.readyForRun && run_) { frameData.pull_condVar.wait(lock);
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.
if (!frameData.readyForRun && !run_) { return false;
// 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;
VLOG("PULL: frame[%d].readyForRun = false", threadFrame_); // Previously we had a quick exit here that avoided calling Run() if run_ was suddenly false,
frameData.readyForRun = false; // but that created a race condition where frames could end up not finished properly on resize etc.
// 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. // Only increment next time if we're done.
nextFrame = frameData.type == GLRRunType::END; nextFrame = frameData.type == GLRRunType::END;
assert(frameData.type == GLRRunType::END || frameData.type == GLRRunType::SYNC); 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_);
} }
ThreadEnd(); VLOG("PULL: Running frame %d", threadFrame_);
if (firstFrame) {
VLOG("PULL: Quitting"); ILOG("Running first frame (%d)", threadFrame_);
firstFrame = false;
}
Run(threadFrame_);
VLOG("PULL: Finished frame %d", threadFrame_);
return true;
} }
void GLRenderManager::StopThread() { void GLRenderManager::StopThread() {

View file

@ -199,7 +199,9 @@ public:
GLRenderManager(); GLRenderManager();
~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. // Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again.
void BeginFrame(); void BeginFrame();
@ -642,10 +644,9 @@ public:
} }
} }
private: void StopThread();
void ThreadStartup();
void ThreadEnd();
private:
void BeginSubmitFrame(int frame); void BeginSubmitFrame(int frame);
void EndSubmitFrame(int frame); void EndSubmitFrame(int frame);
void Submit(int frame, bool triggerFence); void Submit(int frame, bool triggerFence);
@ -654,8 +655,6 @@ private:
void FlushSync(); void FlushSync();
void EndSyncFrame(int frame); void EndSyncFrame(int frame);
void StopThread();
// Per-frame data, round-robin so we can overlap submission with execution of the previous frame. // Per-frame data, round-robin so we can overlap submission with execution of the previous frame.
struct FrameData { struct FrameData {
std::mutex push_mutex; std::mutex push_mutex;