@reearth/ezu 0.4.2 → 0.6.0

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/bundler/ezu.d.ts CHANGED
@@ -76,9 +76,28 @@ export class Renderer {
76
76
  * - `geojson` (remote) → store raw bytes per `(dx, dy)` offset;
77
77
  * projected per tile (and neighbour) at render time.
78
78
  *
79
- * `opts` is a JS object: `{ coord?: [dx, dy] }`. Throws
80
- * `UnknownSource` if `name` doesn't match any entry in the style's
81
- * `sources` block, `MvtDecode` if MVT bytes don't parse, and
79
+ * `opts` is a JS object: `{ coord?: [dx, dy], sourceZoom?: number }`.
80
+ *
81
+ * `sourceZoom` declares that MVT bytes are natively encoded at a
82
+ * *shallower* zoom than the tile being rendered — a vector source
83
+ * that stops at its `maxzoom` while the host serves deeper tiles.
84
+ * The renderer then reprojects each payload from its own ancestor
85
+ * into the tile's frame before rendering (MVT "overzoom"), which is
86
+ * what a client would otherwise do by scaling a raster up. The
87
+ * ancestor is derived, not supplied: for a tile at zoom `z`, the
88
+ * ancestor at `sourceZoom` is unique, so a host that binds the
89
+ * `maxzoom` tile it fetched has nothing further to compute — and
90
+ * each neighbour resolves against its own ancestor, which for a 3×3
91
+ * window may be a different parent than the centre's.
92
+ *
93
+ * `sourceZoom` equal to the rendered zoom is accepted and does
94
+ * nothing, so a host can pass its source's `maxzoom` unconditionally
95
+ * and let shallow tiles take the ordinary path. Deeper than the
96
+ * rendered zoom throws `UnknownSource`: there is no way to invent
97
+ * detail the bytes do not carry.
98
+ *
99
+ * Throws `UnknownSource` if `name` doesn't match any entry in the
100
+ * style's `sources` block, `MvtDecode` if MVT bytes don't parse, and
82
101
  * `DemDecode` for non-image DEM bytes (the decode itself runs at
83
102
  * render time, but obvious cases are caught here).
84
103
  */
@@ -92,6 +111,57 @@ export class Renderer {
92
111
  * Drop every pending source binding. Call between tile renders.
93
112
  */
94
113
  clearSources(): void;
114
+ /**
115
+ * What this renderer is holding, in bytes, so a host can shed load
116
+ * *before* an allocation fails rather than after.
117
+ *
118
+ * Returns a JS object:
119
+ * - `heapBytes` — wasm linear memory committed to the **module**,
120
+ * shared by every `Renderer` in this instance. This is the number
121
+ * that meets an isolate's memory cap. It is a high-water mark:
122
+ * freeing Rust values returns them to the allocator, never to the
123
+ * host, so it only ever grows.
124
+ * - `glyphBytes` / `glyphRanges` — SDF bitmaps resident in the
125
+ * glyph bank, and how many 256-codepoint blocks they span. Glyphs
126
+ * accumulate for the life of the renderer and survive
127
+ * `clearSources`, so on a long-lived instance this is usually
128
+ * what grew. `glyphBudget` is the per-fontstack ceiling
129
+ * `setGlyphBudget` put on them, or `Infinity` if none — note
130
+ * `glyphBytes` totals *every* fontstack, so it can exceed the
131
+ * budget legitimately.
132
+ * - `fontBytes` — outline font files held in the font bank.
133
+ * - `imageBytes` — decoded pixels of bound images and sprite
134
+ * atlases.
135
+ * - `cacheBytes` / `cacheBudget` — the render cache's pixel
136
+ * payload against its own eviction budget; it bounds itself, so
137
+ * `cacheBytes` near `cacheBudget` is steady state, not a leak.
138
+ *
139
+ * These are payload sizes, not an accounting of the heap: they omit
140
+ * allocator overhead, decoded features, per-font glyph-path caches,
141
+ * and the buffers a render is using right now. Expect the parts to
142
+ * sum to less than `heapBytes`.
143
+ */
144
+ memoryUsage(): object;
145
+ /**
146
+ * Codepoints the currently bound features can require, as
147
+ * `{ [glyphsSourceName]: number[] }` sorted ascending.
148
+ *
149
+ * This is the precise form of
150
+ * [`neededGlyphRanges`](Self::needed_glyph_ranges): a host that
151
+ * can build its own glyph PBF — one message holding just these
152
+ * codepoints — transfers only the glyphs the tile draws instead
153
+ * of the whole 256-codepoint block around each of them. On CJK
154
+ * labels that is the difference between a few thousand glyphs and
155
+ * a few tens of megabytes. `bindSource` files each glyph by its
156
+ * own id, so such a subset may span any number of blocks and
157
+ * needs no particular `range` string.
158
+ *
159
+ * Hosts that can only fetch whole `{range}.pbf` files off a
160
+ * MapLibre glyphs endpoint want `neededGlyphRanges` instead. Both
161
+ * calls see the same set of codepoints and carry the same
162
+ * over-approximation caveat.
163
+ */
164
+ neededCodepoints(): object;
95
165
  /**
96
166
  * Glyph ranges the currently bound features can require, as
97
167
  * `{ [glyphsSourceName]: number[] }` where each number is a range
@@ -103,6 +173,11 @@ export class Renderer {
103
173
  * scraping every string in the MVT, call this after binding the
104
174
  * vector sources and bind exactly the listed ranges.
105
175
  *
176
+ * A range holds 256 codepoints and a tile typically draws a
177
+ * handful of them, so this is a coarse unit to fetch in. Hosts
178
+ * that can assemble their own subset PBF should call
179
+ * [`neededCodepoints`](Self::needed_codepoints) instead.
180
+ *
106
181
  * It is an over-approximation, deliberately: a range is listed if
107
182
  * *any* feature in a text layer carries the codepoint in a property
108
183
  * the layer's `text` expression reads, without evaluating filters,
@@ -144,6 +219,31 @@ export class Renderer {
144
219
  * Throws `UnknownSource` if `name` is not declared in the style.
145
220
  */
146
221
  requestedNeighborOffsets(name: string): Array<any>;
222
+ /**
223
+ * Cap the glyph bytes each bound fontstack keeps resident, in
224
+ * bytes. Unset, a fontstack keeps every range ever bound to it for
225
+ * the life of the renderer — `clearSources` does not touch glyphs,
226
+ * and on a long-lived instance rendering across a basemap that is
227
+ * usually what grew.
228
+ *
229
+ * Trimming happens **after** each `renderTile`, not while binding,
230
+ * so a render never loses glyphs that were bound for it. The tile
231
+ * that just drew is therefore the most recently used, and a budget
232
+ * large enough for one tile's glyphs always keeps that tile's; what
233
+ * goes is what earlier tiles needed and this one did not. Set it
234
+ * below one tile's worth and the ceiling still holds — the stack
235
+ * empties after every render and nothing carries over, which
236
+ * renders correctly but buys no reuse.
237
+ *
238
+ * It is a per-fontstack ceiling: a style with a regular, a medium
239
+ * and an italic stack can hold three times what is set here.
240
+ *
241
+ * This host cannot refetch, so anything trimmed must be bound again
242
+ * before the next tile that needs it. `neededCodepoints()` already
243
+ * names exactly what to bind, and a host that re-binds every tile
244
+ * (rather than tracking what it sent) needs no other change.
245
+ */
246
+ setGlyphBudget(bytes: number): void;
147
247
  /**
148
248
  * Replace the active style. Returns the new node count. Invalidates
149
249
  * the intermediate cache and drops any pending source bindings.
@@ -161,6 +261,22 @@ export class Renderer {
161
261
  readonly tileSize: number;
162
262
  }
163
263
 
264
+ /**
265
+ * Wasm linear memory currently committed to this module, in bytes.
266
+ *
267
+ * This is the figure an isolate's memory cap applies to, and the one
268
+ * to watch to shed load before an allocation fails — a refused
269
+ * `memory.grow` throws [`OutOfMemory`](oom) and ends the instance.
270
+ * It never falls: freed Rust values return to the allocator for reuse,
271
+ * but wasm cannot hand pages back to the host. So a drop in demand
272
+ * leaves the number where its peak left it, and only a fresh instance
273
+ * resets it.
274
+ *
275
+ * Module-wide, not per-`Renderer`. For what a given renderer is
276
+ * holding, and which bank to evict, call `memoryUsage()`.
277
+ */
278
+ export function heapBytes(): number;
279
+
164
280
  /**
165
281
  * Whether the wasm binary was compiled with `+simd128`. Lets the demo
166
282
  * page label the renderer build accurately.
package/bundler/ezu.js CHANGED
@@ -5,5 +5,5 @@ import { __wbg_set_wasm } from "./ezu_bg.js";
5
5
  __wbg_set_wasm(wasm);
6
6
  wasm.__wbindgen_start();
7
7
  export {
8
- LogSink, Renderer, simdEnabled, threadsEnabled
8
+ LogSink, Renderer, heapBytes, simdEnabled, threadsEnabled
9
9
  } from "./ezu_bg.js";
package/bundler/ezu_bg.js CHANGED
@@ -142,9 +142,28 @@ export class Renderer {
142
142
  * - `geojson` (remote) → store raw bytes per `(dx, dy)` offset;
143
143
  * projected per tile (and neighbour) at render time.
144
144
  *
145
- * `opts` is a JS object: `{ coord?: [dx, dy] }`. Throws
146
- * `UnknownSource` if `name` doesn't match any entry in the style's
147
- * `sources` block, `MvtDecode` if MVT bytes don't parse, and
145
+ * `opts` is a JS object: `{ coord?: [dx, dy], sourceZoom?: number }`.
146
+ *
147
+ * `sourceZoom` declares that MVT bytes are natively encoded at a
148
+ * *shallower* zoom than the tile being rendered — a vector source
149
+ * that stops at its `maxzoom` while the host serves deeper tiles.
150
+ * The renderer then reprojects each payload from its own ancestor
151
+ * into the tile's frame before rendering (MVT "overzoom"), which is
152
+ * what a client would otherwise do by scaling a raster up. The
153
+ * ancestor is derived, not supplied: for a tile at zoom `z`, the
154
+ * ancestor at `sourceZoom` is unique, so a host that binds the
155
+ * `maxzoom` tile it fetched has nothing further to compute — and
156
+ * each neighbour resolves against its own ancestor, which for a 3×3
157
+ * window may be a different parent than the centre's.
158
+ *
159
+ * `sourceZoom` equal to the rendered zoom is accepted and does
160
+ * nothing, so a host can pass its source's `maxzoom` unconditionally
161
+ * and let shallow tiles take the ordinary path. Deeper than the
162
+ * rendered zoom throws `UnknownSource`: there is no way to invent
163
+ * detail the bytes do not carry.
164
+ *
165
+ * Throws `UnknownSource` if `name` doesn't match any entry in the
166
+ * style's `sources` block, `MvtDecode` if MVT bytes don't parse, and
148
167
  * `DemDecode` for non-image DEM bytes (the decode itself runs at
149
168
  * render time, but obvious cases are caught here).
150
169
  * @param {string} name
@@ -178,6 +197,71 @@ export class Renderer {
178
197
  clearSources() {
179
198
  wasm.renderer_clearSources(this.__wbg_ptr);
180
199
  }
200
+ /**
201
+ * What this renderer is holding, in bytes, so a host can shed load
202
+ * *before* an allocation fails rather than after.
203
+ *
204
+ * Returns a JS object:
205
+ * - `heapBytes` — wasm linear memory committed to the **module**,
206
+ * shared by every `Renderer` in this instance. This is the number
207
+ * that meets an isolate's memory cap. It is a high-water mark:
208
+ * freeing Rust values returns them to the allocator, never to the
209
+ * host, so it only ever grows.
210
+ * - `glyphBytes` / `glyphRanges` — SDF bitmaps resident in the
211
+ * glyph bank, and how many 256-codepoint blocks they span. Glyphs
212
+ * accumulate for the life of the renderer and survive
213
+ * `clearSources`, so on a long-lived instance this is usually
214
+ * what grew. `glyphBudget` is the per-fontstack ceiling
215
+ * `setGlyphBudget` put on them, or `Infinity` if none — note
216
+ * `glyphBytes` totals *every* fontstack, so it can exceed the
217
+ * budget legitimately.
218
+ * - `fontBytes` — outline font files held in the font bank.
219
+ * - `imageBytes` — decoded pixels of bound images and sprite
220
+ * atlases.
221
+ * - `cacheBytes` / `cacheBudget` — the render cache's pixel
222
+ * payload against its own eviction budget; it bounds itself, so
223
+ * `cacheBytes` near `cacheBudget` is steady state, not a leak.
224
+ *
225
+ * These are payload sizes, not an accounting of the heap: they omit
226
+ * allocator overhead, decoded features, per-font glyph-path caches,
227
+ * and the buffers a render is using right now. Expect the parts to
228
+ * sum to less than `heapBytes`.
229
+ * @returns {object}
230
+ */
231
+ memoryUsage() {
232
+ const ret = wasm.renderer_memoryUsage(this.__wbg_ptr);
233
+ if (ret[2]) {
234
+ throw takeFromExternrefTable0(ret[1]);
235
+ }
236
+ return takeFromExternrefTable0(ret[0]);
237
+ }
238
+ /**
239
+ * Codepoints the currently bound features can require, as
240
+ * `{ [glyphsSourceName]: number[] }` sorted ascending.
241
+ *
242
+ * This is the precise form of
243
+ * [`neededGlyphRanges`](Self::needed_glyph_ranges): a host that
244
+ * can build its own glyph PBF — one message holding just these
245
+ * codepoints — transfers only the glyphs the tile draws instead
246
+ * of the whole 256-codepoint block around each of them. On CJK
247
+ * labels that is the difference between a few thousand glyphs and
248
+ * a few tens of megabytes. `bindSource` files each glyph by its
249
+ * own id, so such a subset may span any number of blocks and
250
+ * needs no particular `range` string.
251
+ *
252
+ * Hosts that can only fetch whole `{range}.pbf` files off a
253
+ * MapLibre glyphs endpoint want `neededGlyphRanges` instead. Both
254
+ * calls see the same set of codepoints and carry the same
255
+ * over-approximation caveat.
256
+ * @returns {object}
257
+ */
258
+ neededCodepoints() {
259
+ const ret = wasm.renderer_neededCodepoints(this.__wbg_ptr);
260
+ if (ret[2]) {
261
+ throw takeFromExternrefTable0(ret[1]);
262
+ }
263
+ return takeFromExternrefTable0(ret[0]);
264
+ }
181
265
  /**
182
266
  * Glyph ranges the currently bound features can require, as
183
267
  * `{ [glyphsSourceName]: number[] }` where each number is a range
@@ -189,6 +273,11 @@ export class Renderer {
189
273
  * scraping every string in the MVT, call this after binding the
190
274
  * vector sources and bind exactly the listed ranges.
191
275
  *
276
+ * A range holds 256 codepoints and a tile typically draws a
277
+ * handful of them, so this is a coarse unit to fetch in. Hosts
278
+ * that can assemble their own subset PBF should call
279
+ * [`neededCodepoints`](Self::needed_codepoints) instead.
280
+ *
192
281
  * It is an over-approximation, deliberately: a range is listed if
193
282
  * *any* feature in a text layer carries the codepoint in a property
194
283
  * the layer's `text` expression reads, without evaluating filters,
@@ -271,6 +360,34 @@ export class Renderer {
271
360
  }
272
361
  return takeFromExternrefTable0(ret[0]);
273
362
  }
363
+ /**
364
+ * Cap the glyph bytes each bound fontstack keeps resident, in
365
+ * bytes. Unset, a fontstack keeps every range ever bound to it for
366
+ * the life of the renderer — `clearSources` does not touch glyphs,
367
+ * and on a long-lived instance rendering across a basemap that is
368
+ * usually what grew.
369
+ *
370
+ * Trimming happens **after** each `renderTile`, not while binding,
371
+ * so a render never loses glyphs that were bound for it. The tile
372
+ * that just drew is therefore the most recently used, and a budget
373
+ * large enough for one tile's glyphs always keeps that tile's; what
374
+ * goes is what earlier tiles needed and this one did not. Set it
375
+ * below one tile's worth and the ceiling still holds — the stack
376
+ * empties after every render and nothing carries over, which
377
+ * renders correctly but buys no reuse.
378
+ *
379
+ * It is a per-fontstack ceiling: a style with a regular, a medium
380
+ * and an italic stack can hold three times what is set here.
381
+ *
382
+ * This host cannot refetch, so anything trimmed must be bound again
383
+ * before the next tile that needs it. `neededCodepoints()` already
384
+ * names exactly what to bind, and a host that re-binds every tile
385
+ * (rather than tracking what it sent) needs no other change.
386
+ * @param {number} bytes
387
+ */
388
+ setGlyphBudget(bytes) {
389
+ wasm.renderer_setGlyphBudget(this.__wbg_ptr, bytes);
390
+ }
274
391
  /**
275
392
  * Replace the active style. Returns the new node count. Invalidates
276
393
  * the intermediate cache and drops any pending source bindings.
@@ -297,6 +414,26 @@ export class Renderer {
297
414
  }
298
415
  if (Symbol.dispose) Renderer.prototype[Symbol.dispose] = Renderer.prototype.free;
299
416
 
417
+ /**
418
+ * Wasm linear memory currently committed to this module, in bytes.
419
+ *
420
+ * This is the figure an isolate's memory cap applies to, and the one
421
+ * to watch to shed load before an allocation fails — a refused
422
+ * `memory.grow` throws [`OutOfMemory`](oom) and ends the instance.
423
+ * It never falls: freed Rust values return to the allocator for reuse,
424
+ * but wasm cannot hand pages back to the host. So a drop in demand
425
+ * leaves the number where its peak left it, and only a fresh instance
426
+ * resets it.
427
+ *
428
+ * Module-wide, not per-`Renderer`. For what a given renderer is
429
+ * holding, and which bank to evict, call `memoryUsage()`.
430
+ * @returns {number}
431
+ */
432
+ export function heapBytes() {
433
+ const ret = wasm.heapBytes();
434
+ return ret >>> 0;
435
+ }
436
+
300
437
  /**
301
438
  * Whether the wasm binary was compiled with `+simd128`. Lets the demo
302
439
  * page label the renderer build accurately.
@@ -318,29 +455,29 @@ export function threadsEnabled() {
318
455
  const ret = wasm.threadsEnabled();
319
456
  return ret !== 0;
320
457
  }
321
- export function __wbg___wbindgen_boolean_get_2304fb8c853028c8(arg0) {
458
+ export function __wbg___wbindgen_boolean_get_fa956cfa2d1bd751(arg0) {
322
459
  const v = arg0;
323
460
  const ret = typeof(v) === 'boolean' ? v : undefined;
324
461
  return isLikeNone(ret) ? 0xFFFFFF : ret ? 1 : 0;
325
462
  }
326
- export function __wbg___wbindgen_is_null_2042690d351e14f0(arg0) {
463
+ export function __wbg___wbindgen_is_null_ea9085d691f535d3(arg0) {
327
464
  const ret = arg0 === null;
328
465
  return ret;
329
466
  }
330
- export function __wbg___wbindgen_is_undefined_35bb9f4c7fd651d5(arg0) {
467
+ export function __wbg___wbindgen_is_undefined_c05833b95a3cf397(arg0) {
331
468
  const ret = arg0 === undefined;
332
469
  return ret;
333
470
  }
334
- export function __wbg___wbindgen_number_get_f73a1244370fcc2c(arg0, arg1) {
471
+ export function __wbg___wbindgen_number_get_394265ed1e1b84ee(arg0, arg1) {
335
472
  const obj = arg1;
336
473
  const ret = typeof(obj) === 'number' ? obj : undefined;
337
474
  getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);
338
475
  getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
339
476
  }
340
- export function __wbg___wbindgen_rethrow_2b7cc655458909c2(arg0) {
477
+ export function __wbg___wbindgen_rethrow_4915403b40f010b4(arg0) {
341
478
  throw arg0;
342
479
  }
343
- export function __wbg___wbindgen_string_get_d109740c0d18f4d7(arg0, arg1) {
480
+ export function __wbg___wbindgen_string_get_b0ca35b86a603356(arg0, arg1) {
344
481
  const obj = arg1;
345
482
  const ret = typeof(obj) === 'string' ? obj : undefined;
346
483
  var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc_command_export, wasm.__wbindgen_realloc_command_export);
@@ -348,10 +485,10 @@ export function __wbg___wbindgen_string_get_d109740c0d18f4d7(arg0, arg1) {
348
485
  getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
349
486
  getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
350
487
  }
351
- export function __wbg___wbindgen_throw_9c31b086c2b26051(arg0, arg1) {
488
+ export function __wbg___wbindgen_throw_344f42d3211c4765(arg0, arg1) {
352
489
  throw new Error(getStringFromWasm0(arg0, arg1));
353
490
  }
354
- export function __wbg_call_dfde26266607c996() { return handleError(function (arg0, arg1, arg2) {
491
+ export function __wbg_call_a6e5c5dce5018821() { return handleError(function (arg0, arg1, arg2) {
355
492
  const ret = arg0.call(arg1, arg2);
356
493
  return ret;
357
494
  }, arguments); }
@@ -366,15 +503,15 @@ export function __wbg_error_a6fa202b58aa1cd3(arg0, arg1) {
366
503
  wasm.__wbindgen_free_command_export(deferred0_0, deferred0_1, 1);
367
504
  }
368
505
  }
369
- export function __wbg_get_98fdf51d029a75eb(arg0, arg1) {
506
+ export function __wbg_get_507a50627bffa49b(arg0, arg1) {
370
507
  const ret = arg0[arg1 >>> 0];
371
508
  return ret;
372
509
  }
373
- export function __wbg_get_dcf82ab8aad1a593() { return handleError(function (arg0, arg1) {
510
+ export function __wbg_get_78f252d074a84d0b() { return handleError(function (arg0, arg1) {
374
511
  const ret = Reflect.get(arg0, arg1);
375
512
  return ret;
376
513
  }, arguments); }
377
- export function __wbg_instanceof_Object_03924e0dbda74bd8(arg0) {
514
+ export function __wbg_instanceof_Object_33f20e6f12439f3e(arg0) {
378
515
  let result;
379
516
  try {
380
517
  result = arg0 instanceof Object;
@@ -384,43 +521,43 @@ export function __wbg_instanceof_Object_03924e0dbda74bd8(arg0) {
384
521
  const ret = result;
385
522
  return ret;
386
523
  }
387
- export function __wbg_isArray_94898ed3aad6947b(arg0) {
524
+ export function __wbg_isArray_0677c962b281d01a(arg0) {
388
525
  const ret = Array.isArray(arg0);
389
526
  return ret;
390
527
  }
391
- export function __wbg_length_2591a0f4f659a55c(arg0) {
528
+ export function __wbg_length_370319915dc99107(arg0) {
392
529
  const ret = arg0.length;
393
530
  return ret;
394
531
  }
395
- export function __wbg_new_02d162bc6cf02f60() {
396
- const ret = new Object();
532
+ export function __wbg_new_227d7c05414eb861() {
533
+ const ret = new Error();
397
534
  return ret;
398
535
  }
399
- export function __wbg_new_1f236d63ba0c4784(arg0, arg1) {
400
- const ret = new Error(getStringFromWasm0(arg0, arg1));
536
+ export function __wbg_new_32b398fb48b6d94a() {
537
+ const ret = new Array();
401
538
  return ret;
402
539
  }
403
- export function __wbg_new_227d7c05414eb861() {
404
- const ret = new Error();
540
+ export function __wbg_new_b667d279fd5aa943(arg0, arg1) {
541
+ const ret = new Error(getStringFromWasm0(arg0, arg1));
405
542
  return ret;
406
543
  }
407
- export function __wbg_new_310879b66b6e95e1() {
408
- const ret = new Array();
544
+ export function __wbg_new_da52cf8fe3429cb2() {
545
+ const ret = new Object();
409
546
  return ret;
410
547
  }
411
- export function __wbg_now_81363d44c96dd239() {
548
+ export function __wbg_now_86c0d4ba3fa605b8() {
412
549
  const ret = Date.now();
413
550
  return ret;
414
551
  }
415
- export function __wbg_push_b77c476b01548d0a(arg0, arg1) {
552
+ export function __wbg_push_d2ae3af0c1217ae6(arg0, arg1) {
416
553
  const ret = arg0.push(arg1);
417
554
  return ret;
418
555
  }
419
- export function __wbg_set_a0e911be3da02782() { return handleError(function (arg0, arg1, arg2) {
556
+ export function __wbg_set_8535240470bf2500() { return handleError(function (arg0, arg1, arg2) {
420
557
  const ret = Reflect.set(arg0, arg1, arg2);
421
558
  return ret;
422
559
  }, arguments); }
423
- export function __wbg_set_name_e500733c75ec36b0(arg0, arg1, arg2) {
560
+ export function __wbg_set_name_3bbc583faefa4193(arg0, arg1, arg2) {
424
561
  arg0.name = getStringFromWasm0(arg1, arg2);
425
562
  }
426
563
  export function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {
Binary file
@@ -3,6 +3,7 @@
3
3
  export const memory: WebAssembly.Memory;
4
4
  export const __wbg_logsink_free: (a: number, b: number) => void;
5
5
  export const __wbg_renderer_free: (a: number, b: number) => void;
6
+ export const heapBytes: () => number;
6
7
  export const logsink_clear: (a: number) => void;
7
8
  export const logsink_drain: (a: number) => any;
8
9
  export const logsink_drainLines: (a: number) => [number, number];
@@ -15,10 +16,13 @@ export const renderer_attribution: (a: number) => [number, number];
15
16
  export const renderer_bindSource: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number];
16
17
  export const renderer_boundSources: (a: number) => [number, number];
17
18
  export const renderer_clearSources: (a: number) => void;
19
+ export const renderer_memoryUsage: (a: number) => [number, number, number];
20
+ export const renderer_neededCodepoints: (a: number) => [number, number, number];
18
21
  export const renderer_neededGlyphRanges: (a: number) => [number, number, number];
19
22
  export const renderer_new: (a: number, b: number) => [number, number, number];
20
23
  export const renderer_renderTile: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
21
24
  export const renderer_requestedNeighborOffsets: (a: number, b: number, c: number) => [number, number, number];
25
+ export const renderer_setGlyphBudget: (a: number, b: number) => void;
22
26
  export const renderer_setStyle: (a: number, b: number, c: number) => [number, number, number];
23
27
  export const renderer_tileSize: (a: number) => number;
24
28
  export const simdEnabled: () => number;
package/nodejs/ezu.d.ts CHANGED
@@ -76,9 +76,28 @@ export class Renderer {
76
76
  * - `geojson` (remote) → store raw bytes per `(dx, dy)` offset;
77
77
  * projected per tile (and neighbour) at render time.
78
78
  *
79
- * `opts` is a JS object: `{ coord?: [dx, dy] }`. Throws
80
- * `UnknownSource` if `name` doesn't match any entry in the style's
81
- * `sources` block, `MvtDecode` if MVT bytes don't parse, and
79
+ * `opts` is a JS object: `{ coord?: [dx, dy], sourceZoom?: number }`.
80
+ *
81
+ * `sourceZoom` declares that MVT bytes are natively encoded at a
82
+ * *shallower* zoom than the tile being rendered — a vector source
83
+ * that stops at its `maxzoom` while the host serves deeper tiles.
84
+ * The renderer then reprojects each payload from its own ancestor
85
+ * into the tile's frame before rendering (MVT "overzoom"), which is
86
+ * what a client would otherwise do by scaling a raster up. The
87
+ * ancestor is derived, not supplied: for a tile at zoom `z`, the
88
+ * ancestor at `sourceZoom` is unique, so a host that binds the
89
+ * `maxzoom` tile it fetched has nothing further to compute — and
90
+ * each neighbour resolves against its own ancestor, which for a 3×3
91
+ * window may be a different parent than the centre's.
92
+ *
93
+ * `sourceZoom` equal to the rendered zoom is accepted and does
94
+ * nothing, so a host can pass its source's `maxzoom` unconditionally
95
+ * and let shallow tiles take the ordinary path. Deeper than the
96
+ * rendered zoom throws `UnknownSource`: there is no way to invent
97
+ * detail the bytes do not carry.
98
+ *
99
+ * Throws `UnknownSource` if `name` doesn't match any entry in the
100
+ * style's `sources` block, `MvtDecode` if MVT bytes don't parse, and
82
101
  * `DemDecode` for non-image DEM bytes (the decode itself runs at
83
102
  * render time, but obvious cases are caught here).
84
103
  */
@@ -92,6 +111,57 @@ export class Renderer {
92
111
  * Drop every pending source binding. Call between tile renders.
93
112
  */
94
113
  clearSources(): void;
114
+ /**
115
+ * What this renderer is holding, in bytes, so a host can shed load
116
+ * *before* an allocation fails rather than after.
117
+ *
118
+ * Returns a JS object:
119
+ * - `heapBytes` — wasm linear memory committed to the **module**,
120
+ * shared by every `Renderer` in this instance. This is the number
121
+ * that meets an isolate's memory cap. It is a high-water mark:
122
+ * freeing Rust values returns them to the allocator, never to the
123
+ * host, so it only ever grows.
124
+ * - `glyphBytes` / `glyphRanges` — SDF bitmaps resident in the
125
+ * glyph bank, and how many 256-codepoint blocks they span. Glyphs
126
+ * accumulate for the life of the renderer and survive
127
+ * `clearSources`, so on a long-lived instance this is usually
128
+ * what grew. `glyphBudget` is the per-fontstack ceiling
129
+ * `setGlyphBudget` put on them, or `Infinity` if none — note
130
+ * `glyphBytes` totals *every* fontstack, so it can exceed the
131
+ * budget legitimately.
132
+ * - `fontBytes` — outline font files held in the font bank.
133
+ * - `imageBytes` — decoded pixels of bound images and sprite
134
+ * atlases.
135
+ * - `cacheBytes` / `cacheBudget` — the render cache's pixel
136
+ * payload against its own eviction budget; it bounds itself, so
137
+ * `cacheBytes` near `cacheBudget` is steady state, not a leak.
138
+ *
139
+ * These are payload sizes, not an accounting of the heap: they omit
140
+ * allocator overhead, decoded features, per-font glyph-path caches,
141
+ * and the buffers a render is using right now. Expect the parts to
142
+ * sum to less than `heapBytes`.
143
+ */
144
+ memoryUsage(): object;
145
+ /**
146
+ * Codepoints the currently bound features can require, as
147
+ * `{ [glyphsSourceName]: number[] }` sorted ascending.
148
+ *
149
+ * This is the precise form of
150
+ * [`neededGlyphRanges`](Self::needed_glyph_ranges): a host that
151
+ * can build its own glyph PBF — one message holding just these
152
+ * codepoints — transfers only the glyphs the tile draws instead
153
+ * of the whole 256-codepoint block around each of them. On CJK
154
+ * labels that is the difference between a few thousand glyphs and
155
+ * a few tens of megabytes. `bindSource` files each glyph by its
156
+ * own id, so such a subset may span any number of blocks and
157
+ * needs no particular `range` string.
158
+ *
159
+ * Hosts that can only fetch whole `{range}.pbf` files off a
160
+ * MapLibre glyphs endpoint want `neededGlyphRanges` instead. Both
161
+ * calls see the same set of codepoints and carry the same
162
+ * over-approximation caveat.
163
+ */
164
+ neededCodepoints(): object;
95
165
  /**
96
166
  * Glyph ranges the currently bound features can require, as
97
167
  * `{ [glyphsSourceName]: number[] }` where each number is a range
@@ -103,6 +173,11 @@ export class Renderer {
103
173
  * scraping every string in the MVT, call this after binding the
104
174
  * vector sources and bind exactly the listed ranges.
105
175
  *
176
+ * A range holds 256 codepoints and a tile typically draws a
177
+ * handful of them, so this is a coarse unit to fetch in. Hosts
178
+ * that can assemble their own subset PBF should call
179
+ * [`neededCodepoints`](Self::needed_codepoints) instead.
180
+ *
106
181
  * It is an over-approximation, deliberately: a range is listed if
107
182
  * *any* feature in a text layer carries the codepoint in a property
108
183
  * the layer's `text` expression reads, without evaluating filters,
@@ -144,6 +219,31 @@ export class Renderer {
144
219
  * Throws `UnknownSource` if `name` is not declared in the style.
145
220
  */
146
221
  requestedNeighborOffsets(name: string): Array<any>;
222
+ /**
223
+ * Cap the glyph bytes each bound fontstack keeps resident, in
224
+ * bytes. Unset, a fontstack keeps every range ever bound to it for
225
+ * the life of the renderer — `clearSources` does not touch glyphs,
226
+ * and on a long-lived instance rendering across a basemap that is
227
+ * usually what grew.
228
+ *
229
+ * Trimming happens **after** each `renderTile`, not while binding,
230
+ * so a render never loses glyphs that were bound for it. The tile
231
+ * that just drew is therefore the most recently used, and a budget
232
+ * large enough for one tile's glyphs always keeps that tile's; what
233
+ * goes is what earlier tiles needed and this one did not. Set it
234
+ * below one tile's worth and the ceiling still holds — the stack
235
+ * empties after every render and nothing carries over, which
236
+ * renders correctly but buys no reuse.
237
+ *
238
+ * It is a per-fontstack ceiling: a style with a regular, a medium
239
+ * and an italic stack can hold three times what is set here.
240
+ *
241
+ * This host cannot refetch, so anything trimmed must be bound again
242
+ * before the next tile that needs it. `neededCodepoints()` already
243
+ * names exactly what to bind, and a host that re-binds every tile
244
+ * (rather than tracking what it sent) needs no other change.
245
+ */
246
+ setGlyphBudget(bytes: number): void;
147
247
  /**
148
248
  * Replace the active style. Returns the new node count. Invalidates
149
249
  * the intermediate cache and drops any pending source bindings.
@@ -161,6 +261,22 @@ export class Renderer {
161
261
  readonly tileSize: number;
162
262
  }
163
263
 
264
+ /**
265
+ * Wasm linear memory currently committed to this module, in bytes.
266
+ *
267
+ * This is the figure an isolate's memory cap applies to, and the one
268
+ * to watch to shed load before an allocation fails — a refused
269
+ * `memory.grow` throws [`OutOfMemory`](oom) and ends the instance.
270
+ * It never falls: freed Rust values return to the allocator for reuse,
271
+ * but wasm cannot hand pages back to the host. So a drop in demand
272
+ * leaves the number where its peak left it, and only a fresh instance
273
+ * resets it.
274
+ *
275
+ * Module-wide, not per-`Renderer`. For what a given renderer is
276
+ * holding, and which bank to evict, call `memoryUsage()`.
277
+ */
278
+ export function heapBytes(): number;
279
+
164
280
  /**
165
281
  * Whether the wasm binary was compiled with `+simd128`. Lets the demo
166
282
  * page label the renderer build accurately.