Bladeren bron

[flutter] Proper disposal of native resources.

Mario Zechner 3 jaren geleden
bovenliggende
commit
2438f0c39e

+ 1 - 2
spine-flutter/example/lib/main.dart

@@ -5,7 +5,6 @@ class ExampleSelector extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     const spacer = SizedBox(height: 10);
-
     return Scaffold(
         appBar: AppBar(title: const Text('Spine Examples')),
         body: Center(
@@ -48,6 +47,6 @@ class Spineboy extends StatelessWidget {
 void main() {
   runApp(MaterialApp(
       title: "Spine Examples",
-      home: Spineboy()
+      home: ExampleSelector()
   ));
 }

+ 30 - 3
spine-flutter/lib/spine_flutter.dart

@@ -12,13 +12,15 @@ import 'package:path/path.dart' as Path;
 
 int majorVersion() => _bindings.spine_major_version();
 int minorVersion() => _bindings.spine_minor_version();
+void reportLeaks() => _bindings.spine_report_leaks();
 
 class SpineAtlas {
   Pointer<spine_atlas> _atlas;
   List<Image> atlasPages;
   List<Paint> atlasPagePaints;
+  bool _disposed;
 
-  SpineAtlas(this._atlas, this.atlasPages, this.atlasPagePaints);
+  SpineAtlas(this._atlas, this.atlasPages, this.atlasPagePaints): _disposed = false;
 
   static Future<SpineAtlas> fromAsset(AssetBundle assetBundle, String atlasFileName) async {
     final atlasData = await assetBundle.loadString(atlasFileName);
@@ -51,12 +53,20 @@ class SpineAtlas {
 
     return SpineAtlas(atlas, atlasPages, atlasPagePaints);
   }
+
+  void dispose() {
+    if (_disposed) return;
+    _disposed = true;
+    _bindings.spine_atlas_dispose(this._atlas);
+    for (final image in atlasPages) image.dispose();
+  }
 }
 
 class SpineSkeletonData {
   Pointer<spine_skeleton_data> _skeletonData;
+  bool _disposed;
 
-  SpineSkeletonData(this._skeletonData);
+  SpineSkeletonData(this._skeletonData): _disposed = false;
 
   static SpineSkeletonData fromJson(SpineAtlas atlas, String json) {
     final jsonNative = json.toNativeUtf8();
@@ -83,22 +93,31 @@ class SpineSkeletonData {
     }
     return SpineSkeletonData(skeletonData);
   }
+
+  void dispose() {
+    if (_disposed) return;
+    _disposed = true;
+    _bindings.spine_skeleton_data_dispose(this._skeletonData);
+  }
 }
 
 class SpineSkeletonDrawable {
   SpineAtlas atlas;
   SpineSkeletonData skeletonData;
   late Pointer<spine_skeleton_drawable> _drawable;
+  bool _disposed;
 
-  SpineSkeletonDrawable(this.atlas, this.skeletonData) {
+  SpineSkeletonDrawable(this.atlas, this.skeletonData): _disposed = false {
     _drawable = _bindings.spine_skeleton_drawable_create(skeletonData._skeletonData);
   }
 
   void update(double delta) {
+    if (_disposed) return;
     _bindings.spine_skeleton_drawable_update(_drawable, delta);
   }
 
   List<SpineRenderCommand> render() {
+    if (_disposed) return [];
     Pointer<spine_render_command> nativeCmd = _bindings.spine_skeleton_drawable_render(_drawable);
     List<SpineRenderCommand> commands = [];
     while(nativeCmd.address != nullptr.address) {
@@ -108,6 +127,14 @@ class SpineSkeletonDrawable {
     }
     return commands;
   }
+
+  void dispose() {
+    if (_disposed) return;
+    _disposed = true;
+    atlas.dispose();
+    skeletonData.dispose();
+    _bindings.spine_skeleton_drawable_dispose(_drawable);
+  }
 }
 
 class SpineRenderCommand {

+ 11 - 0
spine-flutter/lib/spine_flutter_bindings_generated.dart

@@ -44,6 +44,15 @@ class SpineFlutterBindings {
   late final _spine_minor_version =
       _spine_minor_versionPtr.asFunction<int Function()>();
 
+  void spine_report_leaks() {
+    return _spine_report_leaks();
+  }
+
+  late final _spine_report_leaksPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function()>>('spine_report_leaks');
+  late final _spine_report_leaks =
+      _spine_report_leaksPtr.asFunction<void Function()>();
+
   ffi.Pointer<spine_atlas> spine_atlas_load(
     ffi.Pointer<ffi.Int8> atlasData,
   ) {
@@ -254,5 +263,7 @@ class spine_skeleton_drawable extends ffi.Struct {
 
   external ffi.Pointer<ffi.Void> animationState;
 
+  external ffi.Pointer<ffi.Void> clipping;
+
   external ffi.Pointer<spine_render_command> renderCommand;
 }

+ 6 - 1
spine-flutter/lib/spine_widget.dart

@@ -47,6 +47,12 @@ class _SpineWidgetState extends State<SpineWidget> {
       return SizedBox();
     }
   }
+
+  @override
+  void dispose() {
+    skeletonDrawable?.dispose();
+    super.dispose();
+  }
 }
 
 class _SpineRenderObjectWidget extends LeafRenderObjectWidget {
@@ -76,7 +82,6 @@ class _SpineRenderObject extends RenderBox {
   set skeletonDrawable(SpineSkeletonDrawable skeletonDrawable) {
     if (_skeletonDrawable == skeletonDrawable) return;
 
-    // FIXME dispose old drawable here?
     _skeletonDrawable = skeletonDrawable;
     markNeedsPaint();
   }

+ 0 - 2
spine-flutter/src/CMakeLists.txt

@@ -18,6 +18,4 @@ set_target_properties(spine_flutter PROPERTIES
 )
 target_include_directories(spine_flutter PUBLIC spine-cpp/include)
 target_compile_definitions(spine_flutter PUBLIC DART_SHARED_LIB)
-#target_compile_options(spine_flutter PUBLIC -fsanitize=address -fno-omit-frame-pointer)
-#set_target_properties(spine_flutter PROPERTIES LINK_FLAGS -fsanitize=address)
 

+ 45 - 35
spine-flutter/src/spine_flutter.cpp

@@ -1,6 +1,7 @@
 #include "spine_flutter.h"
 #include <spine/spine.h>
 #include <spine/Version.h>
+#include <spine/Debug.h>
 
 using namespace spine;
 
@@ -26,6 +27,10 @@ FFI_PLUGIN_EXPORT spine_atlas* spine_atlas_load(const char *atlasData) {
     return result;
 }
 
+void spine_report_leaks() {
+    ((DebugExtension*)spine::SpineExtension::getInstance())->reportLeaks();
+}
+
 FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas) {
     if (!atlas) return;
     if (atlas->atlas) delete (Atlas*)atlas->atlas;
@@ -33,6 +38,7 @@ FFI_PLUGIN_EXPORT void spine_atlas_dispose(spine_atlas *atlas) {
     for (int i = 0; i < atlas->numImagePaths; i++) {
         free(atlas->imagePaths[i]);
     }
+    SpineExtension::free(atlas->imagePaths, __FILE__, __LINE__);
     SpineExtension::free(atlas, __FILE__, __LINE__);
 }
 
@@ -74,27 +80,6 @@ FFI_PLUGIN_EXPORT void spine_skeleton_data_dispose(spine_skeleton_data *skeleton
     SpineExtension::free(skeletonData, __FILE__, __LINE__);
 }
 
-FFI_PLUGIN_EXPORT spine_skeleton_drawable *spine_skeleton_drawable_create(spine_skeleton_data *skeletonData) {
-    spine_skeleton_drawable *drawable = SpineExtension::calloc<spine_skeleton_drawable>(1, __FILE__, __LINE__);
-    drawable->skeleton = new Skeleton((SkeletonData*)skeletonData->skeletonData);
-    drawable->animationState = new AnimationState(new AnimationStateData((SkeletonData*)skeletonData->skeletonData));
-    drawable->clipping = new SkeletonClipping();
-    return drawable;
-}
-
-FFI_PLUGIN_EXPORT void spine_skeleton_drawable_update(spine_skeleton_drawable *drawable, float deltaTime) {
-    if (!drawable) return;
-    if (!drawable->skeleton) return;
-    if (!drawable->animationState) return;
-    if (!drawable->clipping) return;
-
-    Skeleton *skeleton = (Skeleton*)drawable->skeleton;
-    AnimationState *animationState = (AnimationState*)drawable->animationState;
-    animationState->update(deltaTime);
-    animationState->apply(*skeleton);
-    skeleton->updateWorldTransform();
-}
-
 spine_render_command *spine_render_command_create(int32_t numVertices, int32_t numIndices, spine_blend_mode blendMode, int pageIndex) {
     spine_render_command *cmd = SpineExtension::alloc<spine_render_command>(1, __FILE__, __LINE__);
     cmd->positions = SpineExtension::alloc<float>(numVertices << 1, __FILE__, __LINE__);
@@ -118,6 +103,44 @@ void spine_render_command_dispose(spine_render_command *cmd) {
     SpineExtension::free(cmd, __FILE__, __LINE__);
 }
 
+FFI_PLUGIN_EXPORT spine_skeleton_drawable *spine_skeleton_drawable_create(spine_skeleton_data *skeletonData) {
+    spine_skeleton_drawable *drawable = SpineExtension::calloc<spine_skeleton_drawable>(1, __FILE__, __LINE__);
+    drawable->skeleton = new Skeleton((SkeletonData*)skeletonData->skeletonData);
+    drawable->animationState = new AnimationState(new AnimationStateData((SkeletonData*)skeletonData->skeletonData));
+    drawable->clipping = new SkeletonClipping();
+    return drawable;
+}
+
+FFI_PLUGIN_EXPORT void spine_skeleton_drawable_dispose(spine_skeleton_drawable *drawable) {
+    if (!drawable) return;
+    if (drawable->skeleton) delete (Skeleton*)drawable->skeleton;
+    if (drawable->animationState) {
+        AnimationState *state = (AnimationState*)drawable->animationState;
+        delete state->getData();
+        delete (AnimationState*)state;
+    }
+    if (drawable->clipping) delete (SkeletonClipping*)drawable->clipping;
+    while (drawable->renderCommand) {
+        spine_render_command *cmd = drawable->renderCommand;
+        drawable->renderCommand = cmd->next;
+        spine_render_command_dispose(cmd);
+    }
+    SpineExtension::free(drawable, __FILE__, __LINE__);
+}
+
+FFI_PLUGIN_EXPORT void spine_skeleton_drawable_update(spine_skeleton_drawable *drawable, float deltaTime) {
+    if (!drawable) return;
+    if (!drawable->skeleton) return;
+    if (!drawable->animationState) return;
+    if (!drawable->clipping) return;
+
+    Skeleton *skeleton = (Skeleton*)drawable->skeleton;
+    AnimationState *animationState = (AnimationState*)drawable->animationState;
+    animationState->update(deltaTime);
+    animationState->apply(*skeleton);
+    skeleton->updateWorldTransform();
+}
+
 FFI_PLUGIN_EXPORT spine_render_command *spine_skeleton_drawable_render(spine_skeleton_drawable *drawable) {
     if (!drawable) return nullptr;
     if (!drawable->skeleton) return nullptr;
@@ -238,19 +261,6 @@ FFI_PLUGIN_EXPORT spine_render_command *spine_skeleton_drawable_render(spine_ske
     return drawable->renderCommand;
 }
 
-FFI_PLUGIN_EXPORT void spine_skeleton_drawable_dispose(spine_skeleton_drawable *drawable) {
-    if (!drawable) return;
-    if (drawable->skeleton) delete (Skeleton*)drawable->skeleton;
-    if (drawable->animationState) delete (AnimationState*)drawable->animationState;
-    if (drawable->clipping) delete (SkeletonClipping*)drawable->clipping;
-    while (drawable->renderCommand) {
-        spine_render_command *cmd = drawable->renderCommand;
-        drawable->renderCommand = cmd->next;
-        spine_render_command_dispose(cmd);
-    }
-    SpineExtension::free(drawable, __FILE__, __LINE__);
-}
-
 spine::SpineExtension *spine::getDefaultExtension() {
-   return new spine::DefaultSpineExtension();
+   return new spine::DebugExtension(new spine::DefaultSpineExtension());
 }

+ 1 - 0
spine-flutter/src/spine_flutter.h

@@ -25,6 +25,7 @@
 
 FFI_PLUGIN_EXPORT int32_t spine_major_version();
 FFI_PLUGIN_EXPORT int32_t spine_minor_version();
+FFI_PLUGIN_EXPORT void spine_report_leaks();
 
 typedef struct spine_atlas {
     void *atlas;