mirror of
https://github.com/CNCKitchen/stlTexturizer.git
synced 2026-04-07 22:11:32 +00:00
perf: time-based yield reduces background tab overhead by ~95%
Replace fixed-interval yields (every 4096 iterations) with time-based yields (every ~100ms of wall time). In foreground tabs this means ~10 yields per second instead of ~50-200, with identical UI responsiveness. In background tabs where setTimeout(0) is throttled to ~1s, this reduces overhead from ~200 wasted seconds to ~10 — the export runs nearly as fast in the background as in the foreground. Addresses #2 (background tab resource allocation).
This commit is contained in:
+15
-6
@@ -46,8 +46,17 @@ const FLIP_DOT_SQ = FLIP_DOT * FLIP_DOT;
|
|||||||
const CREASE_COS = 0.5; // cos 60° — edges sharper than this are treated as creases
|
const CREASE_COS = 0.5; // cos 60° — edges sharper than this are treated as creases
|
||||||
const CREASE_WEIGHT = 1e4; // quadric penalty weight for crease edges
|
const CREASE_WEIGHT = 1e4; // quadric penalty weight for crease edges
|
||||||
|
|
||||||
// Yield to browser for UI responsiveness during long-running decimation.
|
// Time-based yield: only yield every ~100ms of wall time instead of every N iterations.
|
||||||
// setTimeout(0) guarantees a real rendering frame between iterations.
|
// In foreground tabs setTimeout(0) costs ~4ms; in background tabs it's throttled to ~1s.
|
||||||
|
// By yielding based on elapsed time we get ~10 yields per second in foreground (smooth progress)
|
||||||
|
// and minimal extra delay in background (~10 yields × 1s = ~10s overhead instead of ~200s).
|
||||||
|
let _lastYieldTime = 0;
|
||||||
|
function _shouldYield() {
|
||||||
|
const now = performance.now();
|
||||||
|
if (now - _lastYieldTime < 100) return false;
|
||||||
|
_lastYieldTime = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
function _yieldFrame() {
|
function _yieldFrame() {
|
||||||
return new Promise(r => setTimeout(r, 0));
|
return new Promise(r => setTimeout(r, 0));
|
||||||
}
|
}
|
||||||
@@ -109,10 +118,10 @@ export async function decimate(geometry, targetTriangles, onProgress) {
|
|||||||
const idx = heap.pop();
|
const idx = heap.pop();
|
||||||
if (idx < 0) break;
|
if (idx < 0) break;
|
||||||
|
|
||||||
// Yield periodically based on total iterations (including rejections)
|
// Yield based on elapsed wall time (~every 100ms) instead of fixed iteration count.
|
||||||
// to keep the UI responsive. Critical for flat / low-displacement
|
// Drastically reduces overhead in background tabs where setTimeout is throttled to 1s.
|
||||||
// surfaces where most collapses are rejected by the safety guards.
|
++iterations;
|
||||||
if ((++iterations & 4095) === 0) {
|
if (_shouldYield()) {
|
||||||
await _yieldFrame();
|
await _yieldFrame();
|
||||||
if (onProgress) {
|
if (onProgress) {
|
||||||
const p = Math.min(1, (initFaces - activeFaces) / toRemove);
|
const p = Math.min(1, (initFaces - activeFaces) / toRemove);
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ export async function subdivide(geometry, maxEdgeLength, onProgress, faceWeights
|
|||||||
|
|
||||||
const newTriCount = newIndices.length / 3;
|
const newTriCount = newIndices.length / 3;
|
||||||
if (onProgress) onProgress(Math.min(0.95, (iter + 1) / maxIterations), newTriCount, longestEdge);
|
if (onProgress) onProgress(Math.min(0.95, (iter + 1) / maxIterations), newTriCount, longestEdge);
|
||||||
|
// Yield once per subdivision pass (not per iteration) — keeps background tabs fast
|
||||||
await new Promise(r => setTimeout(r, 0));
|
await new Promise(r => setTimeout(r, 0));
|
||||||
if (!changed || safetyCapHit) break;
|
if (!changed || safetyCapHit) break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user