forked from 1b-agent/opencadstudio-upstream
fix: one VRAM-aware buffer budget for every GPU upload path
max_buffer_size is an API validation limit, not physical VRAM. NVIDIA reports several GB of it on a 2 GB card, so sizing a chunk from it produces buffers larger than the whole device. That is the same bug as #203 (mesh_gpu), #358 (face3d_gpu) and the block-wire vertex buffer: rediscovered three times because each upload path spelled the budget out for itself. mesh_gpu.rs was the only site that clamped the result. Move that clamp into src/scene/pipeline/gpu_budget.rs and route every allocating path through it, so a new upload path cannot reintroduce the mistake by copying one of the unclamped expressions. Five sites had no clamp at all: text_gpu (block-text instances), wire_gpu (block-wire instances), and face3d_gpu (vertices, instances, and upload_chunks). Three behaviour changes worth noting: * Silhouette chunks were capped at a private 64 MiB constant and now use the shared 32 MiB budget. * The storage-hatch chunk limit was the minimum of two device limits, both of them validation figures; it is now also capped by the budget. The `*_fits` predicates next to it are genuine "would wgpu reject this" checks and are left alone. * mesh_gpu's instanced path used the unclamped ceiling to decide whether a mesh fits in a single buffer, which would still admit a multi-GB allocation. It now uses the clamped budget, so a few more meshes take the chunked path. OCS_GPU_CHUNK_MIB overrides the cap. Raising it above the real VRAM is the cheapest way to force an allocation failure and check that the renderer degrades instead of aborting. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8552450aa8
commit
771a5b2c5c
7 files changed
+84
-35
No files matched your search
@@ -1580,10 +1580,8 @@ pub fn build_mesh_batch_filtered(
|
||||
// Derive the caps from the real device limit and vertex size. The previous
|
||||
// fixed 6 M-vertex cap assumed 40 B/vertex, but `position_low` (RTE) grew
|
||||
// MeshVertex to 52 B, so 6 M × 52 B = 312 MB blew past the 256 MB cap.
|
||||
let hard_budget = (device.limits().max_buffer_size as usize / 10) * 9;
|
||||
let budget = hard_budget.min(32 * 1024 * 1024);
|
||||
let vsize = std::mem::size_of::<MeshVertex>();
|
||||
let max_verts = (budget / vsize).max(3);
|
||||
let budget = super::gpu_budget::buffer_budget(device);
|
||||
let max_verts = super::gpu_budget::max_elements::<MeshVertex>(device).max(3);
|
||||
// A triangle contributes three line segments (six standalone edge
|
||||
// vertices). Bound chunks by the largest buffer produced for wire meshes.
|
||||
let max_tris =
|
||||
@@ -1800,9 +1798,9 @@ pub fn build_mesh_batch_filtered(
|
||||
.verts
|
||||
.len()
|
||||
.saturating_mul(std::mem::size_of::<MeshVertex>())
|
||||
<= hard_budget
|
||||
<= budget
|
||||
&& part.indices.len().saturating_mul(std::mem::size_of::<u32>())
|
||||
<= hard_budget
|
||||
<= budget
|
||||
&& part
|
||||
.set
|
||||
.instance_source
|
||||
@@ -1812,7 +1810,7 @@ pub fn build_mesh_batch_filtered(
|
||||
.edge_verts
|
||||
.len()
|
||||
.saturating_mul(std::mem::size_of::<MeshEdgeVertex>())
|
||||
<= hard_budget;
|
||||
<= budget;
|
||||
let triangle_edges_fit = !part.include_edges
|
||||
|| !source.edge_verts.is_empty()
|
||||
|| part
|
||||
@@ -1820,7 +1818,7 @@ pub fn build_mesh_batch_filtered(
|
||||
.len()
|
||||
.saturating_mul(2)
|
||||
.saturating_mul(std::mem::size_of::<MeshEdgeVertex>())
|
||||
<= hard_budget;
|
||||
<= budget;
|
||||
feature_edges_fit && triangle_edges_fit
|
||||
})
|
||||
&& part
|
||||
|
||||
Reference in new issue
Block a user