forked from 1b-agent/opencadstudio-upstream
fix: a rejected upload must not latch the slot as up to date
The drawing vanished from Model and only came back with REGENALL. That is this bug's exact signature, and the guard added two commits ago was incomplete. `cached_wire_id` gates the entire wire upload block — line 620 skips it whenever the slot's id already matches the viewport's content id — and it was stamped unconditionally at the end of that block, whether or not the device had accepted what was uploaded. So a rejected allocation left the slot holding invalid buffers *and* claiming to be current. Nothing rebuilt it. REGENALL worked because it mints a new content id, which is the one thing that makes the ids differ again. `wire_buffer_cache` and `wire_arena_id` were guarded; this third latch, the one that gates them both, was missed. Guarding it individually would leave the same question for `cached_text_source`, `cached_hatch_source` and the rest, each stamped after its own upload. So the check moves to where it covers all of them: if the device reported anything during this viewport's turn, the slot forgets every cache key it holds and the next frame rebuilds it. The counter is device-wide, so an error raised by one viewport also invalidates its neighbours in that frame. That is deliberate — the cost is one slow frame, and the alternative is the failure this fixes. The narrower guards stay: `wire_buffer_cache` is shared across slots, so keeping a bad entry out of it protects viewports that were healthy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0118b28d10
commit
deebc14012
1 file changed
+15
@@ -373,6 +373,12 @@ impl shader::Primitive for Primitive {
|
||||
|
||||
for (i, vp) in self.viewports.iter().enumerate() {
|
||||
let inner = &mut pipeline.inners[slots[i]];
|
||||
// Compared at the end of this viewport's turn. Every "we hold this
|
||||
// now" latch below is stamped after its upload, whether or not the
|
||||
// device accepted it — and the wire latch gates the whole upload
|
||||
// block, so one rejected allocation could leave a slotpermanently empty with
|
||||
// nothing that would ever rebuild it.
|
||||
let slot_errors_before = crate::scene::pipeline::gpu_errors_seen();
|
||||
// Pipeline slots are addressed by list index, but off-canvas
|
||||
// viewports are dropped from the list — so a slot can be reused by a
|
||||
// DIFFERENT viewport across frames (e.g. the first viewport scrolls
|
||||
@@ -1180,6 +1186,15 @@ impl shader::Primitive for Primitive {
|
||||
self.viewcube_text_color,
|
||||
);
|
||||
}
|
||||
|
||||
// A rejected allocation leaves buffers that are invalid but
|
||||
// indistinguishable from good ones at every cache key. Forget
|
||||
// them all, so the next frame rebuilds this slot instead of
|
||||
// drawing nothing for the rest of the session — which is what
|
||||
// sent a user to REGENALL to get the model back.
|
||||
if crate::scene::pipeline::gpu_errors_seen() != slot_errors_before {
|
||||
inner.forget_cached_keys();
|
||||
}
|
||||
}
|
||||
let prepare_ms = nav_prepare_started.elapsed().as_secs_f64() * 1000.0;
|
||||
if let Some(sample) = self.nav_perf {
|
||||
|
||||
Reference in new issue
Block a user