$30 off During Our Annual Pro Sale. View Details »

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

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

[email protected]

November 05, 2019
Tweet

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

  4. State of CAD software

    View Slide

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

    View Slide

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

    View Slide

  7. 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)

    View Slide

  8. Objective: 2D drawings in the browser

    View Slide

  9. View Slide

  10. Binary code format that runs in a host environment

    View Slide

  11. Not just for the web! (See WASI)

    View Slide

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

    View Slide

  13. What is WebAssembly?
    caniuse.com

    View Slide

  14. What is WebAssembly?
    caniuse.com

    View Slide

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

    View Slide

  16. Show me the Rust code!

    View Slide

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

    View Slide

  18. 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)

    View Slide

  19. 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)

    View Slide

  20. 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)

    View Slide

  21. 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)

    View Slide

  22. 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

    View Slide

  23. 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

    View Slide

  24. WebAssembly: numeric instructions

    View Slide

  25. WebAssembly: trigonometry?

    View Slide

  26. WebAssembly: trigonometry?

    View Slide

  27. I want my transcendental functions!

    View Slide

  28. I want my transcendental functions!

    View Slide

  29. WebAssembly interfacing with host
    environment

    View Slide

  30. 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

    View Slide

  31. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {})<br/>.then(wasm => {<br/>var add_func =<br/>wasm.instance.exports.add;<br/>});<br/>

    View Slide

  32. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {})<br/>.then(wasm => {<br/>var add_func =<br/>wasm.instance.exports.add;<br/>});<br/>
    - WebAssembly has no main()
    - It behaves like a JS module/library

    View Slide

  33. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {})<br/>.then(wasm => {<br/>var add_func =<br/>wasm.instance.exports.add;<br/>var result = add_func(10, 20);<br/>console.log(result);<br/>});<br/>

    View Slide

  34. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {})<br/>.then(wasm => {<br/>var add_func =<br/>wasm.instance.exports.add;<br/>var result = add_func(10, 20);<br/>console.log(result);<br/>});<br/>

    View Slide

  35. 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

    View Slide

  36. Where are my transcendental functions?

    View Slide

  37. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {<br/>imports: {<br/>cos: (x) => Math.cos(x)<br/>}<br/>})<br/>.then(wasm => {<br/>wasm.instance.exports.do_trig();<br/>});<br/>

    View Slide

  38. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {<br/>imports: {<br/>cos: (x) => Math.cos(x)<br/>}<br/>})<br/>.then(wasm => {<br/>wasm.instance.exports.do_trig();<br/>});<br/>

    View Slide

  39. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {<br/>imports: {<br/>cos: (x) => Math.cos(x)<br/>}<br/>})<br/>.then(wasm => {<br/>wasm.instance.exports.do_trig();<br/>});<br/>

    View Slide

  40. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {<br/>imports: {<br/>cos: (x) => Math.cos(x)<br/>}<br/>})<br/>.then(wasm => {<br/>wasm.instance.exports.do_trig();<br/>});<br/>
    - We probably want a debug print…
    - But WebAssembly has no I/O!

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  44. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {<br/>imports: {<br/>console_log : (x) => console.log(x),<br/>cos: (x) => Math.cos(x)<br/>}<br/>})<br/>.then(wasm => {<br/>wasm.instance.exports.do_trig();<br/>});<br/>

    View Slide

  45. 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 -----
    <br/>WebAssembly .instantiateStreaming (<br/>fetch('example.wasm' ), {<br/>imports: {<br/>console_log : (x) => console.log(x),<br/>cos: (x) => Math.cos(x)<br/>}<br/>})<br/>.then(wasm => {<br/>wasm.instance.exports.do_trig();<br/>});<br/>

    View Slide

  46. Yay transcendental functions!

    View Slide

  47. 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

    View Slide

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

    View Slide

  49. 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

    View Slide

  50. 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

    View Slide

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

    View Slide

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

    View Slide

  53. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  58. The difficulty with graphics APIs

    View Slide

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

    View Slide

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

    View Slide

  61. 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)

    View Slide

  62. Results

    View Slide

  63. Results

    View Slide

  64. 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

    View Slide

  65. Access all JavaScript APIs from
    WebAssembly

    View Slide

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

    View Slide

  67. The future is bright!

    View Slide

  68. Thank you!
    @TaigaMerlin

    View Slide