Skip to content

Commit

Permalink
support a proper shutdown flow (#311)
Browse files Browse the repository at this point in the history
  • Loading branch information
nmwsharp authored Dec 28, 2024
1 parent 469427d commit 53e5886
Show file tree
Hide file tree
Showing 16 changed files with 72 additions and 28 deletions.
1 change: 1 addition & 0 deletions examples/demo-app/demo_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,7 @@ int main(int argc, char** argv) {
// }

std::cout << "!!!! shutdown time" << std::endl;
polyscope::shutdown();

return 0;
}
1 change: 1 addition & 0 deletions include/polyscope/messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ void exception(std::string message);

// Process any warnings that have accumulated, showing them to the user and clearing the queue.
void showDelayedWarnings();
void clearMessages();
} // namespace polyscope
2 changes: 1 addition & 1 deletion include/polyscope/polyscope.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void unshow();
void frameTick();

// Do shutdown work and de-initialize Polyscope
void shutdown();
void shutdown(bool allowMidFrameShutdown=false);

// Returns true if the user has tried to exit the window at the OS level, e.g clicking the close button. Useful for
// deciding when to exit your control loop when using frameTick()
Expand Down
1 change: 1 addition & 0 deletions include/polyscope/render/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ class Engine {
virtual ~Engine();

// High-level control
virtual void shutdown() {};
virtual void checkError(bool fatal = false) = 0;
void buildEngineGui();

Expand Down
1 change: 1 addition & 0 deletions include/polyscope/render/mock_opengl/mock_gl_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ class MockGLEngine : public Engine {

// High-level control
void initialize();
virtual void shutdown() override;
void checkError(bool fatal = false) override;

void swapDisplayBuffers() override;
Expand Down
1 change: 1 addition & 0 deletions include/polyscope/render/opengl/gl_engine_egl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class GLEngineEGL : public GLEngine {

// High-level control
void initialize();
virtual void shutdown() override;
void swapDisplayBuffers() override;
void checkError(bool fatal = false) override;

Expand Down
1 change: 1 addition & 0 deletions include/polyscope/render/opengl/gl_engine_glfw.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class GLEngineGLFW : public GLEngine {

// High-level control
void initialize();
virtual void shutdown() override;
void swapDisplayBuffers() override;

// === Windowing and framework things
Expand Down
1 change: 1 addition & 0 deletions include/polyscope/slice_plane.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class SlicePlane {

SlicePlane* addSceneSlicePlane(bool initiallyVisible = false);
void removeLastSceneSlicePlane();
void removeAllSlicePlanes();
void buildSlicePlaneGUI();

// flag to open the slice plane menu after adding a slice plane
Expand Down
4 changes: 3 additions & 1 deletion src/messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ void terminatingError(std::string message) {
pushContext(func, false);

// Quit the program
shutdown();
shutdown(true);
std::exit(-1);
}

Expand Down Expand Up @@ -281,4 +281,6 @@ void showDelayedWarnings() {
}
}

void clearMessages() { warningMessages.clear(); }

} // namespace polyscope
22 changes: 19 additions & 3 deletions src/polyscope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -934,14 +934,30 @@ bool windowRequestsClose() {
return false;
}

void shutdown() {
void shutdown(bool allowMidFrameShutdown) {

if (!allowMidFrameShutdown && contextStack.size() > 1) {
terminatingError("shutdown() was called mid-frame (e.g. in a per-frame callback, or UI element). This is not "
"permitted, shutdown() may only be called when the main loop is not executing.");
}

// TODO should we make an effort to destruct everything here?
if (options::usePrefsFile) {
writePrefsFile();
}

render::engine->shutdownImGui();
// Clear out all structures and other scene objects
removeAllStructures();
removeAllGroups();
removeAllSlicePlanes();
clearMessages();
state::userCallback = nullptr;

// Shut down the render engine
render::engine->shutdown();
delete render::engine;
render::engine = nullptr;
state::backend = "";
state::initialized = false;
}

bool registerStructure(Structure* s, bool replaceIfPresent) {
Expand Down
12 changes: 7 additions & 5 deletions src/render/mock_opengl/mock_gl_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,8 @@ namespace polyscope {
namespace render {
namespace backend_openGL_mock {


MockGLEngine* glEngine = nullptr; // alias for engine pointer

void initializeRenderEngine() {
glEngine = new MockGLEngine();
MockGLEngine* glEngine = new MockGLEngine();
engine = glEngine;
glEngine->initialize();
engine->allocateGlobalBuffersAndPrograms();
Expand Down Expand Up @@ -874,7 +871,7 @@ void GLShaderProgram::assignBufferToVAO(GLShaderAttribute& a) {
void GLShaderProgram::createBuffer(GLShaderAttribute& a) {

// generate the buffer if needed
std::shared_ptr<AttributeBuffer> newBuff = glEngine->generateAttributeBuffer(a.type, a.arrayCount);
std::shared_ptr<AttributeBuffer> newBuff = engine->generateAttributeBuffer(a.type, a.arrayCount);
std::shared_ptr<GLAttributeBuffer> engineNewBuff = std::dynamic_pointer_cast<GLAttributeBuffer>(newBuff);
if (!engineNewBuff) throw std::invalid_argument("buffer type cast failed");
a.buff = engineNewBuff;
Expand Down Expand Up @@ -1581,6 +1578,11 @@ void MockGLEngine::initializeImGui() {
configureImGui();
}

void MockGLEngine::shutdown() {
checkError();
shutdownImGui();
}

void MockGLEngine::shutdownImGui() { ImGui::DestroyContext(); }

void MockGLEngine::swapDisplayBuffers() {}
Expand Down
4 changes: 1 addition & 3 deletions src/render/opengl/gl_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ namespace render {

namespace backend_openGL3 {

GLEngine* glEngine = nullptr; // alias for global engine pointer

// == Map enums to native values

// clang-format off
Expand Down Expand Up @@ -1345,7 +1343,7 @@ void GLShaderProgram::createBuffer(GLShaderAttribute& a) {
if (a.location == -1) return;

// generate the buffer if needed
std::shared_ptr<AttributeBuffer> newBuff = glEngine->generateAttributeBuffer(a.type, a.arrayCount);
std::shared_ptr<AttributeBuffer> newBuff = engine->generateAttributeBuffer(a.type, a.arrayCount);
std::shared_ptr<GLAttributeBuffer> engineNewBuff = std::dynamic_pointer_cast<GLAttributeBuffer>(newBuff);
if (!engineNewBuff) throw std::invalid_argument("buffer type cast failed");
a.buff = engineNewBuff;
Expand Down
22 changes: 12 additions & 10 deletions src/render/opengl/gl_engine_egl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ namespace polyscope {
namespace render {
namespace backend_openGL3 {

GLEngineEGL* glEngineEGL = nullptr; // alias for global engine pointer
extern GLEngine* glEngine; // defined in gl_engine.h

namespace { // anonymous helpers

void checkEGLError(bool fatal = true) {
Expand Down Expand Up @@ -116,10 +113,8 @@ void checkEGLError(bool fatal = true) {

void initializeRenderEngine_egl() {

glEngineEGL = new GLEngineEGL(); // create the new global engine object

engine = glEngineEGL; // we keep a few copies of this pointer with various types
glEngine = glEngineEGL;
GLEngineEGL* glEngineEGL = new GLEngineEGL(); // create the new global engine object
engine = glEngineEGL;

// initialize
glEngineEGL->initialize();
Expand All @@ -128,9 +123,7 @@ void initializeRenderEngine_egl() {
}

GLEngineEGL::GLEngineEGL() {}
GLEngineEGL::~GLEngineEGL() {
// eglTerminate(eglDisplay) // TODO handle termination
}
GLEngineEGL::~GLEngineEGL() {}

void GLEngineEGL::initialize() {

Expand Down Expand Up @@ -239,6 +232,15 @@ void GLEngineEGL::initializeImGui() {
configureImGui();
}

void GLEngineEGL::shutdown() {
checkError();
shutdownImGui();

eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(eglDisplay, eglContext);
eglTerminate(eglDisplay);
}

void GLEngineEGL::shutdownImGui() { ImGui::DestroyContext(); }

void GLEngineEGL::ImGuiNewFrame() {
Expand Down
15 changes: 10 additions & 5 deletions src/render/opengl/gl_engine_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,11 @@ namespace polyscope {
namespace render {
namespace backend_openGL3 {

GLEngineGLFW* glEngineGLFW = nullptr; // alias for global engine pointer
extern GLEngine* glEngine; // defined in gl_engine.h

void initializeRenderEngine_glfw() {

glEngineGLFW = new GLEngineGLFW(); // create the new global engine object
GLEngineGLFW* glEngineGLFW = new GLEngineGLFW(); // create the new global engine object

engine = glEngineGLFW; // we keep a few copies of this pointer with various types
glEngine = glEngineGLFW;

// initialize
glEngineGLFW->initialize();
Expand Down Expand Up @@ -119,6 +115,15 @@ void GLEngineGLFW::initializeImGui() {
configureImGui();
}


void GLEngineGLFW::shutdown() {
checkError();
shutdownImGui();
glfwDestroyWindow(mainWindow);
glfwTerminate();
}


void GLEngineGLFW::shutdownImGui() {
// ImGui shutdown things
ImGui_ImplOpenGL3_Shutdown();
Expand Down
6 changes: 6 additions & 0 deletions src/slice_plane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ void removeLastSceneSlicePlane() {
}
}

void removeAllSlicePlanes() {
while(!state::slicePlanes.empty()) {
removeLastSceneSlicePlane();
}
}

void buildSlicePlaneGUI() {


Expand Down
6 changes: 6 additions & 0 deletions test/src/basics_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ TEST_F(PolyscopeTest, Unshow) {
polyscope::state::userCallback = nullptr;
}

TEST_F(PolyscopeTest, ShutdownAndReinitialize) {
polyscope::shutdown();
SetUpTestSuite();
polyscope::show(3);
}

// Make sure that creating an empty buffer does not throw errors
TEST_F(PolyscopeTest, EmptyBuffer) {

Expand Down

0 comments on commit 53e5886

Please sign in to comment.