entangled-worlds-orbiters-shared 3.0.0 → 3.1.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/package.json
CHANGED
|
@@ -158,6 +158,10 @@ export function createViewportCompositor({
|
|
|
158
158
|
let grid = null;
|
|
159
159
|
let raf = null;
|
|
160
160
|
let disposed = false;
|
|
161
|
+
// A load meter's watch on the realm's frames (`setFrameProbe`): null when nobody is watching.
|
|
162
|
+
let frameProbe = null;
|
|
163
|
+
let frameProbeAt = 0;
|
|
164
|
+
let probePixel = null;
|
|
161
165
|
let lastCanvasW = 0;
|
|
162
166
|
let lastCanvasH = 0;
|
|
163
167
|
let viewportH = 0; // per-cell cull band (CSS px), refreshed with the rects
|
|
@@ -514,7 +518,60 @@ export function createViewportCompositor({
|
|
|
514
518
|
// at half the realm's rate. Skipping the whole frame instead leaves every cell showing the last
|
|
515
519
|
// frame that was drawn — together, which is the only way a shared canvas can be consistent.
|
|
516
520
|
if (performanceOn && !frameBudget.shouldRender(nowMs)) return;
|
|
517
|
-
|
|
521
|
+
if (!frameProbe) {
|
|
522
|
+
renderOnce();
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
const probe = frameProbe;
|
|
526
|
+
probe.onFrame?.(nowMs);
|
|
527
|
+
const timed = nowMs - frameProbeAt >= probe.everyMs;
|
|
528
|
+
if (!timed) {
|
|
529
|
+
renderOnce();
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
frameProbeAt = nowMs;
|
|
533
|
+
// Every cell's draw counted together: one composited frame is several renders.
|
|
534
|
+
const info = renderer.info;
|
|
535
|
+
const autoReset = info.autoReset;
|
|
536
|
+
info.autoReset = false;
|
|
537
|
+
info.reset();
|
|
538
|
+
try {
|
|
539
|
+
const started = performance.now();
|
|
540
|
+
renderOnce();
|
|
541
|
+
// A lost context draws nothing and answers nothing: no reading, not a good one.
|
|
542
|
+
if (waitForDraw()) {
|
|
543
|
+
const drawn = performance.now();
|
|
544
|
+
// Asked again with nothing left to draw: what the asking itself costs, taken off the reading.
|
|
545
|
+
waitForDraw();
|
|
546
|
+
probe.onDraw(Math.max(0, drawn - started - (performance.now() - drawn)), info.render.calls, info.render.triangles);
|
|
547
|
+
}
|
|
548
|
+
} finally {
|
|
549
|
+
// Put back as it was, even when a voice throws mid-frame.
|
|
550
|
+
info.autoReset = autoReset;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** Block until the graphics chip has drawn what was sent: reading a pixel back is the one wait every
|
|
555
|
+
* browser honours. False when there is no context to ask. */
|
|
556
|
+
function waitForDraw() {
|
|
557
|
+
const gl = renderer.getContext?.();
|
|
558
|
+
if (!gl || gl.isContextLost()) return false;
|
|
559
|
+
probePixel ??= new Uint8Array(4);
|
|
560
|
+
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, probePixel);
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Watch the realm's frames, for a load meter: `onFrame(nowMs)` for every frame drawn, and one frame
|
|
566
|
+
* every `everyMs` timed to the end of its drawing (`onDraw(workMs, calls, triangles)`, every cell
|
|
567
|
+
* together). Only the timed frame waits for the graphics chip; every other frame is untouched.
|
|
568
|
+
* `null` stops it.
|
|
569
|
+
*
|
|
570
|
+
* @param {{ everyMs: number, onFrame?: (nowMs: number) => void, onDraw: (workMs: number, calls: number, triangles: number) => void } | null} probe
|
|
571
|
+
*/
|
|
572
|
+
function setFrameProbe(probe) {
|
|
573
|
+
frameProbe = probe ?? null;
|
|
574
|
+
frameProbeAt = 0;
|
|
518
575
|
}
|
|
519
576
|
|
|
520
577
|
/**
|
|
@@ -572,6 +629,7 @@ export function createViewportCompositor({
|
|
|
572
629
|
removeVoice,
|
|
573
630
|
renderOnce,
|
|
574
631
|
setPerformanceMode,
|
|
632
|
+
setFrameProbe,
|
|
575
633
|
dispose,
|
|
576
634
|
};
|
|
577
635
|
// Dev handle: lets tooling force a composited frame when rAF is throttled (e.g. a hidden/background
|