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