Add lottie_init() and lottie_shutdown() c api. 17/273517/1
authorSubhransu Mohanty <sub.mohanty@samsung.com>
Fri, 10 Dec 2021 04:30:07 +0000 (13:30 +0900)
committerjykeon <jykeon@samsung.com>
Thu, 7 Apr 2022 01:56:29 +0000 (10:56 +0900)
To support dynamic loading and unloading of rlottie library safely
we need to deallocate the resource cache as well as safely shutdown all the
worker threads.
current patch only stops the Render and Rle task schedulers when lottie_shutdown is called.

Things yet to be implemented during shutdown phase
- Unload image loader if loaded dynamically.
- Check if we can release some cache resources.
- Currently multiple load and unload of rlottie library will not work as we are not starting the
  scheduler again when lottie_init() called multiple time in the same process.

Change-Id: Ifacf3882c4aec3ce87e9840d76f445e727a74f58
Signed-off-by: jykeon <jykeon@samsung.com>
inc/rlottie_capi.h
src/binding/c/lottieanimation_capi.cpp
src/lottie/lottieanimation.cpp
src/vector/vraster.cpp

index 7c883fac15da23a9f704644a21af2c8626bcb8c8..50daeebb1e7eddd13dab588021344bc11e17e8f0 100644 (file)
@@ -46,6 +46,36 @@ typedef enum {
 
 typedef struct Lottie_Animation_S Lottie_Animation;
 
+/**
+ *  @brief Runs lottie initialization code when rlottie library is loaded
+ * dynamically.
+ *
+ *
+ * This api should be called before any other api when rlottie library
+ * is loaded using dlopen() or equivalent.
+ *
+ *  @see lottie_shutdown()
+ *
+ *  @ingroup Lottie_Animation
+ *  @internal
+ */
+RLOTTIE_API void lottie_init();
+
+/**
+ *  @brief Runs lottie teardown code when rlottie library  is loaded
+ * dynamically.
+ *
+ * This api should be called before unloading the rlottie library for
+ * proper cleanup of the resource without doing so will result in undefined
+ * behaviour.
+ *
+ *  @see lottie_init()
+ *
+ *  @ingroup Lottie_Animation
+ *  @internal
+ */
+RLOTTIE_API void lottie_shutdown();
+
 /**
  *  @brief Constructs an animation object from file path.
  *
index a54dac513d8c23f62ce96907b98a9fa17f70044e..abbe2ba42ae059c779064f46b485ff6d8e535d5f 100644 (file)
@@ -26,6 +26,9 @@
 
 using namespace rlottie;
 
+extern void lottie_init_impl();
+extern void lottie_shutdown_impl();
+
 extern "C" {
 #include <string.h>
 #include <stdarg.h>
@@ -38,6 +41,34 @@ struct Lottie_Animation_S
     LOTMarkerList                  *mMarkerList;
 };
 
+static uint32_t _lottie_lib_ref_count = 0;
+
+RLOTTIE_API void lottie_init()
+{
+    if (_lottie_lib_ref_count > 0) {
+        _lottie_lib_ref_count++;
+        return;
+    }
+    lottie_init_impl();
+
+    _lottie_lib_ref_count = 1;
+}
+
+RLOTTIE_API void lottie_shutdown()
+{
+    if (_lottie_lib_ref_count <= 0) {
+        // lottie_init() is not called before lottie_shutdown()
+        // or multiple shutdown is getting called.
+        return;
+    }
+
+    _lottie_lib_ref_count--;
+
+    if (_lottie_lib_ref_count == 0) {
+        lottie_shutdown_impl();
+    }
+}
+
 RLOTTIE_API Lottie_Animation_S *lottie_animation_from_file(const char *path)
 {
     if (auto animation = Animation::loadFromFile(path) ) {
index 601c065c3d5e6e1ae8efdfe4909e5c35ba3379b6..afcc400bc822f30771dbd9a4cf4924a521f79cf0 100644 (file)
@@ -178,20 +178,29 @@ class RenderTaskScheduler {
         for (unsigned n = 0; n != _count; ++n) {
             _threads.emplace_back([&, n] { run(n); });
         }
+
+        IsRunning = true;
     }
 
 public:
+    static bool IsRunning;
+
     static RenderTaskScheduler &instance()
     {
         static RenderTaskScheduler singleton;
         return singleton;
     }
 
-    ~RenderTaskScheduler()
+    ~RenderTaskScheduler() { stop(); }
+
+    void stop()
     {
-        for (auto &e : _q) e.done();
+        if (IsRunning) {
+            IsRunning = false;
 
-        for (auto &e : _threads) e.join();
+            for (auto &e : _q) e.done();
+            for (auto &e : _threads) e.join();
+        }
     }
 
     std::future<Surface> process(SharedRenderTask task)
@@ -214,12 +223,16 @@ public:
 #else
 class RenderTaskScheduler {
 public:
+    static bool IsRunning;
+
     static RenderTaskScheduler &instance()
     {
         static RenderTaskScheduler singleton;
         return singleton;
     }
 
+    void stop() {}
+
     std::future<Surface> process(SharedRenderTask task)
     {
         auto result = task->playerImpl->render(task->frameNo, task->surface,
@@ -228,8 +241,11 @@ public:
         return std::move(task->receiver);
     }
 };
+
 #endif
 
+bool RenderTaskScheduler::IsRunning{false};
+
 std::future<Surface> AnimationImpl::renderAsync(size_t    frameNo,
                                                 Surface &&surface,
                                                 bool      keepAspectRatio)
@@ -441,6 +457,29 @@ void Surface::setDrawRegion(size_t x, size_t y, size_t width, size_t height)
     mDrawArea.h = height;
 }
 
+namespace {
+void lottieShutdownRenderTaskScheduler()
+{
+    if (RenderTaskScheduler::IsRunning) {
+        RenderTaskScheduler::instance().stop();
+    }
+}
+}  // namespace
+
+// private apis exposed to c interface
+void lottie_init_impl()
+{
+    // do nothing for now.
+}
+
+extern void lottieShutdownRasterTaskScheduler();
+
+void lottie_shutdown_impl()
+{
+    lottieShutdownRenderTaskScheduler();
+    lottieShutdownRasterTaskScheduler();
+}
+
 #ifdef LOTTIE_LOGGING_SUPPORT
 void initLogging()
 {
index d64c0a6ac685a2132acefc9002f36374ec64d438..fdf66fb01b6c50677629e7ebf046c0cc1e452b1b 100644 (file)
@@ -461,20 +461,29 @@ class RleTaskScheduler {
         for (unsigned n = 0; n != _count; ++n) {
             _threads.emplace_back([&, n] { run(n); });
         }
+
+        IsRunning = true;
     }
 
 public:
+    static bool IsRunning;
+
     static RleTaskScheduler &instance()
     {
         static RleTaskScheduler singleton;
         return singleton;
     }
 
-    ~RleTaskScheduler()
+    ~RleTaskScheduler() { stop(); }
+
+    void stop()
     {
-        for (auto &e : _q) e.done();
+        if (IsRunning) {
+            IsRunning = false;
 
-        for (auto &e : _threads) e.join();
+            for (auto &e : _q) e.done();
+            for (auto &e : _threads) e.join();
+        }
     }
 
     void process(VTask task)
@@ -499,12 +508,16 @@ public:
     SW_FT_Stroker stroker;
 
 public:
+    static bool IsRunning;
+
     static RleTaskScheduler &instance()
     {
         static RleTaskScheduler singleton;
         return singleton;
     }
 
+    void stop() {}
+
     RleTaskScheduler() { SW_FT_Stroker_New(&stroker); }
 
     ~RleTaskScheduler() { SW_FT_Stroker_Done(stroker); }
@@ -513,6 +526,8 @@ public:
 };
 #endif
 
+bool RleTaskScheduler::IsRunning{false};
+
 struct VRasterizer::VRasterizerImpl {
     VRleTask mTask;
 
@@ -560,4 +575,11 @@ void VRasterizer::rasterize(VPath path, CapStyle cap, JoinStyle join,
     updateRequest();
 }
 
+void lottieShutdownRasterTaskScheduler()
+{
+    if (RleTaskScheduler::IsRunning) {
+        RleTaskScheduler::instance().stop();
+    }
+}
+
 V_END_NAMESPACE