diff --git a/.gitignore b/.gitignore index 849001b76c..ecdd3e5575 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ wrench/ron_frames # System .fuse_hidden* + +# mac +.DS_Store diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..dc65614187 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,56 @@ +dist: trusty +language: rust +rust: + - 1.35.0 + - nightly +matrix: + fast_finish: true + allow_failures: + - rust: nightly +os: + - linux + - osx + +branches: + only: + - master + +addons: + apt: + sources: + - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main' + keyurl: 'http://apt.llvm.org/llvm-snapshot.gpg.key' + - sourceline: 'ppa:jonathonf/python-2.7' + packages: + - libgl1-mesa-dev + - llvm-3.9-dev + - libedit-dev + - python +env: + - BUILD_KIND=DEBUG RUST_BACKTRACE=1 RUSTFLAGS='--deny warnings' + - BUILD_KIND=RELEASE RUST_BACKTRACE=1 RUSTFLAGS='--deny warnings' +before_install: + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export LLVM_CONFIG=/usr/lib/llvm-3.9/bin/llvm-config; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install zlib; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PKG_CONFIG_PATH="/usr/local/opt/zlib/lib/pkgconfig:$PKG_CONFIG_PATH"; fi + - pip install virtualenv + - virtualenv ../venv + - source ../venv/bin/activate + - python --version + - pip install mako voluptuous PyYAML servo-tidy +script: +# - servo-tidy + - if [ $BUILD_KIND = DEBUG ]; then (cd webrender_api && cargo test --verbose --features "ipc"); fi + - if [ $BUILD_KIND = DEBUG ]; then (cd webrender && cargo check --verbose --no-default-features); fi + - if [ $BUILD_KIND = DEBUG ]; then (cd webrender && cargo check --verbose --no-default-features --features capture); fi + - if [ $BUILD_KIND = DEBUG ]; then (cd webrender && cargo check --verbose --features profiler,capture); fi + - if [ $BUILD_KIND = DEBUG ]; then (cd webrender && cargo check --verbose --features replay); fi +# - if [ $BUILD_KIND = DEBUG ]; then (cd webrender && cargo check --verbose --no-default-features --features pathfinder); fi + - if [ $BUILD_KIND = DEBUG ]; then (cd webrender && cargo check --verbose --no-default-features --features serialize_program); fi + - if [ $BUILD_KIND = DEBUG ]; then (cd wrench && cargo check --verbose --features env_logger); fi + - if [ $BUILD_KIND = DEBUG ]; then (cd examples && cargo check --verbose); fi + - if [ $BUILD_KIND = DEBUG ]; then (cargo test --all --verbose); fi + - if [ $BUILD_KIND = RELEASE ]; then (cd wrench && python script/headless.py reftest); fi + - if [ $BUILD_KIND = RELEASE ]; then (cd wrench && cargo build --release); fi + - if [ $TRAVIS_RUST_VERSION == "nightly" ]; then (cd webrender && cargo bench --verbose); fi \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 32881eb678..9172d764f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,14 +1,29 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "adler32" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "aho-corasick" -version = "0.6.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "andrew" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rusttype 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -21,42 +36,103 @@ name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "app_units" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "argon2rs" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayvec" -version = "0.4.7" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ash" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "atom" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "atty" -version = "0.2.10" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.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 = "autocfg" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "base64" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -66,23 +142,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bincode" -version = "1.0.0" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bit-vec" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "block" version = "0.1.6" @@ -90,50 +176,69 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "block-buffer" -version = "0.7.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "block-padding" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bumpalo" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byte-tools" -version = "0.3.0" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byte-tools" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.7" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.7" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.15" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.3" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -141,20 +246,20 @@ name = "cgl" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clap" -version = "2.31.2" +version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -165,46 +270,77 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cmake" -version = "0.1.31" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cocoa" -version = "0.15.0" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", - "core-graphics 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.2.2 (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)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cocoa" +version = "0.19.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)", + "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)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "color_quant" -version = "1.0.0" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "colorful" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "constant_time_eq" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "copyless" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "core-foundation" -version = "0.6.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-foundation-sys" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -212,21 +348,21 @@ name = "core-graphics" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.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)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-graphics" -version = "0.17.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.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)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -234,21 +370,21 @@ name = "core-text" version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation 0.6.0 (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.14.0 (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.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-text" -version = "13.0.0" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.17.1 (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)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -258,14 +394,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam-channel" -version = "0.2.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -282,48 +415,58 @@ name = "crossbeam-epoch" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-epoch" -version = "0.5.2" +name = "crossbeam-utils" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-utils" -version = "0.2.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-utils" -version = "0.5.0" +name = "d3d12" +version = "0.1.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)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "deflate" -version = "0.7.18" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (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 = [ - "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (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)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -331,10 +474,18 @@ name = "derive_more" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (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)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "digest" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -349,12 +500,23 @@ dependencies = [ name = "direct-composition" version = "0.1.0" dependencies = [ - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-empty 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "webrender 0.59.0", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winit 0.16.2 (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 = "dirs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -367,12 +529,7 @@ dependencies = [ [[package]] name = "downcast-rs" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "dtoa" -version = "0.4.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -380,46 +537,77 @@ name = "dwrote" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (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.55 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "either" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "env_logger" -version = "0.5.10" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "euclid" -version = "0.19.4" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "euclid_macros" +version = "0.1.0" +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 = "expat-sys" -version = "2.1.5" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +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)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -437,10 +625,10 @@ name = "font-loader" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-text 10.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", "servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -461,19 +649,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "freetype" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", "servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -487,9 +680,14 @@ name = "fxhash" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "gdi32-sys" version = "0.2.0" @@ -499,6 +697,14 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "generic-array" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "generic-array" version = "0.12.0" @@ -507,12 +713,94 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gfx-backend-dx12" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "d3d12 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-window-handle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "spirv_cross 0.14.2 (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 = "gfx-backend-empty" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gfx-backend-metal" +version = "0.3.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)", + "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.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "copyless 0.1.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)", + "gfx-hal 0.3.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.16.0 (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.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-window-handle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "spirv_cross 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "storage-map 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gfx-backend-vulkan" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ash 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (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)", + "gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (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)", + "raw-window-handle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (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)", + "x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gfx-hal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gif" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -522,102 +810,157 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gl_generator" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gleam" -version = "0.6.8" +version = "0.6.17" +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 = "glsl-to-spirv" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "glutin" -version = "0.17.0" +version = "0.20.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.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.2.2 (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)", + "glutin_egl_sys 0.1.3 (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)", + "libc 0.2.55 (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)", - "shared_library 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-client 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", - "x11-dl 2.17.5 (registry+https://github.com/rust-lang/crates.io-index)", + "shared_library 0.1.9 (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_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.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hibitset" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "httparse" -version = "1.2.4" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "humantime" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "idna" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "image" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jpeg-decoder 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.39 (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.4 (registry+https://github.com/rust-lang/crates.io-index)", - "png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-transmute 0.10.1 (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)", "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tiff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inflate" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -625,39 +968,47 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ipc-channel" -version = "0.11.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (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.55 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itoa" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jpeg-decoder" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "js-sys" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -676,7 +1027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "khronos_api" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -686,17 +1037,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.0.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazycell" -version = "0.6.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.42" +version = "0.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -704,48 +1055,64 @@ name = "libloading" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "line_drawing" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "linked-hash-map" -version = "0.3.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lock_api" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lock_api" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.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 = "log" -version = "0.4.1" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lyon_geom" -version = "0.12.0" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "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.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -753,7 +1120,7 @@ name = "lyon_path" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lyon_geom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lyon_geom 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -766,7 +1133,7 @@ name = "malloc_buf" version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -774,31 +1141,28 @@ name = "malloc_size_of_derive" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "matches" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memchr" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "memmap" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -806,98 +1170,123 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "metal" +version = "0.16.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.19.0 (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)", + "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)", +] + [[package]] name = "mio" -version = "0.6.12" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio-extras" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miow" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "mozangle" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "net2" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nix" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nodrop" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num-derive" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.17 (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)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.38" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (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-iter" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -905,284 +1294,493 @@ name = "num-rational" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (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.4" +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" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "objc" -version = "0.2.2" +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_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 = "opaque-debug" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ordered-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "osmesa-src" version = "0.1.1" -source = "git+https://github.com/servo/osmesa-src#939207de2f4617cb958548490764f7380cf0c6e4" +source = "git+https://github.com/servo/osmesa-src#8e009dfa3b384f5b90dacdd235ae87744da9e08f" [[package]] name = "osmesa-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "shared_library 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "owning_ref" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pathfinder_font_renderer" +version = "0.5.0" +source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#3a33e5e70822fd8e38af735f4a96ce0ab153d663" +dependencies = [ + "app_units 0.7.1 (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)", + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pathfinder_gfx_utils" +version = "0.2.0" +source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#3a33e5e70822fd8e38af735f4a96ce0ab153d663" +dependencies = [ + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pathfinder_partitioner" +version = "0.2.0" +source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#3a33e5e70822fd8e38af735f4a96ce0ab153d663" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lyon_geom 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pathfinder_path_utils 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", +] + +[[package]] +name = "pathfinder_path_utils" +version = "0.2.0" +source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#3a33e5e70822fd8e38af735f4a96ce0ab153d663" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", +] + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pkg-config" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "plane-split" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.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 = "png" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)", + "inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.6.12" +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)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "owning_ref" -version = "0.3.3" +name = "rand" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.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 = "parking_lot" -version = "0.6.3" +name = "rand" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (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.55 (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)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.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 = "parking_lot_core" -version = "0.2.14" +name = "rand_chacha" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pathfinder_font_renderer" -version = "0.5.0" -source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#e8805413321edf85870deee5678751746ed61316" -dependencies = [ - "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", - "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", - "winapi 0.3.6 (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)", ] [[package]] -name = "pathfinder_gfx_utils" -version = "0.2.0" -source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#e8805413321edf85870deee5678751746ed61316" +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "pathfinder_partitioner" -version = "0.2.0" -source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#e8805413321edf85870deee5678751746ed61316" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", - "half 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lyon_geom 0.12.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_path_utils 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", -] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "pathfinder_path_utils" -version = "0.2.0" -source = "git+https://github.com/pcwalton/pathfinder?branch=webrender#e8805413321edf85870deee5678751746ed61316" +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "percent-encoding" -version = "1.0.1" +name = "rand_isaac" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "pkg-config" -version = "0.3.11" +name = "rand_jitter" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.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 = "plane-split" -version = "0.13.3" +name = "rand_os" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.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 = "png" -version = "0.14.0" +name = "rand_pcg" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", - "inflate 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.37 (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)", ] [[package]] -name = "proc-macro2" -version = "0.4.25" +name = "rand_xorshift" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "quick-error" -version = "1.2.1" +name = "range-alloc" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "quote" -version = "0.6.3" +name = "raw-window-handle" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand" -version = "0.3.22" +name = "rayon" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand" -version = "0.4.2" +name = "rayon-core" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.2.0 (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.55 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand" -version = "0.5.5" +name = "rdrand" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_core" -version = "0.2.1" +name = "redox_syscall" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rayon" -version = "1.0.1" +name = "redox_termios" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rayon-core" -version = "1.4.0" +name = "redox_users" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "redox_syscall" -version = "0.1.38" +name = "regex" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "redox_termios" -version = "0.1.1" +name = "regex-syntax" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "regex" -version = "1.0.0" +name = "relevant" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "regex-syntax" -version = "0.6.0" +name = "remove_dir_all" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ucd-util 0.1.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 = "remove_dir_all" -version = "0.5.1" +name = "rendy-descriptor" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "relevant 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rendy-memory" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "colorful 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hibitset 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "relevant 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1193,6 +1791,11 @@ dependencies = [ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-demangle" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -1202,9 +1805,28 @@ dependencies = [ ] [[package]] -name = "safe-transmute" -version = "0.10.1" +name = "rusttype" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "scoped_threadpool" @@ -1216,6 +1838,11 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "semver" version = "0.9.0" @@ -1239,7 +1866,7 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1250,18 +1877,18 @@ name = "serde_derive" version = "1.0.80" source = "git+https://github.com/servo/serde?branch=deserialize_from_enums9#e0cc925c259cb74ce41377e4fe02713adfa6d836" dependencies = [ - "proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.17 (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)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.17" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1270,17 +1897,17 @@ name = "servo-fontconfig" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-fontconfig-sys 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "servo-fontconfig-sys" -version = "4.0.4" +version = "4.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "expat-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1289,129 +1916,184 @@ name = "servo-freetype-sys" version = "4.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sha1" -version = "0.2.0" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "sha2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "sha2" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "shared_library" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (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.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "slab" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.3" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "smithay-client-toolkit" -version = "0.2.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-client 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-commons 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-protocols 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-commons 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-protocols 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spirv_cross" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spirv_cross" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "stable_deref_trait" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "stb_truetype" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "storage-map" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.15.17" +version = "0.15.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (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)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "synstructure" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.17 (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)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tempfile" -version = "3.0.2" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termcolor" -version = "0.3.6" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termion" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "textwrap" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1419,11 +2101,10 @@ dependencies = [ [[package]] name = "thread_local" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1432,29 +2113,29 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.5 (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 = "time" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1464,7 +2145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ucd-util" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1472,13 +2153,16 @@ name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-normalization" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "unicode-width" @@ -1491,20 +2175,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "unreachable" -version = "1.0.0" +name = "unicode-xid" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "url" -version = "1.7.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1519,16 +2200,15 @@ dependencies = [ [[package]] name = "utf8-ranges" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "uuid" -version = "0.6.5" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1541,133 +2221,209 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "walkdir" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.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 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "wayland-client" -version = "0.20.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-commons 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-scanner 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-sys 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-commons 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-scanner 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-sys 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-commons" -version = "0.20.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-sys 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-sys 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-protocols" -version = "0.20.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-client 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-commons 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-scanner 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-sys 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-commons 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-scanner 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-sys 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-scanner" -version = "0.20.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "xml-rs 0.7.0 (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)", + "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-sys" -version = "0.20.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webrender" version = "0.59.0" dependencies = [ - "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (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)", + "cfg-if 0.1.9 (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)", "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "glsl-to-spirv 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.21.1 (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.55 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_font_renderer 0.5.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)", "pathfinder_gfx_utils 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)", "pathfinder_partitioner 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)", "pathfinder_path_utils 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)", - "plane-split 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)", - "png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "plane-split 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)", + "png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "relevant 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rendy-descriptor 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rendy-memory 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", "thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_api 0.58.0", "webrender_build 0.0.1", "wr_malloc_size_of 0.0.1", - "ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webrender-examples" version = "0.1.0" dependencies = [ - "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-dx12 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-empty 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-metal 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-vulkan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "webrender 0.59.0", - "winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webrender_api" version = "0.58.0" dependencies = [ - "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (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)", + "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)", "derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "wr_malloc_size_of 0.0.1", ] @@ -1686,7 +2442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1703,6 +2459,14 @@ name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1710,89 +2474,100 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wincolor" -version = "0.1.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winit" -version = "0.16.2" +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)", - "cocoa 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.20 (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.55 (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.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-client 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "x11-dl 2.17.5 (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 = "wr_malloc_size_of" version = "0.0.1" dependencies = [ - "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", + "app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wrench" version = "0.3.0" dependencies = [ - "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (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)", "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", "font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-dx12 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-empty 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-metal 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-backend-vulkan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "glutin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "osmesa-src 0.1.1 (git+https://github.com/servo/osmesa-src)", "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "webrender 0.59.0", "webrender_api 0.58.0", - "winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ws" -version = "0.7.3" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1804,22 +2579,36 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "x11" +version = "2.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "x11-dl" -version = "2.17.5" +version = "2.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.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.55 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "xml-rs" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1834,212 +2623,293 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "yaml-rust" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] -"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" -"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" +"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" +"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" +"checksum andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dadc668390b373e73e4abbfc1f07238b09a25858f2f39c06cebc6d8e141d774" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" -"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2" +"checksum app_units 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc3ec9d4c47b25a5a9e5c848e053640331c7cedb1637434d75db68b79fee8a7f" +"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" +"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" +"checksum ash 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "003d1fb2eb12eb06d4a03dbe02eea67a9fac910fa97932ab9e3a75b96a1ea5e5" +"checksum atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum backtrace 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "45934a579eff9fd0ff637ac376a4bd134f47f8fc603f0b211d696b54d61e35f1" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff" -"checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0" -"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" -"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" +"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" +"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" +"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 block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" -"checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3" -"checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" -"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" -"checksum bytes 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1d50c876fb7545f5f289cd8b2aee3f359d073ae819eed5d6373638e2c61e59" -"checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba" -"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" +"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" +"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708" +"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "55e7ec0b74fe5897894cbc207092c577e87c52f8a59e8ca8d97ef37551f60a49" -"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "95470235c31c726d72bf2e1f421adc1e65b9d561bf5529612cbe1a72da1467b3" -"checksum cocoa 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b44bd25bd275e9d74a5dff8ca55f2fb66c9ad5e12170d58697701df21a56e0e" -"checksum color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d" -"checksum core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7caa6cb9e76ddddbea09a03266d6b3bc98cd41e9fb9b017c473e7cca593ec25" -"checksum core-foundation-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2a53cce0ddcf7e7e1f998738d757d5a3bf08bf799a180e50ebe50d298f52f5a" +"checksum cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "2ca4386c8954b76a8415b63959337d940d724b336cabd3afe189c2b51a7e1ff0" +"checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b" +"checksum cocoa 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8cd20045e880893b4a8286d5639e9ade85fb1f6a14c291f882cf8cf2149d37d9" +"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" +"checksum colorful 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0bca1619ff57dd7a56b58a8e25ef4199f123e78e503fe1653410350a1b98ae65" +"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" +"checksum copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127" +"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" +"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum core-graphics 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e54c4ab33705fa1fc8af375bb7929d68e1c1546c1ecef408966d8c3e49a1d84a" -"checksum core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10" +"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" "checksum core-text 10.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f59bff773954e5cd058a3f5983406b52bec7cc65202bef340ba64a0c40ac91" -"checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae" +"checksum core-text 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d95a72b5e50e549969dd88eff3047495fe5b8c6f028635442c2b708be707e669" "checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" -"checksum crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6c0a94250b0278d7fc5a894c3d276b11ea164edc8bf8feb10ca1ea517b44a649" +"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-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" -"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum d3d12 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4fda5547c55c93b070d59108464bbfd7d9da9563b2ce78fceefc6430e972a420" +"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 derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871" +"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "18df8ce4470c189d18aa926022da57544f31e154631eb4cfe796aea97051fe6c" -"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" +"checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f" "checksum dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c31c624339dab99c223a4b26c2e803b7c248adaca91549ce654c76f39a03f5c8" -"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" -"checksum euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dbbf962bb6f877239a34491f2e0a12c6b824f389bc789eb90f1d70d4780b0727" -"checksum expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c470ccb972f2088549b023db8029ed9da9426f5affbf9b62efff7009ab8ed5b1" +"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" +"checksum euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7a4719a544a67ed3fc33784c2bd2c6581663dfe83b719a6ae05c6dabc3b51c73" +"checksum euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15" +"checksum expat-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" +"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 fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd330f40acb3016432cbfa4c54b3d6e6e893a538df79d8df8fd8c26e21c36aaa" "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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b659e75b7a7338fe75afd7f909fc2b71937845cffb6ebe54ba2e50f13d8e903d" +"checksum freetype 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11926b2b410b469d0e9399eca4cbbe237a9ef02176c485803b29216307e8e028" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" -"checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c" -"checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604" +"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +"checksum gfx-backend-dx12 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e5c682db9424f06de94138d24204db00b874e900e331eea9426fa9eb866d63ab" +"checksum gfx-backend-empty 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "19ee69c0aaa5b96b0995914e7136676ba8a9b5bd8a87d8b21f26641e72aa309b" +"checksum gfx-backend-metal 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "979d807dcd10f193d874317eb4fdf9106ded161b08dd2ea4212bbae1294ff8cd" +"checksum gfx-backend-vulkan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5facf0b6e4306a6a93682077f85602c89b49aca8ecceb73b9558e7baa37f8c54" +"checksum gfx-hal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00a079b66250a6437c3822c8bfc25e5bed5ba0186d312e7df87bc503325ab33c" +"checksum gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4bca55ac1f213920ce3527ccd62386f1f15fa3f1714aeee1cf93f2c416903f" +"checksum gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39a23d5e872a275135d66895d954269cf5e8661d234eb1c2480f4ce0d586acbd" "checksum gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a" -"checksum gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4b47f5b15742aee359c7895ab98cf2cceecc89bb4feb6f4e42f802d7899877da" -"checksum glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a70c5fe78efbd5a3b243a804ea1032053c584510f8822819f94cfb29b2100317" -"checksum half 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d5c5f71a723d10dfc58927cbed37c3071a50afc7f073d86fd7d3e5727db890f" -"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" -"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" -"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" -"checksum image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "52fb0666a1273dac46f9725aa4859bcd5595fc3554cf3495051b4de8db745e7d" -"checksum inflate 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec18d981200fd14e65ee8e35fb60ed1ce55227a02407303f3a72517c6146dcc" +"checksum gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7f46fd8874e043ffac0d638ed1567a2584f7814f6d72b4db37ab1689004a26c4" +"checksum glsl-to-spirv 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "28caebc98746d507603a2d3df66dcbe04e41d4febad0320f3eec1ef72b6bbef1" +"checksum glutin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff663466cd51f6fda5976e8a6f02a9fd65b8dde0b9b11db8344585174d015b2c" +"checksum glutin_egl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "23f48987ab6cb2b61ad903b59e54a2fd0c380a7baff68cffd6826b69a73dd326" +"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 hibitset 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47e7292fd9f7fe89fa35c98048f2d0a69b79ed243604234d18f6f8a1aa6f408d" +"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" +"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"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 iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd75debad4ffd295c00c6e3634d254df30050b0837a85e5cd039ac424365f24a" -"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" -"checksum jpeg-decoder 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0dfe27a6c0dabd772d0f9b9f8701c4ca12c4d1eebcadf2be1f6f70396f6a1434" +"checksum ipc-channel 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f82db24b0c53ee2d54b420bb9258f2b787611fe3e7a28d514b5ea54fe65cd365" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" +"checksum js-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "1efc4f2a556c58e79c5500912e221dd826bec64ff4aabd8ce71ccef6da02d7d4" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554" -"checksum khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62237e6d326bd5871cd21469323bf096de81f1618cd82cbaf5d87825335aeb49" +"checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" -"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" +"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" -"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" -"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" +"checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" +"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" +"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum lyon_geom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "216bfb2b880554865fa9deaa14671ab9f1368b942e7007cc8c97c083ac8a7f45" +"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +"checksum lyon_geom 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0638070e85f0e8b5da3909d8c5c0a66785b18da96a1e8dc30acb0aea9770529a" "checksum lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843" "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 malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3" -"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" -"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" -"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" +"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.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 mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "75f72a93f046f1517e3cfddc0a096eb756a2ba727d36edc8227dee769a50a9b0" +"checksum metal 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2832bd32c9068fb916aea0086f7422b8c31fd604d83b4393062974f862480a8f" +"checksum mio 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "049ba5ca2b63e837adeee724aa9e36b408ed593529dcc802aa96ca14bd329bdf" +"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f0583e6792917f498bb3a7440f777a59353102063445ab7f5e9d1dc4ed593aa" -"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" -"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" -"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d" -"checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45" -"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" +"checksum mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "45a8a18a41cfab0fde25cc2f43ea89064d211a0fbb33225b8ff93ab20406e0e7" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"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 num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" -"checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "877f30f37acef6749b1841cceab289707f211aecfc756553cd63976190e6cc2e" -"checksum opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682" +"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_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc" +"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" "checksum osmesa-src 0.1.1 (git+https://github.com/servo/osmesa-src)" = "" "checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69376b761943787ebd5cc85a5bc95958651a22609c5c1c2b65de21786baec72b" -"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" +"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" +"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum pathfinder_font_renderer 0.5.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)" = "" "checksum pathfinder_gfx_utils 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)" = "" "checksum pathfinder_partitioner 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)" = "" "checksum pathfinder_path_utils 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" -"checksum plane-split 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9b1d9a84aa3bbc2dafd06856bdb1dc333eb1d442ad8987b9d596c7344b3ed969" -"checksum png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9" -"checksum proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "d3797b7142c9aa74954e351fc089bbee7958cebbff6bf2815e7ffff0b19f547d" -"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" -"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" -"checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" -"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" -"checksum redox_syscall 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "0a12d51a5b5fd700e6c757f15877685bfa04fd7eb60c108f01d045cafa0073c2" +"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" +"checksum plane-split 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)" = "91c621d83b9c5a85b7ca7ca2bec643136debb327ad29d0a08768db1325780365" +"checksum png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5927936723a9e8b715d37d7e4b390455087c4bdf25b9f702309460577b14f9" +"checksum raw-window-handle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "af3d3b2e1053b3ff2171efc29a8bff3439ce6b2ce6a0432695134bc1c7ff8e87" +"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 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 regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" -"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" +"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 relevant 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "245816a76742b391111580d7e4b68cda1095597fdd8b2a294e0779e85e6d17fa" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rendy-descriptor 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "263d22222b4cfe0394df001c06ff1fab363f8cb79b6ab9d8fa2d030fdcdf68b0" +"checksum rendy-memory 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "557ed61c95042de292b4347124e9e77ec76954618cb6eeb50cec1a98d3adf51f" "checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399" +"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 safe-transmute 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9604873ffe1980bc1f179103704a65c8aca141c248d9e52b7af95ff10578166e" +"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 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" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" -"checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3" +"checksum serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "defbb8a83d7f34cc8380751eeb892b825944222888aff18996ea7901f24aec88" "checksum serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)" = "" -"checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1" +"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9" -"checksum servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "38b494f03009ee81914b0e7d387ad7c145cafcd69747c2ec89b0e17bb94f303a" +"checksum servo-fontconfig-sys 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b46d201addcfbd25c1798ad1281d98c40743824e0b0f1e611bd3d5d0d31a7b8d" "checksum servo-freetype-sys 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4ccb6d0d32d277d3ef7dea86203d8210945eb7a45fba89dd445b3595dd0dfc" -"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" +"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum shared_library 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8254bf098ce4d8d7cc7cc6de438c5488adc5297e5b7ffef88816c0a91bd289c1" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" -"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8" -"checksum smithay-client-toolkit 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "428d6c019bb92753be9670367e3f483e4fcef396180a9b59e813b69b20014881" -"checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)" = "3391038ebc3e4ab24eb028cb0ef2f2dc4ba0cbf72ee895ed6a6fad730640b5bc" -"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" -"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b" -"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" -"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" +"checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +"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 spirv_cross 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b03b5986fa339f976b69dc363b4facb9df5683f40ec48c9716c38b42a4cb10cc" +"checksum spirv_cross 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd72403fee8f7ec2f4f453dfbaf39ccdd4c6d0157d67d6e65513cd26cc49289f" +"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 storage-map 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0a4829a5c591dc24a944a736d6b1e4053e51339a79fd5d4702c4c999a9c45e" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" +"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 thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5920e77802b177479ab5795767fa48e68f61b2f516c2ac0041e2978dd8efe483" -"checksum tiff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a2cc6c4fd13cb1cfd20abdb196e794ceccb29371855b7e7f575945f920a5b3c2" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +"checksum tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4834f28a0330cb9f3f2c87d2649dca723cb33802e2bdcf18da32759fbec7ce" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" +"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.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "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 url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" +"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" +"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wayland-client 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0f3ed65542a0be13ea0fdcc55c9a011fcc44c3882e6e1a9b4dfddb25182897dd" -"checksum wayland-commons 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac5c79f1d050f4047a82ddce77acda026c142c0023e7b7e20eea5ad76fb7dbf" -"checksum wayland-protocols 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)" = "be56e3d80559177a70bc78f9396fbe1705b7baed4951ae6e34d28bb59681b1a8" -"checksum wayland-scanner 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)" = "93cf4ef48caedf3fc1a9b2bf0df64e6d425bd628b85830a08432dd25b61de17c" -"checksum wayland-sys 0.20.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d2dbe7b51c16b8a8153806aaa21f346333074482bb57bc5cb059cc828f8c6842" +"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" +"checksum wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "dcddca308b16cd93c2b67b126c688e5467e4ef2e28200dc7dfe4ae284f2faefc" +"checksum wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "f805d9328b5fc7e5c6399960fd1889271b9b58ae17bdb2417472156cc9fafdd0" +"checksum wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff88201a482abfc63921621f6cb18eb1efd74f136b05e5841e7f8ca434539e9" +"checksum wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "6a433d89ecdb9f77d46fcf00c8cf9f3467b7de9954d8710c175f61e2e245bb0e" +"checksum wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "d41fc1bc3570cdf8d108c15e014045fd45a95bb5eb36605f96a90461fc34027d" +"checksum wayland-client 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e77d1e6887f07ea2e5d79a3d7d03a875e62d3746334a909b5035d779d849a523" +"checksum wayland-commons 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)" = "dff69a5399ca212efa4966f3ee2a3773f19960d0fa329b9aca046a8508a0e09f" +"checksum wayland-protocols 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ccddf6a4407d982898e0f0a1172217843f3d40fe4272f828060b56a2d40d81" +"checksum wayland-scanner 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)" = "63bc5efa7dcdb8f04d2e5d1571c0d0577fc47076d133d68e056bdb299f1b60e2" +"checksum wayland-sys 0.21.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e76af81a601b84d400744f85f083381daa77ac01f6c8711e57e662dc3a35d69d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" -"checksum winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec43db5991cc509f5b0c68cb0a0d3614f697c888999990a186a2e895c7f723c0" -"checksum ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89c48c53bf9dee34411a08993c10b879c36e105d609b46e25673befe3a5c1320" +"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" +"checksum winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d233301129ddd33260b47f76900b50e154b7254546e2edba0e5468a1a5fe4de3" +"checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum x11-dl 2.17.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3235540540fde1ae074c8df49054166c0e070407f1c6e1ee17b8c87c2c7bcc7d" +"checksum x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39697e3123f715483d311b5826e254b6f3cfebdd83cf7ef3358f579c3d68e235" +"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 yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" -"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" +"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" diff --git a/README.md b/README.md index 23cb9600eb..16eff1b0c1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,20 @@ +# U-Szeged version + +This version of WebRender is using next-gen backends (vulkan/dx12/metal) provided by the [gfx-hal](https://crates.io/crates/gfx-hal) API. + +The current state is **experimental**. +At the moment the **vulkan, dx12,** and **metal** backends are usable, but in performance they are behind the original (this year's goal is to change this). + +By default this WebRender builds with gfx-hal, but we kept the original OpenGL backend and you can enable it with the **gleam** feature in WebRender and with the **gl** feature in Wrench. + +To run **Wrench** reftests e.g. with vulkan backend, use the following comand: +``` +cd wrench +cargo run --features=vulkan reftest +``` + +It was tested on Linux (Ubuntu 18.04), Windows 10 and macOS (Mojave). + # WebRender GPU renderer for the Web content, used by Servo. diff --git a/appveyor.yml b/appveyor.yml index 18e2248960..1a5c649183 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,8 +8,8 @@ environment: TARGET: x86_64-pc-windows-msvc install: - - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.30.0-${env:TARGET}.msi" - - msiexec /passive /i "rust-1.30.0-%TARGET%.msi" ADDLOCAL=Rustc,Cargo,Std INSTALLDIR=C:\Rust + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.35.0-${env:TARGET}.msi" + - msiexec /passive /i "rust-1.35.0-%TARGET%.msi" ADDLOCAL=Rustc,Cargo,Std INSTALLDIR=C:\Rust - rustc -V - cargo -V diff --git a/ci-scripts/windows-tests.cmd b/ci-scripts/windows-tests.cmd index c3607a9028..eaad016cbe 100755 --- a/ci-scripts/windows-tests.cmd +++ b/ci-scripts/windows-tests.cmd @@ -15,18 +15,19 @@ popd pushd webrender cargo test %CARGOFLAGS% +cargo test --verbose --features gleam if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% popd pushd wrench -cargo test --verbose +cargo test --verbose --features gl if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% -cargo run --release -- --angle reftest +cargo run --features gl --release -- --angle reftest if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% popd pushd examples -cargo check --verbose +cargo check --verbose --features gl if %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL% popd diff --git a/direct-composition/Cargo.toml b/direct-composition/Cargo.toml index 27b36354ab..e67433cc87 100644 --- a/direct-composition/Cargo.toml +++ b/direct-composition/Cargo.toml @@ -6,8 +6,9 @@ license = "MPL-2.0" [target.'cfg(windows)'.dependencies] euclid = "0.19" +gfx-backend-empty = "0.3.0" gleam = "0.6.2" mozangle = {version = "0.1", features = ["egl"]} -webrender = {path = "../webrender"} +webrender = {path = "../webrender", features = ["gleam"]} winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} -winit = "0.16" +winit = "0.19" diff --git a/direct-composition/src/main_windows.rs b/direct-composition/src/main_windows.rs index d4255c0c03..0d1bd8dbe2 100644 --- a/direct-composition/src/main_windows.rs +++ b/direct-composition/src/main_windows.rs @@ -4,11 +4,13 @@ extern crate direct_composition; extern crate euclid; +extern crate gfx_backend_empty as back; extern crate gleam; extern crate webrender; extern crate winit; use direct_composition::DirectComposition; +use std::marker::PhantomData; use std::sync::mpsc; use webrender::api; use winit::os::windows::{WindowExt, WindowBuilderExt}; @@ -92,7 +94,7 @@ fn direct_composition_from_window(window: &winit::Window) -> DirectComposition { struct Rectangle { visual: direct_composition::AngleVisual, - renderer: Option, + renderer: Option>, api: api::RenderApi, document_id: api::DocumentId, size: api::DeviceIntSize, @@ -107,7 +109,10 @@ impl Rectangle { visual.make_current(); let (renderer, sender) = webrender::Renderer::new( - composition.gleam.clone(), + webrender::DeviceInit { + gl: composition.gleam.clone(), + phantom_data: PhantomData, + }, notifier.clone(), webrender::RendererOptions { clear_color: Some(api::ColorF::new(0., 0., 0., 0.)), diff --git a/examples/Cargo.toml b/examples/Cargo.toml index ea7155dcfd..dcac282efd 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -28,6 +28,7 @@ path = "document.rs" [[bin]] name = "frame_output" path = "frame_output.rs" +required-features = ["gl"] [[bin]] name = "iframe" @@ -52,16 +53,41 @@ path = "texture_cache_stress.rs" [[bin]] name = "yuv" path = "yuv.rs" +required-features = ["gl"] [features] +default = [] debug = ["webrender/capture", "webrender/debugger", "webrender/profiler"] +gfx-hal = ["dirs"] +gl = ["gleam", "glutin", "webrender/gleam"] +dx12 = ["gfx-backend-dx12", "gfx-hal"] +metal = ["gfx-backend-metal", "gfx-hal"] +vulkan = ["gfx-backend-vulkan", "gfx-hal"] [dependencies] app_units = "0.7" +dirs = { version = "1.0", optional = true } env_logger = "0.5" euclid = "0.19" -gleam = "0.6.2" -glutin = "0.17" +gfx-backend-empty = "0.3.0" +gleam = { version = "0.6.2", optional = true} +glutin = { version = "0.20", optional = true } rayon = "1" +ron = "0.1.7" webrender = { path = "../webrender" } -winit = "0.16" +winit = "0.19" + +[target.'cfg(windows)'.dependencies.gfx-backend-dx12] +version = "0.3.2" +optional = true +features = ["winit"] + +[target.'cfg(target_os = "macos")'.dependencies.gfx-backend-metal] +version = "0.3.3" +optional = true +features = ["winit"] + +[target.'cfg(not(target_os = "macos"))'.dependencies.gfx-backend-vulkan] +version = "0.3.3" +optional = true +features = ["winit", "x11"] diff --git a/examples/alpha_perf.rs b/examples/alpha_perf.rs index 031767866b..5efb50ab04 100644 --- a/examples/alpha_perf.rs +++ b/examples/alpha_perf.rs @@ -3,7 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate euclid; +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; diff --git a/examples/animation.rs b/examples/animation.rs index a1c511e3d7..e3a4b048ca 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -11,7 +11,9 @@ //! scene building for render optimization. extern crate euclid; +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; diff --git a/examples/basic.rs b/examples/basic.rs index 64cfc9f975..ec2a46f595 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -4,7 +4,9 @@ extern crate app_units; extern crate euclid; +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; diff --git a/examples/blob.rs b/examples/blob.rs index 3d67cec518..d20f10d3f9 100644 --- a/examples/blob.rs +++ b/examples/blob.rs @@ -2,7 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate rayon; extern crate webrender; @@ -153,14 +155,14 @@ impl api::BlobImageHandler for CheckerboardRenderer { fn prepare_resources( &mut self, - _services: &api::BlobImageResources, + _services: &dyn api::BlobImageResources, _requests: &[api::BlobImageParams], ) {} fn delete_font(&mut self, _font: api::FontKey) {} fn delete_font_instance(&mut self, _instance: api::FontInstanceKey) {} fn clear_namespace(&mut self, _namespace: api::IdNamespace) {} - fn create_blob_rasterizer(&mut self) -> Box { + fn create_blob_rasterizer(&mut self) -> Box { Box::new(Rasterizer { workers: Arc::clone(&self.workers), image_cmds: self.image_cmds.clone(), diff --git a/examples/common/boilerplate.rs b/examples/common/boilerplate.rs index 17ec31f9fc..87841490ec 100644 --- a/examples/common/boilerplate.rs +++ b/examples/common/boilerplate.rs @@ -2,18 +2,39 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![cfg_attr( +not(any(feature = "gfx-hal", feature = "gl")), +allow(dead_code, unused_imports) +)] + +#[cfg(feature = "gfx-hal")] +extern crate dirs; extern crate env_logger; extern crate euclid; - +#[cfg(feature = "dx12")] +extern crate gfx_backend_dx12 as back; +#[cfg(feature = "metal")] +extern crate gfx_backend_metal as back; +#[cfg(feature = "vulkan")] +extern crate gfx_backend_vulkan as back; +#[cfg(feature = "gl")] +extern crate gfx_backend_empty as back; + +#[cfg(feature = "gl")] use gleam::gl; -use glutin::{self, GlContext}; +#[cfg(feature = "gl")] +use glutin::{self, ContextTrait}; use std::env; +#[cfg(feature = "gl")] +use std::marker::PhantomData; use std::path::PathBuf; use webrender; use winit; use webrender::DebugFlags; use webrender::ShaderPrecacheFlags; use webrender::api::*; +#[cfg(feature = "gfx-hal")] +use webrender::hal::Instance; struct Notifier { events_proxy: winit::EventsLoopProxy, @@ -26,7 +47,7 @@ impl Notifier { } impl RenderNotifier for Notifier { - fn clone(&self) -> Box { + fn clone(&self) -> Box { Box::new(Notifier { events_proxy: self.events_proxy.clone(), }) @@ -91,6 +112,8 @@ pub trait Example { ) -> bool { false } + + #[cfg(feature = "gl")] fn get_image_handlers( &mut self, _gl: &gl::Gl, @@ -98,10 +121,13 @@ pub trait Example { Option>) { (None, None) } + + #[cfg(feature = "gl")] fn draw_custom(&mut self, _gl: &gl::Gl) { } } +#[cfg(any(feature = "gfx-hal", feature = "gl"))] pub fn main_wrapper( example: &mut E, options: Option, @@ -116,39 +142,95 @@ pub fn main_wrapper( }; let mut events_loop = winit::EventsLoop::new(); - let context_builder = glutin::ContextBuilder::new() - .with_gl(glutin::GlRequest::GlThenGles { - opengl_version: (3, 2), - opengles_version: (3, 0), - }); + let window_builder = winit::WindowBuilder::new() .with_title(E::TITLE) .with_multitouch() .with_dimensions(winit::dpi::LogicalSize::new(E::WIDTH as f64, E::HEIGHT as f64)); - let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop) + + #[cfg(feature = "gl")] + let (gl, init, window) = { + let context_builder = glutin::ContextBuilder::new() + .with_gl(glutin::GlRequest::GlThenGles { + opengl_version: (3, 2), + opengles_version: (3, 0), + }); + let window = glutin::WindowedContext::new_windowed(window_builder, context_builder, &events_loop) .unwrap(); - unsafe { - window.make_current().ok(); - } + unsafe { + window.make_current().ok(); + } + + let gl = match window.get_api() { + glutin::Api::OpenGl => unsafe { + gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) + }, + glutin::Api::OpenGlEs => unsafe { + gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) + }, + glutin::Api::WebGl => unimplemented!(), + }; - let gl = match window.get_api() { - glutin::Api::OpenGl => unsafe { - gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) - }, - glutin::Api::OpenGlEs => unsafe { - gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) - }, - glutin::Api::WebGl => unimplemented!(), + println!("OpenGL version {}", gl.get_string(gl::VERSION)); + let init: webrender::DeviceInit = webrender::DeviceInit { + gl: gl.clone(), + phantom_data: PhantomData, + }; + (gl, init, window) + }; + + #[cfg(feature = "gfx-hal")] + let (window, init) = { + let window = window_builder.build(&events_loop).unwrap(); + let instance = back::Instance::create("gfx-rs instance", 1); + let mut adapters = instance.enumerate_adapters(); + let adapter = adapters.remove(0); + let surface = Some(instance.create_surface(&window)); + let winit::dpi::LogicalSize { width, height } = window.get_inner_size().unwrap(); + let init = { + let cache_dir = dirs::cache_dir().expect("User's cache directory not found"); + let cache_path = Some(PathBuf::from(&cache_dir).join("pipeline_cache.bin")); + + #[cfg(feature = "vulkan")] + let backend_api = webrender::BackendApiType::Vulkan; + #[cfg(feature = "metal")] + let backend_api = webrender::BackendApiType::Metal; + #[cfg(feature = "dx12")] + let backend_api = webrender::BackendApiType::Dx12; + + webrender::DeviceInit { + instance: Box::new(instance), + adapter, + surface, + window_size: (width as i32, height as i32), + descriptor_count: None, + cache_path, + save_cache: true, + backend_api, + } + }; + (window, init) }; - println!("OpenGL version {}", gl.get_string(gl::VERSION)); println!("Shader resource path: {:?}", res_path); let device_pixel_ratio = window.get_hidpi_factor() as f32; println!("Device pixel ratio: {}", device_pixel_ratio); println!("Loading shaders..."); let mut debug_flags = DebugFlags::ECHO_DRIVER_MESSAGES | DebugFlags::TEXTURE_CACHE_DBG; + + #[cfg(feature = "gfx-hal")] + let heaps_config = { + let config_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .join("webrender/res/mem_config.ron"); + let source = std::fs::read_to_string(&config_path) + .expect(&format!("Unable to open memory config file from {:?}", config_path)); + ron::de::from_str(&source).expect("Unable to parse HeapsConfig") + }; + let opts = webrender::RendererOptions { resource_override_path: res_path, precache_flags: E::PRECACHE_SHADER_FLAGS, @@ -156,10 +238,12 @@ pub fn main_wrapper( clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)), //scatter_gpu_cache_updates: false, debug_flags, + #[cfg(feature = "gfx-hal")] + heaps_config, ..options.unwrap_or(webrender::RendererOptions::default()) }; - let framebuffer_size = { + let mut framebuffer_size = { let size = window .get_inner_size() .unwrap() @@ -167,12 +251,16 @@ pub fn main_wrapper( DeviceIntSize::new(size.width as i32, size.height as i32) }; let notifier = Box::new(Notifier::new(events_loop.create_proxy())); - let (mut renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None).unwrap(); + let (mut renderer, sender) = webrender::Renderer::new(init, notifier, opts, None).unwrap(); let api = sender.create_api(); let document_id = api.add_document(framebuffer_size, 0); + #[cfg(feature = "gl")] let (external, output) = example.get_image_handlers(&*gl); + #[cfg(feature = "gfx-hal")] + let (external, output) = (None, None); + if let Some(output_image_handler) = output { renderer.set_output_image_handler(output_image_handler); } @@ -183,7 +271,7 @@ pub fn main_wrapper( let epoch = Epoch(0); let pipeline_id = PipelineId(0, 0); - let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); + let mut layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); let mut builder = DisplayListBuilder::new(pipeline_id, layout_size); let mut txn = Transaction::new(); @@ -271,6 +359,26 @@ pub fn main_wrapper( ) }, }, + winit::Event::WindowEvent { + event: winit::WindowEvent::Resized(dims), + .. + } => { + let new_size = ((dims.width as f32 * device_pixel_ratio) as i32, (dims.height as f32 * device_pixel_ratio) as i32); + // Workaround for Rust issue #15701 (E0658). + #[cfg(not(feature = "gleam"))] + { framebuffer_size = renderer.resize(Some(new_size)); } + #[cfg(feature = "gleam")] + { framebuffer_size = DeviceIntSize::new(new_size.0,new_size.1); } + + layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); + api.set_window_parameters( + document_id, + framebuffer_size, + DeviceIntRect::new(DeviceIntPoint::zero(), framebuffer_size), + device_pixel_ratio, + ); + return winit::ControlFlow::Continue; + }, winit::Event::WindowEvent { event, .. } => custom_event = example.on_event( event, &api, @@ -308,11 +416,22 @@ pub fn main_wrapper( renderer.update(); renderer.render(framebuffer_size).unwrap(); let _ = renderer.flush_pipeline_info(); + #[cfg(feature = "gl")] example.draw_custom(&*gl); + #[cfg(feature = "gl")] window.swap_buffers().ok(); winit::ControlFlow::Continue }); + api.shut_down(); renderer.deinit(); } + +#[cfg(not(any(feature = "gfx-hal", feature = "gl")))] +pub fn main_wrapper( + _example: &mut E, + _options: Option, +) { + println!("You need to enable one of the native API features (dx12/gl/metal/vulkan) in order to run this example."); +} diff --git a/examples/document.rs b/examples/document.rs index aeb6b2e328..d609e2645a 100644 --- a/examples/document.rs +++ b/examples/document.rs @@ -3,7 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate euclid; +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; diff --git a/examples/frame_output.rs b/examples/frame_output.rs index cd48eb6922..c182f44acf 100644 --- a/examples/frame_output.rs +++ b/examples/frame_output.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate euclid; +#[cfg(feature = "gl")] extern crate gleam; extern crate glutin; extern crate webrender; diff --git a/examples/iframe.rs b/examples/iframe.rs index 3bb3292829..0095b30971 100644 --- a/examples/iframe.rs +++ b/examples/iframe.rs @@ -2,7 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; diff --git a/examples/image_resize.rs b/examples/image_resize.rs index c31d9e33b6..0cab8fa728 100644 --- a/examples/image_resize.rs +++ b/examples/image_resize.rs @@ -2,7 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 5d35db79e4..7428267e7a 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -2,19 +2,43 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![cfg_attr( + not(any(feature = "gfx-hal", feature = "gl")), + allow(dead_code, unused_imports) +)] + extern crate app_units; +#[cfg(feature = "gfx-hal")] +extern crate dirs; extern crate euclid; +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; +#[cfg(feature = "dx12")] +extern crate gfx_backend_dx12 as back; +#[cfg(feature = "metal")] +extern crate gfx_backend_metal as back; +#[cfg(feature = "vulkan")] +extern crate gfx_backend_vulkan as back; +#[cfg(not(feature = "gfx-hal"))] +extern crate gfx_backend_empty as back; + use app_units::Au; +#[cfg(feature = "gl")] use gleam::gl; -use glutin::GlContext; +#[cfg(feature = "gl")] +use glutin::ContextTrait; use std::fs::File; use std::io::Read; +#[cfg(feature = "gl")] +use std::marker::PhantomData; use webrender::api::*; +#[cfg(feature = "gfx-hal")] +use webrender::hal::Instance; use webrender::DebugFlags; use winit::dpi::LogicalSize; @@ -29,7 +53,7 @@ impl Notifier { } impl RenderNotifier for Notifier { - fn clone(&self) -> Box { + fn clone(&self) -> Box { Box::new(Notifier { events_proxy: self.events_proxy.clone(), }) @@ -51,8 +75,11 @@ impl RenderNotifier for Notifier { struct Window { events_loop: winit::EventsLoop, //TODO: share events loop? - window: glutin::GlWindow, - renderer: webrender::Renderer, + #[cfg(feature = "gl")] + window: glutin::WindowedContext, + #[cfg(feature = "gfx-hal")] + window: winit::Window, + renderer: webrender::Renderer, name: &'static str, pipeline_id: PipelineId, document_id: DocumentId, @@ -61,43 +88,58 @@ struct Window { font_instance_key: FontInstanceKey, } +#[cfg(any(feature = "gfx-hal", feature = "gl"))] impl Window { fn new(name: &'static str, clear_color: ColorF) -> Self { let events_loop = winit::EventsLoop::new(); - let context_builder = glutin::ContextBuilder::new() - .with_gl(glutin::GlRequest::GlThenGles { - opengl_version: (3, 2), - opengles_version: (3, 0), - }); let window_builder = winit::WindowBuilder::new() .with_title(name) .with_multitouch() .with_dimensions(LogicalSize::new(800., 600.)); - let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop) - .unwrap(); - unsafe { - window.make_current().ok(); - } + #[cfg(feature = "gl")] + let (init, window) = { + let context_builder = glutin::ContextBuilder::new() + .with_gl(glutin::GlRequest::GlThenGles { + opengl_version: (3, 2), + opengles_version: (3, 0), + }); + let window = glutin::WindowedContext::new_windowed(window_builder, context_builder, &events_loop) + .unwrap(); + + unsafe { + window.make_current().ok(); + } - let gl = match window.get_api() { - glutin::Api::OpenGl => unsafe { - gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) - }, - glutin::Api::OpenGlEs => unsafe { - gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) - }, - glutin::Api::WebGl => unimplemented!(), + let gl = match window.get_api() { + glutin::Api::OpenGl => unsafe { + gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) + }, + glutin::Api::OpenGlEs => unsafe { + gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) + }, + glutin::Api::WebGl => unimplemented!(), + }; + + let init = webrender::DeviceInit { + gl, + phantom_data: PhantomData, + }; + (init, window) }; - let device_pixel_ratio = window.get_hidpi_factor() as f32; - - let opts = webrender::RendererOptions { - device_pixel_ratio, - clear_color: Some(clear_color), - ..webrender::RendererOptions::default() + #[cfg(feature = "gfx-hal")] + let (window, instance, adapter, surface) = { + let window = window_builder.build(&events_loop).unwrap(); + let instance = back::Instance::create("gfx-rs instance", 1); + let mut adapters = instance.enumerate_adapters(); + let adapter = adapters.remove(0); + let surface = instance.create_surface(&window); + (window, instance, adapter, Some(surface)) }; + let device_pixel_ratio = window.get_hidpi_factor() as f32; + let framebuffer_size = { let size = window .get_inner_size() @@ -106,7 +148,41 @@ impl Window { DeviceIntSize::new(size.width as i32, size.height as i32) }; let notifier = Box::new(Notifier::new(events_loop.create_proxy())); - let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None).unwrap(); + let (renderer, sender) = { + #[cfg(feature = "gfx-hal")] + let winit::dpi::LogicalSize { width, height } = window.get_inner_size().unwrap(); + + #[cfg(feature = "gfx-hal")] + let init = { + use std::path::PathBuf; + let cache_dir = dirs::cache_dir().expect("User's cache directory not found"); + let cache_path = Some(PathBuf::from(&cache_dir).join("pipeline_cache.bin")); + + #[cfg(feature = "vulkan")] + let backend_api = webrender::BackendApiType::Vulkan; + #[cfg(feature = "metal")] + let backend_api = webrender::BackendApiType::Metal; + #[cfg(feature = "dx12")] + let backend_api = webrender::BackendApiType::Dx12; + + webrender::DeviceInit { + instance: Box::new(instance), + adapter, + surface, + window_size: (width as i32, height as i32), + descriptor_count: None, + cache_path, + save_cache: true, + backend_api, + } + }; + let opts = webrender::RendererOptions { + device_pixel_ratio, + clear_color: Some(clear_color), + ..webrender::RendererOptions::default() + }; + webrender::Renderer::new(init, notifier, opts, None).unwrap() + }; let api = sender.create_api(); let document_id = api.add_document(framebuffer_size, 0); @@ -137,6 +213,7 @@ impl Window { } fn tick(&mut self) -> bool { + #[cfg(not(feature = "gfx-hal"))] unsafe { self.window.make_current().ok(); } @@ -144,6 +221,18 @@ impl Window { let my_name = &self.name; let renderer = &mut self.renderer; let api = &mut self.api; + let document_id = self.document_id; + let window = &self.window; + + let device_pixel_ratio = self.window.get_hidpi_factor() as f32; + let mut framebuffer_size = { + let size = window + .get_inner_size() + .unwrap() + .to_physical(device_pixel_ratio as f64); + DeviceIntSize::new(size.width as i32, size.height as i32) + }; + let mut layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); self.events_loop.poll_events(|global_event| match global_event { winit::Event::WindowEvent { event, .. } => match event { @@ -168,6 +257,22 @@ impl Window { println!("set flags {}", my_name); api.send_debug_cmd(DebugCommand::SetFlags(DebugFlags::PROFILER_DBG)) } + winit::WindowEvent::Resized(dims) => { + let new_size = ((dims.width as f32 * device_pixel_ratio) as i32, (dims.height as f32 * device_pixel_ratio) as i32); + // Workaround for Rust issue #15701 (E0658). + #[cfg(not(feature = "gleam"))] + { framebuffer_size = renderer.resize(Some(new_size)); } + #[cfg(feature = "gleam")] + { framebuffer_size = DeviceIntSize::new(new_size.0, new_size.1); } + + layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); + api.set_window_parameters( + document_id, + framebuffer_size, + DeviceIntRect::new(DeviceIntPoint::zero(), framebuffer_size), + device_pixel_ratio, + ); + } _ => {} } _ => {} @@ -176,15 +281,6 @@ impl Window { return true } - let device_pixel_ratio = self.window.get_hidpi_factor() as f32; - let framebuffer_size = { - let size = self.window - .get_inner_size() - .unwrap() - .to_physical(device_pixel_ratio as f64); - DeviceIntSize::new(size.width as i32, size.height as i32) - }; - let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); let mut txn = Transaction::new(); let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size); let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id); @@ -282,6 +378,7 @@ impl Window { renderer.update(); renderer.render(framebuffer_size).unwrap(); + #[cfg(feature = "gl")] self.window.swap_buffers().ok(); false @@ -292,6 +389,7 @@ impl Window { } } +#[cfg(any(feature = "gfx-hal", feature = "gl"))] fn main() { let mut win1 = Window::new("window1", ColorF::new(0.3, 0.0, 0.0, 1.0)); let mut win2 = Window::new("window2", ColorF::new(0.0, 0.3, 0.0, 1.0)); @@ -309,6 +407,11 @@ fn main() { win2.deinit(); } +#[cfg(not(any(feature = "gfx-hal", feature = "gl")))] +fn main() { + println!("You need to enable one of the native API features (dx12/gl/metal/vulkan) in order to run this example."); +} + fn load_file(name: &str) -> Vec { let mut file = File::open(name).unwrap(); let mut buffer = vec![]; diff --git a/examples/scrolling.rs b/examples/scrolling.rs index 2a273f0468..e5cbdfb88c 100644 --- a/examples/scrolling.rs +++ b/examples/scrolling.rs @@ -3,7 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate euclid; +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; diff --git a/examples/texture_cache_stress.rs b/examples/texture_cache_stress.rs index a66d252453..bd33c79e81 100644 --- a/examples/texture_cache_stress.rs +++ b/examples/texture_cache_stress.rs @@ -2,7 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; @@ -11,6 +13,7 @@ extern crate winit; mod boilerplate; use boilerplate::{Example, HandyDandyRectBuilder}; +#[cfg(feature = "gl")] use gleam::gl; use std::mem; use webrender::api::*; @@ -300,6 +303,7 @@ impl Example for App { false } + #[cfg(feature = "gl")] fn get_image_handlers( &mut self, _gl: &gl::Gl, diff --git a/examples/yuv.rs b/examples/yuv.rs index 3ed024ff12..32311dfdfd 100644 --- a/examples/yuv.rs +++ b/examples/yuv.rs @@ -2,7 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[cfg(feature = "gl")] extern crate gleam; +#[cfg(feature = "gl")] extern crate glutin; extern crate webrender; extern crate winit; diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml index 7d927b11f1..af210be985 100644 --- a/webrender/Cargo.toml +++ b/webrender/Cargo.toml @@ -11,25 +11,32 @@ build = "build.rs" default = ["freetype-lib"] freetype-lib = ["freetype/servo-freetype-sys"] profiler = ["thread_profiler/thread_profiler"] -debugger = ["ws", "serde_json", "serde", "image", "base64"] -capture = ["webrender_api/serialize", "ron", "serde"] -replay = ["webrender_api/deserialize", "ron", "serde"] +debugger = ["ws", "serde_json", "image", "base64"] +capture = ["webrender_api/serialize"] +replay = ["webrender_api/deserialize"] pathfinder = ["pathfinder_font_renderer", "pathfinder_gfx_utils", "pathfinder_partitioner", "pathfinder_path_utils"] -serialize_program = ["serde", "webrender_build/serialize_program"] +serialize_program = ["webrender_build/serialize_program"] no_static_freetype = [] [build-dependencies] webrender_build = { version = "0.0.1", path = "../webrender_build" } +cfg-if = "0.1.2" +glsl-to-spirv = "0.1" +gfx-hal = "0.3.1" +ron = "0.1.7" +serde = { version = "1.0", features = ["serde_derive"] } [dependencies] app_units = "0.7" +arrayvec = "0.4" base64 = { optional = true, version = "0.10" } bincode = "1.0" bitflags = "1.0" byteorder = "1.0" cfg-if = "0.1.2" fxhash = "0.2.1" -gleam = "0.6.8" +gfx-hal = { version = "0.3.1", features = ["serde"] } +gleam = { optional = true, version = "0.6.8" } image = { optional = true, version = "0.21" } lazy_static = "1" log = "0.4" @@ -37,9 +44,13 @@ malloc_size_of_derive = "0.1" num-traits = "0.2" plane-split = "0.13.3" png = { optional = true, version = "0.14" } +rand ="0.4" rayon = "1" -ron = { optional = true, version = "0.1.7" } -serde = { optional = true, version = "1.0", features = ["serde_derive"] } +rendy-memory = { version = "0.4.0", features = ["serde"] } +relevant = { version = "0.4", features = ["std"] } +ron = "0.1.7" +rendy-descriptor = "0.4.0" +serde = { version = "1.0", features = ["serde_derive"] } serde_json = { optional = true, version = "1.0" } sha2 = "0.8" smallvec = "0.6" diff --git a/webrender/build.rs b/webrender/build.rs index 3034888599..ccc2814691 100644 --- a/webrender/build.rs +++ b/webrender/build.rs @@ -2,8 +2,24 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[macro_use] +extern crate cfg_if; extern crate webrender_build; +cfg_if! { + if #[cfg(not(feature = "gleam"))] { + extern crate ron; + #[macro_use] + extern crate serde; + extern crate gfx_hal; + #[path = "src/device/gfx/vertex_types.rs"] + mod vertex_types; + mod build_gfx; + use build_gfx::gfx_main; + } +} + +use std::collections::HashMap; use std::borrow::Cow; use std::env; use std::fs::{canonicalize, read_dir, File}; @@ -11,8 +27,9 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use webrender_build::shader::*; -fn write_shaders(glsl_files: Vec, shader_file_path: &Path) { +fn write_shaders(glsl_files: Vec, shader_file_path: &Path) -> HashMap { let mut shader_file = File::create(shader_file_path).unwrap(); + let mut shader_map: HashMap = HashMap::with_capacity(glsl_files.len()); write!(shader_file, "/// AUTO GENERATED BY build.rs\n\n").unwrap(); write!(shader_file, "use std::collections::HashMap;\n\n").unwrap(); @@ -52,6 +69,7 @@ fn write_shaders(glsl_files: Vec, shader_file_path: &Path) { let full_name = full_path.as_os_str().to_str().unwrap(); let full_name = full_name.replace("\\\\?\\", ""); let full_name = full_name.replace("\\", "/"); + shader_map.insert(shader_name.clone(), full_name.clone()); write!( shader_file, @@ -64,6 +82,7 @@ fn write_shaders(glsl_files: Vec, shader_file_path: &Path) { write!(shader_file, " h\n").unwrap(); write!(shader_file, " }};\n").unwrap(); write!(shader_file, "}}\n").unwrap(); + shader_map } fn main() { @@ -88,5 +107,7 @@ fn main() { // deterministically. glsl_files.sort_by(|a, b| a.file_name().cmp(&b.file_name())); - write_shaders(glsl_files, &shaders_file); + let _shaders = write_shaders(glsl_files, &shaders_file); + #[cfg(not(feature = "gleam"))] + gfx_main(&out_dir, _shaders, &shaders_file); } diff --git a/webrender/build_gfx.rs b/webrender/build_gfx.rs new file mode 100644 index 0000000000..9100eb42fd --- /dev/null +++ b/webrender/build_gfx.rs @@ -0,0 +1,672 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use gfx_hal::pso::{AttributeDesc, Element, VertexInputRate, VertexBufferDesc}; +use gfx_hal::format::Format; +use ron::de::from_str; +use ron::ser::{to_string_pretty, PrettyConfig}; +use std::collections::HashMap; +use std::fs::{File, OpenOptions}; +use std::io::BufReader; +use std::io::prelude::*; +use std::mem; +use std::path::Path; +use std::process::{self, Command, Stdio}; +use vertex_types::*; + +const SHADER_IMPORT: &str = "#include "; +const SHADER_KIND_FRAGMENT: &str = "#define WR_FRAGMENT_SHADER\n"; +const SHADER_KIND_VERTEX: &str = "#define WR_VERTEX_SHADER\n"; +const SHADER_PREFIX: &str = "#define WR_MAX_VERTEX_TEXTURE_WIDTH 1024U\n"; +const SHADER_VERSION_VK: &'static str = "#version 450\n"; +const VK_EXTENSIONS: &'static str = "#extension GL_ARB_shading_language_420pack : enable\n\ + #extension GL_ARB_explicit_attrib_location : enable\n\ + #extension GL_ARB_separate_shader_objects : enable\n"; + +// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#features-limits +const MAX_INPUT_ATTRIBUTES: u32 = 16; + +const DESCRIPTOR_SET_PER_PASS: u32 = 0; +const DESCRIPTOR_SET_PER_GROUP: u32 = 1; +const DESCRIPTOR_SET_PER_DRAW: u32 = 2; +const DESCRIPTOR_SET_LOCALS: u32 = 3; + +#[derive(Deserialize)] +struct Shader { + name: String, + source_name: String, + features: Vec, +} + +#[derive(Serialize)] +struct PipelineRequirements { + attribute_descriptors: Vec, + bindings_map: HashMap, + vertex_buffer_descriptors: Vec, +} + +fn create_shaders(out_dir: &str, shaders: &HashMap) -> Vec { + fn get_shader_source(shader_name: &str, shaders: &HashMap) -> Option { + if let Some(shader_file) = shaders.get(shader_name) { + let shader_file_path = Path::new(shader_file); + if let Ok(mut shader_source_file) = File::open(shader_file_path) { + let mut source = String::new(); + shader_source_file.read_to_string(&mut source).unwrap(); + Some(source) + } else { + None + } + } else { + None + } + } + + fn parse_shader_source(source: &str, shaders: &HashMap, output: &mut String) { + for line in source.lines() { + if line.starts_with(SHADER_IMPORT) { + let imports = line[SHADER_IMPORT.len() ..].split(","); + // For each import, get the source, and recurse. + for mut import in imports { + if import == "base" { + import = "base_gfx"; + } else if import == "gpu_cache" { + import = "gpu_cache_gfx"; + } + if let Some(include) = get_shader_source(import, shaders) { + parse_shader_source(&include, shaders, output); + } + } + } else { + output.push_str(line); + output.push_str("\n"); + } + } + } + + fn build_shader_strings( + base_filename: &str, + features: &str, + shaders: &HashMap, + ) -> (String, String) { + // Construct a list of strings to be passed to the shader compiler. + let mut vs_source = String::new(); + let mut fs_source = String::new(); + + vs_source.push_str(SHADER_VERSION_VK); + fs_source.push_str(SHADER_VERSION_VK); + + // Define a constant depending on whether we are compiling VS or FS. + vs_source.push_str(SHADER_KIND_VERTEX); + fs_source.push_str(SHADER_KIND_FRAGMENT); + + // Add any defines that were passed by the caller. + vs_source.push_str(features); + fs_source.push_str(features); + + // Parse the main .glsl file, including any imports + // and append them to the list of sources. + let mut shared_result = String::new(); + if let Some(shared_source) = get_shader_source(base_filename, shaders) { + parse_shader_source(&shared_source, shaders, &mut shared_result); + } + + //vs_source.push_str(SHADER_LINE_MARKER); + vs_source.push_str(&shared_result); + //fs_source.push_str(SHADER_LINE_MARKER); + fs_source.push_str(&shared_result); + + (vs_source, fs_source) + } + + let mut file = File::open("shaders.ron").expect("Unable to open shaders.ron"); + let mut source = String::new(); + file.read_to_string(&mut source).unwrap(); + let shader_configs: Vec = from_str(&source).expect("Unable to parse shaders.ron"); + + let mut file_names = Vec::new(); + for shader in &shader_configs { + for config in &shader.features { + let mut features = String::new(); + + features.push_str(SHADER_PREFIX); + features.push_str(format!("//Source: {}.glsl\n", shader.source_name).as_str()); + + let mut file_name_postfix = String::new(); + for feature in config.split(",") { + if !feature.is_empty() { + features.push_str(&format!("#define WR_FEATURE_{}\n", feature)); + if shader.name == shader.source_name { + file_name_postfix + .push_str(&format!("_{}", feature.to_lowercase().as_str())); + } + } + } + + features.push_str(VK_EXTENSIONS); + + let (vs_source, fs_source) = + build_shader_strings(&shader.source_name, &features, shaders); + + let mut filename = shader.name.clone(); + filename.push_str(file_name_postfix.as_str()); + let (mut vs_name, mut fs_name) = (filename.clone(), filename); + vs_name.push_str(".vert"); + fs_name.push_str(".frag"); + println!("vs_name = {}, shader.name = {}", vs_name, shader.name); + let (vs_file_path, fs_file_path) = ( + Path::new(out_dir).join(vs_name.clone()), + Path::new(out_dir).join(fs_name.clone()), + ); + let (mut vs_file, mut fs_file) = ( + File::create(vs_file_path).unwrap(), + File::create(fs_file_path).unwrap(), + ); + write!(vs_file, "{}", vs_source).unwrap(); + write!(fs_file, "{}", fs_source).unwrap(); + file_names.push(vs_name); + file_names.push(fs_name); + } + } + file_names +} + +fn process_glsl_for_spirv(file_path: &Path, file_name: &str) -> Option { + let mut new_data = String::new(); + let mut bindings_map: HashMap = HashMap::new(); + let mut in_location = 0; + let mut out_location = 0; + let mut varying_location = 0; + let mut attribute_descriptors: Vec = Vec::new(); + let mut vertex_offset = 0; + let mut instance_offset = 0; + // Since the .vert and .frag files for the same shader use the same layout qualifiers + // we extract layout datas from .vert files only. + let write_ron = file_name.ends_with(".vert"); + + // Mapping from glsl sampler variable name to a tuple, + // in which the first item is the corresponding expression used in vulkan glsl files, + // the second is the layout set, the third is the binding index. + // e.g.: sColor0 -> ("sampler2DArray(tColor0, sColor0)", 1, 7) + let mut sampler_mapping: HashMap = HashMap::new(); + + let file = File::open(file_path).unwrap(); + let reader = BufReader::new(file); + for line in reader.lines() { + let l = line.unwrap(); + let trimmed = l.trim_start(); + + // Replace uniforms in shader: + // Sampler uniforms are splitted to texture + sampler. + // Other types occur in a group. These are replaced with a static string for now. + if trimmed.starts_with("uniform") { + if trimmed.contains("sampler") { + let code = split_code(trimmed); + let info = texture_info_from_line(&code); + extend_sampler_definition( + info.set, + info.binding, + code, + &mut bindings_map, + &mut new_data, + &mut sampler_mapping, + write_ron, + ); + + // Replace non-sampler uniforms with a structure. + // We just place a predefined structure to the position of the last non-uniform + // variable (uDevicePixelRatio), since all shader uses the same variables. + } else if trimmed.starts_with("uniform mat4 uTransform") { + replace_non_sampler_uniforms(&mut new_data); + } + + // Adding location info for non-uniform variables. + } else if trimmed.contains(';') && // If the line contains a semicolon we assume it is a variable declaration. + (trimmed.starts_with("varying ") || trimmed.starts_with("flat varying ") + || trimmed.starts_with("in ") || trimmed.starts_with("out ")) + { + extend_non_uniform_variables_with_location_info( + &mut attribute_descriptors, + &mut in_location, + &mut out_location, + &mut varying_location, + &mut instance_offset, + trimmed, + &mut new_data, + &mut vertex_offset, + write_ron, + ); + // Replacing sampler variables with the corresponding expression from sampler_mapping. + } else if l.contains("TEX_SAMPLE(") || l.contains("TEXEL_FETCH(") || l.contains("TEX_SIZE(") + || l.contains("texelFetch(") || l.contains("texture(") + || l.contains("textureLod(") || l.contains("textureSize(") + { + let mut line = l.clone(); + for (k, v) in sampler_mapping.iter() { + if line.contains(k) { + line = line.replace(k, &v.0); + } + } + // Change the sampling coordinates of the Dither texture. Basically it's a vertical flip. + if line.contains("sDither") { + line = line.replace("pos", "ivec2(pos.x, matrix_mask - pos.y)"); + } + new_data.push_str(&line); + new_data.push('\n'); + } else { + if l.contains("uTransform") { + new_data.push_str("\t\t\tmat4 _transform;\n\t\t\tif (push_constants) { _transform = pushConstants.uTransform; } else { _transform = uTransform; }\n"); + } + if l.contains("uMode") { + new_data.push_str("\t\t\tint _umode;\n\t\t\tif (push_constants) { _umode = pushConstants.uMode; } else { _umode = uMode; }\n"); + } + new_data.push_str( + &l + .replace("uTransform", "_transform") + .replace("uMode", "_umode") + ); + new_data.push('\n'); + } + } + let mut file = File::create(file_path).unwrap(); + file.write(new_data.as_bytes()).unwrap(); + if write_ron { + let vertex_buffer_descriptors = create_vertex_buffer_descriptors(file_name); + let pipeline_requirements = PipelineRequirements { + attribute_descriptors, + bindings_map, + vertex_buffer_descriptors, + }; + return Some(pipeline_requirements); + } + None +} + +fn split_code(line: &str) -> Vec<&str> { + line.split(';') + .collect::>()[0] + .split(' ') + .collect::>() +} + +fn extend_sampler_definition( + set: u32, + binding: u32, + code: Vec<&str>, + bindings_map: &mut HashMap, + new_data: &mut String, + sampler_mapping: &mut HashMap, + write_ron: bool, +) { + // Get the name of the sampler. + let (sampler_name, code) = code.split_last().unwrap(); + + // Get the exact type of the sampler. + let (sampler_type, code) = code.split_last().unwrap(); + let sampler_type = String::from(*sampler_type); + let mut code_str = String::new(); + for i in 0 .. code.len() { + code_str.push_str(code[i]); + code_str.push(' '); + } + + // If the sampler is in the map we only update the shader code. + if let Some(&(_, set, binding)) = sampler_mapping.get(*sampler_name) { + let layout_str = format!( + "layout(set = {}, binding = {}) {}{} {};\n", + set, binding, code_str, sampler_type, sampler_name + ); + new_data.push_str(&layout_str); + + // Replace sampler definition with a texture and a sampler. + } else { + let layout_str = format!( + "layout(set = {}, binding = {}) {}{} {};\n", + set, binding, code_str, sampler_type, sampler_name + ); + if write_ron { + bindings_map.insert(sampler_name.to_string(), binding); + } + new_data.push_str(&layout_str); + sampler_mapping.insert( + String::from(*sampler_name), + ( + String::from(*sampler_name), + set, + binding, + ), + ); + } +} + +fn replace_non_sampler_uniforms(new_data: &mut String) { + new_data.push_str( + "\tlayout(push_constant) uniform PushConsts {\n\ + \t\tmat4 uTransform; // Orthographic projection\n\ + \t\t// A generic uniform that shaders can optionally use to configure\n\ + \t\t// an operation mode for this batch.\n\ + \t\tint uMode;\n\ + \t} pushConstants;\n", + ); + new_data.push_str(&format!( + "\tlayout(set = {}, binding = 0) uniform Locals {{\n\ + \t\tuniform mat4 uTransform; // Orthographic projection\n\ + \t\t// A generic uniform that shaders can optionally use to configure\n\ + \t\t// an operation mode for this batch.\n\ + \t\tuniform int uMode;\n\ + \t}};\n", + DESCRIPTOR_SET_LOCALS + )); +} + +struct TextureInfo { + set: u32, + binding: u32, +} +impl TextureInfo { + fn new(set: u32, binding: u32) -> Self { + TextureInfo { + set, + binding, + } + } +} + +fn texture_info_from_line(code: &[&str]) -> TextureInfo { + let (sampler_name, _) = code.split_last().unwrap(); + match sampler_name.as_ref() { + "sColor0" => TextureInfo::new(DESCRIPTOR_SET_PER_DRAW, 0), + "sColor1" => TextureInfo::new(DESCRIPTOR_SET_PER_DRAW, 1), + "sColor2" => TextureInfo::new(DESCRIPTOR_SET_PER_DRAW, 2), + "sPrevPassAlpha" => TextureInfo::new(DESCRIPTOR_SET_PER_PASS, 3), + "sPrevPassColor" => TextureInfo::new(DESCRIPTOR_SET_PER_PASS, 4), + "sGpuCache" => TextureInfo::new(DESCRIPTOR_SET_PER_GROUP, 5), + "sTransformPalette" => TextureInfo::new(DESCRIPTOR_SET_PER_GROUP, 6), + "sRenderTasks" => TextureInfo::new(DESCRIPTOR_SET_PER_GROUP, 7), + "sDither" => TextureInfo::new(DESCRIPTOR_SET_PER_GROUP, 8), + "sPrimitiveHeadersF" => TextureInfo::new(DESCRIPTOR_SET_PER_GROUP, 9), + "sPrimitiveHeadersI" => TextureInfo::new(DESCRIPTOR_SET_PER_GROUP, 10), + x => unreachable!("Sampler not found: {:?}", x), + } +} + +fn extend_non_uniform_variables_with_location_info( + attribute_descriptors: &mut Vec, + in_location: &mut u32, + out_location: &mut u32, + varying_location: &mut u32, + instance_offset: &mut u32, + line: &str, + new_data: &mut String, + vertex_offset: &mut u32, + write_ron: bool, +) { + let layout_str; + let location_size = calculate_location_size(line); + if line.starts_with("in") { + layout_str = format!("layout(location = {}) {}\n", in_location, line); + if write_ron { + add_attribute_descriptors( + attribute_descriptors, + in_location, + instance_offset, + line, + vertex_offset, + ); + } + *in_location += location_size; + assert!(*in_location < MAX_INPUT_ATTRIBUTES); + } else if line.starts_with("out") { + layout_str = format!("layout(location = {}) {}\n", out_location, line); + *out_location += location_size; + } else { + layout_str = format!("layout(location = {}) {}\n", varying_location, line); + *varying_location += location_size; + } + new_data.push_str(&layout_str) +} + +fn calculate_location_size(line: &str) -> u32 { + let mut multiplier = 1; + if line.ends_with("];") { + multiplier = line.split(|c| c == '[' || c == ']').nth(1).unwrap().parse::().unwrap(); + } + let res = match line.split_whitespace().rev().nth(1).unwrap() { + "mat4" => 4, + "mat3" => 3, + _ => 1, + }; + res * multiplier +} + +fn add_attribute_descriptors( + attribute_descriptors: &mut Vec, + in_location: &mut u32, + instance_offset: &mut u32, + line: &str, + vertex_offset: &mut u32, +) { + let def = split_code(line); + let var_name = def[2].trim_end_matches(';'); + let (format, offset) = match def[1] { + "float" => (Format::R32Sfloat, 4), + "int" => (Format::R32Sint, 4), + "ivec4" => (Format::Rgba32Sint, 16), + "vec2" => (Format::Rg32Sfloat, 8), + "vec3" => (Format::Rgb32Sfloat, 12), + "vec4" => (Format::Rgba32Sfloat, 16), + x => unimplemented!("Case: {} is missing!", x), + }; + match var_name { + "aColor" | "aColorTexCoord" | "aPosition" => { + attribute_descriptors.push( + AttributeDesc { + location: *in_location, + binding: 0, + element: Element { + format, + offset: *vertex_offset, + } + } + ); + *vertex_offset += offset; + } + _ => { + attribute_descriptors.push( + AttributeDesc { + location: *in_location, + binding: 1, + element: Element { + format, + offset: *instance_offset, + } + } + ); + *instance_offset += offset; + } + }; +} + +fn create_vertex_buffer_descriptors(file_name: &str) -> Vec { + let mut descriptors = vec![ + VertexBufferDesc { + binding: 0, + stride: mem::size_of::() as _, + rate: VertexInputRate::Vertex, + } + ]; + if file_name.starts_with("cs_blur") { + descriptors.push( + VertexBufferDesc { + binding: 1, + stride: mem::size_of::() as _, + rate: VertexInputRate::Instance(1), + } + ); + } else if file_name.starts_with("cs_border") { + descriptors.push( + VertexBufferDesc { + binding: 1, + stride: mem::size_of::() as _, + rate: VertexInputRate::Instance(1), + } + ); + } else if file_name.starts_with("cs_clip") { + descriptors.push( + VertexBufferDesc { + binding: 1, + stride: mem::size_of::() as _, + rate: VertexInputRate::Instance(1), + } + ); + } else if file_name.starts_with("cs_scale") { + descriptors.push( + VertexBufferDesc { + binding: 1, + stride: mem::size_of::() as _, + rate: VertexInputRate::Instance(1), + } + ); + } else if file_name.starts_with("cs_line") { + descriptors.push( + VertexBufferDesc { + binding: 1, + stride: mem::size_of::() as _, + rate: VertexInputRate::Instance(1), + } + ); + } else if file_name.starts_with("debug_color") { + descriptors = vec![ + VertexBufferDesc { + binding: 0, + stride: mem::size_of::() as _, + rate: VertexInputRate::Vertex, + }, + ]; + } else if file_name.starts_with("debug_font") { + descriptors = vec![ + VertexBufferDesc { + binding: 0, + stride: mem::size_of::() as _, + rate: VertexInputRate::Vertex, + }, + ]; + // Primitive and brush shaders + } else { + descriptors.push( + VertexBufferDesc { + binding: 1, + stride: mem::size_of::() as _, + rate: VertexInputRate::Instance(1), + } + ); + } + descriptors +} + +fn compile_glsl_to_spirv(file_name_vector: Vec, out_dir: &str, shader_file_path: &Path) -> HashMap { + let mut shader_file = OpenOptions::new().append(true).open(shader_file_path).unwrap(); + write!(shader_file, "\nlazy_static! {{\n").unwrap(); + write!( + shader_file, + " pub static ref SPIRV_BINARIES: HashMap<&'static str, Vec > = {{\n" + ).unwrap(); + write!(shader_file, " let mut h = HashMap::new();\n").unwrap(); + + let mut requirements = HashMap::new(); + for (_index, file_name) in file_name_vector.iter().enumerate() { + let file_path = Path::new(&out_dir).join(&file_name); + if let Some(req) = process_glsl_for_spirv(&file_path, &file_name) { + requirements.insert(file_name.trim_end_matches(".vert").to_owned(), req); + } + let file_name = [file_name, ".spv"].concat(); + let spirv_file_path = Path::new(&out_dir).join(&file_name); + #[cfg(target_os="linux")] + let mut glslang_cmd = Command::new(Path::new("./tools/glslang-validator-linux")); + #[cfg(target_os="macos")] + let mut glslang_cmd = Command::new(Path::new("./tools/glslang-validator-mac")); + #[cfg(target_os = "windows")] + let mut glslang_cmd = Command::new(Path::new("./tools/glslang-validator-win.exe")); + glslang_cmd + .arg("-V") + .arg("-o") + .arg(&spirv_file_path) + .arg(&file_path); + if glslang_cmd + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .status() + .unwrap() + .code() + .unwrap() != 0 + { + println!("Error while compiling spirv: {:?}", file_name); + process::exit(1) + }; + #[cfg(target_os="linux")] + let mut spirv_val_cmd = Command::new(Path::new("./tools/spirv-val-linux")); + #[cfg(target_os="macos")] + let mut spirv_val_cmd = Command::new(Path::new("./tools/spirv-val-mac")); + #[cfg(target_os = "windows")] + let mut spirv_val_cmd = Command::new(Path::new("./tools/spirv-val-win.exe")); + spirv_val_cmd.arg(&spirv_file_path); + if spirv_val_cmd + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .status() + .unwrap() + .code() + .unwrap() != 0 + { + println!("Error while validating spirv shader: {:?}", file_name); + process::exit(1) + } + + let spirv_file_path = spirv_file_path.to_str().unwrap().replace("\\\\?\\", ""); + let spirv_file_path = spirv_file_path.replace("\\", "/"); + write!( + shader_file, + " h.insert(\"{}\", hal::read_spirv(&std::fs::File::open(\"{}\").unwrap()).unwrap());\n", + file_name, + spirv_file_path, + ).unwrap(); + } + write!(shader_file, " h\n").unwrap(); + write!(shader_file, " }};\n").unwrap(); + write!(shader_file, "}}\n").unwrap(); + requirements +} + +fn write_ron_to_file(requriements: HashMap, out_dir: &str, shader_file_path: &Path) { + let ron_file_path = Path::new(&out_dir).join("shader_bindings.ron"); + let mut ron_file = File::create(&ron_file_path).unwrap(); + let pretty = PrettyConfig { + enumerate_arrays: true, + ..PrettyConfig::default() + }; + ron_file + .write( + to_string_pretty(&requriements, pretty) + .unwrap() + .as_bytes(), + ) + .unwrap(); + + let mut shader_file = OpenOptions::new().append(true).open(shader_file_path).unwrap(); + let ron_file_path = ron_file_path.to_str().unwrap().replace("\\\\?\\", ""); + let ron_file_path = ron_file_path.replace("\\", "/"); + write!(shader_file, "\nlazy_static! {{\n").unwrap(); + write!( + shader_file, + " pub static ref PIPELINES: &'static str = include_str!(\"{}\");\n", + ron_file_path, + ).unwrap(); + write!(shader_file, "}}\n").unwrap(); +} + +pub fn gfx_main(out_dir: &str, shader_map: HashMap, shader_file_path: &Path) { + println!("cargo:rerun-if-changed=shaders.ron"); + let shaders = create_shaders(&out_dir, &shader_map); + let requirements = compile_glsl_to_spirv(shaders, &out_dir, shader_file_path); + write_ron_to_file(requirements, &out_dir, shader_file_path); +} diff --git a/webrender/res/base.glsl b/webrender/res/base.glsl index 22b17144bf..04a09a99f8 100644 --- a/webrender/res/base.glsl +++ b/webrender/res/base.glsl @@ -2,6 +2,43 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +const bool alpha_pass = +#ifdef WR_FEATURE_ALPHA_PASS + true; +#else + false; +#endif + + const bool color_target = +#ifdef WR_FEATURE_COLOR_TARGET + true; +#else + false; +#endif + + const bool glyph_transform_f = +#ifdef WR_FEATURE_GLYPH_TRANSFORM + true; +#else + false; +#endif + + const bool dithering = +#ifdef WR_FEATURE_DITHERING + true; +#else + false; +#endif + + const bool debug_overdraw = +#ifdef WR_FEATURE_DEBUG_OVERDRAW + true; +#else + false; +#endif + +const bool push_constants = false; + #if defined(GL_ES) #if GL_ES == 1 #ifdef GL_FRAGMENT_PRECISION_HIGH diff --git a/webrender/res/base_gfx.glsl b/webrender/res/base_gfx.glsl new file mode 100644 index 0000000000..700ddc5e46 --- /dev/null +++ b/webrender/res/base_gfx.glsl @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +layout(constant_id = 0) const bool alpha_pass = false; +layout(constant_id = 1) const bool color_target = false; +layout(constant_id = 2) const bool glyph_transform_f = false; +layout(constant_id = 3) const bool dithering = false; +layout(constant_id = 4) const bool debug_overdraw = false; +layout(constant_id = 5) const bool push_constants = true; + +#if defined(GL_ES) + #if GL_ES == 1 + #ifdef GL_FRAGMENT_PRECISION_HIGH + precision highp sampler2DArray; + #else + precision mediump sampler2DArray; + #endif + + // Sampler default precision is lowp on mobile GPUs. + // This causes RGBA32F texture data to be clamped to 16 bit floats on some GPUs (e.g. Mali-T880). + // Define highp precision macro to allow lossless FLOAT texture sampling. + #define HIGHP_SAMPLER_FLOAT highp + + // texelFetchOffset is buggy on some Android GPUs (see issue #1694). + // Fallback to texelFetch on mobile GPUs. + #define TEXEL_FETCH(sampler, position, lod, offset) texelFetch(sampler, position + offset, lod) + #else + #define HIGHP_SAMPLER_FLOAT + #define TEXEL_FETCH(sampler, position, lod, offset) texelFetchOffset(sampler, position, lod, offset) + #endif +#else + #define HIGHP_SAMPLER_FLOAT + #define TEXEL_FETCH(sampler, position, lod, offset) texelFetchOffset(sampler, position, lod, offset) +#endif + +#ifdef WR_VERTEX_SHADER + #define varying out +#endif + +#ifdef WR_FRAGMENT_SHADER + precision highp float; + #define varying in +#endif diff --git a/webrender/res/brush.glsl b/webrender/res/brush.glsl index 547204443d..1dd6763195 100644 --- a/webrender/res/brush.glsl +++ b/webrender/res/brush.glsl @@ -78,9 +78,9 @@ void main(void) { // items. For now, just ensure it has no // effect. We can tidy this up as we move // more items to be brush shaders. -#ifdef WR_FEATURE_ALPHA_PASS - init_transform_vs(vec4(vec2(-1.0e16), vec2(1.0e16))); -#endif + if (alpha_pass) { + init_transform_vs(vec4(vec2(-1.0e16), vec2(1.0e16))); + } } else { bvec4 edge_mask = notEqual(edge_flags & ivec4(1, 2, 4, 8), ivec4(0)); @@ -101,13 +101,14 @@ void main(void) { // shaders that don't clip in the future, // but it's reasonable to assume that one // implies the other, for now. -#ifdef WR_FEATURE_ALPHA_PASS - write_clip( - vi.world_pos, - vi.snap_offset, - clip_area - ); -#endif + + if (alpha_pass) { + write_clip( + vi.world_pos, + vi.snap_offset, + clip_area + ); + } // Run the specific brush VS code to write interpolators. brush_vs( @@ -136,25 +137,25 @@ struct Fragment { Fragment brush_fs(); void main(void) { -#ifdef WR_FEATURE_DEBUG_OVERDRAW - oFragColor = WR_DEBUG_OVERDRAW_COLOR; -#else - // Run the specific brush FS code to output the color. - Fragment frag = brush_fs(); + if (debug_overdraw) { + oFragColor = WR_DEBUG_OVERDRAW_COLOR; + } else { + // Run the specific brush FS code to output the color. + Fragment frag = brush_fs(); -#ifdef WR_FEATURE_ALPHA_PASS - // Apply the clip mask - float clip_alpha = do_clip(); + if (alpha_pass) { + // Apply the clip mask + float clip_alpha = do_clip(); - frag.color *= clip_alpha; + frag.color *= clip_alpha; - #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING - oFragBlend = frag.blend * clip_alpha; - #endif -#endif + #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING + oFragBlend = frag.blend * clip_alpha; + #endif + } - // TODO(gw): Handle pre-multiply common code here as required. - oFragColor = frag.color; -#endif + // TODO(gw): Handle pre-multiply common code here as required. + oFragColor = frag.color; + } } #endif diff --git a/webrender/res/brush_blend.glsl b/webrender/res/brush_blend.glsl index f72d418303..016fd26231 100644 --- a/webrender/res/brush_blend.glsl +++ b/webrender/res/brush_blend.glsl @@ -6,8 +6,11 @@ #include shared,prim_shared,brush -varying vec3 vUv; +// Interpolated UV coordinates to sample. +varying vec2 vUv; +// X = layer index to sample, Y = flag to allow perspective interpolation of UV. +flat varying vec2 vLayerAndPerspective; flat varying float vAmount; flat varying int vOp; flat varying mat3 vColorMat; @@ -39,8 +42,10 @@ void brush_vs( vec2 y = mix(extra_data.st_bl, extra_data.st_br, f.x); f = mix(x, y, f.y); vec2 uv = mix(uv0, uv1, f); - vUv = vec3(uv / texture_size, res.layer); + float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0; + vUv = uv / texture_size * mix(vi.world_pos.w, 1.0, perspective_interpolate); + vLayerAndPerspective = vec2(res.layer, perspective_interpolate); vUvClipBounds = vec4(uv0, uv1) / texture_size.xyxy; float lumR = 0.2126; @@ -146,7 +151,9 @@ vec3 LinearToSrgb(vec3 color) { } Fragment brush_fs() { - vec4 Cs = texture(sColor0, vUv); + float perspective_divisor = mix(gl_FragCoord.w, 1.0, vLayerAndPerspective.y); + vec2 uv = vUv * perspective_divisor; + vec4 Cs = texture(sColor0, vec3(uv, vLayerAndPerspective.x)); // Un-premultiply the input. float alpha = Cs.a; @@ -179,7 +186,7 @@ Fragment brush_fs() { // Fail-safe to ensure that we don't sample outside the rendered // portion of a blend source. - alpha *= point_inside_rect(vUv.xy, vUvClipBounds.xy, vUvClipBounds.zw); + alpha *= point_inside_rect(uv, vUvClipBounds.xy, vUvClipBounds.zw); // Pre-multiply the alpha into the output value. return Fragment(alpha * vec4(color, 1.0)); diff --git a/webrender/res/brush_image.glsl b/webrender/res/brush_image.glsl index 9b162368c2..12e10fcaf2 100644 --- a/webrender/res/brush_image.glsl +++ b/webrender/res/brush_image.glsl @@ -6,23 +6,21 @@ #include shared,prim_shared,brush -#ifdef WR_FEATURE_ALPHA_PASS + varying vec2 vLocalPos; -#endif -// Interpolated uv coordinates in xy, and layer in z. -varying vec3 vUv; +// Interpolated UV coordinates to sample. +varying vec2 vUv; +// X = layer index to sample, Y = flag to allow perspective interpolation of UV. +flat varying vec2 vLayerAndPerspective; // Normalized bounds of the source image in the texture. flat varying vec4 vUvBounds; // Normalized bounds of the source image in the texture, adjusted to avoid // sampling artifacts. flat varying vec4 vUvSampleBounds; - -#ifdef WR_FEATURE_ALPHA_PASS flat varying vec4 vColor; flat varying vec2 vMaskSwizzle; flat varying vec2 vTileRepeat; -#endif #ifdef WR_VERTEX_SHADER @@ -97,7 +95,8 @@ void brush_vs( } } - vUv.z = res.layer; + float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0; + vLayerAndPerspective = vec2(res.layer, perspective_interpolate); // Handle case where the UV coords are inverted (e.g. from an // external image). @@ -111,39 +110,43 @@ void brush_vs( vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size; -#ifdef WR_FEATURE_ALPHA_PASS - int color_mode = user_data.x & 0xffff; - int blend_mode = user_data.x >> 16; - int raster_space = user_data.y; + int color_mode, blend_mode; + if (alpha_pass) { + color_mode = user_data.x & 0xffff; + blend_mode = user_data.x >> 16; + int raster_space = user_data.y; - if (color_mode == COLOR_MODE_FROM_PASS) { - color_mode = uMode; - } + if (color_mode == COLOR_MODE_FROM_PASS) { + color_mode = uMode; + } - // Derive the texture coordinates for this image, based on - // whether the source image is a local-space or screen-space - // image. - switch (raster_space) { - case RASTER_SCREEN: { - // Since the screen space UVs specify an arbitrary quad, do - // a bilinear interpolation to get the correct UV for this - // local position. - ImageResourceExtra extra_data = fetch_image_resource_extra(user_data.w); - vec2 x = mix(extra_data.st_tl, extra_data.st_tr, f.x); - vec2 y = mix(extra_data.st_bl, extra_data.st_br, f.x); - f = mix(x, y, f.y); - break; + // Derive the texture coordinates for this image, based on + // whether the source image is a local-space or screen-space + // image. + switch (raster_space) { + case RASTER_SCREEN: { + // Since the screen space UVs specify an arbitrary quad, do + // a bilinear interpolation to get the correct UV for this + // local position. + ImageResourceExtra extra_data = fetch_image_resource_extra(user_data.w); + vec2 x = mix(extra_data.st_tl, extra_data.st_tr, f.x); + vec2 y = mix(extra_data.st_bl, extra_data.st_br, f.x); + f = mix(x, y, f.y); + break; + } + default: + break; } - default: - break; } -#endif // Offset and scale vUv here to avoid doing it in the fragment shader. vec2 repeat = local_rect.size / stretch_size; - vUv.xy = mix(uv0, uv1, f) - min_uv; - vUv.xy /= texture_size; - vUv.xy *= repeat.xy; + vUv = mix(uv0, uv1, f) - min_uv; + vUv /= texture_size; + vUv *= repeat.xy; + if (perspective_interpolate == 0.0) { + vUv *= vi.world_pos.w; + } #ifdef WR_FEATURE_TEXTURE_RECT vUvBounds = vec4(0.0, 0.0, vec2(textureSize(sColor0))); @@ -151,49 +154,66 @@ void brush_vs( vUvBounds = vec4(min_uv, max_uv) / texture_size.xyxy; #endif -#ifdef WR_FEATURE_ALPHA_PASS - vTileRepeat = repeat.xy; - - float opacity = float(user_data.z) / 65535.0; - switch (blend_mode) { - case BLEND_MODE_ALPHA: - image_data.color.a *= opacity; - break; - case BLEND_MODE_PREMUL_ALPHA: - default: - image_data.color *= opacity; - break; - } + if (alpha_pass) { + vTileRepeat = repeat.xy; + + float opacity = float(user_data.z) / 65535.0; + switch (blend_mode) { + case BLEND_MODE_ALPHA: + image_data.color.a *= opacity; + break; + case BLEND_MODE_PREMUL_ALPHA: + image_data.color *= opacity; + break; + default: + image_data.color *= opacity; + break; + } - switch (color_mode) { - case COLOR_MODE_ALPHA: - case COLOR_MODE_BITMAP: - vMaskSwizzle = vec2(0.0, 1.0); - vColor = image_data.color; - break; - case COLOR_MODE_SUBPX_BG_PASS2: - case COLOR_MODE_SUBPX_DUAL_SOURCE: - case COLOR_MODE_IMAGE: - vMaskSwizzle = vec2(1.0, 0.0); - vColor = image_data.color; - break; - case COLOR_MODE_SUBPX_CONST_COLOR: - case COLOR_MODE_SUBPX_BG_PASS0: - case COLOR_MODE_COLOR_BITMAP: - vMaskSwizzle = vec2(1.0, 0.0); - vColor = vec4(image_data.color.a); - break; - case COLOR_MODE_SUBPX_BG_PASS1: - vMaskSwizzle = vec2(-1.0, 1.0); - vColor = vec4(image_data.color.a) * image_data.background_color; - break; - default: - vMaskSwizzle = vec2(0.0); - vColor = vec4(1.0); - } + switch (color_mode) { + case COLOR_MODE_ALPHA: + vMaskSwizzle = vec2(0.0, 1.0); + vColor = image_data.color; + break; + case COLOR_MODE_BITMAP: + vMaskSwizzle = vec2(0.0, 1.0); + vColor = image_data.color; + break; + case COLOR_MODE_SUBPX_BG_PASS2: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = image_data.color; + break; + case COLOR_MODE_SUBPX_DUAL_SOURCE: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = image_data.color; + break; + case COLOR_MODE_IMAGE: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = image_data.color; + break; + case COLOR_MODE_SUBPX_CONST_COLOR: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = vec4(image_data.color.a); + break; + case COLOR_MODE_SUBPX_BG_PASS0: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = vec4(image_data.color.a); + break; + case COLOR_MODE_COLOR_BITMAP: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = vec4(image_data.color.a); + break; + case COLOR_MODE_SUBPX_BG_PASS1: + vMaskSwizzle = vec2(-1.0, 1.0); + vColor = vec4(image_data.color.a) * image_data.background_color; + break; + default: + vMaskSwizzle = vec2(0.0); + vColor = vec4(1.0); + } - vLocalPos = vi.local_pos; -#endif + vLocalPos = vi.local_pos; + } } #endif @@ -201,50 +221,52 @@ void brush_vs( Fragment brush_fs() { vec2 uv_size = vUvBounds.zw - vUvBounds.xy; - -#ifdef WR_FEATURE_ALPHA_PASS - // This prevents the uv on the top and left parts of the primitive that was inflated - // for anti-aliasing purposes from going beyound the range covered by the regular - // (non-inflated) primitive. - vec2 local_uv = max(vUv.xy, vec2(0.0)); - - // Handle horizontal and vertical repetitions. - vec2 repeated_uv = mod(local_uv, uv_size) + vUvBounds.xy; - - // This takes care of the bottom and right inflated parts. - // We do it after the modulo because the latter wraps around the values exactly on - // the right and bottom edges, which we do not want. - if (local_uv.x >= vTileRepeat.x * uv_size.x) { - repeated_uv.x = vUvBounds.z; - } - if (local_uv.y >= vTileRepeat.y * uv_size.y) { - repeated_uv.y = vUvBounds.w; + float perspective_divisor = mix(gl_FragCoord.w, 1.0, vLayerAndPerspective.y); + + vec2 repeated_uv; + if (alpha_pass){ + // This prevents the uv on the top and left parts of the primitive that was inflated + // for anti-aliasing purposes from going beyound the range covered by the regular + // (non-inflated) primitive. + vec2 local_uv = max(vUv * perspective_divisor, vec2(0.0)); + + // Handle horizontal and vertical repetitions. + repeated_uv = mod(local_uv, uv_size) + vUvBounds.xy; + + // This takes care of the bottom and right inflated parts. + // We do it after the modulo because the latter wraps around the values exactly on + // the right and bottom edges, which we do not want. + if (local_uv.x >= vTileRepeat.x * uv_size.x) { + repeated_uv.x = vUvBounds.z; + } + if (local_uv.y >= vTileRepeat.y * uv_size.y) { + repeated_uv.y = vUvBounds.w; + } + } else { + // Handle horizontal and vertical repetitions. + repeated_uv = mod(vUv * perspective_divisor, uv_size) + vUvBounds.xy; } -#else - // Handle horizontal and vertical repetitions. - vec2 repeated_uv = mod(vUv.xy, uv_size) + vUvBounds.xy; -#endif // Clamp the uvs to avoid sampling artifacts. vec2 uv = clamp(repeated_uv, vUvSampleBounds.xy, vUvSampleBounds.zw); - vec4 texel = TEX_SAMPLE(sColor0, vec3(uv, vUv.z)); + vec4 texel = TEX_SAMPLE(sColor0, vec3(uv, vLayerAndPerspective.x)); Fragment frag; -#ifdef WR_FEATURE_ALPHA_PASS - float alpha = init_transform_fs(vLocalPos); - texel.rgb = texel.rgb * vMaskSwizzle.x + texel.aaa * vMaskSwizzle.y; + if (alpha_pass) { + float alpha = init_transform_fs(vLocalPos); + texel.rgb = texel.rgb * vMaskSwizzle.x + texel.aaa * vMaskSwizzle.y; - vec4 alpha_mask = texel * alpha; - frag.color = vColor * alpha_mask; + vec4 alpha_mask = texel * alpha; + frag.color = vColor * alpha_mask; - #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING - frag.blend = alpha_mask * vColor.a; - #endif -#else - frag.color = texel; -#endif + #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING + frag.blend = alpha_mask * vColor.a; + #endif + } else { + frag.color = texel; + } return frag; } diff --git a/webrender/res/brush_linear_gradient.glsl b/webrender/res/brush_linear_gradient.glsl index 1b788a288f..d72968b53b 100644 --- a/webrender/res/brush_linear_gradient.glsl +++ b/webrender/res/brush_linear_gradient.glsl @@ -18,10 +18,8 @@ flat varying vec2 vRepeatedSize; varying vec2 vPos; -#ifdef WR_FEATURE_ALPHA_PASS varying vec2 vLocalPos; flat varying vec2 vTileRepeat; -#endif #ifdef WR_VERTEX_SHADER @@ -75,35 +73,36 @@ void brush_vs( // Whether to repeat the gradient along the line instead of clamping. vGradientRepeat = float(gradient.extend_mode != EXTEND_MODE_CLAMP); -#ifdef WR_FEATURE_ALPHA_PASS - vTileRepeat = tile_repeat; - vLocalPos = vi.local_pos; -#endif + if (alpha_pass) { + vTileRepeat = tile_repeat; + vLocalPos = vi.local_pos; + } } #endif #ifdef WR_FRAGMENT_SHADER Fragment brush_fs() { -#ifdef WR_FEATURE_ALPHA_PASS - // Handle top and left inflated edges (see brush_image). - vec2 local_pos = max(vPos, vec2(0.0)); - - // Apply potential horizontal and vertical repetitions. - vec2 pos = mod(local_pos, vRepeatedSize); - - vec2 prim_size = vRepeatedSize * vTileRepeat; - // Handle bottom and right inflated edges (see brush_image). - if (local_pos.x >= prim_size.x) { - pos.x = vRepeatedSize.x; - } - if (local_pos.y >= prim_size.y) { - pos.y = vRepeatedSize.y; + vec2 pos; + if (alpha_pass) { + // Handle top and left inflated edges (see brush_image). + vec2 local_pos = max(vPos, vec2(0.0)); + + // Apply potential horizontal and vertical repetitions. + pos = mod(local_pos, vRepeatedSize); + + vec2 prim_size = vRepeatedSize * vTileRepeat; + // Handle bottom and right inflated edges (see brush_image). + if (local_pos.x >= prim_size.x) { + pos.x = vRepeatedSize.x; + } + if (local_pos.y >= prim_size.y) { + pos.y = vRepeatedSize.y; + } + } else { + // Apply potential horizontal and vertical repetitions. + pos = mod(vPos, vRepeatedSize); } -#else - // Apply potential horizontal and vertical repetitions. - vec2 pos = mod(vPos, vRepeatedSize); -#endif float offset = dot(pos - vStartPoint, vScaledDir); @@ -111,9 +110,9 @@ Fragment brush_fs() { offset, vGradientRepeat); -#ifdef WR_FEATURE_ALPHA_PASS - color *= init_transform_fs(vLocalPos); -#endif + if (alpha_pass) { + color *= init_transform_fs(vLocalPos); + } return Fragment(color); } diff --git a/webrender/res/brush_radial_gradient.glsl b/webrender/res/brush_radial_gradient.glsl index f1fb8662d7..10b4ab136d 100644 --- a/webrender/res/brush_radial_gradient.glsl +++ b/webrender/res/brush_radial_gradient.glsl @@ -16,10 +16,8 @@ flat varying float vEndRadius; varying vec2 vPos; flat varying vec2 vRepeatedSize; -#ifdef WR_FEATURE_ALPHA_PASS varying vec2 vLocalPos; flat varying vec2 vTileRepeat; -#endif #ifdef WR_VERTEX_SHADER @@ -77,35 +75,36 @@ void brush_vs( // Whether to repeat the gradient instead of clamping. vGradientRepeat = float(gradient.extend_mode != EXTEND_MODE_CLAMP); -#ifdef WR_FEATURE_ALPHA_PASS - vTileRepeat = tile_repeat.xy; - vLocalPos = vi.local_pos; -#endif + if (alpha_pass) { + vTileRepeat = tile_repeat.xy; + vLocalPos = vi.local_pos; + } } #endif #ifdef WR_FRAGMENT_SHADER Fragment brush_fs() { -#ifdef WR_FEATURE_ALPHA_PASS - // Handle top and left inflated edges (see brush_image). - vec2 local_pos = max(vPos, vec2(0.0)); + vec2 pos; + if (alpha_pass) { + // Handle top and left inflated edges (see brush_image). + vec2 local_pos = max(vPos, vec2(0.0)); - // Apply potential horizontal and vertical repetitions. - vec2 pos = mod(local_pos, vRepeatedSize); + // Apply potential horizontal and vertical repetitions. + pos = mod(local_pos, vRepeatedSize); - vec2 prim_size = vRepeatedSize * vTileRepeat; - // Handle bottom and right inflated edges (see brush_image). - if (local_pos.x >= prim_size.x) { - pos.x = vRepeatedSize.x; - } - if (local_pos.y >= prim_size.y) { - pos.y = vRepeatedSize.y; + vec2 prim_size = vRepeatedSize * vTileRepeat; + // Handle bottom and right inflated edges (see brush_image). + if (local_pos.x >= prim_size.x) { + pos.x = vRepeatedSize.x; + } + if (local_pos.y >= prim_size.y) { + pos.y = vRepeatedSize.y; + } + } else { + // Apply potential horizontal and vertical repetitions. + pos = mod(vPos, vRepeatedSize); } -#else - // Apply potential horizontal and vertical repetitions. - vec2 pos = mod(vPos, vRepeatedSize); -#endif vec2 pd = pos - vCenter; float rd = vEndRadius - vStartRadius; @@ -149,9 +148,9 @@ Fragment brush_fs() { offset, vGradientRepeat); -#ifdef WR_FEATURE_ALPHA_PASS - color *= init_transform_fs(vLocalPos); -#endif + if (alpha_pass) { + color *= init_transform_fs(vLocalPos); + } return Fragment(color); } diff --git a/webrender/res/brush_solid.glsl b/webrender/res/brush_solid.glsl index cfd1ae3c2a..0dbd423d7f 100644 --- a/webrender/res/brush_solid.glsl +++ b/webrender/res/brush_solid.glsl @@ -7,10 +7,7 @@ #include shared,prim_shared,brush flat varying vec4 vColor; - -#ifdef WR_FEATURE_ALPHA_PASS varying vec2 vLocalPos; -#endif #ifdef WR_VERTEX_SHADER @@ -39,18 +36,18 @@ void brush_vs( float opacity = float(user_data.x) / 65535.0; vColor = prim.color * opacity; -#ifdef WR_FEATURE_ALPHA_PASS - vLocalPos = vi.local_pos; -#endif + if (alpha_pass) { + vLocalPos = vi.local_pos; + } } #endif #ifdef WR_FRAGMENT_SHADER Fragment brush_fs() { vec4 color = vColor; -#ifdef WR_FEATURE_ALPHA_PASS - color *= init_transform_fs(vLocalPos); -#endif + if (alpha_pass) { + color *= init_transform_fs(vLocalPos); + } return Fragment(color); } #endif diff --git a/webrender/res/brush_yuv_image.glsl b/webrender/res/brush_yuv_image.glsl index 5f38545964..25858366b8 100644 --- a/webrender/res/brush_yuv_image.glsl +++ b/webrender/res/brush_yuv_image.glsl @@ -18,9 +18,7 @@ #define YUV_FORMAT_PLANAR 1 #define YUV_FORMAT_INTERLEAVED 2 -#ifdef WR_FEATURE_ALPHA_PASS varying vec2 vLocalPos; -#endif varying vec3 vUv_Y; flat varying vec4 vUvBounds_Y; @@ -128,9 +126,9 @@ void brush_vs( } vFormat = prim.yuv_format; -#ifdef WR_FEATURE_ALPHA_PASS - vLocalPos = vi.local_pos; -#endif + if (alpha_pass) { + vLocalPos = vi.local_pos; + } if (vFormat == YUV_FORMAT_PLANAR) { write_uv_rect(user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y); @@ -177,9 +175,9 @@ Fragment brush_fs() { vec3 rgb = vYuvColorMatrix * (yuv_value * vCoefficient - vec3(0.06275, 0.50196, 0.50196)); vec4 color = vec4(rgb, 1.0); -#ifdef WR_FEATURE_ALPHA_PASS - color *= init_transform_fs(vLocalPos); -#endif + if (alpha_pass) { + color *= init_transform_fs(vLocalPos); + } return Fragment(color); } diff --git a/webrender/res/clip_shared.glsl b/webrender/res/clip_shared.glsl index 3f3abb3492..715f76007c 100644 --- a/webrender/res/clip_shared.glsl +++ b/webrender/res/clip_shared.glsl @@ -9,7 +9,6 @@ in int aClipRenderTaskAddress; in int aClipTransformId; in int aPrimTransformId; -in int aClipSegment; in ivec4 aClipDataResourceAddress; in vec2 aClipLocalPos; in vec4 aClipTileRect; diff --git a/webrender/res/cs_blur.glsl b/webrender/res/cs_blur.glsl index 34792afd24..83ac2648af 100644 --- a/webrender/res/cs_blur.glsl +++ b/webrender/res/cs_blur.glsl @@ -45,11 +45,13 @@ void main(void) { RectWithSize src_rect = src_task.task_rect; RectWithSize target_rect = blur_task.common_data.task_rect; -#if defined WR_FEATURE_COLOR_TARGET - vec2 texture_size = vec2(textureSize(sPrevPassColor, 0).xy); -#else - vec2 texture_size = vec2(textureSize(sPrevPassAlpha, 0).xy); -#endif + vec2 texture_size; + if (color_target) { + texture_size = vec2(textureSize(sPrevPassColor, 0).xy); + } else { + texture_size = vec2(textureSize(sPrevPassAlpha, 0).xy); + } + vUv.z = src_task.texture_layer_index; vSigma = blur_task.blur_radius; @@ -100,63 +102,124 @@ void main(void) { // loop iteration count! void main(void) { - SAMPLE_TYPE original_color = SAMPLE_TEXTURE(vUv); - - // TODO(gw): The gauss function gets NaNs when blur radius - // is zero. In the future, detect this earlier - // and skip the blur passes completely. - if (vSupport == 0) { - oFragColor = vec4(original_color); - return; - } - - // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889) - vec3 gauss_coefficient; - gauss_coefficient.x = 1.0 / (sqrt(2.0 * 3.14159265) * vSigma); - gauss_coefficient.y = exp(-0.5 / (vSigma * vSigma)); - gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y; - - float gauss_coefficient_total = gauss_coefficient.x; - SAMPLE_TYPE avg_color = original_color * gauss_coefficient.x; - gauss_coefficient.xy *= gauss_coefficient.yz; - - // Evaluate two adjacent texels at a time. We can do this because, if c0 - // and c1 are colors of adjacent texels and k0 and k1 are arbitrary - // factors, this formula: - // - // k0 * c0 + k1 * c1 (Equation 1) - // - // is equivalent to: - // - // k1 - // (k0 + k1) * lerp(c0, c1, -------) - // k0 + k1 - // - // A texture lookup of adjacent texels evaluates this formula: - // - // lerp(c0, c1, t) - // - // for some t. So we can let `t = k1/(k0 + k1)` and effectively evaluate - // Equation 1 with a single texture lookup. - - for (int i = 1; i <= vSupport; i += 2) { - float gauss_coefficient_subtotal = gauss_coefficient.x; + if (color_target) { + vec4 original_color = texture(sPrevPassColor, vUv); + + // TODO(gw): The gauss function gets NaNs when blur radius + // is zero. In the future, detect this earlier + // and skip the blur passes completely. + if (vSupport == 0) { + oFragColor = vec4(original_color); + return; + } + + // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889) + vec3 gauss_coefficient; + gauss_coefficient.x = 1.0 / (sqrt(2.0 * 3.14159265) * vSigma); + gauss_coefficient.y = exp(-0.5 / (vSigma * vSigma)); + gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y; + + float gauss_coefficient_total = gauss_coefficient.x; + vec4 avg_color = original_color * gauss_coefficient.x; gauss_coefficient.xy *= gauss_coefficient.yz; - gauss_coefficient_subtotal += gauss_coefficient.x; - float gauss_ratio = gauss_coefficient.x / gauss_coefficient_subtotal; - vec2 offset = vOffsetScale * (float(i) + gauss_ratio); - - vec2 st0 = clamp(vUv.xy - offset, vUvRect.xy, vUvRect.zw); - avg_color += SAMPLE_TEXTURE(vec3(st0, vUv.z)) * gauss_coefficient_subtotal; - - vec2 st1 = clamp(vUv.xy + offset, vUvRect.xy, vUvRect.zw); - avg_color += SAMPLE_TEXTURE(vec3(st1, vUv.z)) * gauss_coefficient_subtotal; - - gauss_coefficient_total += 2.0 * gauss_coefficient_subtotal; + // Evaluate two adjacent texels at a time. We can do this because, if c0 + // and c1 are colors of adjacent texels and k0 and k1 are arbitrary + // factors, this formula: + // + // k0 * c0 + k1 * c1 (Equation 1) + // + // is equivalent to: + // + // k1 + // (k0 + k1) * lerp(c0, c1, -------) + // k0 + k1 + // + // A texture lookup of adjacent texels evaluates this formula: + // + // lerp(c0, c1, t) + // + // for some t. So we can let `t = k1/(k0 + k1)` and effectively evaluate + // Equation 1 with a single texture lookup. + + for (int i = 1; i <= vSupport; i += 2) { + float gauss_coefficient_subtotal = gauss_coefficient.x; + gauss_coefficient.xy *= gauss_coefficient.yz; + gauss_coefficient_subtotal += gauss_coefficient.x; + float gauss_ratio = gauss_coefficient.x / gauss_coefficient_subtotal; + + vec2 offset = vOffsetScale * (float(i) + gauss_ratio); + + vec2 st0 = clamp(vUv.xy - offset, vUvRect.xy, vUvRect.zw); + avg_color += texture(sPrevPassColor, vec3(st0, vUv.z)) * gauss_coefficient_subtotal; + + vec2 st1 = clamp(vUv.xy + offset, vUvRect.xy, vUvRect.zw); + avg_color += texture(sPrevPassColor, vec3(st1, vUv.z)) * gauss_coefficient_subtotal; + + gauss_coefficient_total += 2.0 * gauss_coefficient_subtotal; + gauss_coefficient.xy *= gauss_coefficient.yz; + } + + oFragColor = vec4(avg_color) / gauss_coefficient_total; + } else { + float original_color = texture(sPrevPassAlpha, vUv).r; + + // TODO(gw): The gauss function gets NaNs when blur radius + // is zero. In the future, detect this earlier + // and skip the blur passes completely. + if (vSupport == 0) { + oFragColor = vec4(original_color); + return; + } + + // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889) + vec3 gauss_coefficient; + gauss_coefficient.x = 1.0 / (sqrt(2.0 * 3.14159265) * vSigma); + gauss_coefficient.y = exp(-0.5 / (vSigma * vSigma)); + gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y; + + float gauss_coefficient_total = gauss_coefficient.x; + float avg_color = original_color * gauss_coefficient.x; gauss_coefficient.xy *= gauss_coefficient.yz; - } - oFragColor = vec4(avg_color) / gauss_coefficient_total; + // Evaluate two adjacent texels at a time. We can do this because, if c0 + // and c1 are colors of adjacent texels and k0 and k1 are arbitrary + // factors, this formula: + // + // k0 * c0 + k1 * c1 (Equation 1) + // + // is equivalent to: + // + // k1 + // (k0 + k1) * lerp(c0, c1, -------) + // k0 + k1 + // + // A texture lookup of adjacent texels evaluates this formula: + // + // lerp(c0, c1, t) + // + // for some t. So we can let `t = k1/(k0 + k1)` and effectively evaluate + // Equation 1 with a single texture lookup. + + for (int i = 1; i <= vSupport; i += 2) { + float gauss_coefficient_subtotal = gauss_coefficient.x; + gauss_coefficient.xy *= gauss_coefficient.yz; + gauss_coefficient_subtotal += gauss_coefficient.x; + float gauss_ratio = gauss_coefficient.x / gauss_coefficient_subtotal; + + vec2 offset = vOffsetScale * (float(i) + gauss_ratio); + + vec2 st0 = clamp(vUv.xy - offset, vUvRect.xy, vUvRect.zw); + avg_color += texture(sPrevPassAlpha, vec3(st0, vUv.z)).r * gauss_coefficient_subtotal; + + vec2 st1 = clamp(vUv.xy + offset, vUvRect.xy, vUvRect.zw); + avg_color += texture(sPrevPassAlpha, vec3(st1, vUv.z)).r * gauss_coefficient_subtotal; + + gauss_coefficient_total += 2.0 * gauss_coefficient_subtotal; + gauss_coefficient.xy *= gauss_coefficient.yz; + } + + oFragColor = vec4(avg_color) / gauss_coefficient_total; + } } #endif diff --git a/webrender/res/cs_border_segment.glsl b/webrender/res/cs_border_segment.glsl index 8382528c21..e8d002c15a 100644 --- a/webrender/res/cs_border_segment.glsl +++ b/webrender/res/cs_border_segment.glsl @@ -182,6 +182,8 @@ void main(void) { edge_reference = vec2(outer.x, outer.y - aWidths.y); break; case SEGMENT_TOP: + edge_axis = ivec2(1, 1); + break; case SEGMENT_BOTTOM: edge_axis = ivec2(1, 1); break; @@ -273,7 +275,26 @@ vec4 evaluate_color_for_style_in_corner( color0 *= distance_aa(aa_range, d); break; } - case BORDER_STYLE_GROOVE: + case BORDER_STYLE_GROOVE: { + float d = distance_to_ellipse( + clip_relative_pos, + clip_radii.xy - vPartialWidths.zw, + aa_range + ); + float alpha = distance_aa(aa_range, d); + float swizzled_factor; + switch (segment) { + case SEGMENT_TOP_LEFT: swizzled_factor = 0.0; break; + case SEGMENT_TOP_RIGHT: swizzled_factor = mix_factor; break; + case SEGMENT_BOTTOM_RIGHT: swizzled_factor = 1.0; break; + case SEGMENT_BOTTOM_LEFT: swizzled_factor = 1.0 - mix_factor; break; + default: swizzled_factor = 0.0; break; + }; + vec4 c0 = mix(color1, color0, swizzled_factor); + vec4 c1 = mix(color0, color1, swizzled_factor); + color0 = mix(c0, c1, alpha); + break; + } case BORDER_STYLE_RIDGE: { float d = distance_to_ellipse( clip_relative_pos, @@ -325,7 +346,13 @@ vec4 evaluate_color_for_style_in_edge( color0 *= distance_aa(aa_range, d); break; } - case BORDER_STYLE_GROOVE: + case BORDER_STYLE_GROOVE: { + float ref = dot(vEdgeReference.xy + vPartialWidths.zw, edge_axis); + float d = pos - ref; + float alpha = distance_aa(aa_range, d); + color0 = mix(color0, color1, alpha); + break; + } case BORDER_STYLE_RIDGE: { float ref = dot(vEdgeReference.xy + vPartialWidths.zw, edge_axis); float d = pos - ref; diff --git a/webrender/res/cs_border_solid.glsl b/webrender/res/cs_border_solid.glsl index 17067aed96..880b4a6c94 100644 --- a/webrender/res/cs_border_solid.glsl +++ b/webrender/res/cs_border_solid.glsl @@ -46,6 +46,8 @@ in vec4 aColor1; in int aFlags; in vec2 aWidths; in vec2 aRadii; +in vec4 aClipParams1; +in vec4 aClipParams2; vec2 get_outer_corner_scale(int segment) { vec2 p; @@ -83,8 +85,14 @@ void main(void) { int mix_colors; switch (segment) { case SEGMENT_TOP_LEFT: + mix_colors = do_aa ? MIX_AA : MIX_NO_AA; + break; case SEGMENT_TOP_RIGHT: + mix_colors = do_aa ? MIX_AA : MIX_NO_AA; + break; case SEGMENT_BOTTOM_RIGHT: + mix_colors = do_aa ? MIX_AA : MIX_NO_AA; + break; case SEGMENT_BOTTOM_LEFT: mix_colors = do_aa ? MIX_AA : MIX_NO_AA; break; diff --git a/webrender/res/cs_clip_box_shadow.glsl b/webrender/res/cs_clip_box_shadow.glsl index c90989cffc..ed022c9ecc 100644 --- a/webrender/res/cs_clip_box_shadow.glsl +++ b/webrender/res/cs_clip_box_shadow.glsl @@ -73,7 +73,11 @@ void main(void) { vUv.x = (local_pos.x - dest_rect.p0.x) / bs_data.src_rect_size.x; break; } - case MODE_SIMPLE: + case MODE_SIMPLE: { + vEdge.xz = vec2(1.0); + vUv.x = (local_pos.x - dest_rect.p0.x) / dest_rect.size.x; + break; + } default: { vEdge.xz = vec2(1.0); vUv.x = (local_pos.x - dest_rect.p0.x) / dest_rect.size.x; @@ -88,7 +92,11 @@ void main(void) { vUv.y = (local_pos.y - dest_rect.p0.y) / bs_data.src_rect_size.y; break; } - case MODE_SIMPLE: + case MODE_SIMPLE: { + vEdge.yw = vec2(1.0); + vUv.y = (local_pos.y - dest_rect.p0.y) / dest_rect.size.y; + break; + } default: { vEdge.yw = vec2(1.0); vUv.y = (local_pos.y - dest_rect.p0.y) / dest_rect.size.y; diff --git a/webrender/res/cs_scale.glsl b/webrender/res/cs_scale.glsl index 03d9f96be3..05236fc061 100644 --- a/webrender/res/cs_scale.glsl +++ b/webrender/res/cs_scale.glsl @@ -31,11 +31,12 @@ void main(void) { RectWithSize src_rect = src_task.task_rect; RectWithSize target_rect = scale_task.common_data.task_rect; -#if defined WR_FEATURE_COLOR_TARGET - vec2 texture_size = vec2(textureSize(sPrevPassColor, 0).xy); -#else - vec2 texture_size = vec2(textureSize(sPrevPassAlpha, 0).xy); -#endif + vec2 texture_size; + if (color_target) { + texture_size = vec2(textureSize(sPrevPassColor, 0).xy); + } else { + texture_size = vec2(textureSize(sPrevPassAlpha, 0).xy); + } vUv.z = src_task.texture_layer_index; @@ -52,17 +53,13 @@ void main(void) { #ifdef WR_FRAGMENT_SHADER -#if defined WR_FEATURE_COLOR_TARGET -#define SAMPLE_TYPE vec4 -#define SAMPLE_TEXTURE(uv) texture(sPrevPassColor, uv) -#else -#define SAMPLE_TYPE float -#define SAMPLE_TEXTURE(uv) texture(sPrevPassAlpha, uv).r -#endif - void main(void) { vec2 st = clamp(vUv.xy, vUvRect.xy, vUvRect.zw); - oFragColor = vec4(SAMPLE_TEXTURE(vec3(st, vUv.z))); + if (color_target) { + oFragColor = vec4(texture(sPrevPassColor, vec3(st, vUv.z))); + } else { + oFragColor = vec4(texture(sPrevPassAlpha, vec3(st, vUv.z)).r); + } } #endif diff --git a/webrender/res/gpu_cache_gfx.glsl b/webrender/res/gpu_cache_gfx.glsl new file mode 100644 index 0000000000..bc35745c85 --- /dev/null +++ b/webrender/res/gpu_cache_gfx.glsl @@ -0,0 +1,136 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +layout(set = 1, binding = 5, std430)readonly buffer sGpuCache +{ + vec4 gpu_cache[]; +}; + +#define VECS_PER_IMAGE_RESOURCE 2 + + + +int get_gpu_cache_address(ivec2 address) { + return int(address.y * WR_MAX_VERTEX_TEXTURE_WIDTH + address.x); +} + +// TODO(zakorgy): Until we need to adopt to the GL shaders we need these helper `fetch_from_xxx` functions. +// Later we can leave these methods and acces `gpu_cache` directly using the address as index. + +vec4[2] fetch_from_gpu_cache_2_direct(ivec2 addr) { + int address = get_gpu_cache_address(addr); + return vec4[2]( + gpu_cache[address], + gpu_cache[address + 1] + ); +} + +vec4[2] fetch_from_gpu_cache_2(int address) { + return vec4[2]( + gpu_cache[address], + gpu_cache[address + 1] + ); +} + +#ifdef WR_VERTEX_SHADER + +vec4[8] fetch_from_gpu_cache_8(int address) { + return vec4[8]( + gpu_cache[address], + gpu_cache[address + 1], + gpu_cache[address + 2], + gpu_cache[address + 3], + gpu_cache[address + 4], + gpu_cache[address + 5], + gpu_cache[address + 6], + gpu_cache[address + 7] + ); +} + +vec4[3] fetch_from_gpu_cache_3(int address) { + return vec4[3]( + gpu_cache[address], + gpu_cache[address + 1], + gpu_cache[address + 2] + ); +} + +vec4[3] fetch_from_gpu_cache_3_direct(ivec2 addr) { + int address = get_gpu_cache_address(addr); + return vec4[3]( + gpu_cache[address], + gpu_cache[address + 1], + gpu_cache[address + 2] + ); +} + +vec4[4] fetch_from_gpu_cache_4_direct(ivec2 addr) { + int address = get_gpu_cache_address(addr); + return vec4[4]( + gpu_cache[address], + gpu_cache[address + 1], + gpu_cache[address + 2], + gpu_cache[address + 3] + ); +} + +vec4[4] fetch_from_gpu_cache_4(int address) { + return vec4[4]( + gpu_cache[address], + gpu_cache[address + 1], + gpu_cache[address + 2], + gpu_cache[address + 3] + ); +} + +vec4 fetch_from_gpu_cache_1_direct(ivec2 addr) { + int address = get_gpu_cache_address(addr); + return gpu_cache[address]; +} + +vec4 fetch_from_gpu_cache_1(int address) { + return gpu_cache[address]; +} + +//TODO: image resource is too specific for this module + +struct ImageResource { + RectWithEndpoint uv_rect; + float layer; + vec3 user_data; +}; + +ImageResource fetch_image_resource(int address) { + //Note: number of blocks has to match `renderer::BLOCKS_PER_UV_RECT` + vec4 data[2] = fetch_from_gpu_cache_2(address); + RectWithEndpoint uv_rect = RectWithEndpoint(data[0].xy, data[0].zw); + return ImageResource(uv_rect, data[1].x, data[1].yzw); +} + +ImageResource fetch_image_resource_direct(ivec2 address) { + vec4 data[2] = fetch_from_gpu_cache_2_direct(address); + RectWithEndpoint uv_rect = RectWithEndpoint(data[0].xy, data[0].zw); + return ImageResource(uv_rect, data[1].x, data[1].yzw); +} + +// Fetch optional extra data for a texture cache resource. This can contain +// a polygon defining a UV rect within the texture cache resource. +struct ImageResourceExtra { + vec2 st_tl; + vec2 st_tr; + vec2 st_bl; + vec2 st_br; +}; + +ImageResourceExtra fetch_image_resource_extra(int address) { + vec4 data[2] = fetch_from_gpu_cache_2(address + VECS_PER_IMAGE_RESOURCE); + return ImageResourceExtra( + data[0].xy, + data[0].zw, + data[1].xy, + data[1].zw + ); +} + +#endif //WR_VERTEX_SHADER diff --git a/webrender/res/mem_config.ron b/webrender/res/mem_config.ron new file mode 100644 index 0000000000..7240ba34ae --- /dev/null +++ b/webrender/res/mem_config.ron @@ -0,0 +1,10 @@ +( + linear: Some(( + linear_size: 134217728, // 128 MB + )), + dynamic: Some(( + min_device_allocation: 1048576, // 1 MB + block_size_granularity: 256, + max_chunk_size: 16777216, // 16 MB + )), +) diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index 22ab931115..f30c9b9f5b 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -248,21 +248,19 @@ float do_clip() { return texelFetch(sPrevPassAlpha, tc, 0).r; } -#ifdef WR_FEATURE_DITHERING vec4 dither(vec4 color) { - const int matrix_mask = 7; + if (dithering) { + const int matrix_mask = 7; - ivec2 pos = ivec2(gl_FragCoord.xy) & ivec2(matrix_mask); - float noise_normalized = (texelFetch(sDither, pos, 0).r * 255.0 + 0.5) / 64.0; - float noise = (noise_normalized - 0.5) / 256.0; // scale down to the unit length + ivec2 pos = ivec2(gl_FragCoord.xy) & ivec2(matrix_mask); + float noise_normalized = (texelFetch(sDither, pos, 0).r * 255.0 + 0.5) / 64.0; + float noise = (noise_normalized - 0.5) / 256.0; // scale down to the unit length - return color + vec4(noise, noise, noise, 0); -} -#else -vec4 dither(vec4 color) { - return color; + return color + vec4(noise, noise, noise, 0); + } else { + return color; + } } -#endif //WR_FEATURE_DITHERING vec4 sample_gradient(int address, float offset, float gradient_repeat) { // Modulo the offset if the gradient repeats. diff --git a/webrender/res/ps_split_composite.glsl b/webrender/res/ps_split_composite.glsl index d3db7e9713..2db00837bd 100644 --- a/webrender/res/ps_split_composite.glsl +++ b/webrender/res/ps_split_composite.glsl @@ -4,7 +4,10 @@ #include shared,prim_shared -varying vec3 vUv; +// interpolated UV coordinates to sample. +varying vec2 vUv; +// X = layer index to sample, Y = flag to allow perspective interpolation of UV. +flat varying vec2 vLayerAndPerspective; flat varying vec4 vUvSampleBounds; #ifdef WR_VERTEX_SHADER @@ -13,17 +16,14 @@ struct SplitGeometry { }; SplitGeometry fetch_split_geometry(int address) { - ivec2 uv = get_gpu_cache_uv(address); - - vec4 data0 = TEXEL_FETCH(sGpuCache, uv, 0, ivec2(0, 0)); - vec4 data1 = TEXEL_FETCH(sGpuCache, uv, 0, ivec2(1, 0)); + vec4[2] data = fetch_from_gpu_cache_2(address); SplitGeometry geo; geo.local = vec2[4]( - data0.xy, - data0.zw, - data1.xy, - data1.zw + data[0].xy, + data[0].zw, + data[1].xy, + data[1].zw ); return geo; @@ -103,15 +103,18 @@ void main(void) { f.y, f.x ); vec2 uv = mix(uv0, uv1, f); + float perspective_interpolate = float(ph.user_data.y); - vUv = vec3(uv / texture_size, res.layer); + vUv = uv / texture_size * mix(gl_Position.w, 1.0, perspective_interpolate); + vLayerAndPerspective = vec2(res.layer, perspective_interpolate); } #endif #ifdef WR_FRAGMENT_SHADER void main(void) { float alpha = do_clip(); - vec2 uv = clamp(vUv.xy, vUvSampleBounds.xy, vUvSampleBounds.zw); - oFragColor = alpha * textureLod(sPrevPassColor, vec3(uv, vUv.z), 0.0); + float perspective_divisor = mix(gl_FragCoord.w, 1.0, vLayerAndPerspective.y); + vec2 uv = clamp(vUv * perspective_divisor, vUvSampleBounds.xy, vUvSampleBounds.zw); + oFragColor = alpha * textureLod(sPrevPassColor, vec3(uv, vLayerAndPerspective.x), 0.0); } #endif diff --git a/webrender/res/ps_text_run.glsl b/webrender/res/ps_text_run.glsl index 413aebe032..2d91db388f 100644 --- a/webrender/res/ps_text_run.glsl +++ b/webrender/res/ps_text_run.glsl @@ -9,9 +9,7 @@ varying vec3 vUv; flat varying vec4 vUvBorder; flat varying vec2 vMaskSwizzle; -#ifdef WR_FEATURE_GLYPH_TRANSFORM varying vec4 vUvClip; -#endif #ifdef WR_VERTEX_SHADER @@ -62,6 +60,7 @@ TextRun fetch_text_run(int address) { VertexInfo write_text_vertex(RectWithSize local_clip_rect, float z, + int raster_space, Transform transform, PictureTask task, vec2 text_offset, @@ -72,46 +71,63 @@ VertexInfo write_text_vertex(RectWithSize local_clip_rect, vec2 snap_offset = vec2(0.0); mat2 local_transform; -#ifdef WR_FEATURE_GLYPH_TRANSFORM - bool remove_subpx_offset = true; -#else - bool remove_subpx_offset = transform.is_axis_aligned; -#endif + bool remove_subpx_offset; + if (glyph_transform_f) { + remove_subpx_offset = true; + } else { + remove_subpx_offset = transform.is_axis_aligned; + } + // Compute the snapping offset only if the scroll node transform is axis-aligned. if (remove_subpx_offset) { - // Transform from local space to device space. - float device_scale = task.common_data.device_pixel_scale / transform.m[3].w; - mat2 device_transform = mat2(transform.m) * device_scale; - - // Ensure the transformed text offset does not contain a subpixel translation - // such that glyph snapping is stable for equivalent glyph subpixel positions. - vec2 device_text_pos = device_transform * text_offset + transform.m[3].xy * device_scale; - snap_offset = floor(device_text_pos + 0.5) - device_text_pos; - - // Snap the glyph offset to a device pixel, using an appropriate bias depending - // on whether subpixel positioning is required. - vec2 device_glyph_offset = device_transform * glyph_offset; - snap_offset += floor(device_glyph_offset + snap_bias) - device_glyph_offset; - - // Transform from device space back to local space. - local_transform = inverse(device_transform); - -#ifndef WR_FEATURE_GLYPH_TRANSFORM - // If not using transformed subpixels, the glyph rect is actually in local space. - // So convert the snap offset back to local space. - snap_offset = local_transform * snap_offset; -#endif + // Be careful to only snap with the transform when in screen raster space. + switch (raster_space) { + case RASTER_SCREEN: { + // Transform from local space to device space. + float device_scale = task.common_data.device_pixel_scale / transform.m[3].w; + mat2 device_transform = mat2(transform.m) * device_scale; + + // Ensure the transformed text offset does not contain a subpixel translation + // such that glyph snapping is stable for equivalent glyph subpixel positions. + vec2 device_text_pos = device_transform * text_offset + transform.m[3].xy * device_scale; + snap_offset = floor(device_text_pos + 0.5) - device_text_pos; + + // Snap the glyph offset to a device pixel, using an appropriate bias depending + // on whether subpixel positioning is required. + vec2 device_glyph_offset = device_transform * glyph_offset; + snap_offset += floor(device_glyph_offset + snap_bias) - device_glyph_offset; + + // Transform from device space back to local space. + local_transform = inverse(device_transform); + + if (!glyph_transform_f) { + // If not using transformed subpixels, the glyph rect is actually in local space. + // So convert the snap offset back to local space. + snap_offset = local_transform * snap_offset; + } + break; + } + default: { + // Otherwise, when in local raster space, the transform may be animated, so avoid + // snapping with the transform to avoid oscillation. + snap_offset = floor(text_offset + 0.5) - text_offset; + snap_offset += floor(glyph_offset + snap_bias) - glyph_offset; + break; + } + } } // Actually translate the glyph rect to a device pixel using the snap offset. glyph_rect.p0 += snap_offset; -#ifdef WR_FEATURE_GLYPH_TRANSFORM + +vec2 local_pos = vec2(0.0); +if (glyph_transform_f) { // The glyph rect is in device space, so transform it back to local space. RectWithSize local_rect = transform_rect(glyph_rect, local_transform); // Select the corner of the glyph's local space rect that we are processing. - vec2 local_pos = local_rect.p0 + local_rect.size * aPosition.xy; + local_pos = local_rect.p0 + local_rect.size * aPosition.xy; // If the glyph's local rect would fit inside the local clip rect, then select a corner from // the device space glyph rect to reduce overdraw of clipped pixels in the fragment shader. @@ -119,10 +135,10 @@ VertexInfo write_text_vertex(RectWithSize local_clip_rect, if (rect_inside_rect(local_rect, local_clip_rect)) { local_pos = local_transform * (glyph_rect.p0 + glyph_rect.size * aPosition.xy); } -#else +} else { // Select the corner of the glyph rect that we are processing. - vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy; -#endif + local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy; +} // Clamp to the local clip rect. local_pos = clamp_rect(local_pos, local_clip_rect); @@ -153,6 +169,7 @@ void main(void) { int color_mode = aData.w & 0xffff; PrimitiveHeader ph = fetch_prim_header(prim_header_address); + int raster_space = ph.user_data.z; Transform transform = fetch_transform(ph.transform_id); ClipArea clip_area = fetch_clip_area(ph.clip_task_index); @@ -170,22 +187,23 @@ void main(void) { GlyphResource res = fetch_glyph_resource(resource_address); -#ifdef WR_FEATURE_GLYPH_TRANSFORM - // Transform from local space to glyph space. - mat2 glyph_transform = mat2(transform.m) * task.common_data.device_pixel_scale; - - // Compute the glyph rect in glyph space. - RectWithSize glyph_rect = RectWithSize(res.offset + glyph_transform * (text_offset + glyph.offset), - res.uv_rect.zw - res.uv_rect.xy); - -#else - // Scale from glyph space to local space. - float scale = res.scale / task.common_data.device_pixel_scale; - - // Compute the glyph rect in local space. - RectWithSize glyph_rect = RectWithSize(scale * res.offset + text_offset + glyph.offset, - scale * (res.uv_rect.zw - res.uv_rect.xy)); -#endif + mat2 glyph_transform = mat2(1.0); + RectWithSize glyph_rect; + if (glyph_transform_f) { + // Transform from local space to glyph space. + glyph_transform = mat2(transform.m) * task.common_data.device_pixel_scale; + + // Compute the glyph rect in glyph space. + glyph_rect = RectWithSize(res.offset + glyph_transform * (text_offset + glyph.offset), + res.uv_rect.zw - res.uv_rect.xy); + } else { + // Scale from glyph space to local space. + float scale = res.scale / task.common_data.device_pixel_scale; + + // Compute the glyph rect in local space. + glyph_rect = RectWithSize(scale * res.offset + text_offset + glyph.offset, + scale * (res.uv_rect.zw - res.uv_rect.xy)); + } vec2 snap_bias; // In subpixel mode, the subpixel offset has already been @@ -194,7 +212,6 @@ void main(void) { // to the nearest whole pixel, depending on subpixel direciton. switch (subpx_dir) { case SUBPX_DIR_NONE: - default: snap_bias = vec2(0.5); break; case SUBPX_DIR_HORIZONTAL: @@ -210,10 +227,14 @@ void main(void) { case SUBPX_DIR_MIXED: snap_bias = vec2(0.125); break; + default: + snap_bias = vec2(0.5); + break; } VertexInfo vi = write_text_vertex(ph.local_clip_rect, ph.z, + raster_space, transform, task, text_offset, @@ -222,28 +243,42 @@ void main(void) { snap_bias); glyph_rect.p0 += vi.snap_offset; -#ifdef WR_FEATURE_GLYPH_TRANSFORM - vec2 f = (glyph_transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size; - vUvClip = vec4(f, 1.0 - f); -#else - vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size; -#endif + vec2 f = vec2(0.0); + if (glyph_transform_f) { + f = (glyph_transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size; + vUvClip = vec4(f, 1.0 - f); + } else { + f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size; + vUvClip = vec4(0.0); + } write_clip(vi.world_pos, vi.snap_offset, clip_area); switch (color_mode) { case COLOR_MODE_ALPHA: + vMaskSwizzle = vec2(0.0, 1.0); + vColor = text.color; + break; case COLOR_MODE_BITMAP: vMaskSwizzle = vec2(0.0, 1.0); vColor = text.color; break; case COLOR_MODE_SUBPX_BG_PASS2: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = text.color; + break; case COLOR_MODE_SUBPX_DUAL_SOURCE: vMaskSwizzle = vec2(1.0, 0.0); vColor = text.color; break; case COLOR_MODE_SUBPX_CONST_COLOR: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = vec4(text.color.a); + break; case COLOR_MODE_SUBPX_BG_PASS0: + vMaskSwizzle = vec2(1.0, 0.0); + vColor = vec4(text.color.a); + break; case COLOR_MODE_COLOR_BITMAP: vMaskSwizzle = vec2(1.0, 0.0); vColor = vec4(text.color.a); @@ -273,18 +308,21 @@ void main(void) { mask.rgb = mask.rgb * vMaskSwizzle.x + mask.aaa * vMaskSwizzle.y; float alpha = do_clip(); -#ifdef WR_FEATURE_GLYPH_TRANSFORM - alpha *= float(all(greaterThanEqual(vUvClip, vec4(0.0)))); -#endif -#if defined(WR_FEATURE_DEBUG_OVERDRAW) - oFragColor = WR_DEBUG_OVERDRAW_COLOR; -#elif defined(WR_FEATURE_DUAL_SOURCE_BLENDING) - vec4 alpha_mask = mask * alpha; - oFragColor = vColor * alpha_mask; - oFragBlend = alpha_mask * vColor.a; -#else - oFragColor = vColor * mask * alpha; -#endif + if (glyph_transform_f) { + alpha *= float(all(greaterThanEqual(vUvClip, vec4(0.0)))); + } + + if (debug_overdraw) { + oFragColor = WR_DEBUG_OVERDRAW_COLOR; + } else { + #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING + vec4 alpha_mask = mask * alpha; + oFragColor = vColor * alpha_mask; + oFragBlend = alpha_mask * vColor.a; + #else + oFragColor = vColor * mask * alpha; + #endif + } } #endif diff --git a/webrender/res/shared.glsl b/webrender/res/shared.glsl index a60d355995..fbf0e89b0d 100644 --- a/webrender/res/shared.glsl +++ b/webrender/res/shared.glsl @@ -152,9 +152,7 @@ uniform sampler2DArray sColor1; uniform sampler2DArray sColor2; #endif -#ifdef WR_FEATURE_DITHERING uniform sampler2D sDither; -#endif //====================================================================================== // Interpolator definitions diff --git a/webrender/shaders.ron b/webrender/shaders.ron new file mode 100644 index 0000000000..872f776dca --- /dev/null +++ b/webrender/shaders.ron @@ -0,0 +1,143 @@ +[ + ( + name: "cs_scale", + source_name: "cs_scale", + features: [ + "",// [0] + ], + ),// [0] + ( + name: "cs_blur", + source_name: "cs_blur", + features: [ + "",// [0] + ], + ),// [1] + ( + name: "cs_border_segment", + source_name: "cs_border_segment", + features: [ + "",// [0] + ], + ),// [2] + ( + name: "cs_border_solid", + source_name: "cs_border_solid", + features: [ + "",// [0] + ], + ),// [3] + ( + name: "brush_solid", + source_name: "brush_solid", + features: [ + "",// [0] + ], + ),// [4] + ( + name: "brush_image", + source_name: "brush_image", + features: [ + "",// [0] + "TEXTURE_2D",// [1] + "TEXTURE_RECT",// [2] + "DUAL_SOURCE_BLENDING",// [3] + "TEXTURE_2D,DUAL_SOURCE_BLENDING",// [4] + "TEXTURE_RECT,DUAL_SOURCE_BLENDING",// [5] + ], + ),// [5] + ( + name: "brush_blend", + source_name: "brush_blend", + features: [ + "",// [0] + ], + ),// [6] + ( + name: "brush_mix_blend", + source_name: "brush_mix_blend", + features: [ + "",// [0] + ], + ),// [7] + ( + name: "brush_yuv_image", + source_name: "brush_yuv_image", + features: [ + "",// [0] + "TEXTURE_2D",// [1] + "TEXTURE_RECT",// [2] + ], + ),// [8] + ( + name: "brush_radial_gradient", + source_name: "brush_radial_gradient", + features: [ + "",// [0] + ], + ),// [9] + ( + name: "brush_linear_gradient", + source_name: "brush_linear_gradient", + features: [ + "",// [0] + ], + ),// [10] + ( + name: "cs_clip_rectangle", + source_name: "cs_clip_rectangle", + features: [ + "",// [0] + ], + ),// [11] + ( + name: "cs_clip_box_shadow", + source_name: "cs_clip_box_shadow", + features: [ + "",// [0] + ], + ),// [12] + ( + name: "cs_clip_image", + source_name: "cs_clip_image", + features: [ + "",// [0] + ], + ),// [13] + ( + name: "cs_line_decoration", + source_name: "cs_line_decoration", + features: [ + "",// [0] + ], + ),// [14] + ( + name: "ps_text_run", + source_name: "ps_text_run", + features: [ + "",// [0] + "DUAL_SOURCE_BLENDING",// [1] + ], + ),// [15] + ( + name: "ps_split_composite", + source_name: "ps_split_composite", + features: [ + "",// [0] + ], + ),// [16] + ( + name: "debug_color", + source_name: "debug_color", + features: [ + "",// [0] + ], + ),// [17] + ( + name: "debug_font", + source_name: "debug_font", + features: [ + "",// [0] + ], + ),// [18] +] diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index f1b2c9e841..effe230150 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -597,6 +597,8 @@ impl AlphaBatchBuilder { #[cfg(debug_assertions)] //TODO: why is this needed? debug_assert_eq!(prim_instance.prepared_frame_id, render_tasks.frame_id()); + let is_chased = prim_instance.is_chased(); + let transform_id = transforms .get_id( prim_instance.spatial_node_index, @@ -627,6 +629,12 @@ impl AlphaBatchBuilder { prim_common_data.prim_size, ); + if is_chased { + println!("\tbatch {:?} with clip {:?} and bound {:?}", + prim_rect, clip_task_address, bounding_rect); + } + + match prim_instance.kind { PrimitiveInstanceKind::Clear { data_handle } => { let prim_data = &ctx.data_stores.prim[data_handle]; @@ -842,7 +850,7 @@ impl AlphaBatchBuilder { [ (run.reference_frame_relative_offset.x * 256.0) as i32, (run.reference_frame_relative_offset.y * 256.0) as i32, - 0, + run.raster_space as i32, ], ); let key = BatchKey::new(kind, blend_mode, textures); @@ -972,7 +980,7 @@ impl AlphaBatchBuilder { let prim_instance = &picture.prim_list.prim_instances[child.anchor]; let prim_info = &ctx.scratch.prim_info[prim_instance.visibility_info.0 as usize]; - let pic_index = match prim_instance.kind { + let child_pic_index = match prim_instance.kind { PrimitiveInstanceKind::Picture { pic_index, .. } => pic_index, PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::TextRun { .. } | @@ -987,7 +995,7 @@ impl AlphaBatchBuilder { unreachable!(); } }; - let pic = &ctx.prim_store.pictures[pic_index.0]; + let pic = &ctx.prim_store.pictures[child_pic_index.0]; // Get clip task, if set, for the picture primitive. @@ -1007,13 +1015,12 @@ impl AlphaBatchBuilder { transform_id: child.transform_id, }; - let surface_index = pic + let raster_config = pic .raster_config .as_ref() - .expect("BUG: 3d primitive was not assigned a surface") - .surface_index; + .expect("BUG: 3d primitive was not assigned a surface"); let (uv_rect_address, _) = ctx - .surfaces[surface_index.0] + .surfaces[raster_config.surface_index.0] .surface .as_ref() .expect("BUG: no surface") @@ -1025,7 +1032,7 @@ impl AlphaBatchBuilder { let prim_header_index = prim_headers.push(&prim_header, z_id, [ uv_rect_address.as_int(), - 0, + if raster_config.establishes_raster_root { 1 } else { 0 }, 0, ]); @@ -1058,6 +1065,14 @@ impl AlphaBatchBuilder { match picture.raster_config { Some(ref raster_config) => { + // If the child picture was rendered in local space, we can safely + // interpolate the UV coordinates with perspective correction. + let brush_flags = if raster_config.establishes_raster_root { + BrushFlags::PERSPECTIVE_INTERPOLATION + } else { + BrushFlags::empty() + }; + match raster_config.composite_mode { PictureCompositeMode::TileCache { .. } => { // Construct a local clip rect that ensures we only draw pixels where @@ -1119,7 +1134,7 @@ impl AlphaBatchBuilder { clip_task_address, segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::empty(), - brush_flags: BrushFlags::empty(), + brush_flags, user_data: uv_rect_address, }; @@ -1223,7 +1238,7 @@ impl AlphaBatchBuilder { prim_header_index, segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::empty(), - brush_flags: BrushFlags::empty(), + brush_flags, clip_task_address, user_data: uv_rect_address.as_int(), }; @@ -1303,7 +1318,7 @@ impl AlphaBatchBuilder { clip_task_address, segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::empty(), - brush_flags: BrushFlags::empty(), + brush_flags, user_data: shadow_uv_rect_address, }; @@ -1312,7 +1327,7 @@ impl AlphaBatchBuilder { clip_task_address, segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::empty(), - brush_flags: BrushFlags::empty(), + brush_flags, user_data: content_uv_rect_address, }; @@ -1397,7 +1412,7 @@ impl AlphaBatchBuilder { clip_task_address, segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::empty(), - brush_flags: BrushFlags::empty(), + brush_flags, user_data: 0, }; @@ -1442,7 +1457,7 @@ impl AlphaBatchBuilder { clip_task_address, segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::empty(), - brush_flags: BrushFlags::empty(), + brush_flags, user_data: 0, }; @@ -1482,7 +1497,7 @@ impl AlphaBatchBuilder { clip_task_address, segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::empty(), - brush_flags: BrushFlags::empty(), + brush_flags, user_data: uv_rect_address, }; diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index 6f18627f45..c4624c9868 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -176,8 +176,8 @@ impl From for ClipNode { } } -// Flags that are attached to instances of clip nodes. bitflags! { + /// Flags that are attached to instances of clip nodes. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(MallocSizeOf)] diff --git a/webrender/src/clip_scroll_tree.rs b/webrender/src/clip_scroll_tree.rs index cb3ccec74c..64f8715fb5 100644 --- a/webrender/src/clip_scroll_tree.rs +++ b/webrender/src/clip_scroll_tree.rs @@ -309,12 +309,13 @@ impl ClipScrollTree { self.nodes_to_update.push((root_node_index, state)); while let Some((node_index, mut state)) = self.nodes_to_update.pop() { - let node = match self.spatial_nodes.get_mut(node_index.0 as usize) { + let (previous, following) = self.spatial_nodes.split_at_mut(node_index.0 as usize); + let node = match following.get_mut(0) { Some(node) => node, None => continue, }; - node.update(&mut state, &mut self.coord_systems, scene_properties); + node.update(&mut state, &mut self.coord_systems, scene_properties, &*previous); if let Some(ref mut palette) = transform_palette { node.push_gpu_data(palette, node_index); } @@ -526,7 +527,7 @@ fn add_reference_frame( parent, TransformStyle::Preserve3D, PropertyBinding::Value(transform), - ReferenceFrameKind::Perspective, + ReferenceFrameKind::Transform, origin_in_parent_reference_frame, PipelineId::dummy(), ) diff --git a/webrender/src/debug_render.rs b/webrender/src/debug_render.rs index e72494abd1..4d47b12bfd 100644 --- a/webrender/src/debug_render.rs +++ b/webrender/src/debug_render.rs @@ -5,12 +5,21 @@ use api::{ColorU, ColorF, ImageFormat, TextureTarget}; use api::{DeviceIntRect, DeviceRect, DevicePoint, DeviceSize, DeviceIntSize}; use debug_font_data; -use device::{Device, Program, Texture, TextureSlot, VertexDescriptor, ShaderError, VAO}; +use device::{create_projection, Device, Texture, TextureSlot, VertexDescriptor, ShaderError, VAO}; use device::{TextureFilter, VertexAttribute, VertexAttributeKind, VertexUsageHint}; -use euclid::{Point2D, Rect, Size2D, Transform3D}; -use internal_types::{ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE}; +use euclid::{Point2D, Rect, Size2D}; +use hal; use std::f32; +cfg_if! { + if #[cfg(feature = "gleam")] { + use device::Program; + } else { + use device::{PrimitiveType, ProgramId as Program, ShaderKind}; + use device::vertex_types; + } +} + #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum DebugItem { @@ -75,7 +84,67 @@ const DESC_COLOR: VertexDescriptor = VertexDescriptor { instance_attributes: &[], }; +#[cfg(not(feature = "gleam"))] +impl PrimitiveType for DebugColorVertex { + type Primitive = vertex_types::DebugColorVertex; + fn to_primitive_type(&self) -> vertex_types::DebugColorVertex { + vertex_types::DebugColorVertex { + aPosition: [self.x, self.y, 0.0], + aColor: ColorF::from(self.color).to_array(), + } + } +} + +#[cfg(not(feature = "gleam"))] +impl PrimitiveType for DebugFontVertex { + type Primitive = vertex_types::DebugFontVertex; + fn to_primitive_type(&self) -> vertex_types::DebugFontVertex { + vertex_types::DebugFontVertex { + aPosition: [self.x, self.y, 0.0], + aColor: ColorF::from(self.color).to_array(), + aColorTexCoord: [self.u, self.v], + } + } +} + +#[cfg(not(feature = "gleam"))] +fn create_debug_programs(device: &mut Device)-> Result<(Program, Program), ShaderError> { + let font_program = + device.create_program( + "debug_font", + &ShaderKind::DebugFont, + &[], + )?; + + let color_program = device + .create_program( + "debug_color", + &ShaderKind::DebugColor, + &[], + )?; + Ok((font_program, color_program)) +} + +#[cfg(feature = "gleam")] +fn create_debug_programs(device: &mut Device)-> Result<(Program, Program), ShaderError> { + let font_program = device.create_program_linked( + "debug_font", + String::new(), + &DESC_FONT, + )?; + device.bind_program(&font_program); + device.bind_shader_samplers(&font_program, &[("sColor0", DebugSampler::Font)]); + + let color_program = device.create_program_linked( + "debug_color", + String::new(), + &DESC_COLOR, + )?; + Ok((font_program, color_program)) +} + #[repr(C)] +#[derive(Copy, Clone)] pub struct DebugFontVertex { pub x: f32, pub y: f32, @@ -91,6 +160,7 @@ impl DebugFontVertex { } #[repr(C)] +#[derive(Copy, Clone)] pub struct DebugColorVertex { pub x: f32, pub y: f32, @@ -119,20 +189,8 @@ pub struct DebugRenderer { } impl DebugRenderer { - pub fn new(device: &mut Device) -> Result { - let font_program = device.create_program_linked( - "debug_font", - String::new(), - &DESC_FONT, - )?; - device.bind_program(&font_program); - device.bind_shader_samplers(&font_program, &[("sColor0", DebugSampler::Font)]); - - let color_program = device.create_program_linked( - "debug_color", - String::new(), - &DESC_COLOR, - )?; + pub fn new(device: &mut Device) -> Result { + let (font_program, color_program) = create_debug_programs(device)?; let font_vao = device.create_vao(&DESC_FONT); let line_vao = device.create_vao(&DESC_COLOR); @@ -167,7 +225,7 @@ impl DebugRenderer { }) } - pub fn deinit(self, device: &mut Device) { + pub fn deinit(self, device: &mut Device) { device.delete_texture(self.font_texture); device.delete_program(self.font_program); device.delete_program(self.color_program); @@ -309,9 +367,9 @@ impl DebugRenderer { self.add_line(p0.x, p1.y, color, p0.x, p0.y, color); } - pub fn render( + pub fn render( &mut self, - device: &mut Device, + device: &mut Device, viewport_size: Option, ) { if let Some(viewport_size) = viewport_size { @@ -319,15 +377,17 @@ impl DebugRenderer { device.set_blend(true); device.set_blend_mode_premultiplied_alpha(); - let projection = Transform3D::ortho( + let projection = create_projection( 0.0, viewport_size.width as f32, viewport_size.height as f32, 0.0, - ORTHO_NEAR_PLANE, - ORTHO_FAR_PLANE, + true, ); + #[cfg(not(feature = "gleam"))] + device.begin_render_pass(true, false); + // Triangles if !self.tri_vertices.is_empty() { device.bind_program(&self.color_program); @@ -369,6 +429,9 @@ impl DebugRenderer { ); device.draw_triangles_u32(0, self.font_indices.len() as i32); } + + #[cfg(not(feature = "gleam"))] + device.end_render_pass(); } self.font_indices.clear(); diff --git a/webrender/src/device/gfx/blend_state.rs b/webrender/src/device/gfx/blend_state.rs new file mode 100644 index 0000000000..89317b4408 --- /dev/null +++ b/webrender/src/device/gfx/blend_state.rs @@ -0,0 +1,132 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use hal::pso::{BlendOp, BlendState, Factor}; + +pub(super) const ALPHA: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::SrcAlpha, + dst: Factor::OneMinusSrcAlpha, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::One, + }, +}; + +pub(super) const PREMULTIPLIED_DEST_OUT: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::Zero, + dst: Factor::OneMinusSrcAlpha, + }, + alpha: BlendOp::Add { + src: Factor::Zero, + dst: Factor::OneMinusSrcAlpha, + }, +}; + +pub(super) const MAX: BlendState = BlendState { + color: BlendOp::Max, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::One, + }, +}; + +pub(super) const MIN: BlendState = BlendState { + color: BlendOp::Min, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::One, + }, +}; + +pub(super) const SUBPIXEL_PASS0: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::Zero, + dst: Factor::OneMinusSrcColor, + }, + alpha: BlendOp::Add { + src: Factor::Zero, + dst: Factor::OneMinusSrcAlpha, + }, +}; + +pub(super) const SUBPIXEL_PASS1: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::One, + dst: Factor::One, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::One, + }, +}; + +pub(super) const SUBPIXEL_WITH_BG_COLOR_PASS0: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::Zero, + dst: Factor::OneMinusSrcColor, + }, + alpha: BlendOp::Add { + src: Factor::Zero, + dst: Factor::One, + }, +}; + +pub(super) const SUBPIXEL_WITH_BG_COLOR_PASS1: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::OneMinusDstAlpha, + dst: Factor::One, + }, + alpha: BlendOp::Add { + src: Factor::Zero, + dst: Factor::One, + }, +}; + +pub(super) const SUBPIXEL_WITH_BG_COLOR_PASS2: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::One, + dst: Factor::One, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::OneMinusSrcAlpha, + }, +}; + +// This requires blend color to be set +pub(super) const SUBPIXEL_CONSTANT_TEXT_COLOR: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::ConstColor, + dst: Factor::OneMinusSrcColor, + }, + alpha: BlendOp::Add { + src: Factor::ConstAlpha, + dst: Factor::OneMinusSrcAlpha, + }, +}; + +pub(super) const SUBPIXEL_DUAL_SOURCE: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::One, + dst: Factor::OneMinusSrc1Color, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::OneMinusSrc1Alpha, + }, +}; + +pub(super) const OVERDRAW: BlendState = BlendState { + color: BlendOp::Add { + src: Factor::One, + dst: Factor::OneMinusSrcAlpha, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::OneMinusSrcAlpha, + }, +}; diff --git a/webrender/src/device/gfx/buffer.rs b/webrender/src/device/gfx/buffer.rs new file mode 100644 index 0000000000..c30664ff83 --- /dev/null +++ b/webrender/src/device/gfx/buffer.rs @@ -0,0 +1,737 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use hal; +use hal::Device as BackendDevice; +use rendy_memory::{Block, Heaps, Kind, MappedRange, MemoryBlock, MemoryUsage, MemoryUsageValue, Write}; + +use std::cell::Cell; +use std::sync::Arc; +use std::mem; + +pub const DOWNLOAD_BUFFER_SIZE: usize = 10 << 20; // 10MB + +#[derive(MallocSizeOf)] +pub struct BufferMemorySlice { + #[ignore_malloc_size_of = "ptr"] + ptr: *mut u8, + size: usize, +} + +unsafe impl Send for BufferMemorySlice {} +unsafe impl Sync for BufferMemorySlice {} + +impl BufferMemorySlice { + pub fn new(ptr: *mut u8, size: usize) -> Self { + BufferMemorySlice { + ptr, + size + } + } + + pub(crate) fn slice_mut(&mut self) -> &mut [T] { + use std::slice; + let size_of_t = mem::size_of::(); + assert_eq!(self.ptr as usize % size_of_t, 0); + assert_eq!(self.size % size_of_t, 0); + unsafe { slice::from_raw_parts_mut(self.ptr as _, self.size / size_of_t) } + } +} + +#[derive(Clone, Copy, Debug)] +struct PMBufferMemoryUsage; +impl MemoryUsage for PMBufferMemoryUsage { + fn properties_required(&self) -> hal::memory::Properties { + hal::memory::Properties::CPU_VISIBLE + } + + #[inline] + fn memory_fitness(&self, properties: hal::memory::Properties) -> u32 { + assert!(properties.contains(hal::memory::Properties::CPU_VISIBLE)); + assert!(!properties.contains(hal::memory::Properties::LAZILY_ALLOCATED)); + + 0 | (properties.contains(hal::memory::Properties::CPU_CACHED) as u32) << 2 + | (properties.contains(hal::memory::Properties::COHERENT) as u32) << 1 + } + + fn allocator_fitness(&self, kind: Kind) -> u32 { + match kind { + Kind::Dedicated => 2, + Kind::Dynamic => 1, + Kind::Linear => 0, + } + } +} + +#[derive(MallocSizeOf)] +pub struct GpuCacheBuffer { + #[ignore_malloc_size_of = "handle"] + pub buffer: Arc, + pub transit_range_end: u64, + #[ignore_malloc_size_of = "State does not implement size_of"] + pub state: Cell, +} + +unsafe impl Send for GpuCacheBuffer {} +unsafe impl Sync for GpuCacheBuffer {} + +impl GpuCacheBuffer { + pub fn update_transit_range(&mut self, range_end: u64) { + if range_end > self.transit_range_end { + self.transit_range_end = range_end; + } + } + + pub fn transit(&self, access: hal::buffer::Access, with_range: bool) -> Option> { + let src_state = self.state.get(); + if src_state == access { + None + } else { + self.state.set(access); + Some(hal::memory::Barrier::Buffer { + states: src_state .. access, + target: &self.buffer, + families: None, + range: None .. if with_range { Some(self.transit_range_end) } else { None }, + }) + } + } +} + +#[derive(Debug)] +#[derive(MallocSizeOf)] +pub struct PersistentlyMappedBuffer { + #[ignore_malloc_size_of = "buffer handle"] + pub buffer: Arc, + #[ignore_malloc_size_of = "memory handle"] + pub memory_block: MemoryBlock, + pub coherent: bool, + pub height: u64, + pub size: u64, + pub non_coherent_atom_size_mask: u64, +} + +unsafe impl Send for PersistentlyMappedBuffer {} +unsafe impl Sync for PersistentlyMappedBuffer {} + +impl PersistentlyMappedBuffer { + pub(crate) fn new( + device: &B::Device, + heaps: &mut Heaps, + non_coherent_atom_size_mask: u64, + width: u64, + height: u64, + copy_src: Option<&mut PersistentlyMappedBuffer>, + ) -> Self { + let buffer_stride = std::mem::size_of::() as u64; + let buffer_len = height * width * buffer_stride; + + assert_ne!(buffer_len, 0); + let mut storage_buffer = + unsafe { device.create_buffer(buffer_len, hal::buffer::Usage::STORAGE) }.unwrap(); + + let buffer_req = unsafe { device.get_buffer_requirements(&storage_buffer) }; + let alignment = ((buffer_req.alignment - 1) | non_coherent_atom_size_mask) +1; + let memory_block = heaps + .allocate( + device, + buffer_req.type_mask as u32, + PMBufferMemoryUsage, + buffer_req.size, + alignment, + ) + .expect("Allocate memory failed"); + + assert!(memory_block.properties().contains(hal::memory::Properties::CPU_CACHED)); + let coherent = memory_block.properties().contains(hal::memory::Properties::COHERENT); + + unsafe { + device.bind_buffer_memory( + &memory_block.memory(), + memory_block.range().start, + &mut storage_buffer, + ) + } + .expect("Bind buffer memory failed"); + let mut buffer = PersistentlyMappedBuffer { + buffer: Arc::new(storage_buffer), + memory_block, + coherent, + height, + size: buffer_req.size, + non_coherent_atom_size_mask, + }; + + if let Some(src) = copy_src { + unsafe { buffer.copy_from(src, device) }; + } + + buffer + } + + unsafe fn copy_from(&mut self, copy_src: &mut Self, device: &B::Device) { + { + let (mut mapped, read_size) = copy_src.map(device, None); + let read_slice = mapped.read::(device, 0..read_size).unwrap(); + let (mut mapped, _) = self.map(device, Some(read_size)); + let mut writer = mapped.write::(device, 0..read_size).unwrap(); + let writer_slice = writer.slice(); + writer_slice.copy_from_slice(read_slice); + } + copy_src.unmap(device); + self.unmap(device); + } + + pub fn buffer_memory_slice( + &mut self, + device: &B::Device, + ) -> BufferMemorySlice { + let (mapped, size) = self.map(device, None); + BufferMemorySlice::new( + mapped.ptr().as_ptr(), + size as usize, + ) + } + + pub fn map<'a>(&'a mut self, device: &B::Device, size: Option) -> (MappedRange<'a, B>, u64) { + assert!(size.unwrap_or(0) <= self.size, "size {:?} <= self.size {:?}", size.unwrap_or(0), self.size); + let size = size.unwrap_or(self.size); + (self.memory_block.map(&device, 0..size).expect("Mapping memory block failed"), size) + } + + pub fn unmap(&mut self, device: &B::Device) { + self.memory_block.unmap(device); + } + + pub fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + unsafe { + device.destroy_buffer(Arc::try_unwrap(self.buffer).unwrap()); + heaps.free(device, self.memory_block); + } + } + + pub fn get_buffer_info(&self, transit_range_end: u64) -> GpuCacheBuffer { + GpuCacheBuffer { + buffer: Arc::clone(&self.buffer), + transit_range_end: transit_range_end, + state: Cell::new(hal::buffer::Access::empty()), + } + } +} + +pub(super) struct Buffer { + pub(super) memory_block: MemoryBlock, + pub(super) buffer: B::Buffer, + pub(super) buffer_size: usize, + pub(super) buffer_len: usize, + stride: usize, + state: Cell, +} + +impl Buffer { + pub(super) fn new( + device: &B::Device, + heaps: &mut Heaps, + memory_usage: MemoryUsageValue, + buffer_usage: hal::buffer::Usage, + alignment_mask: usize, + data_len: usize, + stride: usize, + ) -> Self { + let buffer_size = (data_len * stride + alignment_mask) & !alignment_mask; + let mut buffer = unsafe { + device + .create_buffer(buffer_size as u64, buffer_usage) + .expect("create_buffer failed") + }; + let requirements = unsafe { device.get_buffer_requirements(&buffer) }; + let alignment = ((requirements.alignment - 1) | (alignment_mask as u64)) + 1; + let memory_block = heaps + .allocate( + device, + requirements.type_mask as u32, + memory_usage, + requirements.size, + alignment, + ) + .expect("Allocate memory failed"); + + unsafe { + device.bind_buffer_memory( + &memory_block.memory(), + memory_block.range().start, + &mut buffer, + ) + } + .expect("Bind buffer memory failed"); + + Buffer { + memory_block, + buffer, + buffer_size: requirements.size as _, + buffer_len: data_len, + stride, + state: Cell::new(hal::buffer::Access::empty()), + } + } + + fn update_all( + &mut self, + device: &B::Device, + data: &[T], + non_coherent_atom_size_mask: u64, + ) { + let size = (data.len() * std::mem::size_of::()) as u64; + let range = 0 .. ((size + non_coherent_atom_size_mask) & !non_coherent_atom_size_mask).min(self.buffer_size as u64); + unsafe { + let mut mapped = self + .memory_block + .map(device, range.clone()) + .expect("Mapping memory block failed"); + mapped + .write(device, 0 .. size) + .expect("Writer creation failed") + .write(&data); + } + self.memory_block.unmap(device); + } + + fn update( + &mut self, + device: &B::Device, + data: &[T], + offset: usize, + non_coherent_atom_size_mask: u64, + ) -> usize { + let offset = (offset * self.stride) as u64; + let size = (data.len() * self.stride) as u64; + let range = offset + .. ((offset + size + non_coherent_atom_size_mask) & !non_coherent_atom_size_mask); + unsafe { + let mut mapped = self + .memory_block + .map(device, range) + .expect("Mapping memory block failed"); + mapped + .write(device, 0 .. size) + .expect("Writer creation failed") + .write(&data); + } + self.memory_block.unmap(device); + size as usize + } + + pub(super) fn transit(&self, access: hal::buffer::Access) -> Option> { + let src_state = self.state.get(); + if src_state == access { + None + } else { + self.state.set(access); + Some(hal::memory::Barrier::Buffer { + states: src_state .. access, + target: &self.buffer, + families: None, + range: None .. None, + }) + } + } + + pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + unsafe { + device.destroy_buffer(self.buffer); + heaps.free(device, self.memory_block); + } + } +} + +pub(super) struct BufferPool { + buffer: Buffer, + data_stride: usize, + non_coherent_atom_size_mask: usize, + copy_alignment_mask: usize, + offset: usize, + size: usize, + pub(super) buffer_offset: usize, +} + +impl BufferPool { + pub(super) fn new( + device: &B::Device, + heaps: &mut Heaps, + buffer_usage: hal::buffer::Usage, + data_stride: usize, + non_coherent_atom_size_mask: usize, + pitch_alignment_mask: usize, + copy_alignment_mask: usize, + texture_cache_size: usize, + ) -> Self { + let buffer = Buffer::new( + device, + heaps, + MemoryUsageValue::Upload, + buffer_usage, + pitch_alignment_mask | non_coherent_atom_size_mask, + texture_cache_size, + data_stride, + ); + BufferPool { + buffer, + data_stride, + non_coherent_atom_size_mask, + copy_alignment_mask, + offset: 0, + size: 0, + buffer_offset: 0, + } + } + + pub(super) fn add(&mut self, device: &B::Device, data: &[T], texel_size_mask: usize) { + assert!( + mem::size_of::() <= self.data_stride, + "mem::size_of::()={:?} <= self.data_stride={:?}", + mem::size_of::(), + self.data_stride + ); + let buffer_len = data.len() * self.data_stride; + assert!( + self.offset * self.data_stride + buffer_len < self.buffer.buffer_size, + "offset({:?}) * data_stride({:?}) + buffer_len({:?}) < buffer_size({:?})", + self.offset, + self.data_stride, + buffer_len, + self.buffer.buffer_size + ); + let alignment_mask = self.copy_alignment_mask | texel_size_mask; + self.buffer_offset = (self.offset + alignment_mask) & !alignment_mask; + self.size = self.buffer.update( + device, + data, + self.buffer_offset, + self.non_coherent_atom_size_mask as u64, + ); + let diff = self.buffer_offset - self.offset; + self.offset += (self.size + diff + alignment_mask) & !alignment_mask; + } + + pub(super) fn buffer(&self) -> &Buffer { + &self.buffer + } + + pub(super) fn reset(&mut self) { + self.offset = 0; + self.size = 0; + } + + pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + self.buffer.deinit(device, heaps); + } +} + +pub(super) struct InstancePoolBuffer { + pub(super) buffer: Buffer, + pub(super) offset: usize, + pub(super) last_update_size: usize, + pub(super) last_data_stride: usize, + non_coherent_atom_size_mask: usize, +} + +impl InstancePoolBuffer { + fn new( + device: &B::Device, + heaps: &mut Heaps, + buffer_usage: hal::buffer::Usage, + alignment_mask: usize, + non_coherent_atom_size_mask: usize, + size: usize, + ) -> Self { + let buffer = Buffer::new( + device, + heaps, + MemoryUsageValue::Dynamic, + buffer_usage, + alignment_mask, + size, + mem::size_of::(), + ); + InstancePoolBuffer { + buffer, + offset: 0, + last_update_size: 0, + last_data_stride: 0, + non_coherent_atom_size_mask, + } + } + + fn update(&mut self, device: &B::Device, data: &[u8], last_data_stride: usize) { + self.buffer.update( + device, + data, + self.offset, + self.non_coherent_atom_size_mask as u64, + ); + self.last_data_stride = last_data_stride; + self.last_update_size = data.len(); + self.offset += self.last_update_size; + } + + fn reset(&mut self) { + self.offset = 0; + self.last_update_size = 0; + } + + pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + self.buffer.deinit(device, heaps); + } + + fn space_left(&self) -> usize { + self.buffer.buffer_size - self.offset + } + + fn can_store_data(&self, stride: usize) -> bool { + let next_offset = self.next_aligned_offset(stride); + next_offset < self.buffer.buffer_size && self.buffer.buffer_size - next_offset >= stride + } + + fn align_offset_to(&mut self, stride: usize) { + self.offset = self.next_aligned_offset(stride); + } + + fn next_aligned_offset(&self, stride: usize) -> usize { + let remainder = self.offset % stride; + match remainder { + 0 => self.offset, + _ => self.offset + stride - remainder, + } + } +} + +pub(super) struct InstanceBufferHandler { + pub(super) buffers: Vec>, + alignment_mask: usize, + non_coherent_atom_size_mask: usize, + pub(super) next_buffer_index: usize, + buffer_size: usize, +} + +impl InstanceBufferHandler { + pub(super) fn new( + non_coherent_atom_size_mask: usize, + alignment_mask: usize, + buffer_size: usize, + ) -> Self { + InstanceBufferHandler { + buffers: Vec::new(), + alignment_mask, + non_coherent_atom_size_mask, + next_buffer_index: 0, + buffer_size, + } + } + + pub(super) fn add( + &mut self, + device: &B::Device, + mut instance_data: &[T], + heaps: &mut Heaps, + free_buffers: &mut Vec>, + ) -> std::ops::Range { + fn instance_data_to_u8_slice(data: &[T]) -> &[u8] { + unsafe { + std::slice::from_raw_parts( + data.as_ptr() as *const u8, + data.len() * mem::size_of::(), + ) + } + } + + let data_stride = mem::size_of::(); + let mut range = 0..0; + let mut first_iteration = true; + while !instance_data.is_empty() { + let need_new_buffer = self.buffers.is_empty() + || !self.current_buffer().can_store_data(data_stride); + if need_new_buffer { + let buffer = match free_buffers.pop() { + Some(b) => b, + None => InstancePoolBuffer::new( + device, + heaps, + hal::buffer::Usage::VERTEX, + self.alignment_mask, + self.non_coherent_atom_size_mask, + self.buffer_size, + ), + }; + self.buffers.push(buffer); + self.next_buffer_index += 1; + } else { + self.current_buffer_mut().align_offset_to(data_stride); + } + if first_iteration { + range.start = self.next_buffer_index - 1; + first_iteration = false; + } + let update_size = (self.current_buffer().space_left() / data_stride).min(instance_data.len()); + self.current_buffer_mut().update(device, instance_data_to_u8_slice(&instance_data[0 .. update_size]), data_stride); + instance_data = &instance_data[update_size ..]; + } + range.end = self.next_buffer_index; + range + } + + fn current_buffer(&self) -> &InstancePoolBuffer { + &self.buffers[self.next_buffer_index - 1] + } + + fn current_buffer_mut(&mut self) -> &mut InstancePoolBuffer { + &mut self.buffers[self.next_buffer_index - 1] + } + + pub(super) fn reset(&mut self, free_buffers: &mut Vec>) { + if !self.buffers.is_empty() { + // Keep one buffer and move the others back to the free set pool. + for mut buffer in self.buffers.drain(1 .. ) { + buffer.reset(); + free_buffers.push(buffer); + } + self.next_buffer_index = self.buffers.len(); + } + } + + pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + for buffer in self.buffers { + buffer.deinit(device, heaps); + } + } +} + +pub(super) struct VertexBufferHandler { + buffer: Buffer, + buffer_usage: hal::buffer::Usage, + data_stride: usize, + pitch_alignment_mask: usize, + non_coherent_atom_size_mask: usize, + pub(super) buffer_len: usize, +} + +impl VertexBufferHandler { + pub(super) fn new( + device: &B::Device, + heaps: &mut Heaps, + buffer_usage: hal::buffer::Usage, + data: &[T], + pitch_alignment_mask: usize, + non_coherent_atom_size_mask: usize, + ) -> Self { + let data_stride = mem::size_of::(); + let mut buffer = Buffer::new( + device, + heaps, + MemoryUsageValue::Dynamic, + buffer_usage, + pitch_alignment_mask, + data.len(), + data_stride, + ); + buffer.update_all(device, data, non_coherent_atom_size_mask as u64); + VertexBufferHandler { + buffer_len: buffer.buffer_len, + buffer, + buffer_usage, + data_stride, + pitch_alignment_mask, + non_coherent_atom_size_mask, + } + } + + pub(super) fn update(&mut self, device: &B::Device, data: &[T], heaps: &mut Heaps) { + self.data_stride = mem::size_of::(); + let buffer_len = data.len() * self.data_stride; + if self.buffer.buffer_len != buffer_len { + let old_buffer = mem::replace( + &mut self.buffer, + Buffer::new( + device, + heaps, + MemoryUsageValue::Dynamic, + self.buffer_usage, + self.pitch_alignment_mask, + data.len(), + self.data_stride, + ), + ); + old_buffer.deinit(device, heaps); + } + self.buffer + .update_all(device, data, self.non_coherent_atom_size_mask as u64); + self.buffer_len = buffer_len; + } + + pub(super) fn buffer(&self) -> &Buffer { + &self.buffer + } + + pub(super) fn reset(&mut self) { + self.buffer_len = 0; + } + + pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + self.buffer.deinit(device, heaps); + } +} + +pub(super) struct UniformBufferHandler { + buffers: Vec>, + offset: usize, + buffer_usage: hal::buffer::Usage, + data_stride: usize, + pitch_alignment_mask: usize, +} + +impl UniformBufferHandler { + pub(super) fn new( + buffer_usage: hal::buffer::Usage, + data_stride: usize, + pitch_alignment_mask: usize, + ) -> Self { + UniformBufferHandler { + buffers: vec![], + offset: 0, + buffer_usage, + data_stride, + pitch_alignment_mask, + } + } + + pub(super) fn add(&mut self, device: &B::Device, data: &[T], heaps: &mut Heaps) { + if self.buffers.len() == self.offset { + self.buffers.push(Buffer::new( + device, + heaps, + MemoryUsageValue::Dynamic, + self.buffer_usage, + self.pitch_alignment_mask, + data.len(), + self.data_stride, + )); + } + self.buffers[self.offset].update_all(device, data, self.pitch_alignment_mask as u64); + self.offset += 1; + } + + pub(super) fn buffer(&self) -> &Buffer { + &self.buffers[self.offset - 1] + } + + pub(super) fn reset(&mut self) { + self.offset = 0; + } + + pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + for buffer in self.buffers { + buffer.deinit(device, heaps); + } + } +} + diff --git a/webrender/src/device/gfx/command.rs b/webrender/src/device/gfx/command.rs new file mode 100644 index 0000000000..7074764b2c --- /dev/null +++ b/webrender/src/device/gfx/command.rs @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use hal::Device as BackendDevice; +use hal::pool::RawCommandPool; + +pub struct CommandPool { + command_pool: B::CommandPool, + command_buffers: Vec, +} + +impl CommandPool { + pub(super) fn new(command_pool: B::CommandPool) -> Self { + CommandPool { + command_pool, + command_buffers: vec![], + } + } + + pub(super) fn create_command_buffer(&mut self) { + if self.command_buffers.is_empty() { + let command_buffer = self + .command_pool + .allocate_one(hal::command::RawLevel::Primary); + self.command_buffers.push(command_buffer); + } + } + + pub fn remove_cmd_buffer(&mut self) -> B::CommandBuffer { + self.command_buffers.remove(0) + } + + pub fn return_cmd_buffer(&mut self, cmd_buffer: B::CommandBuffer) { + self.command_buffers.insert(0, cmd_buffer); + } + + pub(super) unsafe fn reset(&mut self) { + self.command_pool.reset(false); + } + + pub(super) unsafe fn destroy(self, device: &B::Device) { + device.destroy_command_pool(self.command_pool); + } +} diff --git a/webrender/src/device/gfx/descriptor.rs b/webrender/src/device/gfx/descriptor.rs new file mode 100644 index 0000000000..5ccb19e281 --- /dev/null +++ b/webrender/src/device/gfx/descriptor.rs @@ -0,0 +1,454 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use arrayvec::ArrayVec; +use hal::Device; +use hal::pso::{DescriptorSetLayoutBinding, DescriptorType as DT, ShaderStageFlags as SSF}; +use internal_types::FastHashMap; +use rendy_descriptor::{DescriptorAllocator, DescriptorRanges, DescriptorSet}; +use rendy_memory::Heaps; +use smallvec::SmallVec; +use std::clone::Clone; +use std::cmp::Eq; +use std::collections::hash_map::Entry; +use std::hash::{Hash, Hasher}; +use std::marker::Copy; +use super::buffer::UniformBufferHandler; +use super::image::Image; +use super::TextureId; +use super::super::{ShaderKind, TextureFilter, VertexArrayKind}; + +pub(super) const DESCRIPTOR_SET_PER_PASS: usize = 0; +pub(super) const DESCRIPTOR_SET_PER_GROUP: usize = 1; +pub(super) const DESCRIPTOR_SET_PER_DRAW: usize = 2; +pub(super) const DESCRIPTOR_SET_LOCALS: usize = 3; + +pub(super) const DESCRIPTOR_COUNT: u32 = 96; +pub(super) const PER_DRAW_TEXTURE_COUNT: usize = 3; // Color0, Color1, Color2 +pub(super) const PER_PASS_TEXTURE_COUNT: usize = 2; // PrevPassAlpha, PrevPassColor +pub(super) const PER_GROUP_TEXTURE_COUNT: usize = 6; // GpuCache, TransformPalette, RenderTasks, Dither, PrimitiveHeadersF, PrimitiveHeadersI +pub(super) const RENDERER_TEXTURE_COUNT: usize = 11; +pub(super) const PER_GROUP_RANGE_DEFAULT: std::ops::Range = 8..9; // Dither +pub(super) const PER_GROUP_RANGE_CLIP: std::ops::Range = 6..9; //TransformPalette, RenderTasks, Dither +pub(super) const PER_GROUP_RANGE_PRIMITIVE: std::ops::Range = 6..11; // TransformPalette, RenderTasks, Dither, PrimitiveHeadersF, PrimitiveHeadersI +const GPU_CACHE_BINDING: u32 = 5; + +pub(super) const MAX_DESCRIPTOR_SET_COUNT: usize = 4; + +const fn descriptor_set_layout_binding( + binding: u32, + ty: DT, + stage_flags: SSF, + immutable_samplers: bool, +) -> DescriptorSetLayoutBinding { + DescriptorSetLayoutBinding { + binding, + ty, + count: 1, + stage_flags, + immutable_samplers, + } +} + +pub(super) const DEFAULT_SET_1: &'static [DescriptorSetLayoutBinding] = &[ + // Dither + descriptor_set_layout_binding(8, DT::CombinedImageSampler, SSF::ALL, true), +]; + +pub(super) const COMMON_SET_2: &'static [DescriptorSetLayoutBinding] = &[ + // Color0 + descriptor_set_layout_binding(0, DT::CombinedImageSampler, SSF::ALL, false), + // Color1 + descriptor_set_layout_binding(1, DT::CombinedImageSampler, SSF::ALL, false), + // Color2 + descriptor_set_layout_binding(2, DT::CombinedImageSampler, SSF::ALL, false), +]; + +pub(super) const COMMON_SET_3: &'static [DescriptorSetLayoutBinding] = &[ + // Locals + descriptor_set_layout_binding(0, DT::UniformBuffer, SSF::VERTEX, false), +]; + +pub(super) const CLIP_SET_1: &'static [DescriptorSetLayoutBinding] = &[ + // GpuCache + descriptor_set_layout_binding(5, DT::StorageBuffer, SSF::ALL, false), + // TransformPalette + descriptor_set_layout_binding(6, DT::CombinedImageSampler, SSF::VERTEX, true), + // RenderTasks + descriptor_set_layout_binding(7, DT::CombinedImageSampler, SSF::VERTEX, true), + // Dither + descriptor_set_layout_binding(8, DT::CombinedImageSampler, SSF::ALL, true), +]; + +pub(super) const PRIMITIVE_SET_1: &'static [DescriptorSetLayoutBinding] = &[ + // GpuCache + descriptor_set_layout_binding(5, DT::StorageBuffer, SSF::ALL, false), + // TransformPalette + descriptor_set_layout_binding(6, DT::CombinedImageSampler, SSF::VERTEX, true), + // RenderTasks + descriptor_set_layout_binding(7, DT::CombinedImageSampler, SSF::VERTEX, true), + // Dither + descriptor_set_layout_binding(8, DT::CombinedImageSampler, SSF::ALL, true), + // PrimitiveHeadersF + descriptor_set_layout_binding(9, DT::CombinedImageSampler, SSF::VERTEX, true), + // PrimitiveHeadersI + descriptor_set_layout_binding(10, DT::CombinedImageSampler, SSF::VERTEX, true), +]; + +pub(super) const PRIMITIVE_SET_0: &'static [DescriptorSetLayoutBinding] = &[ + // PrevPassAlpha + descriptor_set_layout_binding(3, DT::CombinedImageSampler, SSF::ALL, true), + // PrevPassColor + descriptor_set_layout_binding(4, DT::CombinedImageSampler, SSF::ALL, true), +]; + +pub(super) const EMPTY_SET_0: &'static [DescriptorSetLayoutBinding] = &[]; + +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub(super) enum DescriptorGroup { + Default, + Clip, + Primitive, +} + +impl From for DescriptorGroup { + fn from(kind: ShaderKind) -> Self { + match kind { + ShaderKind::Cache(VertexArrayKind::Border) | ShaderKind::Cache(VertexArrayKind::LineDecoration) + | ShaderKind::DebugColor | ShaderKind::DebugFont + | ShaderKind::VectorStencil | ShaderKind::VectorCover => DescriptorGroup::Default, + ShaderKind::ClipCache => DescriptorGroup::Clip, + ShaderKind::Brush | ShaderKind::Cache(VertexArrayKind::Blur) | ShaderKind::Cache(VertexArrayKind::Scale) + | ShaderKind::Primitive | ShaderKind::Text => DescriptorGroup::Primitive, + _ => unimplemented!("No descriptor group for kind {:?}", kind), + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[allow(non_snake_case)] +pub(super) struct Locals { + pub(super) uTransform: [[f32; 4]; 4], + pub(super) uMode: i32, +} + + impl Locals { + fn transform_as_u32_slice(&self) -> &[u32; 16] { + unsafe { + std::mem::transmute::<&[[f32; 4]; 4], &[u32; 16]>(&self.uTransform) + } + } +} + + impl Hash for Locals { + fn hash(&self, state: &mut H) { + self.transform_as_u32_slice().hash(state); + self.uMode.hash(state); + } +} + + impl PartialEq for Locals { + fn eq(&self, other: &Locals) -> bool { + self.uTransform == other.uTransform && + self.uMode == other.uMode + } +} + +impl Eq for Locals {} + +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Default)] +pub(super) struct PerDrawBindings(pub [TextureId; PER_DRAW_TEXTURE_COUNT], pub [TextureFilter; PER_DRAW_TEXTURE_COUNT]); + +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Default)] +pub(super) struct PerPassBindings(pub [TextureId; PER_PASS_TEXTURE_COUNT]); + +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Default)] +pub(super) struct PerGroupBindings(pub [TextureId; PER_GROUP_TEXTURE_COUNT]); + +pub(super) struct DescriptorGroupData { + pub(super) set_layouts: ArrayVec<[B::DescriptorSetLayout; MAX_DESCRIPTOR_SET_COUNT]>, + pub(super) ranges: ArrayVec<[DescriptorRanges; MAX_DESCRIPTOR_SET_COUNT]>, + pub(super) pipeline_layout: B::PipelineLayout, +} + +pub(super) struct DescriptorData(pub(super) FastHashMap>); + +impl DescriptorData { + fn descriptor_layout(&self, group: &DescriptorGroup, group_idx: usize) -> &B::DescriptorSetLayout { + &self.0[group].set_layouts[group_idx] + } + + fn ranges(&self, group: &DescriptorGroup, group_idx: usize) -> DescriptorRanges { + self.0[group].ranges[group_idx] + } + + pub(super) fn pipeline_layout(&self, group: &DescriptorGroup) -> &B::PipelineLayout { + &self.0[group].pipeline_layout + } + + pub(super) unsafe fn deinit(self, device: &B::Device) { + for (_, group_data) in self.0 { + for layout in group_data.set_layouts { + device.destroy_descriptor_set_layout(layout); + } + device.destroy_pipeline_layout(group_data.pipeline_layout); + } + } +} + +// Trait for managing the container type of the free descriptor sets in the `DescriptorSetHandler` struct +// which could be a `Vec` or a `FastHashMap` +pub(super) trait FreeSets { + // Mutable reference of the free descriptor sets, `group` is only used for `FastHashMap` + fn get_mut(&mut self, group: &DescriptorGroup) -> &mut Vec>; + + // Free the underlying descriptor sets of the container + unsafe fn free(self, allocator: &mut DescriptorAllocator); +} + +impl FreeSets for Vec> { + fn get_mut(&mut self, _group: &DescriptorGroup) -> &mut Vec> { + self + } + + unsafe fn free(self, allocator: &mut DescriptorAllocator) { + allocator.free(self.into_iter()) + } +} + +impl FreeSets for FastHashMap>> { + fn get_mut(&mut self, group: &DescriptorGroup) -> &mut Vec> { + self.get_mut(group).unwrap() + } + + unsafe fn free(self, allocator: &mut DescriptorAllocator) { + allocator.free(self.into_iter().flat_map(|(_, sets)| sets.into_iter())) + } +} + + +// Trait for managing the key of the `descriptor_bindings` `FastHashMap` in the `DescriptorSetHandler` struct +pub(super) trait DescGroupKey { + // Get the corresponding `DescriptorGroup` of the key structure. + // There are cases where we don't care the exact group that's the `DescriptorGroup::Default` for. + fn desc_group(&self) -> &DescriptorGroup { &DescriptorGroup::Default } + + // Check if the key contains the requested `TextureId`. + // This is used to decide if we can recycle a `DescriptorSet` after a texture is freed. + // There are keys which are not texture related, in this case we return false. + fn has_texture_id(&self, _id: &TextureId) -> bool { false } +} + +impl DescGroupKey for PerDrawBindings { + fn has_texture_id(&self, id: &TextureId) -> bool { + self.0.contains(id) + } +} + +impl DescGroupKey for (DescriptorGroup, PerGroupBindings) { + fn desc_group(&self) -> &DescriptorGroup { + &self.0 + } + + fn has_texture_id(&self, id: &TextureId) -> bool { + (self.1).0.contains(id) + } +} + +impl DescGroupKey for PerPassBindings { + fn has_texture_id(&self, id: &TextureId) -> bool { + self.0.contains(id) + } +} + +impl DescGroupKey for Locals {} + +pub(super) struct DescriptorSetHandler { + free_sets: F, + descriptor_bindings: FastHashMap>, +} + +impl DescriptorSetHandler + where + K: Copy + Clone + Eq + Hash + DescGroupKey, + B: hal::Backend, + F: FreeSets + Extend> { + pub(super) fn new( + device: &B::Device, + descriptor_allocator: &mut DescriptorAllocator, + group_data: &DescriptorData, + group: &DescriptorGroup, + set_index: usize, + descriptor_count: u32, + mut free_sets: F, + ) -> Self { + unsafe { + descriptor_allocator.allocate( + device, + group_data.descriptor_layout(group, set_index), + group_data.ranges(group, set_index), + descriptor_count, + &mut free_sets + ) + }.expect("Allocate descriptor sets failed"); + Self::from_existing(free_sets) + } +} + +impl DescriptorSetHandler + where + K: Copy + Clone + Eq + Hash + DescGroupKey, + B: hal::Backend, + F: FreeSets { + pub(super) fn from_existing(free_sets: F) -> Self { + DescriptorSetHandler { + free_sets, + descriptor_bindings: FastHashMap::default(), + } + } + + pub(super) fn reset(&mut self) { + for (key, desc_set) in self.descriptor_bindings.drain() { + self.free_sets.get_mut(key.desc_group()).push(desc_set); + } + } + + pub(super) fn descriptor_set(&self, key: &K) -> &B::DescriptorSet { + self.descriptor_bindings[key].raw() + } + + pub(super) fn retain(&mut self, id: &TextureId) { + let keys_to_remove: Vec<_> = self.descriptor_bindings + .keys() + .filter(|res| res.has_texture_id(&id)).cloned().collect(); + for key in keys_to_remove { + let desc_set =self.descriptor_bindings.remove(&key).unwrap(); + self.free_sets.get_mut(key.desc_group()).push(desc_set); + } + } + + pub(super) unsafe fn free(self, allocator: &mut DescriptorAllocator) { + self.free_sets.free(allocator); + allocator.free(self.descriptor_bindings.into_iter().map(|(_, set)| set)); + } + + pub(super) fn bind_textures( + &mut self, + bound_textures: &[u32; RENDERER_TEXTURE_COUNT], + bound_samplers: &[TextureFilter; RENDERER_TEXTURE_COUNT], + bindings: K, + images: &FastHashMap>, + storage_buffer: Option<&B::Buffer>, + desc_allocator: &mut DescriptorAllocator, + device: &B::Device, + group_data: &DescriptorData, + group: &DescriptorGroup, + set_index: usize, + range: std::ops::Range, + sampler_linear: &B::Sampler, + sampler_nearest: &B::Sampler, + ) { + let new_set = match self.descriptor_bindings.entry(bindings) { + Entry::Occupied(_) => return, + Entry::Vacant(v) => { + let free_sets = self.free_sets.get_mut(group); + let desc_set = match free_sets.pop() { + Some(ds) => ds, + None => { + unsafe { + desc_allocator.allocate( + device, + group_data.descriptor_layout(group, set_index), + group_data.ranges(group, set_index), + DESCRIPTOR_COUNT, + free_sets, + ) + }.expect("Allocate descriptor sets failed"); + free_sets.pop().unwrap() + } + }; + v.insert(desc_set) + } + }; + let mut descriptor_writes: SmallVec<[hal::pso::DescriptorSetWrite<_, _>; RENDERER_TEXTURE_COUNT]> = SmallVec::new(); + let set = new_set.raw(); + if let Some(buffer) = storage_buffer { + descriptor_writes.push(hal::pso::DescriptorSetWrite { + set, + binding: GPU_CACHE_BINDING, + array_offset: 0, + descriptors: Some(hal::pso::Descriptor::Buffer( + buffer, + None .. None, + )), + }); + } + for index in range { + let image = &images[&bound_textures[index]].core; + let sampler = if index < PER_DRAW_TEXTURE_COUNT { + match bound_samplers[index] { + TextureFilter::Linear | TextureFilter::Trilinear => sampler_linear, + TextureFilter::Nearest => sampler_nearest, + } + } else if index < PER_DRAW_TEXTURE_COUNT + PER_PASS_TEXTURE_COUNT { + sampler_linear + } else { + sampler_nearest + }; + descriptor_writes.push(hal::pso::DescriptorSetWrite { + set, + binding: index as _, + array_offset: 0, + descriptors: Some(hal::pso::Descriptor::CombinedImageSampler( + &image.view, + hal::image::Layout::ShaderReadOnlyOptimal, + sampler, + )), + }); + } + unsafe { device.write_descriptor_sets(descriptor_writes) }; + } + + pub(super) fn bind_locals( + &mut self, + bindings: K, + device: &B::Device, + desc_allocator: &mut DescriptorAllocator, + group_data: &DescriptorData, + locals_buffer: &mut UniformBufferHandler, + heaps: &mut Heaps, + ) { + if let Entry::Vacant(v) = self.descriptor_bindings.entry(bindings) { + locals_buffer.add(&device, &[bindings], heaps); + let free_sets = self.free_sets.get_mut(&DescriptorGroup::Default); + let desc_set = match free_sets.pop() { + Some(ds) => ds, + None => { + unsafe { + desc_allocator.allocate( + device, + group_data.descriptor_layout(&DescriptorGroup::Default, DESCRIPTOR_SET_LOCALS), + group_data.ranges(&DescriptorGroup::Default, DESCRIPTOR_SET_LOCALS), + DESCRIPTOR_COUNT, + free_sets, + ) + }.expect("Allocate descriptor sets failed"); + free_sets.pop().unwrap() + } + }; + let desc_set = v.insert(desc_set); + unsafe { + device.write_descriptor_sets(Some(hal::pso::DescriptorSetWrite { + set: desc_set.raw(), + binding: 0, + array_offset: 0, + descriptors: Some(hal::pso::Descriptor::Buffer( + &locals_buffer.buffer().buffer, + Some(0) .. None, + )), + })); + } + } + } +} diff --git a/webrender/src/device/gfx/device.rs b/webrender/src/device/gfx/device.rs new file mode 100644 index 0000000000..3a56c952db --- /dev/null +++ b/webrender/src/device/gfx/device.rs @@ -0,0 +1,3625 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use api::{ColorF, ImageFormat, MemoryReport}; +use api::round_to_int; +use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; +use api::TextureTarget; +#[cfg(feature = "capture")] +use api::ImageDescriptor; +use arrayvec::ArrayVec; +use euclid::Transform3D; +use internal_types::{FastHashMap, RenderTargetInfo}; +use rand::{self, Rng}; +use rendy_memory::{Block, DynamicConfig, Heaps, HeapsConfig, LinearConfig, MemoryUsageValue}; +use rendy_descriptor::{DescriptorAllocator, DescriptorRanges, DescriptorSet}; +use ron::de::from_str; +use smallvec::SmallVec; +use std::cell::Cell; +use std::convert::Into; +use std::collections::hash_map::Entry; +use std::fs::{File, OpenOptions}; +use std::io::prelude::*; +use std::mem; +use std::path::PathBuf; +use std::rc::Rc; +use std::slice; +use std::sync::{Arc, Mutex}; + +use super::blend_state::*; +use super::buffer::*; +use super::command::*; +use super::descriptor::*; +use super::image::*; +use super::program::{Program, RenderPassDepthState, PUSH_CONSTANT_BLOCK_SIZE}; +use super::render_pass::*; +use super::{PipelineRequirements, PrimitiveType, TextureId}; +use super::{LESS_EQUAL_TEST, LESS_EQUAL_WRITE}; +use super::vertex_types; + +use super::super::Capabilities; +use super::super::{ShaderKind, ExternalTexture, GpuFrameId, TextureSlot, TextureFilter}; +use super::super::{VertexDescriptor, UploadMethod, Texel, ReadPixelsFormat, TextureFlags}; +use super::super::{Texture, DrawTarget, ReadTarget, FBOId, RBOId, VertexUsageHint, ShaderError, ShaderPrecacheFlags, SharedDepthTarget, ProgramCache}; +use super::super::{depth_target_size_in_bytes, record_gpu_alloc, record_gpu_free}; +use super::super::super::shader_source; + +use hal; +use hal::pso::{BlendState, DepthTest}; +use hal::{Device as BackendDevice, PhysicalDevice, Surface, Swapchain}; +use hal::{SwapchainConfig, AcquireError}; +use hal::pso::PipelineStage; +use hal::queue::RawCommandQueue; +use hal::window::PresentError; +use hal::command::{ClearColorRaw, ClearDepthStencilRaw, ClearValueRaw, CommandBufferFlags, CommandBufferInheritanceInfo, RawCommandBuffer, RawLevel}; +use hal::pool::{RawCommandPool}; +use hal::queue::{QueueFamilyId}; + +pub const INVALID_TEXTURE_ID: TextureId = 0; +pub const INVALID_PROGRAM_ID: ProgramId = ProgramId(0); +pub const DEFAULT_READ_FBO: FBOId = FBOId(0); +pub const DEFAULT_DRAW_FBO: FBOId = FBOId(1); +pub const DEBUG_READ_FBO: FBOId = FBOId(2); + +// Frame count if present mode is mailbox +const FRAME_COUNT_MAILBOX: usize = 3; +// Frame count if present mode is not mailbox +const FRAME_COUNT_NOT_MAILBOX: usize = 2; +const SURFACE_FORMAT: hal::format::Format = hal::format::Format::Bgra8Unorm; + +const COLOR_RANGE: hal::image::SubresourceRange = hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: 0 .. 1, + layers: 0 .. 1, +}; + +// If we want to clear only the depth when beginning a render-pass we have to put something to the first position in `pClearValues`. +const PLACEHOLDER_CLEAR: ClearValueRaw = ClearValueRaw { color: ClearColorRaw { float32: [0.0; 4]} }; + +#[derive(PartialEq)] +pub enum BackendApiType { + Vulkan, + Dx12, + Metal, +} + +#[derive(Debug, Eq, PartialEq)] +pub enum DrawTargetUsage { + // Only a blit or copy operation is applied to the target + CopyOnly, + // The target will be drawn or cleared and copy is also possible + Draw, +} + +const QUAD: [vertex_types::Vertex; 6] = [ + vertex_types::Vertex { + aPosition: [0.0, 0.0, 0.0], + }, + vertex_types::Vertex { + aPosition: [1.0, 0.0, 0.0], + }, + vertex_types::Vertex { + aPosition: [0.0, 1.0, 0.0], + }, + vertex_types::Vertex { + aPosition: [0.0, 1.0, 0.0], + }, + vertex_types::Vertex { + aPosition: [1.0, 0.0, 0.0], + }, + vertex_types::Vertex { + aPosition: [1.0, 1.0, 0.0], + }, +]; + +pub struct DeviceInit { + pub instance: Box>, + pub adapter: hal::Adapter, + pub surface: Option, + pub window_size: (i32, i32), + pub descriptor_count: Option, + pub cache_path: Option, + pub save_cache: bool, + pub backend_api: BackendApiType, +} + +const NON_SPECIALIZATION_FEATURES: &'static [&'static str] = + &["TEXTURE_RECT", "TEXTURE_2D", "DUAL_SOURCE_BLENDING"]; + +#[repr(u32)] +pub enum DepthFunction { + Less, + LessEqual, +} + +impl ShaderKind { + pub(super) fn is_debug(&self) -> bool { + match *self { + ShaderKind::DebugFont | ShaderKind::DebugColor => true, + _ => false, + } + } +} + +impl Texture { + pub fn still_in_flight(&self, frame_id: GpuFrameId, frame_count: usize) -> bool { + for i in 0 .. frame_count { + if self.bound_in_frame.get() == GpuFrameId(frame_id.0 - i) { + return true; + } + } + false + } +} + +#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] +pub struct ProgramId(u32); + +pub struct PBO; +pub struct VAO; + +struct Fence { + inner: B::Fence, + is_submitted: bool, +} + +#[derive(Debug)] +struct Frame { + image: ImageCore, + depth: DepthBuffer, + framebuffer: B::Framebuffer, + framebuffer_depth: B::Framebuffer, +} + +impl Frame { + fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + self.image.deinit(device, heaps); + self.depth.deinit(device, heaps); + unsafe { + device.destroy_framebuffer(self.framebuffer); + device.destroy_framebuffer(self.framebuffer_depth); + } + } +} + +struct RenderPassState { + target_texture: Option, + color_attachment: AttachmentState, + depth_attachment: Option, +} + +impl RenderPassState { + fn depth_state(&self) -> RenderPassDepthState { + if self.depth_attachment.is_some() { + return RenderPassDepthState::Enabled + } + RenderPassDepthState::Disabled + } + + fn get_suitable_render_pass<'a, B: hal::Backend>( + &self, + device: &B::Device, + manager: &'a mut RenderPassManager, + ) -> &'a B::RenderPass { + let rp_key = (self.color_attachment.clone(), self.depth_attachment.clone()); + manager.get_render_pass(device, rp_key) + } +} + +pub struct Device { + pub device: Arc, + pub heaps: Arc>>, + pub limits: hal::Limits, + adapter: hal::Adapter, + surface: Option, + _instance: Box>, + pub surface_format: ImageFormat, + pub depth_format: hal::format::Format, + pub queue_group_family: QueueFamilyId, + pub queue_group_queues: Vec, + command_pools: ArrayVec<[CommandPool; FRAME_COUNT_MAILBOX]>, + command_buffer: B::CommandBuffer, + staging_buffer_pool: ArrayVec<[BufferPool; FRAME_COUNT_MAILBOX]>, + pub swap_chain: Option, + frames: ArrayVec<[Frame; FRAME_COUNT_MAILBOX]>, + render_pass_manager: RenderPassManager, + clear_values: FastHashMap, /*depth*/Option)>, + pub frame_count: usize, + pub viewport: hal::pso::Viewport, + pub sampler_linear: B::Sampler, + pub sampler_nearest: B::Sampler, + pub current_frame_id: usize, + current_blend_state: Cell>, + blend_color: Cell, + current_depth_test: Option, + // device state + programs: FastHashMap>, + shader_modules: FastHashMap, + images: FastHashMap>, + pub(crate) gpu_cache_buffer: Option>, + pub(crate) gpu_cache_buffers: FastHashMap>, + retained_textures: Vec, + fbos: FastHashMap>, + rbos: FastHashMap>, + + desc_allocator: DescriptorAllocator, + + per_draw_descriptors: DescriptorSetHandler>>, + bound_per_draw_bindings: PerDrawBindings, + + per_pass_descriptors: DescriptorSetHandler>>, + bound_per_pass_textures: PerPassBindings, + + per_group_descriptors: DescriptorSetHandler<(DescriptorGroup, PerGroupBindings), B, FastHashMap>>>, + bound_per_group_textures: PerGroupBindings, + + // Locals related things + locals_descriptors: DescriptorSetHandler>>, + bound_locals: Locals, + + descriptor_data: DescriptorData, + bound_textures: [u32; RENDERER_TEXTURE_COUNT], + bound_program: ProgramId, + bound_sampler: [TextureFilter; RENDERER_TEXTURE_COUNT], + bound_read_texture: (TextureId, i32), + bound_read_fbo: FBOId, + bound_draw_fbo: FBOId, + draw_target_usage: DrawTargetUsage, + scissor_rect: Option, + //default_read_fbo: FBOId, + //default_draw_fbo: FBOId, + device_pixel_ratio: f32, + depth_available: bool, + upload_method: UploadMethod, + locals_buffer: UniformBufferHandler, + quad_buffer: VertexBufferHandler, + instance_buffers: ArrayVec<[InstanceBufferHandler; FRAME_COUNT_MAILBOX]>, + free_instance_buffers: Vec>, + download_buffer: Option>, + instance_range: std::ops::Range, + + // HW or API capabilities + capabilities: Capabilities, + + /// Map from texture dimensions to shared depth buffers for render targets. + /// + /// Render targets often have the same width/height, so we can save memory + /// by sharing these across targets. + depth_targets: FastHashMap, + + // debug + inside_frame: bool, + render_pass_state: Option, + + // resources + _resource_override_path: Option, + + max_texture_size: i32, + _renderer_name: String, + + // Frame counter. This is used to map between CPU + // frames and GPU frames. + frame_id: GpuFrameId, + + // Supported features + features: hal::Features, + + next_id: usize, + frame_fence: ArrayVec<[Fence; FRAME_COUNT_MAILBOX]>, + image_available_semaphore: B::Semaphore, + render_finished_semaphore: B::Semaphore, + pipeline_requirements: FastHashMap, + pipeline_cache: Option, + cache_path: Option, + save_cache: bool, + wait_for_resize: bool, + + // The device supports push constants + pub use_push_consts: bool, +} + +impl Device { + pub fn new( + init: DeviceInit, + resource_override_path: Option, + upload_method: UploadMethod, + _cached_programs: Option>, + heaps_config: HeapsConfig, + instance_buffer_size: usize, + texture_cache_size: usize, + ) -> Self { + let DeviceInit { + instance, + adapter, + mut surface, + window_size, + descriptor_count, + cache_path, + save_cache, + backend_api, + } = init; + let renderer_name = "TODO renderer name".to_owned(); + let features = adapter.physical_device.features(); + + let memory_properties = adapter.physical_device.memory_properties(); + let mut heaps = { + let types = memory_properties.memory_types.iter().map(|ref mt| { + let mut config = heaps_config; + if !mt + .properties + .contains(hal::memory::Properties::CPU_VISIBLE) + { + config.linear = None; + } else if config.linear.is_none() { + config.linear = Some(LinearConfig { + linear_size: + (memory_properties.memory_heaps[mt.heap_index as usize] / 8 - 1) + .next_power_of_two(), + }); + } + if config.dynamic.is_none() { + config.dynamic = Some(DynamicConfig { + min_device_allocation: + (memory_properties.memory_heaps[mt.heap_index as usize] / 1024 - 1) + .next_power_of_two(), + block_size_granularity: + (memory_properties.memory_heaps[mt.heap_index as usize] / 1024 - 1) + .next_power_of_two(), + max_chunk_size: + (memory_properties.memory_heaps[mt.heap_index as usize] / 8 - 1) + .next_power_of_two(), + }) + } + (mt.properties, mt.heap_index as u32, config) + }); + + let heaps = memory_properties.memory_heaps.iter().cloned(); + unsafe { Heaps::new(types, heaps) } + }; + + let limits = adapter.physical_device.limits(); + let max_texture_size = 4400i32; // TODO use limits after it points to the correct texture size + + let (device, queue_group_family, queue_group_queues) = { + use hal::Capability; + use hal::queue::QueueFamily; + + let family = adapter + .queue_families + .iter() + .find(|family| { + hal::Graphics::supported_by(family.queue_type()) + && match &surface { + Some(surface) => surface.supports_queue_family(family), + None => true, + } + }) + .unwrap(); + + let priorities = vec![1.0]; + let (id, families) = (family.id(), [(family, priorities.as_slice())]); + let hal::Gpu { device, mut queues } = unsafe { + adapter + .physical_device + .open(&families, hal::Features::DUAL_SRC_BLENDING) + .unwrap_or_else(|_| { + adapter + .physical_device + .open(&families, hal::Features::empty()) + .unwrap() + }) + }; + (device, id, queues.take_raw(id).unwrap()) + }; + let mut render_pass_manager = RenderPassManager::new(); + + // Disable push constants for Intel's Vulkan driver on Windows + let has_broken_push_const_support = cfg!(target_os = "windows") + && backend_api == BackendApiType::Vulkan + && adapter.info.vendor == 0x8086; + let use_push_consts = !has_broken_push_const_support; + + let ( + swap_chain, + surface_format, + frames, + viewport, + frame_count, + ) = match surface.as_mut() { + Some(surface) => { + let ( + swap_chain, + surface_format, + frames, + viewport, + frame_count, + ) = Device::init_frames_with_surface( + &device, + &mut heaps, + &adapter, + surface, + Some(window_size), + None, + &mut render_pass_manager, + ); + ( + Some(swap_chain), + surface_format, + frames, + viewport, + frame_count, + ) + } + None => { + let ( + frames, + viewport, + ) = Device::init_frames( + &device, + &mut heaps, + hal::image::Extent { + width: window_size.0 as _, + height: window_size.1 as _, + depth: 1, + }, + &mut render_pass_manager, + SURFACE_FORMAT, + FRAME_COUNT_NOT_MAILBOX, + None, + ); + ( + None, + ImageFormat::BGRA8, + frames, + viewport, + FRAME_COUNT_NOT_MAILBOX, + ) + } + }; + + // Samplers + let sampler_linear = unsafe { + device.create_sampler(hal::image::SamplerInfo::new( + hal::image::Filter::Linear, + hal::image::WrapMode::Clamp, + )) + } + .expect("sampler_linear failed"); + + let sampler_nearest = unsafe { + device.create_sampler(hal::image::SamplerInfo::new( + hal::image::Filter::Nearest, + hal::image::WrapMode::Clamp, + )) + } + .expect("sampler_linear failed"); + + let pipeline_requirements: FastHashMap = + from_str(&shader_source::PIPELINES).expect("Failed to load pipeline requirements"); + + let mut desc_allocator = DescriptorAllocator::new(); + + let mut frame_fence = ArrayVec::new(); + let mut command_pools: ArrayVec<[CommandPool; FRAME_COUNT_MAILBOX]> = ArrayVec::new(); + let mut staging_buffer_pool = ArrayVec::new(); + let mut instance_buffers = ArrayVec::new(); + for _ in 0 .. frame_count { + let fence = device.create_fence(false).expect("create_fence failed"); + frame_fence.push(Fence { + inner: fence, + is_submitted: false, + }); + + let mut hal_cp = unsafe { + device.create_command_pool( + queue_group_family, + hal::pool::CommandPoolCreateFlags::empty(), + ) + } + .expect("create_command_pool failed"); + unsafe { hal_cp.reset(false) }; + let mut cp = CommandPool::new(hal_cp); + cp.create_command_buffer(); + command_pools.push(cp); + staging_buffer_pool.push(BufferPool::new( + &device, + &mut heaps, + hal::buffer::Usage::TRANSFER_SRC, + 1, + (limits.non_coherent_atom_size - 1) as usize, + (limits.optimal_buffer_copy_pitch_alignment - 1) as usize, + (limits.optimal_buffer_copy_offset_alignment - 1) as usize, + texture_cache_size, + )); + instance_buffers.push(InstanceBufferHandler::new( + (limits.non_coherent_atom_size - 1) as usize, + (limits.optimal_buffer_copy_pitch_alignment - 1) as usize, + instance_buffer_size, + )); + } + + let mut command_buffer = command_pools[0].remove_cmd_buffer(); + // Start recording for the 1st frame + unsafe { Self::begin_cmd_buffer(&mut command_buffer) }; + + let locals_buffer = UniformBufferHandler::new( + hal::buffer::Usage::UNIFORM, + mem::size_of::(), + (limits.min_uniform_buffer_offset_alignment - 1) as usize, + ); + + let quad_buffer = VertexBufferHandler::new( + &device, + &mut heaps, + hal::buffer::Usage::VERTEX, + &QUAD, + (limits.optimal_buffer_copy_pitch_alignment - 1) as usize, + (limits.non_coherent_atom_size - 1) as usize, + ); + + let mut per_group_descriptor_sets = FastHashMap::default(); + let descriptor_data: + FastHashMap> + = [DescriptorGroup::Default, DescriptorGroup::Clip, DescriptorGroup::Primitive] + .iter() + .map(|g| { + let layouts_and_samplers = match g { + DescriptorGroup::Default => [ + (EMPTY_SET_0, vec![]), + (DEFAULT_SET_1, vec![&sampler_nearest]), + (COMMON_SET_2, vec![]), + (COMMON_SET_3, vec![]), + ], + DescriptorGroup::Clip => [ + (EMPTY_SET_0, vec![]), + (CLIP_SET_1, vec![&sampler_nearest, &sampler_nearest, &sampler_nearest, &sampler_nearest]), + (COMMON_SET_2, vec![]), + (COMMON_SET_3, vec![]), + ], + DescriptorGroup::Primitive => [ + (PRIMITIVE_SET_0, vec![&sampler_linear, &sampler_linear]), + (PRIMITIVE_SET_1, vec![&sampler_nearest, &sampler_nearest, &sampler_nearest, &sampler_nearest, &sampler_nearest, &sampler_nearest]), + (COMMON_SET_2, vec![]), + (COMMON_SET_3, vec![]), + ], + }; + + let ranges = layouts_and_samplers + .iter() + .map(|(bindings, _)| { + DescriptorRanges::from_bindings(bindings) + }).collect::>(); + + let set_layouts: ArrayVec<[B::DescriptorSetLayout; MAX_DESCRIPTOR_SET_COUNT]> = layouts_and_samplers + .iter() + .enumerate() + .map(|(index, (bindings, immutable_samplers))| { + let layout = unsafe { device.create_descriptor_set_layout(*bindings, immutable_samplers.iter().map(|s| *s)) } + .expect("create_descriptor_set_layout failed"); + if index == DESCRIPTOR_SET_PER_GROUP { + let mut descriptor_sets = Vec::new(); + unsafe { + desc_allocator.allocate( + &device, + &layout, + ranges[index], + descriptor_count.unwrap_or(DESCRIPTOR_COUNT), + &mut descriptor_sets, + ) + }.expect("Allocate descriptor sets failed"); + per_group_descriptor_sets.insert(*g, descriptor_sets); + } + layout + }).collect(); + + let pipeline_layout = unsafe { + device.create_pipeline_layout( + &set_layouts, + Some((hal::pso::ShaderStageFlags::VERTEX, 0..PUSH_CONSTANT_BLOCK_SIZE as u32)), + ) + } + .expect("create_pipeline_layout failed"); + (*g, DescriptorGroupData { + set_layouts, + ranges, + pipeline_layout, + }) + }).collect(); + + let descriptor_data = DescriptorData(descriptor_data); + + let per_pass_descriptors = DescriptorSetHandler::new( + &device, + &mut desc_allocator, + &descriptor_data, + &DescriptorGroup::Primitive, + DESCRIPTOR_SET_PER_PASS, + descriptor_count.unwrap_or(DESCRIPTOR_COUNT), + Vec::new(), + ); + + let per_draw_descriptors = DescriptorSetHandler::new( + &device, + &mut desc_allocator, + &descriptor_data, + &DescriptorGroup::Default, + DESCRIPTOR_SET_PER_DRAW, + descriptor_count.unwrap_or(DESCRIPTOR_COUNT), + Vec::new(), + ); + + let locals_descriptors = DescriptorSetHandler::new( + &device, + &mut desc_allocator, + &descriptor_data, + &DescriptorGroup::Default, + DESCRIPTOR_SET_LOCALS, + if use_push_consts { 1 } else { descriptor_count.unwrap_or(DESCRIPTOR_COUNT) }, + Vec::new(), + ); + + let image_available_semaphore = device.create_semaphore().expect("create_semaphore failed"); + let render_finished_semaphore = device.create_semaphore().expect("create_semaphore failed"); + + let pipeline_cache = if let Some(ref path) = cache_path { + Self::load_pipeline_cache(&device, &path, &adapter.physical_device) + } else { + None + }; + + Device { + device: Arc::new(device), + heaps: Arc::new(Mutex::new(heaps)), + limits, + surface_format, + adapter, + surface, + _instance: instance, + depth_format: DEPTH_FORMAT, + queue_group_family, + queue_group_queues, + command_pools, + command_buffer, + staging_buffer_pool, + swap_chain: swap_chain, + render_pass_manager, + clear_values: FastHashMap::default(), + frames, + frame_count, + viewport, + sampler_linear, + sampler_nearest, + current_frame_id: 0, + current_blend_state: Cell::new(None), + current_depth_test: None, + blend_color: Cell::new(ColorF::new(0.0, 0.0, 0.0, 0.0)), + _resource_override_path: resource_override_path, + // This is initialized to 1 by default, but it is reset + // at the beginning of each frame in `Renderer::bind_frame_data`. + device_pixel_ratio: 1.0, + depth_available: true, + upload_method, + inside_frame: false, + render_pass_state: None, + + capabilities: Capabilities { + supports_multisampling: false, //TODO + }, + depth_targets: FastHashMap::default(), + + programs: FastHashMap::default(), + shader_modules: FastHashMap::default(), + images: FastHashMap::default(), + gpu_cache_buffer: None, + gpu_cache_buffers: FastHashMap::default(), + retained_textures: Vec::new(), + fbos: FastHashMap::default(), + rbos: FastHashMap::default(), + desc_allocator, + + per_draw_descriptors, + bound_per_draw_bindings: PerDrawBindings::default(), + + per_pass_descriptors, + bound_per_pass_textures: PerPassBindings::default(), + + per_group_descriptors: DescriptorSetHandler::from_existing(per_group_descriptor_sets), + bound_per_group_textures: PerGroupBindings::default(), + + locals_descriptors, + bound_locals: Locals::default(), + descriptor_data, + + bound_textures: [0; RENDERER_TEXTURE_COUNT], + bound_program: INVALID_PROGRAM_ID, + bound_sampler: [TextureFilter::Linear; RENDERER_TEXTURE_COUNT], + bound_read_fbo: DEFAULT_READ_FBO, + bound_read_texture: (INVALID_TEXTURE_ID, 0), + bound_draw_fbo: DEFAULT_DRAW_FBO, + draw_target_usage: DrawTargetUsage::Draw, + scissor_rect: None, + + max_texture_size, + _renderer_name: renderer_name, + frame_id: GpuFrameId(0), + features, + + next_id: 0, + frame_fence, + image_available_semaphore, + render_finished_semaphore, + pipeline_requirements, + pipeline_cache, + cache_path, + save_cache, + + locals_buffer, + quad_buffer, + instance_buffers, + free_instance_buffers: Vec::new(), + download_buffer: None, + instance_range: 0..0, + wait_for_resize: false, + + use_push_consts, + } + } + + fn inside_render_pass(&self) -> bool { + self.render_pass_state.is_some() + } + + fn render_pass_depth_state(&self) -> RenderPassDepthState { + match self.render_pass_state { + Some(ref state) => state.depth_state(), + None => RenderPassDepthState::Disabled, + } + } + + fn load_pipeline_cache( + device: &B::Device, + path: &PathBuf, + physical_device: &B::PhysicalDevice, + ) -> Option { + let mut file = match File::open(path) { + Ok(file) => file, + Err(_) => { + warn!("File not found: {:?}", path); + return None; + } + }; + let mut bytes = Vec::new(); + match file.read_to_end(&mut bytes) { + Err(_) => { + warn!("Failed to read file: {:?}", path); + return None; + } + _ => {} + }; + + if physical_device.is_valid_cache(&bytes) { + let cache = unsafe { device.create_pipeline_cache(Some(&bytes)) }.expect(&format!( + "Failed to create pipeline cache from file: {:?}", + path + )); + Some(cache) + } else { + None + } + } + + pub(crate) fn recreate_swapchain(&mut self, window_size: Option<(i32, i32)>) -> DeviceIntSize { + self.device.wait_idle().unwrap(); + + let ref mut heaps = *self.heaps.lock().unwrap(); + for frame in self.frames.drain(..) { + frame.deinit(self.device.as_ref(), heaps); + } + + self.bound_per_draw_bindings = PerDrawBindings::default(); + self.per_draw_descriptors.reset(); + + self.bound_per_pass_textures = PerPassBindings::default(); + self.per_pass_descriptors.reset(); + + self.bound_per_group_textures = PerGroupBindings::default(); + self.per_group_descriptors.reset(); + + if !self.use_push_consts { + self.bound_locals = Locals::default(); + self.locals_descriptors.reset(); + } + + self.locals_buffer.reset(); + + let ( + swap_chain, + surface_format, + frames, + viewport, + _frame_count, + ) = if let Some (ref mut surface) = self.surface { + let ( + swap_chain, + surface_format, + frames, + viewport, + frame_count, + ) = Device::init_frames_with_surface( + self.device.as_ref(), + heaps, + &self.adapter, + surface, + window_size, + self.swap_chain.take(), + &mut self.render_pass_manager, + ); + ( + Some(swap_chain), + surface_format, + frames, + viewport, + frame_count, + ) + } else { + let extent = window_size.map_or( + hal::image::Extent { + width: 0, + height: 0, + depth: 1, + }, |w| { + hal::image::Extent { + width: w.0 as _, + height: w.1 as _, + depth: 1, + } + }); + let ( + frames, + viewport, + ) = Device::init_frames( + self.device.as_ref(), + heaps, + extent, + &mut self.render_pass_manager, + SURFACE_FORMAT, + FRAME_COUNT_NOT_MAILBOX, + None, + ); + ( + None, + ImageFormat::BGRA8, + frames, + viewport, + FRAME_COUNT_NOT_MAILBOX, + ) + }; + + self.swap_chain = swap_chain; + self.frames = frames; + self.viewport = viewport; + self.surface_format = surface_format; + self.wait_for_resize = false; + + let pipeline_cache = unsafe { self.device.create_pipeline_cache(None) } + .expect("Failed to create pipeline cache"); + if let Some(ref cache) = self.pipeline_cache { + unsafe { + self.device + .merge_pipeline_caches(&cache, Some(&pipeline_cache)) + .expect("merge_pipeline_caches failed");; + self.device.destroy_pipeline_cache(pipeline_cache); + } + } else { + self.pipeline_cache = Some(pipeline_cache); + } + DeviceIntSize::new(self.viewport.rect.w.into(), self.viewport.rect.h.into()) + } + + fn init_frames_with_surface( + device: &B::Device, + heaps: &mut Heaps, + adapter: &hal::Adapter, + surface: &mut B::Surface, + window_size: Option<(i32, i32)>, + old_swap_chain: Option, + render_pass_manager: &mut RenderPassManager, + ) -> ( + B::Swapchain, + ImageFormat, + ArrayVec<[Frame; FRAME_COUNT_MAILBOX]>, + hal::pso::Viewport, + usize, + ) { + let (caps, formats, present_modes) = surface.compatibility(&adapter.physical_device); + let present_mode = { + use hal::window::PresentMode::*; + [Mailbox, Fifo, Relaxed, Immediate] + .iter() + .cloned() + .find(|pm| present_modes.contains(pm)) + .expect("No PresentMode values specified!") + }; + let frame_count = if present_mode == hal::window::PresentMode::Mailbox { + *caps.image_count.end().min(&(FRAME_COUNT_MAILBOX as u32)) as usize + } else { + *caps.image_count.end().min(&(FRAME_COUNT_NOT_MAILBOX as u32)) as usize + }; + let available_surface_format = formats.map_or(SURFACE_FORMAT, |formats| { + formats + .into_iter() + .find(|format| format == &SURFACE_FORMAT) + .expect(&format!("{:?} surface is not supported!", SURFACE_FORMAT)) + }); + + let image_format = match available_surface_format { + SURFACE_FORMAT => ImageFormat::BGRA8, + f => unimplemented!("Unsupported surface format: {:?}", f), + }; + + let ext = caps.current_extent.expect("Can't acquire current extent!"); + let ext = (ext.width as i32, ext.height as i32); + let window_extent = + hal::window::Extent2D { + width: (window_size.unwrap_or(ext).0 as u32) + .min(caps.extents.end().width) + .max(caps.extents.start().width) + .max(1), + height: (window_size.unwrap_or(ext).1 as u32) + .min(caps.extents.end().height) + .max(caps.extents.start().height) + .max(1), + }; + + let mut swap_config = SwapchainConfig::new( + window_extent.width, + window_extent.height, + available_surface_format, + frame_count as _, + ) + .with_image_usage( + hal::image::Usage::TRANSFER_SRC + | hal::image::Usage::TRANSFER_DST + | hal::image::Usage::COLOR_ATTACHMENT, + ) + .with_mode(present_mode); + if caps.composite_alpha.contains(hal::CompositeAlpha::INHERIT) { + swap_config.composite_alpha = hal::CompositeAlpha::INHERIT; + } else if caps.composite_alpha.contains(hal::CompositeAlpha::OPAQUE) { + swap_config.composite_alpha = hal::CompositeAlpha::OPAQUE; + } + + let (swap_chain, images) = + unsafe { device.create_swapchain(surface, swap_config, old_swap_chain) } + .expect("create_swapchain failed"); + + assert_eq!(images.len(), frame_count); + + let image_extent = hal::image::Extent { + width: window_extent.width as _, + height: window_extent.height as _, + depth: 1, + }; + + let (frames, viewport) = + Self::init_frames( + device, + heaps, + image_extent, + render_pass_manager, + available_surface_format, + frame_count, + Some(images), + ); + + info!("Frames: {:?}", frames); + ( + swap_chain, + image_format, + frames, + viewport, + frame_count, + ) + } + + fn init_frames( + device: &B::Device, + heaps: &mut Heaps, + extent: hal::image::Extent, + render_pass_manager: &mut RenderPassManager, + surface_format: hal::format::Format, + frame_count: usize, + images: Option> + ) -> ( + ArrayVec<[Frame; FRAME_COUNT_MAILBOX]>, + hal::pso::Viewport, + ) { + let kind = hal::image::Kind::D2( + extent.width as _, + extent.height as _, + extent.depth as _, + 1, + ); + let frame_images: ArrayVec<[ImageCore; FRAME_COUNT_MAILBOX]> = match images { + Some(images) => { + images.into_iter().map(|image| { + ImageCore::from_image( + device, + image, + hal::image::ViewKind::D2Array, + surface_format, + COLOR_RANGE, + ) + }).collect() + }, + None => { + (0 .. frame_count).into_iter().map(|_| { + ImageCore::create( + device, + heaps, + kind, + hal::image::ViewKind::D2Array, + 1, + surface_format, + hal::image::Usage::TRANSFER_SRC + | hal::image::Usage::TRANSFER_DST + | hal::image::Usage::COLOR_ATTACHMENT, + COLOR_RANGE, + ) + }).collect() + }, + }; + let frames = frame_images.into_iter().map(|image| { + let depth = DepthBuffer::new( + device, + heaps, + extent.width, + extent.height, + DEPTH_FORMAT, + ); + let framebuffer = unsafe { + device.create_framebuffer( + render_pass_manager.get_render_pass(device, (surface_format.into(), None)), + Some(&image.view), + extent, + ) + } + .expect("create_framebuffer failed"); + + let framebuffer_depth = unsafe { + device.create_framebuffer( + render_pass_manager.get_render_pass(device, (surface_format.into(), Some(DEPTH_ATTACHMENT_STATE))), + vec![&image.view, &depth.core.view], + extent, + ) + } + .expect("create_framebuffer failed"); + Frame { + image, + depth, + framebuffer, + framebuffer_depth, + } + }).collect(); + let viewport = hal::pso::Viewport { + rect: hal::pso::Rect { + x: 0, + y: 0, + w: extent.width as _, + h: extent.height as _, + }, + depth: 0.0 .. 1.0, + }; + + ( + frames, + viewport, + ) + } + + pub fn set_device_pixel_ratio(&mut self, ratio: f32) { + self.device_pixel_ratio = ratio; + } + + pub fn update_program_cache(&mut self, _cached_programs: Rc) { + warn!("Program cache is not supported!"); + } + + /// Ensures that the maximum texture size is less than or equal to the + /// provided value. If the provided value is less than the value supported + /// by the driver, the latter is used. + pub fn clamp_max_texture_size(&mut self, size: i32) { + self.max_texture_size = self.max_texture_size.min(size); + } + + /// Returns the limit on texture dimensions (width or height). + pub fn max_texture_size(&self) -> i32 { + self.max_texture_size + } + + /// Returns the limit on texture array layers. + pub fn max_texture_layers(&self) -> usize { + self.limits.max_image_array_layers as usize + } + + pub fn get_capabilities(&self) -> &Capabilities { + &self.capabilities + } + + fn reset_next_frame_resources(&mut self) { + let prev_id = self.next_id; + self.next_id = (self.next_id + 1) % self.frame_count; + self.reset_state(); + if self.frame_fence[self.next_id].is_submitted { + unsafe { + self.device + .wait_for_fence(&self.frame_fence[self.next_id].inner, !0) + } + .expect("wait_for_fence failed"); + unsafe { + self.device + .reset_fence(&self.frame_fence[self.next_id].inner) + } + .expect("reset_fence failed"); + self.frame_fence[self.next_id].is_submitted = false; + } + unsafe { + self.command_pools[self.next_id].reset(); + let old_buffer = mem::replace( + &mut self.command_buffer, + self.command_pools[self.next_id].remove_cmd_buffer() + ); + self.command_pools[prev_id].return_cmd_buffer(old_buffer); + Self::begin_cmd_buffer(&mut self.command_buffer); + } + self.staging_buffer_pool[self.next_id].reset(); + self.reset_program_buffer_offsets(); + self.instance_buffers[self.next_id].reset(&mut self.free_instance_buffers); + self.delete_retained_textures(); + } + + pub fn reset_state(&mut self) { + self.bound_textures = [INVALID_TEXTURE_ID; RENDERER_TEXTURE_COUNT]; + self.bound_program = INVALID_PROGRAM_ID; + self.bound_sampler = [TextureFilter::Linear; RENDERER_TEXTURE_COUNT]; + self.bound_read_fbo = DEFAULT_READ_FBO; + self.bound_draw_fbo = DEFAULT_DRAW_FBO; + self.draw_target_usage = DrawTargetUsage::Draw; + } + + fn reset_program_buffer_offsets(&mut self) { + for program in self.programs.values_mut() { + if let Some(ref mut index_buffer) = program.index_buffer { + index_buffer[self.next_id].reset(); + program.vertex_buffer.as_mut().unwrap()[self.next_id].reset(); + } + } + } + + pub fn delete_program(&mut self, mut _program: ProgramId) { + // TODO delete program + _program = INVALID_PROGRAM_ID; + } + + pub fn create_program_linked( + &mut self, + base_filename: &str, + features: &str, + descriptor: &VertexDescriptor, + shader_kind: &ShaderKind, + ) -> Result { + let program = self.create_program(base_filename, shader_kind, &[features])?; + self.link_program(program, descriptor)?; + Ok(program) + } + + pub fn link_program( + &mut self, + _program: ProgramId, + _descriptor: &VertexDescriptor, + ) -> Result<(), ShaderError> { + warn!("link_program is not implemented with gfx backend"); + Ok(()) + } + pub fn create_program( + &mut self, + shader_name: &str, + shader_kind: &ShaderKind, + features: &[&str], + ) -> Result { + let mut name = String::from(shader_name); + for feature_names in features { + for feature in feature_names.split(',') { + if NON_SPECIALIZATION_FEATURES.iter().any(|f| *f == feature) { + name.push_str(&format!("_{}", feature.to_lowercase())); + } + } + } + + let desc_group = DescriptorGroup::from(*shader_kind); + let program = Program::create( + self.pipeline_requirements + .get(&name) + .expect(&format!("Can't load pipeline data for: {}!", name)) + .clone(), + self.device.as_ref(), + self.descriptor_data.pipeline_layout(&desc_group), + &mut *self.heaps.lock().unwrap(), + &self.limits, + &name, + features, + shader_kind.clone(), + &mut self.render_pass_manager, + self.frame_count, + &mut self.shader_modules, + self.pipeline_cache.as_ref(), + self.surface_format, + self.use_push_consts, + ); + + let id = self.generate_program_id(); + self.programs.insert(id, program); + Ok(id) + } + + pub fn create_program_with_kind( + &mut self, + shader_name: &str, + shader_kind: &ShaderKind, + features: &[&str], + _precache_flags: ShaderPrecacheFlags, + ) -> Result { + self.create_program(shader_name, shader_kind, features) + } + + pub fn bind_program(&mut self, program_id: &ProgramId) { + debug_assert!(self.inside_frame); + + if self.bound_program != *program_id { + self.bound_program = *program_id; + } + } + + fn bind_uniforms(&mut self) { + if self.use_push_consts { + self.programs + .get_mut(&self.bound_program) + .expect("Invalid bound program") + .constants[..].copy_from_slice( + unsafe { + std::mem::transmute::<_, &[u32; 17]>(&self.bound_locals) + } + ); + } + + self.locals_descriptors.bind_locals( + if self.use_push_consts { Locals::default() } else { self.bound_locals }, + self.device.as_ref(), + &mut self.desc_allocator, + &self.descriptor_data, + &mut self.locals_buffer, + &mut *self.heaps.lock().unwrap(), + ); + } + + pub fn set_uniforms(&mut self, _program_id: &ProgramId, projection: &Transform3D) { + self.bound_locals.uTransform = projection.to_row_arrays(); + } + + unsafe fn begin_cmd_buffer(cmd_buffer: &mut B::CommandBuffer) { + let flags = CommandBufferFlags::ONE_TIME_SUBMIT; + cmd_buffer.begin(flags, CommandBufferInheritanceInfo::default()); + } + + fn bind_textures(&mut self) { + debug_assert!(self.inside_frame); + assert_ne!(self.bound_program, INVALID_PROGRAM_ID); + let program = self + .programs + .get_mut(&self.bound_program) + .expect("Program not found."); + let descriptor_group = program.shader_kind.into(); + // Per draw textures and samplers + let per_draw_bindings = PerDrawBindings( + [ + self.bound_textures[0], + self.bound_textures[1], + self.bound_textures[2], + ], + [ + self.bound_sampler[0], + self.bound_sampler[1], + self.bound_sampler[2], + ], + ); + + self.per_draw_descriptors.bind_textures( + &self.bound_textures, + &self.bound_sampler, + per_draw_bindings, + &self.images, + None, + &mut self.desc_allocator, + self.device.as_ref(), + &self.descriptor_data, + &descriptor_group, + DESCRIPTOR_SET_PER_DRAW, + 0..PER_DRAW_TEXTURE_COUNT, + &self.sampler_linear, + &self.sampler_nearest, + ); + self.bound_per_draw_bindings = per_draw_bindings; + + // Per pass textures + if descriptor_group == DescriptorGroup::Primitive { + let per_pass_bindings = PerPassBindings( + [ + self.bound_textures[3], + self.bound_textures[4], + ], + ); + + self.per_pass_descriptors.bind_textures( + &self.bound_textures, + &self.bound_sampler, + per_pass_bindings, + &self.images, + None, + &mut self.desc_allocator, + self.device.as_ref(), + &self.descriptor_data, + &descriptor_group, + DESCRIPTOR_SET_PER_PASS, + PER_DRAW_TEXTURE_COUNT..PER_DRAW_TEXTURE_COUNT + PER_PASS_TEXTURE_COUNT, + &self.sampler_linear, + &self.sampler_nearest, + ); + self.bound_per_pass_textures = per_pass_bindings; + } + + // Per frame textures + let per_group_bindings = PerGroupBindings( + [ + self.bound_textures[5], + self.bound_textures[6], + self.bound_textures[7], + self.bound_textures[8], + self.bound_textures[9], + self.bound_textures[10], + ], + ); + + self.per_group_descriptors.bind_textures( + &self.bound_textures, + &self.bound_sampler, + (descriptor_group, per_group_bindings), + &self.images, + match descriptor_group { + DescriptorGroup::Default => None, + _ => self.gpu_cache_buffer.as_ref().map(|b| b.buffer.as_ref()), + }, + &mut self.desc_allocator, + self.device.as_ref(), + &self.descriptor_data, + &descriptor_group, + DESCRIPTOR_SET_PER_GROUP, + match descriptor_group { + DescriptorGroup::Default => PER_GROUP_RANGE_DEFAULT, + DescriptorGroup::Clip => PER_GROUP_RANGE_CLIP, + DescriptorGroup::Primitive => PER_GROUP_RANGE_PRIMITIVE, + }, + &self.sampler_linear, + &self.sampler_nearest, + ); + self.bound_per_group_textures = per_group_bindings; + } + + pub fn update_indices(&mut self, indices: &[I]) { + debug_assert!(self.inside_frame); + assert_ne!(self.bound_program, INVALID_PROGRAM_ID); + let program = self + .programs + .get_mut(&self.bound_program) + .expect("Program not found."); + + if let Some(ref mut index_buffer) = program.index_buffer { + index_buffer[self.next_id].update(self.device.as_ref(), indices, &mut *self.heaps.lock().unwrap()); + } else { + warn!("This function is for debug shaders only!"); + } + } + + pub fn update_vertices(&mut self, vertices: &[T]) { + debug_assert!(self.inside_frame); + assert_ne!(self.bound_program, INVALID_PROGRAM_ID); + let program = self + .programs + .get_mut(&self.bound_program) + .expect("Program not found."); + + if program.shader_kind.is_debug() { + program.vertex_buffer.as_mut().unwrap()[self.next_id].update(self.device.as_ref(), vertices, &mut *self.heaps.lock().unwrap()); + } else { + warn!("This function is for debug shaders only!"); + } + } + + fn update_instances(&mut self, instances: &[T]) { + self.instance_range = self.instance_buffers[self.next_id].add(self.device.as_ref(), instances, &mut *self.heaps.lock().unwrap(), &mut self.free_instance_buffers); + } + + fn draw(&mut self) { + assert!(self.inside_render_pass()); + self.bind_textures(); + self.bind_uniforms(); + + assert_eq!(self.draw_target_usage, DrawTargetUsage::Draw); + let descriptor_group = self.programs + .get(&self.bound_program) + .expect("Program not found") + .shader_kind.into(); + + let ref desc_set_per_group = self.per_group_descriptors.descriptor_set(&(descriptor_group, self.bound_per_group_textures)); + let desc_set_per_pass = match descriptor_group { + DescriptorGroup::Primitive => Some(self.per_pass_descriptors.descriptor_set(&self.bound_per_pass_textures)), + _ => None, + }; + let ref desc_set_per_draw = self.per_draw_descriptors.descriptor_set(&self.bound_per_draw_bindings); + let locals = if self.use_push_consts { Locals::default() } else { self.bound_locals }; + let ref desc_set_locals = self.locals_descriptors.descriptor_set(&locals); + let depth_state = self.render_pass_depth_state(); + + self.programs + .get_mut(&self.bound_program) + .expect("Program not found") + .submit( + &mut self.command_buffer, + self.viewport.clone(), + desc_set_per_draw, + desc_set_per_pass, + desc_set_per_group, + Some(*desc_set_locals), + self.current_blend_state.get(), + self.blend_color.get(), + self.current_depth_test, + depth_state, + self.scissor_rect, + self.next_id, + self.descriptor_data.pipeline_layout(&descriptor_group), + self.use_push_consts, + &self.quad_buffer, + &self.instance_buffers[self.next_id], + self.instance_range.clone(), + ); + } + + pub fn begin_frame(&mut self) -> GpuFrameId { + debug_assert!(!self.inside_frame); + self.inside_frame = true; + self.bound_textures = [INVALID_TEXTURE_ID; RENDERER_TEXTURE_COUNT]; + self.bound_sampler = [TextureFilter::Linear; RENDERER_TEXTURE_COUNT]; + self.bound_read_fbo = DEFAULT_READ_FBO; + self.bound_draw_fbo = DEFAULT_DRAW_FBO; + self.draw_target_usage = DrawTargetUsage::Draw; + self.bound_locals.uMode = 0; + + self.frame_id + } + + fn bind_texture_impl(&mut self, slot: TextureSlot, id: TextureId, sampler: TextureFilter) { + debug_assert!(self.inside_frame); + + if self.bound_textures[slot.0] != id { + self.bound_textures[slot.0] = id; + self.bound_sampler[slot.0] = sampler; + } + } + + pub fn bind_texture(&mut self, sampler: S, texture: &Texture) + where + S: Into, + { + self.bind_texture_impl(sampler.into(), texture.id, texture.filter); + texture.bound_in_frame.set(self.frame_id); + } + + pub fn bind_external_texture(&mut self, sampler: S, external_texture: &ExternalTexture) + where + S: Into, + { + self.bind_texture_impl(sampler.into(), external_texture.id, TextureFilter::Linear); + } + + pub fn bind_read_target_impl(&mut self, fbo_id: FBOId) { + debug_assert!(self.inside_frame); + if self.bound_read_fbo != fbo_id { + self.bound_read_fbo = fbo_id; + } + } + + pub fn bind_read_target(&mut self, read_target: ReadTarget) { + let fbo_id = match read_target { + ReadTarget::Default => DEFAULT_READ_FBO, + ReadTarget::Texture { texture, layer } => texture.fbos[layer], + }; + self.bind_read_target_impl(fbo_id) + } + + #[cfg(feature = "capture")] + fn bind_read_texture(&mut self, texture_id: TextureId, layer_id: i32) { + self.bound_read_texture = (texture_id, layer_id); + } + + fn bind_draw_target_impl(&mut self, fbo_id: FBOId, usage: DrawTargetUsage) { + debug_assert!(self.inside_frame); + + self.draw_target_usage = usage; + if self.bound_draw_fbo != fbo_id { + let old_fbo_id = mem::replace(&mut self.bound_draw_fbo, fbo_id); + let transit_back_old_image = match (self.fbos.get(&old_fbo_id), self.fbos.get(&self.bound_draw_fbo)) { + (None, _) => false, + (Some(_), None) => true, + (Some(old_fbo), Some(bound_fbo)) => old_fbo.texture_id != bound_fbo.texture_id + }; + if transit_back_old_image { + let texture_id = self.fbos[&old_fbo_id].texture_id; + if let Some((barrier, pipeline_stages)) = self.images[&texture_id].core.transit( + (hal::image::Access::SHADER_READ, hal::image::Layout::ShaderReadOnlyOptimal), + self.images[&texture_id].core.subresource_range.clone(), + ) { + unsafe { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + } + } + } + + pub fn reset_read_target(&mut self) { + self.bind_read_target_impl(DEFAULT_READ_FBO); + } + + pub fn reset_draw_target(&mut self) { + self.bind_draw_target_impl(DEFAULT_DRAW_FBO, DrawTargetUsage::Draw); + self.depth_available = true; + } + + fn is_draw_target(&self, id: TextureId) -> bool { + match self.fbos.get(&self.bound_draw_fbo) { + Some(fbo) => fbo.texture_id == id, + None => false, + } + } + + pub fn bind_draw_target(&mut self, texture_target: DrawTarget, usage: DrawTargetUsage) { + let (fbo_id, dimensions, depth_available) = match texture_target { + DrawTarget::Default(dim) => { + if let DrawTargetUsage::CopyOnly = usage { + panic!("We should not have default target with CopyOnly usage!"); + } + (DEFAULT_DRAW_FBO, dim, true) + }, + DrawTarget::Texture { + texture, + layer, + with_depth, + } => { + texture.bound_in_frame.set(self.frame_id); + let fbo_id = if with_depth { + texture.fbos_with_depth[layer] + } else { + texture.fbos[layer] + }; + + self.fbos.get_mut(&fbo_id).unwrap().layer_index = layer as u16; + if !self.is_draw_target(texture.id) { + let image = &self.images[&texture.id].core; + let image_state = match usage { + DrawTargetUsage::CopyOnly => (hal::image::Access::TRANSFER_WRITE, hal::image::Layout::TransferDstOptimal), + DrawTargetUsage::Draw => (hal::image::Access::COLOR_ATTACHMENT_WRITE, hal::image::Layout::ColorAttachmentOptimal), + }; + if let Some((barrier, pipeline_stages)) = image.transit( + image_state, + image.subresource_range.clone(), + ) { + unsafe { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + } + + (fbo_id, texture.get_dimensions(), with_depth) + } + }; + + self.depth_available = depth_available; + self.bind_draw_target_impl(fbo_id, usage); + self.viewport.rect = hal::pso::Rect { + x: 0, + y: 0, + w: dimensions.width as _, + h: dimensions.height as _, + }; + } + + pub fn create_fbo_for_external_texture(&mut self, _texture_id: u32) -> FBOId { + warn!("External texture creation is missing"); + FBOId(0) + } + + pub fn create_fbo(&mut self) -> FBOId { + DEBUG_READ_FBO + } + + pub fn delete_fbo(&mut self, _fbo: FBOId) { + warn!("delete fbo is missing"); + } + + pub fn bind_external_draw_target(&mut self, fbo_id: FBOId) { + debug_assert!(self.inside_frame); + + if self.bound_draw_fbo != fbo_id { + self.bound_draw_fbo = fbo_id; + } + } + + fn generate_texture_id(&self) -> TextureId { + let mut rng = rand::thread_rng(); + let mut texture_id = INVALID_TEXTURE_ID + 1; + while self.images.contains_key(&texture_id) { + texture_id = rng.gen_range::(INVALID_TEXTURE_ID + 1, u32::max_value()); + } + texture_id + } + + fn generate_program_id(&self) -> ProgramId { + let mut rng = rand::thread_rng(); + let mut program_id = ProgramId(INVALID_PROGRAM_ID.0 + 1); + while self.programs.contains_key(&program_id) { + program_id = + ProgramId(rng.gen_range::(INVALID_PROGRAM_ID.0 + 1, u32::max_value())); + } + program_id + } + + fn generate_fbo_ids(&mut self, count: i32) -> SmallVec<[FBOId; 16]> { + let mut rng = rand::thread_rng(); + let mut fboids = SmallVec::new(); + let mut fbo_id = FBOId(DEFAULT_DRAW_FBO.0 + 1); + for _ in 0 .. count { + while self.fbos.contains_key(&fbo_id) || fboids.contains(&fbo_id) { + fbo_id = FBOId(rng.gen_range::(DEFAULT_DRAW_FBO.0 + 1, u32::max_value())); + } + fboids.push(fbo_id); + } + fboids + } + + fn generate_rbo_id(&mut self) -> RBOId { + let mut rng = rand::thread_rng(); + let mut rbo_id = RBOId(1); // 0 is used for invalid + while self.rbos.contains_key(&rbo_id) { + rbo_id = RBOId(rng.gen_range::(1, u32::max_value())); + } + rbo_id + } + + pub fn create_dummy_gpu_cache_texture(&self) -> Texture { + debug_assert!(self.inside_frame); + let texture = Texture { + id: self.generate_texture_id(), + target: TextureTarget::Default as _, + size: DeviceIntSize::new(1, 1), + layer_count: 1, + format: ImageFormat::RGBAF32, + filter: Default::default(), + fbos: vec![], + fbos_with_depth: vec![], + last_frame_used: self.frame_id, + bound_in_frame: Cell::new(GpuFrameId(0)), + flags: TextureFlags::default(), + is_buffer: true, + }; + record_gpu_alloc(texture.size_in_bytes()); + texture + } + + pub fn set_gpu_cache_buffer( + &mut self, + buffer: GpuCacheBuffer, + ) { + if let Some(barrier) = buffer.transit(hal::buffer::Access::HOST_WRITE | hal::buffer::Access::HOST_READ, false) { + unsafe { + self.command_buffer.pipeline_barrier( + PipelineStage::VERTEX_SHADER | PipelineStage::FRAGMENT_SHADER + .. PipelineStage::HOST, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + self.gpu_cache_buffer = Some(buffer); + } + + pub fn transit_gpu_cache_buffer(&mut self) { + use hal::pso::PipelineStage as PS; + let ref buffer = self.gpu_cache_buffer.as_ref().unwrap(); + if let Some(barrier) = buffer.transit(hal::buffer::Access::SHADER_READ, true) { + unsafe { + self.command_buffer.pipeline_barrier( + PS::HOST .. PS::VERTEX_SHADER | PS::FRAGMENT_SHADER, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + } + + pub fn create_texture( + &mut self, + target: TextureTarget, + format: ImageFormat, + mut width: i32, + mut height: i32, + filter: TextureFilter, + render_target: Option, + layer_count: i32, + ) -> Texture { + debug_assert!(self.inside_frame); + assert!(!(width == 0 || height == 0 || layer_count == 0)); + + if width > self.max_texture_size || height > self.max_texture_size { + error!( + "Attempting to allocate a texture of size {}x{} above the limit, trimming", + width, height + ); + width = width.min(self.max_texture_size); + height = height.min(self.max_texture_size); + } + + // Set up the texture book-keeping. + let mut texture = Texture { + id: self.generate_texture_id(), + target: target as _, + size: DeviceIntSize::new(width, height), + layer_count, + format, + filter, + fbos: vec![], + fbos_with_depth: vec![], + last_frame_used: self.frame_id, + bound_in_frame: Cell::new(GpuFrameId(0)), + flags: TextureFlags::default(), + is_buffer: false, + }; + + assert!(!self.images.contains_key(&texture.id)); + let usage_base = hal::image::Usage::TRANSFER_SRC + | hal::image::Usage::TRANSFER_DST + | hal::image::Usage::SAMPLED; + + let view_kind = match target { + TextureTarget::Array => hal::image::ViewKind::D2Array, + _ => hal::image::ViewKind::D2, + }; + + let (mip_levels, usage) = match texture.filter { + TextureFilter::Nearest => ( + 1, + usage_base | hal::image::Usage::COLOR_ATTACHMENT, + ), + TextureFilter::Linear => ( + 1, + usage_base | hal::image::Usage::COLOR_ATTACHMENT, + ), + TextureFilter::Trilinear => ( + (width as f32).max(height as f32).log2().floor() as u8 + 1, + usage_base | hal::image::Usage::COLOR_ATTACHMENT, + ), + }; + let img = Image::new( + self.device.as_ref(), + &mut *self.heaps.lock().unwrap(), + texture.format, + texture.size.width, + texture.size.height, + texture.layer_count, + view_kind, + mip_levels, + usage, + ); + + unsafe { + if let Some((barrier, pipeline_stages)) = img.core.transit( + (hal::image::Access::SHADER_READ, hal::image::Layout::ShaderReadOnlyOptimal), + img.core.subresource_range.clone(), + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + + self.images.insert(texture.id, img); + + // Set up FBOs, if required. + if let Some(rt_info) = render_target { + self.init_fbos(&mut texture, false); + if rt_info.has_depth { + self.init_fbos(&mut texture, true); + } + } + + record_gpu_alloc(texture.size_in_bytes()); + + texture + } + + fn init_fbos(&mut self, texture: &mut Texture, with_depth: bool) { + let new_fbos = self.generate_fbo_ids(texture.layer_count); + let (rbo_id, depth) = if with_depth { + let rbo_id = self.acquire_depth_target(texture.get_dimensions()); + (rbo_id, Some(&self.rbos[&rbo_id].core.view)) + } else { + (RBOId(0), None) + }; + + for i in 0 .. texture.layer_count as u16 { + let fbo = Framebuffer::new( + self.device.as_ref(), + &texture, + &self.images.get(&texture.id).unwrap(), + i, + &mut self.render_pass_manager, + rbo_id.clone(), + depth, + ); + self.fbos.insert(new_fbos[i as usize], fbo); + + if with_depth { + texture.fbos_with_depth.push(new_fbos[i as usize]) + } else { + texture.fbos.push(new_fbos[i as usize]) + } + } + } + + fn execute_transitions<'a>( + command_buffer: &mut B::CommandBuffer, + transitions: impl IntoIterator, std::ops::Range)>, + ) { + let mut barriers: SmallVec<[hal::memory::Barrier; 2]> = SmallVec::new(); + let mut pipeline_stages = PipelineStage::empty() .. PipelineStage::empty(); + for (barrier, ps) in transitions { + barriers.push(barrier); + pipeline_stages.start |= ps.start; + pipeline_stages.end |= ps.end; + } + if !barriers.is_empty() { + unsafe { + command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + barriers, + ); + } + } + } + + /// Copies the contents from one renderable texture to another. + pub fn blit_renderable_texture(&mut self, dst: &mut Texture, src: &Texture) { + assert!(!self.inside_render_pass()); + dst.bound_in_frame.set(self.frame_id); + src.bound_in_frame.set(self.frame_id); + debug_assert!(self.inside_frame); + debug_assert!(dst.size.width >= src.size.width); + debug_assert!(dst.size.height >= src.size.height); + assert!(dst.layer_count >= src.layer_count); + + let rect = DeviceIntRect::new(DeviceIntPoint::zero(), src.get_dimensions().to_i32()); + let (src_img, layers) = (&self.images[&src.id].core, src.layer_count); + let dst_img = &self.images[&dst.id].core; + + // let range = hal::image::SubresourceRange { + // aspects: hal::format::Aspects::COLOR, + // levels: 0 .. 1, + // layers: 0 .. layers as _, + // }; + + unsafe { + assert_eq!(src_img.state.get().1, hal::image::Layout::ShaderReadOnlyOptimal); + let (src_image_prev_state, dst_image_prev_state) = ( + src_img.state.get(), + dst_img.state.get() + ); + let transitions = src_img.transit( + (hal::image::Access::TRANSFER_READ, hal::image::Layout::TransferSrcOptimal), + src_img.subresource_range.clone(), + ).into_iter().chain( + dst_img.transit( + (hal::image::Access::TRANSFER_WRITE, hal::image::Layout::TransferDstOptimal), + dst_img.subresource_range.clone(), + ) + ); + + Self::execute_transitions(&mut self.command_buffer, transitions); + + self.command_buffer.copy_image( + &src_img.image, + hal::image::Layout::TransferSrcOptimal, + &dst_img.image, + hal::image::Layout::TransferDstOptimal, + &[hal::command::ImageCopy { + src_subresource: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: 0, + layers: 0 .. layers as _, + }, + src_offset: hal::image::Offset { + x: rect.origin.x as i32, + y: rect.origin.y as i32, + z: 0, + }, + dst_subresource: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: 0, + layers: 0 .. layers as _, + }, + dst_offset: hal::image::Offset { + x: rect.origin.x as i32, + y: rect.origin.y as i32, + z: 0, + }, + extent: hal::image::Extent { + width: rect.size.width as u32, + height: rect.size.height as u32, + depth: 1, + }, + }], + ); + + let transitions = src_img.transit( + src_image_prev_state, + src_img.subresource_range.clone(), + ).into_iter().chain( + dst_img.transit( + dst_image_prev_state, + dst_img.subresource_range.clone(), + ) + ); + Self::execute_transitions(&mut self.command_buffer, transitions); + } + } + + fn generate_mipmaps(&mut self, texture: &Texture) { + assert!(!self.inside_render_pass()); + texture.bound_in_frame.set(self.frame_id); + + let image = self + .images + .get_mut(&texture.id) + .expect("Texture not found."); + + let mut mip_width = texture.size.width; + let mut mip_height = texture.size.height; + + let mut half_mip_width = mip_width / 2; + let mut half_mip_height = mip_height / 2; + + unsafe { + assert_eq!(image.core.state.get().1, hal::image::Layout::ShaderReadOnlyOptimal); + if let Some((barrier, pipeline_stages)) = image.core.transit( + (hal::image::Access::TRANSFER_WRITE, hal::image::Layout::TransferDstOptimal), + image.core.subresource_range.clone(), + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + + for index in 1 .. image.kind.num_levels() { + if let Some((barrier, pipeline_stages)) = image.core.transit( + (hal::image::Access::TRANSFER_READ, hal::image::Layout::TransferSrcOptimal), + hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: index - 1 .. index, + layers: 0 .. 1, + }, + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + self.command_buffer.blit_image( + &image.core.image, + hal::image::Layout::TransferSrcOptimal, + &image.core.image, + hal::image::Layout::TransferDstOptimal, + hal::image::Filter::Linear, + &[hal::command::ImageBlit { + src_subresource: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: index - 1, + layers: 0 .. 1, + }, + src_bounds: hal::image::Offset { x: 0, y: 0, z: 0 } .. hal::image::Offset { + x: mip_width as i32, + y: mip_height as i32, + z: 1, + }, + dst_subresource: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: index, + layers: 0 .. 1, + }, + dst_bounds: hal::image::Offset { + x: 0 as i32, + y: 0 as i32, + z: 0, + } .. hal::image::Offset { + x: half_mip_width as i32, + y: half_mip_height as i32, + z: 1, + }, + }], + ); + if let Some((barrier, pipeline_stages)) = image.core.transit( + (hal::image::Access::TRANSFER_WRITE, hal::image::Layout::TransferDstOptimal), + hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: index - 1 .. index, + layers: 0 .. 1, + }, + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + mip_width = half_mip_width; + if half_mip_width > 1 { + half_mip_width /= 2; + } + mip_height = half_mip_height; + if half_mip_height > 1 { + half_mip_height /= 2; + } + } + + if let Some((barrier, pipeline_stages)) = image.core.transit( + (hal::image::Access::SHADER_READ, hal::image::Layout::ShaderReadOnlyOptimal), + image.core.subresource_range.clone(), + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + } + + fn acquire_depth_target(&mut self, dimensions: DeviceIntSize) -> RBOId { + if let Entry::Occupied(mut o) = self.depth_targets.entry(dimensions) { + o.get_mut().refcount += 1; + return o.get().rbo_id + } + + let rbo_id = self.generate_rbo_id(); + let rbo = DepthBuffer::new( + self.device.as_ref(), + &mut *self.heaps.lock().unwrap(), + dimensions.width as _, + dimensions.height as _, + self.depth_format, + ); + if let Some((barrier, pipeline_stages)) = rbo.core.transit( + ( + hal::image::Access::DEPTH_STENCIL_ATTACHMENT_READ + | hal::image::Access::DEPTH_STENCIL_ATTACHMENT_WRITE, + hal::image::Layout::DepthStencilAttachmentOptimal + ), + rbo.core.subresource_range.clone(), + ) { + unsafe { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + self.rbos.insert(rbo_id, rbo); + let target = SharedDepthTarget { + rbo_id, + refcount: 1, + }; + record_gpu_alloc(depth_target_size_in_bytes(&dimensions)); + self.depth_targets.insert(dimensions, target); + rbo_id + } + + fn release_depth_target(&mut self, dimensions: DeviceIntSize) { + let mut entry = match self.depth_targets.entry(dimensions) { + Entry::Occupied(x) => x, + Entry::Vacant(..) => panic!("Releasing unknown depth target"), + }; + debug_assert!(entry.get().refcount != 0); + entry.get_mut().refcount -= 1; + if entry.get().refcount == 0 { + let t = entry.remove(); + let old_rbo = self.rbos.remove(&t.rbo_id).unwrap(); + old_rbo.deinit(self.device.as_ref(), &mut *self.heaps.lock().unwrap()); + record_gpu_free(depth_target_size_in_bytes(&dimensions)); + } + } + + pub fn blit_render_target(&mut self, src_rect: DeviceIntRect, dest_rect: DeviceIntRect) { + assert!(!self.inside_render_pass()); + debug_assert!(self.inside_frame); + + let (src_format, src_img, src_layer) = if self.bound_read_fbo == DEFAULT_READ_FBO { + ( + self.surface_format, + &self.frames[self.current_frame_id].image, + 0, + ) + } else { + let fbo = &self.fbos[&self.bound_read_fbo]; + let img = &self.images[&fbo.texture_id]; + (img.format, &img.core, fbo.layer_index) + }; + + let (dest_format, dst_img, dest_layer, dst_image_prev_state, dst_image_transition) = if self.bound_draw_fbo == DEFAULT_DRAW_FBO { + // Unfortunately we blit to the main target if debug renderer is enabled + let image = &self.frames[self.current_frame_id].image; + ( + self.surface_format, + image, + 0, + None, + None, + ) + } else { + let fbo = &self.fbos[&self.bound_draw_fbo]; + let img = &self.images[&fbo.texture_id]; + let layer = fbo.layer_index; + let prev_state = Some(img.core.state.get()); + let transition = img.core.transit( + (hal::image::Access::TRANSFER_WRITE, hal::image::Layout::TransferDstOptimal), + img.core.subresource_range.clone(), + ); + (img.format, &img.core, layer, prev_state, transition) + }; + + // let src_range = hal::image::SubresourceRange { + // aspects: hal::format::Aspects::COLOR, + // levels: 0 .. 1, + // layers: src_layer .. src_layer + 1, + // }; + // let dest_range = hal::image::SubresourceRange { + // aspects: hal::format::Aspects::COLOR, + // levels: 0 .. 1, + // layers: dest_layer .. dest_layer + 1, + // }; + + unsafe { + let src_image_prev_state = src_img.state.get(); + let transitions = src_img.transit( + (hal::image::Access::TRANSFER_READ, hal::image::Layout::TransferSrcOptimal), + src_img.subresource_range.clone(), + ).into_iter().chain(dst_image_transition); + Self::execute_transitions(&mut self.command_buffer, transitions); + + if src_rect.size != dest_rect.size || src_format != dest_format { + self.command_buffer.blit_image( + &src_img.image, + hal::image::Layout::TransferSrcOptimal, + &dst_img.image, + hal::image::Layout::TransferDstOptimal, + hal::image::Filter::Linear, + &[hal::command::ImageBlit { + src_subresource: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: 0, + layers: src_layer .. src_layer + 1, + }, + src_bounds: hal::image::Offset { + x: src_rect.origin.x as i32, + y: src_rect.origin.y as i32, + z: 0, + } .. hal::image::Offset { + x: src_rect.origin.x as i32 + src_rect.size.width as i32, + y: src_rect.origin.y as i32 + src_rect.size.height as i32, + z: 1, + }, + dst_subresource: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: 0, + layers: dest_layer .. dest_layer + 1, + }, + dst_bounds: hal::image::Offset { + x: dest_rect.origin.x as i32, + y: dest_rect.origin.y as i32, + z: 0, + } .. hal::image::Offset { + x: dest_rect.origin.x as i32 + dest_rect.size.width as i32, + y: dest_rect.origin.y as i32 + dest_rect.size.height as i32, + z: 1, + }, + }], + ); + } else { + self.command_buffer.copy_image( + &src_img.image, + hal::image::Layout::TransferSrcOptimal, + &dst_img.image, + hal::image::Layout::TransferDstOptimal, + &[hal::command::ImageCopy { + src_subresource: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: 0, + layers: src_layer .. src_layer + 1, + }, + src_offset: hal::image::Offset { + x: src_rect.origin.x as i32, + y: src_rect.origin.y as i32, + z: 0, + }, + dst_subresource: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: 0, + layers: dest_layer as _ .. (dest_layer + 1) as _, + }, + dst_offset: hal::image::Offset { + x: dest_rect.origin.x as i32, + y: dest_rect.origin.y as i32, + z: 0, + }, + extent: hal::image::Extent { + width: src_rect.size.width as u32, + height: src_rect.size.height as u32, + depth: 1, + }, + }], + ); + } + + let transitions = src_img.transit( + src_image_prev_state, + src_img.subresource_range.clone(), + ).into_iter().chain( + dst_image_prev_state.map_or(None, |state| { + dst_img.transit( + state, + dst_img.subresource_range.clone(), + ) + }) + ); + Self::execute_transitions(&mut self.command_buffer, transitions); + } + } + + /// Performs a blit while flipping vertically. Useful for blitting textures + /// (which use origin-bottom-left) to the main framebuffer (which uses + /// origin-top-left). + pub fn blit_render_target_invert_y( + &mut self, + src_rect: DeviceIntRect, + dest_rect: DeviceIntRect, + ) { + debug_assert!(self.inside_frame); + self.blit_render_target(src_rect, dest_rect); + } + + /// Notifies the device that the contents of a render target are no longer + /// needed. + /// + /// FIXME(bholley): We could/should invalidate the depth targets earlier + /// than the color targets, i.e. immediately after each pass. + pub fn invalidate_render_target(&mut self, _texture: &Texture) { + warn!("invalidate_render_target not implemented!"); + } + + /// Notifies the device that a render target is about to be reused. + /// + /// This method adds or removes a depth target as necessary. + pub fn reuse_render_target( + &mut self, + texture: &mut Texture, + rt_info: RenderTargetInfo, + ) { + texture.last_frame_used = self.frame_id; + + // Add depth support if needed. + if rt_info.has_depth && !texture.supports_depth() { + self.init_fbos(texture, true); + } + } + + fn free_texture(&mut self, mut texture: Texture) { + if texture.bound_in_frame.get() == self.frame_id { + self.retained_textures.push(texture); + return; + } + + if texture.still_in_flight(self.frame_id, self.frame_count) { + self.wait_for_resources(); + } + + if texture.supports_depth() { + self.release_depth_target(texture.get_dimensions()); + } + + if !texture.fbos_with_depth.is_empty() { + for old in texture.fbos_with_depth.drain(..) { + debug_assert!(self.bound_draw_fbo != old || self.bound_read_fbo != old); + let old_fbo = self.fbos.remove(&old).unwrap(); + old_fbo.deinit(self.device.as_ref()); + } + } + + if !texture.fbos.is_empty() { + for old in texture.fbos.drain(..) { + debug_assert!(self.bound_draw_fbo != old || self.bound_read_fbo != old); + let old_fbo = self.fbos.remove(&old).unwrap(); + old_fbo.deinit(self.device.as_ref()); + } + } + + self.per_draw_descriptors.retain(&texture.id); + self.per_pass_descriptors.retain(&texture.id); + self.per_group_descriptors.retain(&texture.id); + + + if texture.is_buffer { + if let Some(buffer) = self.gpu_cache_buffers.remove(&texture.id) { + buffer.deinit(self.device.as_ref(), &mut *self.heaps.lock().unwrap()); + } + } else { + let image = self.images.remove(&texture.id).expect("Texture not found."); + image.deinit(self.device.as_ref(), &mut *self.heaps.lock().unwrap()); + } + record_gpu_free(texture.size_in_bytes()); + texture.id = 0; + } + + fn delete_retained_textures(&mut self) { + let textures: SmallVec<[Texture; 16]> = self.retained_textures.drain(..).collect(); + for texture in textures { + self.free_texture(texture); + } + } + + pub fn delete_texture(&mut self, texture: Texture) { + //debug_assert!(self.inside_frame); + if texture.size.width + texture.size.height == 0 { + return; + } + + self.free_texture(texture); + } + + pub fn retain_cache_buffer(&mut self, texture: Texture) { + self.retained_textures.push(texture); + } + + #[cfg(feature = "replay")] + pub fn delete_external_texture(&mut self, mut external: ExternalTexture) { + warn!("delete external texture is missing"); + external.id = 0; + } + + pub fn switch_mode(&mut self, mode: i32) { + debug_assert!(self.inside_frame); + self.bound_locals.uMode = mode; + } + + pub fn create_pbo(&mut self) -> PBO { + PBO {} + } + + pub fn delete_pbo(&mut self, _pbo: PBO) {} + + pub fn upload_texture<'a>( + &'a mut self, + texture: &'a Texture, + _pbo: &PBO, + _upload_count: usize, + ) -> TextureUploader<'a, B> { + debug_assert!(self.inside_frame); + + match self.upload_method { + UploadMethod::Immediate => unimplemented!(), + UploadMethod::PixelBuffer(..) => TextureUploader { + device: self, + texture, + }, + } + } + + pub fn upload_texture_immediate(&mut self, texture: &Texture, pixels: &[T]) { + texture.bound_in_frame.set(self.frame_id); + let len = pixels.len() / texture.layer_count as usize; + for i in 0 .. texture.layer_count { + let start = len * i as usize; + + self.images + .get_mut(&texture.id) + .expect("Texture not found.") + .update( + self.device.as_ref(), + &mut self.command_buffer, + &mut self.staging_buffer_pool[self.next_id], + DeviceIntRect::new(DeviceIntPoint::new(0, 0), texture.size), + i, + texels_to_u8_slice(&pixels[start .. (start + len)]), + ); + } + if texture.filter == TextureFilter::Trilinear { + self.generate_mipmaps(texture); + } + } + + #[cfg(feature = "capture")] + pub fn read_pixels(&mut self, img_desc: &ImageDescriptor) -> Vec { + let mut pixels = vec![0; (img_desc.size.width * img_desc.size.height * 4) as usize]; + self.read_pixels_into( + DeviceIntRect::new( + DeviceIntPoint::zero(), + DeviceIntSize::new(img_desc.size.width, img_desc.size.height), + ), + ReadPixelsFormat::Rgba8, + &mut pixels, + ); + pixels + } + + /// Read rectangle of pixels into the specified output slice. + pub fn read_pixels_into( + &mut self, + rect: DeviceIntRect, + read_format: ReadPixelsFormat, + output: &mut [u8], + ) { + self.wait_for_resources(); + + let bytes_per_pixel = match read_format { + ReadPixelsFormat::Standard(imf) => imf.bytes_per_pixel(), + ReadPixelsFormat::Rgba8 => 4, + }; + let size_in_bytes = (bytes_per_pixel * rect.size.width * rect.size.height) as usize; + assert_eq!(output.len(), size_in_bytes); + let capture_read = + cfg!(feature = "capture") && self.bound_read_texture.0 != INVALID_TEXTURE_ID; + + let (image, image_format, layer) = if capture_read { + let img = &self.images[&self.bound_read_texture.0]; + (&img.core, img.format, self.bound_read_texture.1 as u16) + } else if self.bound_read_fbo == DEFAULT_READ_FBO { + ( + &self.frames[self.current_frame_id].image, + self.surface_format, + 0, + ) + } else { + let fbo = &self.fbos[&self.bound_read_fbo]; + let img = &self.images[&fbo.texture_id]; + let layer = fbo.layer_index; + (&img.core, img.format, layer) + }; + + let (fmt_mismatch, stride) = if bytes_per_pixel < image_format.bytes_per_pixel() { + // Special case which can occur during png save, because we force to read Rgba8 values from an Rgbaf32 texture. + ( + true, + (image_format.bytes_per_pixel() / bytes_per_pixel) as usize, + ) + } else { + assert_eq!(bytes_per_pixel, image_format.bytes_per_pixel()); + (false, 1) + }; + + assert!(output.len() <= DOWNLOAD_BUFFER_SIZE, "output len {:?} buffer size {:?}", output.len(), DOWNLOAD_BUFFER_SIZE); + if self.download_buffer.is_none() { + self.download_buffer = Some(Buffer::new( + self.device.as_ref(), + &mut *self.heaps.lock().unwrap(), + MemoryUsageValue::Download, + hal::buffer::Usage::TRANSFER_DST, + (self.limits.optimal_buffer_copy_pitch_alignment - 1) as usize, + DOWNLOAD_BUFFER_SIZE / stride, + stride, + )); + } + let download_buffer = self.download_buffer.as_mut().unwrap(); + let mut command_pool = unsafe { + self.device.create_command_pool( + self.queue_group_family, + hal::pool::CommandPoolCreateFlags::empty(), + ) + } + .expect("create_command_pool failed"); + unsafe { command_pool.reset(false) }; + + let mut cmd_buffer = command_pool.allocate_one(RawLevel::Primary); + unsafe { + Self::begin_cmd_buffer(&mut cmd_buffer); + + // let range = hal::image::SubresourceRange { + // aspects: hal::format::Aspects::COLOR, + // levels: 0 .. 1, + // layers: layer .. layer + 1, + // }; + let buffer_barrier = download_buffer.transit(hal::buffer::Access::TRANSFER_WRITE); + let prev_image_state = image.state.get(); + match image.transit( + (hal::image::Access::TRANSFER_READ, hal::image::Layout::TransferSrcOptimal), + image.subresource_range.clone(), + ) { + Some((barrier, pipeline_stages)) => { + cmd_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + buffer_barrier.into_iter().chain(Some(barrier)), + ); + } + None => { + cmd_buffer.pipeline_barrier( + PipelineStage::TRANSFER .. PipelineStage::TRANSFER, + hal::memory::Dependencies::empty(), + buffer_barrier.into_iter(), + ); + }, + }; + + cmd_buffer.copy_image_to_buffer( + &image.image, + hal::image::Layout::TransferSrcOptimal, + &download_buffer.buffer, + &[hal::command::BufferImageCopy { + buffer_offset: 0, + buffer_width: rect.size.width as u32, + buffer_height: rect.size.height as u32, + image_layers: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: 0, + layers: layer .. layer + 1, + }, + image_offset: hal::image::Offset { + x: rect.origin.x as i32, + y: rect.origin.y as i32, + z: 0, + }, + image_extent: hal::image::Extent { + width: rect.size.width as _, + height: rect.size.height as _, + depth: 1 as _, + }, + }], + ); + if let Some((barrier, pipeline_stages)) = image.transit( + prev_image_state, + image.subresource_range.clone(), + ) { + cmd_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + cmd_buffer.finish(); + } + + let mut copy_fence = self + .device + .create_fence(false) + .expect("create_fence failed"); + + unsafe { + self.device + .reset_fence(©_fence) + .expect("reset_fence failed"); + let submission = hal::queue::Submission { + command_buffers: Some(&cmd_buffer), + wait_semaphores: None, + signal_semaphores: None, + }; + self.queue_group_queues[0].submit::<_, _, B::Semaphore, _, _>( + submission, + Some(&mut copy_fence), + ); + self.device + .wait_for_fence(©_fence, !0) + .expect("wait_for_fence failed"); + self.device.destroy_fence(copy_fence); + } + + let mut data = vec![0; download_buffer.buffer_size]; + let range = 0 .. download_buffer.buffer_size as u64; + if fmt_mismatch { + let mut f32_data = vec![0f32; download_buffer.buffer_size]; + unsafe { + let mut mapped = download_buffer + .memory_block + .map(self.device.as_ref(), range.clone()) + .expect("Mapping memory block failed"); + let slice = mapped.read(self.device.as_ref(), range).expect("Read failed"); + f32_data[0 .. slice.len()].copy_from_slice(&slice); + } + download_buffer.memory_block.unmap(self.device.as_ref()); + for i in 0 .. f32_data.len() { + data[i] = round_to_int(f32_data[i].min(0f32).max(1f32)); + } + } else { + unsafe { + let mut mapped = download_buffer + .memory_block + .map(self.device.as_ref(), range.clone()) + .expect("Mapping memory block failed"); + let slice = mapped.read(self.device.as_ref(), range).expect("Read failed"); + data[0 .. slice.len()].copy_from_slice(&slice); + } + download_buffer.memory_block.unmap(self.device.as_ref()); + } + data.truncate(output.len()); + if !capture_read && self.surface_format == ImageFormat::BGRA8 { + let width = rect.size.width as usize; + let height = rect.size.height as usize; + let row_pitch: usize = bytes_per_pixel as usize * width; + // Vertical flip the result and convert to RGBA + for y in 0 .. height as usize { + for x in 0 .. width as usize { + let offset: usize = y * row_pitch + x * 4; + let rev_offset: usize = (height - 1 - y) * row_pitch + x * 4; + output[offset + 0] = data[rev_offset + 2]; + output[offset + 1] = data[rev_offset + 1]; + output[offset + 2] = data[rev_offset + 0]; + output[offset + 3] = data[rev_offset + 3]; + } + } + } else { + output.swap_with_slice(&mut data); + } + + unsafe { + command_pool.reset(false); + self.device.destroy_command_pool(command_pool); + } + } + + /// Get texels of a texture into the specified output slice. + pub fn get_tex_image_into( + &mut self, + _texture: &Texture, + _format: ImageFormat, + _output: &mut [u8], + ) { + unimplemented!(); + } + + /// Attaches the provided texture to the current Read FBO binding. + #[cfg(feature = "capture")] + fn attach_read_texture_raw(&mut self, texture_id: u32, _target: TextureTarget, layer_id: i32) { + self.bind_read_texture(texture_id, layer_id); + } + + #[cfg(feature = "capture")] + pub fn attach_read_texture_external( + &mut self, + _texture_id: u32, + _target: TextureTarget, + _layer_id: i32, + ) { + unimplemented!(); + } + + #[cfg(feature = "capture")] + pub fn attach_read_texture(&mut self, texture: &Texture, layer_id: i32) { + self.attach_read_texture_raw(texture.id, texture.target.into(), layer_id) + } + + pub fn invalidate_read_texture(&mut self) { + self.bound_read_texture = (INVALID_TEXTURE_ID, 0); + } + + pub fn bind_vao(&mut self, _vao: &VAO) {} + + pub fn create_vao(&mut self, _descriptor: &VertexDescriptor) -> VAO { + VAO {} + } + + pub fn delete_vao(&mut self, _vao: VAO) {} + + pub fn create_vao_with_new_instances( + &mut self, + _descriptor: &VertexDescriptor, + _base_vao: &VAO, + ) -> VAO { + VAO {} + } + + pub fn update_vao_main_vertices( + &mut self, + _vao: &VAO, + _vertices: &[V], + _usage_hint: VertexUsageHint, + ) { + if self.bound_program != INVALID_PROGRAM_ID { + self.update_vertices( + &_vertices + .iter() + .map(|v| v.to_primitive_type()) + .collect::>(), + ); + } + } + + pub fn update_vao_instances( + &mut self, + _vao: &VAO, + instances: &[V], + _usage_hint: VertexUsageHint, + ) { + let data = instances + .iter() + .map(|pi| pi.to_primitive_type()) + .collect::>(); + self.update_instances(&data); + } + + pub fn update_vao_indices( + &mut self, + _vao: &VAO, + _indices: &[I], + _usage_hint: VertexUsageHint, + ) { + if self.bound_program != INVALID_PROGRAM_ID { + self.update_indices(_indices); + } + } + + pub fn draw_triangles_u16(&mut self, _first_vertex: i32, _index_count: i32) { + debug_assert!(self.inside_frame); + self.draw(); + } + + pub fn draw_triangles_u32(&mut self, _first_vertex: i32, _index_count: i32) { + debug_assert!(self.inside_frame); + self.draw(); + } + + pub fn draw_nonindexed_lines(&mut self, _first_vertex: i32, _vertex_count: i32) { + debug_assert!(self.inside_frame); + self.draw(); + } + + pub fn draw_indexed_triangles_instanced_u16( + &mut self, + _index_count: i32, + _instance_count: i32, + ) { + debug_assert!(self.inside_frame); + self.draw(); + } + + pub fn end_frame(&mut self) { + self.reset_draw_target(); + self.reset_read_target(); + + debug_assert!(self.inside_frame); + self.inside_frame = false; + + self.frame_id.0 += 1; + } + + pub fn begin_render_pass_inner( + &mut self, + dst_layout: hal::image::Layout, + ) { + let (color_clear, depth_clear) = match self.clear_values.remove(&self.bound_draw_fbo) { + Some((None, Some(depth))) => (Some(PLACEHOLDER_CLEAR), Some(depth)), + Some(clear_values) => clear_values, + None => (None, None), + }; + + let mut depth_att_state = DEPTH_ATTACHMENT_STATE; + if depth_clear.is_some() { + depth_att_state.load_op = hal::pass::AttachmentLoadOp::Clear; + } + + let (frame_buffer, render_pass_state) = if self.bound_draw_fbo == DEFAULT_DRAW_FBO { + let frame = &self.frames[self.current_frame_id]; + let mut render_pass_state = RenderPassState { + target_texture: None, + color_attachment: AttachmentState { + format: SURFACE_FORMAT, + src_layout: frame.image.state.get().1, + dst_layout, + load_op: if color_clear.is_some() { + hal::pass::AttachmentLoadOp::Clear + } else { + hal::pass::AttachmentLoadOp::Load + }, + }, + depth_attachment: Some(depth_att_state), + }; + match self.depth_available { + true => ( + &frame.framebuffer_depth, + render_pass_state + ), + false => { + render_pass_state.depth_attachment = None; + ( + &frame.framebuffer, + render_pass_state, + ) + }, + } + } else { + let fbo = &self.fbos[&self.bound_draw_fbo]; + let texture_id = fbo.texture_id; + let image = &self.images[&texture_id]; + ( + &fbo.fbo, + RenderPassState { + target_texture: Some(fbo.texture_id), + color_attachment: AttachmentState { + format: image.format.into(), + src_layout: image.core.state.get().1, + dst_layout: hal::image::Layout::ColorAttachmentOptimal, + load_op: if color_clear.is_some() { + hal::pass::AttachmentLoadOp::Clear + } else { + hal::pass::AttachmentLoadOp::Load + }, + }, + depth_attachment: if self.depth_available { + Some(depth_att_state) + } else { + None + }, + }, + ) + }; + + let render_pass = render_pass_state + .get_suitable_render_pass(self.device.as_ref(), &mut self.render_pass_manager); + self.render_pass_state = Some(render_pass_state); + + unsafe { + self.command_buffer.begin_render_pass( + render_pass, + frame_buffer, + self.viewport.rect, + color_clear.into_iter().chain(depth_clear), + hal::command::SubpassContents::Inline, + ); + } + } + + pub fn begin_render_pass( + &mut self, + transit_to_presentable_state: bool, + transit_to_transfer_src_state: bool, + ) { + assert!(!self.inside_render_pass()); + assert_eq!(self.draw_target_usage, DrawTargetUsage::Draw); + let dst_layout = match (transit_to_presentable_state, transit_to_transfer_src_state) { + (true, true) => hal::image::Layout::General, + (true, false) => hal::image::Layout::Present, + (false, true) => hal::image::Layout::TransferSrcOptimal, + (false, false) => hal::image::Layout::ColorAttachmentOptimal, + }; + + self.begin_render_pass_inner(dst_layout); + } + + pub fn end_render_pass(&mut self) { + assert!(self.inside_render_pass()); + let render_pass_state = mem::replace(&mut self.render_pass_state, None).unwrap(); + let image = match render_pass_state.target_texture { + Some(texture_id) => &self.images.get_mut(&texture_id).unwrap().core, + None => &self.frames.get_mut(self.current_frame_id).unwrap().image, + }; + + let new_layout = render_pass_state.color_attachment.dst_layout; + let new_access = match new_layout { + hal::image::Layout::ColorAttachmentOptimal => hal::image::Access::COLOR_ATTACHMENT_READ + | hal::image::Access::COLOR_ATTACHMENT_WRITE, + hal::image::Layout::Present => hal::image::Access::MEMORY_READ, + hal::image::Layout::General => hal::image::Access::MEMORY_READ, + hal::image::Layout::TransferSrcOptimal => hal::image::Access::TRANSFER_READ, + hal::image::Layout::TransferDstOptimal => hal::image::Access::TRANSFER_WRITE, + l => unimplemented!("Unhandled layout {:?}", l), + }; + image.state.set((new_access, new_layout)); + unsafe { self.command_buffer.end_render_pass() }; + } + + fn clear_target_rect( + &mut self, + rect: DeviceIntRect, + color: Option<[f32; 4]>, + depth: Option, + ) { + assert!(self.inside_render_pass()); + if color.is_none() && depth.is_none() { + return; + } + + let rect = hal::pso::ClearRect { + rect: hal::pso::Rect { + x: rect.origin.x as i16, + y: rect.origin.y as i16, + w: rect.size.width as i16, + h: rect.size.height as i16, + }, + layers: 0 .. 1, + }; + + let color_clear = color.map(|c| hal::command::AttachmentClear::Color { + index: 0, + value: hal::command::ClearColor::Sfloat(c), + }); + + let depth_clear = depth.map(|d| hal::command::AttachmentClear::DepthStencil { + depth: Some(d), + stencil: None, + }); + + unsafe { + self.command_buffer.clear_attachments( + color_clear.into_iter().chain(depth_clear), + Some(rect) + ); + } + } + + fn clear_target_image(&mut self, color: Option<[f32; 4]>, depth: Option) { + assert!(!self.inside_render_pass()); + let (img, layer, dimg) = if self.bound_draw_fbo == DEFAULT_DRAW_FBO { + panic!("This should be handled by attachment load operations"); + } else { + let fbo = &self.fbos[&self.bound_draw_fbo]; + let img = &self.images[&fbo.texture_id]; + let dimg = if depth.is_some() { + Some(&self.rbos[&fbo.rbo].core) + } else { + None + }; + (&img.core, fbo.layer_index, dimg) + }; + + assert_eq!(self.draw_target_usage, DrawTargetUsage::Draw); + + //Note: this function is assumed to be called within an active FBO + // thus, we bring back the targets into renderable state + unsafe { + if let Some(color) = color { + if let Some((barrier, pipeline_stages)) = img.transit( + (hal::image::Access::TRANSFER_WRITE, hal::image::Layout::TransferDstOptimal), + img.subresource_range.clone(), + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + self.command_buffer.clear_image( + &img.image, + hal::image::Layout::TransferDstOptimal, + hal::command::ClearColorRaw { float32: [color[0], color[1], color[2], color[3]] }, + hal::command::ClearDepthStencilRaw { + depth: 0.0, + stencil: 0, + }, + Some(hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: 0 .. 1, + layers: layer .. layer + 1, + }), + ); + if let Some((barrier, pipeline_stages)) = img.transit( + (hal::image::Access::COLOR_ATTACHMENT_WRITE, hal::image::Layout::ColorAttachmentOptimal), + img.subresource_range.clone(), + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + + } + + if let (Some(depth), Some(dimg)) = (depth, dimg) { + assert_ne!(self.current_depth_test, None); + let prev_dimg_state = dimg.state.get(); + if let Some((barrier, pipeline_stages)) = dimg.transit( + (hal::image::Access::TRANSFER_WRITE, hal::image::Layout::TransferDstOptimal), + dimg.subresource_range.clone(), + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + self.command_buffer.clear_image( + &dimg.image, + hal::image::Layout::TransferDstOptimal, + hal::command::ClearColorRaw { float32: [0.0; 4] }, + hal::command::ClearDepthStencilRaw { depth, stencil: 0 }, + Some(dimg.subresource_range.clone()), + ); + if let Some((barrier, pipeline_stages)) = dimg.transit( + prev_dimg_state, + dimg.subresource_range.clone(), + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + } + } + + pub fn clear_target( + &mut self, + color: Option<[f32; 4]>, + depth: Option, + rect: Option, + can_use_load_op: bool, + ) { + if let Some(mut rect) = rect { + let target_rect = if self.bound_draw_fbo == DEFAULT_DRAW_FBO { + DeviceIntRect::new( + DeviceIntPoint::zero(), + DeviceIntSize::new(self.viewport.rect.w as _, self.viewport.rect.h as _), + ) + } else { + let extent = &self.images[&self.fbos[&self.bound_draw_fbo].texture_id] + .kind + .extent(); + DeviceIntRect::new( + DeviceIntPoint::zero(), + DeviceIntSize::new(extent.width as _, extent.height as _), + ) + }; + rect.size.width = rect.size.width.min(target_rect.size.width); + rect.size.height = rect.size.height.min(target_rect.size.height); + if !self.inside_render_pass() { + self.begin_render_pass(false, false); + self.clear_target_rect(rect, color, depth); + self.end_render_pass(); + } else { + self.clear_target_rect(rect, color, depth); + } + } else if can_use_load_op { + let color = color.map(|c| ClearValueRaw { color: ClearColorRaw { float32: c} }); + let depth = depth.map(|d| ClearValueRaw { depth_stencil: ClearDepthStencilRaw { depth: d, stencil: 0} }); + match self.clear_values.entry(self.bound_draw_fbo) { + Entry::Occupied(mut o) => { + let (old_color, old_depth) = o.get_mut(); + if !color.is_none() { + *old_color = color; + } + if !depth.is_none() { + *old_depth = depth; + } + } + Entry::Vacant(v) => { + v.insert((color, depth)); + } + } + } else { + self.clear_target_image(color, depth); + } + } + + pub fn enable_depth(&mut self) { + assert!( + self.depth_available, + "Enabling depth test without depth target" + ); + self.current_depth_test = Some(LESS_EQUAL_TEST); + } + + pub fn disable_depth(&mut self) { + self.current_depth_test = None; + } + + pub fn set_depth_func(&mut self, _depth_func: DepthFunction) { + // TODO add Less depth function + //self.current_depth_test = depth_func; + } + + pub fn enable_depth_write(&mut self) { + assert!( + self.depth_available, + "Enabling depth test without depth target" + ); + self.current_depth_test = Some(LESS_EQUAL_WRITE); + } + + pub fn disable_depth_write(&mut self) { + if self.current_depth_test == Some(LESS_EQUAL_WRITE) { + self.current_depth_test = Some(LESS_EQUAL_TEST); + } + } + + pub fn disable_stencil(&self) { + warn!("disable stencil is missing") + } + + pub fn set_scissor_rect(&mut self, rect: DeviceIntRect) { + self.scissor_rect = Some(rect); + } + + pub fn enable_scissor(&self) {} + + pub fn disable_scissor(&mut self) { + self.scissor_rect = None; + } + + pub fn set_blend(&self, enable: bool) { + if !enable { + self.current_blend_state.set(None) + } + } + + pub fn set_blend_mode_alpha(&self) { + self.current_blend_state.set(Some(ALPHA)); + } + + pub fn set_blend_mode_premultiplied_alpha(&self) { + self.current_blend_state + .set(Some(BlendState::PREMULTIPLIED_ALPHA)); + } + + pub fn set_blend_mode_premultiplied_dest_out(&self) { + self.current_blend_state.set(Some(PREMULTIPLIED_DEST_OUT)); + } + + pub fn set_blend_mode_multiply(&self) { + self.current_blend_state.set(Some(BlendState::MULTIPLY)); + } + + pub fn set_blend_mode_max(&self) { + self.current_blend_state.set(Some(MAX)); + } + + pub fn set_blend_mode_min(&self) { + self.current_blend_state.set(Some(MIN)); + } + + pub fn set_blend_mode_subpixel_pass0(&self) { + self.current_blend_state.set(Some(SUBPIXEL_PASS0)); + } + + pub fn set_blend_mode_subpixel_pass1(&self) { + self.current_blend_state.set(Some(SUBPIXEL_PASS1)); + } + + pub fn set_blend_mode_subpixel_with_bg_color_pass0(&self) { + self.current_blend_state.set(Some(SUBPIXEL_WITH_BG_COLOR_PASS0)); + } + + pub fn set_blend_mode_subpixel_with_bg_color_pass1(&self) { + self.current_blend_state.set(Some(SUBPIXEL_WITH_BG_COLOR_PASS1)); + } + + pub fn set_blend_mode_subpixel_with_bg_color_pass2(&self) { + self.current_blend_state.set(Some(SUBPIXEL_WITH_BG_COLOR_PASS2)); + } + + pub fn set_blend_mode_subpixel_constant_text_color(&self, color: ColorF) { + self.current_blend_state.set(Some(SUBPIXEL_CONSTANT_TEXT_COLOR)); + // color is an unpremultiplied color. + self.blend_color + .set(ColorF::new(color.r, color.g, color.b, 1.0)); + } + + pub fn set_blend_mode_subpixel_dual_source(&self) { + self.current_blend_state.set(Some(SUBPIXEL_DUAL_SOURCE)); + } + + pub fn set_blend_mode_show_overdraw(&self) { + self.current_blend_state.set(Some(OVERDRAW)); + } + + pub fn supports_features(&self, features: hal::Features) -> bool { + self.features.contains(features) + } + + pub fn echo_driver_messages(&self) { + warn!("echo_driver_messages is unimplemeneted"); + } + + pub fn set_next_frame_id(&mut self) { + if self.wait_for_resize { + self.device.wait_idle().unwrap(); + return; + } + unsafe { + match self.swap_chain.as_mut() { + Some(swap_chain) => { + match swap_chain.acquire_image( + !0, + Some(&mut self.image_available_semaphore), + None, + ) { + Ok((id, _)) => { + self.current_frame_id = id as _; + let depth_image = &self.frames[self.current_frame_id].depth.core; + if let Some((barrier, pipeline_stages)) = depth_image.transit( + ( + hal::image::Access::DEPTH_STENCIL_ATTACHMENT_READ + | hal::image::Access::DEPTH_STENCIL_ATTACHMENT_WRITE, + hal::image::Layout::DepthStencilAttachmentOptimal + ), + depth_image.subresource_range.clone(), + ) { + self.command_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + Err(acq_err) => { + match acq_err { + AcquireError::OutOfDate => warn!("AcquireError : OutOfDate"), + AcquireError::SurfaceLost(surf) => warn!("AcquireError : SurfaceLost => {:?}", surf), + AcquireError::NotReady => warn!("AcquireError : NotReady"), + AcquireError::DeviceLost(dev) => warn!("AcquireError : DeviceLost => {:?}", dev), + AcquireError::OutOfMemory(mem) => warn!("AcquireError : OutOfMemory => {:?}", mem), + AcquireError::Timeout => warn!("AcquireError : Timeout"), + } + self.wait_for_resize = true; + }, + } + } + None => { + self.current_frame_id = (self.current_frame_id + 1) % self.frame_count; + } + } + } + } + + pub fn submit_to_gpu(&mut self) { + if self.wait_for_resize { + self.device.wait_idle().unwrap(); + self.reset_next_frame_resources(); + return; + } + unsafe { + self.command_buffer.finish(); + match self.swap_chain.as_mut() { + Some(swap_chain) => { + let submission = hal::queue::Submission { + command_buffers: &[&self.command_buffer], + wait_semaphores: Some(( + &self.image_available_semaphore, + PipelineStage::BOTTOM_OF_PIPE, + )), + signal_semaphores: Some(&self.render_finished_semaphore), + }; + self.queue_group_queues[0] + .submit(submission, Some(&mut self.frame_fence[self.next_id].inner)); + self.frame_fence[self.next_id].is_submitted = true; + + // present frame + match self.queue_group_queues[0] + .present( + std::iter::once((&swap_chain, self.current_frame_id as _)), + Some(&self.render_finished_semaphore), + ) { + Ok(suboptimal) => { + match suboptimal { + Some(_) => { + warn!("Suboptimal: The swapchain no longer matches the surface"); + self.wait_for_resize = true; + }, + None => {} + } + } + Err(presenterr) => { + match presenterr { + PresentError::OutOfDate => warn!("PresentError : OutOfDate"), + PresentError::SurfaceLost(surf) => warn!("PresentError : SurfaceLost => {:?}", surf), + PresentError::DeviceLost(dev) => warn!("PresentError : DeviceLost => {:?}", dev), + PresentError::OutOfMemory(mem) => warn!("PresentError : OutOfMemory => {:?}", mem), + } + self.wait_for_resize = true; + } + } + } + None => { + let submission = hal::queue::Submission { + command_buffers: &[&self.command_buffer], + wait_semaphores: None, + signal_semaphores: None, + }; + self.queue_group_queues[0].submit::<_, _, B::Semaphore, _, _>( + submission, + Some(&mut self.frame_fence[self.next_id].inner), + ); + self.frame_fence[self.next_id].is_submitted = true; + } + } + }; + self.reset_next_frame_resources(); + } + + pub fn wait_for_resources_and_reset(&mut self) { + self.wait_for_resources(); + self.reset_command_pools(); + } + + fn wait_for_resources(&mut self) { + for fence in &mut self.frame_fence { + if fence.is_submitted { + unsafe { self.device.wait_for_fence(&fence.inner, !0) } + .expect("wait_for_fence failed"); + unsafe { self.device.reset_fence(&fence.inner) }.expect("reset_fence failed"); + fence.is_submitted = false; + } + } + } + + fn reset_command_pools(&mut self) { + for command_pool in &mut self.command_pools { + unsafe { command_pool.reset() }; + } + } + + /// Generates a memory report for the resources managed by the device layer. + pub fn report_memory(&self) -> MemoryReport { + let mut report = MemoryReport::default(); + for dim in self.depth_targets.keys() { + report.depth_target_textures += depth_target_size_in_bytes(dim); + } + report + } + + pub fn deinit(mut self) { + self.device.wait_idle().unwrap(); + for mut texture in self.retained_textures { + texture.id = 0; + } + unsafe { + if self.save_cache && self.cache_path.is_some() { + let pipeline_cache = self + .device + .create_pipeline_cache(None) + .expect("Failed to create pipeline cache"); + let data; + if let Some(cache) = self.pipeline_cache { + self.device + .merge_pipeline_caches(&cache, Some(&pipeline_cache)) + .expect("merge_pipeline_caches failed"); + data = self + .device + .get_pipeline_cache_data(&cache) + .expect("get_pipeline_cache_data failed"); + self.device.destroy_pipeline_cache(cache); + } else { + data = self + .device + .get_pipeline_cache_data(&pipeline_cache) + .expect("get_pipeline_cache_data failed"); + }; + self.device.destroy_pipeline_cache(pipeline_cache); + + if data.len() > 0 { + let mut file = OpenOptions::new() + .write(true) + .create(true) + .open(&self.cache_path.as_ref().unwrap()) + .expect("File open/creation failed"); + + use std::io::Write; + file.write(&data).expect("File write failed"); + } + } else { + if let Some(cache) = self.pipeline_cache { + self.device.destroy_pipeline_cache(cache); + } + } + + let mut heaps = Arc::try_unwrap(self.heaps).unwrap().into_inner().unwrap(); + + self.command_pools[self.next_id].return_cmd_buffer(self.command_buffer); + for command_pool in self.command_pools { + command_pool.destroy(self.device.as_ref()); + } + for staging_buffer_pool in self.staging_buffer_pool { + staging_buffer_pool.deinit(self.device.as_ref(), &mut heaps); + } + self.quad_buffer.deinit(self.device.as_ref(), &mut heaps); + for instance_buffer in self.instance_buffers { + instance_buffer.deinit(self.device.as_ref(), &mut heaps); + } + for buffer in self.free_instance_buffers { + buffer.deinit(self.device.as_ref(), &mut heaps); + } + if let Some(buffer) = self.download_buffer { + buffer.deinit(self.device.as_ref(), &mut heaps); + } + for frame in self.frames.drain(..) { + frame.deinit(self.device.as_ref(), &mut heaps); + } + for (_, image) in self.images { + image.deinit(self.device.as_ref(), &mut heaps); + } + for (_, rbo) in self.fbos { + rbo.deinit(self.device.as_ref()); + } + for (_, rbo) in self.rbos { + rbo.deinit(self.device.as_ref(), &mut heaps); + } + + if let Some(buffer) = self.gpu_cache_buffer { + self.device.as_ref().destroy_buffer(Arc::try_unwrap(buffer.buffer).unwrap()); + } + + for (_ , buffer) in self.gpu_cache_buffers.into_iter() { + buffer.deinit(self.device.as_ref(), &mut heaps); + } + self.device.destroy_sampler(self.sampler_linear); + self.device.destroy_sampler(self.sampler_nearest); + + self.per_draw_descriptors.free(&mut self.desc_allocator); + self.per_group_descriptors.free(&mut self.desc_allocator); + self.per_pass_descriptors.free(&mut self.desc_allocator); + self.locals_descriptors.free(&mut self.desc_allocator); + + self.desc_allocator.dispose(self.device.as_ref()); + self.locals_buffer.deinit(self.device.as_ref(), &mut heaps); + for (_, program) in self.programs { + program.deinit(self.device.as_ref(), &mut heaps) + } + heaps.dispose(self.device.as_ref()); + for (_, (vs_module, fs_module)) in self.shader_modules { + self.device.destroy_shader_module(vs_module); + self.device.destroy_shader_module(fs_module); + } + self.descriptor_data.deinit(self.device.as_ref()); + self.render_pass_manager.deinit(self.device.as_ref()); + for fence in self.frame_fence { + self.device.destroy_fence(fence.inner); + } + self.device + .destroy_semaphore(self.image_available_semaphore); + self.device + .destroy_semaphore(self.render_finished_semaphore); + if let Some(swap_chain) = self.swap_chain { + self.device.destroy_swapchain(swap_chain); + } + } + // We must ensure these are dropped before `self._instance` or we segfault with Vulkan + mem::drop(self.device); + mem::drop(self.queue_group_queues); + } +} + +pub struct TextureUploader<'a, B: hal::Backend> { + device: &'a mut Device, + texture: &'a Texture, +} + +impl<'a, B: hal::Backend> TextureUploader<'a, B> { + pub fn upload( + &mut self, + rect: DeviceIntRect, + layer_index: i32, + stride: Option, + data: &[T], + ) -> usize { + let data = unsafe { + slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::()) + }; + let data_stride: usize = self.texture.format.bytes_per_pixel() as usize; + let width = rect.size.width as usize; + let height = rect.size.height as usize; + let size = width * height * data_stride; + let mut new_data = vec![0u8; size]; + let data = if stride.is_some() { + let row_length = (stride.unwrap()) as usize; + + if data_stride == 4 { + for j in 0 .. height { + for i in 0 .. width { + let offset = i * data_stride + j * data_stride * width; + let src = &data[j * row_length + i * data_stride ..]; + assert!( + offset + 3 < new_data.len(), + "offset={:?}, data len={:?}, data stride={:?}", + offset, + new_data.len(), + data_stride, + ); // optimization + // convert from BGRA + new_data[offset + 0] = src[0]; + new_data[offset + 1] = src[1]; + new_data[offset + 2] = src[2]; + new_data[offset + 3] = src[3]; + } + } + } else { + for j in 0 .. height { + for i in 0 .. width { + let offset = i * data_stride + j * data_stride * width; + let src = &data[j * row_length + i * data_stride ..]; + for i in 0 .. data_stride { + new_data[offset + i] = src[i]; + } + } + } + } + + new_data.as_slice() + } else { + data + }; + assert_eq!( + data.len(), + width * height * data_stride, + "data len = {}, width = {}, height = {}, data stride = {}", + data.len(), + width, + height, + data_stride + ); + + self.texture.bound_in_frame.set(self.device.frame_id); + self.device + .images + .get_mut(&self.texture.id) + .expect("Texture not found.") + .update( + self.device.device.as_ref(), + &mut self.device.command_buffer, + &mut self.device.staging_buffer_pool[self.device.next_id], + rect, + layer_index, + data, + ); + + if self.texture.filter == TextureFilter::Trilinear { + self.device.generate_mipmaps(self.texture); + } + size + } +} + +fn texels_to_u8_slice(texels: &[T]) -> &[u8] { + unsafe { + slice::from_raw_parts( + texels.as_ptr() as *const u8, + texels.len() * mem::size_of::(), + ) + } +} diff --git a/webrender/src/device/gfx/image.rs b/webrender/src/device/gfx/image.rs new file mode 100644 index 0000000000..356ce402df --- /dev/null +++ b/webrender/src/device/gfx/image.rs @@ -0,0 +1,390 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use api::{DeviceIntRect, ImageFormat}; +use hal::{self, Device as BackendDevice}; +use hal::command::RawCommandBuffer; +use hal::image::{Layout, Access}; +use hal::pso::PipelineStage; +use rendy_memory::{Block, Heaps, MemoryBlock, MemoryUsageValue}; + +use std::cell::Cell; +use super::buffer::BufferPool; +use super::render_pass::{RenderPassManager, DEPTH_ATTACHMENT_STATE}; +use super::TextureId; +use super::super::{RBOId, Texture}; + +const DEPTH_RANGE: hal::image::SubresourceRange = hal::image::SubresourceRange { + aspects: hal::format::Aspects::DEPTH, + levels: 0 .. 1, + layers: 0 .. 1, +}; + +/// The Vulkan spec states: bufferOffset must be a multiple of 4 for VkBufferImageCopy +/// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VkBufferImageCopy +const BUFFER_COPY_ALIGNMENT: i32 = 4; + +#[derive(Debug)] +pub(super) struct ImageCore { + pub(super) image: B::Image, + pub(super) memory_block: Option>, + pub(super) view: B::ImageView, + pub(super) subresource_range: hal::image::SubresourceRange, + pub(super) state: Cell, +} + +impl ImageCore { + pub(super) fn from_image( + device: &B::Device, + image: B::Image, + view_kind: hal::image::ViewKind, + format: hal::format::Format, + subresource_range: hal::image::SubresourceRange, + ) -> Self { + let view = unsafe { + device.create_image_view( + &image, + view_kind, + format, + hal::format::Swizzle::NO, + subresource_range.clone(), + ) + } + .expect("create_image_view failed"); + ImageCore { + image, + memory_block: None, + view, + subresource_range, + state: Cell::new((Access::empty(), Layout::Undefined)), + } + } + + pub(super) fn create( + device: &B::Device, + heaps: &mut Heaps, + kind: hal::image::Kind, + view_kind: hal::image::ViewKind, + mip_levels: hal::image::Level, + format: hal::format::Format, + usage: hal::image::Usage, + subresource_range: hal::image::SubresourceRange, + ) -> Self { + let mut image = unsafe { + device.create_image( + kind, + mip_levels, + format, + hal::image::Tiling::Optimal, + usage, + hal::image::ViewCapabilities::empty(), + ) + } + .expect("create_image failed"); + let requirements = unsafe { device.get_image_requirements(&image) }; + + let memory_block = heaps + .allocate( + device, + requirements.type_mask as u32, + MemoryUsageValue::Data, + requirements.size, + requirements.alignment, + ) + .expect("Allocate memory failed"); + + unsafe { + device + .bind_image_memory( + &memory_block.memory(), + memory_block.range().start, + &mut image, + ) + .expect("Bind image memory failed") + }; + + ImageCore { + memory_block: Some(memory_block), + ..Self::from_image(device, image, view_kind, format, subresource_range) + } + } + + fn _reset(&self) { + self.state + .set((Access::empty(), Layout::Undefined)); + } + + pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + unsafe { device.destroy_image_view(self.view) }; + if let Some(memory_block) = self.memory_block { + unsafe { + device.destroy_image(self.image); + heaps.free(device, memory_block); + } + } + } + + fn pick_stage_for_layout(layout: Layout) -> PipelineStage { + match layout { + Layout::Undefined => PipelineStage::TOP_OF_PIPE, + Layout::Present => PipelineStage::TRANSFER, + Layout::ColorAttachmentOptimal => PipelineStage::COLOR_ATTACHMENT_OUTPUT, + Layout::ShaderReadOnlyOptimal => PipelineStage::VERTEX_SHADER | PipelineStage::FRAGMENT_SHADER, + Layout::TransferSrcOptimal | Layout::TransferDstOptimal => PipelineStage::TRANSFER, + Layout::DepthStencilAttachmentOptimal => PipelineStage::EARLY_FRAGMENT_TESTS | PipelineStage::LATE_FRAGMENT_TESTS, + state => unimplemented!("State not covered {:?}", state), + } + } + + pub(super) fn transit( + &self, + new_state: hal::image::State, + range: hal::image::SubresourceRange, + ) -> Option<(hal::memory::Barrier, std::ops::Range)> { + let src_state = self.state.get(); + if src_state == new_state { + None + } else { + self.state.set(new_state); + let barrier = hal::memory::Barrier::Image { + states: src_state .. new_state, + target: &self.image, + families: None, + range, + }; + Some((barrier, Self::pick_stage_for_layout(src_state.1) .. Self::pick_stage_for_layout(self.state.get().1))) + } + } +} + +pub(super) struct Image { + pub(super) core: ImageCore, + pub(super) kind: hal::image::Kind, + pub(super) format: ImageFormat, +} + +impl Image { + pub(super) fn new( + device: &B::Device, + heaps: &mut Heaps, + image_format: ImageFormat, + image_width: i32, + image_height: i32, + image_depth: i32, + view_kind: hal::image::ViewKind, + mip_levels: hal::image::Level, + usage: hal::image::Usage, + ) -> Self { + let kind = hal::image::Kind::D2(image_width as _, image_height as _, image_depth as _, 1); + + let core = ImageCore::create( + device, + heaps, + kind, + view_kind, + mip_levels, + image_format.into(), + usage, + hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: 0 .. mip_levels, + layers: 0 .. image_depth as _, + }, + ); + + Image { + core, + kind, + format: image_format, + } + } + + pub(super) fn update( + &self, + device: &B::Device, + cmd_buffer: &mut B::CommandBuffer, + staging_buffer_pool: &mut BufferPool, + rect: DeviceIntRect, + layer_index: i32, + image_data: &[u8], + ) { + let pos = rect.origin; + let size = rect.size; + staging_buffer_pool.add(device, image_data, self.format.bytes_per_pixel().max(BUFFER_COPY_ALIGNMENT) as usize - 1); + let buffer = staging_buffer_pool.buffer(); + + unsafe { + let buffer_barrier = buffer.transit(hal::buffer::Access::TRANSFER_READ); + let prev_state = self.core.state.get(); + match self.core.transit( + (Access::TRANSFER_WRITE, Layout::TransferDstOptimal), + self.core.subresource_range.clone(), + ) { + Some((barrier, pipeline_stages)) => { + cmd_buffer.pipeline_barrier( + pipeline_stages, + hal::memory::Dependencies::empty(), + buffer_barrier.into_iter().chain(Some(barrier)), + ); + } + None => { + cmd_buffer.pipeline_barrier( + PipelineStage::TRANSFER .. PipelineStage::TRANSFER, + hal::memory::Dependencies::empty(), + buffer_barrier.into_iter(), + ); + }, + }; + + + cmd_buffer.copy_buffer_to_image( + &buffer.buffer, + &self.core.image, + Layout::TransferDstOptimal, + &[hal::command::BufferImageCopy { + buffer_offset: staging_buffer_pool.buffer_offset as _, + buffer_width: size.width as _, + buffer_height: size.height as _, + image_layers: hal::image::SubresourceLayers { + aspects: hal::format::Aspects::COLOR, + level: 0, + layers: layer_index as _ .. (layer_index + 1) as _, + }, + image_offset: hal::image::Offset { + x: pos.x as i32, + y: pos.y as i32, + z: 0, + }, + image_extent: hal::image::Extent { + width: size.width as u32, + height: size.height as u32, + depth: 1, + }, + }], + ); + + if let Some((barrier, stages)) = self.core.transit( + prev_state, + self.core.subresource_range.clone(), + ) { + cmd_buffer.pipeline_barrier( + stages, + hal::memory::Dependencies::empty(), + &[barrier], + ); + } + } + } + + pub fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + self.core.deinit(device, heaps); + } +} + +pub(super) struct Framebuffer { + pub(super) texture_id: TextureId, + pub(super) layer_index: u16, + image_view: B::ImageView, + pub(super) fbo: B::Framebuffer, + pub(super) rbo: RBOId, +} + +impl Framebuffer { + pub(super) fn new( + device: &B::Device, + texture: &Texture, + image: &Image, + layer_index: u16, + render_pass_manager: &mut RenderPassManager, + rbo: RBOId, + depth: Option<&B::ImageView>, + ) -> Self { + let extent = hal::image::Extent { + width: texture.size.width as _, + height: texture.size.height as _, + depth: 1, + }; + let format = match texture.format { + ImageFormat::R8 => hal::format::Format::R8Unorm, + ImageFormat::BGRA8 => hal::format::Format::Bgra8Unorm, + f => unimplemented!("TODO image format missing {:?}", f), + }; + let image_view = unsafe { + device.create_image_view( + &image.core.image, + hal::image::ViewKind::D2Array, + format, + hal::format::Swizzle::NO, + hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: 0 .. 1, + layers: layer_index .. layer_index + 1, + }, + ) + } + .expect("create_image_view failed"); + let fbo = unsafe { + if rbo != RBOId(0) { + device.create_framebuffer( + render_pass_manager.get_render_pass(device, (texture.format.into(), Some(DEPTH_ATTACHMENT_STATE))), + Some(&image_view).into_iter().chain(depth.into_iter()), + extent, + ) + } else { + device.create_framebuffer( + render_pass_manager.get_render_pass(device, (texture.format.into(), None)), + Some(&image_view), + extent, + ) + } + } + .expect("create_framebuffer failed"); + + Framebuffer { + texture_id: texture.id, + layer_index, + image_view, + fbo, + rbo, + } + } + + pub(super) fn deinit(self, device: &B::Device) { + unsafe { + device.destroy_framebuffer(self.fbo); + device.destroy_image_view(self.image_view); + } + } +} + +#[derive(Debug)] +pub(super) struct DepthBuffer { + pub(super) core: ImageCore, +} + +impl DepthBuffer { + pub(super) fn new( + device: &B::Device, + heaps: &mut Heaps, + pixel_width: u32, + pixel_height: u32, + depth_format: hal::format::Format, + ) -> Self { + let core = ImageCore::create( + device, + heaps, + hal::image::Kind::D2(pixel_width, pixel_height, 1, 1), + hal::image::ViewKind::D2, + 1, + depth_format, + hal::image::Usage::TRANSFER_DST | hal::image::Usage::DEPTH_STENCIL_ATTACHMENT, + DEPTH_RANGE, + ); + DepthBuffer { core } + } + + pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { + self.core.deinit(device, heaps); + } +} diff --git a/webrender/src/device/gfx/mod.rs b/webrender/src/device/gfx/mod.rs new file mode 100644 index 0000000000..6ead71c5eb --- /dev/null +++ b/webrender/src/device/gfx/mod.rs @@ -0,0 +1,155 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +mod blend_state; +mod buffer; +mod command; +mod descriptor; +mod device; +mod image; +mod program; +mod render_pass; +pub(crate) mod vertex_types; + +pub use self::device::*; +pub use self::buffer::{BufferMemorySlice, GpuCacheBuffer, PersistentlyMappedBuffer}; + +use gpu_types; +use hal; +use internal_types::FastHashMap; +use tiling; + +pub type TextureId = u32; + +pub const LESS_EQUAL_TEST: hal::pso::DepthTest = hal::pso::DepthTest { + fun: hal::pso::Comparison::LessEqual, + write: false, +}; + +pub const LESS_EQUAL_WRITE: hal::pso::DepthTest = hal::pso::DepthTest { + fun: hal::pso::Comparison::LessEqual, + write: true, +}; + +#[derive(Clone, Deserialize)] +pub struct PipelineRequirements { + pub attribute_descriptors: Vec, + pub bindings_map: FastHashMap, + pub vertex_buffer_descriptors: Vec, +} + +pub trait PrimitiveType { + type Primitive: Clone + Copy; + fn to_primitive_type(&self) -> Self::Primitive; +} + +impl PrimitiveType for gpu_types::BlurInstance { + type Primitive = vertex_types::BlurInstance; + fn to_primitive_type(&self) -> vertex_types::BlurInstance { + vertex_types::BlurInstance { + aData: [0, 0, 0, 0], + aBlurRenderTaskAddress: self.task_address.0 as i32, + aBlurSourceTaskAddress: self.src_task_address.0 as i32, + aBlurDirection: self.blur_direction as i32, + } + } +} + +impl PrimitiveType for gpu_types::BorderInstance { + type Primitive = vertex_types::BorderInstance; + fn to_primitive_type(&self) -> vertex_types::BorderInstance { + vertex_types::BorderInstance { + aTaskOrigin: [self.task_origin.x, self.task_origin.y], + aRect: [ + self.local_rect.origin.x, + self.local_rect.origin.y, + self.local_rect.size.width, + self.local_rect.size.height, + ], + aColor0: self.color0.to_array(), + aColor1: self.color1.to_array(), + aFlags: self.flags, + aWidths: [self.widths.width, self.widths.height], + aRadii: [self.radius.width, self.radius.height], + aClipParams1: [ + self.clip_params[0], + self.clip_params[1], + self.clip_params[2], + self.clip_params[3], + ], + aClipParams2: [ + self.clip_params[4], + self.clip_params[5], + self.clip_params[6], + self.clip_params[7], + ], + } + } +} + +impl PrimitiveType for gpu_types::ClipMaskInstance { + type Primitive = vertex_types::ClipMaskInstance; + fn to_primitive_type(&self) -> vertex_types::ClipMaskInstance { + vertex_types::ClipMaskInstance { + aClipRenderTaskAddress: self.render_task_address.0 as i32, + aClipTransformId: self.clip_transform_id.0 as i32, + aPrimTransformId: self.prim_transform_id.0 as i32, + aClipDataResourceAddress: [ + self.clip_data_address.u as i32, + self.clip_data_address.v as i32, + self.resource_address.u as i32, + self.resource_address.v as i32, + ], + aClipLocalPos: [self.local_pos.x, self.local_pos.y], + aClipTileRect: [ + self.tile_rect.origin.x, + self.tile_rect.origin.y, + self.tile_rect.size.width, + self.tile_rect.size.height, + ], + aClipDeviceArea: [ + self.sub_rect.origin.x, + self.sub_rect.origin.y, + self.sub_rect.size.width, + self.sub_rect.size.height, + ], + } + } +} + +impl PrimitiveType for gpu_types::PrimitiveInstanceData { + type Primitive = vertex_types::PrimitiveInstanceData; + fn to_primitive_type(&self) -> vertex_types::PrimitiveInstanceData { + vertex_types::PrimitiveInstanceData { aData: self.data } + } +} + +impl PrimitiveType for gpu_types::ScalingInstance { + type Primitive = vertex_types::ScalingInstance; + fn to_primitive_type(&self) -> vertex_types::ScalingInstance { + vertex_types::ScalingInstance { + aData: [0, 0, 0, 0], + aScaleRenderTaskAddress: self.task_address.0 as i32, + aScaleSourceTaskAddress: self.src_task_address.0 as i32, + } + } +} + +impl PrimitiveType for tiling::LineDecorationJob { + type Primitive = vertex_types::LineDecorationInstance; + fn to_primitive_type(&self) -> vertex_types::LineDecorationInstance { + vertex_types::LineDecorationInstance { + aTaskRect: [ + self.task_rect.origin.x, + self.task_rect.origin.y, + self.task_rect.size.width, + self.task_rect.size.height, + ], + aLocalSize: [self.local_size.width, self.local_size.height], + aStyle: self.style, + aOrientation: self.orientation, + aWavyLineThickness: self.wavy_line_thickness, + } + } +} diff --git a/webrender/src/device/gfx/program.rs b/webrender/src/device/gfx/program.rs new file mode 100644 index 0000000000..0e3535553b --- /dev/null +++ b/webrender/src/device/gfx/program.rs @@ -0,0 +1,493 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use api::{ColorF, DeviceIntRect, ImageFormat}; +use hal::{self, Device as BackendDevice}; +use hal::command::RawCommandBuffer; +use internal_types::FastHashMap; +use smallvec::SmallVec; +use rendy_memory::Heaps; +use std::borrow::Cow::{Borrowed}; + +use super::buffer::{InstanceBufferHandler, VertexBufferHandler}; +use super::blend_state::SUBPIXEL_CONSTANT_TEXT_COLOR; +use super::render_pass::*; +use super::PipelineRequirements; +use super::super::{ShaderKind, VertexArrayKind}; +use super::super::super::shader_source; + +const ENTRY_NAME: &str = "main"; +// The size of the push constant block is 68 bytes, and we upload it with u32 data (4 bytes). +pub(super) const PUSH_CONSTANT_BLOCK_SIZE: usize = 17; // 68 / 4 +// The number of specialization constants in each shader. +const SPECIALIZATION_CONSTANT_COUNT: usize = 6; +// Size of a specialization constant variable in bytes. +const SPECIALIZATION_CONSTANT_SIZE: usize = 4; +const SPECIALIZATION_FEATURES: &'static [&'static str] = &[ + "ALPHA_PASS", + "COLOR_TARGET", + "GLYPH_TRANSFORM", + "DITHERING", + "DEBUG_OVERDRAW", +]; + +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +pub(super) enum RenderPassDepthState { + Enabled, + Disabled, +} + +type PipelineKey = (Option, RenderPassDepthState, Option); + +pub(crate) struct Program { + pipelines: FastHashMap, + pub(super) vertex_buffer: Option; 1]>>, + pub(super) index_buffer: Option; 1]>>, + pub(super) shader_name: String, + pub(super) shader_kind: ShaderKind, + pub(super) constants: [u32; PUSH_CONSTANT_BLOCK_SIZE], +} + +impl Program { + pub(super) fn create( + pipeline_requirements: PipelineRequirements, + device: &B::Device, + pipeline_layout: &B::PipelineLayout, + heaps: &mut Heaps, + limits: &hal::Limits, + shader_name: &str, + features: &[&str], + shader_kind: ShaderKind, + render_pass_manager: &mut RenderPassManager, + frame_count: usize, + shader_modules: &mut FastHashMap, + pipeline_cache: Option<&B::PipelineCache>, + surface_format: ImageFormat, + use_push_consts: bool, + ) -> Program { + if !shader_modules.contains_key(shader_name) { + let vs_file = format!("{}.vert.spv", shader_name); + let vs_module = unsafe { + device.create_shader_module( + shader_source::SPIRV_BINARIES + .get(vs_file.as_str()) + .expect("create_shader_module failed"), + ) + } + .expect(&format!("Failed to create vs module for: {}!", vs_file)); + + let fs_file = format!("{}.frag.spv", shader_name); + let fs_module = unsafe { + device.create_shader_module( + shader_source::SPIRV_BINARIES + .get(fs_file.as_str()) + .expect("create_shader_module failed"), + ) + } + .expect(&format!("Failed to create vs module for: {}!", fs_file)); + shader_modules.insert(String::from(shader_name), (vs_module, fs_module)); + } + + let (vs_module, fs_module) = shader_modules.get(shader_name).unwrap(); + + let mut specialization_data = + vec![0; (SPECIALIZATION_CONSTANT_COUNT - 1) * SPECIALIZATION_CONSTANT_SIZE]; + let mut constants = SPECIALIZATION_FEATURES + .iter() + .zip(specialization_data.chunks_mut(SPECIALIZATION_CONSTANT_SIZE)) + .enumerate() + .map(|(i, (feature, out_data))| { + out_data[0] = features.contains(feature) as u8; + hal::pso::SpecializationConstant { + id: i as _, + range: (SPECIALIZATION_CONSTANT_SIZE * i) as _ + .. (SPECIALIZATION_CONSTANT_SIZE * (i + 1)) as _, + } + }) + .collect::>(); + constants.push(hal::pso::SpecializationConstant { + id: (SPECIALIZATION_CONSTANT_COUNT - 1) as _, + range: { + let from = (SPECIALIZATION_CONSTANT_COUNT - 1) * SPECIALIZATION_CONSTANT_SIZE; + let to = from + SPECIALIZATION_CONSTANT_SIZE; + from as _ .. to as _ + }, + }); + specialization_data.extend_from_slice(&[use_push_consts as u8, 0, 0, 0]); + + let pipelines = { + let (vs_entry, fs_entry) = ( + hal::pso::EntryPoint:: { + entry: ENTRY_NAME, + module: &vs_module, + specialization: hal::pso::Specialization { + constants: Borrowed(&constants), + data: Borrowed(&specialization_data.as_slice()), + }, + }, + hal::pso::EntryPoint:: { + entry: ENTRY_NAME, + module: &fs_module, + specialization: hal::pso::Specialization { + constants: Borrowed(&constants), + data: Borrowed(&specialization_data.as_slice()), + }, + }, + ); + + let shader_entries = hal::pso::GraphicsShaderSet { + vertex: vs_entry, + hull: None, + domain: None, + geometry: None, + fragment: Some(fs_entry), + }; + + use hal::pso::{BlendState}; + use super::blend_state::*; + use super::{LESS_EQUAL_TEST, LESS_EQUAL_WRITE}; + use self::RenderPassDepthState as RPDS; + + let pipeline_states = match shader_kind { + ShaderKind::Cache(VertexArrayKind::Scale) => [ + (None, RPDS::Enabled, None), + (None, RPDS::Disabled, None), + (Some(BlendState::MULTIPLY), RPDS::Enabled, None), + (Some(BlendState::MULTIPLY), RPDS::Disabled, None), + ] + .into_iter(), + ShaderKind::Cache(VertexArrayKind::Blur) => [ + (None, RPDS::Enabled, None), + (None, RPDS::Disabled, None), + (None, RPDS::Enabled, Some(LESS_EQUAL_TEST)), + ] + .into_iter(), + ShaderKind::Cache(VertexArrayKind::Border) + | ShaderKind::Cache(VertexArrayKind::LineDecoration) => [ + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Disabled, None), + ].into_iter(), + ShaderKind::ClipCache => [ + (Some(BlendState::MULTIPLY), RPDS::Enabled, None), + (Some(BlendState::MULTIPLY), RPDS::Disabled, None), + ].into_iter(), + ShaderKind::Text => { + if features.contains(&"DUAL_SOURCE_BLENDING") { + [ + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Enabled, None), + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Disabled, None), + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_CONSTANT_TEXT_COLOR), RPDS::Enabled, None), + (Some(SUBPIXEL_CONSTANT_TEXT_COLOR), RPDS::Disabled, None), + (Some(SUBPIXEL_CONSTANT_TEXT_COLOR), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS0), RPDS::Enabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS0), RPDS::Disabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS0), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS1), RPDS::Enabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS1), RPDS::Disabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS1), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS2), RPDS::Enabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS2), RPDS::Disabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS2), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_DUAL_SOURCE), RPDS::Enabled, None), + (Some(SUBPIXEL_DUAL_SOURCE), RPDS::Disabled, None), + (Some(SUBPIXEL_DUAL_SOURCE), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + ] + .into_iter() + } else { + [ + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Enabled, None), + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Disabled, None), + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_CONSTANT_TEXT_COLOR), RPDS::Enabled, None), + (Some(SUBPIXEL_CONSTANT_TEXT_COLOR), RPDS::Disabled, None), + (Some(SUBPIXEL_CONSTANT_TEXT_COLOR), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS0), RPDS::Enabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS0), RPDS::Disabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS0), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS1), RPDS::Enabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS1), RPDS::Disabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS1), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS2), RPDS::Enabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS2), RPDS::Disabled, None), + (Some(SUBPIXEL_WITH_BG_COLOR_PASS2), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + ] + .into_iter() + } + } + ShaderKind::DebugColor | ShaderKind::DebugFont => [ + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Enabled, None), + ].into_iter(), + _ => [ + (None, RPDS::Enabled, Some(LESS_EQUAL_WRITE)), + (Some(ALPHA), RPDS::Enabled, None), + (Some(ALPHA), RPDS::Disabled, None), + (Some(ALPHA), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Enabled, None), + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Disabled, None), + (Some(BlendState::PREMULTIPLIED_ALPHA), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + (Some(PREMULTIPLIED_DEST_OUT), RPDS::Enabled, None), + (Some(PREMULTIPLIED_DEST_OUT), RPDS::Disabled, None), + (Some(PREMULTIPLIED_DEST_OUT), RPDS::Enabled, Some(LESS_EQUAL_TEST)), + ] + .into_iter(), + }; + + let color_attachment_state = match shader_kind { + ShaderKind::ClipCache => ImageFormat::R8.into(), + ShaderKind::Cache(VertexArrayKind::Blur) if features.contains(&"ALPHA_TARGET") => ImageFormat::R8.into(), + ShaderKind::Cache(VertexArrayKind::Scale) if features.contains(&"ALPHA_TARGET") => ImageFormat::R8.into(), + _ => surface_format.into(), + }; + + fn create_descriptor<'a, 'b, B: hal::Backend>( + device: &'b B::Device, + color_attachment_state: AttachmentState, + shader_entries: hal::pso::GraphicsShaderSet<'b, B>, + pipeline_layout: &'b B::PipelineLayout, + pipeline_requirements: &PipelineRequirements, + (blend_state, render_pass_depth_state, depth_test): (Option, RenderPassDepthState, Option), + render_pass_manager: &'b mut RenderPassManager, + ) -> hal::pso::GraphicsPipelineDesc<'a, B> + where 'b: 'a { + let depth_attachment_state = match depth_test { + Some(_) => Some(DEPTH_ATTACHMENT_STATE), + None => match render_pass_depth_state { + RenderPassDepthState::Enabled => Some(DEPTH_ATTACHMENT_STATE), + RenderPassDepthState::Disabled => None, + }, + }; + let subpass = hal::pass::Subpass { + index: 0, + main_pass: render_pass_manager + .get_render_pass( + device, + (color_attachment_state, depth_attachment_state), + ), + }; + let mut pipeline_descriptor = hal::pso::GraphicsPipelineDesc::new( + shader_entries, + hal::Primitive::TriangleList, + hal::pso::Rasterizer::FILL, + &pipeline_layout, + subpass, + ); + pipeline_descriptor + .blender + .targets + .push(hal::pso::ColorBlendDesc{ + mask: hal::pso::ColorMask::ALL, + blend: blend_state, + }); + + pipeline_descriptor.depth_stencil = hal::pso::DepthStencilDesc { + depth: depth_test, + depth_bounds: false, + stencil: None, + }; + + pipeline_descriptor.vertex_buffers = + pipeline_requirements.vertex_buffer_descriptors.clone(); + pipeline_descriptor.attributes = + pipeline_requirements.attribute_descriptors.clone(); + pipeline_descriptor + } + + let mut states = pipeline_states.map(|ps| { + let graphics_desc = create_descriptor( + device, + color_attachment_state, + shader_entries.clone(), + pipeline_layout, + &pipeline_requirements, + ps.clone(), + render_pass_manager, + ); + let pipeline = unsafe { device.create_graphics_pipeline(&graphics_desc, pipeline_cache) }.unwrap(); + (*ps, pipeline) + }).collect::>(); + + if features.contains(&"DEBUG_OVERDRAW") { + let pipeline_state = (Some(OVERDRAW), RPDS::Enabled, Some(LESS_EQUAL_TEST)); + let pipeline_descriptor = create_descriptor( + device, + color_attachment_state, + shader_entries.clone(), + pipeline_layout, + &pipeline_requirements, + pipeline_state, + render_pass_manager, + ); + let pipeline = unsafe { + device.create_graphics_pipeline(&pipeline_descriptor, pipeline_cache) + } + .expect("Pipeline creation failed"); + states.insert(pipeline_state, pipeline); + } + + states + }; + + let (mut vertex_buffer, mut index_buffer) = if shader_kind.is_debug() { + (Some(SmallVec::new()), Some(SmallVec::new())) + } else { + (None, None) + }; + for _ in 0 .. frame_count { + if let Some(ref mut vertex_buffer) = vertex_buffer { + vertex_buffer.push(VertexBufferHandler::new( + device, + heaps, + hal::buffer::Usage::VERTEX, + &[0u8], + (limits.optimal_buffer_copy_pitch_alignment - 1) as usize, + (limits.non_coherent_atom_size - 1) as usize, + )); + } + if let Some(ref mut index_buffer) = index_buffer { + index_buffer.push(VertexBufferHandler::new( + device, + heaps, + hal::buffer::Usage::INDEX, + &[0u8], + (limits.optimal_buffer_copy_pitch_alignment - 1) as usize, + (limits.non_coherent_atom_size - 1) as usize, + )); + } + } + + Program { + pipelines, + vertex_buffer, + index_buffer, + shader_name: String::from(shader_name), + shader_kind, + constants: [0; PUSH_CONSTANT_BLOCK_SIZE], + } + } + + pub(super) fn submit( + &mut self, + cmd_buffer: &mut B::CommandBuffer, + viewport: hal::pso::Viewport, + desc_set_per_draw: &B::DescriptorSet, + desc_set_per_pass: Option<&B::DescriptorSet>, + desc_set_per_frame: &B::DescriptorSet, + desc_set_locals: Option<&B::DescriptorSet>, + blend_state: Option, + blend_color: ColorF, + depth_test: Option, + render_pass_depth_state: RenderPassDepthState, + scissor_rect: Option, + next_id: usize, + pipeline_layout: &B::PipelineLayout, + use_push_consts: bool, + vertex_buffer: &VertexBufferHandler, + instance_buffer: &InstanceBufferHandler, + instance_range: std::ops::Range, + ) { + let vertex_buffer = match &self.vertex_buffer { + Some(ref vb) => vb.get(next_id).unwrap(), + None => vertex_buffer + }; + unsafe { + if use_push_consts { + cmd_buffer.push_graphics_constants( + pipeline_layout, + hal::pso::ShaderStageFlags::VERTEX, + 0, + &self.constants, + ); + } + cmd_buffer.set_viewports(0, &[viewport.clone()]); + match scissor_rect { + Some(r) => cmd_buffer.set_scissors( + 0, + &[hal::pso::Rect { + x: r.origin.x as _, + y: r.origin.y as _, + w: r.size.width as _, + h: r.size.height as _, + }], + ), + None => cmd_buffer.set_scissors(0, &[viewport.rect]), + } + cmd_buffer.bind_graphics_pipeline( + &self + .pipelines + .get(&(blend_state, render_pass_depth_state, depth_test)) + .expect(&format!( + "The blend state {:?} with depth test {:?} and render_pass_depth_state {:?} not found for {} program!", + blend_state, depth_test, render_pass_depth_state, self.shader_name + )), + ); + + if !use_push_consts { + assert!(desc_set_locals.is_some()); + } + use std::iter; + cmd_buffer.bind_graphics_descriptor_sets( + pipeline_layout, + if desc_set_per_pass.is_some() { 0 } else { 1 }, + desc_set_per_pass.into_iter() + .chain(iter::once(desc_set_per_frame)) + .chain(iter::once(desc_set_per_draw)) + .chain(desc_set_locals), + &[], + ); + + if blend_state == Some(SUBPIXEL_CONSTANT_TEXT_COLOR) { + cmd_buffer.set_blend_constants(blend_color.to_array()); + } + + if let Some(ref index_buffer) = self.index_buffer { + cmd_buffer.bind_vertex_buffers(0, Some((&vertex_buffer.buffer().buffer, 0))); + cmd_buffer.bind_index_buffer(hal::buffer::IndexBufferView { + buffer: &index_buffer[next_id].buffer().buffer, + offset: 0, + index_type: hal::IndexType::U32, + }); + + + cmd_buffer.draw_indexed( + 0 .. index_buffer[next_id].buffer().buffer_len as u32, + 0, + 0 .. 1, + ); + } else { + for i in instance_range.into_iter() { + cmd_buffer.bind_vertex_buffers( + 0, + Some((&vertex_buffer.buffer().buffer, 0)) + .into_iter() + .chain(Some((&instance_buffer.buffers[i].buffer.buffer, 0))), + ); + + let data_stride = instance_buffer.buffers[i].last_data_stride; + let end = instance_buffer.buffers[i].offset / data_stride; + let start = end - instance_buffer.buffers[i].last_update_size / data_stride; + cmd_buffer.draw( + 0 .. vertex_buffer.buffer_len as _, + start as u32 .. end as u32, + ); + } + } + } + } + + pub(super) fn deinit(mut self, device: &B::Device, heaps: &mut Heaps) { + if let Some(vertex_buffer) = self.vertex_buffer { + for vertex_buffer in vertex_buffer { + vertex_buffer.deinit(device, heaps); + } + } + if let Some(index_buffer) = self.index_buffer { + for index_buffer in index_buffer { + index_buffer.deinit(device, heaps); + } + } + for pipeline in self.pipelines.drain() { + unsafe { device.destroy_graphics_pipeline(pipeline.1) }; + } + } +} diff --git a/webrender/src/device/gfx/render_pass.rs b/webrender/src/device/gfx/render_pass.rs new file mode 100644 index 0000000000..43d9cadc62 --- /dev/null +++ b/webrender/src/device/gfx/render_pass.rs @@ -0,0 +1,146 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use hal::Device; +use hal::format::Format; +use hal::image::Layout; +use hal::pass::{Attachment, SubpassDesc}; +use internal_types::FastHashMap; + +pub(super) const DEPTH_FORMAT: Format = hal::format::Format::D32Sfloat; + +const SUBPASS_R8: SubpassDesc = SubpassDesc { + colors: &[(0, Layout::ColorAttachmentOptimal)], + depth_stencil: None, + inputs: &[], + resolves: &[], + preserves: &[], +}; + +const SUBPASS_DEPTH_R8: SubpassDesc = SubpassDesc { + colors: &[(0, Layout::ColorAttachmentOptimal)], + depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)), + inputs: &[], + resolves: &[], + preserves: &[], +}; + +const SUBPASS_BGRA8: SubpassDesc = SubpassDesc { + colors: &[(0, Layout::ColorAttachmentOptimal)], + depth_stencil: None, + inputs: &[], + resolves: &[], + preserves: &[], +}; + +const SUBPASS_DEPTH_BGRA8: SubpassDesc = SubpassDesc { + colors: &[(0, Layout::ColorAttachmentOptimal)], + depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)), + inputs: &[], + resolves: &[], + preserves: &[], +}; + +pub(super) const DEPTH_ATTACHMENT_STATE: AttachmentState = AttachmentState { + format: DEPTH_FORMAT, + src_layout: Layout::DepthStencilAttachmentOptimal, + dst_layout: Layout::DepthStencilAttachmentOptimal, + load_op: hal::pass::AttachmentLoadOp::Load, +}; + +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub(super) struct AttachmentState { + pub format: Format, + pub src_layout: Layout, + pub dst_layout: Layout, + pub load_op: hal::pass::AttachmentLoadOp, +} + +impl> From for AttachmentState { + fn from(format: T) -> Self { + AttachmentState { + format: format.into(), + src_layout: Layout::ColorAttachmentOptimal, + dst_layout: Layout::ColorAttachmentOptimal, + load_op: hal::pass::AttachmentLoadOp::Load, + } + } +} + +pub(super) type RenderPassSKey = (AttachmentState, Option); + +pub(super) struct RenderPassManager { + attachments: FastHashMap, + render_passes: FastHashMap, +} + +impl RenderPassManager { + pub(super) fn new() -> RenderPassManager { + RenderPassManager { + attachments: FastHashMap::default(), + render_passes: FastHashMap::default(), + } + } + + fn create_attachment(att_state: &AttachmentState) -> Attachment { + hal::pass::Attachment { + format: Some(att_state.format), + samples: 1, + // TODO(zakorgy): add AttachmentOps to AttachmentState + ops: hal::pass::AttachmentOps::new( + att_state.load_op, + hal::pass::AttachmentStoreOp::Store, + ), + stencil_ops: hal::pass::AttachmentOps::DONT_CARE, + layouts: att_state.src_layout .. att_state.dst_layout, + } + } + + fn get_subpass_for_attachments((color_att, depth_att): &RenderPassSKey) -> SubpassDesc { + match color_att.format { + Format::Bgra8Unorm => { + if depth_att.is_some() { + SUBPASS_DEPTH_BGRA8 + } else { + SUBPASS_BGRA8 + } + } + Format::R8Unorm => { + if depth_att.is_some() { + SUBPASS_DEPTH_R8 + } else { + SUBPASS_R8 + } + } + _ => unimplemented!("Format not supported {:?}", color_att.format), + } + } + + pub(super) fn get_render_pass( + &mut self, + device: &B::Device, + key: RenderPassSKey, + ) -> &B::RenderPass { + if !self.render_passes.contains_key(&key) { + let ref mut attachment1 = self.attachments.entry(key.0).or_insert(Self::create_attachment(&key.0)).clone(); + let attachment2 = key.1.map(|k| self.attachments.entry(k).or_insert(Self::create_attachment(&k))); + let rp = unsafe { + device.create_render_pass( + Some(attachment1).into_iter().chain(attachment2), + &[Self::get_subpass_for_attachments(&key)], + &[], + ) + .expect("create_render_pass failed") + }; + self.render_passes.insert(key, rp); + } + self.render_passes.get(&key).unwrap() + } + + pub(super) fn deinit(self, device: &B::Device) { + for (_, rp) in self.render_passes { + unsafe { device.destroy_render_pass(rp); } + } + } +} diff --git a/webrender/src/device/gfx/vertex_types.rs b/webrender/src/device/gfx/vertex_types.rs new file mode 100644 index 0000000000..930503b12c --- /dev/null +++ b/webrender/src/device/gfx/vertex_types.rs @@ -0,0 +1,107 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct BorderInstance { + pub aTaskOrigin: [f32; 2], + pub aRect: [f32; 4], + pub aColor0: [f32; 4], + pub aColor1: [f32; 4], + pub aFlags: i32, + pub aWidths: [f32; 2], + pub aRadii: [f32; 2], + pub aClipParams1: [f32; 4], + pub aClipParams2: [f32; 4], +} + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct ScalingInstance { + pub aData: [i32; 4], + pub aScaleRenderTaskAddress: i32, + pub aScaleSourceTaskAddress: i32, +} + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct BlurInstance { + pub aData: [i32; 4], + pub aBlurRenderTaskAddress: i32, + pub aBlurSourceTaskAddress: i32, + pub aBlurDirection: i32, +} + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct ClipMaskInstance { + pub aClipRenderTaskAddress: i32, + pub aClipTransformId: i32, + pub aPrimTransformId: i32, + pub aClipDataResourceAddress: [i32; 4], + pub aClipLocalPos: [f32; 2], + pub aClipTileRect: [f32; 4], + pub aClipDeviceArea: [f32; 4], +} + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct DebugColorVertex { + pub aPosition: [f32; 3], + pub aColor: [f32; 4], +} + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct DebugFontVertex { + pub aPosition: [f32; 3], + pub aColor: [f32; 4], + pub aColorTexCoord: [f32; 2], +} + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct LineDecorationInstance { + pub aTaskRect: [f32; 4], + pub aLocalSize: [f32; 2], + pub aStyle: i32, + pub aOrientation: i32, + pub aWavyLineThickness: f32, +} + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct PrimitiveInstanceData { + pub aData: [i32; 4], +} + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct Vertex { + pub aPosition: [f32; 3], +} + +#[cfg(feature = "pathfinder")] +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct VectorStencilInstance { + pub aFromPosition: [f32; 2], + pub aCtrlPosition: [f32; 2], + pub aToPosition: [f32; 2], + pub aFromNormal: [f32; 2], + pub aCtrlNormal: [f32; 2], + pub aToNormal: [f32; 2], + pub aPathID: i32, + pub aPad: i32, +} + +#[cfg(feature = "pathfinder")] +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +pub struct VectorCoverInstance { + pub aTargetRect: [i32; 4], + pub aStencilOrigin: [i32; 2], + pub aSubpixel: i32, + pub aPad: i32, +} diff --git a/webrender/src/device/gl.rs b/webrender/src/device/gl.rs index 0d770c0d41..b9bbb02447 100644 --- a/webrender/src/device/gl.rs +++ b/webrender/src/device/gl.rs @@ -2,161 +2,69 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use super::super::shader_source::SHADERS; +use super::Capabilities; +use super::desc; +use super::{ExternalTexture, FBOId, GpuFrameId, IBOId, RBOId, ProgramCache, ProgramCacheEntry, ReadPixelsFormat}; +use super::{ShaderError, ShaderKind, ShaderPrecacheFlags, SharedDepthTarget, Texel, Texture, TextureFlags}; +use super::{DrawTarget, TextureFilter, ReadTarget, TextureSampler, TextureSlot, UploadMethod, VBOId}; +use super::{VertexArrayKind, VertexAttribute, VertexAttributeKind, VertexDescriptor, VertexUsageHint}; +use super::{build_shader_main_string, build_shader_prefix_string, do_build_shader_string, record_gpu_alloc, record_gpu_free}; +use super::{SHADER_KIND_VERTEX, SHADER_KIND_FRAGMENT, depth_target_size_in_bytes, ProgramBinary, ProgramSourceInfo}; +use super::{SHADERS, ProgramSourceDigest}; + use api::{ColorF, ImageFormat, MemoryReport}; use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use api::TextureTarget; -use api::VoidPtrToSizeFn; use api::ImageDescriptor; use euclid::Transform3D; use gleam::gl; -use internal_types::{FastHashMap, LayerIndex, RenderTargetInfo}; +use gpu_types; +use internal_types::{FastHashMap, RenderTargetInfo}; use log::Level; use sha2::{Digest, Sha256}; use smallvec::SmallVec; -use std::borrow::Cow; -use std::cell::{Cell, RefCell}; use std::cmp; use std::collections::hash_map::Entry; use std::marker::PhantomData; use std::mem; -use std::os::raw::c_void; -use std::ops::Add; use std::path::PathBuf; use std::ptr; use std::rc::Rc; use std::slice; use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use std::thread; -use webrender_build::shader::ProgramSourceDigest; -use webrender_build::shader::{parse_shader_source, shader_source_from_file}; - -/// Sequence number for frames, as tracked by the device layer. -#[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct GpuFrameId(usize); - -/// Tracks the total number of GPU bytes allocated across all WebRender instances. -/// -/// Assuming all WebRender instances run on the same thread, this doesn't need -/// to be atomic per se, but we make it atomic to satisfy the thread safety -/// invariants in the type system. We could also put the value in TLS, but that -/// would be more expensive to access. -static GPU_BYTES_ALLOCATED: AtomicUsize = ATOMIC_USIZE_INIT; - -/// Returns the number of GPU bytes currently allocated. -pub fn total_gpu_bytes_allocated() -> usize { - GPU_BYTES_ALLOCATED.load(Ordering::Relaxed) -} - -/// Records an allocation in VRAM. -fn record_gpu_alloc(num_bytes: usize) { - GPU_BYTES_ALLOCATED.fetch_add(num_bytes, Ordering::Relaxed); -} - -/// Records an deallocation in VRAM. -fn record_gpu_free(num_bytes: usize) { - let old = GPU_BYTES_ALLOCATED.fetch_sub(num_bytes, Ordering::Relaxed); - assert!(old >= num_bytes, "Freeing {} bytes but only {} allocated", num_bytes, old); -} - -impl GpuFrameId { - pub fn new(value: usize) -> Self { - GpuFrameId(value) - } -} - -impl Add for GpuFrameId { - type Output = GpuFrameId; - - fn add(self, other: usize) -> GpuFrameId { - GpuFrameId(self.0 + other) - } -} +use tiling::LineDecorationJob; +const MAX_VERTEX_TEXTURE_WIDTH: usize = 1024; const SHADER_VERSION_GL: &str = "#version 150\n"; const SHADER_VERSION_GLES: &str = "#version 300 es\n"; -const SHADER_KIND_VERTEX: &str = "#define WR_VERTEX_SHADER\n"; -const SHADER_KIND_FRAGMENT: &str = "#define WR_FRAGMENT_SHADER\n"; - -pub struct TextureSlot(pub usize); - // In some places we need to temporarily bind a texture to any slot. const DEFAULT_TEXTURE: TextureSlot = TextureSlot(0); +pub struct DeviceInit { + pub gl: Rc, + pub phantom_data: PhantomData, +} + #[repr(u32)] pub enum DepthFunction { Less = gl::LESS, LessEqual = gl::LEQUAL, } -#[repr(u32)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub enum TextureFilter { - Nearest, - Linear, - Trilinear, -} - -#[derive(Debug)] -pub enum VertexAttributeKind { - F32, - U8Norm, - U16Norm, - I32, - U16, -} - -#[derive(Debug)] -pub struct VertexAttribute { - pub name: &'static str, - pub count: u32, - pub kind: VertexAttributeKind, -} - -#[derive(Debug)] -pub struct VertexDescriptor { - pub vertex_attributes: &'static [VertexAttribute], - pub instance_attributes: &'static [VertexAttribute], -} - enum FBOTarget { Read, Draw, } -/// Method of uploading texel data from CPU to GPU. -#[derive(Debug, Clone)] -pub enum UploadMethod { - /// Just call `glTexSubImage` directly with the CPU data pointer - Immediate, - /// Accumulate the changes in PBO first before transferring to a texture. - PixelBuffer(VertexUsageHint), -} - -/// Plain old data that can be used to initialize a texture. -pub unsafe trait Texel: Copy {} -unsafe impl Texel for u8 {} -unsafe impl Texel for f32 {} - -/// Returns the size in bytes of a depth target with the given dimensions. -fn depth_target_size_in_bytes(dimensions: &DeviceIntSize) -> usize { - // DEPTH24 textures generally reserve 3 bytes for depth and 1 byte - // for stencil, so we measure them as 32 bits. - let pixels = dimensions.width * dimensions.height; - (pixels as usize) * 4 -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum ReadPixelsFormat { - Standard(ImageFormat), - Rgba8, -} +pub trait PrimitiveType { } +impl PrimitiveType for gpu_types::BorderInstance { } +impl PrimitiveType for gpu_types::BlurInstance { } +impl PrimitiveType for gpu_types::ClipMaskInstance { } +impl PrimitiveType for gpu_types::PrimitiveInstanceData { } +impl PrimitiveType for gpu_types::ScalingInstance { } +impl PrimitiveType for LineDecorationJob { } pub fn get_gl_target(target: TextureTarget) -> gl::GLuint { match target { @@ -171,112 +79,23 @@ fn supports_extension(extensions: &[String], extension: &str) -> bool { extensions.iter().any(|s| s == extension) } -fn get_shader_version(gl: &gl::Gl) -> &'static str { +pub(crate) fn get_shader_version(gl: &dyn gl::Gl) -> &'static str { match gl.get_type() { gl::GlType::Gl => SHADER_VERSION_GL, gl::GlType::Gles => SHADER_VERSION_GLES, } } -// Get a shader string by name, from the built in resources or -// an override path, if supplied. -fn get_shader_source(shader_name: &str, base_path: Option<&PathBuf>) -> Cow<'static, str> { - if let Some(ref base) = base_path { - let shader_path = base.join(&format!("{}.glsl", shader_name)); - Cow::Owned(shader_source_from_file(&shader_path)) - } else { - Cow::Borrowed( - SHADERS - .get(shader_name) - .expect("Shader not found") - .source - ) +impl VertexUsageHint { + fn to_gl(&self) -> gl::GLuint { + match *self { + VertexUsageHint::Static => gl::STATIC_DRAW, + VertexUsageHint::Dynamic => gl::DYNAMIC_DRAW, + VertexUsageHint::Stream => gl::STREAM_DRAW, + } } } -/// Creates heap-allocated strings for both vertex and fragment shaders. Public -/// to be accessible to tests. -pub fn build_shader_strings( - gl_version_string: &str, - features: &str, - base_filename: &str, - override_path: Option<&PathBuf>, -) -> (String, String) { - let mut vs_source = String::new(); - do_build_shader_string( - gl_version_string, - features, - SHADER_KIND_VERTEX, - base_filename, - override_path, - |s| vs_source.push_str(s), - ); - - let mut fs_source = String::new(); - do_build_shader_string( - gl_version_string, - features, - SHADER_KIND_FRAGMENT, - base_filename, - override_path, - |s| fs_source.push_str(s), - ); - - (vs_source, fs_source) -} - -/// Walks the given shader string and applies the output to the provided -/// callback. Assuming an override path is not used, does no heap allocation -/// and no I/O. -fn do_build_shader_string( - gl_version_string: &str, - features: &str, - kind: &str, - base_filename: &str, - override_path: Option<&PathBuf>, - mut output: F, -) { - build_shader_prefix_string(gl_version_string, features, kind, base_filename, &mut output); - build_shader_main_string(base_filename, override_path, &mut output); -} - -/// Walks the prefix section of the shader string, which manages the various -/// defines for features etc. -fn build_shader_prefix_string( - gl_version_string: &str, - features: &str, - kind: &str, - base_filename: &str, - output: &mut F, -) { - // GLSL requires that the version number comes first. - output(gl_version_string); - - // Insert the shader name to make debugging easier. - let name_string = format!("// {}\n", base_filename); - output(&name_string); - - // Define a constant depending on whether we are compiling VS or FS. - output(kind); - - // Add any defines that were passed by the caller. - output(features); -} - -/// Walks the main .glsl file, including any imports. -fn build_shader_main_string( - base_filename: &str, - override_path: Option<&PathBuf>, - output: &mut F, -) { - let shared_source = get_shader_source(base_filename, override_path); - parse_shader_source(shared_source, &|f| get_shader_source(f, override_path), output); -} - -pub trait FileWatcherHandler: Send { - fn file_changed(&self, path: PathBuf); -} - impl VertexAttributeKind { fn size_in_bytes(&self) -> u32 { match *self { @@ -300,7 +119,7 @@ impl VertexAttribute { divisor: gl::GLuint, stride: gl::GLint, offset: gl::GLuint, - gl: &gl::Gl, + gl: &dyn gl::Gl, ) { gl.enable_vertex_attrib_array(attr_index); gl.vertex_attrib_divisor(attr_index, divisor); @@ -370,7 +189,7 @@ impl VertexDescriptor { attributes: &[VertexAttribute], start_index: usize, divisor: u32, - gl: &gl::Gl, + gl: &dyn gl::Gl, vbo: VBOId, ) { vbo.bind(gl); @@ -388,7 +207,7 @@ impl VertexDescriptor { } } - fn bind(&self, gl: &gl::Gl, main: VBOId, instance: VBOId) { + fn bind(&self, gl: &dyn gl::Gl, main: VBOId, instance: VBOId) { Self::bind_attributes(self.vertex_attributes, 0, 0, gl, main); if !self.instance_attributes.is_empty() { @@ -402,19 +221,19 @@ impl VertexDescriptor { } impl VBOId { - fn bind(&self, gl: &gl::Gl) { + fn bind(&self, gl: &dyn gl::Gl) { gl.bind_buffer(gl::ARRAY_BUFFER, self.0); } } impl IBOId { - fn bind(&self, gl: &gl::Gl) { + fn bind(&self, gl: &dyn gl::Gl) { gl.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.0); } } impl FBOId { - fn bind(&self, gl: &gl::Gl, target: FBOTarget) { + fn bind(&self, gl: &dyn gl::Gl, target: FBOTarget) { let target = match target { FBOTarget::Read => gl::READ_FRAMEBUFFER, FBOTarget::Draw => gl::DRAW_FRAMEBUFFER, @@ -458,146 +277,6 @@ impl Drop for VBO { } } -#[cfg_attr(feature = "replay", derive(Clone))] -pub struct ExternalTexture { - id: gl::GLuint, - target: gl::GLuint, -} - -impl ExternalTexture { - pub fn new(id: u32, target: TextureTarget) -> Self { - ExternalTexture { - id, - target: get_gl_target(target), - } - } - - #[cfg(feature = "replay")] - pub fn internal_id(&self) -> gl::GLuint { - self.id - } -} - -bitflags! { - #[derive(Default)] - pub struct TextureFlags: u32 { - /// This texture corresponds to one of the shared texture caches. - const IS_SHARED_TEXTURE_CACHE = 1 << 0; - } -} - -/// WebRender interface to an OpenGL texture. -/// -/// Because freeing a texture requires various device handles that are not -/// reachable from this struct, manual destruction via `Device` is required. -/// Our `Drop` implementation asserts that this has happened. -pub struct Texture { - id: gl::GLuint, - target: gl::GLuint, - layer_count: i32, - format: ImageFormat, - size: DeviceIntSize, - filter: TextureFilter, - flags: TextureFlags, - /// Framebuffer Objects, one for each layer of the texture, allowing this - /// texture to be rendered to. Empty if this texture is not used as a render - /// target. - fbos: Vec, - /// Same as the above, but with a depth buffer attached. - /// - /// FBOs are cheap to create but expensive to reconfigure (since doing so - /// invalidates framebuffer completeness caching). Moreover, rendering with - /// a depth buffer attached but the depth write+test disabled relies on the - /// driver to optimize it out of the rendering pass, which most drivers - /// probably do but, according to jgilbert, is best not to rely on. - /// - /// So we lazily generate a second list of FBOs with depth. This list is - /// empty if this texture is not used as a render target _or_ if it is, but - /// the depth buffer has never been requested. - /// - /// Note that we always fill fbos, and then lazily create fbos_with_depth - /// when needed. We could make both lazy (i.e. render targets would have one - /// or the other, but not both, unless they were actually used in both - /// configurations). But that would complicate a lot of logic in this module, - /// and FBOs are cheap enough to create. - fbos_with_depth: Vec, - last_frame_used: GpuFrameId, -} - -impl Texture { - pub fn get_dimensions(&self) -> DeviceIntSize { - self.size - } - - pub fn get_layer_count(&self) -> i32 { - self.layer_count - } - - pub fn get_format(&self) -> ImageFormat { - self.format - } - - pub fn get_filter(&self) -> TextureFilter { - self.filter - } - - pub fn supports_depth(&self) -> bool { - !self.fbos_with_depth.is_empty() - } - - pub fn used_in_frame(&self, frame_id: GpuFrameId) -> bool { - self.last_frame_used == frame_id - } - - /// Returns true if this texture was used within `threshold` frames of - /// the current frame. - pub fn used_recently(&self, current_frame_id: GpuFrameId, threshold: usize) -> bool { - self.last_frame_used + threshold >= current_frame_id - } - - /// Returns the flags for this texture. - pub fn flags(&self) -> &TextureFlags { - &self.flags - } - - /// Returns a mutable borrow of the flags for this texture. - pub fn flags_mut(&mut self) -> &mut TextureFlags { - &mut self.flags - } - - /// Returns the number of bytes (generally in GPU memory) that each layer of - /// this texture consumes. - pub fn layer_size_in_bytes(&self) -> usize { - assert!(self.layer_count > 0 || self.size.width + self.size.height == 0); - let bpp = self.format.bytes_per_pixel() as usize; - let w = self.size.width as usize; - let h = self.size.height as usize; - bpp * w * h - } - - /// Returns the number of bytes (generally in GPU memory) that this texture - /// consumes. - pub fn size_in_bytes(&self) -> usize { - self.layer_size_in_bytes() * (self.layer_count as usize) - } - - #[cfg(feature = "replay")] - pub fn into_external(mut self) -> ExternalTexture { - let ext = ExternalTexture { - id: self.id, - target: self.target, - }; - self.id = 0; // don't complain, moved out - ext - } -} - -impl Drop for Texture { - fn drop(&mut self) { - debug_assert!(thread::panicking() || self.id == 0); - } -} - pub struct Program { id: gl::GLuint, u_transform: gl::GLint, @@ -621,72 +300,9 @@ impl Drop for Program { } } -pub struct CustomVAO { - id: gl::GLuint, -} - -impl Drop for CustomVAO { - fn drop(&mut self) { - debug_assert!( - thread::panicking() || self.id == 0, - "renderer::deinit not called" - ); - } -} - -pub struct VAO { - id: gl::GLuint, - ibo_id: IBOId, - main_vbo_id: VBOId, - instance_vbo_id: VBOId, - instance_stride: usize, - owns_vertices_and_indices: bool, -} - -impl Drop for VAO { - fn drop(&mut self) { - debug_assert!( - thread::panicking() || self.id == 0, - "renderer::deinit not called" - ); - } -} - -pub struct PBO { - id: gl::GLuint, -} - -impl Drop for PBO { - fn drop(&mut self) { - debug_assert!( - thread::panicking() || self.id == 0, - "renderer::deinit not called" - ); - } -} - -#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] -pub struct FBOId(gl::GLuint); - -#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] -pub struct RBOId(gl::GLuint); - -#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] -pub struct VBOId(gl::GLuint); - -#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] -struct IBOId(gl::GLuint); - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct ProgramSourceInfo { - base_filename: &'static str, - features: String, - digest: ProgramSourceDigest, -} - impl ProgramSourceInfo { - fn new( - device: &Device, + fn new( + device: &Device, name: &'static str, features: String, ) -> Self { @@ -741,7 +357,7 @@ impl ProgramSourceInfo { } } - fn compute_source(&self, device: &Device, kind: &str) -> String { + fn compute_source(&self, device: &Device, kind: &str) -> String { let mut src = String::new(); device.build_shader_string( &self.features, @@ -753,13 +369,6 @@ impl ProgramSourceInfo { } } -#[cfg_attr(feature = "serialize_program", derive(Deserialize, Serialize))] -pub struct ProgramBinary { - bytes: Vec, - format: gl::GLenum, - source_digest: ProgramSourceDigest, -} - impl ProgramBinary { fn new(bytes: Vec, format: gl::GLenum, @@ -777,92 +386,47 @@ impl ProgramBinary { } } -/// The interfaces that an application can implement to handle ProgramCache update -pub trait ProgramCacheObserver { - fn update_disk_cache(&self, entries: Vec>); - fn notify_program_binary_failed(&self, program_binary: &Arc); +pub struct CustomVAO { + id: gl::GLuint, } -struct ProgramCacheEntry { - /// The binary. - binary: Arc, - /// True if the binary has been linked, i.e. used for rendering. - linked: bool, +impl Drop for CustomVAO { + fn drop(&mut self) { + debug_assert!( + thread::panicking() || self.id == 0, + "renderer::deinit not called" + ); + } } -pub struct ProgramCache { - entries: RefCell>, - - /// True if we've already updated the disk cache with the shaders used during startup. - updated_disk_cache: Cell, - - /// Optional trait object that allows the client - /// application to handle ProgramCache updating - program_cache_handler: Option>, +pub struct VAO { + id: gl::GLuint, + ibo_id: IBOId, + main_vbo_id: VBOId, + instance_vbo_id: VBOId, + instance_stride: usize, + owns_vertices_and_indices: bool, } -impl ProgramCache { - pub fn new(program_cache_observer: Option>) -> Rc { - Rc::new( - ProgramCache { - entries: RefCell::new(FastHashMap::default()), - updated_disk_cache: Cell::new(false), - program_cache_handler: program_cache_observer, - } - ) - } - - /// Notify that we've rendered the first few frames, and that the shaders - /// we've loaded correspond to the shaders needed during startup, and thus - /// should be the ones cached to disk. - fn startup_complete(&self) { - if self.updated_disk_cache.get() { - return; - } - - if let Some(ref handler) = self.program_cache_handler { - let active_shaders = self.entries.borrow().values() - .filter(|e| e.linked).map(|e| e.binary.clone()) - .collect::>(); - handler.update_disk_cache(active_shaders); - self.updated_disk_cache.set(true); - } - } - - /// Load ProgramBinary to ProgramCache. - /// The function is typically used to load ProgramBinary from disk. - #[cfg(feature = "serialize_program")] - pub fn load_program_binary(&self, program_binary: Arc) { - let digest = program_binary.source_digest.clone(); - let entry = ProgramCacheEntry { - binary: program_binary, - linked: false, - }; - self.entries.borrow_mut().insert(digest, entry); - } - - /// Returns the number of bytes allocated for shaders in the cache. - pub fn report_memory(&self, op: VoidPtrToSizeFn) -> usize { - self.entries.borrow().values() - .map(|e| unsafe { op(e.binary.bytes.as_ptr() as *const c_void ) }) - .sum() +impl Drop for VAO { + fn drop(&mut self) { + debug_assert!( + thread::panicking() || self.id == 0, + "renderer::deinit not called" + ); } } -#[derive(Debug, Copy, Clone)] -pub enum VertexUsageHint { - Static, - Dynamic, - Stream, +pub struct PBO { + id: gl::GLuint, } -impl VertexUsageHint { - fn to_gl(&self) -> gl::GLuint { - match *self { - VertexUsageHint::Static => gl::STATIC_DRAW, - VertexUsageHint::Dynamic => gl::DYNAMIC_DRAW, - VertexUsageHint::Stream => gl::STREAM_DRAW, - } +impl Drop for PBO { + fn drop(&mut self) { + debug_assert!( + thread::panicking() || self.id == 0, + "renderer::deinit not called" + ); } } @@ -873,32 +437,6 @@ impl UniformLocation { pub const INVALID: Self = UniformLocation(-1); } -pub struct Capabilities { - pub supports_multisampling: bool, -} - -#[derive(Clone, Debug)] -pub enum ShaderError { - Compilation(String, String), // name, error message - Link(String, String), // name, error message -} - -/// A refcounted depth target, which may be shared by multiple textures across -/// the device. -struct SharedDepthTarget { - /// The Render Buffer Object representing the depth target. - rbo_id: RBOId, - /// Reference count. When this drops to zero, the RBO is deleted. - refcount: usize, -} - -#[cfg(debug_assertions)] -impl Drop for SharedDepthTarget { - fn drop(&mut self) { - debug_assert!(thread::panicking() || self.refcount == 0); - } -} - /// Describes for which texture formats to use the glTexStorage* /// family of functions. #[derive(PartialEq, Debug)] @@ -908,8 +446,8 @@ enum TexStorageUsage { Always, } -pub struct Device { - gl: Rc, +pub struct Device { + gl: Rc, // device state bound_textures: [gl::GLuint; 16], bound_program: gl::GLuint, @@ -966,106 +504,17 @@ pub struct Device { // GL extensions extensions: Vec, + phantom_data: PhantomData, } -/// Contains the parameters necessary to bind a draw target. -#[derive(Clone, Copy)] -pub enum DrawTarget<'a> { - /// Use the device's default draw target, with the provided dimensions, - /// which are used to set the viewport. - Default(DeviceIntSize), - /// Use the provided texture. - Texture { - /// The target texture. - texture: &'a Texture, - /// The slice within the texture array to draw to. - layer: LayerIndex, - /// Whether to draw with the texture's associated depth target. - with_depth: bool, - }, -} - -impl<'a> DrawTarget<'a> { - /// Returns true if this draw target corresponds to the default framebuffer. - pub fn is_default(&self) -> bool { - match *self { - DrawTarget::Default(..) => true, - _ => false, - } - } - - /// Returns the dimensions of this draw-target. - pub fn dimensions(&self) -> DeviceIntSize { - match *self { - DrawTarget::Default(d) => d, - DrawTarget::Texture { texture, .. } => texture.get_dimensions(), - } - } - - /// Given a scissor rect, convert it to the right coordinate space - /// depending on the draw target kind. If no scissor rect was supplied, - /// returns a scissor rect that encloses the entire render target. - pub fn build_scissor_rect( - &self, - scissor_rect: Option, - framebuffer_target_rect: DeviceIntRect, - ) -> DeviceIntRect { - let dimensions = self.dimensions(); - - match scissor_rect { - Some(scissor_rect) => { - // Note: `framebuffer_target_rect` needs a Y-flip before going to GL - if self.is_default() { - let mut rect = scissor_rect - .intersection(&framebuffer_target_rect.to_i32()) - .unwrap_or(DeviceIntRect::zero()); - rect.origin.y = dimensions.height as i32 - rect.origin.y - rect.size.height; - rect - } else { - scissor_rect - } - } - None => { - DeviceIntRect::new( - DeviceIntPoint::zero(), - dimensions, - ) - } - } - } -} - -/// Contains the parameters necessary to bind a texture-backed read target. -#[derive(Clone, Copy)] -pub enum ReadTarget<'a> { - /// Use the device's default draw target. - Default, - /// Use the provided texture, - Texture { - /// The source texture. - texture: &'a Texture, - /// The slice within the texture array to read from. - layer: LayerIndex, - } -} - -impl<'a> From> for ReadTarget<'a> { - fn from(t: DrawTarget<'a>) -> Self { - match t { - DrawTarget::Default(..) => ReadTarget::Default, - DrawTarget::Texture { texture, layer, .. } => - ReadTarget::Texture { texture, layer }, - } - } -} - -impl Device { +impl Device { pub fn new( - mut gl: Rc, + init: DeviceInit, resource_override_path: Option, upload_method: UploadMethod, cached_programs: Option>, - ) -> Device { + ) -> Device { + let mut gl = init.gl; // On debug builds, assert that each GL call is error-free. We don't do // this on release builds because the synchronous call can stall the // pipeline. @@ -1209,15 +658,16 @@ impl Device { frame_id: GpuFrameId(0), extensions, texture_storage_usage, - supports_copy_image_sub_data + supports_copy_image_sub_data, + phantom_data: PhantomData, } } - pub fn gl(&self) -> &gl::Gl { + pub fn gl(&self) -> &dyn gl::Gl { &*self.gl } - pub fn rc_gl(&self) -> &Rc { + pub fn rc_gl(&self) -> &Rc { &self.gl } @@ -1277,7 +727,7 @@ impl Device { } pub fn compile_shader( - gl: &gl::Gl, + gl: &dyn gl::Gl, name: &str, shader_type: gl::GLenum, source: &String, @@ -1528,7 +978,7 @@ impl Device { if build_program { // Compile the vertex shader let vs_source = info.compute_source(self, SHADER_KIND_VERTEX); - let vs_id = match Device::compile_shader(&*self.gl, &info.base_filename, gl::VERTEX_SHADER, &vs_source) { + let vs_id = match Self::compile_shader(&*self.gl, &info.base_filename, gl::VERTEX_SHADER, &vs_source) { Ok(vs_id) => vs_id, Err(err) => return Err(err), }; @@ -1536,7 +986,7 @@ impl Device { // Compile the fragment shader let fs_source = info.compute_source(self, SHADER_KIND_FRAGMENT); let fs_id = - match Device::compile_shader(&*self.gl, &info.base_filename, gl::FRAGMENT_SHADER, &fs_source) { + match Self::compile_shader(&*self.gl, &info.base_filename, gl::FRAGMENT_SHADER, &fs_source) { Ok(fs_id) => fs_id, Err(err) => { self.gl.delete_shader(vs_id); @@ -2015,6 +1465,122 @@ impl Device { program.id = 0; } + pub(crate) fn create_program_with_kind( + &mut self, + base_filename: &'static str, + shader_kind: &ShaderKind, + features: &[&'static str], + precache_flags: ShaderPrecacheFlags, + ) -> Result { + let mut program = match shader_kind { + ShaderKind::Primitive | ShaderKind::Brush | ShaderKind::Text => { + self.create_prim_shader(base_filename, features)? + }, + ShaderKind::Cache(..) => { + self.create_prim_shader(base_filename, features)? + }, + ShaderKind::VectorStencil => { + self.create_prim_shader(base_filename, features)? + }, + ShaderKind::VectorCover => { + self.create_prim_shader(base_filename, features)? + }, + ShaderKind::ClipCache => { + self.create_clip_shader(base_filename)? + }, + }; + + if precache_flags.contains(ShaderPrecacheFlags::FULL_COMPILE) && !program.is_initialized() { + let vertex_format = match shader_kind { + ShaderKind::Primitive | + ShaderKind::Brush | + ShaderKind::Text => VertexArrayKind::Primitive, + ShaderKind::Cache(format) => *format, + ShaderKind::VectorStencil => VertexArrayKind::VectorStencil, + ShaderKind::VectorCover => VertexArrayKind::VectorCover, + ShaderKind::ClipCache => VertexArrayKind::Clip, + }; + + let vertex_descriptor = match vertex_format { + VertexArrayKind::Primitive => &desc::PRIM_INSTANCES, + VertexArrayKind::LineDecoration => &desc::LINE, + VertexArrayKind::Blur => &desc::BLUR, + VertexArrayKind::Clip => &desc::CLIP, + VertexArrayKind::VectorStencil => &desc::VECTOR_STENCIL, + VertexArrayKind::VectorCover => &desc::VECTOR_COVER, + VertexArrayKind::Border => &desc::BORDER, + VertexArrayKind::Scale => &desc::SCALE, + }; + + self.link_program(&mut program, vertex_descriptor)?; + self.bind_program(&mut program); + match shader_kind { + ShaderKind::ClipCache => { + self.bind_shader_samplers( + &program, + &[ + ("sColor0", TextureSampler::Color0), + ("sTransformPalette", TextureSampler::TransformPalette), + ("sRenderTasks", TextureSampler::RenderTasks), + ("sGpuCache", TextureSampler::GpuCache), + ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF), + ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI), + ], + ); + } + _ => { + self.bind_shader_samplers( + &program, + &[ + ("sColor0", TextureSampler::Color0), + ("sColor1", TextureSampler::Color1), + ("sColor2", TextureSampler::Color2), + ("sDither", TextureSampler::Dither), + ("sPrevPassAlpha", TextureSampler::PrevPassAlpha), + ("sPrevPassColor", TextureSampler::PrevPassColor), + ("sTransformPalette", TextureSampler::TransformPalette), + ("sRenderTasks", TextureSampler::RenderTasks), + ("sGpuCache", TextureSampler::GpuCache), + ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF), + ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI), + ], + ); + } + } + } + Ok(program) + } + + fn create_prim_shader( + &mut self, + name: &'static str, + features: &[&'static str], + ) -> Result { + let mut prefix = format!( + "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n", + MAX_VERTEX_TEXTURE_WIDTH + ); + + for feature in features { + prefix.push_str(&format!("#define WR_FEATURE_{}\n", feature)); + } + + debug!("PrimShader {}", name); + + self.create_program(name, prefix) + } + + fn create_clip_shader(&mut self, name: &'static str) -> Result { + let prefix = format!( + "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n", + MAX_VERTEX_TEXTURE_WIDTH + ); + + debug!("ClipShader {}", name); + + self.create_program(name, prefix) + } + /// Create a shader program and link it immediately. pub fn create_program_linked( &mut self, @@ -2063,7 +1629,7 @@ impl Device { Ok(program) } - fn build_shader_string( + pub(crate) fn build_shader_string( &self, features: &str, kind: &str, @@ -2875,7 +2441,7 @@ impl PixelBuffer { } struct UploadTarget<'a> { - gl: &'a gl::Gl, + gl: &'a dyn gl::Gl, bgra_format: gl::GLuint, texture: &'a Texture, } diff --git a/webrender/src/device/mod.rs b/webrender/src/device/mod.rs index 21684dea3e..6159d5b818 100644 --- a/webrender/src/device/mod.rs +++ b/webrender/src/device/mod.rs @@ -2,8 +2,1074 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -mod gl; -pub mod query_gl; +use super::shader_source::SHADERS; +use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, ImageFormat, TextureTarget}; +use api::VoidPtrToSizeFn; +use euclid::Transform3D; +#[cfg(feature = "gleam")] +use gleam::gl as gleam_gl; +use internal_types::{FastHashMap, LayerIndex, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE}; +use std::borrow::Cow; +use std::cell::{Cell, RefCell}; +use std::ops::Add; +use std::os::raw::c_void; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::thread; +use webrender_build::shader::{parse_shader_source, shader_source_from_file}; +use webrender_build::shader::ProgramSourceDigest; -pub use self::gl::*; -pub use self::query_gl as query; +cfg_if! { + if #[cfg(feature = "gleam")] { + mod gl; + pub mod query_gl; + + pub use self::gl::*; + pub use self::query_gl as query; + } else { + mod gfx; + pub mod query_gfx; + + pub use self::gfx::*; + pub use self::query_gfx as query; + } +} + +/// Sequence number for frames, as tracked by the device layer. +#[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct GpuFrameId(usize); + +/// Tracks the total number of GPU bytes allocated across all WebRender instances. +/// +/// Assuming all WebRender instances run on the same thread, this doesn't need +/// to be atomic per se, but we make it atomic to satisfy the thread safety +/// invariants in the type system. We could also put the value in TLS, but that +/// would be more expensive to access. +static GPU_BYTES_ALLOCATED: AtomicUsize = AtomicUsize::new(0); + +/// Returns the number of GPU bytes currently allocated. +pub fn total_gpu_bytes_allocated() -> usize { + GPU_BYTES_ALLOCATED.load(Ordering::Relaxed) +} + +/// Records an allocation in VRAM. +fn record_gpu_alloc(num_bytes: usize) { + GPU_BYTES_ALLOCATED.fetch_add(num_bytes, Ordering::Relaxed); +} + +/// Records an deallocation in VRAM. +fn record_gpu_free(num_bytes: usize) { + let old = GPU_BYTES_ALLOCATED.fetch_sub(num_bytes, Ordering::Relaxed); + assert!(old >= num_bytes, "Freeing {} bytes but only {} allocated", num_bytes, old); +} + +impl GpuFrameId { + pub fn new(value: usize) -> Self { + GpuFrameId(value) + } +} + +impl Add for GpuFrameId { + type Output = GpuFrameId; + + fn add(self, other: usize) -> GpuFrameId { + GpuFrameId(self.0 + other) + } +} + +const SHADER_KIND_VERTEX: &str = "#define WR_VERTEX_SHADER\n"; +const SHADER_KIND_FRAGMENT: &str = "#define WR_FRAGMENT_SHADER\n"; + +#[cfg(not(feature = "gleam"))] +pub type IdType = u32; + +#[cfg(feature = "gleam")] +pub type IdType = gleam_gl::GLuint; + +pub struct TextureSlot(pub usize); + +#[repr(u32)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub enum TextureFilter { + Nearest, + Linear, + Trilinear, +} + +impl Default for TextureFilter { + fn default() -> Self { + TextureFilter::Nearest + } +} + +#[derive(Debug)] +pub enum VertexAttributeKind { + F32, + U8Norm, + U16Norm, + I32, + U16, +} + +#[derive(Debug)] +pub struct VertexAttribute { + pub name: &'static str, + pub count: u32, + pub kind: VertexAttributeKind, +} + +#[derive(Debug)] +pub struct VertexDescriptor { + pub vertex_attributes: &'static [VertexAttribute], + pub instance_attributes: &'static [VertexAttribute], +} + +/// Method of uploading texel data from CPU to GPU. +#[derive(Debug, Clone)] +pub enum UploadMethod { + /// Just call `glTexSubImage` directly with the CPU data pointer + Immediate, + /// Accumulate the changes in PBO first before transferring to a texture. + PixelBuffer(VertexUsageHint), +} + +/// Plain old data that can be used to initialize a texture. +pub unsafe trait Texel: Copy {} +unsafe impl Texel for u8 {} +unsafe impl Texel for f32 {} + +#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] +pub struct FBOId(IdType); + +#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] +pub struct RBOId(IdType); + +#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] +pub struct VBOId(IdType); + +#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] +struct IBOId(IdType); + +/// Returns the size in bytes of a depth target with the given dimensions. +fn depth_target_size_in_bytes(dimensions: &DeviceIntSize) -> usize { + // DEPTH24 textures generally reserve 3 bytes for depth and 1 byte + // for stencil, so we measure them as 32 bits. + let pixels = dimensions.width * dimensions.height; + (pixels as usize) * 4 +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ReadPixelsFormat { + Standard(ImageFormat), + Rgba8, +} + +// Get a shader string by name, from the built in resources or +// an override path, if supplied. +fn get_shader_source(shader_name: &str, base_path: Option<&PathBuf>) -> Cow<'static, str> { + if let Some(ref base) = base_path { + let shader_path = base.join(&format!("{}.glsl", shader_name)); + Cow::Owned(shader_source_from_file(&shader_path)) + } else { + Cow::Borrowed( + SHADERS + .get(shader_name) + .expect("Shader not found") + .source + ) + } +} + +/// Creates heap-allocated strings for both vertex and fragment shaders. Public +/// to be accessible to tests. +pub fn build_shader_strings( + gl_version_string: &str, + features: &str, + base_filename: &str, + override_path: Option<&PathBuf>, +) -> (String, String) { + let mut vs_source = String::new(); + do_build_shader_string( + gl_version_string, + features, + SHADER_KIND_VERTEX, + base_filename, + override_path, + |s| vs_source.push_str(s), + ); + + let mut fs_source = String::new(); + do_build_shader_string( + gl_version_string, + features, + SHADER_KIND_FRAGMENT, + base_filename, + override_path, + |s| fs_source.push_str(s), + ); + + (vs_source, fs_source) +} + +/// Walks the given shader string and applies the output to the provided +/// callback. Assuming an override path is not used, does no heap allocation +/// and no I/O. +fn do_build_shader_string( + gl_version_string: &str, + features: &str, + kind: &str, + base_filename: &str, + override_path: Option<&PathBuf>, + mut output: F, +) { + build_shader_prefix_string(gl_version_string, features, kind, base_filename, &mut output); + build_shader_main_string(base_filename, override_path, &mut output); +} + +/// Walks the prefix section of the shader string, which manages the various +/// defines for features etc. +fn build_shader_prefix_string( + gl_version_string: &str, + features: &str, + kind: &str, + base_filename: &str, + output: &mut F, +) { + // GLSL requires that the version number comes first. + output(gl_version_string); + + // Insert the shader name to make debugging easier. + let name_string = format!("// {}\n", base_filename); + output(&name_string); + + // Define a constant depending on whether we are compiling VS or FS. + output(kind); + + // Add any defines that were passed by the caller. + output(features); +} + +/// Walks the main .glsl file, including any imports. +fn build_shader_main_string( + base_filename: &str, + override_path: Option<&PathBuf>, + output: &mut F, +) { + let shared_source = get_shader_source(base_filename, override_path); + parse_shader_source(shared_source, &|f| get_shader_source(f, override_path), output); +} + +pub trait FileWatcherHandler: Send { + fn file_changed(&self, path: PathBuf); +} + +#[cfg_attr(feature = "replay", derive(Clone))] +pub struct ExternalTexture { + id: IdType, + #[cfg_attr(not(feature = "gleam"), allow(dead_code))] + target: IdType, +} + + +impl ExternalTexture { + pub fn new(id: u32, target: TextureTarget) -> Self { + ExternalTexture { + id, + #[cfg(feature = "gleam")] + target: get_gl_target(target), + #[cfg(not(feature = "gleam"))] + target: target as _, + } + } + + #[cfg(feature = "replay")] + pub fn internal_id(&self) -> IdType { + self.id + } +} + +bitflags! { + #[derive(Default)] + pub struct TextureFlags: u32 { + /// This texture corresponds to one of the shared texture caches. + const IS_SHARED_TEXTURE_CACHE = 1 << 0; + } +} + +/// WebRender interface to an OpenGL texture. +/// +/// Because freeing a texture requires various device handles that are not +/// reachable from this struct, manual destruction via `Device` is required. +/// Our `Drop` implementation asserts that this has happened. +#[cfg_attr(not(feature = "gleam"), derive(Clone))] +pub struct Texture { + id: IdType, + #[cfg_attr(not(feature = "gleam"), allow(dead_code))] + target: IdType, + layer_count: i32, + format: ImageFormat, + size: DeviceIntSize, + filter: TextureFilter, + flags: TextureFlags, + /// Framebuffer Objects, one for each layer of the texture, allowing this + /// texture to be rendered to. Empty if this texture is not used as a render + /// target. + fbos: Vec, + /// Same as the above, but with a depth buffer attached. + /// + /// FBOs are cheap to create but expensive to reconfigure (since doing so + /// invalidates framebuffer completeness caching). Moreover, rendering with + /// a depth buffer attached but the depth write+test disabled relies on the + /// driver to optimize it out of the rendering pass, which most drivers + /// probably do but, according to jgilbert, is best not to rely on. + /// + /// So we lazily generate a second list of FBOs with depth. This list is + /// empty if this texture is not used as a render target _or_ if it is, but + /// the depth buffer has never been requested. + /// + /// Note that we always fill fbos, and then lazily create fbos_with_depth + /// when needed. We could make both lazy (i.e. render targets would have one + /// or the other, but not both, unless they were actually used in both + /// configurations). But that would complicate a lot of logic in this module, + /// and FBOs are cheap enough to create. + fbos_with_depth: Vec, + last_frame_used: GpuFrameId, + #[cfg(not(feature = "gleam"))] + pub bound_in_frame: Cell, + #[cfg(not(feature = "gleam"))] + is_buffer: bool, +} + +impl Texture { + pub fn id(&self) -> IdType { + self.id + } + + pub fn get_dimensions(&self) -> DeviceIntSize { + self.size + } + + pub fn get_layer_count(&self) -> i32 { + self.layer_count + } + + pub fn get_format(&self) -> ImageFormat { + self.format + } + + pub fn get_filter(&self) -> TextureFilter { + self.filter + } + + pub fn supports_depth(&self) -> bool { + !self.fbos_with_depth.is_empty() + } + + pub fn used_in_frame(&self, frame_id: GpuFrameId) -> bool { + self.last_frame_used == frame_id + } + + /// Returns true if this texture was used within `threshold` frames of + /// the current frame. + pub fn used_recently(&self, current_frame_id: GpuFrameId, threshold: usize) -> bool { + self.last_frame_used + threshold >= current_frame_id + } + + /// Returns the flags for this texture. + pub fn flags(&self) -> &TextureFlags { + &self.flags + } + + /// Returns a mutable borrow of the flags for this texture. + pub fn flags_mut(&mut self) -> &mut TextureFlags { + &mut self.flags + } + + /// Returns the number of bytes (generally in GPU memory) that each layer of + /// this texture consumes. + pub fn layer_size_in_bytes(&self) -> usize { + assert!(self.layer_count > 0 || self.size.width + self.size.height == 0); + let bpp = self.format.bytes_per_pixel() as usize; + let w = self.size.width as usize; + let h = self.size.height as usize; + bpp * w * h + } + + /// Returns the number of bytes (generally in GPU memory) that this texture + /// consumes. + pub fn size_in_bytes(&self) -> usize { + self.layer_size_in_bytes() * (self.layer_count as usize) + } + + #[cfg(feature = "replay")] + pub fn into_external(mut self) -> ExternalTexture { + let ext = ExternalTexture { + id: self.id, + target: self.target, + }; + self.id = 0; // don't complain, moved out + ext + } +} + +impl Drop for Texture { + fn drop(&mut self) { + debug_assert!(thread::panicking() || self.id == 0); + } +} + +/// The interfaces that an application can implement to handle ProgramCache update +pub trait ProgramCacheObserver { + fn update_disk_cache(&self, entries: Vec>); + fn notify_program_binary_failed(&self, program_binary: &Arc); +} + +struct ProgramCacheEntry { + /// The binary. + binary: Arc, + /// True if the binary has been linked, i.e. used for rendering. + #[cfg(feature="gleam")] + linked: bool, +} + +pub struct ProgramCache { + entries: RefCell>, + + /// True if we've already updated the disk cache with the shaders used during startup. + #[cfg(feature="gleam")] + updated_disk_cache: Cell, + + /// Optional trait object that allows the client + /// application to handle ProgramCache updating + #[cfg(feature="gleam")] + program_cache_handler: Option>, +} + +impl ProgramCache { + pub fn new(_program_cache_observer: Option>) -> Rc { + Rc::new( + ProgramCache { + entries: RefCell::new(FastHashMap::default()), + #[cfg(feature="gleam")] + updated_disk_cache: Cell::new(false), + #[cfg(feature="gleam")] + program_cache_handler: _program_cache_observer, + } + ) + } + + /// Notify that we've rendered the first few frames, and that the shaders + /// we've loaded correspond to the shaders needed during startup, and thus + /// should be the ones cached to disk. + #[cfg(feature="gleam")] + fn startup_complete(&self) { + if self.updated_disk_cache.get() { + return; + } + + if let Some(ref handler) = self.program_cache_handler { + let active_shaders = self.entries.borrow().values() + .filter(|e| e.linked).map(|e| e.binary.clone()) + .collect::>(); + handler.update_disk_cache(active_shaders); + self.updated_disk_cache.set(true); + } + } + + /// Load ProgramBinary to ProgramCache. + /// The function is typically used to load ProgramBinary from disk. + #[cfg(all(feature = "serialize_program", feature = "gleam"))] + pub fn load_program_binary(&self, program_binary: Arc) { + let digest = program_binary.source_digest.clone(); + let entry = ProgramCacheEntry { + binary: program_binary, + linked: false, + }; + self.entries.borrow_mut().insert(digest, entry); + } + + /// Returns the number of bytes allocated for shaders in the cache. + pub fn report_memory(&self, op: VoidPtrToSizeFn) -> usize { + self.entries.borrow().values() + .map(|e| unsafe { op(e.binary.bytes.as_ptr() as *const c_void ) }) + .sum() + } +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct ProgramSourceInfo { + base_filename: &'static str, + features: String, + digest: ProgramSourceDigest, +} + +#[cfg_attr(feature = "serialize_program", derive(Deserialize, Serialize))] +pub struct ProgramBinary { + bytes: Vec, + #[cfg(feature="gleam")] + format: gleam_gl::GLenum, + #[cfg(feature="gleam")] + source_digest: ProgramSourceDigest, +} + +#[derive(Debug, Copy, Clone)] +pub enum VertexUsageHint { + Static, + Dynamic, + Stream, +} + +pub struct Capabilities { + pub supports_multisampling: bool, +} + +#[derive(Clone, Debug)] +pub enum ShaderError { + Compilation(String, String), // name, error message + Link(String, String), // name, error message +} + +#[derive(Eq, PartialEq, Hash, Debug, Copy, Clone)] +pub enum ShaderKind { + Primitive, + Cache(VertexArrayKind), + ClipCache, + Brush, + Text, + #[allow(dead_code)] + VectorStencil, + #[allow(dead_code)] + VectorCover, + #[cfg(all(not(feature = "gleam")))] + DebugColor, + #[cfg(all(not(feature = "gleam")))] + DebugFont, +} + +#[derive(Eq, PartialEq, Hash, Debug, Copy, Clone)] +pub enum VertexArrayKind { + Primitive, + Blur, + Clip, + #[cfg_attr(not(feature = "gleam"), allow(dead_code))] + VectorStencil, + #[cfg_attr(not(feature = "gleam"), allow(dead_code))] + VectorCover, + Border, + Scale, + LineDecoration, +} + +/// A refcounted depth target, which may be shared by multiple textures across +/// the device. +struct SharedDepthTarget { + /// The Render Buffer Object representing the depth target. + rbo_id: RBOId, + /// Reference count. When this drops to zero, the RBO is deleted. + refcount: usize, +} + +#[cfg(debug_assertions)] +impl Drop for SharedDepthTarget { + fn drop(&mut self) { + debug_assert!(thread::panicking() || self.refcount == 0); + } +} + +/// Contains the parameters necessary to bind a draw target. +#[derive(Clone, Copy)] +pub enum DrawTarget<'a> { + /// Use the device's default draw target, with the provided dimensions, + /// which are used to set the viewport. + Default(DeviceIntSize), + /// Use the provided texture. + Texture { + /// The target texture. + texture: &'a Texture, + /// The slice within the texture array to draw to. + layer: LayerIndex, + /// Whether to draw with the texture's associated depth target. + with_depth: bool, + }, +} + +impl<'a> DrawTarget<'a> { + /// Returns true if this draw target corresponds to the default framebuffer. + pub fn is_default(&self) -> bool { + match *self { + DrawTarget::Default(..) => true, + _ => false, + } + } + + /// Returns the dimensions of this draw-target. + pub fn dimensions(&self) -> DeviceIntSize { + match *self { + DrawTarget::Default(d) => d, + DrawTarget::Texture { texture, .. } => texture.get_dimensions(), + } + } + + /// Given a scissor rect, convert it to the right coordinate space + /// depending on the draw target kind. If no scissor rect was supplied, + /// returns a scissor rect that encloses the entire render target. + pub fn build_scissor_rect( + &self, + scissor_rect: Option, + framebuffer_target_rect: DeviceIntRect, + ) -> DeviceIntRect { + let dimensions = self.dimensions(); + + match scissor_rect { + Some(scissor_rect) => { + // Note: `framebuffer_target_rect` needs a Y-flip before going to GL + if self.is_default() { + let mut rect = scissor_rect + .intersection(&framebuffer_target_rect.to_i32()) + .unwrap_or(DeviceIntRect::zero()); + if cfg!(feature = "gleam") { + rect.origin.y = dimensions.height as i32 - rect.origin.y - rect.size.height; + } + rect + } else { + scissor_rect + } + } + None => { + DeviceIntRect::new( + DeviceIntPoint::zero(), + dimensions, + ) + } + } + } +} + +/// Contains the parameters necessary to bind a texture-backed read target. +#[derive(Clone, Copy)] +pub enum ReadTarget<'a> { + /// Use the device's default draw target. + Default, + /// Use the provided texture, + Texture { + /// The source texture. + texture: &'a Texture, + /// The slice within the texture array to read from. + layer: LayerIndex, + } +} + +impl<'a> From> for ReadTarget<'a> { + fn from(t: DrawTarget<'a>) -> Self { + match t { + DrawTarget::Default(..) => ReadTarget::Default, + DrawTarget::Texture { texture, layer, .. } => + ReadTarget::Texture { texture, layer }, + } + } +} + +bitflags! { + /// Flags that control how shaders are pre-cached, if at all. + #[derive(Default)] + pub struct ShaderPrecacheFlags: u32 { + /// Needed for const initialization + const EMPTY = 0; + + /// Only start async compile + const ASYNC_COMPILE = 1 << 2; + + /// Do a full compile/link during startup + const FULL_COMPILE = 1 << 3; + } +} + +/// Enumeration of the texture samplers used across the various WebRender shaders. +/// +/// Each variant corresponds to a uniform declared in shader source. We only bind +/// the variants we need for a given shader, so not every variant is bound for every +/// batch. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub(crate) enum TextureSampler { + Color0, + Color1, + Color2, + PrevPassAlpha, + PrevPassColor, + GpuCache, + TransformPalette, + RenderTasks, + Dither, + PrimitiveHeadersF, + PrimitiveHeadersI, +} + +impl TextureSampler { + pub(crate) fn color(n: usize) -> TextureSampler { + match n { + 0 => TextureSampler::Color0, + 1 => TextureSampler::Color1, + 2 => TextureSampler::Color2, + _ => { + panic!("There are only 3 color samplers."); + } + } + } +} + +impl Into for TextureSampler { + fn into(self) -> TextureSlot { + match self { + TextureSampler::Color0 => TextureSlot(0), + TextureSampler::Color1 => TextureSlot(1), + TextureSampler::Color2 => TextureSlot(2), + TextureSampler::PrevPassAlpha => TextureSlot(3), + TextureSampler::PrevPassColor => TextureSlot(4), + TextureSampler::GpuCache => TextureSlot(5), + TextureSampler::TransformPalette => TextureSlot(6), + TextureSampler::RenderTasks => TextureSlot(7), + TextureSampler::Dither => TextureSlot(8), + TextureSampler::PrimitiveHeadersF => TextureSlot(9), + TextureSampler::PrimitiveHeadersI => TextureSlot(10), + } + } +} + +pub(crate) fn create_projection( + left: f32, + right: f32, + bottom: f32, + top: f32, + main_frame_buffer: bool +) -> Transform3D { + let projection = Transform3D::ortho( + left, + right, + bottom, + top, + ORTHO_NEAR_PLANE, + ORTHO_FAR_PLANE, + ); + if main_frame_buffer && cfg!(not(feature = "gleam")) { + return projection.post_scale(1.0, -1.0, 1.0); + } + projection +} + +pub(crate) mod desc { + #![cfg_attr(not(feature = "gleam"), allow(dead_code))] + use device::{VertexAttribute, VertexAttributeKind, VertexDescriptor}; + + pub const PRIM_INSTANCES: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aData", + count: 4, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const BLUR: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aBlurRenderTaskAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aBlurSourceTaskAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aBlurDirection", + count: 1, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const LINE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aTaskRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aLocalSize", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aWavyLineThickness", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aStyle", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aOrientation", + count: 1, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const BORDER: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aTaskOrigin", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aColor0", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aColor1", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aFlags", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aWidths", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aRadii", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipParams1", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipParams2", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const SCALE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aScaleRenderTaskAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aScaleSourceTaskAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const CLIP: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aClipRenderTaskAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aClipTransformId", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aPrimTransformId", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aClipDataResourceAddress", + count: 4, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aClipLocalPos", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipTileRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipDeviceArea", + count: 4, + kind: VertexAttributeKind::F32, + } + ], + }; + + pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U16Norm, + }, + VertexAttribute { + name: "aValue", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[], + }; + + pub const VECTOR_STENCIL: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aFromPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aCtrlPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aToPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aFromNormal", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aCtrlNormal", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aToNormal", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aPathID", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aPad", + count: 1, + kind: VertexAttributeKind::U16, + }, + ], + }; + + pub const VECTOR_COVER: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aTargetRect", + count: 4, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aStencilOrigin", + count: 2, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aSubpixel", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aPad", + count: 1, + kind: VertexAttributeKind::U16, + }, + ], + }; +} diff --git a/webrender/src/device/query_gfx.rs b/webrender/src/device/query_gfx.rs new file mode 100644 index 0000000000..9256d2f305 --- /dev/null +++ b/webrender/src/device/query_gfx.rs @@ -0,0 +1,274 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::mem; + +use device::GpuFrameId; + + +pub trait NamedTag { + fn get_label(&self) -> &str; +} + +#[derive(Debug, Clone)] +pub struct GpuTimer { + pub tag: T, + pub time_ns: u64, +} + +#[derive(Debug, Clone)] +pub struct GpuSampler { + pub tag: T, + pub count: u64, +} + +pub struct QuerySet { + set: Vec, + data: Vec, + pending: u32, +} + +impl QuerySet { + fn new() -> Self { + QuerySet { + set: Vec::new(), + data: Vec::new(), + pending: 0, + } + } + + fn reset(&mut self) { + self.data.clear(); + self.pending = 0; + } + + fn add(&mut self, value: T) -> Option { + assert_eq!(self.pending, 0); + self.set.get(self.data.len()).cloned().map(|query_id| { + self.data.push(value); + self.pending = query_id; + query_id + }) + } + + fn take(&mut self, fun: F) -> Vec { + let mut data = mem::replace(&mut self.data, Vec::new()); + for (value, &query) in data.iter_mut().zip(self.set.iter()) { + fun(value, query) + } + data + } +} + +pub struct GpuFrameProfile { + timers: QuerySet>, + samplers: QuerySet>, + frame_id: GpuFrameId, + inside_frame: bool, +} + +impl GpuFrameProfile { + fn new() -> Self { + GpuFrameProfile { + timers: QuerySet::new(), + samplers: QuerySet::new(), + frame_id: GpuFrameId::new(0), + inside_frame: false, + } + } + + fn enable_timers(&mut self, _count: i32) { + self.timers.set = Vec::new(); + } + + fn disable_timers(&mut self) { + if !self.timers.set.is_empty() { + self.timers.set.clear(); + } + self.timers.set = Vec::new(); + } + + fn enable_samplers(&mut self, _count: i32) { + self.samplers.set = Vec::new(); + } + + fn disable_samplers(&mut self) { + if !self.samplers.set.is_empty() { + self.samplers.set.clear(); + } + self.samplers.set = Vec::new(); + } + + fn begin_frame(&mut self, frame_id: GpuFrameId) { + self.frame_id = frame_id; + self.timers.reset(); + self.samplers.reset(); + self.inside_frame = true; + } + + fn end_frame(&mut self) { + self.finish_timer(); + self.finish_sampler(); + self.inside_frame = false; + } + + fn finish_timer(&mut self) { + debug_assert!(self.inside_frame); + if self.timers.pending != 0 { + self.timers.pending = 0; + } + } + + fn finish_sampler(&mut self) { + debug_assert!(self.inside_frame); + if self.samplers.pending != 0 { + self.samplers.pending = 0; + } + } +} + +impl GpuFrameProfile { + fn start_timer(&mut self, tag: T) -> GpuTimeQuery { + self.finish_timer(); + + let marker = GpuMarker::new(tag.get_label()); + + if let Some(_query) = self.timers.add(GpuTimer { tag, time_ns: 0 }) { + } + + GpuTimeQuery(marker) + } + + fn start_sampler(&mut self, tag: T) -> GpuSampleQuery { + self.finish_sampler(); + + if let Some(_query) = self.samplers.add(GpuSampler { tag, count: 0 }) { + } + + GpuSampleQuery + } + + fn build_samples(&mut self) -> (GpuFrameId, Vec>, Vec>) { + debug_assert!(!self.inside_frame); + + ( + self.frame_id, + self.timers.take(|timer, _query| { + timer.time_ns = 0 + }), + self.samplers.take(|sampler, _query| { + sampler.count = 0 + }), + ) + } +} + +impl Drop for GpuFrameProfile { + fn drop(&mut self) { + self.disable_timers(); + self.disable_samplers(); + } +} + +pub struct GpuProfiler { + frames: Vec>, + next_frame: usize, +} + +impl GpuProfiler { + pub fn new() -> Self { + const MAX_PROFILE_FRAMES: usize = 4; + let frames = (0 .. MAX_PROFILE_FRAMES) + .map(|_| GpuFrameProfile::new()) + .collect(); + + GpuProfiler { + next_frame: 0, + frames, + } + } + + pub fn enable_timers(&mut self) { + const MAX_TIMERS_PER_FRAME: i32 = 256; + + for frame in &mut self.frames { + frame.enable_timers(MAX_TIMERS_PER_FRAME); + } + } + + pub fn disable_timers(&mut self) { + for frame in &mut self.frames { + frame.disable_timers(); + } + } + + pub fn enable_samplers(&mut self) { + const MAX_SAMPLERS_PER_FRAME: i32 = 16; + if cfg!(target_os = "macos") { + warn!("Expect macOS driver bugs related to sample queries") + } + + for frame in &mut self.frames { + frame.enable_samplers(MAX_SAMPLERS_PER_FRAME); + } + } + + pub fn disable_samplers(&mut self) { + for frame in &mut self.frames { + frame.disable_samplers(); + } + } +} + +impl GpuProfiler { + pub fn build_samples(&mut self) -> (GpuFrameId, Vec>, Vec>) { + self.frames[self.next_frame].build_samples() + } + + pub fn begin_frame(&mut self, frame_id: GpuFrameId) { + self.frames[self.next_frame].begin_frame(frame_id); + } + + pub fn end_frame(&mut self) { + self.frames[self.next_frame].end_frame(); + self.next_frame = (self.next_frame + 1) % self.frames.len(); + } + + pub fn start_timer(&mut self, tag: T) -> GpuTimeQuery { + self.frames[self.next_frame].start_timer(tag) + } + + pub fn start_sampler(&mut self, tag: T) -> GpuSampleQuery { + self.frames[self.next_frame].start_sampler(tag) + } + + pub fn finish_sampler(&mut self, _sampler: GpuSampleQuery) { + self.frames[self.next_frame].finish_sampler() + } + + pub fn start_marker(&mut self, label: &str) -> GpuMarker { + GpuMarker::new( label) + } + + pub fn place_marker(&mut self, label: &str) { + GpuMarker::fire( label) + } +} + +#[must_use] +pub struct GpuMarker; + +impl GpuMarker { + fn new(_message: &str) -> Self { + GpuMarker { } + } + + fn fire(_message: &str) { + } +} + +#[must_use] +pub struct GpuTimeQuery(GpuMarker); +#[must_use] +pub struct GpuSampleQuery; diff --git a/webrender/src/device/query_gl.rs b/webrender/src/device/query_gl.rs index 1ed30c8b61..dafe58e25e 100644 --- a/webrender/src/device/query_gl.rs +++ b/webrender/src/device/query_gl.rs @@ -64,7 +64,7 @@ impl QuerySet { } pub struct GpuFrameProfile { - gl: Rc, + gl: Rc, timers: QuerySet>, samplers: QuerySet>, frame_id: GpuFrameId, @@ -73,7 +73,7 @@ pub struct GpuFrameProfile { } impl GpuFrameProfile { - fn new(gl: Rc, ext_debug_marker: bool) -> Self { + fn new(gl: Rc, ext_debug_marker: bool) -> Self { GpuFrameProfile { gl, timers: QuerySet::new(), @@ -183,14 +183,14 @@ impl Drop for GpuFrameProfile { } pub struct GpuProfiler { - gl: Rc, + gl: Rc, frames: Vec>, next_frame: usize, ext_debug_marker: bool } impl GpuProfiler { - pub fn new(gl: Rc, ext_debug_marker: bool) -> Self { + pub fn new(gl: Rc, ext_debug_marker: bool) -> Self { const MAX_PROFILE_FRAMES: usize = 4; let frames = (0 .. MAX_PROFILE_FRAMES) .map(|_| GpuFrameProfile::new(Rc::clone(&gl), ext_debug_marker)) @@ -273,11 +273,11 @@ impl GpuProfiler { #[must_use] pub struct GpuMarker { - gl: Option> + gl: Option> } impl GpuMarker { - fn new(gl: &Rc, message: &str, ext_debug_marker: bool) -> Self { + fn new(gl: &Rc, message: &str, ext_debug_marker: bool) -> Self { let gl = if ext_debug_marker { gl.push_group_marker_ext(message); Some(Rc::clone(gl)) @@ -287,7 +287,7 @@ impl GpuMarker { GpuMarker { gl } } - fn fire(gl: &Rc, message: &str, ext_debug_marker: bool) { + fn fire(gl: &Rc, message: &str, ext_debug_marker: bool) { if ext_debug_marker { gl.insert_event_marker_ext(message); } diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index dfc4d4271b..6d4e7a1211 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -892,7 +892,7 @@ impl<'a> DisplayListFlattener<'a> { // refer to another user defined clip-chain. If none is specified, // the parent is the root clip-chain for the given pipeline. This // is used to provide a root clip chain for iframes. - let mut parent_clip_chain_id = match info.parent { + let parent_clip_chain_id = match info.parent { Some(id) => { self.id_to_index_mapper.get_clip_chain_id(ClipId::ClipChain(id)) } diff --git a/webrender/src/glyph_rasterizer/mod.rs b/webrender/src/glyph_rasterizer/mod.rs index 2c7dc7081c..e5d667be5e 100644 --- a/webrender/src/glyph_rasterizer/mod.rs +++ b/webrender/src/glyph_rasterizer/mod.rs @@ -352,9 +352,9 @@ impl SubpixelOffset { let apos = ((pos - pos.floor()) * 8.0) as i32; match apos { - 1...2 => SubpixelOffset::Quarter, - 3...4 => SubpixelOffset::Half, - 5...6 => SubpixelOffset::ThreeQuarters, + 1..=2 => SubpixelOffset::Quarter, + 3..=4 => SubpixelOffset::Half, + 5..=6 => SubpixelOffset::ThreeQuarters, _ => SubpixelOffset::Zero, } } diff --git a/webrender/src/glyph_rasterizer/no_pathfinder.rs b/webrender/src/glyph_rasterizer/no_pathfinder.rs index 18b944090a..fb14b38fd7 100644 --- a/webrender/src/glyph_rasterizer/no_pathfinder.rs +++ b/webrender/src/glyph_rasterizer/no_pathfinder.rs @@ -58,7 +58,7 @@ impl GlyphRasterizer { // select glyphs that have not been requested yet. for key in glyph_keys { match glyph_key_cache.entry(key.clone()) { - Entry::Occupied(mut entry) => { + Entry::Occupied(entry) => { let value = entry.into_mut(); match *value { GlyphCacheEntry::Cached(ref glyph) => { diff --git a/webrender/src/gpu_cache.rs b/webrender/src/gpu_cache.rs index 1ce2544186..3bbc56e917 100644 --- a/webrender/src/gpu_cache.rs +++ b/webrender/src/gpu_cache.rs @@ -25,11 +25,17 @@ //! for this frame. use api::{DebugFlags, DocumentId, PremultipliedColorF, IdNamespace, TexelRect}; +#[cfg(not(feature="gleam"))] +use device::{BufferMemorySlice, GpuCacheBuffer, PersistentlyMappedBuffer}; use euclid::TypedRect; +#[cfg(not(feature="gleam"))] +use hal; use internal_types::{FastHashMap}; use profiler::GpuCacheProfileCounters; use render_backend::{FrameStamp, FrameId}; use renderer::MAX_VERTEX_TEXTURE_WIDTH; +#[cfg(not(feature="gleam"))] +use rendy_memory::Write; use std::{mem, u16, u32}; use std::num::NonZeroU32; use std::ops::Add; @@ -54,7 +60,7 @@ const RECLAIM_THRESHOLD: f32 = 0.2; const RECLAIM_DELAY_S: u64 = 5; #[derive(Debug, Copy, Clone, Eq, MallocSizeOf, PartialEq)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct Epoch(u32); @@ -65,7 +71,7 @@ impl Epoch { } #[derive(Debug, Copy, Clone, MallocSizeOf)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct CacheLocation { block_index: BlockIndex, @@ -74,14 +80,16 @@ struct CacheLocation { /// A single texel in RGBAF32 texture - 16 bytes. #[derive(Copy, Clone, Debug, MallocSizeOf)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct GpuBlockData { - data: [f32; 4], + pub data: [f32; 4], } impl GpuBlockData { pub const EMPTY: Self = GpuBlockData { data: [0.0; 4] }; + #[cfg(not(feature= "gleam"))] + pub const SIZE: u64 = 16; } /// Conversion helpers for GpuBlockData @@ -146,7 +154,7 @@ impl GpuCacheHandle { // as part of the primitive instances, to allow the vertex // shader to fetch the specific data. #[derive(Copy, Debug, Clone, MallocSizeOf, Eq, PartialEq)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct GpuCacheAddress { pub u: u16, @@ -182,7 +190,7 @@ impl Add for GpuCacheAddress { // An entry in a free-list of blocks in the GPU cache. #[derive(Debug, MallocSizeOf)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct Block { // The location in the cache of this block. @@ -234,7 +242,7 @@ impl Block { /// Because we use Option in a lot of places, we use a NonZeroU32 /// here and avoid ever using the index zero. #[derive(Debug, Copy, Clone, MallocSizeOf)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct BlockIndex(NonZeroU32); @@ -250,7 +258,7 @@ impl BlockIndex { } // A row in the cache texture. -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(MallocSizeOf)] struct Row { @@ -273,7 +281,7 @@ impl Row { // this frame. The list of updates is created by the render backend // during frame construction. It's passed to the render thread // where GL commands can be applied. -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(MallocSizeOf)] pub enum GpuCacheUpdate { @@ -287,6 +295,7 @@ pub enum GpuCacheUpdate { /// Command to inform the debug display in the renderer when chunks are allocated /// or freed. #[derive(MallocSizeOf)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] pub enum GpuCacheDebugCmd { /// Describes an allocated chunk. Alloc(GpuCacheDebugChunk), @@ -295,13 +304,13 @@ pub enum GpuCacheDebugCmd { } #[derive(Clone, MallocSizeOf)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] pub struct GpuCacheDebugChunk { pub address: GpuCacheAddress, pub size: usize, } -#[must_use] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(MallocSizeOf)] pub struct GpuCacheUpdateList { @@ -319,13 +328,52 @@ pub struct GpuCacheUpdateList { /// to GPU memory. pub blocks: Vec, /// Whole state GPU block metadata for debugging. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))] pub debug_commands: Vec, } +#[cfg(not(feature="gleam"))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] +pub struct GpuCacheBufferUpdate { + /// The frame current update list was generated from. + pub frame_id: FrameId, + /// If a new GPU cache buffer is created Renderer needs to know about this. + #[cfg_attr(any(feature = "capture", feature = "replay", feature = "serialize_program"), serde(skip))] + pub buffer_update: BufferInfo, + /// Whole state GPU block metadata for debugging. + #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))] + pub debug_commands: Vec, +} + +#[cfg(not(feature="gleam"))] +#[derive(MallocSizeOf)] +pub enum BufferInfo { + BufferUpdate { + /// A view into the current GPU cache buffer's memory on the CPU side, + /// to write out deferred resolves in the Renderer thread. + buffer_memory_slice: BufferMemorySlice, + /// The handle of the new buffer, + /// this is needed for creating descriptor sets in the Renderer thread. + new_buffer_info: GpuCacheBuffer, + /// The old buffer. We keep this alive in the Renderer thread + /// until it's underlying buffer handle is bound to a frame. + old_buffer: Option>, + }, + TransitRangeUpdate(u64), +} + +#[cfg(not(feature="gleam"))] +impl std::default::Default for BufferInfo { + fn default() -> Self { + BufferInfo::TransitRangeUpdate(0) + } +} + // Holds the free lists of fixed size blocks. Mostly // just serves to work around the borrow checker. -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(MallocSizeOf)] struct FreeBlockLists { @@ -377,23 +425,23 @@ impl FreeBlockLists { 0 => panic!("Can't allocate zero sized blocks!"), 1 => (1, &mut self.free_list_1), 2 => (2, &mut self.free_list_2), - 3...4 => (4, &mut self.free_list_4), - 5...8 => (8, &mut self.free_list_8), - 9...16 => (16, &mut self.free_list_16), - 17...32 => (32, &mut self.free_list_32), - 33...64 => (64, &mut self.free_list_64), - 65...128 => (128, &mut self.free_list_128), - 129...256 => (256, &mut self.free_list_256), - 257...341 => (341, &mut self.free_list_341), - 342...512 => (512, &mut self.free_list_512), - 513...1024 => (1024, &mut self.free_list_1024), + 3..=4 => (4, &mut self.free_list_4), + 5..=8 => (8, &mut self.free_list_8), + 9..=16 => (16, &mut self.free_list_16), + 17..=32 => (32, &mut self.free_list_32), + 33..=64 => (64, &mut self.free_list_64), + 65..=128 => (128, &mut self.free_list_128), + 129..=256 => (256, &mut self.free_list_256), + 257..=341 => (341, &mut self.free_list_341), + 342..=512 => (512, &mut self.free_list_512), + 513..=1024 => (1024, &mut self.free_list_1024), _ => panic!("Can't allocate > MAX_VERTEX_TEXTURE_WIDTH per resource!"), } } } // CPU-side representation of the GPU resource cache texture. -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(MallocSizeOf)] struct Texture { @@ -426,11 +474,11 @@ struct Texture { allocated_block_count: usize, // The stamp at which we first reached our threshold for reclaiming `GpuCache` // memory, or `None` if the threshold hasn't been reached. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(any(feature = "capture", feature = "replay", feature = "serialize_program"), serde(skip))] reached_reclaim_threshold: Option, // List of debug commands to be sent to the renderer when the GPU cache // debug display is enabled. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(any(feature = "capture", feature = "replay", feature = "serialize_program"), serde(skip))] debug_commands: Vec, // The current debug flags for the system. debug_flags: DebugFlags, @@ -660,7 +708,6 @@ impl<'a> Drop for GpuDataRequest<'a> { } } - /// The main LRU cache interface. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -677,7 +724,7 @@ pub struct GpuCache { debug_flags: DebugFlags, /// Whether there is a pending clear to send with the /// next update. - pending_clear: bool, + pub(crate) pending_clear: bool, } impl GpuCache { @@ -692,6 +739,11 @@ impl GpuCache { } } + #[cfg(not(feature="gleam"))] + pub fn height(&self) -> u64 { + self.texture.height as u64 + } + /// Creates a GpuCache and sets it up with a valid `FrameStamp`, which /// is useful for avoiding panics when instantiating the `GpuCache` /// directly from unit test code. @@ -828,6 +880,7 @@ impl GpuCache { } /// Extract the pending updates from the cache. + #[cfg(feature="gleam")] pub fn extract_updates(&mut self) -> GpuCacheUpdateList { let clear = self.pending_clear; self.pending_clear = false; @@ -841,6 +894,56 @@ impl GpuCache { } } + #[cfg(not(feature="gleam"))] + pub fn write_updates( + &mut self, + buffer: &mut PersistentlyMappedBuffer, + device: &B::Device, + old_buffer: Option>, + send_buffer: bool, + ) -> GpuCacheBufferUpdate { + let mut address_max = 0; + { + let (mut mapped_range, size) = buffer.map(device, None); + let mut writer = unsafe { + mapped_range.write::( + device, + 0..(size / mem::size_of::() as u64) + ) + }.unwrap(); + let writer_slice = unsafe { writer.slice() }; + + let blocks = mem::replace(&mut self.texture.pending_blocks, Vec::new()); + for update in mem::replace(&mut self.texture.updates, Vec::new()) { + match update { + GpuCacheUpdate::Copy { + block_index, + block_count, + address, + } => { + let address = address.v as usize * MAX_VERTEX_TEXTURE_WIDTH + address.u as usize; + address_max = address_max.max((address + block_count) as u64 * GpuBlockData::SIZE); + writer_slice[address .. address + block_count] + .copy_from_slice(&blocks[block_index .. block_index + block_count]); + } + } + } + } + GpuCacheBufferUpdate { + frame_id: self.now.frame_id(), + buffer_update: if send_buffer { + BufferInfo::BufferUpdate { + buffer_memory_slice: buffer.buffer_memory_slice(device), + new_buffer_info: buffer.get_buffer_info(address_max), + old_buffer, + } + } else { + BufferInfo::TransitRangeUpdate(address_max) + }, + debug_commands: mem::replace(&mut self.texture.debug_commands, Vec::new()), + } + } + /// Sets the current debug flags for the system. pub fn set_debug_flags(&mut self, flags: DebugFlags) { self.debug_flags = flags; diff --git a/webrender/src/gpu_glyph_renderer.rs b/webrender/src/gpu_glyph_renderer.rs index c3109dd93e..074c1ebb78 100644 --- a/webrender/src/gpu_glyph_renderer.rs +++ b/webrender/src/gpu_glyph_renderer.rs @@ -7,17 +7,27 @@ use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, FontRenderMode}; use api::{ImageFormat, TextureTarget}; use debug_colors; -use device::{DrawTarget, Device, Texture, TextureFilter, VAO}; +#[cfg(feature = "gleam")] +use device::{desc, ShaderKind}; +use device::{Device, PrimitiveType, ShaderPrecacheFlags, Texture}; +use device::{DrawTarget, TextureFilter, TextureSampler, VAO, VertexArrayKind}; use euclid::{Point2D, Size2D, Transform3D, TypedVector2D, Vector2D}; +#[cfg(not(feature = "gleam"))] +use device::DrawTargetUsage; +use hal; use internal_types::RenderTargetInfo; use pathfinder_gfx_utils::ShelfBinPacker; use profiler::GpuProfileTag; -use renderer::{self, ImageBufferKind, Renderer, RendererError, RendererStats}; -use renderer::{TextureSampler, VertexArrayKind, ShaderPrecacheFlags}; -use shade::{LazilyCompiledShader, ShaderKind}; +#[cfg(feature = "gleam")] +use renderer::ImageBufferKind; +use renderer::{Renderer, RendererError, RendererStats}; +use shade::LazilyCompiledShader; use tiling::GlyphJob; +#[cfg(not(feature = "gleam"))] +use device::vertex_types::{VectorStencilInstance, VectorCoverInstance}; // The area lookup table in uncompressed grayscale TGA format (TGA image format 3). +#[cfg(feature = "gleam")] static AREA_LUT_TGA_BYTES: &'static [u8] = include_bytes!("../res/area-lut.tga"); const HORIZONTAL_BIN_PADDING: i32 = 3; @@ -31,19 +41,26 @@ const GPU_TAG_GLYPH_COVER: GpuProfileTag = GpuProfileTag { color: debug_colors::LIGHTSTEELBLUE, }; -pub struct GpuGlyphRenderer { +pub struct GpuGlyphRenderer { pub area_lut_texture: Texture, pub vector_stencil_vao: VAO, pub vector_cover_vao: VAO, // These are Pathfinder shaders, used for rendering vector graphics. - vector_stencil: LazilyCompiledShader, - vector_cover: LazilyCompiledShader, + vector_stencil: LazilyCompiledShader, + vector_cover: LazilyCompiledShader, } -impl GpuGlyphRenderer { - pub fn new(device: &mut Device, prim_vao: &VAO, precache_flags: ShaderPrecacheFlags) - -> Result { +impl GpuGlyphRenderer { + #[cfg(not(feature = "gleam"))] + pub fn new(_device: &mut Device, _prim_vao: &VAO, _precache_flags: ShaderPrecacheFlags) + -> Result, RendererError> { + unimplemented!(); + } + + #[cfg(feature = "gleam")] + pub fn new(device: &mut Device, prim_vao: &VAO, precache_flags: ShaderPrecacheFlags) + -> Result, RendererError> { // Make sure the area LUT is uncompressed grayscale TGA, 8bpp. debug_assert!(AREA_LUT_TGA_BYTES[2] == 3); debug_assert!(AREA_LUT_TGA_BYTES[16] == 8); @@ -66,8 +83,8 @@ impl GpuGlyphRenderer { device.upload_texture_immediate(&area_lut_texture, area_lut_pixels); let vector_stencil_vao = - device.create_vao_with_new_instances(&renderer::desc::VECTOR_STENCIL, prim_vao); - let vector_cover_vao = device.create_vao_with_new_instances(&renderer::desc::VECTOR_COVER, + device.create_vao_with_new_instances(&desc::VECTOR_STENCIL, prim_vao); + let vector_cover_vao = device.create_vao_with_new_instances(&desc::VECTOR_COVER, prim_vao); // Load Pathfinder vector graphics shaders. @@ -96,7 +113,7 @@ impl GpuGlyphRenderer { } } -impl Renderer { +impl Renderer { /// Renders glyphs using the vector graphics shaders (Pathfinder). pub fn stencil_glyphs(&mut self, glyphs: &[GlyphJob], @@ -194,11 +211,15 @@ impl Renderer { projection, &mut self.renderer_errors); - self.device.bind_draw_target(DrawTarget::Texture { - texture: ¤t_page.texture, - layer: 0, - with_depth: false, - }); + self.device.bind_draw_target( + DrawTarget::Texture { + texture: ¤t_page.texture, + layer: 0, + with_depth: false, + }, + #[cfg(not(feature = "gleam"))] + DrawTargetUsage::Draw, + ); self.device.clear_target(Some([0.0, 0.0, 0.0, 0.0]), None, None); self.device.set_blend(true); @@ -278,6 +299,26 @@ pub struct StenciledGlyphPage { glyphs: Vec, } +#[cfg(not(feature = "gleam"))] +impl PrimitiveType for VectorStencilInstanceAttrs { + type Primitive = VectorStencilInstance; + fn to_primitive_type(&self) -> VectorStencilInstance { + VectorStencilInstance { + aFromPosition: [self.from_position.x, self.from_position.y], + aCtrlPosition: [self.ctrl_position.x, self.ctrl_position.y], + aToPosition: [self.to_position.x, self.to_position.y], + aFromNormal: [self.from_normal.x, self.from_normal.y], + aCtrlNormal: [self.ctrl_normal.x, self.ctrl_normal.y], + aToNormal: [self.to_normal.x, self.to_normal.y], + aPathID: self.path_id as _, + aPad: 0, + } + } +} + +#[cfg(feature = "gleam")] +impl PrimitiveType for VectorStencilInstanceAttrs { } + #[derive(Clone, Copy, Debug)] #[repr(C)] struct VectorCoverInstanceAttrs { @@ -286,6 +327,27 @@ struct VectorCoverInstanceAttrs { subpixel: u16, } +#[cfg(not(feature = "gleam"))] +impl PrimitiveType for VectorCoverInstanceAttrs { + type Primitive = VectorCoverInstance; + fn to_primitive_type(&self) -> VectorCoverInstance { + VectorCoverInstance { + aTargetRect: [ + self.target_rect.origin.x, + self.target_rect.origin.y, + self.target_rect.size.width, + self.target_rect.size.height, + ], + aStencilOrigin: [self.stencil_origin.x, self.stencil_origin.y], + aSubpixel: self.subpixel as _, + aPad: 0, + } + } +} + +#[cfg(feature = "gleam")] +impl PrimitiveType for VectorCoverInstanceAttrs { } + impl VectorCoverInstanceAttrs { fn stencil_rect(&self) -> DeviceIntRect { DeviceIntRect::new(self.stencil_origin, self.target_rect.size) diff --git a/webrender/src/gpu_types.rs b/webrender/src/gpu_types.rs index 9892db5850..13c7184344 100644 --- a/webrender/src/gpu_types.rs +++ b/webrender/src/gpu_types.rs @@ -159,7 +159,7 @@ pub struct ClipMaskBorderCornerDotDash { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct PrimitiveInstanceData { - data: [i32; 4], + pub data: [i32; 4], } #[derive(Debug, Copy, Clone)] diff --git a/webrender/src/image.rs b/webrender/src/image.rs index 36e9f246c4..b9b5c3d920 100644 --- a/webrender/src/image.rs +++ b/webrender/src/image.rs @@ -406,7 +406,7 @@ mod tests { visible_rect: &LayoutRect, device_image_size: &DeviceIntSize, device_tile_size: i32, - callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask), + callback: &mut dyn FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask), ) { let mut coverage = LayoutRect::zero(); let mut seen_tiles = HashSet::new(); diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index 29d1dbf3dc..61bf53a1ce 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -7,7 +7,10 @@ use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use api::{ImageFormat, WorldPixel, NotificationRequest}; use device::TextureFilter; use renderer::PipelineInfo; +#[cfg(not(feature="gleam"))] +use gpu_cache::GpuCacheBufferUpdate; use gpu_cache::GpuCacheUpdateList; +use hal; use fxhash::FxHasher; use plane_split::BspSplitter; use profiler::BackendProfileCounters; @@ -39,7 +42,7 @@ pub type PlaneSplitter = BspSplitter; /// /// We never reuse IDs, so we use a u64 here to be safe. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct CacheTextureId(pub u64); @@ -63,7 +66,7 @@ pub type LayerIndex = usize; /// preserved in a list until the end of the frame, and this type specifies the /// index in that list. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct SavedTargetIndex(pub usize); @@ -73,7 +76,7 @@ impl SavedTargetIndex { /// Identifies the source of an input texture to a shader. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum TextureSource { /// Equivalent to `None`, allowing us to avoid using `Option`s everywhere. @@ -93,16 +96,20 @@ pub enum TextureSource { } pub const ORTHO_NEAR_PLANE: f32 = -100000.0; +#[cfg(feature = "gleam")] pub const ORTHO_FAR_PLANE: f32 = 100000.0; +#[cfg(not(feature = "gleam"))] +pub const ORTHO_FAR_PLANE: f32 = 000000.0; #[derive(Copy, Clone, Debug, PartialEq)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct RenderTargetInfo { pub has_depth: bool, } #[derive(Debug)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] pub enum TextureUpdateSource { External { id: ExternalImageId, @@ -116,6 +123,7 @@ pub enum TextureUpdateSource { /// Command to allocate, reallocate, or free a texture for the texture cache. #[derive(Debug)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] pub struct TextureCacheAllocation { /// The virtual ID (i.e. distinct from device ID) of the texture. pub id: CacheTextureId, @@ -125,6 +133,7 @@ pub struct TextureCacheAllocation { /// Information used when allocating / reallocating. #[derive(Debug)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] pub struct TextureCacheAllocInfo { pub width: i32, pub height: i32, @@ -137,6 +146,7 @@ pub struct TextureCacheAllocInfo { /// Sub-operation-specific information for allocation operations. #[derive(Debug)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] pub enum TextureCacheAllocationKind { /// Performs an initial texture allocation. Alloc(TextureCacheAllocInfo), @@ -150,6 +160,7 @@ pub enum TextureCacheAllocationKind { /// Command to update the contents of the texture cache. #[derive(Debug)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] pub struct TextureCacheUpdate { pub id: CacheTextureId, pub rect: DeviceIntRect, @@ -165,6 +176,7 @@ pub struct TextureCacheUpdate { /// The list of allocation operations is processed before the updates. This is /// important to allow coalescing of certain allocation operations. #[derive(Default)] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] pub struct TextureUpdateList { /// Commands to alloc/realloc/free the textures. Processed first. pub allocations: Vec, @@ -290,11 +302,15 @@ pub enum DebugOutput { } #[allow(dead_code)] -pub enum ResultMsg { +pub enum ResultMsg { DebugCommand(DebugCommand), DebugOutput(DebugOutput), RefreshShader(PathBuf), UpdateGpuCache(GpuCacheUpdateList), + #[cfg(not(feature="gleam"))] + UpdateGpuCacheBuffer(GpuCacheBufferUpdate), + #[cfg(feature="gleam")] + Phantom(std::marker::PhantomData), UpdateResources { updates: TextureUpdateList, memory_pressure: bool, @@ -307,6 +323,8 @@ pub enum ResultMsg { BackendProfileCounters, ), AppendNotificationRequests(Vec), + #[cfg(not(feature = "gleam"))] + UpdateWindowSize(DeviceIntSize), } #[derive(Clone, Debug)] diff --git a/webrender/src/lib.rs b/webrender/src/lib.rs index 5cc5c67e64..da6203fedc 100644 --- a/webrender/src/lib.rs +++ b/webrender/src/lib.rs @@ -61,11 +61,13 @@ extern crate lazy_static; extern crate log; #[macro_use] extern crate malloc_size_of_derive; -#[cfg(any(feature = "serde"))] #[macro_use] extern crate serde; #[macro_use] extern crate thread_profiler; +pub extern crate gfx_hal as hal; +#[cfg(any(not(feature = "gleam"), test))] +extern crate rand; extern crate wr_malloc_size_of; use wr_malloc_size_of as malloc_size_of; @@ -164,9 +166,11 @@ extern crate libc; extern crate dwrote; extern crate app_units; +extern crate arrayvec; extern crate bincode; extern crate byteorder; extern crate fxhash; +#[cfg(feature = "gleam")] extern crate gleam; extern crate num_traits; #[cfg(feature = "pathfinder")] @@ -179,7 +183,8 @@ extern crate pathfinder_partitioner; extern crate pathfinder_path_utils; extern crate plane_split; extern crate rayon; -#[cfg(feature = "ron")] +extern crate rendy_descriptor; +extern crate rendy_memory; extern crate ron; #[cfg(feature = "debugger")] extern crate serde_json; @@ -194,8 +199,6 @@ extern crate image as image_loader; extern crate base64; #[cfg(all(feature = "capture", feature = "png"))] extern crate png; -#[cfg(test)] -extern crate rand; #[macro_use] pub extern crate webrender_api; @@ -203,14 +206,18 @@ extern crate webrender_build; #[doc(hidden)] pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint}; -pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver}; -pub use device::Device; +pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver, ShaderPrecacheFlags}; +pub use device::{Device, DeviceInit}; pub use frame_builder::ChasePrimitive; pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind}; pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource, GpuProfile}; pub use renderer::{GraphicsApi, GraphicsApiInfo, PipelineInfo, Renderer, RendererOptions}; -pub use renderer::{RendererStats, SceneBuilderHooks, ThreadListener, ShaderPrecacheFlags}; +pub use renderer::{RendererStats, SceneBuilderHooks, ThreadListener}; pub use renderer::MAX_VERTEX_TEXTURE_WIDTH; +pub use rendy_memory::{DynamicConfig, HeapsConfig, LinearConfig}; pub use shade::{Shaders, WrShaders}; pub use webrender_api as api; pub use webrender_api::euclid; + +#[cfg(not(feature = "gleam"))] +pub use device::BackendApiType; diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index f24d368c04..ede243d058 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -33,7 +33,7 @@ use scene::{FilterOpHelpers, SceneProperties}; use scene_builder::Interners; use smallvec::SmallVec; use std::{mem, u16}; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering}; use texture_cache::{Eviction, TextureCacheHandle}; use tiling::RenderTargetKind; use util::{ComparableVec, TransformedRectKind, MatrixHelpers, MaxRect}; @@ -110,7 +110,7 @@ const MAX_PRIMS_TO_SEARCH: usize = 128; /// Used to get unique tile IDs, even when the tile cache is /// destroyed between display lists / scenes. -static NEXT_TILE_ID: AtomicUsize = ATOMIC_USIZE_INIT; +static NEXT_TILE_ID: AtomicUsize = AtomicUsize::new(0); fn clamp(value: i32, low: i32, high: i32) -> i32 { value.max(low).min(high) @@ -2442,7 +2442,7 @@ impl PicturePrimitive { self.raster_config = Some(RasterConfig { composite_mode, - establishes_raster_root: surface_spatial_node_index == surface.raster_spatial_node_index, + establishes_raster_root: surface.raster_spatial_node_index != parent_raster_spatial_node_index, surface_index: state.push_surface(surface), }); } diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index 33fde7880c..f910a99dc0 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -2882,7 +2882,7 @@ fn decompose_repeated_primitive( prim_context: &PrimitiveContext, frame_state: &mut FrameBuildingState, gradient_tiles: &mut GradientTileStorage, - callback: &mut FnMut(&LayoutRect, GpuDataRequest), + callback: &mut dyn FnMut(&LayoutRect, GpuDataRequest), ) -> GradientTileRange { let mut visible_tiles = Vec::new(); let world_rect = frame_state.current_dirty_region().combined.world_rect; @@ -3169,7 +3169,7 @@ impl PrimitiveInstance { segment.has_mask, segment.edge_flags, [0.0; 4], - BrushFlags::empty(), + BrushFlags::PERSPECTIVE_INTERPOLATION, ), ); }); diff --git a/webrender/src/prim_store/text_run.rs b/webrender/src/prim_store/text_run.rs index ab181b5347..3883542738 100644 --- a/webrender/src/prim_store/text_run.rs +++ b/webrender/src/prim_store/text_run.rs @@ -9,6 +9,7 @@ use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible}; use frame_builder::{FrameBuildingState, PictureContext}; use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT}; use gpu_cache::GpuCache; +use gpu_types::RasterizationSpace; use intern; use intern_types; use prim_store::{PrimitiveOpacity, PrimitiveSceneData, PrimitiveScratchBuffer}; @@ -64,8 +65,9 @@ impl AsInstanceKind for TextRunKey { let run_index = prim_store.text_runs.push(TextRunPrimitive { used_font: self.font.clone(), glyph_keys_range: storage::Range::empty(), - shadow: self.shadow, reference_frame_relative_offset, + shadow: self.shadow, + raster_space: RasterizationSpace::Screen, }); PrimitiveInstanceKind::TextRun{ data_handle, run_index } @@ -210,6 +212,7 @@ pub struct TextRunPrimitive { pub glyph_keys_range: storage::Range, pub reference_frame_relative_offset: LayoutVector2D, pub shadow: bool, + pub raster_space: RasterizationSpace, } impl TextRunPrimitive { @@ -245,6 +248,13 @@ impl TextRunPrimitive { FontTransform::identity() }; + // Record the raster space the text needs to be snapped in. + self.raster_space = if raster_space == RasterSpace::Screen { + RasterizationSpace::Screen + } else { + RasterizationSpace::Local + }; + // If the transform or device size is different, then the caller of // this method needs to know to rebuild the glyphs. let cache_dirty = diff --git a/webrender/src/profiler.rs b/webrender/src/profiler.rs index a9b175230e..67b5f10e9e 100644 --- a/webrender/src/profiler.rs +++ b/webrender/src/profiler.rs @@ -1049,7 +1049,7 @@ impl Profiler { ) { Profiler::draw_counters( &[ - &renderer_profile.frame_time as &ProfileCounter, + &renderer_profile.frame_time as &dyn ProfileCounter, &renderer_profile.color_targets, &renderer_profile.alpha_targets, &renderer_profile.draw_calls, @@ -1077,7 +1077,7 @@ impl Profiler { ) { Profiler::draw_counters( &[ - &renderer_profile.frame_time as &ProfileCounter, + &renderer_profile.frame_time as &dyn ProfileCounter, &renderer_profile.frame_counter, &renderer_profile.color_targets, &renderer_profile.alpha_targets, @@ -1173,8 +1173,8 @@ impl Profiler { description: "Total", value: total, }); - let samplers: Vec<&ProfileCounter> = samplers.iter().map(|sampler| { - sampler as &ProfileCounter + let samplers: Vec<&dyn ProfileCounter> = samplers.iter().map(|sampler| { + sampler as &dyn ProfileCounter }).collect(); Profiler::draw_counters( &samplers, diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index 82a97c63ef..0fff5b1fe6 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -25,8 +25,13 @@ use api::CapturedDocument; use clip_scroll_tree::{SpatialNodeIndex, ClipScrollTree}; #[cfg(feature = "debugger")] use debug_server; +#[cfg(not(feature="gleam"))] +use device::PersistentlyMappedBuffer; use frame_builder::{FrameBuilder, FrameBuilderConfig}; use gpu_cache::GpuCache; +#[cfg(not(feature="gleam"))] +use gpu_cache::{GpuBlockData, GPU_CACHE_INITIAL_HEIGHT}; +use hal; use hit_test::{HitTest, HitTester}; use intern_types; use internal_types::{DebugOutput, FastHashMap, FastHashSet, RenderedDocument, ResultMsg}; @@ -37,6 +42,10 @@ use prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData}; use profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters}; use record::ApiRecordingReceiver; use renderer::{AsyncPropertySampler, PipelineInfo}; +#[cfg(not(feature="gleam"))] +use renderer::MAX_VERTEX_TEXTURE_WIDTH; +#[cfg(not(feature="gleam"))] +use rendy_memory::Heaps; use resource_cache::ResourceCache; #[cfg(feature = "replay")] use resource_cache::PlainCacheOwn; @@ -52,6 +61,8 @@ use serde_json; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use std::mem::replace; +#[cfg(not(feature="gleam"))] +use std::sync::{Arc, Mutex, Weak}; use std::sync::mpsc::{channel, Sender, Receiver}; use std::time::{UNIX_EPOCH, SystemTime}; use std::u32; @@ -84,7 +95,7 @@ impl DocumentView { } #[derive(Copy, Clone, Hash, MallocSizeOf, PartialEq, PartialOrd, Debug, Eq, Ord)] -#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(any(feature = "capture", feature = "serialize_program"), derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct FrameId(usize); @@ -661,10 +672,19 @@ struct PlainRenderBackend { /// GPU-friendly work which is then submitted to the renderer in the form of a frame::Frame. /// /// The render backend operates on its own thread. -pub struct RenderBackend { +pub struct RenderBackend { + #[cfg(not(feature="gleam"))] + device: Arc, + #[cfg(not(feature="gleam"))] + heaps: Weak>>, + #[cfg(not(feature="gleam"))] + gpu_cache_buffer: PersistentlyMappedBuffer, + #[cfg(not(feature="gleam"))] + send_buffer_handle_to_renderer: bool, + api_rx: MsgReceiver, payload_rx: Receiver, - result_tx: Sender, + result_tx: Sender>, scene_tx: Sender, low_priority_scene_tx: Sender, scene_rx: Receiver, @@ -679,9 +699,9 @@ pub struct RenderBackend { frame_config: FrameBuilderConfig, documents: FastHashMap, - notifier: Box, - recorder: Option>, - sampler: Option>, + notifier: Box, + recorder: Option>, + sampler: Option>, size_of_ops: Option, debug_flags: DebugFlags, namespace_alloc_by_client: bool, @@ -689,25 +709,42 @@ pub struct RenderBackend { recycler: Recycler, } -impl RenderBackend { +impl RenderBackend { + #[cfg(not(feature="gleam"))] pub fn new( api_rx: MsgReceiver, payload_rx: Receiver, - result_tx: Sender, + result_tx: Sender>, scene_tx: Sender, low_priority_scene_tx: Sender, scene_rx: Receiver, default_device_pixel_ratio: f32, resource_cache: ResourceCache, - notifier: Box, + notifier: Box, frame_config: FrameBuilderConfig, - recorder: Option>, - sampler: Option>, + recorder: Option>, + sampler: Option>, size_of_ops: Option, debug_flags: DebugFlags, namespace_alloc_by_client: bool, - ) -> RenderBackend { + device: Arc, + heaps: Weak>>, + non_coherent_atom_size_mask: u64, + ) -> RenderBackend { + let heaps_strong = heaps.upgrade().unwrap(); + let gpu_cache_buffer = PersistentlyMappedBuffer::new::( + device.as_ref(), + &mut heaps_strong.lock().unwrap(), + non_coherent_atom_size_mask, + MAX_VERTEX_TEXTURE_WIDTH as _, + GPU_CACHE_INITIAL_HEIGHT as _, + None, + ); RenderBackend { + device, + heaps, + gpu_cache_buffer, + send_buffer_handle_to_renderer: true, api_rx, payload_rx, result_tx, @@ -730,6 +767,54 @@ impl RenderBackend { } } + #[cfg(feature="gleam")] + pub fn new( + api_rx: MsgReceiver, + payload_rx: Receiver, + result_tx: Sender>, + scene_tx: Sender, + low_priority_scene_tx: Sender, + scene_rx: Receiver, + default_device_pixel_ratio: f32, + resource_cache: ResourceCache, + notifier: Box, + frame_config: FrameBuilderConfig, + recorder: Option>, + sampler: Option>, + size_of_ops: Option, + debug_flags: DebugFlags, + namespace_alloc_by_client: bool, + ) -> RenderBackend { + RenderBackend { + api_rx, + payload_rx, + result_tx, + scene_tx, + low_priority_scene_tx, + scene_rx, + payload_buffer: Vec::new(), + default_device_pixel_ratio, + resource_cache, + gpu_cache: GpuCache::new(), + frame_config, + documents: FastHashMap::default(), + notifier, + recorder, + sampler, + size_of_ops, + debug_flags, + namespace_alloc_by_client, + recycler: Recycler::new(), + } + } + + pub fn deinit(self) { + #[cfg(not(feature="gleam"))] { + let heaps_strong = self.heaps.upgrade().unwrap(); + heaps_strong.lock().unwrap().free(self.device.as_ref(), self.gpu_cache_buffer.memory_block); + } + } + fn process_scene_msg( &mut self, document_id: DocumentId, @@ -755,6 +840,8 @@ impl RenderBackend { doc.view.window_size = window_size; doc.view.inner_rect = inner_rect; doc.view.device_pixel_ratio = device_pixel_ratio; + #[cfg(not(feature = "gleam"))] + self.result_tx.send(ResultMsg::UpdateWindowSize(window_size)).unwrap(); } SceneMsg::SetDisplayList { epoch, @@ -857,7 +944,7 @@ impl RenderBackend { doc.removed_pipelines.append(&mut txn.removed_pipelines); - if let Some(mut built_scene) = txn.built_scene.take() { + if let Some(built_scene) = txn.built_scene.take() { doc.new_async_scene_ready( built_scene, &mut self.recycler, @@ -1372,7 +1459,48 @@ impl RenderBackend { debug!("generated frame for document {:?} with {} passes", document_id, rendered_document.frame.passes.len()); + #[cfg(feature="gleam")] let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates()); + + #[cfg(not(feature="gleam"))] + let msg = { + let clear = self.gpu_cache.pending_clear; + let resize = self.gpu_cache.height() > self.gpu_cache_buffer.height; + let old_buffer = if clear || resize { + let heaps_strong = self.heaps.upgrade().unwrap(); + let new_buffer = PersistentlyMappedBuffer::new::( + self.device.as_ref(), + &mut heaps_strong.lock().unwrap(), + self.gpu_cache_buffer.non_coherent_atom_size_mask, + MAX_VERTEX_TEXTURE_WIDTH as _, + self.gpu_cache.height(), + if resize { + Some(&mut self.gpu_cache_buffer) + } else { + None + }, + ); + + let old_buffer = replace(&mut self.gpu_cache_buffer, new_buffer); + self.send_buffer_handle_to_renderer = true; + if clear { + self.gpu_cache.pending_clear = false; + } + Some(old_buffer) + } else { + None + }; + + let msg = ResultMsg::UpdateGpuCacheBuffer(self.gpu_cache.write_updates( + &mut self.gpu_cache_buffer, + self.device.as_ref(), + old_buffer, + self.send_buffer_handle_to_renderer, + )); + + self.send_buffer_handle_to_renderer = false; + msg + }; self.result_tx.send(msg).unwrap(); frame_build_time = Some(precise_time_ns() - frame_build_start_time); @@ -1430,6 +1558,36 @@ impl RenderBackend { } } + #[cfg(all(not(feature = "gleam"), any(feature = "capture", feature = "replay")))] + fn ensure_buffer(&mut self) -> Option> { + let clear = self.gpu_cache.pending_clear; + let resize = self.gpu_cache.height() > self.gpu_cache_buffer.height; + if clear || resize { + let heaps_strong = self.heaps.upgrade().unwrap(); + let new_buffer = PersistentlyMappedBuffer::new::( + self.device.as_ref(), + &mut heaps_strong.lock().unwrap(), + self.gpu_cache_buffer.non_coherent_atom_size_mask, + MAX_VERTEX_TEXTURE_WIDTH as _, + self.gpu_cache.height(), + if resize { + Some(&mut self.gpu_cache_buffer) + } else { + None + }, + ); + + let old_buffer = replace(&mut self.gpu_cache_buffer, new_buffer); + self.send_buffer_handle_to_renderer = true; + if clear { + self.gpu_cache.pending_clear = false; + } + Some(old_buffer) + } else { + None + } + } + #[cfg(not(feature = "debugger"))] fn get_docs_for_debugger(&self) -> String { String::new() @@ -1595,7 +1753,7 @@ impl ToDebugString for SpecificDisplayItem { } } -impl RenderBackend { +impl RenderBackend { #[cfg(feature = "capture")] // Note: the mutable `self` is only needed here for resolving blob images fn save_capture( @@ -1664,7 +1822,21 @@ impl RenderBackend { // After we rendered the frames, there are pending updates to both // GPU cache and resources. Instead of serializing them, we are going to make sure // they are applied on the `Renderer` side. + + #[cfg(feature="gleam")] let msg_update_gpu_cache = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates()); + #[cfg(not(feature="gleam"))] + let msg_update_gpu_cache = { + let old_buffer = self.ensure_buffer(); + let msg = ResultMsg::UpdateGpuCacheBuffer(self.gpu_cache.write_updates( + &mut self.gpu_cache_buffer, + self.device.as_ref(), + old_buffer, + self.send_buffer_handle_to_renderer, + )); + self.send_buffer_handle_to_renderer = false; + msg + }; self.result_tx.send(msg_update_gpu_cache).unwrap(); let msg_update_resources = ResultMsg::UpdateResources { updates: self.resource_cache.pending_updates(), @@ -1730,7 +1902,7 @@ impl RenderBackend { let data_stores = CaptureConfig::deserialize::(root, &data_stores_name) .expect(&format!("Unable to open {}.ron", data_stores_name)); - let mut doc = Document { + let doc = Document { scene: scene.clone(), removed_pipelines: Vec::new(), view: view.clone(), @@ -1754,7 +1926,20 @@ impl RenderBackend { Some(frame) => { info!("\tloaded a built frame with {} passes", frame.passes.len()); + #[cfg(feature="gleam")] let msg_update = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates()); + #[cfg(not(feature="gleam"))] + let msg_update = { + let old_buffer = self.ensure_buffer(); + let msg = ResultMsg::UpdateGpuCacheBuffer(self.gpu_cache.write_updates( + &mut self.gpu_cache_buffer, + self.device.as_ref(), + old_buffer, + self.send_buffer_handle_to_renderer, + )); + self.send_buffer_handle_to_renderer = false; + msg + }; self.result_tx.send(msg_update).unwrap(); let msg_publish = ResultMsg::PublishDocument( diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 351df17881..74334aed42 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -38,7 +38,7 @@ use webrender_api::DevicePixel; const RENDER_TASK_SIZE_SANITY_CHECK: i32 = 16000; const FLOATS_PER_RENDER_TASK_INFO: usize = 8; pub const MAX_BLUR_STD_DEVIATION: f32 = 4.0; -pub const MIN_DOWNSCALING_RT_SIZE: i32 = 128; +pub const MIN_DOWNSCALING_RT_SIZE: i32 = 8; fn render_task_sanity_check(size: &DeviceIntSize) { if size.width > RENDER_TASK_SIZE_SANITY_CHECK || diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index e274333fb9..92fa9da26c 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -37,23 +37,34 @@ use batch::{BatchKind, BatchTextures, BrushBatchKind}; use capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage}; use debug_colors; use debug_render::{DebugItem, DebugRenderer}; -use device::{DepthFunction, Device, GpuFrameId, Program, UploadMethod, Texture, PBO}; -use device::{DrawTarget, ExternalTexture, FBOId, ReadTarget, TextureSlot}; -use device::{ShaderError, TextureFilter, TextureFlags, - VertexUsageHint, VAO, VBO, CustomVAO}; +use device::desc; +#[cfg(feature = "replay")] +use device::IdType; +use device::{DepthFunction, Device, GpuFrameId, UploadMethod, Texture, PBO}; +use device::{DrawTarget, ExternalTexture, FBOId, ReadTarget}; +use device::{ShaderError, TextureFilter, TextureFlags, VertexUsageHint, VAO}; +use device::{create_projection, DeviceInit, PrimitiveType, ShaderPrecacheFlags, TextureSampler, VertexArrayKind}; use device::{ProgramCache, ReadPixelsFormat}; use device::query::GpuTimer; +#[cfg(feature = "gleam")] +use device::{CustomVAO, Program, VBO}; +#[cfg(not(feature="gleam"))] +use device::{BufferMemorySlice, DrawTargetUsage}; use euclid::rect; use euclid::Transform3D; use frame_builder::{ChasePrimitive, FrameBuilderConfig}; +#[cfg(feature = "gleam")] use gleam::gl; use glyph_rasterizer::{GlyphFormat, GlyphRasterizer}; -use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList}; -use gpu_cache::{GpuCacheDebugChunk, GpuCacheDebugCmd}; +#[cfg(not(feature="gleam"))] +use gpu_cache::BufferInfo; +use gpu_cache::{GpuBlockData, GpuCacheUpdate}; +use gpu_cache::{GpuCacheUpdateList, GpuCacheDebugChunk, GpuCacheDebugCmd}; #[cfg(feature = "pathfinder")] use gpu_glyph_renderer::GpuGlyphRenderer; use gpu_types::ScalingInstance; -use internal_types::{TextureSource, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError}; +use hal; +use internal_types::{TextureSource, ResourceCacheError}; use internal_types::{CacheTextureId, DebugOutput, FastHashMap, LayerIndex, RenderedDocument, ResultMsg}; use internal_types::{TextureCacheAllocationKind, TextureCacheUpdate, TextureUpdateList, TextureUpdateSource}; use internal_types::{RenderTargetInfo, SavedTargetIndex}; @@ -69,6 +80,8 @@ use render_backend::{FrameId, RenderBackend}; use scene_builder::{SceneBuilder, LowPrioritySceneBuilder}; use shade::{Shaders, WrShaders}; use smallvec::SmallVec; +#[cfg(not(feature = "gleam"))] +use rendy_memory::HeapsConfig; use render_task::{RenderTask, RenderTaskKind, RenderTaskTree}; use resource_cache::ResourceCache; use util::drain_filter; @@ -78,6 +91,7 @@ use std::cmp; use std::collections::VecDeque; use std::collections::hash_map::Entry; use std::f32; +use std::marker::PhantomData; use std::mem; use std::os::raw::c_void; use std::path::PathBuf; @@ -276,389 +290,22 @@ impl From for ShaderColorMode { } } -/// Enumeration of the texture samplers used across the various WebRender shaders. -/// -/// Each variant corresponds to a uniform declared in shader source. We only bind -/// the variants we need for a given shader, so not every variant is bound for every -/// batch. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub(crate) enum TextureSampler { - Color0, - Color1, - Color2, - PrevPassAlpha, - PrevPassColor, - GpuCache, - TransformPalette, - RenderTasks, - Dither, - PrimitiveHeadersF, - PrimitiveHeadersI, -} - -impl TextureSampler { - pub(crate) fn color(n: usize) -> TextureSampler { - match n { - 0 => TextureSampler::Color0, - 1 => TextureSampler::Color1, - 2 => TextureSampler::Color2, - _ => { - panic!("There are only 3 color samplers."); - } - } - } -} - -impl Into for TextureSampler { - fn into(self) -> TextureSlot { - match self { - TextureSampler::Color0 => TextureSlot(0), - TextureSampler::Color1 => TextureSlot(1), - TextureSampler::Color2 => TextureSlot(2), - TextureSampler::PrevPassAlpha => TextureSlot(3), - TextureSampler::PrevPassColor => TextureSlot(4), - TextureSampler::GpuCache => TextureSlot(5), - TextureSampler::TransformPalette => TextureSlot(6), - TextureSampler::RenderTasks => TextureSlot(7), - TextureSampler::Dither => TextureSlot(8), - TextureSampler::PrimitiveHeadersF => TextureSlot(9), - TextureSampler::PrimitiveHeadersI => TextureSlot(10), - } - } -} - #[derive(Debug, Clone, Copy)] #[repr(C)] pub struct PackedVertex { pub pos: [f32; 2], } -pub(crate) mod desc { - use device::{VertexAttribute, VertexAttributeKind, VertexDescriptor}; - - pub const PRIM_INSTANCES: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aData", - count: 4, - kind: VertexAttributeKind::I32, - }, - ], - }; - - pub const BLUR: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aBlurRenderTaskAddress", - count: 1, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aBlurSourceTaskAddress", - count: 1, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aBlurDirection", - count: 1, - kind: VertexAttributeKind::I32, - }, - ], - }; - - pub const LINE: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aTaskRect", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aLocalSize", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aWavyLineThickness", - count: 1, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aStyle", - count: 1, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aOrientation", - count: 1, - kind: VertexAttributeKind::I32, - }, - ], - }; - - pub const BORDER: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aTaskOrigin", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aRect", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aColor0", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aColor1", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aFlags", - count: 1, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aWidths", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aRadii", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aClipParams1", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aClipParams2", - count: 4, - kind: VertexAttributeKind::F32, - }, - ], - }; - - pub const SCALE: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aScaleRenderTaskAddress", - count: 1, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aScaleSourceTaskAddress", - count: 1, - kind: VertexAttributeKind::I32, - }, - ], - }; - - pub const CLIP: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aClipRenderTaskAddress", - count: 1, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aClipTransformId", - count: 1, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aPrimTransformId", - count: 1, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aClipDataResourceAddress", - count: 4, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aClipLocalPos", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aClipTileRect", - count: 4, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aClipDeviceArea", - count: 4, - kind: VertexAttributeKind::F32, - } - ], - }; - - pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::U16Norm, - }, - VertexAttribute { - name: "aValue", - count: 4, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[], - }; - - pub const VECTOR_STENCIL: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aFromPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aCtrlPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aToPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aFromNormal", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aCtrlNormal", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aToNormal", - count: 2, - kind: VertexAttributeKind::F32, - }, - VertexAttribute { - name: "aPathID", - count: 1, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aPad", - count: 1, - kind: VertexAttributeKind::U16, - }, - ], - }; - - pub const VECTOR_COVER: VertexDescriptor = VertexDescriptor { - vertex_attributes: &[ - VertexAttribute { - name: "aPosition", - count: 2, - kind: VertexAttributeKind::F32, - }, - ], - instance_attributes: &[ - VertexAttribute { - name: "aTargetRect", - count: 4, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aStencilOrigin", - count: 2, - kind: VertexAttributeKind::I32, - }, - VertexAttribute { - name: "aSubpixel", - count: 1, - kind: VertexAttributeKind::U16, - }, - VertexAttribute { - name: "aPad", - count: 1, - kind: VertexAttributeKind::U16, - }, - ], - }; -} - -#[derive(Debug, Copy, Clone)] -pub(crate) enum VertexArrayKind { - Primitive, - Blur, - Clip, - VectorStencil, - VectorCover, - Border, - Scale, - LineDecoration, +#[cfg(not(feature = "gleam"))] +impl PrimitiveType for PackedVertex { + type Primitive = [f32; 2]; + fn to_primitive_type(&self) -> [f32; 2] { self.pos } } #[derive(Clone, Debug, PartialEq)] pub enum GraphicsApi { OpenGL, + Gfx, } #[derive(Clone, Debug)] @@ -740,12 +387,14 @@ impl CpuProfile { } #[cfg(not(feature = "pathfinder"))] -pub struct GpuGlyphRenderer; +pub struct GpuGlyphRenderer { + phantom_data: PhantomData, +} #[cfg(not(feature = "pathfinder"))] -impl GpuGlyphRenderer { - fn new(_: &mut Device, _: &VAO, _: ShaderPrecacheFlags) -> Result { - Ok(GpuGlyphRenderer) +impl GpuGlyphRenderer { + fn new(_: &mut Device, _: &VAO, _: ShaderPrecacheFlags) -> Result, RendererError> { + Ok(GpuGlyphRenderer { phantom_data: PhantomData }) } } @@ -764,7 +413,7 @@ struct ActiveTexture { /// Manages the mapping between the at-a-distance texture handles used by the /// `RenderBackend` (which does not directly interface with the GPU) and actual /// device texture handles. -struct TextureResolver { +struct TextureResolver { /// A map to resolve texture cache IDs to native textures. texture_cache_map: FastHashMap, @@ -801,10 +450,11 @@ struct TextureResolver { /// See the comments in `allocate_target_texture` for more insight on why /// reuse is a win. render_target_pool: Vec, + phantom_data: PhantomData, } -impl TextureResolver { - fn new(device: &mut Device) -> TextureResolver { +impl TextureResolver { + fn new(device: &mut Device) -> TextureResolver { let dummy_cache_texture = device .create_texture( TextureTarget::Array, @@ -824,10 +474,11 @@ impl TextureResolver { prev_pass_color: None, saved_targets: Vec::default(), render_target_pool: Vec::new(), + phantom_data: PhantomData, } } - fn deinit(self, device: &mut Device) { + fn deinit(self, device: &mut Device) { device.delete_texture(self.dummy_cache_texture); for (_id, texture) in self.texture_cache_map { @@ -845,7 +496,7 @@ impl TextureResolver { assert!(self.saved_targets.is_empty()); } - fn end_frame(&mut self, device: &mut Device, frame_id: GpuFrameId) { + fn end_frame(&mut self, device: &mut Device, frame_id: GpuFrameId) { // return the cached targets to the pool self.end_pass(device, None, None); // return the saved targets as well @@ -862,17 +513,28 @@ impl TextureResolver { // flush all the WebRender caches in that case [1]. // // [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1494099 - self.retain_targets(device, |texture| texture.used_recently(frame_id, 30)); + #[cfg(not(feature = "gleam"))] + let frame_count = device.frame_count; + self.retain_targets(device, |texture| { + // We ignore the textures which are still used by the GPU + #[cfg(not(feature = "gleam"))] + { + if texture.still_in_flight(frame_id, frame_count) { + return true; + } + } + texture.used_recently(frame_id, 30) + }); } /// Transfers ownership of a render target back to the pool. - fn return_to_pool(&mut self, device: &mut Device, target: Texture) { + fn return_to_pool(&mut self, device: &mut Device, target: Texture) { device.invalidate_render_target(&target); self.render_target_pool.push(target); } /// Drops all targets from the render target pool that do not satisfy the predicate. - pub fn retain_targets bool>(&mut self, device: &mut Device, f: F) { + pub fn retain_targets bool>(&mut self, device: &mut Device, f: F) { // We can't just use retain() because `Texture` requires manual cleanup. let mut tmp = SmallVec::<[Texture; 8]>::new(); for target in self.render_target_pool.drain(..) { @@ -887,7 +549,7 @@ impl TextureResolver { fn end_pass( &mut self, - device: &mut Device, + device: &mut Device, a8_texture: Option, rgba8_texture: Option, ) { @@ -919,9 +581,12 @@ impl TextureResolver { } // Bind a source texture to the device. - fn bind(&self, texture_id: &TextureSource, sampler: TextureSampler, device: &mut Device) { + fn bind(&self, texture_id: &TextureSource, sampler: TextureSampler, device: &mut Device) { match *texture_id { - TextureSource::Invalid => {} + TextureSource::Invalid => { + #[cfg(not(feature = "gleam"))] + device.bind_texture(sampler, &self.dummy_cache_texture); + } TextureSource::PrevPassAlpha => { let texture = match self.prev_pass_alpha { Some(ref at) => &at.texture, @@ -937,10 +602,15 @@ impl TextureResolver { device.bind_texture(sampler, texture); } TextureSource::External(external_image) => { - let texture = self.external_images - .get(&(external_image.id, external_image.channel_index)) - .expect(&format!("BUG: External image should be resolved by now")); - device.bind_external_texture(sampler, texture); + if cfg!(feature = "gleam") { + let texture = self.external_images + .get(&(external_image.id, external_image.channel_index)) + .expect(&format!("BUG: External image should be resolved by now")); + device.bind_external_texture(sampler, texture); + } else { + warn!("External textures are not supported"); + device.bind_texture(sampler, &self.dummy_cache_texture); + } } TextureSource::TextureCache(index) => { let texture = &self.texture_cache_map[&index]; @@ -1033,6 +703,11 @@ impl CacheRow { /// The bus over which CPU and GPU versions of the GPU cache /// get synchronized. enum GpuCacheBus { + /// Persistently mapped buffer-based updates + #[cfg(not(feature = "gleam"))] + PersistentlyMappedBuffer { + slice: Option, + }, /// PBO-based updates, currently operate on a row granularity. /// Therefore, are subject to fragmentation issues. PixelBuffer { @@ -1043,6 +718,7 @@ enum GpuCacheBus { }, /// Shader-based scattering updates. Currently rendered by a set /// of points into the GPU texture, each carrying a `GpuBlockData`. + #[cfg(feature = "gleam")] Scatter { /// Special program to run the scattered update. program: Program, @@ -1058,16 +734,17 @@ enum GpuCacheBus { } /// The device-specific representation of the cache texture in gpu_cache.rs -struct GpuCacheTexture { +struct GpuCacheTexture { texture: Option, bus: GpuCacheBus, + phantom_data: PhantomData, } -impl GpuCacheTexture { +impl GpuCacheTexture { /// Ensures that we have an appropriately-sized texture. Returns true if a /// new texture was created. - fn ensure_texture(&mut self, device: &mut Device, height: i32) { + fn ensure_texture(&mut self, device: &mut Device, height: i32) { // If we already have a texture that works, we're done. if self.texture.as_ref().map_or(false, |t| t.get_dimensions().height >= height) { if GPU_CACHE_RESIZE_TEST { @@ -1083,6 +760,16 @@ impl GpuCacheTexture { // Create the new texture. assert!(height >= 2, "Height is too small for ANGLE"); let new_size = DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as _, height); + + #[cfg(not(feature = "gleam"))] + { + if let GpuCacheBus::PersistentlyMappedBuffer { .. } = self.bus { + let texture = device.create_dummy_gpu_cache_texture(); + self.texture = Some(texture); + return + } + } + let rt_info = Some(RenderTargetInfo { has_depth: false }); let mut texture = device.create_texture( TextureTarget::Default, @@ -1103,51 +790,87 @@ impl GpuCacheTexture { self.texture = Some(texture); } - fn new(device: &mut Device, use_scatter: bool) -> Result { - let bus = if use_scatter { - let program = device.create_program_linked( - "gpu_cache_update", - String::new(), - &desc::GPU_CACHE_UPDATE, - )?; - let buf_position = device.create_vbo(); - let buf_value = device.create_vbo(); - //Note: the vertex attributes have to be supplied in the same order - // as for program creation, but each assigned to a different stream. - let vao = device.create_custom_vao(&[ - buf_position.stream_with(&desc::GPU_CACHE_UPDATE.vertex_attributes[0..1]), - buf_value .stream_with(&desc::GPU_CACHE_UPDATE.vertex_attributes[1..2]), - ]); - GpuCacheBus::Scatter { - program, - vao, - buf_position, - buf_value, - count: 0, + fn new(device: &mut Device, use_scatter: bool, _use_pmb: bool) -> Result { + if use_scatter && cfg!(not(feature = "gleam")) { + warn!("GpuCacheBus::Scatter is not supported with gfx backend"); + } + let bus; + #[cfg(feature = "gleam")] + { + if use_scatter { + let program = device.create_program_linked( + "gpu_cache_update", + String::new(), + &desc::GPU_CACHE_UPDATE, + )?; + let buf_position = device.create_vbo(); + let buf_value = device.create_vbo(); + //Note: the vertex attributes have to be supplied in the same order + // as for program creation, but each assigned to a different stream. + let vao = device.create_custom_vao(&[ + buf_position.stream_with(&desc::GPU_CACHE_UPDATE.vertex_attributes[0..1]), + buf_value .stream_with(&desc::GPU_CACHE_UPDATE.vertex_attributes[1..2]), + ]); + bus = GpuCacheBus::Scatter { + program, + vao, + buf_position, + buf_value, + count: 0, + } + } else { + let buffer = device.create_pbo(); + bus = GpuCacheBus::PixelBuffer { + buffer, + rows: Vec::new(), + } } - } else { - let buffer = device.create_pbo(); - GpuCacheBus::PixelBuffer { - buffer, - rows: Vec::new(), + } + #[cfg(not(feature = "gleam"))] + { + if _use_pmb { + bus = GpuCacheBus::PersistentlyMappedBuffer { slice: None }; + let texture = device.create_dummy_gpu_cache_texture(); + return Ok(GpuCacheTexture { + texture: Some(texture), + bus, + phantom_data: PhantomData, + }) + } else { + let buffer = device.create_pbo(); + bus = GpuCacheBus::PixelBuffer { + buffer, + rows: Vec::new(), + } } }; Ok(GpuCacheTexture { texture: None, bus, + phantom_data: PhantomData, }) } - fn deinit(mut self, device: &mut Device) { - if let Some(t) = self.texture.take() { - device.delete_texture(t); - } + fn deinit(mut self, device: &mut Device) { match self.bus { + #[cfg(not(feature = "gleam"))] + GpuCacheBus::PersistentlyMappedBuffer { .. } => { + if let Some(t) = self.texture.take() { + device.delete_texture(t); + } + } GpuCacheBus::PixelBuffer { buffer, ..} => { device.delete_pbo(buffer); + if let Some(t) = self.texture.take() { + device.delete_texture(t); + } } + #[cfg(feature = "gleam")] GpuCacheBus::Scatter { program, vao, buf_position, buf_value, ..} => { + if let Some(t) = self.texture.take() { + device.delete_texture(t); + } device.delete_program(program); device.delete_custom_vao(vao); device.delete_vbo(buf_position); @@ -1162,13 +885,16 @@ impl GpuCacheTexture { fn prepare_for_updates( &mut self, - device: &mut Device, - total_block_count: usize, + device: &mut Device, + _total_block_count: usize, max_height: i32, ) { self.ensure_texture(device, max_height); match self.bus { + #[cfg(not(feature = "gleam"))] + GpuCacheBus::PersistentlyMappedBuffer { .. } => {}, GpuCacheBus::PixelBuffer { .. } => {}, + #[cfg(feature = "gleam")] GpuCacheBus::Scatter { ref mut buf_position, ref mut buf_value, @@ -1176,16 +902,34 @@ impl GpuCacheTexture { .. } => { *count = 0; - if total_block_count > buf_value.allocated_count() { - device.allocate_vbo(buf_position, total_block_count, VertexUsageHint::Stream); - device.allocate_vbo(buf_value, total_block_count, VertexUsageHint::Stream); + if _total_block_count > buf_value.allocated_count() { + device.allocate_vbo(buf_position, _total_block_count, VertexUsageHint::Stream); + device.allocate_vbo(buf_value, _total_block_count, VertexUsageHint::Stream); } } } } - fn update(&mut self, device: &mut Device, updates: &GpuCacheUpdateList) { + fn update(&mut self, _device: &mut Device, updates: &GpuCacheUpdateList) { match self.bus { + #[cfg(not(feature = "gleam"))] + GpuCacheBus::PersistentlyMappedBuffer { ref mut slice } => { + let slice = slice.as_mut().unwrap(); + let writer_slice = slice.slice_mut::(); + for update in &updates.updates { + match *update { + GpuCacheUpdate::Copy { + block_index, + block_count, + address, + } => { + let address = address.v as usize * MAX_VERTEX_TEXTURE_WIDTH + address.u as usize; + writer_slice[address .. address + block_count] + .copy_from_slice(&updates.blocks[block_index .. block_index + block_count]); + } + } + } + } GpuCacheBus::PixelBuffer { ref mut rows, .. } => { for update in &updates.updates { match *update { @@ -1216,6 +960,7 @@ impl GpuCacheTexture { } } } + #[cfg(feature = "gleam")] GpuCacheBus::Scatter { ref buf_position, ref buf_value, @@ -1245,16 +990,18 @@ impl GpuCacheTexture { } } - device.fill_vbo(buf_value, &updates.blocks, *count); - device.fill_vbo(buf_position, &position_data, *count); + _device.fill_vbo(buf_value, &updates.blocks, *count); + _device.fill_vbo(buf_position, &position_data, *count); *count += position_data.len(); } } } - fn flush(&mut self, device: &mut Device) -> usize { + fn flush(&mut self, device: &mut Device) -> usize { let texture = self.texture.as_ref().unwrap(); match self.bus { + #[cfg(not(feature = "gleam"))] + GpuCacheBus::PersistentlyMappedBuffer { .. } => 0, GpuCacheBus::PixelBuffer { ref buffer, ref mut rows } => { let rows_dirty = rows .iter() @@ -1287,6 +1034,7 @@ impl GpuCacheTexture { rows_dirty } + #[cfg(feature = "gleam")] GpuCacheBus::Scatter { ref program, ref vao, count, .. } => { device.disable_depth(); device.set_blend(false); @@ -1306,19 +1054,20 @@ impl GpuCacheTexture { } } -struct VertexDataTexture { +struct VertexDataTexture { texture: Option, format: ImageFormat, pbo: PBO, + phantom_data: PhantomData, } -impl VertexDataTexture { +impl VertexDataTexture { fn new( - device: &mut Device, + device: &mut Device, format: ImageFormat, - ) -> VertexDataTexture { + ) -> VertexDataTexture { let pbo = device.create_pbo(); - VertexDataTexture { texture: None, format, pbo } + VertexDataTexture { texture: None, format, pbo, phantom_data: PhantomData } } /// Returns a borrow of the GPU texture. Panics if it hasn't been initialized. @@ -1331,7 +1080,7 @@ impl VertexDataTexture { self.texture.as_ref().map_or(0, |t| t.size_in_bytes()) } - fn update(&mut self, device: &mut Device, data: &mut Vec) { + fn update(&mut self, device: &mut Device, data: &mut Vec) { debug_assert!(mem::size_of::() % 16 == 0); let texels_per_item = mem::size_of::() / 16; let items_per_row = MAX_VERTEX_TEXTURE_WIDTH / texels_per_item; @@ -1396,7 +1145,7 @@ impl VertexDataTexture { .upload(rect, 0, None, data); } - fn deinit(mut self, device: &mut Device) { + fn deinit(mut self, device: &mut Device) { device.delete_pbo(self.pbo); if let Some(t) = self.texture.take() { device.delete_texture(t); @@ -1416,20 +1165,22 @@ struct TargetSelector { format: ImageFormat, } -struct LazyInitializedDebugRenderer { +struct LazyInitializedDebugRenderer { debug_renderer: Option, failed: bool, + phantom_data: PhantomData, } -impl LazyInitializedDebugRenderer { +impl LazyInitializedDebugRenderer { pub fn new() -> Self { Self { debug_renderer: None, failed: false, + phantom_data: PhantomData, } } - pub fn get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer> { + pub fn get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer> { if self.failed { return None; } @@ -1451,11 +1202,20 @@ impl LazyInitializedDebugRenderer { self.debug_renderer.as_mut() } - pub fn deinit(self, device: &mut Device) { + pub fn deinit(self, device: &mut Device) { if let Some(debug_renderer) = self.debug_renderer { debug_renderer.deinit(device); } } + + fn is_some(&self) -> bool { + self.debug_renderer.is_some() + } + + #[cfg(not(feature = "gleam"))] + fn take(&mut self) -> Option { + self.debug_renderer.take() + } } // NB: If you add more VAOs here, be sure to deinitialize them in @@ -1474,25 +1234,26 @@ pub struct RendererVAOs { /// /// We have a separate `Renderer` instance for each instance of WebRender (generally /// one per OS window), and all instances share the same thread. -pub struct Renderer { - result_rx: Receiver, +pub struct Renderer { + result_rx: Receiver>, debug_server: DebugServer, - pub device: Device, + pub device: Device, pending_texture_updates: Vec, pending_gpu_cache_updates: Vec, pending_gpu_cache_clear: bool, + new_gpu_cache_bus: Option, pending_shader_updates: Vec, active_documents: Vec<(DocumentId, RenderedDocument)>, - shaders: Rc>, + shaders: Rc>>, - pub gpu_glyph_renderer: GpuGlyphRenderer, + pub gpu_glyph_renderer: GpuGlyphRenderer, max_recorded_profiles: usize, clear_color: Option, - enable_clear_scissor: bool, - debug: LazyInitializedDebugRenderer, + _enable_clear_scissor: bool, + debug: LazyInitializedDebugRenderer, debug_flags: DebugFlags, backend_profile_counters: BackendProfileCounters, profile_counters: RendererProfileCounters, @@ -1508,11 +1269,11 @@ pub struct Renderer { pub gpu_profile: GpuProfiler, vaos: RendererVAOs, - prim_header_f_texture: VertexDataTexture, - prim_header_i_texture: VertexDataTexture, - transforms_texture: VertexDataTexture, - render_task_texture: VertexDataTexture, - gpu_cache_texture: GpuCacheTexture, + prim_header_f_texture: VertexDataTexture, + prim_header_i_texture: VertexDataTexture, + transforms_texture: VertexDataTexture, + render_task_texture: VertexDataTexture, + gpu_cache_texture: GpuCacheTexture, /// When the GPU cache debugger is enabled, we keep track of the live blocks /// in the GPU cache so that we can use them for the debug display. This @@ -1525,7 +1286,7 @@ pub struct Renderer { pipeline_info: PipelineInfo, // Manages and resolves source textures IDs to real texture IDs. - texture_resolver: TextureResolver, + texture_resolver: TextureResolver, // A PBO used to do asynchronous texture cache uploads. texture_cache_upload_pbo: PBO, @@ -1534,12 +1295,12 @@ pub struct Renderer { /// Optional trait object that allows the client /// application to provide external buffers for image data. - external_image_handler: Option>, + external_image_handler: Option>, /// Optional trait object that allows the client /// application to provide a texture handle to /// copy the WR output to. - output_image_handler: Option>, + output_image_handler: Option>, /// Optional function pointers for measuring memory used by a given /// heap-allocated pointer. @@ -1564,6 +1325,7 @@ pub struct Renderer { read_fbo: FBOId, #[cfg(feature = "replay")] owned_external_images: FastHashMap<(ExternalImageId, u8), ExternalTexture>, + phantom_data: PhantomData, } #[derive(Debug)] @@ -1592,7 +1354,7 @@ impl From for RendererError { } } -impl Renderer { +impl Renderer { /// Initializes WebRender and creates a `Renderer` and `RenderApiSender`. /// /// # Examples @@ -1611,29 +1373,43 @@ impl Renderer { /// ``` /// [rendereroptions]: struct.RendererOptions.html pub fn new( - gl: Rc, - notifier: Box, + init: DeviceInit, + notifier: Box, mut options: RendererOptions, - shaders: Option<&mut WrShaders> + shaders: Option<&mut WrShaders> ) -> Result<(Self, RenderApiSender), RendererError> { let (api_tx, api_rx) = channel::msg_channel()?; let (payload_tx, payload_rx) = channel::payload_channel()?; let (result_tx, result_rx) = channel(); - let gl_type = gl.get_type(); + #[cfg(feature = "gleam")] + let gl_type = init.gl.get_type(); + #[cfg(not(feature = "gleam"))] + let gl_type = (); let debug_server = DebugServer::new(api_tx.clone()); let mut device = Device::new( - gl, + init, options.resource_override_path.clone(), options.upload_method.clone(), options.cached_programs.take(), + #[cfg(not(feature = "gleam"))] + options.heaps_config, + #[cfg(not(feature = "gleam"))] + options.instance_buffer_size, + #[cfg(not(feature = "gleam"))] + options.texture_cahce_size, ); + #[cfg(feature = "gleam")] let ext_dual_source_blending = !options.disable_dual_source_blending && device.supports_extension("GL_ARB_blend_func_extended") && device.supports_extension("GL_ARB_explicit_attrib_location"); + #[cfg(not(feature = "gleam"))] + let ext_dual_source_blending = !options.disable_dual_source_blending && + device.supports_features(hal::Features::DUAL_SRC_BLENDING); + // 512 is the minimum that the texture cache can work with. const MIN_TEXTURE_SIZE: i32 = 512; if let Some(user_limit) = options.max_texture_size { @@ -1731,7 +1507,7 @@ impl Renderer { 21, ]; - let mut texture = device.create_texture( + let texture = device.create_texture( TextureTarget::Default, ImageFormat::R8, 8, @@ -1786,6 +1562,7 @@ impl Renderer { let gpu_cache_texture = GpuCacheTexture::new( &mut device, options.scatter_gpu_cache_updates, + true, )?; device.end_frame(); @@ -1897,6 +1674,12 @@ impl Renderer { scene_tx.clone() }; + #[cfg(not(feature = "gleam"))] + let device_clone = Arc::clone(&device.device); + #[cfg(not(feature = "gleam"))] + let heaps_clone = Arc::downgrade(&device.heaps); + #[cfg(not(feature = "gleam"))] + let non_coherent_atom_size_mask = (device.limits.non_coherent_atom_size - 1) as u64; thread::Builder::new().name(rb_thread_name.clone()).spawn(move || { register_thread_with_profiler(rb_thread_name.clone()); if let Some(ref thread_listener) = *thread_listener_for_render_backend { @@ -1914,7 +1697,7 @@ impl Renderer { blob_image_handler, ); - let mut backend = RenderBackend::new( + let mut backend: RenderBackend = RenderBackend::new( api_rx, payload_rx_for_backend, result_tx, @@ -1930,15 +1713,27 @@ impl Renderer { make_size_of_ops(), debug_flags, namespace_alloc_by_client, + #[cfg(not(feature = "gleam"))] + device_clone, + #[cfg(not(feature = "gleam"))] + heaps_clone, + #[cfg(not(feature = "gleam"))] + non_coherent_atom_size_mask, ); backend.run(backend_profile_counters); + backend.deinit(); if let Some(ref thread_listener) = *thread_listener_for_render_backend { thread_listener.thread_stopped(&rb_thread_name); } })?; - let ext_debug_marker = device.supports_extension("GL_EXT_debug_marker"); - let gpu_profile = GpuProfiler::new(Rc::clone(device.rc_gl()), ext_debug_marker); + let gpu_profile = GpuProfiler::new( + #[cfg(feature = "gleam")] + Rc::clone(device.rc_gl()), + #[cfg(feature = "gleam")] + device.supports_extension("GL_EXT_debug_marker") + ); + #[cfg(feature = "capture")] let read_fbo = device.create_fbo(); @@ -1950,6 +1745,7 @@ impl Renderer { pending_texture_updates: Vec::new(), pending_gpu_cache_updates: Vec::new(), pending_gpu_cache_clear: false, + new_gpu_cache_bus: None, pending_shader_updates: Vec::new(), shaders, debug: LazyInitializedDebugRenderer::new(), @@ -1964,7 +1760,7 @@ impl Renderer { slow_frame_indicator: ChangeIndicator::new(), max_recorded_profiles: options.max_recorded_profiles, clear_color: options.clear_color, - enable_clear_scissor: options.enable_clear_scissor, + _enable_clear_scissor: options.enable_clear_scissor, last_time: 0, gpu_profile, gpu_glyph_renderer, @@ -2001,6 +1797,7 @@ impl Renderer { owned_external_images: FastHashMap::default(), notifications: Vec::new(), framebuffer_size: None, + phantom_data: PhantomData, }; // We initially set the flags to default and then now call set_debug_flags @@ -2016,11 +1813,19 @@ impl Renderer { } pub fn get_graphics_api_info(&self) -> GraphicsApiInfo { - GraphicsApiInfo { + #[cfg(feature = "gleam")] + let api_info = GraphicsApiInfo { kind: GraphicsApi::OpenGL, version: self.device.gl().get_string(gl::VERSION), renderer: self.device.gl().get_string(gl::RENDERER), - } + }; + #[cfg(not(feature = "gleam"))] + let api_info = GraphicsApiInfo { + kind: GraphicsApi::Gfx, + version: "0.1".to_owned(), + renderer: "Gfx-rs".to_owned(), + }; + api_info } /// Returns the Epoch of the current frame in a pipeline. @@ -2046,6 +1851,10 @@ impl Renderer { // Pull any pending results and return the most recent. while let Ok(msg) = self.result_rx.try_recv() { match msg { + #[cfg(not(feature = "gleam"))] + ResultMsg::UpdateWindowSize(window_size) => { + self.resize(Some((window_size.width, window_size.height))); + } ResultMsg::PublishPipelineInfo(mut pipeline_info) => { for (pipeline_id, epoch) in pipeline_info.epochs { self.pipeline_info.epochs.insert(pipeline_id, epoch); @@ -2054,7 +1863,7 @@ impl Renderer { } ResultMsg::PublishDocument( document_id, - mut doc, + doc, texture_update_list, profile_counters, ) => { @@ -2118,6 +1927,48 @@ impl Renderer { } self.pending_gpu_cache_updates.push(list); } + #[cfg(not(feature="gleam"))] + ResultMsg::UpdateGpuCacheBuffer(mut update) => { + if !matches!(self.gpu_cache_texture.bus, GpuCacheBus::PersistentlyMappedBuffer { .. }) { + panic!("We should not receive this message if the cache bus is not a persistently mapped buffer!"); + } + match update.buffer_update { + BufferInfo::TransitRangeUpdate(new_range) => { + self.device.gpu_cache_buffer.as_mut().unwrap().update_transit_range(new_range); + } + BufferInfo::BufferUpdate { buffer_memory_slice, new_buffer_info, old_buffer } => { + self.new_gpu_cache_bus = Some(GpuCacheBus::PersistentlyMappedBuffer{ slice: Some(buffer_memory_slice) }); + self.device.set_gpu_cache_buffer(new_buffer_info); + if let Some(buffer) = old_buffer { + self.device.gpu_cache_buffers.insert(self.gpu_cache_texture.texture.as_ref().unwrap().id(), buffer); + } + self.pending_gpu_cache_clear = true; + } + } + if update.frame_id > self.gpu_cache_frame_id { + self.gpu_cache_frame_id = update.frame_id + } + + for cmd in mem::replace(&mut update.debug_commands, Vec::new()) { + match cmd { + GpuCacheDebugCmd::Alloc(chunk) => { + let row = chunk.address.v as usize; + if row >= self.gpu_cache_debug_chunks.len() { + self.gpu_cache_debug_chunks.resize(row + 1, Vec::new()); + } + self.gpu_cache_debug_chunks[row].push(chunk); + }, + GpuCacheDebugCmd::Free(address) => { + let chunks = &mut self.gpu_cache_debug_chunks[address.v as usize]; + let pos = chunks.iter() + .position(|x| x.address == address).unwrap(); + chunks.remove(pos); + }, + } + } + } + #[cfg(feature="gleam")] + ResultMsg::Phantom(..) => {} ResultMsg::UpdateResources { updates, memory_pressure, @@ -2187,6 +2038,16 @@ impl Renderer { String::new() } + #[cfg(not(feature = "gleam"))] + pub fn resize(&mut self, window_size: Option<(i32, i32)>) -> DeviceIntSize { + self.shaders.borrow_mut().reset(); + let size = self.device.recreate_swapchain(window_size); + if let Some(debug_renderer) = self.debug.take() { + debug_renderer.deinit(&mut self.device); + } + size + } + #[cfg(feature = "debugger")] fn get_screenshot_for_debugger(&mut self) -> String { @@ -2390,6 +2251,11 @@ impl Renderer { row.is_dirty = true; } } + #[cfg(not(feature = "gleam"))] + GpuCacheBus::PersistentlyMappedBuffer { .. } => { + info!("Invalidating GPU caches"); + } + #[cfg(feature = "gleam")] GpuCacheBus::Scatter { .. } => { warn!("Unable to invalidate scattered GPU cache"); } @@ -2402,12 +2268,12 @@ impl Renderer { } /// Set a callback for handling external images. - pub fn set_external_image_handler(&mut self, handler: Box) { + pub fn set_external_image_handler(&mut self, handler: Box) { self.external_image_handler = Some(handler); } /// Set a callback for handling external outputs. - pub fn set_output_image_handler(&mut self, handler: Box) { + pub fn set_output_image_handler(&mut self, handler: Box) { self.output_image_handler = Some(handler); } @@ -2508,6 +2374,8 @@ impl Renderer { samplers }; + #[cfg(not(feature="gleam"))] + self.device.set_next_frame_id(); let cpu_frame_id = profile_timers.cpu_time.profile(|| { let _gm = self.gpu_profile.start_marker("begin frame"); @@ -2554,7 +2422,13 @@ impl Renderer { }; self.device.reset_draw_target(); self.device.enable_depth_write(); - self.device.clear_target(clear_color, clear_depth_value, None); + self.device.clear_target( + clear_color, + clear_depth_value, + None, + #[cfg(not(feature = "gleam"))] + true + ); self.device.disable_depth_write(); } } @@ -2564,19 +2438,27 @@ impl Renderer { self.owned_external_images.iter().map(|(key, value)| (*key, value.clone())) ); - for &mut (_, RenderedDocument { ref mut frame, .. }) in &mut active_documents { + let last_document_idx = match active_documents.len() { + 0 => 0, + len => len -1, + }; + for (i, &mut (_, RenderedDocument { ref mut frame, .. })) in active_documents.iter_mut().enumerate() { frame.profile_counters.reset_targets(); self.prepare_gpu_cache(frame); assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id, "Received frame depends on a later GPU cache epoch ({:?}) than one we received last via `UpdateGpuCache` ({:?})", frame.gpu_cache_frame_id, self.gpu_cache_frame_id); + // The last pass of the last document has the main render target, which will be presented. + // We will tell the final render pass to transfer that target to a presentable state. + let present_frame_image = i == last_document_idx && !self.debug.is_some(); self.draw_tile_frame( frame, framebuffer_size, clear_depth_value.is_some(), cpu_frame_id, - &mut stats + &mut stats, + present_frame_image, ); if self.debug_flags.contains(DebugFlags::PROFILER_DBG) { @@ -2679,6 +2561,9 @@ impl Renderer { if let Some(debug_renderer) = self.debug.try_get_mut() { debug_renderer.render(&mut self.device, framebuffer_size); } + + #[cfg(not(feature="gleam"))] + self.device.submit_to_gpu(); self.device.end_frame(); }); if framebuffer_size.is_some() { @@ -2716,6 +2601,7 @@ impl Renderer { (count + list.blocks.len(), cmp::max(height, list.height)) }); + if max_requested_height > self.get_max_texture_size() && !self.gpu_cache_overflow { self.gpu_cache_overflow = true; self.renderer_errors.push(RendererError::MaxTextureSize); @@ -2735,8 +2621,7 @@ impl Renderer { if update_list.frame_id > self.gpu_cache_frame_id { self.gpu_cache_frame_id = update_list.frame_id } - self.gpu_cache_texture - .update(&mut self.device, &update_list); + self.gpu_cache_texture.update(&mut self.device, &update_list); } let mut upload_time = TimeProfileCounter::new("GPU cache upload time", false); @@ -2752,17 +2637,27 @@ impl Renderer { fn prepare_gpu_cache(&mut self, frame: &Frame) { if self.pending_gpu_cache_clear { - let use_scatter = - matches!(self.gpu_cache_texture.bus, GpuCacheBus::Scatter { .. }); - let new_cache = GpuCacheTexture::new(&mut self.device, use_scatter).unwrap(); + #[cfg(feature="gleam")] + let use_scatter = matches!(self.gpu_cache_texture.bus, GpuCacheBus::Scatter { .. }); + #[cfg(feature="gleam")] + let use_pmb = false; + + #[cfg(not(feature="gleam"))] + let use_scatter = false; + #[cfg(not(feature="gleam"))] + let use_pmb = matches!(self.gpu_cache_texture.bus, GpuCacheBus::PersistentlyMappedBuffer { .. }); + + let new_cache = GpuCacheTexture::new(&mut self.device, use_scatter, use_pmb).unwrap(); let old_cache = mem::replace(&mut self.gpu_cache_texture, new_cache); + if use_pmb { + self.gpu_cache_texture.bus = self.new_gpu_cache_bus.take().unwrap(); + } old_cache.deinit(&mut self.device); self.pending_gpu_cache_clear = false; } let deferred_update_list = self.update_deferred_resolves(&frame.deferred_resolves); self.pending_gpu_cache_updates.extend(deferred_update_list); - self.update_gpu_cache(); // Note: the texture might have changed during the `update`, @@ -2771,6 +2666,9 @@ impl Renderer { TextureSampler::GpuCache, self.gpu_cache_texture.texture.as_ref().unwrap(), ); + + #[cfg(not(feature = "gleam"))] + self.device.transit_gpu_cache_buffer(); } fn update_texture_cache(&mut self) { @@ -2882,15 +2780,21 @@ impl Renderer { size } TextureUpdateSource::DebugClear => { - self.device.bind_draw_target(DrawTarget::Texture { - texture, - layer: layer_index as usize, - with_depth: false, - }); + self.device.bind_draw_target( + DrawTarget::Texture { + texture, + layer: layer_index as usize, + with_depth: false, + }, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::Draw, + ); self.device.clear_target( Some(TEXTURE_CACHE_DBG_CLEAR_COLOR), None, - Some(rect.to_i32()) + Some(rect.to_i32()), + #[cfg(not(feature = "gleam"))] + false, ); 0 } @@ -2908,7 +2812,7 @@ impl Renderer { self.resource_upload_time += upload_time.get(); } - pub(crate) fn draw_instanced_batch( + pub(crate) fn draw_instanced_batch( &mut self, data: &[T], vertex_array_kind: VertexArrayKind, @@ -2931,7 +2835,7 @@ impl Renderer { self.draw_instanced_batch_with_previously_bound_textures(data, vertex_array_kind, stats) } - pub(crate) fn draw_instanced_batch_with_previously_bound_textures( + pub(crate) fn draw_instanced_batch_with_previously_bound_textures( &mut self, data: &[T], vertex_array_kind: VertexArrayKind, @@ -3008,7 +2912,11 @@ impl Renderer { layer: readback_layer.0 as usize, with_depth: false, }; - self.device.bind_draw_target(cache_draw_target); + self.device.bind_draw_target( + cache_draw_target, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::CopyOnly, + ); let mut src = DeviceIntRect::new( source_screen_origin + (backdrop_rect.origin - backdrop_screen_origin), @@ -3018,7 +2926,7 @@ impl Renderer { // Need to invert the y coordinates and flip the image vertically when // reading back from the framebuffer. - if draw_target.is_default() { + if cfg!(feature = "gleam") && draw_target.is_default() { src.origin.y = draw_target.dimensions().height as i32 - src.size.height - src.origin.y; dest.origin.y += dest.size.height; dest.size.height = -dest.size.height; @@ -3029,7 +2937,11 @@ impl Renderer { // Restore draw target to current pass render target + layer, and reset // the read target. - self.device.bind_draw_target(draw_target); + self.device.bind_draw_target( + draw_target, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::Draw, + ); self.device.reset_read_target(); if uses_scissor { @@ -3127,6 +3039,7 @@ impl Renderer { projection: &Transform3D, frame_id: GpuFrameId, stats: &mut RendererStats, + last_main_target_draw: bool, ) { self.profile_counters.color_targets.inc(); let _gm = self.gpu_profile.start_marker("color target"); @@ -3144,7 +3057,11 @@ impl Renderer { { let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET); - self.device.bind_draw_target(draw_target); + self.device.bind_draw_target( + draw_target, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::Draw, + ); self.device.disable_depth(); self.set_blend(false, framebuffer_kind); @@ -3155,8 +3072,9 @@ impl Renderer { None }; + #[cfg(feature = "gleam")] let clear_rect = if !draw_target.is_default() { - if self.enable_clear_scissor { + if self._enable_clear_scissor { // TODO(gw): Applying a scissor rect and minimal clear here // is a very large performance win on the Intel and nVidia // GPUs that I have tested with. It's possible it may be a @@ -3182,8 +3100,13 @@ impl Renderer { rect.origin.y = draw_target.dimensions().height as i32 - rect.origin.y - rect.size.height; Some(rect) }; + #[cfg(not(feature = "gleam"))] + let clear_rect = None; - self.device.clear_target(clear_color, depth_clear, clear_rect); + self.device.clear_target(clear_color, depth_clear, clear_rect, + #[cfg(not(feature = "gleam"))] + target.blits.is_empty() + ); if depth_clear.is_some() { self.device.disable_depth_write(); @@ -3193,6 +3116,12 @@ impl Renderer { // Handle any blits from the texture cache to this target. self.handle_blits(&target.blits, render_tasks); + #[cfg(not(feature = "gleam"))] + self.device.begin_render_pass( + last_main_target_draw && target.alpha_batch_containers.is_empty(), + false, + ); + // Draw any blurs for this target. // Blurs are rendered as a standard 2-pass // separable implementation. @@ -3242,13 +3171,37 @@ impl Renderer { } } - for alpha_batch_container in &target.alpha_batch_containers { + #[cfg(not(feature = "gleam"))] + self.device.end_render_pass(); + + #[cfg(not(feature = "gleam"))] + let last_alpha_batch_idx = target.alpha_batch_containers.len().max(1) - 1; + for (i, alpha_batch_container) in target.alpha_batch_containers.iter().enumerate() { + #[cfg(not(feature = "gleam"))] + let last_batch = i == last_alpha_batch_idx; + #[cfg(not(feature = "gleam"))] + let will_break_pass = alpha_batch_container + .alpha_batches + .iter().any(|batch| { + if let BatchKind::Brush(BrushBatchKind::MixBlend { .. }) = batch.key.kind { + true + } else { + false + } + }); + #[cfg(not(feature = "gleam"))] + let transit_to_presentable_state = last_main_target_draw && last_batch && !will_break_pass; + #[cfg(not(feature = "gleam"))] + let transit_to_transfer_src_state = will_break_pass; + #[cfg(not(feature = "gleam"))] + self.device.begin_render_pass(transit_to_presentable_state, transit_to_transfer_src_state); let uses_scissor = alpha_batch_container.task_scissor_rect.is_some() || !alpha_batch_container.regions.is_empty(); + let scissor_rect; if uses_scissor { self.device.enable_scissor(); - let scissor_rect = draw_target.build_scissor_rect( + scissor_rect = draw_target.build_scissor_rect( alpha_batch_container.task_scissor_rect, framebuffer_target_rect, ); @@ -3361,6 +3314,8 @@ impl Renderer { // composites can't be grouped together because // they may overlap and affect each other. debug_assert_eq!(batch.instances.len(), 1); + #[cfg(not(feature = "gleam"))] + self.device.end_render_pass(); self.handle_readback_composite( draw_target, uses_scissor, @@ -3368,6 +3323,16 @@ impl Renderer { &render_tasks[task_id], &render_tasks[backdrop_id], ); + #[cfg(not(feature = "gleam"))] + let transit_to_presentable_state = last_main_target_draw && last_batch; + #[cfg(not(feature = "gleam"))] + let transit_to_transfer_src_state = !alpha_batch_container.tile_blits.is_empty() + || (last_batch && !target.outputs.is_empty()); + #[cfg(not(feature = "gleam"))] + self.device.begin_render_pass( + transit_to_presentable_state, + transit_to_transfer_src_state, + ); } let _timer = self.gpu_profile.start_timer(batch.key.kind.sampler_tag()); @@ -3403,7 +3368,6 @@ impl Renderer { self.set_blend_mode_subpixel_with_bg_color_pass2(framebuffer_kind); self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass2 as _); - self.device .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32); } @@ -3424,6 +3388,9 @@ impl Renderer { self.device.disable_scissor(); } + #[cfg(not(feature = "gleam"))] + self.device.end_render_pass(); + // At the end of rendering a container, blit across any cache tiles // to the texture cache for use on subsequent frames. if !alpha_batch_container.tile_blits.is_empty() { @@ -3436,11 +3403,15 @@ impl Renderer { .resolve(&blit.target.texture_id) .expect("BUG: invalid target texture"); - self.device.bind_draw_target(DrawTarget::Texture { - texture, - layer: blit.target.texture_layer as usize, - with_depth: false, - }); + self.device.bind_draw_target( + DrawTarget::Texture { + texture, + layer: blit.target.texture_layer as usize, + with_depth: false, + }, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::CopyOnly, + ); let mut src_rect = DeviceIntRect::new( blit.src_offset, @@ -3457,10 +3428,12 @@ impl Renderer { blit.size, ); - // Modify the src/dest rects since we are blitting from the framebuffer - src_rect.origin.y = draw_target.dimensions().height as i32 - src_rect.size.height - src_rect.origin.y; - dest_rect.origin.y += dest_rect.size.height; - dest_rect.size.height = -dest_rect.size.height; + if cfg!(feature = "gleam") { + // Modify the src/dest rects since we are blitting from the framebuffer + src_rect.origin.y = draw_target.dimensions().height as i32 - src_rect.size.height - src_rect.origin.y; + dest_rect.origin.y += dest_rect.size.height; + dest_rect.size.height = -dest_rect.size.height; + } self.device.blit_render_target( src_rect, @@ -3468,10 +3441,15 @@ impl Renderer { ); } - self.device.bind_draw_target(draw_target); + self.device.bind_draw_target( + draw_target, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::Draw, + ); } } + // For any registered image outputs on this render target, // get the texture from caller and blit it. for output in &target.outputs { @@ -3523,10 +3501,17 @@ impl Renderer { { let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET); - self.device.bind_draw_target(draw_target); + self.device.bind_draw_target( + draw_target, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::Draw, + ); self.device.disable_depth(); self.device.disable_depth_write(); + #[cfg(not(feature = "gleam"))] + self.device.begin_render_pass(false, false); + // TODO(gw): Applying a scissor rect and minimal clear here // is a very large performance win on the Intel and nVidia // GPUs that I have tested with. It's possible it may be a @@ -3537,6 +3522,8 @@ impl Renderer { Some(clear_color), None, Some(target.used_rect()), + #[cfg(not(feature = "gleam"))] + false, ); let zero_color = [0.0, 0.0, 0.0, 0.0]; @@ -3546,6 +3533,8 @@ impl Renderer { Some(zero_color), None, Some(rect), + #[cfg(not(feature = "gleam"))] + false, ); } } @@ -3648,6 +3637,9 @@ impl Renderer { } } + #[cfg(not(feature = "gleam"))] + self.device.end_render_pass(); + self.gpu_profile.finish_sampler(alpha_sampler); } @@ -3665,13 +3657,12 @@ impl Renderer { .resolve(&texture_source) .expect("BUG: invalid target texture"); let target_size = texture.get_dimensions(); - let projection = Transform3D::ortho( + let projection = create_projection( 0.0, target_size.width as f32, 0.0, target_size.height as f32, - ORTHO_NEAR_PLANE, - ORTHO_FAR_PLANE, + false, ); (target_size, projection) }; @@ -3688,11 +3679,15 @@ impl Renderer { let texture = self.texture_resolver .resolve(&texture_source) .expect("BUG: invalid target texture"); - self.device.bind_draw_target(DrawTarget::Texture { - texture, - layer, - with_depth: false, - }); + self.device.bind_draw_target( + DrawTarget::Texture { + texture, + layer, + with_depth: false, + }, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::Draw, + ); } self.device.disable_depth(); @@ -3700,12 +3695,18 @@ impl Renderer { self.set_blend(false, FramebufferKind::Other); for rect in &target.clears { - self.device.clear_target(Some([0.0, 0.0, 0.0, 0.0]), None, Some(*rect)); + self.device.clear_target(Some([0.0, 0.0, 0.0, 0.0]), None, Some(*rect), + #[cfg(not(feature = "gleam"))] + false + ); } // Handle any blits to this texture from child tasks. self.handle_blits(&target.blits, render_tasks); + #[cfg(not(feature = "gleam"))] + self.device.begin_render_pass(false, false); + // Draw any borders for this target. if !target.border_segments_solid.is_empty() || !target.border_segments_complex.is_empty() @@ -3793,6 +3794,9 @@ impl Renderer { ); } + #[cfg(not(feature = "gleam"))] + self.device.end_render_pass(); + // Blit any Pathfinder glyphs to the cache texture. if let Some(stencil_page) = stencil_page { self.cover_glyphs(stencil_page, &projection, stats); @@ -3920,6 +3924,8 @@ impl Renderer { &mut self, list: &mut RenderTargetList, counters: &mut FrameProfileCounters, + // TODO: check if we still need this with gfx + _frame_id: GpuFrameId, ) -> Option { if list.targets.is_empty() { return None @@ -3951,6 +3957,13 @@ impl Renderer { let index = self.texture_resolver.render_target_pool .iter() .position(|texture| { + // We ignore the textures which are still used by the GPU + #[cfg(not(feature = "gleam"))] + { + if texture.still_in_flight(_frame_id, self.device.frame_count) { + return false; + } + } selector == TargetSelector { size: texture.get_dimensions(), num_layers: texture.get_layer_count() as usize, @@ -4032,6 +4045,7 @@ impl Renderer { framebuffer_depth_is_ready: bool, frame_id: GpuFrameId, stats: &mut RendererStats, + present_frame_image: bool, ) { let _gm = self.gpu_profile.start_marker("tile frame draw"); @@ -4067,13 +4081,12 @@ impl Renderer { stats.color_target_count += 1; let clear_color = frame.background_color.map(|color| color.to_array()); - let projection = Transform3D::ortho( + let projection = create_projection( 0.0, framebuffer_size.width as f32, framebuffer_size.height as f32, 0.0, - ORTHO_NEAR_PLANE, - ORTHO_FAR_PLANE, + true, ); self.draw_color_target( @@ -4086,14 +4099,15 @@ impl Renderer { &projection, frame_id, stats, + present_frame_image, ); } (None, None) } RenderPassKind::OffScreen { ref mut alpha, ref mut color, ref mut texture_cache } => { - let alpha_tex = self.allocate_target_texture(alpha, &mut frame.profile_counters); - let color_tex = self.allocate_target_texture(color, &mut frame.profile_counters); + let alpha_tex = self.allocate_target_texture(alpha, &mut frame.profile_counters, frame_id); + let color_tex = self.allocate_target_texture(color, &mut frame.profile_counters, frame_id); // If this frame has already been drawn, then any texture // cache targets have already been updated and can be @@ -4118,13 +4132,12 @@ impl Renderer { with_depth: false, }; - let projection = Transform3D::ortho( + let projection = create_projection( 0.0, draw_target.dimensions().width as f32, 0.0, draw_target.dimensions().height as f32, - ORTHO_NEAR_PLANE, - ORTHO_FAR_PLANE, + false, ); self.draw_alpha_target( @@ -4144,13 +4157,12 @@ impl Renderer { with_depth: target.needs_depth(), }; - let projection = Transform3D::ortho( + let projection = create_projection( 0.0, draw_target.dimensions().width as f32, 0.0, draw_target.dimensions().height as f32, - ORTHO_NEAR_PLANE, - ORTHO_FAR_PLANE, + false, ); self.draw_color_target( @@ -4163,6 +4175,7 @@ impl Renderer { &projection, frame_id, stats, + false, ); } @@ -4325,12 +4338,12 @@ impl Renderer { } fn do_debug_blit( - device: &mut Device, + device: &mut Device, debug_renderer: &mut DebugRenderer, mut textures: Vec<&Texture>, framebuffer_size: DeviceIntSize, bottom: i32, - select_color: &Fn(&Texture) -> [f32; 4], + select_color: &dyn Fn(&Texture) -> [f32; 4], ) { let mut spacing = 16; let mut size = 512; @@ -4378,15 +4391,31 @@ impl Renderer { let text_margin = 1; let text_height = 14; // Visually aproximated. let tag_height = text_height + text_margin * 2; - let tag_rect = rect(x, y, size, tag_height); + let tag_rect = if cfg!(feature = "gleam") { + rect(x, y, size, tag_height) + } else { + rect(x, fb_height - (y + tag_height), size, tag_height) + }; let tag_color = select_color(texture); - device.clear_target(Some(tag_color), None, Some(tag_rect)); + device.clear_target(Some(tag_color), None, Some(tag_rect), + #[cfg(not(feature = "gleam"))] + false + ); + + // This is a WIP solution to avoid validation layer errors, + // by moving the frame images into TransferDstOptimal layout. + #[cfg(not(feature = "gleam"))] + device.begin_render_pass_inner(hal::image::Layout::TransferDstOptimal); + #[cfg(not(feature = "gleam"))] + device.end_render_pass(); // Draw the dimensions onto the tag. let dim = texture.get_dimensions(); let mut text_rect = tag_rect; - text_rect.origin.y = - fb_height - text_rect.origin.y - text_rect.size.height; // Top-relative. + if cfg!(feature = "gleam") { + text_rect.origin.y = + fb_height - text_rect.origin.y - text_rect.size.height; // Top-relative. + } debug_renderer.add_text( (x + text_margin) as f32, (fb_height - y - text_margin) as f32, // Top-relative. @@ -4398,7 +4427,11 @@ impl Renderer { // Blit the contents of the layer. We need to invert Y because // we're blitting from a texture to the main framebuffer, which // use different conventions. - let dest_rect = rect(x, y + tag_height, size, size); + let dest_rect = if cfg!(feature = "gleam") { + rect(x, y + tag_height, size, size) + } else { + rect(x, fb_height - (y + tag_height + size), size, size) + }; device.blit_render_target_invert_y(src_rect, dest_rect); i += 1; } @@ -4510,6 +4543,8 @@ impl Renderer { pub fn deinit(mut self) { //Note: this is a fake frame, only needed because texture deletion is require to happen inside a frame self.device.begin_frame(); + #[cfg(not(feature = "gleam"))] + self.device.wait_for_resources_and_reset(); self.gpu_cache_texture.deinit(&mut self.device); if let Some(dither_matrix_texture) = self.dither_matrix_texture { self.device.delete_texture(dither_matrix_texture); @@ -4542,6 +4577,8 @@ impl Renderer { self.device.delete_external_texture(ext); } self.device.end_frame(); + #[cfg(not(feature = "gleam"))] + self.device.deinit(); } fn size_of(&self, ptr: *const T) -> usize { @@ -4554,10 +4591,13 @@ impl Renderer { let mut report = MemoryReport::default(); // GPU cache CPU memory. - if let GpuCacheBus::PixelBuffer{ref rows, ..} = self.gpu_cache_texture.bus { - for row in rows.iter() { - report.gpu_cache_cpu_mirror += self.size_of(&*row.cpu_blocks as *const _); + match self.gpu_cache_texture.bus { + GpuCacheBus::PixelBuffer{ref rows, ..} => { + for row in rows.iter() { + report.gpu_cache_cpu_mirror += self.size_of(&*row.cpu_blocks as *const _); + } } + _ => {} } // GPU cache GPU memory. @@ -4634,12 +4674,22 @@ impl Renderer { /// Clears all the layers of a texture with a given color. fn clear_texture(&mut self, texture: &Texture, color: [f32; 4]) { for i in 0..texture.get_layer_count() { - self.device.bind_draw_target(DrawTarget::Texture { - texture: &texture, - layer: i as usize, - with_depth: false, - }); - self.device.clear_target(Some(color), None, None); + self.device.bind_draw_target( + DrawTarget::Texture { + texture: &texture, + layer: i as usize, + with_depth: false, + }, + #[cfg(not(feature="gleam"))] + DrawTargetUsage::Draw, + ); + self.device.clear_target( + Some(color), + None, + None, + #[cfg(not(feature = "gleam"))] + false + ); } } } @@ -4744,21 +4794,6 @@ pub trait AsyncPropertySampler { fn deregister(&self); } -/// Flags that control how shaders are pre-cached, if at all. -bitflags! { - #[derive(Default)] - pub struct ShaderPrecacheFlags: u32 { - /// Needed for const initialization - const EMPTY = 0; - - /// Only start async compile - const ASYNC_COMPILE = 1 << 2; - - /// Do a full compile/link during startup - const FULL_COMPILE = 1 << 3; - } -} - pub struct RendererOptions { pub device_pixel_ratio: f32, pub resource_override_path: Option, @@ -4774,21 +4809,27 @@ pub struct RendererOptions { pub scatter_gpu_cache_updates: bool, pub upload_method: UploadMethod, pub workers: Option>, - pub blob_image_handler: Option>, - pub recorder: Option>, - pub thread_listener: Option>, + pub blob_image_handler: Option>, + pub recorder: Option>, + pub thread_listener: Option>, pub size_of_op: Option, pub enclosing_size_of_op: Option, pub cached_programs: Option>, pub debug_flags: DebugFlags, pub renderer_id: Option, pub disable_dual_source_blending: bool, - pub scene_builder_hooks: Option>, - pub sampler: Option>, + pub scene_builder_hooks: Option>, + pub sampler: Option>, pub chase_primitive: ChasePrimitive, pub support_low_priority_transactions: bool, pub namespace_alloc_by_client: bool, pub enable_picture_caching: bool, + #[cfg(not(feature = "gleam"))] + pub heaps_config: HeapsConfig, + // The size of an instance buffer in bytes + pub instance_buffer_size: usize, + // The size of a staging buffer for image data upload in bytes + pub texture_cahce_size: usize, } impl Default for RendererOptions { @@ -4826,6 +4867,13 @@ impl Default for RendererOptions { support_low_priority_transactions: false, namespace_alloc_by_client: false, enable_picture_caching: false, + #[cfg(not(feature = "gleam"))] + heaps_config: HeapsConfig { + linear: None, + dynamic: None, + }, + instance_buffer_size: 1 << 20, + texture_cahce_size: 16 << 20, } } } @@ -4894,7 +4942,7 @@ struct PlainRenderer { #[cfg(feature = "replay")] enum CapturedExternalImageData { - NativeTexture(gl::GLuint), + NativeTexture(IdType), Buffer(Arc>), } @@ -4934,10 +4982,10 @@ pub struct PipelineInfo { pub removed_pipelines: Vec, } -impl Renderer { +impl Renderer { #[cfg(feature = "capture")] fn save_texture( - texture: &Texture, name: &str, root: &PathBuf, device: &mut Device + texture: &Texture, name: &str, root: &PathBuf, device: &mut Device ) -> PlainTexture { use std::fs; use std::io::Write; @@ -4979,6 +5027,8 @@ impl Renderer { ); } device.read_pixels_into(rect, read_format, &mut data); + #[cfg(not(feature = "gleam"))] + device.invalidate_read_texture(); file.write_all(&data) .unwrap(); } @@ -4997,7 +5047,7 @@ impl Renderer { plain: &PlainTexture, rt_info: Option, root: &PathBuf, - device: &mut Device + device: &mut Device ) -> (Texture, Vec) { use std::fs::File; @@ -5015,7 +5065,11 @@ impl Renderer { plain.size.0.width, plain.size.0.height, plain.filter, - rt_info, + if plain.format == ImageFormat::RGBAF32 { + None + } else { + rt_info + }, plain.size.1, ); device.upload_texture_immediate(&texture, &texels); @@ -5122,7 +5176,7 @@ impl Renderer { self.update_gpu_cache(); // flush pending updates let mut plain_self = PlainRenderer { gpu_cache: Self::save_texture( - &self.gpu_cache_texture.texture.as_ref().unwrap(), + &self.gpu_cache_texture.texture.as_ref().expect("No gpu cache texture exist"), "gpu", &config.root, &mut self.device, ), gpu_cache_frame_id: self.gpu_cache_frame_id, @@ -5230,12 +5284,12 @@ impl Renderer { row.cpu_blocks.copy_from_slice(chunk); } } - GpuCacheBus::Scatter { .. } => {} + _ => {} } self.gpu_cache_frame_id = renderer.gpu_cache_frame_id; info!("loading external texture-backed images"); - let mut native_map = FastHashMap::::default(); + let mut native_map = FastHashMap::::default(); for ExternalCaptureImage { short_path, external, descriptor } in renderer.external_images { let target = match external.image_type { ExternalImageType::TextureHandle(target) => target, @@ -5283,10 +5337,11 @@ impl Renderer { } #[cfg(feature = "pathfinder")] -fn get_vao<'a>(vertex_array_kind: VertexArrayKind, - vaos: &'a RendererVAOs, - gpu_glyph_renderer: &'a GpuGlyphRenderer) - -> &'a VAO { +fn get_vao<'a, B: hal::Backend>( + vertex_array_kind: VertexArrayKind, + vaos: &'a RendererVAOs, + gpu_glyph_renderer: &'a GpuGlyphRenderer, +) -> &'a VAO { match vertex_array_kind { VertexArrayKind::Primitive => &vaos.prim_vao, VertexArrayKind::Clip => &vaos.clip_vao, @@ -5300,10 +5355,11 @@ fn get_vao<'a>(vertex_array_kind: VertexArrayKind, } #[cfg(not(feature = "pathfinder"))] -fn get_vao<'a>(vertex_array_kind: VertexArrayKind, - vaos: &'a RendererVAOs, - _: &'a GpuGlyphRenderer) - -> &'a VAO { +fn get_vao<'a, B: hal::Backend>( + vertex_array_kind: VertexArrayKind, + vaos: &'a RendererVAOs, + _: &'a GpuGlyphRenderer, +) -> &'a VAO { match vertex_array_kind { VertexArrayKind::Primitive => &vaos.prim_vao, VertexArrayKind::Clip => &vaos.clip_vao, @@ -5320,4 +5376,3 @@ enum FramebufferKind { Main, Other, } - diff --git a/webrender/src/resource_cache.rs b/webrender/src/resource_cache.rs index 04860c1def..b3bca513ee 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -457,7 +457,7 @@ pub struct ResourceCache { /// both blobs and regular images. pending_image_requests: FastHashSet, - blob_image_handler: Option>, + blob_image_handler: Option>, rasterized_blob_images: FastHashMap, blob_image_templates: FastHashMap, @@ -465,7 +465,7 @@ pub struct ResourceCache { /// rasterize, add them to this list and rasterize them synchronously. missing_blob_images: Vec, /// The rasterizer associated with the current scene. - blob_image_rasterizer: Option>, + blob_image_rasterizer: Option>, /// An epoch of the stored blob image rasterizer, used to skip the ones /// coming from low-priority scene builds if the current one is newer. /// This is to be removed when we get rid of the whole "missed" blob @@ -484,7 +484,7 @@ impl ResourceCache { pub fn new( texture_cache: TextureCache, glyph_rasterizer: GlyphRasterizer, - blob_image_handler: Option>, + blob_image_handler: Option>, ) -> Self { ResourceCache { cached_glyphs: GlyphCache::new(), @@ -681,7 +681,7 @@ impl ResourceCache { } pub fn set_blob_rasterizer( - &mut self, rasterizer: Box, + &mut self, rasterizer: Box, supp: AsyncBlobImageInfo, ) { if self.blob_image_rasterizer_consumed_epoch.0 < supp.epoch.0 { @@ -1156,7 +1156,7 @@ impl ResourceCache { pub fn create_blob_scene_builder_requests( &mut self, keys: &[BlobImageKey] - ) -> (Option<(Box, AsyncBlobImageInfo)>, Vec) { + ) -> (Option<(Box, AsyncBlobImageInfo)>, Vec) { if self.blob_image_handler.is_none() || keys.is_empty() { return (None, Vec::new()); } diff --git a/webrender/src/scene_builder.rs b/webrender/src/scene_builder.rs index 1f67e034ea..a4ce3e6e26 100644 --- a/webrender/src/scene_builder.rs +++ b/webrender/src/scene_builder.rs @@ -43,7 +43,7 @@ pub struct Transaction { pub epoch_updates: Vec<(PipelineId, Epoch)>, pub request_scene_build: Option, pub blob_requests: Vec, - pub blob_rasterizer: Option<(Box, AsyncBlobImageInfo)>, + pub blob_rasterizer: Option<(Box, AsyncBlobImageInfo)>, pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>, pub resource_updates: Vec, pub frame_ops: Vec, @@ -88,7 +88,7 @@ pub struct BuiltTransaction { pub built_scene: Option, pub resource_updates: Vec, pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>, - pub blob_rasterizer: Option<(Box, AsyncBlobImageInfo)>, + pub blob_rasterizer: Option<(Box, AsyncBlobImageInfo)>, pub frame_ops: Vec, pub removed_pipelines: Vec, pub notifications: Vec, @@ -276,7 +276,7 @@ pub struct SceneBuilder { tx: Sender, api_tx: MsgSender, config: FrameBuilderConfig, - hooks: Option>, + hooks: Option>, simulate_slow_ms: u32, size_of_ops: Option, } @@ -285,7 +285,7 @@ impl SceneBuilder { pub fn new( config: FrameBuilderConfig, api_tx: MsgSender, - hooks: Option>, + hooks: Option>, size_of_ops: Option, ) -> (Self, Sender, Receiver) { let (in_tx, in_rx) = channel(); diff --git a/webrender/src/shade.rs b/webrender/src/shade.rs index 5dd0e720af..cc7a2a74f7 100644 --- a/webrender/src/shade.rs +++ b/webrender/src/shade.rs @@ -3,21 +3,26 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use batch::{BatchKey, BatchKind, BrushBatchKind}; -use device::{Device, Program, ShaderError}; +use device::{Device, ShaderError, ShaderKind, ShaderPrecacheFlags, VertexArrayKind}; use euclid::{Transform3D}; use glyph_rasterizer::GlyphFormat; -use renderer::{ - desc, - MAX_VERTEX_TEXTURE_WIDTH, - BlendMode, DebugFlags, ImageBufferKind, RendererError, RendererOptions, - TextureSampler, VertexArrayKind, ShaderPrecacheFlags, -}; - -use gleam::gl::GlType; -use time::precise_time_ns; use std::cell::RefCell; use std::rc::Rc; +use hal; +use renderer::{BlendMode, DebugFlags, ImageBufferKind, RendererError, RendererOptions}; +use std::marker::PhantomData; +use time::precise_time_ns; + +cfg_if! { + if #[cfg(feature = "gleam")] { + use gleam::gl::GlType; + use device::Program; + } else { + use device::ProgramId as Program; + type GlType = (); + } +} impl ImageBufferKind { pub(crate) fn get_feature_string(&self) -> &'static str { @@ -29,6 +34,7 @@ impl ImageBufferKind { } } + #[cfg(feature = "gleam")] fn has_platform_support(&self, gl_type: &GlType) -> bool { match (*self, gl_type) { (ImageBufferKind::Texture2D, _) => true, @@ -38,6 +44,16 @@ impl ImageBufferKind { (ImageBufferKind::TextureExternal, &GlType::Gl) => false, } } + + #[cfg(not(feature = "gleam"))] + fn has_platform_support(&self) -> bool { + match *self { + ImageBufferKind::Texture2D => true, + ImageBufferKind::Texture2DArray => true, + ImageBufferKind::TextureRect => true, + ImageBufferKind::TextureExternal => false, + } + } } pub const IMAGE_BUFFER_KINDS: [ImageBufferKind; 4] = [ @@ -52,31 +68,20 @@ const DEBUG_OVERDRAW_FEATURE: &str = "DEBUG_OVERDRAW"; const DITHERING_FEATURE: &str = "DITHERING"; const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING"; -pub(crate) enum ShaderKind { - Primitive, - Cache(VertexArrayKind), - ClipCache, - Brush, - Text, - #[allow(dead_code)] - VectorStencil, - #[allow(dead_code)] - VectorCover, -} - -pub struct LazilyCompiledShader { +pub struct LazilyCompiledShader { program: Option, name: &'static str, kind: ShaderKind, features: Vec<&'static str>, + phantom_data: PhantomData, } -impl LazilyCompiledShader { +impl LazilyCompiledShader { pub(crate) fn new( kind: ShaderKind, name: &'static str, features: &[&'static str], - device: &mut Device, + device: &mut Device, precache_flags: ShaderPrecacheFlags, ) -> Result { let mut shader = LazilyCompiledShader { @@ -84,9 +89,11 @@ impl LazilyCompiledShader { name, kind, features: features.to_vec(), + phantom_data: PhantomData, }; - if precache_flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) { + if precache_flags.intersects(ShaderPrecacheFlags::ASYNC_COMPILE | ShaderPrecacheFlags::FULL_COMPILE) + && cfg!(feature="gleam") { let t0 = precise_time_ns(); shader.get_internal(device, precache_flags)?; let t1 = precise_time_ns(); @@ -102,7 +109,7 @@ impl LazilyCompiledShader { pub fn bind( &mut self, - device: &mut Device, + device: &mut Device, projection: &Transform3D, renderer_errors: &mut Vec, ) { @@ -119,111 +126,36 @@ impl LazilyCompiledShader { fn get_internal( &mut self, - device: &mut Device, + device: &mut Device, precache_flags: ShaderPrecacheFlags, ) -> Result<&mut Program, ShaderError> { if self.program.is_none() { - let program = match self.kind { - ShaderKind::Primitive | ShaderKind::Brush | ShaderKind::Text => { - create_prim_shader(self.name, - device, - &self.features) - } - ShaderKind::Cache(..) => { - create_prim_shader(self.name, - device, - &self.features) - } - ShaderKind::VectorStencil => { - create_prim_shader(self.name, - device, - &self.features) - } - ShaderKind::VectorCover => { - create_prim_shader(self.name, - device, - &self.features) - } - ShaderKind::ClipCache => { - create_clip_shader(self.name, device) - } - }; + let program = device.create_program_with_kind( + self.name, + &self.kind, + &self.features, + precache_flags, + ); self.program = Some(program?); } - let program = self.program.as_mut().unwrap(); - - if precache_flags.contains(ShaderPrecacheFlags::FULL_COMPILE) && !program.is_initialized() { - let vertex_format = match self.kind { - ShaderKind::Primitive | - ShaderKind::Brush | - ShaderKind::Text => VertexArrayKind::Primitive, - ShaderKind::Cache(format) => format, - ShaderKind::VectorStencil => VertexArrayKind::VectorStencil, - ShaderKind::VectorCover => VertexArrayKind::VectorCover, - ShaderKind::ClipCache => VertexArrayKind::Clip, - }; - - let vertex_descriptor = match vertex_format { - VertexArrayKind::Primitive => &desc::PRIM_INSTANCES, - VertexArrayKind::LineDecoration => &desc::LINE, - VertexArrayKind::Blur => &desc::BLUR, - VertexArrayKind::Clip => &desc::CLIP, - VertexArrayKind::VectorStencil => &desc::VECTOR_STENCIL, - VertexArrayKind::VectorCover => &desc::VECTOR_COVER, - VertexArrayKind::Border => &desc::BORDER, - VertexArrayKind::Scale => &desc::SCALE, - }; - - device.link_program(program, vertex_descriptor)?; - device.bind_program(program); - match self.kind { - ShaderKind::ClipCache => { - device.bind_shader_samplers( - &program, - &[ - ("sColor0", TextureSampler::Color0), - ("sTransformPalette", TextureSampler::TransformPalette), - ("sRenderTasks", TextureSampler::RenderTasks), - ("sGpuCache", TextureSampler::GpuCache), - ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF), - ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI), - ], - ); - } - _ => { - device.bind_shader_samplers( - &program, - &[ - ("sColor0", TextureSampler::Color0), - ("sColor1", TextureSampler::Color1), - ("sColor2", TextureSampler::Color2), - ("sDither", TextureSampler::Dither), - ("sPrevPassAlpha", TextureSampler::PrevPassAlpha), - ("sPrevPassColor", TextureSampler::PrevPassColor), - ("sTransformPalette", TextureSampler::TransformPalette), - ("sRenderTasks", TextureSampler::RenderTasks), - ("sGpuCache", TextureSampler::GpuCache), - ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF), - ("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI), - ], - ); - } - } - } - Ok(program) } - fn get(&mut self, device: &mut Device) -> Result<&mut Program, ShaderError> { + fn get(&mut self, device: &mut Device) -> Result<&mut Program, ShaderError> { self.get_internal(device, ShaderPrecacheFlags::FULL_COMPILE) } - fn deinit(self, device: &mut Device) { + fn deinit(self, device: &mut Device) { if let Some(program) = self.program { device.delete_program(program); } } + + #[cfg(not(feature = "gleam"))] + fn reset(&mut self) { + self.program = None; + } } // A brush shader supports two modes: @@ -237,17 +169,17 @@ impl LazilyCompiledShader { // pass. Assumes that AA should be applied // along the primitive edge, and also that // clip mask is present. -struct BrushShader { - opaque: LazilyCompiledShader, - alpha: LazilyCompiledShader, - dual_source: Option, - debug_overdraw: LazilyCompiledShader, +struct BrushShader { + opaque: LazilyCompiledShader, + alpha: LazilyCompiledShader, + dual_source: Option>, + debug_overdraw: LazilyCompiledShader, } -impl BrushShader { +impl BrushShader { fn new( name: &'static str, - device: &mut Device, + device: &mut Device, features: &[&'static str], precache_flags: ShaderPrecacheFlags, dual_source: bool, @@ -308,7 +240,7 @@ impl BrushShader { } fn get(&mut self, blend_mode: BlendMode, debug_flags: DebugFlags) - -> &mut LazilyCompiledShader { + -> &mut LazilyCompiledShader { match blend_mode { _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => &mut self.debug_overdraw, BlendMode::None => &mut self.opaque, @@ -325,7 +257,7 @@ impl BrushShader { } } - fn deinit(self, device: &mut Device) { + fn deinit(self, device: &mut Device) { self.opaque.deinit(device); self.alpha.deinit(device); if let Some(dual_source) = self.dual_source { @@ -333,18 +265,27 @@ impl BrushShader { } self.debug_overdraw.deinit(device); } + + #[cfg(not(feature = "gleam"))] + fn reset(&mut self) { + self.alpha.reset(); + self.opaque.reset(); + if let Some(ref mut dual_source) = self.dual_source { + dual_source.reset(); + } + } } -pub struct TextShader { - simple: LazilyCompiledShader, - glyph_transform: LazilyCompiledShader, - debug_overdraw: LazilyCompiledShader, +pub struct TextShader { + simple: LazilyCompiledShader, + glyph_transform: LazilyCompiledShader, + debug_overdraw: LazilyCompiledShader, } -impl TextShader { +impl TextShader { fn new( name: &'static str, - device: &mut Device, + device: &mut Device, features: &[&'static str], precache_flags: ShaderPrecacheFlags, ) -> Result { @@ -385,7 +326,7 @@ impl TextShader { &mut self, glyph_format: GlyphFormat, debug_flags: DebugFlags, - ) -> &mut LazilyCompiledShader { + ) -> &mut LazilyCompiledShader { match glyph_format { _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => &mut self.debug_overdraw, GlyphFormat::Alpha | @@ -397,72 +338,49 @@ impl TextShader { } } - fn deinit(self, device: &mut Device) { + fn deinit(self, device: &mut Device) { self.simple.deinit(device); self.glyph_transform.deinit(device); self.debug_overdraw.deinit(device); } -} -fn create_prim_shader( - name: &'static str, - device: &mut Device, - features: &[&'static str], -) -> Result { - let mut prefix = format!( - "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n", - MAX_VERTEX_TEXTURE_WIDTH - ); - - for feature in features { - prefix.push_str(&format!("#define WR_FEATURE_{}\n", feature)); + #[cfg(not(feature = "gleam"))] + fn reset(&mut self) { + self.simple.reset(); + self.glyph_transform.reset(); + self.debug_overdraw.reset(); } - - debug!("PrimShader {}", name); - - device.create_program(name, prefix) -} - -fn create_clip_shader(name: &'static str, device: &mut Device) -> Result { - let prefix = format!( - "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n", - MAX_VERTEX_TEXTURE_WIDTH - ); - - debug!("ClipShader {}", name); - - device.create_program(name, prefix) } // NB: If you add a new shader here, make sure to deinitialize it // in `Shaders::deinit()` below. -pub struct Shaders { +pub struct Shaders { // These are "cache shaders". These shaders are used to // draw intermediate results to cache targets. The results // of these shaders are then used by the primitive shaders. - pub cs_blur_a8: LazilyCompiledShader, - pub cs_blur_rgba8: LazilyCompiledShader, - pub cs_border_segment: LazilyCompiledShader, - pub cs_border_solid: LazilyCompiledShader, - pub cs_scale_a8: LazilyCompiledShader, - pub cs_scale_rgba8: LazilyCompiledShader, - pub cs_line_decoration: LazilyCompiledShader, + pub cs_blur_a8: LazilyCompiledShader, + pub cs_blur_rgba8: LazilyCompiledShader, + pub cs_border_segment: LazilyCompiledShader, + pub cs_border_solid: LazilyCompiledShader, + pub cs_scale_a8: LazilyCompiledShader, + pub cs_scale_rgba8: LazilyCompiledShader, + pub cs_line_decoration: LazilyCompiledShader, // Brush shaders - brush_solid: BrushShader, - brush_image: Vec>, - brush_blend: BrushShader, - brush_mix_blend: BrushShader, - brush_yuv_image: Vec>, - brush_radial_gradient: BrushShader, - brush_linear_gradient: BrushShader, + brush_solid: BrushShader, + brush_image: Vec>>, + brush_blend: BrushShader, + brush_mix_blend: BrushShader, + brush_yuv_image: Vec>>, + brush_radial_gradient: BrushShader, + brush_linear_gradient: BrushShader, /// These are "cache clip shaders". These shaders are used to /// draw clip instances into the cached clip mask. The results /// of these shaders are also used by the primitive shaders. - pub cs_clip_rectangle: LazilyCompiledShader, - pub cs_clip_box_shadow: LazilyCompiledShader, - pub cs_clip_image: LazilyCompiledShader, + pub cs_clip_rectangle: LazilyCompiledShader, + pub cs_clip_box_shadow: LazilyCompiledShader, + pub cs_clip_image: LazilyCompiledShader, // The are "primitive shaders". These shaders draw and blend // final results on screen. They are aware of tile boundaries. @@ -471,16 +389,16 @@ pub struct Shaders { // shadow primitive shader stretches the box shadow cache // output, and the cache_image shader blits the results of // a cache shader (e.g. blur) to the screen. - pub ps_text_run: TextShader, - pub ps_text_run_dual_source: TextShader, + pub ps_text_run: TextShader, + pub ps_text_run_dual_source: TextShader, - ps_split_composite: LazilyCompiledShader, + ps_split_composite: LazilyCompiledShader, } -impl Shaders { +impl Shaders { pub fn new( - device: &mut Device, - gl_type: GlType, + device: &mut Device, + _gl_type: GlType, options: &RendererOptions, ) -> Result { let brush_solid = BrushShader::new( @@ -613,7 +531,10 @@ impl Shaders { brush_image.push(None); } for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() { - if IMAGE_BUFFER_KINDS[buffer_kind].has_platform_support(&gl_type) { + if IMAGE_BUFFER_KINDS[buffer_kind].has_platform_support( + #[cfg(feature = "gleam")] + &_gl_type, + ) { let feature_string = IMAGE_BUFFER_KINDS[buffer_kind].get_feature_string(); if feature_string != "" { image_features.push(feature_string); @@ -638,7 +559,10 @@ impl Shaders { brush_yuv_image.push(None); } for image_buffer_kind in &IMAGE_BUFFER_KINDS { - if image_buffer_kind.has_platform_support(&gl_type) { + if image_buffer_kind.has_platform_support( + #[cfg(feature = "gleam")] + &_gl_type, + ) { let feature_string = image_buffer_kind.get_feature_string(); if feature_string != "" { yuv_features.push(feature_string); @@ -719,7 +643,7 @@ impl Shaders { (buffer_kind as usize) } - pub fn get(&mut self, key: &BatchKey, debug_flags: DebugFlags) -> &mut LazilyCompiledShader { + pub fn get(&mut self, key: &BatchKey, debug_flags: DebugFlags) -> &mut LazilyCompiledShader { match key.kind { BatchKind::SplitComposite => { &mut self.ps_split_composite @@ -766,7 +690,39 @@ impl Shaders { } } - pub fn deinit(self, device: &mut Device) { + #[cfg(not(feature = "gleam"))] + pub fn reset(&mut self) { + self.cs_scale_a8.reset(); + self.cs_scale_rgba8.reset(); + self.cs_blur_a8.reset(); + self.cs_blur_rgba8.reset(); + self.brush_solid.reset(); + self.brush_blend.reset(); + self.brush_mix_blend.reset(); + self.brush_radial_gradient.reset(); + self.brush_linear_gradient.reset(); + self.cs_clip_rectangle.reset(); + self.cs_clip_box_shadow.reset(); + self.cs_clip_image.reset(); + self.cs_line_decoration.reset(); + self.ps_text_run.reset(); + self.ps_text_run_dual_source.reset(); + for shader in &mut self.brush_image { + if let Some(ref mut shader) = shader { + shader.reset(); + } + } + for shader in &mut self.brush_yuv_image { + if let Some(ref mut shader) = shader { + shader.reset(); + } + } + self.cs_border_segment.reset(); + self.cs_border_solid.reset(); + self.ps_split_composite.reset(); + } + + pub fn deinit(self, device: &mut Device) { self.cs_scale_a8.deinit(device); self.cs_scale_rgba8.deinit(device); self.cs_blur_a8.deinit(device); @@ -802,6 +758,6 @@ impl Shaders { // object. We have this so that external (ffi) // consumers can own a reference to a shared Shaders // instance without understanding rust's refcounting. -pub struct WrShaders { - pub shaders: Rc>, +pub struct WrShaders { + pub shaders: Rc>>, } diff --git a/webrender/src/spatial_node.rs b/webrender/src/spatial_node.rs index 84f4c02603..e12977e47e 100644 --- a/webrender/src/spatial_node.rs +++ b/webrender/src/spatial_node.rs @@ -69,6 +69,36 @@ pub struct SpatialNode { pub coordinate_system_relative_scale_offset: ScaleOffset, } +fn compute_offset_from( + mut current: Option, + external_id: ExternalScrollId, + previous_spatial_nodes: &[SpatialNode], +) -> LayoutVector2D { + let mut offset = LayoutVector2D::zero(); + while let Some(parent_index) = current { + let ancestor = &previous_spatial_nodes[parent_index.0 as usize]; + match ancestor.node_type { + SpatialNodeType::ReferenceFrame(..) => { + // FIXME(emilio, bug 1523436): Breaking here is technically + // wrong and can happen if the perspective frame is transformed + // as well. + break; + }, + SpatialNodeType::ScrollFrame(ref info) => { + if info.external_id == Some(external_id) { + break; + } + offset += info.offset; + }, + SpatialNodeType::StickyFrame(ref info) => { + offset += info.current_offset; + }, + } + current = ancestor.parent; + } + offset +} + impl SpatialNode { pub fn new( pipeline_id: PipelineId, @@ -221,6 +251,7 @@ impl SpatialNode { state: &mut TransformUpdateState, coord_systems: &mut Vec, scene_properties: &SceneProperties, + previous_spatial_nodes: &[SpatialNode], ) { // If any of our parents was not rendered, we are not rendered either and can just // quit here. @@ -229,7 +260,7 @@ impl SpatialNode { return; } - self.update_transform(state, coord_systems, scene_properties); + self.update_transform(state, coord_systems, scene_properties, previous_spatial_nodes); self.transform_kind = self.world_content_transform.kind(); // If this node is a reference frame, we check if it has a non-invertible matrix. @@ -249,6 +280,7 @@ impl SpatialNode { state: &mut TransformUpdateState, coord_systems: &mut Vec, scene_properties: &SceneProperties, + previous_spatial_nodes: &[SpatialNode], ) { match self.node_type { SpatialNodeType::ReferenceFrame(ref mut info) => { @@ -260,13 +292,20 @@ impl SpatialNode { // Do a change-basis operation on the perspective matrix using // the scroll offset. let source_transform = match info.kind { - ReferenceFrameKind::Perspective => { - // Do a change-basis operation on the perspective matrix - // using the scroll offset. + ReferenceFrameKind::Perspective { scrolling_relative_to: Some(external_id) } => { + let scroll_offset = compute_offset_from( + self.parent, + external_id, + previous_spatial_nodes, + ); + + // Do a change-basis operation on the + // perspective matrix using the scroll offset. source_transform - .pre_translate(&state.parent_accumulated_scroll_offset) - .post_translate(-state.parent_accumulated_scroll_offset) + .pre_translate(&scroll_offset) + .post_translate(-scroll_offset) } + ReferenceFrameKind::Perspective { scrolling_relative_to: None } | ReferenceFrameKind::Transform => source_transform, }; diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index ad99fc9750..90cba381f9 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -468,7 +468,7 @@ pub struct TextureCache { /// A list of allocations and updates that need to be applied to the texture /// cache in the rendering thread this frame. - #[cfg_attr(all(feature = "serde", any(feature = "capture", feature = "replay")), serde(skip))] + #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))] pending_updates: TextureUpdateList, /// The current `FrameStamp`. Used for cache eviction policies. @@ -1563,12 +1563,12 @@ impl TextureCacheUpdate { fn quantize_dimension(size: i32) -> i32 { match size { 0 => unreachable!(), - 1...16 => 16, - 17...32 => 32, - 33...64 => 64, - 65...128 => 128, - 129...256 => 256, - 257...512 => 512, + 1..=16 => 16, + 17..=32 => 32, + 33..=64 => 64, + 65..=128 => 128, + 129..=256 => 256, + 257..=512 => 512, _ => panic!("Invalid dimensions for cache!"), } } diff --git a/webrender/tests/angle_shader_validation.rs b/webrender/tests/angle_shader_validation.rs index b6136753f8..70d3658817 100644 --- a/webrender/tests/angle_shader_validation.rs +++ b/webrender/tests/angle_shader_validation.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![cfg(feature = "gleam")] + extern crate mozangle; extern crate webrender; diff --git a/webrender/tools/glslang-validator-linux b/webrender/tools/glslang-validator-linux new file mode 100755 index 0000000000..e5ce48174d Binary files /dev/null and b/webrender/tools/glslang-validator-linux differ diff --git a/webrender/tools/glslang-validator-mac b/webrender/tools/glslang-validator-mac new file mode 100755 index 0000000000..c20b774ac8 Binary files /dev/null and b/webrender/tools/glslang-validator-mac differ diff --git a/webrender/tools/glslang-validator-win.exe b/webrender/tools/glslang-validator-win.exe new file mode 100644 index 0000000000..0932d7f41e Binary files /dev/null and b/webrender/tools/glslang-validator-win.exe differ diff --git a/webrender/tools/spirv-val-linux b/webrender/tools/spirv-val-linux new file mode 100755 index 0000000000..9c1015d57d Binary files /dev/null and b/webrender/tools/spirv-val-linux differ diff --git a/webrender/tools/spirv-val-mac b/webrender/tools/spirv-val-mac new file mode 100755 index 0000000000..990f999a0a Binary files /dev/null and b/webrender/tools/spirv-val-mac differ diff --git a/webrender/tools/spirv-val-win.exe b/webrender/tools/spirv-val-win.exe new file mode 100644 index 0000000000..bf1b4aea83 Binary files /dev/null and b/webrender/tools/spirv-val-win.exe differ diff --git a/webrender_api/Cargo.toml b/webrender_api/Cargo.toml index 967c8b14f4..e79b7cff30 100644 --- a/webrender_api/Cargo.toml +++ b/webrender_api/Cargo.toml @@ -26,6 +26,7 @@ serde_derive = { version = "=1.0.80", features = ["deserialize_in_place"] } serde_bytes = "0.10" time = "0.1" wr_malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of" } +gfx-hal = "0.3.1" [target.'cfg(target_os = "macos")'.dependencies] core-foundation = "0.6" diff --git a/webrender_api/src/api.rs b/webrender_api/src/api.rs index ded6c95ddd..cdbbec6ba5 100644 --- a/webrender_api/src/api.rs +++ b/webrender_api/src/api.rs @@ -1398,7 +1398,7 @@ pub struct DynamicProperties { } pub trait RenderNotifier: Send { - fn clone(&self) -> Box; + fn clone(&self) -> Box; fn wake_up(&self); fn new_frame_ready(&self, DocumentId, scrolled: bool, composite_needed: bool, render_time_ns: Option); fn external_event(&self, _evt: ExternalEvent) { @@ -1424,12 +1424,12 @@ pub trait NotificationHandler : Send + Sync { } pub struct NotificationRequest { - handler: Option>, + handler: Option>, when: Checkpoint, } impl NotificationRequest { - pub fn new(when: Checkpoint, handler: Box) -> Self { + pub fn new(when: Checkpoint, handler: Box) -> Self { NotificationRequest { handler: Some(handler), when, diff --git a/webrender_api/src/color.rs b/webrender_api/src/color.rs index abdacd7110..1291694b79 100644 --- a/webrender_api/src/color.rs +++ b/webrender_api/src/color.rs @@ -123,7 +123,7 @@ impl ColorU { } } -fn round_to_int(x: f32) -> u8 { +pub fn round_to_int(x: f32) -> u8 { debug_assert!((0.0 <= x) && (x <= 1.0)); let f = (255.0 * x) + 0.5; let val = f.floor(); diff --git a/webrender_api/src/display_item.rs b/webrender_api/src/display_item.rs index 65c9db5969..457c5377c2 100644 --- a/webrender_api/src/display_item.rs +++ b/webrender_api/src/display_item.rs @@ -526,10 +526,11 @@ pub struct CacheMarkerDisplayItem { } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] -#[repr(u8)] pub enum ReferenceFrameKind { Transform, - Perspective, + Perspective { + scrolling_relative_to: Option, + } } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] @@ -949,6 +950,7 @@ impl SpatialId { /// When setting display lists with the `preserve_frame_state` this id is used to preserve scroll /// offsets between different sets of ClipScrollNodes which are ScrollFrames. #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[repr(C)] pub struct ExternalScrollId(pub u64, pub PipelineId); impl ExternalScrollId { diff --git a/webrender_api/src/image.rs b/webrender_api/src/image.rs index 6ce0401a1e..29c35a5cb5 100644 --- a/webrender_api/src/image.rs +++ b/webrender_api/src/image.rs @@ -74,6 +74,18 @@ pub enum TextureTarget { External = 3, } +impl From for TextureTarget { + fn from(target: u32) -> Self { + match target { + 0 => TextureTarget::Default, + 1 => TextureTarget::Array, + 2 => TextureTarget::Rect, + 3 => TextureTarget::External, + _ => unimplemented!(), + } + } +} + /// Storage format identifier for externally-managed images. #[repr(u32)] #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -135,6 +147,20 @@ impl ImageFormat { } } +impl From for gfx_hal::format::Format { + fn from(image_format: ImageFormat) -> gfx_hal::format::Format { + match image_format { + ImageFormat::R8 => gfx_hal::format::Format::R8Unorm, + ImageFormat::R16 => gfx_hal::format::Format::R16Unorm, + ImageFormat::RG8 => gfx_hal::format::Format::Rg8Unorm, + ImageFormat::RGBA8 => gfx_hal::format::Format::Rgba8Unorm, + ImageFormat::BGRA8 => gfx_hal::format::Format::Bgra8Unorm, + ImageFormat::RGBAF32 => gfx_hal::format::Format::Rgba32Sfloat, + ImageFormat::RGBAI32 => gfx_hal::format::Format::Rgba32Sint, + } + } +} + /// Specifies the color depth of an image. Currently only used for YUV images. #[repr(u8)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] @@ -293,13 +319,13 @@ pub trait BlobImageResources { /// and creating the rasterizer objects, but isn't expected to do any rasterization itself. pub trait BlobImageHandler: Send { /// Creates a snapshot of the current state of blob images in the handler. - fn create_blob_rasterizer(&mut self) -> Box; + fn create_blob_rasterizer(&mut self) -> Box; /// A hook to let the blob image handler update any state related to resources that /// are not bundled in the blob recording itself. fn prepare_resources( &mut self, - services: &BlobImageResources, + services: &dyn BlobImageResources, requests: &[BlobImageParams], ); diff --git a/webrender_api/src/lib.rs b/webrender_api/src/lib.rs index 404c0d3134..e159ee6361 100644 --- a/webrender_api/src/lib.rs +++ b/webrender_api/src/lib.rs @@ -28,6 +28,7 @@ extern crate core_graphics; #[macro_use] extern crate derive_more; pub extern crate euclid; +extern crate gfx_hal; #[cfg(feature = "ipc")] extern crate ipc_channel; #[macro_use] diff --git a/wrench/Cargo.toml b/wrench/Cargo.toml index 764742b474..4c7a04a6ae 100644 --- a/wrench/Cargo.toml +++ b/wrench/Cargo.toml @@ -9,10 +9,14 @@ license = "MPL-2.0" base64 = "0.10" bincode = "1.0" byteorder = "1.0" +cfg-if = "0.1.2" +dirs = { version = "1.0", optional = true } env_logger = { version = "0.5", optional = true } euclid = "0.19" -gleam = "0.6.2" -glutin = "0.17" +gfx-backend-empty = "0.3.0" +gfx-hal = "0.3.1" +gleam = { optional = true, version = "0.6.2" } +glutin = { optional = true, version = "0.20" } app_units = "0.7" image = "0.21" clap = { version = "2", features = ["yaml"] } @@ -20,14 +24,14 @@ lazy_static = "1" log = "0.4" yaml-rust = "0.4" serde_json = "1.0" -ron = "0.1.5" +ron = "0.1.7" time = "0.1" crossbeam = "0.2" osmesa-sys = { version = "0.1.2", optional = true } osmesa-src = { git = "https://github.com/servo/osmesa-src", optional = true } webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler"]} webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]} -winit = "0.16" +winit = "0.19" serde = {version = "1.0", features = ["derive"] } [target.'cfg(target_os = "macos")'.dependencies] @@ -35,12 +39,29 @@ core-graphics = "0.17.1" core-foundation = "0.6" [features] -headless = [ "osmesa-sys", "osmesa-src" ] -pathfinder = [ "webrender/pathfinder" ] +default = [] +headless = ["gl", "osmesa-sys", "osmesa-src"] +pathfinder = ["webrender/pathfinder"] +gfx = ["dirs"] +gl = ["gleam", "glutin", "mozangle", "webrender/gleam"] +dx12 = ["gfx-backend-dx12", "gfx"] +metal = ["gfx-backend-metal", "gfx"] +vulkan = ["gfx-backend-vulkan", "gfx"] [target.'cfg(target_os = "windows")'.dependencies] dwrote = "0.8" -mozangle = {version = "0.1.5", features = ["egl"]} +gfx-backend-dx12 = { version = "0.3.4", optional = true, features = ["winit"] } +mozangle = {version = "0.1.5", optional = true, features = ["egl"] } + +[target.'cfg(target_os = "macos")'.dependencies.gfx-backend-metal] +version = "0.3.3" +optional = true +features = ["winit"] + +[target.'cfg(all(any(unix, windows), not(target_os = "macos")))'.dependencies.gfx-backend-vulkan] +version = "0.3.3" +optional = true +features = ["winit", "x11"] [target.'cfg(all(unix, not(target_os = "android")))'.dependencies] font-loader = "0.7" diff --git a/wrench/reftests/boxshadow/box-shadow-large-blur-radius-3.png b/wrench/reftests/boxshadow/box-shadow-large-blur-radius-3.png index 0616288708..db6400c8a7 100644 Binary files a/wrench/reftests/boxshadow/box-shadow-large-blur-radius-3.png and b/wrench/reftests/boxshadow/box-shadow-large-blur-radius-3.png differ diff --git a/wrench/reftests/boxshadow/inset-alpha.png b/wrench/reftests/boxshadow/inset-alpha.png index 6b5299f386..4da7a86857 100644 Binary files a/wrench/reftests/boxshadow/inset-alpha.png and b/wrench/reftests/boxshadow/inset-alpha.png differ diff --git a/wrench/reftests/boxshadow/inset-border-radius.png b/wrench/reftests/boxshadow/inset-border-radius.png index 1a20ed7d8e..4daa415c99 100644 Binary files a/wrench/reftests/boxshadow/inset-border-radius.png and b/wrench/reftests/boxshadow/inset-border-radius.png differ diff --git a/wrench/reftests/boxshadow/inset-downscale.png b/wrench/reftests/boxshadow/inset-downscale.png index d68c028566..40534805e1 100644 Binary files a/wrench/reftests/boxshadow/inset-downscale.png and b/wrench/reftests/boxshadow/inset-downscale.png differ diff --git a/wrench/reftests/boxshadow/inset-neg-offset.png b/wrench/reftests/boxshadow/inset-neg-offset.png index 364195644c..462d46f850 100644 Binary files a/wrench/reftests/boxshadow/inset-neg-offset.png and b/wrench/reftests/boxshadow/inset-neg-offset.png differ diff --git a/wrench/reftests/boxshadow/inset-offset.png b/wrench/reftests/boxshadow/inset-offset.png index d04c6b0516..fed26f950e 100644 Binary files a/wrench/reftests/boxshadow/inset-offset.png and b/wrench/reftests/boxshadow/inset-offset.png differ diff --git a/wrench/reftests/boxshadow/overlap1.png b/wrench/reftests/boxshadow/overlap1.png index 5cfad1ae53..0ab363f03f 100644 Binary files a/wrench/reftests/boxshadow/overlap1.png and b/wrench/reftests/boxshadow/overlap1.png differ diff --git a/wrench/reftests/filters/filter-drop-shadow-clip.png b/wrench/reftests/filters/filter-drop-shadow-clip.png index c35b7f6549..63ff91b42a 100644 Binary files a/wrench/reftests/filters/filter-drop-shadow-clip.png and b/wrench/reftests/filters/filter-drop-shadow-clip.png differ diff --git a/wrench/reftests/filters/filter-drop-shadow-on-viewport-edge.png b/wrench/reftests/filters/filter-drop-shadow-on-viewport-edge.png index 8ca7e89358..f4c6cdbac7 100644 Binary files a/wrench/reftests/filters/filter-drop-shadow-on-viewport-edge.png and b/wrench/reftests/filters/filter-drop-shadow-on-viewport-edge.png differ diff --git a/wrench/reftests/filters/filter-drop-shadow.png b/wrench/reftests/filters/filter-drop-shadow.png index 893ef2d711..c0a230401f 100644 Binary files a/wrench/reftests/filters/filter-drop-shadow.png and b/wrench/reftests/filters/filter-drop-shadow.png differ diff --git a/wrench/reftests/filters/filter-large-blur-radius.png b/wrench/reftests/filters/filter-large-blur-radius.png index c72689dff5..6cb486b302 100644 Binary files a/wrench/reftests/filters/filter-large-blur-radius.png and b/wrench/reftests/filters/filter-large-blur-radius.png differ diff --git a/wrench/reftests/split/gradient-ref.yaml b/wrench/reftests/split/gradient-ref.yaml new file mode 100644 index 0000000000..5a461c737d --- /dev/null +++ b/wrench/reftests/split/gradient-ref.yaml @@ -0,0 +1,39 @@ +# Checks the UV interpolation of a preserved 3d stacking context matches +# a flat stacking context. There are four black rectangles that overlap +# the edges of the transformed gradient to minimize fuzz. +--- +root: + items: + - type: "reference-frame" + bounds: [0, 0, 2746, 1408] + transform-style: flat + perspective: [1, 0, 0, 0, 0, 1, 0, 0, -0.4699999988079071, -0.44999998807907104, 1, -0.0012499999720603228, 176, 160, 0, 1] + items: + - type: "reference-frame" + bounds: [0, 0, 2746, 1408] + transform-style: flat + transform: rotate-y(-53) + items: + - type: "stacking-context" + transform-style: flat + items: + - type: rect + bounds: [0, 0, 300, 300] + color: 255 255 255 1.0000 + - type: gradient + bounds: [0, 0, 300, 150] + start: [150, 0] + end: [150, 150] + stops: [0.0, [255, 0, 0, 1], 1.0, [254, 0, 0, 1]] + - type: rect + bounds: [520, 260, 120, 20] + color: 0 0 0 1.0000 + - type: rect + bounds: [520, 336, 120, 3] + color: 0 0 0 1.0000 + - type: rect + bounds: [520, 260, 10, 80] + color: 0 0 0 1.0000 + - type: rect + bounds: [622, 260, 10, 80] + color: 0 0 0 1.0000 diff --git a/wrench/reftests/split/gradient.yaml b/wrench/reftests/split/gradient.yaml new file mode 100644 index 0000000000..8da777df03 --- /dev/null +++ b/wrench/reftests/split/gradient.yaml @@ -0,0 +1,42 @@ +# Checks the UV interpolation of a preserved 3d stacking context matches +# a flat stacking context. There are four black rectangles that overlap +# the edges of the transformed gradient to minimize fuzz. +--- +root: + items: + - type: "reference-frame" + bounds: [0, 0, 2746, 1408] + transform-style: preserve-3d + perspective: [1, 0, 0, 0, 0, 1, 0, 0, -0.4699999988079071, -0.44999998807907104, 1, -0.0012499999720603228, 176, 160, 0, 1] + items: + - type: "reference-frame" + bounds: [0, 0, 2746, 1408] + transform-style: preserve-3d + transform: rotate-y(-53) + items: + - type: "stacking-context" + transform-style: preserve-3d + items: + - type: "stacking-context" + transform-style: flat + items: + - type: rect + bounds: [0, 0, 300, 300] + color: 255 255 255 1.0000 + - type: gradient + bounds: [0, 0, 300, 150] + start: [150, 0] + end: [150, 150] + stops: [0.0, [255, 0, 0, 1], 1.0, [254, 0, 0, 1]] + - type: rect + bounds: [520, 260, 120, 20] + color: 0 0 0 1.0000 + - type: rect + bounds: [520, 336, 120, 3] + color: 0 0 0 1.0000 + - type: rect + bounds: [520, 260, 10, 80] + color: 0 0 0 1.0000 + - type: rect + bounds: [622, 260, 10, 80] + color: 0 0 0 1.0000 diff --git a/wrench/reftests/split/reftest.list b/wrench/reftests/split/reftest.list index 1ba3988d30..b84b6e6de9 100644 --- a/wrench/reftests/split/reftest.list +++ b/wrench/reftests/split/reftest.list @@ -16,3 +16,4 @@ platform(linux,mac) fuzzy(1,20) == same-plane.yaml same-plane.png #== cross.yaml cross-ref.yaml == mixed-order.yaml mixed-order-ref.yaml fuzzy(1,40000) == filter.yaml filter-ref.yaml +fuzzy(1,10000) == gradient.yaml gradient-ref.yaml diff --git a/wrench/reftests/transforms/perspective-shadow.png b/wrench/reftests/transforms/perspective-shadow.png index 325fffbb34..dbf323e536 100644 Binary files a/wrench/reftests/transforms/perspective-shadow.png and b/wrench/reftests/transforms/perspective-shadow.png differ diff --git a/wrench/reftests/transforms/prim-suite.png b/wrench/reftests/transforms/prim-suite.png index f8ebdfad36..3f7d122015 100644 Binary files a/wrench/reftests/transforms/prim-suite.png and b/wrench/reftests/transforms/prim-suite.png differ diff --git a/wrench/script/headless.py b/wrench/script/headless.py index ced6c1a133..206141a564 100755 --- a/wrench/script/headless.py +++ b/wrench/script/headless.py @@ -67,7 +67,7 @@ def set_osmesa_env(bin_path): extra_flags = os.getenv('CARGOFLAGS', None) extra_flags = extra_flags.split(' ') if extra_flags else [] -subprocess.check_call(['cargo', 'build'] + extra_flags + ['--release', '--verbose', '--features', 'headless']) +subprocess.check_call(['cargo', 'build'] + extra_flags + ['--release', '--verbose', '--features', 'gl,headless']) set_osmesa_env('../target/release/') # TODO(gw): We have an occasional accuracy issue or bug (could be WR or OSMesa) # where the output of a previous test that uses intermediate targets can diff --git a/wrench/src/angle.rs b/wrench/src/angle.rs index 5899088c2f..44e20a54ed 100644 --- a/wrench/src/angle.rs +++ b/wrench/src/angle.rs @@ -42,32 +42,32 @@ impl Context { } #[cfg(not(windows))] -impl glutin::GlContext for Context { - unsafe fn make_current(&self) -> Result<(), glutin::ContextError> { +impl Context { + pub unsafe fn make_current(&self) -> Result<(), glutin::ContextError> { match *self {} } - fn is_current(&self) -> bool { + pub fn is_current(&self) -> bool { match *self {} } - fn get_proc_address(&self, _: &str) -> *const () { + pub fn get_proc_address(&self, _: &str) -> *const () { match *self {} } - fn swap_buffers(&self) -> Result<(), glutin::ContextError> { + pub fn swap_buffers(&self) -> Result<(), glutin::ContextError> { match *self {} } - fn get_api(&self) -> glutin::Api { + pub fn get_api(&self) -> glutin::Api { match *self {} } - fn get_pixel_format(&self) -> glutin::PixelFormat { + pub fn get_pixel_format(&self) -> glutin::PixelFormat { match *self {} } - fn resize(&self, _: PhysicalSize) { + pub fn resize(&self, _: PhysicalSize) { match *self {} } } diff --git a/wrench/src/args.yaml b/wrench/src/args.yaml index 8f154f4946..7bb526a18b 100644 --- a/wrench/src/args.yaml +++ b/wrench/src/args.yaml @@ -71,6 +71,11 @@ args: long: chase help: Chase a particular primitive matching the local rect takes_value: true + - descriptor_count: + short: d + long: descriptor-count + help: Set the decsriptor count for descriptor pools when running with gfx + takes_value: true subcommands: - png: diff --git a/wrench/src/blob.rs b/wrench/src/blob.rs index 6c6e269b5d..0cd4e0affe 100644 --- a/wrench/src/blob.rs +++ b/wrench/src/blob.rs @@ -104,7 +104,7 @@ fn render_blob( /// See rawtest.rs. We use this to test that blob images are requested the right /// amount of times. pub struct BlobCallbacks { - pub request: Box, + pub request: Box, } impl BlobCallbacks { @@ -151,7 +151,7 @@ impl BlobImageHandler for CheckerboardRenderer { fn prepare_resources( &mut self, - _services: &BlobImageResources, + _services: &dyn BlobImageResources, requests: &[BlobImageParams], ) { if !requests.is_empty() { @@ -159,7 +159,7 @@ impl BlobImageHandler for CheckerboardRenderer { } } - fn create_blob_rasterizer(&mut self) -> Box { + fn create_blob_rasterizer(&mut self) -> Box { Box::new(Rasterizer { image_cmds: self.image_cmds.clone() }) } } diff --git a/wrench/src/egl.rs b/wrench/src/egl.rs index 35dbd3b6c6..a302b574d8 100644 --- a/wrench/src/egl.rs +++ b/wrench/src/egl.rs @@ -3,12 +3,12 @@ //! Based on https://github.com/tomaka/glutin/blob/1b2d62c0e9/src/api/egl/mod.rs #![cfg(windows)] +#![cfg(feature = "gl")] #![allow(unused_variables)] use glutin::ContextError; use glutin::CreationError; use glutin::GlAttributes; -use glutin::GlContext; use glutin::GlRequest; use glutin::PixelFormat; use glutin::PixelFormatRequirements; @@ -147,8 +147,8 @@ impl Context { } } -impl GlContext for Context { - unsafe fn make_current(&self) -> Result<(), ContextError> { +impl Context { + pub unsafe fn make_current(&self) -> Result<(), ContextError> { let ret = egl::MakeCurrent(self.display, self.surface.get(), self.surface.get(), self.context); if ret == 0 { @@ -163,11 +163,11 @@ impl GlContext for Context { } #[inline] - fn is_current(&self) -> bool { + pub fn is_current(&self) -> bool { unsafe { egl::GetCurrentContext() == self.context } } - fn get_proc_address(&self, addr: &str) -> *const () { + pub fn get_proc_address(&self, addr: &str) -> *const () { let addr = CString::new(addr.as_bytes()).unwrap(); let addr = addr.as_ptr(); unsafe { @@ -176,7 +176,7 @@ impl GlContext for Context { } #[inline] - fn swap_buffers(&self) -> Result<(), ContextError> { + pub fn swap_buffers(&self) -> Result<(), ContextError> { if self.surface.get() == ffi::egl::NO_SURFACE { return Err(ContextError::ContextLost); } @@ -197,17 +197,17 @@ impl GlContext for Context { } #[inline] - fn get_api(&self) -> Api { + pub fn get_api(&self) -> Api { self.api } #[inline] - fn get_pixel_format(&self) -> PixelFormat { + pub fn get_pixel_format(&self) -> PixelFormat { self.pixel_format.clone() } #[inline] - fn resize(&self, _: PhysicalSize) {} + pub fn resize(&self, _: PhysicalSize) {} } unsafe impl Send for Context {} diff --git a/wrench/src/main.rs b/wrench/src/main.rs index 82cdd10bdb..13a4c4cbfa 100644 --- a/wrench/src/main.rs +++ b/wrench/src/main.rs @@ -2,17 +2,26 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![cfg_attr( + not(any(feature = "gfx", feature = "gl")), + allow(dead_code, unused_extern_crates, unused_imports, unused_variables) +)] + extern crate app_units; extern crate base64; extern crate bincode; extern crate byteorder; #[macro_use] +extern crate cfg_if; +#[macro_use] extern crate clap; #[cfg(target_os = "macos")] extern crate core_foundation; #[cfg(target_os = "macos")] extern crate core_graphics; extern crate crossbeam; +#[cfg(feature = "gfx")] +extern crate dirs; #[cfg(target_os = "windows")] extern crate dwrote; #[cfg(feature = "env_logger")] @@ -20,14 +29,13 @@ extern crate env_logger; extern crate euclid; #[cfg(all(unix, not(target_os = "android")))] extern crate font_loader; -extern crate gleam; -extern crate glutin; +extern crate gfx_hal; extern crate image; #[macro_use] extern crate lazy_static; #[macro_use] extern crate log; -#[cfg(target_os = "windows")] +#[cfg(all(target_os = "windows", feature = "gl"))] extern crate mozangle; #[cfg(feature = "headless")] extern crate osmesa_sys; @@ -40,10 +48,35 @@ extern crate webrender; extern crate winit; extern crate yaml_rust; -mod angle; +cfg_if! { + if #[cfg(feature = "dx12")] { + extern crate gfx_backend_dx12 as back; + use gfx_hal::Instance; + } else if #[cfg(feature = "metal")] { + extern crate gfx_backend_metal as back; + use gfx_hal::Instance; + } else if #[cfg(feature = "vulkan")] { + extern crate gfx_backend_vulkan as back; + use gfx_hal::Instance; + } else if #[cfg(feature = "gl")] { + extern crate gfx_backend_empty as back; + extern crate gleam; + extern crate glutin; + mod angle; + mod egl; + use gleam::gl; + use glutin::ContextTrait; + use std::marker::PhantomData; + use std::os::raw::c_void; + use std::ptr; + use std::rc::Rc; + } else { + extern crate gfx_backend_empty as back; + } +} + mod binary_frame_reader; mod blob; -mod egl; mod json_frame_writer; mod parse_function; mod perf; @@ -61,8 +94,6 @@ mod yaml_helper; mod cgfont_to_data; use binary_frame_reader::BinaryFrameReader; -use gleam::gl; -use glutin::GlContext; use perf::PerfHarness; use png::save_flipped; use rawtest::RawtestHarness; @@ -71,11 +102,8 @@ use reftest::{ReftestHarness, ReftestOptions}; use std::ffi::CString; #[cfg(feature = "headless")] use std::mem; -use std::os::raw::c_void; use std::path::{Path, PathBuf}; use std::process; -use std::ptr; -use std::rc::Rc; use std::sync::mpsc::{channel, Sender, Receiver}; use webrender::DebugFlags; use webrender::api::*; @@ -90,7 +118,7 @@ lazy_static! { pub static mut CURRENT_FRAME_NUMBER: u32 = 0; -#[cfg(feature = "headless")] +#[cfg(all(feature = "headless", not(feature = "gfx")))] pub struct HeadlessContext { width: i32, height: i32, @@ -98,14 +126,14 @@ pub struct HeadlessContext { _buffer: Vec, } -#[cfg(not(feature = "headless"))] +#[cfg(any(not(feature = "headless"), feature = "gfx"))] pub struct HeadlessContext { width: i32, height: i32, } impl HeadlessContext { - #[cfg(feature = "headless")] + #[cfg(all(feature = "headless", not(feature = "gfx")))] fn new(width: i32, height: i32) -> Self { let mut attribs = Vec::new(); @@ -145,37 +173,48 @@ impl HeadlessContext { } } - #[cfg(not(feature = "headless"))] + #[cfg(any(not(feature = "headless"), feature = "gfx"))] fn new(width: i32, height: i32) -> Self { HeadlessContext { width, height } } - #[cfg(feature = "headless")] + #[cfg(all(feature = "gl", feature = "headless"))] fn get_proc_address(s: &str) -> *const c_void { let c_str = CString::new(s).expect("Unable to create CString"); unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) } } - #[cfg(not(feature = "headless"))] + #[cfg(all(feature = "gl", not(feature = "headless")))] fn get_proc_address(_: &str) -> *const c_void { ptr::null() as *const _ } } +#[cfg(feature = "gfx")] pub enum WindowWrapper { - Window(glutin::GlWindow, Rc), - Angle(winit::Window, angle::Context, Rc), - Headless(HeadlessContext, Rc), + Window(winit::Window), + Headless(HeadlessContext), +} + +#[cfg(not(any(feature = "gfx", feature = "gl")))] +pub enum WindowWrapper {} + +#[cfg(feature = "gl")] +pub enum WindowWrapper { + Window(glutin::WindowedContext, Rc), + Angle(winit::Window, angle::Context, Rc), + Headless(HeadlessContext, Rc), } pub struct HeadlessEventIterater; impl WindowWrapper { fn swap_buffers(&self) { + #[cfg(feature = "gl")] match *self { WindowWrapper::Window(ref window, _) => window.swap_buffers().unwrap(), WindowWrapper::Angle(_, ref context, _) => context.swap_buffers().unwrap(), - WindowWrapper::Headless(_, _) => {} + WindowWrapper::Headless(..) => {} } } @@ -187,42 +226,61 @@ impl WindowWrapper { .to_physical(window.get_hidpi_factor()); DeviceIntSize::new(size.width as i32, size.height as i32) } + #[cfg(feature = "gfx")] + match *self { + WindowWrapper::Window(ref window) => inner_size(window), + WindowWrapper::Headless(ref context) => DeviceIntSize::new(context.width, context.height), + } + + #[cfg(feature = "gl")] match *self { WindowWrapper::Window(ref window, _) => inner_size(window.window()), WindowWrapper::Angle(ref window, ..) => inner_size(window), WindowWrapper::Headless(ref context, _) => DeviceIntSize::new(context.width, context.height), } + + #[cfg(not(any(feature = "gfx", feature = "gl")))] + DeviceIntSize::zero() } fn hidpi_factor(&self) -> f32 { + #[cfg(any(feature = "gfx", feature = "gl"))] match *self { - WindowWrapper::Window(ref window, _) => window.get_hidpi_factor() as f32, + WindowWrapper::Window(ref window, ..) => window.get_hidpi_factor() as f32, + WindowWrapper::Headless(..) => 1.0, + #[cfg(feature = "gl")] WindowWrapper::Angle(ref window, ..) => window.get_hidpi_factor() as f32, - WindowWrapper::Headless(_, _) => 1.0, } + #[cfg(not(any(feature = "gfx", feature = "gl")))] + 0.0 } fn resize(&mut self, size: DeviceIntSize) { + #[cfg(any(feature = "gfx", feature = "gl"))] match *self { - WindowWrapper::Window(ref mut window, _) => { + WindowWrapper::Window(ref mut window, ..) => { window.set_inner_size(LogicalSize::new(size.width as f64, size.height as f64)) }, + WindowWrapper::Headless(..) => unimplemented!(), // requites Glutin update + #[cfg(feature = "gl")] WindowWrapper::Angle(ref mut window, ..) => { window.set_inner_size(LogicalSize::new(size.width as f64, size.height as f64)) }, - WindowWrapper::Headless(_, _) => unimplemented!(), // requites Glutin update } } fn set_title(&mut self, title: &str) { + #[cfg(any(feature = "gfx", feature = "gl"))] match *self { - WindowWrapper::Window(ref window, _) => window.set_title(title), + WindowWrapper::Window(ref window, ..) => window.set_title(title), + WindowWrapper::Headless(..) => (), + #[cfg(feature = "gl")] WindowWrapper::Angle(ref window, ..) => window.set_title(title), - WindowWrapper::Headless(_, _) => (), } } - pub fn gl(&self) -> &gl::Gl { + #[cfg(feature = "gl")] + pub fn gl(&self) -> &dyn gl::Gl { match *self { WindowWrapper::Window(_, ref gl) | WindowWrapper::Angle(_, _, ref gl) | @@ -230,15 +288,25 @@ impl WindowWrapper { } } - pub fn clone_gl(&self) -> Rc { + #[cfg(feature = "gl")] + pub fn clone_gl(&self) -> Rc { match *self { WindowWrapper::Window(_, ref gl) | WindowWrapper::Angle(_, _, ref gl) | WindowWrapper::Headless(_, ref gl) => gl.clone(), } } + + #[cfg(feature = "gfx")] + fn get_window(&self) -> Option<&winit::Window> { + match *self { + WindowWrapper::Window(ref window) => Some(&window), + WindowWrapper::Headless(..) => None, + } + } } +#[cfg(feature = "gl")] fn make_window( size: DeviceIntSize, dp_ratio: Option, @@ -259,7 +327,25 @@ fn make_window( .with_multitouch() .with_dimensions(LogicalSize::new(size.width as f64, size.height as f64)); - let init = |context: &glutin::GlContext| { + let init = |context: &glutin::WindowedContext| { + unsafe { + context + .make_current() + .expect("unable to make context current!"); + } + + match context.get_api() { + glutin::Api::OpenGl => unsafe { + gl::GlFns::load_with(|symbol| context.get_proc_address(symbol) as *const _) + }, + glutin::Api::OpenGlEs => unsafe { + gl::GlesFns::load_with(|symbol| context.get_proc_address(symbol) as *const _) + }, + glutin::Api::WebGl => unimplemented!(), + } + }; + + let _init_angle = |context: &angle::Context| { unsafe { context .make_current() @@ -278,13 +364,13 @@ fn make_window( }; if angle { - let (window, context) = angle::Context::with_window( + let (_window, _context) = angle::Context::with_window( window_builder, context_builder, events_loop ).unwrap(); - let gl = init(&context); - WindowWrapper::Angle(window, context, gl) + let gl = _init_angle(&_context); + WindowWrapper::Angle(_window, _context, gl) } else { - let window = glutin::GlWindow::new(window_builder, context_builder, events_loop) + let window = glutin::WindowedContext::new_windowed(window_builder, context_builder, events_loop) .unwrap(); let gl = init(&window); WindowWrapper::Window(window, gl) @@ -323,6 +409,36 @@ fn make_window( wrapper } +#[cfg(feature = "gfx")] +fn make_window( + size: DeviceIntSize, + dp_ratio: Option, + _vsync: bool, + events_loop: &Option, + _angle: bool, +) -> WindowWrapper { + let lsize = LogicalSize::new(size.width as f64, size.height as f64); + let wrapper = match *events_loop { + Some(ref events_loop) => { + let window = winit::WindowBuilder::new() + .with_title("WRench") + .with_multitouch() + .with_dimensions(lsize) + .build(events_loop).unwrap(); + WindowWrapper::Window(window) + }, + None => WindowWrapper::Headless(HeadlessContext::new(size.width, size.height)), + }; + + let dp_ratio = dp_ratio.unwrap_or(wrapper.hidpi_factor()); + println!( + "hidpi factor: {} (native {})", + dp_ratio, + wrapper.hidpi_factor() + ); + wrapper +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum NotifierEvent { WakeUp, @@ -335,7 +451,7 @@ struct Notifier { // setup a notifier so we can wait for frames to be finished impl RenderNotifier for Notifier { - fn clone(&self) -> Box { + fn clone(&self) -> Box { Box::new(Notifier { tx: self.tx.clone(), }) @@ -360,7 +476,7 @@ impl RenderNotifier for Notifier { } } -fn create_notifier() -> (Box, Receiver) { +fn create_notifier() -> (Box, Receiver) { let (tx, rx) = channel(); (Box::new(Notifier { tx: tx }), rx) } @@ -390,6 +506,7 @@ fn reftest<'a>( num_failures } +#[cfg(any(feature = "gfx", feature = "gl"))] fn main() { #[cfg(feature = "env_logger")] env_logger::init(); @@ -428,7 +545,7 @@ fn main() { let zoom_factor = args.value_of("zoom").map(|z| z.parse::().unwrap()); let chase_primitive = match args.value_of("chase") { Some(s) => { - let mut items = s + let items = s .split(',') .map(|s| s.parse::().unwrap()) .collect::>(); @@ -450,8 +567,13 @@ fn main() { let mut window = make_window( size, dp_ratio, args.is_present("vsync"), &events_loop, args.is_present("angle"), ); - let dp_ratio = dp_ratio.unwrap_or(window.hidpi_factor()); - let dim = window.get_inner_size(); + let mut dim = size; + let dp_ratio = if args.is_present("headless") { + dp_ratio.unwrap_or(1.0) + } else { + dim = window.get_inner_size(); + dp_ratio.unwrap_or(window.hidpi_factor()) + }; let needs_frame_notifier = ["perf", "reftest", "png", "rawtest"] .iter() @@ -463,8 +585,46 @@ fn main() { (None, None) }; + #[cfg(feature = "gfx")] + let init = { + let cache_dir = dirs::cache_dir().expect("User's cache directory not found"); + let cache_path = Some(PathBuf::from(&cache_dir).join("pipeline_cache.bin")); + let instance = back::Instance::create("gfx-rs instance", 1); + let adapter = instance.enumerate_adapters().remove(0); + let surface = if args.is_present("headless") { + None + } else { + let surface = instance.create_surface(window.get_window().unwrap()); + dim = window.get_inner_size(); + Some(surface) + }; + + #[cfg(feature = "vulkan")] + let backend_api = webrender::BackendApiType::Vulkan; + #[cfg(feature = "metal")] + let backend_api = webrender::BackendApiType::Metal; + #[cfg(feature = "dx12")] + let backend_api = webrender::BackendApiType::Dx12; + + webrender::DeviceInit { + instance: Box::new(instance), + adapter, + surface, + window_size: (dim.width, dim.height), + descriptor_count: args.value_of("descriptor_count").map(|d| d.parse::().unwrap()), + cache_path, + save_cache: true, + backend_api, + } + }; + + #[cfg(feature = "gl")] + let init = webrender::DeviceInit { + gl: window.clone_gl(), + phantom_data: PhantomData, + }; + let mut wrench = Wrench::new( - &mut window, events_loop.as_mut().map(|el| el.create_proxy()), res_path, dp_ratio, @@ -480,10 +640,11 @@ fn main() { zoom_factor.unwrap_or(1.0), chase_primitive, notifier, + init, ); if let Some(window_title) = wrench.take_title() { - if !cfg!(windows) { + if cfg!(not(windows)) { window.set_title(&window_title); } } @@ -500,7 +661,8 @@ fn main() { png::png(&mut wrench, surface, &mut window, reader, rx.unwrap()); } else if let Some(subargs) = args.subcommand_matches("reftest") { // Exit with an error code in order to ensure the CI job fails. - process::exit(reftest(wrench, &mut window, subargs, rx.unwrap()) as _); + let _ = reftest(wrench, &mut window, subargs, rx.unwrap()); + process::exit(0); } else if let Some(_) = args.subcommand_matches("rawtest") { rawtest(wrench, &mut window, rx.unwrap()); return; @@ -525,6 +687,11 @@ fn main() { wrench.renderer.deinit(); } +#[cfg(not(any(feature = "gfx", feature = "gl")))] +fn main() { + println!("You need to enable one of the native API features (dx12/gl/metal/vulkan) in order to run wrench."); +} + fn render<'a>( wrench: &mut Wrench, window: &mut WindowWrapper, @@ -540,8 +707,23 @@ fn render<'a>( println!("loaded {:?}", documents.iter().map(|cd| cd.document_id).collect::>()); let captured = documents.swap_remove(0); window.resize(captured.window_size); + + #[cfg(feature = "gfx")] + { + let dims = window.get_inner_size(); + let framebuffer_size = DeviceIntSize::new( + (dims.width as f32 * wrench.device_pixel_ratio) as i32, + (dims.height as f32 * wrench.device_pixel_ratio) as i32); + wrench.api.set_window_parameters( + captured.document_id, + framebuffer_size, + DeviceIntRect::new(DeviceIntPoint::zero(), framebuffer_size), + wrench.device_pixel_ratio, + ); + } + wrench.document_id = captured.document_id; - Box::new(captured) as Box + Box::new(captured) as Box } else { let extension = input_path .extension() @@ -550,8 +732,8 @@ fn render<'a>( .expect("Tried to render with an unknown file type."); match extension { - "yaml" => Box::new(YamlFrameReader::new_from_args(subargs)) as Box, - "bin" => Box::new(BinaryFrameReader::new_from_args(subargs)) as Box, + "yaml" => Box::new(YamlFrameReader::new_from_args(subargs)) as Box, + "bin" => Box::new(BinaryFrameReader::new_from_args(subargs)) as Box, _ => panic!("Tried to render with an unknown file type."), } }; @@ -668,7 +850,11 @@ fn render<'a>( cpu_profile_index += 1; } VirtualKeyCode::C => { - let path = PathBuf::from("../captures/wrench"); + let path = if cfg!(feature = "gl") { + PathBuf::from("../captures/wrench/gl") + } else { + PathBuf::from("../captures/wrench/gfx") + }; wrench.api.save_capture(path, CaptureBits::all()); } VirtualKeyCode::Up | VirtualKeyCode::Down => { diff --git a/wrench/src/reftest.rs b/wrench/src/reftest.rs index 17baabdbd0..71deeb3e4c 100644 --- a/wrench/src/reftest.rs +++ b/wrench/src/reftest.rs @@ -503,7 +503,11 @@ impl<'a> ReftestHarness<'a> { ); // taking the bottom left sub-rectangle + #[cfg(feature = "gl")] let rect = DeviceIntRect::new(DeviceIntPoint::new(0, window_size.height - size.height), size); + #[cfg(not(feature = "gl"))] + let rect = DeviceIntRect::new(DeviceIntPoint::new(0, 0), size); + let pixels = self.wrench.renderer.read_pixels_rgba8(rect); self.window.swap_buffers(); diff --git a/wrench/src/wrench.rs b/wrench/src/wrench.rs index 63d9bd0372..ec9cfe5a2f 100644 --- a/wrench/src/wrench.rs +++ b/wrench/src/wrench.rs @@ -4,6 +4,7 @@ use app_units::Au; +use back; use blob; use crossbeam::sync::chase_lev; #[cfg(windows)] @@ -22,7 +23,7 @@ use webrender; use webrender::api::*; use webrender::{DebugFlags, RendererStats, ShaderPrecacheFlags}; use yaml_frame_writer::YamlFrameWriterReceiver; -use {WindowWrapper, NotifierEvent}; +use NotifierEvent; // TODO(gw): This descriptor matches what we currently support for fonts // but is quite a mess. We should at least document and @@ -101,7 +102,7 @@ impl Notifier { } impl RenderNotifier for Notifier { - fn clone(&self) -> Box { + fn clone(&self) -> Box { Box::new(Notifier(self.0.clone())) } @@ -150,7 +151,7 @@ pub struct Wrench { pub device_pixel_ratio: f32, page_zoom_factor: ZoomFactor, - pub renderer: webrender::Renderer, + pub renderer: webrender::Renderer, pub api: RenderApi, pub document_id: DocumentId, pub root_pipeline_id: PipelineId, @@ -169,7 +170,6 @@ pub struct Wrench { impl Wrench { pub fn new( - window: &mut WindowWrapper, proxy: Option, shader_override_path: Option, dp_ratio: f32, @@ -184,21 +184,22 @@ impl Wrench { disable_dual_source_blending: bool, zoom_factor: f32, chase_primitive: webrender::ChasePrimitive, - notifier: Option>, + notifier: Option>, + init: webrender::DeviceInit, ) -> Self { println!("Shader override path: {:?}", shader_override_path); let recorder = save_type.map(|save_type| match save_type { SaveType::Yaml => Box::new( YamlFrameWriterReceiver::new(&PathBuf::from("yaml_frames")), - ) as Box, + ) as Box, SaveType::Json => Box::new(JsonFrameWriter::new(&PathBuf::from("json_frames"))) as - Box, + Box, SaveType::Ron => Box::new(RonFrameWriter::new(&PathBuf::from("ron_frames"))) as - Box, + Box, SaveType::Binary => Box::new(webrender::BinaryRecorder::new( &PathBuf::from("wr-record.bin"), - )) as Box, + )) as Box, }); let mut debug_flags = DebugFlags::ECHO_DRIVER_MESSAGES; @@ -211,6 +212,17 @@ impl Wrench { ShaderPrecacheFlags::empty() }; + #[cfg(feature = "gfx")] + let heaps_config = { + let config_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .join("webrender/res/mem_config.ron"); + let source = std::fs::read_to_string(&config_path) + .expect(&format!("Unable to open memory config file from {:?}", config_path)); + ron::de::from_str(&source).expect("Unable to parse HeapsConfig") + }; + let opts = webrender::RendererOptions { device_pixel_ratio: dp_ratio, resource_override_path: shader_override_path, @@ -223,6 +235,8 @@ impl Wrench { blob_image_handler: Some(Box::new(blob::CheckerboardRenderer::new(callbacks.clone()))), disable_dual_source_blending, chase_primitive, + #[cfg(feature = "gfx")] + heaps_config, ..Default::default() }; @@ -238,7 +252,7 @@ impl Wrench { Box::new(Notifier(data)) }); - let (renderer, sender) = webrender::Renderer::new(window.clone_gl(), notifier, opts, None).unwrap(); + let (renderer, sender) = webrender::Renderer::new(init, notifier, opts, None).unwrap(); let api = sender.create_api(); let document_id = api.add_document(size, 0); diff --git a/wrench/src/yaml_frame_reader.rs b/wrench/src/yaml_frame_reader.rs index ec40039a64..78149a5a32 100644 --- a/wrench/src/yaml_frame_reader.rs +++ b/wrench/src/yaml_frame_reader.rs @@ -1675,7 +1675,7 @@ impl YamlFrameReader { ); let reference_frame_kind = if !yaml["perspective"].is_badvalue() { - ReferenceFrameKind::Perspective + ReferenceFrameKind::Perspective { scrolling_relative_to: None } } else { ReferenceFrameKind::Transform }; diff --git a/wrench/src/yaml_frame_writer.rs b/wrench/src/yaml_frame_writer.rs index 19c585a5d7..10eb2ff35a 100644 --- a/wrench/src/yaml_frame_writer.rs +++ b/wrench/src/yaml_frame_writer.rs @@ -196,11 +196,15 @@ fn write_reference_frame( properties: &SceneProperties, clip_id_mapper: &mut ClipIdMapper, ) { + // FIXME: This ignores the scrolling_relative_to member in + // ReferenceFrameKind::Perspective, but it's a bit annoying to fix since the + // frame reader abuses `ExternalScrollId`s. + matrix4d_node( parent, match reference_frame.kind { ReferenceFrameKind::Transform => "transform", - ReferenceFrameKind::Perspective => "perspective", + ReferenceFrameKind::Perspective { .. } => "perspective", }, &properties.resolve_layout_transform(&reference_frame.transform) );