forked from 1b-agent/opencadstudio-upstream
Bound GPU uploads and complete Greek and performance integration
This commit is contained in:
1 parent
89624f64fc
commit
9d991d7feb
14 files changed
+678
-380
No files matched your search
@@ -0,0 +1,177 @@
|
||||
use super::*;
|
||||
use crate::scene::model::{mesh_model::MeshLodSet, mesh_model::MeshModel, wire_model::WireModel};
|
||||
use acadrust::{types::Transform, Handle};
|
||||
use iced::futures::executor::block_on;
|
||||
|
||||
// OCS_GPU_CHUNK_MIB=1 cargo test --lib bounded_gpu_uploads -- --ignored --nocapture
|
||||
#[test]
|
||||
#[ignore = "requires a GPU adapter and OCS_GPU_CHUNK_MIB=1"]
|
||||
fn bounded_gpu_uploads_preserve_geometry_and_instancing() {
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
|
||||
let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions::default()))
|
||||
.expect("GPU adapter");
|
||||
eprintln!("GPU regression adapter: {:?}", adapter.get_info());
|
||||
let (device, queue) = block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||
required_limits: adapter.limits(),
|
||||
..Default::default()
|
||||
}))
|
||||
.expect("GPU device");
|
||||
let budget = gpu_budget::buffer_budget(&device) as u64;
|
||||
assert_eq!(budget, 1024 * 1024, "run with OCS_GPU_CHUNK_MIB=1");
|
||||
let validation = device.push_error_scope(wgpu::ErrorFilter::Validation);
|
||||
let pipeline = Pipeline::new(&device, &queue, wgpu::TextureFormat::Bgra8UnormSrgb);
|
||||
|
||||
let line = WireModel {
|
||||
points: vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]],
|
||||
..Default::default()
|
||||
};
|
||||
let count = gpu_budget::max_storage_elements::<wire_gpu::WireConst>(&device) + 2;
|
||||
let wires = vec![line; count];
|
||||
for bgl in [pipeline.wire_const_bgl.as_ref(), None] {
|
||||
let chunks =
|
||||
wire_gpu::WireGpu::from_run(&device, &queue, &wires, &Default::default(), false, bgl);
|
||||
assert!(chunks.len() > 1);
|
||||
assert_eq!(
|
||||
chunks
|
||||
.iter()
|
||||
.map(|chunk| chunk.instance_count as usize)
|
||||
.sum::<usize>(),
|
||||
count
|
||||
);
|
||||
assert!(chunks
|
||||
.iter()
|
||||
.all(|chunk| chunk.instance_buffer.size() <= budget));
|
||||
}
|
||||
let segments = gpu_budget::max_elements::<wire_gpu::WireInstance>(&device) + 1;
|
||||
let dense = WireModel {
|
||||
points: (0..=segments).map(|i| [i as f32, 0.0, 0.0]).collect(),
|
||||
..Default::default()
|
||||
};
|
||||
let chunks = wire_gpu::WireGpu::from_run(
|
||||
&device,
|
||||
&queue,
|
||||
&[dense],
|
||||
&Default::default(),
|
||||
false,
|
||||
pipeline.wire_const_bgl.as_ref(),
|
||||
);
|
||||
assert!(chunks.len() > 1);
|
||||
assert_eq!(
|
||||
chunks
|
||||
.iter()
|
||||
.map(|chunk| chunk.instance_count as usize)
|
||||
.sum::<usize>(),
|
||||
segments
|
||||
);
|
||||
assert!(chunks
|
||||
.iter()
|
||||
.all(|chunk| chunk.instance_buffer.size() <= budget));
|
||||
|
||||
let vertices = vec![
|
||||
bytemuck::Zeroable::zeroed();
|
||||
gpu_budget::max_elements_grouped::<text_gpu::TextVertex>(&device, 6) + 6
|
||||
];
|
||||
let text = text_gpu::upload_vertices(&device, &queue, &vertices);
|
||||
assert_eq!(text.len(), 2);
|
||||
assert_eq!(
|
||||
text.iter()
|
||||
.map(|chunk| chunk.vertex_count as usize)
|
||||
.sum::<usize>(),
|
||||
vertices.len()
|
||||
);
|
||||
assert!(text
|
||||
.iter()
|
||||
.all(|chunk| chunk.vertex_count % 6 == 0 && chunk.vertex_buffer.size() <= budget));
|
||||
|
||||
let source = |triangles: usize| {
|
||||
let mut set = MeshLodSet::from_single(MeshModel {
|
||||
name: "7".to_owned(),
|
||||
verts: (0..triangles)
|
||||
.flat_map(|_| [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
|
||||
.collect(),
|
||||
verts_low: Vec::new(),
|
||||
normals: Vec::new(),
|
||||
indices: (0..triangles as u32 * 3).collect(),
|
||||
triangle_material_handles: Vec::new(),
|
||||
triangle_colors: Vec::new(),
|
||||
color: [1.0; 4],
|
||||
selected: false,
|
||||
});
|
||||
set.prepare_instance_source(Handle::new(7));
|
||||
set.lods.clear();
|
||||
set.instance_transform = Some(Transform::identity());
|
||||
set.instance_handle = Some(Handle::new(101));
|
||||
set
|
||||
};
|
||||
let triangles = gpu_budget::max_elements::<mesh_gpu::MeshVertex>(&device) / 3 + 1;
|
||||
let first = source(triangles);
|
||||
let mut second = first.clone();
|
||||
second.instance_handle = Some(Handle::new(102));
|
||||
let (mesh, total) = mesh_gpu::build_mesh_batch(&device, &queue, &[first, second]);
|
||||
assert!(mesh.len() > 1);
|
||||
assert_eq!(total, (triangles * 2) as u64);
|
||||
assert_eq!(
|
||||
mesh.iter()
|
||||
.map(|chunk| chunk.index_count as usize / 3)
|
||||
.sum::<usize>(),
|
||||
triangles
|
||||
);
|
||||
for chunk in &mesh {
|
||||
assert_eq!(
|
||||
chunk.instance_count, 2,
|
||||
"large geometry must remain instanced"
|
||||
);
|
||||
assert_eq!(chunk.handles.len(), 2);
|
||||
assert_eq!(chunk.highlight_ranges.len(), 2);
|
||||
assert!(chunk
|
||||
.highlight_ranges
|
||||
.iter()
|
||||
.all(|range| range.index_count == chunk.index_count && range.instance_start < 2));
|
||||
for buffer in [
|
||||
&chunk.vertex_buffer,
|
||||
&chunk.index_buffer,
|
||||
&chunk.transp_index_buffer,
|
||||
&chunk.edge_vertex_buffer,
|
||||
&chunk.wire_vertex_buffer,
|
||||
&chunk.instance_buffer,
|
||||
] {
|
||||
assert!(
|
||||
buffer.size() <= budget,
|
||||
"buffer size {} exceeds {budget}",
|
||||
buffer.size()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let instance_count = gpu_budget::max_elements::<mesh_gpu::MeshInstanceGpu>(&device) + 1;
|
||||
let mut repeated = vec![source(1); instance_count];
|
||||
for (index, set) in repeated.iter_mut().enumerate() {
|
||||
set.instance_handle = Some(Handle::new(1000 + index as u64));
|
||||
}
|
||||
let (mesh, total) = mesh_gpu::build_mesh_batch(&device, &queue, &repeated);
|
||||
assert_eq!(mesh.len(), 2);
|
||||
assert_eq!(total, instance_count as u64);
|
||||
assert_eq!(mesh[0].vertex_buffer, mesh[1].vertex_buffer);
|
||||
assert_eq!(mesh[0].index_buffer, mesh[1].index_buffer);
|
||||
assert_eq!(
|
||||
mesh.iter()
|
||||
.map(|chunk| chunk.instance_count as usize)
|
||||
.sum::<usize>(),
|
||||
instance_count
|
||||
);
|
||||
for chunk in &mesh {
|
||||
assert!(chunk.instance_buffer.size() <= budget);
|
||||
assert_eq!(chunk.highlight_ranges.len(), chunk.instance_count as usize);
|
||||
assert!(chunk
|
||||
.highlight_ranges
|
||||
.iter()
|
||||
.all(|range| range.instance_start < chunk.instance_count));
|
||||
}
|
||||
|
||||
queue.submit([]);
|
||||
device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
|
||||
assert!(
|
||||
block_on(validation.pop()).is_none(),
|
||||
"GPU validation failed"
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user