From 1fa3760127a44fd44cbda4b7ee0aa9ccc172e011 Mon Sep 17 00:00:00 2001 From: bofeng Date: Thu, 14 Dec 2023 14:04:38 +0800 Subject: [PATCH 1/6] 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(); From 81413aad13d2284dba47230a4eaddffd23deee58 Mon Sep 17 00:00:00 2001 From: bofeng Date: Thu, 14 Dec 2023 14:06:51 +0800 Subject: [PATCH 2/6] refine --- cocos/spine/skeleton-cache.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cocos/spine/skeleton-cache.ts b/cocos/spine/skeleton-cache.ts index 13cb1afcb4f..0ea64aca0bb 100644 --- a/cocos/spine/skeleton-cache.ts +++ b/cocos/spine/skeleton-cache.ts @@ -347,15 +347,8 @@ class SkeletonCache { 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; } From 2804b5750a3a3b7f74415c04e621318f198f9f64 Mon Sep 17 00:00:00 2001 From: bofeng Date: Fri, 15 Dec 2023 15:22:19 +0800 Subject: [PATCH 3/6] refine --- cocos/spine/skeleton-cache.ts | 36 ++++++++++++++++++++++------------- cocos/spine/skeleton.ts | 14 ++++++++------ 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/cocos/spine/skeleton-cache.ts b/cocos/spine/skeleton-cache.ts index 0ea64aca0bb..72287d53716 100644 --- a/cocos/spine/skeleton-cache.ts +++ b/cocos/spine/skeleton-cache.ts @@ -342,17 +342,24 @@ class SkeletonCache { } } - public removeSkeleton (uuid: string, skeletonComponent: Skeleton): void { - const sharedInstances = this._sharedCacheMap.get(uuid); - if (sharedInstances) { - const index = sharedInstances.indexOf(skeletonComponent); - if (index !== -1) { - sharedInstances.splice(index, 1); - } - if (sharedInstances.length > 0) { - return; + public removeSkeleton (skeletonComponent: Skeleton): void { + const uuid = skeletonComponent.skeletonData?.uuid; + if (!uuid) { + return; + } + const isSharedOperate = this === SkeletonCache.sharedCache; + if (isSharedOperate) { + const sharedInstances = this._sharedCacheMap.get(uuid); + if (sharedInstances) { + const index = sharedInstances.indexOf(skeletonComponent); + if (index !== -1) { + sharedInstances.splice(index, 1); + } + if (sharedInstances.length > 0) { + return; + } + this._sharedCacheMap.delete(uuid); } - this._sharedCacheMap.delete(uuid); } const sharedOperate = (aniKey: string, animationCache: AnimationCache): void => { @@ -362,7 +369,7 @@ class SkeletonCache { const privateOperate = (aniKey: string, animationCache: AnimationCache): void => { animationCache.destroy(); }; - const operate = sharedInstances ? sharedOperate : privateOperate; + const operate = isSharedOperate ? sharedOperate : privateOperate; const skeletonInfo = this._skeletonCache[uuid]; if (!skeletonInfo) return; @@ -381,7 +388,10 @@ class SkeletonCache { delete this._skeletonCache[uuid]; } - public getSkeletonCache (uuid: string, skeletonData: spine.SkeletonData, skeletonComponent: Skeleton): SkeletonCacheItemInfo { + public getOrCreateSkeletonInfo (skeletonComponent: Skeleton): SkeletonCacheItemInfo { + const skeletonData = skeletonComponent.skeletonData; + const uuid = skeletonData!.uuid; + const runtimeData = skeletonData!.getRuntimeData(); if (SkeletonCache.sharedCache === this) { let sharedInstances = this._sharedCacheMap.get(uuid); if (!sharedInstances) { @@ -394,7 +404,7 @@ class SkeletonCache { } let skeletonInfo = this._skeletonCache[uuid]; if (!skeletonInfo) { - const skeleton = new spine.Skeleton(skeletonData); + const skeleton = new spine.Skeleton(runtimeData!); const clipper = null; const state = null; const listener = new TrackEntryListeners(); diff --git a/cocos/spine/skeleton.ts b/cocos/spine/skeleton.ts index 3a9b1098cd6..d43d5998d4d 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); + this._skeletonCache.removeSkeleton(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); + this._skeletonCache.removeSkeleton(this); } super.onDestroy(); } @@ -788,10 +788,8 @@ export class Skeleton extends UIRenderer { if (this.debugBones || this.debugSlots) { warn('Debug bones or slots is invalid in cached mode'); } - if (this.skeletonData) { - const skeletonInfo = this._skeletonCache!.getSkeletonCache(this.skeletonData.uuid, skeletonData, this); - this._skeleton = skeletonInfo.skeleton!; - } + const skeletonInfo = this._skeletonCache!.getOrCreateSkeletonInfo(this); + this._skeleton = skeletonInfo.skeleton!; } else { this._skeleton = this._instance.initSkeleton(skeletonData); this._state = this._instance.getAnimationState(); @@ -1316,6 +1314,10 @@ export class Skeleton extends UIRenderer { if (this._instance) { this._instance.isCache = this.isAnimationCached(); } + if (this._skeletonCache) { + this._skeletonCache.removeSkeleton(this); + this._skeletonCache = null; + } this._updateSkeletonData(); this.markForUpdateRenderData(); } From 9de0f588fe52605ba7c5f3e7766e00555732cb35 Mon Sep 17 00:00:00 2001 From: bofeng Date: Fri, 15 Dec 2023 16:31:51 +0800 Subject: [PATCH 4/6] refine --- cocos/spine/skeleton-cache.ts | 88 +++++++++++++++++------------------ cocos/spine/skeleton.ts | 41 ++++++++++------ 2 files changed, 70 insertions(+), 59 deletions(-) diff --git a/cocos/spine/skeleton-cache.ts b/cocos/spine/skeleton-cache.ts index 72287d53716..911c13ef4a3 100644 --- a/cocos/spine/skeleton-cache.ts +++ b/cocos/spine/skeleton-cache.ts @@ -53,6 +53,7 @@ export interface SkeletonCacheItemInfo { listener: TrackEntryListeners; curAnimationCache: AnimationCache | null; animationsCache: { [key: string]: AnimationCache }; + assetUUID: string; } class SpineModel { @@ -314,7 +315,7 @@ class SkeletonCache { //for shared mode only protected _animationPool: { [key: string]: AnimationCache }; - private _sharedCacheMap: Map> = new Map>(); + private _sharedCacheMap: Map = new Map(); constructor () { this._privateMode = false; this._animationPool = {}; @@ -342,28 +343,21 @@ class SkeletonCache { } } - public removeSkeleton (skeletonComponent: Skeleton): void { - const uuid = skeletonComponent.skeletonData?.uuid; - if (!uuid) { - return; - } + public destroySkeleton (assetUuid: string): void { const isSharedOperate = this === SkeletonCache.sharedCache; if (isSharedOperate) { - const sharedInstances = this._sharedCacheMap.get(uuid); - if (sharedInstances) { - const index = sharedInstances.indexOf(skeletonComponent); - if (index !== -1) { - sharedInstances.splice(index, 1); - } - if (sharedInstances.length > 0) { + let refCount = this._sharedCacheMap.get(assetUuid); + if (refCount) { + refCount -= 1; + if (refCount > 0) { return; } - this._sharedCacheMap.delete(uuid); + this._sharedCacheMap.delete(assetUuid); } } const sharedOperate = (aniKey: string, animationCache: AnimationCache): void => { - this._animationPool[`${uuid}#${aniKey}`] = animationCache; + this._animationPool[`${assetUuid}#${aniKey}`] = animationCache; animationCache.clear(); }; const privateOperate = (aniKey: string, animationCache: AnimationCache): void => { @@ -371,7 +365,7 @@ class SkeletonCache { }; const operate = isSharedOperate ? sharedOperate : privateOperate; - const skeletonInfo = this._skeletonCache[uuid]; + const skeletonInfo = this._skeletonCache[assetUuid]; if (!skeletonInfo) return; const animationsCache = skeletonInfo.animationsCache; for (const aniKey in animationsCache) { @@ -385,44 +379,46 @@ class SkeletonCache { if (skeletonInfo.skeleton) { spine.wasmUtil.destroySpineSkeleton(skeletonInfo.skeleton); } - delete this._skeletonCache[uuid]; + delete this._skeletonCache[assetUuid]; } - public getOrCreateSkeletonInfo (skeletonComponent: Skeleton): SkeletonCacheItemInfo { - const skeletonData = skeletonComponent.skeletonData; - const uuid = skeletonData!.uuid; - const runtimeData = skeletonData!.getRuntimeData(); + public createSkeletonInfo (skeletonAsset: SkeletonData): SkeletonCacheItemInfo { + const uuid = skeletonAsset.uuid; + const runtimeData = skeletonAsset.getRuntimeData(); 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 refCount = this._sharedCacheMap.get(uuid); + if (!refCount) { + refCount = 1; + } else { + refCount += 1; } + this._sharedCacheMap.set(uuid, refCount); } - let skeletonInfo = this._skeletonCache[uuid]; - if (!skeletonInfo) { - const skeleton = new spine.Skeleton(runtimeData!); - const clipper = null; - const state = null; - const listener = new TrackEntryListeners(); - - this._skeletonCache[uuid] = skeletonInfo = { - skeleton, - clipper, - state, - listener, - // Cache all kinds of animation frame. - // When skeleton is dispose, clear all animation cache. - animationsCache: {} as any, - curAnimationCache: null, - }; - } + + const skeleton = new spine.Skeleton(runtimeData!); + const clipper = null; + const state = null; + const listener = new TrackEntryListeners(); + + const skeletonInfo = this._skeletonCache[uuid] = { + skeleton, + clipper, + state, + listener, + // Cache all kinds of animation frame. + // When skeleton is dispose, clear all animation cache. + animationsCache: {} as any, + curAnimationCache: null, + assetUUID: uuid, + }; return skeletonInfo; } + public getSkeletonInfo (skeletonAsset: SkeletonData): null | SkeletonCacheItemInfo { + const uuid = skeletonAsset.uuid; + return this._skeletonCache[uuid]; + } + public getAnimationCache (uuid: string, animationName: string): null | AnimationCache { const skeletonInfo = this._skeletonCache[uuid]; if (!skeletonInfo) return null; diff --git a/cocos/spine/skeleton.ts b/cocos/spine/skeleton.ts index d43d5998d4d..64b270e14ab 100644 --- a/cocos/spine/skeleton.ts +++ b/cocos/spine/skeleton.ts @@ -41,7 +41,7 @@ import { AttachUtil } from './attach-util'; import { SPINE_WASM } from './lib/instantiated'; import spine from './lib/spine-core.js'; import { VertexEffectDelegate } from './vertex-effect-delegate'; -import SkeletonCache, { AnimationCache, AnimationFrame } from './skeleton-cache'; +import SkeletonCache, { AnimationCache, AnimationFrame, SkeletonCacheItemInfo } from './skeleton-cache'; import { TrackEntryListeners } from './track-entry-listeners'; import { setPropertyEnumType } from '../core/internal-index'; @@ -240,6 +240,7 @@ export class Skeleton extends UIRenderer { protected _instance: spine.SkeletonInstance = null!; protected _state: spine.AnimationState = null!; protected _textures: Texture2D[] = []; + private _skeletonInfo: SkeletonCacheItemInfo | null = null; // Animation name protected _animationName = ''; protected _skinName = ''; @@ -353,9 +354,6 @@ export class Skeleton extends UIRenderer { set skeletonData (value: SkeletonData | null) { if (value) value.resetEnums(); if (this._skeletonData !== value) { - if (this._skeletonCache && this._skeletonData) { - this._skeletonCache.removeSkeleton(this); - } this.destroyRenderData(); this._skeletonData = value as any; this.defaultSkin = ''; @@ -715,11 +713,11 @@ export class Skeleton extends UIRenderer { if (!JSB) { spine.SkeletonSystem.destroySpineInstance(this._instance); } - if (this._skeletonCache && this._skeletonData) { - this._skeletonCache.removeSkeleton(this); - } + this._destroySkeletonInfo(this._skeletonCache); + this._skeletonCache = null; super.onDestroy(); } + /** * @en Clear animation and set to setup pose. * @zh 清除动画并还原到初始姿势。 @@ -777,19 +775,33 @@ export class Skeleton extends UIRenderer { */ public setSkeletonData (skeletonData: spine.SkeletonData): void { if (!EDITOR_NOT_IN_PREVIEW) { + const preSkeletonCache = this._skeletonCache; if (this._cacheMode === AnimationCacheMode.SHARED_CACHE) { this._skeletonCache = SkeletonCache.sharedCache; } else if (this._cacheMode === AnimationCacheMode.PRIVATE_CACHE) { this._skeletonCache = new SkeletonCache(); this._skeletonCache.enablePrivateMode(); + } else { + this._skeletonCache = null; + } + //cache mode may be changed + if (preSkeletonCache !== this._skeletonCache) { + this._destroySkeletonInfo(preSkeletonCache); } } if (this.isAnimationCached()) { if (this.debugBones || this.debugSlots) { warn('Debug bones or slots is invalid in cached mode'); } - const skeletonInfo = this._skeletonCache!.getOrCreateSkeletonInfo(this); - this._skeleton = skeletonInfo.skeleton!; + let skeletonInfo = this._skeletonCache!.getSkeletonInfo(this._skeletonData!); + if (this._skeletonInfo !== skeletonInfo) { + this._destroySkeletonInfo(this._skeletonCache); + if (!skeletonInfo) { + skeletonInfo = this._skeletonCache!.createSkeletonInfo(this._skeletonData!); + } + this._skeletonInfo = skeletonInfo; + this._skeleton = this._skeletonInfo.skeleton!; + } } else { this._skeleton = this._instance.initSkeleton(skeletonData); this._state = this._instance.getAnimationState(); @@ -1314,10 +1326,6 @@ export class Skeleton extends UIRenderer { if (this._instance) { this._instance.isCache = this.isAnimationCached(); } - if (this._skeletonCache) { - this._skeletonCache.removeSkeleton(this); - this._skeletonCache = null; - } this._updateSkeletonData(); this.markForUpdateRenderData(); } @@ -1847,6 +1855,13 @@ export class Skeleton extends UIRenderer { } this._instance.setSlotTexture(slotName, textureID); } + + private _destroySkeletonInfo (skeletonCache: SkeletonCache | null): void { + if (skeletonCache && this._skeletonInfo) { + skeletonCache.destroySkeleton(this._skeletonInfo.assetUUID); + this._skeletonInfo = null; + } + } } legacyCC.internal.SpineSkeleton = Skeleton; From e04805585a1b442d55000f5f38cacb916d76db13 Mon Sep 17 00:00:00 2001 From: bofeng Date: Fri, 15 Dec 2023 16:58:04 +0800 Subject: [PATCH 5/6] set external config version --- native/external-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/external-config.json b/native/external-config.json index 2531b1bbc80..89a1e20ef94 100644 --- a/native/external-config.json +++ b/native/external-config.json @@ -3,6 +3,6 @@ "type": "github", "owner": "cocos-creator", "name": "engine-native-external", - "checkout": "v3.8.2-21" + "checkout": "v3.8.2-22" } } \ No newline at end of file From c75985fa4944717691019cf8fa14332ee20a2072 Mon Sep 17 00:00:00 2001 From: bofeng Date: Fri, 15 Dec 2023 17:43:40 +0800 Subject: [PATCH 6/6] refine --- cocos/spine/skeleton-cache.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cocos/spine/skeleton-cache.ts b/cocos/spine/skeleton-cache.ts index 911c13ef4a3..9d71d88fb98 100644 --- a/cocos/spine/skeleton-cache.ts +++ b/cocos/spine/skeleton-cache.ts @@ -315,6 +315,7 @@ class SkeletonCache { //for shared mode only protected _animationPool: { [key: string]: AnimationCache }; + //for shared mode only, key is asset uuid and value is ref count. private _sharedCacheMap: Map = new Map(); constructor () { this._privateMode = false; @@ -344,8 +345,7 @@ class SkeletonCache { } public destroySkeleton (assetUuid: string): void { - const isSharedOperate = this === SkeletonCache.sharedCache; - if (isSharedOperate) { + if (!this._privateMode) { let refCount = this._sharedCacheMap.get(assetUuid); if (refCount) { refCount -= 1; @@ -363,7 +363,7 @@ class SkeletonCache { const privateOperate = (aniKey: string, animationCache: AnimationCache): void => { animationCache.destroy(); }; - const operate = isSharedOperate ? sharedOperate : privateOperate; + const operate = this._privateMode ? privateOperate : sharedOperate; const skeletonInfo = this._skeletonCache[assetUuid]; if (!skeletonInfo) return; @@ -385,7 +385,7 @@ class SkeletonCache { public createSkeletonInfo (skeletonAsset: SkeletonData): SkeletonCacheItemInfo { const uuid = skeletonAsset.uuid; const runtimeData = skeletonAsset.getRuntimeData(); - if (SkeletonCache.sharedCache === this) { + if (!this._privateMode) { let refCount = this._sharedCacheMap.get(uuid); if (!refCount) { refCount = 1;