diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04cd2f3..5fc5c60 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -274,20 +274,26 @@ jobs: if: runner.os == 'macOS' run: cargo nextest run -p imaging_snapshot_tests --locked --all-features --no-fail-fast + - name: cargo nextest (imaging_vello, vello-0-7) + run: cargo nextest run -p imaging_vello --locked --no-default-features --features vello-0-7 --no-fail-fast + - name: cargo nextest (imaging_vello, vello-0-8) run: cargo nextest run -p imaging_vello --locked --no-default-features --features vello-0-8 --no-fail-fast - - name: cargo nextest (imaging_vello, vello-0-7) - run: cargo nextest run -p imaging_vello --locked --no-default-features --features vello-0-7 --no-fail-fast + - name: cargo nextest (imaging_vello, vello-0-9) + run: cargo nextest run -p imaging_vello --locked --no-default-features --features vello-0-9 --no-fail-fast - name: cargo test --doc run: cargo test --doc ${{ env.RUST_ALL_FEATURES_EXCLUDE_PKGS }} --workspace --locked --all-features --no-fail-fast + - name: cargo test --doc (imaging_vello, vello-0-7) + run: cargo test --doc -p imaging_vello --locked --no-default-features --features vello-0-7 --no-fail-fast + - name: cargo test --doc (imaging_vello, vello-0-8) run: cargo test --doc -p imaging_vello --locked --no-default-features --features vello-0-8 --no-fail-fast - - name: cargo test --doc (imaging_vello, vello-0-7) - run: cargo test --doc -p imaging_vello --locked --no-default-features --features vello-0-7 --no-fail-fast + - name: cargo test --doc (imaging_vello, vello-0-9) + run: cargo test --doc -p imaging_vello --locked --no-default-features --features vello-0-9 --no-fail-fast package: name: cargo package --list @@ -434,8 +440,8 @@ jobs: env: RUSTDOCFLAGS: '--cfg docsrs -D warnings' - - name: cargo doc (imaging_vello, vello-0-8) - run: cargo doc -p imaging_vello --locked --no-default-features --features vello-0-8 --no-deps --document-private-items + - name: cargo doc (imaging_vello, vello-0-9) + run: cargo doc -p imaging_vello --locked --no-default-features --features vello-0-9 --no-deps --document-private-items env: RUSTDOCFLAGS: '--cfg docsrs -D warnings' @@ -444,6 +450,11 @@ jobs: env: RUSTDOCFLAGS: '--cfg docsrs -D warnings' + - name: cargo doc (imaging_vello, vello-0-8) + run: cargo doc -p imaging_vello --locked --no-default-features --features vello-0-8 --no-deps --document-private-items + env: + RUSTDOCFLAGS: '--cfg docsrs -D warnings' + # If this fails, consider changing your text or adding something to .typos.toml. typos: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 6465b65..3a818e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,7 +199,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec", + "bit-vec 0.8.0", +] + +[[package]] +name = "bit-set" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ddef2995421ab6a5c779542c81ee77c115206f4ad9d5a8e05f4ff49716a3dd" +dependencies = [ + "bit-vec 0.9.1", ] [[package]] @@ -208,6 +217,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" + [[package]] name = "bitflags" version = "1.3.2" @@ -238,6 +253,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -382,6 +406,17 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "codespan-reporting" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + [[package]] name = "color" version = "0.3.3" @@ -495,6 +530,25 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.11.1", + "objc2", +] + +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading", +] + [[package]] name = "document-features" version = "0.2.12" @@ -731,6 +785,24 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "glifo" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d99fc21d493812643aae86d53b7bbd02f376434a90317e8a790bc209fdd6605e" +dependencies = [ + "bytemuck", + "core_maths", + "foldhash 0.2.0", + "hashbrown 0.17.1", + "log", + "peniko", + "png 0.18.1", + "skrifa 0.42.1", + "smallvec", + "vello_common", +] + [[package]] name = "glob" version = "0.3.3" @@ -749,6 +821,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glow" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29038e1c483364cc6bb3cf78feee1816002e127c331a1eec55a4d202b9e1adb5" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "glutin_wgl_sys" version = "0.6.1" @@ -1086,7 +1170,7 @@ dependencies = [ "kurbo", "peniko", "pollster", - "skrifa", + "skrifa 0.40.0", "svg_imaging", "vello_hybrid", ] @@ -1115,6 +1199,7 @@ dependencies = [ "pollster", "vello 0.7.0", "vello 0.8.0", + "vello 0.9.0", ] [[package]] @@ -1132,6 +1217,7 @@ dependencies = [ name = "imaging_vello_hybrid" version = "0.0.1" dependencies = [ + "glifo", "imaging", "imaging_wgpu", "kurbo", @@ -1139,7 +1225,7 @@ dependencies = [ "pollster", "vello_common", "vello_hybrid", - "wgpu 28.0.0", + "wgpu 29.0.3", ] [[package]] @@ -1149,6 +1235,7 @@ dependencies = [ "imaging", "wgpu 27.0.1", "wgpu 28.0.0", + "wgpu 29.0.3", ] [[package]] @@ -1485,11 +1572,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" dependencies = [ "arrayvec", - "bit-set", + "bit-set 0.8.0", "bitflags 2.11.1", "cfg-if", "cfg_aliases", - "codespan-reporting", + "codespan-reporting 0.12.0", "half", "hashbrown 0.16.1", "hexf-parse", @@ -1499,7 +1586,7 @@ dependencies = [ "num-traits", "once_cell", "rustc-hash 1.1.0", - "spirv", + "spirv 0.3.0+sdk-1.3.268.0", "thiserror 2.0.18", "unicode-ident", ] @@ -1511,11 +1598,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", - "bit-set", + "bit-set 0.8.0", + "bitflags 2.11.1", + "cfg-if", + "cfg_aliases", + "codespan-reporting 0.12.0", + "half", + "hashbrown 0.16.1", + "hexf-parse", + "indexmap", + "libm", + "log", + "num-traits", + "once_cell", + "rustc-hash 1.1.0", + "spirv 0.3.0+sdk-1.3.268.0", + "thiserror 2.0.18", + "unicode-ident", +] + +[[package]] +name = "naga" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd91265cc2454558f659b3b4b9640f0ddb8cc6521277f166b8a8c181c898079" +dependencies = [ + "arrayvec", + "bit-set 0.9.1", "bitflags 2.11.1", "cfg-if", "cfg_aliases", - "codespan-reporting", + "codespan-reporting 0.13.1", "half", "hashbrown 0.16.1", "hexf-parse", @@ -1525,7 +1638,7 @@ dependencies = [ "num-traits", "once_cell", "rustc-hash 1.1.0", - "spirv", + "spirv 0.4.0+sdk-1.4.341.0", "thiserror 2.0.18", "unicode-ident", ] @@ -1577,6 +1690,68 @@ dependencies = [ "malloc_buf", ] +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.11.1", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" +dependencies = [ + "bitflags 2.11.1", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -1821,6 +1996,18 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "raw-window-metal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" +dependencies = [ + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-quartz-core", +] + [[package]] name = "rayon" version = "1.12.0" @@ -1846,6 +2033,16 @@ name = "read-fonts" version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" +dependencies = [ + "bytemuck", + "font-types 0.11.3", +] + +[[package]] +name = "read-fonts" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4ed38b89c2c77ff968c524145ad65fb010f38af5c7a224b53b81d47ac2daa81" dependencies = [ "bytemuck", "core_maths", @@ -2144,10 +2341,20 @@ name = "skrifa" version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" +dependencies = [ + "bytemuck", + "read-fonts 0.37.0", +] + +[[package]] +name = "skrifa" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c34617370ae968efb7161bb2beb517d9084659aae19e24b89e3db25b46e4564" dependencies = [ "bytemuck", "core_maths", - "read-fonts", + "read-fonts 0.39.2", ] [[package]] @@ -2190,6 +2397,15 @@ dependencies = [ "bitflags 2.11.1", ] +[[package]] +name = "spirv" +version = "0.4.0+sdk-1.4.341.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f" +dependencies = [ + "bitflags 2.11.1", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -2245,7 +2461,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64" dependencies = [ - "skrifa", + "skrifa 0.40.0", "yazi", "zeno", ] @@ -2611,7 +2827,7 @@ dependencies = [ "log", "peniko", "png 0.17.16", - "skrifa", + "skrifa 0.40.0", "static_assertions", "thiserror 2.0.18", "vello_encoding 0.7.0", @@ -2630,7 +2846,7 @@ dependencies = [ "log", "peniko", "png 0.18.1", - "skrifa", + "skrifa 0.40.0", "static_assertions", "thiserror 2.0.18", "vello_encoding 0.8.0", @@ -2639,43 +2855,52 @@ dependencies = [ ] [[package]] -name = "vello_api" -version = "0.0.7" +name = "vello" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5088cd0113bc5332c753f24503825e3bc93e26c7883c9dc3ad9637bb62c4634" +checksum = "261359dbef879f8110ef7e1c442246c838d33d3d91cb05e0ea9288d432760c9f" dependencies = [ "bytemuck", + "futures-intrusive", + "log", "peniko", + "png 0.18.1", + "skrifa 0.42.1", + "static_assertions", + "thiserror 2.0.18", + "vello_encoding 0.9.0", + "vello_shaders 0.9.0", + "wgpu 29.0.3", ] [[package]] name = "vello_common" -version = "0.0.7" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "986dc49a501a683477614bf07b8e7b6c79ae4828efce3bf22e51850f4a0a8a4c" +checksum = "19d672facaa2d697285a786cd9d44d614cd2ce54cdc022504bf339f8fff3b750" dependencies = [ "bytemuck", "fearless_simd", "guillotiere 0.7.0", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "libm", "log", "peniko", "png 0.18.1", - "skrifa", "smallvec", "thiserror 2.0.18", ] [[package]] name = "vello_cpu" -version = "0.0.7" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a678f91c7524a3a9ac9a19df9f83552866ec70b2ca26441b916a6b219b6aa2de" +checksum = "588691169aed86b5c8fb487266afee01323234e6fd0a3f2aaec0eaa8e4007f23" dependencies = [ "bytemuck", - "hashbrown 0.16.1", - "vello_api", + "glifo", + "hashbrown 0.17.1", + "png 0.18.1", "vello_common", ] @@ -2688,7 +2913,7 @@ dependencies = [ "bytemuck", "guillotiere 0.6.2", "peniko", - "skrifa", + "skrifa 0.40.0", "smallvec", ] @@ -2701,24 +2926,37 @@ dependencies = [ "bytemuck", "guillotiere 0.7.0", "peniko", - "skrifa", + "skrifa 0.40.0", + "smallvec", +] + +[[package]] +name = "vello_encoding" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2346f5f0d7dccb3582fcd397b4a57b43165209f1424e0d76e85dd814db164af7" +dependencies = [ + "bytemuck", + "guillotiere 0.7.0", + "peniko", + "skrifa 0.42.1", "smallvec", ] [[package]] name = "vello_hybrid" -version = "0.0.7" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a2b295a72c9fb73be9679c0d468c64d4f97ef09b91ce6d16d309747719c6ff2" +checksum = "86ca7acbf6e59ae8c354c524732c73da45239a3a8ee03d0c8a9ad66a6622e488" dependencies = [ "bytemuck", - "hashbrown 0.16.1", + "glifo", + "hashbrown 0.17.1", "log", "thiserror 2.0.18", - "vello_api", "vello_common", "vello_sparse_shaders", - "wgpu 28.0.0", + "wgpu 29.0.3", ] [[package]] @@ -2747,11 +2985,24 @@ dependencies = [ "vello_encoding 0.8.0", ] +[[package]] +name = "vello_shaders" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd38937516fa4b47423d9255bb5e4a65e839ec9d57c38c4af6189ce56bf46b7" +dependencies = [ + "bytemuck", + "log", + "naga 29.0.3", + "thiserror 2.0.18", + "vello_encoding 0.9.0", +] + [[package]] name = "vello_sparse_shaders" -version = "0.0.7" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afd2601f1c8cc1e16807aaf1a66dd182eb6f895df095a48fb353fe49377a9ce" +checksum = "e004cfe28eb71738643f60460b9cae2236eba57b351afebf244148256ff25d8b" [[package]] name = "version_check" @@ -2830,6 +3081,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.98" @@ -2905,6 +3168,36 @@ dependencies = [ "wgpu-types 28.0.0", ] +[[package]] +name = "wgpu" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb3feacc458f7bee8bc1737149b42b6c731aa461039a4264a67bb6681646b250" +dependencies = [ + "arrayvec", + "bitflags 2.11.1", + "bytemuck", + "cfg-if", + "cfg_aliases", + "document-features", + "hashbrown 0.16.1", + "js-sys", + "log", + "naga 29.0.3", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core 29.0.3", + "wgpu-hal 29.0.3", + "wgpu-types 29.0.3", +] + [[package]] name = "wgpu-core" version = "27.0.3" @@ -2912,8 +3205,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7" dependencies = [ "arrayvec", - "bit-set", - "bit-vec", + "bit-set 0.8.0", + "bit-vec 0.8.0", "bitflags 2.11.1", "bytemuck", "cfg_aliases", @@ -2944,8 +3237,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d23f4642f53f666adcfd2d3218ab174d1e6681101aef18696b90cbe64d1c10f9" dependencies = [ "arrayvec", - "bit-set", - "bit-vec", + "bit-set 0.8.0", + "bit-vec 0.8.0", "bitflags 2.11.1", "bytemuck", "cfg_aliases", @@ -2969,6 +3262,39 @@ dependencies = [ "wgpu-types 28.0.0", ] +[[package]] +name = "wgpu-core" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02da3ad1b568337f25513b317870960ef87073ea0945502e44b864b67a8c77b7" +dependencies = [ + "arrayvec", + "bit-set 0.9.1", + "bit-vec 0.9.1", + "bitflags 2.11.1", + "bytemuck", + "cfg_aliases", + "document-features", + "hashbrown 0.16.1", + "indexmap", + "log", + "naga 29.0.3", + "once_cell", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.18", + "wgpu-core-deps-apple 29.0.3", + "wgpu-core-deps-emscripten 29.0.3", + "wgpu-core-deps-windows-linux-android 29.0.3", + "wgpu-hal 29.0.3", + "wgpu-naga-bridge", + "wgpu-types 29.0.3", +] + [[package]] name = "wgpu-core-deps-apple" version = "27.0.0" @@ -2987,6 +3313,15 @@ dependencies = [ "wgpu-hal 28.0.1", ] +[[package]] +name = "wgpu-core-deps-apple" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e51b5447e144b3dbba4feb01f80f4fa21696fa0cd99afb2c3df1affd6fdb28" +dependencies = [ + "wgpu-hal 29.0.3", +] + [[package]] name = "wgpu-core-deps-emscripten" version = "27.0.0" @@ -3005,6 +3340,15 @@ dependencies = [ "wgpu-hal 28.0.1", ] +[[package]] +name = "wgpu-core-deps-emscripten" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3487cd6293a963bc5c0c0396f6a2192043c50003c07f4efdccbad3d90ec9d819" +dependencies = [ + "wgpu-hal 29.0.3", +] + [[package]] name = "wgpu-core-deps-windows-linux-android" version = "27.0.0" @@ -3023,6 +3367,15 @@ dependencies = [ "wgpu-hal 28.0.1", ] +[[package]] +name = "wgpu-core-deps-windows-linux-android" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb01076d0aa08b0ba9bd741e178b5cc440f5abe99d9581323a4c8b5d1a1916" +dependencies = [ + "wgpu-hal 29.0.3", +] + [[package]] name = "wgpu-hal" version = "27.0.4" @@ -3032,14 +3385,14 @@ dependencies = [ "android_system_properties", "arrayvec", "ash", - "bit-set", + "bit-set 0.8.0", "bitflags 2.11.1", "block", "bytemuck", "cfg-if", "cfg_aliases", "core-graphics-types", - "glow", + "glow 0.16.0", "glutin_wgl_sys", "gpu-alloc", "gpu-allocator 0.27.0", @@ -3081,14 +3434,14 @@ dependencies = [ "android_system_properties", "arrayvec", "ash", - "bit-set", + "bit-set 0.8.0", "bitflags 2.11.1", "block", "bytemuck", "cfg-if", "cfg_aliases", "core-graphics-types", - "glow", + "glow 0.16.0", "glutin_wgl_sys", "gpu-allocator 0.28.0", "gpu-descriptor", @@ -3120,6 +3473,70 @@ dependencies = [ "windows-core 0.62.2", ] +[[package]] +name = "wgpu-hal" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8e1a9e7a8512f276f7c62e018c7fa8d60954303fed2e5750114332049193f" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set 0.9.1", + "bitflags 2.11.1", + "block2", + "bytemuck", + "cfg-if", + "cfg_aliases", + "glow 0.17.0", + "glutin_wgl_sys", + "gpu-allocator 0.28.0", + "gpu-descriptor", + "hashbrown 0.16.1", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "naga 29.0.3", + "ndk-sys", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", + "objc2-quartz-core", + "once_cell", + "ordered-float", + "parking_lot", + "portable-atomic", + "portable-atomic-util", + "profiling", + "range-alloc", + "raw-window-handle", + "raw-window-metal", + "renderdoc-sys", + "smallvec", + "thiserror 2.0.18", + "wasm-bindgen", + "wayland-sys", + "web-sys", + "wgpu-naga-bridge", + "wgpu-types 29.0.3", + "windows 0.62.2", + "windows-core 0.62.2", + "windows-result 0.4.1", +] + +[[package]] +name = "wgpu-naga-bridge" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c654c483f058800972c3645e95388a7eca31bf9fe1933bc20e036588a0be02" +dependencies = [ + "naga 29.0.3", + "wgpu-types 29.0.3", +] + [[package]] name = "wgpu-types" version = "27.0.1" @@ -3147,6 +3564,20 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wgpu-types" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9bcc31518a0e9735aefebedb5f7a9ef3ed1c42549c9f4c882fa9060ceaac639" +dependencies = [ + "bitflags 2.11.1", + "bytemuck", + "js-sys", + "log", + "raw-window-handle", + "web-sys", +] + [[package]] name = "winapi-util" version = "0.1.11" diff --git a/imaging_skia/src/lib.rs b/imaging_skia/src/lib.rs index 0c0c248..1c2f2a4 100644 --- a/imaging_skia/src/lib.rs +++ b/imaging_skia/src/lib.rs @@ -194,7 +194,9 @@ use crate::gpu_readback::{ ReadbackError, ScratchTexture, read_texture_into, read_texture_into_target, }; #[cfg(feature = "gpu")] -use imaging_wgpu::{TextureRenderer, TextureRendererError, TextureTargetError}; +use imaging_wgpu::v28::TextureRenderer; +#[cfg(feature = "gpu")] +use imaging_wgpu::{TextureRendererError, TextureTargetError}; use sinks::MaskCache; pub use sinks::{SkCanvasSink, SkPictureRecorderSink}; #[cfg(feature = "gpu")] diff --git a/imaging_snapshot_tests/Cargo.toml b/imaging_snapshot_tests/Cargo.toml index 4d8e8ab..0860989 100644 --- a/imaging_snapshot_tests/Cargo.toml +++ b/imaging_snapshot_tests/Cargo.toml @@ -20,7 +20,7 @@ kurbo = { default-features = true, workspace = true } peniko = { default-features = true, workspace = true } skrifa = "0.40.0" svg_imaging = { workspace = true } -vello_hybrid = { default-features = true, optional = true, version = "0.0.7" } +vello_hybrid = { default-features = true, optional = true, version = "0.0.9" } [lints] workspace = true diff --git a/imaging_snapshot_tests/src/cases/mod.rs b/imaging_snapshot_tests/src/cases/mod.rs index 378c72d..47680ed 100644 --- a/imaging_snapshot_tests/src/cases/mod.rs +++ b/imaging_snapshot_tests/src/cases/mod.rs @@ -101,6 +101,10 @@ pub const CASES: &[&dyn SnapshotCase] = &[ &gradients::GmGradientsSweep, &gradients::GmGradientsTwoPointRadial, &images::GmImageBrushes, + // Keep the Vello GPU glyph image-brush snapshots adjacent to the image-brush + // case until the Vello 0.9 atlas invalidation fix is released. + &text::GmGlyphRunsImageFill, + &text::GmGlyphRunsImageStroke, &masks::GmMaskAlpha, &masks::GmMaskLuminance, &clips::GmClipNonIsolated, @@ -116,8 +120,6 @@ pub const CASES: &[&dyn SnapshotCase] = &[ &text::GmGlyphRunsGradientFill, &text::GmGlyphRunsGradientBrushTransform, &text::GmGlyphRunsGradientStroke, - &text::GmGlyphRunsImageFill, - &text::GmGlyphRunsImageStroke, &text::GmTextEditorLorem, &svg::GmSvgLayeredCard, &svg::GmSvgLuminanceMask, diff --git a/imaging_snapshot_tests/src/cases/text.rs b/imaging_snapshot_tests/src/cases/text.rs index ea7e52e..3c60dea 100644 --- a/imaging_snapshot_tests/src/cases/text.rs +++ b/imaging_snapshot_tests/src/cases/text.rs @@ -89,7 +89,10 @@ impl SnapshotCase for GmGlyphRunsGradientBrushTransform { } fn supports_backend(&self, backend: &str) -> bool { - matches!(backend, "skia" | "tiny_skia" | "vello_cpu" | "vello_hybrid") + matches!( + backend, + "skia" | "tiny_skia" | "vello" | "vello_cpu" | "vello_hybrid" + ) } fn skia_max_diff_pixels(&self) -> u64 { @@ -205,6 +208,13 @@ impl SnapshotCase for GmGlyphRunsImageFill { "gm_glyph_runs_image_fill" } + fn supports_backend(&self, backend: &str) -> bool { + matches!( + backend, + "skia" | "tiny_skia" | "vello" | "vello_cpu" | "vello_hybrid" + ) + } + fn run(&self, sink: &mut dyn PaintSink, width: f64, height: f64) { background(sink, width, height, Color::from_rgba8(247, 243, 236, 255)); let mut painter = Painter::new(sink); @@ -232,6 +242,13 @@ impl SnapshotCase for GmGlyphRunsImageStroke { "gm_glyph_runs_image_stroke" } + fn supports_backend(&self, backend: &str) -> bool { + matches!( + backend, + "skia" | "tiny_skia" | "vello" | "vello_cpu" | "vello_hybrid" + ) + } + fn vello_max_diff_pixels(&self) -> u64 { 8 } diff --git a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_brush_transform.png b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_brush_transform.png new file mode 100644 index 0000000..22a9092 Binary files /dev/null and b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_brush_transform.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_fill.png b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_fill.png index 06306f0..3ab269f 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_fill.png and b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_fill.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_stroke.png b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_stroke.png index c8f71df..406a540 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_stroke.png and b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_gradient_stroke.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_image_fill.png b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_image_fill.png index 4e98cbb..7358f19 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_image_fill.png and b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_image_fill.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_image_stroke.png b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_image_stroke.png index bdb32d9..a1d26fc 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_image_stroke.png and b/imaging_snapshot_tests/tests/snapshots/vello/gm_glyph_runs_image_stroke.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello/gm_image_brushes.png b/imaging_snapshot_tests/tests/snapshots/vello/gm_image_brushes.png index 29dec68..1b1dae1 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello/gm_image_brushes.png and b/imaging_snapshot_tests/tests/snapshots/vello/gm_image_brushes.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_blend_grid.png b/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_blend_grid.png index 3c354de..93e1c2a 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_blend_grid.png and b/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_blend_grid.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_clip_stroke_nested.png b/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_clip_stroke_nested.png index 11be3de..e333c6c 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_clip_stroke_nested.png and b/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_clip_stroke_nested.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_image_brushes.png b/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_image_brushes.png index 2fd48a3..d1eb750 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_image_brushes.png and b/imaging_snapshot_tests/tests/snapshots/vello_cpu/gm_image_brushes.png differ diff --git a/imaging_snapshot_tests/tests/snapshots/vello_hybrid/gm_glyph_runs_gradient_brush_transform.png b/imaging_snapshot_tests/tests/snapshots/vello_hybrid/gm_glyph_runs_gradient_brush_transform.png index c6ae18d..8f87c5f 100644 Binary files a/imaging_snapshot_tests/tests/snapshots/vello_hybrid/gm_glyph_runs_gradient_brush_transform.png and b/imaging_snapshot_tests/tests/snapshots/vello_hybrid/gm_glyph_runs_gradient_brush_transform.png differ diff --git a/imaging_vello/CHANGELOG.md b/imaging_vello/CHANGELOG.md index 0d813e9..6b74a41 100644 --- a/imaging_vello/CHANGELOG.md +++ b/imaging_vello/CHANGELOG.md @@ -13,12 +13,24 @@ The latest published `imaging_vello` release is [0.0.1](#001-2026-05-21), which ## [Unreleased] +### Changed + +- Updated the backend to Vello 0.9 and `wgpu` 29. ([#64][] by [@waywardmonkeys][]) +- Kept the `vello-0-7` and `vello-0-8` compatibility features for integrations that still use + `wgpu` 27 or 28. ([#64][] by [@waywardmonkeys][]) +- Enabled glyph brush transforms through the Vello 0.9 glyph-run API. + ([#64][] by [@waywardmonkeys][]) + ## [0.0.1][] (2026-05-21) This release has an [MSRV][] of 1.92. This is the initial release. +[@waywardmonkeys]: https://github.com/waywardmonkeys + +[#64]: https://github.com/forest-rs/imaging/pull/64 + [Unreleased]: https://github.com/forest-rs/imaging/compare/imaging_vello-v0.0.1...HEAD [0.0.1]: https://github.com/forest-rs/imaging/releases/tag/imaging_vello-v0.0.1 diff --git a/imaging_vello/Cargo.toml b/imaging_vello/Cargo.toml index bd34e97..5560140 100644 --- a/imaging_vello/Cargo.toml +++ b/imaging_vello/Cargo.toml @@ -17,11 +17,13 @@ kurbo = { default-features = true, workspace = true } peniko = { default-features = true, workspace = true } vello_07 = { default-features = true, optional = true, package = "vello", version = "0.7.0" } vello_08 = { default-features = true, optional = true, package = "vello", version = "0.8.0" } +vello_09 = { default-features = true, optional = true, package = "vello", version = "0.9.0" } [features] -default = ["vello-0-8"] +default = ["vello-0-9"] vello-0-7 = ["dep:vello_07", "imaging_wgpu/wgpu-27"] vello-0-8 = ["dep:vello_08", "imaging_wgpu/wgpu-28"] +vello-0-9 = ["dep:vello_09", "imaging_wgpu/wgpu-29"] [dev-dependencies] pollster = "0.4.0" @@ -30,6 +32,6 @@ pollster = "0.4.0" workspace = true [package.metadata.docs.rs] -features = ["vello-0-8"] +features = ["vello-0-9"] default-target = "x86_64-unknown-linux-gnu" targets = [] diff --git a/imaging_vello/README.md b/imaging_vello/README.md index a4a770a..0df3a11 100644 --- a/imaging_vello/README.md +++ b/imaging_vello/README.md @@ -32,10 +32,11 @@ Semantic [`imaging::record::Scene`] values can be lowered to native Vello scenes In UI integrations, the host application should usually own the `wgpu` device, queue, and presentation targets, then pass those handles into [`VelloRenderer`]. -Enable exactly one backend compatibility feature: +Enable a Vello compatibility feature: -- `vello-0-8` (default) -- `vello-0-7` +- `vello-0-9` (default) +- `vello-0-8` for integrations that still use `wgpu` 28 +- `vello-0-7` for integrations that still use `wgpu` 27 # Render A Recorded Scene diff --git a/imaging_vello/src/lib.rs b/imaging_vello/src/lib.rs index 0202587..2ce163e 100644 --- a/imaging_vello/src/lib.rs +++ b/imaging_vello/src/lib.rs @@ -12,10 +12,11 @@ //! In UI integrations, the host application should usually own the `wgpu` device, queue, and //! presentation targets, then pass those handles into [`VelloRenderer`]. //! -//! Enable exactly one backend compatibility feature: +//! Enable a Vello compatibility feature: //! -//! - `vello-0-8` (default) -//! - `vello-0-7` +//! - `vello-0-9` (default) +//! - `vello-0-8` for integrations that still use `wgpu` 28 +//! - `vello-0-7` for integrations that still use `wgpu` 27 //! //! # Render A Recorded Scene //! @@ -113,11 +114,8 @@ mod scene_sink; mod wgpu_support; -#[cfg(all(feature = "vello-0-7", feature = "vello-0-8"))] -compile_error!("Enable exactly one of `vello-0-7` or `vello-0-8`."); - -#[cfg(not(any(feature = "vello-0-7", feature = "vello-0-8")))] -compile_error!("Enable one of `vello-0-7` or `vello-0-8`."); +#[cfg(not(any(feature = "vello-0-7", feature = "vello-0-8", feature = "vello-0-9")))] +compile_error!("Enable one of `vello-0-7`, `vello-0-8`, or `vello-0-9`."); use imaging::RgbaImage; use imaging::record::{Scene, ValidateError, replay}; @@ -125,13 +123,31 @@ use imaging::render::{ GpuReadbackError, ImageBufferFormat, ImageBufferTarget, ImageRenderer, ImageRendererError, ImageTargetError, RenderContentError, RenderSource, RenderUnsupportedError, }; -use imaging_wgpu::{TextureRenderer, TextureRendererError, TextureTargetError, TextureViewTarget}; +#[cfg(all( + not(any(feature = "vello-0-8", feature = "vello-0-9")), + feature = "vello-0-7" +))] +use imaging_wgpu::v27::{TextureRenderer, TextureViewTarget}; +#[cfg(all(not(feature = "vello-0-9"), feature = "vello-0-8"))] +use imaging_wgpu::v28::{TextureRenderer, TextureViewTarget}; +#[cfg(feature = "vello-0-9")] +use imaging_wgpu::v29::{TextureRenderer, TextureViewTarget}; +use imaging_wgpu::{TextureRendererError, TextureTargetError}; use kurbo::Rect; -#[cfg(feature = "vello-0-7")] +#[cfg(all(feature = "vello-0-7", feature = "vello-0-9"))] +use vello_07 as _; +#[cfg(all( + not(any(feature = "vello-0-8", feature = "vello-0-9")), + feature = "vello-0-7" +))] pub use vello_07 as vello; -#[cfg(all(not(feature = "vello-0-7"), feature = "vello-0-8"))] +#[cfg(all(feature = "vello-0-8", feature = "vello-0-9"))] +use vello_08 as _; +#[cfg(all(not(feature = "vello-0-9"), feature = "vello-0-8"))] pub use vello_08 as vello; +#[cfg(feature = "vello-0-9")] +pub use vello_09 as vello; pub use crate::vello::wgpu; use crate::vello::{AaConfig, RenderParams}; @@ -146,7 +162,7 @@ pub use scene_sink::VelloSceneSink; pub enum Error { /// The scene is invalid (unbalanced stacks). InvalidScene(ValidateError), - /// An image brush was encountered; this backend does not support it. + /// An unsupported image-brush use was encountered. UnsupportedImageBrush, /// A filter configuration could not be translated. UnsupportedFilter, @@ -154,7 +170,7 @@ pub enum Error { UnsupportedMask, /// Glyph draws with non-default blend modes are not supported by this backend yet. UnsupportedGlyphBlend, - /// Glyph brush transforms are not supported until Vello exposes them on glyph runs. + /// Glyph brush transforms are not supported by older Vello compatibility lanes. UnsupportedGlyphBrushTransform, /// Blurred rounded rect draws with non-default blend modes are not supported by this backend yet. UnsupportedBlurredRoundedRectBlend, diff --git a/imaging_vello/src/scene_sink.rs b/imaging_vello/src/scene_sink.rs index 0060d3b..03d4342 100644 --- a/imaging_vello/src/scene_sink.rs +++ b/imaging_vello/src/scene_sink.rs @@ -124,11 +124,14 @@ impl<'a> VelloSceneSink<'a> { self.set_error_once(Error::UnsupportedGlyphBlend); return; } + #[cfg(all( + not(feature = "vello-0-9"), + any(feature = "vello-0-7", feature = "vello-0-8") + ))] if glyph_run.brush_transform.is_some() { self.set_error_once(Error::UnsupportedGlyphBrushTransform); return; } - let Some(paint) = self.brush_to_brush(glyph_run.brush, glyph_run.composite) else { return; }; @@ -140,8 +143,10 @@ impl<'a> VelloSceneSink<'a> { .font_size(glyph_run.font_size) .hint(glyph_run.hint) .normalized_coords(glyph_run.normalized_coords) - .brush(&paint) - .brush_alpha(glyph_run.composite.alpha); + .brush(&paint); + #[cfg(feature = "vello-0-9")] + let builder = builder.brush_transform(glyph_run.brush_transform); + let builder = builder.brush_alpha(glyph_run.composite.alpha); let builder = builder.glyph_transform(glyph_run.glyph_transform); let glyphs = glyphs.map(|glyph| VelloGlyph { id: glyph.id, @@ -552,7 +557,38 @@ mod tests { } #[test] - fn vello_scene_sink_rejects_glyph_brush_transforms_until_vello_supports_them() { + #[cfg(feature = "vello-0-9")] + fn vello_scene_sink_accepts_glyph_brush_transforms() { + const TEST_FONT_BYTES: &[u8] = include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../test_assets/fonts/NotoSans-Regular.ttf" + )); + + let font = FontData::new(Blob::new(Arc::new(TEST_FONT_BYTES)), 0); + let style = Style::Fill(Fill::NonZero); + let mut glyphs = [imaging::record::Glyph { + id: 1, + x: 0.0, + y: 0.0, + }] + .into_iter(); + + let mut scene = vello::Scene::new(); + let mut sink = VelloSceneSink::new(&mut scene, Rect::new(0.0, 0.0, 32.0, 32.0)); + sink.glyph_run( + GlyphRunRef::new(&font, &style, Color::BLACK) + .brush_transform(Some(Affine::translate((-200.0, 0.0)))), + &mut glyphs, + ); + sink.finish().expect("glyph brush transform should encode"); + } + + #[test] + #[cfg(all( + not(feature = "vello-0-9"), + any(feature = "vello-0-7", feature = "vello-0-8") + ))] + fn vello_scene_sink_rejects_glyph_brush_transforms_before_vello_0_9() { let font = FontData::new(Blob::new(Arc::new([0_u8, 1_u8, 2_u8, 3_u8])), 0); let style = Style::Fill(Fill::NonZero); let mut glyphs = [imaging::record::Glyph { diff --git a/imaging_vello_cpu/CHANGELOG.md b/imaging_vello_cpu/CHANGELOG.md index 13358aa..7d82ea2 100644 --- a/imaging_vello_cpu/CHANGELOG.md +++ b/imaging_vello_cpu/CHANGELOG.md @@ -13,12 +13,21 @@ on 2026-05-21. You can find its changes [documented below](#001-2026-05-21). ## [Unreleased] +### Changed + +- Updated the backend to `vello_cpu` 0.0.9 and `vello_common` 0.0.9. + ([#64][] by [@waywardmonkeys][]) + ## [0.0.1][] (2026-05-21) This release has an [MSRV][] of 1.92. This is the initial release. +[@waywardmonkeys]: https://github.com/waywardmonkeys + +[#64]: https://github.com/forest-rs/imaging/pull/64 + [Unreleased]: https://github.com/forest-rs/imaging/compare/imaging_vello_cpu-v0.0.1...HEAD [0.0.1]: https://github.com/forest-rs/imaging/releases/tag/imaging_vello_cpu-v0.0.1 diff --git a/imaging_vello_cpu/Cargo.toml b/imaging_vello_cpu/Cargo.toml index 42373ba..f00e417 100644 --- a/imaging_vello_cpu/Cargo.toml +++ b/imaging_vello_cpu/Cargo.toml @@ -14,8 +14,8 @@ categories = ["graphics", "rendering"] imaging.workspace = true kurbo.workspace = true peniko.workspace = true -vello_common = { default-features = false, version = "0.0.7" } -vello_cpu = { default-features = false, features = ["text", "u8_pipeline"], version = "0.0.7" } +vello_common = { default-features = false, version = "0.0.9" } +vello_cpu = { default-features = false, features = ["text", "u8_pipeline"], version = "0.0.9" } [lints] workspace = true diff --git a/imaging_vello_cpu/src/lib.rs b/imaging_vello_cpu/src/lib.rs index 2c0a1eb..c9e0acd 100644 --- a/imaging_vello_cpu/src/lib.rs +++ b/imaging_vello_cpu/src/lib.rs @@ -76,13 +76,14 @@ use imaging::{ RenderContentError, RenderSource, RenderUnsupportedError, }, }; -use kurbo::{Affine, Rect, Shape as _}; +use kurbo::{Affine, Shape as _}; use peniko::{BlendMode, Brush, BrushRef, Fill, Style}; use vello_common::filter_effects::{EdgeMode, Filter as VelloFilter, FilterGraph, FilterPrimitive}; -use vello_common::glyph::Glyph as VelloGlyph; use vello_common::paint::{Image as VelloImage, ImageSource}; use vello_cpu::kurbo::{BezPath, StrokeOpts, stroke}; -use vello_cpu::{Pixmap, RenderContext, RenderMode, RenderSettings}; +use vello_cpu::{ + Glyph as VelloGlyph, Pixmap, RenderContext, RenderMode, RenderSettings, Resources, +}; /// Errors that can occur when rendering via Vello CPU. #[derive(Debug)] @@ -109,6 +110,7 @@ impl core::error::Error for Error {} #[derive(Debug)] pub struct VelloCpuRenderer { ctx: RenderContext, + resources: Resources, width: u16, height: u16, tolerance: f64, @@ -149,6 +151,7 @@ impl VelloCpuRenderer { let ctx = RenderContext::new_with(width, height, Self::render_settings()); Self { ctx, + resources: Resources::new(), width, height, tolerance: 0.1, @@ -190,6 +193,7 @@ impl VelloCpuRenderer { } self.ctx = RenderContext::new_with(width, height, Self::render_settings()); + self.resources = Resources::new(); self.width = width; self.height = height; self.clear_cached_masks(); @@ -240,6 +244,7 @@ impl VelloCpuRenderer { image.resize(u32::from(self.width), u32::from(self.height)); self.ctx.flush(); self.ctx.render_to_buffer( + &mut self.resources, image.data.as_mut_slice(), self.width, self.height, @@ -280,6 +285,7 @@ impl VelloCpuRenderer { self.ctx.flush(); self.ctx.render_to_buffer( + &mut self.resources, &mut target.data[..required_len], self.width, self.height, @@ -302,14 +308,6 @@ impl VelloCpuRenderer { } } - fn rect_fits_viewport_fast_path(&self, rect: &Rect, transform: Affine) -> bool { - let transformed = transform.transform_rect_bbox(*rect); - transformed.x0 >= 0.0 - && transformed.y0 >= 0.0 - && transformed.x1 <= f64::from(self.width) - && transformed.y1 <= f64::from(self.height) - } - fn brush_to_paint( &mut self, brush: BrushRef<'_>, @@ -413,13 +411,23 @@ impl VelloCpuRenderer { .set_paint_transform(glyph_run.brush_transform.unwrap_or(Affine::IDENTITY)); self.ctx.set_paint(paint); self.ctx.set_blend_mode(glyph_run.composite.blend); + // TODO: Revisit this allocation. `PaintSink` currently gives us a + // one-shot iterator, while glifo's glyph builders need a cloneable + // glyph source. + let glyphs = glyphs + .map(|glyph| VelloGlyph { + id: glyph.id, + x: glyph.x, + y: glyph.y, + }) + .collect::>(); match glyph_run.style { Style::Fill(fill_rule) => { self.ctx.set_fill_rule(*fill_rule); let builder = self .ctx - .glyph_run(glyph_run.font) + .glyph_run(&mut self.resources, glyph_run.font) .font_size(glyph_run.font_size) .hint(glyph_run.hint) .normalized_coords(glyph_run.normalized_coords); @@ -428,18 +436,13 @@ impl VelloCpuRenderer { } else { builder }; - let glyphs = glyphs.map(|glyph| VelloGlyph { - id: glyph.id, - x: glyph.x, - y: glyph.y, - }); - builder.fill_glyphs(glyphs); + builder.fill_glyphs(glyphs.into_iter()); } Style::Stroke(stroke) => { self.ctx.set_stroke(stroke.clone()); let builder = self .ctx - .glyph_run(glyph_run.font) + .glyph_run(&mut self.resources, glyph_run.font) .font_size(glyph_run.font_size) .hint(glyph_run.hint) .normalized_coords(glyph_run.normalized_coords); @@ -448,12 +451,7 @@ impl VelloCpuRenderer { } else { builder }; - let glyphs = glyphs.map(|glyph| VelloGlyph { - id: glyph.id, - x: glyph.x, - y: glyph.y, - }); - builder.stroke_glyphs(glyphs); + builder.stroke_glyphs(glyphs.into_iter()); } } } @@ -498,7 +496,9 @@ impl VelloCpuRenderer { let mut pixmap = Pixmap::new(self.width, self.height); renderer.ctx.flush(); - renderer.ctx.render_to_pixmap(&mut pixmap); + renderer + .ctx + .render_to_pixmap(&mut renderer.resources, &mut pixmap); let mask = match mode { MaskMode::Alpha => vello_cpu::Mask::new_alpha(&pixmap), MaskMode::Luminance => vello_cpu::Mask::new_luminance(&pixmap), @@ -708,16 +708,7 @@ impl PaintSink for VelloCpuRenderer { self.ctx.set_paint(paint); match draw.shape { - GeometryRef::Rect(r) => { - if self.rect_fits_viewport_fast_path(&r, draw.transform) { - self.ctx.fill_rect(&r); - } else { - // Work around a vello_cpu 0.0.7 rect fast-path panic for strips that land - // outside the viewport. Fall back to path filling until the upstream fix lands. - let path = r.to_path(self.tolerance); - self.ctx.fill_path(&path); - } - } + GeometryRef::Rect(r) => self.ctx.fill_rect(&r), GeometryRef::RoundedRect(rr) => { let path = rr.to_path(self.tolerance); self.ctx.fill_path(&path); diff --git a/imaging_vello_hybrid/CHANGELOG.md b/imaging_vello_hybrid/CHANGELOG.md index 608e700..915fd8e 100644 --- a/imaging_vello_hybrid/CHANGELOG.md +++ b/imaging_vello_hybrid/CHANGELOG.md @@ -13,12 +13,21 @@ released on 2026-05-21. You can find its changes [documented below](#001-2026-05 ## [Unreleased] +### Changed + +- Updated the backend to `vello_hybrid` 0.0.9 and `wgpu` 29. + ([#64][] by [@waywardmonkeys][]) + ## [0.0.1][] (2026-05-21) This release has an [MSRV][] of 1.92. This is the initial release. +[@waywardmonkeys]: https://github.com/waywardmonkeys + +[#64]: https://github.com/forest-rs/imaging/pull/64 + [Unreleased]: https://github.com/forest-rs/imaging/compare/imaging_vello_hybrid-v0.0.1...HEAD [0.0.1]: https://github.com/forest-rs/imaging/releases/tag/imaging_vello_hybrid-v0.0.1 diff --git a/imaging_vello_hybrid/Cargo.toml b/imaging_vello_hybrid/Cargo.toml index 19865ef..78227d8 100644 --- a/imaging_vello_hybrid/Cargo.toml +++ b/imaging_vello_hybrid/Cargo.toml @@ -11,16 +11,17 @@ keywords = ["gpu", "graphics", "imaging", "rendering", "vello"] categories = ["graphics", "rendering"] [dependencies] +glifo = { default-features = false, version = "0.1" } imaging = { features = ["std"], workspace = true } -imaging_wgpu = { default-features = false, features = ["wgpu-28"], workspace = true } +imaging_wgpu = { default-features = false, features = ["wgpu-29"], workspace = true } kurbo = { default-features = true, workspace = true } peniko = { default-features = true, workspace = true } -vello_common = { default-features = true, version = "0.0.7" } -vello_hybrid = { default-features = true, version = "0.0.7" } +vello_common = { default-features = true, version = "0.0.9" } +vello_hybrid = { default-features = true, version = "0.0.9" } wgpu = { default-features = false, features = [ "std", "wgsl", -], version = "28.0.0" } +], version = "29.0.3" } [lints] workspace = true diff --git a/imaging_vello_hybrid/src/image_registry.rs b/imaging_vello_hybrid/src/image_registry.rs index e29681e..a261570 100644 --- a/imaging_vello_hybrid/src/image_registry.rs +++ b/imaging_vello_hybrid/src/image_registry.rs @@ -31,6 +31,7 @@ impl HybridImageRegistry { pub(crate) fn begin_upload_session<'a>( &'a mut self, + resources: &mut vello_hybrid::Resources, renderer: &'a mut vello_hybrid::Renderer, device: &'a wgpu::Device, queue: &'a wgpu::Queue, @@ -42,7 +43,7 @@ impl HybridImageRegistry { // and the exact memory usage isn't as important. While doing it at resolve time // can lead to situations where we evict something from the same session, // which would mean dangling image references in draw calls. - self.evict_to_budget(renderer, device, queue, &mut encoder); + self.evict_to_budget(resources, renderer, device, queue, &mut encoder); HybridImageUploadSession { registry: self, @@ -68,6 +69,7 @@ impl HybridImageRegistry { fn evict_to_budget( &mut self, + resources: &mut vello_hybrid::Resources, renderer: &mut vello_hybrid::Renderer, device: &wgpu::Device, queue: &wgpu::Queue, @@ -78,19 +80,20 @@ impl HybridImageRegistry { break; }; self.bytes_used = self.bytes_used.saturating_sub(oldest.bytes); - renderer.destroy_image(device, queue, encoder, oldest.id); + renderer.destroy_image(resources, device, queue, encoder, oldest.id); } } pub(crate) fn clear( &mut self, + resources: &mut vello_hybrid::Resources, renderer: &mut vello_hybrid::Renderer, device: &wgpu::Device, queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, ) { for image in self.live.drain(..) { - renderer.destroy_image(device, queue, encoder, image.id); + renderer.destroy_image(resources, device, queue, encoder, image.id); } self.bytes_used = 0; } @@ -106,7 +109,11 @@ pub(crate) struct HybridImageUploadSession<'a> { } impl HybridImageUploadSession<'_> { - pub(crate) fn resolve_image_brush(&mut self, brush: &ImageBrush) -> Result { + pub(crate) fn resolve_image_brush( + &mut self, + resources: &mut vello_hybrid::Resources, + brush: &ImageBrush, + ) -> Result { let key = ImageKey::derive(&brush.image); let image = if let Some(image) = self.pending.iter().find(|ri| ri.key == key).copied() { image @@ -121,6 +128,7 @@ impl HybridImageUploadSession<'_> { )); }; let id = self.renderer.upload_image( + resources, self.device, self.queue, self.encoder @@ -131,7 +139,7 @@ impl HybridImageUploadSession<'_> { let image = RegisteredImage { key, id, - may_have_opacities: pixmap.may_have_opacities(), + may_have_transparency: pixmap.may_have_transparency(), bytes: brush .image .format @@ -143,12 +151,15 @@ impl HybridImageUploadSession<'_> { }; Ok(VelloImage { - image: ImageSource::opaque_id_with_opacity_hint(image.id, image.may_have_opacities), + image: ImageSource::opaque_id_with_transparency_hint( + image.id, + image.may_have_transparency, + ), sampler: brush.sampler, }) } - pub(crate) fn finish(&mut self, success: bool) { + pub(crate) fn finish(&mut self, resources: &mut vello_hybrid::Resources, success: bool) { if success { for image in self.pending.drain(..) { self.registry.live.push_back(image); @@ -157,6 +168,7 @@ impl HybridImageUploadSession<'_> { } else { for image in self.pending.drain(..) { self.renderer.destroy_image( + resources, self.device, self.queue, self.encoder @@ -177,7 +189,7 @@ impl HybridImageUploadSession<'_> { struct RegisteredImage { key: ImageKey, id: ImageId, - may_have_opacities: bool, + may_have_transparency: bool, bytes: usize, } @@ -255,13 +267,13 @@ mod tests { let a_ri = RegisteredImage { key: a_key, id: ImageId::new(0), - may_have_opacities: true, + may_have_transparency: true, bytes: a.data.len(), }; let b_ri = RegisteredImage { key: b_key, id: ImageId::new(1), - may_have_opacities: true, + may_have_transparency: true, bytes: b.data.len(), }; diff --git a/imaging_vello_hybrid/src/lib.rs b/imaging_vello_hybrid/src/lib.rs index 96976eb..2272235 100644 --- a/imaging_vello_hybrid/src/lib.rs +++ b/imaging_vello_hybrid/src/lib.rs @@ -161,16 +161,17 @@ mod image_registry; mod scene_sink; mod wgpu_support; -use image_registry::{HybridImageRegistry, HybridImageUploadSession}; +use image_registry::HybridImageRegistry; use imaging::RgbaImage; use imaging::record::{Scene, ValidateError, replay}; use imaging::render::{ GpuReadbackError, ImageBufferFormat, ImageBufferTarget, ImageRenderer, ImageRendererError, ImageTargetError, RenderContentError, RenderSource, RenderUnsupportedError, }; -pub use imaging_wgpu::wgpu; -use imaging_wgpu::{TextureRenderer, TextureRendererError, TextureTargetError, TextureViewTarget}; -use vello_hybrid::{RenderError, RenderSize, RenderTargetConfig}; +pub use imaging_wgpu::v29::wgpu; +use imaging_wgpu::v29::{TextureRenderer, TextureViewTarget}; +use imaging_wgpu::{TextureRendererError, TextureTargetError}; +use vello_hybrid::{RenderError, RenderSize, RenderTargetConfig, TextureBindings}; use wgpu::{CommandEncoderDescriptor, TextureFormat}; use crate::wgpu_support::{ @@ -210,6 +211,7 @@ impl core::error::Error for Error {} #[derive(Debug)] pub(crate) struct VelloHybridRendererState { renderer: vello_hybrid::Renderer, + resources: vello_hybrid::Resources, device: wgpu::Device, queue: wgpu::Queue, tolerance: f64, @@ -246,6 +248,7 @@ impl VelloHybridRendererState { Self { renderer, + resources: vello_hybrid::Resources::new(), device, queue, tolerance: 0.1, @@ -253,29 +256,19 @@ impl VelloHybridRendererState { } } - pub(crate) fn begin_image_upload_session( - &mut self, - label: &'static str, - ) -> HybridImageUploadSession<'_> { - let encoder = self - .device - .create_command_encoder(&CommandEncoderDescriptor { label: Some(label) }); - self.image_registry.begin_upload_session( - &mut self.renderer, - &self.device, - &self.queue, - encoder, - ) - } - fn clear_cached_images(&mut self) { let mut encoder = self .device .create_command_encoder(&CommandEncoderDescriptor { label: Some("imaging_vello_hybrid clear cached images"), }); - self.image_registry - .clear(&mut self.renderer, &self.device, &self.queue, &mut encoder); + self.image_registry.clear( + &mut self.resources, + &mut self.renderer, + &self.device, + &self.queue, + &mut encoder, + ); self.queue.submit([encoder.finish()]); } @@ -297,11 +290,13 @@ impl VelloHybridRendererState { self.renderer .render( scene, + &mut self.resources, &self.device, &self.queue, &mut encoder, &render_size, texture_view, + &TextureBindings::new(), ) .map_err(Error::Render)?; @@ -330,13 +325,6 @@ impl VelloHybridRenderer { self.state.clear_cached_images(); } - pub(crate) fn begin_image_upload_session( - &mut self, - label: &'static str, - ) -> HybridImageUploadSession<'_> { - self.state.begin_image_upload_session(label) - } - /// Lower a semantic [`imaging::record::Scene`] into a native [`vello_hybrid::Scene`]. pub fn encode_scene( &mut self, diff --git a/imaging_vello_hybrid/src/scene_sink.rs b/imaging_vello_hybrid/src/scene_sink.rs index 2808c81..a32cdf8 100644 --- a/imaging_vello_hybrid/src/scene_sink.rs +++ b/imaging_vello_hybrid/src/scene_sink.rs @@ -3,17 +3,18 @@ use super::Error; use crate::{VelloHybridRenderer, image_registry::HybridImageUploadSession}; +use glifo::Glyph as VelloGlyph; use imaging::{ BlurredRoundedRect, ClipRef, Composite, FillRef, GeometryRef, GlyphRunRef, GroupRef, PaintSink, StrokeRef, }; use kurbo::{Affine, Shape as _}; use peniko::{Brush, BrushRef, ImageBrush, Style}; -use vello_common::glyph::Glyph as VelloGlyph; /// Borrowed adapter that streams `imaging` commands into an existing [`vello_hybrid::Scene`]. pub struct VelloHybridSceneSink<'a> { scene: &'a mut vello_hybrid::Scene, + resources: SceneSinkResources<'a>, image_upload: Option>, tolerance: f64, error: Option, @@ -21,6 +22,20 @@ pub struct VelloHybridSceneSink<'a> { group_depth: u32, } +enum SceneSinkResources<'a> { + Owned(Box), + Borrowed(&'a mut vello_hybrid::Resources), +} + +impl SceneSinkResources<'_> { + fn as_mut(&mut self) -> &mut vello_hybrid::Resources { + match self { + Self::Owned(resources) => resources.as_mut(), + Self::Borrowed(resources) => resources, + } + } +} + impl core::fmt::Debug for VelloHybridSceneSink<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("VelloHybridSceneSink") @@ -37,6 +52,7 @@ impl<'a> VelloHybridSceneSink<'a> { pub fn new(scene: &'a mut vello_hybrid::Scene) -> Self { Self { scene, + resources: SceneSinkResources::Owned(Box::new(vello_hybrid::Resources::new())), image_upload: None, tolerance: 0.1, error: None, @@ -54,11 +70,23 @@ impl<'a> VelloHybridSceneSink<'a> { scene: &'a mut vello_hybrid::Scene, renderer: &'a mut VelloHybridRenderer, ) -> Self { + let state = &mut renderer.state; + let encoder = state + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("imaging_vello_hybrid scene upload images"), + }); + let image_upload = state.image_registry.begin_upload_session( + &mut state.resources, + &mut state.renderer, + &state.device, + &state.queue, + encoder, + ); Self { scene, - image_upload: Some( - renderer.begin_image_upload_session("imaging_vello_hybrid scene upload images"), - ), + resources: SceneSinkResources::Borrowed(&mut state.resources), + image_upload: Some(image_upload), tolerance: 0.1, error: None, clip_depth: 0, @@ -84,7 +112,7 @@ impl<'a> VelloHybridSceneSink<'a> { }; if let Some(mut image_upload) = self.image_upload.take() { - image_upload.finish(result.is_ok()); + image_upload.finish(self.resources.as_mut(), result.is_ok()); } result @@ -114,7 +142,7 @@ impl<'a> VelloHybridSceneSink<'a> { self.set_error_once(Error::UnsupportedImageBrush); return None; }; - match image_upload.resolve_image_brush(image) { + match image_upload.resolve_image_brush(self.resources.as_mut(), image) { Ok(image) => Some(image), Err(err) => { self.set_error_once(err); @@ -169,13 +197,23 @@ impl<'a> VelloHybridSceneSink<'a> { .set_paint_transform(glyph_run.brush_transform.unwrap_or(Affine::IDENTITY)); self.scene.set_blend_mode(glyph_run.composite.blend); self.scene.set_paint(paint); + // TODO: Revisit this allocation. `PaintSink` currently gives us a + // one-shot iterator, while glifo's glyph builders need a cloneable + // glyph source. + let glyphs = glyphs + .map(|glyph| VelloGlyph { + id: glyph.id, + x: glyph.x, + y: glyph.y, + }) + .collect::>(); match glyph_run.style { Style::Fill(fill_rule) => { self.scene.set_fill_rule(*fill_rule); let builder = self .scene - .glyph_run(glyph_run.font) + .glyph_run(self.resources.as_mut(), glyph_run.font) .font_size(glyph_run.font_size) .hint(glyph_run.hint) .normalized_coords(glyph_run.normalized_coords); @@ -184,18 +222,13 @@ impl<'a> VelloHybridSceneSink<'a> { } else { builder }; - let glyphs = glyphs.map(|glyph| VelloGlyph { - id: glyph.id, - x: glyph.x, - y: glyph.y, - }); - builder.fill_glyphs(glyphs); + builder.fill_glyphs(glyphs.into_iter()); } Style::Stroke(stroke) => { self.scene.set_stroke(stroke.clone()); let builder = self .scene - .glyph_run(glyph_run.font) + .glyph_run(self.resources.as_mut(), glyph_run.font) .font_size(glyph_run.font_size) .hint(glyph_run.hint) .normalized_coords(glyph_run.normalized_coords); @@ -204,12 +237,7 @@ impl<'a> VelloHybridSceneSink<'a> { } else { builder }; - let glyphs = glyphs.map(|glyph| VelloGlyph { - id: glyph.id, - x: glyph.x, - y: glyph.y, - }); - builder.stroke_glyphs(glyphs); + builder.stroke_glyphs(glyphs.into_iter()); } } } diff --git a/imaging_wgpu/CHANGELOG.md b/imaging_wgpu/CHANGELOG.md index facf0d9..d5f08bc 100644 --- a/imaging_wgpu/CHANGELOG.md +++ b/imaging_wgpu/CHANGELOG.md @@ -13,12 +13,21 @@ The latest published `imaging_wgpu` release is [0.0.1](#001-2026-05-21), which w ## [Unreleased] +### Changed + +- Bumped the default renderer lane to `wgpu` 29 while keeping `wgpu` 27 and 28 available through + explicit version features and modules. ([#64][] by [@waywardmonkeys][]) + ## [0.0.1][] (2026-05-21) This release has an [MSRV][] of 1.92. This is the initial release. +[@waywardmonkeys]: https://github.com/waywardmonkeys + +[#64]: https://github.com/forest-rs/imaging/pull/64 + [Unreleased]: https://github.com/forest-rs/imaging/compare/imaging_wgpu-v0.0.1...HEAD [0.0.1]: https://github.com/forest-rs/imaging/releases/tag/imaging_wgpu-v0.0.1 diff --git a/imaging_wgpu/Cargo.toml b/imaging_wgpu/Cargo.toml index 063c1d5..e6a1d64 100644 --- a/imaging_wgpu/Cargo.toml +++ b/imaging_wgpu/Cargo.toml @@ -11,21 +11,23 @@ keywords = ["graphics", "imaging", "rendering", "wgpu"] categories = ["graphics", "rendering"] [features] -default = ["wgpu-28"] -# Normal consumers should enable exactly one version feature. If both are enabled by a -# workspace-wide `--all-features` build, the crate exports `wgpu-28` deterministically. +default = ["wgpu-29"] +# Normal consumers should enable exactly one version feature. If multiple are enabled by a +# workspace-wide `--all-features` build, the crate exports `wgpu-29` deterministically. wgpu-27 = ["dep:wgpu_27"] wgpu-28 = ["dep:wgpu_28"] +wgpu-29 = ["dep:wgpu_29"] [dependencies] imaging = { features = ["std"], workspace = true } wgpu_27 = { default-features = false, features = ["std"], optional = true, package = "wgpu", version = "27.0.1" } wgpu_28 = { default-features = false, features = ["std"], optional = true, package = "wgpu", version = "28.0.0" } +wgpu_29 = { default-features = false, features = ["std"], optional = true, package = "wgpu", version = "29.0.3" } [lints] workspace = true [package.metadata.docs.rs] -features = ["wgpu-28"] +features = ["wgpu-29"] default-target = "x86_64-unknown-linux-gnu" targets = [] diff --git a/imaging_wgpu/README.md b/imaging_wgpu/README.md index 15f8e95..05fa353 100644 --- a/imaging_wgpu/README.md +++ b/imaging_wgpu/README.md @@ -23,18 +23,20 @@ Full documentation at https://github.com/orium/cargo-rdme --> `wgpu` texture rendering traits for `imaging` backends. -The default feature set enables `wgpu-28`. Consumers that need `wgpu-27` should disable -default features and enable `wgpu-27`. +The default feature set enables `wgpu-29`. Consumers that need `wgpu-27` or `wgpu-28` +should disable default features and enable the matching version feature. -Workspace-wide `--all-features` builds enable both, so this crate resolves that case -deterministically by exporting `wgpu-28` as [`wgpu`] and keeping `wgpu-27` linked only to -satisfy older dependents that may still request it transitively. +Workspace-wide `--all-features` builds enable multiple lanes, so this crate resolves that case +deterministically by exporting `wgpu-29` as [`wgpu`]. Backends that must stay on an older +`wgpu` version should use the explicit [`v27`] or [`v28`] module. This crate is `std`-only because it depends on `wgpu`. [`wgpu`]: https://docs.rs/imaging_wgpu/latest/imaging_wgpu/wgpu/ +[`v27`]: https://docs.rs/imaging_wgpu/latest/imaging_wgpu/v27/ +[`v28`]: https://docs.rs/imaging_wgpu/latest/imaging_wgpu/v28/ ## Minimum supported Rust Version (MSRV) diff --git a/imaging_wgpu/src/lib.rs b/imaging_wgpu/src/lib.rs index 9bae24e..3233912 100644 --- a/imaging_wgpu/src/lib.rs +++ b/imaging_wgpu/src/lib.rs @@ -3,57 +3,22 @@ //! `wgpu` texture rendering traits for `imaging` backends. //! -//! The default feature set enables `wgpu-28`. Consumers that need `wgpu-27` should disable -//! default features and enable `wgpu-27`. +//! The default feature set enables `wgpu-29`. Consumers that need `wgpu-27` or `wgpu-28` +//! should disable default features and enable the matching version feature. //! -//! Workspace-wide `--all-features` builds enable both, so this crate resolves that case -//! deterministically by exporting `wgpu-28` as [`wgpu`] and keeping `wgpu-27` linked only to -//! satisfy older dependents that may still request it transitively. +//! Workspace-wide `--all-features` builds enable multiple lanes, so this crate resolves that case +//! deterministically by exporting `wgpu-29` as [`wgpu`]. Backends that must stay on an older +//! `wgpu` version should use the explicit [`v27`] or [`v28`] module. //! //! This crate is `std`-only because it depends on `wgpu`. #![deny(unsafe_code)] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -use imaging::render::{ImageRenderer, RenderSource}; use std::boxed::Box; -use std::vec::Vec; -#[cfg(not(any(feature = "wgpu-27", feature = "wgpu-28")))] -compile_error!("Enable one of `wgpu-27` or `wgpu-28`."); - -// `cargo --all-features` enables both version flags across the workspace. Prefer the newer API -// surface in that case so the crate still compiles deterministically. -#[cfg(all(feature = "wgpu-27", feature = "wgpu-28"))] -use wgpu_27 as _; - -#[cfg(all(not(feature = "wgpu-28"), feature = "wgpu-27"))] -pub use wgpu_27 as wgpu; -#[cfg(feature = "wgpu-28")] -pub use wgpu_28 as wgpu; - -/// Shared `wgpu` texture-view render target used by view-based [`TextureRenderer`] backends. -#[derive(Clone, Debug)] -pub struct TextureViewTarget { - /// Render-target texture view. - pub view: wgpu::TextureView, - /// Effective render width in pixels. - pub width: u32, - /// Effective render height in pixels. - pub height: u32, -} - -impl TextureViewTarget { - /// Create a shared texture-view render target wrapper. - #[must_use] - pub fn new(view: &wgpu::TextureView, width: u32, height: u32) -> Self { - Self { - view: view.clone(), - width, - height, - } - } -} +#[cfg(not(any(feature = "wgpu-27", feature = "wgpu-28", feature = "wgpu-29")))] +compile_error!("Enable one of `wgpu-27`, `wgpu-28`, or `wgpu-29`."); /// Shared texture-render-target failures surfaced by texture renderers. #[derive(Debug)] @@ -136,38 +101,93 @@ impl core::error::Error for TextureRendererError { } } -/// Renderer capability for drawing a [`RenderSource`] into a backend-selected `wgpu` texture target. -/// -/// These methods intentionally use names distinct from [`imaging::render::ImageRenderer`] so -/// renderers that implement both traits can be called without fully qualified syntax. -pub trait TextureRenderer: ImageRenderer { - /// Concrete caller-owned target type consumed by this renderer. - type TextureTarget; - - /// Owned texture type returned by [`Self::render_source_texture`]. - type Texture; - - /// Return the `wgpu` texture formats this renderer can draw into directly. - /// - /// Callers can use this to preflight swapchain or offscreen target formats before calling - /// [`Self::render_source_into_texture`]. - fn supported_texture_formats(&self) -> Vec; - - /// Render a source into a caller-provided texture target. - /// - /// Renderers should treat the target as a fresh output and may clear or overwrite any - /// existing contents before drawing. - fn render_source_into_texture( - &mut self, - source: &mut dyn RenderSource, - target: Self::TextureTarget, - ) -> Result<(), TextureRendererError>; - - /// Render a source and return a backend-owned texture. - fn render_source_texture( - &mut self, - source: &mut dyn RenderSource, - width: u32, - height: u32, - ) -> Result; +macro_rules! define_wgpu_lane { + ($module:ident, $wgpu:ident) => { + /// Version-specific `wgpu` texture rendering traits and target wrappers. + pub mod $module { + use imaging::render::{ImageRenderer, RenderSource}; + use std::vec::Vec; + + pub use $wgpu as wgpu; + + /// Shared `wgpu` texture-view render target used by view-based [`TextureRenderer`] + /// backends. + #[derive(Clone, Debug)] + pub struct TextureViewTarget { + /// Render-target texture view. + pub view: wgpu::TextureView, + /// Effective render width in pixels. + pub width: u32, + /// Effective render height in pixels. + pub height: u32, + } + + impl TextureViewTarget { + /// Create a shared texture-view render target wrapper. + #[must_use] + pub fn new(view: &wgpu::TextureView, width: u32, height: u32) -> Self { + Self { + view: view.clone(), + width, + height, + } + } + } + + /// Renderer capability for drawing a [`RenderSource`] into a backend-selected `wgpu` + /// texture target. + /// + /// These methods intentionally use names distinct from + /// [`imaging::render::ImageRenderer`] so renderers that implement both traits can be + /// called without fully qualified syntax. + pub trait TextureRenderer: ImageRenderer { + /// Concrete caller-owned target type consumed by this renderer. + type TextureTarget; + + /// Owned texture type returned by [`Self::render_source_texture`]. + type Texture; + + /// Return the `wgpu` texture formats this renderer can draw into directly. + /// + /// Callers can use this to preflight swapchain or offscreen target formats before + /// calling [`Self::render_source_into_texture`]. + fn supported_texture_formats(&self) -> Vec; + + /// Render a source into a caller-provided texture target. + /// + /// Renderers should treat the target as a fresh output and may clear or overwrite + /// any existing contents before drawing. + fn render_source_into_texture( + &mut self, + source: &mut dyn RenderSource, + target: Self::TextureTarget, + ) -> Result<(), crate::TextureRendererError>; + + /// Render a source and return a backend-owned texture. + fn render_source_texture( + &mut self, + source: &mut dyn RenderSource, + width: u32, + height: u32, + ) -> Result; + } + } + }; } + +#[cfg(feature = "wgpu-27")] +define_wgpu_lane!(v27, wgpu_27); +#[cfg(feature = "wgpu-28")] +define_wgpu_lane!(v28, wgpu_28); +#[cfg(feature = "wgpu-29")] +define_wgpu_lane!(v29, wgpu_29); + +#[cfg(all( + not(any(feature = "wgpu-28", feature = "wgpu-29")), + feature = "wgpu-27" +))] +pub use v27::{TextureRenderer, TextureViewTarget, wgpu}; +#[cfg(all(not(feature = "wgpu-29"), feature = "wgpu-28"))] +pub use v28::{TextureRenderer, TextureViewTarget, wgpu}; +#[cfg(feature = "wgpu-29")] +pub use v29::{TextureRenderer, TextureViewTarget, wgpu};