(width: f64, height: f64, _title: f64, fullscreen: f64)
| 37 | |
| 38 | #[wasm_bindgen] |
| 39 | pub fn bloom_init_window(width: f64, height: f64, _title: f64, fullscreen: f64) { |
| 40 | // Set up panic hook for better error messages in the browser console |
| 41 | console_error_panic_hook::set_once(); |
| 42 | |
| 43 | // Idempotent: once an init is in flight (or done), later calls are no-ops. |
| 44 | // Perry's main() typically calls initWindow after the JS orchestrator has |
| 45 | // already kicked off wgpu setup — the second call must not start a new one. |
| 46 | if INIT_STARTED.swap(true, Ordering::SeqCst) { |
| 47 | return; |
| 48 | } |
| 49 | |
| 50 | let log_w = width as u32; |
| 51 | let log_h = height as u32; |
| 52 | let _fullscreen = fullscreen != 0.0; |
| 53 | |
| 54 | wasm_bindgen_futures::spawn_local(async move { |
| 55 | let window = web_sys::window().expect("no global window"); |
| 56 | let document = window.document().expect("no document"); |
| 57 | let canvas = document |
| 58 | .get_element_by_id("bloom-canvas") |
| 59 | .expect("no element with id 'bloom-canvas'") |
| 60 | .dyn_into::<web_sys::HtmlCanvasElement>() |
| 61 | .expect("element is not a canvas"); |
| 62 | |
| 63 | // HiDPI: size the canvas *backing store* (set_width/set_height, |
| 64 | // i.e. the WebGPU surface) to logical × devicePixelRatio so a |
| 65 | // 4K Retina display actually renders at 4K. CSS layout dimensions |
| 66 | // stay in logical pixels — index.html keeps `width: 100%` on |
| 67 | // the canvas — so the document layout is unchanged. Clamp to |
| 68 | // [1, 3] because higher dprs (some phones report 4) are wasted |
| 69 | // shading work and can crash low-end mobile GPUs. |
| 70 | let dpr = window.device_pixel_ratio().max(1.0).min(3.0); |
| 71 | let phys_w = ((log_w as f64) * dpr).round() as u32; |
| 72 | let phys_h = ((log_h as f64) * dpr).round() as u32; |
| 73 | canvas.set_width(phys_w); |
| 74 | canvas.set_height(phys_h); |
| 75 | |
| 76 | let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { |
| 77 | backends: wgpu::Backends::BROWSER_WEBGPU | wgpu::Backends::GL, |
| 78 | ..wgpu::InstanceDescriptor::new_without_display_handle() |
| 79 | }); |
| 80 | |
| 81 | let surface = instance |
| 82 | .create_surface(wgpu::SurfaceTarget::Canvas(canvas)) |
| 83 | .expect("Failed to create surface from canvas"); |
| 84 | |
| 85 | let adapter = instance |
| 86 | .request_adapter(&wgpu::RequestAdapterOptions { |
| 87 | compatible_surface: Some(&surface), |
| 88 | power_preference: wgpu::PowerPreference::HighPerformance, |
| 89 | ..Default::default() |
| 90 | }) |
| 91 | .await |
| 92 | .expect("No WebGPU/WebGL adapter found"); |
| 93 | |
| 94 | let (device, queue) = adapter |
| 95 | .request_device( |
| 96 | &wgpu::DeviceDescriptor { |
nothing calls this directly
no test coverage detected