git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

src/web/mod.rs (2.4K)

 1 //! The browser's side of cce-ui: a WebGPU renderer that draws the same
 2 //! [`Frame2D`](crate::draw::Frame2D)s the Vulkan renderer does, from the same
 3 //! shaders (`draw::shaders`), atlas (`draw::glyphs`) and image queue
 4 //! (`draw::images`), and the shell that runs an `Application` on a canvas
 5 //! with it ([`run`]) — the page's events in through the shared `Driver`,
 6 //! `Pacer::turn` on animation frames — and a [`ComputeDevice`] that runs
 7 //! `crate::compute` jobs on WebGPU.
 8 //!
 9 //! wasm32 only, and it needs web-sys's WebGPU bindings switched on
10 //! (`--cfg=web_sys_unstable_apis`, set for this crate in `.cargo/config.toml`).
11 
12 mod compute;
13 mod renderer;
14 mod rt;
15 mod scene;
16 mod shell;
17 
18 pub use compute::ComputeDevice;
19 pub use renderer::{Capture, PendingCapture, WebRenderer};
20 pub use shell::{capture, run, Fonts, Sizing};
21 
22 use wasm_bindgen::JsValue;
23 
24 /// Ask the browser for a WebGPU device, with `limits` (WebGPU limit names)
25 /// raised to what the adapter offers — a device is created at the spec's
26 /// defaults otherwise, which are below what most adapters can do. What the
27 /// device rejects later, and why it was lost, goes to the console: a WebGPU
28 /// validation error is otherwise silent.
29 pub(crate) async fn request_device(
30     limits: &[&str],
31 ) -> Result<(web_sys::Gpu, web_sys::GpuAdapter, web_sys::GpuDevice), JsValue> {
32     let window = web_sys::window().ok_or("no window")?;
33     let gpu = window.navigator().gpu();
34     let adapter = gpu
35         .request_adapter()
36         .await?
37         .into_option()
38         .ok_or("this browser offers no WebGPU adapter")?;
39     let desc = web_sys::GpuDeviceDescriptor::new();
40     if !limits.is_empty() {
41         let offered = adapter.limits();
42         let required = js_sys::Object::new();
43         for name in limits {
44             let v = js_sys::Reflect::get(&offered, &JsValue::from_str(name))?;
45             if !v.is_undefined() {
46                 js_sys::Reflect::set(&required, &JsValue::from_str(name), &v)?;
47             }
48         }
49         js_sys::Reflect::set(&desc, &JsValue::from_str("requiredLimits"), &required)?;
50     }
51     let device: web_sys::GpuDevice = adapter.request_device_with_descriptor(&desc).await?;
52     js_sys::Function::new_with_args(
53         "d",
54         "d.onuncapturederror = (e) => console.error('cce-ui WebGPU:', e.error.message); \
55          d.lost.then((i) => console.error('cce-ui WebGPU device lost:', i.reason, i.message));",
56     )
57     .call1(&JsValue::NULL, &device)?;
58     Ok((gpu, adapter, device))
59 }