@taole/giftstage 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -153,7 +153,9 @@ mounted.destroy();
153
153
 
154
154
  `sprite-v2` 每实例为 24 floats:`0–15` 完全延续 birth/lifetime/弹道/scale/rotation/RGBA,`16–17` 是 CSS 逻辑宽高,`18–19` 是归一化 anchor,`20–23` 是 atlas UV。header 为 8 floats:秒制时间、已求值 opacity、已求值 size、fade mode、`sx/sy` 与两个零 padding。WebGL2 的实例 stride 为 96 bytes、header 为 32 bytes;WebGPU 从 `8 + instanceIndex × 24` 读取。非均匀 backing scale 只在最终顶点应用,不能再用 `sqrt(sx × sy)` 近似 v2 尺寸。
155
155
 
156
- atlas descriptor 必须提供 `width × height × 4` 的不可变 `Uint8Array`,声明 `colorSpace:'srgb'` 与 `alphaMode:'premultiplied'`。透明像素 RGB 应为零;shader 不会再次乘采样 alpha。`ParticleAtlasHandle.destroy()` 只释放调用方 lease,存活 group 会保留内部引用;context/device loss 后旧 handle 的 `lost` 为 true,不能在新设备上复活。
156
+ atlas descriptor 必须提供 `width × height × 4` 的不可变 `Uint8Array`,声明 `colorSpace:'srgb'` 与 `alphaMode:'premultiplied'`。透明像素 RGB 应为零;shader 不会再次乘采样 alpha。`ParticleAtlasHandle.destroy()` 只释放调用方 lease,存活 group 会保留内部引用;context/device loss 后旧 handle 的 `lost` 为 true,不能在新设备上复活。
157
+
158
+ `await host.createParticleAtlas()` 同时等待 sprite-v2 管线准备完成,建议放在插件预加载阶段、`scope.start()` 之前。WebGPU 使用异步编译并缓存普通/叠加混合及有/无 stencil 的四种管线;WebGL2 提前编译并链接粒子程序。预加载不会绘制舞台或推进时钟,重复创建 atlas 会复用管线;准备失败时 atlas 创建会拒绝,不发布半就绪资源。此优化移除粒子管线首次编译造成的播放期停顿,不改变动画时长,也不保证其他素材或驱动工作完全没有长帧。
157
159
 
158
160
  envelope 使用绝对毫秒半开区间 `[startMs,endMs)`,支持 `linear` / `hold`,边界右连续,因此可以表达中心闪光的瞬时跳变。`setTime()` 仅更新每 batch header,实例 buffer 创建后保持不变;pause 不产生写入,seek 直接求值绝对时间。
159
161
 
@@ -212,14 +214,24 @@ envelope 使用绝对毫秒半开区间 `[startMs,endMs)`,支持 `linear` / `h
212
214
  SVGA atlas 在主线程组合或逐页上传时的单帧时间片上限,默认 `12ms`。
213
215
  实际时间片会按当前刷新周期的一半动态调整,避免高刷新率设备上的加载任务挤占渲染帧。
214
216
 
215
- - `svgaLoadFrameBudgetMs?: number`
216
- SVGA 主线程加载任务的共享时间片上限,默认 `12ms`。图片 fallback、atlas、clip、音频、slot 纹理和二进制缓存共用同一帧预算。
217
+ - `svgaLoadFrameBudgetMs?: number`
218
+ SVGA 主线程加载任务的共享时间片上限,默认 `12ms`。图片 fallback、atlas、clip、音频、slot 纹理、二进制缓存和 Hybrid 命令表构建共用同一帧预算。
219
+ Hybrid 的路径解析、裁剪检查、逐帧计划和命令打包会分片执行;同一资源的重复裁剪路径复用分类和矩形结果,避免视频与复杂 SVGA 同播时被同步准备工作阻塞。资源释放或后端丢失后会取消未完成的构建。
217
220
 
221
+ - `svgaCommandTableInWorker?: boolean`
222
+ 默认 `true`。后台 Worker 构建 GPU 命令表并打包帧数据;关闭时使用主线程共享帧预算分片。CPU 模式跳过 GPU 帧表准备。Worker 不可用、异常或结果校验失败时,每个资源最多回退一次,取消不触发回退。
223
+ 输入按不超过 64 KiB 的片段复制,只转移专用副本;CPU 回退持有的原始数组保持有效。GPU 资源仍在主线程创建,并在发布前检查资源生命周期。
224
+
225
+ - `onSVGAPreparationProfile?: (profile: SVGAPreparationProfile) => void`
226
+ 可选的 GPU 资源准备汇总回调;未配置时不进行详细采样。每个准备任务结束时回调一次,包括实际 `executor`、回退原因、完成/取消/失败状态和各阶段数据。
227
+ `mainThreadExecutionMs` 与 `workerExecutionMs` 是实际执行片段累计;`elapsedMs` 包含调度等待,不能当作 CPU 计算时间。各阶段可能重叠,不能相加作为总准备时长。
228
+ 阶段包括裁剪准备、Worker 排队、输入复制、命令构建、帧表打包、校验和 GPU 提交,另含最大连续片段、命中次数与字节数。GPU 提交时间是主线程调用耗时,并非 GPU 完成时间;网络/解析等待不属于此准备汇总。
229
+
218
230
  - `svgaWorkerFrameBudgetMs?: number`
219
231
  SVGA Worker 连续执行 JS 循环的时间片上限,默认 `4ms`,范围 `1-8ms`。单次 WASM protobuf 调用和单次原生 API 调用仍不可抢占。
220
232
 
221
233
  - `svgaWorkerTaskConcurrency?: number`
222
- parser、图片解码、atlasclip CPU 密集 Worker 的全局并发上限,默认 `1`。Atlas 首帧页面可提前返回,但后台 PNG 编码完成前仍持有该名额,避免与其他重载 Worker 叠加。
234
+ parser、图片解码、atlasclip 和命令表 Worker 的全局并发上限,默认 `1`。命令任务每个时间片重新排队,前台解析/首帧优先,同级 FIFO;连续 8 次前台许可后允许一个后台片段。Atlas 首帧页面可提前返回,但后台 PNG 编码完成前仍持有该名额,避免与其他重载 Worker 叠加。
223
235
 
224
236
  - `svgaWorkerImageDecodeConcurrency?: number`
225
237
  图片解码 Worker 内 `createImageBitmap` 并发上限,默认 `2`。运行时可按批次耗时收缩并发,负载恢复后回升,但不会超过该上限。
@@ -233,7 +245,9 @@ envelope 使用绝对毫秒半开区间 `[startMs,endMs)`,支持 `linear` / `h
233
245
  - `svgaParseProfile?: boolean`
234
246
  是否输出 `[GiftStage:SVGA:Profile]` 结构化解析日志,默认 `false`。日志包含 `DecompressionStream` 格式尝试、输入/输出 chunk、解压耗时以及 protobuf/payload 构建耗时;WASM payload 路径还会拆分 `prostDecodeMs`、`metadataAndImagesMs`、`frameTableMs`、`finalizeMs` 和 WASM 边界复制耗时。缓存命中不输出。
235
247
 
236
- SVGA 礼物在加载阶段被 `destroy()` / `removeGift()` 时,会取消排队任务并终止正在执行的 parser、图片解码、atlas clip Worker。相同 URL 的共享加载按消费者计数,单个礼物取消不会中断其他仍在等待的礼物。
248
+ SVGA 礼物在加载阶段被 `destroy()` / `removeGift()` 时会取消相应订阅。相同 URL 的共享加载按消费者计数;裁剪生产和命令表属于资源,资源释放或 Stage 销毁才取消生产。命令任务使用 ID/代次隔离,取消一个资源不会终止其他资源的 Worker。
249
+
250
+ 同一个 Stage 的裁剪预热、渲染和命令构建共用分类/矩形分析;重复路径只保留小型分析结果,网格缓存与磁盘格式不变。首帧只等待该帧裁剪与纹理,其余准备推迟到首帧绘制后。渲染循环不再同步解析未准备好的裁剪路径,继续按整帧等待处理。
237
251
 
238
252
  - `onError?: (error: Error) => void`
239
253
  统一错误回调。
@@ -15,7 +15,7 @@ export declare class GiftStage {
15
15
  private readonly sharedSVGAEntities;
16
16
  private readonly pendingSharedSVGAEntities;
17
17
  /** One full clip-prewarm task per entity, shared by every slot using that entity. */
18
- private readonly svgaFullClipPrewarmPromises;
18
+ private svgaFullClipPrewarmPromises;
19
19
  /** Deferred persistent-cache writer captured while a URL-backed entity is being assembled. */
20
20
  private readonly svgaPersistentCacheWriters;
21
21
  private readonly svgaPersistentCacheWritePromises;
@@ -54,6 +54,9 @@ export declare class GiftStage {
54
54
  private reservedSVGAGpuFrameTableBytes;
55
55
  private svgaBackendLost;
56
56
  private svgaPreparingEntities;
57
+ private svgaCommandControllers;
58
+ private svgaPreparationSequence;
59
+ private svgaPreparationProfiles;
57
60
  private activeSVGATimelineEntities;
58
61
  private svgaEntitySources;
59
62
  private runtimeFallbackCount;
@@ -95,6 +98,7 @@ export declare class GiftStage {
95
98
  * so those focused harnesses exercise SVGA loading without having to mirror
96
99
  * every constructor-only field.
97
100
  */
101
+ private getSVGAPreparationProfile;
98
102
  private ensureSVGATimelineBookkeeping;
99
103
  private emitRuntimeDiagnostic;
100
104
  private recordObserverError;
@@ -111,6 +115,7 @@ export declare class GiftStage {
111
115
  * playbacks can start directly on the selected GPU path.
112
116
  */
113
117
  private ensureSVGAFrameTable;
118
+ private assertSVGAFrameTableActive;
114
119
  private refreshSVGATimelineSlots;
115
120
  private assignSVGATimelineStateToSlot;
116
121
  private releaseSVGAFrameTable;
@@ -1,3 +1,4 @@
1
+ import type { SVGAPreparationRecorder } from '../utils/svga-preparation-profile.js';
1
2
  import type { GPUBackend, GiftSlot, GiftHandle, GPUTextureHandle, VideoEntity } from '../types/index.js';
2
3
  import { type SVGAClipMeshMap } from '../renderers/svga-batch-renderer.js';
3
4
  import { PostAnimator } from './post-animator.js';
@@ -127,7 +128,10 @@ export declare class RenderManager {
127
128
  * cannot bypass media side effects while seeking the visual frame.
128
129
  */
129
130
  applyPlaybackScopeMediaTime(id: string, timeMs: number, emitInitialFrame?: boolean, discontinuous?: boolean): void;
131
+ releaseSVGAPreparation(entity: NonNullable<GiftSlot['videoEntity']>): void;
132
+ get svgaClipAnalysis(): import("../utils/svga-clip-analysis.js").SVGAClipAnalysisCache;
130
133
  prewarmSVGAClipMeshes(entity: NonNullable<GiftSlot['videoEntity']>, options?: {
134
+ profile?: SVGAPreparationRecorder;
131
135
  frameBudgetMs?: number;
132
136
  workerTimeSliceMs?: number;
133
137
  useWorker?: boolean;
@@ -135,6 +139,7 @@ export declare class RenderManager {
135
139
  signal?: AbortSignal;
136
140
  }): Promise<number>;
137
141
  prewarmSVGAClipMeshesForFrame(entity: NonNullable<GiftSlot['videoEntity']>, frame: number, options?: {
142
+ profile?: SVGAPreparationRecorder;
138
143
  frameBudgetMs?: number;
139
144
  workerTimeSliceMs?: number;
140
145
  useWorker?: boolean;
@@ -145,6 +150,10 @@ export declare class RenderManager {
145
150
  retainSVGAHybridMeshes(entity: NonNullable<GiftSlot['videoEntity']>): void;
146
151
  releaseSVGAHybridMeshes(entity: NonNullable<GiftSlot['videoEntity']>): void;
147
152
  hydrateSVGAClipMeshes(meshes: SVGAClipMeshMap | null | undefined): void;
153
+ hydrateSVGAClipMeshesCooperative(meshes: SVGAClipMeshMap | null | undefined, options?: {
154
+ frameBudgetMs?: number;
155
+ signal?: AbortSignal;
156
+ }): Promise<void>;
148
157
  snapshotSVGAClipMeshes(entity: NonNullable<GiftSlot['videoEntity']>): SVGAClipMeshMap;
149
158
  private renderLoop;
150
159
  private drawPreparedFrameWithReplay;