diff --git a/.gitignore b/.gitignore index 82600a0a..ac289464 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ target /site/dist node_modules /examples/c_canvas_minimal/build +/shaders/build +/c/build # Editors *.swp diff --git a/Cargo.lock b/Cargo.lock index ba24425d..215c4503 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ name = "approx" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -90,7 +90,7 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -98,7 +98,7 @@ name = "backtrace" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", @@ -117,11 +117,10 @@ dependencies = [ [[package]] name = "base64" -version = "0.9.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -143,17 +142,56 @@ name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "canvas_glutin_minimal" +version = "0.1.0" +dependencies = [ + "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_renderer 0.1.0", +] + +[[package]] +name = "canvas_metal_minimal" +version = "0.1.0" +dependencies = [ + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", + "pathfinder_renderer 0.1.0", + "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "canvas_minimal" version = "0.1.0" dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -168,6 +206,7 @@ version = "0.1.0" dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -180,8 +219,10 @@ dependencies = [ name = "canvas_text" version = "0.1.0" dependencies = [ + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", @@ -190,6 +231,23 @@ dependencies = [ "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cbindgen" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.36" @@ -220,7 +278,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -335,6 +393,14 @@ dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crc32fast" version = "1.2.0" @@ -392,6 +458,14 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "data-url" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "deflate" version = "0.7.19" @@ -406,19 +480,32 @@ name = "demo" version = "0.1.0" dependencies = [ "color-backtrace 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_demo 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", "pathfinder_simd 0.3.0", "pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "derivative" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dirs" version = "1.0.5" @@ -444,13 +531,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "dwrote" -version = "0.5.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -495,7 +580,7 @@ version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -544,11 +629,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "float-cmp" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "float-ord" @@ -557,23 +639,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "font-kit" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-text 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "dwrote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -707,6 +784,77 @@ dependencies = [ "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "glutin" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", + "derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_egl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_emscripten_sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_gles2_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_glx_sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glutin_emscripten_sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "glutin_gles2_sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "half" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "harfbuzz" version = "0.3.1" @@ -728,6 +876,15 @@ dependencies = [ "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "harfbuzz_rs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hashbrown" version = "0.1.8" @@ -738,6 +895,11 @@ dependencies = [ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "humantime" version = "1.2.0" @@ -758,7 +920,7 @@ dependencies = [ "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -772,7 +934,7 @@ dependencies = [ "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -784,14 +946,6 @@ dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "itertools" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.4.4" @@ -861,6 +1015,14 @@ name = "khronos_api" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "kurbo" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.3.0" @@ -900,7 +1062,7 @@ name = "line_drawing" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -942,7 +1104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -953,6 +1115,16 @@ dependencies = [ "lyon_geom 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lzma-rs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lzw" version = "0.10.0" @@ -966,6 +1138,11 @@ dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memchr" version = "2.2.0" @@ -994,6 +1171,23 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "metal" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nfd" version = "0.0.4" @@ -1019,6 +1213,15 @@ name = "nodrop" version = "0.1.13" 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.2.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 = "num" version = "0.1.42" @@ -1026,7 +1229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1044,7 +1247,7 @@ name = "num-integer" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1053,7 +1256,7 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1062,7 +1265,7 @@ version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1071,13 +1274,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "num_cpus" @@ -1098,6 +1304,33 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc_exception" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1105,7 +1338,7 @@ name = "ordered-float" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1163,11 +1396,18 @@ dependencies = [ name = "pathfinder_c" version = "0.1.0" dependencies = [ + "cbindgen 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", "pathfinder_renderer 0.1.0", "pathfinder_simd 0.3.0", ] @@ -1176,11 +1416,24 @@ dependencies = [ name = "pathfinder_canvas" version = "0.1.0" dependencies = [ - "font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", "pathfinder_text 0.1.0", - "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a89e9ca99e0d6736ea1b7754517f4df14fd96a2b)", + "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e)", +] + +[[package]] +name = "pathfinder_content" +version = "0.1.0" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_geometry 0.3.0", + "pathfinder_simd 0.3.0", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1191,28 +1444,26 @@ dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", "pathfinder_gpu 0.1.0", + "pathfinder_metal 0.1.0", "pathfinder_renderer 0.1.0", "pathfinder_simd 0.3.0", "pathfinder_svg 0.1.0", "pathfinder_ui 0.1.0", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pathfinder_geometry" version = "0.3.0" dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_simd 0.3.0", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1233,6 +1484,7 @@ name = "pathfinder_gpu" version = "0.1.0" dependencies = [ "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_simd 0.3.0", ] @@ -1254,6 +1506,7 @@ dependencies = [ "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_demo 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gl 0.1.0", @@ -1264,17 +1517,36 @@ dependencies = [ "pathfinder_ui 0.1.0", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pathfinder_metal" +version = "0.1.0" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_geometry 0.3.0", + "pathfinder_gpu 0.1.0", + "pathfinder_simd 0.3.0", ] [[package]] name = "pathfinder_renderer" version = "0.1.0" dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gpu 0.1.0", "pathfinder_simd 0.3.0", @@ -1298,9 +1570,23 @@ name = "pathfinder_svg" version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", - "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pathfinder_swf" +version = "0.1.0" +dependencies = [ + "pathfinder_content 0.1.0", + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_renderer 0.1.0", + "swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1308,11 +1594,12 @@ name = "pathfinder_text" version = "0.1.0" dependencies = [ "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", - "font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_renderer 0.1.0", - "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a89e9ca99e0d6736ea1b7754517f4df14fd96a2b)", + "skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e)", ] [[package]] @@ -1320,6 +1607,7 @@ name = "pathfinder_ui" version = "0.1.0" dependencies = [ "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_content 0.1.0", "pathfinder_geometry 0.3.0", "pathfinder_gpu 0.1.0", "pathfinder_simd 0.3.0", @@ -1423,7 +1711,7 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1441,7 +1729,7 @@ name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1502,7 +1790,7 @@ name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1537,7 +1825,7 @@ dependencies = [ [[package]] name = "rctree" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1593,11 +1881,19 @@ dependencies = [ ] [[package]] -name = "roxmltree" -version = "0.4.1" +name = "remove_dir_all" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "xmlparser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "roxmltree" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "xmlparser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1629,11 +1925,6 @@ name = "ryu" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "safemem" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "same-file" version = "1.0.4" @@ -1765,10 +2056,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "skribo" version = "0.0.1" -source = "git+https://github.com/linebender/skribo.git?rev=a89e9ca99e0d6736ea1b7754517f4df14fd96a2b#a89e9ca99e0d6736ea1b7754517f4df14fd96a2b" +source = "git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e#a2d683856ba1f2d0095b12dd7823d1602a87614e" dependencies = [ "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", - "font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1823,30 +2114,82 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "svg-to-skia" version = "0.1.0" dependencies = [ - "usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "svgdom" -version = "0.15.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "roxmltree 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "roxmltree 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "svgtypes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "svgtypes" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "float-cmp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "swf-fixed" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "swf-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lzma-rs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "swf-tree" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "swf_basic" +version = "0.1.0" +dependencies = [ + "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_geometry 0.3.0", + "pathfinder_gl 0.1.0", + "pathfinder_gpu 0.1.0", + "pathfinder_renderer 0.1.0", + "pathfinder_swf 0.1.0", + "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.15.34" @@ -1868,6 +2211,19 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term" version = "0.5.2" @@ -1923,11 +2279,32 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ttf-parser" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-normalization" version = "0.1.8" @@ -1937,8 +2314,13 @@ dependencies = [ ] [[package]] -name = "unicode-segmentation" -version = "1.2.1" +name = "unicode-script" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-vo" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1961,16 +2343,22 @@ dependencies = [ [[package]] name = "usvg" -version = "0.4.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "data-url 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "harfbuzz_rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kurbo 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "libflate 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lyon_geom 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rctree 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rctree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "svgdom 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ttf-parser 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-script 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-vo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2115,6 +2503,29 @@ dependencies = [ "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winit" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smithay-client-toolkit 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "x11-dl" version = "2.18.3" @@ -2145,7 +2556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "xmlparser" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] @@ -2159,14 +2570,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "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 byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" +"checksum cbindgen 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f861ef68cabbb271d373a7795014052bff37edce22c620d95e395e8719d7dc5" "checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d" "checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" @@ -2184,17 +2597,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" "checksum core-text 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d95a72b5e50e549969dd88eff3047495fe5b8c6f028635442c2b708be707e669" +"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum data-url 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33fe99ccedd6e84bc035f1931bb2e6be79739d6242bd895e7311c886c50dc9c" "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" +"checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898" "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" "checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f" -"checksum dwrote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30a998e9ff70cd208ccdc4f864e998688bf61d7b897dccec8e17a884d17358bf" +"checksum dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd1369e02db5e9b842a9b67bce8a2fcc043beafb2ae8a799dd482d46ea1ff0d" "checksum egl 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a373bc9844200b1ff15bd1b245931d1c20d09d06e4ec09f361171f29a4b0752d" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" @@ -2205,9 +2621,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" -"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600" +"checksum float-cmp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ae3a6394183450225f33d9419cbd627b3cfc831e14f3f1146d5bcaf984e00c" "checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" -"checksum font-kit 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5be0133b580e2920076afd5bd4b81dc172d10e5653bd1c516476718d52347859" +"checksum font-kit 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c5b784f7a48d718df8d9ee28f81f8afa0a7ffdd61038957cba1ec6837a836d46" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11926b2b410b469d0e9399eca4cbbe237a9ef02176c485803b29216307e8e028" @@ -2221,14 +2637,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gl_generator 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "75d69f914b49d9ff32fdf394cbd798f8c716d74fd19f9cc29da3e99797b2a78d" "checksum gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7f46fd8874e043ffac0d638ed1567a2584f7814f6d72b4db37ab1689004a26c4" "checksum glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "535c6eda58adbb227604b2db10a022ffd6339d7ea3e970f338e7d98aeb24fcc3" +"checksum glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb26027a84c3b9e1949ef0df0b6a3db8d0c124243a5c161ea25c7def90cb1474" +"checksum glutin_egl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "23f48987ab6cb2b61ad903b59e54a2fd0c380a7baff68cffd6826b69a73dd326" +"checksum glutin_emscripten_sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "245b3fdb08df6ffed7585365851f8404af9c7e2dd4b59f15262e968b6a95a0c7" +"checksum glutin_gles2_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89996c30857ae1b4de4b5189abf1ea822a20a9fe9e1c93e5e7b862ff0bdd5cdf" +"checksum glutin_glx_sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1290a5ca5e46fcfa7f66f949cc9d9194b2cb6f2ed61892c8c2b82343631dba57" +"checksum glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f801bbc91efc22dd1c4818a47814fc72bf74d024510451b119381579bfa39021" +"checksum half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9353c2a89d550b58fa0061d8ed8d002a7d8cdf2494eb0e432859bd3a9e543836" "checksum harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46f7426266a5ece3e49eae6f48e602c0f8c39917354a847eac9c06437dcde8da" "checksum harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1042ab0b3e7bc1ff64f7f5935778b644ff2194a1cae5ec52167127d3fd23961" +"checksum harfbuzz_rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "534c8e9b15d8db6e69654b07dad955f4132757194e7d2bba620d38cf08996088" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" +"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a" "checksum image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "293e54ce142a936a39da748ba8178ae6aa1914b82d846a4278f11590c89bf116" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" -"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc62c8e50e381768ce8ee0428ee53741929f7ebd73e4d83f669bcf7693e00ae" "checksum jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9f0cd42ac65f758063fea55126b0148b1ce0a6354ff78e07a4d6806bc65c4ab3" @@ -2238,6 +2662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum khronos 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c0711aaa80e6ba6eb1fa8978f1f46bfcb38ceb2f3f33f3736efbff39dac89f50" "checksum khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554" "checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +"checksum kurbo 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e6076333105a72e8d2c227ba6a6da0dc3c8e5f53f02053f598a6087a1ea8991" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" "checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" @@ -2249,25 +2674,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum lyon_geom 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0ea0ba5f8d2d91d6d895aca54d1ec0d84ddfa4826f33fbfe8abb39f08f9e4153" "checksum lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843" +"checksum lzma-rs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9550ba35a4d6bb6be7f273bce93af3a3141c517bf7d7298763a7149e1bdb9af5" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum metal 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd3f21d259068945192293b7a98b1c6844af9eb7602e393c405198b229efc157" "checksum nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e752e3c216bc8a491c5b59fa46da10f1379ae450b19ac688e07f4bb55042e98" "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" -"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d" +"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +"checksum objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc" +"checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" "checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" "checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" @@ -2296,19 +2728,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum rctree 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da0b3901505c2faa2390e27188078852eb3ed0dd9176e2153f403cdcdd18e0e7" +"checksum rctree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "193d11923532b462b7231e2d7fb785a9c0d580b03c0eccac460a1e9ee0e87fda" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" "checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -"checksum roxmltree 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "02660467d0c2da1b6276042501aee6e15ec5b8ff59423243f185b294cd53acf3" +"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum roxmltree 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "330d8f80a274bc3cb608908ee345970e7e24b96907f1ad69615a498bec57871c" "checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusttype 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "25951e85bb2647960969f72c559392245a5bd07446a589390bf427dda31cdc4a" "checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" @@ -2325,30 +2757,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" "checksum simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "135685097a85a64067df36e28a243e94a94f76d829087ce0be34eeb014260c0e" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" -"checksum skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a89e9ca99e0d6736ea1b7754517f4df14fd96a2b)" = "" +"checksum skribo 0.0.1 (git+https://github.com/linebender/skribo.git?rev=a2d683856ba1f2d0095b12dd7823d1602a87614e)" = "" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" "checksum smithay-client-toolkit 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4899558362a65589b53313935099835acf999740915e134dff20cca7c6a28b" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9b53b3ed152fc6b871f7232a8772c640567fd25d056941450637ecba32924d" -"checksum svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c43c25e6de7264024b5e351eb0c342039eb5acf51f2e9d0099bbd324b661453b" +"checksum svgdom 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ddce601e49ed213b0126ff4172cd9f5f8dba5f1df2277ecbe0e298f9865baba" +"checksum svgtypes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "444c882c28925ae0585df228a90f9951569588646ceca4753560de93cdd02258" +"checksum swf-fixed 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3c575807f18641c5e079568b53630a46baf441da57caccd9ced9a9ee70f941" +"checksum swf-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b6349830c1ed5d26b97d801e3fb8664556e12a01560e3479e3961e8f5675a05" +"checksum swf-tree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c075cea0328cc5f6ee694bcd1c43534d1186a730d79258b10735f8f08e2f1baa" "checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" "checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum ttf-parser 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29637063e570f7e5260924119666113215386c1b94e1d1ceb4525e269dfbe2d0" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" +"checksum unicode-script 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09f03ad95feb4fde244d79985bfd79eb34ff2702fedb441d2ba3f4ff813efd19" +"checksum unicode-vo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ebf4d5244ba2e8305caf9de7949377794ecdea5a9e3c84fc5610d78d21f5ee" +"checksum usvg 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3dbc9befcea2c86048398f47e0e4c98a748e6d9404eb3de564eb7048a7ec635" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" @@ -2365,8 +2805,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c57c15bd4c0ef18dff33e263e452abe32d00e2e05771cacaa410a14cc1c0776" +"checksum winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d233301129ddd33260b47f76900b50e154b7254546e2edba0e5468a1a5fe4de3" "checksum x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)" = "940586acb859ea05c53971ac231685799a7ec1dee66ac0bccc0e6ad96e06b4e3" "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5" -"checksum xmlparser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d78a7f29bb57edf63321d545d84f99360df71df36929a090bc067e1bcb65e34d" +"checksum xmlparser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ecec95f00fb0ff019153e64ea520f87d1409769db3e8f4db3ea588638a3e1cee" diff --git a/Cargo.toml b/Cargo.toml index b3a19f48..174b1bcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,23 +2,29 @@ members = [ "c", "canvas", + "content", "demo/android/rust", "demo/common", "demo/magicleap", "demo/native", + "examples/canvas_glutin_minimal", + "examples/canvas_metal_minimal", "examples/canvas_minimal", "examples/canvas_moire", "examples/canvas_text", "examples/lottie_basic", "examples/svg2pdf", + "examples/swf_basic", "geometry", "gl", "gpu", "lottie", "pdf", + "metal", "renderer", "simd", "svg", + "swf", "text", "ui", "utils/area-lut", diff --git a/c/Cargo.toml b/c/Cargo.toml index 7c17d4b2..e1c0eb0b 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -3,16 +3,23 @@ name = "pathfinder_c" version = "0.1.0" authors = ["Patrick Walton "] edition = "2018" +build = "build.rs" [lib] crate-type = ["staticlib"] [dependencies] +font-kit = "0.2" +foreign-types = "0.3" gl = "0.6" +libc = "0.2" [dependencies.pathfinder_canvas] path = "../canvas" +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" @@ -27,3 +34,12 @@ path = "../renderer" [dependencies.pathfinder_simd] path = "../simd" + +[target.'cfg(target_os = "macos")'.dependencies] +metal = "0.14" + +[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] +path = "../metal" + +[build-dependencies] +cbindgen = "0.8" diff --git a/c/build.rs b/c/build.rs new file mode 100644 index 00000000..def89d30 --- /dev/null +++ b/c/build.rs @@ -0,0 +1,20 @@ +// pathfinder/c/build.rs +// +// Copyright © 2019 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. + +use cbindgen; +use std::env; +use std::fs; + +fn main() { + fs::create_dir_all("build/include/pathfinder").expect("Failed to create directories!"); + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + cbindgen::generate(crate_dir).expect("cbindgen failed!") + .write_to_file("build/include/pathfinder/pathfinder.h"); +} diff --git a/c/cbindgen.toml b/c/cbindgen.toml new file mode 100644 index 00000000..4d096e5d --- /dev/null +++ b/c/cbindgen.toml @@ -0,0 +1,19 @@ +language = "C" +header = """\ +/* Generated code. Do not edit; instead run `cargo build` in `pathfinder_c`. */ + +extern \"C\" { +""" +trailer = "}" +include_guard = "PF_PATHFINDER_H" +include_version = true + +[parse] +parse_deps = true +include = [ + "pathfinder_canvas", + "pathfinder_content", + "pathfinder_geometry", + "pathfinder_gl", + "pathfinder_renderer", +] diff --git a/c/include/pathfinder/pathfinder.h b/c/include/pathfinder/pathfinder.h deleted file mode 100644 index 8962e782..00000000 --- a/c/include/pathfinder/pathfinder.h +++ /dev/null @@ -1,171 +0,0 @@ -// pathfinder/c/include/pathfinder/pathfinder.h -// -// Copyright © 2019 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. - -#ifndef PF_PATHFINDER_H -#define PF_PATHFINDER_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Macros - -// `canvas` - -#define PF_LINE_CAP_BUTT 0 -#define PF_LINE_CAP_SQUARE 1 -#define PF_LINE_CAP_ROUND 2 - -// `gl` - -#define PF_GL_VERSION_GL3 0 -#define PF_GL_VERSION_GLES3 1 - -// `gpu` - -#define PF_CLEAR_FLAGS_HAS_COLOR 0x1 -#define PF_CLEAR_FLAGS_HAS_DEPTH 0x2 -#define PF_CLEAR_FLAGS_HAS_STENCIL 0x4 -#define PF_CLEAR_FLAGS_HAS_RECT 0x8 - -// Types - -// `canvas` - -struct PFCanvas; -typedef struct PFCanvas *PFCanvasRef; -struct PFPath; -typedef struct PFPath *PFPathRef; -struct PFCanvasFontContext; -typedef struct PFCanvasFontContext *PFCanvasFontContextRef; -typedef uint8_t PFLineCap; - -// `geometry` - -struct PFColorF { - float r, g, b, a; -}; -typedef struct PFColorF PFColorF; -struct PFVector2F { - float x, y; -}; -typedef struct PFVector2F PFVector2F; -struct PFVector2I { - int32_t x, y; -}; -typedef struct PFVector2I PFVector2I; -struct PFRectF { - PFVector2F origin, lower_right; -}; -typedef struct PFRectF PFRectF; -struct PFRectI { - PFVector2I origin, lower_right; -}; -typedef struct PFRectI PFRectI; - -// `gl` - -struct PFGLDevice; -typedef struct PFGLDevice *PFGLDeviceRef; -struct PFGLDestFramebuffer; -typedef struct PFGLDestFramebuffer *PFGLDestFramebufferRef; -typedef const void *(*PFGLFunctionLoader)(const char *data, void *userdata); -struct PFGLRenderer; -typedef struct PFGLRenderer *PFGLRendererRef; -typedef uint32_t PFGLVersion; - -// `gpu` - -typedef uint8_t PFClearFlags; -struct PFClearParams { - PFColorF color; - float depth; - uint8_t stencil; - PFRectI rect; - PFClearFlags flags; -}; -typedef struct PFClearParams PFClearParams; -struct PFResourceLoader; -typedef struct PFResourceLoader *PFResourceLoaderRef; - -// `renderer` - -struct PFRenderOptions { - uint32_t placeholder; -}; -typedef struct PFRenderOptions PFRenderOptions; -struct PFScene; -typedef struct PFScene *PFSceneRef; -struct PFSceneProxy; -typedef struct PFSceneProxy *PFSceneProxyRef; - -// Functions - -// `canvas` - -PFCanvasRef PFCanvasCreate(PFCanvasFontContextRef font_context, const PFVector2F *size); -void PFCanvasDestroy(PFCanvasRef canvas); -PFCanvasFontContextRef PFCanvasFontContextCreate(); -void PFCanvasFontContextDestroy(PFCanvasFontContextRef font_context); -PFCanvasFontContextRef PFCanvasFontContextClone(PFCanvasFontContextRef font_context); -PFSceneRef PFCanvasCreateScene(PFCanvasRef canvas); -void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect); -void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect); -void PFCanvasSetLineWidth(PFCanvasRef canvas, float new_line_width); -void PFCanvasSetLineCap(PFCanvasRef canvas, PFLineCap new_line_cap); -void PFCanvasFillPath(PFCanvasRef canvas, PFPathRef path); -void PFCanvasStrokePath(PFCanvasRef canvas, PFPathRef path); -PFPathRef PFPathCreate(); -void PFPathDestroy(PFPathRef path); -PFPathRef PFPathClone(PFPathRef path); -void PFPathMoveTo(PFPathRef path, const PFVector2F *to); -void PFPathLineTo(PFPathRef path, const PFVector2F *to); -void PFPathQuadraticCurveTo(PFPathRef path, const PFVector2F *ctrl, const PFVector2F *to); -void PFPathBezierCurveTo(PFPathRef path, - const PFVector2F *ctrl0, - const PFVector2F *ctrl1, - const PFVector2F *to); -void PFPathClosePath(PFPathRef path); - -// `gl` - -PFGLDestFramebufferRef PFGLDestFramebufferCreateFullWindow(const PFVector2I *window_size); -void PFGLDestFramebufferDestroy(PFGLDestFramebufferRef dest_framebuffer); -PFGLDeviceRef PFGLDeviceCreate(PFGLVersion version, uint32_t default_framebuffer); -void PFGLDeviceDestroy(PFGLDeviceRef device); -void PFGLDeviceClear(PFGLDeviceRef device, const PFClearParams *params); -void PFGLLoadWith(PFGLFunctionLoader loader, void *userdata); -PFGLRendererRef PFGLRendererCreate(PFGLDeviceRef device, - PFResourceLoaderRef resources, - PFGLDestFramebufferRef dest_framebuffer); -void PFGLRendererDestroy(PFGLRendererRef renderer); -/// Returns a borrowed reference to the device. -PFGLDeviceRef PFGLRendererGetDevice(PFGLRendererRef renderer); -void PFSceneProxyBuildAndRenderGL(PFSceneProxyRef scene_proxy, - PFGLRendererRef renderer, - const PFRenderOptions *options); - -// `gpu` - -PFResourceLoaderRef PFFilesystemResourceLoaderLocate(); -void PFResourceLoaderDestroy(PFResourceLoaderRef loader); - -// `renderer` - -PFSceneProxyRef PFSceneProxyCreateFromSceneAndRayonExecutor(PFSceneRef scene); -void PFSceneProxyDestroy(PFSceneProxyRef scene_proxy); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/c/src/lib.rs b/c/src/lib.rs index f3ec9c71..6b6235c1 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -10,42 +10,89 @@ //! C bindings to Pathfinder. +use font_kit::handle::Handle; +use foreign_types::ForeignTypeRef; use gl; -use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::{RectF, RectI}; -use pathfinder_geometry::color::ColorF; -use pathfinder_geometry::stroke::LineCap; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin}; +use pathfinder_canvas::{Path2D, TextMetrics}; +use pathfinder_content::color::{ColorF, ColorU}; +use pathfinder_content::outline::ArcDirection; +use pathfinder_content::stroke::LineCap; +use pathfinder_geometry::rect::{RectF, RectI}; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use pathfinder_renderer::scene::Scene; use pathfinder_simd::default::F32x4; use std::ffi::CString; use std::os::raw::{c_char, c_void}; +use std::slice; +use std::str; + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use metal::{CAMetalLayer, CoreAnimationLayerRef}; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice; // Constants +// `canvas` + pub const PF_LINE_CAP_BUTT: u8 = 0; pub const PF_LINE_CAP_SQUARE: u8 = 1; pub const PF_LINE_CAP_ROUND: u8 = 2; -pub const PF_CLEAR_FLAGS_HAS_COLOR: u8 = 0x1; -pub const PF_CLEAR_FLAGS_HAS_DEPTH: u8 = 0x2; -pub const PF_CLEAR_FLAGS_HAS_STENCIL: u8 = 0x4; -pub const PF_CLEAR_FLAGS_HAS_RECT: u8 = 0x8; +pub const PF_LINE_JOIN_MITER: u8 = 0; +pub const PF_LINE_JOIN_BEVEL: u8 = 1; +pub const PF_LINE_JOIN_ROUND: u8 = 2; + +// `content` + +pub const PF_ARC_DIRECTION_CW: u8 = 0; +pub const PF_ARC_DIRECTION_CCW: u8 = 1; + +// `renderer` + +pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1; // Types +// External: `font-kit` +pub type FKHandleRef = *mut Handle; + // `canvas` pub type PFCanvasRef = *mut CanvasRenderingContext2D; pub type PFPathRef = *mut Path2D; pub type PFCanvasFontContextRef = *mut CanvasFontContext; +pub type PFFillStyleRef = *mut FillStyle; pub type PFLineCap = u8; +pub type PFLineJoin = u8; +pub type PFArcDirection = u8; +#[repr(C)] +pub struct PFTextMetrics { + pub width: f32, +} + +// `content` +#[repr(C)] +pub struct PFColorF { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} +#[repr(C)] +pub struct PFColorU { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} // `geometry` #[repr(C)] @@ -68,13 +115,6 @@ pub struct PFRectI { pub origin: PFVector2I, pub lower_right: PFVector2I, } -#[repr(C)] -pub struct PFColorF { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, -} // `gl` pub type PFGLDeviceRef = *mut GLDevice; @@ -84,25 +124,30 @@ pub type PFGLFunctionLoader = extern "C" fn(name: *const c_char, userdata: *mut // `gpu` pub type PFGLDestFramebufferRef = *mut DestFramebuffer; pub type PFGLRendererRef = *mut Renderer; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +pub type PFMetalDestFramebufferRef = *mut DestFramebuffer; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +pub type PFMetalRendererRef = *mut Renderer; // FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is // stable? pub type PFResourceLoaderRef = *mut Box; -#[repr(C)] -pub struct PFClearParams { - pub color: PFColorF, - pub depth: f32, - pub stencil: u8, - pub rect: PFRectI, - pub flags: PFClearFlags, -} -pub type PFClearFlags = u8; + +// `metal` +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +pub type PFMetalDeviceRef = *mut MetalDevice; // `renderer` pub type PFSceneRef = *mut Scene; pub type PFSceneProxyRef = *mut SceneProxy; +#[repr(C)] +pub struct PFRendererOptions { + pub background_color: PFColorF, + pub flags: PFRendererOptionsFlags, +} +pub type PFRendererOptionsFlags = u8; // TODO(pcwalton) #[repr(C)] -pub struct PFRenderOptions { +pub struct PFBuildOptions { pub placeholder: u32, } @@ -123,8 +168,18 @@ pub unsafe extern "C" fn PFCanvasDestroy(canvas: PFCanvasRef) { } #[no_mangle] -pub unsafe extern "C" fn PFCanvasFontContextCreate() -> PFCanvasFontContextRef { - Box::into_raw(Box::new(CanvasFontContext::new())) +pub unsafe extern "C" fn PFCanvasFontContextCreateWithSystemSource() -> PFCanvasFontContextRef { + Box::into_raw(Box::new(CanvasFontContext::from_system_source())) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasFontContextCreateWithFonts(fonts: *const FKHandleRef, + font_count: usize) + -> PFCanvasFontContextRef { + let fonts = slice::from_raw_parts(fonts, font_count); + Box::into_raw(Box::new(CanvasFontContext::from_fonts(fonts.into_iter().map(|font| { + (**font).clone() + })))) } #[no_mangle] @@ -144,6 +199,8 @@ pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef Box::into_raw(Box::new(Box::from_raw(canvas).into_scene())) } +// Drawing rectangles + #[no_mangle] pub unsafe extern "C" fn PFCanvasFillRect(canvas: PFCanvasRef, rect: *const PFRectF) { (*canvas).fill_rect((*rect).to_rust()) @@ -154,6 +211,33 @@ pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PF (*canvas).stroke_rect((*rect).to_rust()) } +// Drawing text + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasFillText(canvas: PFCanvasRef, + string: *const c_char, + string_len: usize, + position: *const PFVector2F) { + (*canvas).fill_text(to_rust_string(&string, string_len), (*position).to_rust()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasStrokeText(canvas: PFCanvasRef, + string: *const c_char, + string_len: usize, + position: *const PFVector2F) { + (*canvas).stroke_text(to_rust_string(&string, string_len), (*position).to_rust()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasMeasureText(canvas: PFCanvasRef, + string: *const c_char, + string_len: usize, + out_text_metrics: *mut PFTextMetrics) { + debug_assert!(!out_text_metrics.is_null()); + *out_text_metrics = (*canvas).measure_text(to_rust_string(&string, string_len)).to_c() +} + #[no_mangle] pub unsafe extern "C" fn PFCanvasSetLineWidth(canvas: PFCanvasRef, new_line_width: f32) { (*canvas).set_line_width(new_line_width) @@ -168,6 +252,55 @@ pub unsafe extern "C" fn PFCanvasSetLineCap(canvas: PFCanvasRef, new_line_cap: P }); } +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineJoin(canvas: PFCanvasRef, new_line_join: PFLineJoin) { + (*canvas).set_line_join(match new_line_join { + PF_LINE_JOIN_BEVEL => LineJoin::Bevel, + PF_LINE_JOIN_ROUND => LineJoin::Round, + _ => LineJoin::Miter, + }); +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetMiterLimit(canvas: PFCanvasRef, new_miter_limit: f32) { + (*canvas).set_miter_limit(new_miter_limit); +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineDash(canvas: PFCanvasRef, + new_line_dashes: *const f32, + new_line_dash_count: usize) { + (*canvas).set_line_dash(slice::from_raw_parts(new_line_dashes, new_line_dash_count).to_vec()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offset: f32) { + (*canvas).set_line_dash_offset(new_offset) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef, + postscript_name: *const c_char, + postscript_name_len: usize) { + (*canvas).set_font_by_postscript_name(to_rust_string(&postscript_name, postscript_name_len)) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetFontSize(canvas: PFCanvasRef, new_font_size: f32) { + (*canvas).set_font_size(new_font_size) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetFillStyle(canvas: PFCanvasRef, fill_style: PFFillStyleRef) { + (*canvas).set_fill_style(*fill_style) +} + +#[no_mangle] +pub unsafe extern "C" fn PFCanvasSetStrokeStyle(canvas: PFCanvasRef, + stroke_style: PFFillStyleRef) { + (*canvas).set_stroke_style(*stroke_style) +} + /// Consumes the path. #[no_mangle] pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) { @@ -220,11 +353,55 @@ pub unsafe extern "C" fn PFPathBezierCurveTo(path: PFPathRef, (*path).bezier_curve_to((*ctrl0).to_rust(), (*ctrl1).to_rust(), (*to).to_rust()) } +#[no_mangle] +pub unsafe extern "C" fn PFPathArc(path: PFPathRef, + center: *const PFVector2F, + radius: f32, + start_angle: f32, + end_angle: f32, + direction: PFArcDirection) { + let direction = if direction == 0 { ArcDirection::CW } else { ArcDirection::CCW }; + (*path).arc((*center).to_rust(), radius, start_angle, end_angle, direction) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathArcTo(path: PFPathRef, + ctrl: *const PFVector2F, + to: *const PFVector2F, + radius: f32) { + (*path).arc_to((*ctrl).to_rust(), (*to).to_rust(), radius) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathRect(path: PFPathRef, rect: *const PFRectF) { + (*path).rect((*rect).to_rust()) +} + +#[no_mangle] +pub unsafe extern "C" fn PFPathEllipse(path: PFPathRef, + center: *const PFVector2F, + axes: *const PFVector2F, + rotation: f32, + start_angle: f32, + end_angle: f32) { + (*path).ellipse((*center).to_rust(), (*axes).to_rust(), rotation, start_angle, end_angle) +} + #[no_mangle] pub unsafe extern "C" fn PFPathClosePath(path: PFPathRef) { (*path).close_path() } +#[no_mangle] +pub unsafe extern "C" fn PFFillStyleCreateColor(color: *const PFColorU) -> PFFillStyleRef { + Box::into_raw(Box::new(FillStyle::Color((*color).to_rust()))) +} + +#[no_mangle] +pub unsafe extern "C" fn PFFillStyleDestroy(fill_style: PFFillStyleRef) { + drop(Box::from_raw(fill_style)) +} + // `gl` #[no_mangle] @@ -252,11 +429,6 @@ pub unsafe extern "C" fn PFGLDeviceDestroy(device: PFGLDeviceRef) { drop(Box::from_raw(device)) } -#[no_mangle] -pub unsafe extern "C" fn PFGLDeviceClear(device: PFGLDeviceRef, params: *const PFClearParams) { - (*device).clear(&(*params).to_rust()) -} - #[no_mangle] pub unsafe extern "C" fn PFResourceLoaderDestroy(loader: PFResourceLoaderRef) { drop(Box::from_raw(loader)) @@ -279,11 +451,13 @@ pub unsafe extern "C" fn PFGLDestFramebufferDestroy(dest_framebuffer: PFGLDestFr #[no_mangle] pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef, resources: PFResourceLoaderRef, - dest_framebuffer: PFGLDestFramebufferRef) + dest_framebuffer: PFGLDestFramebufferRef, + options: *const PFRendererOptions) -> PFGLRendererRef { Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device), &**resources, - *Box::from_raw(dest_framebuffer)))) + *Box::from_raw(dest_framebuffer), + (*options).to_rust()))) } #[no_mangle] @@ -296,11 +470,74 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG &mut (*renderer).device } +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I) + -> PFMetalDestFramebufferRef { + Box::into_raw(Box::new(DestFramebuffer::full_window((*window_size).to_rust()))) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalDestFramebufferDestroy(dest_framebuffer: + PFMetalDestFramebufferRef) { + drop(Box::from_raw(dest_framebuffer)) +} + +/// Takes ownership of `device` and `dest_framebuffer`, but not `resources`. +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef, + resources: PFResourceLoaderRef, + dest_framebuffer: PFMetalDestFramebufferRef, + options: *const PFRendererOptions) + -> PFMetalRendererRef { + Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device), + &**resources, + *Box::from_raw(dest_framebuffer), + (*options).to_rust()))) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalRendererDestroy(renderer: PFMetalRendererRef) { + drop(Box::from_raw(renderer)) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalRendererGetDevice(renderer: PFMetalRendererRef) -> PFMetalDeviceRef { + &mut (*renderer).device +} + #[no_mangle] pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef, renderer: PFGLRendererRef, - options: *const PFRenderOptions) { - (*scene_proxy).build_and_render(&mut *renderer, (*options).to_rust()) + build_options: *const PFBuildOptions) { + (*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust()) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFSceneProxyBuildAndRenderMetal(scene_proxy: PFSceneProxyRef, + renderer: PFMetalRendererRef, + build_options: *const PFBuildOptions) { + (*scene_proxy).build_and_render(&mut *renderer, (*build_options).to_rust()) +} + +// `metal` + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalDeviceCreate(layer: *mut CAMetalLayer) + -> PFMetalDeviceRef { + Box::into_raw(Box::new(MetalDevice::new(CoreAnimationLayerRef::from_ptr(layer)))) +} + +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +#[no_mangle] +pub unsafe extern "C" fn PFMetalDeviceDestroy(device: PFMetalDeviceRef) { + drop(Box::from_raw(device)) } // `renderer` @@ -321,7 +558,26 @@ pub unsafe extern "C" fn PFSceneProxyDestroy(scene_proxy: PFSceneProxyRef) { drop(Box::from_raw(scene_proxy)) } -// Helpers for `geometry` +// Helpers for `canvas` + +unsafe fn to_rust_string(ptr: &*const c_char, mut len: usize) -> &str { + if len == 0 { + len = libc::strlen(*ptr); + } + str::from_utf8(slice::from_raw_parts(*ptr as *const u8, len)).unwrap() +} + +trait TextMetricsExt { + fn to_c(&self) -> PFTextMetrics; +} + +impl TextMetricsExt for TextMetrics { + fn to_c(&self) -> PFTextMetrics { + PFTextMetrics { width: self.width } + } +} + +// Helpers for `content` impl PFColorF { #[inline] @@ -330,6 +586,15 @@ impl PFColorF { } } +impl PFColorU { + #[inline] + pub fn to_rust(&self) -> ColorU { + ColorU { r: self.r, g: self.g, b: self.b, a: self.a } + } +} + +// Helpers for `geometry` + impl PFRectF { #[inline] pub fn to_rust(&self) -> RectF { @@ -358,28 +623,14 @@ impl PFVector2I { } } -// Helpers for `gpu` +// Helpers for `renderer` -impl PFClearParams { - pub fn to_rust(&self) -> ClearParams { - ClearParams { - color: if (self.flags & PF_CLEAR_FLAGS_HAS_COLOR) != 0 { - Some(self.color.to_rust()) - } else { - None - }, - rect: if (self.flags & PF_CLEAR_FLAGS_HAS_RECT) != 0 { - Some(self.rect.to_rust()) - } else { - None - }, - depth: if (self.flags & PF_CLEAR_FLAGS_HAS_DEPTH) != 0 { - Some(self.depth) - } else { - None - }, - stencil: if (self.flags & PF_CLEAR_FLAGS_HAS_STENCIL) != 0 { - Some(self.stencil) +impl PFRendererOptions { + pub fn to_rust(&self) -> RendererOptions { + let has_background_color = self.flags & PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR; + RendererOptions { + background_color: if has_background_color != 0 { + Some(self.background_color.to_rust()) } else { None }, @@ -387,10 +638,8 @@ impl PFClearParams { } } -// Helpers for `renderer` - -impl PFRenderOptions { - pub fn to_rust(&self) -> RenderOptions { - RenderOptions::default() +impl PFBuildOptions { + pub fn to_rust(&self) -> BuildOptions { + BuildOptions::default() } } diff --git a/canvas/Cargo.toml b/canvas/Cargo.toml index d93ac0cf..fb4f8037 100644 --- a/canvas/Cargo.toml +++ b/canvas/Cargo.toml @@ -8,7 +8,10 @@ edition = "2018" crate-type = ["rlib", "staticlib"] [dependencies] -font-kit = "0.1" +font-kit = "0.2" + +[dependencies.pathfinder_content] +path = "../content" [dependencies.pathfinder_geometry] path = "../geometry" @@ -21,4 +24,4 @@ path = "../text" [dependencies.skribo] git = "https://github.com/linebender/skribo.git" -rev = "a89e9ca99e0d6736ea1b7754517f4df14fd96a2b" +rev = "a2d683856ba1f2d0095b12dd7823d1602a87614e" diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index b31fa1c0..581ca48a 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -11,24 +11,28 @@ //! A simple API for Pathfinder that mirrors a subset of HTML canvas. use font_kit::family_name::FamilyName; +use font_kit::handle::Handle; use font_kit::hinting::HintingOptions; +use font_kit::loaders::default::Font; use font_kit::properties::Properties; -use font_kit::source::SystemSource; -use pathfinder_geometry::basic::line_segment::LineSegment2F; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::color::ColorU; -use pathfinder_geometry::dash::OutlineDash; -use pathfinder_geometry::outline::{ArcDirection, Contour, Outline}; -use pathfinder_geometry::stroke::{LineCap, LineJoin as StrokeLineJoin}; -use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle}; +use font_kit::source::{Source, SystemSource}; +use font_kit::sources::mem::MemSource; +use pathfinder_content::color::ColorU; +use pathfinder_content::dash::OutlineDash; +use pathfinder_content::outline::{ArcDirection, Contour, Outline}; +use pathfinder_content::stroke::{LineCap, LineJoin as StrokeLineJoin}; +use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; use pathfinder_renderer::paint::{Paint, PaintId}; use pathfinder_renderer::scene::{PathObject, Scene}; use pathfinder_text::{SceneExt, TextRenderMode}; use skribo::{FontCollection, FontFamily, Layout, TextStyle}; use std::default::Default; use std::f32::consts::PI; +use std::iter; use std::mem; use std::sync::Arc; @@ -170,6 +174,40 @@ impl CanvasRenderingContext2D { // Text styles + #[inline] + pub fn set_font_collection(&mut self, font_collection: Arc) { + self.current_state.font_collection = font_collection; + } + + #[inline] + pub fn set_font_families(&mut self, font_families: I) where I: Iterator { + let mut font_collection = FontCollection::new(); + for font_family in font_families { + font_collection.add_family(font_family); + } + self.current_state.font_collection = Arc::new(font_collection); + } + + /// A convenience method to set a single font family. + #[inline] + pub fn set_font_family(&mut self, font_family: FontFamily) { + self.set_font_families(iter::once(font_family)) + } + + /// A convenience method to set a single font family consisting of a single font. + #[inline] + pub fn set_font(&mut self, font: Font) { + self.set_font_family(FontFamily::new_from_font(font)) + } + + /// A convenience method to set a single font family consisting of a font + /// described by a PostScript name. + #[inline] + pub fn set_font_by_postscript_name(&mut self, postscript_name: &str) { + let font = self.font_context.font_source.select_by_postscript_name(postscript_name); + self.set_font(font.expect("Didn't find the font!").load().unwrap()); + } + #[inline] pub fn set_font_size(&mut self, new_font_size: f32) { self.current_state.font_size = new_font_size; @@ -488,7 +526,7 @@ pub enum TextAlign { Center, } -// We duplicate `pathfinder_geometry::stroke::LineJoin` here because the HTML canvas API treats the +// We duplicate `pathfinder_content::stroke::LineJoin` here because the HTML canvas API treats the // miter limit as part of the canvas state, while the native Pathfinder API treats the miter limit // as part of the line join. Pathfinder's choice is more logical, because the miter limit is // specific to miter joins. In this API, however, for compatibility we go with the HTML canvas @@ -509,29 +547,37 @@ pub struct TextMetrics { #[derive(Clone)] pub struct CanvasFontContext { #[allow(dead_code)] - font_source: Arc, + font_source: Arc, #[allow(dead_code)] default_font_collection: Arc, } impl CanvasFontContext { - pub fn new() -> CanvasFontContext { - let font_source = Arc::new(SystemSource::new()); - + pub fn new(font_source: Arc) -> CanvasFontContext { let mut default_font_collection = FontCollection::new(); - let default_font = - font_source.select_best_match(&[FamilyName::SansSerif], &Properties::new()) - .expect("Failed to select the default font!") - .load() - .expect("Failed to load the default font!"); - default_font_collection.add_family(FontFamily::new_from_font(default_font)); - let default_font_collection = Arc::new(default_font_collection); + if let Ok(default_font) = font_source.select_best_match(&[FamilyName::SansSerif], + &Properties::new()) { + if let Ok(default_font) = default_font.load() { + default_font_collection.add_family(FontFamily::new_from_font(default_font)); + } + } CanvasFontContext { font_source, - default_font_collection, + default_font_collection: Arc::new(default_font_collection), } } + + /// A convenience method to create a font context with the system source. + /// This allows usage of fonts installed on the system. + pub fn from_system_source() -> CanvasFontContext { + CanvasFontContext::new(Arc::new(SystemSource::new())) + } + + /// A convenience method to create a font context with a set of in-memory fonts. + pub fn from_fonts(fonts: I) -> CanvasFontContext where I: Iterator { + CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap())) + } } // Text layout utilities diff --git a/content/Cargo.toml b/content/Cargo.toml new file mode 100644 index 00000000..cdd7b473 --- /dev/null +++ b/content/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "pathfinder_content" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +arrayvec = "0.4" +bitflags = "1.0" +log = "0.4" +smallvec = "0.6" + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_simd] +path = "../simd" diff --git a/geometry/src/clip.rs b/content/src/clip.rs similarity index 98% rename from geometry/src/clip.rs rename to content/src/clip.rs index 4569a68d..b4620ba5 100644 --- a/geometry/src/clip.rs +++ b/content/src/clip.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/clip.rs +// pathfinder/content/src/clip.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::{Vector2F, Vector4F}; -use crate::basic::rect::RectF; use crate::outline::{Contour, PointFlags, PushSegmentFlags}; use crate::segment::{CubicSegment, Segment}; -use crate::util::lerp; use arrayvec::ArrayVec; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::util::lerp; +use pathfinder_geometry::vector::{Vector2F, Vector4F}; use smallvec::SmallVec; use std::fmt::Debug; use std::mem; diff --git a/geometry/src/color.rs b/content/src/color.rs similarity index 85% rename from geometry/src/color.rs rename to content/src/color.rs index cde14be6..5f3676be 100644 --- a/geometry/src/color.rs +++ b/content/src/color.rs @@ -75,13 +75,18 @@ impl Debug for ColorU { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct ColorF(pub F32x4); impl ColorF { + #[inline] + pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF { + ColorF(F32x4::new(r, g, b, a)) + } + #[inline] pub fn transparent_black() -> ColorF { - ColorF(F32x4::default()) + ColorF::default() } #[inline] @@ -120,3 +125,16 @@ impl ColorF { self.0[3] } } + +impl Debug for ColorF { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + write!( + formatter, + "rgba({}, {}, {}, {})", + self.r() * 255.0, + self.g() * 255.0, + self.b() * 255.0, + self.a() + ) + } +} diff --git a/geometry/src/dash.rs b/content/src/dash.rs similarity index 100% rename from geometry/src/dash.rs rename to content/src/dash.rs diff --git a/geometry/src/dilation.rs b/content/src/dilation.rs similarity index 98% rename from geometry/src/dilation.rs rename to content/src/dilation.rs index 4441c90b..40a1c729 100644 --- a/geometry/src/dilation.rs +++ b/content/src/dilation.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/dilation.rs +// pathfinder/content/src/dilation.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::basic::vector::Vector2F; use crate::orientation::Orientation; use crate::outline::Contour; +use pathfinder_geometry::vector::Vector2F; pub struct ContourDilator<'a> { contour: &'a mut Contour, diff --git a/geometry/src/basic/mod.rs b/content/src/lib.rs similarity index 50% rename from geometry/src/basic/mod.rs rename to content/src/lib.rs index d77c1fc0..00abb4d1 100644 --- a/geometry/src/basic/mod.rs +++ b/content/src/lib.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/basic/mod.rs +// pathfinder/content/src/lib.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -8,10 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Basic geometry and linear algebra primitives, optimized with SIMD. +//! Pathfinder's representation of a vector scene. +//! +//! This module also contains various path utilities. -pub mod line_segment; -pub mod rect; -pub mod transform2d; -pub mod transform3d; -pub mod vector; +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate log; + +pub mod clip; +pub mod color; +pub mod dash; +pub mod orientation; +pub mod outline; +pub mod segment; +pub mod stroke; +pub mod transform; + +mod dilation; diff --git a/geometry/src/orientation.rs b/content/src/orientation.rs similarity index 100% rename from geometry/src/orientation.rs rename to content/src/orientation.rs diff --git a/geometry/src/outline.rs b/content/src/outline.rs similarity index 98% rename from geometry/src/outline.rs rename to content/src/outline.rs index 5858941c..b09cc668 100644 --- a/geometry/src/outline.rs +++ b/content/src/outline.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/outline.rs +// pathfinder/content/src/outline.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -10,16 +10,16 @@ //! A compressed in-memory representation of paths. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::Vector2F; -use crate::basic::rect::RectF; -use crate::basic::transform2d::Transform2DF; -use crate::basic::transform3d::Perspective; use crate::clip::{self, ContourPolygonClipper, ContourRectClipper}; use crate::dilation::ContourDilator; use crate::orientation::Orientation; use crate::segment::{Segment, SegmentFlags, SegmentKind}; -use crate::unit_vector::UnitVector; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::Perspective; +use pathfinder_geometry::unit_vector::UnitVector; +use pathfinder_geometry::vector::Vector2F; use std::f32::consts::PI; use std::fmt::{self, Debug, Formatter}; use std::mem; diff --git a/geometry/src/segment.rs b/content/src/segment.rs similarity index 98% rename from geometry/src/segment.rs rename to content/src/segment.rs index 2cd8adf4..4a9d6a76 100644 --- a/geometry/src/segment.rs +++ b/content/src/segment.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/segment.rs +// pathfinder/content/src/segment.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -10,10 +10,10 @@ //! Line or curve segments, optimized with SIMD. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::Vector2F; -use crate::basic::transform2d::Transform2DF; -use crate::util::{self, EPSILON}; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::util::{self, EPSILON}; +use pathfinder_geometry::vector::Vector2F; use pathfinder_simd::default::F32x4; use std::f32::consts::SQRT_2; diff --git a/geometry/src/stroke.rs b/content/src/stroke.rs similarity index 98% rename from geometry/src/stroke.rs rename to content/src/stroke.rs index 4e9a195a..48f68276 100644 --- a/geometry/src/stroke.rs +++ b/content/src/stroke.rs @@ -1,4 +1,4 @@ -// pathfinder/geometry/src/stroke.rs +// pathfinder/content/src/stroke.rs // // Copyright © 2019 The Pathfinder Project Developers. // @@ -10,12 +10,12 @@ //! Utilities for converting path strokes to fills. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::Vector2F; -use crate::basic::rect::RectF; -use crate::basic::transform2d::Transform2DF; use crate::outline::{ArcDirection, Contour, Outline, PushSegmentFlags}; use crate::segment::Segment; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::vector::Vector2F; use std::f32; const TOLERANCE: f32 = 0.01; diff --git a/content/src/transform.rs b/content/src/transform.rs new file mode 100644 index 00000000..283b4386 --- /dev/null +++ b/content/src/transform.rs @@ -0,0 +1,124 @@ +// pathfinder/content/src/transform.rs +// +// Copyright © 2019 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. + +//! Utilities for transforming paths. + +use crate::segment::Segment; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::Perspective; + +/// Transforms a path with a SIMD 2D transform. +pub struct Transform2DFPathIter +where + I: Iterator, +{ + iter: I, + transform: Transform2DF, +} + +impl Iterator for Transform2DFPathIter +where + I: Iterator, +{ + type Item = Segment; + + #[inline] + fn next(&mut self) -> Option { + // TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD? + let mut segment = self.iter.next()?; + if !segment.is_none() { + segment + .baseline + .set_from(&self.transform.transform_point(segment.baseline.from())); + segment + .baseline + .set_to(&self.transform.transform_point(segment.baseline.to())); + if !segment.is_line() { + segment + .ctrl + .set_from(&self.transform.transform_point(segment.ctrl.from())); + if !segment.is_quadratic() { + segment + .ctrl + .set_to(&self.transform.transform_point(segment.ctrl.to())); + } + } + } + Some(segment) + } +} + +impl Transform2DFPathIter +where + I: Iterator, +{ + #[inline] + pub fn new(iter: I, transform: &Transform2DF) -> Transform2DFPathIter { + Transform2DFPathIter { + iter, + transform: *transform, + } + } +} + +/// Transforms a path with a perspective projection. +pub struct PerspectivePathIter +where + I: Iterator, +{ + iter: I, + perspective: Perspective, +} + +impl Iterator for PerspectivePathIter +where + I: Iterator, +{ + type Item = Segment; + + #[inline] + fn next(&mut self) -> Option { + let mut segment = self.iter.next()?; + if !segment.is_none() { + segment.baseline.set_from( + &self + .perspective + .transform_point_2d(&segment.baseline.from()), + ); + segment + .baseline + .set_to(&self.perspective.transform_point_2d(&segment.baseline.to())); + if !segment.is_line() { + segment + .ctrl + .set_from(&self.perspective.transform_point_2d(&segment.ctrl.from())); + if !segment.is_quadratic() { + segment + .ctrl + .set_to(&self.perspective.transform_point_2d(&segment.ctrl.to())); + } + } + } + Some(segment) + } +} + +impl PerspectivePathIter +where + I: Iterator, +{ + #[inline] + pub fn new(iter: I, perspective: &Perspective) -> PerspectivePathIter { + PerspectivePathIter { + iter, + perspective: *perspective, + } + } +} diff --git a/demo/android/rust/src/lib.rs b/demo/android/rust/src/lib.rs index 6e322418..4fdf1fa7 100644 --- a/demo/android/rust/src/lib.rs +++ b/demo/android/rust/src/lib.rs @@ -16,8 +16,8 @@ use jni::{JNIEnv, JavaVM}; use pathfinder_demo::window::{Event, SVGPath, View, Window, WindowSize}; use pathfinder_demo::DemoApp; use pathfinder_demo::Options; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::ResourceLoader; use std::cell::RefCell; diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index 95cb3976..b6aa30e5 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -4,11 +4,14 @@ version = "0.1.0" edition = "2018" authors = ["Patrick Walton "] +[features] +pf-gl = [] + [dependencies] clap = "2.32" gl = "0.6" rayon = "1.0" -usvg = "0.4" +usvg = "0.7" [dependencies.image] version = "0.21" @@ -19,6 +22,9 @@ features = ["png_codec"] version = "0.4" features = ["release_max_level_warn"] +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" @@ -39,3 +45,9 @@ path = "../../svg" [dependencies.pathfinder_ui] path = "../../ui" + +[target.'cfg(target_os = "macos")'.dependencies] +metal = "0.14" + +[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] +path = "../../metal" diff --git a/demo/common/src/camera.rs b/demo/common/src/camera.rs index f8dc6445..eea0649e 100644 --- a/demo/common/src/camera.rs +++ b/demo/common/src/camera.rs @@ -14,10 +14,10 @@ // proper. use crate::window::{OcularTransform, View}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I, Vector4F}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF}; +use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F}; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::{Perspective, Transform3DF}; use std::f32::consts::FRAC_PI_4; const NEAR_CLIP_PLANE: f32 = 0.01; diff --git a/demo/common/src/device.rs b/demo/common/src/device.rs index 29b27540..1417bb0b 100644 --- a/demo/common/src/device.rs +++ b/demo/common/src/device.rs @@ -63,20 +63,19 @@ where ) -> GroundVertexArray { let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&ground_program.program, "Position"); + let position_attr = device.get_vertex_attr(&ground_program.program, "Position").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&ground_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); GroundVertexArray { vertex_array } } diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 2121a93d..e97231b2 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -22,17 +22,17 @@ use crate::device::{GroundProgram, GroundVertexArray}; use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction}; use crate::window::{Event, Keycode, SVGPath, Window, WindowSize}; use clap::{App, Arg}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_geometry::color::ColorU; -use pathfinder_gl::GLDevice; -use pathfinder_gpu::Device; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::Transform3DF; +use pathfinder_content::color::ColorU; use pathfinder_gpu::resources::ResourceLoader; +use pathfinder_gpu::Device; use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy}; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderStats, RenderTime, Renderer}; -use pathfinder_renderer::options::{RenderOptions, RenderTransform}; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::{RenderStats, RenderTime, Renderer}; +use pathfinder_renderer::options::{BuildOptions, RenderTransform}; use pathfinder_renderer::post::STEM_DARKENING_FACTORS; use pathfinder_renderer::scene::Scene; use pathfinder_svg::BuiltSVG; @@ -44,6 +44,11 @@ use std::thread; use std::time::Duration; use usvg::{Options as UsvgOptions, Tree}; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::GLDevice as DeviceImpl; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice as DeviceImpl; + static DEFAULT_SVG_VIRTUAL_PATH: &'static str = "svg/Ghostscript_Tiger.svg"; const MOUSELOOK_ROTATION_SPEED: f32 = 0.007; @@ -112,22 +117,31 @@ pub struct DemoApp where W: Window { build_time: Option, ui_model: DemoUIModel, - ui_presenter: DemoUIPresenter, + ui_presenter: DemoUIPresenter, scene_proxy: SceneProxy, - renderer: Renderer, + renderer: Renderer, - scene_framebuffer: Option<::Framebuffer>, + scene_framebuffer: Option<::Framebuffer>, - ground_program: GroundProgram, - ground_vertex_array: GroundVertexArray, + ground_program: GroundProgram, + ground_vertex_array: GroundVertexArray, } impl DemoApp where W: Window { pub fn new(window: W, window_size: WindowSize, mut options: Options) -> DemoApp { let expire_message_event_id = window.create_user_event_id(); - let device = GLDevice::new(window.gl_version(), window.gl_default_framebuffer()); + let device; + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + { + device = DeviceImpl::new(window.metal_layer()); + } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + { + device = DeviceImpl::new(window.gl_version(), window.gl_default_framebuffer()); + } + let resources = window.resource_loader(); // Read command line options. @@ -144,8 +158,12 @@ impl DemoApp where W: Window { viewport, window_size: window_size.device_size(), }; + // FIXME(pcwalton) + let render_options = RendererOptions { + background_color: None, + }; - let renderer = Renderer::new(device, resources, dest_framebuffer); + let renderer = Renderer::new(device, resources, dest_framebuffer, render_options); let scene_metadata = SceneMetadata::new_clipping_view_box(&mut built_svg.scene, viewport.size()); let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size()); @@ -246,7 +264,7 @@ impl DemoApp where W: Window { Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)), }; - let render_options = RenderOptions { + let build_options = BuildOptions { transform: self.render_transform.clone().unwrap(), dilation: if self.ui_model.stem_darkening_effect_enabled { let font_size = APPROX_FONT_SIZE * self.window_size.backing_scale_factor; @@ -258,7 +276,7 @@ impl DemoApp where W: Window { subpixel_aa_enabled: self.ui_model.subpixel_aa_effect_enabled, }; - self.render_command_stream = Some(self.scene_proxy.build_with_stream(render_options)); + self.render_command_stream = Some(self.scene_proxy.build_with_stream(build_options)); } fn handle_events(&mut self, events: Vec) -> Vec { @@ -488,7 +506,9 @@ impl DemoApp where W: Window { self.handle_ui_events(frame, &mut ui_action); - self.window.present(); + self.renderer.device.end_commands(); + + self.window.present(&mut self.renderer.device); self.frame_counter += 1; } diff --git a/demo/common/src/renderer.rs b/demo/common/src/renderer.rs index 742186c1..c4bc0cc3 100644 --- a/demo/common/src/renderer.rs +++ b/demo/common/src/renderer.rs @@ -14,11 +14,14 @@ use crate::camera::{Camera, Mode}; use crate::window::{View, Window}; use crate::{BackgroundColor, DemoApp, UIVisibility}; use image::ColorType; -use pathfinder_geometry::color::{ColorF, ColorU}; -use pathfinder_gpu::{ClearParams, DepthFunc, DepthState, Device, Primitive, RenderState}; -use pathfinder_gpu::{TextureFormat, UniformData}; -use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderMode}; +use pathfinder_content::color::{ColorF, ColorU}; +use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions}; +use pathfinder_gpu::{RenderState, RenderTarget, TextureData, TextureFormat, UniformData}; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::Transform3DF; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::RenderMode; use pathfinder_renderer::gpu_data::RenderCommand; use pathfinder_renderer::options::RenderTransform; use pathfinder_renderer::post::DEFRINGING_KERNEL_CORE_GRAPHICS; @@ -42,13 +45,14 @@ const GRIDLINE_COUNT: i32 = 10; impl DemoApp where W: Window { pub fn prepare_frame_rendering(&mut self) -> u32 { - // Make the GL context current. + // Make the context current. let view = self.ui_model.mode.view(0); self.window.make_current(view); // Set up framebuffers. let window_size = self.window_size.device_size(); - let scene_count = match self.camera.mode() { + let mode = self.camera.mode(); + let scene_count = match mode { Mode::VR => { let viewport = self.window.viewport(View::Stereo(0)); if self.scene_framebuffer.is_none() @@ -82,49 +86,47 @@ impl DemoApp where W: Window { } }; - // Begin drawing the scene. - self.renderer.bind_dest_framebuffer(); - // Clear to the appropriate color. - let clear_color = if scene_count == 2 { - ColorF::transparent_black() - } else { - self.background_color().to_f32() + let clear_color = match mode { + Mode::TwoD => Some(self.background_color().to_f32()), + Mode::ThreeD => None, + Mode::VR => Some(ColorF::transparent_black()), }; - self.renderer.device.clear(&ClearParams { - color: Some(clear_color), - depth: Some(1.0), - stencil: Some(0), - ..ClearParams::default() - }); + self.renderer.set_options(RendererOptions { background_color: clear_color }); scene_count } pub fn draw_scene(&mut self) { + self.renderer.device.begin_commands(); + let view = self.ui_model.mode.view(0); self.window.make_current(view); if self.camera.mode() != Mode::VR { - self.draw_environment(); + self.draw_environment(0); } + self.renderer.device.end_commands(); + self.render_vector_scene(); // Reattach default framebuffer. - if self.camera.mode() != Mode::VR { - return; + if self.camera.mode() == Mode::VR { + if let DestFramebuffer::Other(scene_framebuffer) = + self.renderer + .replace_dest_framebuffer(DestFramebuffer::Default { + viewport: self.window.viewport(View::Mono), + window_size: self.window_size.device_size(), + }) + { + self.scene_framebuffer = Some(scene_framebuffer); + } } + } - if let DestFramebuffer::Other(scene_framebuffer) = - self.renderer - .replace_dest_framebuffer(DestFramebuffer::Default { - viewport: self.window.viewport(View::Mono), - window_size: self.window_size.device_size(), - }) - { - self.scene_framebuffer = Some(scene_framebuffer); - } + pub fn begin_compositing(&mut self) { + self.renderer.device.begin_commands(); } pub fn composite_scene(&mut self, render_scene_index: u32) { @@ -151,21 +153,12 @@ impl DemoApp where W: Window { let viewport = self.window.viewport(View::Stereo(render_scene_index)); self.window.make_current(View::Stereo(render_scene_index)); - self.renderer - .replace_dest_framebuffer(DestFramebuffer::Default { - viewport, - window_size: self.window_size.device_size(), - }); - - self.renderer.bind_draw_framebuffer(); - self.renderer.device.clear(&ClearParams { - color: Some(self.background_color().to_f32()), - depth: Some(1.0), - stencil: Some(0), - rect: Some(viewport), + self.renderer.replace_dest_framebuffer(DestFramebuffer::Default { + viewport, + window_size: self.window_size.device_size(), }); - self.draw_environment(); + self.draw_environment(render_scene_index); let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap(); let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer); @@ -207,7 +200,7 @@ impl DemoApp where W: Window { } // Draws the ground, if applicable. - fn draw_environment(&self) { + fn draw_environment(&self, render_scene_index: u32) { let frame = &self.current_frame.as_ref().unwrap(); let perspective = match frame.transform { @@ -233,31 +226,35 @@ impl DemoApp where W: Window { transform = transform.post_mul(&Transform3DF::from_scale(ground_scale, 1.0, ground_scale)); - let device = &self.renderer.device; - device.bind_vertex_array(&self.ground_vertex_array.vertex_array); - device.use_program(&self.ground_program.program); - device.set_uniform( - &self.ground_program.transform_uniform, - UniformData::from_transform_3d(&transform), - ); - device.set_uniform( - &self.ground_program.ground_color_uniform, - UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0), - ); - device.set_uniform( - &self.ground_program.gridline_color_uniform, - UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0), - ); - device.set_uniform(&self.ground_program.gridline_count_uniform, - UniformData::Int(GRIDLINE_COUNT)); - device.draw_elements( - Primitive::Triangles, - 6, - &RenderState { + // Don't clear the first scene after drawing it. + let clear_color = if render_scene_index == 0 { + Some(self.background_color().to_f32()) + } else { + None + }; + + self.renderer.device.draw_elements(6, &RenderState { + target: &self.renderer.draw_render_target(), + program: &self.ground_program.program, + vertex_array: &self.ground_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[], + uniforms: &[ + (&self.ground_program.transform_uniform, + UniformData::from_transform_3d(&transform)), + (&self.ground_program.ground_color_uniform, + UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0)), + (&self.ground_program.gridline_color_uniform, + UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0)), + (&self.ground_program.gridline_count_uniform, UniformData::Int(GRIDLINE_COUNT)), + ], + viewport: self.renderer.draw_viewport(), + options: RenderOptions { depth: Some(DepthState { func: DepthFunc::Less, write: true }), - ..RenderState::default() + clear_ops: ClearOps { color: clear_color, depth: Some(1.0), stencil: Some(0) }, + ..RenderOptions::default() }, - ); + }); } fn render_vector_scene(&mut self) { @@ -305,10 +302,11 @@ impl DemoApp where W: Window { pub fn take_raster_screenshot(&mut self, path: PathBuf) { let drawable_size = self.window_size.device_size(); - let pixels = self - .renderer - .device - .read_pixels_from_default_framebuffer(drawable_size); + let viewport = RectI::new(Vector2I::default(), drawable_size); + let pixels = match self.renderer.device.read_pixels(&RenderTarget::Default, viewport) { + TextureData::U8(pixels) => pixels, + TextureData::U16(_) => panic!("Unexpected pixel format for default framebuffer!"), + }; image::save_buffer( path, &pixels, diff --git a/demo/common/src/ui.rs b/demo/common/src/ui.rs index 0a13c3bc..2c7c8c5e 100644 --- a/demo/common/src/ui.rs +++ b/demo/common/src/ui.rs @@ -11,8 +11,8 @@ use crate::camera::Mode; use crate::window::Window; use crate::{BackgroundColor, Options}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::Device; use pathfinder_renderer::gpu::debug::DebugUIPresenter; @@ -500,9 +500,7 @@ where Vector2I::new(widget_x, slider_track_y), Vector2I::new(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT), ); - debug_ui_presenter - .ui_presenter - .draw_rect_outline(device, slider_track_rect, TEXT_COLOR); + debug_ui_presenter.ui_presenter.draw_rect_outline(device, slider_track_rect, TEXT_COLOR); let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2; let slider_knob_rect = RectI::new( @@ -528,7 +526,11 @@ where let widget_origin = panel_position + Vector2I::new(0, widget_size.y() * index); let widget_rect = RectI::new(widget_origin, widget_size); - if self.draw_menu_item(device, debug_ui_presenter, &text, widget_rect, false) { + if self.draw_menu_item(device, + debug_ui_presenter, + &text, + widget_rect, + false) { // FIXME(pcwalton): This is not sufficient for Android, where we will need to take in // the contents of the file. if let Ok(path) = window.run_save_dialog(screenshot_type.extension()) { @@ -554,7 +556,11 @@ where let widget_rect = RectI::new(widget_origin, widget_size); let selected = color == model.background_color; - if self.draw_menu_item(device, debug_ui_presenter, text, widget_rect, selected) { + if self.draw_menu_item(device, + debug_ui_presenter, + text, + widget_rect, + selected) { model.background_color = color; *action = UIAction::ModelChanged; } diff --git a/demo/common/src/window.rs b/demo/common/src/window.rs index 6ca9852c..edacf767 100644 --- a/demo/common/src/window.rs +++ b/demo/common/src/window.rs @@ -10,24 +10,38 @@ //! A minimal cross-platform windowing layer. -use gl::types::GLuint; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF}; -use pathfinder_gl::GLVersion; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::{Perspective, Transform3DF}; use pathfinder_gpu::resources::ResourceLoader; use rayon::ThreadPoolBuilder; use std::path::PathBuf; -pub trait Window { - fn gl_version(&self) -> GLVersion; - fn gl_default_framebuffer(&self) -> GLuint { - 0 - } +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use metal::CoreAnimationLayerRef; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice; + +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use gl::types::GLuint; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::{GLDevice, GLVersion}; + +pub trait Window { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn gl_version(&self) -> GLVersion; + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn gl_default_framebuffer(&self) -> GLuint { 0 } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn present(&mut self, device: &mut GLDevice); + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn metal_layer(&self) -> &CoreAnimationLayerRef; + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn present(&mut self, device: &mut MetalDevice); - fn viewport(&self, view: View) -> RectI; fn make_current(&mut self, view: View); - fn present(&mut self); + fn viewport(&self, view: View) -> RectI; fn resource_loader(&self) -> &dyn ResourceLoader; fn create_user_event_id(&self) -> u32; fn push_user_event(message_type: u32, message_data: u32); diff --git a/demo/magicleap/Cargo.toml b/demo/magicleap/Cargo.toml index 22a81069..6e7e8ff0 100644 --- a/demo/magicleap/Cargo.toml +++ b/demo/magicleap/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Alan Jeffrey "] [dependencies] gl = "0.6" rayon = "1.0" -usvg = "0.4" +usvg = "0.7" egl = "0.2" log = "0.4" smallvec = "0.6" @@ -20,6 +20,9 @@ crate-type = ["cdylib"] [features] mocked = ["glutin"] +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_demo] path = "../common" diff --git a/demo/magicleap/src/display.rs b/demo/magicleap/src/display.rs index 6a0f94ba..2176e43d 100644 --- a/demo/magicleap/src/display.rs +++ b/demo/magicleap/src/display.rs @@ -10,10 +10,10 @@ use std::error::Error; use std::io; -use pathfinder_geometry::basic::point::Point2DI32; -use pathfinder_geometry::basic::rect::RectI32; -use pathfinder_geometry::basic::transform3d::Perspective; -use pathfinder_geometry::basic::transform3d::Transform3DF32; +use pathfinder_geometry::point::Point2DI32; +use pathfinder_geometry::rect::RectI32; +use pathfinder_geometry::transform3d::Perspective; +use pathfinder_geometry::transform3d::Transform3DF32; use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::ResourceLoader; diff --git a/demo/magicleap/src/glwindow.rs b/demo/magicleap/src/glwindow.rs index bd90d08e..50005428 100644 --- a/demo/magicleap/src/glwindow.rs +++ b/demo/magicleap/src/glwindow.rs @@ -25,10 +25,10 @@ use crate::display::Display; use crate::display::DisplayCamera; use crate::display::DisplayError; -use pathfinder_geometry::basic::point::Point2DI32; -use pathfinder_geometry::basic::rect::RectI32; -use pathfinder_geometry::basic::transform3d::Transform3DF32; -use pathfinder_geometry::basic::transform3d::Perspective; +use pathfinder_geometry::point::Point2DI32; +use pathfinder_geometry::rect::RectI32; +use pathfinder_geometry::transform3d::Transform3DF32; +use pathfinder_geometry::transform3d::Perspective; use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::FilesystemResourceLoader; use pathfinder_gpu::resources::ResourceLoader; diff --git a/demo/magicleap/src/immersive.rs b/demo/magicleap/src/immersive.rs index 775a0b37..b01741ce 100644 --- a/demo/magicleap/src/immersive.rs +++ b/demo/magicleap/src/immersive.rs @@ -15,13 +15,13 @@ use pathfinder_demo::Camera; use pathfinder_demo::CameraTransform3D; use pathfinder_gl::GLDevice; use pathfinder_renderer::gpu::renderer::Renderer; -use pathfinder_geometry::basic::point::Point2DI32; -use pathfinder_geometry::basic::point::Point2DF32; -use pathfinder_geometry::basic::point::Point3DF32; -use pathfinder_geometry::basic::rect::RectI32; -use pathfinder_geometry::basic::transform2d::Transform2DF32; -use pathfinder_geometry::basic::transform3d::Transform3DF32; -use pathfinder_geometry::basic::transform3d::Perspective; +use pathfinder_geometry::point::Point2DI32; +use pathfinder_geometry::point::Point2DF32; +use pathfinder_geometry::point::Point3DF32; +use pathfinder_geometry::rect::RectI32; +use pathfinder_geometry::transform2d::Transform2DF32; +use pathfinder_geometry::transform3d::Transform3DF32; +use pathfinder_geometry::transform3d::Perspective; use pathfinder_gpu::Device; use pathfinder_simd::default::F32x4; use pathfinder_svg::BuiltSVG; diff --git a/demo/magicleap/src/lib.rs b/demo/magicleap/src/lib.rs index 8238b068..5530e4ab 100644 --- a/demo/magicleap/src/lib.rs +++ b/demo/magicleap/src/lib.rs @@ -29,11 +29,11 @@ use pathfinder_demo::BackgroundColor; use pathfinder_demo::Mode; use pathfinder_demo::window::Event; use pathfinder_demo::window::SVGPath; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_content::color::ColorF; use pathfinder_gl::GLDevice; use pathfinder_gl::GLVersion; use pathfinder_gpu::ClearParams; @@ -113,6 +113,7 @@ pub unsafe extern "C" fn magicleap_pathfinder_demo_run(app: *mut c_void) { } let scene_count = app.demo.prepare_frame(events); app.demo.draw_scene(); + app.demo.begin_compositing(); for scene_index in 0..scene_count { app.demo.composite_scene(scene_index); } diff --git a/demo/magicleap/src/magicleap.rs b/demo/magicleap/src/magicleap.rs index 1790c4a3..29c74df9 100644 --- a/demo/magicleap/src/magicleap.rs +++ b/demo/magicleap/src/magicleap.rs @@ -48,12 +48,12 @@ use pathfinder_demo::window::OcularTransform; use pathfinder_demo::window::View; use pathfinder_demo::window::Window; use pathfinder_demo::window::WindowSize; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::Perspective; -use pathfinder_geometry::basic::transform3d::Transform3DF; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::Perspective; +use pathfinder_geometry::transform3d::Transform3DF; use pathfinder_geometry::util; use pathfinder_gl::GLVersion; use pathfinder_gpu::resources::FilesystemResourceLoader; diff --git a/demo/native/Cargo.toml b/demo/native/Cargo.toml index 5e4468de..05c33dd3 100644 --- a/demo/native/Cargo.toml +++ b/demo/native/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" authors = ["Patrick Walton "] [features] +pf-gl = ["pathfinder_demo/pf-gl"] pf-no-simd = ["pathfinder_simd/pf-no-simd"] [dependencies] @@ -30,5 +31,12 @@ path = "../../gpu" [dependencies.pathfinder_simd] path = "../../simd" +[target.'cfg(target_os = "macos")'.dependencies] +foreign-types = "0.3" +metal = "0.14" + +[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] +path = "../../metal" + [target.'cfg(not(windows))'.dependencies] jemallocator = "0.1" diff --git a/demo/native/src/main.rs b/demo/native/src/main.rs index ad166dae..29069ae1 100644 --- a/demo/native/src/main.rs +++ b/demo/native/src/main.rs @@ -13,18 +13,35 @@ use nfd::Response; use pathfinder_demo::window::{Event, Keycode, SVGPath, View, Window, WindowSize}; use pathfinder_demo::{DemoApp, Options}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_gl::GLVersion; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use sdl2::event::{Event as SDLEvent, WindowEvent}; use sdl2::keyboard::Keycode as SDLKeycode; -use sdl2::video::{GLContext, GLProfile, Window as SDLWindow}; +use sdl2::video::Window as SDLWindow; use sdl2::{EventPump, EventSubsystem, Sdl, VideoSubsystem}; use sdl2_sys::{SDL_Event, SDL_UserEvent}; use std::path::PathBuf; use std::ptr; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use foreign_types::ForeignTypeRef; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use metal::{CAMetalLayer, CoreAnimationLayerRef}; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use pathfinder_metal::MetalDevice; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2::hint; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2::render::Canvas; +#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] +use sdl2_sys::SDL_RenderGetMetalLayer; + +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use pathfinder_gl::{GLDevice, GLVersion}; +#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] +use sdl2::video::{GLContext, GLProfile}; + #[cfg(not(windows))] use jemallocator; @@ -55,6 +72,7 @@ fn main() { let scene_count = app.prepare_frame(events); app.draw_scene(); + app.begin_compositing(); for scene_index in 0..scene_count { app.composite_scene(scene_index); } @@ -69,22 +87,36 @@ thread_local! { } struct WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] window: SDLWindow, + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + gl_context: GLContext, + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + canvas: Canvas, + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + metal_layer: *mut CAMetalLayer, + event_pump: EventPump, #[allow(dead_code)] - gl_context: GLContext, resource_loader: FilesystemResourceLoader, selected_file: Option, open_svg_message_type: u32, } impl Window for WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn gl_version(&self) -> GLVersion { GLVersion::GL3 } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn metal_layer(&self) -> &CoreAnimationLayerRef { + unsafe { CoreAnimationLayerRef::from_ptr(self.metal_layer) } + } + fn viewport(&self, view: View) -> RectI { - let (width, height) = self.window.drawable_size(); + let (width, height) = self.window().drawable_size(); let mut width = width as i32; let height = height as i32; let mut x_offset = 0; @@ -95,12 +127,22 @@ impl Window for WindowImpl { RectI::new(Vector2I::new(x_offset, 0), Vector2I::new(width, height)) } + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn make_current(&mut self, _view: View) { - self.window.gl_make_current(&self.gl_context).unwrap(); + self.window().gl_make_current(&self.gl_context).unwrap(); } - fn present(&mut self) { - self.window.gl_swap_window(); + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn make_current(&mut self, _: View) {} + + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn present(&mut self, _: &mut GLDevice) { + self.window().gl_swap_window(); + } + + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn present(&mut self, device: &mut MetalDevice) { + device.present_drawable(); } fn resource_loader(&self) -> &dyn ResourceLoader { @@ -141,6 +183,7 @@ impl Window for WindowImpl { } impl WindowImpl { + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] fn new() -> WindowImpl { SDL_VIDEO.with(|sdl_video| { SDL_EVENT.with(|sdl_event| { @@ -185,9 +228,55 @@ impl WindowImpl { }) } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn new() -> WindowImpl { + assert!(hint::set("SDL_RENDER_DRIVER", "metal")); + + SDL_VIDEO.with(|sdl_video| { + SDL_EVENT.with(|sdl_event| { + let window = sdl_video + .window( + "Pathfinder Demo", + DEFAULT_WINDOW_WIDTH, + DEFAULT_WINDOW_HEIGHT, + ) + .opengl() + .resizable() + .allow_highdpi() + .build() + .unwrap(); + + let canvas = window.into_canvas().present_vsync().build().unwrap(); + let metal_layer = unsafe { + SDL_RenderGetMetalLayer(canvas.raw()) as *mut CAMetalLayer + }; + + let event_pump = SDL_CONTEXT.with(|sdl_context| sdl_context.event_pump().unwrap()); + + let resource_loader = FilesystemResourceLoader::locate(); + + let open_svg_message_type = unsafe { sdl_event.register_event().unwrap() }; + + WindowImpl { + event_pump, + canvas, + metal_layer, + resource_loader, + open_svg_message_type, + selected_file: None, + } + }) + }) + } + + #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] + fn window(&self) -> &SDLWindow { &self.window } + #[cfg(all(target_os = "macos", not(feature = "pf-gl")))] + fn window(&self) -> &SDLWindow { self.canvas.window() } + fn size(&self) -> WindowSize { - let (logical_width, logical_height) = self.window.size(); - let (drawable_width, _) = self.window.drawable_size(); + let (logical_width, logical_height) = self.window().size(); + let (drawable_width, _) = self.window().drawable_size(); WindowSize { logical_size: Vector2I::new(logical_width as i32, logical_height as i32), backing_scale_factor: drawable_width as f32 / logical_width as f32, diff --git a/examples/c_canvas_minimal/Makefile b/examples/c_canvas_minimal/Makefile index 35f4b9ef..d2c8a5dc 100644 --- a/examples/c_canvas_minimal/Makefile +++ b/examples/c_canvas_minimal/Makefile @@ -5,7 +5,7 @@ RUST_TARGET_DIR?=../../target RUST_SRC_DIR?=../../c RUSTFLAGS?=-C target-cpu=native -CFLAGS?=-Wall -g -I../../c/include +CFLAGS?=-Wall -g -I../../c/build/include LIBS?=-lpathfinder_c MKDIR?=mkdir -p RM?=rm @@ -15,7 +15,7 @@ UNAME=$(shell uname -s) ifeq ($(UNAME),Darwin) # FIXME(pcwalton): Don't link against HarfBuzz!! LIBS+=-framework OpenGL -framework CoreFoundation -framework CoreGraphics -framework CoreText - LIBS+=-lharfbuzz + LIBS+=-framework Metal -lharfbuzz else LIBS+=-lGL endif diff --git a/examples/c_canvas_minimal/c_canvas_minimal.c b/examples/c_canvas_minimal/c_canvas_minimal.c index 9e773b02..bcfa09b9 100644 --- a/examples/c_canvas_minimal/c_canvas_minimal.c +++ b/examples/c_canvas_minimal/c_canvas_minimal.c @@ -58,15 +58,13 @@ int main(int argc, const char **argv) { PFGLDestFramebufferCreateFullWindow(&(PFVector2I){640, 480}); PFGLRendererRef renderer = PFGLRendererCreate(PFGLDeviceCreate(PF_GL_VERSION_GL3, 0), PFFilesystemResourceLoaderLocate(), - dest_framebuffer); - - // Clear to white. - PFGLDeviceClear(PFGLRendererGetDevice(renderer), &(PFClearParams){ - (PFColorF){1.0, 1.0, 1.0, 1.0}, 0.0, 0, {0}, PF_CLEAR_FLAGS_HAS_COLOR + dest_framebuffer, + &(PFRendererOptions){ + (PFColorF){1.0, 1.0, 1.0, 1.0}, PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR }); // Make a canvas. We're going to draw a house. - PFCanvasRef canvas = PFCanvasCreate(PFCanvasFontContextCreate(), + PFCanvasRef canvas = PFCanvasCreate(PFCanvasFontContextCreateWithSystemSource(), &(PFVector2F){640.0f, 480.0f}); // Set line width. @@ -89,7 +87,7 @@ int main(int argc, const char **argv) { // Render the canvas to screen. PFSceneRef scene = PFCanvasCreateScene(canvas); PFSceneProxyRef scene_proxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene); - PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFRenderOptions){0}); + PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFBuildOptions){0}); SDL_GL_SwapWindow(window); // Wait for a keypress. diff --git a/examples/canvas_glutin_minimal/Cargo.toml b/examples/canvas_glutin_minimal/Cargo.toml new file mode 100644 index 00000000..2b1a6bb3 --- /dev/null +++ b/examples/canvas_glutin_minimal/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "canvas_glutin_minimal" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +gl = "0.6" +glutin = "0.21" + +[dependencies.pathfinder_canvas] +path = "../../canvas" + +[dependencies.pathfinder_content] +path = "../../content" + +[dependencies.pathfinder_geometry] +path = "../../geometry" + +[dependencies.pathfinder_gl] +path = "../../gl" + +[dependencies.pathfinder_gpu] +path = "../../gpu" + +[dependencies.pathfinder_renderer] +path = "../../renderer" + diff --git a/examples/canvas_glutin_minimal/src/main.rs b/examples/canvas_glutin_minimal/src/main.rs new file mode 100644 index 00000000..597f7e27 --- /dev/null +++ b/examples/canvas_glutin_minimal/src/main.rs @@ -0,0 +1,96 @@ +// pathfinder/examples/canvas_glutin_minimal/src/main.rs +// +// Copyright © 2019 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. + +//! Demonstrates how to use the Pathfinder canvas API with `glutin`. + +use glutin::dpi::PhysicalSize; +use glutin::{ContextBuilder, ControlFlow, Event, EventsLoop, GlProfile, GlRequest, KeyboardInput}; +use glutin::{VirtualKeyCode, WindowBuilder, WindowEvent}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; +use pathfinder_content::color::ColorF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; +use pathfinder_gl::{GLDevice, GLVersion}; +use pathfinder_gpu::resources::FilesystemResourceLoader; +use pathfinder_renderer::concurrent::rayon::RayonExecutor; +use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::options::BuildOptions; + +fn main() { + // Calculate the right logical size of the window. + let mut event_loop = EventsLoop::new(); + let hidpi_factor = event_loop.get_primary_monitor().get_hidpi_factor(); + let window_size = Vector2I::new(640, 480); + let physical_window_size = PhysicalSize::new(window_size.x() as f64, window_size.y() as f64); + let logical_window_size = physical_window_size.to_logical(hidpi_factor); + + // Open a window. + let window_builder = WindowBuilder::new().with_title("Minimal example") + .with_dimensions(logical_window_size); + + // Create an OpenGL 3.x context for Pathfinder to use. + let gl_context = ContextBuilder::new().with_gl(GlRequest::Latest) + .with_gl_profile(GlProfile::Core) + .build_windowed(window_builder, &event_loop) + .unwrap(); + + // Load OpenGL, and make the context current. + let gl_context = unsafe { gl_context.make_current().unwrap() }; + gl::load_with(|name| gl_context.get_proc_address(name) as *const _); + + // Create a Pathfinder renderer. + let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), + &FilesystemResourceLoader::locate(), + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); + + // Make a canvas. We're going to draw a house. + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(), + window_size.to_f32()); + + // Set line width. + canvas.set_line_width(10.0); + + // Draw walls. + canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0))); + + // Draw door. + canvas.fill_rect(RectF::new(Vector2F::new(130.0, 190.0), Vector2F::new(40.0, 60.0))); + + // Draw roof. + let mut path = Path2D::new(); + path.move_to(Vector2F::new(50.0, 140.0)); + path.line_to(Vector2F::new(150.0, 60.0)); + path.line_to(Vector2F::new(250.0, 140.0)); + path.close_path(); + canvas.stroke_path(path); + + // Render the canvas to screen. + let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); + scene.build_and_render(&mut renderer, BuildOptions::default()); + gl_context.swap_buffers().unwrap(); + + // Wait for a keypress. + event_loop.run_forever(|event| { + match event { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } | + Event::WindowEvent { + event: WindowEvent::KeyboardInput { + input: KeyboardInput { virtual_keycode: Some(VirtualKeyCode::Escape), .. }, + .. + }, + .. + } => ControlFlow::Break, + _ => ControlFlow::Continue, + } + }) +} diff --git a/examples/canvas_metal_minimal/Cargo.toml b/examples/canvas_metal_minimal/Cargo.toml new file mode 100644 index 00000000..74cfde80 --- /dev/null +++ b/examples/canvas_metal_minimal/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "canvas_metal_minimal" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +foreign-types = "0.3" +gl = "0.6" +metal = "0.14" +objc = "0.2" +sdl2 = "0.32" +sdl2-sys = "0.32" + +[dependencies.pathfinder_canvas] +path = "../../canvas" + +[dependencies.pathfinder_content] +path = "../../content" + +[dependencies.pathfinder_geometry] +path = "../../geometry" + +[dependencies.pathfinder_gl] +path = "../../gl" + +[dependencies.pathfinder_gpu] +path = "../../gpu" + +[dependencies.pathfinder_metal] +path = "../../metal" + +[dependencies.pathfinder_renderer] +path = "../../renderer" diff --git a/examples/canvas_metal_minimal/src/main.rs b/examples/canvas_metal_minimal/src/main.rs new file mode 100644 index 00000000..2b0b6b06 --- /dev/null +++ b/examples/canvas_metal_minimal/src/main.rs @@ -0,0 +1,88 @@ +// pathfinder/examples/canvas_metal_minimal/src/main.rs +// +// Copyright © 2019 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. + +use foreign_types::ForeignTypeRef; +use metal::{CAMetalLayer, CoreAnimationLayerRef}; +use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; +use pathfinder_content::color::ColorF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; +use pathfinder_gpu::resources::FilesystemResourceLoader; +use pathfinder_metal::MetalDevice; +use pathfinder_renderer::concurrent::rayon::RayonExecutor; +use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; +use sdl2::event::Event; +use sdl2::hint; +use sdl2::keyboard::Keycode; +use sdl2_sys::SDL_RenderGetMetalLayer; + +fn main() { + // Set up SDL2. + assert!(hint::set("SDL_RENDER_DRIVER", "metal")); + let sdl_context = sdl2::init().unwrap(); + let video = sdl_context.video().unwrap(); + + // Open a window. + let window_size = Vector2I::new(640, 480); + let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32) + .opengl() + .build() + .unwrap(); + + // Create a Metal context. + let canvas = window.into_canvas().present_vsync().build().unwrap(); + let metal_layer = unsafe { + CoreAnimationLayerRef::from_ptr(SDL_RenderGetMetalLayer(canvas.raw()) as *mut CAMetalLayer) + }; + + // Create a Pathfinder renderer. + let mut renderer = Renderer::new(MetalDevice::new(metal_layer), + &FilesystemResourceLoader::locate(), + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); + + // Make a canvas. We're going to draw a house. + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(), + window_size.to_f32()); + + // Set line width. + canvas.set_line_width(10.0); + + // Draw walls. + canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0))); + + // Draw door. + canvas.fill_rect(RectF::new(Vector2F::new(130.0, 190.0), Vector2F::new(40.0, 60.0))); + + // Draw roof. + let mut path = Path2D::new(); + path.move_to(Vector2F::new(50.0, 140.0)); + path.line_to(Vector2F::new(150.0, 60.0)); + path.line_to(Vector2F::new(250.0, 140.0)); + path.close_path(); + canvas.stroke_path(path); + + // Render the canvas to screen. + let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); + scene.build_and_render(&mut renderer, BuildOptions::default()); + renderer.device.present_drawable(); + + // Wait for a keypress. + let mut event_pump = sdl_context.event_pump().unwrap(); + loop { + match event_pump.wait_event() { + Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return, + _ => {} + } + } +} diff --git a/examples/canvas_minimal/Cargo.toml b/examples/canvas_minimal/Cargo.toml index ccd2fe25..0becc032 100644 --- a/examples/canvas_minimal/Cargo.toml +++ b/examples/canvas_minimal/Cargo.toml @@ -12,6 +12,9 @@ sdl2-sys = "0.32" [dependencies.pathfinder_canvas] path = "../../canvas" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/examples/canvas_minimal/src/main.rs b/examples/canvas_minimal/src/main.rs index 07588dcc..dce34e5d 100644 --- a/examples/canvas_minimal/src/main.rs +++ b/examples/canvas_minimal/src/main.rs @@ -9,16 +9,16 @@ // except according to those terms. use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; +use pathfinder_content::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -48,13 +48,12 @@ fn main() { // Create a Pathfinder renderer. let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(window_size)); - - // Clear to white. - renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); // Make a canvas. We're going to draw a house. - let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(), + window_size.to_f32()); // Set line width. canvas.set_line_width(10.0); @@ -75,7 +74,7 @@ fn main() { // Render the canvas to screen. let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); - scene.build_and_render(&mut renderer, RenderOptions::default()); + scene.build_and_render(&mut renderer, BuildOptions::default()); window.gl_swap_window(); // Wait for a keypress. diff --git a/examples/canvas_moire/Cargo.toml b/examples/canvas_moire/Cargo.toml index 0bab187d..cb8f98ea 100644 --- a/examples/canvas_moire/Cargo.toml +++ b/examples/canvas_moire/Cargo.toml @@ -12,6 +12,9 @@ sdl2-sys = "0.32" [dependencies.pathfinder_canvas] path = "../../canvas" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/examples/canvas_moire/src/main.rs b/examples/canvas_moire/src/main.rs index 7a55404e..36312a09 100644 --- a/examples/canvas_moire/src/main.rs +++ b/examples/canvas_moire/src/main.rs @@ -9,15 +9,15 @@ // except according to those terms. use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, Path2D}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::color::{ColorF, ColorU}; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_content::color::{ColorF, ColorU}; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; @@ -67,7 +67,8 @@ fn main() { // Create our renderers. let renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(drawable_size)); + DestFramebuffer::full_window(drawable_size), + RendererOptions { background_color: Some(ColorF::white()) }); let mut moire_renderer = MoireRenderer::new(renderer, window_size, drawable_size); // Enter main render loop. @@ -99,7 +100,7 @@ impl MoireRenderer { -> MoireRenderer { MoireRenderer { renderer, - font_context: CanvasFontContext::new(), + font_context: CanvasFontContext::from_system_source(), scene: SceneProxy::new(RayonExecutor), frame: 0, window_size, @@ -124,10 +125,7 @@ impl MoireRenderer { Vector2F::new(1.0, sin_time).scale(cos_time * INNER_RADIUS); // Clear to background color. - self.renderer.device.clear(&ClearParams { - color: Some(background_color), - ..ClearParams::default() - }); + self.renderer.set_options(RendererOptions { background_color: Some(background_color) }); // Make a canvas. let mut canvas = CanvasRenderingContext2D::new(self.font_context.clone(), @@ -142,7 +140,7 @@ impl MoireRenderer { // Build and render scene. self.scene.replace_scene(canvas.into_scene()); - self.scene.build_and_render(&mut self.renderer, RenderOptions::default()); + self.scene.build_and_render(&mut self.renderer, BuildOptions::default()); self.frame += 1; } diff --git a/examples/canvas_text/Cargo.toml b/examples/canvas_text/Cargo.toml index 174d4c96..6250e71a 100644 --- a/examples/canvas_text/Cargo.toml +++ b/examples/canvas_text/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Patrick Walton "] edition = "2018" [dependencies] +font-kit = "0.2" gl = "0.6" sdl2 = "0.32" sdl2-sys = "0.32" @@ -12,6 +13,9 @@ sdl2-sys = "0.32" [dependencies.pathfinder_canvas] path = "../../canvas" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_geometry] path = "../../geometry" diff --git a/examples/canvas_text/src/main.rs b/examples/canvas_text/src/main.rs index 0829723e..2942e3ae 100644 --- a/examples/canvas_text/src/main.rs +++ b/examples/canvas_text/src/main.rs @@ -8,19 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use font_kit::handle::Handle; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, TextAlign}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_content::color::ColorF; use pathfinder_gl::{GLDevice, GLVersion}; -use pathfinder_gpu::resources::FilesystemResourceLoader; -use pathfinder_gpu::{ClearParams, Device}; +use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; -use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer}; -use pathfinder_renderer::options::RenderOptions; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; +use std::iter; +use std::sync::Arc; fn main() { // Set up SDL2. @@ -45,17 +48,22 @@ fn main() { window.gl_make_current(&gl_context).unwrap(); // Create a Pathfinder renderer. + let resource_loader = FilesystemResourceLoader::locate(); let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0), - &FilesystemResourceLoader::locate(), - DestFramebuffer::full_window(window_size)); + &resource_loader, + DestFramebuffer::full_window(window_size), + RendererOptions { background_color: Some(ColorF::white()) }); - // Clear to white. - renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() }); + // Load a font. + let font_data = Arc::new(resource_loader.slurp("fonts/overpass-regular.otf").unwrap()); + let font = Handle::from_memory(font_data, 0); + let font_context = CanvasFontContext::from_fonts(iter::once(font)); - // Make a canvas. We're going to draw some text. - let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32()); + // Make a canvas. + let mut canvas = CanvasRenderingContext2D::new(font_context, window_size.to_f32()); // Draw the text. + canvas.set_font_by_postscript_name("Overpass-Regular"); canvas.set_font_size(32.0); canvas.fill_text("Hello Pathfinder!", Vector2F::new(32.0, 48.0)); canvas.set_text_align(TextAlign::Right); @@ -63,7 +71,7 @@ fn main() { // Render the canvas to screen. let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor); - scene.build_and_render(&mut renderer, RenderOptions::default()); + scene.build_and_render(&mut renderer, BuildOptions::default()); window.gl_swap_window(); // Wait for a keypress. diff --git a/examples/swf_basic/Cargo.toml b/examples/swf_basic/Cargo.toml new file mode 100644 index 00000000..ced4ed19 --- /dev/null +++ b/examples/swf_basic/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "swf_basic" +version = "0.1.0" +authors = ["Jon Hardie "] +edition = "2018" + +[dependencies] +gl = "0.6" +sdl2 = "0.32" +sdl2-sys = "0.32" + +swf-parser = "0.7.0" +swf-tree = "0.7.0" + +[dependencies.pathfinder_geometry] +path = "../../geometry" + +[dependencies.pathfinder_gl] +path = "../../gl" + +[dependencies.pathfinder_gpu] +path = "../../gpu" + +[dependencies.pathfinder_renderer] +path = "../../renderer" + +[dependencies.pathfinder_swf] +path = "../../swf" diff --git a/examples/swf_basic/src/main.rs b/examples/swf_basic/src/main.rs new file mode 100644 index 00000000..cd790074 --- /dev/null +++ b/examples/swf_basic/src/main.rs @@ -0,0 +1,136 @@ +// pathfinder/examples/swf_basic/src/main.rs +// +// Copyright © 2019 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. + +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::RectF; +use pathfinder_gl::{GLDevice, GLVersion}; +use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader}; +use pathfinder_renderer::concurrent::rayon::RayonExecutor; +use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions}; +use pathfinder_renderer::options::{RenderTransform, BuildOptions}; +use sdl2::event::Event; +use sdl2::keyboard::Keycode; +use sdl2::video::GLProfile; +use pathfinder_renderer::scene::Scene; +use pathfinder_swf::{draw_paths_into_scene, process_swf_tags}; +use std::env; +use std::fs::read; +use pathfinder_geometry::transform2d::Transform2DF; + +fn main() { + let resource_loader = FilesystemResourceLoader::locate(); + + let swf_bytes; + if let Some(path) = env::args().skip(1).next() { + match read(path) { + Ok(bytes) => { + swf_bytes = bytes; + }, + Err(e) => panic!(e) + } + } else { + // NOTE(jon): This is a version of the ghostscript tiger graphic flattened to a single + // layer with no overlapping shapes. This is how artwork is 'natively' created in the Flash + // authoring tool when an artist just draws directly onto the canvas (without 'object' mode + // turned on, which is the default). + // Subsequent shapes with different fills will knock out existing fills where they overlap. + // A downside of this in current pathfinder is that cracks are visible between shape fills - + // especially obvious if you set the context clear color to #ff00ff or similar. + + // Common speculation as to why the swf format stores vector graphics in this way says that + // it is to save on file-size bytes, however in the case of our tiger, it results in a + // larger file than the layered version, since the overlapping shapes and strokes create + // a lot more geometry. I think a more likely explanation for the choice is that it was + // done to reduce overdraw in the software rasterizer running on late 90's era hardware? + // Indeed, this mode gives pathfinders' occlusion culling pass nothing to do! + + // NOTE(jon): This is a version of the same graphic cut and pasted into the Flash authoring + // tool from the SVG version loaded in Illustrator. When layered graphics are pasted + // into Flash, by default they retain their layering, expressed as groups. + // They are still presented as being on a single timeline layer. + // They will be drawn back to front in much the same way as the SVG version. + + let default_tiger = resource_loader.slurp("swf/tiger.swf").unwrap(); + swf_bytes = Vec::from(&default_tiger[..]); + } + + let (_, movie): (_, swf_tree::Movie) = swf_parser::parsers::movie::parse_movie(&swf_bytes[..]).unwrap(); + + // Set up SDL2. + let sdl_context = sdl2::init().unwrap(); + let video = sdl_context.video().unwrap(); + + // Make sure we have at least a GL 3.0 context. Pathfinder requires this. + let gl_attributes = video.gl_attr(); + gl_attributes.set_context_profile(GLProfile::Core); + gl_attributes.set_context_version(3, 3); + + // process swf scene + // TODO(jon): Since swf is a streaming format, this really wants to be a lazy iterator over + // swf frames eventually. + let (library, stage) = process_swf_tags(&movie); + + // Open a window. + let window_size = Vector2I::new(stage.width(), stage.height()); + let window = video.window("Minimal example", window_size.x() as u32, window_size.y() as u32) + .opengl() + .allow_highdpi() + .build() + .unwrap(); + + let pixel_size = Vector2I::new( + window.drawable_size().0 as i32, + window.drawable_size().1 as i32 + ); + let device_pixel_ratio = pixel_size.x() as f32 / window_size.x() as f32; + + // Create the GL context, and make it current. + let gl_context = window.gl_create_context().unwrap(); + gl::load_with(|name| video.gl_get_proc_address(name) as *const _); + window.gl_make_current(&gl_context).unwrap(); + + // Create a Pathfinder renderer. + let mut renderer = Renderer::new( + GLDevice::new(GLVersion::GL3, 0), + &resource_loader, + DestFramebuffer::full_window(pixel_size), + RendererOptions { background_color: Some(stage.background_color()) } + ); + // Clear to swf stage background color. + let mut scene = Scene::new(); + scene.set_view_box(RectF::new( + Vector2F::default(), + Vector2F::new( + stage.width() as f32 * device_pixel_ratio, + stage.height() as f32 * device_pixel_ratio) + )); + draw_paths_into_scene(&library, &mut scene); + + // Render the canvas to screen. + let scene = SceneProxy::from_scene(scene, RayonExecutor); + let mut build_options = BuildOptions::default(); + let scale_transform = Transform2DF::from_scale( + Vector2F::new(device_pixel_ratio, device_pixel_ratio) + ); + build_options.transform = RenderTransform::Transform2D(scale_transform); + scene.build_and_render(&mut renderer, build_options); + + window.gl_swap_window(); + // Wait for a keypress. + let mut event_pump = sdl_context.event_pump().unwrap(); + loop { + match event_pump.wait_event() { + Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return, + _ => {} + } + } +} diff --git a/geometry/Cargo.toml b/geometry/Cargo.toml index 580a84da..8136c255 100644 --- a/geometry/Cargo.toml +++ b/geometry/Cargo.toml @@ -5,11 +5,6 @@ edition = "2018" authors = ["Patrick Walton "] [dependencies] -arrayvec = "0.4" -bitflags = "1.0" -serde = "1.0" -serde_derive = "1.0" -smallvec = "0.6" [dependencies.log] version = "0.4" diff --git a/geometry/src/lib.rs b/geometry/src/lib.rs index 8445b7ae..3ff52601 100644 --- a/geometry/src/lib.rs +++ b/geometry/src/lib.rs @@ -8,24 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Utilities for Bézier curves. -//! -//! These may be merged into upstream Lyon eventually. +//! Basic geometry and linear algebra primitives, optimized with SIMD. -#[macro_use] -extern crate bitflags; -#[macro_use] -extern crate log; - -pub mod basic; -pub mod clip; -pub mod color; -pub mod dash; -pub mod orientation; -pub mod outline; -pub mod segment; -pub mod stroke; +pub mod line_segment; +pub mod rect; +pub mod transform2d; +pub mod transform3d; +pub mod unit_vector; pub mod util; - -mod dilation; -mod unit_vector; +pub mod vector; diff --git a/geometry/src/basic/line_segment.rs b/geometry/src/line_segment.rs similarity index 98% rename from geometry/src/basic/line_segment.rs rename to geometry/src/line_segment.rs index 3d68f655..7842c893 100644 --- a/geometry/src/basic/line_segment.rs +++ b/geometry/src/line_segment.rs @@ -10,8 +10,8 @@ //! Line segment types, optimized with SIMD. -use crate::basic::vector::Vector2F; -use crate::basic::transform2d::Matrix2x2F; +use crate::vector::Vector2F; +use crate::transform2d::Matrix2x2F; use crate::util; use pathfinder_simd::default::F32x4; use std::ops::{Add, Sub}; diff --git a/geometry/src/basic/rect.rs b/geometry/src/rect.rs similarity index 99% rename from geometry/src/basic/rect.rs rename to geometry/src/rect.rs index 95e60ee3..ec7e103a 100644 --- a/geometry/src/basic/rect.rs +++ b/geometry/src/rect.rs @@ -10,7 +10,7 @@ //! 2D axis-aligned rectangles, optimized with SIMD. -use crate::basic::vector::{Vector2F, Vector2I}; +use crate::vector::{Vector2F, Vector2I}; use pathfinder_simd::default::{F32x4, I32x4}; #[derive(Clone, Copy, Debug, PartialEq, Default)] diff --git a/geometry/src/basic/transform2d.rs b/geometry/src/transform2d.rs similarity index 82% rename from geometry/src/basic/transform2d.rs rename to geometry/src/transform2d.rs index db0df148..b48c8882 100644 --- a/geometry/src/basic/transform2d.rs +++ b/geometry/src/transform2d.rs @@ -10,11 +10,10 @@ //! 2D affine transforms. -use crate::basic::line_segment::LineSegment2F; -use crate::basic::vector::Vector2F; -use crate::basic::rect::RectF; -use crate::basic::transform3d::Transform3DF; -use crate::segment::Segment; +use crate::line_segment::LineSegment2F; +use crate::vector::Vector2F; +use crate::rect::RectF; +use crate::transform3d::Transform3DF; use crate::unit_vector::UnitVector; use pathfinder_simd::default::F32x4; use std::ops::Sub; @@ -295,57 +294,3 @@ impl Transform2DF { Vector2F(self.matrix.0.zwxy()).length() } } - -/// Transforms a path with a SIMD 2D transform. -pub struct Transform2DFPathIter -where - I: Iterator, -{ - iter: I, - transform: Transform2DF, -} - -impl Iterator for Transform2DFPathIter -where - I: Iterator, -{ - type Item = Segment; - - #[inline] - fn next(&mut self) -> Option { - // TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD? - let mut segment = self.iter.next()?; - if !segment.is_none() { - segment - .baseline - .set_from(&self.transform.transform_point(segment.baseline.from())); - segment - .baseline - .set_to(&self.transform.transform_point(segment.baseline.to())); - if !segment.is_line() { - segment - .ctrl - .set_from(&self.transform.transform_point(segment.ctrl.from())); - if !segment.is_quadratic() { - segment - .ctrl - .set_to(&self.transform.transform_point(segment.ctrl.to())); - } - } - } - Some(segment) - } -} - -impl Transform2DFPathIter -where - I: Iterator, -{ - #[inline] - pub fn new(iter: I, transform: &Transform2DF) -> Transform2DFPathIter { - Transform2DFPathIter { - iter, - transform: *transform, - } - } -} diff --git a/geometry/src/basic/transform3d.rs b/geometry/src/transform3d.rs similarity index 89% rename from geometry/src/basic/transform3d.rs rename to geometry/src/transform3d.rs index bdd71c0c..7425b34c 100644 --- a/geometry/src/basic/transform3d.rs +++ b/geometry/src/transform3d.rs @@ -10,10 +10,9 @@ //! 3D transforms that can be applied to paths. -use crate::basic::vector::{Vector2F, Vector2I, Vector4F}; -use crate::basic::rect::RectF; -use crate::basic::transform2d::Matrix2x2F; -use crate::segment::Segment; +use crate::vector::{Vector2F, Vector2I, Vector4F}; +use crate::rect::RectF; +use crate::transform2d::Matrix2x2F; use pathfinder_simd::default::F32x4; use std::ops::{Add, Neg}; @@ -372,65 +371,10 @@ impl Perspective { } } -/// Transforms a path with a perspective projection. -pub struct PerspectivePathIter -where - I: Iterator, -{ - iter: I, - perspective: Perspective, -} - -impl Iterator for PerspectivePathIter -where - I: Iterator, -{ - type Item = Segment; - - #[inline] - fn next(&mut self) -> Option { - let mut segment = self.iter.next()?; - if !segment.is_none() { - segment.baseline.set_from( - &self - .perspective - .transform_point_2d(&segment.baseline.from()), - ); - segment - .baseline - .set_to(&self.perspective.transform_point_2d(&segment.baseline.to())); - if !segment.is_line() { - segment - .ctrl - .set_from(&self.perspective.transform_point_2d(&segment.ctrl.from())); - if !segment.is_quadratic() { - segment - .ctrl - .set_to(&self.perspective.transform_point_2d(&segment.ctrl.to())); - } - } - } - Some(segment) - } -} - -impl PerspectivePathIter -where - I: Iterator, -{ - #[inline] - pub fn new(iter: I, perspective: &Perspective) -> PerspectivePathIter { - PerspectivePathIter { - iter, - perspective: *perspective, - } - } -} - #[cfg(test)] mod test { - use crate::basic::vector::Vector4F; - use crate::basic::transform3d::Transform3DF; + use crate::vector::Vector4F; + use crate::transform3d::Transform3DF; #[test] fn test_post_mul() { diff --git a/geometry/src/unit_vector.rs b/geometry/src/unit_vector.rs index 35533e7a..b46431b0 100644 --- a/geometry/src/unit_vector.rs +++ b/geometry/src/unit_vector.rs @@ -10,7 +10,7 @@ //! A utility module that allows unit vectors to be treated like angles. -use crate::basic::vector::Vector2F; +use crate::vector::Vector2F; use pathfinder_simd::default::F32x4; #[derive(Clone, Copy, Debug)] diff --git a/geometry/src/basic/vector.rs b/geometry/src/vector.rs similarity index 100% rename from geometry/src/basic/vector.rs rename to geometry/src/vector.rs diff --git a/gl/src/lib.rs b/gl/src/lib.rs index 030f63f9..1c832544 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -14,13 +14,13 @@ extern crate log; use gl::types::{GLboolean, GLchar, GLenum, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::Vector2I; use pathfinder_gpu::resources::ResourceLoader; -use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams}; -use pathfinder_gpu::{DepthFunc, Device, Primitive, RenderState, ShaderKind, StencilFunc}; -use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass}; -use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{RenderTarget, BlendState, BufferData, BufferTarget, BufferUploadMode}; +use pathfinder_gpu::{ClearOps, DepthFunc, Device, Primitive, RenderOptions, RenderState}; +use pathfinder_gpu::{ShaderKind, StencilFunc, TextureData, TextureFormat, UniformData}; +use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::F32x4; use std::ffi::CString; use std::mem; @@ -60,10 +60,32 @@ impl GLDevice { } } - fn set_render_state(&self, render_state: &RenderState) { + fn set_render_state(&self, render_state: &RenderState) { + self.bind_render_target(render_state.target); + + unsafe { + let (origin, size) = (render_state.viewport.origin(), render_state.viewport.size()); + gl::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.use_program(render_state.program); + self.bind_vertex_array(render_state.vertex_array); + for (texture_unit, texture) in render_state.textures.iter().enumerate() { + self.bind_texture(texture, texture_unit as u32); + } + + render_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data)); + self.set_render_options(&render_state.options); + } + + fn set_render_options(&self, render_options: &RenderOptions) { unsafe { // Set blend. - match render_state.blend { + match render_options.blend { BlendState::Off => { gl::Disable(gl::BLEND); ck(); } @@ -91,7 +113,7 @@ impl GLDevice { } // Set depth. - match render_state.depth { + match render_options.depth { None => { gl::Disable(gl::DEPTH_TEST); ck(); } @@ -103,7 +125,7 @@ impl GLDevice { } // Set stencil. - match render_state.stencil { + match render_options.stencil { None => { gl::Disable(gl::STENCIL_TEST); ck(); } @@ -123,14 +145,50 @@ impl GLDevice { } // Set color mask. - let color_mask = render_state.color_mask as GLboolean; + let color_mask = render_options.color_mask as GLboolean; gl::ColorMask(color_mask, color_mask, color_mask, color_mask); ck(); } } - fn reset_render_state(&self, render_state: &RenderState) { + fn set_uniform(&self, uniform: &GLUniform, data: &UniformData) { unsafe { - match render_state.blend { + match *data { + UniformData::Int(value) => { + gl::Uniform1i(uniform.location, value); ck(); + } + UniformData::Mat4(data) => { + assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4); + let data_ptr: *const F32x4 = data.as_ptr(); + gl::UniformMatrix4fv(uniform.location, + 1, + gl::FALSE, + data_ptr as *const GLfloat); + } + UniformData::Vec2(data) => { + gl::Uniform2f(uniform.location, data.x(), data.y()); ck(); + } + UniformData::Vec4(data) => { + gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck(); + } + UniformData::TextureUnit(unit) => { + gl::Uniform1i(uniform.location, unit as GLint); 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.unuse_program(); + self.unbind_vertex_array(); + } + + fn reset_render_options(&self, render_options: &RenderOptions) { + unsafe { + match render_options.blend { BlendState::Off => {} BlendState::RGBOneAlphaOneMinusSrcAlpha | BlendState::RGBOneAlphaOne | @@ -139,11 +197,11 @@ impl GLDevice { } } - if render_state.depth.is_some() { + if render_options.depth.is_some() { gl::Disable(gl::DEPTH_TEST); ck(); } - if render_state.stencil.is_some() { + if render_options.stencil.is_some() { gl::StencilMask(!0); ck(); gl::Disable(gl::STENCIL_TEST); ck(); } @@ -165,37 +223,18 @@ impl Device for GLDevice { type VertexAttr = GLVertexAttr; fn create_texture(&self, format: TextureFormat, size: Vector2I) -> GLTexture { - let (gl_internal_format, gl_format, gl_type); - match format { - TextureFormat::R8 => { - gl_internal_format = gl::R8 as GLint; - gl_format = gl::RED; - gl_type = gl::UNSIGNED_BYTE; - } - TextureFormat::R16F => { - gl_internal_format = gl::R16F as GLint; - gl_format = gl::RED; - gl_type = gl::HALF_FLOAT; - } - TextureFormat::RGBA8 => { - gl_internal_format = gl::RGBA as GLint; - gl_format = gl::RGBA; - gl_type = gl::UNSIGNED_BYTE; - } - } - - let mut texture = GLTexture { gl_texture: 0, size }; + let mut texture = GLTexture { gl_texture: 0, size, format }; unsafe { gl::GenTextures(1, &mut texture.gl_texture); ck(); self.bind_texture(&texture, 0); gl::TexImage2D(gl::TEXTURE_2D, 0, - gl_internal_format, + format.gl_internal_format(), size.x() as GLsizei, size.y() as GLsizei, 0, - gl_format, - gl_type, + format.gl_format(), + format.gl_type(), ptr::null()); ck(); } @@ -206,7 +245,7 @@ impl Device for GLDevice { fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> GLTexture { assert!(data.len() >= size.x() as usize * size.y() as usize); - let mut texture = GLTexture { gl_texture: 0, size }; + let mut texture = GLTexture { gl_texture: 0, size, format: TextureFormat::R8 }; unsafe { gl::GenTextures(1, &mut texture.gl_texture); ck(); self.bind_texture(&texture, 0); @@ -304,12 +343,16 @@ impl Device for GLDevice { } } - fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> GLVertexAttr { + fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option { let name = CString::new(format!("a{}", name)).unwrap(); let attr = unsafe { - gl::GetAttribLocation(program.gl_program, name.as_ptr() as *const GLchar) as GLuint + gl::GetAttribLocation(program.gl_program, name.as_ptr() as *const GLchar) }; ck(); - GLVertexAttr { attr } + if attr < 0 { + None + } else { + Some(GLVertexAttr { attr: attr as GLuint }) + } } fn get_uniform(&self, program: &GLProgram, name: &str) -> GLUniform { @@ -320,13 +363,14 @@ impl Device for GLDevice { GLUniform { location } } - fn use_program(&self, program: &Self::Program) { - unsafe { - gl::UseProgram(program.gl_program); ck(); - } - } + fn configure_vertex_attr(&self, + vertex_array: &GLVertexArray, + attr: &GLVertexAttr, + descriptor: &VertexAttrDescriptor) { + debug_assert_ne!(descriptor.stride, 0); + + self.bind_vertex_array(vertex_array); - fn configure_vertex_attr(&self, attr: &GLVertexAttr, descriptor: &VertexAttrDescriptor) { unsafe { let attr_type = descriptor.attr_type.to_gl_type(); match descriptor.class { @@ -355,41 +399,8 @@ impl Device for GLDevice { gl::VertexAttribDivisor(attr.attr, descriptor.divisor); ck(); gl::EnableVertexAttribArray(attr.attr); ck(); } - } - fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData) { - unsafe { - match data { - UniformData::Int(value) => { - gl::Uniform1i(uniform.location, value); ck(); - } - UniformData::Mat2(data) => { - assert_eq!(mem::size_of::(), 4 * 4); - let data_ptr: *const F32x4 = &data; - gl::UniformMatrix2fv(uniform.location, - 1, - gl::FALSE, - data_ptr as *const GLfloat); - } - UniformData::Mat4(data) => { - assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4); - let data_ptr: *const F32x4 = data.as_ptr(); - gl::UniformMatrix4fv(uniform.location, - 1, - gl::FALSE, - data_ptr as *const GLfloat); - } - UniformData::Vec2(data) => { - gl::Uniform2f(uniform.location, data.x(), data.y()); ck(); - } - UniformData::Vec4(data) => { - gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck(); - } - UniformData::TextureUnit(unit) => { - gl::Uniform1i(uniform.location, unit as GLint); ck(); - } - } - } + self.unbind_vertex_array(); } fn create_framebuffer(&self, texture: GLTexture) -> GLFramebuffer { @@ -466,77 +477,67 @@ impl Device for GLDevice { self.set_texture_parameters(texture); } - fn read_pixels_from_default_framebuffer(&self, size: Vector2I) -> Vec { - let mut pixels = vec![0; size.x() as usize * size.y() as usize * 4]; - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); - gl::ReadPixels(0, - 0, - size.x() as GLsizei, - size.y() as GLsizei, - gl::RGBA, - gl::UNSIGNED_BYTE, - pixels.as_mut_ptr() as *mut GLvoid); ck(); - } + fn read_pixels(&self, render_target: &RenderTarget, viewport: RectI) -> TextureData { + let (origin, size) = (viewport.origin(), viewport.size()); + let format = self.render_target_format(render_target); + self.bind_render_target(render_target); - // Flip right-side-up. - let stride = size.x() as usize * 4; - for y in 0..(size.y() as usize / 2) { - let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride); - for offset in 0..stride { - pixels.swap(index_a + offset, index_b + offset); + match format { + TextureFormat::R8 | TextureFormat::RGBA8 => { + let channels = format.channels(); + let mut pixels = vec![0; size.x() as usize * size.y() as usize * channels]; + unsafe { + gl::ReadPixels(origin.x(), + origin.y(), + size.x() as GLsizei, + size.y() as GLsizei, + format.gl_format(), + format.gl_type(), + pixels.as_mut_ptr() as *mut GLvoid); ck(); + } + flip_y(&mut pixels, size, channels); + TextureData::U8(pixels) } - } - - pixels - } - - fn clear(&self, params: &ClearParams) { - unsafe { - if let Some(rect) = params.rect { - let (origin, size) = (rect.origin(), rect.size()); - gl::Scissor(origin.x(), origin.y(), size.x(), size.y()); ck(); - gl::Enable(gl::SCISSOR_TEST); ck(); - } - - let mut flags = 0; - if let Some(color) = params.color { - gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck(); - gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck(); - flags |= gl::COLOR_BUFFER_BIT; - } - if let Some(depth) = params.depth { - gl::DepthMask(gl::TRUE); ck(); - gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES - flags |= gl::DEPTH_BUFFER_BIT; - } - if let Some(stencil) = params.stencil { - gl::StencilMask(!0); ck(); - gl::ClearStencil(stencil as GLint); ck(); - flags |= gl::STENCIL_BUFFER_BIT; - } - if flags != 0 { - gl::Clear(flags); ck(); - } - - if params.rect.is_some() { - gl::Disable(gl::SCISSOR_TEST); ck(); + TextureFormat::R16F => { + let mut pixels = vec![0; size.x() as usize * size.y() as usize]; + unsafe { + gl::ReadPixels(origin.x(), + origin.y(), + size.x() as GLsizei, + size.y() as GLsizei, + format.gl_format(), + format.gl_type(), + pixels.as_mut_ptr() as *mut GLvoid); ck(); + } + flip_y(&mut pixels, size, 1); + TextureData::U16(pixels) } } } - fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) { + 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) { + unsafe { gl::Flush(); } + } + + fn draw_arrays(&self, index_count: u32, render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawArrays(primitive.to_gl_primitive(), 0, index_count as GLsizei); ck(); + gl::DrawArrays(render_state.primitive.to_gl_primitive(), + 0, + index_count as GLsizei); ck(); } self.reset_render_state(render_state); } - fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) { + fn draw_elements(&self, index_count: u32, render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawElements(primitive.to_gl_primitive(), + gl::DrawElements(render_state.primitive.to_gl_primitive(), index_count as GLsizei, gl::UNSIGNED_INT, ptr::null()); ck(); @@ -545,13 +546,12 @@ impl Device for GLDevice { } fn draw_elements_instanced(&self, - primitive: Primitive, index_count: u32, instance_count: u32, - render_state: &RenderState) { + render_state: &RenderState) { self.set_render_state(render_state); unsafe { - gl::DrawElementsInstanced(primitive.to_gl_primitive(), + gl::DrawElementsInstanced(render_state.primitive.to_gl_primitive(), index_count as GLsizei, gl::UNSIGNED_INT, ptr::null(), @@ -584,66 +584,102 @@ impl Device for GLDevice { } #[inline] - fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool { + fn get_timer_query(&self, query: &Self::TimerQuery) -> Option { unsafe { let mut result = 0; gl::GetQueryObjectiv(query.gl_query, gl::QUERY_RESULT_AVAILABLE, &mut result); ck(); - result != gl::FALSE as GLint - } - } - - #[inline] - fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration { - unsafe { + if result == gl::FALSE as GLint { + return None; + } let mut result = 0; gl::GetQueryObjectui64v(query.gl_query, gl::QUERY_RESULT, &mut result); ck(); - Duration::from_nanos(result) + Some(Duration::from_nanos(result)) } } #[inline] + fn bind_buffer(&self, vertex_array: &GLVertexArray, buffer: &GLBuffer, target: BufferTarget) { + self.bind_vertex_array(vertex_array); + unsafe { + gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck(); + } + 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) + } +} + +impl GLDevice { + fn bind_render_target(&self, attachment: &RenderTarget) { + match *attachment { + RenderTarget::Default => self.bind_default_framebuffer(), + RenderTarget::Framebuffer(framebuffer) => self.bind_framebuffer(framebuffer), + } + } + fn bind_vertex_array(&self, vertex_array: &GLVertexArray) { unsafe { gl::BindVertexArray(vertex_array.gl_vertex_array); ck(); } } - #[inline] - fn bind_buffer(&self, buffer: &GLBuffer, target: BufferTarget) { + fn unbind_vertex_array(&self) { unsafe { - gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck(); + gl::BindVertexArray(0); ck(); } } - #[inline] - fn bind_default_framebuffer(&self, viewport: RectI) { - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); - gl::Viewport(viewport.origin().x(), - viewport.origin().y(), - viewport.size().x(), - viewport.size().y()); ck(); - } - } - - #[inline] - fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) { - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer); ck(); - gl::Viewport(0, 0, framebuffer.texture.size.x(), framebuffer.texture.size.y()); ck(); - } - } - - #[inline] fn bind_texture(&self, texture: &GLTexture, unit: u32) { unsafe { gl::ActiveTexture(gl::TEXTURE0 + unit); ck(); gl::BindTexture(gl::TEXTURE_2D, texture.gl_texture); ck(); } } -} -impl GLDevice { + fn unbind_texture(&self, unit: u32) { + unsafe { + gl::ActiveTexture(gl::TEXTURE0 + unit); ck(); + gl::BindTexture(gl::TEXTURE_2D, 0); ck(); + } + } + + fn use_program(&self, program: &GLProgram) { + unsafe { + gl::UseProgram(program.gl_program); ck(); + } + } + + fn unuse_program(&self) { + unsafe { + gl::UseProgram(0); ck(); + } + } + + fn bind_default_framebuffer(&self) { + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, self.default_framebuffer); ck(); + } + } + + fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) { + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer); ck(); + } + } + fn preprocess(&self, output: &mut Vec, source: &[u8], version: &str) { let mut index = 0; while index < source.len() { @@ -665,6 +701,39 @@ impl GLDevice { } } } + + fn clear(&self, ops: &ClearOps) { + unsafe { + let mut flags = 0; + if let Some(color) = ops.color { + gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck(); + gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck(); + flags |= gl::COLOR_BUFFER_BIT; + } + if let Some(depth) = ops.depth { + gl::DepthMask(gl::TRUE); ck(); + gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES + flags |= gl::DEPTH_BUFFER_BIT; + } + if let Some(stencil) = ops.stencil { + gl::StencilMask(!0); ck(); + gl::ClearStencil(stencil as GLint); ck(); + flags |= gl::STENCIL_BUFFER_BIT; + } + if flags != 0 { + gl::Clear(flags); ck(); + } + } + } + + fn render_target_format(&self, render_target: &RenderTarget) -> TextureFormat { + match *render_target { + RenderTarget::Default => TextureFormat::RGBA8, + RenderTarget::Framebuffer(ref framebuffer) => { + self.framebuffer_texture(framebuffer).format + } + } + } } pub struct GLVertexArray { @@ -749,7 +818,7 @@ impl Drop for GLBuffer { #[derive(Debug)] pub struct GLUniform { - pub location: GLint, + location: GLint, } pub struct GLProgram { @@ -783,6 +852,7 @@ impl Drop for GLShader { pub struct GLTexture { gl_texture: GLuint, pub size: Vector2I, + pub format: TextureFormat, } pub struct GLTimerQuery { @@ -859,7 +929,36 @@ impl StencilFuncExt for StencilFunc { match self { StencilFunc::Always => gl::ALWAYS, StencilFunc::Equal => gl::EQUAL, - StencilFunc::NotEqual => gl::NOTEQUAL, + } + } +} + +trait TextureFormatExt { + fn gl_internal_format(self) -> GLint; + fn gl_format(self) -> GLuint; + fn gl_type(self) -> GLuint; +} + +impl TextureFormatExt for TextureFormat { + fn gl_internal_format(self) -> GLint { + match self { + TextureFormat::R8 => gl::R8 as GLint, + TextureFormat::R16F => gl::R16F as GLint, + TextureFormat::RGBA8 => gl::RGBA as GLint, + } + } + + fn gl_format(self) -> GLuint { + match self { + TextureFormat::R8 | TextureFormat::R16F => gl::RED, + TextureFormat::RGBA8 => gl::RGBA, + } + } + + fn gl_type(self) -> GLuint { + match self { + TextureFormat::R8 | TextureFormat::RGBA8 => gl::UNSIGNED_BYTE, + TextureFormat::R16F => gl::HALF_FLOAT, } } } @@ -925,4 +1024,15 @@ fn ck() { #[cfg(not(debug_assertions))] fn ck() {} -// Shader preprocessing +// Utilities + +// Flips a buffer of image data upside-down. +fn flip_y(pixels: &mut [T], size: Vector2I, channels: usize) { + let stride = size.x() as usize * channels; + for y in 0..(size.y() as usize / 2) { + let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride); + for offset in 0..stride { + pixels.swap(index_a + offset, index_b + offset); + } + } +} diff --git a/gpu/Cargo.toml b/gpu/Cargo.toml index c493efa2..cc9ca12f 100644 --- a/gpu/Cargo.toml +++ b/gpu/Cargo.toml @@ -11,6 +11,9 @@ version = "0.21" default-features = false features = ["png_codec"] +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index cfe4b4ee..70dcd132 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -12,16 +12,16 @@ use crate::resources::ResourceLoader; use image::ImageFormat; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_geometry::color::ColorF; +use pathfinder_content::color::ColorF; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::Transform3DF; +use pathfinder_geometry::vector::Vector2I; use pathfinder_simd::default::F32x4; use std::time::Duration; pub mod resources; -pub trait Device { +pub trait Device: Sized { type Buffer; type Framebuffer; type Program; @@ -34,6 +34,8 @@ pub trait Device { fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture; fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> Self::Texture; + fn create_shader(&self, resources: &dyn ResourceLoader, name: &str, kind: ShaderKind) + -> Self::Shader; fn create_shader_from_source(&self, name: &str, source: &[u8], kind: ShaderKind) -> Self::Shader; fn create_vertex_array(&self) -> Self::VertexArray; @@ -44,11 +46,16 @@ pub trait Device { vertex_shader: Self::Shader, fragment_shader: Self::Shader, ) -> Self::Program; - fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Self::VertexAttr; + fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option; fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform; - fn use_program(&self, program: &Self::Program); - fn configure_vertex_attr(&self, attr: &Self::VertexAttr, descriptor: &VertexAttrDescriptor); - fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData); + fn bind_buffer(&self, + vertex_array: &Self::VertexArray, + buffer: &Self::Buffer, + target: BufferTarget); + fn configure_vertex_attr(&self, + vertex_array: &Self::VertexArray, + attr: &Self::VertexAttr, + descriptor: &VertexAttrDescriptor); fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer; fn create_buffer(&self) -> Self::Buffer; fn allocate_buffer( @@ -61,27 +68,19 @@ pub trait Device { fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture; fn texture_size(&self, texture: &Self::Texture) -> Vector2I; fn upload_to_texture(&self, texture: &Self::Texture, size: Vector2I, data: &[u8]); - fn read_pixels_from_default_framebuffer(&self, size: Vector2I) -> Vec; - fn clear(&self, params: &ClearParams); - fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState); - fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState); + fn read_pixels(&self, target: &RenderTarget, viewport: RectI) -> TextureData; + fn begin_commands(&self); + fn end_commands(&self); + fn draw_arrays(&self, index_count: u32, render_state: &RenderState); + fn draw_elements(&self, index_count: u32, render_state: &RenderState); fn draw_elements_instanced(&self, - primitive: Primitive, index_count: u32, instance_count: u32, - render_state: &RenderState); + render_state: &RenderState); fn create_timer_query(&self) -> Self::TimerQuery; fn begin_timer_query(&self, query: &Self::TimerQuery); fn end_timer_query(&self, query: &Self::TimerQuery); - fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool; - fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration; - - // TODO(pcwalton): Go bindless... - fn bind_vertex_array(&self, vertex_array: &Self::VertexArray); - fn bind_buffer(&self, buffer: &Self::Buffer, target: BufferTarget); - fn bind_default_framebuffer(&self, viewport: RectI); - fn bind_framebuffer(&self, framebuffer: &Self::Framebuffer); - fn bind_texture(&self, texture: &Self::Texture, unit: u32); + fn get_timer_query(&self, query: &Self::TimerQuery) -> Option; fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture { let data = resources.slurp(&format!("textures/{}.png", name)).unwrap(); @@ -92,20 +91,6 @@ pub trait Device { self.create_texture_from_data(size, &image) } - fn create_shader( - &self, - resources: &dyn ResourceLoader, - name: &str, - kind: ShaderKind, - ) -> Self::Shader { - let suffix = match kind { - ShaderKind::Vertex => 'v', - ShaderKind::Fragment => 'f', - }; - let source = resources.slurp(&format!("shaders/gl3/{}.{}s.glsl", name, suffix)).unwrap(); - self.create_shader_from_source(name, &source, kind) - } - fn create_program_from_shader_names( &self, resources: &dyn ResourceLoader, @@ -124,7 +109,7 @@ pub trait Device { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum TextureFormat { R8, R16F, @@ -167,7 +152,6 @@ pub enum ShaderKind { #[derive(Clone, Copy)] pub enum UniformData { Int(i32), - Mat2(F32x4), Mat4([F32x4; 4]), Vec2(F32x4), Vec4(F32x4), @@ -180,23 +164,41 @@ pub enum Primitive { Lines, } -#[derive(Clone, Copy, Default)] -pub struct ClearParams { +#[derive(Clone)] +pub struct RenderState<'a, D> where D: Device { + pub target: &'a RenderTarget<'a, D>, + pub program: &'a D::Program, + pub vertex_array: &'a D::VertexArray, + pub primitive: Primitive, + pub uniforms: &'a [(&'a D::Uniform, UniformData)], + pub textures: &'a [&'a D::Texture], + pub viewport: RectI, + pub options: RenderOptions, +} + +#[derive(Clone, Debug)] +pub struct RenderOptions { + pub blend: BlendState, + pub depth: Option, + pub stencil: Option, + pub clear_ops: ClearOps, + pub color_mask: bool, +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct ClearOps { pub color: Option, - pub rect: Option, pub depth: Option, pub stencil: Option, } -#[derive(Clone, Debug)] -pub struct RenderState { - pub blend: BlendState, - pub depth: Option, - pub stencil: Option, - pub color_mask: bool, +#[derive(Clone, Copy, Debug)] +pub enum RenderTarget<'a, D> where D: Device { + Default, + Framebuffer(&'a D::Framebuffer), } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum BlendState { Off, RGBOneAlphaOne, @@ -228,16 +230,16 @@ pub struct StencilState { pub enum StencilFunc { Always, Equal, - NotEqual, } -impl Default for RenderState { +impl Default for RenderOptions { #[inline] - fn default() -> RenderState { - RenderState { + fn default() -> RenderOptions { + RenderOptions { blend: BlendState::default(), depth: None, stencil: None, + clear_ops: ClearOps::default(), color_mask: true, } } @@ -276,6 +278,12 @@ impl Default for StencilFunc { } } +#[derive(Clone, Debug)] +pub enum TextureData { + U8(Vec), + U16(Vec), +} + impl UniformData { #[inline] pub fn from_transform_3d(transform: &Transform3DF) -> UniformData { @@ -291,6 +299,7 @@ pub struct VertexAttrDescriptor { pub stride: usize, pub offset: usize, pub divisor: u32, + pub buffer_index: u32, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -299,3 +308,20 @@ pub enum VertexAttrClass { FloatNorm, Int, } + +impl TextureFormat { + #[inline] + pub fn channels(self) -> usize { + match self { + TextureFormat::R8 | TextureFormat::R16F => 1, + TextureFormat::RGBA8 => 4, + } + } +} + +impl ClearOps { + #[inline] + pub fn has_ops(&self) -> bool { + self.color.is_some() || self.depth.is_some() || self.stencil.is_some() + } +} diff --git a/metal/Cargo.toml b/metal/Cargo.toml new file mode 100644 index 00000000..8ddef24b --- /dev/null +++ b/metal/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pathfinder_metal" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[dependencies] +bitflags = "1.0" +byteorder = "1.3" +block = "0.1" +cocoa = "0.18" +core-foundation = "0.6" +foreign-types = "0.3" +metal = "0.14" +objc = "0.2" + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_gpu] +path = "../gpu" + +[dependencies.pathfinder_simd] +path = "../simd" diff --git a/metal/src/lib.rs b/metal/src/lib.rs new file mode 100644 index 00000000..13f157bc --- /dev/null +++ b/metal/src/lib.rs @@ -0,0 +1,1485 @@ +// pathfinder/metal/src/lib.rs +// +// Copyright © 2019 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 Metal implementation of the device abstraction, for macOS and iOS. + +#![allow(non_upper_case_globals)] + +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate objc; + +use block::{Block, ConcreteBlock, RcBlock}; +use byteorder::{NativeEndian, WriteBytesExt}; +use cocoa::foundation::{NSRange, NSUInteger}; +use core_foundation::base::TCFType; +use core_foundation::string::{CFString, CFStringRef}; +use foreign_types::{ForeignType, ForeignTypeRef}; +use metal::{self, Argument, ArgumentEncoder, Buffer, CommandBuffer, CommandBufferRef}; +use metal::{CommandQueue, CompileOptions, CoreAnimationDrawable, CoreAnimationDrawableRef}; +use metal::{CoreAnimationLayer, CoreAnimationLayerRef, DepthStencilDescriptor, Function, Library}; +use metal::{MTLArgument, MTLArgumentEncoder, MTLBlendFactor, MTLClearColor, MTLColorWriteMask}; +use metal::{MTLCompareFunction, MTLDataType, MTLDevice, MTLFunctionType, MTLIndexType}; +use metal::{MTLLoadAction, MTLOrigin, MTLPixelFormat, MTLPrimitiveType, MTLRegion}; +use metal::{MTLRenderPipelineReflection, MTLRenderPipelineState, MTLResourceOptions}; +use metal::{MTLResourceUsage, MTLSamplerAddressMode, MTLSamplerMinMagFilter, MTLSize}; +use metal::{MTLStencilOperation, MTLStorageMode, MTLStoreAction, MTLTextureType, MTLTextureUsage}; +use metal::{MTLVertexFormat, MTLVertexStepFunction, MTLViewport, RenderCommandEncoder}; +use metal::{RenderCommandEncoderRef, RenderPassDescriptor, RenderPassDescriptorRef}; +use metal::{RenderPipelineColorAttachmentDescriptorRef, RenderPipelineDescriptor}; +use metal::{RenderPipelineReflection, RenderPipelineReflectionRef, RenderPipelineState}; +use metal::{SamplerDescriptor, SamplerState, StencilDescriptor, StructMemberRef, StructType}; +use metal::{StructTypeRef, TextureDescriptor, Texture, TextureRef, VertexAttribute}; +use metal::{VertexAttributeRef, VertexDescriptor, VertexDescriptorRef}; +use objc::runtime::{Class, Object}; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_gpu::resources::ResourceLoader; +use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, DepthFunc, Device}; +use pathfinder_gpu::{Primitive, RenderState, RenderTarget, ShaderKind, StencilFunc, TextureData}; +use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrClass}; +use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_simd::default::F32x4; +use std::cell::{Cell, RefCell}; +use std::mem; +use std::ptr; +use std::rc::Rc; +use std::slice; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +const FIRST_VERTEX_BUFFER_INDEX: u64 = 1; + +pub struct MetalDevice { + device: metal::Device, + layer: CoreAnimationLayer, + drawable: CoreAnimationDrawable, + main_depth_stencil_texture: Texture, + command_queue: CommandQueue, + command_buffers: RefCell>, + sampler: SamplerState, + shared_event: SharedEvent, + shared_event_listener: SharedEventListener, + next_timer_query_event_value: Cell, +} + +pub struct MetalProgram { + vertex: MetalShader, + fragment: MetalShader, +} + +#[derive(Clone)] +pub struct MetalBuffer { + buffer: Rc>>, +} + +impl MetalDevice { + #[inline] + pub fn new(layer: &CoreAnimationLayerRef) -> MetalDevice { + let layer = layer.retain(); + let device = layer.device(); + let drawable = layer.next_drawable().unwrap().retain(); + let command_queue = device.new_command_queue(); + + let sampler_descriptor = SamplerDescriptor::new(); + sampler_descriptor.set_support_argument_buffers(true); + sampler_descriptor.set_normalized_coordinates(true); + sampler_descriptor.set_min_filter(MTLSamplerMinMagFilter::Linear); + sampler_descriptor.set_mag_filter(MTLSamplerMinMagFilter::Linear); + sampler_descriptor.set_address_mode_s(MTLSamplerAddressMode::ClampToEdge); + sampler_descriptor.set_address_mode_t(MTLSamplerAddressMode::ClampToEdge); + let sampler = device.new_sampler(&sampler_descriptor); + + let main_color_texture = drawable.texture(); + let framebuffer_size = Vector2I::new(main_color_texture.width() as i32, + main_color_texture.height() as i32); + let main_depth_stencil_texture = device.create_depth_stencil_texture(framebuffer_size); + + let shared_event = device.new_shared_event(); + + MetalDevice { + device, + layer, + drawable, + main_depth_stencil_texture, + command_queue, + command_buffers: RefCell::new(vec![]), + sampler, + shared_event, + shared_event_listener: SharedEventListener::new(), + next_timer_query_event_value: Cell::new(1), + } + } + + pub fn present_drawable(&mut self) { + self.begin_commands(); + self.command_buffers.borrow_mut().last().unwrap().present_drawable(&self.drawable); + self.end_commands(); + self.drawable = self.layer.next_drawable().unwrap().retain(); + } +} + +pub struct MetalFramebuffer(MetalTexture); + +pub struct MetalShader { + #[allow(dead_code)] + library: Library, + function: Function, + uniforms: RefCell, +} + +enum ShaderUniforms { + Unknown, + NoUniforms, + Uniforms { encoder: ArgumentEncoder, struct_type: StructType } +} + +pub struct MetalTexture { + texture: Texture, + dirty: Cell, +} + +pub struct MetalTimerQuery { + event_value: u64, + start_time: Cell>, + end_time: Cell>, +} + +#[derive(Clone)] +pub struct MetalUniform { + indices: RefCell>, + name: String, +} + +#[derive(Clone, Copy)] +pub struct MetalUniformIndices { + vertex: Option, + fragment: Option, +} + +#[derive(Clone, Copy)] +pub struct MetalUniformIndex { + main: u64, + sampler: Option, +} + +pub struct MetalVertexArray { + descriptor: VertexDescriptor, + vertex_buffers: RefCell>, + index_buffer: RefCell>, +} + +impl Device for MetalDevice { + type Buffer = MetalBuffer; + type Framebuffer = MetalFramebuffer; + type Program = MetalProgram; + type Shader = MetalShader; + type Texture = MetalTexture; + type TimerQuery = Arc; + type Uniform = MetalUniform; + type VertexArray = MetalVertexArray; + type VertexAttr = VertexAttribute; + + // TODO: Add texture usage hint. + fn create_texture(&self, format: TextureFormat, size: Vector2I) -> MetalTexture { + let descriptor = TextureDescriptor::new(); + descriptor.set_texture_type(MTLTextureType::D2); + match format { + TextureFormat::R8 => descriptor.set_pixel_format(MTLPixelFormat::R8Unorm), + TextureFormat::R16F => descriptor.set_pixel_format(MTLPixelFormat::R16Float), + TextureFormat::RGBA8 => descriptor.set_pixel_format(MTLPixelFormat::RGBA8Unorm), + } + descriptor.set_width(size.x() as u64); + descriptor.set_height(size.y() as u64); + descriptor.set_storage_mode(MTLStorageMode::Managed); + descriptor.set_usage(MTLTextureUsage::Unknown); + MetalTexture { texture: self.device.new_texture(&descriptor), dirty: Cell::new(false) } + } + + fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> MetalTexture { + assert!(data.len() >= size.x() as usize * size.y() as usize); + let texture = self.create_texture(TextureFormat::R8, size); + self.upload_to_texture(&texture, size, data); + texture + } + + fn create_shader_from_source(&self, _: &str, source: &[u8], _: ShaderKind) -> MetalShader { + let source = String::from_utf8(source.to_vec()).expect("Source wasn't valid UTF-8!"); + + let compile_options = CompileOptions::new(); + let library = self.device.new_library_with_source(&source, &compile_options).unwrap(); + let function = library.get_function("main0", None).unwrap(); + + MetalShader { library, function, uniforms: RefCell::new(ShaderUniforms::Unknown) } + } + + fn create_vertex_array(&self) -> MetalVertexArray { + MetalVertexArray { + descriptor: VertexDescriptor::new().retain(), + vertex_buffers: RefCell::new(vec![]), + index_buffer: RefCell::new(None), + } + } + + fn bind_buffer(&self, + vertex_array: &MetalVertexArray, + buffer: &MetalBuffer, + target: BufferTarget) { + match target { + BufferTarget::Vertex => { + vertex_array.vertex_buffers.borrow_mut().push((*buffer).clone()) + } + BufferTarget::Index => { + *vertex_array.index_buffer.borrow_mut() = Some((*buffer).clone()) + } + } + } + + fn create_program_from_shaders(&self, + _: &dyn ResourceLoader, + _: &str, + vertex_shader: MetalShader, + fragment_shader: MetalShader) + -> MetalProgram { + MetalProgram { vertex: vertex_shader, fragment: fragment_shader } + } + + fn get_vertex_attr(&self, program: &MetalProgram, name: &str) -> Option { + // TODO(pcwalton): Cache the function? + let attributes = program.vertex.function.real_vertex_attributes(); + for attribute_index in 0..attributes.len() { + let attribute = attributes.object_at(attribute_index); + let this_name = attribute.name().as_bytes(); + if this_name[0] == b'a' && this_name[1..] == *name.as_bytes() { + return Some(attribute.retain()) + } + } + None + } + + fn get_uniform(&self, _: &Self::Program, name: &str) -> MetalUniform { + MetalUniform { indices: RefCell::new(None), name: name.to_owned() } + } + + fn configure_vertex_attr(&self, + vertex_array: &MetalVertexArray, + attr: &VertexAttribute, + descriptor: &VertexAttrDescriptor) { + debug_assert_ne!(descriptor.stride, 0); + + let attribute_index = attr.attribute_index(); + + let attr_info = vertex_array.descriptor + .attributes() + .object_at(attribute_index as usize) + .unwrap(); + let format = match (descriptor.class, descriptor.attr_type, descriptor.size) { + (VertexAttrClass::Int, VertexAttrType::I8, 2) => MTLVertexFormat::Char2, + (VertexAttrClass::Int, VertexAttrType::I8, 3) => MTLVertexFormat::Char3, + (VertexAttrClass::Int, VertexAttrType::I8, 4) => MTLVertexFormat::Char4, + (VertexAttrClass::Int, VertexAttrType::U8, 2) => MTLVertexFormat::UChar2, + (VertexAttrClass::Int, VertexAttrType::U8, 3) => MTLVertexFormat::UChar3, + (VertexAttrClass::Int, VertexAttrType::U8, 4) => MTLVertexFormat::UChar4, + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 2) => { + MTLVertexFormat::UChar2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 3) => { + MTLVertexFormat::UChar3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U8, 4) => { + MTLVertexFormat::UChar4Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 2) => { + MTLVertexFormat::Char2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 3) => { + MTLVertexFormat::Char3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 4) => { + MTLVertexFormat::Char4Normalized + } + (VertexAttrClass::Int, VertexAttrType::I16, 2) => MTLVertexFormat::Short2, + (VertexAttrClass::Int, VertexAttrType::I16, 3) => MTLVertexFormat::Short3, + (VertexAttrClass::Int, VertexAttrType::I16, 4) => MTLVertexFormat::Short4, + (VertexAttrClass::Int, VertexAttrType::U16, 2) => MTLVertexFormat::UShort2, + (VertexAttrClass::Int, VertexAttrType::U16, 3) => MTLVertexFormat::UShort3, + (VertexAttrClass::Int, VertexAttrType::U16, 4) => MTLVertexFormat::UShort4, + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 2) => { + MTLVertexFormat::UShort2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 3) => { + MTLVertexFormat::UShort3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 4) => { + MTLVertexFormat::UShort4Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 2) => { + MTLVertexFormat::Short2Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 3) => { + MTLVertexFormat::Short3Normalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 4) => { + MTLVertexFormat::Short4Normalized + } + (VertexAttrClass::Float, VertexAttrType::F32, 1) => MTLVertexFormat::Float, + (VertexAttrClass::Float, VertexAttrType::F32, 2) => MTLVertexFormat::Float2, + (VertexAttrClass::Float, VertexAttrType::F32, 3) => MTLVertexFormat::Float3, + (VertexAttrClass::Float, VertexAttrType::F32, 4) => MTLVertexFormat::Float4, + (VertexAttrClass::Int, VertexAttrType::I8, 1) => MTLVertexFormat::Char, + (VertexAttrClass::Int, VertexAttrType::U8, 1) => MTLVertexFormat::UChar, + (VertexAttrClass::FloatNorm, VertexAttrType::I8, 1) => MTLVertexFormat::CharNormalized, + (VertexAttrClass::Int, VertexAttrType::I16, 1) => MTLVertexFormat::Short, + (VertexAttrClass::Int, VertexAttrType::U16, 1) => MTLVertexFormat::UShort, + (VertexAttrClass::FloatNorm, VertexAttrType::U16, 1) => { + MTLVertexFormat::UShortNormalized + } + (VertexAttrClass::FloatNorm, VertexAttrType::I16, 1) => { + MTLVertexFormat::ShortNormalized + } + (attr_class, attr_type, attr_size) => { + panic!("Unsupported vertex class/type/size combination: {:?}/{:?}/{}!", + attr_class, + attr_type, + attr_size) + } + }; + attr_info.set_format(format); + attr_info.set_offset(descriptor.offset as u64); + let buffer_index = descriptor.buffer_index as u64 + FIRST_VERTEX_BUFFER_INDEX; + attr_info.set_buffer_index(buffer_index); + + // FIXME(pcwalton): Metal separates out per-buffer info from per-vertex info, while our + // GL-like API does not. So we end up setting this state over and over again. Not great. + let layout = vertex_array.descriptor.layouts().object_at(buffer_index as usize).unwrap(); + if descriptor.divisor == 0 { + layout.set_step_function(MTLVertexStepFunction::PerVertex); + layout.set_step_rate(1); + } else { + layout.set_step_function(MTLVertexStepFunction::PerInstance); + layout.set_step_rate(descriptor.divisor as u64); + } + layout.set_stride(descriptor.stride as u64); + } + + fn create_framebuffer(&self, texture: MetalTexture) -> MetalFramebuffer { + MetalFramebuffer(texture) + } + + fn create_buffer(&self) -> MetalBuffer { + MetalBuffer { buffer: Rc::new(RefCell::new(None)) } + } + + fn allocate_buffer(&self, + buffer: &MetalBuffer, + data: BufferData, + _: BufferTarget, + mode: BufferUploadMode) { + let mut options = match mode { + BufferUploadMode::Static => MTLResourceOptions::CPUCacheModeWriteCombined, + BufferUploadMode::Dynamic => MTLResourceOptions::CPUCacheModeDefaultCache, + }; + options |= MTLResourceOptions::StorageModeManaged; + + match data { + BufferData::Uninitialized(size) => { + let size = (size * mem::size_of::()) as u64; + let new_buffer = self.device.new_buffer(size, options); + *buffer.buffer.borrow_mut() = Some(new_buffer); + } + BufferData::Memory(slice) => { + let size = (slice.len() * mem::size_of::()) as u64; + let new_buffer = self.device.new_buffer_with_data(slice.as_ptr() as *const _, + size, + options); + *buffer.buffer.borrow_mut() = Some(new_buffer); + } + } + } + + fn framebuffer_texture<'f>(&self, framebuffer: &'f MetalFramebuffer) -> &'f MetalTexture { + &framebuffer.0 + } + + fn texture_size(&self, texture: &MetalTexture) -> Vector2I { + Vector2I::new(texture.texture.width() as i32, texture.texture.height() as i32) + } + + fn upload_to_texture(&self, texture: &MetalTexture, size: Vector2I, data: &[u8]) { + assert!(data.len() >= size.x() as usize * size.y() as usize); + let format = self.texture_format(&texture.texture).expect("Unexpected texture format!"); + assert!(format == TextureFormat::R8 || format == TextureFormat::RGBA8); + + let origin = MTLOrigin { x: 0, y: 0, z: 0 }; + let size = MTLSize { width: size.x() as u64, height: size.y() as u64, depth: 1 }; + let region = MTLRegion { origin, size }; + let stride = size.width * format.channels() as u64; + texture.texture.replace_region(region, 0, stride, data.as_ptr() as *const _); + + texture.dirty.set(true); + } + + fn read_pixels(&self, target: &RenderTarget, viewport: RectI) -> TextureData { + let texture = self.render_target_color_texture(target); + self.synchronize_texture(&texture); + + let (origin, size) = (viewport.origin(), viewport.size()); + let metal_origin = MTLOrigin { x: origin.x() as u64, y: origin.y() as u64, z: 0 }; + let metal_size = MTLSize { width: size.x() as u64, height: size.y() as u64, depth: 1 }; + let metal_region = MTLRegion { origin: metal_origin, size: metal_size }; + + let format = self.texture_format(&texture) + .expect("Unexpected framebuffer texture format!"); + match format { + TextureFormat::R8 | TextureFormat::RGBA8 => { + let channels = format.channels(); + let stride = size.x() as usize * channels; + let mut pixels = vec![0; stride * size.y() as usize]; + texture.get_bytes(pixels.as_mut_ptr() as *mut _, metal_region, 0, stride as u64); + TextureData::U8(pixels) + } + TextureFormat::R16F => { + let stride = size.x() as usize; + let mut pixels = vec![0; stride * size.y() as usize]; + texture.get_bytes(pixels.as_mut_ptr() as *mut _, + metal_region, + 0, + stride as u64 * 2); + TextureData::U16(pixels) + } + } + } + + fn begin_commands(&self) { + self.command_buffers.borrow_mut().push(self.command_queue.new_command_buffer().retain()); + } + + fn end_commands(&self) { + let command_buffer = self.command_buffers.borrow_mut().pop().unwrap(); + command_buffer.commit(); + } + + fn draw_arrays(&self, index_count: u32, render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + encoder.draw_primitives(primitive, 0, index_count as u64); + encoder.end_encoding(); + } + + fn draw_elements(&self, index_count: u32, render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + let index_type = MTLIndexType::UInt32; + let index_count = index_count as u64; + let index_buffer = render_state.vertex_array + .index_buffer + .borrow(); + let index_buffer = index_buffer.as_ref().expect("No index buffer bound to VAO!"); + let index_buffer = index_buffer.buffer.borrow(); + let index_buffer = index_buffer.as_ref().expect("Index buffer not allocated!"); + encoder.draw_indexed_primitives(primitive, index_count, index_type, index_buffer, 0); + encoder.end_encoding(); + } + + fn draw_elements_instanced(&self, + index_count: u32, + instance_count: u32, + render_state: &RenderState) { + let encoder = self.prepare_to_draw(render_state); + let primitive = render_state.primitive.to_metal_primitive(); + let index_type = MTLIndexType::UInt32; + let index_buffer = render_state.vertex_array + .index_buffer + .borrow(); + let index_buffer = index_buffer.as_ref().expect("No index buffer bound to VAO!"); + let index_buffer = index_buffer.buffer.borrow(); + let index_buffer = index_buffer.as_ref().expect("Index buffer not allocated!"); + encoder.draw_indexed_primitives_instanced(primitive, + index_count as u64, + index_type, + index_buffer, + 0, + instance_count as u64); + encoder.end_encoding(); + } + + fn create_timer_query(&self) -> Arc { + let event_value = self.next_timer_query_event_value.get(); + self.next_timer_query_event_value.set(event_value + 2); + + let query = Arc::new(MetalTimerQuery { + event_value, + start_time: Cell::new(None), + end_time: Cell::new(None), + }); + + let captured_query = query.clone(); + let start_block = ConcreteBlock::new(move |_: *mut Object, _: u64| { + captured_query.start_time.set(Some(Instant::now())) + }); + let captured_query = query.clone(); + let end_block = ConcreteBlock::new(move |_: *mut Object, _: u64| { + captured_query.end_time.set(Some(Instant::now())) + }); + self.shared_event.notify_listener_at_value(&self.shared_event_listener, + event_value, + start_block.copy()); + self.shared_event.notify_listener_at_value(&self.shared_event_listener, + event_value + 1, + end_block.copy()); + + query + } + + fn begin_timer_query(&self, query: &Arc) { + self.command_buffers + .borrow_mut() + .last() + .unwrap() + .encode_signal_event(&self.shared_event, query.event_value); + } + + fn end_timer_query(&self, query: &Arc) { + self.command_buffers + .borrow_mut() + .last() + .unwrap() + .encode_signal_event(&self.shared_event, query.event_value + 1); + } + + fn get_timer_query(&self, query: &Arc) -> Option { + match (query.start_time.get(), query.end_time.get()) { + (Some(start_time), Some(end_time)) => Some(end_time - start_time), + _ => None, + } + } + + #[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/metal/{}.{}s.metal", name, suffix); + self.create_shader_from_source(name, &resources.slurp(&path).unwrap(), kind) + } +} + +impl MetalDevice { + fn get_uniform_index(&self, shader: &MetalShader, name: &str) -> Option { + let uniforms = shader.uniforms.borrow(); + let struct_type = match *uniforms { + ShaderUniforms::Unknown => panic!("get_uniform_index() called before reflection!"), + ShaderUniforms::NoUniforms => return None, + ShaderUniforms::Uniforms { ref struct_type, .. } => struct_type, + }; + let main_member = match struct_type.member_from_name(&format!("u{}", name)) { + None => return None, + Some(main_member) => main_member, + }; + let main_index = main_member.argument_index(); + let sampler_index = match struct_type.member_from_name(&format!("u{}Smplr", name)) { + None => None, + Some(sampler_member) => Some(sampler_member.argument_index()), + }; + Some(MetalUniformIndex { main: main_index, sampler: sampler_index }) + } + + fn populate_uniform_indices_if_necessary(&self, + uniform: &MetalUniform, + program: &MetalProgram) { + + let mut indices = uniform.indices.borrow_mut(); + if indices.is_some() { + return; + } + + *indices = Some(MetalUniformIndices { + vertex: self.get_uniform_index(&program.vertex, &uniform.name), + fragment: self.get_uniform_index(&program.fragment, &uniform.name), + }); + } + + fn render_target_color_texture(&self, render_target: &RenderTarget) + -> Texture { + match *render_target { + RenderTarget::Default {..} => self.drawable.texture().retain(), + RenderTarget::Framebuffer(framebuffer) => framebuffer.0.texture.retain(), + } + } + + fn render_target_depth_texture(&self, render_target: &RenderTarget) + -> Option { + match *render_target { + RenderTarget::Default {..} => Some(self.main_depth_stencil_texture.retain()), + RenderTarget::Framebuffer(_) => None, + } + } + + fn render_target_has_depth(&self, render_target: &RenderTarget) -> bool { + match *render_target { + RenderTarget::Default {..} => true, + RenderTarget::Framebuffer(_) => false, + } + } + + fn prepare_to_draw(&self, render_state: &RenderState) -> RenderCommandEncoder { + let command_buffers = self.command_buffers.borrow(); + let command_buffer = command_buffers.last().unwrap(); + + // FIXME(pcwalton): Is this necessary? + let mut blit_command_encoder = None; + for texture in render_state.textures { + if !texture.dirty.get() { + continue; + } + if blit_command_encoder.is_none() { + blit_command_encoder = Some(command_buffer.new_blit_command_encoder()); + } + let blit_command_encoder = blit_command_encoder.as_ref().unwrap(); + blit_command_encoder.synchronize_resource(&texture.texture); + texture.dirty.set(false); + } + if let Some(blit_command_encoder) = blit_command_encoder { + blit_command_encoder.end_encoding(); + } + + let render_pass_descriptor = self.create_render_pass_descriptor(render_state); + + let encoder = command_buffer.new_render_command_encoder(&render_pass_descriptor).retain(); + self.set_viewport(&encoder, &render_state.viewport); + + let render_pipeline_descriptor = RenderPipelineDescriptor::new(); + render_pipeline_descriptor.set_vertex_function(Some(&render_state.program + .vertex + .function)); + render_pipeline_descriptor.set_fragment_function(Some(&render_state.program + .fragment + .function)); + render_pipeline_descriptor.set_vertex_descriptor(Some(&render_state.vertex_array + .descriptor)); + + // Create render pipeline state. + let pipeline_color_attachment = render_pipeline_descriptor.color_attachments() + .object_at(0) + .unwrap(); + self.prepare_pipeline_color_attachment_for_render(pipeline_color_attachment, + render_state); + + if self.render_target_has_depth(render_state.target) { + let depth_stencil_format = MTLPixelFormat::Depth32Float_Stencil8; + render_pipeline_descriptor.set_depth_attachment_pixel_format(depth_stencil_format); + render_pipeline_descriptor.set_stencil_attachment_pixel_format(depth_stencil_format); + } + + let reflection_options = MTLPipelineOption::ArgumentInfo | + MTLPipelineOption::BufferTypeInfo; + let (render_pipeline_state, reflection) = + self.device.real_new_render_pipeline_state_with_reflection(&render_pipeline_descriptor, + reflection_options); + + self.populate_shader_uniforms_if_necessary(&render_state.program.vertex, &reflection); + self.populate_shader_uniforms_if_necessary(&render_state.program.fragment, &reflection); + + for (vertex_buffer_index, vertex_buffer) in render_state.vertex_array + .vertex_buffers + .borrow() + .iter() + .enumerate() { + let real_index = vertex_buffer_index as u64 + FIRST_VERTEX_BUFFER_INDEX; + let buffer = vertex_buffer.buffer.borrow(); + let buffer = buffer.as_ref().map(|buffer| buffer.as_ref()).unwrap(); + encoder.set_vertex_buffer(real_index, Some(buffer), 0); + encoder.use_resource(buffer, MTLResourceUsage::Read); + } + + self.set_uniforms(&encoder, render_state); + encoder.set_render_pipeline_state(&render_pipeline_state); + self.set_depth_stencil_state(&encoder, render_state); + encoder + } + + fn populate_shader_uniforms_if_necessary(&self, + shader: &MetalShader, + reflection: &RenderPipelineReflectionRef) { + let mut uniforms = shader.uniforms.borrow_mut(); + match *uniforms { + ShaderUniforms::Unknown => {} + ShaderUniforms::NoUniforms | ShaderUniforms::Uniforms { .. } => return, + } + + let arguments = match shader.function.function_type() { + MTLFunctionType::Vertex => reflection.real_vertex_arguments(), + MTLFunctionType::Fragment => reflection.real_fragment_arguments(), + _ => panic!("Unexpected shader function type!"), + }; + + let mut has_descriptor_set = false; + for argument_index in 0..arguments.len() { + let argument = arguments.object_at(argument_index); + if argument.name() == "spvDescriptorSet0" { + has_descriptor_set = true; + break; + } + } + if !has_descriptor_set { + *uniforms = ShaderUniforms::NoUniforms; + return; + } + + let (encoder, argument) = shader.function.new_argument_encoder_with_reflection(0); + match argument.buffer_data_type() { + MTLDataType::Struct => {} + data_type => { + panic!("Unexpected data type for argument buffer: {}!", data_type as u32) + } + } + let struct_type = argument.buffer_struct_type().retain(); + *uniforms = ShaderUniforms::Uniforms { encoder, struct_type }; + } + + fn create_argument_buffer(&self, shader: &MetalShader) -> Option { + let uniforms = shader.uniforms.borrow(); + let encoder = match *uniforms { + ShaderUniforms::Unknown => unreachable!(), + ShaderUniforms::NoUniforms => return None, + ShaderUniforms::Uniforms { ref encoder, .. } => encoder, + }; + + let buffer_options = MTLResourceOptions::CPUCacheModeDefaultCache | + MTLResourceOptions::StorageModeManaged; + let buffer = self.device.new_buffer(encoder.encoded_length(), buffer_options); + encoder.set_argument_buffer(&buffer, 0); + Some(buffer) + } + + fn set_uniforms(&self, + render_command_encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + let vertex_argument_buffer = self.create_argument_buffer(&render_state.program.vertex); + let fragment_argument_buffer = self.create_argument_buffer(&render_state.program.fragment); + + let vertex_uniforms = render_state.program.vertex.uniforms.borrow(); + let fragment_uniforms = render_state.program.fragment.uniforms.borrow(); + + let (mut have_vertex_uniforms, mut have_fragment_uniforms) = (false, false); + if let ShaderUniforms::Uniforms { .. } = *vertex_uniforms { + have_vertex_uniforms = true; + let vertex_argument_buffer = vertex_argument_buffer.as_ref().unwrap(); + render_command_encoder.use_resource(vertex_argument_buffer, MTLResourceUsage::Read); + render_command_encoder.set_vertex_buffer(0, Some(vertex_argument_buffer), 0); + } + if let ShaderUniforms::Uniforms { .. } = *fragment_uniforms { + have_fragment_uniforms = true; + let fragment_argument_buffer = fragment_argument_buffer.as_ref().unwrap(); + render_command_encoder.use_resource(fragment_argument_buffer, MTLResourceUsage::Read); + render_command_encoder.set_fragment_buffer(0, Some(fragment_argument_buffer), 0); + } + + if !have_vertex_uniforms && !have_fragment_uniforms { + return; + } + + let (mut uniform_buffer_data, mut uniform_buffer_ranges) = (vec![], vec![]); + for &(_, uniform_data) in render_state.uniforms.iter() { + let start_index = uniform_buffer_data.len(); + match uniform_data { + UniformData::Int(value) => { + uniform_buffer_data.write_i32::(value).unwrap() + } + UniformData::Mat4(matrix) => { + for column in &matrix { + uniform_buffer_data.write_f32::(column.x()).unwrap(); + uniform_buffer_data.write_f32::(column.y()).unwrap(); + uniform_buffer_data.write_f32::(column.z()).unwrap(); + uniform_buffer_data.write_f32::(column.w()).unwrap(); + } + } + UniformData::Vec2(vector) => { + uniform_buffer_data.write_f32::(vector.x()).unwrap(); + uniform_buffer_data.write_f32::(vector.y()).unwrap(); + } + UniformData::Vec4(vector) => { + uniform_buffer_data.write_f32::(vector.x()).unwrap(); + uniform_buffer_data.write_f32::(vector.y()).unwrap(); + uniform_buffer_data.write_f32::(vector.z()).unwrap(); + uniform_buffer_data.write_f32::(vector.w()).unwrap(); + } + UniformData::TextureUnit(_) => {} + } + let end_index = uniform_buffer_data.len(); + uniform_buffer_ranges.push(start_index..end_index); + } + + let buffer_options = MTLResourceOptions::CPUCacheModeWriteCombined | + MTLResourceOptions::StorageModeManaged; + let data_buffer = self.device + .new_buffer_with_data(uniform_buffer_data.as_ptr() as *const _, + uniform_buffer_data.len() as u64, + buffer_options); + + for (&(uniform, ref uniform_data), buffer_range) in + render_state.uniforms.iter().zip(uniform_buffer_ranges.iter()) { + self.populate_uniform_indices_if_necessary(uniform, &render_state.program); + let indices = uniform.indices.borrow_mut(); + let indices = indices.as_ref().unwrap(); + if let Some(vertex_index) = indices.vertex { + if let ShaderUniforms::Uniforms { + encoder: ref argument_encoder, + .. + } = *vertex_uniforms { + self.set_uniform(vertex_index, + argument_encoder, + uniform_data, + &data_buffer, + buffer_range.start as u64, + render_command_encoder, + render_state); + } + } + if let Some(fragment_index) = indices.fragment { + if let ShaderUniforms::Uniforms { + encoder: ref argument_encoder, + .. + } = *fragment_uniforms { + self.set_uniform(fragment_index, + argument_encoder, + uniform_data, + &data_buffer, + buffer_range.start as u64, + render_command_encoder, + render_state); + } + } + } + + render_command_encoder.use_resource(&data_buffer, MTLResourceUsage::Read); + + if let Some(vertex_argument_buffer) = vertex_argument_buffer { + let range = NSRange::new(0, vertex_argument_buffer.length()); + vertex_argument_buffer.did_modify_range(range); + } + if let Some(fragment_argument_buffer) = fragment_argument_buffer { + let range = NSRange::new(0, fragment_argument_buffer.length()); + fragment_argument_buffer.did_modify_range(range); + } + } + + fn set_uniform(&self, + argument_index: MetalUniformIndex, + argument_encoder: &ArgumentEncoder, + uniform_data: &UniformData, + buffer: &Buffer, + buffer_offset: u64, + render_command_encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + match *uniform_data { + UniformData::TextureUnit(unit) => { + let texture = render_state.textures[unit as usize]; + argument_encoder.set_texture(&texture.texture, argument_index.main); + let mut resource_usage = MTLResourceUsage::Read; + if let Some(sampler_index) = argument_index.sampler { + argument_encoder.set_sampler_state(&self.sampler, sampler_index); + resource_usage |= MTLResourceUsage::Sample; + } + render_command_encoder.use_resource(&texture.texture, resource_usage); + } + _ => argument_encoder.set_buffer(buffer, buffer_offset, argument_index.main), + } + } + + fn prepare_pipeline_color_attachment_for_render( + &self, + pipeline_color_attachment: &RenderPipelineColorAttachmentDescriptorRef, + render_state: &RenderState) { + let pixel_format = self.render_target_color_texture(&render_state.target).pixel_format(); + pipeline_color_attachment.set_pixel_format(pixel_format); + + let blending_enabled = render_state.options.blend != BlendState::Off; + pipeline_color_attachment.set_blending_enabled(blending_enabled); + match render_state.options.blend { + BlendState::Off => {} + BlendState::RGBOneAlphaOne => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + BlendState::RGBOneAlphaOneMinusSrcAlpha => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_rgb_blend_factor( + MTLBlendFactor::OneMinusSourceAlpha); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha => { + pipeline_color_attachment.set_source_rgb_blend_factor(MTLBlendFactor::SourceAlpha); + pipeline_color_attachment.set_destination_rgb_blend_factor( + MTLBlendFactor::OneMinusSourceAlpha); + pipeline_color_attachment.set_source_alpha_blend_factor(MTLBlendFactor::One); + pipeline_color_attachment.set_destination_alpha_blend_factor(MTLBlendFactor::One); + } + } + + if render_state.options.color_mask { + pipeline_color_attachment.set_write_mask(MTLColorWriteMask::all()); + } else { + pipeline_color_attachment.set_write_mask(MTLColorWriteMask::empty()); + } + } + + fn create_render_pass_descriptor(&self, render_state: &RenderState) + -> RenderPassDescriptor { + let render_pass_descriptor = RenderPassDescriptor::new().retain(); + let color_attachment = render_pass_descriptor.color_attachments().object_at(0).unwrap(); + color_attachment.set_texture(Some(&self.render_target_color_texture(render_state.target))); + + match render_state.options.clear_ops.color { + Some(color) => { + let color = MTLClearColor::new(color.r() as f64, + color.g() as f64, + color.b() as f64, + color.a() as f64); + color_attachment.set_clear_color(color); + color_attachment.set_load_action(MTLLoadAction::Clear); + } + None => color_attachment.set_load_action(MTLLoadAction::Load), + } + color_attachment.set_store_action(MTLStoreAction::Store); + + let depth_stencil_texture = self.render_target_depth_texture(render_state.target); + if let Some(depth_stencil_texture) = depth_stencil_texture { + let depth_attachment = render_pass_descriptor.depth_attachment().unwrap(); + let stencil_attachment = render_pass_descriptor.stencil_attachment().unwrap(); + depth_attachment.set_texture(Some(&depth_stencil_texture)); + stencil_attachment.set_texture(Some(&depth_stencil_texture)); + + match render_state.options.clear_ops.depth { + Some(depth) => { + depth_attachment.set_clear_depth(depth as f64); + depth_attachment.set_load_action(MTLLoadAction::Clear); + } + None => depth_attachment.set_load_action(MTLLoadAction::Load), + } + depth_attachment.set_store_action(MTLStoreAction::Store); + + match render_state.options.clear_ops.stencil { + Some(value) => { + stencil_attachment.set_clear_stencil(value as u32); + stencil_attachment.set_load_action(MTLLoadAction::Clear); + } + None => stencil_attachment.set_load_action(MTLLoadAction::Load), + } + stencil_attachment.set_store_action(MTLStoreAction::Store); + } + + render_pass_descriptor + } + + fn set_depth_stencil_state(&self, + encoder: &RenderCommandEncoderRef, + render_state: &RenderState) { + let depth_stencil_descriptor = DepthStencilDescriptor::new(); + + match render_state.options.depth { + Some(depth_state) => { + let compare_function = depth_state.func.to_metal_compare_function(); + depth_stencil_descriptor.set_depth_compare_function(compare_function); + depth_stencil_descriptor.set_depth_write_enabled(depth_state.write); + } + None => { + depth_stencil_descriptor.set_depth_compare_function(MTLCompareFunction::Always); + depth_stencil_descriptor.set_depth_write_enabled(false); + } + } + + match render_state.options.stencil { + Some(stencil_state) => { + let stencil_descriptor = StencilDescriptor::new(); + let compare_function = stencil_state.func.to_metal_compare_function(); + let (pass_operation, write_mask) = if stencil_state.write { + (MTLStencilOperation::Replace, stencil_state.mask) + } else { + (MTLStencilOperation::Keep, 0) + }; + stencil_descriptor.set_stencil_compare_function(compare_function); + stencil_descriptor.set_stencil_failure_operation(MTLStencilOperation::Keep); + stencil_descriptor.set_depth_failure_operation(MTLStencilOperation::Keep); + stencil_descriptor.set_depth_stencil_pass_operation(pass_operation); + stencil_descriptor.set_write_mask(write_mask); + depth_stencil_descriptor.set_front_face_stencil(Some(&stencil_descriptor)); + depth_stencil_descriptor.set_back_face_stencil(Some(&stencil_descriptor)); + encoder.set_stencil_reference_value(stencil_state.reference); + } + None => { + depth_stencil_descriptor.set_front_face_stencil(None); + depth_stencil_descriptor.set_back_face_stencil(None); + } + } + + let depth_stencil_state = self.device.new_depth_stencil_state(&depth_stencil_descriptor); + encoder.set_depth_stencil_state(&depth_stencil_state); + } + + fn texture_format(&self, texture: &Texture) -> Option { + match texture.pixel_format() { + MTLPixelFormat::R8Unorm => Some(TextureFormat::R8), + MTLPixelFormat::R16Float => Some(TextureFormat::R16F), + MTLPixelFormat::RGBA8Unorm => Some(TextureFormat::RGBA8), + _ => None, + } + } + + fn set_viewport(&self, encoder: &RenderCommandEncoderRef, viewport: &RectI) { + encoder.set_viewport(MTLViewport { + originX: viewport.origin().x() as f64, + originY: viewport.origin().y() as f64, + width: viewport.size().x() as f64, + height: viewport.size().y() as f64, + znear: 0.0, + zfar: 1.0, + }) + } + + fn synchronize_texture(&self, texture: &Texture) { + { + let command_buffers = self.command_buffers.borrow(); + let encoder = command_buffers.last().unwrap().new_blit_command_encoder(); + encoder.synchronize_resource(&texture); + encoder.end_encoding(); + } + + self.end_commands(); + self.begin_commands(); + } +} + +trait DeviceExtra { + fn create_depth_stencil_texture(&self, size: Vector2I) -> Texture; +} + +impl DeviceExtra for metal::Device { + fn create_depth_stencil_texture(&self, size: Vector2I) -> Texture { + let descriptor = TextureDescriptor::new(); + descriptor.set_texture_type(MTLTextureType::D2); + descriptor.set_pixel_format(MTLPixelFormat::Depth32Float_Stencil8); + descriptor.set_width(size.x() as u64); + descriptor.set_height(size.y() as u64); + descriptor.set_storage_mode(MTLStorageMode::Private); + descriptor.set_usage(MTLTextureUsage::Unknown); + self.new_texture(&descriptor) + } +} + +// Conversion helpers + +trait DepthFuncExt { + fn to_metal_compare_function(self) -> MTLCompareFunction; +} + +impl DepthFuncExt for DepthFunc { + fn to_metal_compare_function(self) -> MTLCompareFunction { + match self { + DepthFunc::Less => MTLCompareFunction::Less, + DepthFunc::Always => MTLCompareFunction::Always, + } + } +} + +trait PrimitiveExt { + fn to_metal_primitive(self) -> MTLPrimitiveType; +} + +impl PrimitiveExt for Primitive { + fn to_metal_primitive(self) -> MTLPrimitiveType { + match self { + Primitive::Triangles => MTLPrimitiveType::Triangle, + Primitive::Lines => MTLPrimitiveType::Line, + } + } +} + +trait StencilFuncExt { + fn to_metal_compare_function(self) -> MTLCompareFunction; +} + +impl StencilFuncExt for StencilFunc { + fn to_metal_compare_function(self) -> MTLCompareFunction { + match self { + StencilFunc::Always => MTLCompareFunction::Always, + StencilFunc::Equal => MTLCompareFunction::Equal, + } + } +} + +trait UniformDataExt { + fn as_bytes(&self) -> Option<&[u8]>; +} + +impl UniformDataExt for UniformData { + fn as_bytes(&self) -> Option<&[u8]> { + unsafe { + match *self { + UniformData::TextureUnit(_) => None, + UniformData::Int(ref data) => { + Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 1)) + } + UniformData::Mat4(ref data) => { + Some(slice::from_raw_parts(&data[0] as *const F32x4 as *const u8, 4 * 16)) + } + UniformData::Vec2(ref data) => { + Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 2)) + } + UniformData::Vec4(ref data) => { + Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4)) + } + } + } + } +} + +// Extra structs missing from `metal-rs` + +bitflags! { + struct MTLPipelineOption: NSUInteger { + const ArgumentInfo = 1 << 0; + const BufferTypeInfo = 1 << 1; + } +} + +// Extra objects missing from `metal-rs` + +struct ArgumentArray(*mut Object); + +impl Drop for ArgumentArray { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl ArgumentArray { + unsafe fn from_ptr(object: *mut Object) -> ArgumentArray { + ArgumentArray(msg_send![object, retain]) + } + + fn len(&self) -> u64 { + unsafe { msg_send![self.0, count] } + } + + fn object_at(&self, index: u64) -> Argument { + unsafe { + let argument: *mut MTLArgument = msg_send![self.0, objectAtIndex:index]; + Argument::from_ptr(msg_send![argument, retain]) + } + } +} + +struct SharedEvent(*mut Object); + +impl Drop for SharedEvent { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl SharedEvent { + fn notify_listener_at_value(&self, + listener: &SharedEventListener, + value: u64, + block: RcBlock<(*mut Object, u64), ()>) { + unsafe { + // If the block doesn't have a signature, this segfaults. + let block = &*block as + *const Block<(*mut Object, u64), ()> as + *mut Block<(*mut Object, u64), ()> as + *mut BlockBase<(*mut Object, u64), ()>; + (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE; + (*block).extra = &BLOCK_EXTRA; + msg_send![self.0, notifyListener:listener.0 atValue:value block:block]; + mem::forget(block); + } + + extern "C" fn dtor(_: *mut BlockBase<(*mut Object, u64), ()>) {} + + static mut SIGNATURE: &[u8] = b"v16@?0Q8\0"; + static mut SIGNATURE_PTR: *const i8 = unsafe { &SIGNATURE[0] as *const u8 as *const i8 }; + static mut BLOCK_EXTRA: BlockExtra<(*mut Object, u64), ()> = BlockExtra { + unknown0: 0 as *mut i32, + unknown1: 0 as *mut i32, + unknown2: 0 as *mut i32, + dtor: dtor, + signature: unsafe { &SIGNATURE_PTR }, + }; + } +} + +struct SharedEventListener(*mut Object); + +impl Drop for SharedEventListener { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl SharedEventListener { + fn new() -> SharedEventListener { + unsafe { + let listener: *mut Object = msg_send![class!(MTLSharedEventListener), alloc]; + SharedEventListener(msg_send![listener, init]) + } + } +} + +struct VertexAttributeArray(*mut Object); + +impl Drop for VertexAttributeArray { + fn drop(&mut self) { + unsafe { msg_send![self.0, release] } + } +} + +impl VertexAttributeArray { + unsafe fn from_ptr(object: *mut Object) -> VertexAttributeArray { + VertexAttributeArray(msg_send![object, retain]) + } + + fn len(&self) -> u64 { + unsafe { msg_send![self.0, count] } + } + + fn object_at(&self, index: u64) -> &VertexAttributeRef { + unsafe { VertexAttributeRef::from_ptr(msg_send![self.0, objectAtIndex:index]) } + } +} + +// Extra methods missing from `metal-rs` + +trait CoreAnimationLayerExt { + fn device(&self) -> metal::Device; +} + +impl CoreAnimationLayerExt for CoreAnimationLayer { + fn device(&self) -> metal::Device { + unsafe { + let device: *mut MTLDevice = msg_send![self.as_ptr(), device]; + metal::Device::from_ptr(msg_send![device, retain]) + } + } +} + +trait CommandBufferExt { + fn encode_signal_event(&self, event: &SharedEvent, value: u64); +} + +impl CommandBufferExt for CommandBuffer { + fn encode_signal_event(&self, event: &SharedEvent, value: u64) { + unsafe { + msg_send![self.as_ptr(), encodeSignalEvent:event.0 value:value] + } + } +} + +trait DeviceExt { + // `new_render_pipeline_state_with_reflection()` in `metal-rs` doesn't correctly initialize the + // `reflection` argument. This is a better definition. + fn real_new_render_pipeline_state_with_reflection(&self, + descriptor: &RenderPipelineDescriptor, + options: MTLPipelineOption) + -> (RenderPipelineState, + RenderPipelineReflection); + fn new_shared_event(&self) -> SharedEvent; +} + +impl DeviceExt for metal::Device { + fn real_new_render_pipeline_state_with_reflection(&self, + descriptor: &RenderPipelineDescriptor, + options: MTLPipelineOption) + -> (RenderPipelineState, + RenderPipelineReflection) { + unsafe { + let mut reflection_ptr: *mut MTLRenderPipelineReflection = ptr::null_mut(); + let mut error_ptr: *mut Object = ptr::null_mut(); + let render_pipeline_state_ptr: *mut MTLRenderPipelineState = + msg_send![self.as_ptr(), + newRenderPipelineStateWithDescriptor:descriptor.as_ptr() + options:options + reflection:&mut reflection_ptr + error:&mut error_ptr]; + if !error_ptr.is_null() { + let description: CFStringRef = msg_send![error_ptr, description]; + panic!("Render pipeline state construction failed: {}", + CFString::wrap_under_get_rule(description).to_string()); + } + assert!(!render_pipeline_state_ptr.is_null()); + assert!(!reflection_ptr.is_null()); + (RenderPipelineState::from_ptr(render_pipeline_state_ptr), + RenderPipelineReflection::from_ptr(msg_send![reflection_ptr, retain])) + } + } + + fn new_shared_event(&self) -> SharedEvent { + unsafe { SharedEvent(msg_send![self.as_ptr(), newSharedEvent]) } + } +} + +trait FunctionExt { + // `vertex_attributes()` in `metal-rs` segfaults! This is a better definition. + fn real_vertex_attributes(&self) -> VertexAttributeArray; + fn new_argument_encoder_with_reflection(&self, buffer_index: u64) + -> (ArgumentEncoder, Argument); +} + +impl FunctionExt for Function { + fn real_vertex_attributes(&self) -> VertexAttributeArray { + unsafe { + VertexAttributeArray::from_ptr(msg_send![(*self).as_ptr(), vertexAttributes]) + } + } + + fn new_argument_encoder_with_reflection(&self, buffer_index: u64) + -> (ArgumentEncoder, Argument) { + unsafe { + let mut reflection = ptr::null_mut(); + let encoder: *mut MTLArgumentEncoder = + msg_send![self.as_ptr(), newArgumentEncoderWithBufferIndex:buffer_index + reflection:&mut reflection]; + msg_send![reflection, retain]; + (ArgumentEncoder::from_ptr(encoder), Argument::from_ptr(reflection)) + } + } +} + +trait RenderPipelineReflectionExt { + // `vertex_arguments()` in `metal-rs` segfaults! This is a better definition. + fn real_vertex_arguments(&self) -> ArgumentArray; + // `fragment_arguments()` in `metal-rs` segfaults! This is a better definition. + fn real_fragment_arguments(&self) -> ArgumentArray; +} + +impl RenderPipelineReflectionExt for RenderPipelineReflectionRef { + fn real_vertex_arguments(&self) -> ArgumentArray { + unsafe { ArgumentArray::from_ptr(msg_send![self.as_ptr(), vertexArguments]) } + } + + fn real_fragment_arguments(&self) -> ArgumentArray { + unsafe { ArgumentArray::from_ptr(msg_send![self.as_ptr(), fragmentArguments]) } + } +} + +trait StructMemberExt { + fn argument_index(&self) -> u64; +} + +impl StructMemberExt for StructMemberRef { + fn argument_index(&self) -> u64 { + unsafe { msg_send![self.as_ptr(), argumentIndex] } + } +} + +// Memory management helpers + +trait Retain { + type Owned; + fn retain(&self) -> Self::Owned; +} + +impl Retain for CommandBufferRef { + type Owned = CommandBuffer; + fn retain(&self) -> CommandBuffer { + unsafe { CommandBuffer::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for CoreAnimationDrawableRef { + type Owned = CoreAnimationDrawable; + fn retain(&self) -> CoreAnimationDrawable { + unsafe { CoreAnimationDrawable::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for CoreAnimationLayerRef { + type Owned = CoreAnimationLayer; + fn retain(&self) -> CoreAnimationLayer { + unsafe { CoreAnimationLayer::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for RenderCommandEncoderRef { + type Owned = RenderCommandEncoder; + fn retain(&self) -> RenderCommandEncoder { + unsafe { RenderCommandEncoder::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for RenderPassDescriptorRef { + type Owned = RenderPassDescriptor; + fn retain(&self) -> RenderPassDescriptor { + unsafe { RenderPassDescriptor::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for StructTypeRef { + type Owned = StructType; + fn retain(&self) -> StructType { + unsafe { StructType::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for TextureRef { + type Owned = Texture; + fn retain(&self) -> Texture { + unsafe { Texture::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for VertexAttributeRef { + type Owned = VertexAttribute; + fn retain(&self) -> VertexAttribute { + unsafe { VertexAttribute::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +impl Retain for VertexDescriptorRef { + type Owned = VertexDescriptor; + fn retain(&self) -> VertexDescriptor { + unsafe { VertexDescriptor::from_ptr(msg_send![self.as_ptr(), retain]) } + } +} + +// Extra block stuff not supported by `block` + +const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000; +const BLOCK_HAS_SIGNATURE: i32 = 0x40000000; + +#[repr(C)] +struct BlockBase { + isa: *const Class, // 0x00 + flags: i32, // 0x08 + _reserved: i32, // 0x0c + invoke: unsafe extern fn(*mut Block, ...) -> R, // 0x10 + extra: *const BlockExtra, // 0x18 +} + +type BlockExtraDtor = extern "C" fn(*mut BlockBase); + +#[repr(C)] +struct BlockExtra { + unknown0: *mut i32, // 0x00 + unknown1: *mut i32, // 0x08 + unknown2: *mut i32, // 0x10 + dtor: BlockExtraDtor, // 0x18 + signature: *const *const i8, // 0x20 +} diff --git a/renderer/Cargo.toml b/renderer/Cargo.toml index 0a575b30..e8e789a0 100644 --- a/renderer/Cargo.toml +++ b/renderer/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" authors = ["Patrick Walton "] [dependencies] +bitflags = "1.0" byteorder = "1.2" fixedbitset = "0.1" hashbrown = "0.1" @@ -17,6 +18,9 @@ smallvec = "0.6" version = "0.4" features = ["release_max_level_warn"] +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index 73562f8d..b3d4ca1c 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -12,14 +12,14 @@ use crate::concurrent::executor::Executor; use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, FillBatchPrimitive, RenderCommand}; -use crate::options::{PreparedRenderOptions, RenderCommandListener}; +use crate::options::{PreparedBuildOptions, RenderCommandListener}; use crate::scene::Scene; use crate::tile_map::DenseTileMap; use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler}; use crate::z_buffer::ZBuffer; -use pathfinder_geometry::basic::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8}; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::{RectF, RectI}; +use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8}; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::{RectF, RectI}; use pathfinder_geometry::util; use pathfinder_simd::default::{F32x4, I32x4}; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -28,7 +28,7 @@ use std::u16; pub(crate) struct SceneBuilder<'a> { scene: &'a Scene, - built_options: &'a PreparedRenderOptions, + built_options: &'a PreparedBuildOptions, pub(crate) next_alpha_tile_index: AtomicUsize, pub(crate) z_buffer: ZBuffer, @@ -38,7 +38,7 @@ pub(crate) struct SceneBuilder<'a> { impl<'a> SceneBuilder<'a> { pub(crate) fn new( scene: &'a Scene, - built_options: &'a PreparedRenderOptions, + built_options: &'a PreparedBuildOptions, listener: Box, ) -> SceneBuilder<'a> { let effective_view_box = scene.effective_view_box(built_options); @@ -76,7 +76,7 @@ impl<'a> SceneBuilder<'a> { &self, path_index: usize, view_box: RectF, - built_options: &PreparedRenderOptions, + built_options: &PreparedBuildOptions, scene: &Scene, ) -> Vec { let path_object = &scene.paths[path_index]; diff --git a/renderer/src/concurrent/scene_proxy.rs b/renderer/src/concurrent/scene_proxy.rs index 09c0e38d..22e29155 100644 --- a/renderer/src/concurrent/scene_proxy.rs +++ b/renderer/src/concurrent/scene_proxy.rs @@ -22,9 +22,9 @@ use crate::concurrent::executor::Executor; use crate::gpu::renderer::Renderer; use crate::gpu_data::RenderCommand; -use crate::options::{RenderCommandListener, RenderOptions}; +use crate::options::{BuildOptions, RenderCommandListener}; use crate::scene::Scene; -use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::rect::RectF; use pathfinder_gpu::Device; use std::sync::mpsc::{self, Receiver, Sender}; use std::thread; @@ -59,15 +59,15 @@ impl SceneProxy { #[inline] pub fn build_with_listener(&self, - options: RenderOptions, + options: BuildOptions, listener: Box) { self.sender.send(MainToWorkerMsg::Build(options, listener)).unwrap(); } #[inline] - pub fn build_with_stream(&self, options: RenderOptions) -> RenderCommandStream { + pub fn build_with_stream(&self, options: BuildOptions) -> RenderCommandStream { let (sender, receiver) = mpsc::sync_channel(MAX_MESSAGES_IN_FLIGHT); - let listener = Box::new(move |command| sender.send(command).unwrap()); + let listener = Box::new(move |command| drop(sender.send(command))); self.build_with_listener(options, listener); RenderCommandStream::new(receiver) } @@ -81,11 +81,11 @@ impl SceneProxy { /// renderer.render_command(&command) /// } #[inline] - pub fn build_and_render(&self, renderer: &mut Renderer, options: RenderOptions) + pub fn build_and_render(&self, renderer: &mut Renderer, build_options: BuildOptions) where D: Device { renderer.begin_scene(); - for command in self.build_with_stream(options) { - renderer.render_command(&command) + for command in self.build_with_stream(build_options) { + renderer.render_command(&command); } renderer.end_scene(); } @@ -118,7 +118,7 @@ fn scene_thread(mut scene: Scene, enum MainToWorkerMsg { ReplaceScene(Scene), SetViewBox(RectF), - Build(RenderOptions, Box), + Build(BuildOptions, Box), GetSVG(Sender>), } diff --git a/renderer/src/gpu/debug.rs b/renderer/src/gpu/debug.rs index 5e982d79..7d28b952 100644 --- a/renderer/src/gpu/debug.rs +++ b/renderer/src/gpu/debug.rs @@ -16,8 +16,8 @@ //! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/ use crate::gpu::renderer::{RenderStats, RenderTime}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::Device; use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UIPresenter, WINDOW_COLOR}; diff --git a/renderer/src/gpu/mod.rs b/renderer/src/gpu/mod.rs index cc28fc80..a5e818e0 100644 --- a/renderer/src/gpu/mod.rs +++ b/renderer/src/gpu/mod.rs @@ -11,4 +11,5 @@ //! The GPU renderer for Pathfinder 3. pub mod debug; +pub mod options; pub mod renderer; diff --git a/renderer/src/gpu/options.rs b/renderer/src/gpu/options.rs new file mode 100644 index 00000000..8ffe9d88 --- /dev/null +++ b/renderer/src/gpu/options.rs @@ -0,0 +1,60 @@ +// pathfinder/renderer/src/gpu/options.rs +// +// Copyright © 2019 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. + +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_content::color::ColorF; +use pathfinder_gpu::Device; + +/// Options that influence rendering. +#[derive(Default)] +pub struct RendererOptions { + pub background_color: Option, +} + +#[derive(Clone)] +pub enum DestFramebuffer +where + D: Device, +{ + Default { + viewport: RectI, + window_size: Vector2I, + }, + Other(D::Framebuffer), +} + +impl Default for DestFramebuffer where D: Device { + #[inline] + fn default() -> DestFramebuffer { + DestFramebuffer::Default { viewport: RectI::default(), window_size: Vector2I::default() } + } +} + +impl DestFramebuffer +where + D: Device, +{ + #[inline] + pub fn full_window(window_size: Vector2I) -> DestFramebuffer { + let viewport = RectI::new(Vector2I::default(), window_size); + DestFramebuffer::Default { viewport, window_size } + } + + #[inline] + pub fn window_size(&self, device: &D) -> Vector2I { + match *self { + DestFramebuffer::Default { window_size, .. } => window_size, + DestFramebuffer::Other(ref framebuffer) => { + device.texture_size(device.framebuffer_texture(framebuffer)) + } + } + } +} diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index 0579d0f2..f70f56d7 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -9,19 +9,20 @@ // except according to those terms. use crate::gpu::debug::DebugUIPresenter; +use crate::gpu::options::{DestFramebuffer, RendererOptions}; use crate::gpu_data::{AlphaTileBatchPrimitive, FillBatchPrimitive, PaintData}; use crate::gpu_data::{RenderCommand, SolidTileBatchPrimitive}; use crate::post::DefringingKernel; use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; -use pathfinder_geometry::basic::vector::{Vector2I, Vector4F}; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::basic::transform3d::Transform3DF; -use pathfinder_geometry::color::ColorF; +use pathfinder_geometry::vector::{Vector2I, Vector4F}; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform3d::Transform3DF; +use pathfinder_content::color::ColorF; use pathfinder_gpu::resources::ResourceLoader; -use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams}; -use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc}; -use pathfinder_gpu::{StencilState, TextureFormat, UniformData, VertexAttrClass}; -use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearOps}; +use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderOptions, RenderState}; +use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureFormat, UniformData}; +use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::{F32x4, I32x4}; use std::cmp; use std::collections::VecDeque; @@ -30,7 +31,7 @@ use std::ops::{Add, Div}; use std::time::Duration; use std::u32; -static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1]; +static QUAD_VERTEX_POSITIONS: [u16; 8] = [0, 0, 1, 0, 1, 1, 0, 1]; static QUAD_VERTEX_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3]; // FIXME(pcwalton): Shrink this again! @@ -39,7 +40,7 @@ const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * 256; // TODO(pcwalton): Replace with `mem::size_of` calls? const FILL_INSTANCE_SIZE: usize = 8; -const SOLID_TILE_INSTANCE_SIZE: usize = 10; +const SOLID_TILE_INSTANCE_SIZE: usize = 12; const MASK_TILE_INSTANCE_SIZE: usize = 12; const MAX_FILLS_PER_BATCH: usize = 0x4000; @@ -53,6 +54,7 @@ where // Core data dest_framebuffer: DestFramebuffer, + options: RendererOptions, fill_program: FillProgram, solid_multicolor_tile_program: SolidTileMulticolorProgram, alpha_multicolor_tile_program: AlphaTileMulticolorProgram, @@ -84,7 +86,7 @@ where reprojection_vertex_array: ReprojectionVertexArray, // Rendering state - mask_framebuffer_cleared: bool, + framebuffer_flags: FramebufferFlags, buffered_fills: Vec, // Debug @@ -103,11 +105,11 @@ impl Renderer where D: Device, { - pub fn new( - device: D, - resources: &dyn ResourceLoader, - dest_framebuffer: DestFramebuffer, - ) -> Renderer { + pub fn new(device: D, + resources: &dyn ResourceLoader, + dest_framebuffer: DestFramebuffer, + options: RendererOptions) + -> Renderer { let fill_program = FillProgram::new(&device, resources); let solid_multicolor_tile_program = SolidTileMulticolorProgram::new(&device, resources); @@ -190,10 +192,11 @@ where let window_size = dest_framebuffer.window_size(&device); let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size); - let renderer = Renderer { + Renderer { device, dest_framebuffer, + options, fill_program, solid_monochrome_tile_program, alpha_monochrome_tile_program, @@ -227,23 +230,18 @@ where free_timer_queries: vec![], debug_ui_presenter, - mask_framebuffer_cleared: false, + framebuffer_flags: FramebufferFlags::empty(), buffered_fills: vec![], render_mode: RenderMode::default(), use_depth: false, - }; - - // As a convenience, bind the destination framebuffer. - renderer.bind_dest_framebuffer(); - - renderer + } } pub fn begin_scene(&mut self) { + self.framebuffer_flags = FramebufferFlags::empty(); + self.device.begin_commands(); self.init_postprocessing_framebuffer(); - - self.mask_framebuffer_cleared = false; self.stats = RenderStats::default(); } @@ -258,8 +256,8 @@ where RenderCommand::AddPaintData(ref paint_data) => self.upload_paint_data(paint_data), RenderCommand::AddFills(ref fills) => self.add_fills(fills), RenderCommand::FlushFills => { - self.begin_composite_timer_query(); self.draw_buffered_fills(); + self.begin_composite_timer_query(); } RenderCommand::SolidTile(ref solid_tiles) => { let count = solid_tiles.len(); @@ -284,10 +282,11 @@ where self.end_composite_timer_query(); self.pending_timers.push_back(mem::replace(&mut self.current_timers, RenderTimers::new())); + + self.device.end_commands(); } pub fn draw_debug_ui(&self) { - self.bind_dest_framebuffer(); self.debug_ui_presenter.draw(&self.device); } @@ -297,19 +296,19 @@ where // Accumulate stage-0 time. let mut total_stage_0_time = Duration::new(0, 0); for timer_query in &timers.stage_0 { - if !self.device.timer_query_is_available(timer_query) { - return None; + match self.device.get_timer_query(timer_query) { + None => return None, + Some(stage_0_time) => total_stage_0_time += stage_0_time, } - total_stage_0_time += self.device.get_timer_query(timer_query); } // Get stage-1 time. let stage_1_time = { let stage_1_timer_query = timers.stage_1.as_ref().unwrap(); - if !self.device.timer_query_is_available(&stage_1_timer_query) { - return None; + match self.device.get_timer_query(stage_1_timer_query) { + None => return None, + Some(query) => query, } - self.device.get_timer_query(stage_1_timer_query) }; // Recycle all timer queries. @@ -333,6 +332,11 @@ where mem::replace(&mut self.dest_framebuffer, new_dest_framebuffer) } + #[inline] + pub fn set_options(&mut self, new_options: RendererOptions) { + self.options = new_options + } + #[inline] pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) { self.debug_ui_presenter.ui_presenter.set_framebuffer_size(new_framebuffer_size); @@ -396,24 +400,11 @@ where ); } - fn clear_mask_framebuffer(&mut self) { - self.device.bind_framebuffer(&self.mask_framebuffer); - - // TODO(pcwalton): Only clear the appropriate portion? - self.device.clear(&ClearParams { - color: Some(ColorF::transparent_black()), - ..ClearParams::default() - }); - } - fn add_fills(&mut self, mut fills: &[FillBatchPrimitive]) { if fills.is_empty() { return; } - let timer_query = self.allocate_timer_query(); - self.device.begin_timer_query(&timer_query); - self.stats.fill_count += fills.len(); while !fills.is_empty() { @@ -424,9 +415,6 @@ where self.draw_buffered_fills(); } } - - self.device.end_timer_query(&timer_query); - self.current_timers.stage_0.push(timer_query); } fn draw_buffered_fills(&mut self) { @@ -441,178 +429,184 @@ where BufferUploadMode::Dynamic, ); - if !self.mask_framebuffer_cleared { - self.clear_mask_framebuffer(); - self.mask_framebuffer_cleared = true; - } - - self.device.bind_framebuffer(&self.mask_framebuffer); - - self.device - .bind_vertex_array(&self.fill_vertex_array.vertex_array); - self.device.use_program(&self.fill_program.program); - self.device.set_uniform( - &self.fill_program.framebuffer_size_uniform, - UniformData::Vec2( - I32x4::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT, 0, 0).to_f32x4(), - ), - ); - self.device.set_uniform( - &self.fill_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); - self.device.bind_texture(&self.area_lut_texture, 0); - self.device.set_uniform( - &self.fill_program.area_lut_uniform, - UniformData::TextureUnit(0), - ); - let render_state = RenderState { - blend: BlendState::RGBOneAlphaOne, - ..RenderState::default() + let mut clear_color = None; + if !self.framebuffer_flags.contains( + FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS) { + clear_color = Some(ColorF::default()); }; - debug_assert!(self.buffered_fills.len() <= u32::MAX as usize); - self.device.draw_elements_instanced( - Primitive::Triangles, - 6, - self.buffered_fills.len() as u32, - &render_state, - ); - self.buffered_fills.clear() + let timer_query = self.allocate_timer_query(); + self.device.begin_timer_query(&timer_query); + + debug_assert!(self.buffered_fills.len() <= u32::MAX as usize); + self.device.draw_elements_instanced(6, self.buffered_fills.len() as u32, &RenderState { + target: &RenderTarget::Framebuffer(&self.mask_framebuffer), + program: &self.fill_program.program, + vertex_array: &self.fill_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&self.area_lut_texture], + uniforms: &[ + (&self.fill_program.framebuffer_size_uniform, + UniformData::Vec2(I32x4::new(MASK_FRAMEBUFFER_WIDTH, + MASK_FRAMEBUFFER_HEIGHT, + 0, + 0).to_f32x4())), + (&self.fill_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + (&self.fill_program.area_lut_uniform, UniformData::TextureUnit(0)), + ], + viewport: self.mask_viewport(), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOne, + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.device.end_timer_query(&timer_query); + self.current_timers.stage_0.push(timer_query); + + self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS); + self.buffered_fills.clear(); } fn draw_alpha_tiles(&mut self, count: u32) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); let alpha_tile_vertex_array = self.alpha_tile_vertex_array(); let alpha_tile_program = self.alpha_tile_program(); - self.device - .bind_vertex_array(&alpha_tile_vertex_array.vertex_array); - self.device.use_program(&alpha_tile_program.program); - self.device.set_uniform( - &alpha_tile_program.framebuffer_size_uniform, - UniformData::Vec2(self.draw_viewport().size().to_f32().0), - ); - self.device.set_uniform( - &alpha_tile_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); - self.device - .bind_texture(self.device.framebuffer_texture(&self.mask_framebuffer), 0); - self.device.set_uniform( - &alpha_tile_program.stencil_texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &alpha_tile_program.stencil_texture_size_uniform, - UniformData::Vec2( - I32x4::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT, 0, 0).to_f32x4(), - ), - ); + let draw_viewport = self.draw_viewport(); + let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)]; + let mut uniforms = vec![ + (&alpha_tile_program.framebuffer_size_uniform, + UniformData::Vec2(draw_viewport.size().to_f32().0)), + (&alpha_tile_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + (&alpha_tile_program.stencil_texture_uniform, UniformData::TextureUnit(0)), + (&alpha_tile_program.stencil_texture_size_uniform, + UniformData::Vec2(I32x4::new(MASK_FRAMEBUFFER_WIDTH, + MASK_FRAMEBUFFER_HEIGHT, + 0, + 0).to_f32x4())), + // FIXME(pcwalton): Fill this in properly! + (&alpha_tile_program.view_box_origin_uniform, UniformData::Vec2(F32x4::default())), + ]; match self.render_mode { RenderMode::Multicolor => { let paint_texture = self.paint_texture.as_ref().unwrap(); - self.device.bind_texture(paint_texture, 1); - self.device.set_uniform( - &self.alpha_multicolor_tile_program.paint_texture_uniform, - UniformData::TextureUnit(1), - ); - self.device.set_uniform( - &self.alpha_multicolor_tile_program.paint_texture_size_uniform, - UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x4()) - ); + textures.push(paint_texture); + uniforms.push((&self.alpha_multicolor_tile_program.paint_texture_uniform, + UniformData::TextureUnit(1))); + uniforms.push((&self.alpha_multicolor_tile_program.paint_texture_size_uniform, + UniformData::Vec2(self.device + .texture_size(paint_texture) + .0 + .to_f32x4()))); } RenderMode::Monochrome { .. } if self.postprocessing_needed() => { - self.device.set_uniform( - &self.alpha_monochrome_tile_program.color_uniform, - UniformData::Vec4(F32x4::splat(1.0)), - ); + uniforms.push((&self.alpha_monochrome_tile_program.color_uniform, + UniformData::Vec4(F32x4::splat(1.0)))); } RenderMode::Monochrome { fg_color, .. } => { - self.device.set_uniform( - &self.alpha_monochrome_tile_program.color_uniform, - UniformData::Vec4(fg_color.0), - ); + uniforms.push((&self.alpha_monochrome_tile_program.color_uniform, + UniformData::Vec4(fg_color.0))); } } - // FIXME(pcwalton): Fill this in properly! - self.device.set_uniform( - &alpha_tile_program.view_box_origin_uniform, - UniformData::Vec2(F32x4::default()), - ); - let render_state = RenderState { - blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, - stencil: self.stencil_state(), - ..RenderState::default() - }; - self.device.draw_elements_instanced(Primitive::Triangles, 6, count, &render_state); + self.device.draw_elements_instanced(6, count, &RenderState { + target: &self.draw_render_target(), + program: &alpha_tile_program.program, + vertex_array: &alpha_tile_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &textures, + uniforms: &uniforms, + viewport: draw_viewport, + options: RenderOptions { + blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, + stencil: self.stencil_state(), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.preserve_draw_framebuffer(); } fn draw_solid_tiles(&mut self, count: u32) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); let solid_tile_vertex_array = self.solid_tile_vertex_array(); let solid_tile_program = self.solid_tile_program(); - self.device - .bind_vertex_array(&solid_tile_vertex_array.vertex_array); - self.device.use_program(&solid_tile_program.program); - self.device.set_uniform( - &solid_tile_program.framebuffer_size_uniform, - UniformData::Vec2(self.draw_viewport().size().0.to_f32x4()), - ); - self.device.set_uniform( - &solid_tile_program.tile_size_uniform, - UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, 0, 0).to_f32x4()), - ); + let draw_viewport = self.draw_viewport(); + let mut textures = vec![]; + let mut uniforms = vec![ + (&solid_tile_program.framebuffer_size_uniform, + UniformData::Vec2(draw_viewport.size().0.to_f32x4())), + (&solid_tile_program.tile_size_uniform, + UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, + TILE_HEIGHT as i32, + 0, + 0).to_f32x4())), + // FIXME(pcwalton): Fill this in properly! + (&solid_tile_program.view_box_origin_uniform, UniformData::Vec2(F32x4::default())), + ]; match self.render_mode { RenderMode::Multicolor => { let paint_texture = self.paint_texture.as_ref().unwrap(); - self.device.bind_texture(paint_texture, 0); - self.device.set_uniform( - &self - .solid_multicolor_tile_program - .paint_texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &self - .solid_multicolor_tile_program - .paint_texture_size_uniform, - UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x4()) - ); + textures.push(paint_texture); + uniforms.push((&self.solid_multicolor_tile_program.paint_texture_uniform, + UniformData::TextureUnit(0))); + uniforms.push((&self.solid_multicolor_tile_program.paint_texture_size_uniform, + UniformData::Vec2(self.device + .texture_size(paint_texture) + .0 + .to_f32x4()))); } RenderMode::Monochrome { .. } if self.postprocessing_needed() => { - self.device.set_uniform( - &self.solid_monochrome_tile_program.color_uniform, - UniformData::Vec4(F32x4::splat(1.0)), - ); + uniforms.push((&self.solid_monochrome_tile_program.color_uniform, + UniformData::Vec4(F32x4::splat(1.0)))); } RenderMode::Monochrome { fg_color, .. } => { - self.device.set_uniform( - &self.solid_monochrome_tile_program.color_uniform, - UniformData::Vec4(fg_color.0), - ); + uniforms.push((&self.solid_monochrome_tile_program.color_uniform, + UniformData::Vec4(fg_color.0))); } } - // FIXME(pcwalton): Fill this in properly! - self.device.set_uniform( - &solid_tile_program.view_box_origin_uniform, - UniformData::Vec2(F32x4::default()), - ); - let render_state = RenderState { - stencil: self.stencil_state(), - ..RenderState::default() - }; - self.device.draw_elements_instanced(Primitive::Triangles, 6, count, &render_state); + self.device.draw_elements_instanced(6, count, &RenderState { + target: &self.draw_render_target(), + program: &solid_tile_program.program, + vertex_array: &solid_tile_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &textures, + uniforms: &uniforms, + viewport: draw_viewport, + options: RenderOptions { + stencil: self.stencil_state(), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.preserve_draw_framebuffer(); } fn postprocess(&mut self) { + let mut clear_color = None; + if !self.framebuffer_flags + .contains(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS) { + clear_color = self.options.background_color; + } + let (fg_color, bg_color, defringing_kernel, gamma_correction_enabled); match self.render_mode { RenderMode::Multicolor => return, @@ -629,62 +623,52 @@ where } } - self.bind_dest_framebuffer(); - - self.device - .bind_vertex_array(&self.postprocess_vertex_array.vertex_array); - self.device.use_program(&self.postprocess_program.program); - self.device.set_uniform( - &self.postprocess_program.framebuffer_size_uniform, - UniformData::Vec2(self.main_viewport().size().to_f32().0), - ); - match defringing_kernel { - Some(ref kernel) => { - self.device.set_uniform( - &self.postprocess_program.kernel_uniform, - UniformData::Vec4(F32x4::from_slice(&kernel.0)), - ); - } - None => { - self.device.set_uniform( - &self.postprocess_program.kernel_uniform, - UniformData::Vec4(F32x4::default()), - ); - } - } - let postprocess_source_framebuffer = self.postprocess_source_framebuffer.as_ref().unwrap(); let source_texture = self .device .framebuffer_texture(postprocess_source_framebuffer); let source_texture_size = self.device.texture_size(source_texture); - self.device.bind_texture(&source_texture, 0); - self.device.set_uniform( - &self.postprocess_program.source_uniform, - UniformData::TextureUnit(0), - ); - self.device.set_uniform( - &self.postprocess_program.source_size_uniform, - UniformData::Vec2(source_texture_size.0.to_f32x4()), - ); - self.device.bind_texture(&self.gamma_lut_texture, 1); - self.device.set_uniform( - &self.postprocess_program.gamma_lut_uniform, - UniformData::TextureUnit(1), - ); - self.device.set_uniform( - &self.postprocess_program.fg_color_uniform, - UniformData::Vec4(fg_color.0), - ); - self.device.set_uniform( - &self.postprocess_program.bg_color_uniform, - UniformData::Vec4(bg_color.0), - ); - self.device.set_uniform( - &self.postprocess_program.gamma_correction_enabled_uniform, - UniformData::Int(gamma_correction_enabled as i32), - ); - self.device.draw_arrays(Primitive::Triangles, 4, &RenderState::default()); + let main_viewport = self.main_viewport(); + + let mut uniforms = vec![ + (&self.postprocess_program.framebuffer_size_uniform, + UniformData::Vec2(main_viewport.size().to_f32().0)), + (&self.postprocess_program.source_uniform, UniformData::TextureUnit(0)), + (&self.postprocess_program.source_size_uniform, + UniformData::Vec2(source_texture_size.0.to_f32x4())), + (&self.postprocess_program.gamma_lut_uniform, UniformData::TextureUnit(1)), + (&self.postprocess_program.fg_color_uniform, UniformData::Vec4(fg_color.0)), + (&self.postprocess_program.bg_color_uniform, UniformData::Vec4(bg_color.0)), + (&self.postprocess_program.gamma_correction_enabled_uniform, + UniformData::Int(gamma_correction_enabled as i32)), + ]; + + match defringing_kernel { + Some(ref kernel) => { + uniforms.push((&self.postprocess_program.kernel_uniform, + UniformData::Vec4(F32x4::from_slice(&kernel.0)))); + } + None => { + uniforms.push((&self.postprocess_program.kernel_uniform, + UniformData::Vec4(F32x4::default()))); + } + } + + self.device.draw_elements(6, &RenderState { + target: &self.dest_render_target(), + program: &self.postprocess_program.program, + vertex_array: &self.postprocess_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&source_texture, &self.gamma_lut_texture], + uniforms: &uniforms, + viewport: main_viewport, + options: RenderOptions { + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() + }, + }); + + self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS); } fn solid_tile_program(&self) -> &SolidTileProgram { @@ -715,7 +699,7 @@ where } } - fn draw_stencil(&self, quad_positions: &[Vector4F]) { + fn draw_stencil(&mut self, quad_positions: &[Vector4F]) { self.device.allocate_buffer( &self.stencil_vertex_array.vertex_buffer, BufferData::Memory(quad_positions), @@ -736,19 +720,17 @@ where BufferUploadMode::Dynamic, ); - self.bind_draw_framebuffer(); - - self.device.bind_vertex_array(&self.stencil_vertex_array.vertex_array); - self.device.use_program(&self.stencil_program.program); - self.device.draw_elements( - Primitive::Triangles, - indices.len() as u32, - &RenderState { + self.device.draw_elements(indices.len() as u32, &RenderState { + target: &self.draw_render_target(), + program: &self.stencil_program.program, + vertex_array: &self.stencil_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[], + uniforms: &[], + viewport: self.draw_viewport(), + options: RenderOptions { // FIXME(pcwalton): Should we really write to the depth buffer? - depth: Some(DepthState { - func: DepthFunc::Less, - write: true, - }), + depth: Some(DepthState { func: DepthFunc::Less, write: true }), stencil: Some(StencilState { func: StencilFunc::Always, reference: 1, @@ -756,63 +738,57 @@ where write: true, }), color_mask: false, - ..RenderState::default() + clear_ops: ClearOps { stencil: Some(0), ..ClearOps::default() }, + ..RenderOptions::default() }, - ) + }); } pub fn reproject_texture( - &self, + &mut self, texture: &D::Texture, old_transform: &Transform3DF, new_transform: &Transform3DF, ) { - self.bind_draw_framebuffer(); + let clear_color = self.clear_color_for_draw_operation(); - self.device.bind_vertex_array(&self.reprojection_vertex_array.vertex_array); - self.device.use_program(&self.reprojection_program.program); - self.device.set_uniform( - &self.reprojection_program.old_transform_uniform, - UniformData::from_transform_3d(old_transform), - ); - self.device.set_uniform( - &self.reprojection_program.new_transform_uniform, - UniformData::from_transform_3d(new_transform), - ); - self.device.bind_texture(texture, 0); - self.device.set_uniform( - &self.reprojection_program.texture_uniform, - UniformData::TextureUnit(0), - ); - self.device.draw_elements( - Primitive::Triangles, - 6, - &RenderState { + self.device.draw_elements(6, &RenderState { + target: &self.draw_render_target(), + program: &self.reprojection_program.program, + vertex_array: &self.reprojection_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[texture], + uniforms: &[ + (&self.reprojection_program.old_transform_uniform, + UniformData::from_transform_3d(old_transform)), + (&self.reprojection_program.new_transform_uniform, + UniformData::from_transform_3d(new_transform)), + (&self.reprojection_program.texture_uniform, UniformData::TextureUnit(0)), + ], + viewport: self.draw_viewport(), + options: RenderOptions { blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha, - depth: Some(DepthState { - func: DepthFunc::Less, - write: false, - }), - ..RenderState::default() + depth: Some(DepthState { func: DepthFunc::Less, write: false, }), + clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, + ..RenderOptions::default() }, - ); + }); + + self.preserve_draw_framebuffer(); } - pub fn bind_draw_framebuffer(&self) { + pub fn draw_render_target(&self) -> RenderTarget { if self.postprocessing_needed() { - self.device - .bind_framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()); + RenderTarget::Framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()) } else { - self.bind_dest_framebuffer(); + self.dest_render_target() } } - pub fn bind_dest_framebuffer(&self) { + pub fn dest_render_target(&self) -> RenderTarget { match self.dest_framebuffer { - DestFramebuffer::Default { viewport, .. } => { - self.device.bind_default_framebuffer(viewport) - } - DestFramebuffer::Other(ref framebuffer) => self.device.bind_framebuffer(framebuffer), + DestFramebuffer::Default { .. } => RenderTarget::Default, + DestFramebuffer::Other(ref framebuffer) => RenderTarget::Framebuffer(framebuffer), } } @@ -833,16 +809,21 @@ where let texture = self .device .create_texture(TextureFormat::R8, source_framebuffer_size); - self.postprocess_source_framebuffer = Some(self.device.create_framebuffer(texture)) + self.postprocess_source_framebuffer = + Some(self.device.create_framebuffer(texture)); } }; - self.device - .bind_framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap()); - self.device.clear(&ClearParams { - color: Some(ColorF::transparent_black()), - ..ClearParams::default() - }); + /* + self.device.clear(&RenderTarget::Framebuffer(self.postprocess_source_framebuffer + .as_ref() + .unwrap()), + RectI::new(Vector2I::default(), source_framebuffer_size), + &ClearParams { + color: Some(ColorF::transparent_black()), + ..ClearParams::default() + }); + */ } fn postprocessing_needed(&self) -> bool { @@ -869,7 +850,33 @@ where }) } - fn draw_viewport(&self) -> RectI { + fn clear_color_for_draw_operation(&mut self) -> Option { + let postprocessing_needed = self.postprocessing_needed(); + let flag = if postprocessing_needed { + FramebufferFlags::MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS + } else { + FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS + }; + + if self.framebuffer_flags.contains(flag) { + None + } else if !postprocessing_needed { + self.options.background_color + } else { + Some(ColorF::default()) + } + } + + fn preserve_draw_framebuffer(&mut self) { + let flag = if self.postprocessing_needed() { + FramebufferFlags::MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS + } else { + FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS + }; + self.framebuffer_flags.insert(flag); + } + + pub fn draw_viewport(&self) -> RectI { let main_viewport = self.main_viewport(); match self.render_mode { RenderMode::Monochrome { @@ -895,6 +902,11 @@ where } } + fn mask_viewport(&self) -> RectI { + let texture = self.device.framebuffer_texture(&self.mask_framebuffer); + RectI::new(Vector2I::default(), self.device.texture_size(texture)) + } + fn allocate_timer_query(&mut self) -> D::TimerQuery { match self.free_timer_queries.pop() { Some(query) => query, @@ -909,8 +921,9 @@ where } fn end_composite_timer_query(&mut self) { - let query = self.current_timers.stage_1.as_ref().expect("No stage 1 timer query yet?!"); - self.device.end_timer_query(&query); + if let Some(ref query) = self.current_timers.stage_1 { + self.device.end_timer_query(query); + } } } @@ -944,66 +957,70 @@ where BufferUploadMode::Dynamic, ); - let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord"); - let from_px_attr = device.get_vertex_attr(&fill_program.program, "FromPx"); - let to_px_attr = device.get_vertex_attr(&fill_program.program, "ToPx"); - let from_subpx_attr = device.get_vertex_attr(&fill_program.program, "FromSubpx"); - let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx"); - let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex"); + let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap(); + let from_px_attr = device.get_vertex_attr(&fill_program.program, "FromPx").unwrap(); + let to_px_attr = device.get_vertex_attr(&fill_program.program, "ToPx").unwrap(); + let from_subpx_attr = device.get_vertex_attr(&fill_program.program, "FromSubpx").unwrap(); + let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx").unwrap(); + let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&fill_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&from_px_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &from_px_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&to_px_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &to_px_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 1, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&from_subpx_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &from_subpx_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::FloatNorm, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 2, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&to_subpx_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &to_subpx_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::FloatNorm, attr_type: VertexAttrType::U8, stride: FILL_INSTANCE_SIZE, offset: 4, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&tile_index_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::U16, stride: FILL_INSTANCE_SIZE, offset: 6, divisor: 1, + buffer_index: 1, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); FillVertexArray { vertex_array, vertex_buffer } } @@ -1029,60 +1046,71 @@ where ) -> AlphaTileVertexArray { let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); - let tess_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, "TessCoord"); - let tile_origin_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileOrigin"); - let backdrop_attr = device.get_vertex_attr(&alpha_tile_program.program, "Backdrop"); - let tile_index_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileIndex"); + let tess_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, "TessCoord") + .unwrap(); + let tile_origin_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileOrigin") + .unwrap(); + let backdrop_attr = device.get_vertex_attr(&alpha_tile_program.program, "Backdrop") + .unwrap(); + let tile_index_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileIndex") + .unwrap(); let color_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, "ColorTexCoord"); // NB: The object must be of type `I16`, not `U16`, to work around a macOS Radeon // driver bug. - device.bind_vertex_array(&vertex_array); - device.use_program(&alpha_tile_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tile_origin_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor { size: 3, class: VertexAttrClass::Int, attr_type: VertexAttrType::U8, stride: MASK_TILE_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&backdrop_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &backdrop_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::I8, stride: MASK_TILE_INSTANCE_SIZE, offset: 3, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&tile_index_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor { size: 1, class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, stride: MASK_TILE_INSTANCE_SIZE, offset: 6, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: MASK_TILE_INSTANCE_SIZE, - offset: 8, - divisor: 1, - }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + if let Some(color_tex_coord_attr) = color_tex_coord_attr { + device.configure_vertex_attr(&vertex_array, + &color_tex_coord_attr, + &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: MASK_TILE_INSTANCE_SIZE, + offset: 8, + divisor: 1, + buffer_index: 1, + }); + } + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); AlphaTileVertexArray { vertex_array, vertex_buffer } } @@ -1108,42 +1136,49 @@ where ) -> SolidTileVertexArray { let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); - let tess_coord_attr = device.get_vertex_attr(&solid_tile_program.program, "TessCoord"); - let tile_origin_attr = device.get_vertex_attr(&solid_tile_program.program, "TileOrigin"); + let tess_coord_attr = device.get_vertex_attr(&solid_tile_program.program, "TessCoord") + .unwrap(); + let tile_origin_attr = device.get_vertex_attr(&solid_tile_program.program, "TileOrigin") + .unwrap(); let color_tex_coord_attr = device.get_vertex_attr(&solid_tile_program.program, "ColorTexCoord"); // NB: The object must be of type short, not unsigned short, to work around a macOS // Radeon driver bug. - device.bind_vertex_array(&vertex_array); - device.use_program(&solid_tile_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tess_coord_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&tile_origin_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, + class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, stride: SOLID_TILE_INSTANCE_SIZE, offset: 0, divisor: 1, + buffer_index: 1, }); - device.configure_vertex_attr(&color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: SOLID_TILE_INSTANCE_SIZE, - offset: 4, - divisor: 1, - }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + if let Some(color_tex_coord_attr) = color_tex_coord_attr { + device.configure_vertex_attr(&vertex_array, + &color_tex_coord_attr, + &VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::FloatNorm, + attr_type: VertexAttrType::U16, + stride: SOLID_TILE_INSTANCE_SIZE, + offset: 4, + divisor: 1, + buffer_index: 1, + }); + } + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); SolidTileVertexArray { vertex_array, vertex_buffer } } @@ -1225,10 +1260,10 @@ where { fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileMulticolorProgram { let solid_tile_program = SolidTileProgram::new(device, "tile_solid_multicolor", resources); - let paint_texture_uniform = - device.get_uniform(&solid_tile_program.program, "PaintTexture"); - let paint_texture_size_uniform = - device.get_uniform(&solid_tile_program.program, "PaintTextureSize"); + let paint_texture_uniform = device.get_uniform(&solid_tile_program.program, + "PaintTexture"); + let paint_texture_size_uniform = device.get_uniform(&solid_tile_program.program, + "PaintTextureSize"); SolidTileMulticolorProgram { solid_tile_program, paint_texture_uniform, @@ -1373,8 +1408,8 @@ where let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let kernel_uniform = device.get_uniform(&program, "Kernel"); let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT"); - let gamma_correction_enabled_uniform = - device.get_uniform(&program, "GammaCorrectionEnabled"); + let gamma_correction_enabled_uniform = device.get_uniform(&program, + "GammaCorrectionEnabled"); let fg_color_uniform = device.get_uniform(&program, "FGColor"); let bg_color_uniform = device.get_uniform(&program, "BGColor"); PostprocessProgram { @@ -1409,20 +1444,20 @@ where quad_vertex_indices_buffer: &D::Buffer, ) -> PostprocessVertexArray { let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position"); + let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position") + .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&postprocess_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); PostprocessVertexArray { vertex_array } } @@ -1462,20 +1497,19 @@ where let vertex_array = device.create_vertex_array(); let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); - let position_attr = device.get_vertex_attr(&stencil_program.program, "Position"); + let position_attr = device.get_vertex_attr(&stencil_program.program, "Position").unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&stencil_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 3, class: VertexAttrClass::Float, attr_type: VertexAttrType::F32, stride: 4 * 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(&index_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); StencilVertexArray { vertex_array, vertex_buffer, index_buffer } } @@ -1528,58 +1562,25 @@ where quad_vertex_indices_buffer: &D::Buffer, ) -> ReprojectionVertexArray { let vertex_array = device.create_vertex_array(); + let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position") + .unwrap(); - let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position"); - - device.bind_vertex_array(&vertex_array); - device.use_program(&reprojection_program.program); - device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U8, - stride: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: 4, offset: 0, divisor: 0, + buffer_index: 0, }); - device.bind_buffer(quad_vertex_indices_buffer, BufferTarget::Index); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); ReprojectionVertexArray { vertex_array } } } -#[derive(Clone)] -pub enum DestFramebuffer -where - D: Device, -{ - Default { - viewport: RectI, - window_size: Vector2I, - }, - Other(D::Framebuffer), -} - -impl DestFramebuffer -where - D: Device, -{ - #[inline] - pub fn full_window(window_size: Vector2I) -> DestFramebuffer { - let viewport = RectI::new(Vector2I::default(), window_size); - DestFramebuffer::Default { viewport, window_size } - } - - fn window_size(&self, device: &D) -> Vector2I { - match *self { - DestFramebuffer::Default { window_size, .. } => window_size, - DestFramebuffer::Other(ref framebuffer) => { - device.texture_size(device.framebuffer_texture(framebuffer)) - } - } - } -} - #[derive(Clone, Copy)] pub enum RenderMode { Multicolor, @@ -1665,3 +1666,11 @@ impl Add for RenderTime { } } } + +bitflags! { + struct FramebufferFlags: u8 { + const MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS = 0x01; + const MUST_PRESERVE_POSTPROCESS_FRAMEBUFFER_CONTENTS = 0x02; + const MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS = 0x04; + } +} diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 76734d59..6e65cb46 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -12,9 +12,9 @@ use crate::options::BoundingQuad; use crate::tile_map::DenseTileMap; -use pathfinder_geometry::basic::line_segment::{LineSegmentU4, LineSegmentU8}; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8}; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectF; use std::fmt::{Debug, Formatter, Result as DebugResult}; use std::time::Duration; @@ -75,6 +75,7 @@ pub struct SolidTileBatchPrimitive { pub origin_u: u16, pub origin_v: u16, pub object_index: u16, + pub pad: u16, } #[derive(Clone, Copy, Debug, Default)] diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 0f80405e..ea7f7072 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -10,6 +10,8 @@ //! The CPU portion of Pathfinder's renderer. +#[macro_use] +extern crate bitflags; #[macro_use] extern crate log; diff --git a/renderer/src/options.rs b/renderer/src/options.rs index 2cb34fe6..0266ec78 100644 --- a/renderer/src/options.rs +++ b/renderer/src/options.rs @@ -11,11 +11,11 @@ //! Options that control how rendering is to be performed. use crate::gpu_data::RenderCommand; -use pathfinder_geometry::basic::vector::{Vector2F, Vector4F}; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::basic::transform3d::Perspective; -use pathfinder_geometry::clip::PolygonClipper3D; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::transform3d::Perspective; +use pathfinder_geometry::vector::{Vector2F, Vector4F}; +use pathfinder_content::clip::PolygonClipper3D; pub trait RenderCommandListener: Send + Sync { fn send(&self, command: RenderCommand); @@ -31,16 +31,17 @@ where } } +/// Options that influence scene building. #[derive(Clone, Default)] -pub struct RenderOptions { +pub struct BuildOptions { pub transform: RenderTransform, pub dilation: Vector2F, pub subpixel_aa_enabled: bool, } -impl RenderOptions { - pub(crate) fn prepare(self, bounds: RectF) -> PreparedRenderOptions { - PreparedRenderOptions { +impl BuildOptions { + pub(crate) fn prepare(self, bounds: RectF) -> PreparedBuildOptions { + PreparedBuildOptions { transform: self.transform.prepare(bounds), dilation: self.dilation, subpixel_aa_enabled: self.subpixel_aa_enabled, @@ -119,13 +120,13 @@ impl RenderTransform { } } -pub(crate) struct PreparedRenderOptions { +pub(crate) struct PreparedBuildOptions { pub(crate) transform: PreparedRenderTransform, pub(crate) dilation: Vector2F, pub(crate) subpixel_aa_enabled: bool, } -impl PreparedRenderOptions { +impl PreparedBuildOptions { #[inline] pub(crate) fn bounding_quad(&self) -> BoundingQuad { match self.transform { diff --git a/renderer/src/paint.rs b/renderer/src/paint.rs index d0140004..2426092c 100644 --- a/renderer/src/paint.rs +++ b/renderer/src/paint.rs @@ -10,8 +10,8 @@ use crate::gpu_data::PaintData; use crate::scene::Scene; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::color::ColorU; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_content::color::ColorU; const PAINT_TEXTURE_WIDTH: i32 = 256; const PAINT_TEXTURE_HEIGHT: i32 = 256; diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 78f4f27a..f441d02f 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -12,15 +12,15 @@ use crate::builder::SceneBuilder; use crate::concurrent::executor::Executor; -use crate::options::{PreparedRenderOptions, PreparedRenderTransform}; -use crate::options::{RenderCommandListener, RenderOptions}; +use crate::options::{BuildOptions, PreparedBuildOptions}; +use crate::options::{PreparedRenderTransform, RenderCommandListener}; use crate::paint::{Paint, PaintId}; use hashbrown::HashMap; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::color::ColorU; -use pathfinder_geometry::outline::Outline; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_content::color::ColorU; +use pathfinder_content::outline::Outline; use std::io::{self, Write}; #[derive(Clone)] @@ -89,7 +89,7 @@ impl Scene { pub(crate) fn apply_render_options( &self, original_outline: &Outline, - options: &PreparedRenderOptions, + options: &PreparedBuildOptions, ) -> Outline { let effective_view_box = self.effective_view_box(options); @@ -156,7 +156,7 @@ impl Scene { } #[inline] - pub(crate) fn effective_view_box(&self, render_options: &PreparedRenderOptions) -> RectF { + pub(crate) fn effective_view_box(&self, render_options: &PreparedBuildOptions) -> RectF { if render_options.subpixel_aa_enabled { self.view_box.scale_xy(Vector2F::new(3.0, 1.0)) } else { @@ -166,7 +166,7 @@ impl Scene { #[inline] pub fn build(&self, - options: RenderOptions, + options: BuildOptions, listener: Box, executor: &E) where E: Executor { diff --git a/renderer/src/tile_map.rs b/renderer/src/tile_map.rs index a280df3b..f0d5ac40 100644 --- a/renderer/src/tile_map.rs +++ b/renderer/src/tile_map.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectI; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectI; #[derive(Debug)] pub struct DenseTileMap { diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index 3f5eb89a..0c98f0a5 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -12,11 +12,11 @@ use crate::builder::SceneBuilder; use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, TileObjectPrimitive}; use crate::paint::{self, PaintId}; use crate::sorted_vector::SortedVector; -use pathfinder_geometry::basic::line_segment::LineSegment2F; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::{RectF, RectI}; -use pathfinder_geometry::outline::{Contour, Outline, PointIndex}; -use pathfinder_geometry::segment::Segment; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; +use pathfinder_geometry::rect::{RectF, RectI}; +use pathfinder_content::outline::{Contour, Outline, PointIndex}; +use pathfinder_content::segment::Segment; use std::cmp::Ordering; use std::mem; diff --git a/renderer/src/z_buffer.rs b/renderer/src/z_buffer.rs index 889cc666..ae4bdf9e 100644 --- a/renderer/src/z_buffer.rs +++ b/renderer/src/z_buffer.rs @@ -15,8 +15,8 @@ use crate::paint; use crate::scene::PathObject; use crate::tile_map::DenseTileMap; use crate::tiles; -use pathfinder_geometry::basic::vector::Vector2I; -use pathfinder_geometry::basic::rect::RectF; +use pathfinder_geometry::vector::Vector2I; +use pathfinder_geometry::rect::RectF; use std::ops::Range; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; @@ -91,6 +91,7 @@ impl SolidTileBatchPrimitive { object_index: object_index, origin_u: origin_uv.x() as u16, origin_v: origin_uv.y() as u16, + pad: 0, } } } diff --git a/resources/fonts/SIL Open Font License.txt b/resources/fonts/SIL Open Font License.txt new file mode 100755 index 00000000..ec2cdcae --- /dev/null +++ b/resources/fonts/SIL Open Font License.txt @@ -0,0 +1,49 @@ +Copyright 2011 Red Hat, Inc., +with Reserved Font Name OVERPASS. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the copyright statement(s). + +"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/resources/fonts/overpass-regular.otf b/resources/fonts/overpass-regular.otf new file mode 100755 index 00000000..c9531c0e Binary files /dev/null and b/resources/fonts/overpass-regular.otf differ diff --git a/resources/shaders/gl3/debug_solid.fs.glsl b/resources/shaders/gl3/debug_solid.fs.glsl index eeaaf489..06550da6 100644 --- a/resources/shaders/gl3/debug_solid.fs.glsl +++ b/resources/shaders/gl3/debug_solid.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/debug_solid.vs.glsl b/resources/shaders/gl3/debug_solid.vs.glsl index 3c38f3f7..a5ac2df8 100644 --- a/resources/shaders/gl3/debug_solid.vs.glsl +++ b/resources/shaders/gl3/debug_solid.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -14,10 +16,10 @@ precision highp float; uniform vec2 uFramebufferSize; -in vec2 aPosition; +in ivec2 aPosition; void main(){ - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vec2 position = vec2(aPosition)/ uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position . x, - position . y, 0.0, 1.0); } diff --git a/resources/shaders/gl3/debug_texture.fs.glsl b/resources/shaders/gl3/debug_texture.fs.glsl index 9601adf2..5670374b 100644 --- a/resources/shaders/gl3/debug_texture.fs.glsl +++ b/resources/shaders/gl3/debug_texture.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/debug_texture.vs.glsl b/resources/shaders/gl3/debug_texture.vs.glsl index b3b546d8..d037b869 100644 --- a/resources/shaders/gl3/debug_texture.vs.glsl +++ b/resources/shaders/gl3/debug_texture.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,14 +17,14 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTextureSize; -in vec2 aPosition; -in vec2 aTexCoord; +in ivec2 aPosition; +in ivec2 aTexCoord; out vec2 vTexCoord; void main(){ - vTexCoord = aTexCoord / uTextureSize; - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vTexCoord = vec2(aTexCoord)/ uTextureSize; + vec2 position = vec2(aPosition)/ uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position . x, - position . y, 0.0, 1.0); } diff --git a/resources/shaders/gl3/demo_ground.fs.glsl b/resources/shaders/gl3/demo_ground.fs.glsl index 3bf84270..49dd50dc 100644 --- a/resources/shaders/gl3/demo_ground.fs.glsl +++ b/resources/shaders/gl3/demo_ground.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/demo_ground.vs.glsl b/resources/shaders/gl3/demo_ground.vs.glsl index 418eb50a..4f216416 100644 --- a/resources/shaders/gl3/demo_ground.vs.glsl +++ b/resources/shaders/gl3/demo_ground.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,12 +17,12 @@ precision highp float; uniform mat4 uTransform; uniform int uGridlineCount; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition * float(uGridlineCount); - gl_Position = uTransform * vec4(aPosition . x, 0.0, aPosition . y, 1.0); + vTexCoord = vec2(aPosition * uGridlineCount); + gl_Position = uTransform * vec4(ivec4(aPosition . x, 0, aPosition . y, 1)); } diff --git a/resources/shaders/gl3/fill.fs.glsl b/resources/shaders/gl3/fill.fs.glsl index aeebe141..d70a93bd 100644 --- a/resources/shaders/gl3/fill.fs.glsl +++ b/resources/shaders/gl3/fill.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/fill.vs.glsl b/resources/shaders/gl3/fill.vs.glsl index fac4560a..83314eb1 100644 --- a/resources/shaders/gl3/fill.vs.glsl +++ b/resources/shaders/gl3/fill.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -15,7 +17,7 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTileSize; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uint aFromPx; in uint aToPx; in vec2 aFromSubpx; @@ -27,7 +29,7 @@ out vec2 vTo; vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ uint tilesPerRow = uint(stencilTextureWidth / uTileSize . x); - uvec2 tileOffset = uvec2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return vec2(tileOffset)* uTileSize; } @@ -38,11 +40,11 @@ void main(){ vec2 to = vec2(aToPx & 15u, aToPx >> 4u)+ aToSubpx; vec2 position; - if(aTessCoord . x < 0.5) + if(aTessCoord . x == 0u) position . x = floor(min(from . x, to . x)); else position . x = ceil(max(from . x, to . x)); - if(aTessCoord . y < 0.5) + if(aTessCoord . y == 0u) position . y = floor(min(from . y, to . y)); else position . y = uTileSize . y; @@ -50,6 +52,10 @@ void main(){ vFrom = from - position; vTo = to - position; - gl_Position = vec4((tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0, 0.0, 1.0); + vec2 globalPosition =(tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0; + + + + gl_Position = vec4(globalPosition, 0.0, 1.0); } diff --git a/resources/shaders/gl3/post.fs.glsl b/resources/shaders/gl3/post.fs.glsl index 0a74556b..b9de3d7b 100644 --- a/resources/shaders/gl3/post.fs.glsl +++ b/resources/shaders/gl3/post.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/post.vs.glsl b/resources/shaders/gl3/post.vs.glsl index 29e75ade..a1d8effb 100644 --- a/resources/shaders/gl3/post.vs.glsl +++ b/resources/shaders/gl3/post.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -12,12 +14,18 @@ precision highp float; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition; - gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + + + + + + gl_Position = vec4(vec2(position)* 2.0 - 1.0, 0.0, 1.0); } diff --git a/resources/shaders/gl3/reproject.fs.glsl b/resources/shaders/gl3/reproject.fs.glsl index 427b632c..f1344a2e 100644 --- a/resources/shaders/gl3/reproject.fs.glsl +++ b/resources/shaders/gl3/reproject.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/reproject.vs.glsl b/resources/shaders/gl3/reproject.vs.glsl index d1c70544..f32005f2 100644 --- a/resources/shaders/gl3/reproject.vs.glsl +++ b/resources/shaders/gl3/reproject.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -14,12 +16,18 @@ precision highp float; uniform mat4 uNewTransform; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition; - gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + + + + + + gl_Position = uNewTransform * vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/gl3/stencil.fs.glsl b/resources/shaders/gl3/stencil.fs.glsl index e2e093ab..b37ee045 100644 --- a/resources/shaders/gl3/stencil.fs.glsl +++ b/resources/shaders/gl3/stencil.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/stencil.vs.glsl b/resources/shaders/gl3/stencil.vs.glsl index 2fee81a2..0f44276e 100644 --- a/resources/shaders/gl3/stencil.vs.glsl +++ b/resources/shaders/gl3/stencil.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_alpha.fs.glsl b/resources/shaders/gl3/tile_alpha.fs.glsl index 3af9cf4d..0e7247d7 100644 --- a/resources/shaders/gl3/tile_alpha.fs.glsl +++ b/resources/shaders/gl3/tile_alpha.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl b/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl index d99d7dd7..df40901e 100644 --- a/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl +++ b/resources/shaders/gl3/tile_alpha_monochrome.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -30,10 +32,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -49,9 +51,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ void computeVaryings(){ vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0; - vec2 pixelPosition =(origin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize . x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl b/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl index be655748..2adf4dc3 100644 --- a/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl +++ b/resources/shaders/gl3/tile_alpha_multicolor.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -30,10 +32,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -49,9 +51,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){ void computeVaryings(){ vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0; - vec2 pixelPosition =(origin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition =(origin + vec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize . x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/resources/shaders/gl3/tile_solid.fs.glsl b/resources/shaders/gl3/tile_solid.fs.glsl index 2079d945..f8f8f7a7 100644 --- a/resources/shaders/gl3/tile_solid.fs.glsl +++ b/resources/shaders/gl3/tile_solid.fs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + diff --git a/resources/shaders/gl3/tile_solid_monochrome.vs.glsl b/resources/shaders/gl3/tile_solid_monochrome.vs.glsl index d7544c26..c0808cbd 100644 --- a/resources/shaders/gl3/tile_solid_monochrome.vs.glsl +++ b/resources/shaders/gl3/tile_solid_monochrome.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -29,19 +31,18 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings(){ - vec2 pixelPosition =(aTileOrigin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); vColor = getColor(); - gl_Position = vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/gl3/tile_solid_multicolor.vs.glsl b/resources/shaders/gl3/tile_solid_multicolor.vs.glsl index 0e23e0a4..4ff5208c 100644 --- a/resources/shaders/gl3/tile_solid_multicolor.vs.glsl +++ b/resources/shaders/gl3/tile_solid_multicolor.vs.glsl @@ -1,4 +1,6 @@ #version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + @@ -29,19 +31,18 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings(){ - vec2 pixelPosition =(aTileOrigin + aTessCoord)* uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord))* uTileSize + uViewBoxOrigin; vec2 position =(pixelPosition / uFramebufferSize * 2.0 - 1.0)* vec2(1.0, - 1.0); vColor = getColor(); - gl_Position = vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/metal/debug_solid.fs.metal b/resources/shaders/metal/debug_solid.fs.metal index 6fc13e2f..49f35a94 100644 --- a/resources/shaders/metal/debug_solid.fs.metal +++ b/resources/shaders/metal/debug_solid.fs.metal @@ -1,17 +1,23 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uColor [[id(0)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; }; -fragment main0_out main0(float4 uColor [[buffer(0)]]) +fragment main0_out main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.oFragColor = float4(uColor.xyz, 1.0) * uColor.w; + out.oFragColor = float4((*spvDescriptorSet0.uColor).xyz, 1.0) * (*spvDescriptorSet0.uColor).w; return out; } diff --git a/resources/shaders/metal/debug_solid.vs.metal b/resources/shaders/metal/debug_solid.vs.metal index bcad2a03..ec9d440f 100644 --- a/resources/shaders/metal/debug_solid.vs.metal +++ b/resources/shaders/metal/debug_solid.vs.metal @@ -1,8 +1,14 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uFramebufferSize [[id(0)]]; +}; + struct main0_out { float4 gl_Position [[position]]; @@ -10,13 +16,13 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float2 uFramebufferSize [[buffer(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float2 position = ((in.aPosition / uFramebufferSize) * 2.0) - float2(1.0); + float2 position = ((float2(in.aPosition) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); out.gl_Position = float4(position.x, -position.y, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/debug_texture.fs.metal b/resources/shaders/metal/debug_texture.fs.metal index 67bc2370..80a811f3 100644 --- a/resources/shaders/metal/debug_texture.fs.metal +++ b/resources/shaders/metal/debug_texture.fs.metal @@ -1,8 +1,16 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + texture2d uTexture [[id(0)]]; + sampler uTextureSmplr [[id(1)]]; + constant float4* uColor [[id(2)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,11 +21,11 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4 uColor [[buffer(0)]], texture2d uTexture [[texture(0)]], sampler uTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float alpha = uTexture.sample(uTextureSmplr, in.vTexCoord).x * uColor.w; - out.oFragColor = float4(uColor.xyz, 1.0) * alpha; + float alpha = spvDescriptorSet0.uTexture.sample(spvDescriptorSet0.uTextureSmplr, in.vTexCoord).x * (*spvDescriptorSet0.uColor).w; + out.oFragColor = float4((*spvDescriptorSet0.uColor).xyz, 1.0) * alpha; return out; } diff --git a/resources/shaders/metal/debug_texture.vs.metal b/resources/shaders/metal/debug_texture.vs.metal index 25eb20b8..87a31507 100644 --- a/resources/shaders/metal/debug_texture.vs.metal +++ b/resources/shaders/metal/debug_texture.vs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTextureSize [[id(0)]]; + constant float2* uFramebufferSize [[id(1)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,15 +18,15 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; - float2 aTexCoord [[attribute(1)]]; + int2 aPosition [[attribute(0)]]; + int2 aTexCoord [[attribute(1)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float2 uTextureSize [[buffer(0)]], float2 uFramebufferSize [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aTexCoord / uTextureSize; - float2 position = ((in.aPosition / uFramebufferSize) * 2.0) - float2(1.0); + out.vTexCoord = float2(in.aTexCoord) / (*spvDescriptorSet0.uTextureSize); + float2 position = ((float2(in.aPosition) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); out.gl_Position = float4(position.x, -position.y, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/demo_ground.fs.metal b/resources/shaders/metal/demo_ground.fs.metal index 919b2f37..1b64111f 100644 --- a/resources/shaders/metal/demo_ground.fs.metal +++ b/resources/shaders/metal/demo_ground.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4* uGridlineColor [[id(0)]]; + constant float4* uGroundColor [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,12 +20,12 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4 uGridlineColor [[buffer(0)]], float4 uGroundColor [[buffer(1)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float2 texCoordPx = fract(in.vTexCoord) / fwidth(in.vTexCoord); bool4 _33 = bool4(any(texCoordPx <= float2(1.0))); - out.oFragColor = float4(_33.x ? uGridlineColor.x : uGroundColor.x, _33.y ? uGridlineColor.y : uGroundColor.y, _33.z ? uGridlineColor.z : uGroundColor.z, _33.w ? uGridlineColor.w : uGroundColor.w); + out.oFragColor = float4(_33.x ? (*spvDescriptorSet0.uGridlineColor).x : (*spvDescriptorSet0.uGroundColor).x, _33.y ? (*spvDescriptorSet0.uGridlineColor).y : (*spvDescriptorSet0.uGroundColor).y, _33.z ? (*spvDescriptorSet0.uGridlineColor).z : (*spvDescriptorSet0.uGroundColor).z, _33.w ? (*spvDescriptorSet0.uGridlineColor).w : (*spvDescriptorSet0.uGroundColor).w); return out; } diff --git a/resources/shaders/metal/demo_ground.vs.metal b/resources/shaders/metal/demo_ground.vs.metal index 049083ea..997185f5 100644 --- a/resources/shaders/metal/demo_ground.vs.metal +++ b/resources/shaders/metal/demo_ground.vs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant int* uGridlineCount [[id(0)]]; + constant float4x4* uTransform [[id(1)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,14 +18,14 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], int uGridlineCount [[buffer(0)]], float4x4 uTransform [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aPosition * float(uGridlineCount); - out.gl_Position = uTransform * float4(in.aPosition.x, 0.0, in.aPosition.y, 1.0); + out.vTexCoord = float2(in.aPosition * int2((*spvDescriptorSet0.uGridlineCount))); + out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(int4(in.aPosition.x, 0, in.aPosition.y, 1)); return out; } diff --git a/resources/shaders/metal/fill.fs.metal b/resources/shaders/metal/fill.fs.metal index d002bba6..bfa765e5 100644 --- a/resources/shaders/metal/fill.fs.metal +++ b/resources/shaders/metal/fill.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + texture2d uAreaLUT [[id(0)]]; + sampler uAreaLUTSmplr [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -14,7 +21,7 @@ struct main0_in float2 vTo [[user(locn1)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], texture2d uAreaLUT [[texture(0)]], sampler uAreaLUTSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float2 from = in.vFrom; @@ -29,7 +36,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d uAreaLUT [[t float y = mix(left.y, right.y, t); float d = (right.y - left.y) / (right.x - left.x); float dX = window.x - window.y; - out.oFragColor = float4(uAreaLUT.sample(uAreaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0))).x * dX); + out.oFragColor = float4(spvDescriptorSet0.uAreaLUT.sample(spvDescriptorSet0.uAreaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0))).x * dX); return out; } diff --git a/resources/shaders/metal/fill.vs.metal b/resources/shaders/metal/fill.vs.metal index 1c545156..87f77d2a 100644 --- a/resources/shaders/metal/fill.vs.metal +++ b/resources/shaders/metal/fill.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,12 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uFramebufferSize [[id(1)]]; +}; + struct main0_out { float2 vFrom [[user(locn0)]]; @@ -14,7 +21,7 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint aFromPx [[attribute(1)]]; uint aToPx [[attribute(2)]]; float2 aFromSubpx [[attribute(3)]]; @@ -22,23 +29,23 @@ struct main0_in uint aTileIndex [[attribute(5)]]; }; -float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize, thread uint& aTileIndex) +float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize) { uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x); - uint2 tileOffset = uint2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uint2 tileOffset = uint2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return float2(tileOffset) * uTileSize; } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uFramebufferSize [[buffer(1)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; uint param = in.aTileIndex; - float param_1 = uFramebufferSize.x; - float2 tileOrigin = computeTileOffset(param, param_1, uTileSize, in.aTileIndex); + float param_1 = (*spvDescriptorSet0.uFramebufferSize).x; + float2 tileOrigin = computeTileOffset(param, param_1, (*spvDescriptorSet0.uTileSize)); float2 from = float2(float(in.aFromPx & 15u), float(in.aFromPx >> 4u)) + in.aFromSubpx; float2 to = float2(float(in.aToPx & 15u), float(in.aToPx >> 4u)) + in.aToSubpx; float2 position; - if (in.aTessCoord.x < 0.5) + if (in.aTessCoord.x == 0u) { position.x = floor(fast::min(from.x, to.x)); } @@ -46,17 +53,19 @@ vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], { position.x = ceil(fast::max(from.x, to.x)); } - if (in.aTessCoord.y < 0.5) + if (in.aTessCoord.y == 0u) { position.y = floor(fast::min(from.y, to.y)); } else { - position.y = uTileSize.y; + position.y = (*spvDescriptorSet0.uTileSize).y; } out.vFrom = from - position; out.vTo = to - position; - out.gl_Position = float4((((tileOrigin + position) / uFramebufferSize) * 2.0) - float2(1.0), 0.0, 1.0); + float2 globalPosition = (((tileOrigin + position) / (*spvDescriptorSet0.uFramebufferSize)) * 2.0) - float2(1.0); + globalPosition.y = -globalPosition.y; + out.gl_Position = float4(globalPosition, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/post.fs.metal b/resources/shaders/metal/post.fs.metal index 66ca87f8..3c9502b4 100644 --- a/resources/shaders/metal/post.fs.metal +++ b/resources/shaders/metal/post.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,19 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + texture2d uGammaLUT [[id(0)]]; + sampler uGammaLUTSmplr [[id(1)]]; + constant float4* uKernel [[id(2)]]; + texture2d uSource [[id(3)]]; + sampler uSourceSmplr [[id(4)]]; + constant float2* uSourceSize [[id(5)]]; + constant int* uGammaCorrectionEnabled [[id(6)]]; + constant float4* uBGColor [[id(7)]]; + constant float4* uFGColor [[id(8)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -78,42 +92,42 @@ float3 gammaCorrect(thread const float3& bgColor, thread const float3& fgColor, return float3(gammaCorrectChannel(param, param_1, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_2, param_3, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_4, param_5, uGammaLUT, uGammaLUTSmplr)); } -fragment main0_out main0(main0_in in [[stage_in]], int uGammaCorrectionEnabled [[buffer(2)]], float4 uKernel [[buffer(0)]], float2 uSourceSize [[buffer(1)]], float4 uBGColor [[buffer(3)]], float4 uFGColor [[buffer(4)]], texture2d uGammaLUT [[texture(0)]], texture2d uSource [[texture(0)]], sampler uGammaLUTSmplr [[sampler(0)]], sampler uSourceSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; float3 alpha; - if (uKernel.w == 0.0) + if ((*spvDescriptorSet0.uKernel).w == 0.0) { - alpha = uSource.sample(uSourceSmplr, in.vTexCoord).xxx; + alpha = spvDescriptorSet0.uSource.sample(spvDescriptorSet0.uSourceSmplr, in.vTexCoord).xxx; } else { - float param_3 = 1.0 / uSourceSize.x; + float param_3 = 1.0 / (*spvDescriptorSet0.uSourceSize).x; float4 param; float param_1; float4 param_2; - sample9Tap(param, param_1, param_2, param_3, uKernel, uSource, uSourceSmplr, in.vTexCoord); + sample9Tap(param, param_1, param_2, param_3, (*spvDescriptorSet0.uKernel), spvDescriptorSet0.uSource, spvDescriptorSet0.uSourceSmplr, in.vTexCoord); float4 alphaLeft = param; float alphaCenter = param_1; float4 alphaRight = param_2; float4 param_4 = alphaLeft; float3 param_5 = float3(alphaCenter, alphaRight.xy); - float r = convolve7Tap(param_4, param_5, uKernel); + float r = convolve7Tap(param_4, param_5, (*spvDescriptorSet0.uKernel)); float4 param_6 = float4(alphaLeft.yzw, alphaCenter); float3 param_7 = alphaRight.xyz; - float g = convolve7Tap(param_6, param_7, uKernel); + float g = convolve7Tap(param_6, param_7, (*spvDescriptorSet0.uKernel)); float4 param_8 = float4(alphaLeft.zw, alphaCenter, alphaRight.x); float3 param_9 = alphaRight.yzw; - float b = convolve7Tap(param_8, param_9, uKernel); + float b = convolve7Tap(param_8, param_9, (*spvDescriptorSet0.uKernel)); alpha = float3(r, g, b); } - if (uGammaCorrectionEnabled != 0) + if ((*spvDescriptorSet0.uGammaCorrectionEnabled) != 0) { - float3 param_10 = uBGColor.xyz; + float3 param_10 = (*spvDescriptorSet0.uBGColor).xyz; float3 param_11 = alpha; - alpha = gammaCorrect(param_10, param_11, uGammaLUT, uGammaLUTSmplr); + alpha = gammaCorrect(param_10, param_11, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr); } - out.oFragColor = float4(mix(uBGColor.xyz, uFGColor.xyz, alpha), 1.0); + out.oFragColor = float4(mix((*spvDescriptorSet0.uBGColor).xyz, (*spvDescriptorSet0.uFGColor).xyz, alpha), 1.0); return out; } diff --git a/resources/shaders/metal/post.vs.metal b/resources/shaders/metal/post.vs.metal index a960ca1b..f7385038 100644 --- a/resources/shaders/metal/post.vs.metal +++ b/resources/shaders/metal/post.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include @@ -11,14 +12,16 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - out.vTexCoord = in.aPosition; - out.gl_Position = float4((in.aPosition * 2.0) - float2(1.0), 0.0, 1.0); + float2 position = float2(in.aPosition); + out.vTexCoord = position; + position.y = 1.0 - position.y; + out.gl_Position = float4((float2(position) * 2.0) - float2(1.0), 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/reproject.fs.metal b/resources/shaders/metal/reproject.fs.metal index 3e2a2039..be9ff4dd 100644 --- a/resources/shaders/metal/reproject.fs.metal +++ b/resources/shaders/metal/reproject.fs.metal @@ -1,8 +1,16 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4x4* uOldTransform [[id(0)]]; + texture2d uTexture [[id(1)]]; + sampler uTextureSmplr [[id(2)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -13,12 +21,12 @@ struct main0_in float2 vTexCoord [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], float4x4 uOldTransform [[buffer(0)]], texture2d uTexture [[texture(0)]], sampler uTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float4 normTexCoord = uOldTransform * float4(in.vTexCoord, 0.0, 1.0); + float4 normTexCoord = (*spvDescriptorSet0.uOldTransform) * float4(in.vTexCoord, 0.0, 1.0); float2 texCoord = ((normTexCoord.xy / float2(normTexCoord.w)) + float2(1.0)) * 0.5; - out.oFragColor = uTexture.sample(uTextureSmplr, texCoord); + out.oFragColor = spvDescriptorSet0.uTexture.sample(spvDescriptorSet0.uTextureSmplr, texCoord); return out; } diff --git a/resources/shaders/metal/reproject.vs.metal b/resources/shaders/metal/reproject.vs.metal index d125c376..3bdc9034 100644 --- a/resources/shaders/metal/reproject.vs.metal +++ b/resources/shaders/metal/reproject.vs.metal @@ -1,8 +1,14 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float4x4* uNewTransform [[id(0)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -11,14 +17,16 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], float4x4 uNewTransform [[buffer(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - out.vTexCoord = in.aPosition; - out.gl_Position = uNewTransform * float4(in.aPosition, 0.0, 1.0); + float2 position = float2(in.aPosition); + out.vTexCoord = position; + position.y = 1.0 - position.y; + out.gl_Position = (*spvDescriptorSet0.uNewTransform) * float4(position, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/stencil.fs.metal b/resources/shaders/metal/stencil.fs.metal index 426311ef..999cc7e1 100644 --- a/resources/shaders/metal/stencil.fs.metal +++ b/resources/shaders/metal/stencil.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include diff --git a/resources/shaders/metal/stencil.vs.metal b/resources/shaders/metal/stencil.vs.metal index 2dc23a5d..6b6182d4 100644 --- a/resources/shaders/metal/stencil.vs.metal +++ b/resources/shaders/metal/stencil.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include @@ -13,7 +14,7 @@ struct main0_in float3 aPosition [[attribute(0)]]; }; -vertex main0_out main0(main0_in in [[stage_in]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; out.gl_Position = float4(in.aPosition, 1.0); diff --git a/resources/shaders/metal/tile_alpha.fs.metal b/resources/shaders/metal/tile_alpha.fs.metal index 30afe4cd..2e72b19e 100644 --- a/resources/shaders/metal/tile_alpha.fs.metal +++ b/resources/shaders/metal/tile_alpha.fs.metal @@ -1,8 +1,15 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include using namespace metal; +struct spvDescriptorSetBuffer0 +{ + texture2d uStencilTexture [[id(0)]]; + sampler uStencilTextureSmplr [[id(1)]]; +}; + struct main0_out { float4 oFragColor [[color(0)]]; @@ -15,10 +22,10 @@ struct main0_in float4 vColor [[user(locn2)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], texture2d uStencilTexture [[texture(0)]], sampler uStencilTextureSmplr [[sampler(0)]]) +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float coverage = abs(uStencilTexture.sample(uStencilTextureSmplr, in.vTexCoord).x + in.vBackdrop); + float coverage = abs(spvDescriptorSet0.uStencilTexture.sample(spvDescriptorSet0.uStencilTextureSmplr, in.vTexCoord).x + in.vBackdrop); out.oFragColor = float4(in.vColor.xyz, in.vColor.w * coverage); return out; } diff --git a/resources/shaders/metal/tile_alpha_monochrome.vs.metal b/resources/shaders/metal/tile_alpha_monochrome.vs.metal index e92a3af0..9c9e1b56 100644 --- a/resources/shaders/metal/tile_alpha_monochrome.vs.metal +++ b/resources/shaders/metal/tile_alpha_monochrome.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,15 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + constant float2* uStencilTextureSize [[id(3)]]; + constant float4* uColor [[id(4)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -15,10 +25,10 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint3 aTileOrigin [[attribute(1)]]; int aBackdrop [[attribute(2)]]; - uint aTileIndex [[attribute(3)]]; + int aTileIndex [[attribute(3)]]; }; float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize) @@ -33,25 +43,25 @@ float4 getColor(thread float4 uColor) return uColor; } -void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread float2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread uint& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) +void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) { float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0); - float2 pixelPosition = ((origin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); - uint param = aTileIndex; + uint param = uint(aTileIndex); float param_1 = uStencilTextureSize.x; float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize); - float2 maskTexCoord = maskTexCoordOrigin + (aTessCoord * uTileSize); + float2 maskTexCoord = maskTexCoordOrigin + (float2(aTessCoord) * uTileSize); vTexCoord = maskTexCoord / uStencilTextureSize; vBackdrop = float(aBackdrop); vColor = getColor(uColor); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float2 uStencilTextureSize [[buffer(3)]], float4 uColor [[buffer(4)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(uTileSize, in.aTileOrigin, in.aTessCoord, uViewBoxOrigin, uFramebufferSize, in.aTileIndex, uStencilTextureSize, out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, uColor); + computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor)); return out; } diff --git a/resources/shaders/metal/tile_alpha_multicolor.vs.metal b/resources/shaders/metal/tile_alpha_multicolor.vs.metal index 525d7fe3..7e62af78 100644 --- a/resources/shaders/metal/tile_alpha_multicolor.vs.metal +++ b/resources/shaders/metal/tile_alpha_multicolor.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,16 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + constant float2* uStencilTextureSize [[id(3)]]; + texture2d uPaintTexture [[id(4)]]; + sampler uPaintTextureSmplr [[id(5)]]; +}; + struct main0_out { float2 vTexCoord [[user(locn0)]]; @@ -15,10 +26,10 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; + uint2 aTessCoord [[attribute(0)]]; uint3 aTileOrigin [[attribute(1)]]; int aBackdrop [[attribute(2)]]; - uint aTileIndex [[attribute(3)]]; + int aTileIndex [[attribute(3)]]; float2 aColorTexCoord [[attribute(4)]]; }; @@ -34,25 +45,25 @@ float4 getColor(thread texture2d uPaintTexture, thread const sampler uPai return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0)); } -void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread float2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread uint& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) +void computeVaryings(thread float2 uTileSize, thread uint3& aTileOrigin, thread uint2& aTessCoord, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread int& aTileIndex, thread float2 uStencilTextureSize, thread float2& vTexCoord, thread float& vBackdrop, thread int& aBackdrop, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) { float2 origin = float2(aTileOrigin.xy) + (float2(float(aTileOrigin.z & 15u), float(aTileOrigin.z >> 4u)) * 256.0); - float2 pixelPosition = ((origin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = ((origin + float2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); - uint param = aTileIndex; + uint param = uint(aTileIndex); float param_1 = uStencilTextureSize.x; float2 maskTexCoordOrigin = computeTileOffset(param, param_1, uTileSize); - float2 maskTexCoord = maskTexCoordOrigin + (aTessCoord * uTileSize); + float2 maskTexCoord = maskTexCoordOrigin + (float2(aTessCoord) * uTileSize); vTexCoord = maskTexCoord / uStencilTextureSize; vBackdrop = float(aBackdrop); vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float2 uStencilTextureSize [[buffer(3)]], texture2d uPaintTexture [[texture(0)]], sampler uPaintTextureSmplr [[sampler(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(uTileSize, in.aTileOrigin, in.aTessCoord, uViewBoxOrigin, uFramebufferSize, in.aTileIndex, uStencilTextureSize, out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, uPaintTexture, uPaintTextureSmplr, in.aColorTexCoord); + computeVaryings((*spvDescriptorSet0.uTileSize), in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), in.aTileIndex, (*spvDescriptorSet0.uStencilTextureSize), out.vTexCoord, out.vBackdrop, in.aBackdrop, out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord); return out; } diff --git a/resources/shaders/metal/tile_solid.fs.metal b/resources/shaders/metal/tile_solid.fs.metal index fed4023d..ac500c97 100644 --- a/resources/shaders/metal/tile_solid.fs.metal +++ b/resources/shaders/metal/tile_solid.fs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #include #include diff --git a/resources/shaders/metal/tile_solid_monochrome.vs.metal b/resources/shaders/metal/tile_solid_monochrome.vs.metal index 83410055..46328863 100644 --- a/resources/shaders/metal/tile_solid_monochrome.vs.metal +++ b/resources/shaders/metal/tile_solid_monochrome.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,14 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + constant float4* uColor [[id(3)]]; +}; + struct main0_out { float4 vColor [[user(locn0)]]; @@ -13,8 +22,8 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; - float2 aTileOrigin [[attribute(1)]]; + uint2 aTessCoord [[attribute(0)]]; + int2 aTileOrigin [[attribute(1)]]; }; float4 getColor(thread float4 uColor) @@ -22,18 +31,18 @@ float4 getColor(thread float4 uColor) return uColor; } -void computeVaryings(thread float2& aTileOrigin, thread float2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) +void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread float4 uColor) { - float2 pixelPosition = ((aTileOrigin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); vColor = getColor(uColor); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], float4 uColor [[buffer(3)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(in.aTileOrigin, in.aTessCoord, uTileSize, uViewBoxOrigin, uFramebufferSize, out.vColor, out.gl_Position, uColor); + computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, (*spvDescriptorSet0.uColor)); return out; } diff --git a/resources/shaders/metal/tile_solid_multicolor.vs.metal b/resources/shaders/metal/tile_solid_multicolor.vs.metal index 3f5d0c45..573f5173 100644 --- a/resources/shaders/metal/tile_solid_multicolor.vs.metal +++ b/resources/shaders/metal/tile_solid_multicolor.vs.metal @@ -1,3 +1,4 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! #pragma clang diagnostic ignored "-Wmissing-prototypes" #include @@ -5,6 +6,15 @@ using namespace metal; +struct spvDescriptorSetBuffer0 +{ + constant float2* uTileSize [[id(0)]]; + constant float2* uViewBoxOrigin [[id(1)]]; + constant float2* uFramebufferSize [[id(2)]]; + texture2d uPaintTexture [[id(3)]]; + sampler uPaintTextureSmplr [[id(4)]]; +}; + struct main0_out { float4 vColor [[user(locn0)]]; @@ -13,8 +23,8 @@ struct main0_out struct main0_in { - float2 aTessCoord [[attribute(0)]]; - float2 aTileOrigin [[attribute(1)]]; + uint2 aTessCoord [[attribute(0)]]; + int2 aTileOrigin [[attribute(1)]]; float2 aColorTexCoord [[attribute(2)]]; }; @@ -23,18 +33,18 @@ float4 getColor(thread texture2d uPaintTexture, thread const sampler uPai return uPaintTexture.sample(uPaintTextureSmplr, aColorTexCoord, level(0.0)); } -void computeVaryings(thread float2& aTileOrigin, thread float2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) +void computeVaryings(thread int2& aTileOrigin, thread uint2& aTessCoord, thread float2 uTileSize, thread float2 uViewBoxOrigin, thread float2 uFramebufferSize, thread float4& vColor, thread float4& gl_Position, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& aColorTexCoord) { - float2 pixelPosition = ((aTileOrigin + aTessCoord) * uTileSize) + uViewBoxOrigin; + float2 pixelPosition = (float2(aTileOrigin + int2(aTessCoord)) * uTileSize) + uViewBoxOrigin; float2 position = (((pixelPosition / uFramebufferSize) * 2.0) - float2(1.0)) * float2(1.0, -1.0); vColor = getColor(uPaintTexture, uPaintTextureSmplr, aColorTexCoord); gl_Position = float4(position, 0.0, 1.0); } -vertex main0_out main0(main0_in in [[stage_in]], float2 uTileSize [[buffer(0)]], float2 uViewBoxOrigin [[buffer(1)]], float2 uFramebufferSize [[buffer(2)]], texture2d uPaintTexture [[texture(0)]], sampler uPaintTextureSmplr [[sampler(0)]], uint gl_VertexID [[vertex_id]], uint gl_InstanceID [[instance_id]]) +vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - computeVaryings(in.aTileOrigin, in.aTessCoord, uTileSize, uViewBoxOrigin, uFramebufferSize, out.vColor, out.gl_Position, uPaintTexture, uPaintTextureSmplr, in.aColorTexCoord); + computeVaryings(in.aTileOrigin, in.aTessCoord, (*spvDescriptorSet0.uTileSize), (*spvDescriptorSet0.uViewBoxOrigin), (*spvDescriptorSet0.uFramebufferSize), out.vColor, out.gl_Position, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.aColorTexCoord); return out; } diff --git a/resources/shaders/spirv/debug_solid.fs.spv b/resources/shaders/spirv/debug_solid.fs.spv deleted file mode 100644 index ae1e7b85..00000000 Binary files a/resources/shaders/spirv/debug_solid.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/debug_solid.vs.spv b/resources/shaders/spirv/debug_solid.vs.spv deleted file mode 100644 index 0c94d0df..00000000 Binary files a/resources/shaders/spirv/debug_solid.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/debug_texture.fs.spv b/resources/shaders/spirv/debug_texture.fs.spv deleted file mode 100644 index 1be8ae23..00000000 Binary files a/resources/shaders/spirv/debug_texture.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/debug_texture.vs.spv b/resources/shaders/spirv/debug_texture.vs.spv deleted file mode 100644 index 22f838c7..00000000 Binary files a/resources/shaders/spirv/debug_texture.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/demo_ground.fs.spv b/resources/shaders/spirv/demo_ground.fs.spv deleted file mode 100644 index 8dc291cf..00000000 Binary files a/resources/shaders/spirv/demo_ground.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/demo_ground.vs.spv b/resources/shaders/spirv/demo_ground.vs.spv deleted file mode 100644 index 0a0926a6..00000000 Binary files a/resources/shaders/spirv/demo_ground.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/fill.fs.spv b/resources/shaders/spirv/fill.fs.spv deleted file mode 100644 index 4cb3b288..00000000 Binary files a/resources/shaders/spirv/fill.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/fill.vs.spv b/resources/shaders/spirv/fill.vs.spv deleted file mode 100644 index 1ae09e95..00000000 Binary files a/resources/shaders/spirv/fill.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/post.fs.spv b/resources/shaders/spirv/post.fs.spv deleted file mode 100644 index b6d2fec3..00000000 Binary files a/resources/shaders/spirv/post.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/post.vs.spv b/resources/shaders/spirv/post.vs.spv deleted file mode 100644 index 6d35fb90..00000000 Binary files a/resources/shaders/spirv/post.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/reproject.fs.spv b/resources/shaders/spirv/reproject.fs.spv deleted file mode 100644 index 34b4930a..00000000 Binary files a/resources/shaders/spirv/reproject.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/reproject.vs.spv b/resources/shaders/spirv/reproject.vs.spv deleted file mode 100644 index 9b39096e..00000000 Binary files a/resources/shaders/spirv/reproject.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/stencil.fs.spv b/resources/shaders/spirv/stencil.fs.spv deleted file mode 100644 index 4c89a941..00000000 Binary files a/resources/shaders/spirv/stencil.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/stencil.vs.spv b/resources/shaders/spirv/stencil.vs.spv deleted file mode 100644 index e24f65ab..00000000 Binary files a/resources/shaders/spirv/stencil.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/tile_alpha.fs.spv b/resources/shaders/spirv/tile_alpha.fs.spv deleted file mode 100644 index 006cb101..00000000 Binary files a/resources/shaders/spirv/tile_alpha.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/tile_alpha_monochrome.vs.spv b/resources/shaders/spirv/tile_alpha_monochrome.vs.spv deleted file mode 100644 index 782bc4f9..00000000 Binary files a/resources/shaders/spirv/tile_alpha_monochrome.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/tile_alpha_multicolor.vs.spv b/resources/shaders/spirv/tile_alpha_multicolor.vs.spv deleted file mode 100644 index 99363c6b..00000000 Binary files a/resources/shaders/spirv/tile_alpha_multicolor.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/tile_solid.fs.spv b/resources/shaders/spirv/tile_solid.fs.spv deleted file mode 100644 index cce99735..00000000 Binary files a/resources/shaders/spirv/tile_solid.fs.spv and /dev/null differ diff --git a/resources/shaders/spirv/tile_solid_monochrome.vs.spv b/resources/shaders/spirv/tile_solid_monochrome.vs.spv deleted file mode 100644 index 14cf6c14..00000000 Binary files a/resources/shaders/spirv/tile_solid_monochrome.vs.spv and /dev/null differ diff --git a/resources/shaders/spirv/tile_solid_multicolor.vs.spv b/resources/shaders/spirv/tile_solid_multicolor.vs.spv deleted file mode 100644 index 9e6cdceb..00000000 Binary files a/resources/shaders/spirv/tile_solid_multicolor.vs.spv and /dev/null differ diff --git a/resources/swf/tiger-flat.swf b/resources/swf/tiger-flat.swf new file mode 100644 index 00000000..70127188 Binary files /dev/null and b/resources/swf/tiger-flat.swf differ diff --git a/resources/swf/tiger.swf b/resources/swf/tiger.swf new file mode 100644 index 00000000..9bb17c65 Binary files /dev/null and b/resources/swf/tiger.swf differ diff --git a/shaders/Makefile b/shaders/Makefile index 42e78baa..327144c8 100644 --- a/shaders/Makefile +++ b/shaders/Makefile @@ -37,14 +37,20 @@ INCLUDES=\ OUT=\ $(SHADERS:%=$(TARGET_DIR)/gl3/%) \ $(SHADERS:%.glsl=$(TARGET_DIR)/metal/%.metal) \ + $(SHADERS:%.glsl=build/metal/%.spv) \ $(EMPTY) GLSL_VERSION=330 GLSLANGFLAGS=--auto-map-locations -I. +GLSLANGFLAGS_METAL=$(GLSLANGFLAGS) -DPF_ORIGIN_UPPER_LEFT=1 -SPIRVCROSSFLAGS=--msl +SPIRVCROSS?=spirv-cross +SPIRVCROSSFLAGS=--msl --msl-version 020100 --msl-argument-buffers -SED_ARGS=-e "s/\#version 330/\#version \{\{version\}\}/" -e "s/\#line.*$$//" +GLSL_VERSION_HEADER="\#version {{version}}" +HEADER="// Automatically generated from files in pathfinder/shaders/. Do not edit!" + +GLSL_SED_ARGS=-e "s/\#version 330//" -e "s/\#line.*$$//" all: $(OUT) @@ -53,17 +59,17 @@ all: $(OUT) clean: rm -f $(OUT) -$(TARGET_DIR)/spirv/%.fs.spv: %.fs.glsl $(INCLUDES) - mkdir -p $(TARGET_DIR)/spirv && glslangValidator $(GLSLANGFLAGS) -G$(GLSL_VERSION) -S frag -o $@ $< +build/metal/%.fs.spv: %.fs.glsl $(INCLUDES) + mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S frag -o $@ $< $(TARGET_DIR)/gl3/%.fs.glsl: %.fs.glsl $(INCLUDES) - mkdir -p $(TARGET_DIR)/gl3 && glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(SED_ARGS) > $@ + mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) -$(TARGET_DIR)/spirv/%.vs.spv: %.vs.glsl $(INCLUDES) - mkdir -p $(TARGET_DIR)/spirv && glslangValidator $(GLSLANGFLAGS) -G$(GLSL_VERSION) -S vert -o $@ $< +build/metal/%.vs.spv: %.vs.glsl $(INCLUDES) + mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S vert -o $@ $< $(TARGET_DIR)/gl3/%.vs.glsl: %.vs.glsl $(INCLUDES) - mkdir -p $(TARGET_DIR)/gl3 && glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(SED_ARGS) > $@ + mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) -$(TARGET_DIR)/metal/%.metal: $(TARGET_DIR)/spirv/%.spv - mkdir -p $(TARGET_DIR)/metal && spirv-cross $(SPIRVCROSSFLAGS) --output $@ $< +$(TARGET_DIR)/metal/%.metal: build/metal/%.spv + mkdir -p $(TARGET_DIR)/metal && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< | sed $(METAL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) diff --git a/shaders/debug_solid.vs.glsl b/shaders/debug_solid.vs.glsl index 10b92ad8..8dd2f383 100644 --- a/shaders/debug_solid.vs.glsl +++ b/shaders/debug_solid.vs.glsl @@ -14,9 +14,9 @@ precision highp float; uniform vec2 uFramebufferSize; -in vec2 aPosition; +in ivec2 aPosition; void main() { - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vec2 position = vec2(aPosition) / uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position.x, -position.y, 0.0, 1.0); } diff --git a/shaders/debug_texture.vs.glsl b/shaders/debug_texture.vs.glsl index 734916f1..7df2a288 100644 --- a/shaders/debug_texture.vs.glsl +++ b/shaders/debug_texture.vs.glsl @@ -15,13 +15,13 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTextureSize; -in vec2 aPosition; -in vec2 aTexCoord; +in ivec2 aPosition; +in ivec2 aTexCoord; out vec2 vTexCoord; void main() { - vTexCoord = aTexCoord / uTextureSize; - vec2 position = aPosition / uFramebufferSize * 2.0 - 1.0; + vTexCoord = vec2(aTexCoord) / uTextureSize; + vec2 position = vec2(aPosition) / uFramebufferSize * 2.0 - 1.0; gl_Position = vec4(position.x, -position.y, 0.0, 1.0); } diff --git a/shaders/demo_ground.vs.glsl b/shaders/demo_ground.vs.glsl index b145ce04..e2a618b6 100644 --- a/shaders/demo_ground.vs.glsl +++ b/shaders/demo_ground.vs.glsl @@ -15,11 +15,11 @@ precision highp float; uniform mat4 uTransform; uniform int uGridlineCount; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition * float(uGridlineCount); - gl_Position = uTransform * vec4(aPosition.x, 0.0, aPosition.y, 1.0); + vTexCoord = vec2(aPosition * uGridlineCount); + gl_Position = uTransform * vec4(ivec4(aPosition.x, 0, aPosition.y, 1)); } diff --git a/shaders/fill.vs.glsl b/shaders/fill.vs.glsl index f5abbf7e..7b75578b 100644 --- a/shaders/fill.vs.glsl +++ b/shaders/fill.vs.glsl @@ -1,6 +1,6 @@ #version 330 -// pathfinder/resources/fill.vs.glsl +// pathfinder/shaders/fill.vs.glsl // // Copyright © 2019 The Pathfinder Project Developers. // @@ -15,7 +15,7 @@ precision highp float; uniform vec2 uFramebufferSize; uniform vec2 uTileSize; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uint aFromPx; in uint aToPx; in vec2 aFromSubpx; @@ -27,7 +27,7 @@ out vec2 vTo; vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) { uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x); - uvec2 tileOffset = uvec2(aTileIndex % tilesPerRow, aTileIndex / tilesPerRow); + uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); return vec2(tileOffset) * uTileSize; } @@ -38,11 +38,11 @@ void main() { vec2 to = vec2(aToPx & 15u, aToPx >> 4u) + aToSubpx; vec2 position; - if (aTessCoord.x < 0.5) + if (aTessCoord.x == 0u) position.x = floor(min(from.x, to.x)); else position.x = ceil(max(from.x, to.x)); - if (aTessCoord.y < 0.5) + if (aTessCoord.y == 0u) position.y = floor(min(from.y, to.y)); else position.y = uTileSize.y; @@ -50,5 +50,9 @@ void main() { vFrom = from - position; vTo = to - position; - gl_Position = vec4((tileOrigin + position) / uFramebufferSize * 2.0 - 1.0, 0.0, 1.0); + vec2 globalPosition = (tileOrigin + position) / uFramebufferSize * 2.0 - 1.0; +#ifdef PF_ORIGIN_UPPER_LEFT + globalPosition.y = -globalPosition.y; +#endif + gl_Position = vec4(globalPosition, 0.0, 1.0); } diff --git a/shaders/post.vs.glsl b/shaders/post.vs.glsl index 2ee824a7..52cf3eea 100644 --- a/shaders/post.vs.glsl +++ b/shaders/post.vs.glsl @@ -12,11 +12,17 @@ precision highp float; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition; - gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + +#ifdef PF_ORIGIN_UPPER_LEFT + // FIXME(pcwalton): This is wrong. + position.y = 1.0 - position.y; +#endif + gl_Position = vec4(vec2(position) * 2.0 - 1.0, 0.0, 1.0); } diff --git a/shaders/reproject.vs.glsl b/shaders/reproject.vs.glsl index 91d9f9a9..f10433b1 100644 --- a/shaders/reproject.vs.glsl +++ b/shaders/reproject.vs.glsl @@ -14,11 +14,17 @@ precision highp float; uniform mat4 uNewTransform; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition; - gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0); + vec2 position = vec2(aPosition); + vTexCoord = position; + +#ifdef PF_ORIGIN_UPPER_LEFT + // FIXME(pcwalton): This is wrong. + position.y = 1.0 - position.y; +#endif + gl_Position = uNewTransform * vec4(position, 0.0, 1.0); } diff --git a/shaders/tile_alpha_vertex.inc.glsl b/shaders/tile_alpha_vertex.inc.glsl index 6993a13d..e5211809 100644 --- a/shaders/tile_alpha_vertex.inc.glsl +++ b/shaders/tile_alpha_vertex.inc.glsl @@ -13,10 +13,10 @@ uniform vec2 uTileSize; uniform vec2 uStencilTextureSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; +in uvec2 aTessCoord; in uvec3 aTileOrigin; in int aBackdrop; -in uint aTileIndex; +in int aTileIndex; out vec2 vTexCoord; out float vBackdrop; @@ -32,9 +32,9 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) { void computeVaryings() { vec2 origin = vec2(aTileOrigin.xy) + vec2(aTileOrigin.z & 15u, aTileOrigin.z >> 4u) * 256.0; - vec2 pixelPosition = (origin + aTessCoord) * uTileSize + uViewBoxOrigin; + vec2 pixelPosition = (origin + vec2(aTessCoord)) * uTileSize + uViewBoxOrigin; vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0); - vec2 maskTexCoordOrigin = computeTileOffset(aTileIndex, uStencilTextureSize.x); + vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize.x); vec2 maskTexCoord = maskTexCoordOrigin + aTessCoord * uTileSize; vTexCoord = maskTexCoord / uStencilTextureSize; diff --git a/shaders/tile_solid_vertex.inc.glsl b/shaders/tile_solid_vertex.inc.glsl index 73f30cd0..fc7c8bc5 100644 --- a/shaders/tile_solid_vertex.inc.glsl +++ b/shaders/tile_solid_vertex.inc.glsl @@ -12,18 +12,17 @@ uniform vec2 uFramebufferSize; uniform vec2 uTileSize; uniform vec2 uViewBoxOrigin; -in vec2 aTessCoord; -in vec2 aTileOrigin; +in uvec2 aTessCoord; +in ivec2 aTileOrigin; out vec4 vColor; vec4 getColor(); void computeVaryings() { - vec2 pixelPosition = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin; + vec2 pixelPosition = vec2(aTileOrigin + ivec2(aTessCoord)) * uTileSize + uViewBoxOrigin; vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0); vColor = getColor(); - //vColor = vec4(1.0, 0.0, 0.0, 1.0); gl_Position = vec4(position, 0.0, 1.0); } diff --git a/svg/Cargo.toml b/svg/Cargo.toml index 61d0280a..13c630dc 100644 --- a/svg/Cargo.toml +++ b/svg/Cargo.toml @@ -6,7 +6,10 @@ authors = ["Patrick Walton "] [dependencies] bitflags = "1.0" -usvg = "0.4" +usvg = "0.7" + +[dependencies.pathfinder_content] +path = "../content" [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/svg/src/lib.rs b/svg/src/lib.rs index ab664535..2d9b6454 100644 --- a/svg/src/lib.rs +++ b/svg/src/lib.rs @@ -13,14 +13,15 @@ #[macro_use] extern crate bitflags; -use pathfinder_geometry::basic::line_segment::LineSegment2F; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::rect::RectF; -use pathfinder_geometry::basic::transform2d::{Transform2DF, Transform2DFPathIter}; -use pathfinder_geometry::color::ColorU; -use pathfinder_geometry::outline::Outline; -use pathfinder_geometry::segment::{Segment, SegmentFlags}; -use pathfinder_geometry::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle}; +use pathfinder_content::color::ColorU; +use pathfinder_content::outline::Outline; +use pathfinder_content::segment::{Segment, SegmentFlags}; +use pathfinder_content::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle}; +use pathfinder_content::transform::Transform2DFPathIter; +use pathfinder_geometry::line_segment::LineSegment2F; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::vector::Vector2F; use pathfinder_renderer::paint::Paint; use pathfinder_renderer::scene::{PathObject, Scene}; use std::fmt::{Display, Formatter, Result as FormatResult}; @@ -104,10 +105,6 @@ impl BuiltSVG { self.result_flags .insert(BuildResultFlags::UNSUPPORTED_MASK_ATTR); } - if group.opacity.is_some() { - self.result_flags - .insert(BuildResultFlags::UNSUPPORTED_OPACITY_ATTR); - } for kid in node.children() { self.process_node(&kid, &transform) @@ -140,7 +137,7 @@ impl BuiltSVG { line_width: f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH), line_cap: LineCap::from_usvg_line_cap(stroke.linecap), line_join: LineJoin::from_usvg_line_join(stroke.linejoin, - stroke.miterlimit as f32), + stroke.miterlimit.value() as f32), }; let path = UsvgPathToSegments::new(path.segments.iter().cloned()); @@ -194,10 +191,6 @@ impl BuiltSVG { self.result_flags .insert(BuildResultFlags::UNSUPPORTED_NESTED_SVG_NODE); } - NodeKind::Text(..) => { - self.result_flags - .insert(BuildResultFlags::UNSUPPORTED_TEXT_NODE); - } } } } @@ -268,8 +261,8 @@ impl PaintExt for Paint { fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> RectF { RectF::new( - Vector2F::new(rect.x as f32, rect.y as f32), - Vector2F::new(rect.width as f32, rect.height as f32), + Vector2F::new(rect.x() as f32, rect.y() as f32), + Vector2F::new(rect.width() as f32, rect.height() as f32), ) } diff --git a/swf/Cargo.toml b/swf/Cargo.toml new file mode 100644 index 00000000..389a0fd7 --- /dev/null +++ b/swf/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pathfinder_swf" +version = "0.1.0" +authors = ["Jon Hardie "] +edition = "2018" + +[dependencies] +swf-parser = "0.7.0" +swf-tree = "0.7.0" + +[dependencies.pathfinder_content] +path = "../content" + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_renderer] +path = "../renderer" + +[dependencies.pathfinder_gl] +path = "../gl" + +[dependencies.pathfinder_gpu] +path = "../gpu" diff --git a/swf/src/lib.rs b/swf/src/lib.rs new file mode 100644 index 00000000..c8a683e8 --- /dev/null +++ b/swf/src/lib.rs @@ -0,0 +1,206 @@ +// pathfinder/swf/src/lib.rs +// +// Copyright © 2019 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. + +use std::ops::Add; +use pathfinder_content::color::{ColorU, ColorF}; +use pathfinder_content::outline::{Outline, Contour}; +use pathfinder_geometry::vector::Vector2F; +use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_renderer::scene::{PathObject, Scene}; + +use swf_tree; +use swf_tree::tags::SetBackgroundColor; +use swf_tree::{Tag, SRgb8, Movie}; + +use crate::shapes::{GraphicLayers, PaintOrLine}; + +mod shapes; + +type SymbolId = u16; + +// In swf, most values are specified in a fixed point format known as "twips" or twentieths of +// a pixel. We store twips in their integer form, as if we were to convert them to floating point +// at the beginning of the pipeline it's easy to start running into precision errors when we add +// coordinate deltas and then try and compare coords for equality. + +#[derive(Copy, Clone, Debug, PartialEq)] +struct Twips(i32); + +impl Twips { + // Divide twips by 20 to get the f32 value, just to be used once all processing + // of the swf coords is completed and we want to output. + fn as_f32(&self) -> f32 { + self.0 as f32 / 20.0 + } +} + +impl Add for Twips { + type Output = Twips; + fn add(self, rhs: Twips) -> Self { + Twips(self.0 + rhs.0) + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +struct Point2 { + x: T, + y: T +} + +impl Point2 { + fn as_f32(self: Point2) -> Point2 { + Point2 { + x: self.x.as_f32(), + y: self.y.as_f32(), + } + } +} + +impl Add for Point2 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Point2 { x: self.x + rhs.x, y: self.y + rhs.y } + } +} + +enum Symbol { + Graphic(GraphicLayers), + // Timeline, // TODO(jon) +} + +pub struct Stage { + // TODO(jon): Support some kind of lazy frames iterator. + // frames: Timeline, + background_color: SRgb8, + width: i32, + height: i32, +} + +impl Stage { + pub fn width(&self) -> i32 { + self.width + } + + pub fn height(&self) -> i32 { + self.height + } + + pub fn background_color(&self) -> ColorF { + ColorU { + r: self.background_color.r, + g: self.background_color.g, + b: self.background_color.b, + a: 255, + }.to_f32() + } +} + + +pub struct SymbolLibrary(Vec); + +impl SymbolLibrary { + fn add_symbol(&mut self, symbol: Symbol) { + self.0.push(symbol); + } + + fn symbols(&self) -> &Vec { + &self.0 + } +} + +pub fn process_swf_tags(movie: &Movie) -> (SymbolLibrary, Stage) { + let mut symbol_library = SymbolLibrary(Vec::new()); + let stage_width = Twips(movie.header.frame_size.x_max); + let stage_height = Twips(movie.header.frame_size.y_max); + // let num_frames = movie.header.frame_count; + + let mut stage = Stage { + // frames: Timeline(Vec::new()), // TODO(jon) + background_color: SRgb8 { + r: 255, + g: 255, + b: 255 + }, + width: stage_width.as_f32() as i32, + height: stage_height.as_f32() as i32, + }; + + for tag in &movie.tags { + match tag { + Tag::SetBackgroundColor(SetBackgroundColor { color }) => { + stage.background_color = *color; + }, + Tag::DefineShape(shape) => { + symbol_library.add_symbol(Symbol::Graphic(shapes::decode_shape(&shape))); + // We will assume that symbol ids just go up, and are 1 based. + let symbol_id: SymbolId = shape.id; + debug_assert!(symbol_id as usize == symbol_library.0.len()); + } + _ => () + } + } + (symbol_library, stage) +} + +#[allow(irrefutable_let_patterns)] +pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) { + for symbol in library.symbols() { + // NOTE: Right now symbols only contain graphics. + if let Symbol::Graphic(graphic) = symbol { + for style_layer in graphic.layers() { + let mut path = Outline::new(); + let paint_id = scene.push_paint(&style_layer.fill()); + + for shape in style_layer.shapes() { + let mut contour = Contour::new(); + let Point2 { x, y } = shape.outline.first().unwrap().from.as_f32(); + contour.push_endpoint(Vector2F::new(x, y)); + for segment in &shape.outline { + let Point2 { x, y } = segment.to.as_f32(); + match segment.ctrl { + Some(ctrl) => { + let Point2 { x: ctrl_x, y: ctrl_y } = ctrl.as_f32(); + contour.push_quadratic( + Vector2F::new(ctrl_x, ctrl_y), + Vector2F::new(x, y) + ); + } + None => { + contour.push_endpoint(Vector2F::new(x, y)); + }, + } + } + if shape.is_closed() { + // NOTE: I'm not sure if this really does anything in this context, + // since all our closed shapes already have coincident start and end points. + contour.close(); + } + path.push_contour(contour); + } + + if let PaintOrLine::Line(line) = style_layer.kind() { + let mut stroke_to_fill = OutlineStrokeToFill::new(&path, StrokeStyle { + line_width: line.width.as_f32(), + line_cap: line.cap, + line_join: line.join, + }); + stroke_to_fill.offset(); + path = stroke_to_fill.into_outline(); + } + + scene.push_path(PathObject::new( + path, + paint_id, + String::new() + )); + } + } + } +} diff --git a/swf/src/shapes.rs b/swf/src/shapes.rs new file mode 100644 index 00000000..ff0a7b02 --- /dev/null +++ b/swf/src/shapes.rs @@ -0,0 +1,625 @@ +// pathfinder/swf/src/shapes.rs +// +// Copyright © 2019 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. + +use pathfinder_renderer::paint::Paint; +use pathfinder_content::stroke::{LineJoin, LineCap}; +use crate::{Twips, Point2}; +use std::mem; +use std::cmp::Ordering; +use swf_tree::{ + FillStyle, + StraightSRgba8, + LineStyle, + fill_styles, + JoinStyle, + CapStyle, + join_styles, + ShapeRecord, + shape_records, + Vector2D +}; +use pathfinder_content::color::ColorU; +use swf_tree::tags::DefineShape; + +#[derive(Clone, Copy, Debug)] +pub(crate) struct LineSegment { + pub(crate) from: Point2, + pub(crate) to: Point2, + pub(crate) ctrl: Option>, +} + +impl LineSegment { + fn reverse(&mut self) { + let tmp = self.from; + self.from = self.to; + self.to = tmp; + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub(crate) enum LineDirection { + Left, + Right, +} + +impl LineDirection { + fn reverse(&mut self) { + *self = match self { + LineDirection::Right => LineDirection::Left, + LineDirection::Left => LineDirection::Right + }; + } +} + +#[derive(Clone, Debug)] +pub(crate) struct Shape { + pub(crate) outline: Vec, // Could be Vec<(start, end)> + direction: LineDirection, + reversed: bool, +} + +impl Shape { + pub fn new_with_direction(direction: LineDirection) -> Shape { + Shape { + direction, + outline: Vec::new(), + reversed: false, + } + } + + fn prepend_shape(&mut self, shape: &mut Shape) { + shape.append_shape(&self); + mem::swap(&mut self.outline, &mut shape.outline); + } + + fn append_shape(&mut self, shape: &Shape) { + self.outline.extend_from_slice(&shape.outline); + } + + fn add_line_segment(&mut self, segment: LineSegment) { + self.outline.push(segment); + } + + #[inline] + fn len(&self) -> usize { + self.outline.len() + } + + #[inline] + fn first(&self) -> &LineSegment { + &self.outline.first().unwrap() + } + + #[inline] + fn last(&self) -> &LineSegment { + &self.outline.last().unwrap() + } + + #[inline] + fn comes_before(&self, other: &Shape) -> bool { + self.last().to == other.first().from + } + + #[inline] + fn comes_after(&self, other: &Shape) -> bool { + self.first().from == other.last().to + } + + #[inline] + pub(crate) fn is_closed(&self) -> bool { + self.len() > 1 && self.comes_after(self) + } + + fn reverse(&mut self) { + self.reversed = !self.reversed; + self.direction.reverse(); + for segment in &mut self.outline { + segment.reverse(); + } + self.outline.reverse(); + } +} + +pub(crate) struct SwfLineStyle { + color: Paint, + pub(crate) width: Twips, + pub(crate) join: LineJoin, + pub(crate) cap: LineCap, +} + +pub(crate) enum PaintOrLine { + Paint(Paint), + Line(SwfLineStyle), +} + +pub(crate) struct StyleLayer { + fill: PaintOrLine, + // TODO(jon): Maybe shapes are actually slices into a single buffer, then we don't + // need to realloc anything, we're just shuffling shapes around? + shapes: Vec, +} + +impl StyleLayer { + pub(crate) fn kind(&self) -> &PaintOrLine { + &self.fill + } + + fn is_fill(&self) -> bool { + match &self.fill { + PaintOrLine::Paint(_) => true, + PaintOrLine::Line(_) => false, + } + } + + pub(crate) fn fill(&self) -> Paint { + match &self.fill { + PaintOrLine::Paint(paint) => *paint, + PaintOrLine::Line(line) => line.color, + } + } + + fn push_new_shape(&mut self, direction: LineDirection) { + if let Some(prev_shape) = self.shapes.last_mut() { + // Check that the previous shape was actually used, otherwise reuse it. + if prev_shape.len() != 0 { + self.shapes.push(Shape::new_with_direction(direction)) + } else { + prev_shape.direction = direction; + } + } else { + self.shapes.push(Shape::new_with_direction(direction)) + } + } + + pub(crate) fn shapes(&self) -> &Vec { + &self.shapes + } + + fn shapes_mut(&mut self) -> &mut Vec { + &mut self.shapes + } + + fn current_shape_mut(&mut self) -> &mut Shape { + self.shapes.last_mut().unwrap() + } + + fn consolidate_edges(&mut self) { + // Reverse left fill shape fragments in place. + { + self.shapes + .iter_mut() + .filter(|frag| frag.direction == LineDirection::Left) + .for_each(|frag| frag.reverse()); + } + + // Sort shapes into [closed...open] + if self.is_fill() { + // I think sorting is only necessary when we want to have closed shapes, + // lines don't really need this? + self.shapes.sort_unstable_by(|a, b| { + match (a.is_closed(), b.is_closed()) { + (true, true) | (false, false) => Ordering::Equal, + (true, false) => Ordering::Less, + (false, true) => Ordering::Greater, + } + }); + } + + // A cursor at the index of the first unclosed shape, if any. + let first_open_index = self.shapes + .iter() + .position(|frag| !frag.is_closed()); + + if let Some(first_open_index) = first_open_index { + if self.shapes.len() - first_open_index >= 2 { + // TODO(jon): This might be sped up by doing it in a way that we don't have + // to allocate more vecs? + // Also, maybe avoid path reversal, and just flag the path as reversed and iterate it + // backwards. + let unmatched_pieces = find_matches(first_open_index, &mut self.shapes, false); + if let Some(mut unmatched_pieces) = unmatched_pieces { + if self.is_fill() { + // If they didn't match before, they're probably parts of inner shapes + // and should be reversed again so they have correct winding + let unclosed = find_matches(0, &mut unmatched_pieces, true); + // If it's a shape we should always be able to close it. + debug_assert!(unclosed.is_none()); + } + for dropped in &mut unmatched_pieces { + dropped.reverse(); + } + self.shapes.extend_from_slice(&unmatched_pieces); + } + // FIXME(jon): Sometimes we don't get the correct winding of internal closed shapes, + // need to figure out why this happens. + } + } + } +} + + +fn get_new_styles<'a>( + fills: &'a Vec, + lines: &'a Vec +) -> impl Iterator + 'a { + // This enforces the order that fills and line groupings are added in. + // Fills always come first. + fills.iter().filter_map(|fill_style| { + match fill_style { + FillStyle::Solid( + fill_styles::Solid { + color: StraightSRgba8 { + r, + g, + b, + a + } + } + ) => { + Some(PaintOrLine::Paint(Paint { + color: ColorU { + r: *r, + g: *g, + b: *b, + a: *a + } + })) + }, + _ => unimplemented!("Unimplemented fill style") + } + }).chain( + lines.iter().filter_map(|LineStyle { + width, + fill, + join, + start_cap, + end_cap: _, + /* + TODO(jon): Handle these cases? + pub no_h_scale: bool, + pub no_v_scale: bool, + pub no_close: bool, + pub pixel_hinting: bool, + */ + .. + }| { + if let FillStyle::Solid(fill_styles::Solid { + color: StraightSRgba8 { + r, + g, + b, + a + } + }) = fill { + // NOTE: PathFinder doesn't support different cap styles for start and end of + // strokes, so lets assume that they're always the same for the inputs we care about. + // Alternately, we split a line in two with a diff cap style for each. + // assert_eq!(start_cap, end_cap); + Some(PaintOrLine::Line(SwfLineStyle { + width: Twips(*width as i32), + color: Paint { color: ColorU { r: *r, g: *g, b: *b, a: *a } }, + join: match join { + JoinStyle::Bevel => LineJoin::Bevel, + JoinStyle::Round => LineJoin::Round, + JoinStyle::Miter(join_styles::Miter { limit }) => { + LineJoin::Miter(*limit as f32) + }, + }, + cap: match start_cap { + CapStyle::None => LineCap::Butt, + CapStyle::Square => LineCap::Square, + CapStyle::Round => LineCap::Round, + }, + })) + } else { + unimplemented!("unimplemented line fill style"); + } + }) + ) +} + +pub(crate) fn decode_shape(shape: &DefineShape) -> GraphicLayers { + let DefineShape { + shape, + // id, + // has_fill_winding, NOTE(jon): Could be important for some inputs? + // has_non_scaling_strokes, + // has_scaling_strokes, + .. + } = shape; + let mut graphic = GraphicLayers::new(); + let mut current_line_style = None; + let mut current_left_fill = None; + let mut current_right_fill = None; + let mut prev_pos = None; + + let mut some_fill_set = false; + let mut both_fills_set; + let mut both_fills_same = false; + let mut both_fills_set_and_same = false; + + // Create style groups for initially specified fills and lines. + for fills_or_line in get_new_styles(&shape.initial_styles.fill, &shape.initial_styles.line) { + match fills_or_line { + PaintOrLine::Paint(fill) => graphic.begin_fill_style(fill), + PaintOrLine::Line(line) => graphic.begin_line_style(line), + } + } + + for record in &shape.records { + match record { + ShapeRecord::StyleChange( + shape_records::StyleChange { + move_to, + new_styles, + line_style, + left_fill, + right_fill, + } + ) => { + // Start a whole new style grouping. + if let Some(new_style) = new_styles { + // Consolidate current style grouping and begin a new one. + graphic.end_style_group(); + graphic.begin_style_group(); + for fills_or_line in get_new_styles(&new_style.fill, &new_style.line) { + match fills_or_line { + PaintOrLine::Paint(fill) => graphic.begin_fill_style(fill), + PaintOrLine::Line(line) => graphic.begin_line_style(line), + } + } + } + + // If there's a change in right fill + if let Some(fill_id) = right_fill { + if *fill_id == 0 { + current_right_fill = None; + } else { + current_right_fill = Some(*fill_id); + graphic + .with_fill_style_mut(*fill_id) + .unwrap() + .push_new_shape(LineDirection::Right); + } + } + // If there's a change in left fill + if let Some(fill_id) = left_fill { + if *fill_id == 0 { + current_left_fill = None; + } else { + current_left_fill = Some(*fill_id); + graphic + .with_fill_style_mut(*fill_id) + .unwrap() + .push_new_shape(LineDirection::Left); + } + } + + some_fill_set = current_left_fill.is_some() || current_right_fill.is_some(); + both_fills_set = current_left_fill.is_some() && current_right_fill.is_some(); + both_fills_same = current_left_fill == current_right_fill; + both_fills_set_and_same = both_fills_set && both_fills_same; + + // If there's a change in line style + if let Some(style_id) = line_style { + if *style_id == 0 { + current_line_style = None; + } else { + current_line_style = Some(*style_id); + graphic + .with_line_style_mut(*style_id) + .unwrap() + .push_new_shape(LineDirection::Right); + } + } + + // Move to, start new shape fragments with the current styles. + if let Some(Vector2D { x, y }) = move_to { + let to: Point2 = Point2 { x: Twips(*x), y: Twips(*y) }; + prev_pos = Some(to); + + // If we didn't start a new shape for the current fill due to a fill + // style change earlier, we definitely want to start a new shape now, + // since each move_to command indicates a new shape fragment. + if let Some(current_right_fill) = current_right_fill { + graphic + .with_fill_style_mut(current_right_fill) + .unwrap() + .push_new_shape(LineDirection::Right); + } + if let Some(current_left_fill) = current_left_fill { + graphic + .with_fill_style_mut(current_left_fill) + .unwrap() + .push_new_shape(LineDirection::Left); + } + if let Some(current_line_style) = current_line_style { + // TODO(jon): Does the direction of this line depend on the current + // fill directions? + graphic + .with_line_style_mut(current_line_style) + .unwrap() + .push_new_shape(LineDirection::Right); + } + } + }, + ShapeRecord::Edge( + shape_records::Edge { + delta, + control_delta, + } + ) => { + let from = prev_pos.unwrap(); + let to = Point2 { + x: from.x + Twips(delta.x), + y: from.y + Twips(delta.y) + }; + prev_pos = Some(to); + let new_segment = LineSegment { + from, + to, + ctrl: control_delta.map(|Vector2D { x, y }| { + Point2 { + x: from.x + Twips(x), + y: from.y + Twips(y), + } + }), + }; + if some_fill_set && !both_fills_same { + for fill_id in [ + current_right_fill, + current_left_fill + ].iter() { + if let Some(fill_id) = fill_id { + graphic + .with_fill_style_mut(*fill_id) + .unwrap() + .current_shape_mut() + .add_line_segment(new_segment); + } + } + } else if both_fills_set_and_same { + for (fill_id, direction) in [ + (current_right_fill, LineDirection::Right), + (current_left_fill, LineDirection::Left) + ].iter() { + // NOTE: If both left and right fill are set the same, + // then we don't record the edge as part of the current shape; + // it's will just be an internal stroke inside an otherwise solid + // shape, and recording these edges as part of the shape means that + // we can't determine the closed shape outline later. + if let Some(fill_id) = fill_id { + graphic + .with_fill_style_mut(*fill_id) + .unwrap() + .push_new_shape(*direction); + } + } + } + if let Some(current_line_style) = current_line_style { + graphic + .with_line_style_mut(current_line_style) + .unwrap() + .current_shape_mut() + .add_line_segment(new_segment); + } + } + } + } + // NOTE: Consolidate current group of styles, joining edges of shapes/strokes where + // possible and forming closed shapes. In swf, all filled shapes should always be closed, + // so there will always be a solution for joining shape line segments together so that + // the start point and end point are coincident. + graphic.end_style_group(); + graphic +} + +fn find_matches( + mut first_open_index: usize, + shapes: &mut Vec, + reverse: bool +) -> Option> { + let mut dropped_pieces = None; + while first_open_index < shapes.len() { + // Take the last unclosed value, and try to join it onto + // one of the other unclosed values. + let mut last = shapes.pop().unwrap(); + if reverse { + last.reverse(); + } + let mut found_match = false; + for i in first_open_index..shapes.len() { + let fragment = &mut shapes[i]; + if last.comes_after(fragment) { + // NOTE(jon): We do realloc quite a bit here, I wonder if it's worth trying + // to avoid that? Could do it with another level of indirection, where an outline + // is a list of fragments. + + // println!("app ({}, {})", last.reversed, fragment.reversed); + fragment.append_shape(&last); + found_match = true; + } else if last.comes_before(fragment) { + // println!("pre ({}, {})", last.reversed, fragment.reversed); + fragment.prepend_shape(&mut last); + found_match = true; + } + if found_match { + if fragment.is_closed() { + // Move the shape that was just closed to the left side of the current slice, + // and advance the cursor. + shapes.swap(first_open_index, i); + first_open_index += 1; + } + break; + } + } + if !found_match { + // Have we tried matching a reversed version of this segment? + // move last back onto the array, it will never be closed, presumably because + // it's a set of line segments rather than a shape that needs to be closed. + let dropped_pieces: &mut Vec = dropped_pieces.get_or_insert(Vec::new()); + dropped_pieces.push(last); + } + } + dropped_pieces +} + +pub(crate) struct GraphicLayers { + style_layers: Vec, + base_layer_offset: usize, + stroke_layer_offset: Option, +} + +impl GraphicLayers { + fn new() -> GraphicLayers { + GraphicLayers { style_layers: Vec::new(), stroke_layer_offset: None, base_layer_offset: 0 } + } + + fn begin_style_group(&mut self) { + self.stroke_layer_offset = None; + self.base_layer_offset = self.style_layers.len(); + } + + fn begin_fill_style(&mut self, fill: Paint) { + self.style_layers.push(StyleLayer { fill: PaintOrLine::Paint(fill), shapes: Vec::new() }) + } + + fn begin_line_style(&mut self, line: SwfLineStyle) { + if self.stroke_layer_offset.is_none() { + self.stroke_layer_offset = Some(self.style_layers.len()); + } + self.style_layers.push(StyleLayer { fill: PaintOrLine::Line(line), shapes: Vec::new() }) + } + + fn with_fill_style_mut(&mut self, fill_id: usize) -> Option<&mut StyleLayer> { + self.style_layers.get_mut(self.base_layer_offset + fill_id - 1) + } + + fn with_line_style_mut(&mut self, line_id: usize) -> Option<&mut StyleLayer> { + self.style_layers.get_mut((self.stroke_layer_offset.unwrap() + line_id) - 1) + } + + pub(crate) fn layers(&self) -> &Vec { + &self.style_layers + } + + fn end_style_group(&mut self) { + for style_layer in &mut self.style_layers[self.base_layer_offset..] { + // There can be an unused style group at the end of each layer, which we should remove. + if let Some(last) = style_layer.shapes().last() { + if last.len() == 0 { + style_layer.shapes_mut().pop(); + } + } + style_layer.consolidate_edges(); + } + } +} + diff --git a/swf/src/timeline.rs b/swf/src/timeline.rs new file mode 100644 index 00000000..e3f684b3 --- /dev/null +++ b/swf/src/timeline.rs @@ -0,0 +1,42 @@ +// pathfinder/swf/src/timeline.rs +// +// Copyright © 2019 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. + +struct PlacementInfo { + symbol_id: u32, + translate_x: Twips, + translate_y: Twips, +} + +struct Timeline(Vec); + +impl Timeline { + fn first(&self) -> &Frame { + &self.0[0] + } + + fn last(&self) -> &Frame { + &self.0[self.0.len() - 1] + } + + fn first_mut(&mut self) -> &mut Frame { + &mut self.0[0] + } + + fn last_mut(&mut self) -> &mut Frame { + let last = self.0.len() - 1; + &mut self.0[last] + } +} + +struct Frame { + duration_frames_initial: u16, + duration_remaining_frames: u16, + placements: Vec +} diff --git a/text/Cargo.toml b/text/Cargo.toml index 352e801f..493f98e3 100644 --- a/text/Cargo.toml +++ b/text/Cargo.toml @@ -6,9 +6,12 @@ edition = "2018" [dependencies] euclid = "0.19" -font-kit = "0.1" +font-kit = "0.2" lyon_path = "0.12" +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" @@ -17,4 +20,4 @@ path = "../renderer" [dependencies.skribo] git = "https://github.com/linebender/skribo.git" -rev = "a89e9ca99e0d6736ea1b7754517f4df14fd96a2b" +rev = "a2d683856ba1f2d0095b12dd7823d1602a87614e" diff --git a/text/src/lib.rs b/text/src/lib.rs index cbf56765..49dcd1ce 100644 --- a/text/src/lib.rs +++ b/text/src/lib.rs @@ -13,10 +13,10 @@ use font_kit::error::GlyphLoadingError; use font_kit::hinting::HintingOptions; use font_kit::loader::Loader; use lyon_path::builder::{FlatPathBuilder, PathBuilder}; -use pathfinder_geometry::basic::vector::Vector2F; -use pathfinder_geometry::basic::transform2d::Transform2DF; -use pathfinder_geometry::outline::{Contour, Outline}; -use pathfinder_geometry::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_content::outline::{Contour, Outline}; +use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; +use pathfinder_geometry::transform2d::Transform2DF; +use pathfinder_geometry::vector::Vector2F; use pathfinder_renderer::paint::PaintId; use pathfinder_renderer::scene::{PathObject, Scene}; use skribo::{FontCollection, Layout, TextStyle}; diff --git a/ui/Cargo.toml b/ui/Cargo.toml index 259f8c26..2cad25a6 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -13,6 +13,9 @@ serde_json = "1.0" version = "0.1" features = ["serde"] +[dependencies.pathfinder_content] +path = "../content" + [dependencies.pathfinder_geometry] path = "../geometry" diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 0955dbf7..7ae36ab3 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -17,12 +17,12 @@ extern crate serde_derive; use hashbrown::HashMap; -use pathfinder_geometry::basic::vector::{Vector2F, Vector2I}; -use pathfinder_geometry::basic::rect::RectI; -use pathfinder_geometry::color::ColorU; +use pathfinder_content::color::ColorU; +use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, Device, Primitive}; -use pathfinder_gpu::{RenderState, UniformData, VertexAttrClass}; +use pathfinder_gpu::{RenderOptions, RenderState, RenderTarget, UniformData, VertexAttrClass}; use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; use pathfinder_simd::default::F32x4; use serde_json; @@ -131,7 +131,11 @@ impl UIPresenter where D: Device { self.draw_rect(device, rect, color, false); } - fn draw_rect(&self, device: &D, rect: RectI, color: ColorU, filled: bool) { + fn draw_rect(&self, + device: &D, + rect: RectI, + color: ColorU, + filled: bool) { let vertex_data = [ DebugSolidVertex::new(rect.origin()), DebugSolidVertex::new(rect.upper_right()), @@ -160,8 +164,6 @@ impl UIPresenter where D: Device { index_data: &[u32], color: ColorU, filled: bool) { - device.bind_vertex_array(&self.solid_vertex_array.vertex_array); - device.allocate_buffer(&self.solid_vertex_array.vertex_buffer, BufferData::Memory(vertex_data), BufferTarget::Vertex, @@ -171,15 +173,23 @@ impl UIPresenter where D: Device { BufferTarget::Index, BufferUploadMode::Dynamic); - device.use_program(&self.solid_program.program); - device.set_uniform(&self.solid_program.framebuffer_size_uniform, - UniformData::Vec2(self.framebuffer_size.0.to_f32x4())); - set_color_uniform(device, &self.solid_program.color_uniform, color); - let primitive = if filled { Primitive::Triangles } else { Primitive::Lines }; - device.draw_elements(primitive, index_data.len() as u32, &RenderState { - blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, - ..RenderState::default() + device.draw_elements(index_data.len() as u32, &RenderState { + target: &RenderTarget::Default, + program: &self.solid_program.program, + vertex_array: &self.solid_vertex_array.vertex_array, + primitive, + uniforms: &[ + (&self.solid_program.framebuffer_size_uniform, + UniformData::Vec2(self.framebuffer_size.0.to_f32x4())), + (&self.solid_program.color_uniform, get_color_uniform(color)), + ], + textures: &[], + viewport: RectI::new(Vector2I::default(), self.framebuffer_size), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, + ..RenderOptions::default() + }, }); } @@ -396,19 +406,25 @@ impl UIPresenter where D: Device { BufferTarget::Index, BufferUploadMode::Dynamic); - device.bind_vertex_array(&self.texture_vertex_array.vertex_array); - device.use_program(&self.texture_program.program); - device.set_uniform(&self.texture_program.framebuffer_size_uniform, - UniformData::Vec2(self.framebuffer_size.0.to_f32x4())); - device.set_uniform(&self.texture_program.texture_size_uniform, - UniformData::Vec2(device.texture_size(&texture).0.to_f32x4())); - set_color_uniform(device, &self.texture_program.color_uniform, color); - device.bind_texture(texture, 0); - device.set_uniform(&self.texture_program.texture_uniform, UniformData::TextureUnit(0)); - - device.draw_elements(Primitive::Triangles, index_data.len() as u32, &RenderState { - blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, - ..RenderState::default() + device.draw_elements(index_data.len() as u32, &RenderState { + target: &RenderTarget::Default, + program: &self.texture_program.program, + vertex_array: &self.texture_vertex_array.vertex_array, + primitive: Primitive::Triangles, + textures: &[&texture], + uniforms: &[ + (&self.texture_program.framebuffer_size_uniform, + UniformData::Vec2(self.framebuffer_size.0.to_f32x4())), + (&self.texture_program.color_uniform, get_color_uniform(color)), + (&self.texture_program.texture_uniform, UniformData::TextureUnit(0)), + (&self.texture_program.texture_size_uniform, + UniformData::Vec2(device.texture_size(&texture).0.to_f32x4())) + ], + viewport: RectI::new(Vector2I::default(), self.framebuffer_size), + options: RenderOptions { + blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, + ..RenderOptions::default() + }, }); } @@ -508,9 +524,9 @@ impl UIPresenter where D: Device { let highlight_size = Vector2I::new(SEGMENT_SIZE, BUTTON_HEIGHT); let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1); self.draw_solid_rounded_rect(device, - RectI::new(origin + Vector2I::new(x_offset, 0), + RectI::new(origin + Vector2I::new(x_offset, 0), highlight_size), - TEXT_COLOR); + TEXT_COLOR); } let mut segment_origin = origin + Vector2I::new(SEGMENT_SIZE + 1, 0); @@ -520,9 +536,9 @@ impl UIPresenter where D: Device { Some(value) if value == prev_segment_index || value == next_segment_index => {} _ => { self.draw_line(device, - segment_origin, - segment_origin + Vector2I::new(0, BUTTON_HEIGHT), - TEXT_COLOR); + segment_origin, + segment_origin + Vector2I::new(0, BUTTON_HEIGHT), + TEXT_COLOR); } } segment_origin = segment_origin + Vector2I::new(SEGMENT_SIZE + 1, 0); @@ -585,28 +601,30 @@ impl DebugTextureVertexArray where D: Device { let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position"); - let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord"); + let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position") + .unwrap(); + let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord") + .unwrap(); - device.bind_vertex_array(&vertex_array); - device.use_program(&debug_texture_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.bind_buffer(&index_buffer, BufferTarget::Index); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_TEXTURE_VERTEX_SIZE, offset: 0, divisor: 0, + buffer_index: 0, }); - device.configure_vertex_attr(&tex_coord_attr, &VertexAttrDescriptor { + device.configure_vertex_attr(&vertex_array, &tex_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_TEXTURE_VERTEX_SIZE, offset: 4, divisor: 0, + buffer_index: 0, }); DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer } @@ -624,18 +642,18 @@ impl DebugSolidVertexArray where D: Device { let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); let vertex_array = device.create_vertex_array(); - let position_attr = device.get_vertex_attr(&debug_solid_program.program, "Position"); - device.bind_vertex_array(&vertex_array); - device.use_program(&debug_solid_program.program); - device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); - device.bind_buffer(&index_buffer, BufferTarget::Index); - device.configure_vertex_attr(&position_attr, &VertexAttrDescriptor { + let position_attr = + device.get_vertex_attr(&debug_solid_program.program, "Position").unwrap(); + device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); + device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); + device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::U16, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, stride: DEBUG_SOLID_VERTEX_SIZE, offset: 0, divisor: 0, + buffer_index: 0, }); DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer } @@ -711,9 +729,9 @@ impl CornerRects { } } -fn set_color_uniform(device: &D, uniform: &D::Uniform, color: ColorU) where D: Device { +fn get_color_uniform(color: ColorU) -> UniformData { let color = F32x4::new(color.r as f32, color.g as f32, color.b as f32, color.a as f32); - device.set_uniform(uniform, UniformData::Vec4(color * F32x4::splat(1.0 / 255.0))); + UniformData::Vec4(color * F32x4::splat(1.0 / 255.0)) } #[derive(Clone, Copy)] diff --git a/utils/svg-to-skia/Cargo.toml b/utils/svg-to-skia/Cargo.toml index a3a57cb4..1024e7c1 100644 --- a/utils/svg-to-skia/Cargo.toml +++ b/utils/svg-to-skia/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Patrick Walton "] edition = "2018" [dependencies] -usvg = "0.4" +usvg = "0.7"