7

我的 rust 程序正在管理 2d html 画布上下文的内存,我试图达到 ~60fps。我可以很容易地计算出每一帧之间的增量,结果大约是 5 毫秒。

我不清楚如何让我的 Rust webassembly 程序在剩余的 11 毫秒内休眠。一种选择是让 JavaScript 在每个程序上调用 RustrequestAnimationFrame并将其用作驱动程序,但我很想尽可能将其全部保留在 Rust 中。

setTimeout(renderNext, 11)在编译到 wasm 目标时,我正在有效地寻找与 JavaScript 等效的 Rust 。

4

2 回答 2

4

在您的requestAnimationFrame回调中,调用setTimeout,然后依次调用requestAnimationFrame. 你可以在这里看到这个的 JS 版本。

根据书中的例子,wasm-bindgen下面是我在 Rust 中的做法:

fn animate_limited(mut draw_frame: impl FnMut() + 'static, max_fps: i32) {
    // Based on:
    // https://rustwasm.github.io/docs/wasm-bindgen/examples/request-animation-frame.html#srclibrs

    // https://doc.rust-lang.org/book/ch15-05-interior-mutability.html
    let animate_cb = Rc::new(RefCell::new(None));
    let animate_cb2 = animate_cb.clone();

    let timeout_cb = Rc::new(RefCell::new(None));
    let timeout_cb2 = timeout_cb.clone();

    let w = window();
    *timeout_cb2.borrow_mut() = Some(Closure::wrap(Box::new(move || {
        request_animation_frame(&w, animate_cb.borrow().as_ref().unwrap());
    }) as Box<dyn FnMut()>));

    let w2 = window();
    *animate_cb2.borrow_mut() = Some(Closure::wrap(Box::new(move || {
        draw_frame();

        set_timeout(&w2, timeout_cb.borrow().as_ref().unwrap(), 1000 / max_fps);
    }) as Box<dyn FnMut()>));

    request_animation_frame(&window(), animate_cb2.borrow().as_ref().unwrap());
}

fn window() -> web_sys::Window {
    web_sys::window().expect("no global `window` exists")
}

fn request_animation_frame(window: &web_sys::Window, f: &Closure<dyn FnMut()>) -> i32 {
    window
        .request_animation_frame(f.as_ref().unchecked_ref())
        .expect("should register `requestAnimationFrame` OK")
}

fn set_timeout(window: &web_sys::Window, f: &Closure<dyn FnMut()>, timeout_ms: i32) -> i32 {
    window
        .set_timeout_with_callback_and_timeout_and_arguments_0(
            f.as_ref().unchecked_ref(),
            timeout_ms,
        )
        .expect("should register `setTimeout` OK")
}

然后,您只需传递animate_limited一个函数来进行绘图(像move || { /* drawing logic here */ }这样的闭包就可以了),以及您想要的最大帧速率。

几乎可以肯定,那里需要改进。我对 Rust 很陌生,只是花了太长时间才弄清楚如何使它工作。希望这能让其他人在未来更快。

于 2020-08-30T05:05:38.163 回答
2

setTimeout(renderNext, 11)在编译到 wasm 目标时,我正在有效地寻找与 JavaScript 等效的 Rust 。

有几个 Rust crate 绑定到 JavaScript Web API,最值得注意的是web-sys. 查看其中一个重载的文档setTimeout

不过,这并不是真正的 Rust 等价物,因为它非常直接地调用了 JS 函数。但是您将无法解决这个问题:睡眠或获取当前时间都是主机环境必须提供的功能。它们不能单独用原始语言实现。

一种选择是让 JavaScript 在每个程序上调用 RustrequestAnimationFrame并将其用作驱动程序,但我很想尽可能将其全部保留在 Rust 中。

是的,您应该使用requestAnimationFrame链接到web-sys文档)。这比自己计时要好得多。特别是,当标签不活动和类似的内容时,此方法还将暂停调用您的代码。在桌面环境中你会做同样的事情:要求宿主环境(即操作系统,通常通过 OpenGL 左右)来同步你的程序到屏幕刷新。

于 2019-09-03T07:25:34.020 回答