forked from 1b-agent/opencadstudio-upstream
fix(wasm): make the web build actually run in the browser
With the wasm bundle building, get it rendering in a browser:
- Enable iced `webgl` so wgpu uses WebGL2 where WebGPU is absent
(e.g. Firefox by default), and `fira-sans` so UI text has an
embedded font (the web has no system fonts) — without it every
label was blank.
- Replace `std::time::Instant` with `iced::time::Instant` (web-safe);
`Instant::now()` panics ("time not implemented") on wasm and crashed
at boot via the command line.
- Skip the batched-hatch pipeline on wasm: its bind group needs
vertex-stage storage buffers, which WebGL2 lacks (validation error
on "New drawing"). Fields become Option; upload/draw guard on them.
Hatches don't draw on the web for now; everything else does.
- Fix the trunk feature flag (`data-cargo-no-default-features`) and
ignore the `dist/` build output.
Native build + 75 tests unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
f2c4a1736a
commit
c49ad887b8
11 files changed
+55
-14
No files matched your search
+2
-2
@@ -1710,7 +1710,7 @@ impl Scene {
|
||||
Some([cx - w * margin, cy - h * margin, cx + w * margin, cy + h * margin])
|
||||
};
|
||||
let block = self.model_space_block_handle();
|
||||
let t_tess = std::time::Instant::now();
|
||||
let t_tess = iced::time::Instant::now();
|
||||
let arc = Arc::new(self.wires_for_block_culled(block, tess_region, wpp, None, None));
|
||||
self.last_tess_ms.set(t_tess.elapsed().as_secs_f32() * 1000.0);
|
||||
self.last_tess_wires.set(arc.len());
|
||||
@@ -1739,7 +1739,7 @@ impl Scene {
|
||||
}
|
||||
}
|
||||
let layout_block = self.current_layout_block_handle();
|
||||
let t_tess = std::time::Instant::now();
|
||||
let t_tess = iced::time::Instant::now();
|
||||
let mut wires = self.wires_for_block(layout_block);
|
||||
self.last_tess_ms.set(t_tess.elapsed().as_secs_f32() * 1000.0);
|
||||
self.last_tess_wires.set(wires.len());
|
||||
|
||||
@@ -35,8 +35,9 @@ pub struct Pipeline {
|
||||
hatch_pipeline: wgpu::RenderPipeline,
|
||||
/// Phase 4-B — single-draw batched hatch pipeline. Per-instance
|
||||
/// data lives in storage buffers; one draw call covers every
|
||||
/// hatch in the frame.
|
||||
hatch_batched_pipeline: wgpu::RenderPipeline,
|
||||
/// hatch in the frame. `None` on WebGL2 (wasm), which lacks
|
||||
/// vertex-stage storage buffers.
|
||||
hatch_batched_pipeline: Option<wgpu::RenderPipeline>,
|
||||
image_pipeline: wgpu::RenderPipeline,
|
||||
mesh_pipeline: wgpu::RenderPipeline,
|
||||
/// Wireframe variant of the mesh pipeline (LineList topology, same
|
||||
@@ -56,8 +57,8 @@ pub struct Pipeline {
|
||||
uniform_bind_group: wgpu::BindGroup,
|
||||
hatch_bgl1: wgpu::BindGroupLayout,
|
||||
/// Group-1 layout for the batched hatch pipeline (storage buffers
|
||||
/// for instances / boundary / families / dashes).
|
||||
hatch_batched_bgl1: wgpu::BindGroupLayout,
|
||||
/// for instances / boundary / families / dashes). `None` on WebGL2.
|
||||
hatch_batched_bgl1: Option<wgpu::BindGroupLayout>,
|
||||
image_bgl1: wgpu::BindGroupLayout,
|
||||
depth_texture_size: Size<u32>,
|
||||
depth_view: wgpu::TextureView,
|
||||
@@ -355,6 +356,16 @@ impl Pipeline {
|
||||
});
|
||||
|
||||
// ── Hatch batched pipeline (Phase 4-B) ─────────────────────────────
|
||||
// WebGL2 (the wasm fallback backend) has no vertex-stage storage
|
||||
// buffers, which this pipeline's bind group requires. Skip it on wasm
|
||||
// and run without the batched-hatch optimization.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let (hatch_batched_bgl1, hatch_batched_pipeline): (
|
||||
Option<wgpu::BindGroupLayout>,
|
||||
Option<wgpu::RenderPipeline>,
|
||||
) = (None, None);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let (hatch_batched_bgl1, hatch_batched_pipeline) = {
|
||||
let hatch_batched_bgl1 = hatch_batched_gpu::HatchBatchedGpu::bind_group_layout(device);
|
||||
let hatch_batched_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("hatch_batched.pipeline_layout"),
|
||||
@@ -406,6 +417,8 @@ impl Pipeline {
|
||||
multiview: None,
|
||||
cache: None,
|
||||
});
|
||||
(Some(hatch_batched_bgl1), Some(hatch_batched_pipeline))
|
||||
};
|
||||
|
||||
// ── Mesh pipeline ──────────────────────────────────────────────────
|
||||
let mesh_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
@@ -1152,10 +1165,15 @@ impl Pipeline {
|
||||
}
|
||||
|
||||
pub fn upload_hatches(&mut self, device: &wgpu::Device, hatches: &[HatchModel]) {
|
||||
// No batched pipeline (WebGL2) → nothing to upload.
|
||||
let Some(bgl1) = &self.hatch_batched_bgl1 else {
|
||||
self.gpu_hatch_batched = None;
|
||||
return;
|
||||
};
|
||||
let renderable: Vec<HatchModel> =
|
||||
hatches.iter().filter(|h| h.boundary.len() >= 3).cloned().collect();
|
||||
self.gpu_hatch_batched =
|
||||
hatch_batched_gpu::HatchBatchedGpu::build(device, &self.hatch_batched_bgl1, &renderable);
|
||||
hatch_batched_gpu::HatchBatchedGpu::build(device, bgl1, &renderable);
|
||||
}
|
||||
|
||||
pub fn upload_wipeouts(&mut self, device: &wgpu::Device, wipeouts: &[HatchModel]) {
|
||||
@@ -1257,8 +1275,10 @@ impl Pipeline {
|
||||
// by `compute_hatch_lod`). Per-hatch viewport scissor
|
||||
// (paper-space MSPACE) isn't ported to the batched path
|
||||
// yet — follow-up if it shows up as a visual issue.
|
||||
if let Some(batch) = &self.gpu_hatch_batched {
|
||||
pass.set_pipeline(&self.hatch_batched_pipeline);
|
||||
if let (Some(batch), Some(pipeline)) =
|
||||
(&self.gpu_hatch_batched, &self.hatch_batched_pipeline)
|
||||
{
|
||||
pass.set_pipeline(pipeline);
|
||||
pass.set_bind_group(0, &self.uniform_bind_group, &[]);
|
||||
pass.set_bind_group(1, &batch.bind_group, &[]);
|
||||
pass.set_vertex_buffer(0, batch.vertex_buffer.slice(..));
|
||||
|
||||
Reference in new issue
Block a user