From d7aeafaf84cd9823dc554677eee97f5ffa528780 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 16 Aug 2026 21:34:04 +0200 Subject: [PATCH] Move to wgpu 29, the version Slint can share a device with MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Groundwork for spike S1. Importing a texture into a Slint scene requires it to come from the *same* `wgpu::Device` Slint renders with, and Slint hands out a device of the version it was compiled against. Slint 1.17 offers `unstable-wgpu-28` and `unstable-wgpu-29` and nothing older, so wgpu 23 could never have met it: two semver-incompatible wgpu crates in one tree are two distinct types, and the device would not typecheck across the gap. The version is therefore not a free choice, and the manifest now says so — Slint and wgpu move together or not at all. The Slint requirement is also corrected from "1.9" to the 1.17 it has actually been resolving to. Nothing about the render path changes here. The readback bridge is still in place and still the display path, so this is verified by the tests that already existed rather than by anything new: 39 dr-gpu tests, which compare real pixels off a real device, and 888 across the workspace, all passing. Zero-copy lands separately and small. What the six releases cost, in full: - `ImageCopyTexture`/`ImageCopyBuffer`/`ImageDataLayout` became the `TexelCopy*` names (24). - `Instance::new` takes the descriptor by value, and `InstanceDescriptor` lost its `Default` — it carries a boxed display handle now, so a headless context says `new_without_display_handle` and means it. - `request_adapter` returns `Result` rather than `Option` (24). - `DeviceDescriptor` absorbed the API trace from `request_device`'s second argument and gained `experimental_features` (25). - `PipelineLayoutDescriptor` takes `Option<&BindGroupLayout>` per slot, and `push_constant_ranges` became `immediate_size`. - `Maintain` became `PollType`, and `poll` is fallible. Two of those are improvements worth having rather than churn. The error scope is a guard whose `pop` runs on drop, so an early return from the pipeline compiler no longer leaves a scope open on the device for whatever ran next to fall into. And a fallible `poll` reports a lost device (NFR-R7) at the point it happens, where before the map callback simply never arrived and the failure surfaced later as a readback that spun out its poll limit. Still to do for S1: dr-ui renders through `renderer-femtovg`, which is OpenGL. Texture import needs Slint itself rendering on wgpu. Co-Authored-By: Claude Opus 5 --- Cargo.lock | 373 +++++++++++++------------------- Cargo.toml | 18 +- core/dr-gpu/examples/bench.rs | 4 +- core/dr-gpu/examples/develop.rs | 14 +- core/dr-gpu/src/adjust.rs | 38 +++- core/dr-gpu/src/demosaic.rs | 14 +- core/dr-gpu/src/lib.rs | 68 +++--- docs/traceability.md | 4 +- 8 files changed, 260 insertions(+), 273 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f67bebd..3874c60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,7 +218,7 @@ checksum = "f211a51805bc641f3ad5b7664c77d2547af685cc33b4cd8d31964027a46f13f1" dependencies = [ "anstyle", "memchr", - "unicode-width 0.2.2", + "unicode-width", ] [[package]] @@ -592,18 +592,18 @@ dependencies = [ [[package]] name = "bit-set" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +checksum = "34ddef2995421ab6a5c779542c81ee77c115206f4ad9d5a8e05f4ff49716a3dd" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" [[package]] name = "bit_field" @@ -635,12 +635,6 @@ dependencies = [ "no_std_io2", ] -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - [[package]] name = "block-buffer" version = "0.10.4" @@ -697,7 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a88b7ea17d208c4193f2c1e6de3c35fe71f98c96982d5ced308bdcc749ff6e1f" dependencies = [ "bytes", - "cfg_aliases 0.2.2", + "cfg_aliases", ] [[package]] @@ -859,12 +853,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cfg_aliases" version = "0.2.2" @@ -934,12 +922,13 @@ dependencies = [ [[package]] name = "codespan-reporting" -version = "0.11.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" dependencies = [ + "serde", "termcolor", - "unicode-width 0.1.14", + "unicode-width", ] [[package]] @@ -1740,7 +1729,7 @@ dependencies = [ "bitflags 2.13.1", "bytemuck", "fnv", - "glow 0.17.0", + "glow", "imgref", "itertools 0.14.0", "log", @@ -1869,8 +1858,8 @@ dependencies = [ "read-fonts 0.39.2", "roxmltree 0.21.1", "smallvec", - "windows 0.62.2", - "windows-core 0.62.2", + "windows", + "windows-core", "yeslogic-fontconfig-sys", ] @@ -2059,7 +2048,7 @@ version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ - "unicode-width 0.2.2", + "unicode-width", ] [[package]] @@ -2129,18 +2118,6 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" -[[package]] -name = "glow" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483" -dependencies = [ - "js-sys", - "slotmap", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "glow" version = "0.17.0" @@ -2160,7 +2137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12124de845cacfebedff80e877bb37b5b75c34c5a4c89e47e1cdd67fb6041325" dependencies = [ "bitflags 2.13.1", - "cfg_aliases 0.2.2", + "cfg_aliases", "cgl", "dispatch2", "glutin_egl_sys", @@ -2184,7 +2161,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" dependencies = [ - "cfg_aliases 0.2.2", + "cfg_aliases", "glutin", "raw-window-handle", "winit", @@ -2219,35 +2196,18 @@ dependencies = [ "gl_generator", ] -[[package]] -name = "gpu-alloc" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45cf04b2726f02df5508c6de726acdc90cdf97ac771a9a0ffd8ba10a6e696bf9" -dependencies = [ - "bitflags 2.13.1", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bbed164dd10ed526c2e4fe3e721ca4a71c61730e5aafac6844b417b3227058" -dependencies = [ - "bitflags 2.13.1", -] - [[package]] name = "gpu-allocator" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" dependencies = [ + "ash", + "hashbrown 0.16.1", "log", "presser", - "thiserror 1.0.69", - "windows 0.58.0", + "thiserror 2.0.20", + "windows", ] [[package]] @@ -2284,6 +2244,7 @@ checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "num-traits", "zerocopy", ] @@ -2518,7 +2479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68e76f2b13846ca54bba6b8eb3b5454b26879ad987396d0a2d8abedc31a6c469" dependencies = [ "calloop 0.14.4", - "cfg_aliases 0.2.2", + "cfg_aliases", "drm", "gbm", "glutin", @@ -2538,7 +2499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2247a4590a02a466b2f4916cc789dfe66247f6af826f00eb84a2685259a45c1c" dependencies = [ "cfg-if", - "cfg_aliases 0.2.2", + "cfg_aliases", "i-slint-backend-android-activity", "i-slint-backend-linuxkms", "i-slint-backend-winit", @@ -2556,7 +2517,7 @@ checksum = "a27c7e8f53418d3017362465367b6612b6e439a68097d627d1b91c94b885f0a6" dependencies = [ "block2 0.6.2", "cfg-if", - "cfg_aliases 0.2.2", + "cfg_aliases", "copypasta", "derive_more", "futures", @@ -2584,7 +2545,7 @@ dependencies = [ "wasm-bindgen", "web-sys", "webbrowser", - "windows 0.62.2", + "windows", "winit", "zbus", ] @@ -2687,7 +2648,7 @@ dependencies = [ "wasm-bindgen", "web-sys", "web-time", - "windows 0.62.2", + "windows", ] [[package]] @@ -2711,7 +2672,7 @@ dependencies = [ "const-field-offset", "derive_more", "femtovg", - "glow 0.17.0", + "glow", "i-slint-common", "i-slint-core", "i-slint-core-macros", @@ -2731,11 +2692,11 @@ checksum = "7b6eed7f3f0a9a3d3ca6e8b9d4ca233371d989351fdb2a7ab88ec368b99e7b57" dependencies = [ "bytemuck", "cfg-if", - "cfg_aliases 0.2.2", + "cfg_aliases", "clru", "const-field-offset", "derive_more", - "glow 0.17.0", + "glow", "glutin", "i-slint-common", "i-slint-core", @@ -2756,7 +2717,7 @@ dependencies = [ "softbuffer", "unicode-segmentation", "vtable", - "windows 0.62.2", + "windows", "write-fonts", ] @@ -2792,7 +2753,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -3751,15 +3712,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - [[package]] name = "maybe-rayon" version = "0.1.1" @@ -3800,21 +3752,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "metal" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" -dependencies = [ - "bitflags 2.13.1", - "block", - "core-graphics-types", - "foreign-types", - "log", - "objc", - "paste", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3895,23 +3832,28 @@ dependencies = [ [[package]] name = "naga" -version = "23.1.0" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f" +checksum = "b2bf919621e7975acb27d881bae2fb993e0d45c8e0446e85e6272971e00dc8df" dependencies = [ "arrayvec", "bit-set", "bitflags 2.13.1", - "cfg_aliases 0.1.1", + "cfg-if", + "cfg_aliases", "codespan-reporting", + "half", + "hashbrown 0.16.1", "hexf-parse", "indexmap", + "libm", "log", + "num-traits", + "once_cell", "rustc-hash 1.1.0", "spirv", - "termcolor", - "thiserror 1.0.69", - "unicode-xid", + "thiserror 2.0.20", + "unicode-ident", ] [[package]] @@ -3987,7 +3929,7 @@ checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ "bitflags 2.13.1", "cfg-if", - "cfg_aliases 0.2.2", + "cfg_aliases", "libc", ] @@ -4132,15 +4074,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "objc-sys" version = "0.3.5" @@ -4417,6 +4350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" dependencies = [ "bitflags 2.13.1", + "block2 0.6.2", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -4557,6 +4491,15 @@ dependencies = [ "libredox", ] +[[package]] +name = "ordered-float" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-stream" version = "0.2.0" @@ -5327,7 +5270,7 @@ dependencies = [ "natord", "snafu", "unicode-linebreak", - "unicode-width 0.2.2", + "unicode-width", ] [[package]] @@ -5797,7 +5740,7 @@ checksum = "9f512ac418a64194842dd05566320805dad1c957c521039db2486fd6368865bc" dependencies = [ "bitflags 2.13.1", "skia-bindings", - "windows 0.62.2", + "windows", ] [[package]] @@ -6043,9 +5986,9 @@ dependencies = [ [[package]] name = "spirv" -version = "0.3.0+sdk-1.3.268.0" +version = "0.4.0+sdk-1.4.341.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f" dependencies = [ "bitflags 2.13.1", ] @@ -6728,12 +6671,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-width" version = "0.2.2" @@ -7173,17 +7110,22 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "wgpu" -version = "23.0.1" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f70000db37c469ea9d67defdc13024ddf9a5f1b89cb2941b812ad7cde1735a" +checksum = "76e8840e1ba2881d4cbb18d2147627a56af426ff064c0401eb0c8410c6325d07" dependencies = [ "arrayvec", - "cfg_aliases 0.1.1", + "bitflags 2.13.1", + "bytemuck", + "cfg-if", + "cfg_aliases", "document-features", + "hashbrown 0.16.1", "js-sys", "log", "naga", "parking_lot", + "portable-atomic", "profiling", "raw-window-handle", "smallvec", @@ -7198,82 +7140,139 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "23.0.1" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a" +checksum = "2f519832254e56965a9940c4af57dcb75f702b6f6fa4a0b172f685395843a4d7" dependencies = [ "arrayvec", + "bit-set", "bit-vec", "bitflags 2.13.1", - "cfg_aliases 0.1.1", + "bytemuck", + "cfg_aliases", "document-features", + "hashbrown 0.16.1", "indexmap", "log", "naga", "once_cell", "parking_lot", + "portable-atomic", "profiling", "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.20", + "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", + "wgpu-core-deps-windows-linux-android", "wgpu-hal", + "wgpu-naga-bridge", "wgpu-types", ] [[package]] -name = "wgpu-hal" -version = "23.0.1" +name = "wgpu-core-deps-apple" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89364b8a0b211adc7b16aeaf1bd5ad4a919c1154b44c9ce27838213ba05fd821" +checksum = "f5e39e26c4c0e07589e67d18546cf79ff45383659fc72fca4dd293358a0347f3" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-emscripten" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e09be551dc939498bdd5f6b2c66e55ab275dad25825267a08605a80fc9f0af" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-windows-linux-android" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e592c1bbef6ad047647ae6e666ebd8cee7a32bb4544d9700ec96cbf73230257" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-hal" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ace1c17727311c22a46e4e3faf56ea6de81af99dcc839bdfb54857b94d448d" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set", "bitflags 2.13.1", - "block", + "block2 0.6.2", "bytemuck", - "cfg_aliases 0.1.1", - "core-graphics-types", - "glow 0.14.2", + "cfg-if", + "cfg_aliases", + "glow", "glutin_wgl_sys", - "gpu-alloc", "gpu-allocator", "gpu-descriptor", + "hashbrown 0.16.1", "js-sys", "khronos-egl", "libc", "libloading", "log", - "metal", "naga", - "ndk-sys 0.5.0+25.2.9519653", - "objc", + "ndk-sys 0.6.0+11769913", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", + "objc2-quartz-core 0.3.2", "once_cell", + "ordered-float", "parking_lot", + "portable-atomic", + "portable-atomic-util", "profiling", "range-alloc", "raw-window-handle", + "raw-window-metal", "renderdoc-sys", - "rustc-hash 1.1.0", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.20", "wasm-bindgen", + "wayland-sys", "web-sys", + "wgpu-naga-bridge", + "wgpu-types", + "windows", + "windows-core", + "windows-result", +] + +[[package]] +name = "wgpu-naga-bridge" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95226013f547544b223281cd16a4fb549aa9dcb562adbda0faae4c73ffbbc161" +dependencies = [ + "naga", "wgpu-types", - "windows 0.58.0", - "windows-core 0.58.0", ] [[package]] name = "wgpu-types" -version = "23.0.0" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068" +checksum = "84bf84cd9ca8ca45e2b223a3868f1adf9bfc0c66aeac212e76ee7e40fdadf8f5" dependencies = [ "bitflags 2.13.1", + "bytemuck", "js-sys", + "log", + "raw-window-handle", "web-sys", ] @@ -7286,16 +7285,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.62.2" @@ -7303,7 +7292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ "windows-collections", - "windows-core 0.62.2", + "windows-core", "windows-future", "windows-numerics", ] @@ -7314,20 +7303,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core 0.62.2", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -7336,11 +7312,11 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement 0.60.2", - "windows-interface 0.59.3", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.4.1", - "windows-strings 0.5.1", + "windows-result", + "windows-strings", ] [[package]] @@ -7349,22 +7325,11 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.62.2", + "windows-core", "windows-link", "windows-threading", ] -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "windows-implement" version = "0.60.2" @@ -7376,17 +7341,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "windows-interface" version = "0.59.3" @@ -7423,19 +7377,10 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core 0.62.2", + "windows-core", "windows-link", ] -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.4.1" @@ -7445,16 +7390,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.5.1" @@ -7709,7 +7644,7 @@ dependencies = [ "block2 0.5.1", "bytemuck", "calloop 0.13.0", - "cfg_aliases 0.2.2", + "cfg_aliases", "concurrent-queue", "core-foundation 0.9.4", "core-graphics", diff --git a/Cargo.toml b/Cargo.toml index 5461121..0e1c692 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,9 +39,21 @@ dr-sync-nextcloud = { path = "core/dr-sync-nextcloud" } dr-ui = { path = "ui/dr-ui" } # GPU + UI -wgpu = "23" -slint = { version = "1.9", default-features = false } -slint-build = "1.9" +# +# The wgpu version is not a free choice: it is dictated by Slint. Importing a +# texture into the scene (ARCH §6.1, spike S1) requires it to come from the +# *same* `wgpu::Device` Slint renders with, and Slint will only hand out a +# device of the version it was compiled against. Slint 1.17 offers +# `unstable-wgpu-28` and `unstable-wgpu-29` and nothing older, so 29 it is — +# pinned to the same `29.0.4` floor Slint itself requires, because two +# semver-compatible-but-different wgpu crates in one tree are two *types*, and +# the device would not typecheck across them. +# +# Consequently: bumping Slint may force a wgpu bump, and wgpu cannot be bumped +# on its own. They move together or not at all. +wgpu = "29.0.4" +slint = { version = "1.17", default-features = false } +slint-build = "1.17" # UI token codegen (S2): style.yaml -> theme.slint. serde_yaml was deprecated # by its maintainer in 2024 and serde_yml, the first fork, has since been diff --git a/core/dr-gpu/examples/bench.rs b/core/dr-gpu/examples/bench.rs index d4c0a1d..ce22204 100644 --- a/core/dr-gpu/examples/bench.rs +++ b/core/dr-gpu/examples/bench.rs @@ -31,7 +31,9 @@ fn main() { for i in 0..n { rt.render(i as f32 * 0.01); } - ctx.device.poll(wgpu::Maintain::Wait); + ctx.device + .poll(wgpu::PollType::wait_indefinitely()) + .expect("poll"); let compute = t0.elapsed().as_secs_f64() / n as f64; let t1 = Instant::now(); diff --git a/core/dr-gpu/examples/develop.rs b/core/dr-gpu/examples/develop.rs index 9fa6084..2f65762 100644 --- a/core/dr-gpu/examples/develop.rs +++ b/core/dr-gpu/examples/develop.rs @@ -14,7 +14,7 @@ use dr_gpu::{AdjustPass, Demosaicer, GpuContext}; use dr_pipeline::ops::{ blacks_whites, brilliance, colour_mixer, contrast, curve, exposure, highlights_shadows, - saturation, vibrance, white_balance, + vibrance, white_balance, }; use dr_pipeline::{EditGraph, ParamId}; @@ -46,7 +46,9 @@ fn main() { let t1 = std::time::Instant::now(); let demosaicer = Demosaicer::new(&ctx).expect("demosaicer"); let image = demosaicer.run(&raw).expect("demosaic"); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.device + .poll(wgpu::PollType::wait_indefinitely()) + .expect("poll"); println!("demosaiced {:.0} ms", t1.elapsed().as_secs_f32() * 1000.0); // Build an edit. The presets exist so the output can be eyeballed for @@ -123,7 +125,9 @@ fn main() { let t2 = std::time::Instant::now(); adjust.render(&image, &shader, w, h).expect("adjust"); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.device + .poll(wgpu::PollType::wait_indefinitely()) + .expect("poll"); println!("adjusted {:.2} ms", t2.elapsed().as_secs_f32() * 1000.0); // Time a second render with only a value changed: this is the slider @@ -132,7 +136,9 @@ fn main() { let again = graph.compose(); let t3 = std::time::Instant::now(); adjust.render(&image, &again, w, h).expect("adjust"); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.device + .poll(wgpu::PollType::wait_indefinitely()) + .expect("poll"); println!( "re-render {:.2} ms ({} pipeline(s) compiled)", t3.elapsed().as_secs_f32() * 1000.0, diff --git a/core/dr-gpu/src/adjust.rs b/core/dr-gpu/src/adjust.rs index 1715b01..f62e29f 100644 --- a/core/dr-gpu/src/adjust.rs +++ b/core/dr-gpu/src/adjust.rs @@ -105,8 +105,8 @@ impl AdjustPass { .device .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("adjust-layout"), - bind_group_layouts: &[&bind_group_layout], - push_constant_ranges: &[], + bind_group_layouts: &[Some(&bind_group_layout)], + immediate_size: 0, }); Self { @@ -127,7 +127,13 @@ impl AdjustPass { // A validation error here is a codegen bug, not a user error. // Push an error scope so it surfaces as a Result rather than a // panic from wgpu's default handler. - self.ctx + // + // Since wgpu 29 the scope is a guard rather than a device-level + // push/pop pair, which is the better shape: an early return from + // this function pops it on drop instead of leaving a scope open on + // the device for whatever ran next to fall into. + let scope = self + .ctx .device .push_error_scope(wgpu::ErrorFilter::Validation); @@ -151,7 +157,7 @@ impl AdjustPass { cache: None, }); - if let Some(err) = pollster::block_on(self.ctx.device.pop_error_scope()) { + if let Some(err) = pollster::block_on(scope.pop()) { return Err(GpuError::ShaderCompilation(format!( "{err}\n\n--- generated source ---\n{}", numbered(&shader.source) @@ -335,15 +341,15 @@ impl AdjustPass { let mut enc = self.ctx.device.create_command_encoder(&Default::default()); enc.copy_texture_to_buffer( - wgpu::ImageCopyTexture { + wgpu::TexelCopyTextureInfo { texture: &target.texture, mip_level: 0, origin: wgpu::Origin3d::ZERO, aspect: wgpu::TextureAspect::All, }, - wgpu::ImageCopyBuffer { + wgpu::TexelCopyBufferInfo { buffer: &buf, - layout: wgpu::ImageDataLayout { + layout: wgpu::TexelCopyBufferLayout { offset: 0, bytes_per_row: Some(padded), rows_per_image: Some(h), @@ -376,7 +382,13 @@ impl AdjustPass { // reporting an error. let mut mapped = None; for _ in 0..READBACK_POLL_LIMIT { - self.ctx.device.poll(wgpu::Maintain::Poll); + // A poll error is a lost device, which is exactly the case the + // bounded spin exists to escape — returning here reports it + // immediately rather than spinning out the full limit first. + self.ctx + .device + .poll(wgpu::PollType::Poll) + .map_err(|e| GpuError::Readback(e.to_string()))?; match rx.try_recv() { Ok(r) => { mapped = Some(r); @@ -485,15 +497,15 @@ mod tests { let mut enc = ctx.device.create_command_encoder(&Default::default()); enc.copy_texture_to_buffer( - wgpu::ImageCopyTexture { + wgpu::TexelCopyTextureInfo { texture: tex, mip_level: 0, origin: wgpu::Origin3d::ZERO, aspect: wgpu::TextureAspect::All, }, - wgpu::ImageCopyBuffer { + wgpu::TexelCopyBufferInfo { buffer: &buf, - layout: wgpu::ImageDataLayout { + layout: wgpu::TexelCopyBufferLayout { offset: 0, bytes_per_row: Some(padded), rows_per_image: Some(h), @@ -512,7 +524,9 @@ mod tests { slice.map_async(wgpu::MapMode::Read, move |r| { let _ = tx.send(r); }); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.device + .poll(wgpu::PollType::wait_indefinitely()) + .expect("poll"); rx.recv().expect("map").expect("map ok"); let data = slice.get_mapped_range(); diff --git a/core/dr-gpu/src/demosaic.rs b/core/dr-gpu/src/demosaic.rs index 49ab10b..6e84077 100644 --- a/core/dr-gpu/src/demosaic.rs +++ b/core/dr-gpu/src/demosaic.rs @@ -281,8 +281,8 @@ impl Demosaicer { .device .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("demosaic-layout"), - bind_group_layouts: &[&bind_group_layout], - push_constant_ranges: &[], + bind_group_layouts: &[Some(&bind_group_layout)], + immediate_size: 0, }); let pipeline = ctx @@ -648,15 +648,15 @@ mod tests { let mut enc = ctx.device.create_command_encoder(&Default::default()); enc.copy_texture_to_buffer( - wgpu::ImageCopyTexture { + wgpu::TexelCopyTextureInfo { texture: img.texture(), mip_level: 0, origin: wgpu::Origin3d::ZERO, aspect: wgpu::TextureAspect::All, }, - wgpu::ImageCopyBuffer { + wgpu::TexelCopyBufferInfo { buffer: &buf, - layout: wgpu::ImageDataLayout { + layout: wgpu::TexelCopyBufferLayout { offset: 0, bytes_per_row: Some(padded), rows_per_image: Some(h), @@ -675,7 +675,9 @@ mod tests { slice.map_async(wgpu::MapMode::Read, move |r| { let _ = tx.send(r); }); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.device + .poll(wgpu::PollType::wait_indefinitely()) + .expect("poll"); rx.recv().expect("map").expect("map ok"); let data = slice.get_mapped_range(); diff --git a/core/dr-gpu/src/lib.rs b/core/dr-gpu/src/lib.rs index 58ce16e..1b7fb92 100644 --- a/core/dr-gpu/src/lib.rs +++ b/core/dr-gpu/src/lib.rs @@ -35,12 +35,15 @@ impl GpuContext { /// /// Used by tests and by the Slint path, which supplies its own surface. pub async fn new_headless() -> Result { - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - // Vulkan on both targets (D1). GL is allowed as a fallback so a - // machine without a Vulkan loader still runs the tests. - backends: wgpu::Backends::VULKAN | wgpu::Backends::GL, - ..Default::default() - }); + // `new_without_display_handle` rather than a struct literal: the + // descriptor carries a boxed display handle and so has no `Default`, + // and a headless context is precisely the case with no display to + // hand it. + let mut descriptor = wgpu::InstanceDescriptor::new_without_display_handle(); + // Vulkan on both targets (D1). GL is allowed as a fallback so a + // machine without a Vulkan loader still runs the tests. + descriptor.backends = wgpu::Backends::VULKAN | wgpu::Backends::GL; + let instance = wgpu::Instance::new(descriptor); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { @@ -49,7 +52,10 @@ impl GpuContext { force_fallback_adapter: false, }) .await - .ok_or(GpuError::NoAdapter)?; + // A `Result` since wgpu 24, where it was an `Option`. The error + // says which backends were tried, which is worth more than the + // bare "no adapter" this used to report. + .map_err(|_| GpuError::NoAdapter)?; let adapter_info = adapter.get_info(); log::info!( @@ -60,19 +66,22 @@ impl GpuContext { ); let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: Some("darkroom-device"), - required_features: wgpu::Features::empty(), - // Defaults, not `downlevel_defaults`: storage textures - // in compute shaders are required, and the downlevel tier - // does not guarantee them. This is effectively our GPU - // floor (NFR-COMPAT-1). - required_limits: wgpu::Limits::default(), - memory_hints: wgpu::MemoryHints::Performance, - }, - None, - ) + .request_device(&wgpu::DeviceDescriptor { + label: Some("darkroom-device"), + required_features: wgpu::Features::empty(), + // Defaults, not `downlevel_defaults`: storage textures + // in compute shaders are required, and the downlevel tier + // does not guarantee them. This is effectively our GPU + // floor (NFR-COMPAT-1). + required_limits: wgpu::Limits::default(), + memory_hints: wgpu::MemoryHints::Performance, + // Nothing behind a feature flag wgpu itself calls unstable — + // the pipeline is ordinary compute and storage textures. + experimental_features: wgpu::ExperimentalFeatures::disabled(), + // The API trace, absorbed into the descriptor in wgpu 25 from + // the second argument this call used to take. + trace: wgpu::Trace::Off, + }) .await .map_err(|e| GpuError::DeviceRequest(e.to_string()))?; @@ -182,8 +191,8 @@ impl RenderTarget { .device .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("render-target-layout"), - bind_group_layouts: &[&bind_group_layout], - push_constant_ranges: &[], + bind_group_layouts: &[Some(&bind_group_layout)], + immediate_size: 0, }); let pipeline = ctx @@ -370,15 +379,15 @@ impl RenderTarget { let mut enc = self.ctx.device.create_command_encoder(&Default::default()); enc.copy_texture_to_buffer( - wgpu::ImageCopyTexture { + wgpu::TexelCopyTextureInfo { texture: &self.texture, mip_level: 0, origin: wgpu::Origin3d::ZERO, aspect: wgpu::TextureAspect::All, }, - wgpu::ImageCopyBuffer { + wgpu::TexelCopyBufferInfo { buffer: buf, - layout: wgpu::ImageDataLayout { + layout: wgpu::TexelCopyBufferLayout { offset: 0, bytes_per_row: Some(padded), rows_per_image: Some(self.height), @@ -397,7 +406,14 @@ impl RenderTarget { slice.map_async(wgpu::MapMode::Read, move |r| { let _ = tx.send(r); }); - self.ctx.device.poll(wgpu::Maintain::Wait); + // Fallible since wgpu 26, and worth propagating rather than ignoring: + // the failure it reports is a lost device (NFR-R7), and without this + // the map callback below simply never arrives and the error surfaces + // as a timeout somewhere less informative. + self.ctx + .device + .poll(wgpu::PollType::wait_indefinitely()) + .map_err(|e| GpuError::Readback(e.to_string()))?; rx.recv() .map_err(|e| GpuError::Readback(e.to_string()))? .map_err(|e| GpuError::Readback(e.to_string()))?; diff --git a/docs/traceability.md b/docs/traceability.md index 986acc7..af6023b 100644 --- a/docs/traceability.md +++ b/docs/traceability.md @@ -56,7 +56,7 @@ _None._ | FR-DEV-3d | [`core/dr-pipeline/src/framing.rs:174`](../core/dr-pipeline/src/framing.rs#L174) | | FR-DEV-3e | [`core/dr-decode/src/lib.rs:492`](../core/dr-decode/src/lib.rs#L492), [`core/dr-decode/src/lib.rs:612`](../core/dr-decode/src/lib.rs#L612) | | FR-DEV-3h | [`core/dr-decode/src/lib.rs:307`](../core/dr-decode/src/lib.rs#L307), [`core/dr-decode/src/preview.rs:29`](../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:188`](../core/dr-pipeline/src/framing.rs#L188), [`core/dr-types/src/lib.rs:272`](../core/dr-types/src/lib.rs#L272) | -| FR-DEV-4 | [`core/dr-gpu/src/lib.rs:123`](../core/dr-gpu/src/lib.rs#L123) | +| FR-DEV-4 | [`core/dr-gpu/src/lib.rs:132`](../core/dr-gpu/src/lib.rs#L132) | | FR-DSP-1 | [`ui/dr-ui/src/lib.rs:45`](../ui/dr-ui/src/lib.rs#L45) | | FR-EXP-1 | [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) | | FR-EXP-2 | [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) | @@ -105,7 +105,7 @@ _None._ | NFR-RES-4 | [`core/dr-catalog/src/cache.rs:1`](../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/schema.rs:230`](../core/dr-catalog/src/schema.rs#L230), [`core/dr-thumbs/src/codec.rs:1`](../core/dr-thumbs/src/codec.rs#L1), [`core/dr-thumbs/src/lib.rs:1`](../core/dr-thumbs/src/lib.rs#L1), [`core/dr-thumbs/src/lib.rs:376`](../core/dr-thumbs/src/lib.rs#L376) | | NFR-SEC-1 | [`core/dr-decode/src/error.rs:1`](../core/dr-decode/src/error.rs#L1) | | R1 | [`tools/traceability/src/lib.rs:495`](../tools/traceability/src/lib.rs#L495), [`tools/traceability/src/lib.rs:499`](../tools/traceability/src/lib.rs#L499) | -| R4 | [`core/dr-gpu/src/lib.rs:123`](../core/dr-gpu/src/lib.rs#L123) | +| R4 | [`core/dr-gpu/src/lib.rs:132`](../core/dr-gpu/src/lib.rs#L132) | ## Not yet tagged