From 0366e05c44410d3e38f2311865564c15b514e31b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 25 Mar 2018 14:45:43 -0700 Subject: [PATCH] Headless: Quick update to use render thread. --- headless/SDLHeadlessHost.cpp | 98 +++++++++++++++++++++++++++++++----- headless/SDLHeadlessHost.h | 14 +++++- 2 files changed, 97 insertions(+), 15 deletions(-) diff --git a/headless/SDLHeadlessHost.cpp b/headless/SDLHeadlessHost.cpp index ed60e409d9..a2ec3a9b51 100644 --- a/headless/SDLHeadlessHost.cpp +++ b/headless/SDLHeadlessHost.cpp @@ -32,11 +32,13 @@ #include "GPU/GPUState.h" #include "base/logging.h" +#include "base/timeutil.h" #include "gfx/gl_common.h" #include "gfx_es2/gpu_features.h" #include "file/vfs.h" #include "file/zip_read.h" #include "thin3d/thin3d_create.h" +#include "thin3d/GLRenderManager.h" const bool WINDOW_VISIBLE = false; const int WINDOW_WIDTH = 480; @@ -53,20 +55,47 @@ SDL_Window *CreateHiddenWindow() { class GLDummyGraphicsContext : public DummyGraphicsContext { public: GLDummyGraphicsContext() { - CheckGLExtensions(); - draw_ = Draw::T3DCreateGLContext(); - SetGPUBackend(GPUBackend::OPENGL); - bool success = draw_->CreatePresets(); - assert(success); } ~GLDummyGraphicsContext() { delete draw_; } + bool InitFromRenderThread(std::string *errorMessage) override; + + void ShutdownFromRenderThread() override { + delete draw_; + draw_ = nullptr; + + SDL_GL_DeleteContext(glContext_); + glContext_ = nullptr; + SDL_DestroyWindow(screen_); + screen_ = nullptr; + } + Draw::DrawContext *GetDrawContext() override { return draw_; } + void ThreadStart() override { + renderManager_->ThreadStart(); + } + + bool ThreadFrame() override { + return renderManager_->ThreadFrame(); + } + + void ThreadEnd() override { + renderManager_->ThreadEnd(); + } + + void StopThread() override { + renderManager_->WaitUntilQueueIdle(); + renderManager_->StopThread(); + } + private: Draw::DrawContext *draw_; + GLRenderManager *renderManager_ = nullptr; + SDL_Window *screen_; + SDL_GLContext glContext_; }; void SDLHeadlessHost::LoadNativeAssets() { @@ -75,7 +104,7 @@ void SDLHeadlessHost::LoadNativeAssets() { VFSRegister("", new DirectoryAssetReader("../")); } -bool SDLHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext **ctx) { +bool GLDummyGraphicsContext::InitFromRenderThread(std::string *errorMessage) { SDL_Init(SDL_INIT_VIDEO); // TODO @@ -115,29 +144,72 @@ bool SDLHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext * } #endif + CheckGLExtensions(); + draw_ = Draw::T3DCreateGLContext(); + renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + SetGPUBackend(GPUBackend::OPENGL); + bool success = draw_->CreatePresets(); + assert(success); + renderManager_->SetSwapFunction([&]() { + SDL_GL_SwapWindow(screen_); + }); + + return success; +} + +bool SDLHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext **ctx) { GraphicsContext *graphicsContext = new GLDummyGraphicsContext(); *ctx = graphicsContext; gfx_ = graphicsContext; + std::thread th([&]{ + while (threadState_ == RenderThreadState::IDLE) + sleep_ms(1); + threadState_ = RenderThreadState::STARTING; + + std::string err; + if (!gfx_->InitFromRenderThread(&err)) { + threadState_ = RenderThreadState::START_FAILED; + return; + } + gfx_->ThreadStart(); + threadState_ = RenderThreadState::STARTED; + + while (threadState_ != RenderThreadState::STOP_REQUESTED) { + if (!gfx_->ThreadFrame()) { + break; + } + gfx_->SwapBuffers(); + } + + threadState_ = RenderThreadState::STOPPING; + gfx_->ThreadEnd(); + gfx_->ShutdownFromRenderThread(); + threadState_ = RenderThreadState::STOPPED; + }); + th.detach(); + LoadNativeAssets(); - return true; + threadState_ = RenderThreadState::START_REQUESTED; + while (threadState_ == RenderThreadState::START_REQUESTED || threadState_ == RenderThreadState::STARTING) + sleep_ms(1); + + return threadState_ == RenderThreadState::STARTED; } void SDLHeadlessHost::ShutdownGraphics() { + gfx_->StopThread(); + while (threadState_ != RenderThreadState::STOPPED) + sleep_ms(1); + gfx_->Shutdown(); delete gfx_; gfx_ = nullptr; - - SDL_GL_DeleteContext(glContext_); - glContext_ = nullptr; - SDL_DestroyWindow(screen_); - screen_ = nullptr; } void SDLHeadlessHost::SwapBuffers() { gfx_->SwapBuffers(); - SDL_GL_SwapWindow(screen_); } #endif diff --git a/headless/SDLHeadlessHost.h b/headless/SDLHeadlessHost.h index 9f50c8931f..daa0fe0413 100644 --- a/headless/SDLHeadlessHost.h +++ b/headless/SDLHeadlessHost.h @@ -38,9 +38,19 @@ public: protected: void LoadNativeAssets(); - SDL_Window *screen_; - SDL_GLContext glContext_; + enum class RenderThreadState { + IDLE, + START_REQUESTED, + STARTING, + START_FAILED, + STARTED, + STOP_REQUESTED, + STOPPING, + STOPPED, + }; + GraphicsContext *gfx_; + volatile RenderThreadState threadState_ = RenderThreadState::IDLE; }; #endif