Slide 1

Slide 1 text

Visualization of mechanical CAD drawings using WebAssembly and WebGL Rust Tokyo 2019 @TaigaMerlin

Slide 2

Slide 2 text

Introduction ● Aki, CTO @ CADDi Inc (キャディ株式会社) ● Former embedded engineer ● Following Rust since 0.9 ● Eagerly awaiting 1.39 (ha)

Slide 3

Slide 3 text

Agenda 1. State of CAD software 2. WebAssembly 3. WebGL 4. Results 5. Learnings

Slide 4

Slide 4 text

State of CAD software

Slide 5

Slide 5 text

[C]omputer [A]ided [D]esign grabcad.com/library/engine-v-twin

Slide 6

Slide 6 text

[C]omputer [A]ided [D]esign www.eventshigh.com

Slide 7

Slide 7 text

CAD in manufacturing 3D geometric kernels ● Open CASCADE (C++, OSS) ● Parasolid (C, proprietary) ● ACIS (C++, proprietary) 2D drawing used in procurement ● rust dxf (Rust, OSS) ● libdxfrw (C++, OSS)

Slide 8

Slide 8 text

Objective: 2D drawings in the browser

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Binary code format that runs in a host environment

Slide 11

Slide 11 text

Not just for the web! (See WASI)

Slide 12

Slide 12 text

Host environment What is WebAssembly? C++, Rust, etc .wasm .js .html .css

Slide 13

Slide 13 text

What is WebAssembly? caniuse.com

Slide 14

Slide 14 text

What is WebAssembly? caniuse.com

Slide 15

Slide 15 text

Who’s using WebAssembly? ...and many more!

Slide 16

Slide 16 text

Show me the Rust code!

Slide 17

Slide 17 text

WebAssembly sample ----- RUST ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a+b }

Slide 18

Slide 18 text

WebAssembly sample ----- RUST ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a+b } ----- WASM/WAT ----- (func $add (type 1) (param i32 i32) (result i32) local.get 0 local.get 1 i32.add)

Slide 19

Slide 19 text

WebAssembly is typed ----- RUST ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a+b } ----- WASM/WAT ----- (func $add (type 1) (param i32 i32) (result i32) local.get 0 local.get 1 i32.add)

Slide 20

Slide 20 text

WebAssembly resembles a stack machine ----- RUST ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a+b } ----- WASM/WAT ----- (func $add (type 1) (param i32 i32) (result i32) local.get 0 ← push arg 0 onto the stack local.get 1 i32.add)

Slide 21

Slide 21 text

WebAssembly resembles a stack machine ----- RUST ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a+b } ----- WASM/WAT ----- (func $add (type 1) (param i32 i32) (result i32) local.get 0 ← push arg 0 onto the stack local.get 1 ← push arg 1 onto the stack i32.add)

Slide 22

Slide 22 text

WebAssembly resembles a stack machine ----- RUST ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a+b } ----- WASM/WAT ----- (func $add (type 1) (param i32 i32) (result i32) local.get 0 ← push arg 0 onto the stack local.get 1 ← push arg 1 onto the stack i32.add) ← execute math operation

Slide 23

Slide 23 text

WebAssembly resembles a stack machine ----- RUST ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a+b } ----- WASM/WAT ----- (func $add (type 1) (param i32 i32) (result i32) local.get 0 ← push arg 0 onto the stack local.get 1 ← push arg 1 onto the stack i32.add) ← execute math operation

Slide 24

Slide 24 text

WebAssembly: numeric instructions

Slide 25

Slide 25 text

WebAssembly: trigonometry?

Slide 26

Slide 26 text

WebAssembly: trigonometry?

Slide 27

Slide 27 text

I want my transcendental functions!

Slide 28

Slide 28 text

I want my transcendental functions!

Slide 29

Slide 29 text

WebAssembly interfacing with host environment

Slide 30

Slide 30 text

Rust (.wasm) ⇔ JavaScript (.js) ----- Rust ----- pub fn rust_function () { unsafe { js_function (); } } ----- JavaScript ----- wasm.instance.exports.rust_function (); Calling Rust from JavaScript Calling JavaScript from Rust

Slide 31

Slide 31 text

Call a Rust function from JavaScript ----- Rust ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a + b } ----- SHELL ----- $ rustc -O --target=wasm32-unknown-unknown example.rs -o example.wasm ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), {}) .then(wasm => { var add_func = wasm.instance.exports.add; });

Slide 32

Slide 32 text

Call a Rust function from JavaScript ----- Rust ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a + b } ----- SHELL ----- $ rustc -O --target=wasm32-unknown-unknown example.rs -o example.wasm ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), {}) .then(wasm => { var add_func = wasm.instance.exports.add; }); - WebAssembly has no main() - It behaves like a JS module/library

Slide 33

Slide 33 text

Call a Rust function from JavaScript ----- Rust ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a + b } ----- SHELL ----- $ rustc -O --target=wasm32-unknown-unknown example.rs -o example.wasm ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), {}) .then(wasm => { var add_func = wasm.instance.exports.add; var result = add_func(10, 20); console.log(result); });

Slide 34

Slide 34 text

Call a Rust function from JavaScript ----- Rust ----- #[no_mangle] pub extern fn add(a: i32, b: i32) -> i32 { a + b } ----- SHELL ----- $ rustc -O --target=wasm32-unknown-unknown example.rs -o example.wasm ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), {}) .then(wasm => { var add_func = wasm.instance.exports.add; var result = add_func(10, 20); console.log(result); });

Slide 35

Slide 35 text

Call a Rust function from JavaScript ● Can be used to implement compute heavy code in Rust ● Access those functions from JavaScript ● eg: Image resizing algorithm for an image editing online tool

Slide 36

Slide 36 text

Where are my transcendental functions?

Slide 37

Slide 37 text

Call a JavaScript function from Rust ----- Rust ----- #[link(wasm_import_module = "imports")] extern { fn cos(theta: f64) -> f64; } #[no_mangle] pub extern fn do_trig() { unsafe { cos(0.0); } } ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), { imports: { cos: (x) => Math.cos(x) } }) .then(wasm => { wasm.instance.exports.do_trig(); });

Slide 38

Slide 38 text

Call a JavaScript function from Rust ----- Rust ----- #[link(wasm_import_module = "imports")] extern { fn cos(theta: f64) -> f64; } #[no_mangle] pub extern fn do_trig() { unsafe { cos(0.0); } } ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), { imports: { cos: (x) => Math.cos(x) } }) .then(wasm => { wasm.instance.exports.do_trig(); });

Slide 39

Slide 39 text

Call a JavaScript function from Rust ----- Rust ----- #[link(wasm_import_module = "imports")] extern { fn cos(theta: f64) -> f64; } #[no_mangle] pub extern fn do_trig() { unsafe { cos(0.0); } } ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), { imports: { cos: (x) => Math.cos(x) } }) .then(wasm => { wasm.instance.exports.do_trig(); });

Slide 40

Slide 40 text

Call a JavaScript function from Rust ----- Rust ----- #[link(wasm_import_module = "imports")] extern { fn cos(theta: f64) -> f64; } #[no_mangle] pub extern fn do_trig() { unsafe { cos(0.0); } } ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), { imports: { cos: (x) => Math.cos(x) } }) .then(wasm => { wasm.instance.exports.do_trig(); }); - We probably want a debug print… - But WebAssembly has no I/O!

Slide 41

Slide 41 text

Let’s print the result! JavaScript Math.cos() Rust do_trig() cos()

Slide 42

Slide 42 text

Let’s print the result! JavaScript Math.cos() console.log() Rust do_trig() cos()

Slide 43

Slide 43 text

Let’s print the result! JavaScript Math.cos() console.log() Rust do_trig() cos() console_log()

Slide 44

Slide 44 text

Call a JavaScript function from Rust ----- RUST ----- #[link(wasm_import_module = "imports")] extern { fn console_log (x: f64); fn cos(theta: f64) -> f64; } #[no_mangle] pub extern fn do_trig() { unsafe { console_log (cos(0.0)); console_log (cos(3.14/4.0)); } } ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), { imports: { console_log : (x) => console.log(x), cos: (x) => Math.cos(x) } }) .then(wasm => { wasm.instance.exports.do_trig(); });

Slide 45

Slide 45 text

Call a JavaScript function from Rust ----- RUST ----- #[link(wasm_import_module = "imports")] extern { fn console_log (x: f64); fn cos(theta: f64) -> f64; } #[no_mangle] pub extern fn do_trig() { unsafe { console_log (cos(0.0)); console_log (cos(3.14/4.0)); } } ----- HTML ----- WebAssembly .instantiateStreaming ( fetch('example.wasm' ), { imports: { console_log : (x) => console.log(x), cos: (x) => Math.cos(x) } }) .then(wasm => { wasm.instance.exports.do_trig(); });

Slide 46

Slide 46 text

Yay transcendental functions!

Slide 47

Slide 47 text

Call a JavaScript function from Rust ----- RUST ----- #[link(wasm_import_module = "imports")] extern { fn console_log (x: f64); } #[no_mangle] pub extern fn do_trig() { ... } Imported function Exported function

Slide 48

Slide 48 text

example.wasm WebAssembly Format (abridged) Import section Export section console_log() #0 do_trig() #3

Slide 49

Slide 49 text

example.wasm WebAssembly Format (abridged) Import section Export section console_log() Code section local.get 0 local.get 1 i32.add #2 #0 do_trig() #3 Data section 0x67 0x65 0x74 0x20 0x74 0x68 0x69 0x73 0x3f 0x20 0x44 0x4d 0x20 0x6d 0x65 #0

Slide 50

Slide 50 text

example.wasm WebAssembly Format (abridged) Import section Export section console_log() Code section local.get 0 local.get 1 i32.add #2 #0 do_trig() #3 Data section Memory section: declares linear memory regions 0x67 0x65 0x74 0x20 0x74 0x68 0x69 0x73 0x3f 0x20 0x44 0x4d 0x20 0x6d 0x65 #0

Slide 51

Slide 51 text

.wasm file WebAssembly DATA CODE LINEAR MEMORY PROCESSOR program memory program instructions

Slide 52

Slide 52 text

WebAssembly has a Harvard-like architecture DATA PROCESSOR CODE I/O

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

3D Applications Raytracing experiments.withgoogle.com newnaw.com What can WebGL do?

Slide 55

Slide 55 text

What is WebGL? ● JavaScript API for 2D and 3D rendering in the browser caniuse.com

Slide 56

Slide 56 text

What is WebGL2? ● WebGL ⇒ WebGL2 ⇒ WebGPU(?) caniuse.com

Slide 57

Slide 57 text

What is WebGL2? ● WebGL ⇒ WebGL2 ⇒ WebGPU(?) caniuse.com

Slide 58

Slide 58 text

The difficulty with graphics APIs

Slide 59

Slide 59 text

Software architecture Native Application Native CAD library (x86) Graphics stack (OpenGL)

Slide 60

Slide 60 text

Software architecture Native Application Native CAD library (x86) Graphics stack (OpenGL) Web Application Native CAD library (wasm) Graphics stack (WebGL) vs

Slide 61

Slide 61 text

Software architecture Native Application Native CAD library (x86) Graphics stack (OpenGL) Web Application Native CAD library (wasm) Graphics stack (WebGL) vs - kiss3d (graphics engine supporting WebGL) - rust-dxf (native DXF file parser)

Slide 62

Slide 62 text

Results

Slide 63

Slide 63 text

Results

Slide 64

Slide 64 text

Current challenges ● Text rendering for CJK languages (Font support, garbled text, etc) ● Running native code expecting native syscalls and interfaces (Emscripten) ● Rust graphics ecosystem is still young

Slide 65

Slide 65 text

Access all JavaScript APIs from WebAssembly

Slide 66

Slide 66 text

● wasm-bindgen ● web-sys: DOM, WebGL, WebAudio, etc ● js-sys: ECMAScript Rust and JavaScript coexist peacefully

Slide 67

Slide 67 text

The future is bright!

Slide 68

Slide 68 text

Thank you! @TaigaMerlin