More work on shutdown, still hanging though.
This commit is contained in:
parent
57615344e4
commit
fdca06d208
7 changed files with 73 additions and 54 deletions
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_; }
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue