Skip to content

Commit

Permalink
Fix spine cache mode memory leak.
Browse files Browse the repository at this point in the history
  • Loading branch information
Canvasfull committed Oct 11, 2023
1 parent 63639b0 commit 7f217c2
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 46 deletions.
2 changes: 0 additions & 2 deletions cocos/spine/assembler/simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
THE SOFTWARE.
*/

import { UIRenderable } from '../../2d';
import { IAssembler } from '../../2d/renderer/base';

import { Batcher2D } from '../../2d/renderer/batcher-2d';
Expand All @@ -36,7 +35,6 @@ import { director } from '../../game';
import spine from '../lib/spine-core.js';
import { Color, Vec3 } from '../../core';
import { MaterialInstance } from '../../render-scene';
import { SkeletonSystem } from '../skeleton-system';

const _slotColor = new Color(0, 0, 255, 255);
const _boneColor = new Color(255, 0, 0, 255);
Expand Down
13 changes: 7 additions & 6 deletions cocos/spine/attach-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { Mat4 } from '../core';
import { Skeleton } from './skeleton';
import { Node } from '../scene-graph';
import spine from './lib/spine-core';
import { FrameBoneInfo } from './skeleton-cache';

const tempMat4 = new Mat4();

Expand All @@ -36,8 +37,8 @@ const tempMat4 = new Mat4();
*/
export class AttachUtil {
protected isInitialized = false;
protected skeletonBones: spine.Bone[] | FrameBoneInfo[] | undefined;
protected socketNodes: Map<number, Node> | undefined;
protected skeletonBones: spine.Bone[] | FrameBoneInfo[] | null = null;
protected socketNodes: Map<number, Node> | null = null;
private keysToDelete: number[] = [];

constructor () {
Expand All @@ -46,20 +47,20 @@ export class AttachUtil {

init (skeletonComp: Skeleton): void {
this.isInitialized = false;
if (!skeletonComp || skeletonComp.socketNodes.size === 0) return;
if (!skeletonComp || skeletonComp.socketNodes?.size === 0) return;
const isCached = skeletonComp.isAnimationCached();
this.skeletonBones = isCached && skeletonComp._curFrame ? skeletonComp._curFrame.boneInfos : skeletonComp._skeleton.bones;
if (!this.skeletonBones || this.skeletonBones.length < 1) return;
this.socketNodes = skeletonComp.socketNodes;
if (this.socketNodes.size <= 0) return;
if (!this.socketNodes || this.socketNodes.size <= 0) return;
this.isInitialized = true;
this._syncAttachedNode();
}

reset (): void {
this.isInitialized = false;
this.skeletonBones = undefined;
this.socketNodes = undefined;
this.skeletonBones = null;
this.socketNodes = null;
this.keysToDelete.length = 0;
}

Expand Down
31 changes: 15 additions & 16 deletions cocos/spine/skeleton-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const _useTint = true;
const _byteStrideOneColor = getAttributeStride(vfmtPosUvColor4B);
const _byteStrideTwoColor = getAttributeStride(vfmtPosUvTwoColor4B);

class FrameBoneInfo {
export class FrameBoneInfo {
a = 0;
b = 0;
c = 0;
Expand All @@ -46,9 +46,9 @@ class FrameBoneInfo {
}

export interface SkeletonCacheItemInfo {
skeleton: spine.Skeleton;
clipper: spine.SkeletonClipping;
state: spine.AnimationState;
skeleton: spine.Skeleton | null;
clipper: spine.SkeletonClipping | null;
state: spine.AnimationState | null;
listener: TrackEntryListeners;
curAnimationCache: AnimationCache | null;
animationsCache: { [key: string]: AnimationCache };
Expand Down Expand Up @@ -97,6 +97,7 @@ export class AnimationCache {
this._inited = false;
this._invalid = true;
this._instance = new spine.SkeletonInstance();
this._instance.isCache = true;
this._skeletonData = data;
this._skeleton = this._instance.initSkeleton(data);
this._instance.setUseTint(_useTint);
Expand Down Expand Up @@ -169,19 +170,17 @@ export class AnimationCache {
const vUint8Buf = new Uint8Array(Float32Array.BYTES_PER_ELEMENT * floatStride * vc);
const iUint16Buf = new Uint16Array(ic);

const HEAPU8 = spine.wasmUtil.wasm.HEAPU8;
const vPtr = model.vPtr;
const vLength = vc * Float32Array.BYTES_PER_ELEMENT * floatStride;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const vData = spine.wasmUtil.wasm.HEAPU8.subarray(vPtr, vPtr + vLength);

vUint8Buf.set(vData);
vUint8Buf.set(HEAPU8.subarray(vPtr, vPtr + vLength));

Check failure on line 177 in cocos/spine/skeleton-cache.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Unsafe argument of type `any` assigned to a parameter of type `ArrayLike<number>`

const iPtr = model.iPtr;
const iLength = Uint16Array.BYTES_PER_ELEMENT * ic;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const iData = spine.wasmUtil.wasm.HEAPU8.subarray(iPtr, iPtr + iLength);
const iUint8Buf = new Uint8Array(iUint16Buf.buffer);
iUint8Buf.set(iData);
iUint8Buf.set(HEAPU8.subarray(iPtr, iPtr + iLength));

Check failure on line 183 in cocos/spine/skeleton-cache.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Unsafe argument of type `any` assigned to a parameter of type `ArrayLike<number>`

const modelData = new SpineModel();
modelData.vCount = vc;
Expand Down Expand Up @@ -300,7 +299,7 @@ export class AnimationCache {
this.invalidAllFrame();
}

public destory (): void {
public destroy (): void {
spine.wasmUtil.destroySpineInstance(this._instance);
}
}
Expand Down Expand Up @@ -358,10 +357,10 @@ class SkeletonCache {
public getSkeletonCache (uuid: string, skeletonData: spine.SkeletonData): SkeletonCacheItemInfo {
let skeletonInfo = this._skeletonCache[uuid];
if (!skeletonInfo) {
const skeleton = new spine.Skeleton(skeletonData);
const clipper = new spine.SkeletonClipping();
const stateData = new spine.AnimationStateData(skeleton.data);
const state = new spine.AnimationState(stateData);
const skeleton = null; //new spine.Skeleton(skeletonData);
const clipper = null; //new spine.SkeletonClipping();
//const stateData = null; //new spine.AnimationStateData(skeleton.data);
const state = null; //new spine.AnimationState(stateData);
const listener = new TrackEntryListeners();

this._skeletonCache[uuid] = skeletonInfo = {
Expand Down Expand Up @@ -416,14 +415,14 @@ class SkeletonCache {
const animationPool = this._animationPool;
for (const key in animationPool) {
if (key.includes(uuid)) {
animationPool[key].destory();
animationPool[key].destroy();
delete animationPool[key];
}
}
} else {
const animationPool = this._animationPool;
for (const key in animationPool) {
animationPool[key].destory();
animationPool[key].destroy();
delete animationPool[key];
}
}
Expand Down
45 changes: 23 additions & 22 deletions cocos/spine/skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,6 @@ export class Skeleton extends UIRenderer {
@serializable
protected _cacheMode = AnimationCacheMode.REALTIME;
@serializable
protected _defaultCacheMode: AnimationCacheMode = AnimationCacheMode.REALTIME;
@serializable
protected _sockets: SpineSocket[] = [];
@serializable
protected _useTint = false;
Expand Down Expand Up @@ -475,11 +473,11 @@ export class Skeleton extends UIRenderer {
@editable
@type(AnimationCacheMode)
get defaultCacheMode (): AnimationCacheMode {
return this._defaultCacheMode;
return this._cacheMode;
}
set defaultCacheMode (mode: AnimationCacheMode) {
this._defaultCacheMode = mode;
this.setAnimationCacheMode(this._defaultCacheMode);
this._cacheMode = mode;
this.setAnimationCacheMode(this._cacheMode);
}

/**
Expand Down Expand Up @@ -613,7 +611,7 @@ export class Skeleton extends UIRenderer {
this.markForUpdateRenderData();
}
}
get socketNodes (): Map<number, Node> { return this._socketNodes; }
get socketNodes (): Map<number, Node> | null { return this._socketNodes; }

/**
* @en The name of current playing animation.
Expand Down Expand Up @@ -699,19 +697,17 @@ export class Skeleton extends UIRenderer {
this._vBuffer = null;
this._iBuffer = null;
this.attachUtil.reset();
this.attachUtil = null;
this._textures = null;
//this._textures.length = 0;
this._slotTextures?.clear();
this._slotTextures = null;
this._cachedSockets.clear();
this._cachedSockets = null;
this._socketNodes.clear();
this._socketNodes = null;
//if (this._cacheMode == AnimationCacheMode.PRIVATE_CACHE) this._animCache?.destroy();
this._animCache = null;
SkeletonSystem.getInstance().remove(this);
if (!JSB) {
spine.wasmUtil.destroySpineInstance(this._instance);
}
this._instance = null;
super.onDestroy();
}
/**
Expand All @@ -737,17 +733,19 @@ export class Skeleton extends UIRenderer {
}
this._instance.dtRate = this._timeScale * timeScale;
this._needUpdateSkeltonData = false;
const data = this.skeletonData?.getRuntimeData();
if (!data) return;
this.setSkeletonData(data);
if (this.defaultSkin) this.setSkin(this.defaultSkin);
this._textures = skeletonData.textures;
//const data = this.skeletonData?.getRuntimeData();
//if (!data) return;
//this.setSkeletonData(data);
this._runtimeData = skeletonData.getRuntimeData();
if (!this._runtimeData) return;
this.setSkeletonData(this._runtimeData);

if (this.defaultSkin) this.setSkin(this.defaultSkin);
this._textures = skeletonData.textures;

this._refreshInspector();
if (this.defaultAnimation) this.animation = this.defaultAnimation.toString();
if (this.defaultSkin) this.setSkin(this.defaultSkin);
//if (this.defaultSkin) this.setSkin(this.defaultSkin);
this._updateUseTint();
this._indexBoneSockets();
this._updateSocketBindings();
Expand Down Expand Up @@ -782,7 +780,10 @@ export class Skeleton extends UIRenderer {
}
if (this.skeletonData) {
const skeletonInfo = this._skeletonCache!.getSkeletonCache(this.skeletonData.uuid, skeletonData);
this._skeleton = skeletonInfo.skeleton;
if (skeletonInfo.skeleton == null) {
skeletonInfo.skeleton = this._instance.initSkeleton(skeletonData);
}
this._skeleton = skeletonInfo.skeleton!;
}
} else {
this._skeleton = this._instance.initSkeleton(skeletonData);
Expand Down Expand Up @@ -1303,11 +1304,11 @@ export class Skeleton extends UIRenderer {
this._cacheMode = cacheMode;
//this.setSkin(this.defaultSkin);
this._instance.isCache = this.isAnimationCached();
this.attachUtil.init(this);
//this.attachUtil.init(this);
this._updateSkeletonData();
this.setSkin(this.defaultSkin);
this._updateUseTint();
this._updateSocketBindings();
//this.setSkin(this.defaultSkin);
//this._updateUseTint();
//this._updateSocketBindings();
this.markForUpdateRenderData();
}
}
Expand Down
1 change: 1 addition & 0 deletions native/cocos/editor-support/spine-wasm/spine-model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ SpineModel::SpineModel() {

SpineModel::~SpineModel() {
delete SpineModel::data;
SpineModel::data = nullptr;
}

/*
Expand Down

0 comments on commit 7f217c2

Please sign in to comment.