Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize spine memory leak & optimize. #16384

Closed
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 24 additions & 36 deletions cocos/spine/assembler/simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
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 All @@ -58,6 +59,8 @@
const DEBUG_TYPE_REGION = 0;
const DEBUG_TYPE_MESH = 1;

const tempVecPos = new Vec3(0, 0, 0);

function _getSlotMaterial (blendMode: number, comp: Skeleton): MaterialInstance {
let src: BlendFactor;
let dst: BlendFactor;
Expand All @@ -84,12 +87,6 @@
}

export const simple: IAssembler = {
fillBuffers (render: UIRenderable, batcher: Batcher2D) {

},
updateColor (render: UIRenderable) {

},
vCount: 32767,
ensureAccessor (useTint: boolean) {
let accessor = useTint ? _tintAccessor : _accessor;
Expand Down Expand Up @@ -141,70 +138,62 @@
}
const rd = comp.renderData!;
const accessor = _useTint ? _tintAccessor : _accessor;
comp.syncAttachedNode();
if (rd.vertexCount > 0 || rd.indexCount > 0) accessor.getMeshBuffer(rd.chunk.bufferId).setDirty();
}

function realTimeTraverse (comp: Skeleton): void {
const floatStride = (_useTint ? _byteStrideTwoColor : _byteStrideOneColor) / Float32Array.BYTES_PER_ELEMENT;
const floatStride = (comp.useTint ? _byteStrideTwoColor : _byteStrideOneColor) / Float32Array.BYTES_PER_ELEMENT;
const model = comp.updateRenderData();
if (!model) return;
const vc = model.vCount as number;
const ic = model.iCount as number;
const rd = comp.renderData!;
if (vc < 1 || ic < 1) return;

const rd = comp.renderData!;
if (rd.vertexCount !== vc || rd.indexCount !== ic) {
rd.resize(vc, ic);
rd.indices = new Uint16Array(ic);
comp._vLength = vc * Float32Array.BYTES_PER_ELEMENT * floatStride;
comp._vBuffer = new Uint8Array(rd.chunk.vb.buffer, rd.chunk.vb.byteOffset, Float32Array.BYTES_PER_ELEMENT * rd.chunk.vb.length);
comp._iLength = Uint16Array.BYTES_PER_ELEMENT * ic;
comp._iBuffer = new Uint8Array(rd.indices.buffer);
}
if (vc < 1 || ic < 1) return;

const vbuf = rd.chunk.vb;
const vUint8Buf = new Uint8Array(vbuf.buffer, vbuf.byteOffset, Float32Array.BYTES_PER_ELEMENT * vbuf.length);

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 as TypedArray);

const iPtr = model.iPtr;
const ibuf = rd.indices!;
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(ibuf.buffer);
iUint8Buf.set(iData as TypedArray);
const HEAPU8 = spine.wasmUtil.wasm.HEAPU8;

comp._vBuffer?.set(HEAPU8.subarray(vPtr, vPtr + comp._vLength), 0);

Check failure on line 168 in cocos/spine/assembler/simple.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Unsafe argument of type `any` assigned to a parameter of type `ArrayLike<number>`
comp._iBuffer?.set(HEAPU8.subarray(iPtr, iPtr + comp._iLength), 0);

Check failure on line 169 in cocos/spine/assembler/simple.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 chunkOffset = rd.chunk.vertexOffset;
for (let i = 0; i < ic; i++) {
ibuf[i] += chunkOffset;
}
for (let i = 0; i < ic; i++) ibuf[i] += chunkOffset;

const meshes = model.getMeshes();
const count = meshes.size();
const data = model.getData();
const count = data.size();
let indexOffset = 0;
let indexCount = 0;
for (let i = 0; i < count; i++) {
const mesh = meshes.get(i);
const material = _getSlotMaterial(mesh.blendMode as number, comp);
const textureID = mesh.textureID as number;
indexCount = mesh.iCount;
for (let i = 0; i < count; i += 6) {
indexCount = data.get(i + 3);
const material = _getSlotMaterial(data.get(i + 4), comp);

Check failure on line 179 in cocos/spine/assembler/simple.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Unsafe argument of type `any` assigned to a parameter of type `number`
const textureID: number = data.get(i + 5);
comp.requestDrawData(material, textureID, indexOffset, indexCount);
indexOffset += indexCount;
}

// if enableBatch apply worldMatrix
if (comp.enableBatch) {
const worldMat = comp.node.worldMatrix;
let index = 0;
const tempVecPos = new Vec3(0, 0, 0);
for (let i = 0; i < vc; i++) {
index = i * floatStride;
tempVecPos.x = vbuf[index];
tempVecPos.y = vbuf[index + 1];
tempVecPos.z = 0;
dumganhar marked this conversation as resolved.
Show resolved Hide resolved
tempVecPos.transformMat4(worldMat);
vbuf[index] = tempVecPos.x;
vbuf[index + 1] = tempVecPos.y;
vbuf[index + 2] = tempVecPos.z;
vbuf[index + 2] = 0;
}
}

Expand Down Expand Up @@ -341,7 +330,6 @@
if (comp.enableBatch) {
const worldMat = comp.node.worldMatrix;
let index = 0;
const tempVecPos = new Vec3(0, 0, 0);
for (let i = 0; i < vc; i++) {
index = i * floatStride;
tempVecPos.x = vbuf[index];
Expand Down
95 changes: 40 additions & 55 deletions cocos/spine/attach-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,75 +35,60 @@
* @class sp.AttachUtil
*/
export class AttachUtil {
protected _inited = false;
protected _skeleton: spine.Skeleton | null = null;
protected _skeletonNode: Node|null = null;
protected _skeletonComp: Skeleton|null = null;
protected isInitialized = false;
protected skeletonBones: spine.Bone[] | FrameBoneInfo[] | undefined;

Check failure on line 39 in cocos/spine/attach-util.ts

View workflow job for this annotation

GitHub Actions / npm_test

Cannot find name 'FrameBoneInfo'.
protected socketNodes: Map<number, Node> | undefined;
private keysToDelete: number[] = [];
dumganhar marked this conversation as resolved.
Show resolved Hide resolved

constructor () {
this._inited = false;
this._skeleton = null;
this._skeletonNode = null;
this._skeletonComp = null;
this.isInitialized = false;
}

init (skeletonComp: Skeleton): void {
this._inited = true;
this._skeleton = skeletonComp._skeleton;
this._skeletonNode = skeletonComp.node;
this._skeletonComp = skeletonComp;
this.isInitialized = false;
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;
this.isInitialized = true;
this._syncAttachedNode();
}

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

_syncAttachedNode (): void {
if (!this._inited) return;

const socketNodes = this._skeletonComp!.socketNodes;
if (socketNodes.size === 0) return;

let boneInfos;
const isCached = this._skeletonComp!.isAnimationCached();
if (isCached && this._skeletonComp!._curFrame) {
boneInfos = this._skeletonComp!._curFrame.boneInfos;
} else {
boneInfos = this._skeleton!.bones;
}

if (!boneInfos || boneInfos.length < 1) return;

const matrixHandle = (node: Node, bone: any): void => {
const tm = tempMat4;
tm.m00 = bone.a;
tm.m01 = bone.c;
tm.m04 = bone.b;
tm.m05 = bone.d;
tm.m12 = bone.worldX;
tm.m13 = bone.worldY;
node.matrix = tempMat4;
};

for (const boneIdx of socketNodes.keys()) {
const boneNode = socketNodes.get(boneIdx);
// Node has been destroy
if (!this.isInitialized) return;
const socketNodes = this.socketNodes!;
for (const [boneIdx, boneNode] of socketNodes) {
if (!boneNode || !boneNode.isValid) {
socketNodes.delete(boneIdx);
this.keysToDelete.push(boneIdx);
continue;
}
const bone = boneInfos[boneIdx];
// Bone has been destroy
if (!bone) {
boneNode.removeFromParent();
boneNode.destroy();
socketNodes.delete(boneIdx);
continue;
}
matrixHandle(boneNode, bone);
const bone = this.skeletonBones![boneIdx];
if (bone) this.matrixHandle(boneNode, bone);
}
if (this.keysToDelete.length <= 0) return;
for (const boneIdx of this.keysToDelete) {
socketNodes.delete(boneIdx);
}
this.keysToDelete.length = 0;
}

matrixHandle (node: Node, bone: any): void {
const tm = tempMat4;
tm.m00 = bone.a;
tm.m01 = bone.c;
tm.m04 = bone.b;
tm.m05 = bone.d;
tm.m12 = bone.worldX;
tm.m13 = bone.worldY;
node.matrix = tempMat4;
}
}
29 changes: 27 additions & 2 deletions cocos/spine/lib/spine-core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,32 @@
/* eslint @typescript-eslint/no-explicit-any: "off" */

declare namespace spine {

class String {
length: number;
isEmpty: boolean;
strPtr: number;
str: string;
}

class SPVectorFloat {
size(): number;
resize(newSize: number, defaultValue: number);
set(index: number, value: number);
get(index: number): number;
delete();
}

class Animation {
constructor(name: string, timelines: Array<Timeline>, duration: number);
duration: number;
name: string;
timelines: Array<Timeline>;
apply(skeleton: Skeleton, lastTime: number, time: number, loop: boolean, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 48 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 166. Maximum allowed is 150
hasTimeline(id: number): boolean;
}
interface Timeline {
apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 52 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 151. Maximum allowed is 150
getPropertyId(): number;
}
enum MixBlend {
Expand Down Expand Up @@ -76,7 +92,7 @@
getCurveType(frameIndex: number): number;
setCurve(frameIndex: number, cx1: number, cy1: number, cx2: number, cy2: number): void;
getCurvePercent(frameIndex: number, percent: number): number;
abstract apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 95 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 160. Maximum allowed is 150
}
class RotateTimeline extends CurveTimeline {
static ENTRIES: number;
Expand All @@ -88,7 +104,7 @@
constructor(frameCount: number);
getPropertyId(): number;
setFrame(frameIndex: number, time: number, degrees: number): void;
apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 107 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 151. Maximum allowed is 150
}
class TranslateTimeline extends CurveTimeline {
static readonly ENTRIES: number;
Expand All @@ -96,17 +112,17 @@
constructor(frameCount: number);
getPropertyId(): number;
setFrame(frameIndex: number, time: number, x: number, y: number): void;
apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 115 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 151. Maximum allowed is 150
}
class ScaleTimeline extends TranslateTimeline {
constructor(frameCount: number);
getPropertyId(): number;
apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 120 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 151. Maximum allowed is 150
}
class ShearTimeline extends TranslateTimeline {
constructor(frameCount: number);
getPropertyId(): number;
apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 125 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 151. Maximum allowed is 150
}
class ColorTimeline extends CurveTimeline {
static ENTRIES: number;
Expand All @@ -117,7 +133,7 @@
getSlotIndex(): number;
setSlotIndex(inValue: number): void;
setFrame(frameIndex: number, time: number, r: number, g: number, b: number, a: number): void;
apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 136 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 151. Maximum allowed is 150
}
class TwoColorTimeline extends CurveTimeline {
static readonly ENTRIES: number;
Expand All @@ -128,7 +144,7 @@
getSlotIndex(): number;
setSlotIndex(inValue: number): void;
setFrame(frameIndex: number, time: number, r: number, g: number, b: number, a: number, r2: number, g2: number, b2: number): void;
apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 147 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 151. Maximum allowed is 150
}
class AttachmentTimeline implements Timeline {
slotIndex: number;
Expand All @@ -141,7 +157,7 @@
setSlotIndex(inValue: number): void;
getAttachmentNames(): Array<string>;
setFrame(frameIndex: number, time: number, attachmentName: string): void;
apply(skeleton: Skeleton, lastTime: number, time: number, events: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;

Check warning on line 160 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 151. Maximum allowed is 150
}
class DeformTimeline extends CurveTimeline {
slotIndex: number;
Expand Down Expand Up @@ -555,7 +571,6 @@
transformConstraints: Array<TransformConstraint>;
pathConstraints: Array<PathConstraint>;
_updateCache: Updatable[];
updateCacheReset: Updatable[];
skin: Skin;
color: Color;
time: number;
Expand Down Expand Up @@ -685,7 +700,7 @@
scale: number;
private linkedMeshes;
constructor(attachmentLoader: AttachmentLoader);
readSkeletonData(json: string | any): SkeletonData;
readSkeletonData(json: any): SkeletonData;
readAttachment(map: any, skin: Skin, slotIndex: number, name: string, skeletonData: SkeletonData): Attachment;
readVertices(map: any, attachment: VertexAttachment, verticesLength: number): void;
readAnimation(map: any, name: string, skeletonData: SkeletonData): void;
Expand Down Expand Up @@ -764,7 +779,7 @@
MipMapNearestNearest = 9984,
MipMapLinearNearest = 9985,
MipMapNearestLinear = 9986,
MipMapLinearLinear = 9987

Check failure on line 782 in cocos/spine/lib/spine-core.d.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Duplicate enum member value 9987
}
enum TextureWrap {
MirroredRepeat = 33648,
Expand Down Expand Up @@ -1163,7 +1178,17 @@
end(): void;
}

class SkeletonSystem {
public static updateAnimation(deltaTime: number): void;
public static updateRenderData(): void;
public static getCount(): number;
}

class SkeletonInstance {
dtRate: number;
isCache: boolean;
isDelete: boolean;
enable: boolean;
initSkeleton(data: SkeletonData);
getAnimationState();
setAnimation(trackIndex: number, name: string, loop: boolean): spine.TrackEntry | null;
Expand Down
Loading
Loading