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

Refine: make multi skeleton component shared one instance of spine.Skeleton while spine working at sharedCache mode #16593

Merged
merged 6 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions cocos/spine/lib/spine-core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@
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 @@ -92,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 @@ -104,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 @@ -112,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 @@ -133,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 @@ -144,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 @@ -157,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 @@ -779,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 @@ -1220,6 +1220,7 @@
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;
Expand Down
47 changes: 42 additions & 5 deletions cocos/spine/skeleton-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
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;
Expand Down Expand Up @@ -174,13 +175,13 @@
const vPtr = model.vPtr;
const vLength = vc * Float32Array.BYTES_PER_ELEMENT * floatStride;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
vUint8Buf.set(HEAPU8.subarray(vPtr, vPtr + vLength));

Check failure on line 178 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 iUint8Buf = new Uint8Array(iUint16Buf.buffer);
iUint8Buf.set(HEAPU8.subarray(iPtr, iPtr + iLength));

Check failure on line 184 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 @@ -310,7 +311,10 @@

protected _privateMode: boolean;
protected _skeletonCache: { [key: string]: SkeletonCacheItemInfo };

//for shared mode only
protected _animationPool: { [key: string]: AnimationCache };
private _sharedCacheMap: Map<string, Array<Skeleton>> = new Map<string, Array<Skeleton>>();
constructor () {
this._privateMode = false;
this._animationPool = {};
Expand Down Expand Up @@ -338,7 +342,28 @@
}
}

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) {
sharedInstances.splice(index, 1);
}
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 => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it called privateOperate? What does private mean here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private corresponds to privateCache mode.

animationCache.destroy();
};
const operate = sharedInstances ? sharedOperate : privateOperate;

const skeletonInfo = this._skeletonCache[uuid];
if (!skeletonInfo) return;
const animationsCache = skeletonInfo.animationsCache;
Expand All @@ -347,17 +372,29 @@
// 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<Skeleton>();
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skeleton is forever null in the old code?

Copy link
Contributor Author

@bofeng-song bofeng-song Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skeleton will constructor by skeleton component's _instance in old code

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we move the spine.Skeleton construction code to here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, previous logic multi skeleton component can not share the same object of spine.skeleton

const clipper = null;
const state = null;
const listener = new TrackEntryListeners();
Expand Down
9 changes: 3 additions & 6 deletions cocos/spine/skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
6 changes: 6 additions & 0 deletions native/cocos/editor-support/spine-wasm/spine-wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions native/cocos/editor-support/spine-wasm/spine-wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading