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 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;
};

View File

@ -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();

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) {
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();
}

View File

@ -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_; }

View File

@ -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;

View File

@ -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<std::mutex> 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<std::mutex> 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() {

View File

@ -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;