From 1fa3760127a44fd44cbda4b7ee0aa9ccc172e011 Mon Sep 17 00:00:00 2001 From: bofeng Date: Thu, 14 Dec 2023 14:04:38 +0800 Subject: [PATCH] Refine: make multi skeleton component shared one instance of spine.Skeleton while spine working at sharedCache mode --- cocos/spine/lib/spine-core.d.ts | 1 + cocos/spine/skeleton-cache.ts | 54 +++++++++++++++++-- cocos/spine/skeleton.ts | 9 ++-- .../spine-wasm/spine-type-export.cpp | 1 + .../editor-support/spine-wasm/spine-wasm.cpp | 6 +++ .../editor-support/spine-wasm/spine-wasm.h | 1 + 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/cocos/spine/lib/spine-core.d.ts b/cocos/spine/lib/spine-core.d.ts index 9fdecf2ed5b..8211706e3be 100644 --- a/cocos/spine/lib/spine-core.d.ts +++ b/cocos/spine/lib/spine-core.d.ts @@ -1220,6 +1220,7 @@ declare namespace spine { static createSpineSkeletonDataWithBinary(byteSize: number, atlasText: string): SkeletonData; static registerSpineSkeletonDataWithUUID(data: SkeletonData, uuid: string); static destroySpineSkeletonDataWithUUID(uuid: string); + static destroySpineSkeleton(skeleton: Skeleton): void; static getCurrentListenerID(): number; static getCurrentEventType(): EventType; static getCurrentTrackEntry(): TrackEntry; diff --git a/cocos/spine/skeleton-cache.ts b/cocos/spine/skeleton-cache.ts index c39e8d76f83..13cb1afcb4f 100644 --- a/cocos/spine/skeleton-cache.ts +++ b/cocos/spine/skeleton-cache.ts @@ -28,6 +28,7 @@ import { SPINE_WASM } from './lib/instantiated'; import spine from './lib/spine-core.js'; import { SkeletonData } from './skeleton-data'; import { warn } from '../core/platform/debug'; +import { Skeleton } from './skeleton'; const MaxCacheTime = 30; const FrameTime = 1 / 60; @@ -310,7 +311,10 @@ class SkeletonCache { protected _privateMode: boolean; protected _skeletonCache: { [key: string]: SkeletonCacheItemInfo }; + + //for shared mode only protected _animationPool: { [key: string]: AnimationCache }; + private _sharedCacheMap: Map> = new Map>(); constructor () { this._privateMode = false; this._animationPool = {}; @@ -338,7 +342,35 @@ class SkeletonCache { } } - public removeSkeleton (uuid: string): void { + public removeSkeleton (uuid: string, skeletonComponent: Skeleton): void { + const sharedInstances = this._sharedCacheMap.get(uuid); + if (sharedInstances) { + const index = sharedInstances.indexOf(skeletonComponent); + if (index !== -1) { + console.log('bf test delete index=', index); + sharedInstances.splice(index, 1); + } + sharedInstances.forEach((skeleton) => { + if (skeleton === skeletonComponent) { + console.log('bf test 0000index=', skeleton); + } + }); + console.log('bf test index=', index); + if (sharedInstances.length > 0) { + return; + } + this._sharedCacheMap.delete(uuid); + } + + const sharedOperate = (aniKey: string, animationCache: AnimationCache): void => { + this._animationPool[`${uuid}#${aniKey}`] = animationCache; + animationCache.clear(); + }; + const privateOperate = (aniKey: string, animationCache: AnimationCache): void => { + animationCache.destroy(); + }; + const operate = sharedInstances ? sharedOperate : privateOperate; + const skeletonInfo = this._skeletonCache[uuid]; if (!skeletonInfo) return; const animationsCache = skeletonInfo.animationsCache; @@ -347,17 +379,29 @@ class SkeletonCache { // No need to create TypedArray next time. const animationCache = animationsCache[aniKey]; if (!animationCache) continue; - this._animationPool[`${uuid}#${aniKey}`] = animationCache; - animationCache.clear(); + operate(aniKey, animationCache); } + if (skeletonInfo.skeleton) { + spine.wasmUtil.destroySpineSkeleton(skeletonInfo.skeleton); + } delete this._skeletonCache[uuid]; } - public getSkeletonCache (uuid: string, skeletonData: spine.SkeletonData): SkeletonCacheItemInfo { + public getSkeletonCache (uuid: string, skeletonData: spine.SkeletonData, skeletonComponent: Skeleton): SkeletonCacheItemInfo { + if (SkeletonCache.sharedCache === this) { + let sharedInstances = this._sharedCacheMap.get(uuid); + if (!sharedInstances) { + sharedInstances = new Array(); + this._sharedCacheMap.set(uuid, sharedInstances); + } + if (sharedInstances.indexOf(skeletonComponent) === -1) { + sharedInstances.push(skeletonComponent); + } + } let skeletonInfo = this._skeletonCache[uuid]; if (!skeletonInfo) { - const skeleton = null; + const skeleton = new spine.Skeleton(skeletonData); const clipper = null; const state = null; const listener = new TrackEntryListeners(); diff --git a/cocos/spine/skeleton.ts b/cocos/spine/skeleton.ts index 6821f129b73..3a9b1098cd6 100644 --- a/cocos/spine/skeleton.ts +++ b/cocos/spine/skeleton.ts @@ -354,7 +354,7 @@ export class Skeleton extends UIRenderer { if (value) value.resetEnums(); if (this._skeletonData !== value) { if (this._skeletonCache && this._skeletonData) { - this._skeletonCache.removeSkeleton(this._skeletonData.uuid); + this._skeletonCache.removeSkeleton(this._skeletonData.uuid, this); } this.destroyRenderData(); this._skeletonData = value as any; @@ -716,7 +716,7 @@ export class Skeleton extends UIRenderer { spine.SkeletonSystem.destroySpineInstance(this._instance); } if (this._skeletonCache && this._skeletonData) { - this._skeletonCache.removeSkeleton(this._skeletonData.uuid); + this._skeletonCache.removeSkeleton(this._skeletonData.uuid, this); } super.onDestroy(); } @@ -789,10 +789,7 @@ export class Skeleton extends UIRenderer { warn('Debug bones or slots is invalid in cached mode'); } if (this.skeletonData) { - const skeletonInfo = this._skeletonCache!.getSkeletonCache(this.skeletonData.uuid, skeletonData); - if (!skeletonInfo.skeleton) { - skeletonInfo.skeleton = this._instance.initSkeleton(skeletonData); - } + const skeletonInfo = this._skeletonCache!.getSkeletonCache(this.skeletonData.uuid, skeletonData, this); this._skeleton = skeletonInfo.skeleton!; } } else { diff --git a/native/cocos/editor-support/spine-wasm/spine-type-export.cpp b/native/cocos/editor-support/spine-wasm/spine-type-export.cpp index 7fbb4e71557..83133336b98 100644 --- a/native/cocos/editor-support/spine-wasm/spine-type-export.cpp +++ b/native/cocos/editor-support/spine-wasm/spine-type-export.cpp @@ -1626,6 +1626,7 @@ EMSCRIPTEN_BINDINGS(cocos_spine) { .class_function("createSpineSkeletonDataWithBinary", &SpineWasmUtil::createSpineSkeletonDataWithBinary, allow_raw_pointers()) .class_function("registerSpineSkeletonDataWithUUID", &SpineWasmUtil::registerSpineSkeletonDataWithUUID, allow_raw_pointers()) .class_function("destroySpineSkeletonDataWithUUID", &SpineWasmUtil::destroySpineSkeletonDataWithUUID) + .class_function("destroySpineSkeleton", &SpineWasmUtil::destroySpineSkeleton, allow_raw_pointers()) .class_function("getCurrentListenerID", &SpineWasmUtil::getCurrentListenerID) .class_function("getCurrentEventType", &SpineWasmUtil::getCurrentEventType) .class_function("getCurrentTrackEntry", &SpineWasmUtil::getCurrentTrackEntry, allow_raw_pointers()) diff --git a/native/cocos/editor-support/spine-wasm/spine-wasm.cpp b/native/cocos/editor-support/spine-wasm/spine-wasm.cpp index ec59ef8b939..4fa26f2004b 100644 --- a/native/cocos/editor-support/spine-wasm/spine-wasm.cpp +++ b/native/cocos/editor-support/spine-wasm/spine-wasm.cpp @@ -82,6 +82,12 @@ void SpineWasmUtil::destroySpineSkeletonDataWithUUID(const std::string& uuid) { } } +void SpineWasmUtil::destroySpineSkeleton(Skeleton* skeleton) { + if (skeleton) { + delete skeleton; + } +} + uint32_t SpineWasmUtil::queryStoreMemory(uint32_t size) { if (s_mem) { if (s_memSize < size) { diff --git a/native/cocos/editor-support/spine-wasm/spine-wasm.h b/native/cocos/editor-support/spine-wasm/spine-wasm.h index e1e0cb6fb66..993e2c97eca 100644 --- a/native/cocos/editor-support/spine-wasm/spine-wasm.h +++ b/native/cocos/editor-support/spine-wasm/spine-wasm.h @@ -18,6 +18,7 @@ class SpineWasmUtil { static SkeletonData* createSpineSkeletonDataWithBinary(uint32_t byteSize, const std::string& altasStr); static void registerSpineSkeletonDataWithUUID(SkeletonData* data, const std::string& uuid); static void destroySpineSkeletonDataWithUUID(const std::string& uuid); + static void destroySpineSkeleton(Skeleton* skeleton); static uint32_t getCurrentListenerID(); static EventType getCurrentEventType();