From 8ae7b522dc0fcc112ceebf131af7fb979aa92ce8 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 16 May 2025 10:07:53 -0700 Subject: [PATCH] [skwasm] Add the capability of dumping live object counts in debug mode. (#168389) This adds a debugging utility that allows us to dump counts of the live skwasm objects in debug mode. This is useful for understanding memory leaks. This is not code that runs in production or affects end users, so I'm not bothering to write specific unit tests for this functionality. --------- Co-authored-by: Kevin Moore --- .../ci/licenses_golden/licenses_flutter | 2 + .../lib/web_ui/lib/src/engine/scene_view.dart | 24 +---- .../skwasm/skwasm_impl/raw/skwasm_module.dart | 3 + .../engine/skwasm/skwasm_impl/renderer.dart | 70 +++++++++++++- engine/src/flutter/lib/web_ui/skwasm/BUILD.gn | 2 + .../lib/web_ui/skwasm/animated_image.cpp | 4 + .../lib/web_ui/skwasm/contour_measure.cpp | 6 ++ engine/src/flutter/lib/web_ui/skwasm/data.cpp | 3 + .../src/flutter/lib/web_ui/skwasm/filters.cpp | 17 ++++ .../src/flutter/lib/web_ui/skwasm/fonts.cpp | 5 + .../src/flutter/lib/web_ui/skwasm/image.cpp | 6 ++ .../lib/web_ui/skwasm/live_objects.cpp | 96 +++++++++++++++++++ .../flutter/lib/web_ui/skwasm/live_objects.h | 35 +++++++ .../src/flutter/lib/web_ui/skwasm/paint.cpp | 3 + engine/src/flutter/lib/web_ui/skwasm/path.cpp | 6 ++ .../src/flutter/lib/web_ui/skwasm/picture.cpp | 5 + .../src/flutter/lib/web_ui/skwasm/shaders.cpp | 10 ++ .../src/flutter/lib/web_ui/skwasm/string.cpp | 5 + .../src/flutter/lib/web_ui/skwasm/surface.cpp | 3 + .../lib/web_ui/skwasm/text/line_metrics.cpp | 3 + .../lib/web_ui/skwasm/text/paragraph.cpp | 6 ++ .../web_ui/skwasm/text/paragraph_builder.cpp | 6 ++ .../text/paragraph_builder_builtin_icu.cpp | 3 + .../text/paragraph_builder_client_icu.cpp | 3 + .../lib/web_ui/skwasm/text/strut_style.cpp | 3 + .../lib/web_ui/skwasm/text/text_style.cpp | 4 + .../flutter/lib/web_ui/skwasm/vertices.cpp | 3 + 27 files changed, 313 insertions(+), 23 deletions(-) create mode 100644 engine/src/flutter/lib/web_ui/skwasm/live_objects.cpp create mode 100644 engine/src/flutter/lib/web_ui/skwasm/live_objects.h diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 63e60ced536..e63416129d8 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -55286,6 +55286,8 @@ FILE: ../../../flutter/lib/web_ui/skwasm/fonts.cpp FILE: ../../../flutter/lib/web_ui/skwasm/helpers.h FILE: ../../../flutter/lib/web_ui/skwasm/image.cpp FILE: ../../../flutter/lib/web_ui/skwasm/library_skwasm_support.js +FILE: ../../../flutter/lib/web_ui/skwasm/live_objects.cpp +FILE: ../../../flutter/lib/web_ui/skwasm/live_objects.h FILE: ../../../flutter/lib/web_ui/skwasm/paint.cpp FILE: ../../../flutter/lib/web_ui/skwasm/path.cpp FILE: ../../../flutter/lib/web_ui/skwasm/picture.cpp diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/scene_view.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/scene_view.dart index 69e030adb3f..3bfc0c928a6 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/scene_view.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/scene_view.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:convert'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; @@ -206,28 +205,11 @@ class EngineSceneView { } } - String _generateDebugFilename() { - final now = DateTime.now(); - final String y = now.year.toString().padLeft(4, '0'); - final String mo = now.month.toString().padLeft(2, '0'); - final String d = now.day.toString().padLeft(2, '0'); - final String h = now.hour.toString().padLeft(2, '0'); - final String mi = now.minute.toString().padLeft(2, '0'); - final String s = now.second.toString().padLeft(2, '0'); - return 'flutter-scene-$y-$mo-$d-$h-$mi-$s.json'; - } - - void dumpDebugInfo() { + Map? dumpDebugInfo() { if (kDebugMode && _previousRender != null) { - final Map debugJson = _previousRender!.scene.debugJsonDescription; - final String jsonString = jsonEncode(debugJson); - final blob = createDomBlob([jsonString], {'type': 'application/json'}); - final url = domWindow.URL.createObjectURL(blob); - final element = domDocument.createElement('a'); - element.setAttribute('href', url); - element.setAttribute('download', _generateDebugFilename()); - element.click(); + return _previousRender!.scene.debugJsonDescription; } + return null; } } diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart index fe45e99cacc..5921b47d18f 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart @@ -28,3 +28,6 @@ external bool skwasmIsMultiThreaded(); @Native(symbol: 'skwasm_isHeavy', isLeaf: true) external bool skwasmIsHeavy(); + +@Native)>(symbol: 'skwasm_getLiveObjectCounts', isLeaf: true) +external void skwasmGetLiveObjectCounts(Pointer objectCounts); diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart index c067820604e..ea07ea716a0 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart @@ -3,6 +3,8 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi'; import 'dart:js_interop'; import 'dart:math' as math; import 'dart:typed_data'; @@ -488,10 +490,74 @@ class SkwasmRenderer implements Renderer { ); } + String _generateDebugFilename(String filePrefix) { + final now = DateTime.now(); + final String y = now.year.toString().padLeft(4, '0'); + final String mo = now.month.toString().padLeft(2, '0'); + final String d = now.day.toString().padLeft(2, '0'); + final String h = now.hour.toString().padLeft(2, '0'); + final String mi = now.minute.toString().padLeft(2, '0'); + final String s = now.second.toString().padLeft(2, '0'); + return '$filePrefix-$y-$mo-$d-$h-$mi-$s.json'; + } + + void _dumpDebugInfo(String filePrefix, Map json) { + final String jsonString = const JsonEncoder.withIndent(' ').convert(json); + final blob = createDomBlob([jsonString], {'type': 'application/json'}); + final url = domWindow.URL.createObjectURL(blob); + final element = domDocument.createElement('a'); + element.setAttribute('href', url); + element.setAttribute('download', _generateDebugFilename(filePrefix)); + element.click(); + } + @override void dumpDebugInfo() { - for (final view in _sceneViews.values) { - view.dumpDebugInfo(); + if (kDebugMode) { + withStackScope((StackScope scope) { + final Pointer counts = scope.allocUint32Array(28); + skwasmGetLiveObjectCounts(counts); + final Map countsJson = { + 'lineBreakBufferCount': counts[0], + 'unicodePositionBufferCount': counts[1], + 'lineMetricsCount': counts[2], + 'textBoxListCount': counts[3], + 'paragraphBuilderCount': counts[4], + 'paragraphCount': counts[5], + 'strutStyleCount': counts[6], + 'textStyleCount': counts[7], + 'animatedImageCount': counts[8], + 'countourMeasureIterCount': counts[9], + 'countourMeasureCount': counts[10], + 'dataCount': counts[11], + 'colorFilterCount': counts[12], + 'imageFilterCount': counts[13], + 'maskFilterCount': counts[14], + 'typefaceCount': counts[15], + 'fontCollectionCount': counts[16], + 'imageCount': counts[17], + 'paintCount': counts[18], + 'pathCount': counts[19], + 'pictureCount': counts[20], + 'pictureRecorderCount': counts[21], + 'shaderCount': counts[22], + 'runtimeEffectCount': counts[23], + 'stringCount': counts[24], + 'string16Count': counts[25], + 'surfaceCount': counts[26], + 'verticesCount': counts[27], + }; + _dumpDebugInfo('live_object_counts', countsJson); + }); + + int i = 0; + for (final view in _sceneViews.values) { + final Map? debugJson = view.dumpDebugInfo(); + if (debugJson != null) { + _dumpDebugInfo('flutter-scene$i', debugJson); + i++; + } + } } } } diff --git a/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn b/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn index 850c24f081f..d5a875cf8ce 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn +++ b/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn @@ -17,6 +17,8 @@ template("skwasm_variant") { "fonts.cpp", "helpers.h", "image.cpp", + "live_objects.cpp", + "live_objects.h", "paint.cpp", "path.cpp", "picture.cpp", diff --git a/engine/src/flutter/lib/web_ui/skwasm/animated_image.cpp b/engine/src/flutter/lib/web_ui/skwasm/animated_image.cpp index f61507c30e8..a1ea2d67e0e 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/animated_image.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/animated_image.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "export.h" +#include "live_objects.h" #include "skwasm_support.h" #include "third_party/skia/include/android/SkAnimatedImage.h" @@ -28,6 +29,7 @@ std::unique_ptr getCodecForData(SkData* data) { SKWASM_EXPORT SkAnimatedImage* animatedImage_create(SkData* data, int targetWidth, int targetHeight) { + liveAnimatedImageCount++; auto codec = getCodecForData(data); if (!codec) { printf("Failed to create codec for animated image.\n"); @@ -52,6 +54,7 @@ SKWASM_EXPORT SkAnimatedImage* animatedImage_create(SkData* data, } SKWASM_EXPORT void animatedImage_dispose(SkAnimatedImage* image) { + liveAnimatedImageCount--; image->unref(); } @@ -73,5 +76,6 @@ SKWASM_EXPORT void animatedImage_decodeNextFrame(SkAnimatedImage* image) { } SKWASM_EXPORT SkImage* animatedImage_getCurrentFrame(SkAnimatedImage* image) { + liveImageCount++; return image->getCurrentFrame().release(); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/contour_measure.cpp b/engine/src/flutter/lib/web_ui/skwasm/contour_measure.cpp index 4af486ffe3d..d8abb1f2c18 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/contour_measure.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/contour_measure.cpp @@ -4,6 +4,7 @@ #include "export.h" #include "helpers.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkContourMeasure.h" #include "third_party/skia/include/core/SkPath.h" @@ -12,6 +13,7 @@ using namespace Skwasm; SKWASM_EXPORT SkContourMeasureIter* contourMeasureIter_create(SkPath* path, bool forceClosed, SkScalar resScale) { + liveCountourMeasureIterCount++; return new SkContourMeasureIter(*path, forceClosed, resScale); } @@ -19,16 +21,19 @@ SKWASM_EXPORT SkContourMeasure* contourMeasureIter_next( SkContourMeasureIter* iter) { auto next = iter->next(); if (next) { + liveCountourMeasureCount++; next->ref(); } return next.get(); } SKWASM_EXPORT void contourMeasureIter_dispose(SkContourMeasureIter* iter) { + liveCountourMeasureIterCount--; delete iter; } SKWASM_EXPORT void contourMeasure_dispose(SkContourMeasure* measure) { + liveCountourMeasureCount--; measure->unref(); } @@ -56,5 +61,6 @@ SKWASM_EXPORT SkPath* contourMeasure_getSegment(SkContourMeasure* measure, delete outPath; return nullptr; } + livePathCount++; return outPath; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/data.cpp b/engine/src/flutter/lib/web_ui/skwasm/data.cpp index 1f1b9b748aa..d230fcbb44f 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/data.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/data.cpp @@ -3,10 +3,12 @@ // found in the LICENSE file. #include "export.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkData.h" SKWASM_EXPORT SkData* skData_create(size_t size) { + liveDataCount++; return SkData::MakeUninitialized(size).release(); } @@ -23,5 +25,6 @@ SKWASM_EXPORT size_t skData_getSize(SkData* data) { } SKWASM_EXPORT void skData_dispose(SkData* data) { + liveDataCount--; return data->unref(); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/filters.cpp b/engine/src/flutter/lib/web_ui/skwasm/filters.cpp index d50763ead09..e68554544b2 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/filters.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/filters.cpp @@ -4,6 +4,7 @@ #include "export.h" #include "helpers.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" @@ -14,21 +15,25 @@ using namespace Skwasm; SKWASM_EXPORT SkImageFilter* imageFilter_createBlur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode) { + liveImageFilterCount++; return SkImageFilters::Blur(sigmaX, sigmaY, tileMode, nullptr).release(); } SKWASM_EXPORT SkImageFilter* imageFilter_createDilate(SkScalar radiusX, SkScalar radiusY) { + liveImageFilterCount++; return SkImageFilters::Dilate(radiusX, radiusY, nullptr).release(); } SKWASM_EXPORT SkImageFilter* imageFilter_createErode(SkScalar radiusX, SkScalar radiusY) { + liveImageFilterCount++; return SkImageFilters::Erode(radiusX, radiusY, nullptr).release(); } SKWASM_EXPORT SkImageFilter* imageFilter_createMatrix(SkScalar* matrix33, FilterQuality quality) { + liveImageFilterCount++; return SkImageFilters::MatrixTransform(createMatrix(matrix33), samplingOptionsForQuality(quality), nullptr) @@ -37,18 +42,22 @@ SKWASM_EXPORT SkImageFilter* imageFilter_createMatrix(SkScalar* matrix33, SKWASM_EXPORT SkImageFilter* imageFilter_createFromColorFilter( SkColorFilter* filter) { + liveImageFilterCount++; return SkImageFilters::ColorFilter(sk_ref_sp(filter), nullptr) .release(); } SKWASM_EXPORT SkImageFilter* imageFilter_compose(SkImageFilter* outer, SkImageFilter* inner) { + liveImageFilterCount++; + return SkImageFilters::Compose(sk_ref_sp(outer), sk_ref_sp(inner)) .release(); } SKWASM_EXPORT void imageFilter_dispose(SkImageFilter* filter) { + liveImageFilterCount--; filter->unref(); } @@ -62,39 +71,47 @@ SKWASM_EXPORT void imageFilter_getFilterBounds(SkImageFilter* filter, SKWASM_EXPORT SkColorFilter* colorFilter_createMode(SkColor color, SkBlendMode mode) { + liveColorFilterCount++; return SkColorFilters::Blend(color, mode).release(); } SKWASM_EXPORT SkColorFilter* colorFilter_createMatrix( float* matrixData // 20 values ) { + liveColorFilterCount++; return SkColorFilters::Matrix(matrixData).release(); } SKWASM_EXPORT SkColorFilter* colorFilter_createSRGBToLinearGamma() { + liveColorFilterCount++; return SkColorFilters::SRGBToLinearGamma().release(); } SKWASM_EXPORT SkColorFilter* colorFilter_createLinearToSRGBGamma() { + liveColorFilterCount++; return SkColorFilters::LinearToSRGBGamma().release(); } SKWASM_EXPORT SkColorFilter* colorFilter_compose(SkColorFilter* outer, SkColorFilter* inner) { + liveColorFilterCount++; return SkColorFilters::Compose(sk_ref_sp(outer), sk_ref_sp(inner)) .release(); } SKWASM_EXPORT void colorFilter_dispose(SkColorFilter* filter) { + liveColorFilterCount--; filter->unref(); } SKWASM_EXPORT SkMaskFilter* maskFilter_createBlur(SkBlurStyle blurStyle, SkScalar sigma) { + liveMaskFilterCount++; return SkMaskFilter::MakeBlur(blurStyle, sigma).release(); } SKWASM_EXPORT void maskFilter_dispose(SkMaskFilter* filter) { + liveMaskFilterCount--; filter->unref(); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/fonts.cpp b/engine/src/flutter/lib/web_ui/skwasm/fonts.cpp index e8e3e4d5eab..11b3caacee2 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/fonts.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/fonts.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "export.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkFontMgr.h" #include "third_party/skia/include/ports/SkFontMgr_empty.h" #include "third_party/skia/modules/skparagraph/include/FontCollection.h" @@ -15,6 +16,7 @@ using namespace skia::textlayout; using namespace Skwasm; SKWASM_EXPORT FlutterFontCollection* fontCollection_create() { + liveFontCollectionCount++; auto collection = sk_make_sp(); auto provider = sk_make_sp(); collection->enableFontFallback(); @@ -26,6 +28,7 @@ SKWASM_EXPORT FlutterFontCollection* fontCollection_create() { } SKWASM_EXPORT void fontCollection_dispose(FlutterFontCollection* collection) { + liveFontCollectionCount--; delete collection; } @@ -35,11 +38,13 @@ static sk_sp default_fontmgr() { } SKWASM_EXPORT SkTypeface* typeface_create(SkData* fontData) { + liveTypefaceCount++; auto typeface = default_fontmgr()->makeFromData(sk_ref_sp(fontData)); return typeface.release(); } SKWASM_EXPORT void typeface_dispose(SkTypeface* typeface) { + liveTypefaceCount--; typeface->unref(); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/image.cpp b/engine/src/flutter/lib/web_ui/skwasm/image.cpp index 5fe04b5c0f9..2c22fb0d18d 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/image.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/image.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "export.h" +#include "live_objects.h" #include "skwasm_support.h" #include "surface.h" #include "wrappers.h" @@ -116,6 +117,7 @@ class TextureSourceImageGenerator : public GrExternalTextureGenerator { SKWASM_EXPORT SkImage* image_createFromPicture(SkPicture* picture, int32_t width, int32_t height) { + liveImageCount++; return DeferredFromPicture(sk_ref_sp(picture), {width, height}, nullptr, nullptr, BitDepth::kU8, SkColorSpace::MakeSRGB()) @@ -127,6 +129,7 @@ SKWASM_EXPORT SkImage* image_createFromPixels(SkData* data, int height, PixelFormat pixelFormat, size_t rowByteCount) { + liveImageCount++; return SkImages::RasterFromData( SkImageInfo::Make(width, height, colorTypeForPixelFormat(pixelFormat), @@ -140,6 +143,7 @@ SKWASM_EXPORT SkImage* image_createFromTextureSource(SkwasmObject textureSource, int width, int height, Skwasm::Surface* surface) { + liveImageCount++; return SkImages::DeferredFromTextureGenerator( std::unique_ptr( new TextureSourceImageGenerator( @@ -151,10 +155,12 @@ SKWASM_EXPORT SkImage* image_createFromTextureSource(SkwasmObject textureSource, } SKWASM_EXPORT void image_ref(SkImage* image) { + liveImageCount++; image->ref(); } SKWASM_EXPORT void image_dispose(SkImage* image) { + liveImageCount--; image->unref(); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/live_objects.cpp b/engine/src/flutter/lib/web_ui/skwasm/live_objects.cpp new file mode 100644 index 00000000000..e964657752d --- /dev/null +++ b/engine/src/flutter/lib/web_ui/skwasm/live_objects.cpp @@ -0,0 +1,96 @@ +#include "live_objects.h" + +#include "export.h" + +uint32_t liveLineBreakBufferCount = 0; +uint32_t liveUnicodePositionBufferCount = 0; +uint32_t liveLineMetricsCount = 0; +uint32_t liveTextBoxListCount = 0; +uint32_t liveParagraphBuilderCount = 0; +uint32_t liveParagraphCount = 0; +uint32_t liveStrutStyleCount = 0; +uint32_t liveTextStyleCount = 0; +uint32_t liveAnimatedImageCount = 0; +uint32_t liveCountourMeasureIterCount = 0; +uint32_t liveCountourMeasureCount = 0; +uint32_t liveDataCount = 0; +uint32_t liveColorFilterCount = 0; +uint32_t liveImageFilterCount = 0; +uint32_t liveMaskFilterCount = 0; +uint32_t liveTypefaceCount = 0; +uint32_t liveFontCollectionCount = 0; +uint32_t liveImageCount = 0; +uint32_t livePaintCount = 0; +uint32_t livePathCount = 0; +uint32_t livePictureCount = 0; +uint32_t livePictureRecorderCount = 0; +uint32_t liveShaderCount = 0; +uint32_t liveRuntimeEffectCount = 0; +uint32_t liveStringCount = 0; +uint32_t liveString16Count = 0; +uint32_t liveSurfaceCount = 0; +uint32_t liveVerticesCount = 0; + +namespace { +struct LiveObjectCounts { + uint32_t lineBreakBufferCount; + uint32_t unicodePositionBufferCount; + uint32_t lineMetricsCount; + uint32_t textBoxListCount; + uint32_t paragraphBuilderCount; + uint32_t paragraphCount; + uint32_t strutStyleCount; + uint32_t textStyleCount; + uint32_t animatedImageCount; + uint32_t countourMeasureIterCount; + uint32_t countourMeasureCount; + uint32_t dataCount; + uint32_t colorFilterCount; + uint32_t imageFilterCount; + uint32_t maskFilterCount; + uint32_t typefaceCount; + uint32_t fontCollectionCount; + uint32_t imageCount; + uint32_t paintCount; + uint32_t pathCount; + uint32_t pictureCount; + uint32_t pictureRecorderCount; + uint32_t shaderCount; + uint32_t runtimeEffectCount; + uint32_t stringCount; + uint32_t string16Count; + uint32_t surfaceCount; + uint32_t verticesCount; +}; +} // namespace + +SKWASM_EXPORT void skwasm_getLiveObjectCounts(LiveObjectCounts* counts) { + counts->lineBreakBufferCount = liveLineBreakBufferCount; + counts->unicodePositionBufferCount = liveUnicodePositionBufferCount; + counts->lineMetricsCount = liveLineMetricsCount; + counts->textBoxListCount = liveTextBoxListCount; + counts->paragraphBuilderCount = liveParagraphBuilderCount; + counts->paragraphCount = liveParagraphCount; + counts->strutStyleCount = liveStrutStyleCount; + counts->textStyleCount = liveTextStyleCount; + counts->animatedImageCount = liveAnimatedImageCount; + counts->countourMeasureIterCount = liveCountourMeasureIterCount; + counts->countourMeasureCount = liveCountourMeasureCount; + counts->dataCount = liveDataCount; + counts->colorFilterCount = liveColorFilterCount; + counts->imageFilterCount = liveImageFilterCount; + counts->maskFilterCount = liveMaskFilterCount; + counts->typefaceCount = liveTypefaceCount; + counts->fontCollectionCount = liveFontCollectionCount; + counts->imageCount = liveImageCount; + counts->paintCount = livePaintCount; + counts->pathCount = livePathCount; + counts->pictureCount = livePictureCount; + counts->pictureRecorderCount = livePictureRecorderCount; + counts->shaderCount = liveShaderCount; + counts->runtimeEffectCount = liveRuntimeEffectCount; + counts->stringCount = liveStringCount; + counts->string16Count = liveString16Count; + counts->surfaceCount = liveSurfaceCount; + counts->verticesCount = liveVerticesCount; +} diff --git a/engine/src/flutter/lib/web_ui/skwasm/live_objects.h b/engine/src/flutter/lib/web_ui/skwasm/live_objects.h new file mode 100644 index 00000000000..9e82aec7060 --- /dev/null +++ b/engine/src/flutter/lib/web_ui/skwasm/live_objects.h @@ -0,0 +1,35 @@ +#ifndef FLUTTER_LIB_WEB_UI_SKWASM_LIVE_OBJECTS_H_ +#define FLUTTER_LIB_WEB_UI_SKWASM_LIVE_OBJECTS_H_ + +#include + +extern uint32_t liveLineBreakBufferCount; +extern uint32_t liveUnicodePositionBufferCount; +extern uint32_t liveLineMetricsCount; +extern uint32_t liveTextBoxListCount; +extern uint32_t liveParagraphBuilderCount; +extern uint32_t liveParagraphCount; +extern uint32_t liveStrutStyleCount; +extern uint32_t liveTextStyleCount; +extern uint32_t liveAnimatedImageCount; +extern uint32_t liveCountourMeasureIterCount; +extern uint32_t liveCountourMeasureCount; +extern uint32_t liveDataCount; +extern uint32_t liveColorFilterCount; +extern uint32_t liveImageFilterCount; +extern uint32_t liveMaskFilterCount; +extern uint32_t liveTypefaceCount; +extern uint32_t liveFontCollectionCount; +extern uint32_t liveImageCount; +extern uint32_t livePaintCount; +extern uint32_t livePathCount; +extern uint32_t livePictureCount; +extern uint32_t livePictureRecorderCount; +extern uint32_t liveShaderCount; +extern uint32_t liveRuntimeEffectCount; +extern uint32_t liveStringCount; +extern uint32_t liveString16Count; +extern uint32_t liveSurfaceCount; +extern uint32_t liveVerticesCount; + +#endif // FLUTTER_LIB_WEB_UI_SKWASM_LIVE_OBJECTS_H_ diff --git a/engine/src/flutter/lib/web_ui/skwasm/paint.cpp b/engine/src/flutter/lib/web_ui/skwasm/paint.cpp index 1c131a56155..1288d2b8ae4 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/paint.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/paint.cpp @@ -4,6 +4,7 @@ #include "export.h" #include "helpers.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" @@ -20,6 +21,7 @@ SKWASM_EXPORT SkPaint* paint_create(bool isAntiAlias, SkPaint::Cap strokeCap, SkPaint::Join strokeJoin, SkScalar strokeMiterLimit) { + livePaintCount++; auto paint = new SkPaint(); paint->setAntiAlias(isAntiAlias); paint->setBlendMode(blendMode); @@ -33,6 +35,7 @@ SKWASM_EXPORT SkPaint* paint_create(bool isAntiAlias, } SKWASM_EXPORT void paint_dispose(SkPaint* paint) { + livePaintCount--; delete paint; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/path.cpp b/engine/src/flutter/lib/web_ui/skwasm/path.cpp index 1c8052c76e8..73d7fb31311 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/path.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/path.cpp @@ -4,6 +4,7 @@ #include "export.h" #include "helpers.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkString.h" #include "third_party/skia/include/pathops/SkPathOps.h" @@ -12,14 +13,17 @@ using namespace Skwasm; SKWASM_EXPORT SkPath* path_create() { + livePathCount++; return new SkPath(); } SKWASM_EXPORT void path_dispose(SkPath* path) { + livePathCount--; delete path; } SKWASM_EXPORT SkPath* path_copy(SkPath* path) { + livePathCount++; return new SkPath(*path); } @@ -187,6 +191,7 @@ SKWASM_EXPORT void path_getBounds(SkPath* path, SkRect* rect) { SKWASM_EXPORT SkPath* path_combine(SkPathOp operation, const SkPath* path1, const SkPath* path2) { + livePathCount++; SkPath* output = new SkPath(); if (Op(*path1, *path2, operation, output)) { output->setFillType(path1->getFillType()); @@ -198,6 +203,7 @@ SKWASM_EXPORT SkPath* path_combine(SkPathOp operation, } SKWASM_EXPORT SkString* path_getSvgString(SkPath* path) { + liveStringCount++; SkString* string = new SkString(SkParsePath::ToSVGString(*path)); return string; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/picture.cpp b/engine/src/flutter/lib/web_ui/skwasm/picture.cpp index aac6465cb4e..9596f1dca90 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/picture.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/picture.cpp @@ -4,6 +4,7 @@ #include "export.h" #include "helpers.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkBBHFactory.h" #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPictureRecorder.h" @@ -14,10 +15,12 @@ using namespace Skwasm; SkRTreeFactory bbhFactory; SKWASM_EXPORT SkPictureRecorder* pictureRecorder_create() { + livePictureRecorderCount++; return new SkPictureRecorder(); } SKWASM_EXPORT void pictureRecorder_dispose(SkPictureRecorder* recorder) { + livePictureRecorderCount--; delete recorder; } @@ -29,6 +32,7 @@ SKWASM_EXPORT SkCanvas* pictureRecorder_beginRecording( SKWASM_EXPORT SkPicture* pictureRecorder_endRecording( SkPictureRecorder* recorder) { + livePictureCount++; return recorder->finishRecordingAsPicture().release(); } @@ -37,6 +41,7 @@ SKWASM_EXPORT void picture_getCullRect(SkPicture* picture, SkRect* outRect) { } SKWASM_EXPORT void picture_dispose(SkPicture* picture) { + livePictureCount--; picture->unref(); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/shaders.cpp b/engine/src/flutter/lib/web_ui/skwasm/shaders.cpp index 18e15474705..824775f8be7 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/shaders.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/shaders.cpp @@ -4,6 +4,7 @@ #include "export.h" #include "helpers.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/effects/SkGradientShader.h" #include "third_party/skia/include/effects/SkRuntimeEffect.h" @@ -19,6 +20,7 @@ SKWASM_EXPORT SkShader* shader_createLinearGradient( SkTileMode tileMode, SkScalar* matrix33 // Can be nullptr ) { + liveShaderCount++; if (matrix33) { SkMatrix localMatrix = createMatrix(matrix33); return SkGradientShader::MakeLinear(endPoints, colors, stops, count, @@ -39,6 +41,7 @@ SKWASM_EXPORT SkShader* shader_createRadialGradient(SkScalar centerX, int count, SkTileMode tileMode, SkScalar* matrix33) { + liveShaderCount++; if (matrix33) { SkMatrix localMatrix = createMatrix(matrix33); return SkGradientShader::MakeRadial({centerX, centerY}, radius, colors, @@ -60,6 +63,7 @@ SKWASM_EXPORT SkShader* shader_createConicalGradient( int count, SkTileMode tileMode, SkScalar* matrix33) { + liveShaderCount++; if (matrix33) { SkMatrix localMatrix = createMatrix(matrix33); return SkGradientShader::MakeTwoPointConical( @@ -84,6 +88,7 @@ SKWASM_EXPORT SkShader* shader_createSweepGradient(SkScalar centerX, SkScalar startAngle, SkScalar endAngle, SkScalar* matrix33) { + liveShaderCount++; if (matrix33) { SkMatrix localMatrix = createMatrix(matrix33); return SkGradientShader::MakeSweep(centerX, centerY, colors, stops, count, @@ -99,10 +104,12 @@ SKWASM_EXPORT SkShader* shader_createSweepGradient(SkScalar centerX, } SKWASM_EXPORT void shader_dispose(SkShader* shader) { + liveShaderCount--; shader->unref(); } SKWASM_EXPORT SkRuntimeEffect* runtimeEffect_create(SkString* source) { + liveRuntimeEffectCount++; auto result = SkRuntimeEffect::MakeForShader(*source); if (result.effect == nullptr) { printf("Failed to compile shader. Error text:\n%s", @@ -114,6 +121,7 @@ SKWASM_EXPORT SkRuntimeEffect* runtimeEffect_create(SkString* source) { } SKWASM_EXPORT void runtimeEffect_dispose(SkRuntimeEffect* effect) { + liveRuntimeEffectCount--; effect->unref(); } @@ -126,6 +134,7 @@ SKWASM_EXPORT SkShader* shader_createRuntimeEffectShader( SkData* uniforms, SkShader** children, size_t childCount) { + liveShaderCount++; std::vector> childPointers; for (size_t i = 0; i < childCount; i++) { childPointers.emplace_back(sk_ref_sp(children[i])); @@ -142,6 +151,7 @@ SKWASM_EXPORT SkShader* shader_createFromImage(SkImage* image, SkTileMode tileModeY, FilterQuality quality, SkScalar* matrix33) { + liveShaderCount++; if (matrix33) { SkMatrix localMatrix = createMatrix(matrix33); return image diff --git a/engine/src/flutter/lib/web_ui/skwasm/string.cpp b/engine/src/flutter/lib/web_ui/skwasm/string.cpp index 59bef9823d8..fda897164aa 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/string.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/string.cpp @@ -3,10 +3,12 @@ // found in the LICENSE file. #include "export.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkString.h" SKWASM_EXPORT SkString* skString_allocate(size_t length) { + liveStringCount++; return new SkString(length); } @@ -19,10 +21,12 @@ SKWASM_EXPORT int skString_getLength(SkString* string) { } SKWASM_EXPORT void skString_free(SkString* string) { + liveStringCount--; return delete string; } SKWASM_EXPORT std::u16string* skString16_allocate(size_t length) { + liveString16Count++; std::u16string* string = new std::u16string(); string->resize(length); return string; @@ -33,5 +37,6 @@ SKWASM_EXPORT char16_t* skString16_getData(std::u16string* string) { } SKWASM_EXPORT void skString16_free(std::u16string* string) { + liveString16Count--; delete string; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/surface.cpp b/engine/src/flutter/lib/web_ui/skwasm/surface.cpp index cb91b10728e..2117e31d199 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/surface.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/surface.cpp @@ -5,6 +5,7 @@ #include "surface.h" #include #include +#include "live_objects.h" #include "skwasm_support.h" #include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h" @@ -234,6 +235,7 @@ SkwasmObject TextureSourceWrapper::getTextureSource() { } SKWASM_EXPORT Surface* surface_create() { + liveSurfaceCount++; return new Surface(); } @@ -248,6 +250,7 @@ SKWASM_EXPORT void surface_setCallbackHandler( } SKWASM_EXPORT void surface_destroy(Surface* surface) { + liveSurfaceCount--; // Dispatch to the worker skwasm_dispatchDisposeSurface(surface->getThreadId(), surface); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/text/line_metrics.cpp b/engine/src/flutter/lib/web_ui/skwasm/text/line_metrics.cpp index c163dc322de..b94bff0d72f 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/text/line_metrics.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/text/line_metrics.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "../export.h" +#include "../live_objects.h" #include "third_party/skia/modules/skparagraph/include/Paragraph.h" using namespace skia::textlayout; @@ -16,6 +17,7 @@ SKWASM_EXPORT LineMetrics* lineMetrics_create(bool hardBreak, double left, double baseline, size_t lineNumber) { + liveLineMetricsCount++; auto metrics = new LineMetrics(); metrics->fHardBreak = hardBreak; metrics->fAscent = ascent; @@ -30,6 +32,7 @@ SKWASM_EXPORT LineMetrics* lineMetrics_create(bool hardBreak, } SKWASM_EXPORT void lineMetrics_dispose(LineMetrics* metrics) { + liveLineMetricsCount--; delete metrics; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/text/paragraph.cpp b/engine/src/flutter/lib/web_ui/skwasm/text/paragraph.cpp index 0b94bdc03ba..1d96c7e0ae2 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/text/paragraph.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/text/paragraph.cpp @@ -4,6 +4,7 @@ #include "third_party/skia/modules/skparagraph/include/Paragraph.h" #include "../export.h" +#include "../live_objects.h" #include "DartTypes.h" #include "TextStyle.h" #include "include/core/SkScalar.h" @@ -11,6 +12,7 @@ using namespace skia::textlayout; SKWASM_EXPORT void paragraph_dispose(Paragraph* paragraph) { + liveParagraphCount--; delete paragraph; } @@ -125,6 +127,7 @@ SKWASM_EXPORT int paragraph_getLineNumberAt(Paragraph* paragraph, SKWASM_EXPORT LineMetrics* paragraph_getLineMetricsAtIndex(Paragraph* paragraph, size_t lineNumber) { + liveLineMetricsCount++; auto metrics = new LineMetrics(); if (paragraph->getLineMetricsAt(lineNumber, metrics)) { return metrics; @@ -139,6 +142,7 @@ struct TextBoxList { }; SKWASM_EXPORT void textBoxList_dispose(TextBoxList* list) { + liveTextBoxListCount--; delete list; } @@ -160,12 +164,14 @@ SKWASM_EXPORT TextBoxList* paragraph_getBoxesForRange( int end, RectHeightStyle heightStyle, RectWidthStyle widthStyle) { + liveTextBoxListCount++; return new TextBoxList{ paragraph->getRectsForRange(start, end, heightStyle, widthStyle)}; } SKWASM_EXPORT TextBoxList* paragraph_getBoxesForPlaceholders( Paragraph* paragraph) { + liveTextBoxListCount++; return new TextBoxList{paragraph->getRectsForPlaceholders()}; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp b/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp index d638f3e5b23..3cf25b12b0a 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "../export.h" +#include "../live_objects.h" #include "../wrappers.h" #include "third_party/skia/modules/skparagraph/include/ParagraphBuilder.h" #include "third_party/skia/modules/skunicode/include/SkUnicode_client.h" @@ -11,6 +12,7 @@ using namespace skia::textlayout; using namespace Skwasm; SKWASM_EXPORT void paragraphBuilder_dispose(ParagraphBuilder* builder) { + liveParagraphBuilderCount--; delete builder; } @@ -48,6 +50,7 @@ SKWASM_EXPORT void paragraphBuilder_pop(ParagraphBuilder* builder) { SKWASM_EXPORT std::vector* unicodePositionBuffer_create( size_t length) { + liveUnicodePositionBufferCount++; return new std::vector(length); } @@ -58,11 +61,13 @@ SKWASM_EXPORT SkUnicode::Position* unicodePositionBuffer_getDataPointer( SKWASM_EXPORT void unicodePositionBuffer_free( std::vector* buffer) { + liveUnicodePositionBufferCount--; delete buffer; } SKWASM_EXPORT std::vector* lineBreakBuffer_create( size_t length) { + liveLineBreakBufferCount++; return new std::vector( length, {0, SkUnicode::LineBreakType::kSoftLineBreak}); } @@ -74,5 +79,6 @@ SKWASM_EXPORT SkUnicode::LineBreakBefore* lineBreakBuffer_getDataPointer( SKWASM_EXPORT void lineBreakBuffer_free( std::vector* buffer) { + liveLineBreakBufferCount--; delete buffer; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder_builtin_icu.cpp b/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder_builtin_icu.cpp index bccc1c3b291..e31ddef45d9 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder_builtin_icu.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder_builtin_icu.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "../export.h" +#include "../live_objects.h" #include "../wrappers.h" #include "modules/skunicode/include/SkUnicode_icu.h" #include "third_party/skia/modules/skparagraph/include/ParagraphBuilder.h" @@ -17,12 +18,14 @@ SKWASM_EXPORT bool skwasm_isHeavy() { SKWASM_EXPORT ParagraphBuilder* paragraphBuilder_create( ParagraphStyle* style, FlutterFontCollection* collection) { + liveParagraphBuilderCount++; return ParagraphBuilder::make(*style, collection->collection, SkUnicodes::ICU::Make()) .release(); } SKWASM_EXPORT Paragraph* paragraphBuilder_build(ParagraphBuilder* builder) { + liveParagraphCount++; return builder->Build().release(); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder_client_icu.cpp b/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder_client_icu.cpp index a157afc10ac..5dfcb7b10e1 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder_client_icu.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/text/paragraph_builder_client_icu.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "../export.h" +#include "../live_objects.h" #include "../wrappers.h" #include "third_party/skia/modules/skparagraph/include/ParagraphBuilder.h" #include "third_party/skia/modules/skunicode/include/SkUnicode_client.h" @@ -17,11 +18,13 @@ SKWASM_EXPORT bool skwasm_isHeavy() { SKWASM_EXPORT ParagraphBuilder* paragraphBuilder_create( ParagraphStyle* style, FlutterFontCollection* collection) { + liveParagraphBuilderCount++; return ParagraphBuilder::make(*style, collection->collection, nullptr) .release(); } SKWASM_EXPORT Paragraph* paragraphBuilder_build(ParagraphBuilder* builder) { + liveParagraphCount++; auto [words, graphemeBreaks, lineBreaks] = builder->getClientICUData(); auto text = builder->getText(); sk_sp clientICU = diff --git a/engine/src/flutter/lib/web_ui/skwasm/text/strut_style.cpp b/engine/src/flutter/lib/web_ui/skwasm/text/strut_style.cpp index 6d1de9b44cb..32de4f02abe 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/text/strut_style.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/text/strut_style.cpp @@ -3,17 +3,20 @@ // found in the LICENSE file. #include "../export.h" +#include "../live_objects.h" #include "third_party/skia/modules/skparagraph/include/Paragraph.h" using namespace skia::textlayout; SKWASM_EXPORT StrutStyle* strutStyle_create() { + liveStrutStyleCount++; auto style = new StrutStyle(); style->setStrutEnabled(true); return style; } SKWASM_EXPORT void strutStyle_dispose(StrutStyle* style) { + liveStrutStyleCount--; delete style; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/text/text_style.cpp b/engine/src/flutter/lib/web_ui/skwasm/text/text_style.cpp index 06171a25595..32585589082 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/text/text_style.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/text/text_style.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "../export.h" +#include "../live_objects.h" #include "../wrappers.h" #include "third_party/skia/modules/skparagraph/include/Paragraph.h" @@ -12,6 +13,7 @@ using namespace skia::textlayout; using namespace Skwasm; SKWASM_EXPORT TextStyle* textStyle_create() { + liveTextStyleCount++; auto style = new TextStyle(); // Default color in flutter is black. @@ -20,10 +22,12 @@ SKWASM_EXPORT TextStyle* textStyle_create() { } SKWASM_EXPORT TextStyle* textStyle_copy(TextStyle* style) { + liveTextStyleCount++; return new TextStyle(*style); } SKWASM_EXPORT void textStyle_dispose(TextStyle* style) { + liveTextStyleCount--; delete style; } diff --git a/engine/src/flutter/lib/web_ui/skwasm/vertices.cpp b/engine/src/flutter/lib/web_ui/skwasm/vertices.cpp index caf187f1c7e..2490653902f 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/vertices.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/vertices.cpp @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "export.h" +#include "live_objects.h" #include "third_party/skia/include/core/SkVertices.h" @@ -13,11 +14,13 @@ SKWASM_EXPORT SkVertices* vertices_create(SkVertices::VertexMode vertexMode, SkColor* colors, int indexCount, uint16_t* indices) { + liveVerticesCount++; return SkVertices::MakeCopy(vertexMode, vertexCount, positions, textureCoordinates, colors, indexCount, indices) .release(); } SKWASM_EXPORT void vertices_dispose(SkVertices* vertices) { + liveVerticesCount--; vertices->unref(); }