diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 8dc1e0f71..918d20335 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -42,6 +42,9 @@ public: // Forces a map update: always triggers a rerender. void update(); + // Triggers a cleanup that releases resources. + void cleanup(); + // Controls buffer swapping. bool needsSwap(); void swapped(); @@ -104,6 +107,7 @@ private: // uv async callbacks static void render(uv_async_t *async); static void terminate(uv_async_t *async); + static void cleanup(uv_async_t *async); static void delete_async(uv_handle_t *handle); // Setup @@ -163,6 +167,7 @@ private: uv_thread_t thread; uv_async_t *async_terminate = nullptr; uv_async_t *async_render = nullptr; + uv_async_t *async_cleanup = nullptr; }; } diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 585958648..4f5646db6 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -50,6 +50,13 @@ public: void setup(); + + // Perform cleanup tasks that prepare shutting down the app. This doesn't mean that the + // app will be shut down. That means all operations must be automatically be reversed (e.g. through + // lazy initialization) in case rendering continues. + void cleanup(); + + void clear(); // Updates the default matrices to the current viewport dimensions. diff --git a/src/map/map.cpp b/src/map/map.cpp index 8317735a3..ec47c6292 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -53,6 +53,10 @@ void Map::start() { uv_async_init(loop, async_render, render); async_render->data = this; + async_cleanup = new uv_async_t(); + uv_async_init(loop, async_cleanup, cleanup); + async_cleanup->data = this; + uv_thread_create(&thread, [](void *arg) { Map *map = static_cast(arg); map->run(); @@ -67,6 +71,8 @@ void Map::stop() { async_terminate = nullptr; uv_close((uv_handle_t *)async_render, delete_async); async_render = nullptr; + uv_close((uv_handle_t *)async_cleanup, delete_async); + async_cleanup = nullptr; // Run the event loop once to make sure our async delete handlers are called. uv_run(loop, UV_RUN_ONCE); @@ -112,6 +118,17 @@ void Map::swapped() { rerender(); } +void Map::cleanup() { + uv_async_send(async_cleanup); +} + +void Map::cleanup(uv_async_t *async) { + Map *map = static_cast(async->data); + + map->view.make_active(); + map->painter.cleanup(); +} + void Map::render(uv_async_t *async) { Map *map = static_cast(async->data); diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 9a390765c..8f609d881 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -21,7 +21,7 @@ Painter::Painter(Map &map) } Painter::~Painter() { - clearFramebuffers(); + cleanup(); } bool Painter::needsAnimation() const { @@ -75,6 +75,10 @@ void Painter::setupShaders() { compositeShader = std::make_unique(); } +void Painter::cleanup() { + clearFramebuffers(); +} + void Painter::resize() { const TransformState &state = map.getState(); if (gl_viewport != state.getFramebufferDimensions()) {