Wasm + Rust + WebGl = 🤓🥰
Cecília Carneiro e Silva
Tema
- WebGL
WebAssembly
(Lin Clark)
História
- JS não é um bom target de compilação.
- Código resultantes eram grandes.
(Lin Clark)
Evolução das "JS Engines"
JS Optimizado ~ 2 x nativo. (Incrível)
(Franziska Hinkelmann)
Why?
- JIT + tierting compilers.
- Baixa predictibilidade JS.
- Alto start up time.
Wat - S-expressions
(module
(func $add (param $lhs i32) (param $rhs i32) (result i32)
local.get $lhs
local.get $rhs
i32.add)
(export "add" (func $add))
)
MVP
- Apenas o mínimo. Funcionando nos 4 principais browser.
- Algumas funcionalidade ficaram de fora:
- SIMD, multithreading, CG... (for now)
- Implementação é dependente do browser.
Rust
(Niko Matsakis)
Why specifically is it good?
- Lots of concurrency bugs are impossible
- No more use-after-free
- Awesome enums (can contain data!)
- Explicit error-handling (the Result type)
- No more NULL pointer (the Option type)
- Pattern matching (switch on steroids)
- The language tooling is really good
wasm32-unknown-unknown
- Um dos pilares do meu mestrado.
- Linguagem ajuda a entender coisas que você fez errado sua vida inteira.
- Forte investimento da Mozilla.
- Ferramentas e um ecossistema bem ativo.
DDD - Data Driven Design
(Azriel)
WebGL
Engine de Rasterização.
Vertex and Fragment Shaders
(WebGL Fundamentals)
Cellular Automata
- Modelo de computação baseado em células de um mundo estruturado.
- Células possuem estados.
- Estados podem mudar com o passar do tempo.
- Influência local.
(game of life)
Demo
Aplicação
- Incêndio na floresta.
Wasm + JS
Wasm + JS + Rust
JS -> Wasm
import * as wasm from "wasm-webgl";
const playPauseButton = document.getElementById("play-pause");
const play = () => {
playPauseButton.textContent = "▶";
};
playPauseButton.addEventListener("click", event => {
playPauseButton.disabled = true;
wasm.start();
});
play();
Start()
#[wasm_bindgen]
pub fn start() -> Result<(), JsValue> {
...;
let canvas: web_sys::HtmlCanvasElement = canvas
.dyn_into::<web_sys::HtmlCanvasElement>()?;
...;
let universe = Rc::new(RefCell::new(Universe::new(WIDTH, HEIGHT, GAME_CONFIG)));
{
let f = Rc::new(RefCell::new(None));
let g = f.clone();
...;
*g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
...;
draw_universe(&context.clone(), &universe.borrow()).unwrap();
request_animation_frame(f.borrow().as_ref().unwrap());
}) as Box<FnMut()>));
request_animation_frame(g.borrow().as_ref().unwrap());
}
}
WebGL - Shaders
let vert_shader = compile_shader(
&context,
WebGlRenderingContext::VERTEX_SHADER,
r#"
attribute vec2 position;
attribute float point_size;
attribute vec3 color;
varying vec3 u_color;
void main() {
gl_Position = vec4(position, 0, 1);
gl_PointSize = point_size;
u_color = color;
}
"#,
)?;
let frag_shader = compile_shader(
&context,
WebGlRenderingContext::FRAGMENT_SHADER,
r#"
precision mediump float;
varying vec3 u_color;
void main() {
gl_FragColor = vec4(u_color, 1.0);
}
"#,
)?;
draw_universe
for col in 0..WIDTH {
for row in 0..HEIGHT {
let x = (0.5 + col as f32) * size_square - 1.0;
let y = (0.5 + row as f32) * size_square - 1.0;
table_points.push(x);
table_points.push(y);
}
}
let vertices = table_points.as_slice();
context_array_bind(&context, &vertices, 0, 2)?;
let colors = colors.as_slice();
context_array_bind(context, &colors, 2, 3)?;
context.clear_color(0.0, 0.0, 0.0, 1.0);
context.clear(WebGlRenderingContext::COLOR_BUFFER_BIT);
context.draw_arrays(
WebGlRenderingContext::POINTS,
0,
universe_size.try_into().unwrap(),
);
Wasm(Rust) -> JS
#[wasm_bindgen(module = "/defined-in-js.js")]
extern "C" {
pub fn pause();
}
const playPauseButton = document.getElementById("play-pause");
export function pause() {
playPauseButton.disabled = false;
}
Rust Closure + JS Callback
let fps = Rc::new(RefCell::new(new_fps_value().unwrap()));
{
let fps = fps.clone();
let a = Closure::wrap(Box::new(move || {
*fps.borrow_mut() = new_fps_value().unwrap();
// js::log(&fps.to_string());
}) as Box<dyn FnMut()>);
document
.get_element_by_id("fps-control")
.expect("Should have a #fps-control slider on the page")
.dyn_ref::<HtmlElement>()
.expect("#fps-control be an `HtmlElement`")
.set_onchange(Some(a.as_ref().unchecked_ref()));
a.forget();
}
- Automata Game
-
Water Simulation
-
Epic Garden
The End
Wasm + Rust + WebGl = 🤓🥰
By Cecília Carneiro e Silva
Wasm + Rust + WebGl = 🤓🥰
- 107