@taole/giftstage 0.3.2 → 0.3.4
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 +99 -85
- package/dist/core/gift-stage.d.ts +1 -0
- package/dist/gift-stage.cjs +901 -885
- package/dist/gift-stage.es.js +2747 -2616
- package/dist/gpu/webgl2-backend.d.ts +1 -0
- package/dist/gpu/webgpu-backend.d.ts +4 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/utils/clip-mesh.d.ts +5 -0
- package/dist/utils/svg-path-parser.d.ts +2 -0
- package/dist/utils/svga-hybrid-command-table.d.ts +9 -5
- package/package.json +80 -80
package/README.md
CHANGED
|
@@ -87,11 +87,11 @@ npm run perf:record
|
|
|
87
87
|
npm run test:perf
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
基线覆盖冷/热启动、100 个静态图片、SVGA Direct 的 1/2/10/50 个同资源实例、
|
|
91
|
-
复杂 Clip/Shape Hybrid 的 Auto/CPU 对照、20 个共享 VAP 和 20 个共享 AlphaVideo。
|
|
92
|
-
除首帧、P50/P95/P99、长任务、堆变化、draw/Stencil 外,还记录 SVGA CPU Sprite
|
|
93
|
-
展开数、GPU 帧表上传、每帧动态上传字节、路径晋升与回退。可用
|
|
94
|
-
`npm run test:perf -- --project=chromium-webgl2 --scenarios=<逗号分隔场景>` 做聚焦复测。
|
|
90
|
+
基线覆盖冷/热启动、100 个静态图片、SVGA Direct 的 1/2/10/50 个同资源实例、
|
|
91
|
+
复杂 Clip/Shape Hybrid 的 Auto/CPU 对照、20 个共享 VAP 和 20 个共享 AlphaVideo。
|
|
92
|
+
除首帧、P50/P95/P99、长任务、堆变化、draw/Stencil 外,还记录 SVGA CPU Sprite
|
|
93
|
+
展开数、GPU 帧表上传、每帧动态上传字节、路径晋升与回退。可用
|
|
94
|
+
`npm run test:perf -- --project=chromium-webgl2 --scenarios=<逗号分隔场景>` 做聚焦复测。
|
|
95
95
|
基线保存在 `tests/performance/baselines/`;Windows 会自动探测系统 Chrome,也可通过
|
|
96
96
|
`PLAYWRIGHT_CHROME_EXECUTABLE_PATH` 指定浏览器。
|
|
97
97
|
|
|
@@ -141,21 +141,23 @@ mounted.destroy();
|
|
|
141
141
|
|
|
142
142
|
- `preload()`:复用 GiftStage 的 SVGA/Image 缓存并返回引用计数资源租约。
|
|
143
143
|
- `createPlaybackScope()`:使用 GiftStage 唯一 RAF、逻辑时钟和作用域清理;SVGA、WebCodecs、HTMLVideo 回退与定时图片均按 Scope 绝对时间定位,不叠加 RenderManager 的全局 `dt`。SVGA 的可见帧、`onFrame` 与嵌入音频由同一个绝对时间入口同步,跨帧、seek、循环和暂停恢复会重建正确音频偏移,且 `start()` 前不会触发首帧音频/回调。HTMLVideo 在 Scope 内保持暂停并使用独立实例,显式暂停和页面隐藏期间逻辑时间冻结。
|
|
144
|
-
- `createMotionTrack()`:接收 8-float TypedArray/SoA 父级轨道。WebGPU 可把它与核心 SVGA 帧表在同一顶点着色器中合成;WebGL2 的 SVGA 内部帧仍可走 GPU Direct/Hybrid,但父级 MotionTrack 继续使用确定性 CPU reference sampler。图片与 WebGL1 同样使用 CPU reference。
|
|
145
|
-
- `createParticleBatch()`:保留 16-float `ballistic-v1` ABI,WebGPU/WebGL2 使用持久实例缓冲和 GPU 弹道求值;缺省仍在媒体之后合成。
|
|
146
|
-
- `host.createParticleAtlas()` + `scope.createParticleBatchGroup()`:可选 `sprite-v2` 能力。插件上传一次不可变预乘 RGBA8 atlas,再以原子 group 发布多个 24-float sprite batch。group 任一 draw 失败会 abort 整帧并以同一权威时间重放,不会显示 smoke-only 等局部结果。
|
|
147
|
-
- 粒子 `compositeLayer` 支持 `behind-media` / `above-media`;正式帧顺序为 `begin → behind particles → media → above particles → end`,`zIndex` 只在同一 phase 内排序。WebGL1 明确不可用,不提供 Canvas2D 粒子后端。
|
|
148
|
-
- `stage.capabilities`:插件可在播放前判断实际后端、GPU 轨道媒体范围和粒子能力。
|
|
149
|
-
|
|
150
|
-
### ParticleBatch v2 迁移
|
|
151
|
-
|
|
152
|
-
`stage.capabilities.particles.formats` 包含 `sprite-v2`,且同时具备 `spriteAtlas`、`compositeLayers`、`batchEnvelope`、`atomicBatchGroup` 和 `maxInstancesPerBatch` 时,插件才能启用纹理粒子;不得只按 `apiVersion` 判断。旧核心缺少这些可选字段时继续使用原有 v1 或明确跳过效果。
|
|
153
|
-
|
|
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
|
-
|
|
144
|
+
- `createMotionTrack()`:接收 8-float TypedArray/SoA 父级轨道。WebGPU 可把它与核心 SVGA 帧表在同一顶点着色器中合成;WebGL2 的 SVGA 内部帧仍可走 GPU Direct/Hybrid,但父级 MotionTrack 继续使用确定性 CPU reference sampler。图片与 WebGL1 同样使用 CPU reference。
|
|
145
|
+
- `createParticleBatch()`:保留 16-float `ballistic-v1` ABI,WebGPU/WebGL2 使用持久实例缓冲和 GPU 弹道求值;缺省仍在媒体之后合成。
|
|
146
|
+
- `host.createParticleAtlas()` + `scope.createParticleBatchGroup()`:可选 `sprite-v2` 能力。插件上传一次不可变预乘 RGBA8 atlas,再以原子 group 发布多个 24-float sprite batch。group 任一 draw 失败会 abort 整帧并以同一权威时间重放,不会显示 smoke-only 等局部结果。
|
|
147
|
+
- 粒子 `compositeLayer` 支持 `behind-media` / `above-media`;正式帧顺序为 `begin → behind particles → media → above particles → end`,`zIndex` 只在同一 phase 内排序。WebGL1 明确不可用,不提供 Canvas2D 粒子后端。
|
|
148
|
+
- `stage.capabilities`:插件可在播放前判断实际后端、GPU 轨道媒体范围和粒子能力。
|
|
149
|
+
|
|
150
|
+
### ParticleBatch v2 迁移
|
|
151
|
+
|
|
152
|
+
`stage.capabilities.particles.formats` 包含 `sprite-v2`,且同时具备 `spriteAtlas`、`compositeLayers`、`batchEnvelope`、`atomicBatchGroup` 和 `maxInstancesPerBatch` 时,插件才能启用纹理粒子;不得只按 `apiVersion` 判断。旧核心缺少这些可选字段时继续使用原有 v1 或明确跳过效果。
|
|
153
|
+
|
|
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
|
+
|
|
156
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
157
|
|
|
158
|
-
|
|
158
|
+
`await host.createParticleAtlas()` 同时等待 sprite-v2 管线准备完成,建议放在插件预加载阶段、`scope.start()` 之前。WebGPU 使用异步编译并缓存普通/叠加混合及有/无 stencil 的四种管线;WebGL2 提前编译并链接粒子程序。预加载不会绘制舞台或推进时钟,重复创建 atlas 会复用管线;准备失败时 atlas 创建会拒绝,不发布半就绪资源。此优化移除粒子管线首次编译造成的播放期停顿,不改变动画时长,也不保证其他素材或驱动工作完全没有长帧。
|
|
159
|
+
|
|
160
|
+
envelope 使用绝对毫秒半开区间 `[startMs,endMs)`,支持 `linear` / `hold`,边界右连续,因此可以表达中心闪光的瞬时跳变。`setTime()` 仅更新每 batch header,实例 buffer 创建后保持不变;pause 不产生写入,seek 直接求值绝对时间。
|
|
159
161
|
|
|
160
162
|
## 核心 API
|
|
161
163
|
|
|
@@ -212,8 +214,9 @@ 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
|
|
|
218
221
|
- `svgaWorkerFrameBudgetMs?: number`
|
|
219
222
|
SVGA Worker 连续执行 JS 循环的时间片上限,默认 `4ms`,范围 `1-8ms`。单次 WASM protobuf 调用和单次原生 API 调用仍不可抢占。
|
|
@@ -221,46 +224,46 @@ envelope 使用绝对毫秒半开区间 `[startMs,endMs)`,支持 `linear` / `h
|
|
|
221
224
|
- `svgaWorkerTaskConcurrency?: number`
|
|
222
225
|
parser、图片解码、atlas 和 clip 等 CPU 密集 Worker 的全局并发上限,默认 `1`。Atlas 首帧页面可提前返回,但后台 PNG 编码完成前仍持有该名额,避免与其他重载 Worker 叠加。
|
|
223
226
|
|
|
224
|
-
- `svgaWorkerImageDecodeConcurrency?: number`
|
|
225
|
-
图片解码 Worker 内 `createImageBitmap` 并发上限,默认 `2`。运行时可按批次耗时收缩并发,负载恢复后回升,但不会超过该上限。
|
|
226
|
-
|
|
227
|
-
- `svgaFrameEvaluation?: 'auto' | 'cpu'`
|
|
228
|
-
SVGA 帧动画求值策略,默认 `auto`。`auto` 按后端能力、表大小和资源计划选择 `gpu-direct`、`gpu-hybrid` 或 `cpu-reference`;`cpu` 强制使用 CPU reference。普通单礼物和同资源多实例都经过同一策略。
|
|
229
|
-
|
|
230
|
-
- `svgaGpuFrameTableBudgetBytes?: number`
|
|
231
|
-
所有活动 SVGA GPU 帧表、静态 Sprite metadata 和 Hybrid Command Table 共享的全局预算,默认 `32 MiB`。预算不足时仅当前资源回退到 `cpu-reference`,不会影响已存在的其他礼物。
|
|
227
|
+
- `svgaWorkerImageDecodeConcurrency?: number`
|
|
228
|
+
图片解码 Worker 内 `createImageBitmap` 并发上限,默认 `2`。运行时可按批次耗时收缩并发,负载恢复后回升,但不会超过该上限。
|
|
229
|
+
|
|
230
|
+
- `svgaFrameEvaluation?: 'auto' | 'cpu'`
|
|
231
|
+
SVGA 帧动画求值策略,默认 `auto`。`auto` 按后端能力、表大小和资源计划选择 `gpu-direct`、`gpu-hybrid` 或 `cpu-reference`;`cpu` 强制使用 CPU reference。普通单礼物和同资源多实例都经过同一策略。
|
|
232
|
+
|
|
233
|
+
- `svgaGpuFrameTableBudgetBytes?: number`
|
|
234
|
+
所有活动 SVGA GPU 帧表、静态 Sprite metadata 和 Hybrid Command Table 共享的全局预算,默认 `32 MiB`。预算不足时仅当前资源回退到 `cpu-reference`,不会影响已存在的其他礼物。
|
|
232
235
|
|
|
233
236
|
- `svgaParseProfile?: boolean`
|
|
234
237
|
是否输出 `[GiftStage:SVGA:Profile]` 结构化解析日志,默认 `false`。日志包含 `DecompressionStream` 格式尝试、输入/输出 chunk、解压耗时以及 protobuf/payload 构建耗时;WASM payload 路径还会拆分 `prostDecodeMs`、`metadataAndImagesMs`、`frameTableMs`、`finalizeMs` 和 WASM 边界复制耗时。缓存命中不输出。
|
|
235
238
|
|
|
236
239
|
SVGA 礼物在加载阶段被 `destroy()` / `removeGift()` 时,会取消排队任务并终止正在执行的 parser、图片解码、atlas 或 clip Worker。相同 URL 的共享加载按消费者计数,单个礼物取消不会中断其他仍在等待的礼物。
|
|
237
240
|
|
|
238
|
-
- `onError?: (error: Error) => void`
|
|
239
|
-
统一错误回调。
|
|
240
|
-
|
|
241
|
-
- `onSVGARenderPathChange?: (info) => void`
|
|
242
|
-
当 SVGA 礼物完成资格分析、帧表上传、原子晋升或发生回退时通知路径变化。除资源与路径字段外,`info` 还包含 `pathState`、`frameTableBytes`、`commandTableBytes`、`drawBatchMode` 和 `drawCompatibleInstanceCount`。
|
|
243
|
-
|
|
244
|
-
- `onRuntimeDiagnostic?: (event) => void`
|
|
245
|
-
接收 frame abort、replay failure、无时钟 retry、frame controller failure、运行期 fallback、Clip 协议/网格异常、Stencil 事务失败、Atlas 命令无效、Particle group 原子失败、Backend 操作拒绝/隔离、WebGPU uncaptured error、backend loss 和 observer error 等结构化事件。事件只在本地回调,不会由 GiftStage 上传;回调异常会被隔离,不能中断渲染降级事务。
|
|
241
|
+
- `onError?: (error: Error) => void`
|
|
242
|
+
统一错误回调。
|
|
243
|
+
|
|
244
|
+
- `onSVGARenderPathChange?: (info) => void`
|
|
245
|
+
当 SVGA 礼物完成资格分析、帧表上传、原子晋升或发生回退时通知路径变化。除资源与路径字段外,`info` 还包含 `pathState`、`frameTableBytes`、`commandTableBytes`、`drawBatchMode` 和 `drawCompatibleInstanceCount`。
|
|
246
|
+
|
|
247
|
+
- `onRuntimeDiagnostic?: (event) => void`
|
|
248
|
+
接收 frame abort、replay failure、无时钟 retry、frame controller failure、运行期 fallback、Clip 协议/网格异常、Stencil 事务失败、Atlas 命令无效、Particle group 原子失败、Backend 操作拒绝/隔离、WebGPU uncaptured error、backend loss 和 observer error 等结构化事件。事件只在本地回调,不会由 GiftStage 上传;回调异常会被隔离,不能中断渲染降级事务。
|
|
246
249
|
|
|
247
250
|
### `await stage.ready`
|
|
248
251
|
|
|
249
252
|
等待底层后端和运行环境初始化完成。建议在第一次 `addGift()` 前等待。
|
|
250
253
|
|
|
251
|
-
### `stage.addGift(options)`
|
|
254
|
+
### `stage.addGift(options)`
|
|
252
255
|
|
|
253
256
|
插入一个礼物,返回:
|
|
254
257
|
|
|
255
258
|
```ts
|
|
256
|
-
Promise<GiftHandle>;
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### `stage.getDiagnostics()`
|
|
260
|
-
|
|
261
|
-
返回当前 Stage 生命周期内的累计运行诊断快照,包括 frame abort/replay/retry、FastPath fallback、native submitted/rejected draw、WebGPU uncaptured error、backend loss、observer error 以及最后一个结构化事件。该快照不会被性能测试采样窗口重置,返回对象可安全交给业务遥测系统;GiftStage 自身不上传数据。
|
|
259
|
+
Promise<GiftHandle>;
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### `stage.getDiagnostics()`
|
|
262
263
|
|
|
263
|
-
|
|
264
|
+
返回当前 Stage 生命周期内的累计运行诊断快照,包括 frame abort/replay/retry、FastPath fallback、native submitted/rejected draw、WebGPU uncaptured error、backend loss、observer error 以及最后一个结构化事件。该快照不会被性能测试采样窗口重置,返回对象可安全交给业务遥测系统;GiftStage 自身不上传数据。
|
|
265
|
+
|
|
266
|
+
### `GiftHandle` API
|
|
264
267
|
|
|
265
268
|
`addGift()` 返回的句柄可用于控制单个礼物:
|
|
266
269
|
|
|
@@ -269,11 +272,11 @@ Promise<GiftHandle>;
|
|
|
269
272
|
- `gift.pause()`
|
|
270
273
|
- `gift.resume()`
|
|
271
274
|
- 暂停期间礼物播放时钟、图片 `duration` 和后置动画都会冻结
|
|
272
|
-
- `gift.destroy()`
|
|
273
|
-
- 立即移除当前礼物
|
|
274
|
-
- `gift.getRenderInfo()`
|
|
275
|
-
- 返回 SVGA 的实时路径诊断;非 SVGA 或尚未形成资源计划时返回 `null`。`pathState` 为 `preparing | settled | fallback`,`drawBatchMode` 为 `multi-slot | per-slot | hybrid-scheduled`,可直接区分资源共享与实际 Draw 合批状态。
|
|
276
|
-
- `gift.animate(stepOrSteps?)`
|
|
275
|
+
- `gift.destroy()`
|
|
276
|
+
- 立即移除当前礼物
|
|
277
|
+
- `gift.getRenderInfo()`
|
|
278
|
+
- 返回 SVGA 的实时路径诊断;非 SVGA 或尚未形成资源计划时返回 `null`。`pathState` 为 `preparing | settled | fallback`,`drawBatchMode` 为 `multi-slot | per-slot | hybrid-scheduled`,可直接区分资源共享与实际 Draw 合批状态。
|
|
279
|
+
- `gift.animate(stepOrSteps?)`
|
|
277
280
|
- 创建链式动画并返回 `GiftAnimationChain`
|
|
278
281
|
|
|
279
282
|
`GiftAnimationChain` 支持:
|
|
@@ -307,25 +310,25 @@ Promise<GiftHandle>;
|
|
|
307
310
|
|
|
308
311
|
恢复舞台。
|
|
309
312
|
|
|
310
|
-
### `stage.destroy()`
|
|
311
|
-
|
|
312
|
-
销毁舞台并释放资源。
|
|
313
|
-
|
|
314
|
-
### SVGA 帧动画路径
|
|
315
|
-
|
|
316
|
-
SVGA 资源的 9-float 帧行会在准备阶段打包为 3 个 `vec4`。WebGPU 使用持久 storage buffer,WebGL2 使用 `RGBA32F + NEAREST + texelFetch` 数据纹理。CPU 始终权威维护帧号、循环、暂停、Seek、音频与回调;GPU 根据该帧号读取子 Sprite 矩阵、透明度和可见性。
|
|
317
|
-
|
|
318
|
-
Direct 对连续且兼容的同资源 slot 使用 4 个 `vec4`/slot 的父级状态并进行 slot-major 实例化合批;多 Atlas、不同 MotionTrack binding 或无法证明重排安全的区间继续使用 per-slot Direct,不回退 CPU。Hybrid 在资源准备期生成 `frameOffsets + operations + spriteIndices + meshReferences` 不可变命令表,并把连续同 Atlas 的纹理操作进一步预编译为 execution run;运行时只读取当前帧 run slice。Texture、Shape 和 Clip Mask Shader 读取同一核心帧表,每帧动态上传仍只有 slot 父级状态。结构相同的不同权威帧可通过 `frameScheduleIds` 共用一次合批;矩形纹理 Clip 使用静态本地裁剪 metadata,不增加 Stencil pass。MoveTo-only、线段、重复点或零面积 Clip 按 SVG/Canvas 的空裁剪语义直接隐藏对应 Sprite,不创建 Mesh/Stencil,也不会触发资源回退。
|
|
319
|
-
|
|
320
|
-
- `gpu-direct`:普通 atlas sprite 的帧变换、透明度和布局由 GPU 求值。
|
|
321
|
-
- `gpu-hybrid`:Shape/Clip 的精确 paint order 与 Draw/Stencil 提交由 CPU 按不可变命令表调度,Texture、Shape、Clip Mask 的动画属性都由 GPU 帧表求值。
|
|
322
|
-
- `cpu-reference`:WebGL1、动态 `svgaSlots`、表校验/上传失败、预算不足或策略为 `cpu` 时使用确定性的 CPU 路径。
|
|
323
|
-
|
|
324
|
-
插件可通过 `stage.capabilities.svgaFrameTimeline` 判断 `transport`(`storage-buffer`、`float-texture` 或 `unavailable`)、正式 `direct`/`hybrid` 能力、`supportedPaths` 和 `maxTableBytes`,不需要启用 experimental policy。同一解析资源的多个实例共享帧表、静态 metadata 和 Hybrid Command Table;`compatibleInstanceCount` 表示资源共享数,实际本帧合批数量由 `drawCompatibleInstanceCount` 报告。
|
|
325
|
-
|
|
326
|
-
`addGift()` 不等待 GPU 帧表:非预加载礼物先显示 CPU reference 首帧,再在完整帧边界原子晋升。`preload('svga')` 会等待同一资源级帧表与调度准备完成。FastPath 提交若被后端拒绝,会丢弃未提交帧、同步降级该资源,并在同一 RAF 以原顺序完整重放一次;重放再次失败时 WebGL2 会清成透明帧,并在下一 RAF 不推进 CPU 权威时间轴地重试。不支持该帧事务的自定义 Backend 会直接使用 CPU Reference。WebGL1、动态 `svgaSlots`、能力/尺寸/预算校验失败和上传失败均按资源缓存回退,不逐帧重试;Stage 与单礼物都可用 `svgaFrameEvaluation: 'cpu'` 强制关闭。
|
|
327
|
-
|
|
328
|
-
性能诊断中的 `submittedDrawCalls` 仅表示命令已经到达 WebGL `drawElements*` 或 WebGPU `drawIndexed` 调用/编码;它不表示 GPU 已经执行完成。`rejectedDrawCalls` 表示在原生提交前被后端校验或容量检查拒绝。GPU error scope、pipeline validation 与 framebuffer 像素门禁用于补充验证执行结果。
|
|
313
|
+
### `stage.destroy()`
|
|
314
|
+
|
|
315
|
+
销毁舞台并释放资源。
|
|
316
|
+
|
|
317
|
+
### SVGA 帧动画路径
|
|
318
|
+
|
|
319
|
+
SVGA 资源的 9-float 帧行会在准备阶段打包为 3 个 `vec4`。WebGPU 使用持久 storage buffer,WebGL2 使用 `RGBA32F + NEAREST + texelFetch` 数据纹理。CPU 始终权威维护帧号、循环、暂停、Seek、音频与回调;GPU 根据该帧号读取子 Sprite 矩阵、透明度和可见性。
|
|
320
|
+
|
|
321
|
+
Direct 对连续且兼容的同资源 slot 使用 4 个 `vec4`/slot 的父级状态并进行 slot-major 实例化合批;多 Atlas、不同 MotionTrack binding 或无法证明重排安全的区间继续使用 per-slot Direct,不回退 CPU。Hybrid 在资源准备期生成 `frameOffsets + operations + spriteIndices + meshReferences` 不可变命令表,并把连续同 Atlas 的纹理操作进一步预编译为 execution run;运行时只读取当前帧 run slice。Texture、Shape 和 Clip Mask Shader 读取同一核心帧表,每帧动态上传仍只有 slot 父级状态。结构相同的不同权威帧可通过 `frameScheduleIds` 共用一次合批;矩形纹理 Clip 使用静态本地裁剪 metadata,不增加 Stencil pass。MoveTo-only、线段、重复点或零面积 Clip 按 SVG/Canvas 的空裁剪语义直接隐藏对应 Sprite,不创建 Mesh/Stencil,也不会触发资源回退。
|
|
322
|
+
|
|
323
|
+
- `gpu-direct`:普通 atlas sprite 的帧变换、透明度和布局由 GPU 求值。
|
|
324
|
+
- `gpu-hybrid`:Shape/Clip 的精确 paint order 与 Draw/Stencil 提交由 CPU 按不可变命令表调度,Texture、Shape、Clip Mask 的动画属性都由 GPU 帧表求值。
|
|
325
|
+
- `cpu-reference`:WebGL1、动态 `svgaSlots`、表校验/上传失败、预算不足或策略为 `cpu` 时使用确定性的 CPU 路径。
|
|
326
|
+
|
|
327
|
+
插件可通过 `stage.capabilities.svgaFrameTimeline` 判断 `transport`(`storage-buffer`、`float-texture` 或 `unavailable`)、正式 `direct`/`hybrid` 能力、`supportedPaths` 和 `maxTableBytes`,不需要启用 experimental policy。同一解析资源的多个实例共享帧表、静态 metadata 和 Hybrid Command Table;`compatibleInstanceCount` 表示资源共享数,实际本帧合批数量由 `drawCompatibleInstanceCount` 报告。
|
|
328
|
+
|
|
329
|
+
`addGift()` 不等待 GPU 帧表:非预加载礼物先显示 CPU reference 首帧,再在完整帧边界原子晋升。`preload('svga')` 会等待同一资源级帧表与调度准备完成。FastPath 提交若被后端拒绝,会丢弃未提交帧、同步降级该资源,并在同一 RAF 以原顺序完整重放一次;重放再次失败时 WebGL2 会清成透明帧,并在下一 RAF 不推进 CPU 权威时间轴地重试。不支持该帧事务的自定义 Backend 会直接使用 CPU Reference。WebGL1、动态 `svgaSlots`、能力/尺寸/预算校验失败和上传失败均按资源缓存回退,不逐帧重试;Stage 与单礼物都可用 `svgaFrameEvaluation: 'cpu'` 强制关闭。
|
|
330
|
+
|
|
331
|
+
性能诊断中的 `submittedDrawCalls` 仅表示命令已经到达 WebGL `drawElements*` 或 WebGPU `drawIndexed` 调用/编码;它不表示 GPU 已经执行完成。`rejectedDrawCalls` 表示在原生提交前被后端校验或容量检查拒绝。GPU error scope、pipeline validation 与 framebuffer 像素门禁用于补充验证执行结果。
|
|
329
332
|
|
|
330
333
|
## `addGift()` 参数
|
|
331
334
|
|
|
@@ -741,9 +744,20 @@ await stage.addGift({
|
|
|
741
744
|
异常情况处理:
|
|
742
745
|
|
|
743
746
|
- `IndexedDB` 不可用、事务失败、写入失败、容量不足时,会自动降级
|
|
744
|
-
- 损坏的 `SVGA` 磁盘缓存会自动删除并重新生成
|
|
745
|
-
|
|
746
|
-
|
|
747
|
+
- 损坏的 `SVGA` 磁盘缓存会自动删除并重新生成
|
|
748
|
+
|
|
749
|
+
### SVGA 半透明边缘与 Safari 首播
|
|
750
|
+
|
|
751
|
+
Worker 首次合成图集和缓存 PNG 解码都显式使用 `premultiplyAlpha: 'premultiply'`,
|
|
752
|
+
上传时声明 `sourcePremultiplied: true`。不要改回直接使用 `transferToImageBitmap()`:
|
|
753
|
+
WebKit 的该路径可能丢失预乘标记,而 WebGL 对 ImageBitmap 会忽略上传时的预乘开关,
|
|
754
|
+
导致无缓存首播的半透明边缘发白、过亮,缓存播放却正常。
|
|
755
|
+
|
|
756
|
+
运行 `node scripts/verify-svga-atlas-alpha.mjs` 可在 Chromium 中检查 WebGL1/2 的
|
|
757
|
+
Worker 首次合成、PNG 缓存解码及主线程回退像素;加 `--webkit` 可使用已安装的
|
|
758
|
+
Playwright WebKit。该检查不替代真实 iPhone / Mac Safari 的素材回归。
|
|
759
|
+
|
|
760
|
+
## 项目结构
|
|
747
761
|
|
|
748
762
|
主要目录:
|
|
749
763
|
|
|
@@ -764,7 +778,7 @@ await stage.addGift({
|
|
|
764
778
|
|
|
765
779
|
- [src/index.ts](/D:/MyDocuments/UnityProjects/SVGAPlayer-Unity/gift-stage/src/index.ts)
|
|
766
780
|
|
|
767
|
-
主要导出:
|
|
781
|
+
主要导出:
|
|
768
782
|
|
|
769
783
|
- `GiftStage`
|
|
770
784
|
- `createBackend`
|
|
@@ -774,19 +788,19 @@ await stage.addGift({
|
|
|
774
788
|
- `parseSVGA`
|
|
775
789
|
- `buildAtlas`
|
|
776
790
|
- `parseVAPConfig`
|
|
777
|
-
- 相关类型定义
|
|
778
|
-
|
|
779
|
-
### 第三方 `GPUBackend` 迁移
|
|
780
|
-
|
|
781
|
-
`GPUBackend` 的帧与提交操作使用显式结果契约。第三方实现必须让 `beginFrame()`、`draw(command)`、`endFrame()` 和 `abortFrame()` 返回:
|
|
782
|
-
|
|
783
|
-
```ts
|
|
784
|
-
{ submitted: true }
|
|
785
|
-
// 或
|
|
786
|
-
{ submitted: false, reason, message? }
|
|
787
|
-
```
|
|
788
|
-
|
|
789
|
-
稳定的 `reason` 为 `backend-lost | invalid-command | missing-resource | capacity | validation-error | submission-error`。只有真正到达原生 `drawElements` / `drawIndexed` 或成功完成对应帧操作时才能返回 `submitted: true`;不得再实现或依赖 `wasLastDrawSubmitted()`,也不得用性能计数差值推断提交结果。`abortFrame()` 拒绝表示无法保证失败帧被丢弃,Stage 会立即隔离该 Backend。
|
|
791
|
+
- 相关类型定义
|
|
792
|
+
|
|
793
|
+
### 第三方 `GPUBackend` 迁移
|
|
794
|
+
|
|
795
|
+
`GPUBackend` 的帧与提交操作使用显式结果契约。第三方实现必须让 `beginFrame()`、`draw(command)`、`endFrame()` 和 `abortFrame()` 返回:
|
|
796
|
+
|
|
797
|
+
```ts
|
|
798
|
+
{ submitted: true }
|
|
799
|
+
// 或
|
|
800
|
+
{ submitted: false, reason, message? }
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
稳定的 `reason` 为 `backend-lost | invalid-command | missing-resource | capacity | validation-error | submission-error`。只有真正到达原生 `drawElements` / `drawIndexed` 或成功完成对应帧操作时才能返回 `submitted: true`;不得再实现或依赖 `wasLastDrawSubmitted()`,也不得用性能计数差值推断提交结果。`abortFrame()` 拒绝表示无法保证失败帧被丢弃,Stage 会立即隔离该 Backend。
|
|
790
804
|
|
|
791
805
|
## Demo
|
|
792
806
|
|
|
@@ -111,6 +111,7 @@ export declare class GiftStage {
|
|
|
111
111
|
* playbacks can start directly on the selected GPU path.
|
|
112
112
|
*/
|
|
113
113
|
private ensureSVGAFrameTable;
|
|
114
|
+
private assertSVGAFrameTableActive;
|
|
114
115
|
private refreshSVGATimelineSlots;
|
|
115
116
|
private assignSVGATimelineStateToSlot;
|
|
116
117
|
private releaseSVGAFrameTable;
|