From a526a6bd789561a526e7311c7a52394fff23a296 Mon Sep 17 00:00:00 2001 From: Levi Burner Date: Fri, 3 Jun 2022 10:21:08 -0400 Subject: [PATCH] Simulate: move all glfw calls to main thread to fix MacOS --- simulate/main.cc | 59 +++++++++++++++++++++++++------------------- simulate/simulate.cc | 20 +-------------- simulate/simulate.h | 10 +++----- 3 files changed, 39 insertions(+), 50 deletions(-) diff --git a/simulate/main.cc b/simulate/main.cc index 34e8f263..b5496367 100644 --- a/simulate/main.cc +++ b/simulate/main.cc @@ -92,7 +92,7 @@ mjModel* LoadModel(const char* file, mj::Simulate& simulate) { } // simulate in background thread (while rendering in main thread) -void SimulateLoop(mj::Simulate& simulate) { +void PhysicsLoop(mj::Simulate& simulate) { // cpu-sim syncronization point double cpusync = 0; mjtNum simsync = 0; @@ -222,6 +222,31 @@ void SimulateLoop(mj::Simulate& simulate) { } } // end unnamed namespace +//---------------------------------- physics_thread --------------------------------------- +void PhysicsThread(mj::Simulate* simulate, const char* filename) { + // request loadmodel if file given (otherwise drag-and-drop) + if (filename != nullptr) { + m = LoadModel(filename, *simulate); + if (m) { + d = mj_makeData(m); + simulate->load(filename, m, d, true); + mj_forward(m, d); + + // allocate ctrlnoise + free(ctrlnoise); + ctrlnoise = (mjtNum*) malloc(sizeof(mjtNum)*m->nu); + mju_zero(ctrlnoise, m->nu); + } + } + + PhysicsLoop(*simulate); + + // delete everything we allocated + free(ctrlnoise); + mj_deleteData(d); + mj_deleteModel(m); +} + //---------------------------------- main ------------------------------------------------- // run event loop @@ -240,33 +265,17 @@ int main(int argc, const char** argv) { mju_error("could not initialize GLFW"); } - // start simulation thread (this creates the UI) - simulate.startthread(); - - // request loadmodel if file given (otherwise drag-and-drop) - if (argc>1) { - m = LoadModel(argv[1], simulate); - if (m) { - d = mj_makeData(m); - simulate.load(argv[1], m, d, true); - mj_forward(m, d); - - // allocate ctrlnoise - free(ctrlnoise); - ctrlnoise = (mjtNum*) malloc(sizeof(mjtNum)*m->nu); - mju_zero(ctrlnoise, m->nu); - } + const char* filename = nullptr; + if (argc > 1) { + filename = argv[1]; } - SimulateLoop(simulate); + // start physics thread + std::thread physicsthreadhandle = std::thread(&PhysicsThread, &simulate, filename); - // If simulate loop exited its time to stop the UI - simulate.stopthread(); - - // delete everything we allocated - free(ctrlnoise); - mj_deleteData(d); - mj_deleteModel(m); + // start simulation UI loop (blocking call) + simulate.renderloop(); + physicsthreadhandle.join(); // terminate GLFW (crashes with Linux NVidia drivers) #if defined(__APPLE__) || defined(_WIN32) diff --git a/simulate/simulate.cc b/simulate/simulate.cc index 78eb1225..0033f788 100644 --- a/simulate/simulate.cc +++ b/simulate/simulate.cc @@ -1535,18 +1535,6 @@ namespace mju = ::mujoco::sample_util; Simulate::Simulate(void) { } // TODO constructor is now empty... -//------------------------ start the render thread ----------------------------- -void Simulate::startthread(void) { - this->renderthreadhandle = std::thread(&Simulate::renderthread, this); -} - -//------------------------ stop the render thread ------------------------------ -void Simulate::stopthread(void) { - // stop simulation thread - this->exitrequest = 1; - this->renderthreadhandle.join(); -} - //------------------------ apply pose perturbations ---------------------------- void Simulate::applyposepertubations(int flg_paused) { if (this->m != nullptr) { @@ -1798,7 +1786,7 @@ void Simulate::clearcallback(void) { uiClearCallback(this->window); } -void Simulate::renderthread(void) { +void Simulate::renderloop(void) { // Set timer callback (milliseconds) mjcb_time = timer; @@ -1900,12 +1888,6 @@ void Simulate::renderthread(void) { this->clearcallback(); mjv_freeScene(&this->scn); mjr_freeContext(&this->con); - - // terminate GLFW (crashes with Linux NVidia drivers) - // Must call terminate in this thread on Windows with NVidia drivers (Intel is fine) -#if defined(__APPLE__) || defined(_WIN32) - glfwTerminate(); -#endif } } // namespace mujoco diff --git a/simulate/simulate.h b/simulate/simulate.h index 461318c6..f6da9c10 100644 --- a/simulate/simulate.h +++ b/simulate/simulate.h @@ -44,7 +44,7 @@ class MJSIMULATEAPI Simulate { Simulate(void); // Start the Simulate UI thread - void startthread(void); + // void startthread(void); // Stop the Simulate UI thread void stopthread(void); @@ -72,15 +72,13 @@ class MJSIMULATEAPI Simulate { // clear callbacks registered in external structures void clearcallback(void); - // thread to render the UI - void renderthread(void); + // loop to render the UI (must be called from main thread because of MacOS) + // https://discourse.glfw.org/t/multithreading-glfw/573/5 + void renderloop(void); // constants static constexpr int kMaxFilenameLength = 1000; - // the UI rendering thread - std::thread renderthreadhandle; - // model and data to be visualized mjModel* mnew = nullptr; mjData* dnew = nullptr;