@taole/giftstage 0.1.32 → 0.1.33

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.
@@ -20,7 +20,9 @@ export declare class WebGL1Backend implements GPUBackend {
20
20
  init(): Promise<void>;
21
21
  private initPrograms;
22
22
  private getUniforms;
23
- beginFrame(): void;
23
+ beginFrame(options?: {
24
+ stencil?: boolean;
25
+ }): void;
24
26
  endFrame(): void;
25
27
  private getBufferSourceByteLength;
26
28
  private normalizeIndexSource;
@@ -35,7 +35,9 @@ export declare class WebGL2Backend implements GPUBackend {
35
35
  init(): Promise<void>;
36
36
  private initPrograms;
37
37
  private getUniforms;
38
- beginFrame(): void;
38
+ beginFrame(options?: {
39
+ stencil?: boolean;
40
+ }): void;
39
41
  endFrame(): void;
40
42
  private getBufferSourceByteLength;
41
43
  createBuffer(data: GPUBufferSource, usage: BufferUsage): GPUBufferHandle;
@@ -20,6 +20,7 @@ export declare class WebGPUBackend implements GPUBackend {
20
20
  private texturedBindGroupLayout;
21
21
  private dualTexturedBindGroupLayout;
22
22
  private instancedTextureBindGroupLayout;
23
+ private uniformOnlyBindGroupLayout;
23
24
  /** `device.limits.minUniformBufferOffsetAlignment` (typically 256). */
24
25
  private uniformSlotStride;
25
26
  /** Ring size for per-draw uniforms (`queue.writeBuffer` must not overwrite before draw — see `draw()`). */
@@ -29,6 +30,7 @@ export declare class WebGPUBackend implements GPUBackend {
29
30
  /** Skip redundant `setPipeline` / stencil / VB-IB when drawing many quads with the same geometry. */
30
31
  private lastDrawPipeline;
31
32
  private lastStencilRef;
33
+ private frameUsesStencil;
32
34
  private lastVertexBufferId;
33
35
  private lastIndexBufferId;
34
36
  /** Single 160-byte upload for textured draws (replaces multiple `writeBuffer` calls). */
@@ -98,8 +100,9 @@ export declare class WebGPUBackend implements GPUBackend {
98
100
  constructor(canvas: HTMLCanvasElement, adapter: GPUAdapter, wantAntialias?: boolean);
99
101
  init(): Promise<void>;
100
102
  private configureCanvasContext;
101
- private ensureDepthStencil;
103
+ private ensureFrameAttachments;
102
104
  private initPipelines;
105
+ private ensureStencilPipelines;
103
106
  private ensureInstancedProjectionBuffer;
104
107
  private ensureInstancedStorageBuffer;
105
108
  private ensureInstancedSvgaPipeline;
@@ -110,7 +113,9 @@ export declare class WebGPUBackend implements GPUBackend {
110
113
  private createInstancedAlphaVideoPipeline;
111
114
  private createTexturedPipeline;
112
115
  private createClipMaskPipeline;
113
- beginFrame(): void;
116
+ beginFrame(options?: {
117
+ stencil?: boolean;
118
+ }): void;
114
119
  endFrame(): void;
115
120
  private ensureInstancedProjection;
116
121
  private gpuBufferUsage;
@@ -18,6 +18,7 @@ export declare class AlphaVideoRenderer {
18
18
  private readonly processedHtmlGatesScratch;
19
19
  private readonly instancedTexturesScratch;
20
20
  private readonly instancedUniformsScratch;
21
+ constructor(onHtmlVideoFrame?: (video: HTMLVideoElement) => void);
21
22
  private readonly instancedDrawCommand;
22
23
  private readonly geometryTexturesScratch;
23
24
  private readonly geometryUniformsScratch;
@@ -63,11 +63,15 @@ export declare class SVGABatchRenderer {
63
63
  private drawGroupScratch;
64
64
  /** Per-entity result of the "any frame has shapes" scan (no-atlas render check). */
65
65
  private entityHasShapesCache;
66
+ /** 0=no clip, 1=scissor-compatible clips only, 2=stencil required, 255=not analyzed. */
67
+ private entityFrameClipModeCache;
66
68
  private readonly affineScratch;
67
69
  beginFrame(backend: GPUBackend): void;
68
70
  flush(backend: GPUBackend, slots: Map<string, GiftSlot>): void;
69
71
  drawSlot(backend: GPUBackend, slot: GiftSlot): void;
70
72
  drawSlots(backend: GPUBackend, slots: Iterable<GiftSlot>): void;
73
+ requiresStencil(slots: Iterable<GiftSlot>): boolean;
74
+ private getFrameClipMode;
71
75
  prewarmClipMeshes(entity: Pick<VideoEntity, 'spriteTable'>, options?: SVGAClipPrewarmOptions): Promise<number>;
72
76
  hydrateClipMeshes(meshes: SVGAClipMeshMap | null | undefined): void;
73
77
  snapshotClipMeshes(entity: Pick<VideoEntity, 'spriteTable'>): SVGAClipMeshMap;
@@ -17,6 +17,7 @@ export declare class VAPRenderer {
17
17
  private scratchTransform;
18
18
  private readonly processedHtmlGatesScratch;
19
19
  private readonly vapVertexScratch;
20
+ constructor(onHtmlVideoFrame?: (video: HTMLVideoElement) => void);
20
21
  private projCacheW;
21
22
  private projCacheH;
22
23
  private projCache;
@@ -62,7 +62,9 @@ export interface GPUBackend {
62
62
  /** Maximum supported 2D texture dimension for this backend/device. */
63
63
  readonly maxTextureSize?: number;
64
64
  init(): Promise<void>;
65
- beginFrame(): void;
65
+ beginFrame(options?: {
66
+ stencil?: boolean;
67
+ }): void;
66
68
  endFrame(): void;
67
69
  createBuffer(data: GPUBufferSource, usage: BufferUsage): GPUBufferHandle;
68
70
  updateBuffer(handle: GPUBufferHandle, data: GPUBufferSource, offset?: number): void;
@@ -318,9 +320,9 @@ export interface GiftStageOptions {
318
320
  } | false;
319
321
  /**
320
322
  * Edge smoothing: WebGL2 uses the context multisampled framebuffer; WebGPU uses 4× MSAA + resolve.
321
- * Default: **true** for WebGL2, **false** for WebGPU (MSAA is expensive with large transparent-video fills).
322
- * Set `true` explicitly when using WebGPU + sharp SVGA edges.
323
- * Many concurrent transparent videos: keep WebGPU `antialias` off (default) and consider lowering {@link resolution}.
323
+ * Default: **true** for WebGL2 and WebGPU.
324
+ * Many concurrent transparent videos: consider setting `antialias: false` and lowering {@link resolution}
325
+ * when fill-rate or framebuffer bandwidth becomes the bottleneck.
324
326
  */
325
327
  antialias?: boolean;
326
328
  /**
@@ -4,6 +4,7 @@
4
4
  * when many `<video>` elements run together (especially with WebGPU texture copies).
5
5
  */
6
6
  export declare class HtmlVideoUploadGate {
7
+ private readonly onFrameAvailable?;
7
8
  private readonly frameInfo;
8
9
  private readonly pending;
9
10
  private readonly lastHandle;
@@ -18,12 +19,16 @@ export declare class HtmlVideoUploadGate {
18
19
  private readonly stagnationLogged;
19
20
  /** When `requestVideoFrameCallback` is missing, fall back to `currentTime` changes (coarser than rVFC). */
20
21
  private readonly lastTimeFallback;
22
+ /** Low-frequency wake-up used to detect browsers that stop delivering rVFC callbacks. */
23
+ private readonly healthTimers;
24
+ constructor(onFrameAvailable?: (video: HTMLVideoElement) => void);
21
25
  /**
22
26
  * Returns true when `updateTexture` should run for this slot: first time, or a new decoded frame was signaled.
23
27
  */
24
28
  preUpload(slotId: string, video: HTMLVideoElement): boolean;
25
29
  getFrameInfo(slotId: string): VideoFrameCallbackMetadata | undefined;
26
30
  private ensureRvf;
31
+ private ensureHealthTimer;
27
32
  private consumeTimeAdvance;
28
33
  private markProgress;
29
34
  private tryRecoverStalledPlayback;
@@ -1,6 +1,52 @@
1
1
  import type { SVGAWorkerMoviePayload } from '../parsers/svga-parser-worker-client';
2
2
  type PersistKind = 'arrayBuffer' | 'text';
3
3
  type MemoryKind = PersistKind | 'json' | 'svga-payload' | 'svga-asset';
4
+ export declare class AsyncLimiter {
5
+ private maxConcurrent;
6
+ private active;
7
+ private queue;
8
+ constructor(maxConcurrent: number);
9
+ setMaxConcurrent(maxConcurrent: number): void;
10
+ run<T>(task: () => Promise<T>): Promise<T>;
11
+ private drain;
12
+ }
13
+ export declare class ResourceCacheManager {
14
+ private readonly limiter;
15
+ private readonly pending;
16
+ private readonly memory;
17
+ private memoryBytes;
18
+ private maxMemoryBytes;
19
+ private maxPersistentBytes;
20
+ private dbPromise;
21
+ private persistentTrimPromise;
22
+ configure(opts?: {
23
+ maxConcurrent?: number;
24
+ maxMemoryBytes?: number;
25
+ maxPersistentBytes?: number;
26
+ }): void;
27
+ runLimited<T>(task: () => Promise<T>): Promise<T>;
28
+ fetchArrayBuffer(url: string, signal?: AbortSignal): Promise<ArrayBuffer>;
29
+ fetchText(url: string, signal?: AbortSignal): Promise<string>;
30
+ fetchJSON<T>(url: string, signal?: AbortSignal): Promise<T>;
31
+ getSVGAWorkerPayload(cacheKey: string): SVGAWorkerMoviePayload | null;
32
+ setSVGAWorkerPayload(cacheKey: string, payload: SVGAWorkerMoviePayload): void;
33
+ getMemoryValue<T>(key: string, kind: MemoryKind): T | null;
34
+ setMemoryValue<T>(key: string, kind: MemoryKind, value: T, size: number): void;
35
+ getPersistedArrayBuffer(key: string): Promise<ArrayBuffer | null>;
36
+ setPersistedArrayBuffer(key: string, value: ArrayBuffer): Promise<void>;
37
+ deletePersistedValue(key: string): Promise<void>;
38
+ private getOrCreatePending;
39
+ private getMemory;
40
+ private setMemory;
41
+ private trimMemory;
42
+ private openDb;
43
+ private getPersistent;
44
+ private setPersistent;
45
+ private touchPersistent;
46
+ private schedulePersistentTrim;
47
+ private trimPersistent;
48
+ private deletePersistent;
49
+ }
4
50
  export declare function configureResourceCache(opts?: {
5
51
  maxConcurrent?: number;
6
52
  maxMemoryBytes?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taole/giftstage",
3
- "version": "0.1.32",
3
+ "version": "0.1.33",
4
4
  "description": "High-performance WebGPU/WebGL gift animation player unifying SVGA, VAP, AlphaVideo, and images",
5
5
  "type": "module",
6
6
  "main": "dist/gift-stage.cjs.js",
@@ -33,6 +33,8 @@
33
33
  "test:watch": "vitest",
34
34
  "test:browser": "vitest run --browser.enabled --browser.name=chromium",
35
35
  "test:e2e": "playwright test",
36
+ "test:perf": "node scripts/run-performance.mjs",
37
+ "perf:record": "node scripts/run-performance.mjs --record",
36
38
  "lint": "eslint src/ tests/",
37
39
  "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
38
40
  "typecheck": "tsc --noEmit",
@@ -46,6 +48,7 @@
46
48
  "@vitest/browser": "^3.0.0",
47
49
  "@webgpu/types": "^0.1.69",
48
50
  "eslint": "^9.0.0",
51
+ "fake-indexeddb": "^6.2.5",
49
52
  "jsdom": "^24.1.3",
50
53
  "playwright": "^1.50.0",
51
54
  "prettier": "^3.4.0",