diff --git a/Cargo.lock b/Cargo.lock index 668fa40a..08954b2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,11 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "anyhow" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "approx" version = "0.3.2" @@ -172,6 +177,11 @@ name = "build_const" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bumpalo" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bytemuck" version = "1.2.0" @@ -1056,6 +1066,14 @@ dependencies = [ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hermit-abi" version = "0.1.6" @@ -1077,6 +1095,19 @@ dependencies = [ "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "image" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "image" version = "0.22.4" @@ -1177,6 +1208,14 @@ dependencies = [ "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "js-sys" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1457,6 +1496,15 @@ name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nom" version = "5.1.0" @@ -1847,6 +1895,20 @@ dependencies = [ "serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pathfinder_webgl" +version = "0.1.0" +dependencies = [ + "image 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_geometry 0.4.0", + "pathfinder_gpu 0.1.0", + "pathfinder_renderer 0.1.0", + "pathfinder_simd 0.4.0", + "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1862,6 +1924,17 @@ name = "plain" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "png" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "png" version = "0.15.3" @@ -2297,6 +2370,11 @@ dependencies = [ "wayland-protocols 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sourcefile" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stable_deref_trait" version = "1.1.1" @@ -2486,6 +2564,11 @@ name = "unicode-script" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-vo" version = "0.1.0" @@ -2568,6 +2651,70 @@ name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasm-bindgen" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bumpalo 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasm-bindgen-webidl" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wayland-client" version = "0.23.6" @@ -2623,6 +2770,26 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "web-sys" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "weedle" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -2736,6 +2903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" "checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" "checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" @@ -2751,6 +2919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" +"checksum bumpalo 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742" "checksum bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" @@ -2835,9 +3004,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum harfbuzz-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d74cab8498b2d15700b694fb38f77562869d05e1f8b602dd05221a1ca2d63" "checksum harfbuzz_rs 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cab35982090055087fad29795c465b33e8cf201bda50bfa008311ffe88630f16" "checksum hashbrown 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "728e7d31e63d53c436094370f1e6fa249f60a4bb318cc5dfbbbe0aa2bc5a29d7" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" "checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +"checksum image 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)" = "35371e467cd7b0b3d1d6013d619203658467df12d61b0ca43cd67b743b1965eb" "checksum image 0.22.4 (registry+https://github.com/rust-lang/crates.io-index)" = "53cb19c4e35102e5c6fb9ade5e0e236c5588424dc171a849af3141bf0b47768a" "checksum image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4e336ec01a678e7ab692914c641181528e8656451e6252f8f9e33728882eaf" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" @@ -2849,6 +3020,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum jni 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1981310da491a4f0f815238097d0d43d8072732b5ae5f8bd0d8eadf5bf245402" "checksum jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" "checksum jpeg-decoder 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0256f0aec7352539102a9efbcb75543227b7ab1117e0f95450023af730128451" +"checksum js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7889c7c36282151f6bf465be4700359318aef36baa951462382eae49e9577cf9" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum khronos 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c0711aaa80e6ba6eb1fa8978f1f46bfcb38ceb2f3f33f3736efbff39dac89f50" "checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" @@ -2882,6 +3054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e752e3c216bc8a491c5b59fa46da10f1379ae450b19ac688e07f4bb55042e98" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum nom 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c433f4d505fe6ce7ff78523d2fa13a0b9f2690e181fc26168bcbe5ccc5d14e07" "checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" @@ -2898,6 +3071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +"checksum png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359" "checksum png 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef859a23054bbfee7811284275ae522f0434a3c8e7f4b74bd4a35ae7e1c4a283" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum pretty_env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" @@ -2950,6 +3124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" "checksum smithay-client-toolkit 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "93960e8975909fcb14cc755de93af2149d8b8f4eb368315537d40cfd0f324054" +"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" @@ -2970,6 +3145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" "checksum unicode-script 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc3ca3febe3d301fa4ff250e63a11d9da58390c3f079c736fc6602bcd36449d2" +"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-vo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" @@ -2981,11 +3157,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +"checksum wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "5205e9afdf42282b192e2310a5b463a6d1c1d774e30dc3c791ac37ab42d2616c" +"checksum wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "11cdb95816290b525b32587d76419facd99662a07e59d3cdb560488a819d9a45" +"checksum wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "574094772ce6921576fb6f2e3f7497b8a76273b6db092be18fc48a082de09dc3" +"checksum wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "e85031354f25eaebe78bb7db1c3d86140312a911a106b2e29f9cc440ce3e7668" +"checksum wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e7e61fc929f4c0dddb748b102ebf9f632e2b8d739f2016542b4de2965a9601" +"checksum wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d" "checksum wayland-client 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda" "checksum wayland-commons 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb" "checksum wayland-protocols 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9" "checksum wayland-scanner 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d" "checksum wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4" +"checksum web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b" +"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index db945194..1d80d4a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ members = [ "utils/gamma-lut", "utils/svg-to-skia", "utils/convert", + "webgl", ] default-members = [ diff --git a/webgl/Cargo.toml b/webgl/Cargo.toml new file mode 100644 index 00000000..0219709e --- /dev/null +++ b/webgl/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "pathfinder_webgl" +version = "0.1.0" +edition = "2018" +authors = ["Sebastian Köln "] + +[dependencies] +wasm-bindgen = "*" +log = "0.4.8" + +[dependencies.image] +version = "0.21" +default-features = false +features = ["png_codec"] + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_gpu] +path = "../gpu" + +[dependencies.pathfinder_renderer] +path = "../renderer" + +[dependencies.pathfinder_simd] +path = "../simd" + +[dependencies.web-sys] +version = "0.3.4" +features = [ + 'Document', + 'Element', + 'HtmlCanvasElement', + 'WebGlBuffer', + 'WebGlFramebuffer', + 'WebGl2RenderingContext', + 'WebGlProgram', + 'WebGlShader', + 'WebGlUniformLocation', + 'WebGlTexture', + 'WebGlProgram', + 'WebGlVertexArrayObject', + 'Window', +] \ No newline at end of file diff --git a/webgl/src/lib.rs b/webgl/src/lib.rs new file mode 100644 index 00000000..680dc059 --- /dev/null +++ b/webgl/src/lib.rs @@ -0,0 +1,1086 @@ +// pathfinder/webgl/src/lib.rs +// +// Copyright © 2020 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A WebGL implementation of the device abstraction. + +#[macro_use] +extern crate log; + +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_gpu::resources::ResourceLoader; +use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, RenderTarget}; +use pathfinder_gpu::{BufferUploadMode, ClearOps, DepthFunc, Device, Primitive, RenderOptions}; +use pathfinder_gpu::{RenderState, ShaderKind, StencilFunc, TextureData, TextureDataRef}; +use pathfinder_gpu::{TextureFormat, TextureSamplingFlags, UniformData, VertexAttrClass}; +use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use std::mem; +use std::str; +use std::time::Duration; +use web_sys::WebGl2RenderingContext as WebGl; + +pub struct WebGlDevice { + context: web_sys::WebGl2RenderingContext, +} + +impl WebGlDevice { + pub fn new(context: web_sys::WebGl2RenderingContext) -> Self { + context.get_extension("EXT_color_buffer_float").unwrap(); + WebGlDevice { context } + } + + // Error checking + + #[cfg(debug_assertions)] + fn ck(&self) { + let mut num_errors = 0; + loop { + let err = self.context.get_error(); + println!( + "GL error: 0x{:x} ({})", + err, + match err { + WebGl::NO_ERROR => break, + WebGl::INVALID_ENUM => "INVALID_ENUM", + WebGl::INVALID_VALUE => "INVALID_VALUE", + WebGl::INVALID_OPERATION => "INVALID_OPERATION", + WebGl::INVALID_FRAMEBUFFER_OPERATION => "INVALID_FRAMEBUFFER_OPERATION", + WebGl::OUT_OF_MEMORY => "OUT_OF_MEMORY", + _ => "Unknown", + } + ); + num_errors += 1; + } + if num_errors > 0 { + panic!("aborting due to {} errors", num_errors); + } + } + + #[cfg(not(debug_assertions))] + #[inline] + fn ck(&self) {} + + #[inline] + fn bind_texture(&self, texture: &WebGlTexture, unit: u32) { + self.context.active_texture(WebGl::TEXTURE0 + unit); + self.context + .bind_texture(WebGl::TEXTURE_2D, Some(&texture.texture)); + } + + #[inline] + fn unbind_texture(&self, unit: u32) { + self.context.active_texture(WebGl::TEXTURE0 + unit); + self.context.bind_texture(WebGl::TEXTURE_2D, None); + } + + #[inline] + fn bind_render_target(&self, attachment: &RenderTarget) { + let framebuffer = match *attachment { + RenderTarget::Default => None, + RenderTarget::Framebuffer(framebuffer) => Some(framebuffer), + }; + self.context + .bind_framebuffer(WebGl::FRAMEBUFFER, framebuffer.map(|f| &f.framebuffer)); + } + + #[inline] + fn bind_vertex_array(&self, vertex_array: &WebGlVertexArray) { + self.context + .bind_vertex_array(Some(&vertex_array.gl_vertex_array)); + self.ck(); + } + + #[inline] + fn unbind_vertex_array(&self) { + self.context.bind_vertex_array(None); + self.ck(); + } + #[inline] + fn set_uniform(&self, uniform: &WebGlUniform, data: &UniformData) { + let location = uniform.location.as_ref(); + + match *data { + UniformData::Float(value) => { + self.context.uniform1f(location, value); + self.ck(); + } + UniformData::Int(value) => { + self.context.uniform1i(location, value); + self.ck(); + } + UniformData::Mat2(data) => { + self.context.uniform_matrix2fv_with_f32_array( + location, + false, + &[data.x(), data.y(), data.z(), data.w()], + ); + } + UniformData::Mat4(data) => { + self.context.uniform_matrix4fv_with_f32_array( + location, + false, + &[ + data[0].x(), + data[0].y(), + data[0].z(), + data[0].w(), + data[1].x(), + data[1].y(), + data[1].z(), + data[1].w(), + data[2].x(), + data[2].y(), + data[2].z(), + data[2].w(), + data[3].x(), + data[3].y(), + data[3].z(), + data[3].w(), + ], + ); + } + UniformData::Vec2(data) => { + self.context.uniform2f(location, data.x(), data.y()); + self.ck(); + } + UniformData::Vec3(data) => { + self.context.uniform3f(location, data[0], data[1], data[2]); + self.ck(); + } + UniformData::Vec4(data) => { + self.context + .uniform4f(location, data.x(), data.y(), data.z(), data.w()); + self.ck(); + } + UniformData::IVec3(data) => { + self.context.uniform3i(location, data[0], data[1], data[2]); + self.ck(); + } + UniformData::TextureUnit(unit) => { + self.context.uniform1i(location, unit as i32); + self.ck(); + } + } + } + fn set_render_state(&self, render_state: &RenderState) { + self.bind_render_target(render_state.target); + + let (origin, size) = (render_state.viewport.origin(), render_state.viewport.size()); + self.context + .viewport(origin.x(), origin.y(), size.x(), size.y()); + + if render_state.options.clear_ops.has_ops() { + self.clear(&render_state.options.clear_ops); + } + + self.context + .use_program(Some(&render_state.program.gl_program)); + self.context + .bind_vertex_array(Some(&render_state.vertex_array.gl_vertex_array)); + for (texture_unit, texture) in render_state.textures.iter().enumerate() { + self.bind_texture(texture, texture_unit as u32); + } + + for (uniform, data) in render_state.uniforms { + self.set_uniform(uniform, data); + } + self.set_render_options(&render_state.options); + } + + fn set_render_options(&self, render_options: &RenderOptions) { + match render_options.blend { + None => { + self.context.disable(WebGl::BLEND); + self.ck(); + } + Some(blend) => { + let func = match blend.op { + BlendOp::Add => WebGl::FUNC_ADD, + BlendOp::Subtract => WebGl::FUNC_SUBTRACT, + BlendOp::ReverseSubtract => WebGl::FUNC_REVERSE_SUBTRACT, + BlendOp::Max => WebGl::MAX, + BlendOp::Min => WebGl::MIN, + }; + self.context.blend_equation(func); + self.ck(); + + let func = |f| match f { + BlendFactor::Zero => WebGl::ZERO, + BlendFactor::One => WebGl::ONE, + BlendFactor::SrcAlpha => WebGl::SRC_ALPHA, + BlendFactor::OneMinusSrcAlpha => WebGl::ONE_MINUS_SRC_ALPHA, + BlendFactor::DestAlpha => WebGl::DST_ALPHA, + BlendFactor::OneMinusDestAlpha => WebGl::ONE_MINUS_DST_ALPHA, + BlendFactor::DestColor => WebGl::DST_COLOR, + }; + + self.context.blend_func_separate( + func(blend.src_rgb_factor), + func(blend.dest_rgb_factor), + func(blend.src_alpha_factor), + func(blend.dest_alpha_factor), + ); + self.context.enable(WebGl::BLEND); + self.ck(); + } + } + + // Set depth. + match render_options.depth { + None => { + self.context.disable(WebGl::DEPTH_TEST); + self.ck(); + } + Some(ref state) => { + self.context.depth_func(state.func.to_gl_depth_func()); + self.ck(); + self.context.depth_mask(state.write as bool); + self.ck(); + self.context.enable(WebGl::DEPTH_TEST); + self.ck(); + } + } + + // Set stencil. + match render_options.stencil { + None => { + self.context.disable(WebGl::STENCIL_TEST); + self.ck(); + } + Some(ref state) => { + self.context.stencil_func( + state.func.to_gl_stencil_func(), + state.reference as i32, + state.mask, + ); + self.ck(); + let (pass_action, write_mask) = if state.write { + (WebGl::REPLACE, state.mask) + } else { + (WebGl::KEEP, 0) + }; + self.context + .stencil_op(WebGl::KEEP, WebGl::KEEP, pass_action); + self.ck(); + self.context.stencil_mask(write_mask); + self.context.enable(WebGl::STENCIL_TEST); + self.ck(); + } + } + + // Set color mask. + let color_mask = render_options.color_mask as bool; + self.context + .color_mask(color_mask, color_mask, color_mask, color_mask); + self.ck(); + } + + fn reset_render_state(&self, render_state: &RenderState) { + self.reset_render_options(&render_state.options); + for texture_unit in 0..(render_state.textures.len() as u32) { + self.unbind_texture(texture_unit); + } + self.context.use_program(None); + self.unbind_vertex_array(); + } + + fn reset_render_options(&self, render_options: &RenderOptions) { + if render_options.blend.is_some() { + self.context.disable(WebGl::BLEND); + } + + if render_options.depth.is_some() { + self.context.disable(WebGl::DEPTH_TEST); + } + + if render_options.stencil.is_some() { + self.context.stencil_mask(!0); + self.context.disable(WebGl::STENCIL_TEST); + } + + self.context.color_mask(true, true, true, true); + self.ck(); + } + + #[inline] + fn clear(&self, ops: &ClearOps) { + let mut flags = 0; + if let Some(color) = ops.color { + self.context.color_mask(true, true, true, true); + self.context + .clear_color(color.r(), color.g(), color.b(), color.a()); + flags |= WebGl::COLOR_BUFFER_BIT; + } + if let Some(depth) = ops.depth { + self.context.depth_mask(true); + self.context.clear_depth(depth as _); + flags |= WebGl::DEPTH_BUFFER_BIT; + } + if let Some(stencil) = ops.stencil { + self.context.stencil_mask(!0); + self.context.clear_stencil(stencil as i32); + flags |= WebGl::STENCIL_BUFFER_BIT; + } + if flags != 0 { + self.context.clear(flags); + } + } + + fn preprocess(&self, source: &[u8], version: &str) -> String { + let source = std::str::from_utf8(source).unwrap(); + let mut output = String::new(); + + let mut pos = 0; + while let Some(index) = source[pos..].find("{{") { + let index = index + pos; + if index > pos { + output.push_str(&source[pos..index]); + } + let end_index = index + 2 + source[index + 2..].find("}").unwrap(); + assert_eq!(&source[end_index + 1..end_index + 2], "}"); + let ident = &source[index + 2..end_index]; + if ident == "version" { + output.push_str(version); + } else { + panic!("unknown template variable: `{}`", ident); + } + pos = end_index + 2; + } + output.push_str(&source[pos..]); + /* + for (line_nr, line) in output.lines().enumerate() { + debug!("{:3}: {}", line_nr + 1, line); + } + */ + output + } +} + +fn slice_to_u8(slice: &[T]) -> &[u8] { + unsafe { + std::slice::from_raw_parts( + slice.as_ptr() as *const u8, + slice.len() * mem::size_of::(), + ) + } +} +fn check_and_extract_data( + data_ref: TextureDataRef, + minimum_size: Vector2I, + format: TextureFormat, +) -> &[u8] { + let channels = match (format, data_ref) { + (TextureFormat::R8, TextureDataRef::U8(_)) => 1, + (TextureFormat::RGBA8, TextureDataRef::U8(_)) => 4, + (TextureFormat::RGBA16F, TextureDataRef::F16(_)) => 4, + (TextureFormat::RGBA32F, TextureDataRef::F32(_)) => 4, + _ => panic!("Unimplemented texture format!"), + }; + + let area = minimum_size.x() as usize * minimum_size.y() as usize; + + match data_ref { + TextureDataRef::U8(data) => { + assert!(data.len() >= area * channels); + slice_to_u8(data) + } + TextureDataRef::F16(data) => { + assert!(data.len() >= area * channels); + slice_to_u8(data) + } + TextureDataRef::F32(data) => { + assert!(data.len() >= area * channels); + slice_to_u8(data) + } + } +} + +impl Device for WebGlDevice { + type Buffer = WebGlBuffer; + type Framebuffer = WebGlFramebuffer; + type Program = WebGlProgram; + type Shader = WebGlShader; + type Texture = WebGlTexture; + type TextureDataReceiver = (); + type TimerQuery = WebGlTimerQuery; + type Uniform = WebGlUniform; + type VertexArray = WebGlVertexArray; + type VertexAttr = WebGlVertexAttr; + + fn create_texture(&self, format: TextureFormat, size: Vector2I) -> WebGlTexture { + let texture = self.context.create_texture().unwrap(); + let texture = WebGlTexture { + texture, + format, + size, + context: self.context.clone(), + }; + self.bind_texture(&texture, 0); + self.context + .tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array( + WebGl::TEXTURE_2D, + 0, + format.gl_internal_format() as i32, + size.x(), + size.y(), + 0, + format.gl_format(), + format.gl_type(), + None, + ) + .unwrap(); + + self.set_texture_sampling_mode(&texture, TextureSamplingFlags::empty()); + texture + } + + fn create_texture_from_data( + &self, + format: TextureFormat, + size: Vector2I, + data_ref: TextureDataRef, + ) -> WebGlTexture { + let data = check_and_extract_data(data_ref, size, format); + + let texture = self.context.create_texture().unwrap(); + let texture = WebGlTexture { + texture, + format, + size, + context: self.context.clone(), + }; + + self.bind_texture(&texture, 0); + self.context + .tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array( + WebGl::TEXTURE_2D, + 0, + format.gl_internal_format() as i32, + size.x(), + size.y(), + 0, + format.gl_format(), + format.gl_type(), + Some(data), + ) + .unwrap(); + + self.set_texture_sampling_mode(&texture, TextureSamplingFlags::empty()); + texture + } + + #[inline] + fn texture_format(&self, texture: &Self::Texture) -> TextureFormat { + texture.format + } + + fn create_shader_from_source( + &self, + name: &str, + source: &[u8], + kind: ShaderKind, + ) -> WebGlShader { + let glsl_version_spec = "300 es"; + + let source = self.preprocess(source, glsl_version_spec); + + let gl_shader_kind = match kind { + ShaderKind::Vertex => WebGl::VERTEX_SHADER, + ShaderKind::Fragment => WebGl::FRAGMENT_SHADER, + }; + + let gl_shader = self + .context + .create_shader(gl_shader_kind) + .expect("could not create shader"); + self.context.shader_source(&gl_shader, &source); + self.context.compile_shader(&gl_shader); + let compile_status = self + .context + .get_shader_parameter(&gl_shader, WebGl::COMPILE_STATUS); + if !compile_status.as_bool().unwrap_or(false) { + if let Some(info_log) = self.context.get_shader_info_log(&gl_shader) { + info!("Shader info log:\n{}", info_log); + } + panic!("{:?} shader '{}' compilation failed", kind, name); + } + + WebGlShader { gl_shader } + } + + fn create_program_from_shaders( + &self, + _resources: &dyn ResourceLoader, + name: &str, + vertex_shader: WebGlShader, + fragment_shader: WebGlShader, + ) -> WebGlProgram { + let gl_program = self + .context + .create_program() + .expect("unable to create program object"); + self.context + .attach_shader(&gl_program, &vertex_shader.gl_shader); + self.context + .attach_shader(&gl_program, &fragment_shader.gl_shader); + self.context.link_program(&gl_program); + if !self + .context + .get_program_parameter(&gl_program, WebGl::LINK_STATUS) + .as_bool() + .unwrap_or(false) + { + if let Some(info_log) = self.context.get_program_info_log(&gl_program) { + info!("Program info log for {}:\n{}", name, info_log); + } + panic!("Program {:?} linking failed", name); + } + + WebGlProgram { + context: self.context.clone(), + gl_program, + } + } + + #[inline] + fn create_vertex_array(&self) -> WebGlVertexArray { + WebGlVertexArray { + context: self.context.clone(), + gl_vertex_array: self.context.create_vertex_array().unwrap(), + } + } + + fn get_vertex_attr(&self, program: &WebGlProgram, name: &str) -> Option { + let name = format!("a{}", name); + let attr = self.context.get_attrib_location(&program.gl_program, &name); + if attr < 0 { + return None; + } + Some(WebGlVertexAttr { attr: attr as u32 }) + } + + fn get_uniform(&self, program: &WebGlProgram, name: &str) -> WebGlUniform { + let name = format!("u{}", name); + let location = self + .context + .get_uniform_location(&program.gl_program, &name); + self.ck(); + WebGlUniform { location: location } + } + + fn configure_vertex_attr( + &self, + vertex_array: &WebGlVertexArray, + attr: &WebGlVertexAttr, + descriptor: &VertexAttrDescriptor, + ) { + debug_assert_ne!(descriptor.stride, 0); + + self.context + .bind_vertex_array(Some(&vertex_array.gl_vertex_array)); + + let attr_type = descriptor.attr_type.to_gl_type(); + match descriptor.class { + VertexAttrClass::Float | VertexAttrClass::FloatNorm => { + let normalized = descriptor.class == VertexAttrClass::FloatNorm; + self.context.vertex_attrib_pointer_with_i32( + attr.attr, + descriptor.size as i32, + attr_type, + normalized, + descriptor.stride as i32, + descriptor.offset as i32, + ); + } + VertexAttrClass::Int => { + self.context.vertex_attrib_i_pointer_with_i32( + attr.attr, + descriptor.size as i32, + attr_type, + descriptor.stride as i32, + descriptor.offset as i32, + ); + } + } + + self.context + .vertex_attrib_divisor(attr.attr, descriptor.divisor); + self.context.enable_vertex_attrib_array(attr.attr); + self.context.bind_vertex_array(None); + } + + fn create_framebuffer(&self, texture: WebGlTexture) -> WebGlFramebuffer { + debug!( + "texture size = {:?}, format = {:?}", + texture.size, texture.format + ); + let gl_framebuffer = self.context.create_framebuffer().unwrap(); + self.context + .bind_framebuffer(WebGl::FRAMEBUFFER, Some(&gl_framebuffer)); + self.bind_texture(&texture, 0); + + self.context.framebuffer_texture_2d( + WebGl::FRAMEBUFFER, + WebGl::COLOR_ATTACHMENT0, + WebGl::TEXTURE_2D, + Some(&texture.texture), + 0, + ); + self.ck(); + match self.context.check_framebuffer_status(WebGl::FRAMEBUFFER) { + WebGl::FRAMEBUFFER_COMPLETE => {} + WebGl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => panic!("FRAMEBUFFER_INCOMPLETE_ATTACHMENT"), + WebGl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => { + panic!("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT") + } + WebGl::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => panic!("FRAMEBUFFER_INCOMPLETE_DIMENSIONS"), + WebGl::FRAMEBUFFER_UNSUPPORTED => panic!("FRAMEBUFFER_UNSUPPORTED"), + WebGl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => { + panic!("FRAMEBUFFER_INCOMPLETE_MULTISAMPLE") + } + WebGl::RENDERBUFFER_SAMPLES => panic!("RENDERBUFFER_SAMPLES"), + code => panic!("unknown code {}", code), + } + + WebGlFramebuffer { + framebuffer: gl_framebuffer, + texture, + } + } + + fn destroy_framebuffer(&self, framebuffer: Self::Framebuffer) -> Self::Texture { + self.context + .delete_framebuffer(Some(&framebuffer.framebuffer)); + framebuffer.texture + } + + fn create_buffer(&self) -> WebGlBuffer { + let buffer = self.context.create_buffer().unwrap(); + WebGlBuffer { + buffer, + context: self.context.clone(), + } + } + + fn allocate_buffer( + &self, + buffer: &WebGlBuffer, + data: BufferData, + target: BufferTarget, + mode: BufferUploadMode, + ) { + let target = match target { + BufferTarget::Vertex => WebGl::ARRAY_BUFFER, + BufferTarget::Index => WebGl::ELEMENT_ARRAY_BUFFER, + }; + self.context.bind_buffer(target, Some(&buffer.buffer)); + self.ck(); + let usage = mode.to_gl_usage(); + match data { + BufferData::Uninitialized(len) => { + self.context + .buffer_data_with_i32(target, (len * mem::size_of::()) as i32, usage) + } + BufferData::Memory(buffer) => { + self.context + .buffer_data_with_u8_array(target, slice_to_u8(buffer), usage) + } + } + } + + #[inline] + fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture { + &framebuffer.texture + } + + #[inline] + fn texture_size(&self, texture: &Self::Texture) -> Vector2I { + texture.size + } + + fn set_texture_sampling_mode(&self, texture: &Self::Texture, flags: TextureSamplingFlags) { + self.bind_texture(texture, 0); + self.context + .tex_parameteri(WebGl::TEXTURE_2D, + WebGl::TEXTURE_MIN_FILTER, + if flags.contains(TextureSamplingFlags::NEAREST_MIN) { + WebGl::NEAREST as i32 + } else { + WebGl::LINEAR as i32 + }); + self.context + .tex_parameteri(WebGl::TEXTURE_2D, + WebGl::TEXTURE_MAG_FILTER, + if flags.contains(TextureSamplingFlags::NEAREST_MAG) { + WebGl::NEAREST as i32 + } else { + WebGl::LINEAR as i32 + }); + self.context + .tex_parameteri(WebGl::TEXTURE_2D, + WebGl::TEXTURE_WRAP_S, + if flags.contains(TextureSamplingFlags::REPEAT_U) { + WebGl::REPEAT as i32 + } else { + WebGl::CLAMP_TO_EDGE as i32 + }); + self.context + .tex_parameteri(WebGl::TEXTURE_2D, + WebGl::TEXTURE_WRAP_T, + if flags.contains(TextureSamplingFlags::REPEAT_V) { + WebGl::REPEAT as i32 + } else { + WebGl::CLAMP_TO_EDGE as i32 + }); + } + + fn upload_to_texture(&self, texture: &WebGlTexture, rect: RectI, data_ref: TextureDataRef) { + let data = check_and_extract_data(data_ref, rect.size(), texture.format); + assert!(rect.size().x() >= 0); + assert!(rect.size().y() >= 0); + assert!(rect.max_x() <= texture.size.x()); + assert!(rect.max_y() <= texture.size.y()); + + self.bind_texture(texture, 0); + if rect.origin() == Vector2I::default() && rect.size() == texture.size { + self.context + .tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array( + WebGl::TEXTURE_2D, + 0, + texture.format.gl_internal_format() as i32, + texture.size.x() as i32, + texture.size.y() as i32, + 0, + texture.format.gl_format(), + texture.format.gl_type(), + Some(data), + ) + .unwrap(); + } else { + self.context + .tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_u8_array( + WebGl::TEXTURE_2D, + 0, + rect.origin().x(), + rect.origin().y(), + texture.size.x() as i32, + texture.size.y() as i32, + texture.format.gl_format(), + texture.format.gl_type(), + Some(data), + ) + .unwrap(); + } + + self.set_texture_sampling_mode(&texture, TextureSamplingFlags::empty()); + } + + fn read_pixels(&self, _render_target: &RenderTarget, _viewport: RectI) -> () { + panic!("read_pixels is not supported"); + } + + fn begin_commands(&self) { + // TODO(pcwalton): Add some checks in debug mode to make sure render commands are bracketed + // by these? + } + + fn end_commands(&self) { + self.context.flush(); + } + + fn draw_arrays(&self, index_count: u32, render_state: &RenderState) { + self.set_render_state(render_state); + self.context.draw_arrays( + render_state.primitive.to_gl_primitive(), + 0, + index_count as i32, + ); + self.reset_render_state(render_state); + } + + fn draw_elements(&self, index_count: u32, render_state: &RenderState) { + self.set_render_state(render_state); + self.context.draw_elements_with_i32( + render_state.primitive.to_gl_primitive(), + index_count as i32, + WebGl::UNSIGNED_INT, + 0, + ); + self.reset_render_state(render_state); + } + + fn draw_elements_instanced( + &self, + index_count: u32, + instance_count: u32, + render_state: &RenderState, + ) { + self.set_render_state(render_state); + self.context.draw_elements_instanced_with_i32( + render_state.primitive.to_gl_primitive(), + index_count as i32, + WebGl::UNSIGNED_INT, + 0, + instance_count as i32, + ); + self.reset_render_state(render_state); + } + + #[inline] + fn create_timer_query(&self) -> WebGlTimerQuery { + // FIXME use performance timers + WebGlTimerQuery {} + } + + #[inline] + fn begin_timer_query(&self, _query: &Self::TimerQuery) { + // FIXME use performance timers + } + + #[inline] + fn end_timer_query(&self, _: &Self::TimerQuery) { + // FIXME use performance timers + } + + #[inline] + fn try_recv_timer_query(&self, _query: &WebGlTimerQuery) -> Option { + None + } + + #[inline] + fn recv_timer_query(&self, _query: &WebGlTimerQuery) -> Duration { + Duration::from_millis(0) + } + fn try_recv_texture_data(&self, _receiver: &Self::TextureDataReceiver) -> Option { + None + } + fn recv_texture_data(&self, _receiver: &Self::TextureDataReceiver) -> TextureData { + unimplemented!() + } + + #[inline] + fn bind_buffer( + &self, + vertex_array: &WebGlVertexArray, + buffer: &WebGlBuffer, + target: BufferTarget, + ) { + self.bind_vertex_array(vertex_array); + self.context + .bind_buffer(target.to_gl_target(), Some(&buffer.buffer)); + self.unbind_vertex_array(); + } + + #[inline] + fn create_shader( + &self, + resources: &dyn ResourceLoader, + name: &str, + kind: ShaderKind, + ) -> Self::Shader { + let suffix = match kind { + ShaderKind::Vertex => 'v', + ShaderKind::Fragment => 'f', + }; + let path = format!("shaders/gl3/{}.{}s.glsl", name, suffix); + self.create_shader_from_source(name, &resources.slurp(&path).unwrap(), kind) + } +} + +pub struct WebGlVertexArray { + context: web_sys::WebGl2RenderingContext, + pub gl_vertex_array: web_sys::WebGlVertexArrayObject, +} + +impl Drop for WebGlVertexArray { + #[inline] + fn drop(&mut self) { + self.context + .delete_vertex_array(Some(&self.gl_vertex_array)); + } +} + +pub struct WebGlVertexAttr { + attr: u32, +} + +pub struct WebGlFramebuffer { + pub framebuffer: web_sys::WebGlFramebuffer, + pub texture: WebGlTexture, +} + +pub struct WebGlBuffer { + context: web_sys::WebGl2RenderingContext, + pub buffer: web_sys::WebGlBuffer, +} + +impl Drop for WebGlBuffer { + fn drop(&mut self) { + self.context.delete_buffer(Some(&self.buffer)); + } +} + +#[derive(Debug)] +pub struct WebGlUniform { + location: Option, +} + +pub struct WebGlProgram { + context: web_sys::WebGl2RenderingContext, + pub gl_program: web_sys::WebGlProgram, +} + +impl Drop for WebGlProgram { + fn drop(&mut self) { + self.context.delete_program(Some(&self.gl_program)); + } +} + +pub struct WebGlShader { + gl_shader: web_sys::WebGlShader, +} + +pub struct WebGlTexture { + context: web_sys::WebGl2RenderingContext, + texture: web_sys::WebGlTexture, + pub size: Vector2I, + pub format: TextureFormat, +} +impl Drop for WebGlTexture { + fn drop(&mut self) { + self.context.delete_texture(Some(&self.texture)); + } +} + +pub struct WebGlTimerQuery {} + +trait BufferTargetExt { + fn to_gl_target(self) -> u32; +} + +impl BufferTargetExt for BufferTarget { + fn to_gl_target(self) -> u32 { + match self { + BufferTarget::Vertex => WebGl::ARRAY_BUFFER, + BufferTarget::Index => WebGl::ELEMENT_ARRAY_BUFFER, + } + } +} + +trait BufferUploadModeExt { + fn to_gl_usage(self) -> u32; +} + +impl BufferUploadModeExt for BufferUploadMode { + fn to_gl_usage(self) -> u32 { + match self { + BufferUploadMode::Static => WebGl::STATIC_DRAW, + BufferUploadMode::Dynamic => WebGl::DYNAMIC_DRAW, + } + } +} + +trait DepthFuncExt { + fn to_gl_depth_func(self) -> u32; +} + +impl DepthFuncExt for DepthFunc { + fn to_gl_depth_func(self) -> u32 { + match self { + DepthFunc::Less => WebGl::LESS, + DepthFunc::Always => WebGl::ALWAYS, + } + } +} + +trait PrimitiveExt { + fn to_gl_primitive(self) -> u32; +} + +impl PrimitiveExt for Primitive { + fn to_gl_primitive(self) -> u32 { + match self { + Primitive::Triangles => WebGl::TRIANGLES, + Primitive::Lines => WebGl::LINES, + } + } +} + +trait StencilFuncExt { + fn to_gl_stencil_func(self) -> u32; +} + +impl StencilFuncExt for StencilFunc { + fn to_gl_stencil_func(self) -> u32 { + match self { + StencilFunc::Always => WebGl::ALWAYS, + StencilFunc::Equal => WebGl::EQUAL, + } + } +} + +trait TextureFormatExt { + fn gl_internal_format(self) -> u32; + fn gl_format(self) -> u32; + fn gl_type(self) -> u32; +} + +impl TextureFormatExt for TextureFormat { + fn gl_internal_format(self) -> u32 { + match self { + TextureFormat::R8 => WebGl::R8, + TextureFormat::R16F => WebGl::R16F, + TextureFormat::RGBA8 => WebGl::RGBA, + TextureFormat::RGBA16F => WebGl::RGBA16F, + TextureFormat::RGBA32F => WebGl::RGBA32F, + } + } + + fn gl_format(self) -> u32 { + match self { + TextureFormat::R8 | TextureFormat::R16F => WebGl::RED, + TextureFormat::RGBA8 | TextureFormat::RGBA16F | TextureFormat::RGBA32F => WebGl::RGBA, + } + } + + fn gl_type(self) -> u32 { + match self { + TextureFormat::R8 | TextureFormat::RGBA8 => WebGl::UNSIGNED_BYTE, + TextureFormat::R16F | TextureFormat::RGBA16F => WebGl::HALF_FLOAT, + TextureFormat::RGBA32F => WebGl::FLOAT, + } + } +} + +trait VertexAttrTypeExt { + fn to_gl_type(self) -> u32; +} + +impl VertexAttrTypeExt for VertexAttrType { + fn to_gl_type(self) -> u32 { + match self { + VertexAttrType::F32 => WebGl::FLOAT, + VertexAttrType::I16 => WebGl::SHORT, + VertexAttrType::I8 => WebGl::BYTE, + VertexAttrType::U16 => WebGl::UNSIGNED_SHORT, + VertexAttrType::U8 => WebGl::UNSIGNED_BYTE, + } + } +} + +/// The version/dialect of OpenGL we should render with. +#[derive(Clone, Copy)] +#[repr(u32)] +pub enum GLVersion { + /// OpenGL 3.0+, core profile. + GL3 = 0, + /// OpenGL ES 3.0+. + GLES3 = 1, +}