@taole/giftstage 0.1.33 → 0.1.35

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.
@@ -19,7 +19,23 @@ export declare class WebGL1Backend implements GPUBackend {
19
19
  constructor(canvas: HTMLCanvasElement, antialias?: boolean);
20
20
  init(): Promise<void>;
21
21
  private initPrograms;
22
- private getUniforms;
22
+ private makeProgramEntry;
23
+ /**
24
+ * `u_transform` on `svga-batch-premul` defaults to identity; shape draws overwrite it and
25
+ * this re-upload restores it for the next plain batch draw. Uploaded unconditionally because
26
+ * renderers mutate their scratch transform arrays in place (reference never changes).
27
+ */
28
+ private applyIdentityTransform;
29
+ /** Sampler uniforms are constant per shader; set them once instead of every draw. */
30
+ private bindProgramSamplers;
31
+ /**
32
+ * `u_transform` always comes from a renderer-owned scratch `Float32Array` that gets
33
+ * overwritten in place per draw, so its reference never changes — only its content does.
34
+ * Skipping the upload based on reference equality would silently apply a stale transform,
35
+ * so unlike `u_projection` (whose cached arrays are replaced, not mutated, on resize) it is
36
+ * uploaded unconditionally here.
37
+ */
38
+ private applyDrawUniforms;
23
39
  beginFrame(options?: {
24
40
  stencil?: boolean;
25
41
  }): void;
@@ -22,8 +22,16 @@ export declare class WebGL2Backend implements GPUBackend {
22
22
  private videoElementDirectUploadValidated;
23
23
  /** DYNAMIC_DRAW upload target for `svga-instanced-premul` (`FrameJobData` per instance). */
24
24
  private static readonly INST_SVGA_GL_MAX;
25
+ private static readonly INST_SVGA_GL_FLOATS;
26
+ private static readonly INST_SVGA_GL_STRIDE;
25
27
  private static readonly INST_SVGA_GL_BYTES;
26
28
  private instancedSvgaInstanceGLBuffer;
29
+ /** DYNAMIC_DRAW upload target for instanced clip-mask affine transforms. */
30
+ private static readonly INST_CLIP_MASK_GL_MAX;
31
+ private static readonly INST_CLIP_MASK_GL_FLOATS;
32
+ private static readonly INST_CLIP_MASK_GL_STRIDE;
33
+ private static readonly INST_CLIP_MASK_GL_BYTES;
34
+ private instancedClipMaskGLBuffer;
27
35
  /** DYNAMIC_DRAW upload target for `alpha-video-instanced` (rect+atlasRemap+opacity per instance). */
28
36
  private static readonly INST_ALPHA_GL_MAX;
29
37
  private static readonly INST_ALPHA_GL_BYTES;
@@ -34,7 +42,25 @@ export declare class WebGL2Backend implements GPUBackend {
34
42
  constructor(canvas: HTMLCanvasElement, antialias?: boolean);
35
43
  init(): Promise<void>;
36
44
  private initPrograms;
37
- private getUniforms;
45
+ private makeProgramEntry;
46
+ /**
47
+ * `u_transform` on `svga-batch-premul` defaults to identity; shape draws overwrite it and
48
+ * this re-upload restores it for the next plain batch draw. Uploaded unconditionally because
49
+ * renderers mutate their scratch transform arrays in place (reference never changes).
50
+ */
51
+ private applyIdentityTransform;
52
+ /** Sampler uniforms are constant per shader; set them once instead of every draw. */
53
+ private bindProgramSamplers;
54
+ /** Shared by `draw()` and the instanced draw paths, which only ever supply `u_projection`. */
55
+ private applyProjectionUniform;
56
+ /**
57
+ * `u_transform` always comes from a renderer-owned scratch `Float32Array` that gets
58
+ * overwritten in place per draw, so its reference never changes — only its content does.
59
+ * Skipping the upload based on reference equality would silently apply a stale transform,
60
+ * so unlike `u_projection` (whose cached arrays are replaced, not mutated, on resize) it is
61
+ * uploaded unconditionally here.
62
+ */
63
+ private applyDrawUniforms;
38
64
  beginFrame(options?: {
39
65
  stencil?: boolean;
40
66
  }): void;
@@ -63,6 +89,8 @@ export declare class WebGL2Backend implements GPUBackend {
63
89
  private deleteAllVertexArrays;
64
90
  private ensureInstancedSvgaInstanceBuffer;
65
91
  private drawInstancedSvgaGL;
92
+ private ensureInstancedClipMaskBuffer;
93
+ private drawInstancedClipMaskGL;
66
94
  private ensureInstancedAlphaInstanceBuffer;
67
95
  private drawInstancedAlphaGL;
68
96
  private ensureInstancedVapInstanceBuffer;
@@ -27,6 +27,19 @@ export declare class WebGPUBackend implements GPUBackend {
27
27
  private readonly maxUniformSlots;
28
28
  /** Resets each `beginFrame`. */
29
29
  private uniformSlotIndex;
30
+ /**
31
+ * CPU-side mirror of `uniformBuffer`, sized identically. Per-draw uniform writes go here
32
+ * instead of `queue.writeBuffer` directly; `endFrame` uploads the touched byte range in one
33
+ * `writeBuffer` call before `submit`, cutting dozens of JS→native calls per frame down to one
34
+ * (writes are visible to the frame's command buffer as long as they land before `submit`).
35
+ * Eagerly sized from the default stride/slot count so it's always usable even before `init()`
36
+ * creates the real GPU buffer (matching size); `init()` reallocates it to the device's actual
37
+ * uniform offset alignment.
38
+ */
39
+ private uniformShadow;
40
+ /** Half-open touched range `[min, max)` in `uniformShadow`; reset each `beginFrame`. */
41
+ private uniformShadowDirtyMin;
42
+ private uniformShadowDirtyMax;
30
43
  /** Skip redundant `setPipeline` / stencil / VB-IB when drawing many quads with the same geometry. */
31
44
  private lastDrawPipeline;
32
45
  private lastStencilRef;
@@ -72,18 +85,16 @@ export declare class WebGPUBackend implements GPUBackend {
72
85
  private dualTexturedBindGroupCache;
73
86
  /** All instanced pipelines also share one texture layout. */
74
87
  private instancedTextureBindGroupCache;
75
- /** Batched SVGA sprites (FrameJobData packed as 13 floats per instance). */
88
+ /** Batched SVGA sprites (pre-scaled affine, UVs, and packed framebuffer clip rect). */
76
89
  private static readonly SVGA_INSTANCED_MAX;
77
90
  private static readonly SVGA_INSTANCED_STRIDE;
91
+ private static readonly CLIP_MASK_INSTANCED_MAX;
92
+ private static readonly CLIP_MASK_INSTANCED_STRIDE;
78
93
  /** Batched alpha-video (storage instances + projection uniform). */
79
94
  private static readonly ALPHA_INSTANCED_MAX;
80
95
  private static readonly ALPHA_INSTANCED_STRIDE;
81
96
  private static readonly VAP_INSTANCED_MAX;
82
97
  private static readonly VAP_INSTANCED_STRIDE;
83
- /** One draw may bind up to this many bytes of instance storage (max instances × stride). */
84
- private static readonly INSTANCED_SVGA_CHUNK_BYTES;
85
- private static readonly INSTANCED_ALPHA_CHUNK_BYTES;
86
- private static readonly INSTANCED_VAP_CHUNK_BYTES;
87
98
  /**
88
99
  * Multiple `queue.writeBuffer(..., offset 0)` to the same storage buffer before one `submit` only keep the
89
100
  * last write; one shared ring + dynamic offsets keeps all instanced paths non-overlapping until submit.
@@ -94,9 +105,19 @@ export declare class WebGPUBackend implements GPUBackend {
94
105
  private storageBindOffsetAlign;
95
106
  /** Reset in `beginFrame`; all instanced draw types reserve non-overlapping chunks. */
96
107
  private instancedStorageRingOffset;
108
+ /** Grow-only CPU mirror; expands to the frame's actual storage high-water mark. */
109
+ private instancedStorageShadow;
110
+ private instancedStorageShadowDirtyMax;
97
111
  private readonly instancedProjectionCache;
98
112
  private instancedProjectionValid;
113
+ /** Storage range written by the latest instanced clip-mask write pass; reused by its clear. */
114
+ private lastClipMaskStorageBase;
115
+ private lastClipMaskStorageByteLength;
99
116
  private lastInstancedTextureBindGroup;
117
+ private performanceBufferWrites;
118
+ private performanceBufferWriteBytes;
119
+ private performanceStorageBufferWrites;
120
+ private performanceStorageBufferWriteBytes;
100
121
  constructor(canvas: HTMLCanvasElement, adapter: GPUAdapter, wantAntialias?: boolean);
101
122
  init(): Promise<void>;
102
123
  private configureCanvasContext;
@@ -105,10 +126,13 @@ export declare class WebGPUBackend implements GPUBackend {
105
126
  private ensureStencilPipelines;
106
127
  private ensureInstancedProjectionBuffer;
107
128
  private ensureInstancedStorageBuffer;
129
+ private ensureInstancedDataBindGroup;
108
130
  private ensureInstancedSvgaPipeline;
131
+ private ensureInstancedClipMaskPipeline;
109
132
  private ensureInstancedAlphaPipeline;
110
133
  private ensureInstancedVapPipeline;
111
134
  private createInstancedSvgaPipeline;
135
+ private createInstancedClipMaskPipeline;
112
136
  private createVapInstancedPipeline;
113
137
  private createInstancedAlphaVideoPipeline;
114
138
  private createTexturedPipeline;
@@ -117,6 +141,21 @@ export declare class WebGPUBackend implements GPUBackend {
117
141
  stencil?: boolean;
118
142
  }): void;
119
143
  endFrame(): void;
144
+ getPerformanceSnapshot(): {
145
+ bufferWrites: number;
146
+ bufferWriteBytes: number;
147
+ storageBufferWrites: number;
148
+ storageBufferWriteBytes: number;
149
+ };
150
+ resetPerformanceSnapshot(): void;
151
+ private writeBuffer;
152
+ /** Uploads the touched range of `uniformShadow` in one call — must run before `queue.submit`. */
153
+ private flushUniformShadow;
154
+ /** Uploads every instanced draw's non-overlapping shadow range in one call before submit. */
155
+ private flushInstancedStorageShadow;
156
+ private writeInstancedStorageShadow;
157
+ /** Records a per-draw uniform write into the CPU shadow instead of touching the GPU buffer. */
158
+ private writeUniformShadow;
120
159
  private ensureInstancedProjection;
121
160
  private gpuBufferUsage;
122
161
  private bufferSourceByteLength;
@@ -150,6 +189,7 @@ export declare class WebGPUBackend implements GPUBackend {
150
189
  draw(cmd: DrawCommand): void;
151
190
  /** One `drawIndexed` with `instanceCount` for all SVGA sprites sharing the same atlas. */
152
191
  private drawInstancedSvga;
192
+ private drawInstancedClipMask;
153
193
  /** One `drawIndexed` with `instanceCount` for all gifts sharing the same video texture (e.g. atlas). */
154
194
  private drawInstancedAlpha;
155
195
  private drawInstancedVap;
@@ -2,7 +2,7 @@
2
2
  * SVGA sprite SoA table: flat frame floats + deduped clip/shapes side tables.
3
3
  * Replaces per-sprite `frames: SVGAFrame[]` object graphs on the hot path.
4
4
  */
5
- import type { SVGAShape, SVGATransform } from '../types';
5
+ import type { SVGAParams, SVGAShape, SVGATransform } from '../types';
6
6
  /** Floats per frame in `frameData`: layoutW, layoutH, a, b, c, d, tx, ty, alpha. */
7
7
  export declare const SPRITE_FRAME_FLOATS = 9;
8
8
  export interface SVGASpriteTable {
@@ -20,6 +20,7 @@ export interface SVGASpriteTable {
20
20
  /** spriteCount × frameCount; -1 = none. */
21
21
  shapesIndex: Int32Array;
22
22
  hasAnyShapes: boolean;
23
+ allFramesInsideViewBox?: boolean;
23
24
  }
24
25
  /** Loose frame shape used when converting from AoS decode (JS proto / fixtures). */
25
26
  export interface SVGAFrameLike {
@@ -55,5 +56,10 @@ export declare function getSpriteClipPath(table: SVGASpriteTable, spriteIndex: n
55
56
  * Resolves shape `keep` chains to shared array references.
56
57
  */
57
58
  export declare function spriteTableFromSprites(sprites: SVGASpriteLike[], frameCountHint?: number): SVGASpriteTable;
59
+ /**
60
+ * Compute the renderer's scissor-elision flag before the entity becomes renderable. Shapes are
61
+ * conservative because their geometry is not represented by the sprite layout rectangle.
62
+ */
63
+ export declare function ensureAllFramesInsideViewBox(params: Pick<SVGAParams, 'viewBoxWidth' | 'viewBoxHeight'>, table: SVGASpriteTable): boolean;
58
64
  /** Empty table used when there are no sprites. */
59
65
  export declare function emptySpriteTable(frameCount?: number): SVGASpriteTable;
@@ -1,20 +1,22 @@
1
1
  import type { VAPConfig, VAPFrameItem } from '../types';
2
2
  export declare function parseVAPConfig(config: string | object): Promise<VAPConfig>;
3
3
  export declare function getVAPFrame(config: VAPConfig, frameIndex: number): VAPFrameItem | undefined;
4
- /**
5
- * Logical content size for layout/aspect (matches visible RGB frame, not full mp4 frame).
6
- * `videoW`/`videoH` often include separate alpha bands; use `w`/`h` or `rgbFrame` w×h.
7
- */
8
- export declare function getVAPContentSize(info: VAPConfig['info']): {
4
+ export interface VAPContentSize {
9
5
  w: number;
10
6
  h: number;
11
- };
7
+ }
12
8
  /**
13
- * Compute normalized UV coordinates for a frame region within the video texture.
9
+ * Logical content size for layout/aspect (matches visible RGB frame, not full mp4 frame).
10
+ * `videoW`/`videoH` often include separate alpha bands; use `w`/`h` or `rgbFrame` w×h.
14
11
  */
15
- export declare function computeVAPUV(region: [number, number, number, number], videoW: number, videoH: number): {
12
+ export declare function getVAPContentSize(info: VAPConfig['info'], out?: VAPContentSize): VAPContentSize;
13
+ export interface VAPUVRect {
16
14
  left: number;
17
15
  right: number;
18
16
  top: number;
19
17
  bottom: number;
20
- };
18
+ }
19
+ /**
20
+ * Compute normalized UV coordinates for a frame region within the video texture.
21
+ */
22
+ export declare function computeVAPUV(region: [number, number, number, number], videoW: number, videoH: number, out?: VAPUVRect): VAPUVRect;
@@ -10,6 +10,7 @@ export declare class AlphaVideoRenderer {
10
10
  private scratchTransform;
11
11
  private readonly contentSizeScratch;
12
12
  private readonly layoutScratch;
13
+ private readonly clipScratch;
13
14
  private readonly wcDbgFirstDraw;
14
15
  private readonly wcDbgNullWarns;
15
16
  private readonly htmlGate;
@@ -3,9 +3,14 @@ export declare class ImageRenderer {
3
3
  private quadVB;
4
4
  private quadIB;
5
5
  private readonly scratchTransform;
6
+ private readonly layoutScratch;
7
+ private readonly clipScratch;
6
8
  private projCacheW;
7
9
  private projCacheH;
8
10
  private projCache;
11
+ private readonly texturesScratch;
12
+ private readonly uniformsScratch;
13
+ private readonly drawCommand;
9
14
  private static readonly QUAD_VERTS;
10
15
  private static readonly QUAD_INDICES;
11
16
  drawSlot(backend: GPUBackend, slot: GiftSlot): void;
@@ -12,6 +12,13 @@ export interface ClipMeshCache {
12
12
  w: number;
13
13
  h: number;
14
14
  } | null;
15
+ /** Local-space bounds cached for conservative instanced stencil safety checks. */
16
+ bounds?: {
17
+ x0: number;
18
+ y0: number;
19
+ x1: number;
20
+ y1: number;
21
+ };
15
22
  /** Lazily created static GPU buffers (local-space vertices, transformed via u_transform). */
16
23
  vertexBuf?: GPUBufferHandle | null;
17
24
  indexBuf?: GPUBufferHandle | null;
@@ -25,8 +32,16 @@ interface SVGAClipPrewarmOptions {
25
32
  }
26
33
  export type SVGAClipMeshMap = Map<string, ClipMeshCache>;
27
34
  export declare class SVGABatchRenderer {
35
+ private readonly onClipMeshReady?;
28
36
  private static readonly INSTANCED_QUAD_VERTS;
29
37
  private static readonly INSTANCED_QUAD_INDICES;
38
+ /**
39
+ * @param onClipMeshReady Called once a background clip mesh build (queued by the hot-path
40
+ * lookup in `getClipMeshForSprite`, see `queueClipMeshBuild`) finishes, so the owner can
41
+ * `invalidate()` a redraw — otherwise a slot whose animation has stopped dirtying may never
42
+ * pick up the now-available precise clip.
43
+ */
44
+ constructor(onClipMeshReady?: (() => void) | undefined);
30
45
  private pool;
31
46
  private vertexBufHandles;
32
47
  private indexBufHandles;
@@ -42,60 +57,202 @@ export declare class SVGABatchRenderer {
42
57
  private clipMeshCache;
43
58
  /** Meshes with lazily created GPU buffers (released in destroy). */
44
59
  private clipMeshesWithBuffers;
60
+ /** Clip paths queued by `queueClipMeshBuild`, awaiting the next background build flush. */
61
+ private pendingClipMeshPaths;
62
+ /** True while a background build (worker or frame-budgeted main thread) is in flight. */
63
+ private clipMeshBuildInFlight;
45
64
  private clipFrameDataScratch;
65
+ /** One-off scratch used only to capture a row for `svgaStaticBatchCache` (P1-10); never read
66
+ * back — each captured entry clones out of it immediately via `.slice()`. */
67
+ private staticBatchCacheRowScratch;
46
68
  private instancedFrameDataScratch;
69
+ private instancedFrameDataWords;
47
70
  private clipSpriteVertsScratch;
48
71
  private clipSpriteIndicesScratch;
49
- private shapeVertsScratch;
72
+ private clipMaskBatchTransformsScratch;
50
73
  private instancedQuadVB;
51
74
  private instancedQuadIB;
52
75
  private whiteTexture;
53
76
  private shapeMeshCache;
77
+ /** Shape meshes with lazily created static GPU buffers (released in destroy). */
78
+ private shapeMeshesWithBuffers;
54
79
  /** Column-major mat4 scratch for clip-mask u_transform (uploaded synchronously per draw). */
55
80
  private clipTransformMat;
81
+ /** Column-major mat4 scratch for the shape draw's u_transform (consumed synchronously). */
82
+ private shapeTransformMat;
56
83
  /** Scissor rect of the slot currently being drawn (canvas pixels), for clip intersection/restore. */
57
84
  private slotScissor;
85
+ private slotClipX0;
86
+ private slotClipY0;
87
+ private slotClipX1;
88
+ private slotClipY1;
89
+ /**
90
+ * Whether `slotScissor` is currently the *active* GPU scissor rect (vs. the outer scissor
91
+ * having been intentionally skipped for a slot that cannot draw outside its own box — see
92
+ * `spriteTable.allFramesInsideViewBox`). Drives `restoreSlotScissor`'s fallback target.
93
+ */
94
+ private slotScissorActive;
95
+ /**
96
+ * True while a clip stencil mask written for a shape is still live for its sprite sibling
97
+ * (texture + clip + shape single-write merge, P1-3). `drawClippedSprite` checks this to
98
+ * skip its own stencil write/clear.
99
+ */
100
+ private sharedClipStencilActive;
101
+ private readonly layoutScratch;
58
102
  /** Grow-only SpriteWork pool; cursor resets each flushGroup. */
59
103
  private spriteWorkPool;
60
104
  private spriteWorkCursor;
61
105
  /** Reused scratch arrays (consumed synchronously). */
62
106
  private batchSpritesScratch;
63
107
  private drawGroupScratch;
108
+ private sharedSlotLayerWorkPool;
109
+ private sharedSlotLayerWorksScratch;
110
+ private clipLayerBatchPool;
111
+ private clipLayerBatchesScratch;
64
112
  /** Per-entity result of the "any frame has shapes" scan (no-atlas render check). */
65
113
  private entityHasShapesCache;
66
114
  /** 0=no clip, 1=scissor-compatible clips only, 2=stencil required, 255=not analyzed. */
67
115
  private entityFrameClipModeCache;
116
+ /**
117
+ * Per-entity `ClipMeshCache` lookup aligned with `spriteTable.clipPaths` (index = `clipPathIndex`
118
+ * value), so the hot per-sprite loop can resolve a clip mesh with a direct array read instead of
119
+ * `getSpriteClipPath` (string build) + a string-keyed `Map` lookup. `undefined` = not yet resolved;
120
+ * resolution always goes through `getClipMesh`'s string cache, so array entries never go stale.
121
+ */
122
+ private entityClipMeshArrayCache;
68
123
  private readonly affineScratch;
124
+ /**
125
+ * Reused DrawCommand/uniforms/textures per rendering branch (never allocated per draw).
126
+ * Backends consume `DrawCommand` synchronously inside `backend.draw`, so mutating these
127
+ * shared objects between calls is safe as long as no reference is retained past the call.
128
+ * Grouped by branch (plain instanced sprite / plain batch sprite / clipped instanced /
129
+ * clipped batch / clip-mask stencil / shape) per the uniform field sets each shader expects.
130
+ */
131
+ private readonly plainInstancedTexturesScratch;
132
+ private readonly plainInstancedUniformsScratch;
133
+ private readonly plainInstancedDrawCommand;
134
+ private readonly plainBatchTexturesScratch;
135
+ private readonly plainBatchUniformsScratch;
136
+ private readonly plainBatchDrawCommand;
137
+ /** `drawClippedSprite`'s stencil-test pass on instanced backends (webgl2/webgpu). */
138
+ private readonly clipInstancedTexturesScratch;
139
+ private readonly clipInstancedUniformsScratch;
140
+ private readonly clipInstancedDrawCommand;
141
+ /** `drawClippedSprite`'s stencil-test pass on the WebGL1 fallback. */
142
+ private readonly clipBatchTexturesScratch;
143
+ private readonly clipBatchUniformsScratch;
144
+ private readonly clipBatchDrawCommand;
145
+ /**
146
+ * Clip-mask stencil write/clear, shared by `drawClippedSprite`'s pass-1 write,
147
+ * `drawShapeFrame`'s non-rect-clip write, and `clearClipStencil`'s clear (all mutate then
148
+ * synchronously `backend.draw`, never concurrently).
149
+ */
150
+ private readonly clipMaskTexturesScratch;
151
+ private readonly clipMaskUniformsScratch;
152
+ private readonly clipMaskDrawCommand;
153
+ private readonly clipMaskInstancedUniformsScratch;
154
+ private readonly clipMaskInstancedDrawCommand;
155
+ /**
156
+ * `drawShapeFrame`'s fill/stroke draw (always the shared white texture). `u_transform`
157
+ * carries the per-frame sprite x slot transform so the static shape mesh stays on the GPU;
158
+ * `u_opacity` carries slot opacity (per-vertex alpha is baked into the mesh).
159
+ */
160
+ private readonly shapeTexturesScratch;
161
+ private readonly shapeUniformsScratch;
162
+ private readonly shapeDrawCommand;
69
163
  beginFrame(backend: GPUBackend): void;
70
164
  flush(backend: GPUBackend, slots: Map<string, GiftSlot>): void;
71
165
  drawSlot(backend: GPUBackend, slot: GiftSlot): void;
72
166
  drawSlots(backend: GPUBackend, slots: Iterable<GiftSlot>): void;
73
167
  requiresStencil(slots: Iterable<GiftSlot>): boolean;
168
+ /**
169
+ * Returns the target frame only when every clip path referenced by its visible sprites has a
170
+ * resolved cache entry. A miss queues background triangulation and keeps the previous complete
171
+ * frame on screen, preventing a partially built frame from being drawn without clipping.
172
+ */
173
+ private resolveRenderableFrame;
174
+ private isFrameClipReady;
74
175
  private getFrameClipMode;
75
176
  prewarmClipMeshes(entity: Pick<VideoEntity, 'spriteTable'>, options?: SVGAClipPrewarmOptions): Promise<number>;
177
+ prewarmClipMeshesForFrame(entity: Pick<VideoEntity, 'spriteTable'>, frame: number, options?: SVGAClipPrewarmOptions): Promise<number>;
178
+ private collectFrameClipPaths;
179
+ /** Builds every not-yet-cached path in `paths`, worker-first with a frame-budgeted fallback. */
180
+ private buildMissingClipMeshes;
181
+ /**
182
+ * Called from the render-loop hot path (`getClipMeshForSprite`) when a clip path has no cached
183
+ * mesh yet — instead of triangulating synchronously inline, queue it and build it in the
184
+ * background (batched with any other paths queued in the same tick) so the current frame keeps
185
+ * moving. Safe to call repeatedly: paths already cached or already queued are no-ops.
186
+ */
187
+ private queueClipMeshBuild;
188
+ private scheduleClipMeshBuildFlush;
189
+ private flushPendingClipMeshBuilds;
76
190
  hydrateClipMeshes(meshes: SVGAClipMeshMap | null | undefined): void;
77
191
  snapshotClipMeshes(entity: Pick<VideoEntity, 'spriteTable'>): SVGAClipMeshMap;
78
192
  private flushGroup;
193
+ /**
194
+ * Transposes disjoint slots sharing one entity into sprite layers. Reordering across slots is
195
+ * safe because their outer clip bounds do not overlap; order within every slot remains sprite
196
+ * index order. Non-rect clips sharing one mesh become write -> instanced test -> clear.
197
+ */
198
+ private tryFlushDisjointSharedEntityLayers;
199
+ private resetClipLayerBatches;
200
+ private acquireClipLayerBatch;
201
+ private resolveClipTransform;
202
+ private intersectWorkClipRect;
203
+ private drawBatchedClipLayer;
79
204
  private acquireSpriteWork;
205
+ /**
206
+ * Like `acquireSpriteWork`, but for a P1-10 static batch cache replay entry: only `handle` and
207
+ * `cachedRow` matter, since `packFrameData` short-circuits on `cachedRow` and every other draw
208
+ * call only reads `work.handle`.
209
+ */
210
+ private acquireCachedSpriteWork;
211
+ private updateSlotClipBounds;
212
+ private copyCurrentSlotClipToWork;
80
213
  /** Drop object references so removed slots/entities are not retained by the pool. */
81
214
  private releaseSpriteWorks;
215
+ /** Snapshot check for a P1-10 static batch cache: any mismatch means rebuild, never a stale hit. */
216
+ private staticBatchCacheMatches;
217
+ /** Clones the packed row for `work` into a fresh array so it survives past this frame's scratch reuse. */
218
+ private captureStaticBatchCacheEntry;
219
+ /** Replays a P1-10 static batch cache hit: same override/batch branching as the live loop, just
220
+ * sourced from pre-packed rows instead of recomputing layout/transform/texture lookups. */
221
+ private drawFromStaticBatchCache;
82
222
  private getProjection;
83
223
  private drawBatch;
84
224
  private drawBatchInstancedWebGL;
85
225
  private drawClippedSprite;
226
+ /**
227
+ * WebGL1 clipped-sprite draw: pack + upload the quad, then draw with stencil 'test'.
228
+ * Caller is responsible for the surrounding stencil write/clear. Uses separate buffers to
229
+ * avoid WebGPU writeBuffer aliasing with the batch draw.
230
+ */
231
+ private drawBatchSpriteWithStencilTest;
86
232
  /** Rect clip in canvas space intersected with the slot scissor. Returns false when fully clipped. */
87
233
  private applyClipRectScissor;
88
234
  private restoreSlotScissor;
89
235
  private getClipRect;
236
+ private getClipMeshBounds;
90
237
  private ensureClipMeshBuffers;
91
238
  private packClipTransform;
92
239
  private drawSingleSprite;
93
240
  private clearClipStencil;
94
241
  private rotateTransform;
95
242
  private packFrameData;
243
+ private packInstancedFrameData;
244
+ private packClipCoordinatePair;
245
+ private packFrameDataAt;
96
246
  /** Resolve atlas/override texture into a pooled SpriteWork entry. Returns false when missing. */
97
247
  private resolveSpriteTextureInto;
98
248
  private drawShapeFrame;
249
+ /**
250
+ * Clear the shared mask after a shape-first clip merge once the sprite sibling has drawn.
251
+ * Called by `drawClippedSprite`'s shared-mask branch.
252
+ */
253
+ private clearSharedClipStencil;
254
+ private ensureShapeMeshBuffers;
255
+ private packShapeTransform;
99
256
  private hasAtlasTexture;
100
257
  private hasRenderableSVGA;
101
258
  private getWhiteTexture;
@@ -107,6 +264,20 @@ export declare class SVGABatchRenderer {
107
264
  private clamp01;
108
265
  private cleanupPoints;
109
266
  private getClipMesh;
267
+ /**
268
+ * Hot-path clip mesh lookup: reads `clipPathIndex` directly (no string build/compare) and
269
+ * memoizes the resolved mesh per (entity, clipPathIndex) so repeat frames skip the string-keyed
270
+ * `clipMeshCache` lookup too.
271
+ *
272
+ * Returns `undefined` (rather than triangulating inline) when the path hasn't been built yet —
273
+ * prewarm normally finishes before an entity is ever drawn, but with `svgaPrewarmClipMeshes:
274
+ * false`, an aborted/partially failed prewarm, or a slot rendered before prewarm completes, this
275
+ * lookup would otherwise pay a synchronous SVG-parse + triangulate cost inside the render loop.
276
+ * The path is queued for a background build instead (see `queueClipMeshBuild`); callers already
277
+ * treat a falsy return as "no clip this frame" (draw unclipped / assume stencil conservatively),
278
+ * and a redraw is requested once the build lands so later frames clip precisely.
279
+ */
280
+ private getClipMeshForSprite;
110
281
  private ensureVertexBuffer;
111
282
  private ensureIndexBuffer;
112
283
  private ensureClipSpriteVertexBuffer;
@@ -15,8 +15,32 @@ export declare class VAPRenderer {
15
15
  private readonly scratchAtlasRemap;
16
16
  private instancePackScratch;
17
17
  private scratchTransform;
18
+ private readonly contentSizeScratch;
19
+ private readonly rgbUVScratch;
20
+ private readonly alphaUVScratch;
21
+ private readonly maskUVScratch;
18
22
  private readonly processedHtmlGatesScratch;
19
23
  private readonly vapVertexScratch;
24
+ private readonly layoutScratch;
25
+ private readonly clipScratch;
26
+ /** `drawInstancedVapBatches` grow-only scratch: avoids a fresh array/Map per frame. */
27
+ private readonly instancedListScratch;
28
+ private readonly instancedByTexScratch;
29
+ private readonly instancedTexturesScratch;
30
+ private readonly instancedUniformsScratch;
31
+ private readonly instancedDrawCommand;
32
+ /** `drawGeometry` (plain VAP quad) reused command/uniforms/textures. */
33
+ private readonly geometryTexturesScratch;
34
+ private readonly geometryUniformsScratch;
35
+ private readonly geometryDrawCommand;
36
+ /** `drawMixedGeometry` (composited rgba overlay) reused command/uniforms/textures. */
37
+ private readonly mixedGeometryTexturesScratch;
38
+ private readonly mixedGeometryUniformsScratch;
39
+ private readonly mixedGeometryDrawCommand;
40
+ /** `drawMixedDirectGeometry` per-frame-object overlay reused command/uniforms/textures. */
41
+ private readonly overlayTexturesScratch;
42
+ private readonly overlayUniformsScratch;
43
+ private readonly overlayDrawCommand;
20
44
  constructor(onHtmlVideoFrame?: (video: HTMLVideoElement) => void);
21
45
  private projCacheW;
22
46
  private projCacheH;
@@ -35,6 +35,10 @@ export declare const glsl: {
35
35
  readonly vert: string;
36
36
  readonly frag: string;
37
37
  };
38
+ readonly clipMaskInstanced: {
39
+ readonly vert: string;
40
+ readonly frag: string;
41
+ };
38
42
  };
39
43
  export declare const wgsl: {
40
44
  readonly svgaBatchPremul: string;
@@ -46,4 +50,5 @@ export declare const wgsl: {
46
50
  readonly alphaVideoInstanced: string;
47
51
  readonly rgbaTextured: string;
48
52
  readonly clipMask: string;
53
+ readonly clipMaskInstanced: string;
49
54
  };