Browse Source

display: Fix significant memory leak on newer macOS versions

It seems the Metal-based OpenGL driver uses autorelease a lot for resources that last only a single frame, so we need to create an autorelease pool around the frame lest the resources will only get cleaned up at application exit.
rdb 1 year ago
parent
commit
9f493f588d
1 changed files with 28 additions and 0 deletions
  1. 28 0
      panda/src/display/graphicsEngine.cxx

+ 28 - 0
panda/src/display/graphicsEngine.cxx

@@ -62,6 +62,17 @@
   #include <sys/time.h>
   #include <sys/time.h>
 #endif
 #endif
 
 
+#if defined(__APPLE__) && !defined(CPPPARSER)
+#include <AvailabilityMacros.h>
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+extern "C" {
+  void *objc_autoreleasePoolPush();
+  void objc_autoreleasePoolPop(void *);
+};
+#endif
+#endif
+
 using std::string;
 using std::string;
 
 
 PT(GraphicsEngine) GraphicsEngine::_global_ptr;
 PT(GraphicsEngine) GraphicsEngine::_global_ptr;
@@ -2550,11 +2561,20 @@ do_frame(GraphicsEngine *engine, Thread *current_thread) {
   PStatTimer timer(engine->_do_frame_pcollector, current_thread);
   PStatTimer timer(engine->_do_frame_pcollector, current_thread);
   LightReMutexHolder holder(_wl_lock);
   LightReMutexHolder holder(_wl_lock);
 
 
+#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+  // Enclose the entire frame in an autorelease pool.
+  void *pool = objc_autoreleasePoolPush();
+#endif
+
   engine->cull_to_bins(_cull, current_thread);
   engine->cull_to_bins(_cull, current_thread);
   engine->cull_and_draw_together(_cdraw, current_thread);
   engine->cull_and_draw_together(_cdraw, current_thread);
   engine->draw_bins(_draw, current_thread);
   engine->draw_bins(_draw, current_thread);
   engine->process_events(_window, current_thread);
   engine->process_events(_window, current_thread);
 
 
+#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+  objc_autoreleasePoolPop(pool);
+#endif
+
   // If any GSG's on the list have no more outstanding pointers, clean them
   // If any GSG's on the list have no more outstanding pointers, clean them
   // up.  (We are in the draw thread for all of these GSG's.)
   // up.  (We are in the draw thread for all of these GSG's.)
   if (any_done_gsgs()) {
   if (any_done_gsgs()) {
@@ -2586,10 +2606,18 @@ void GraphicsEngine::WindowRenderer::
 do_windows(GraphicsEngine *engine, Thread *current_thread) {
 do_windows(GraphicsEngine *engine, Thread *current_thread) {
   LightReMutexHolder holder(_wl_lock);
   LightReMutexHolder holder(_wl_lock);
 
 
+#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+  void *pool = objc_autoreleasePoolPush();
+#endif
+
   engine->process_events(_window, current_thread);
   engine->process_events(_window, current_thread);
 
 
   engine->make_contexts(_cdraw, current_thread);
   engine->make_contexts(_cdraw, current_thread);
   engine->make_contexts(_draw, current_thread);
   engine->make_contexts(_draw, current_thread);
+
+#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+  objc_autoreleasePoolPop(pool);
+#endif
 }
 }
 
 
 /**
 /**