mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-11 13:52:19 +00:00
Finish traffic surface sampling with the camera still
Road samples that were not ready, or left over when a pass ran out of its slice, waited for the next camera move; with the camera at rest they stayed pending and part of the network never settled on the ground. The flow now requests the frame it needs and continues the unresolved samples within the same 12 ms slice and station budget.
This commit is contained in:
1 parent
ab41c765cc
commit
be395f0f52
2 files changed
+86
-6
No files matched your search
@@ -538,6 +538,7 @@ export function createFlow({ state: layerState, services, parts, source }) {
|
||||
current() &&
|
||||
performance.now() < deadline
|
||||
) {
|
||||
engine.render.request('traffic-surface');
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
if (!current()) return false;
|
||||
prepared = await prepareRoadSurfaces(
|
||||
@@ -555,10 +556,9 @@ export function createFlow({ state: layerState, services, parts, source }) {
|
||||
if (
|
||||
current() &&
|
||||
!preview &&
|
||||
!label.includes('refined') &&
|
||||
(!trafficSurfaceReady(engine) ||
|
||||
((!refining && !trafficSurfaceReady(engine)) ||
|
||||
prepared.pending.length ||
|
||||
ready.some((road) => road.surfaceSettled === false))
|
||||
(!refining && ready.some((road) => road.surfaceSettled === false)))
|
||||
) {
|
||||
layerState._surfaceRefineRemove?.();
|
||||
const stop = () => {
|
||||
@@ -572,17 +572,21 @@ export function createFlow({ state: layerState, services, parts, source }) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
if (!trafficSurfaceReady(engine)) return;
|
||||
if (!trafficSurfaceReady(engine)) {
|
||||
engine.render.request('traffic-surface');
|
||||
return;
|
||||
}
|
||||
stop();
|
||||
// Revalidate only local samples taken at a coarser rendered LOD. This
|
||||
// background upgrade never holds road acquisition or first paint.
|
||||
// background upgrade never holds road acquisition or first paint;
|
||||
// missing samples keep retrying while refined heights stay cached.
|
||||
layerState._surfaceRefining = true;
|
||||
applyFlowThenRender(
|
||||
roads,
|
||||
clamped,
|
||||
generation,
|
||||
altitude,
|
||||
`${label} refined`,
|
||||
refining ? label : `${label} refined`,
|
||||
trace,
|
||||
false,
|
||||
signal,
|
||||
@@ -598,6 +602,7 @@ export function createFlow({ state: layerState, services, parts, source }) {
|
||||
});
|
||||
const timer = setTimeout(stop, 10000);
|
||||
layerState._surfaceRefineRemove = stop;
|
||||
engine.render.request('traffic-surface');
|
||||
}
|
||||
return current() && ready.length > 0;
|
||||
}
|
||||
|
||||
@@ -166,6 +166,81 @@ test('the handoff pass on a loading globe refines once its surface is ready', as
|
||||
);
|
||||
});
|
||||
|
||||
test('a still camera drains pending surface samples across bounded passes using requested frames', async (t) => {
|
||||
const surface = incomingGlobe(t);
|
||||
surface.ready = true;
|
||||
surface.frame();
|
||||
const { engine } = surface;
|
||||
const { state, flow } = fixture(surface);
|
||||
t.after(() => {
|
||||
state._activeFetchAbort.abort();
|
||||
state._surfaceRefineRemove?.();
|
||||
});
|
||||
const roads = Array.from({ length: 20 }, (_, i) => road(i * 0.0001, GROUND));
|
||||
let time = 0;
|
||||
let available = 8;
|
||||
let samples = 0;
|
||||
let samplesAtYield;
|
||||
let frames = 0;
|
||||
const measured = new Set();
|
||||
t.mock.method(performance, 'now', () => time);
|
||||
engine.fake.script('terrainHeight', (point) => {
|
||||
samples++;
|
||||
if (samples === 1) setTimeout(() => (samplesAtYield = samples), 0);
|
||||
time += 3;
|
||||
const key = `${point.longitude},${point.latitude}`;
|
||||
if (!measured.has(key)) {
|
||||
if (!available) return undefined;
|
||||
available--;
|
||||
measured.add(key);
|
||||
}
|
||||
return GROUND;
|
||||
});
|
||||
let cameraChanges = 0;
|
||||
t.after(engine.camera.changed.addEventListener(() => cameraChanges++));
|
||||
t.after(
|
||||
engine.frames.preRender.addEventListener(() => {
|
||||
available = 8;
|
||||
surface.ready = ++frames > 1;
|
||||
}),
|
||||
);
|
||||
const requests = engine.fake.renderRequests;
|
||||
await flow.applyFlowThenRender(
|
||||
roads,
|
||||
{ ...bounds, coverage },
|
||||
1,
|
||||
1800,
|
||||
'Loaded full',
|
||||
);
|
||||
assert.ok(samples * 3 > 12, 'the samples exceed one surface slice');
|
||||
assert.equal(samplesAtYield, 4, 'sampling yields at the 12 ms budget');
|
||||
assert.ok(state._surfacePending > 0, 'some streets are not loaded yet');
|
||||
let rendered = requests;
|
||||
await settle(() => {
|
||||
if (engine.fake.renderRequests > rendered) {
|
||||
rendered = engine.fake.renderRequests;
|
||||
surface.frame();
|
||||
}
|
||||
return !state._surfacePending && !state._surfaceRefining;
|
||||
});
|
||||
assert.equal(state._surfacePending, 0);
|
||||
assert.equal(cameraChanges, 0, 'no camera trigger resumes the work');
|
||||
assert.ok(rendered - requests > 1, 'missing heights need further frames');
|
||||
assert.equal(state._surfaceRefineRemove, null);
|
||||
for (const r of roads) {
|
||||
assert.equal(r.surfaceReady, true);
|
||||
assert.ok(
|
||||
r.waypoints.every(
|
||||
(point) => Math.abs(height(point) - GROUND - DOT_HEIGHT_OFFSET) < 0.01,
|
||||
),
|
||||
);
|
||||
}
|
||||
const finished = engine.fake.renderRequests;
|
||||
surface.frame();
|
||||
await nextTask();
|
||||
assert.equal(engine.fake.renderRequests, finished, 'settled work is idle');
|
||||
});
|
||||
|
||||
test('resuming the viewport republishes the retained roads as a pass that can still refine', () => {
|
||||
const labels = [];
|
||||
const state = createState({ services: {} });
|
||||
|
||||
Reference in new issue
Block a user