feather_ui/
util.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 Fundament Research Institute <https://fundament.institute>
3
4use wgpu::CompilationMessageType;
5
6use crate::graphics::Driver;
7use crate::shaders;
8
9pub fn create_hotloader<T: 'static>(
10    path: &std::path::Path,
11    label: &'static str,
12    driver: std::sync::Weak<Driver>,
13) -> eyre::Result<notify::RecommendedWatcher> {
14    use notify::Watcher;
15    let mut prev = std::fs::read_to_string(path)?;
16    let pathbuf = path.to_owned();
17    let mut watcher = notify::recommended_watcher(move |_| {
18        if let Some(driver) = driver.upgrade() {
19            let contents = std::fs::read_to_string(&pathbuf).unwrap();
20            if contents != prev {
21                prev = contents;
22                driver
23                    .device
24                    .push_error_scope(wgpu::ErrorFilter::Validation);
25                let module = shaders::load_wgsl(&driver.device, label, &prev);
26                let err = futures_lite::future::block_on(driver.device.pop_error_scope());
27                if let Some(e) = err {
28                    println!("{e}");
29                } else {
30                    let info = futures_lite::future::block_on(module.get_compilation_info());
31
32                    let mut errored = false;
33                    for m in info.messages {
34                        println!("{m:?}");
35                        errored = errored || m.message_type == CompilationMessageType::Error;
36                    }
37                    if !errored {
38                        driver.reload_pipeline::<T>(module);
39                    }
40                }
41            }
42        }
43    })?;
44
45    watcher.watch(path, notify::RecursiveMode::NonRecursive)?;
46
47    Ok(watcher)
48}
49
50/// Allocates `&[T]` on stack space.
51pub(crate) fn alloca_array<T, R>(n: usize, f: impl FnOnce(&mut [T]) -> R) -> R {
52    use std::mem::{align_of, size_of};
53
54    alloca::with_alloca_zeroed(
55        (n * size_of::<T>()) + (align_of::<T>() - 1),
56        |memory| unsafe {
57            let mut raw_memory = memory.as_mut_ptr();
58            if raw_memory as usize % align_of::<T>() != 0 {
59                raw_memory =
60                    raw_memory.add(align_of::<T>() - raw_memory as usize % align_of::<T>());
61            }
62
63            f(std::slice::from_raw_parts_mut::<T>(
64                raw_memory.cast::<T>(),
65                n,
66            ))
67        },
68    )
69}