forked from 1b-agent/opencadstudio-upstream
Merge commit '19490a548bad05356d69bd47c6e3827a6d3b0a77'
This commit is contained in:
commit
66067860f9
2 files changed
+41
-7
No files matched your search
@@ -8,19 +8,50 @@ fn device_ceiling(device: &wgpu::Device) -> usize {
|
||||
(usize::try_from(device.limits().max_buffer_size).unwrap_or(usize::MAX) / 10) * 9
|
||||
}
|
||||
|
||||
/// Optional per-buffer cap in MiB, useful for testing smaller chunks.
|
||||
fn cap_bytes() -> usize {
|
||||
static CAP: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
|
||||
/// The wire arena keeps one persistent instance buffer for the whole resident
|
||||
/// set and patches it in place. Capping that at the per-chunk budget pushes any
|
||||
/// drawing past ~524 k instances onto the batched fallback, which re-uploads
|
||||
/// everything on every edit — 200 ms a click on a drawing with 821 k. A single
|
||||
/// long-lived buffer can afford more than a transient chunk, and 128 MiB is
|
||||
/// still four times smaller than the 505 MiB allocation that crashed a 2 GB
|
||||
/// card in the first place.
|
||||
const ARENA_CAP_BYTES: usize = 128 * 1024 * 1024;
|
||||
|
||||
/// `OCS_GPU_CHUNK_MIB`, when set. Overrides both caps so a test can force
|
||||
/// small buffers.
|
||||
fn env_cap_bytes() -> Option<usize> {
|
||||
static CAP: std::sync::OnceLock<Option<usize>> = std::sync::OnceLock::new();
|
||||
*CAP.get_or_init(|| {
|
||||
std::env::var("OCS_GPU_CHUNK_MIB")
|
||||
.ok()
|
||||
.and_then(|value| value.trim().parse::<usize>().ok())
|
||||
.filter(|mib| *mib > 0)
|
||||
.and_then(|mib| mib.checked_mul(1024 * 1024))
|
||||
.unwrap_or(HARD_CAP_BYTES)
|
||||
})
|
||||
}
|
||||
|
||||
/// Optional per-buffer cap in MiB, useful for testing smaller chunks.
|
||||
fn cap_bytes() -> usize {
|
||||
env_cap_bytes().unwrap_or(HARD_CAP_BYTES)
|
||||
}
|
||||
|
||||
/// Largest byte size the wire arena's persistent buffers may take.
|
||||
pub fn arena_budget(device: &wgpu::Device) -> usize {
|
||||
device_ceiling(device).min(env_cap_bytes().unwrap_or(ARENA_CAP_BYTES))
|
||||
}
|
||||
|
||||
/// How many `T` fit in one arena buffer. Never returns 0.
|
||||
pub fn max_arena_elements<T>(device: &wgpu::Device) -> usize {
|
||||
(arena_budget(device) / std::mem::size_of::<T>().max(1)).max(1)
|
||||
}
|
||||
|
||||
/// Arena storage buffers must also fit in one binding.
|
||||
pub fn max_arena_storage_elements<T>(device: &wgpu::Device) -> usize {
|
||||
(arena_budget(device).min(device.limits().max_storage_buffer_binding_size as usize)
|
||||
/ std::mem::size_of::<T>().max(1))
|
||||
.max(1)
|
||||
}
|
||||
|
||||
/// Largest byte size a single buffer built by this renderer may take.
|
||||
pub fn buffer_budget(device: &wgpu::Device) -> usize {
|
||||
device_ceiling(device).min(cap_bytes())
|
||||
|
||||
@@ -313,8 +313,10 @@ impl WireArena {
|
||||
const_bgl: &wgpu::BindGroupLayout,
|
||||
mesh_edge: bool,
|
||||
) -> Option<Self> {
|
||||
let instance_limit = super::gpu_budget::max_elements::<WireInstance>(device) as u64;
|
||||
let constant_limit = super::gpu_budget::max_storage_elements::<WireConst>(device) as u64;
|
||||
let instance_limit =
|
||||
super::gpu_budget::max_arena_elements::<WireInstance>(device) as u64;
|
||||
let constant_limit =
|
||||
super::gpu_budget::max_arena_storage_elements::<WireConst>(device) as u64;
|
||||
let ranges = handle_ranges(wires)?;
|
||||
let perf = crate::perf::enabled();
|
||||
let total_started = iced::time::Instant::now();
|
||||
@@ -971,7 +973,8 @@ impl PackedWireArena {
|
||||
depth_map: &FxHashMap<u64, [f32; 2]>,
|
||||
mesh_edge: bool,
|
||||
) -> Option<Self> {
|
||||
let packed_limit = super::gpu_budget::max_elements::<PackedWireInstance>(device) as u64;
|
||||
let packed_limit =
|
||||
super::gpu_budget::max_arena_elements::<PackedWireInstance>(device) as u64;
|
||||
let ranges = handle_ranges(wires)?;
|
||||
let max_instances: usize = wires
|
||||
.iter()
|
||||
|
||||
Reference in new issue
Block a user