Simulate: move all glfw calls to main thread to fix MacOS

This commit is contained in:
Levi Burner
2022-06-03 10:21:08 -04:00
parent 62008a0e19
commit a526a6bd78
3 changed files with 39 additions and 50 deletions
+34 -25
View File
@@ -92,7 +92,7 @@ mjModel* LoadModel(const char* file, mj::Simulate& simulate) {
} }
// simulate in background thread (while rendering in main thread) // simulate in background thread (while rendering in main thread)
void SimulateLoop(mj::Simulate& simulate) { void PhysicsLoop(mj::Simulate& simulate) {
// cpu-sim syncronization point // cpu-sim syncronization point
double cpusync = 0; double cpusync = 0;
mjtNum simsync = 0; mjtNum simsync = 0;
@@ -222,6 +222,31 @@ void SimulateLoop(mj::Simulate& simulate) {
} }
} // end unnamed namespace } // 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 ------------------------------------------------- //---------------------------------- main -------------------------------------------------
// run event loop // run event loop
@@ -240,33 +265,17 @@ int main(int argc, const char** argv) {
mju_error("could not initialize GLFW"); mju_error("could not initialize GLFW");
} }
// start simulation thread (this creates the UI) const char* filename = nullptr;
simulate.startthread(); if (argc > 1) {
filename = argv[1];
// 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);
}
} }
SimulateLoop(simulate); // start physics thread
std::thread physicsthreadhandle = std::thread(&PhysicsThread, &simulate, filename);
// If simulate loop exited its time to stop the UI // start simulation UI loop (blocking call)
simulate.stopthread(); simulate.renderloop();
physicsthreadhandle.join();
// delete everything we allocated
free(ctrlnoise);
mj_deleteData(d);
mj_deleteModel(m);
// terminate GLFW (crashes with Linux NVidia drivers) // terminate GLFW (crashes with Linux NVidia drivers)
#if defined(__APPLE__) || defined(_WIN32) #if defined(__APPLE__) || defined(_WIN32)
+1 -19
View File
@@ -1535,18 +1535,6 @@ namespace mju = ::mujoco::sample_util;
Simulate::Simulate(void) { Simulate::Simulate(void) {
} // TODO constructor is now empty... } // 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 ---------------------------- //------------------------ apply pose perturbations ----------------------------
void Simulate::applyposepertubations(int flg_paused) { void Simulate::applyposepertubations(int flg_paused) {
if (this->m != nullptr) { if (this->m != nullptr) {
@@ -1798,7 +1786,7 @@ void Simulate::clearcallback(void) {
uiClearCallback(this->window); uiClearCallback(this->window);
} }
void Simulate::renderthread(void) { void Simulate::renderloop(void) {
// Set timer callback (milliseconds) // Set timer callback (milliseconds)
mjcb_time = timer; mjcb_time = timer;
@@ -1900,12 +1888,6 @@ void Simulate::renderthread(void) {
this->clearcallback(); this->clearcallback();
mjv_freeScene(&this->scn); mjv_freeScene(&this->scn);
mjr_freeContext(&this->con); 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 } // namespace mujoco
+4 -6
View File
@@ -44,7 +44,7 @@ class MJSIMULATEAPI Simulate {
Simulate(void); Simulate(void);
// Start the Simulate UI thread // Start the Simulate UI thread
void startthread(void); // void startthread(void);
// Stop the Simulate UI thread // Stop the Simulate UI thread
void stopthread(void); void stopthread(void);
@@ -72,15 +72,13 @@ class MJSIMULATEAPI Simulate {
// clear callbacks registered in external structures // clear callbacks registered in external structures
void clearcallback(void); void clearcallback(void);
// thread to render the UI // loop to render the UI (must be called from main thread because of MacOS)
void renderthread(void); // https://discourse.glfw.org/t/multithreading-glfw/573/5
void renderloop(void);
// constants // constants
static constexpr int kMaxFilenameLength = 1000; static constexpr int kMaxFilenameLength = 1000;
// the UI rendering thread
std::thread renderthreadhandle;
// model and data to be visualized // model and data to be visualized
mjModel* mnew = nullptr; mjModel* mnew = nullptr;
mjData* dnew = nullptr; mjData* dnew = nullptr;