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