forked from 1b-agent/opencadstudio-upstream
fix: an out-of-memory GPU no longer aborts the process
The crash in #358 was not the out-of-memory itself. wgpu reports OOM as recoverable and the app already installs a handler that logs and keeps the session alive. What killed the process was what happened next: create_buffer_init maps the new buffer unconditionally, and mapping the invalid buffer an OOM device returns panics. That panic unwinds through iced's main-thread redraw, trips the wgpu-hal swapchain assertion in a destructor, and becomes a non-unwinding abort -- no chance to autosave. Every allocation whose size scales with the drawing now goes through src/scene/pipeline/gpu_upload.rs, which creates the buffer unmapped and fills it with Queue::write_buffer. A failed allocation then surfaces as a validation error on the write, which reaches install_gpu_error_handler and degrades the frame -- exactly what that handler's comment promised: "A bad frame must degrade, not end the session." Converted: block-wire vertices and instances, the wire const storage buffer, all three wire-arena allocators, face3d vertices and instances, block-text instances and text vertices, both hatch backends, and the silhouette buffers. mesh_gpu already allocated this way, which is why the mesh path never produced this panic; the rest now match it. No mapped_at_creation:true remains in the renderer. The create_buffer_init calls left are fixed-size or bounded-small -- uniforms, the viewcube's static geometry, per-image and per-wipeout quads -- where an allocation failure is not a realistic outcome. Two trade-offs worth stating: * write_buffer stages through a copy, which mapping at creation avoided. Chunking bounds that transient cost, and the measured block-wire upload got faster with chunking, not slower. * `queue` had to be threaded through the wire, face3d, text and hatch builders and their callers. Mechanical, but it widens the diff. This touches every upload path, so it needs a visual check against a real drawing before it goes upstream. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
771a5b2c5c
commit
d0ef752532
10 files changed
+362
-208
No files matched your search
@@ -608,6 +608,7 @@ impl shader::Primitive for Primitive {
|
||||
{
|
||||
inner.upload_face3d(
|
||||
device,
|
||||
queue,
|
||||
&vp.face3d_wires[..],
|
||||
&vp_wires[..],
|
||||
!face3d_fill_active,
|
||||
@@ -785,6 +786,7 @@ impl shader::Primitive for Primitive {
|
||||
inner.wire_arena_fallback = std::sync::Arc::new(
|
||||
crate::scene::pipeline::WireGpu::from_run_refs(
|
||||
device,
|
||||
queue,
|
||||
®ular,
|
||||
&draw_depths,
|
||||
false,
|
||||
@@ -821,6 +823,7 @@ impl shader::Primitive for Primitive {
|
||||
inner.wire_arena_fallback = std::sync::Arc::new(
|
||||
crate::scene::pipeline::WireGpu::from_run_refs(
|
||||
device,
|
||||
queue,
|
||||
&mesh,
|
||||
&draw_depths,
|
||||
true,
|
||||
@@ -918,7 +921,7 @@ impl shader::Primitive for Primitive {
|
||||
Some(entry) => entry,
|
||||
None => {
|
||||
let entry =
|
||||
inner.build_wire_buffers(device, &vp_wires[..], &draw_depths);
|
||||
inner.build_wire_buffers(device, queue, &vp_wires[..], &draw_depths);
|
||||
pipeline
|
||||
.wire_buffer_cache
|
||||
.insert(vp.wire_content_id, entry.clone());
|
||||
@@ -1000,6 +1003,7 @@ impl shader::Primitive for Primitive {
|
||||
};
|
||||
inner.upload_selected_wires(
|
||||
device,
|
||||
queue,
|
||||
&vp_wires[..],
|
||||
&vp.selected_handles,
|
||||
&vp.hover_handles,
|
||||
@@ -1012,6 +1016,7 @@ impl shader::Primitive for Primitive {
|
||||
// base text buffer.
|
||||
inner.upload_text_highlight(
|
||||
device,
|
||||
queue,
|
||||
&vp_wires[..],
|
||||
&vp.selected_handles,
|
||||
&vp.hover_handles,
|
||||
@@ -1066,7 +1071,7 @@ impl shader::Primitive for Primitive {
|
||||
// Live overlay (command preview / interim / grip drag) — small and
|
||||
// refreshed every frame it's present, so a drag never re-uploads
|
||||
// the resident base wire buffer.
|
||||
inner.upload_preview_wires(device, &vp.preview_wires[..], &draw_depths);
|
||||
inner.upload_preview_wires(device, queue, &vp.preview_wires[..], &draw_depths);
|
||||
inner.upload_preview_text(device, queue, &vp.preview_text_verts[..]);
|
||||
// Cull / scissor / LOD project AABBs relative-to-eye (matching the
|
||||
// GPU's RTE path) so the math stays precise at UTM-scale coords.
|
||||
@@ -1087,6 +1092,7 @@ impl shader::Primitive for Primitive {
|
||||
if inner.silhouette_key != silhouette_key {
|
||||
inner.upload_silhouettes(
|
||||
device,
|
||||
queue,
|
||||
if silhouette_enabled { &vp.meshes[..] } else { &[] },
|
||||
vp.wire_content_id,
|
||||
vp.view_dir,
|
||||
|
||||
Reference in new issue
Block a user