viewport: idle the render loop when only unfetchable chunks remain

The streaming settle burst re-armed the render loop whenever a
non-resident chunk was frustum-visible, but the enqueue only fetches
chunks that are contribution-visible (big enough on screen) and not in a
blocked cooldown. A chunk that is in the frustum but sub-pixel is never
loaded, so visible_pending stayed true forever and the loop spun at full
frame rate with no input.

Match visible_pending to the enqueue's eligibility test: a non-resident
chunk keeps the loop alive only if it's actively loading, or is
contribution-visible and past its cooldown. Sub-pixel / cooldown-blocked
chunks no longer prevent idle; they still stream in when a camera move or
eviction requests a frame.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-07-08 19:43:07 +10:00
parent 60cab3e7c4
commit 90196dd51d
+11 -1
View File
@@ -2515,7 +2515,17 @@ void ViewportCore::driveStreamingLoads() {
for (const auto& [session_model_id, m] : models_gpu_) {
if (m.streaming_file_path.empty() || m.hidden) continue;
for (const auto& c : m.chunks) {
if (!c.is_resident && (c.frustum_visible_count > 0 || c.is_loading)) {
if (c.is_resident) continue;
// Keep the loop alive only for chunks we're actually loading or that
// are eligible to enqueue — the same test the enqueue below uses
// (contribution-visible and not in a blocked cooldown). A chunk
// that's in the frustum but sub-pixel (contribution_visible_count
// == 0) is never fetched, so it must not keep the render loop
// spinning at idle; likewise a cooldown-blocked chunk only retries
// after real work (an eviction or camera move) requests a frame.
if (c.is_loading
|| (c.contribution_visible_count > 0
&& c.blocked_cooldown_until_frame_idx <= streaming_frame_idx_)) {
visible_pending = true;
break;
}